This commit is contained in:
Florian Pose 2011-05-12 16:45:02 +02:00
commit 01de69446f
107 changed files with 113154 additions and 1607 deletions

View File

@ -136,3 +136,5 @@ tool/Makefile
tool/Makefile.in
tool/TAGS
tool/ethercat
debuild.log

View File

@ -27,6 +27,7 @@ General Features:
* Supports any realtime environment through independent architecture.
- RTAI, Xenomai, RT-Preempt, etc.
- RTDM Interface for userspace realtime enviroments
- Operation possible without any realtime extension at all.
* Common API for Realtime-Applications in kernel- and userspace.

View File

@ -35,4 +35,8 @@ ifeq (@ENABLE_TTY@,1)
obj-m += tty/
endif
ifeq (@ENABLE_RTDM@,1)
obj-m += rtdm/
endif
#------------------------------------------------------------------------------

View File

@ -47,6 +47,10 @@ if ENABLE_TTY
SUBDIRS += tty
endif
if ENABLE_RTDM
SUBDIRS += rtdm
endif
# userspace example depends on lib/
SUBDIRS += examples
@ -59,6 +63,7 @@ DIST_SUBDIRS = \
master \
script \
tool \
rtdm \
tty
noinst_HEADERS = \

View File

@ -365,13 +365,15 @@ AC_SUBST(KERNEL_R8169,[$kernel_r8169])
AC_ARG_WITH([rtai-dir],
AC_HELP_STRING(
[--with-rtai-dir=<DIR>],
[RTAI path (only for RTAI examples)]
[RTAI path (only for RTDM Interface or RTAI examples)]
),
[
rtaidir=[$withval]
rtai=1
],
[
rtaidir=""
rtai=0
]
)
@ -387,6 +389,71 @@ else
fi
AC_SUBST(RTAI_DIR,[$rtaidir])
AM_CONDITIONAL(ENABLE_RTAI, test "x$rtai" = "x1")
AC_SUBST(ENABLE_RTAI,[$rtai])
#------------------------------------------------------------------------------
# Xenomai path (optional)
#------------------------------------------------------------------------------
AC_ARG_WITH([xenomai-dir],
AC_HELP_STRING(
[--with-xenomai-dir=<DIR>],
[Xenomai path (only for RTDM Interface)]
),
[
xenomaidir=[$withval]
xeno=1
],
[
xenomaidir=""
xeno=0
]
)
AC_MSG_CHECKING([for Xenomai path])
if test -z "${xenomaidir}"; then
AC_MSG_RESULT([not specified.])
else
if test \! -r ${xenomaidir}/include/xeno_config.h; then
AC_MSG_ERROR([no Xenomai installation found in ${xenomaidir}!])
fi
AC_MSG_RESULT([$xenomaidir])
fi
AC_SUBST(XENOMAI_DIR,[$xenomaidir])
AM_CONDITIONAL(ENABLE_XENOMAI, test "x$xeno" = "x1")
AC_SUBST(ENABLE_XENOMAI,[$xeno])
#------------------------------------------------------------------------------
# RTDM Interface (optional)
#------------------------------------------------------------------------------
AC_ARG_ENABLE([rtdm],
AC_HELP_STRING(
[--enable-rtdm],
[Enable RTDM Interface, depends on RTAI or Xenomai]
),
[
case "${enableval}" in
yes) rtdm=1
;;
no) rtdm=0
;;
*) AC_MSG_ERROR([Invalid value for --enable-rtdm])
;;
esac
],
[rtdm=0]
)
if test "x${rtdm}" = "x1"; then
AC_DEFINE([EC_RTDM], [1], [RTDM interfaces enabled])
fi
AM_CONDITIONAL(ENABLE_RTDM, test "x$rtdm" = "x1")
AC_SUBST(ENABLE_RTDM,[$rtdm])
#------------------------------------------------------------------------------
# Debug interface
@ -512,6 +579,31 @@ if test "x${hrtimer}" = "x1"; then
AC_DEFINE([EC_USE_HRTIMER], [1], [Use hrtimer for scheduling])
fi
#------------------------------------------------------------------------------
# Use 2 datagrams (payload+last-byte) when sending to mailbox (reduces frame size)
#------------------------------------------------------------------------------
AC_ARG_ENABLE([mboxframesize],
AS_HELP_STRING([--enable-mboxframesize],
[Reduced frame size when sending to mailbox, uses 2 datagrams (default: no)]),
[
case "${enableval}" in
yes) mboxframesize=1
;;
no) mboxframesize=0
;;
*) AC_MSG_ERROR([Invalid value for --enable-mboxframesize])
;;
esac
],
[mboxframesize=0]
)
if test "x${mboxframesize}" = "x1"; then
AC_DEFINE([EC_REDUCE_MBOXFRAMESIZE], [1], [Reduced frame size when sending to mailbox])
fi
#------------------------------------------------------------------------------
# Read alias address from register
#------------------------------------------------------------------------------
@ -536,6 +628,7 @@ if test "x${regalias}" = "x1"; then
AC_DEFINE([EC_REGALIAS], [1], [Read alias adresses from register])
fi
#------------------------------------------------------------------------------
# Command-line tool
#-----------------------------------------------------------------------------
@ -626,6 +719,9 @@ AC_CONFIG_FILES([
examples/tty/Kbuild
examples/tty/Makefile
examples/user/Makefile
examples/xenomai/Makefile
examples/xenomai_posix/Makefile
examples/rtai_rtdm/Makefile
include/Makefile
lib/Makefile
m4/Makefile
@ -638,6 +734,8 @@ AC_CONFIG_FILES([
tool/Makefile
tty/Kbuild
tty/Makefile
rtdm/Makefile
rtdm/Kbuild
])
AC_OUTPUT

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -59,8 +59,14 @@ noinst_HEADERS = \
8139too-2.6.29-orig.c \
8139too-2.6.31-ethercat.c \
8139too-2.6.31-orig.c \
8139too-2.6.32-ethercat.c \
8139too-2.6.32-orig.c \
8139too-2.6.33-ethercat.c \
8139too-2.6.33-orig.c \
8139too-2.6.34-ethercat.c \
8139too-2.6.34-orig.c \
8139too-2.6.35-ethercat.c \
8139too-2.6.35-orig.c \
8139too-2.6.36-ethercat.c \
8139too-2.6.36-orig.c \
8139too-2.6.37-ethercat.c \
@ -79,6 +85,8 @@ noinst_HEADERS = \
e100-2.6.29-orig.c \
e100-2.6.31-ethercat.c \
e100-2.6.31-orig.c \
e100-2.6.33-ethercat.c \
e100-2.6.33-orig.c \
ecdev.h \
generic.c \
r8169-2.6.24-ethercat.c \
@ -91,6 +99,8 @@ noinst_HEADERS = \
r8169-2.6.29-orig.c \
r8169-2.6.31-ethercat.c \
r8169-2.6.31-orig.c
r8169-2.6.33-ethercat.c \
r8169-2.6.33-orig.c
EXTRA_DIST = \
Kbuild.in

File diff suppressed because it is too large Load Diff

3091
devices/e100-2.6.33-orig.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -46,6 +46,8 @@ EXTRA_DIST = \
e1000-2.6.27-orig.h \
e1000-2.6.28-ethercat.h \
e1000-2.6.28-orig.h \
e1000-2.6.33-ethercat.h \
e1000-2.6.33-orig.h \
e1000_ethtool-2.6.13-ethercat.c \
e1000_ethtool-2.6.13-orig.c \
e1000_ethtool-2.6.18-ethercat.c \
@ -62,6 +64,8 @@ EXTRA_DIST = \
e1000_ethtool-2.6.27-orig.c \
e1000_ethtool-2.6.28-ethercat.c \
e1000_ethtool-2.6.28-orig.c \
e1000_ethtool-2.6.33-ethercat.c \
e1000_ethtool-2.6.33-orig.c \
e1000_hw-2.6.13-ethercat.c \
e1000_hw-2.6.13-ethercat.h \
e1000_hw-2.6.13-orig.c \
@ -94,6 +98,10 @@ EXTRA_DIST = \
e1000_hw-2.6.28-ethercat.h \
e1000_hw-2.6.28-orig.c \
e1000_hw-2.6.28-orig.h \
e1000_hw-2.6.33-ethercat.c \
e1000_hw-2.6.33-ethercat.h \
e1000_hw-2.6.33-orig.c \
e1000_hw-2.6.33-orig.h \
e1000_main-2.6.13-ethercat.c \
e1000_main-2.6.13-orig.c \
e1000_main-2.6.18-ethercat.c \
@ -110,6 +118,8 @@ EXTRA_DIST = \
e1000_main-2.6.27-orig.c \
e1000_main-2.6.28-ethercat.c \
e1000_main-2.6.28-orig.c \
e1000_main-2.6.33-ethercat.c \
e1000_main-2.6.33-orig.c \
e1000_osdep-2.6.13-ethercat.h \
e1000_osdep-2.6.13-orig.h \
e1000_osdep-2.6.18-ethercat.h \
@ -126,6 +136,8 @@ EXTRA_DIST = \
e1000_osdep-2.6.27-orig.h \
e1000_osdep-2.6.28-ethercat.h \
e1000_osdep-2.6.28-orig.h \
e1000_osdep-2.6.33-ethercat.h \
e1000_osdep-2.6.33-orig.h \
e1000_param-2.6.13-ethercat.c \
e1000_param-2.6.13-orig.c \
e1000_param-2.6.18-ethercat.c \
@ -142,6 +154,8 @@ EXTRA_DIST = \
e1000_param-2.6.27-orig.c \
e1000_param-2.6.28-ethercat.c \
e1000_param-2.6.28-orig.c
e1000_param-2.6.33-ethercat.c \
e1000_param-2.6.33-orig.c
BUILT_SOURCES = \

View File

@ -0,0 +1,357 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
Copyright(c) 1999 - 2006 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
/* Linux PRO/1000 Ethernet Driver main header file */
#ifndef _E1000_H_
#define _E1000_H_
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/types.h>
#include <asm/byteorder.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/pagemap.h>
#include <linux/dma-mapping.h>
#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/capability.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <linux/reboot.h>
#include <net/checksum.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include "../ecdev.h"
#define BAR_0 0
#define BAR_1 1
#define BAR_5 5
#define INTEL_E1000_ETHERNET_DEVICE(device_id) {\
PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
struct e1000_adapter;
#include "e1000_hw-2.6.31-ethercat.h"
#ifdef DBG
#define E1000_DBG(args...) printk(KERN_DEBUG "ec_e1000: " args)
#else
#define E1000_DBG(args...)
#endif
#define E1000_ERR(args...) printk(KERN_ERR "ec_e1000: " args)
#define PFX "ec_e1000: "
#define DPRINTK(nlevel, klevel, fmt, args...) \
do { \
if (NETIF_MSG_##nlevel & adapter->msg_enable) \
printk(KERN_##klevel PFX "%s: %s: " fmt, \
adapter->netdev->name, __func__, ##args); \
} while (0)
#define E1000_MAX_INTR 10
/* TX/RX descriptor defines */
#define E1000_DEFAULT_TXD 256
#define E1000_MAX_TXD 256
#define E1000_MIN_TXD 80
#define E1000_MAX_82544_TXD 4096
#define E1000_DEFAULT_RXD 256
#define E1000_MAX_RXD 256
#define E1000_MIN_RXD 80
#define E1000_MAX_82544_RXD 4096
/* this is the size past which hardware will drop packets when setting LPE=0 */
#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
/* Supported Rx Buffer Sizes */
#define E1000_RXBUFFER_128 128 /* Used for packet split */
#define E1000_RXBUFFER_256 256 /* Used for packet split */
#define E1000_RXBUFFER_512 512
#define E1000_RXBUFFER_1024 1024
#define E1000_RXBUFFER_2048 2048
#define E1000_RXBUFFER_4096 4096
#define E1000_RXBUFFER_8192 8192
#define E1000_RXBUFFER_16384 16384
/* SmartSpeed delimiters */
#define E1000_SMARTSPEED_DOWNSHIFT 3
#define E1000_SMARTSPEED_MAX 15
/* Packet Buffer allocations */
#define E1000_PBA_BYTES_SHIFT 0xA
#define E1000_TX_HEAD_ADDR_SHIFT 7
#define E1000_PBA_TX_MASK 0xFFFF0000
/* Flow Control Watermarks */
#define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */
#define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */
#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
#define E1000_TX_QUEUE_WAKE 16
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */
#define AUTO_ALL_MODES 0
#define E1000_EEPROM_82544_APM 0x0004
#define E1000_EEPROM_ICH8_APME 0x0004
#define E1000_EEPROM_APME 0x0400
#ifndef E1000_MASTER_SLAVE
/* Switch to override PHY master/slave setting */
#define E1000_MASTER_SLAVE e1000_ms_hw_default
#endif
#define E1000_MNG_VLAN_NONE (-1)
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct e1000_buffer {
struct sk_buff *skb;
dma_addr_t dma;
unsigned long time_stamp;
u16 length;
u16 next_to_watch;
};
struct e1000_tx_ring {
/* pointer to the descriptor ring memory */
void *desc;
/* physical address of the descriptor ring */
dma_addr_t dma;
/* length of descriptor ring in bytes */
unsigned int size;
/* number of descriptors in the ring */
unsigned int count;
/* next descriptor to associate a buffer with */
unsigned int next_to_use;
/* next descriptor to check for DD status bit */
unsigned int next_to_clean;
/* array of buffer information structs */
struct e1000_buffer *buffer_info;
u16 tdh;
u16 tdt;
bool last_tx_tso;
};
struct e1000_rx_ring {
/* pointer to the descriptor ring memory */
void *desc;
/* physical address of the descriptor ring */
dma_addr_t dma;
/* length of descriptor ring in bytes */
unsigned int size;
/* number of descriptors in the ring */
unsigned int count;
/* next descriptor to associate a buffer with */
unsigned int next_to_use;
/* next descriptor to check for DD status bit */
unsigned int next_to_clean;
/* array of buffer information structs */
struct e1000_buffer *buffer_info;
/* cpu for rx queue */
int cpu;
u16 rdh;
u16 rdt;
};
#define E1000_DESC_UNUSED(R) \
((((R)->next_to_clean > (R)->next_to_use) \
? 0 : (R)->count) + (R)->next_to_clean - (R)->next_to_use - 1)
#define E1000_RX_DESC_EXT(R, i) \
(&(((union e1000_rx_desc_extended *)((R).desc))[i]))
#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc)
#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc)
#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc)
/* board specific private data structure */
struct e1000_adapter {
struct timer_list tx_fifo_stall_timer;
struct timer_list watchdog_timer;
struct timer_list phy_info_timer;
struct vlan_group *vlgrp;
u16 mng_vlan_id;
u32 bd_number;
u32 rx_buffer_len;
u32 wol;
u32 smartspeed;
u32 en_mng_pt;
u16 link_speed;
u16 link_duplex;
spinlock_t stats_lock;
unsigned int total_tx_bytes;
unsigned int total_tx_packets;
unsigned int total_rx_bytes;
unsigned int total_rx_packets;
/* Interrupt Throttle Rate */
u32 itr;
u32 itr_setting;
u16 tx_itr;
u16 rx_itr;
struct work_struct reset_task;
u8 fc_autoneg;
struct timer_list blink_timer;
unsigned long led_status;
/* TX */
struct e1000_tx_ring *tx_ring; /* One per active queue */
unsigned int restart_queue;
unsigned long tx_queue_len;
u32 txd_cmd;
u32 tx_int_delay;
u32 tx_abs_int_delay;
u32 gotcl;
u64 gotcl_old;
u64 tpt_old;
u64 colc_old;
u32 tx_timeout_count;
u32 tx_fifo_head;
u32 tx_head_addr;
u32 tx_fifo_size;
u8 tx_timeout_factor;
atomic_t tx_fifo_stall;
bool pcix_82544;
bool detect_tx_hung;
/* RX */
bool (*clean_rx)(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
void (*alloc_rx_buf)(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int cleaned_count);
struct e1000_rx_ring *rx_ring; /* One per active queue */
struct napi_struct napi;
int num_tx_queues;
int num_rx_queues;
u64 hw_csum_err;
u64 hw_csum_good;
u64 rx_hdr_split;
u32 alloc_rx_buff_failed;
u32 rx_int_delay;
u32 rx_abs_int_delay;
bool rx_csum;
u32 gorcl;
u64 gorcl_old;
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
struct net_device_stats net_stats;
/* structs defined in e1000_hw.h */
struct e1000_hw hw;
struct e1000_hw_stats stats;
struct e1000_phy_info phy_info;
struct e1000_phy_stats phy_stats;
u32 test_icr;
struct e1000_tx_ring test_tx_ring;
struct e1000_rx_ring test_rx_ring;
int msg_enable;
bool have_msi;
/* to not mess up cache alignment, always add to the bottom */
bool tso_force;
bool smart_power_down; /* phy smart power down */
bool quad_port_a;
unsigned long flags;
u32 eeprom_wol;
/* for ioport free */
int bars;
int need_ioport;
ec_device_t *ecdev;
unsigned long ec_watchdog_jiffies;
};
enum e1000_state_t {
__E1000_TESTING,
__E1000_RESETTING,
__E1000_DOWN
};
extern char e1000_driver_name[];
extern const char e1000_driver_version[];
extern int e1000_up(struct e1000_adapter *adapter);
extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_reinit_locked(struct e1000_adapter *adapter);
extern void e1000_reset(struct e1000_adapter *adapter);
extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx);
extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
extern void e1000_update_stats(struct e1000_adapter *adapter);
extern void e1000_power_up_phy(struct e1000_adapter *);
extern void e1000_set_ethtool_ops(struct net_device *netdev);
extern void e1000_check_options(struct e1000_adapter *adapter);
#endif /* _E1000_H_ */

View File

@ -0,0 +1,352 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
Copyright(c) 1999 - 2006 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
/* Linux PRO/1000 Ethernet Driver main header file */
#ifndef _E1000_H_
#define _E1000_H_
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/types.h>
#include <asm/byteorder.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/pagemap.h>
#include <linux/dma-mapping.h>
#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/capability.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <linux/reboot.h>
#include <net/checksum.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#define BAR_0 0
#define BAR_1 1
#define BAR_5 5
#define INTEL_E1000_ETHERNET_DEVICE(device_id) {\
PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
struct e1000_adapter;
#include "e1000_hw.h"
#ifdef DBG
#define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args)
#else
#define E1000_DBG(args...)
#endif
#define E1000_ERR(args...) printk(KERN_ERR "e1000: " args)
#define PFX "e1000: "
#define DPRINTK(nlevel, klevel, fmt, args...) \
do { \
if (NETIF_MSG_##nlevel & adapter->msg_enable) \
printk(KERN_##klevel PFX "%s: %s: " fmt, \
adapter->netdev->name, __func__, ##args); \
} while (0)
#define E1000_MAX_INTR 10
/* TX/RX descriptor defines */
#define E1000_DEFAULT_TXD 256
#define E1000_MAX_TXD 256
#define E1000_MIN_TXD 80
#define E1000_MAX_82544_TXD 4096
#define E1000_DEFAULT_RXD 256
#define E1000_MAX_RXD 256
#define E1000_MIN_RXD 80
#define E1000_MAX_82544_RXD 4096
/* this is the size past which hardware will drop packets when setting LPE=0 */
#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
/* Supported Rx Buffer Sizes */
#define E1000_RXBUFFER_128 128 /* Used for packet split */
#define E1000_RXBUFFER_256 256 /* Used for packet split */
#define E1000_RXBUFFER_512 512
#define E1000_RXBUFFER_1024 1024
#define E1000_RXBUFFER_2048 2048
#define E1000_RXBUFFER_4096 4096
#define E1000_RXBUFFER_8192 8192
#define E1000_RXBUFFER_16384 16384
/* SmartSpeed delimiters */
#define E1000_SMARTSPEED_DOWNSHIFT 3
#define E1000_SMARTSPEED_MAX 15
/* Packet Buffer allocations */
#define E1000_PBA_BYTES_SHIFT 0xA
#define E1000_TX_HEAD_ADDR_SHIFT 7
#define E1000_PBA_TX_MASK 0xFFFF0000
/* Flow Control Watermarks */
#define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */
#define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */
#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
#define E1000_TX_QUEUE_WAKE 16
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */
#define AUTO_ALL_MODES 0
#define E1000_EEPROM_82544_APM 0x0004
#define E1000_EEPROM_ICH8_APME 0x0004
#define E1000_EEPROM_APME 0x0400
#ifndef E1000_MASTER_SLAVE
/* Switch to override PHY master/slave setting */
#define E1000_MASTER_SLAVE e1000_ms_hw_default
#endif
#define E1000_MNG_VLAN_NONE (-1)
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct e1000_buffer {
struct sk_buff *skb;
dma_addr_t dma;
unsigned long time_stamp;
u16 length;
u16 next_to_watch;
};
struct e1000_tx_ring {
/* pointer to the descriptor ring memory */
void *desc;
/* physical address of the descriptor ring */
dma_addr_t dma;
/* length of descriptor ring in bytes */
unsigned int size;
/* number of descriptors in the ring */
unsigned int count;
/* next descriptor to associate a buffer with */
unsigned int next_to_use;
/* next descriptor to check for DD status bit */
unsigned int next_to_clean;
/* array of buffer information structs */
struct e1000_buffer *buffer_info;
u16 tdh;
u16 tdt;
bool last_tx_tso;
};
struct e1000_rx_ring {
/* pointer to the descriptor ring memory */
void *desc;
/* physical address of the descriptor ring */
dma_addr_t dma;
/* length of descriptor ring in bytes */
unsigned int size;
/* number of descriptors in the ring */
unsigned int count;
/* next descriptor to associate a buffer with */
unsigned int next_to_use;
/* next descriptor to check for DD status bit */
unsigned int next_to_clean;
/* array of buffer information structs */
struct e1000_buffer *buffer_info;
/* cpu for rx queue */
int cpu;
u16 rdh;
u16 rdt;
};
#define E1000_DESC_UNUSED(R) \
((((R)->next_to_clean > (R)->next_to_use) \
? 0 : (R)->count) + (R)->next_to_clean - (R)->next_to_use - 1)
#define E1000_RX_DESC_EXT(R, i) \
(&(((union e1000_rx_desc_extended *)((R).desc))[i]))
#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc)
#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc)
#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc)
/* board specific private data structure */
struct e1000_adapter {
struct timer_list tx_fifo_stall_timer;
struct timer_list watchdog_timer;
struct timer_list phy_info_timer;
struct vlan_group *vlgrp;
u16 mng_vlan_id;
u32 bd_number;
u32 rx_buffer_len;
u32 wol;
u32 smartspeed;
u32 en_mng_pt;
u16 link_speed;
u16 link_duplex;
spinlock_t stats_lock;
unsigned int total_tx_bytes;
unsigned int total_tx_packets;
unsigned int total_rx_bytes;
unsigned int total_rx_packets;
/* Interrupt Throttle Rate */
u32 itr;
u32 itr_setting;
u16 tx_itr;
u16 rx_itr;
struct work_struct reset_task;
u8 fc_autoneg;
struct timer_list blink_timer;
unsigned long led_status;
/* TX */
struct e1000_tx_ring *tx_ring; /* One per active queue */
unsigned int restart_queue;
unsigned long tx_queue_len;
u32 txd_cmd;
u32 tx_int_delay;
u32 tx_abs_int_delay;
u32 gotcl;
u64 gotcl_old;
u64 tpt_old;
u64 colc_old;
u32 tx_timeout_count;
u32 tx_fifo_head;
u32 tx_head_addr;
u32 tx_fifo_size;
u8 tx_timeout_factor;
atomic_t tx_fifo_stall;
bool pcix_82544;
bool detect_tx_hung;
/* RX */
bool (*clean_rx)(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
void (*alloc_rx_buf)(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int cleaned_count);
struct e1000_rx_ring *rx_ring; /* One per active queue */
struct napi_struct napi;
int num_tx_queues;
int num_rx_queues;
u64 hw_csum_err;
u64 hw_csum_good;
u64 rx_hdr_split;
u32 alloc_rx_buff_failed;
u32 rx_int_delay;
u32 rx_abs_int_delay;
bool rx_csum;
u32 gorcl;
u64 gorcl_old;
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
struct net_device_stats net_stats;
/* structs defined in e1000_hw.h */
struct e1000_hw hw;
struct e1000_hw_stats stats;
struct e1000_phy_info phy_info;
struct e1000_phy_stats phy_stats;
u32 test_icr;
struct e1000_tx_ring test_tx_ring;
struct e1000_rx_ring test_rx_ring;
int msg_enable;
bool have_msi;
/* to not mess up cache alignment, always add to the bottom */
bool tso_force;
bool smart_power_down; /* phy smart power down */
bool quad_port_a;
unsigned long flags;
u32 eeprom_wol;
/* for ioport free */
int bars;
int need_ioport;
};
enum e1000_state_t {
__E1000_TESTING,
__E1000_RESETTING,
__E1000_DOWN
};
extern char e1000_driver_name[];
extern const char e1000_driver_version[];
extern int e1000_up(struct e1000_adapter *adapter);
extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_reinit_locked(struct e1000_adapter *adapter);
extern void e1000_reset(struct e1000_adapter *adapter);
extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx);
extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
extern void e1000_update_stats(struct e1000_adapter *adapter);
extern void e1000_power_up_phy(struct e1000_adapter *);
extern void e1000_set_ethtool_ops(struct net_device *netdev);
extern void e1000_check_options(struct e1000_adapter *adapter);
#endif /* _E1000_H_ */

View File

@ -0,0 +1,361 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
Copyright(c) 1999 - 2006 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
/* Linux PRO/1000 Ethernet Driver main header file */
#ifndef _E1000_H_
#define _E1000_H_
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/types.h>
#include <asm/byteorder.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/pagemap.h>
#include <linux/dma-mapping.h>
#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/capability.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <linux/reboot.h>
#include <net/checksum.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include "../ecdev.h"
#define BAR_0 0
#define BAR_1 1
#define BAR_5 5
#define INTEL_E1000_ETHERNET_DEVICE(device_id) {\
PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
struct e1000_adapter;
#include "e1000_hw-2.6.33-ethercat.h"
#ifdef DBG
#define E1000_DBG(args...) printk(KERN_DEBUG "ec_e1000: " args)
#else
#define E1000_DBG(args...)
#endif
#define E1000_ERR(args...) printk(KERN_ERR "ec_e1000: " args)
#define PFX "ec_e1000: "
#define DPRINTK(nlevel, klevel, fmt, args...) \
do { \
if (NETIF_MSG_##nlevel & adapter->msg_enable) \
printk(KERN_##klevel PFX "%s: %s: " fmt, \
adapter->netdev->name, __func__, ##args); \
} while (0)
#define E1000_MAX_INTR 10
/* TX/RX descriptor defines */
#define E1000_DEFAULT_TXD 256
#define E1000_MAX_TXD 256
#define E1000_MIN_TXD 80
#define E1000_MAX_82544_TXD 4096
#define E1000_DEFAULT_RXD 256
#define E1000_MAX_RXD 256
#define E1000_MIN_RXD 80
#define E1000_MAX_82544_RXD 4096
#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */
#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */
/* this is the size past which hardware will drop packets when setting LPE=0 */
#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
/* Supported Rx Buffer Sizes */
#define E1000_RXBUFFER_128 128 /* Used for packet split */
#define E1000_RXBUFFER_256 256 /* Used for packet split */
#define E1000_RXBUFFER_512 512
#define E1000_RXBUFFER_1024 1024
#define E1000_RXBUFFER_2048 2048
#define E1000_RXBUFFER_4096 4096
#define E1000_RXBUFFER_8192 8192
#define E1000_RXBUFFER_16384 16384
/* SmartSpeed delimiters */
#define E1000_SMARTSPEED_DOWNSHIFT 3
#define E1000_SMARTSPEED_MAX 15
/* Packet Buffer allocations */
#define E1000_PBA_BYTES_SHIFT 0xA
#define E1000_TX_HEAD_ADDR_SHIFT 7
#define E1000_PBA_TX_MASK 0xFFFF0000
/* Flow Control Watermarks */
#define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */
#define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */
#define E1000_FC_PAUSE_TIME 0xFFFF /* pause for the max or until send xon */
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
#define E1000_TX_QUEUE_WAKE 16
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */
#define AUTO_ALL_MODES 0
#define E1000_EEPROM_82544_APM 0x0004
#define E1000_EEPROM_APME 0x0400
#ifndef E1000_MASTER_SLAVE
/* Switch to override PHY master/slave setting */
#define E1000_MASTER_SLAVE e1000_ms_hw_default
#endif
#define E1000_MNG_VLAN_NONE (-1)
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct e1000_buffer {
struct sk_buff *skb;
dma_addr_t dma;
struct page *page;
unsigned long time_stamp;
u16 length;
u16 next_to_watch;
u16 mapped_as_page;
};
struct e1000_tx_ring {
/* pointer to the descriptor ring memory */
void *desc;
/* physical address of the descriptor ring */
dma_addr_t dma;
/* length of descriptor ring in bytes */
unsigned int size;
/* number of descriptors in the ring */
unsigned int count;
/* next descriptor to associate a buffer with */
unsigned int next_to_use;
/* next descriptor to check for DD status bit */
unsigned int next_to_clean;
/* array of buffer information structs */
struct e1000_buffer *buffer_info;
u16 tdh;
u16 tdt;
bool last_tx_tso;
};
struct e1000_rx_ring {
/* pointer to the descriptor ring memory */
void *desc;
/* physical address of the descriptor ring */
dma_addr_t dma;
/* length of descriptor ring in bytes */
unsigned int size;
/* number of descriptors in the ring */
unsigned int count;
/* next descriptor to associate a buffer with */
unsigned int next_to_use;
/* next descriptor to check for DD status bit */
unsigned int next_to_clean;
/* array of buffer information structs */
struct e1000_buffer *buffer_info;
struct sk_buff *rx_skb_top;
/* cpu for rx queue */
int cpu;
u16 rdh;
u16 rdt;
};
#define E1000_DESC_UNUSED(R) \
((((R)->next_to_clean > (R)->next_to_use) \
? 0 : (R)->count) + (R)->next_to_clean - (R)->next_to_use - 1)
#define E1000_RX_DESC_EXT(R, i) \
(&(((union e1000_rx_desc_extended *)((R).desc))[i]))
#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc)
#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc)
#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc)
/* board specific private data structure */
struct e1000_adapter {
struct timer_list tx_fifo_stall_timer;
struct timer_list watchdog_timer;
struct timer_list phy_info_timer;
struct vlan_group *vlgrp;
u16 mng_vlan_id;
u32 bd_number;
u32 rx_buffer_len;
u32 wol;
u32 smartspeed;
u32 en_mng_pt;
u16 link_speed;
u16 link_duplex;
spinlock_t stats_lock;
unsigned int total_tx_bytes;
unsigned int total_tx_packets;
unsigned int total_rx_bytes;
unsigned int total_rx_packets;
/* Interrupt Throttle Rate */
u32 itr;
u32 itr_setting;
u16 tx_itr;
u16 rx_itr;
struct work_struct reset_task;
u8 fc_autoneg;
struct timer_list blink_timer;
unsigned long led_status;
/* TX */
struct e1000_tx_ring *tx_ring; /* One per active queue */
unsigned int restart_queue;
unsigned long tx_queue_len;
u32 txd_cmd;
u32 tx_int_delay;
u32 tx_abs_int_delay;
u32 gotcl;
u64 gotcl_old;
u64 tpt_old;
u64 colc_old;
u32 tx_timeout_count;
u32 tx_fifo_head;
u32 tx_head_addr;
u32 tx_fifo_size;
u8 tx_timeout_factor;
atomic_t tx_fifo_stall;
bool pcix_82544;
bool detect_tx_hung;
/* RX */
bool (*clean_rx)(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
void (*alloc_rx_buf)(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int cleaned_count);
struct e1000_rx_ring *rx_ring; /* One per active queue */
struct napi_struct napi;
int num_tx_queues;
int num_rx_queues;
u64 hw_csum_err;
u64 hw_csum_good;
u32 alloc_rx_buff_failed;
u32 rx_int_delay;
u32 rx_abs_int_delay;
bool rx_csum;
u32 gorcl;
u64 gorcl_old;
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
/* structs defined in e1000_hw.h */
struct e1000_hw hw;
struct e1000_hw_stats stats;
struct e1000_phy_info phy_info;
struct e1000_phy_stats phy_stats;
u32 test_icr;
struct e1000_tx_ring test_tx_ring;
struct e1000_rx_ring test_rx_ring;
int msg_enable;
/* to not mess up cache alignment, always add to the bottom */
bool tso_force;
bool smart_power_down; /* phy smart power down */
bool quad_port_a;
unsigned long flags;
u32 eeprom_wol;
/* for ioport free */
int bars;
int need_ioport;
bool discarding;
ec_device_t *ecdev;
unsigned long ec_watchdog_jiffies;
};
enum e1000_state_t {
__E1000_TESTING,
__E1000_RESETTING,
__E1000_DOWN
};
extern char e1000_driver_name[];
extern const char e1000_driver_version[];
extern int e1000_up(struct e1000_adapter *adapter);
extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_reinit_locked(struct e1000_adapter *adapter);
extern void e1000_reset(struct e1000_adapter *adapter);
extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx);
extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
extern void e1000_update_stats(struct e1000_adapter *adapter);
extern void e1000_power_up_phy(struct e1000_adapter *);
extern void e1000_set_ethtool_ops(struct net_device *netdev);
extern void e1000_check_options(struct e1000_adapter *adapter);
#endif /* _E1000_H_ */

View File

@ -0,0 +1,356 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
Copyright(c) 1999 - 2006 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
/* Linux PRO/1000 Ethernet Driver main header file */
#ifndef _E1000_H_
#define _E1000_H_
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/types.h>
#include <asm/byteorder.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/pagemap.h>
#include <linux/dma-mapping.h>
#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/capability.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <linux/reboot.h>
#include <net/checksum.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#define BAR_0 0
#define BAR_1 1
#define BAR_5 5
#define INTEL_E1000_ETHERNET_DEVICE(device_id) {\
PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
struct e1000_adapter;
#include "e1000_hw.h"
#ifdef DBG
#define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args)
#else
#define E1000_DBG(args...)
#endif
#define E1000_ERR(args...) printk(KERN_ERR "e1000: " args)
#define PFX "e1000: "
#define DPRINTK(nlevel, klevel, fmt, args...) \
do { \
if (NETIF_MSG_##nlevel & adapter->msg_enable) \
printk(KERN_##klevel PFX "%s: %s: " fmt, \
adapter->netdev->name, __func__, ##args); \
} while (0)
#define E1000_MAX_INTR 10
/* TX/RX descriptor defines */
#define E1000_DEFAULT_TXD 256
#define E1000_MAX_TXD 256
#define E1000_MIN_TXD 80
#define E1000_MAX_82544_TXD 4096
#define E1000_DEFAULT_RXD 256
#define E1000_MAX_RXD 256
#define E1000_MIN_RXD 80
#define E1000_MAX_82544_RXD 4096
#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */
#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */
/* this is the size past which hardware will drop packets when setting LPE=0 */
#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
/* Supported Rx Buffer Sizes */
#define E1000_RXBUFFER_128 128 /* Used for packet split */
#define E1000_RXBUFFER_256 256 /* Used for packet split */
#define E1000_RXBUFFER_512 512
#define E1000_RXBUFFER_1024 1024
#define E1000_RXBUFFER_2048 2048
#define E1000_RXBUFFER_4096 4096
#define E1000_RXBUFFER_8192 8192
#define E1000_RXBUFFER_16384 16384
/* SmartSpeed delimiters */
#define E1000_SMARTSPEED_DOWNSHIFT 3
#define E1000_SMARTSPEED_MAX 15
/* Packet Buffer allocations */
#define E1000_PBA_BYTES_SHIFT 0xA
#define E1000_TX_HEAD_ADDR_SHIFT 7
#define E1000_PBA_TX_MASK 0xFFFF0000
/* Flow Control Watermarks */
#define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */
#define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */
#define E1000_FC_PAUSE_TIME 0xFFFF /* pause for the max or until send xon */
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
#define E1000_TX_QUEUE_WAKE 16
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */
#define AUTO_ALL_MODES 0
#define E1000_EEPROM_82544_APM 0x0004
#define E1000_EEPROM_APME 0x0400
#ifndef E1000_MASTER_SLAVE
/* Switch to override PHY master/slave setting */
#define E1000_MASTER_SLAVE e1000_ms_hw_default
#endif
#define E1000_MNG_VLAN_NONE (-1)
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct e1000_buffer {
struct sk_buff *skb;
dma_addr_t dma;
struct page *page;
unsigned long time_stamp;
u16 length;
u16 next_to_watch;
u16 mapped_as_page;
};
struct e1000_tx_ring {
/* pointer to the descriptor ring memory */
void *desc;
/* physical address of the descriptor ring */
dma_addr_t dma;
/* length of descriptor ring in bytes */
unsigned int size;
/* number of descriptors in the ring */
unsigned int count;
/* next descriptor to associate a buffer with */
unsigned int next_to_use;
/* next descriptor to check for DD status bit */
unsigned int next_to_clean;
/* array of buffer information structs */
struct e1000_buffer *buffer_info;
u16 tdh;
u16 tdt;
bool last_tx_tso;
};
struct e1000_rx_ring {
/* pointer to the descriptor ring memory */
void *desc;
/* physical address of the descriptor ring */
dma_addr_t dma;
/* length of descriptor ring in bytes */
unsigned int size;
/* number of descriptors in the ring */
unsigned int count;
/* next descriptor to associate a buffer with */
unsigned int next_to_use;
/* next descriptor to check for DD status bit */
unsigned int next_to_clean;
/* array of buffer information structs */
struct e1000_buffer *buffer_info;
struct sk_buff *rx_skb_top;
/* cpu for rx queue */
int cpu;
u16 rdh;
u16 rdt;
};
#define E1000_DESC_UNUSED(R) \
((((R)->next_to_clean > (R)->next_to_use) \
? 0 : (R)->count) + (R)->next_to_clean - (R)->next_to_use - 1)
#define E1000_RX_DESC_EXT(R, i) \
(&(((union e1000_rx_desc_extended *)((R).desc))[i]))
#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc)
#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc)
#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc)
/* board specific private data structure */
struct e1000_adapter {
struct timer_list tx_fifo_stall_timer;
struct timer_list watchdog_timer;
struct timer_list phy_info_timer;
struct vlan_group *vlgrp;
u16 mng_vlan_id;
u32 bd_number;
u32 rx_buffer_len;
u32 wol;
u32 smartspeed;
u32 en_mng_pt;
u16 link_speed;
u16 link_duplex;
spinlock_t stats_lock;
unsigned int total_tx_bytes;
unsigned int total_tx_packets;
unsigned int total_rx_bytes;
unsigned int total_rx_packets;
/* Interrupt Throttle Rate */
u32 itr;
u32 itr_setting;
u16 tx_itr;
u16 rx_itr;
struct work_struct reset_task;
u8 fc_autoneg;
struct timer_list blink_timer;
unsigned long led_status;
/* TX */
struct e1000_tx_ring *tx_ring; /* One per active queue */
unsigned int restart_queue;
unsigned long tx_queue_len;
u32 txd_cmd;
u32 tx_int_delay;
u32 tx_abs_int_delay;
u32 gotcl;
u64 gotcl_old;
u64 tpt_old;
u64 colc_old;
u32 tx_timeout_count;
u32 tx_fifo_head;
u32 tx_head_addr;
u32 tx_fifo_size;
u8 tx_timeout_factor;
atomic_t tx_fifo_stall;
bool pcix_82544;
bool detect_tx_hung;
/* RX */
bool (*clean_rx)(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
void (*alloc_rx_buf)(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int cleaned_count);
struct e1000_rx_ring *rx_ring; /* One per active queue */
struct napi_struct napi;
int num_tx_queues;
int num_rx_queues;
u64 hw_csum_err;
u64 hw_csum_good;
u32 alloc_rx_buff_failed;
u32 rx_int_delay;
u32 rx_abs_int_delay;
bool rx_csum;
u32 gorcl;
u64 gorcl_old;
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
/* structs defined in e1000_hw.h */
struct e1000_hw hw;
struct e1000_hw_stats stats;
struct e1000_phy_info phy_info;
struct e1000_phy_stats phy_stats;
u32 test_icr;
struct e1000_tx_ring test_tx_ring;
struct e1000_rx_ring test_rx_ring;
int msg_enable;
/* to not mess up cache alignment, always add to the bottom */
bool tso_force;
bool smart_power_down; /* phy smart power down */
bool quad_port_a;
unsigned long flags;
u32 eeprom_wol;
/* for ioport free */
int bars;
int need_ioport;
bool discarding;
};
enum e1000_state_t {
__E1000_TESTING,
__E1000_RESETTING,
__E1000_DOWN
};
extern char e1000_driver_name[];
extern const char e1000_driver_version[];
extern int e1000_up(struct e1000_adapter *adapter);
extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_reinit_locked(struct e1000_adapter *adapter);
extern void e1000_reset(struct e1000_adapter *adapter);
extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx);
extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
extern void e1000_update_stats(struct e1000_adapter *adapter);
extern void e1000_power_up_phy(struct e1000_adapter *);
extern void e1000_set_ethtool_ops(struct net_device *netdev);
extern void e1000_check_options(struct e1000_adapter *adapter);
#endif /* _E1000_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,113 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
Copyright(c) 1999 - 2006 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
/* glue for the OS independent part of e1000
* includes register access macros
*/
#ifndef _E1000_OSDEP_H_
#define _E1000_OSDEP_H_
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#ifdef DBG
#define DEBUGOUT(S) printk(KERN_DEBUG S "\n")
#define DEBUGOUT1(S, A...) printk(KERN_DEBUG S "\n", A)
#else
#define DEBUGOUT(S)
#define DEBUGOUT1(S, A...)
#endif
#define DEBUGFUNC(F) DEBUGOUT(F "\n")
#define DEBUGOUT2 DEBUGOUT1
#define DEBUGOUT3 DEBUGOUT2
#define DEBUGOUT7 DEBUGOUT3
#define er32(reg) \
(readl(hw->hw_addr + ((hw->mac_type >= e1000_82543) \
? E1000_##reg : E1000_82542_##reg)))
#define ew32(reg, value) \
(writel((value), (hw->hw_addr + ((hw->mac_type >= e1000_82543) \
? E1000_##reg : E1000_82542_##reg))))
#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
writel((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 2))))
#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
readl((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 2)))
#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \
writew((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 1))))
#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
readw((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 1)))
#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
writeb((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
(offset))))
#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
readb((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
(offset)))
#define E1000_WRITE_FLUSH() er32(STATUS)
#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) ( \
writel((value), ((a)->flash_address + reg)))
#define E1000_READ_ICH_FLASH_REG(a, reg) ( \
readl((a)->flash_address + reg))
#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) ( \
writew((value), ((a)->flash_address + reg)))
#define E1000_READ_ICH_FLASH_REG16(a, reg) ( \
readw((a)->flash_address + reg))
#endif /* _E1000_OSDEP_H_ */

View File

@ -0,0 +1,113 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
Copyright(c) 1999 - 2006 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
/* glue for the OS independent part of e1000
* includes register access macros
*/
#ifndef _E1000_OSDEP_H_
#define _E1000_OSDEP_H_
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#ifdef DBG
#define DEBUGOUT(S) printk(KERN_DEBUG S "\n")
#define DEBUGOUT1(S, A...) printk(KERN_DEBUG S "\n", A)
#else
#define DEBUGOUT(S)
#define DEBUGOUT1(S, A...)
#endif
#define DEBUGFUNC(F) DEBUGOUT(F "\n")
#define DEBUGOUT2 DEBUGOUT1
#define DEBUGOUT3 DEBUGOUT2
#define DEBUGOUT7 DEBUGOUT3
#define er32(reg) \
(readl(hw->hw_addr + ((hw->mac_type >= e1000_82543) \
? E1000_##reg : E1000_82542_##reg)))
#define ew32(reg, value) \
(writel((value), (hw->hw_addr + ((hw->mac_type >= e1000_82543) \
? E1000_##reg : E1000_82542_##reg))))
#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
writel((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 2))))
#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
readl((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 2)))
#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \
writew((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 1))))
#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
readw((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 1)))
#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
writeb((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
(offset))))
#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
readb((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
(offset)))
#define E1000_WRITE_FLUSH() er32(STATUS)
#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) ( \
writel((value), ((a)->flash_address + reg)))
#define E1000_READ_ICH_FLASH_REG(a, reg) ( \
readl((a)->flash_address + reg))
#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) ( \
writew((value), ((a)->flash_address + reg)))
#define E1000_READ_ICH_FLASH_REG16(a, reg) ( \
readw((a)->flash_address + reg))
#endif /* _E1000_OSDEP_H_ */

View File

@ -0,0 +1,113 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
Copyright(c) 1999 - 2006 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
/* glue for the OS independent part of e1000
* includes register access macros
*/
#ifndef _E1000_OSDEP_H_
#define _E1000_OSDEP_H_
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#ifdef DBG
#define DEBUGOUT(S) printk(KERN_DEBUG S "\n")
#define DEBUGOUT1(S, A...) printk(KERN_DEBUG S "\n", A)
#else
#define DEBUGOUT(S)
#define DEBUGOUT1(S, A...)
#endif
#define DEBUGFUNC(F) DEBUGOUT(F "\n")
#define DEBUGOUT2 DEBUGOUT1
#define DEBUGOUT3 DEBUGOUT2
#define DEBUGOUT7 DEBUGOUT3
#define er32(reg) \
(readl(hw->hw_addr + ((hw->mac_type >= e1000_82543) \
? E1000_##reg : E1000_82542_##reg)))
#define ew32(reg, value) \
(writel((value), (hw->hw_addr + ((hw->mac_type >= e1000_82543) \
? E1000_##reg : E1000_82542_##reg))))
#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
writel((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 2))))
#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
readl((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 2)))
#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \
writew((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 1))))
#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
readw((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 1)))
#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
writeb((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
(offset))))
#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
readb((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
(offset)))
#define E1000_WRITE_FLUSH() er32(STATUS)
#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) ( \
writel((value), ((a)->flash_address + reg)))
#define E1000_READ_ICH_FLASH_REG(a, reg) ( \
readl((a)->flash_address + reg))
#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) ( \
writew((value), ((a)->flash_address + reg)))
#define E1000_READ_ICH_FLASH_REG16(a, reg) ( \
readw((a)->flash_address + reg))
#endif /* _E1000_OSDEP_H_ */

View File

@ -0,0 +1,113 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
Copyright(c) 1999 - 2006 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
/* glue for the OS independent part of e1000
* includes register access macros
*/
#ifndef _E1000_OSDEP_H_
#define _E1000_OSDEP_H_
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#ifdef DBG
#define DEBUGOUT(S) printk(KERN_DEBUG S "\n")
#define DEBUGOUT1(S, A...) printk(KERN_DEBUG S "\n", A)
#else
#define DEBUGOUT(S)
#define DEBUGOUT1(S, A...)
#endif
#define DEBUGFUNC(F) DEBUGOUT(F "\n")
#define DEBUGOUT2 DEBUGOUT1
#define DEBUGOUT3 DEBUGOUT2
#define DEBUGOUT7 DEBUGOUT3
#define er32(reg) \
(readl(hw->hw_addr + ((hw->mac_type >= e1000_82543) \
? E1000_##reg : E1000_82542_##reg)))
#define ew32(reg, value) \
(writel((value), (hw->hw_addr + ((hw->mac_type >= e1000_82543) \
? E1000_##reg : E1000_82542_##reg))))
#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
writel((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 2))))
#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
readl((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 2)))
#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \
writew((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 1))))
#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
readw((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
((offset) << 1)))
#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
writeb((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
(offset))))
#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
readb((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
(offset)))
#define E1000_WRITE_FLUSH() er32(STATUS)
#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) ( \
writel((value), ((a)->flash_address + reg)))
#define E1000_READ_ICH_FLASH_REG(a, reg) ( \
readl((a)->flash_address + reg))
#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) ( \
writew((value), ((a)->flash_address + reg)))
#define E1000_READ_ICH_FLASH_REG16(a, reg) ( \
readw((a)->flash_address + reg))
#endif /* _E1000_OSDEP_H_ */

View File

@ -0,0 +1,792 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
Copyright(c) 1999 - 2006 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
#include "e1000-2.6.31-ethercat.h"
/* This is the only thing that needs to be changed to adjust the
* maximum number of ports that the driver can manage.
*/
#define E1000_MAX_NIC 32
#define OPTION_UNSET -1
#define OPTION_DISABLED 0
#define OPTION_ENABLED 1
/* All parameters are treated the same, as an integer array of values.
* This macro just reduces the need to repeat the same declaration code
* over and over (plus this helps to avoid typo bugs).
*/
#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
#define E1000_PARAM(X, desc) \
static int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
static unsigned int num_##X; \
module_param_array_named(X, X, int, &num_##X, 0); \
MODULE_PARM_DESC(X, desc);
/* Transmit Descriptor Count
*
* Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
* Valid Range: 80-4096 for 82544 and newer
*
* Default Value: 256
*/
E1000_PARAM(TxDescriptors, "Number of transmit descriptors");
/* Receive Descriptor Count
*
* Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
* Valid Range: 80-4096 for 82544 and newer
*
* Default Value: 256
*/
E1000_PARAM(RxDescriptors, "Number of receive descriptors");
/* User Specified Speed Override
*
* Valid Range: 0, 10, 100, 1000
* - 0 - auto-negotiate at all supported speeds
* - 10 - only link at 10 Mbps
* - 100 - only link at 100 Mbps
* - 1000 - only link at 1000 Mbps
*
* Default Value: 0
*/
E1000_PARAM(Speed, "Speed setting");
/* User Specified Duplex Override
*
* Valid Range: 0-2
* - 0 - auto-negotiate for duplex
* - 1 - only link at half duplex
* - 2 - only link at full duplex
*
* Default Value: 0
*/
E1000_PARAM(Duplex, "Duplex setting");
/* Auto-negotiation Advertisement Override
*
* Valid Range: 0x01-0x0F, 0x20-0x2F (copper); 0x20 (fiber)
*
* The AutoNeg value is a bit mask describing which speed and duplex
* combinations should be advertised during auto-negotiation.
* The supported speed and duplex modes are listed below
*
* Bit 7 6 5 4 3 2 1 0
* Speed (Mbps) N/A N/A 1000 N/A 100 100 10 10
* Duplex Full Full Half Full Half
*
* Default Value: 0x2F (copper); 0x20 (fiber)
*/
E1000_PARAM(AutoNeg, "Advertised auto-negotiation setting");
#define AUTONEG_ADV_DEFAULT 0x2F
#define AUTONEG_ADV_MASK 0x2F
/* User Specified Flow Control Override
*
* Valid Range: 0-3
* - 0 - No Flow Control
* - 1 - Rx only, respond to PAUSE frames but do not generate them
* - 2 - Tx only, generate PAUSE frames but ignore them on receive
* - 3 - Full Flow Control Support
*
* Default Value: Read flow control settings from the EEPROM
*/
E1000_PARAM(FlowControl, "Flow Control setting");
#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
/* XsumRX - Receive Checksum Offload Enable/Disable
*
* Valid Range: 0, 1
* - 0 - disables all checksum offload
* - 1 - enables receive IP/TCP/UDP checksum offload
* on 82543 and newer -based NICs
*
* Default Value: 1
*/
E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
/* Transmit Interrupt Delay in units of 1.024 microseconds
* Tx interrupt delay needs to typically be set to something non zero
*
* Valid Range: 0-65535
*/
E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
#define DEFAULT_TIDV 8
#define MAX_TXDELAY 0xFFFF
#define MIN_TXDELAY 0
/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds
*
* Valid Range: 0-65535
*/
E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay");
#define DEFAULT_TADV 32
#define MAX_TXABSDELAY 0xFFFF
#define MIN_TXABSDELAY 0
/* Receive Interrupt Delay in units of 1.024 microseconds
* hardware will likely hang if you set this to anything but zero.
*
* Valid Range: 0-65535
*/
E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
#define DEFAULT_RDTR 0
#define MAX_RXDELAY 0xFFFF
#define MIN_RXDELAY 0
/* Receive Absolute Interrupt Delay in units of 1.024 microseconds
*
* Valid Range: 0-65535
*/
E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
#define DEFAULT_RADV 8
#define MAX_RXABSDELAY 0xFFFF
#define MIN_RXABSDELAY 0
/* Interrupt Throttle Rate (interrupts/sec)
*
* Valid Range: 100-100000 (0=off, 1=dynamic, 3=dynamic conservative)
*/
E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
#define DEFAULT_ITR 3
#define MAX_ITR 100000
#define MIN_ITR 100
/* Enable Smart Power Down of the PHY
*
* Valid Range: 0, 1
*
* Default Value: 0 (disabled)
*/
E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
/* Enable Kumeran Lock Loss workaround
*
* Valid Range: 0, 1
*
* Default Value: 1 (enabled)
*/
E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
struct e1000_option {
enum { enable_option, range_option, list_option } type;
const char *name;
const char *err;
int def;
union {
struct { /* range_option info */
int min;
int max;
} r;
struct { /* list_option info */
int nr;
const struct e1000_opt_list { int i; char *str; } *p;
} l;
} arg;
};
static int __devinit e1000_validate_option(unsigned int *value,
const struct e1000_option *opt,
struct e1000_adapter *adapter)
{
if (*value == OPTION_UNSET) {
*value = opt->def;
return 0;
}
switch (opt->type) {
case enable_option:
switch (*value) {
case OPTION_ENABLED:
DPRINTK(PROBE, INFO, "%s Enabled\n", opt->name);
return 0;
case OPTION_DISABLED:
DPRINTK(PROBE, INFO, "%s Disabled\n", opt->name);
return 0;
}
break;
case range_option:
if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
DPRINTK(PROBE, INFO,
"%s set to %i\n", opt->name, *value);
return 0;
}
break;
case list_option: {
int i;
const struct e1000_opt_list *ent;
for (i = 0; i < opt->arg.l.nr; i++) {
ent = &opt->arg.l.p[i];
if (*value == ent->i) {
if (ent->str[0] != '\0')
DPRINTK(PROBE, INFO, "%s\n", ent->str);
return 0;
}
}
}
break;
default:
BUG();
}
DPRINTK(PROBE, INFO, "Invalid %s value specified (%i) %s\n",
opt->name, *value, opt->err);
*value = opt->def;
return -1;
}
static void e1000_check_fiber_options(struct e1000_adapter *adapter);
static void e1000_check_copper_options(struct e1000_adapter *adapter);
/**
* e1000_check_options - Range Checking for Command Line Parameters
* @adapter: board private structure
*
* This routine checks all command line parameters for valid user
* input. If an invalid value is given, or if no user specified
* value exists, a default value is used. The final value is stored
* in a variable in the adapter structure.
**/
void __devinit e1000_check_options(struct e1000_adapter *adapter)
{
struct e1000_option opt;
int bd = adapter->bd_number;
if (bd >= E1000_MAX_NIC) {
DPRINTK(PROBE, NOTICE,
"Warning: no configuration for board #%i\n", bd);
DPRINTK(PROBE, NOTICE, "Using defaults for all values\n");
}
{ /* Transmit Descriptor Count */
struct e1000_tx_ring *tx_ring = adapter->tx_ring;
int i;
e1000_mac_type mac_type = adapter->hw.mac_type;
opt = (struct e1000_option) {
.type = range_option,
.name = "Transmit Descriptors",
.err = "using default of "
__MODULE_STRING(E1000_DEFAULT_TXD),
.def = E1000_DEFAULT_TXD,
.arg = { .r = {
.min = E1000_MIN_TXD,
.max = mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD
}}
};
if (num_TxDescriptors > bd) {
tx_ring->count = TxDescriptors[bd];
e1000_validate_option(&tx_ring->count, &opt, adapter);
tx_ring->count = ALIGN(tx_ring->count,
REQ_TX_DESCRIPTOR_MULTIPLE);
} else {
tx_ring->count = opt.def;
}
for (i = 0; i < adapter->num_tx_queues; i++)
tx_ring[i].count = tx_ring->count;
}
{ /* Receive Descriptor Count */
struct e1000_rx_ring *rx_ring = adapter->rx_ring;
int i;
e1000_mac_type mac_type = adapter->hw.mac_type;
opt = (struct e1000_option) {
.type = range_option,
.name = "Receive Descriptors",
.err = "using default of "
__MODULE_STRING(E1000_DEFAULT_RXD),
.def = E1000_DEFAULT_RXD,
.arg = { .r = {
.min = E1000_MIN_RXD,
.max = mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD
}}
};
if (num_RxDescriptors > bd) {
rx_ring->count = RxDescriptors[bd];
e1000_validate_option(&rx_ring->count, &opt, adapter);
rx_ring->count = ALIGN(rx_ring->count,
REQ_RX_DESCRIPTOR_MULTIPLE);
} else {
rx_ring->count = opt.def;
}
for (i = 0; i < adapter->num_rx_queues; i++)
rx_ring[i].count = rx_ring->count;
}
{ /* Checksum Offload Enable/Disable */
opt = (struct e1000_option) {
.type = enable_option,
.name = "Checksum Offload",
.err = "defaulting to Enabled",
.def = OPTION_ENABLED
};
if (num_XsumRX > bd) {
unsigned int rx_csum = XsumRX[bd];
e1000_validate_option(&rx_csum, &opt, adapter);
adapter->rx_csum = rx_csum;
} else {
adapter->rx_csum = opt.def;
}
}
{ /* Flow Control */
struct e1000_opt_list fc_list[] =
{{ E1000_FC_NONE, "Flow Control Disabled" },
{ E1000_FC_RX_PAUSE,"Flow Control Receive Only" },
{ E1000_FC_TX_PAUSE,"Flow Control Transmit Only" },
{ E1000_FC_FULL, "Flow Control Enabled" },
{ E1000_FC_DEFAULT, "Flow Control Hardware Default" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "Flow Control",
.err = "reading default settings from EEPROM",
.def = E1000_FC_DEFAULT,
.arg = { .l = { .nr = ARRAY_SIZE(fc_list),
.p = fc_list }}
};
if (num_FlowControl > bd) {
unsigned int fc = FlowControl[bd];
e1000_validate_option(&fc, &opt, adapter);
adapter->hw.fc = adapter->hw.original_fc = fc;
} else {
adapter->hw.fc = adapter->hw.original_fc = opt.def;
}
}
{ /* Transmit Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Transmit Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_TIDV),
.def = DEFAULT_TIDV,
.arg = { .r = { .min = MIN_TXDELAY,
.max = MAX_TXDELAY }}
};
if (num_TxIntDelay > bd) {
adapter->tx_int_delay = TxIntDelay[bd];
e1000_validate_option(&adapter->tx_int_delay, &opt,
adapter);
} else {
adapter->tx_int_delay = opt.def;
}
}
{ /* Transmit Absolute Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Transmit Absolute Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_TADV),
.def = DEFAULT_TADV,
.arg = { .r = { .min = MIN_TXABSDELAY,
.max = MAX_TXABSDELAY }}
};
if (num_TxAbsIntDelay > bd) {
adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
adapter);
} else {
adapter->tx_abs_int_delay = opt.def;
}
}
{ /* Receive Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Receive Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_RDTR),
.def = DEFAULT_RDTR,
.arg = { .r = { .min = MIN_RXDELAY,
.max = MAX_RXDELAY }}
};
if (num_RxIntDelay > bd) {
adapter->rx_int_delay = RxIntDelay[bd];
e1000_validate_option(&adapter->rx_int_delay, &opt,
adapter);
} else {
adapter->rx_int_delay = opt.def;
}
}
{ /* Receive Absolute Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Receive Absolute Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_RADV),
.def = DEFAULT_RADV,
.arg = { .r = { .min = MIN_RXABSDELAY,
.max = MAX_RXABSDELAY }}
};
if (num_RxAbsIntDelay > bd) {
adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
adapter);
} else {
adapter->rx_abs_int_delay = opt.def;
}
}
{ /* Interrupt Throttling Rate */
opt = (struct e1000_option) {
.type = range_option,
.name = "Interrupt Throttling Rate (ints/sec)",
.err = "using default of " __MODULE_STRING(DEFAULT_ITR),
.def = DEFAULT_ITR,
.arg = { .r = { .min = MIN_ITR,
.max = MAX_ITR }}
};
if (num_InterruptThrottleRate > bd) {
adapter->itr = InterruptThrottleRate[bd];
switch (adapter->itr) {
case 0:
DPRINTK(PROBE, INFO, "%s turned off\n",
opt.name);
break;
case 1:
DPRINTK(PROBE, INFO, "%s set to dynamic mode\n",
opt.name);
adapter->itr_setting = adapter->itr;
adapter->itr = 20000;
break;
case 3:
DPRINTK(PROBE, INFO,
"%s set to dynamic conservative mode\n",
opt.name);
adapter->itr_setting = adapter->itr;
adapter->itr = 20000;
break;
default:
e1000_validate_option(&adapter->itr, &opt,
adapter);
/* save the setting, because the dynamic bits change itr */
/* clear the lower two bits because they are
* used as control */
adapter->itr_setting = adapter->itr & ~3;
break;
}
} else {
adapter->itr_setting = opt.def;
adapter->itr = 20000;
}
}
{ /* Smart Power Down */
opt = (struct e1000_option) {
.type = enable_option,
.name = "PHY Smart Power Down",
.err = "defaulting to Disabled",
.def = OPTION_DISABLED
};
if (num_SmartPowerDownEnable > bd) {
unsigned int spd = SmartPowerDownEnable[bd];
e1000_validate_option(&spd, &opt, adapter);
adapter->smart_power_down = spd;
} else {
adapter->smart_power_down = opt.def;
}
}
{ /* Kumeran Lock Loss Workaround */
opt = (struct e1000_option) {
.type = enable_option,
.name = "Kumeran Lock Loss Workaround",
.err = "defaulting to Enabled",
.def = OPTION_ENABLED
};
if (num_KumeranLockLoss > bd) {
unsigned int kmrn_lock_loss = KumeranLockLoss[bd];
e1000_validate_option(&kmrn_lock_loss, &opt, adapter);
adapter->hw.kmrn_lock_loss_workaround_disabled = !kmrn_lock_loss;
} else {
adapter->hw.kmrn_lock_loss_workaround_disabled = !opt.def;
}
}
switch (adapter->hw.media_type) {
case e1000_media_type_fiber:
case e1000_media_type_internal_serdes:
e1000_check_fiber_options(adapter);
break;
case e1000_media_type_copper:
e1000_check_copper_options(adapter);
break;
default:
BUG();
}
}
/**
* e1000_check_fiber_options - Range Checking for Link Options, Fiber Version
* @adapter: board private structure
*
* Handles speed and duplex options on fiber adapters
**/
static void __devinit e1000_check_fiber_options(struct e1000_adapter *adapter)
{
int bd = adapter->bd_number;
if (num_Speed > bd) {
DPRINTK(PROBE, INFO, "Speed not valid for fiber adapters, "
"parameter ignored\n");
}
if (num_Duplex > bd) {
DPRINTK(PROBE, INFO, "Duplex not valid for fiber adapters, "
"parameter ignored\n");
}
if ((num_AutoNeg > bd) && (AutoNeg[bd] != 0x20)) {
DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is "
"not valid for fiber adapters, "
"parameter ignored\n");
}
}
/**
* e1000_check_copper_options - Range Checking for Link Options, Copper Version
* @adapter: board private structure
*
* Handles speed and duplex options on copper adapters
**/
static void __devinit e1000_check_copper_options(struct e1000_adapter *adapter)
{
struct e1000_option opt;
unsigned int speed, dplx, an;
int bd = adapter->bd_number;
{ /* Speed */
static const struct e1000_opt_list speed_list[] = {
{ 0, "" },
{ SPEED_10, "" },
{ SPEED_100, "" },
{ SPEED_1000, "" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "Speed",
.err = "parameter ignored",
.def = 0,
.arg = { .l = { .nr = ARRAY_SIZE(speed_list),
.p = speed_list }}
};
if (num_Speed > bd) {
speed = Speed[bd];
e1000_validate_option(&speed, &opt, adapter);
} else {
speed = opt.def;
}
}
{ /* Duplex */
static const struct e1000_opt_list dplx_list[] = {
{ 0, "" },
{ HALF_DUPLEX, "" },
{ FULL_DUPLEX, "" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "Duplex",
.err = "parameter ignored",
.def = 0,
.arg = { .l = { .nr = ARRAY_SIZE(dplx_list),
.p = dplx_list }}
};
if (e1000_check_phy_reset_block(&adapter->hw)) {
DPRINTK(PROBE, INFO,
"Link active due to SoL/IDER Session. "
"Speed/Duplex/AutoNeg parameter ignored.\n");
return;
}
if (num_Duplex > bd) {
dplx = Duplex[bd];
e1000_validate_option(&dplx, &opt, adapter);
} else {
dplx = opt.def;
}
}
if ((num_AutoNeg > bd) && (speed != 0 || dplx != 0)) {
DPRINTK(PROBE, INFO,
"AutoNeg specified along with Speed or Duplex, "
"parameter ignored\n");
adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
} else { /* Autoneg */
static const struct e1000_opt_list an_list[] =
#define AA "AutoNeg advertising "
{{ 0x01, AA "10/HD" },
{ 0x02, AA "10/FD" },
{ 0x03, AA "10/FD, 10/HD" },
{ 0x04, AA "100/HD" },
{ 0x05, AA "100/HD, 10/HD" },
{ 0x06, AA "100/HD, 10/FD" },
{ 0x07, AA "100/HD, 10/FD, 10/HD" },
{ 0x08, AA "100/FD" },
{ 0x09, AA "100/FD, 10/HD" },
{ 0x0a, AA "100/FD, 10/FD" },
{ 0x0b, AA "100/FD, 10/FD, 10/HD" },
{ 0x0c, AA "100/FD, 100/HD" },
{ 0x0d, AA "100/FD, 100/HD, 10/HD" },
{ 0x0e, AA "100/FD, 100/HD, 10/FD" },
{ 0x0f, AA "100/FD, 100/HD, 10/FD, 10/HD" },
{ 0x20, AA "1000/FD" },
{ 0x21, AA "1000/FD, 10/HD" },
{ 0x22, AA "1000/FD, 10/FD" },
{ 0x23, AA "1000/FD, 10/FD, 10/HD" },
{ 0x24, AA "1000/FD, 100/HD" },
{ 0x25, AA "1000/FD, 100/HD, 10/HD" },
{ 0x26, AA "1000/FD, 100/HD, 10/FD" },
{ 0x27, AA "1000/FD, 100/HD, 10/FD, 10/HD" },
{ 0x28, AA "1000/FD, 100/FD" },
{ 0x29, AA "1000/FD, 100/FD, 10/HD" },
{ 0x2a, AA "1000/FD, 100/FD, 10/FD" },
{ 0x2b, AA "1000/FD, 100/FD, 10/FD, 10/HD" },
{ 0x2c, AA "1000/FD, 100/FD, 100/HD" },
{ 0x2d, AA "1000/FD, 100/FD, 100/HD, 10/HD" },
{ 0x2e, AA "1000/FD, 100/FD, 100/HD, 10/FD" },
{ 0x2f, AA "1000/FD, 100/FD, 100/HD, 10/FD, 10/HD" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "AutoNeg",
.err = "parameter ignored",
.def = AUTONEG_ADV_DEFAULT,
.arg = { .l = { .nr = ARRAY_SIZE(an_list),
.p = an_list }}
};
if (num_AutoNeg > bd) {
an = AutoNeg[bd];
e1000_validate_option(&an, &opt, adapter);
} else {
an = opt.def;
}
adapter->hw.autoneg_advertised = an;
}
switch (speed + dplx) {
case 0:
adapter->hw.autoneg = adapter->fc_autoneg = 1;
if ((num_Speed > bd) && (speed != 0 || dplx != 0))
DPRINTK(PROBE, INFO,
"Speed and duplex autonegotiation enabled\n");
break;
case HALF_DUPLEX:
DPRINTK(PROBE, INFO, "Half Duplex specified without Speed\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at "
"Half Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
ADVERTISE_100_HALF;
break;
case FULL_DUPLEX:
DPRINTK(PROBE, INFO, "Full Duplex specified without Speed\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at "
"Full Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
ADVERTISE_100_FULL |
ADVERTISE_1000_FULL;
break;
case SPEED_10:
DPRINTK(PROBE, INFO, "10 Mbps Speed specified "
"without Duplex\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at 10 Mbps only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
ADVERTISE_10_FULL;
break;
case SPEED_10 + HALF_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 10 Mbps Half Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_10_half;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_10 + FULL_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 10 Mbps Full Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_10_full;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_100:
DPRINTK(PROBE, INFO, "100 Mbps Speed specified "
"without Duplex\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at "
"100 Mbps only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
ADVERTISE_100_FULL;
break;
case SPEED_100 + HALF_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 100 Mbps Half Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_100_half;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_100 + FULL_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 100 Mbps Full Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_100_full;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_1000:
DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without "
"Duplex\n");
goto full_duplex_only;
case SPEED_1000 + HALF_DUPLEX:
DPRINTK(PROBE, INFO,
"Half Duplex is not supported at 1000 Mbps\n");
/* fall through */
case SPEED_1000 + FULL_DUPLEX:
full_duplex_only:
DPRINTK(PROBE, INFO,
"Using Autonegotiation at 1000 Mbps Full Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
break;
default:
BUG();
}
/* Speed, AutoNeg and MDI/MDI-X must all play nice */
if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) {
DPRINTK(PROBE, INFO,
"Speed, AutoNeg and MDI-X specifications are "
"incompatible. Setting MDI-X to a compatible value.\n");
}
}

View File

@ -0,0 +1,792 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
Copyright(c) 1999 - 2006 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
#include "e1000.h"
/* This is the only thing that needs to be changed to adjust the
* maximum number of ports that the driver can manage.
*/
#define E1000_MAX_NIC 32
#define OPTION_UNSET -1
#define OPTION_DISABLED 0
#define OPTION_ENABLED 1
/* All parameters are treated the same, as an integer array of values.
* This macro just reduces the need to repeat the same declaration code
* over and over (plus this helps to avoid typo bugs).
*/
#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
#define E1000_PARAM(X, desc) \
static int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
static unsigned int num_##X; \
module_param_array_named(X, X, int, &num_##X, 0); \
MODULE_PARM_DESC(X, desc);
/* Transmit Descriptor Count
*
* Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
* Valid Range: 80-4096 for 82544 and newer
*
* Default Value: 256
*/
E1000_PARAM(TxDescriptors, "Number of transmit descriptors");
/* Receive Descriptor Count
*
* Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
* Valid Range: 80-4096 for 82544 and newer
*
* Default Value: 256
*/
E1000_PARAM(RxDescriptors, "Number of receive descriptors");
/* User Specified Speed Override
*
* Valid Range: 0, 10, 100, 1000
* - 0 - auto-negotiate at all supported speeds
* - 10 - only link at 10 Mbps
* - 100 - only link at 100 Mbps
* - 1000 - only link at 1000 Mbps
*
* Default Value: 0
*/
E1000_PARAM(Speed, "Speed setting");
/* User Specified Duplex Override
*
* Valid Range: 0-2
* - 0 - auto-negotiate for duplex
* - 1 - only link at half duplex
* - 2 - only link at full duplex
*
* Default Value: 0
*/
E1000_PARAM(Duplex, "Duplex setting");
/* Auto-negotiation Advertisement Override
*
* Valid Range: 0x01-0x0F, 0x20-0x2F (copper); 0x20 (fiber)
*
* The AutoNeg value is a bit mask describing which speed and duplex
* combinations should be advertised during auto-negotiation.
* The supported speed and duplex modes are listed below
*
* Bit 7 6 5 4 3 2 1 0
* Speed (Mbps) N/A N/A 1000 N/A 100 100 10 10
* Duplex Full Full Half Full Half
*
* Default Value: 0x2F (copper); 0x20 (fiber)
*/
E1000_PARAM(AutoNeg, "Advertised auto-negotiation setting");
#define AUTONEG_ADV_DEFAULT 0x2F
#define AUTONEG_ADV_MASK 0x2F
/* User Specified Flow Control Override
*
* Valid Range: 0-3
* - 0 - No Flow Control
* - 1 - Rx only, respond to PAUSE frames but do not generate them
* - 2 - Tx only, generate PAUSE frames but ignore them on receive
* - 3 - Full Flow Control Support
*
* Default Value: Read flow control settings from the EEPROM
*/
E1000_PARAM(FlowControl, "Flow Control setting");
#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
/* XsumRX - Receive Checksum Offload Enable/Disable
*
* Valid Range: 0, 1
* - 0 - disables all checksum offload
* - 1 - enables receive IP/TCP/UDP checksum offload
* on 82543 and newer -based NICs
*
* Default Value: 1
*/
E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
/* Transmit Interrupt Delay in units of 1.024 microseconds
* Tx interrupt delay needs to typically be set to something non zero
*
* Valid Range: 0-65535
*/
E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
#define DEFAULT_TIDV 8
#define MAX_TXDELAY 0xFFFF
#define MIN_TXDELAY 0
/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds
*
* Valid Range: 0-65535
*/
E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay");
#define DEFAULT_TADV 32
#define MAX_TXABSDELAY 0xFFFF
#define MIN_TXABSDELAY 0
/* Receive Interrupt Delay in units of 1.024 microseconds
* hardware will likely hang if you set this to anything but zero.
*
* Valid Range: 0-65535
*/
E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
#define DEFAULT_RDTR 0
#define MAX_RXDELAY 0xFFFF
#define MIN_RXDELAY 0
/* Receive Absolute Interrupt Delay in units of 1.024 microseconds
*
* Valid Range: 0-65535
*/
E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
#define DEFAULT_RADV 8
#define MAX_RXABSDELAY 0xFFFF
#define MIN_RXABSDELAY 0
/* Interrupt Throttle Rate (interrupts/sec)
*
* Valid Range: 100-100000 (0=off, 1=dynamic, 3=dynamic conservative)
*/
E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
#define DEFAULT_ITR 3
#define MAX_ITR 100000
#define MIN_ITR 100
/* Enable Smart Power Down of the PHY
*
* Valid Range: 0, 1
*
* Default Value: 0 (disabled)
*/
E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
/* Enable Kumeran Lock Loss workaround
*
* Valid Range: 0, 1
*
* Default Value: 1 (enabled)
*/
E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
struct e1000_option {
enum { enable_option, range_option, list_option } type;
const char *name;
const char *err;
int def;
union {
struct { /* range_option info */
int min;
int max;
} r;
struct { /* list_option info */
int nr;
const struct e1000_opt_list { int i; char *str; } *p;
} l;
} arg;
};
static int __devinit e1000_validate_option(unsigned int *value,
const struct e1000_option *opt,
struct e1000_adapter *adapter)
{
if (*value == OPTION_UNSET) {
*value = opt->def;
return 0;
}
switch (opt->type) {
case enable_option:
switch (*value) {
case OPTION_ENABLED:
DPRINTK(PROBE, INFO, "%s Enabled\n", opt->name);
return 0;
case OPTION_DISABLED:
DPRINTK(PROBE, INFO, "%s Disabled\n", opt->name);
return 0;
}
break;
case range_option:
if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
DPRINTK(PROBE, INFO,
"%s set to %i\n", opt->name, *value);
return 0;
}
break;
case list_option: {
int i;
const struct e1000_opt_list *ent;
for (i = 0; i < opt->arg.l.nr; i++) {
ent = &opt->arg.l.p[i];
if (*value == ent->i) {
if (ent->str[0] != '\0')
DPRINTK(PROBE, INFO, "%s\n", ent->str);
return 0;
}
}
}
break;
default:
BUG();
}
DPRINTK(PROBE, INFO, "Invalid %s value specified (%i) %s\n",
opt->name, *value, opt->err);
*value = opt->def;
return -1;
}
static void e1000_check_fiber_options(struct e1000_adapter *adapter);
static void e1000_check_copper_options(struct e1000_adapter *adapter);
/**
* e1000_check_options - Range Checking for Command Line Parameters
* @adapter: board private structure
*
* This routine checks all command line parameters for valid user
* input. If an invalid value is given, or if no user specified
* value exists, a default value is used. The final value is stored
* in a variable in the adapter structure.
**/
void __devinit e1000_check_options(struct e1000_adapter *adapter)
{
struct e1000_option opt;
int bd = adapter->bd_number;
if (bd >= E1000_MAX_NIC) {
DPRINTK(PROBE, NOTICE,
"Warning: no configuration for board #%i\n", bd);
DPRINTK(PROBE, NOTICE, "Using defaults for all values\n");
}
{ /* Transmit Descriptor Count */
struct e1000_tx_ring *tx_ring = adapter->tx_ring;
int i;
e1000_mac_type mac_type = adapter->hw.mac_type;
opt = (struct e1000_option) {
.type = range_option,
.name = "Transmit Descriptors",
.err = "using default of "
__MODULE_STRING(E1000_DEFAULT_TXD),
.def = E1000_DEFAULT_TXD,
.arg = { .r = {
.min = E1000_MIN_TXD,
.max = mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD
}}
};
if (num_TxDescriptors > bd) {
tx_ring->count = TxDescriptors[bd];
e1000_validate_option(&tx_ring->count, &opt, adapter);
tx_ring->count = ALIGN(tx_ring->count,
REQ_TX_DESCRIPTOR_MULTIPLE);
} else {
tx_ring->count = opt.def;
}
for (i = 0; i < adapter->num_tx_queues; i++)
tx_ring[i].count = tx_ring->count;
}
{ /* Receive Descriptor Count */
struct e1000_rx_ring *rx_ring = adapter->rx_ring;
int i;
e1000_mac_type mac_type = adapter->hw.mac_type;
opt = (struct e1000_option) {
.type = range_option,
.name = "Receive Descriptors",
.err = "using default of "
__MODULE_STRING(E1000_DEFAULT_RXD),
.def = E1000_DEFAULT_RXD,
.arg = { .r = {
.min = E1000_MIN_RXD,
.max = mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD
}}
};
if (num_RxDescriptors > bd) {
rx_ring->count = RxDescriptors[bd];
e1000_validate_option(&rx_ring->count, &opt, adapter);
rx_ring->count = ALIGN(rx_ring->count,
REQ_RX_DESCRIPTOR_MULTIPLE);
} else {
rx_ring->count = opt.def;
}
for (i = 0; i < adapter->num_rx_queues; i++)
rx_ring[i].count = rx_ring->count;
}
{ /* Checksum Offload Enable/Disable */
opt = (struct e1000_option) {
.type = enable_option,
.name = "Checksum Offload",
.err = "defaulting to Enabled",
.def = OPTION_ENABLED
};
if (num_XsumRX > bd) {
unsigned int rx_csum = XsumRX[bd];
e1000_validate_option(&rx_csum, &opt, adapter);
adapter->rx_csum = rx_csum;
} else {
adapter->rx_csum = opt.def;
}
}
{ /* Flow Control */
struct e1000_opt_list fc_list[] =
{{ E1000_FC_NONE, "Flow Control Disabled" },
{ E1000_FC_RX_PAUSE,"Flow Control Receive Only" },
{ E1000_FC_TX_PAUSE,"Flow Control Transmit Only" },
{ E1000_FC_FULL, "Flow Control Enabled" },
{ E1000_FC_DEFAULT, "Flow Control Hardware Default" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "Flow Control",
.err = "reading default settings from EEPROM",
.def = E1000_FC_DEFAULT,
.arg = { .l = { .nr = ARRAY_SIZE(fc_list),
.p = fc_list }}
};
if (num_FlowControl > bd) {
unsigned int fc = FlowControl[bd];
e1000_validate_option(&fc, &opt, adapter);
adapter->hw.fc = adapter->hw.original_fc = fc;
} else {
adapter->hw.fc = adapter->hw.original_fc = opt.def;
}
}
{ /* Transmit Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Transmit Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_TIDV),
.def = DEFAULT_TIDV,
.arg = { .r = { .min = MIN_TXDELAY,
.max = MAX_TXDELAY }}
};
if (num_TxIntDelay > bd) {
adapter->tx_int_delay = TxIntDelay[bd];
e1000_validate_option(&adapter->tx_int_delay, &opt,
adapter);
} else {
adapter->tx_int_delay = opt.def;
}
}
{ /* Transmit Absolute Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Transmit Absolute Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_TADV),
.def = DEFAULT_TADV,
.arg = { .r = { .min = MIN_TXABSDELAY,
.max = MAX_TXABSDELAY }}
};
if (num_TxAbsIntDelay > bd) {
adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
adapter);
} else {
adapter->tx_abs_int_delay = opt.def;
}
}
{ /* Receive Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Receive Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_RDTR),
.def = DEFAULT_RDTR,
.arg = { .r = { .min = MIN_RXDELAY,
.max = MAX_RXDELAY }}
};
if (num_RxIntDelay > bd) {
adapter->rx_int_delay = RxIntDelay[bd];
e1000_validate_option(&adapter->rx_int_delay, &opt,
adapter);
} else {
adapter->rx_int_delay = opt.def;
}
}
{ /* Receive Absolute Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Receive Absolute Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_RADV),
.def = DEFAULT_RADV,
.arg = { .r = { .min = MIN_RXABSDELAY,
.max = MAX_RXABSDELAY }}
};
if (num_RxAbsIntDelay > bd) {
adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
adapter);
} else {
adapter->rx_abs_int_delay = opt.def;
}
}
{ /* Interrupt Throttling Rate */
opt = (struct e1000_option) {
.type = range_option,
.name = "Interrupt Throttling Rate (ints/sec)",
.err = "using default of " __MODULE_STRING(DEFAULT_ITR),
.def = DEFAULT_ITR,
.arg = { .r = { .min = MIN_ITR,
.max = MAX_ITR }}
};
if (num_InterruptThrottleRate > bd) {
adapter->itr = InterruptThrottleRate[bd];
switch (adapter->itr) {
case 0:
DPRINTK(PROBE, INFO, "%s turned off\n",
opt.name);
break;
case 1:
DPRINTK(PROBE, INFO, "%s set to dynamic mode\n",
opt.name);
adapter->itr_setting = adapter->itr;
adapter->itr = 20000;
break;
case 3:
DPRINTK(PROBE, INFO,
"%s set to dynamic conservative mode\n",
opt.name);
adapter->itr_setting = adapter->itr;
adapter->itr = 20000;
break;
default:
e1000_validate_option(&adapter->itr, &opt,
adapter);
/* save the setting, because the dynamic bits change itr */
/* clear the lower two bits because they are
* used as control */
adapter->itr_setting = adapter->itr & ~3;
break;
}
} else {
adapter->itr_setting = opt.def;
adapter->itr = 20000;
}
}
{ /* Smart Power Down */
opt = (struct e1000_option) {
.type = enable_option,
.name = "PHY Smart Power Down",
.err = "defaulting to Disabled",
.def = OPTION_DISABLED
};
if (num_SmartPowerDownEnable > bd) {
unsigned int spd = SmartPowerDownEnable[bd];
e1000_validate_option(&spd, &opt, adapter);
adapter->smart_power_down = spd;
} else {
adapter->smart_power_down = opt.def;
}
}
{ /* Kumeran Lock Loss Workaround */
opt = (struct e1000_option) {
.type = enable_option,
.name = "Kumeran Lock Loss Workaround",
.err = "defaulting to Enabled",
.def = OPTION_ENABLED
};
if (num_KumeranLockLoss > bd) {
unsigned int kmrn_lock_loss = KumeranLockLoss[bd];
e1000_validate_option(&kmrn_lock_loss, &opt, adapter);
adapter->hw.kmrn_lock_loss_workaround_disabled = !kmrn_lock_loss;
} else {
adapter->hw.kmrn_lock_loss_workaround_disabled = !opt.def;
}
}
switch (adapter->hw.media_type) {
case e1000_media_type_fiber:
case e1000_media_type_internal_serdes:
e1000_check_fiber_options(adapter);
break;
case e1000_media_type_copper:
e1000_check_copper_options(adapter);
break;
default:
BUG();
}
}
/**
* e1000_check_fiber_options - Range Checking for Link Options, Fiber Version
* @adapter: board private structure
*
* Handles speed and duplex options on fiber adapters
**/
static void __devinit e1000_check_fiber_options(struct e1000_adapter *adapter)
{
int bd = adapter->bd_number;
if (num_Speed > bd) {
DPRINTK(PROBE, INFO, "Speed not valid for fiber adapters, "
"parameter ignored\n");
}
if (num_Duplex > bd) {
DPRINTK(PROBE, INFO, "Duplex not valid for fiber adapters, "
"parameter ignored\n");
}
if ((num_AutoNeg > bd) && (AutoNeg[bd] != 0x20)) {
DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is "
"not valid for fiber adapters, "
"parameter ignored\n");
}
}
/**
* e1000_check_copper_options - Range Checking for Link Options, Copper Version
* @adapter: board private structure
*
* Handles speed and duplex options on copper adapters
**/
static void __devinit e1000_check_copper_options(struct e1000_adapter *adapter)
{
struct e1000_option opt;
unsigned int speed, dplx, an;
int bd = adapter->bd_number;
{ /* Speed */
static const struct e1000_opt_list speed_list[] = {
{ 0, "" },
{ SPEED_10, "" },
{ SPEED_100, "" },
{ SPEED_1000, "" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "Speed",
.err = "parameter ignored",
.def = 0,
.arg = { .l = { .nr = ARRAY_SIZE(speed_list),
.p = speed_list }}
};
if (num_Speed > bd) {
speed = Speed[bd];
e1000_validate_option(&speed, &opt, adapter);
} else {
speed = opt.def;
}
}
{ /* Duplex */
static const struct e1000_opt_list dplx_list[] = {
{ 0, "" },
{ HALF_DUPLEX, "" },
{ FULL_DUPLEX, "" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "Duplex",
.err = "parameter ignored",
.def = 0,
.arg = { .l = { .nr = ARRAY_SIZE(dplx_list),
.p = dplx_list }}
};
if (e1000_check_phy_reset_block(&adapter->hw)) {
DPRINTK(PROBE, INFO,
"Link active due to SoL/IDER Session. "
"Speed/Duplex/AutoNeg parameter ignored.\n");
return;
}
if (num_Duplex > bd) {
dplx = Duplex[bd];
e1000_validate_option(&dplx, &opt, adapter);
} else {
dplx = opt.def;
}
}
if ((num_AutoNeg > bd) && (speed != 0 || dplx != 0)) {
DPRINTK(PROBE, INFO,
"AutoNeg specified along with Speed or Duplex, "
"parameter ignored\n");
adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
} else { /* Autoneg */
static const struct e1000_opt_list an_list[] =
#define AA "AutoNeg advertising "
{{ 0x01, AA "10/HD" },
{ 0x02, AA "10/FD" },
{ 0x03, AA "10/FD, 10/HD" },
{ 0x04, AA "100/HD" },
{ 0x05, AA "100/HD, 10/HD" },
{ 0x06, AA "100/HD, 10/FD" },
{ 0x07, AA "100/HD, 10/FD, 10/HD" },
{ 0x08, AA "100/FD" },
{ 0x09, AA "100/FD, 10/HD" },
{ 0x0a, AA "100/FD, 10/FD" },
{ 0x0b, AA "100/FD, 10/FD, 10/HD" },
{ 0x0c, AA "100/FD, 100/HD" },
{ 0x0d, AA "100/FD, 100/HD, 10/HD" },
{ 0x0e, AA "100/FD, 100/HD, 10/FD" },
{ 0x0f, AA "100/FD, 100/HD, 10/FD, 10/HD" },
{ 0x20, AA "1000/FD" },
{ 0x21, AA "1000/FD, 10/HD" },
{ 0x22, AA "1000/FD, 10/FD" },
{ 0x23, AA "1000/FD, 10/FD, 10/HD" },
{ 0x24, AA "1000/FD, 100/HD" },
{ 0x25, AA "1000/FD, 100/HD, 10/HD" },
{ 0x26, AA "1000/FD, 100/HD, 10/FD" },
{ 0x27, AA "1000/FD, 100/HD, 10/FD, 10/HD" },
{ 0x28, AA "1000/FD, 100/FD" },
{ 0x29, AA "1000/FD, 100/FD, 10/HD" },
{ 0x2a, AA "1000/FD, 100/FD, 10/FD" },
{ 0x2b, AA "1000/FD, 100/FD, 10/FD, 10/HD" },
{ 0x2c, AA "1000/FD, 100/FD, 100/HD" },
{ 0x2d, AA "1000/FD, 100/FD, 100/HD, 10/HD" },
{ 0x2e, AA "1000/FD, 100/FD, 100/HD, 10/FD" },
{ 0x2f, AA "1000/FD, 100/FD, 100/HD, 10/FD, 10/HD" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "AutoNeg",
.err = "parameter ignored",
.def = AUTONEG_ADV_DEFAULT,
.arg = { .l = { .nr = ARRAY_SIZE(an_list),
.p = an_list }}
};
if (num_AutoNeg > bd) {
an = AutoNeg[bd];
e1000_validate_option(&an, &opt, adapter);
} else {
an = opt.def;
}
adapter->hw.autoneg_advertised = an;
}
switch (speed + dplx) {
case 0:
adapter->hw.autoneg = adapter->fc_autoneg = 1;
if ((num_Speed > bd) && (speed != 0 || dplx != 0))
DPRINTK(PROBE, INFO,
"Speed and duplex autonegotiation enabled\n");
break;
case HALF_DUPLEX:
DPRINTK(PROBE, INFO, "Half Duplex specified without Speed\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at "
"Half Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
ADVERTISE_100_HALF;
break;
case FULL_DUPLEX:
DPRINTK(PROBE, INFO, "Full Duplex specified without Speed\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at "
"Full Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
ADVERTISE_100_FULL |
ADVERTISE_1000_FULL;
break;
case SPEED_10:
DPRINTK(PROBE, INFO, "10 Mbps Speed specified "
"without Duplex\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at 10 Mbps only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
ADVERTISE_10_FULL;
break;
case SPEED_10 + HALF_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 10 Mbps Half Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_10_half;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_10 + FULL_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 10 Mbps Full Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_10_full;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_100:
DPRINTK(PROBE, INFO, "100 Mbps Speed specified "
"without Duplex\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at "
"100 Mbps only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
ADVERTISE_100_FULL;
break;
case SPEED_100 + HALF_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 100 Mbps Half Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_100_half;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_100 + FULL_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 100 Mbps Full Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_100_full;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_1000:
DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without "
"Duplex\n");
goto full_duplex_only;
case SPEED_1000 + HALF_DUPLEX:
DPRINTK(PROBE, INFO,
"Half Duplex is not supported at 1000 Mbps\n");
/* fall through */
case SPEED_1000 + FULL_DUPLEX:
full_duplex_only:
DPRINTK(PROBE, INFO,
"Using Autonegotiation at 1000 Mbps Full Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
break;
default:
BUG();
}
/* Speed, AutoNeg and MDI/MDI-X must all play nice */
if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) {
DPRINTK(PROBE, INFO,
"Speed, AutoNeg and MDI-X specifications are "
"incompatible. Setting MDI-X to a compatible value.\n");
}
}

View File

@ -0,0 +1,770 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
Copyright(c) 1999 - 2006 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
#include "e1000-2.6.33-ethercat.h"
/* This is the only thing that needs to be changed to adjust the
* maximum number of ports that the driver can manage.
*/
#define E1000_MAX_NIC 32
#define OPTION_UNSET -1
#define OPTION_DISABLED 0
#define OPTION_ENABLED 1
/* All parameters are treated the same, as an integer array of values.
* This macro just reduces the need to repeat the same declaration code
* over and over (plus this helps to avoid typo bugs).
*/
#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
#define E1000_PARAM(X, desc) \
static int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
static unsigned int num_##X; \
module_param_array_named(X, X, int, &num_##X, 0); \
MODULE_PARM_DESC(X, desc);
/* Transmit Descriptor Count
*
* Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
* Valid Range: 80-4096 for 82544 and newer
*
* Default Value: 256
*/
E1000_PARAM(TxDescriptors, "Number of transmit descriptors");
/* Receive Descriptor Count
*
* Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
* Valid Range: 80-4096 for 82544 and newer
*
* Default Value: 256
*/
E1000_PARAM(RxDescriptors, "Number of receive descriptors");
/* User Specified Speed Override
*
* Valid Range: 0, 10, 100, 1000
* - 0 - auto-negotiate at all supported speeds
* - 10 - only link at 10 Mbps
* - 100 - only link at 100 Mbps
* - 1000 - only link at 1000 Mbps
*
* Default Value: 0
*/
E1000_PARAM(Speed, "Speed setting");
/* User Specified Duplex Override
*
* Valid Range: 0-2
* - 0 - auto-negotiate for duplex
* - 1 - only link at half duplex
* - 2 - only link at full duplex
*
* Default Value: 0
*/
E1000_PARAM(Duplex, "Duplex setting");
/* Auto-negotiation Advertisement Override
*
* Valid Range: 0x01-0x0F, 0x20-0x2F (copper); 0x20 (fiber)
*
* The AutoNeg value is a bit mask describing which speed and duplex
* combinations should be advertised during auto-negotiation.
* The supported speed and duplex modes are listed below
*
* Bit 7 6 5 4 3 2 1 0
* Speed (Mbps) N/A N/A 1000 N/A 100 100 10 10
* Duplex Full Full Half Full Half
*
* Default Value: 0x2F (copper); 0x20 (fiber)
*/
E1000_PARAM(AutoNeg, "Advertised auto-negotiation setting");
#define AUTONEG_ADV_DEFAULT 0x2F
#define AUTONEG_ADV_MASK 0x2F
/* User Specified Flow Control Override
*
* Valid Range: 0-3
* - 0 - No Flow Control
* - 1 - Rx only, respond to PAUSE frames but do not generate them
* - 2 - Tx only, generate PAUSE frames but ignore them on receive
* - 3 - Full Flow Control Support
*
* Default Value: Read flow control settings from the EEPROM
*/
E1000_PARAM(FlowControl, "Flow Control setting");
#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
/* XsumRX - Receive Checksum Offload Enable/Disable
*
* Valid Range: 0, 1
* - 0 - disables all checksum offload
* - 1 - enables receive IP/TCP/UDP checksum offload
* on 82543 and newer -based NICs
*
* Default Value: 1
*/
E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
/* Transmit Interrupt Delay in units of 1.024 microseconds
* Tx interrupt delay needs to typically be set to something non zero
*
* Valid Range: 0-65535
*/
E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
#define DEFAULT_TIDV 8
#define MAX_TXDELAY 0xFFFF
#define MIN_TXDELAY 0
/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds
*
* Valid Range: 0-65535
*/
E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay");
#define DEFAULT_TADV 32
#define MAX_TXABSDELAY 0xFFFF
#define MIN_TXABSDELAY 0
/* Receive Interrupt Delay in units of 1.024 microseconds
* hardware will likely hang if you set this to anything but zero.
*
* Valid Range: 0-65535
*/
E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
#define DEFAULT_RDTR 0
#define MAX_RXDELAY 0xFFFF
#define MIN_RXDELAY 0
/* Receive Absolute Interrupt Delay in units of 1.024 microseconds
*
* Valid Range: 0-65535
*/
E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
#define DEFAULT_RADV 8
#define MAX_RXABSDELAY 0xFFFF
#define MIN_RXABSDELAY 0
/* Interrupt Throttle Rate (interrupts/sec)
*
* Valid Range: 100-100000 (0=off, 1=dynamic, 3=dynamic conservative)
*/
E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
#define DEFAULT_ITR 3
#define MAX_ITR 100000
#define MIN_ITR 100
/* Enable Smart Power Down of the PHY
*
* Valid Range: 0, 1
*
* Default Value: 0 (disabled)
*/
E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
/* Enable Kumeran Lock Loss workaround
*
* Valid Range: 0, 1
*
* Default Value: 1 (enabled)
*/
E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
struct e1000_option {
enum { enable_option, range_option, list_option } type;
const char *name;
const char *err;
int def;
union {
struct { /* range_option info */
int min;
int max;
} r;
struct { /* list_option info */
int nr;
const struct e1000_opt_list { int i; char *str; } *p;
} l;
} arg;
};
static int __devinit e1000_validate_option(unsigned int *value,
const struct e1000_option *opt,
struct e1000_adapter *adapter)
{
if (*value == OPTION_UNSET) {
*value = opt->def;
return 0;
}
switch (opt->type) {
case enable_option:
switch (*value) {
case OPTION_ENABLED:
DPRINTK(PROBE, INFO, "%s Enabled\n", opt->name);
return 0;
case OPTION_DISABLED:
DPRINTK(PROBE, INFO, "%s Disabled\n", opt->name);
return 0;
}
break;
case range_option:
if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
DPRINTK(PROBE, INFO,
"%s set to %i\n", opt->name, *value);
return 0;
}
break;
case list_option: {
int i;
const struct e1000_opt_list *ent;
for (i = 0; i < opt->arg.l.nr; i++) {
ent = &opt->arg.l.p[i];
if (*value == ent->i) {
if (ent->str[0] != '\0')
DPRINTK(PROBE, INFO, "%s\n", ent->str);
return 0;
}
}
}
break;
default:
BUG();
}
DPRINTK(PROBE, INFO, "Invalid %s value specified (%i) %s\n",
opt->name, *value, opt->err);
*value = opt->def;
return -1;
}
static void e1000_check_fiber_options(struct e1000_adapter *adapter);
static void e1000_check_copper_options(struct e1000_adapter *adapter);
/**
* e1000_check_options - Range Checking for Command Line Parameters
* @adapter: board private structure
*
* This routine checks all command line parameters for valid user
* input. If an invalid value is given, or if no user specified
* value exists, a default value is used. The final value is stored
* in a variable in the adapter structure.
**/
void __devinit e1000_check_options(struct e1000_adapter *adapter)
{
struct e1000_option opt;
int bd = adapter->bd_number;
if (bd >= E1000_MAX_NIC) {
DPRINTK(PROBE, NOTICE,
"Warning: no configuration for board #%i\n", bd);
DPRINTK(PROBE, NOTICE, "Using defaults for all values\n");
}
{ /* Transmit Descriptor Count */
struct e1000_tx_ring *tx_ring = adapter->tx_ring;
int i;
e1000_mac_type mac_type = adapter->hw.mac_type;
opt = (struct e1000_option) {
.type = range_option,
.name = "Transmit Descriptors",
.err = "using default of "
__MODULE_STRING(E1000_DEFAULT_TXD),
.def = E1000_DEFAULT_TXD,
.arg = { .r = {
.min = E1000_MIN_TXD,
.max = mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD
}}
};
if (num_TxDescriptors > bd) {
tx_ring->count = TxDescriptors[bd];
e1000_validate_option(&tx_ring->count, &opt, adapter);
tx_ring->count = ALIGN(tx_ring->count,
REQ_TX_DESCRIPTOR_MULTIPLE);
} else {
tx_ring->count = opt.def;
}
for (i = 0; i < adapter->num_tx_queues; i++)
tx_ring[i].count = tx_ring->count;
}
{ /* Receive Descriptor Count */
struct e1000_rx_ring *rx_ring = adapter->rx_ring;
int i;
e1000_mac_type mac_type = adapter->hw.mac_type;
opt = (struct e1000_option) {
.type = range_option,
.name = "Receive Descriptors",
.err = "using default of "
__MODULE_STRING(E1000_DEFAULT_RXD),
.def = E1000_DEFAULT_RXD,
.arg = { .r = {
.min = E1000_MIN_RXD,
.max = mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD
}}
};
if (num_RxDescriptors > bd) {
rx_ring->count = RxDescriptors[bd];
e1000_validate_option(&rx_ring->count, &opt, adapter);
rx_ring->count = ALIGN(rx_ring->count,
REQ_RX_DESCRIPTOR_MULTIPLE);
} else {
rx_ring->count = opt.def;
}
for (i = 0; i < adapter->num_rx_queues; i++)
rx_ring[i].count = rx_ring->count;
}
{ /* Checksum Offload Enable/Disable */
opt = (struct e1000_option) {
.type = enable_option,
.name = "Checksum Offload",
.err = "defaulting to Enabled",
.def = OPTION_ENABLED
};
if (num_XsumRX > bd) {
unsigned int rx_csum = XsumRX[bd];
e1000_validate_option(&rx_csum, &opt, adapter);
adapter->rx_csum = rx_csum;
} else {
adapter->rx_csum = opt.def;
}
}
{ /* Flow Control */
struct e1000_opt_list fc_list[] =
{{ E1000_FC_NONE, "Flow Control Disabled" },
{ E1000_FC_RX_PAUSE,"Flow Control Receive Only" },
{ E1000_FC_TX_PAUSE,"Flow Control Transmit Only" },
{ E1000_FC_FULL, "Flow Control Enabled" },
{ E1000_FC_DEFAULT, "Flow Control Hardware Default" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "Flow Control",
.err = "reading default settings from EEPROM",
.def = E1000_FC_DEFAULT,
.arg = { .l = { .nr = ARRAY_SIZE(fc_list),
.p = fc_list }}
};
if (num_FlowControl > bd) {
unsigned int fc = FlowControl[bd];
e1000_validate_option(&fc, &opt, adapter);
adapter->hw.fc = adapter->hw.original_fc = fc;
} else {
adapter->hw.fc = adapter->hw.original_fc = opt.def;
}
}
{ /* Transmit Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Transmit Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_TIDV),
.def = DEFAULT_TIDV,
.arg = { .r = { .min = MIN_TXDELAY,
.max = MAX_TXDELAY }}
};
if (num_TxIntDelay > bd) {
adapter->tx_int_delay = TxIntDelay[bd];
e1000_validate_option(&adapter->tx_int_delay, &opt,
adapter);
} else {
adapter->tx_int_delay = opt.def;
}
}
{ /* Transmit Absolute Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Transmit Absolute Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_TADV),
.def = DEFAULT_TADV,
.arg = { .r = { .min = MIN_TXABSDELAY,
.max = MAX_TXABSDELAY }}
};
if (num_TxAbsIntDelay > bd) {
adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
adapter);
} else {
adapter->tx_abs_int_delay = opt.def;
}
}
{ /* Receive Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Receive Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_RDTR),
.def = DEFAULT_RDTR,
.arg = { .r = { .min = MIN_RXDELAY,
.max = MAX_RXDELAY }}
};
if (num_RxIntDelay > bd) {
adapter->rx_int_delay = RxIntDelay[bd];
e1000_validate_option(&adapter->rx_int_delay, &opt,
adapter);
} else {
adapter->rx_int_delay = opt.def;
}
}
{ /* Receive Absolute Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Receive Absolute Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_RADV),
.def = DEFAULT_RADV,
.arg = { .r = { .min = MIN_RXABSDELAY,
.max = MAX_RXABSDELAY }}
};
if (num_RxAbsIntDelay > bd) {
adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
adapter);
} else {
adapter->rx_abs_int_delay = opt.def;
}
}
{ /* Interrupt Throttling Rate */
opt = (struct e1000_option) {
.type = range_option,
.name = "Interrupt Throttling Rate (ints/sec)",
.err = "using default of " __MODULE_STRING(DEFAULT_ITR),
.def = DEFAULT_ITR,
.arg = { .r = { .min = MIN_ITR,
.max = MAX_ITR }}
};
if (num_InterruptThrottleRate > bd) {
adapter->itr = InterruptThrottleRate[bd];
switch (adapter->itr) {
case 0:
DPRINTK(PROBE, INFO, "%s turned off\n",
opt.name);
break;
case 1:
DPRINTK(PROBE, INFO, "%s set to dynamic mode\n",
opt.name);
adapter->itr_setting = adapter->itr;
adapter->itr = 20000;
break;
case 3:
DPRINTK(PROBE, INFO,
"%s set to dynamic conservative mode\n",
opt.name);
adapter->itr_setting = adapter->itr;
adapter->itr = 20000;
break;
default:
e1000_validate_option(&adapter->itr, &opt,
adapter);
/* save the setting, because the dynamic bits change itr */
/* clear the lower two bits because they are
* used as control */
adapter->itr_setting = adapter->itr & ~3;
break;
}
} else {
adapter->itr_setting = opt.def;
adapter->itr = 20000;
}
}
{ /* Smart Power Down */
opt = (struct e1000_option) {
.type = enable_option,
.name = "PHY Smart Power Down",
.err = "defaulting to Disabled",
.def = OPTION_DISABLED
};
if (num_SmartPowerDownEnable > bd) {
unsigned int spd = SmartPowerDownEnable[bd];
e1000_validate_option(&spd, &opt, adapter);
adapter->smart_power_down = spd;
} else {
adapter->smart_power_down = opt.def;
}
}
switch (adapter->hw.media_type) {
case e1000_media_type_fiber:
case e1000_media_type_internal_serdes:
e1000_check_fiber_options(adapter);
break;
case e1000_media_type_copper:
e1000_check_copper_options(adapter);
break;
default:
BUG();
}
}
/**
* e1000_check_fiber_options - Range Checking for Link Options, Fiber Version
* @adapter: board private structure
*
* Handles speed and duplex options on fiber adapters
**/
static void __devinit e1000_check_fiber_options(struct e1000_adapter *adapter)
{
int bd = adapter->bd_number;
if (num_Speed > bd) {
DPRINTK(PROBE, INFO, "Speed not valid for fiber adapters, "
"parameter ignored\n");
}
if (num_Duplex > bd) {
DPRINTK(PROBE, INFO, "Duplex not valid for fiber adapters, "
"parameter ignored\n");
}
if ((num_AutoNeg > bd) && (AutoNeg[bd] != 0x20)) {
DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is "
"not valid for fiber adapters, "
"parameter ignored\n");
}
}
/**
* e1000_check_copper_options - Range Checking for Link Options, Copper Version
* @adapter: board private structure
*
* Handles speed and duplex options on copper adapters
**/
static void __devinit e1000_check_copper_options(struct e1000_adapter *adapter)
{
struct e1000_option opt;
unsigned int speed, dplx, an;
int bd = adapter->bd_number;
{ /* Speed */
static const struct e1000_opt_list speed_list[] = {
{ 0, "" },
{ SPEED_10, "" },
{ SPEED_100, "" },
{ SPEED_1000, "" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "Speed",
.err = "parameter ignored",
.def = 0,
.arg = { .l = { .nr = ARRAY_SIZE(speed_list),
.p = speed_list }}
};
if (num_Speed > bd) {
speed = Speed[bd];
e1000_validate_option(&speed, &opt, adapter);
} else {
speed = opt.def;
}
}
{ /* Duplex */
static const struct e1000_opt_list dplx_list[] = {
{ 0, "" },
{ HALF_DUPLEX, "" },
{ FULL_DUPLEX, "" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "Duplex",
.err = "parameter ignored",
.def = 0,
.arg = { .l = { .nr = ARRAY_SIZE(dplx_list),
.p = dplx_list }}
};
if (num_Duplex > bd) {
dplx = Duplex[bd];
e1000_validate_option(&dplx, &opt, adapter);
} else {
dplx = opt.def;
}
}
if ((num_AutoNeg > bd) && (speed != 0 || dplx != 0)) {
DPRINTK(PROBE, INFO,
"AutoNeg specified along with Speed or Duplex, "
"parameter ignored\n");
adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
} else { /* Autoneg */
static const struct e1000_opt_list an_list[] =
#define AA "AutoNeg advertising "
{{ 0x01, AA "10/HD" },
{ 0x02, AA "10/FD" },
{ 0x03, AA "10/FD, 10/HD" },
{ 0x04, AA "100/HD" },
{ 0x05, AA "100/HD, 10/HD" },
{ 0x06, AA "100/HD, 10/FD" },
{ 0x07, AA "100/HD, 10/FD, 10/HD" },
{ 0x08, AA "100/FD" },
{ 0x09, AA "100/FD, 10/HD" },
{ 0x0a, AA "100/FD, 10/FD" },
{ 0x0b, AA "100/FD, 10/FD, 10/HD" },
{ 0x0c, AA "100/FD, 100/HD" },
{ 0x0d, AA "100/FD, 100/HD, 10/HD" },
{ 0x0e, AA "100/FD, 100/HD, 10/FD" },
{ 0x0f, AA "100/FD, 100/HD, 10/FD, 10/HD" },
{ 0x20, AA "1000/FD" },
{ 0x21, AA "1000/FD, 10/HD" },
{ 0x22, AA "1000/FD, 10/FD" },
{ 0x23, AA "1000/FD, 10/FD, 10/HD" },
{ 0x24, AA "1000/FD, 100/HD" },
{ 0x25, AA "1000/FD, 100/HD, 10/HD" },
{ 0x26, AA "1000/FD, 100/HD, 10/FD" },
{ 0x27, AA "1000/FD, 100/HD, 10/FD, 10/HD" },
{ 0x28, AA "1000/FD, 100/FD" },
{ 0x29, AA "1000/FD, 100/FD, 10/HD" },
{ 0x2a, AA "1000/FD, 100/FD, 10/FD" },
{ 0x2b, AA "1000/FD, 100/FD, 10/FD, 10/HD" },
{ 0x2c, AA "1000/FD, 100/FD, 100/HD" },
{ 0x2d, AA "1000/FD, 100/FD, 100/HD, 10/HD" },
{ 0x2e, AA "1000/FD, 100/FD, 100/HD, 10/FD" },
{ 0x2f, AA "1000/FD, 100/FD, 100/HD, 10/FD, 10/HD" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "AutoNeg",
.err = "parameter ignored",
.def = AUTONEG_ADV_DEFAULT,
.arg = { .l = { .nr = ARRAY_SIZE(an_list),
.p = an_list }}
};
if (num_AutoNeg > bd) {
an = AutoNeg[bd];
e1000_validate_option(&an, &opt, adapter);
} else {
an = opt.def;
}
adapter->hw.autoneg_advertised = an;
}
switch (speed + dplx) {
case 0:
adapter->hw.autoneg = adapter->fc_autoneg = 1;
if ((num_Speed > bd) && (speed != 0 || dplx != 0))
DPRINTK(PROBE, INFO,
"Speed and duplex autonegotiation enabled\n");
break;
case HALF_DUPLEX:
DPRINTK(PROBE, INFO, "Half Duplex specified without Speed\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at "
"Half Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
ADVERTISE_100_HALF;
break;
case FULL_DUPLEX:
DPRINTK(PROBE, INFO, "Full Duplex specified without Speed\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at "
"Full Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
ADVERTISE_100_FULL |
ADVERTISE_1000_FULL;
break;
case SPEED_10:
DPRINTK(PROBE, INFO, "10 Mbps Speed specified "
"without Duplex\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at 10 Mbps only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
ADVERTISE_10_FULL;
break;
case SPEED_10 + HALF_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 10 Mbps Half Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_10_half;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_10 + FULL_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 10 Mbps Full Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_10_full;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_100:
DPRINTK(PROBE, INFO, "100 Mbps Speed specified "
"without Duplex\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at "
"100 Mbps only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
ADVERTISE_100_FULL;
break;
case SPEED_100 + HALF_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 100 Mbps Half Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_100_half;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_100 + FULL_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 100 Mbps Full Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_100_full;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_1000:
DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without "
"Duplex\n");
goto full_duplex_only;
case SPEED_1000 + HALF_DUPLEX:
DPRINTK(PROBE, INFO,
"Half Duplex is not supported at 1000 Mbps\n");
/* fall through */
case SPEED_1000 + FULL_DUPLEX:
full_duplex_only:
DPRINTK(PROBE, INFO,
"Using Autonegotiation at 1000 Mbps Full Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
break;
default:
BUG();
}
/* Speed, AutoNeg and MDI/MDI-X must all play nice */
if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) {
DPRINTK(PROBE, INFO,
"Speed, AutoNeg and MDI-X specifications are "
"incompatible. Setting MDI-X to a compatible value.\n");
}
}

View File

@ -0,0 +1,770 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
Copyright(c) 1999 - 2006 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
#include "e1000.h"
/* This is the only thing that needs to be changed to adjust the
* maximum number of ports that the driver can manage.
*/
#define E1000_MAX_NIC 32
#define OPTION_UNSET -1
#define OPTION_DISABLED 0
#define OPTION_ENABLED 1
/* All parameters are treated the same, as an integer array of values.
* This macro just reduces the need to repeat the same declaration code
* over and over (plus this helps to avoid typo bugs).
*/
#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
#define E1000_PARAM(X, desc) \
static int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
static unsigned int num_##X; \
module_param_array_named(X, X, int, &num_##X, 0); \
MODULE_PARM_DESC(X, desc);
/* Transmit Descriptor Count
*
* Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
* Valid Range: 80-4096 for 82544 and newer
*
* Default Value: 256
*/
E1000_PARAM(TxDescriptors, "Number of transmit descriptors");
/* Receive Descriptor Count
*
* Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
* Valid Range: 80-4096 for 82544 and newer
*
* Default Value: 256
*/
E1000_PARAM(RxDescriptors, "Number of receive descriptors");
/* User Specified Speed Override
*
* Valid Range: 0, 10, 100, 1000
* - 0 - auto-negotiate at all supported speeds
* - 10 - only link at 10 Mbps
* - 100 - only link at 100 Mbps
* - 1000 - only link at 1000 Mbps
*
* Default Value: 0
*/
E1000_PARAM(Speed, "Speed setting");
/* User Specified Duplex Override
*
* Valid Range: 0-2
* - 0 - auto-negotiate for duplex
* - 1 - only link at half duplex
* - 2 - only link at full duplex
*
* Default Value: 0
*/
E1000_PARAM(Duplex, "Duplex setting");
/* Auto-negotiation Advertisement Override
*
* Valid Range: 0x01-0x0F, 0x20-0x2F (copper); 0x20 (fiber)
*
* The AutoNeg value is a bit mask describing which speed and duplex
* combinations should be advertised during auto-negotiation.
* The supported speed and duplex modes are listed below
*
* Bit 7 6 5 4 3 2 1 0
* Speed (Mbps) N/A N/A 1000 N/A 100 100 10 10
* Duplex Full Full Half Full Half
*
* Default Value: 0x2F (copper); 0x20 (fiber)
*/
E1000_PARAM(AutoNeg, "Advertised auto-negotiation setting");
#define AUTONEG_ADV_DEFAULT 0x2F
#define AUTONEG_ADV_MASK 0x2F
/* User Specified Flow Control Override
*
* Valid Range: 0-3
* - 0 - No Flow Control
* - 1 - Rx only, respond to PAUSE frames but do not generate them
* - 2 - Tx only, generate PAUSE frames but ignore them on receive
* - 3 - Full Flow Control Support
*
* Default Value: Read flow control settings from the EEPROM
*/
E1000_PARAM(FlowControl, "Flow Control setting");
#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
/* XsumRX - Receive Checksum Offload Enable/Disable
*
* Valid Range: 0, 1
* - 0 - disables all checksum offload
* - 1 - enables receive IP/TCP/UDP checksum offload
* on 82543 and newer -based NICs
*
* Default Value: 1
*/
E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
/* Transmit Interrupt Delay in units of 1.024 microseconds
* Tx interrupt delay needs to typically be set to something non zero
*
* Valid Range: 0-65535
*/
E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
#define DEFAULT_TIDV 8
#define MAX_TXDELAY 0xFFFF
#define MIN_TXDELAY 0
/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds
*
* Valid Range: 0-65535
*/
E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay");
#define DEFAULT_TADV 32
#define MAX_TXABSDELAY 0xFFFF
#define MIN_TXABSDELAY 0
/* Receive Interrupt Delay in units of 1.024 microseconds
* hardware will likely hang if you set this to anything but zero.
*
* Valid Range: 0-65535
*/
E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
#define DEFAULT_RDTR 0
#define MAX_RXDELAY 0xFFFF
#define MIN_RXDELAY 0
/* Receive Absolute Interrupt Delay in units of 1.024 microseconds
*
* Valid Range: 0-65535
*/
E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
#define DEFAULT_RADV 8
#define MAX_RXABSDELAY 0xFFFF
#define MIN_RXABSDELAY 0
/* Interrupt Throttle Rate (interrupts/sec)
*
* Valid Range: 100-100000 (0=off, 1=dynamic, 3=dynamic conservative)
*/
E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
#define DEFAULT_ITR 3
#define MAX_ITR 100000
#define MIN_ITR 100
/* Enable Smart Power Down of the PHY
*
* Valid Range: 0, 1
*
* Default Value: 0 (disabled)
*/
E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
/* Enable Kumeran Lock Loss workaround
*
* Valid Range: 0, 1
*
* Default Value: 1 (enabled)
*/
E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
struct e1000_option {
enum { enable_option, range_option, list_option } type;
const char *name;
const char *err;
int def;
union {
struct { /* range_option info */
int min;
int max;
} r;
struct { /* list_option info */
int nr;
const struct e1000_opt_list { int i; char *str; } *p;
} l;
} arg;
};
static int __devinit e1000_validate_option(unsigned int *value,
const struct e1000_option *opt,
struct e1000_adapter *adapter)
{
if (*value == OPTION_UNSET) {
*value = opt->def;
return 0;
}
switch (opt->type) {
case enable_option:
switch (*value) {
case OPTION_ENABLED:
DPRINTK(PROBE, INFO, "%s Enabled\n", opt->name);
return 0;
case OPTION_DISABLED:
DPRINTK(PROBE, INFO, "%s Disabled\n", opt->name);
return 0;
}
break;
case range_option:
if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
DPRINTK(PROBE, INFO,
"%s set to %i\n", opt->name, *value);
return 0;
}
break;
case list_option: {
int i;
const struct e1000_opt_list *ent;
for (i = 0; i < opt->arg.l.nr; i++) {
ent = &opt->arg.l.p[i];
if (*value == ent->i) {
if (ent->str[0] != '\0')
DPRINTK(PROBE, INFO, "%s\n", ent->str);
return 0;
}
}
}
break;
default:
BUG();
}
DPRINTK(PROBE, INFO, "Invalid %s value specified (%i) %s\n",
opt->name, *value, opt->err);
*value = opt->def;
return -1;
}
static void e1000_check_fiber_options(struct e1000_adapter *adapter);
static void e1000_check_copper_options(struct e1000_adapter *adapter);
/**
* e1000_check_options - Range Checking for Command Line Parameters
* @adapter: board private structure
*
* This routine checks all command line parameters for valid user
* input. If an invalid value is given, or if no user specified
* value exists, a default value is used. The final value is stored
* in a variable in the adapter structure.
**/
void __devinit e1000_check_options(struct e1000_adapter *adapter)
{
struct e1000_option opt;
int bd = adapter->bd_number;
if (bd >= E1000_MAX_NIC) {
DPRINTK(PROBE, NOTICE,
"Warning: no configuration for board #%i\n", bd);
DPRINTK(PROBE, NOTICE, "Using defaults for all values\n");
}
{ /* Transmit Descriptor Count */
struct e1000_tx_ring *tx_ring = adapter->tx_ring;
int i;
e1000_mac_type mac_type = adapter->hw.mac_type;
opt = (struct e1000_option) {
.type = range_option,
.name = "Transmit Descriptors",
.err = "using default of "
__MODULE_STRING(E1000_DEFAULT_TXD),
.def = E1000_DEFAULT_TXD,
.arg = { .r = {
.min = E1000_MIN_TXD,
.max = mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD
}}
};
if (num_TxDescriptors > bd) {
tx_ring->count = TxDescriptors[bd];
e1000_validate_option(&tx_ring->count, &opt, adapter);
tx_ring->count = ALIGN(tx_ring->count,
REQ_TX_DESCRIPTOR_MULTIPLE);
} else {
tx_ring->count = opt.def;
}
for (i = 0; i < adapter->num_tx_queues; i++)
tx_ring[i].count = tx_ring->count;
}
{ /* Receive Descriptor Count */
struct e1000_rx_ring *rx_ring = adapter->rx_ring;
int i;
e1000_mac_type mac_type = adapter->hw.mac_type;
opt = (struct e1000_option) {
.type = range_option,
.name = "Receive Descriptors",
.err = "using default of "
__MODULE_STRING(E1000_DEFAULT_RXD),
.def = E1000_DEFAULT_RXD,
.arg = { .r = {
.min = E1000_MIN_RXD,
.max = mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD
}}
};
if (num_RxDescriptors > bd) {
rx_ring->count = RxDescriptors[bd];
e1000_validate_option(&rx_ring->count, &opt, adapter);
rx_ring->count = ALIGN(rx_ring->count,
REQ_RX_DESCRIPTOR_MULTIPLE);
} else {
rx_ring->count = opt.def;
}
for (i = 0; i < adapter->num_rx_queues; i++)
rx_ring[i].count = rx_ring->count;
}
{ /* Checksum Offload Enable/Disable */
opt = (struct e1000_option) {
.type = enable_option,
.name = "Checksum Offload",
.err = "defaulting to Enabled",
.def = OPTION_ENABLED
};
if (num_XsumRX > bd) {
unsigned int rx_csum = XsumRX[bd];
e1000_validate_option(&rx_csum, &opt, adapter);
adapter->rx_csum = rx_csum;
} else {
adapter->rx_csum = opt.def;
}
}
{ /* Flow Control */
struct e1000_opt_list fc_list[] =
{{ E1000_FC_NONE, "Flow Control Disabled" },
{ E1000_FC_RX_PAUSE,"Flow Control Receive Only" },
{ E1000_FC_TX_PAUSE,"Flow Control Transmit Only" },
{ E1000_FC_FULL, "Flow Control Enabled" },
{ E1000_FC_DEFAULT, "Flow Control Hardware Default" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "Flow Control",
.err = "reading default settings from EEPROM",
.def = E1000_FC_DEFAULT,
.arg = { .l = { .nr = ARRAY_SIZE(fc_list),
.p = fc_list }}
};
if (num_FlowControl > bd) {
unsigned int fc = FlowControl[bd];
e1000_validate_option(&fc, &opt, adapter);
adapter->hw.fc = adapter->hw.original_fc = fc;
} else {
adapter->hw.fc = adapter->hw.original_fc = opt.def;
}
}
{ /* Transmit Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Transmit Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_TIDV),
.def = DEFAULT_TIDV,
.arg = { .r = { .min = MIN_TXDELAY,
.max = MAX_TXDELAY }}
};
if (num_TxIntDelay > bd) {
adapter->tx_int_delay = TxIntDelay[bd];
e1000_validate_option(&adapter->tx_int_delay, &opt,
adapter);
} else {
adapter->tx_int_delay = opt.def;
}
}
{ /* Transmit Absolute Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Transmit Absolute Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_TADV),
.def = DEFAULT_TADV,
.arg = { .r = { .min = MIN_TXABSDELAY,
.max = MAX_TXABSDELAY }}
};
if (num_TxAbsIntDelay > bd) {
adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
adapter);
} else {
adapter->tx_abs_int_delay = opt.def;
}
}
{ /* Receive Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Receive Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_RDTR),
.def = DEFAULT_RDTR,
.arg = { .r = { .min = MIN_RXDELAY,
.max = MAX_RXDELAY }}
};
if (num_RxIntDelay > bd) {
adapter->rx_int_delay = RxIntDelay[bd];
e1000_validate_option(&adapter->rx_int_delay, &opt,
adapter);
} else {
adapter->rx_int_delay = opt.def;
}
}
{ /* Receive Absolute Interrupt Delay */
opt = (struct e1000_option) {
.type = range_option,
.name = "Receive Absolute Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_RADV),
.def = DEFAULT_RADV,
.arg = { .r = { .min = MIN_RXABSDELAY,
.max = MAX_RXABSDELAY }}
};
if (num_RxAbsIntDelay > bd) {
adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
adapter);
} else {
adapter->rx_abs_int_delay = opt.def;
}
}
{ /* Interrupt Throttling Rate */
opt = (struct e1000_option) {
.type = range_option,
.name = "Interrupt Throttling Rate (ints/sec)",
.err = "using default of " __MODULE_STRING(DEFAULT_ITR),
.def = DEFAULT_ITR,
.arg = { .r = { .min = MIN_ITR,
.max = MAX_ITR }}
};
if (num_InterruptThrottleRate > bd) {
adapter->itr = InterruptThrottleRate[bd];
switch (adapter->itr) {
case 0:
DPRINTK(PROBE, INFO, "%s turned off\n",
opt.name);
break;
case 1:
DPRINTK(PROBE, INFO, "%s set to dynamic mode\n",
opt.name);
adapter->itr_setting = adapter->itr;
adapter->itr = 20000;
break;
case 3:
DPRINTK(PROBE, INFO,
"%s set to dynamic conservative mode\n",
opt.name);
adapter->itr_setting = adapter->itr;
adapter->itr = 20000;
break;
default:
e1000_validate_option(&adapter->itr, &opt,
adapter);
/* save the setting, because the dynamic bits change itr */
/* clear the lower two bits because they are
* used as control */
adapter->itr_setting = adapter->itr & ~3;
break;
}
} else {
adapter->itr_setting = opt.def;
adapter->itr = 20000;
}
}
{ /* Smart Power Down */
opt = (struct e1000_option) {
.type = enable_option,
.name = "PHY Smart Power Down",
.err = "defaulting to Disabled",
.def = OPTION_DISABLED
};
if (num_SmartPowerDownEnable > bd) {
unsigned int spd = SmartPowerDownEnable[bd];
e1000_validate_option(&spd, &opt, adapter);
adapter->smart_power_down = spd;
} else {
adapter->smart_power_down = opt.def;
}
}
switch (adapter->hw.media_type) {
case e1000_media_type_fiber:
case e1000_media_type_internal_serdes:
e1000_check_fiber_options(adapter);
break;
case e1000_media_type_copper:
e1000_check_copper_options(adapter);
break;
default:
BUG();
}
}
/**
* e1000_check_fiber_options - Range Checking for Link Options, Fiber Version
* @adapter: board private structure
*
* Handles speed and duplex options on fiber adapters
**/
static void __devinit e1000_check_fiber_options(struct e1000_adapter *adapter)
{
int bd = adapter->bd_number;
if (num_Speed > bd) {
DPRINTK(PROBE, INFO, "Speed not valid for fiber adapters, "
"parameter ignored\n");
}
if (num_Duplex > bd) {
DPRINTK(PROBE, INFO, "Duplex not valid for fiber adapters, "
"parameter ignored\n");
}
if ((num_AutoNeg > bd) && (AutoNeg[bd] != 0x20)) {
DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is "
"not valid for fiber adapters, "
"parameter ignored\n");
}
}
/**
* e1000_check_copper_options - Range Checking for Link Options, Copper Version
* @adapter: board private structure
*
* Handles speed and duplex options on copper adapters
**/
static void __devinit e1000_check_copper_options(struct e1000_adapter *adapter)
{
struct e1000_option opt;
unsigned int speed, dplx, an;
int bd = adapter->bd_number;
{ /* Speed */
static const struct e1000_opt_list speed_list[] = {
{ 0, "" },
{ SPEED_10, "" },
{ SPEED_100, "" },
{ SPEED_1000, "" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "Speed",
.err = "parameter ignored",
.def = 0,
.arg = { .l = { .nr = ARRAY_SIZE(speed_list),
.p = speed_list }}
};
if (num_Speed > bd) {
speed = Speed[bd];
e1000_validate_option(&speed, &opt, adapter);
} else {
speed = opt.def;
}
}
{ /* Duplex */
static const struct e1000_opt_list dplx_list[] = {
{ 0, "" },
{ HALF_DUPLEX, "" },
{ FULL_DUPLEX, "" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "Duplex",
.err = "parameter ignored",
.def = 0,
.arg = { .l = { .nr = ARRAY_SIZE(dplx_list),
.p = dplx_list }}
};
if (num_Duplex > bd) {
dplx = Duplex[bd];
e1000_validate_option(&dplx, &opt, adapter);
} else {
dplx = opt.def;
}
}
if ((num_AutoNeg > bd) && (speed != 0 || dplx != 0)) {
DPRINTK(PROBE, INFO,
"AutoNeg specified along with Speed or Duplex, "
"parameter ignored\n");
adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
} else { /* Autoneg */
static const struct e1000_opt_list an_list[] =
#define AA "AutoNeg advertising "
{{ 0x01, AA "10/HD" },
{ 0x02, AA "10/FD" },
{ 0x03, AA "10/FD, 10/HD" },
{ 0x04, AA "100/HD" },
{ 0x05, AA "100/HD, 10/HD" },
{ 0x06, AA "100/HD, 10/FD" },
{ 0x07, AA "100/HD, 10/FD, 10/HD" },
{ 0x08, AA "100/FD" },
{ 0x09, AA "100/FD, 10/HD" },
{ 0x0a, AA "100/FD, 10/FD" },
{ 0x0b, AA "100/FD, 10/FD, 10/HD" },
{ 0x0c, AA "100/FD, 100/HD" },
{ 0x0d, AA "100/FD, 100/HD, 10/HD" },
{ 0x0e, AA "100/FD, 100/HD, 10/FD" },
{ 0x0f, AA "100/FD, 100/HD, 10/FD, 10/HD" },
{ 0x20, AA "1000/FD" },
{ 0x21, AA "1000/FD, 10/HD" },
{ 0x22, AA "1000/FD, 10/FD" },
{ 0x23, AA "1000/FD, 10/FD, 10/HD" },
{ 0x24, AA "1000/FD, 100/HD" },
{ 0x25, AA "1000/FD, 100/HD, 10/HD" },
{ 0x26, AA "1000/FD, 100/HD, 10/FD" },
{ 0x27, AA "1000/FD, 100/HD, 10/FD, 10/HD" },
{ 0x28, AA "1000/FD, 100/FD" },
{ 0x29, AA "1000/FD, 100/FD, 10/HD" },
{ 0x2a, AA "1000/FD, 100/FD, 10/FD" },
{ 0x2b, AA "1000/FD, 100/FD, 10/FD, 10/HD" },
{ 0x2c, AA "1000/FD, 100/FD, 100/HD" },
{ 0x2d, AA "1000/FD, 100/FD, 100/HD, 10/HD" },
{ 0x2e, AA "1000/FD, 100/FD, 100/HD, 10/FD" },
{ 0x2f, AA "1000/FD, 100/FD, 100/HD, 10/FD, 10/HD" }};
opt = (struct e1000_option) {
.type = list_option,
.name = "AutoNeg",
.err = "parameter ignored",
.def = AUTONEG_ADV_DEFAULT,
.arg = { .l = { .nr = ARRAY_SIZE(an_list),
.p = an_list }}
};
if (num_AutoNeg > bd) {
an = AutoNeg[bd];
e1000_validate_option(&an, &opt, adapter);
} else {
an = opt.def;
}
adapter->hw.autoneg_advertised = an;
}
switch (speed + dplx) {
case 0:
adapter->hw.autoneg = adapter->fc_autoneg = 1;
if ((num_Speed > bd) && (speed != 0 || dplx != 0))
DPRINTK(PROBE, INFO,
"Speed and duplex autonegotiation enabled\n");
break;
case HALF_DUPLEX:
DPRINTK(PROBE, INFO, "Half Duplex specified without Speed\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at "
"Half Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
ADVERTISE_100_HALF;
break;
case FULL_DUPLEX:
DPRINTK(PROBE, INFO, "Full Duplex specified without Speed\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at "
"Full Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
ADVERTISE_100_FULL |
ADVERTISE_1000_FULL;
break;
case SPEED_10:
DPRINTK(PROBE, INFO, "10 Mbps Speed specified "
"without Duplex\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at 10 Mbps only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
ADVERTISE_10_FULL;
break;
case SPEED_10 + HALF_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 10 Mbps Half Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_10_half;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_10 + FULL_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 10 Mbps Full Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_10_full;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_100:
DPRINTK(PROBE, INFO, "100 Mbps Speed specified "
"without Duplex\n");
DPRINTK(PROBE, INFO, "Using Autonegotiation at "
"100 Mbps only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
ADVERTISE_100_FULL;
break;
case SPEED_100 + HALF_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 100 Mbps Half Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_100_half;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_100 + FULL_DUPLEX:
DPRINTK(PROBE, INFO, "Forcing to 100 Mbps Full Duplex\n");
adapter->hw.autoneg = adapter->fc_autoneg = 0;
adapter->hw.forced_speed_duplex = e1000_100_full;
adapter->hw.autoneg_advertised = 0;
break;
case SPEED_1000:
DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without "
"Duplex\n");
goto full_duplex_only;
case SPEED_1000 + HALF_DUPLEX:
DPRINTK(PROBE, INFO,
"Half Duplex is not supported at 1000 Mbps\n");
/* fall through */
case SPEED_1000 + FULL_DUPLEX:
full_duplex_only:
DPRINTK(PROBE, INFO,
"Using Autonegotiation at 1000 Mbps Full Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
break;
default:
BUG();
}
/* Speed, AutoNeg and MDI/MDI-X must all play nice */
if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) {
DPRINTK(PROBE, INFO,
"Speed, AutoNeg and MDI-X specifications are "
"incompatible. Setting MDI-X to a compatible value.\n");
}
}

File diff suppressed because it is too large Load Diff

4950
devices/r8169-2.6.33-orig.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -35,4 +35,5 @@ ifeq (@ENABLE_TTY@,1)
obj-m += tty/
endif
#------------------------------------------------------------------------------

View File

@ -40,12 +40,28 @@ SUBDIRS += \
tty
endif
if ENABLE_RTDM
if ENABLE_XENOMAI
SUBDIRS += \
xenomai \
xenomai_posix
endif
if ENABLE_RTAI
SUBDIRS += \
rtai_rtdm
endif
endif
DIST_SUBDIRS = \
dc_rtai \
dc_user \
mini \
rtai \
tty \
xenomai \
xenomai_posix \
rtai_rtdm \
user
EXTRA_DIST = \

View File

@ -229,8 +229,8 @@ void run(long data)
}
ecrt_master_sync_slave_clocks(master);
ecrt_domain_queue(domain1);
ecrt_master_send(master);
rt_sem_signal(&master_sem);
ecrt_master_send(master);
rt_task_wait_period();
}
@ -238,30 +238,18 @@ void run(long data)
/*****************************************************************************/
void send_callback(void *cb_data)
void request_lock_callback(void *cb_data)
{
ec_master_t *m = (ec_master_t *) cb_data;
// too close to the next real time cycle: deny access...
if (get_cycles() - t_last_cycle <= t_critical) {
rt_sem_wait(&master_sem);
ecrt_master_send_ext(m);
rt_sem_signal(&master_sem);
}
rt_sem_wait(&master_sem);
}
/*****************************************************************************/
void receive_callback(void *cb_data)
void release_lock_callback(void *cb_data)
{
ec_master_t *m = (ec_master_t *) cb_data;
// too close to the next real time cycle: deny access...
if (get_cycles() - t_last_cycle <= t_critical) {
rt_sem_wait(&master_sem);
ecrt_master_receive(m);
rt_sem_signal(&master_sem);
}
rt_sem_signal(&master_sem);
}
/*****************************************************************************/
@ -285,7 +273,7 @@ int __init init_mod(void)
goto out_return;
}
ecrt_master_callbacks(master, send_callback, receive_callback, master);
ecrt_master_callbacks(master, request_lock_callback, release_lock_callback, master);
printk(KERN_INFO PFX "Registering domain...\n");
if (!(domain1 = ecrt_master_create_domain(master))) {

View File

@ -346,10 +346,9 @@ void cyclic_task(unsigned long data)
EC_WRITE_U8(domain1_pd + off_dig_out, blink ? 0x06 : 0x09);
// send process data
down(&master_sem);
ecrt_domain_queue(domain1);
ecrt_master_send(master);
up(&master_sem);
ecrt_master_send(master);
// restart timer
timer.expires += HZ / FREQUENCY;
@ -358,21 +357,17 @@ void cyclic_task(unsigned long data)
/*****************************************************************************/
void send_callback(void *cb_data)
void request_lock_callback(void *cb_data)
{
ec_master_t *m = (ec_master_t *) cb_data;
down(&master_sem);
ecrt_master_send_ext(m);
up(&master_sem);
}
/*****************************************************************************/
void receive_callback(void *cb_data)
void release_lock_callback(void *cb_data)
{
ec_master_t *m = (ec_master_t *) cb_data;
down(&master_sem);
ecrt_master_receive(m);
up(&master_sem);
}
@ -398,7 +393,7 @@ int __init init_mini_module(void)
}
sema_init(&master_sem, 1);
ecrt_master_callbacks(master, send_callback, receive_callback, master);
ecrt_master_callbacks(master, request_lock_callback, release_lock_callback, master);
printk(KERN_INFO PFX "Registering domain...\n");
if (!(domain1 = ecrt_master_create_domain(master))) {

View File

@ -234,8 +234,8 @@ void run(long data)
rt_sem_wait(&master_sem);
ecrt_domain_queue(domain1);
ecrt_master_send(master);
rt_sem_signal(&master_sem);
ecrt_master_send(master);
rt_task_wait_period();
}
@ -243,30 +243,18 @@ void run(long data)
/*****************************************************************************/
void send_callback(void *cb_data)
void request_lock_callback(void *cb_data)
{
ec_master_t *m = (ec_master_t *) cb_data;
// too close to the next real time cycle: deny access...
if (get_cycles() - t_last_cycle <= t_critical) {
rt_sem_wait(&master_sem);
ecrt_master_send_ext(m);
rt_sem_signal(&master_sem);
}
rt_sem_wait(&master_sem);
}
/*****************************************************************************/
void receive_callback(void *cb_data)
void release_lock_callback(void *cb_data)
{
ec_master_t *m = (ec_master_t *) cb_data;
// too close to the next real time cycle: deny access...
if (get_cycles() - t_last_cycle <= t_critical) {
rt_sem_wait(&master_sem);
ecrt_master_receive(m);
rt_sem_signal(&master_sem);
}
rt_sem_signal(&master_sem);
}
/*****************************************************************************/
@ -292,7 +280,7 @@ int __init init_mod(void)
goto out_return;
}
ecrt_master_callbacks(master, send_callback, receive_callback, master);
ecrt_master_callbacks(master, request_lock_callback, release_lock_callback, master);
printk(KERN_INFO PFX "Registering domain...\n");
if (!(domain1 = ecrt_master_create_domain(master))) {

View File

@ -0,0 +1,40 @@
#------------------------------------------------------------------------------
#
# $Id$
#
# Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
#
# This file is part of the IgH EtherCAT Master.
#
# The IgH EtherCAT Master is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
#
# The IgH EtherCAT Master is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# the IgH EtherCAT Master; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ---
#
# The license mentioned above concerns the source code only. Using the
# EtherCAT technology and brand is only permitted in compliance with the
# industrial property and similar rights of Beckhoff Automation GmbH.
#
#------------------------------------------------------------------------------
AM_CFLAGS = -Wall
noinst_PROGRAMS = ec_rtai_rtdm_example
ec_rtai_rtdm_example_SOURCES = main.c
ec_rtai_rtdm_example_CFLAGS = -I. -I"$(RTAI_DIR)"/include -O2 -I"$(LINUX_SOURCE_DIR)"/include -Wall -Wstrict-prototypes -pipe -I$(top_srcdir)/include
ec_rtai_rtdm_example_LDFLAGS = -L"$(RTAI_DIR)"/lib -llxrt -lrtdm -lpthread -L$(top_builddir)/lib/.libs -lethercat
#------------------------------------------------------------------------------

40
examples/rtai_rtdm/README Normal file
View File

@ -0,0 +1,40 @@
-------------------------------------------------------------------------------
$Id$
-------------------------------------------------------------------------------
This is a minimal example application for the use of the EtherCAT
master realtime RTDM interface with an RTAI-LXRT thread.
The application expects an RTAI installation. Configure the master sources
specifying --enable-rtdm --with-rtai-dir to have the right include paths.
Most probably you'll have different EtherCAT slaves present. Try adjusting the
section "process data" in main.c to your bus configuration.
There are some features that can be disabled by commenting out the respective
defines at the head of main.c.
---
To build the example, call:
make
To run it, load the appropriate RTAI modules:
insmod $(RTAI_DIR)/modules/rtai_hal.ko
insmod $(RTAI_DIR)/modules/rtai_lxrt.ko
insmod $(RTAI_DIR)/modules/rtai_sem.ko
insmod $(RTAI_DIR)/modules/rtai_rtdm.ko
Preload the EtherCAT RTDM module:
modprobe ec_rtdm
and call as root:
./ec_rtai_rtdm_example
...and watch the system logs for the outputs.
-------------------------------------------------------------------------------

752
examples/rtai_rtdm/main.c Normal file
View File

@ -0,0 +1,752 @@
/******************************************************************************
*
* $Id$
*
* main.c Copyright (C) 2011 IgH Andreas Stewering-Bone
*
* This file is part of ethercatrtdm interface to IgH EtherCAT master
*
* The IgH EtherCAT master is free software; you can
* redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation; version 2.1
* of the License.
*
* The IgH EtherCAT Master is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* The IgH EtherCAT master userspace library is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the IgH EtherCAT master userspace library. If not, see
* <http://www.gnu.org/licenses/>.
*
* The license mentioned above concerns the source code only. Using the
* EtherCAT technology and brand is only permitted in compliance with the
* industrial property and similar rights of Beckhoff Automation GmbH.
*
*****************************************************************************/
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <rtai_lxrt.h>
#include <rtdm/rtdm.h>
#include "../../include/ecrt.h"
#include "../../include/ec_rtdm.h"
#define rt_printf(X,Y)
#define NSEC_PER_SEC 1000000000
RT_TASK* task; // Stores a handle.
int priority=0; // Highest
int stack_size=0; // Use default (512)
int msg_size=0; // Use default (256)
static unsigned int cycle = 1000; /* 1 ms */
int rt_fd = -1;
int run=0;
unsigned int sync_ref_counter = 0;
CstructMstrAttach MstrAttach;
/****************************************************************************/
// Optional features
#define CONFIGURE_PDOS 1
/****************************************************************************/
// EtherCAT
static ec_master_t *master = NULL;
static ec_master_state_t master_state = {};
static ec_domain_t *domain1 = NULL;
static ec_domain_state_t domain1_state = {};
/****************************************************************************/
static uint8_t *domain1_pd = NULL;
// process data
#define BusCoupler01_Pos 0, 0
#define DigOutSlave01_Pos 0, 1
#define DigOutSlave02_Pos 0, 2
#define DigInSlave01_Pos 0, 3
#define AnaOutSlave01_Pos 0, 4
#define AnaInSlave01_Pos 0, 5
#define BusCoupler02_Pos 0, 6
#define AnaInSlave02_Pos 0, 7
#define Beckhoff_EK1100 0x00000002, 0x044c2c52
#define Beckhoff_EL1014 0x00000002, 0x03f63052
#define Beckhoff_EL2004 0x00000002, 0x07d43052
#define Beckhoff_EL4132 0x00000002, 0x10243052
#define Beckhoff_EL3102 0x00000002, 0x0c1e3052
#define Beckhoff_EL4102 0x00000002, 0x10063052
#define Beckhoff_EL6731 0x00000002, 0x1a4b3052
#define Beckhoff_EL6600 0x00000002, 0x19c93052
#define Beckhoff_EL3602 0x00000002, 0x0e123052
#define Beckhoff_EL5151 0x00000002, 0x141f3052
// offsets for PDO entries
static unsigned int off_dig_out0 = 0;
static unsigned int off_dig_out1 = 0;
static unsigned int off_dig_out2 = 0;
static unsigned int off_dig_out3 = 0;
static unsigned int off_dig_in0 = 0;
static unsigned int off_ana_out0 = 0;
static unsigned int off_ana_out1 = 0;
static unsigned int off_ana_in0_status = 0;
static unsigned int off_ana_in0_value = 0;
static unsigned int off_ana_in1_status = 0;
static unsigned int off_ana_in1_value = 0;
// process data
unsigned int bit_position0=0; /* Pointer to a variable to store a bit */
unsigned int bit_position1=0; /* Pointer to a variable to store a bit */
unsigned int bit_position2=0; /* Pointer to a variable to store a bit */
unsigned int bit_position3=0; /* Pointer to a variable to store a bit */
const static ec_pdo_entry_reg_t domain1_regs[] = {
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7000, 0x01, &off_dig_out0, &bit_position0},
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7010, 0x01, &off_dig_out1, &bit_position1},
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7020, 0x01, &off_dig_out2, &bit_position2},
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7030, 0x01, &off_dig_out3, &bit_position3},
{DigInSlave01_Pos, Beckhoff_EL1014, 0x6000, 0x01, &off_dig_in0},
{AnaOutSlave01_Pos, Beckhoff_EL4132, 0x3001, 0x01, &off_ana_out0},
{AnaOutSlave01_Pos, Beckhoff_EL4132, 0x3002, 0x01, &off_ana_out1},
{AnaInSlave01_Pos, Beckhoff_EL3102, 0x3101, 0x01, &off_ana_in0_status},
{AnaInSlave01_Pos, Beckhoff_EL3102, 0x3101, 0x02, &off_ana_in0_value},
{AnaInSlave01_Pos, Beckhoff_EL3102, 0x3102, 0x01, &off_ana_in1_status},
{AnaInSlave01_Pos, Beckhoff_EL3102, 0x3102, 0x02, &off_ana_in1_value},
{}
};
char rt_dev_file[64];
static unsigned int blink = 0;
static ec_slave_config_t *sc_dig_out_01 = NULL;
static ec_slave_config_t *sc_dig_out_02 = NULL;
static ec_slave_config_t *sc_dig_in_01 = NULL;
static ec_slave_config_t *sc_ana_out_01 = NULL;
static ec_slave_config_t *sc_ana_in_01 = NULL;
static ec_slave_config_t *sc_ana_in_02 = NULL;
/*****************************************************************************/
/* Slave 1, "EL2004"
* Vendor ID: 0x00000002
* Product code: 0x07d43052
* Revision number: 0x00100000
*/
ec_pdo_entry_info_t slave_1_pdo_entries[] = {
{0x7000, 0x01, 1}, /* Output */
{0x7010, 0x01, 1}, /* Output */
{0x7020, 0x01, 1}, /* Output */
{0x7030, 0x01, 1}, /* Output */
};
ec_pdo_info_t slave_1_pdos[] = {
{0x1600, 1, slave_1_pdo_entries + 0}, /* Channel 1 */
{0x1601, 1, slave_1_pdo_entries + 1}, /* Channel 2 */
{0x1602, 1, slave_1_pdo_entries + 2}, /* Channel 3 */
{0x1603, 1, slave_1_pdo_entries + 3}, /* Channel 4 */
};
ec_sync_info_t slave_1_syncs[] = {
{0, EC_DIR_OUTPUT, 4, slave_1_pdos + 0, EC_WD_ENABLE},
{0xff}
};
/* Slave 2, "EL2004"
* Vendor ID: 0x00000002
* Product code: 0x07d43052
* Revision number: 0x00100000
*/
ec_pdo_entry_info_t slave_2_pdo_entries[] = {
{0x7000, 0x01, 1}, /* Output */
{0x7010, 0x01, 1}, /* Output */
{0x7020, 0x01, 1}, /* Output */
{0x7030, 0x01, 1}, /* Output */
};
ec_pdo_info_t slave_2_pdos[] = {
{0x1600, 1, slave_2_pdo_entries + 0}, /* Channel 1 */
{0x1601, 1, slave_2_pdo_entries + 1}, /* Channel 2 */
{0x1602, 1, slave_2_pdo_entries + 2}, /* Channel 3 */
{0x1603, 1, slave_2_pdo_entries + 3}, /* Channel 4 */
};
ec_sync_info_t slave_2_syncs[] = {
{0, EC_DIR_OUTPUT, 4, slave_2_pdos + 0, EC_WD_ENABLE},
{0xff}
};
/* Slave 3, "EL1014"
* Vendor ID: 0x00000002
* Product code: 0x03f63052
* Revision number: 0x00100000
*/
ec_pdo_entry_info_t slave_3_pdo_entries[] = {
{0x6000, 0x01, 1}, /* Input */
{0x6010, 0x01, 1}, /* Input */
{0x6020, 0x01, 1}, /* Input */
{0x6030, 0x01, 1}, /* Input */
};
ec_pdo_info_t slave_3_pdos[] = {
{0x1a00, 1, slave_3_pdo_entries + 0}, /* Channel 1 */
{0x1a01, 1, slave_3_pdo_entries + 1}, /* Channel 2 */
{0x1a02, 1, slave_3_pdo_entries + 2}, /* Channel 3 */
{0x1a03, 1, slave_3_pdo_entries + 3}, /* Channel 4 */
};
ec_sync_info_t slave_3_syncs[] = {
{0, EC_DIR_INPUT, 4, slave_3_pdos + 0, EC_WD_DISABLE},
{0xff}
};
/* Slave 4, "EL4132"
* Vendor ID: 0x00000002
* Product code: 0x10243052
* Revision number: 0x03f90000
*/
ec_pdo_entry_info_t slave_4_pdo_entries[] = {
{0x3001, 0x01, 16}, /* Output */
{0x3002, 0x01, 16}, /* Output */
};
ec_pdo_info_t slave_4_pdos[] = {
{0x1600, 1, slave_4_pdo_entries + 0}, /* RxPDO 01 mapping */
{0x1601, 1, slave_4_pdo_entries + 1}, /* RxPDO 02 mapping */
};
ec_sync_info_t slave_4_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 2, slave_4_pdos + 0, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{0xff}
};
/* Slave 5, "EL3102"
* Vendor ID: 0x00000002
* Product code: 0x0c1e3052
* Revision number: 0x00000000
*/
ec_pdo_entry_info_t slave_5_pdo_entries[] = {
{0x3101, 0x01, 8}, /* Status */
{0x3101, 0x02, 16}, /* Value */
{0x3102, 0x01, 8}, /* Status */
{0x3102, 0x02, 16}, /* Value */
};
ec_pdo_info_t slave_5_pdos[] = {
{0x1a00, 2, slave_5_pdo_entries + 0}, /* TxPDO 001 mapping */
{0x1a01, 2, slave_5_pdo_entries + 2}, /* TxPDO 002 mapping */
};
ec_sync_info_t slave_5_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 2, slave_5_pdos + 0, EC_WD_DISABLE},
{0xff}
};
/* Slave 6, "EL6731-0010"
* Vendor ID: 0x00000002
* Product code: 0x1a4b3052
* Revision number: 0x0011000a
*/
ec_sync_info_t slave_6_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
};
/* Slave 7, "EL6601"
* Vendor ID: 0x00000002
* Product code: 0x19c93052
* Revision number: 0x00110000
*/
/*
ec_sync_info_t slave_7_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{0xff}
};
*/
/* Master 0, Slave 7, "EL3602"
* Vendor ID: 0x00000002
* Product code: 0x0e123052
* Revision number: 0x00100000
*/
ec_pdo_entry_info_t slave_7_pdo_entries[] = {
{0x6000, 0x01, 1}, /* Underrange */
{0x6000, 0x02, 1}, /* Overrange */
{0x6000, 0x03, 2}, /* Limit 1 */
{0x6000, 0x05, 2}, /* Limit 2 */
{0x6000, 0x07, 1}, /* Error */
{0x0000, 0x00, 7}, /* Gap */
{0x1800, 0x07, 1},
{0x1800, 0x09, 1},
{0x6000, 0x11, 32}, /* Value */
{0x6010, 0x01, 1}, /* Underrange */
{0x6010, 0x02, 1}, /* Overrange */
{0x6010, 0x03, 2}, /* Limit 1 */
{0x6010, 0x05, 2}, /* Limit 2 */
{0x6010, 0x07, 1}, /* Error */
{0x0000, 0x00, 7}, /* Gap */
{0x1801, 0x07, 1},
{0x1801, 0x09, 1},
{0x6010, 0x11, 32}, /* Value */
};
ec_pdo_info_t slave_7_pdos[] = {
{0x1a00, 9, slave_7_pdo_entries + 0}, /* AI TxPDO-Map Inputs Ch.1 */
{0x1a01, 9, slave_7_pdo_entries + 9}, /* AI TxPDO-Map Inputs Ch.2 */
};
ec_sync_info_t slave_7_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 2, slave_7_pdos + 0, EC_WD_DISABLE},
{0xff}
};
/* Master 0, Slave 8, "EL5151"
* Vendor ID: 0x00000002
* Product code: 0x141f3052
* Revision number: 0x00130000
*/
ec_pdo_entry_info_t slave_8_pdo_entries[] = {
{0x6000, 0x01, 1},
{0x6000, 0x02, 1},
{0x6000, 0x03, 1},
{0x0000, 0x00, 4}, /* Gap */
{0x6000, 0x08, 1},
{0x6000, 0x09, 1},
{0x6000, 0x0a, 1},
{0x6000, 0x0b, 1},
{0x0000, 0x00, 1}, /* Gap */
{0x6000, 0x0d, 1},
{0x1c32, 0x20, 1},
{0x0000, 0x00, 1}, /* Gap */
{0x1800, 0x09, 1},
{0x6000, 0x11, 32},
{0x6000, 0x12, 32},
{0x6000, 0x14, 32},
};
ec_pdo_info_t slave_8_pdos[] = {
{0x0000, 0, NULL},
{0x1a00, 15, slave_8_pdo_entries + 0},
{0x1a02, 1, slave_8_pdo_entries + 15},
};
ec_sync_info_t slave_8_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 1, slave_8_pdos + 0, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 2, slave_8_pdos + 1, EC_WD_DISABLE},
{0xff}
};
/*****************************************************************************/
void rt_check_domain_state(void)
{
ec_domain_state_t ds;
if (rt_fd>=0)
{
ecrt_rtdm_domain_state(rt_fd,&ds);
}
if (ds.working_counter != domain1_state.working_counter)
{
rt_printf("Domain1: WC %u.\n", ds.working_counter);
}
if (ds.wc_state != domain1_state.wc_state)
{
rt_printf("Domain1: State %u.\n", ds.wc_state);
}
domain1_state = ds;
}
void rt_check_master_state(void)
{
ec_master_state_t ms;
if (rt_fd>=0)
{
ecrt_rtdm_master_state(rt_fd,&ms);
}
if (ms.slaves_responding != master_state.slaves_responding)
{
rt_printf("%u slave(s).\n", ms.slaves_responding);
}
if (ms.al_states != master_state.al_states)
{
rt_printf("AL states: 0x%02X.\n", ms.al_states);
}
if (ms.link_up != master_state.link_up)
{
rt_printf("Link is %s.\n", ms.link_up ? "up" : "down");
}
master_state = ms;
}
void rt_sync(void)
{
RTIME now_ns;
uint64_t now;
now_ns = rt_get_cpu_time_ns();
now = (uint64_t)now_ns;
if (rt_fd>=0)
{
ecrt_rtdm_master_application_time(rt_fd, &now);
}
if (sync_ref_counter) {
sync_ref_counter--;
} else {
sync_ref_counter = 9;
if (rt_fd>=0)
{
ecrt_rtdm_master_sync_reference_clock(rt_fd);
}
}
if (rt_fd>=0)
{
ecrt_rtdm_master_sync_slave_clocks(rt_fd) ;
}
}
/*****************************************************************************/
/**********************************************************/
void cleanup_all(void)
{
run = 0;
}
void catch_signal(int sig)
{
cleanup_all();
}
void my_cyclic(void)
{
int counter = 0;
int divcounter = 0;
int divider = 10;
int period;
rt_set_periodic_mode();
period = (int) nano2count((RTIME)cycle*1000);
start_rt_timer(period);
rt_make_hard_real_time();
rt_task_make_periodic(task, rt_get_time() + 10*period, period);
while(1) {
rt_task_wait_period();
counter++;
if (counter>60000) {
run=0;
}
if(run == 0) {
rt_make_soft_real_time();
stop_rt_timer();
return;
}
// receive ethercat
ecrt_rtdm_master_recieve(rt_fd);
ecrt_rtdm_domain_process(rt_fd);
rt_check_domain_state();
if (divcounter ==0)
{
divcounter=divider;
rt_check_master_state();
}
divcounter--;
if ((counter % 200)==0)
{
blink = !blink;
}
EC_WRITE_U8(domain1_pd + off_dig_out0, blink ? 0x0 : 0x0F);
EC_WRITE_U16(domain1_pd + off_ana_out0, blink ? 0x0: 0xfff);
//sync DC
rt_sync();
// send process data
ecrt_rtdm_domain_queque(rt_fd);
ecrt_rtdm_master_send(rt_fd);
}
return;
}
int main(int argc, char *argv[])
{
ec_slave_config_t *sc;
int rtstatus;
signal(SIGTERM, catch_signal);
signal(SIGINT, catch_signal);
signal(SIGHUP, catch_signal);
mlockall(MCL_CURRENT|MCL_FUTURE);
MstrAttach.masterindex = 0;
printf("request master\n");
master = ecrt_request_master(MstrAttach.masterindex);
if (!master)
return -1;
domain1 = ecrt_master_create_domain(master);
if (!domain1)
return -1;
#ifdef CONFIGURE_PDOS
printf("Configuring PDOs...\n");
printf("Get Configuring el2004...\n");
sc_dig_out_01 = ecrt_master_slave_config(master, DigOutSlave01_Pos, Beckhoff_EL2004);
if (!sc_dig_out_01) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL2004...\n");
if (ecrt_slave_config_pdos(sc_dig_out_01, EC_END, slave_1_syncs))
{
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring el2004...\n");
sc_dig_out_02 = ecrt_master_slave_config(master, DigOutSlave02_Pos, Beckhoff_EL2004);
if (!sc_dig_out_02) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL2004...\n");
if (ecrt_slave_config_pdos(sc_dig_out_02, EC_END, slave_2_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring el1014...\n");
sc_dig_in_01 = ecrt_master_slave_config(master, DigInSlave01_Pos, Beckhoff_EL1014);
if (!sc_dig_in_01) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL1014...\n");
if (ecrt_slave_config_pdos(sc_dig_in_01, EC_END, slave_3_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring EL4132...\n");
sc_ana_out_01 = ecrt_master_slave_config(master, AnaOutSlave01_Pos, Beckhoff_EL4132);
if (!sc_ana_out_01) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL4132...\n");
if (ecrt_slave_config_pdos(sc_ana_out_01, EC_END, slave_4_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring EL3102...\n");
sc_ana_in_01 = ecrt_master_slave_config(master, AnaInSlave01_Pos, Beckhoff_EL3102);
if (!sc_ana_in_01) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL3102...\n");
if (ecrt_slave_config_pdos(sc_ana_in_01, EC_END, slave_5_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring EL3602...\n");
sc_ana_in_02 = ecrt_master_slave_config(master, AnaInSlave02_Pos, Beckhoff_EL3602);
if (!sc_ana_in_02) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL3602...\n");
if (ecrt_slave_config_pdos(sc_ana_in_02, EC_END, slave_7_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
#endif
// Create configuration for bus coupler
sc = ecrt_master_slave_config(master, BusCoupler01_Pos, Beckhoff_EK1100);
if (!sc)
return -1;
#ifdef CONFIGURE_PDOS
if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
fprintf(stderr, "PDO entry registration failed!\n");
return -1;
}
#endif
sprintf(&rt_dev_file[0],"%s%u",EC_RTDM_DEV_FILE_NAME,0);
rt_fd = rt_dev_open( &rt_dev_file[0], 0);
if (rt_fd < 0) {
printf("can't open %s\n", &rt_dev_file[0]);
return -1;
}
MstrAttach.domainindex = ecrt_domain_index(domain1);
// attach the master over rtdm driver
rtstatus=ecrt_rtdm_master_attach(rt_fd, &MstrAttach);
if (rtstatus < 0)
{
printf("cannot attach to master over rtdm\n");
return -1;
}
printf("Activating master...\n");
if (ecrt_master_activate(master))
return -1;
if (!(domain1_pd = ecrt_domain_data(domain1))) {
return -1;
}
fprintf(stderr, "domain1_pd: 0x%.6x\n", (unsigned int)domain1_pd);
run=1;
/* Create cyclic RT-thread */
struct sched_param param;
param.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1;
if( sched_setscheduler( 0, SCHED_FIFO, &param ) == -1 ) {
puts("ERROR IN SETTING THE SCHEDULER");
perror("errno");
exit(1);
}
task = rt_task_init( nam2num("ec_rtai_rtdm_example"), priority, stack_size, msg_size);
my_cyclic();
rt_task_delete(task);
if (rt_fd >= 0)
{
printf("closing rt device %s\n", &rt_dev_file[0]);
rt_dev_close(rt_fd);
}
printf("End of Program\n");
ecrt_release_master(master);
return 0;
}

View File

@ -141,8 +141,8 @@ void cyclic_task(unsigned long data)
// send process data
down(&master_sem);
ecrt_domain_queue(domain1);
ecrt_master_send(master);
up(&master_sem);
ecrt_master_send(master);
// restart timer
timer.expires += HZ / FREQUENCY;
@ -151,21 +151,17 @@ void cyclic_task(unsigned long data)
/*****************************************************************************/
void send_callback(void *cb_data)
void request_lock_callback(void *cb_data)
{
ec_master_t *m = (ec_master_t *) cb_data;
down(&master_sem);
ecrt_master_send_ext(m);
up(&master_sem);
}
/*****************************************************************************/
void receive_callback(void *cb_data)
void release_lock_callback(void *cb_data)
{
ec_master_t *m = (ec_master_t *) cb_data;
down(&master_sem);
ecrt_master_receive(m);
up(&master_sem);
}
@ -186,7 +182,7 @@ int __init init_mini_module(void)
}
sema_init(&master_sem, 1);
ecrt_master_callbacks(master, send_callback, receive_callback, master);
ecrt_master_callbacks(master, request_lock_callback, release_lock_callback, master);
printk(KERN_INFO PFX "Registering domain...\n");
if (!(domain1 = ecrt_master_create_domain(master))) {

View File

@ -0,0 +1,39 @@
#------------------------------------------------------------------------------
#
# $Id$
#
# Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
#
# This file is part of the IgH EtherCAT Master.
#
# The IgH EtherCAT Master is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
#
# The IgH EtherCAT Master is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# the IgH EtherCAT Master; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ---
#
# The license mentioned above concerns the source code only. Using the
# EtherCAT technology and brand is only permitted in compliance with the
# industrial property and similar rights of Beckhoff Automation GmbH.
#
#------------------------------------------------------------------------------
AM_CFLAGS = -Wall
noinst_PROGRAMS = ec_xenomai_example
ec_xenomai_example_SOURCES = main.c
ec_xenomai_example_CFLAGS = -I"$(XENOMAI_DIR)"/include -D_GNU_SOURCE -D_REENTRANT -Wall -pipe -D__XENO__ -I$(top_srcdir)/include
ec_xenomai_example_LDFLAGS = -lrtdm -L$(top_builddir)/lib/.libs -lethercat -lnative -L"$(XENOMAI_DIR)"/lib -lrtdk -lxenomai -lpthread
#------------------------------------------------------------------------------

35
examples/xenomai/README Normal file
View File

@ -0,0 +1,35 @@
-------------------------------------------------------------------------------
$Id$
-------------------------------------------------------------------------------
This is a minimal example application for the use of the EtherCAT
master realtime RTDM interface with an XENOMAI NATIVE thread.
The application expects an XENOMAI installation. Configure the master sources
specifying --enable-rtdm --with-xenomai-dir to have the right include paths.
Most probably you'll have different EtherCAT slaves present. Try adjusting the
section "process data" in main.c to your bus configuration.
There are some features that can be disabled by commenting out the respective
defines at the head of main.c.
---
To build the example, call:
make
To run it, preload the EtherCAT RTDM module:
modprobe ec_rtdm
and call as root:
./ec_xenomai_example
...and watch the system logs for the outputs.
-------------------------------------------------------------------------------

948
examples/xenomai/main.c Normal file
View File

@ -0,0 +1,948 @@
/******************************************************************************
*
* $Id$
*
* main.c Copyright (C) 2009-2010 Moehwald GmbH B.Benner
* 2011 IgH Andreas Stewering-Bone
*
* This file is part of ethercatrtdm interface to IgH EtherCAT master
*
* The Moehwald ethercatrtdm interface is free software; you can
* redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation; version 2.1
* of the License.
*
* The IgH EtherCAT Master is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* The IgH EtherCAT master userspace library is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the IgH EtherCAT master userspace library. If not, see
* <http://www.gnu.org/licenses/>.
*
* The license mentioned above concerns the source code only. Using the
* EtherCAT technology and brand is only permitted in compliance with the
* industrial property and similar rights of Beckhoff Automation GmbH.
*
*****************************************************************************/
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <rtdm/rtdm.h>
#include <native/task.h>
#include <native/sem.h>
#include <native/mutex.h>
#include <native/timer.h>
#include <rtdk.h>
#include <pthread.h>
/****************************************************************************/
#include "../../include/ecrt.h"
#include "../../include/ec_rtdm.h"
RT_TASK my_task;
int rt_fd = -1;
int run=0;
unsigned int sync_ref_counter = 0;
CstructMstrAttach MstrAttach;
/****************************************************************************/
// Optional features
#define CONFIGURE_PDOS 1
//#define SDO_ACCESS 1
/****************************************************************************/
// EtherCAT
static ec_master_t *master = NULL;
static ec_master_state_t master_state = {};
static ec_domain_t *domain1 = NULL;
static ec_domain_state_t domain1_state = {};
//static ec_slave_config_t *sc_ana_in = NULL;
//static ec_slave_config_state_t sc_ana_in_state = {};
// Timer
static unsigned int sig_alarms = 0;
//static unsigned int user_alarms = 0;
/****************************************************************************/
static uint8_t *domain1_pd = NULL;
// process data
#define BusCoupler01_Pos 0, 0
#define DigOutSlave01_Pos 0, 1
#define DigOutSlave02_Pos 0, 2
#define DigInSlave01_Pos 0, 3
#define AnaOutSlave01_Pos 0, 4
#define AnaInSlave01_Pos 0, 5
#define BusCoupler02_Pos 0, 6
#define AnaInSlave02_Pos 0, 7
#define DPSlave01_Pos 0, 8
#define Beckhoff_EK1100 0x00000002, 0x044c2c52
#define Beckhoff_EL1014 0x00000002, 0x03f63052
#define Beckhoff_EL2004 0x00000002, 0x07d43052
#define Beckhoff_EL4132 0x00000002, 0x10243052
#define Beckhoff_EL3102 0x00000002, 0x0c1e3052
#define Beckhoff_EL4102 0x00000002, 0x10063052
#define Beckhoff_EL6731 0x00000002, 0x1a4b3052
#define Beckhoff_EL6600 0x00000002, 0x19c93052
#define Beckhoff_EL3602 0x00000002, 0x0e123052
#define Beckhoff_EL5151 0x00000002, 0x141f3052
// offsets for PDO entries
static unsigned int off_dig_out0 = 0;
static unsigned int off_dig_out1 = 0;
static unsigned int off_dig_out2 = 0;
static unsigned int off_dig_out3 = 0;
static unsigned int off_dig_out4 = 0;
static unsigned int off_dig_out5 = 0;
static unsigned int off_dig_out6 = 0;
static unsigned int off_dig_out7 = 0;
static unsigned int off_dig_in0 = 0;
static unsigned int off_dig_in1 = 0;
static unsigned int off_dig_in2 = 0;
static unsigned int off_dig_in3 = 0;
static unsigned int off_ana_out0 = 0;
static unsigned int off_ana_out1 = 0;
static unsigned int off_ana_in0_status = 0;
static unsigned int off_ana_in0_value = 0;
static unsigned int off_ana_in1_status = 0;
static unsigned int off_ana_in1_value = 0;
static unsigned int off_ana_in2_status = 0;
static unsigned int off_ana_in2_value = 0;
static unsigned int off_ana_in3_status = 0;
static unsigned int off_ana_in3_value = 0;
//static unsigned int off_dp_slave;
// process data
unsigned int bit_position0=0; /* Pointer to a variable to store a bit */
unsigned int bit_position1=0; /* Pointer to a variable to store a bit */
unsigned int bit_position2=0; /* Pointer to a variable to store a bit */
unsigned int bit_position3=0; /* Pointer to a variable to store a bit */
const static ec_pdo_entry_reg_t domain1_regs[] = {
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7000, 0x01, &off_dig_out0, &bit_position0},
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7010, 0x01, &off_dig_out1, &bit_position1},
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7020, 0x01, &off_dig_out2, &bit_position2},
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7030, 0x01, &off_dig_out3, &bit_position3},
{DigInSlave01_Pos, Beckhoff_EL1014, 0x6000, 0x01, &off_dig_in0},
{AnaOutSlave01_Pos, Beckhoff_EL4132, 0x3001, 0x01, &off_ana_out0},
{AnaOutSlave01_Pos, Beckhoff_EL4132, 0x3002, 0x01, &off_ana_out1},
{AnaInSlave01_Pos, Beckhoff_EL3102, 0x3101, 0x01, &off_ana_in0_status},
{AnaInSlave01_Pos, Beckhoff_EL3102, 0x3101, 0x02, &off_ana_in0_value},
{AnaInSlave01_Pos, Beckhoff_EL3102, 0x3102, 0x01, &off_ana_in1_status},
{AnaInSlave01_Pos, Beckhoff_EL3102, 0x3102, 0x02, &off_ana_in1_value},
{}
};
char rt_dev_file[64];
static unsigned int counter = 0;
static unsigned int blink = 0;
static ec_slave_config_t *sc_dig_out_01 = NULL;
static ec_slave_config_t *sc_dig_out_02 = NULL;
static ec_slave_config_t *sc_dig_in_01 = NULL;
static ec_slave_config_t *sc_ana_out_01 = NULL;
static ec_slave_config_t *sc_ana_in_01 = NULL;
static ec_slave_config_t *sc_dpslv_01 = NULL;
static ec_slave_config_t *sc_ana_in_02 = NULL;
/*****************************************************************************/
/* Slave 1, "EL2004"
* Vendor ID: 0x00000002
* Product code: 0x07d43052
* Revision number: 0x00100000
*/
ec_pdo_entry_info_t slave_1_pdo_entries[] = {
{0x7000, 0x01, 1}, /* Output */
{0x7010, 0x01, 1}, /* Output */
{0x7020, 0x01, 1}, /* Output */
{0x7030, 0x01, 1}, /* Output */
};
ec_pdo_info_t slave_1_pdos[] = {
{0x1600, 1, slave_1_pdo_entries + 0}, /* Channel 1 */
{0x1601, 1, slave_1_pdo_entries + 1}, /* Channel 2 */
{0x1602, 1, slave_1_pdo_entries + 2}, /* Channel 3 */
{0x1603, 1, slave_1_pdo_entries + 3}, /* Channel 4 */
};
ec_sync_info_t slave_1_syncs[] = {
{0, EC_DIR_OUTPUT, 4, slave_1_pdos + 0, EC_WD_ENABLE},
{0xff}
};
/* Slave 2, "EL2004"
* Vendor ID: 0x00000002
* Product code: 0x07d43052
* Revision number: 0x00100000
*/
ec_pdo_entry_info_t slave_2_pdo_entries[] = {
{0x7000, 0x01, 1}, /* Output */
{0x7010, 0x01, 1}, /* Output */
{0x7020, 0x01, 1}, /* Output */
{0x7030, 0x01, 1}, /* Output */
};
ec_pdo_info_t slave_2_pdos[] = {
{0x1600, 1, slave_2_pdo_entries + 0}, /* Channel 1 */
{0x1601, 1, slave_2_pdo_entries + 1}, /* Channel 2 */
{0x1602, 1, slave_2_pdo_entries + 2}, /* Channel 3 */
{0x1603, 1, slave_2_pdo_entries + 3}, /* Channel 4 */
};
ec_sync_info_t slave_2_syncs[] = {
{0, EC_DIR_OUTPUT, 4, slave_2_pdos + 0, EC_WD_ENABLE},
{0xff}
};
/* Slave 3, "EL1014"
* Vendor ID: 0x00000002
* Product code: 0x03f63052
* Revision number: 0x00100000
*/
ec_pdo_entry_info_t slave_3_pdo_entries[] = {
{0x6000, 0x01, 1}, /* Input */
{0x6010, 0x01, 1}, /* Input */
{0x6020, 0x01, 1}, /* Input */
{0x6030, 0x01, 1}, /* Input */
};
ec_pdo_info_t slave_3_pdos[] = {
{0x1a00, 1, slave_3_pdo_entries + 0}, /* Channel 1 */
{0x1a01, 1, slave_3_pdo_entries + 1}, /* Channel 2 */
{0x1a02, 1, slave_3_pdo_entries + 2}, /* Channel 3 */
{0x1a03, 1, slave_3_pdo_entries + 3}, /* Channel 4 */
};
ec_sync_info_t slave_3_syncs[] = {
{0, EC_DIR_INPUT, 4, slave_3_pdos + 0, EC_WD_DISABLE},
{0xff}
};
/* Slave 4, "EL4132"
* Vendor ID: 0x00000002
* Product code: 0x10243052
* Revision number: 0x03f90000
*/
ec_pdo_entry_info_t slave_4_pdo_entries[] = {
{0x3001, 0x01, 16}, /* Output */
{0x3002, 0x01, 16}, /* Output */
};
ec_pdo_info_t slave_4_pdos[] = {
{0x1600, 1, slave_4_pdo_entries + 0}, /* RxPDO 01 mapping */
{0x1601, 1, slave_4_pdo_entries + 1}, /* RxPDO 02 mapping */
};
ec_sync_info_t slave_4_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 2, slave_4_pdos + 0, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{0xff}
};
/* Slave 5, "EL3102"
* Vendor ID: 0x00000002
* Product code: 0x0c1e3052
* Revision number: 0x00000000
*/
ec_pdo_entry_info_t slave_5_pdo_entries[] = {
{0x3101, 0x01, 8}, /* Status */
{0x3101, 0x02, 16}, /* Value */
{0x3102, 0x01, 8}, /* Status */
{0x3102, 0x02, 16}, /* Value */
};
ec_pdo_info_t slave_5_pdos[] = {
{0x1a00, 2, slave_5_pdo_entries + 0}, /* TxPDO 001 mapping */
{0x1a01, 2, slave_5_pdo_entries + 2}, /* TxPDO 002 mapping */
};
ec_sync_info_t slave_5_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 2, slave_5_pdos + 0, EC_WD_DISABLE},
{0xff}
};
/* Slave 6, "EL6731-0010"
* Vendor ID: 0x00000002
* Product code: 0x1a4b3052
* Revision number: 0x0011000a
*/
ec_sync_info_t slave_6_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
};
/* Slave 7, "EL6601"
* Vendor ID: 0x00000002
* Product code: 0x19c93052
* Revision number: 0x00110000
*/
/*
ec_sync_info_t slave_7_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{0xff}
};
*/
/* Master 0, Slave 7, "EL3602"
* Vendor ID: 0x00000002
* Product code: 0x0e123052
* Revision number: 0x00100000
*/
ec_pdo_entry_info_t slave_7_pdo_entries[] = {
{0x6000, 0x01, 1}, /* Underrange */
{0x6000, 0x02, 1}, /* Overrange */
{0x6000, 0x03, 2}, /* Limit 1 */
{0x6000, 0x05, 2}, /* Limit 2 */
{0x6000, 0x07, 1}, /* Error */
{0x0000, 0x00, 7}, /* Gap */
{0x1800, 0x07, 1},
{0x1800, 0x09, 1},
{0x6000, 0x11, 32}, /* Value */
{0x6010, 0x01, 1}, /* Underrange */
{0x6010, 0x02, 1}, /* Overrange */
{0x6010, 0x03, 2}, /* Limit 1 */
{0x6010, 0x05, 2}, /* Limit 2 */
{0x6010, 0x07, 1}, /* Error */
{0x0000, 0x00, 7}, /* Gap */
{0x1801, 0x07, 1},
{0x1801, 0x09, 1},
{0x6010, 0x11, 32}, /* Value */
};
ec_pdo_info_t slave_7_pdos[] = {
{0x1a00, 9, slave_7_pdo_entries + 0}, /* AI TxPDO-Map Inputs Ch.1 */
{0x1a01, 9, slave_7_pdo_entries + 9}, /* AI TxPDO-Map Inputs Ch.2 */
};
ec_sync_info_t slave_7_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 2, slave_7_pdos + 0, EC_WD_DISABLE},
{0xff}
};
/* Master 0, Slave 8, "EL5151"
* Vendor ID: 0x00000002
* Product code: 0x141f3052
* Revision number: 0x00130000
*/
ec_pdo_entry_info_t slave_8_pdo_entries[] = {
{0x6000, 0x01, 1},
{0x6000, 0x02, 1},
{0x6000, 0x03, 1},
{0x0000, 0x00, 4}, /* Gap */
{0x6000, 0x08, 1},
{0x6000, 0x09, 1},
{0x6000, 0x0a, 1},
{0x6000, 0x0b, 1},
{0x0000, 0x00, 1}, /* Gap */
{0x6000, 0x0d, 1},
{0x1c32, 0x20, 1},
{0x0000, 0x00, 1}, /* Gap */
{0x1800, 0x09, 1},
{0x6000, 0x11, 32},
{0x6000, 0x12, 32},
{0x6000, 0x14, 32},
};
ec_pdo_info_t slave_8_pdos[] = {
{0x0000, 0, NULL},
{0x1a00, 15, slave_8_pdo_entries + 0},
{0x1a02, 1, slave_8_pdo_entries + 15},
};
ec_sync_info_t slave_8_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 1, slave_8_pdos + 0, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 2, slave_8_pdos + 1, EC_WD_DISABLE},
{0xff}
};
/*****************************************************************************/
#if SDO_ACCESS
static ec_sdo_request_t *sdo;
uint8_t *sdo_adr = NULL;
#endif
void rt_check_domain_state(void)
{
ec_domain_state_t ds;
if (rt_fd>=0)
{
ecrt_rtdm_domain_state(rt_fd,&ds);
}
if (ds.working_counter != domain1_state.working_counter)
{
rt_printf("Domain1: WC %u.\n", ds.working_counter);
}
if (ds.wc_state != domain1_state.wc_state)
{
rt_printf("Domain1: State %u.\n", ds.wc_state);
}
domain1_state = ds;
}
void rt_check_master_state(void)
{
ec_master_state_t ms;
if (rt_fd>=0)
{
ecrt_rtdm_master_state(rt_fd,&ms);
}
if (ms.slaves_responding != master_state.slaves_responding)
{
rt_printf("%u slave(s).\n", ms.slaves_responding);
}
if (ms.al_states != master_state.al_states)
{
rt_printf("AL states: 0x%02X.\n", ms.al_states);
}
if (ms.link_up != master_state.link_up)
{
rt_printf("Link is %s.\n", ms.link_up ? "up" : "down");
}
master_state = ms;
}
void rt_sync()
{
RTIME now;
now = rt_timer_read();
if (rt_fd>=0)
{
ecrt_rtdm_master_application_time(rt_fd, &now);
}
if (sync_ref_counter) {
sync_ref_counter--;
} else {
sync_ref_counter = 9;
if (rt_fd>=0)
{
ecrt_rtdm_master_sync_reference_clock(rt_fd);
}
}
if (rt_fd>=0)
{
ecrt_rtdm_master_sync_slave_clocks(rt_fd) ;
}
}
/*****************************************************************************/
#if SDO_ACCESS
void read_sdo(void)
{
switch (ecrt_sdo_request_state(sdo))
{
case EC_REQUEST_UNUSED: // request was not used yet
ecrt_sdo_request_read(sdo); // trigger first read
break;
case EC_REQUEST_BUSY:
fprintf(stderr, "Still busy...\n");
break;
case EC_REQUEST_SUCCESS:
fprintf(stderr, "SDO value: 0x%04X\n",
EC_READ_U16(ecrt_sdo_request_data(sdo)));
ecrt_sdo_request_read(sdo); // trigger next read
break;
case EC_REQUEST_ERROR:
fprintf(stderr, "Failed to read SDO!\n");
ecrt_sdo_request_read(sdo); // retry reading
break;
}
}
void PrintSDOState(void)
{
switch (ecrt_sdo_request_state(sdo))
{
case EC_REQUEST_UNUSED: // request was not used yet
fprintf(stderr, "SDO State: EC_REQUEST_UNUSED\n"); // trigger first read
break;
case EC_REQUEST_BUSY:
fprintf(stderr, "SDO State: EC_REQUEST_BUSY\n");
break;
case EC_REQUEST_SUCCESS:
fprintf(stderr, "SDO State: EC_REQUEST_SUCCESS\n");
break;
case EC_REQUEST_ERROR:
fprintf(stderr, "SDO State: EC_REQUEST_ERROR\n");
break;
default:
fprintf(stderr, "SDO State: undefined\n");
break;
}
}
#endif
static int cyccount=0;
/****************************************************************************/
void signal_handler(int signum) {
switch (signum) {
case SIGALRM:
sig_alarms++;
break;
}
}
/**********************************************************/
/* REAL TIME TASK */
/**********************************************************/
void my_task_proc(void *arg)
{
int counter = 0;
int divcounter = 0;
int divider = 10;
int ret;
RTIME periodns;
float period;
period=1E-3; //1kHz
periodns=(RTIME)(((double)period * 1E9) + 0.4999999);
rt_task_set_periodic(NULL, TM_NOW, periodns);
run=1;
ret = rt_task_set_mode(0, T_PRIMARY, NULL);
if (ret) {
rt_printf("error while rt_task_set_mode, code %d\n",ret);
return;
}
while (run) {
rt_task_wait_period(NULL);
counter++;
if (counter>600000) {
run=0;
return;
}
// receive ethercat
ecrt_rtdm_master_recieve(rt_fd);
ecrt_rtdm_domain_process(rt_fd);
rt_check_domain_state();
if (divcounter ==0)
{
divcounter=divider;
rt_check_master_state();
}
divcounter--;
if ((counter % 200)==0)
{
blink = !blink;
}
EC_WRITE_U8(domain1_pd + off_dig_out0, blink ? 0x0 : 0x0F);
EC_WRITE_U16(domain1_pd + off_ana_out0, blink ? 0x0: 0xfff);
//sync DC
rt_sync();
// send process data
ecrt_rtdm_domain_queque(rt_fd);
ecrt_rtdm_master_send(rt_fd);
}
}
/**********************************************************/
/* CLEANING UP */
/**********************************************************/
void cleanup_all(void)
{
printf("delete my_task\n");
rt_task_delete(&my_task);
if (rt_fd >= 0) {
printf("closing rt device %s\n", &rt_dev_file[0]);
rt_dev_close(rt_fd);
}
}
/****************************************************************************/
void catch_signal(int sig) {
cleanup_all();
printf("exit\n");
exit(0);
return;
}
/****************************************************************************/
int main(int argc, char **argv)
{
ec_slave_config_t *sc;
int rtstatus;
mlockall(MCL_CURRENT | MCL_FUTURE);
/* Perform auto-init of rt_print buffers if the task doesn't do so */
rt_print_auto_init(1);
signal(SIGTERM, catch_signal);
signal(SIGINT, catch_signal);
MstrAttach.masterindex = 0;
printf("request master\n");
master = ecrt_request_master(MstrAttach.masterindex);
if (!master)
return -1;
domain1 = ecrt_master_create_domain(master);
if (!domain1)
return -1;
#ifdef CONFIGURE_PDOS
printf("Configuring PDOs...\n");
printf("Get Configuring el2004...\n");
sc_dig_out_01 = ecrt_master_slave_config(master, DigOutSlave01_Pos, Beckhoff_EL2004);
if (!sc_dig_out_01) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL2004...\n");
if (ecrt_slave_config_pdos(sc_dig_out_01, EC_END, slave_1_syncs))
{
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring el2004...\n");
sc_dig_out_02 = ecrt_master_slave_config(master, DigOutSlave02_Pos, Beckhoff_EL2004);
if (!sc_dig_out_02) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL2004...\n");
if (ecrt_slave_config_pdos(sc_dig_out_02, EC_END, slave_2_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring el1014...\n");
sc_dig_in_01 = ecrt_master_slave_config(master, DigInSlave01_Pos, Beckhoff_EL1014);
if (!sc_dig_in_01) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL1014...\n");
if (ecrt_slave_config_pdos(sc_dig_in_01, EC_END, slave_3_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring EL4132...\n");
sc_ana_out_01 = ecrt_master_slave_config(master, AnaOutSlave01_Pos, Beckhoff_EL4132);
if (!sc_ana_out_01) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL4132...\n");
if (ecrt_slave_config_pdos(sc_ana_out_01, EC_END, slave_4_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring EL3102...\n");
sc_ana_in_01 = ecrt_master_slave_config(master, AnaInSlave01_Pos, Beckhoff_EL3102);
if (!sc_ana_in_01) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL3102...\n");
if (ecrt_slave_config_pdos(sc_ana_in_01, EC_END, slave_5_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring EL3602...\n");
sc_ana_in_02 = ecrt_master_slave_config(master, AnaInSlave02_Pos, Beckhoff_EL3602);
if (!sc_ana_in_02) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
// DP Slave Parameter Set
/* printf( "Creating SDO requests...\n");
if (!(sdo = ecrt_slave_config_create_sdo_request(sc_ana_in_02, 0x8000, 0x06, 1))) {
fprintf(stderr, "Failed to create SDO request.\n");
return -1;
}
ecrt_sdo_request_timeout(sdo, 500); // ms
EC_WRITE_U8(ecrt_sdo_request_data(sdo), 00);
PrintSDOState();
ecrt_sdo_request_write(sdo);
PrintSDOState();
*/
printf("Configuring EL3602...\n");
if (ecrt_slave_config_pdos(sc_ana_in_02, EC_END, slave_7_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
#endif
// Create configuration for bus coupler
sc = ecrt_master_slave_config(master, BusCoupler01_Pos, Beckhoff_EK1100);
if (!sc)
return -1;
#ifdef CONFIGURE_PDOS
if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
fprintf(stderr, "PDO entry registration failed!\n");
return -1;
}
#endif
printf("Get Configuring EL6731...\n");
sc_dpslv_01 = ecrt_master_slave_config(master, DPSlave01_Pos, Beckhoff_EL6731);
if (!sc_dpslv_01) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL6731...\n");
if (ecrt_slave_config_pdos(sc_dpslv_01, EC_END, slave_7_syncs))
{
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
#if SDO_ACCESS
// DP Slave Parameter Set
fprintf(stderr, "Creating SDO requests...\n");
if (!(sdo = ecrt_slave_config_create_sdo_request(sc_dpslv_01, 0x8000, 0, 1))) {
fprintf(stderr, "Failed to create SDO request.\n");
return -1;
}
ecrt_sdo_request_timeout(sdo, 500); // ms
EC_WRITE_U8(ecrt_sdo_request_data(sdo), 0);
PrintSDOState();
ecrt_sdo_request_write(sdo);
PrintSDOState();
// Station Address
if (!(sdo = ecrt_slave_config_create_sdo_request(sc_dpslv_01, 0x8000, 1, 2))) {
fprintf(stderr, "Failed to create SDO request.\n");
return -1;
}
ecrt_sdo_request_timeout(sdo, 500); // ms
EC_WRITE_U16(ecrt_sdo_request_data(sdo), 5);
//EC_WRITE_U8(ecrt_sdo_request_data(sdo), 00);
//EC_WRITE_U8(ecrt_sdo_request_data(sdo)+1, 10);
PrintSDOState();
ecrt_sdo_request_write(sdo);
PrintSDOState();
// Device Type (DP Ident Number)
if (!(sdo = ecrt_slave_config_create_sdo_request(sc_dpslv_01, 0x8000, 4, 4))) {
fprintf(stderr, "Failed to create SDO request.\n");
return -1;
}
ecrt_sdo_request_timeout(sdo, 500); // ms
sdo_adr = ecrt_sdo_request_data(sdo);
EC_WRITE_U32(sdo_adr, 0x095F);
//EC_WRITE_U8(sdo_ad, 0x00); // Device Type
//EC_WRITE_U8(sdo_adr+1, 0x00);
//EC_WRITE_U8(sdo_adr+2, 0x09);
//EC_WRITE_U8(sdo_adr+3, 0x5F);
PrintSDOState();
ecrt_sdo_request_write(sdo);
PrintSDOState();
// DP CfgData Slave
if (!(sdo = ecrt_slave_config_create_sdo_request(sc_dpslv_01, 0x8002, 0, 244))) {
fprintf(stderr, "Failed to create SDO request.\n");
return -1;
}
ecrt_sdo_request_timeout(sdo, 500); // ms
sdo_adr = ecrt_sdo_request_data(sdo);
EC_WRITE_U8(sdo_adr, 0x10); // Device Type
EC_WRITE_U8(sdo_adr+1, 0x20);
PrintSDOState();
ecrt_sdo_request_write(sdo);
PrintSDOState();
// DP Slave Parameter Set
if (!(sdo = ecrt_slave_config_create_sdo_request(sc_dpslv_01, 0x8000, 0, 1))) {
fprintf(stderr, "Failed to create SDO request.\n");
return -1;
}
ecrt_sdo_request_timeout(sdo, 500); // ms
EC_WRITE_U8(ecrt_sdo_request_data(sdo), 0x33); // DP Slave Parameter Set
PrintSDOState();
ecrt_sdo_request_write(sdo);
PrintSDOState();
#endif
sprintf(&rt_dev_file[0],"%s%u",EC_RTDM_DEV_FILE_NAME,0);
rt_fd = rt_dev_open( &rt_dev_file[0], 0);
if (rt_fd < 0) {
printf("can't open %s\n", &rt_dev_file[0]);
return -1;
}
MstrAttach.domainindex = ecrt_domain_index(domain1);
// attach the master over rtdm driver
rtstatus=ecrt_rtdm_master_attach(rt_fd, &MstrAttach);
if (rtstatus < 0)
{
printf("cannot attach to master over rtdm\n");
return -1;
}
printf("Activating master...\n");
if (ecrt_master_activate(master))
return -1;
if (!(domain1_pd = ecrt_domain_data(domain1))) {
return -1;
}
fprintf(stderr, "domain1_pd: 0x%.6x\n", (unsigned int)domain1_pd);
int ret;
run=1;
ret = rt_task_create(&my_task,"my_task",0,80,T_FPU);
printf("starting my_task\n");
ret = rt_task_start(&my_task,&my_task_proc,NULL);
while (run)
{
sched_yield();
}
rt_task_delete(&my_task);
if (rt_fd >= 0)
{
printf("closing rt device %s\n", &rt_dev_file[0]);
rt_dev_close(rt_fd);
}
printf("End of Program\n");
ecrt_release_master(master);
return 0;
}
/****************************************************************************/

View File

@ -0,0 +1,40 @@
#------------------------------------------------------------------------------
#
# $Id$
#
# Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
#
# This file is part of the IgH EtherCAT Master.
#
# The IgH EtherCAT Master is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
#
# The IgH EtherCAT Master is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# the IgH EtherCAT Master; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ---
#
# The license mentioned above concerns the source code only. Using the
# EtherCAT technology and brand is only permitted in compliance with the
# industrial property and similar rights of Beckhoff Automation GmbH.
#
#------------------------------------------------------------------------------
AM_CFLAGS = -Wall
noinst_PROGRAMS = ec_xenomai_posix_example
ec_xenomai_posix_example_SOURCES = main.c
ec_xenomai_posix_example_CFLAGS = -I"$(XENOMAI_DIR)"/include -D_GNU_SOURCE -D_REENTRANT -Wall -pipe -D__XENO__ -I"$(XENOMAI_DIR)"/include/posix -I$(top_srcdir)/include
ec_xenomai_posix_example_LDFLAGS = -Wl,@"$(XENOMAI_DIR)"/lib/posix.wrappers -L"$(XENOMAI_DIR)"/lib -lpthread_rt -lrtdm -L$(top_builddir)/lib/.libs -lethercat -lrtdk -lxenomai -lpthread
#------------------------------------------------------------------------------

View File

@ -0,0 +1,35 @@
-------------------------------------------------------------------------------
$Id$
-------------------------------------------------------------------------------
This is a minimal example application for the use of the EtherCAT
master realtime RTDM interface with an XENOMAI POSIX thread.
The application expects an XENOMAI installation. Configure the master sources
specifying --enable-rtdm --with-xenomai-dir to have the right include paths.
Most probably you'll have different EtherCAT slaves present. Try adjusting the
section "process data" in main.c to your bus configuration.
There are some features that can be disabled by commenting out the respective
defines at the head of main.c.
---
To build the example, call:
make
To run it, preload the EtherCAT RTDM module:
modprobe ec_rtdm
and call as root:
./ec_xenomai_posix_example
...and watch the system logs for the outputs.
-------------------------------------------------------------------------------

View File

@ -0,0 +1,768 @@
/******************************************************************************
*
* $Id$
*
* main.c Copyright (C) 2011 IgH Andreas Stewering-Bone
*
* This file is part of ethercatrtdm interface to IgH EtherCAT master
*
* The IgH EtherCAT master is free software; you can
* redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation; version 2.1
* of the License.
*
* The IgH EtherCAT Master is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* The IgH EtherCAT master userspace library is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the IgH EtherCAT master userspace library. If not, see
* <http://www.gnu.org/licenses/>.
*
* The license mentioned above concerns the source code only. Using the
* EtherCAT technology and brand is only permitted in compliance with the
* industrial property and similar rights of Beckhoff Automation GmbH.
*
*****************************************************************************/
#include <errno.h>
#include <mqueue.h>
#include <signal.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <time.h>
#include <rtdm/rtdm.h>
#include <rtdk.h>
#include "../../include/ecrt.h"
#include "../../include/ec_rtdm.h"
#define NSEC_PER_SEC 1000000000
static unsigned int cycle = 1000; /* 1 ms */
static pthread_t cyclicthread;
int rt_fd = -1;
int run=0;
unsigned int sync_ref_counter = 0;
CstructMstrAttach MstrAttach;
/****************************************************************************/
// Optional features
#define CONFIGURE_PDOS 1
/****************************************************************************/
// EtherCAT
static ec_master_t *master = NULL;
static ec_master_state_t master_state = {};
static ec_domain_t *domain1 = NULL;
static ec_domain_state_t domain1_state = {};
/****************************************************************************/
static uint8_t *domain1_pd = NULL;
// process data
#define BusCoupler01_Pos 0, 0
#define DigOutSlave01_Pos 0, 1
#define DigOutSlave02_Pos 0, 2
#define DigInSlave01_Pos 0, 3
#define AnaOutSlave01_Pos 0, 4
#define AnaInSlave01_Pos 0, 5
#define BusCoupler02_Pos 0, 6
#define AnaInSlave02_Pos 0, 7
#define Beckhoff_EK1100 0x00000002, 0x044c2c52
#define Beckhoff_EL1014 0x00000002, 0x03f63052
#define Beckhoff_EL2004 0x00000002, 0x07d43052
#define Beckhoff_EL4132 0x00000002, 0x10243052
#define Beckhoff_EL3102 0x00000002, 0x0c1e3052
#define Beckhoff_EL4102 0x00000002, 0x10063052
#define Beckhoff_EL6731 0x00000002, 0x1a4b3052
#define Beckhoff_EL6600 0x00000002, 0x19c93052
#define Beckhoff_EL3602 0x00000002, 0x0e123052
#define Beckhoff_EL5151 0x00000002, 0x141f3052
// offsets for PDO entries
static unsigned int off_dig_out0 = 0;
static unsigned int off_dig_out1 = 0;
static unsigned int off_dig_out2 = 0;
static unsigned int off_dig_out3 = 0;
static unsigned int off_dig_in0 = 0;
static unsigned int off_ana_out0 = 0;
static unsigned int off_ana_out1 = 0;
static unsigned int off_ana_in0_status = 0;
static unsigned int off_ana_in0_value = 0;
static unsigned int off_ana_in1_status = 0;
static unsigned int off_ana_in1_value = 0;
// process data
unsigned int bit_position0=0; /* Pointer to a variable to store a bit */
unsigned int bit_position1=0; /* Pointer to a variable to store a bit */
unsigned int bit_position2=0; /* Pointer to a variable to store a bit */
unsigned int bit_position3=0; /* Pointer to a variable to store a bit */
const static ec_pdo_entry_reg_t domain1_regs[] = {
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7000, 0x01, &off_dig_out0, &bit_position0},
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7010, 0x01, &off_dig_out1, &bit_position1},
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7020, 0x01, &off_dig_out2, &bit_position2},
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7030, 0x01, &off_dig_out3, &bit_position3},
{DigInSlave01_Pos, Beckhoff_EL1014, 0x6000, 0x01, &off_dig_in0},
{AnaOutSlave01_Pos, Beckhoff_EL4132, 0x3001, 0x01, &off_ana_out0},
{AnaOutSlave01_Pos, Beckhoff_EL4132, 0x3002, 0x01, &off_ana_out1},
{AnaInSlave01_Pos, Beckhoff_EL3102, 0x3101, 0x01, &off_ana_in0_status},
{AnaInSlave01_Pos, Beckhoff_EL3102, 0x3101, 0x02, &off_ana_in0_value},
{AnaInSlave01_Pos, Beckhoff_EL3102, 0x3102, 0x01, &off_ana_in1_status},
{AnaInSlave01_Pos, Beckhoff_EL3102, 0x3102, 0x02, &off_ana_in1_value},
{}
};
char rt_dev_file[64];
static unsigned int blink = 0;
static ec_slave_config_t *sc_dig_out_01 = NULL;
static ec_slave_config_t *sc_dig_out_02 = NULL;
static ec_slave_config_t *sc_dig_in_01 = NULL;
static ec_slave_config_t *sc_ana_out_01 = NULL;
static ec_slave_config_t *sc_ana_in_01 = NULL;
static ec_slave_config_t *sc_ana_in_02 = NULL;
/*****************************************************************************/
/* Slave 1, "EL2004"
* Vendor ID: 0x00000002
* Product code: 0x07d43052
* Revision number: 0x00100000
*/
ec_pdo_entry_info_t slave_1_pdo_entries[] = {
{0x7000, 0x01, 1}, /* Output */
{0x7010, 0x01, 1}, /* Output */
{0x7020, 0x01, 1}, /* Output */
{0x7030, 0x01, 1}, /* Output */
};
ec_pdo_info_t slave_1_pdos[] = {
{0x1600, 1, slave_1_pdo_entries + 0}, /* Channel 1 */
{0x1601, 1, slave_1_pdo_entries + 1}, /* Channel 2 */
{0x1602, 1, slave_1_pdo_entries + 2}, /* Channel 3 */
{0x1603, 1, slave_1_pdo_entries + 3}, /* Channel 4 */
};
ec_sync_info_t slave_1_syncs[] = {
{0, EC_DIR_OUTPUT, 4, slave_1_pdos + 0, EC_WD_ENABLE},
{0xff}
};
/* Slave 2, "EL2004"
* Vendor ID: 0x00000002
* Product code: 0x07d43052
* Revision number: 0x00100000
*/
ec_pdo_entry_info_t slave_2_pdo_entries[] = {
{0x7000, 0x01, 1}, /* Output */
{0x7010, 0x01, 1}, /* Output */
{0x7020, 0x01, 1}, /* Output */
{0x7030, 0x01, 1}, /* Output */
};
ec_pdo_info_t slave_2_pdos[] = {
{0x1600, 1, slave_2_pdo_entries + 0}, /* Channel 1 */
{0x1601, 1, slave_2_pdo_entries + 1}, /* Channel 2 */
{0x1602, 1, slave_2_pdo_entries + 2}, /* Channel 3 */
{0x1603, 1, slave_2_pdo_entries + 3}, /* Channel 4 */
};
ec_sync_info_t slave_2_syncs[] = {
{0, EC_DIR_OUTPUT, 4, slave_2_pdos + 0, EC_WD_ENABLE},
{0xff}
};
/* Slave 3, "EL1014"
* Vendor ID: 0x00000002
* Product code: 0x03f63052
* Revision number: 0x00100000
*/
ec_pdo_entry_info_t slave_3_pdo_entries[] = {
{0x6000, 0x01, 1}, /* Input */
{0x6010, 0x01, 1}, /* Input */
{0x6020, 0x01, 1}, /* Input */
{0x6030, 0x01, 1}, /* Input */
};
ec_pdo_info_t slave_3_pdos[] = {
{0x1a00, 1, slave_3_pdo_entries + 0}, /* Channel 1 */
{0x1a01, 1, slave_3_pdo_entries + 1}, /* Channel 2 */
{0x1a02, 1, slave_3_pdo_entries + 2}, /* Channel 3 */
{0x1a03, 1, slave_3_pdo_entries + 3}, /* Channel 4 */
};
ec_sync_info_t slave_3_syncs[] = {
{0, EC_DIR_INPUT, 4, slave_3_pdos + 0, EC_WD_DISABLE},
{0xff}
};
/* Slave 4, "EL4132"
* Vendor ID: 0x00000002
* Product code: 0x10243052
* Revision number: 0x03f90000
*/
ec_pdo_entry_info_t slave_4_pdo_entries[] = {
{0x3001, 0x01, 16}, /* Output */
{0x3002, 0x01, 16}, /* Output */
};
ec_pdo_info_t slave_4_pdos[] = {
{0x1600, 1, slave_4_pdo_entries + 0}, /* RxPDO 01 mapping */
{0x1601, 1, slave_4_pdo_entries + 1}, /* RxPDO 02 mapping */
};
ec_sync_info_t slave_4_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 2, slave_4_pdos + 0, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{0xff}
};
/* Slave 5, "EL3102"
* Vendor ID: 0x00000002
* Product code: 0x0c1e3052
* Revision number: 0x00000000
*/
ec_pdo_entry_info_t slave_5_pdo_entries[] = {
{0x3101, 0x01, 8}, /* Status */
{0x3101, 0x02, 16}, /* Value */
{0x3102, 0x01, 8}, /* Status */
{0x3102, 0x02, 16}, /* Value */
};
ec_pdo_info_t slave_5_pdos[] = {
{0x1a00, 2, slave_5_pdo_entries + 0}, /* TxPDO 001 mapping */
{0x1a01, 2, slave_5_pdo_entries + 2}, /* TxPDO 002 mapping */
};
ec_sync_info_t slave_5_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 2, slave_5_pdos + 0, EC_WD_DISABLE},
{0xff}
};
/* Slave 6, "EL6731-0010"
* Vendor ID: 0x00000002
* Product code: 0x1a4b3052
* Revision number: 0x0011000a
*/
ec_sync_info_t slave_6_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
};
/* Slave 7, "EL6601"
* Vendor ID: 0x00000002
* Product code: 0x19c93052
* Revision number: 0x00110000
*/
/*
ec_sync_info_t slave_7_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{0xff}
};
*/
/* Master 0, Slave 7, "EL3602"
* Vendor ID: 0x00000002
* Product code: 0x0e123052
* Revision number: 0x00100000
*/
ec_pdo_entry_info_t slave_7_pdo_entries[] = {
{0x6000, 0x01, 1}, /* Underrange */
{0x6000, 0x02, 1}, /* Overrange */
{0x6000, 0x03, 2}, /* Limit 1 */
{0x6000, 0x05, 2}, /* Limit 2 */
{0x6000, 0x07, 1}, /* Error */
{0x0000, 0x00, 7}, /* Gap */
{0x1800, 0x07, 1},
{0x1800, 0x09, 1},
{0x6000, 0x11, 32}, /* Value */
{0x6010, 0x01, 1}, /* Underrange */
{0x6010, 0x02, 1}, /* Overrange */
{0x6010, 0x03, 2}, /* Limit 1 */
{0x6010, 0x05, 2}, /* Limit 2 */
{0x6010, 0x07, 1}, /* Error */
{0x0000, 0x00, 7}, /* Gap */
{0x1801, 0x07, 1},
{0x1801, 0x09, 1},
{0x6010, 0x11, 32}, /* Value */
};
ec_pdo_info_t slave_7_pdos[] = {
{0x1a00, 9, slave_7_pdo_entries + 0}, /* AI TxPDO-Map Inputs Ch.1 */
{0x1a01, 9, slave_7_pdo_entries + 9}, /* AI TxPDO-Map Inputs Ch.2 */
};
ec_sync_info_t slave_7_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 2, slave_7_pdos + 0, EC_WD_DISABLE},
{0xff}
};
/* Master 0, Slave 8, "EL5151"
* Vendor ID: 0x00000002
* Product code: 0x141f3052
* Revision number: 0x00130000
*/
ec_pdo_entry_info_t slave_8_pdo_entries[] = {
{0x6000, 0x01, 1},
{0x6000, 0x02, 1},
{0x6000, 0x03, 1},
{0x0000, 0x00, 4}, /* Gap */
{0x6000, 0x08, 1},
{0x6000, 0x09, 1},
{0x6000, 0x0a, 1},
{0x6000, 0x0b, 1},
{0x0000, 0x00, 1}, /* Gap */
{0x6000, 0x0d, 1},
{0x1c32, 0x20, 1},
{0x0000, 0x00, 1}, /* Gap */
{0x1800, 0x09, 1},
{0x6000, 0x11, 32},
{0x6000, 0x12, 32},
{0x6000, 0x14, 32},
};
ec_pdo_info_t slave_8_pdos[] = {
{0x0000, 0, NULL},
{0x1a00, 15, slave_8_pdo_entries + 0},
{0x1a02, 1, slave_8_pdo_entries + 15},
};
ec_sync_info_t slave_8_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 1, slave_8_pdos + 0, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 2, slave_8_pdos + 1, EC_WD_DISABLE},
{0xff}
};
/*****************************************************************************/
void rt_check_domain_state(void)
{
ec_domain_state_t ds;
if (rt_fd>=0)
{
ecrt_rtdm_domain_state(rt_fd,&ds);
}
if (ds.working_counter != domain1_state.working_counter)
{
rt_printf("Domain1: WC %u.\n", ds.working_counter);
}
if (ds.wc_state != domain1_state.wc_state)
{
rt_printf("Domain1: State %u.\n", ds.wc_state);
}
domain1_state = ds;
}
void rt_check_master_state(void)
{
ec_master_state_t ms;
if (rt_fd>=0)
{
ecrt_rtdm_master_state(rt_fd,&ms);
}
if (ms.slaves_responding != master_state.slaves_responding)
{
rt_printf("%u slave(s).\n", ms.slaves_responding);
}
if (ms.al_states != master_state.al_states)
{
rt_printf("AL states: 0x%02X.\n", ms.al_states);
}
if (ms.link_up != master_state.link_up)
{
rt_printf("Link is %s.\n", ms.link_up ? "up" : "down");
}
master_state = ms;
}
void rt_sync()
{
struct timespec now;
uint64_t now_ns;
clock_gettime(CLOCK_REALTIME,&now);
now_ns = 1000000000LL*now.tv_sec + now.tv_nsec;
if (rt_fd>=0)
{
ecrt_rtdm_master_application_time(rt_fd, &now_ns);
}
if (sync_ref_counter) {
sync_ref_counter--;
} else {
sync_ref_counter = 9;
if (rt_fd>=0)
{
ecrt_rtdm_master_sync_reference_clock(rt_fd);
}
}
if (rt_fd>=0)
{
ecrt_rtdm_master_sync_slave_clocks(rt_fd) ;
}
}
/*****************************************************************************/
/**********************************************************/
void cleanup_all(void)
{
run = 0;
}
void catch_signal(int sig)
{
cleanup_all();
}
void *my_thread(void *arg)
{
struct timespec next_period;
int counter = 0;
int divcounter = 0;
int divider = 10;
clock_gettime(CLOCK_REALTIME, &next_period);
while(1) {
next_period.tv_nsec += cycle * 1000;
while (next_period.tv_nsec >= NSEC_PER_SEC) {
next_period.tv_nsec -= NSEC_PER_SEC;
next_period.tv_sec++;
}
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &next_period, NULL);
counter++;
if (counter>60000) {
run=0;
return NULL;
}
if(run == 0) {
return NULL;
}
// receive ethercat
ecrt_rtdm_master_recieve(rt_fd);
ecrt_rtdm_domain_process(rt_fd);
rt_check_domain_state();
if (divcounter ==0)
{
divcounter=divider;
rt_check_master_state();
}
divcounter--;
if ((counter % 200)==0)
{
blink = !blink;
}
EC_WRITE_U8(domain1_pd + off_dig_out0, blink ? 0x0 : 0x0F);
EC_WRITE_U16(domain1_pd + off_ana_out0, blink ? 0x0: 0xfff);
//sync DC
rt_sync();
// send process data
ecrt_rtdm_domain_queque(rt_fd);
ecrt_rtdm_master_send(rt_fd);
}
return NULL;
}
int main(int argc, char *argv[])
{
ec_slave_config_t *sc;
int rtstatus;
signal(SIGTERM, catch_signal);
signal(SIGINT, catch_signal);
signal(SIGHUP, catch_signal);
mlockall(MCL_CURRENT|MCL_FUTURE);
MstrAttach.masterindex = 0;
printf("request master\n");
master = ecrt_request_master(MstrAttach.masterindex);
if (!master)
return -1;
domain1 = ecrt_master_create_domain(master);
if (!domain1)
return -1;
#ifdef CONFIGURE_PDOS
printf("Configuring PDOs...\n");
printf("Get Configuring el2004...\n");
sc_dig_out_01 = ecrt_master_slave_config(master, DigOutSlave01_Pos, Beckhoff_EL2004);
if (!sc_dig_out_01) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL2004...\n");
if (ecrt_slave_config_pdos(sc_dig_out_01, EC_END, slave_1_syncs))
{
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring el2004...\n");
sc_dig_out_02 = ecrt_master_slave_config(master, DigOutSlave02_Pos, Beckhoff_EL2004);
if (!sc_dig_out_02) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL2004...\n");
if (ecrt_slave_config_pdos(sc_dig_out_02, EC_END, slave_2_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring el1014...\n");
sc_dig_in_01 = ecrt_master_slave_config(master, DigInSlave01_Pos, Beckhoff_EL1014);
if (!sc_dig_in_01) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL1014...\n");
if (ecrt_slave_config_pdos(sc_dig_in_01, EC_END, slave_3_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring EL4132...\n");
sc_ana_out_01 = ecrt_master_slave_config(master, AnaOutSlave01_Pos, Beckhoff_EL4132);
if (!sc_ana_out_01) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL4132...\n");
if (ecrt_slave_config_pdos(sc_ana_out_01, EC_END, slave_4_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring EL3102...\n");
sc_ana_in_01 = ecrt_master_slave_config(master, AnaInSlave01_Pos, Beckhoff_EL3102);
if (!sc_ana_in_01) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL3102...\n");
if (ecrt_slave_config_pdos(sc_ana_in_01, EC_END, slave_5_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Get Configuring EL3602...\n");
sc_ana_in_02 = ecrt_master_slave_config(master, AnaInSlave02_Pos, Beckhoff_EL3602);
if (!sc_ana_in_02) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
printf("Configuring EL3602...\n");
if (ecrt_slave_config_pdos(sc_ana_in_02, EC_END, slave_7_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
#endif
// Create configuration for bus coupler
sc = ecrt_master_slave_config(master, BusCoupler01_Pos, Beckhoff_EK1100);
if (!sc)
return -1;
#ifdef CONFIGURE_PDOS
if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
fprintf(stderr, "PDO entry registration failed!\n");
return -1;
}
#endif
sprintf(&rt_dev_file[0],"%s%u",EC_RTDM_DEV_FILE_NAME,0);
rt_fd = rt_dev_open( &rt_dev_file[0], 0);
if (rt_fd < 0) {
printf("can't open %s\n", &rt_dev_file[0]);
return -1;
}
MstrAttach.domainindex = ecrt_domain_index(domain1);
// attach the master over rtdm driver
rtstatus=ecrt_rtdm_master_attach(rt_fd, &MstrAttach);
if (rtstatus < 0)
{
printf("cannot attach to master over rtdm\n");
return -1;
}
printf("Activating master...\n");
if (ecrt_master_activate(master))
return -1;
if (!(domain1_pd = ecrt_domain_data(domain1))) {
return -1;
}
fprintf(stderr, "domain1_pd: 0x%.6x\n", (unsigned int)domain1_pd);
int ret;
run=1;
/* Create cyclic RT-thread */
struct sched_param param = { .sched_priority = 82 };
pthread_attr_t thattr;
pthread_attr_init(&thattr);
pthread_attr_setdetachstate(&thattr, PTHREAD_CREATE_JOINABLE);
pthread_attr_setinheritsched(&thattr, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setschedpolicy(&thattr, SCHED_FIFO);
pthread_setschedparam(cyclicthread, SCHED_FIFO, &param);
pthread_set_name_np(cyclicthread, "ec_xenomai_posix_test");
ret = pthread_create(&cyclicthread, &thattr, &my_thread, NULL);
if (ret) {
fprintf(stderr, "%s: pthread_create cyclic task failed\n",
strerror(-ret));
goto failure;
}
while (run)
{
sched_yield();
}
if (rt_fd >= 0)
{
printf("closing rt device %s\n", &rt_dev_file[0]);
rt_dev_close(rt_fd);
}
printf("End of Program\n");
ecrt_release_master(master);
return 0;
failure:
pthread_kill(cyclicthread, SIGHUP);
pthread_join(cyclicthread, NULL);
return 1;
}

View File

@ -33,6 +33,7 @@
include_HEADERS = \
ecrt.h \
ectty.h
ectty.h \
ec_rtdm.h
#------------------------------------------------------------------------------

78
include/ec_rtdm.h Normal file
View File

@ -0,0 +1,78 @@
/******************************************************************************
*
* $Id$
*
* ec_rtdm.h Copyright (C) 2009-2010 Moehwald GmbH B.Benner
* 2011 IgH Andreas Stewering-Bone
*
* This file is part of the IgH EtherCAT master
*
* The IgH EtherCAT master is free software; you can
* redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation; version 2.1
* of the License.
*
* The IgH EtherCAT master userspace library is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the IgH EtherCAT master userspace library. If not, see
* <http://www.gnu.org/licenses/>.
*
* The license mentioned above concerns the source code only. Using the
* EtherCAT technology and brand is only permitted in compliance with the
* industrial property and similar rights of Beckhoff Automation GmbH.
*
*****************************************************************************/
#ifndef __ECRT_RTDM_H
#define __ECRT_RTDM_H
//
// Basefilename of RTDM device
//
#define EC_RTDM_DEV_FILE_NAME "ec_rtdm"
//
// IOCTRL Values for RTDM_EXTENSION
//
// Realtime IOCTRL function
#define EC_RTDM_MSTRATTACH 1 // attach to a running master
#define EC_RTDM_MSTRGETMUTNAME 2 // return the mutexname
#define EC_RTDM_MASTER_RECEIVE 3 // call the master receive
#define EC_RTDM_DOMAIN_PROCESS 4 // process domain data
#define EC_RTDM_DOMAIN_QUEQUE 5 // prepare domain data
#define EC_RTDM_MASTER_SEND 6 // call the master send
#define EC_RTDM_DOMAINSTATE 7 // get domain state
#define EC_RTDM_MASTERSTATE 8 // get master state
#define EC_RTDM_MASTER_APP_TIME 9 // set app time
#define EC_RTDM_SYNC_REF_CLOCK 10 // sync ref clock
#define EC_RTDM_SYNC_SLAVE_CLOCK 11 // sync slave clocks
#define EC_RTDM_MASTER_SYNC_MONITOR_QUEQUE 12 // prepare DC sync information
#define EC_RTDM_MASTER_SYNC_MONITOR_PROCESS 13 // get DC sync information
typedef struct _CstructMstrAttach
{
unsigned int domainindex;
unsigned int masterindex;
} CstructMstrAttach;
#define ecrt_rtdm_master_attach(X,Y) rt_dev_ioctl(X, EC_RTDM_MSTRATTACH, Y)
#define ecrt_rtdm_master_recieve(X) rt_dev_ioctl(X, EC_RTDM_MASTER_RECEIVE)
#define ecrt_rtdm_domain_process(X) rt_dev_ioctl(X, EC_RTDM_DOMAIN_PROCESS)
#define ecrt_rtdm_domain_queque(X) rt_dev_ioctl(X, EC_RTDM_DOMAIN_QUEQUE)
#define ecrt_rtdm_master_send(X) rt_dev_ioctl(X, EC_RTDM_MASTER_SEND)
#define ecrt_rtdm_domain_state(X,Y) rt_dev_ioctl(X, EC_RTDM_DOMAINSTATE, Y)
#define ecrt_rtdm_master_state(X,Y) rt_dev_ioctl(X, EC_RTDM_MASTERSTATE, Y)
#define ecrt_rtdm_master_application_time(X,Y) rt_dev_ioctl(X, EC_RTDM_MASTER_APP_TIME, Y)
#define ecrt_rtdm_master_sync_reference_clock(X) rt_dev_ioctl(X, EC_RTDM_SYNC_REF_CLOCK)
#define ecrt_rtdm_master_sync_slave_clocks(X) rt_dev_ioctl(X, EC_RTDM_SYNC_SLAVE_CLOCK)
#define ecrt_rtdm_master_sync_monitor_queque(X) rt_dev_ioctl(X, EC_RTDM_MASTER_MONITOR_QUEQUE)
#define ecrt_rtdm_master_sync_monitor_process(X,Y) rt_dev_ioctl(X, EC_RTDM_MASTER_MONITOR_PROCESS,Y)
#endif

View File

@ -5,7 +5,7 @@
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT master userspace library.
*
*
* The IgH EtherCAT master userspace library is free software; you can
* redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation; version 2.1
@ -19,9 +19,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with the IgH EtherCAT master userspace library. If not, see
* <http://www.gnu.org/licenses/>.
*
*
* ---
*
*
* The license mentioned above concerns the source code only. Using the
* EtherCAT technology and brand is only permitted in compliance with the
* industrial property and similar rights of Beckhoff Automation GmbH.
@ -47,11 +47,9 @@
* ecrt_master_sync_slave_clocks() for offset and drift compensation. The
* EC_TIMEVAL2NANO() macro can be used for epoch time conversion, while the
* ecrt_master_sync_monitor_queue() and ecrt_master_sync_monitor_process()
* methods can be used to monitor the synchrony.
* methods can be used to monitor the synchrony.
* - Improved the callback mechanism. ecrt_master_callbacks() now takes two
* callback functions for sending and receiving datagrams.
* ecrt_master_send_ext() is used to execute the sending of non-application
* datagrams.
* callback functions for locking and unlocking the fsm datagram queue.
* - Added watchdog configuration (method ecrt_slave_config_watchdog(),
* #ec_watchdog_mode_t, \a watchdog_mode parameter in ec_sync_info_t and
* ecrt_slave_config_sync_manager()).
@ -79,6 +77,9 @@
* and ecrt_master_read_idn() and ecrt_master_write_idn() to read/write IDNs
* ad-hoc via the user-space library.
* - Added ecrt_master_reset() to initiate retrying to configure slaves.
* - Added support for overlapping PDOs which allows inputs to use the same
* space as outputs on the frame. This reduces the frame length.
*
*
* @{
*/
@ -136,6 +137,9 @@
*/
#define EC_MAX_STRING_LENGTH 64
/** Maximum number of slave ports. */
#define EC_MAX_PORTS 4
/** Timeval to nanoseconds conversion.
*
* This macro converts a Unix epoch time to EtherCAT DC time.
@ -148,7 +152,7 @@
(((TV).tv_sec - 946684800ULL) * 1000000000ULL + (TV).tv_usec * 1000ULL)
/******************************************************************************
* Data types
* Data types
*****************************************************************************/
struct ec_master;
@ -193,7 +197,7 @@ typedef struct {
/** Slave configuration state.
*
* This is used as an output parameter of ecrt_slave_config_state().
*
*
* \see ecrt_slave_config_state().
*/
typedef struct {
@ -221,12 +225,33 @@ typedef struct {
typedef struct {
unsigned int slave_count; /**< Number of slaves in the bus. */
unsigned int link_up : 1; /**< \a true, if the network link is up. */
uint8_t scan_busy; /**< \a true, while the master is scanning the bus */
uint8_t scan_busy; /**< \a true, while the master is scanning the bus */
uint64_t app_time; /**< Application time. */
} ec_master_info_t;
/*****************************************************************************/
/** EtherCAT slave port descriptor.
*/
typedef enum {
EC_PORT_NOT_IMPLEMENTED, /**< Port is not implemented. */
EC_PORT_NOT_CONFIGURED, /**< Port is not configured. */
EC_PORT_EBUS, /**< Port is an e-bus. */
EC_PORT_MII /**< Port is a mii. */
} ec_slave_port_desc_t;
/*****************************************************************************/
/** EtherCAT slave port information.
*/
typedef struct {
uint8_t link_up; /**< Link detected. */
uint8_t loop_closed; /**< Loop closed. */
uint8_t signal_detected; /**< Detected signal on RX port. */
} ec_slave_port_link_t;
/*****************************************************************************/
/** Slave information.
*
* This is used as an output parameter of ecrt_master_get_slave().
@ -241,6 +266,13 @@ typedef struct {
uint32_t serial_number; /**< Serial-Number stored on the slave. */
uint16_t alias; /**< The slaves alias if not equal to 0. */
int16_t current_on_ebus; /**< Used current in mA. */
struct {
ec_slave_port_desc_t desc;
ec_slave_port_link_t link;
uint32_t receive_time;
uint16_t next_slave;
uint32_t delay_to_next_dc;
} ports[EC_MAX_PORTS];
uint8_t al_state; /**< Current state of the slave. */
uint8_t error_flag; /**< Error flag for that slave. */
uint8_t sync_count; /**< Number of sync managers. */
@ -312,9 +344,9 @@ typedef struct {
/*****************************************************************************/
/** PDO configuration information.
*
*
* This is the data type of the \a pdos field in ec_sync_info_t.
*
*
* \see ecrt_slave_config_pdos().
*/
typedef struct {
@ -363,7 +395,7 @@ typedef struct {
uint8_t subindex; /**< PDO entry subindex. */
unsigned int *offset; /**< Pointer to a variable to store the PDO entry's
(byte-)offset in the process data. */
unsigned int *bit_position; /**< Pointer to a variable to store a bit
unsigned int *bit_position; /**< Pointer to a variable to store a bit
position (0-7) within the \a offset. Can be
NULL, in which case an error is raised if the
PDO entry does not byte-align. */
@ -409,7 +441,7 @@ extern "C" {
unsigned int ecrt_version_magic(void);
/** Requests an EtherCAT master for realtime operation.
*
*
* Before an application can access an EtherCAT master, it has to reserve one
* for exclusive use.
*
@ -455,6 +487,23 @@ void ecrt_release_master(
ec_master_t *master /**< EtherCAT master */
);
#ifdef __KERNEL__
/** Attach to a running master
*
* This function returns the master handle for the RTDM-Interface
*
* \return Pointer to the opened master, otherwise \a NULL.
*/
ec_master_t *ecrt_attach_master(
unsigned int master_index /**< Index of the master to request. */
);
#endif // #ifdef __KERNEL__
/******************************************************************************
* Master methods
*****************************************************************************/
@ -479,29 +528,50 @@ int ecrt_master_reserve(
/** Sets the locking callbacks.
*
* For concurrent master access, i. e. if other instances than the application
* want to send and receive datagrams on the bus, the application has to
* provide a callback mechanism. This method takes two function pointers as
* its parameters. Asynchronous master access (like EoE processing) is only
* possible if the callbacks have been set.
* For concurrent master access, the application has to provide a locking
* mechanism. The method takes two function pointers and a data value as
* its parameters.
* The arbitrary \a cb_data value will be passed as argument on every callback.
*
* The task of the send callback (\a send_cb) is to decide, if the bus is
* currently accessible and whether or not to call the ecrt_master_send_ext()
* method.
*
* The task of the receive callback (\a receive_cb) is to decide, if a call to
* ecrt_master_receive() is allowed and to execute it respectively.
*/
void ecrt_master_callbacks(
ec_master_t *master, /**< EtherCAT master */
void (*send_cb)(void *), /**< Datagram sending callback. */
void (*receive_cb)(void *), /**< Receive callback. */
void *cb_data /**< Arbitraty pointer passed to the callback functions.
*/
void (*lock_cb)(void *), /**< Lock function. */
void (*unlock_cb)(void *), /**< Unlock function. */
void *cb_data /**< Arbitrary user data. */
);
/** Returns domain structure pointer
*
* This functions return the domain structure pointer for usage inside the
* RTDM-Interface.
*
* \return Pointer to the domain on success, else NULL.
*/
ec_domain_t *ecrt_master_find_domain(
ec_master_t *master,
unsigned int index);
#endif /* __KERNEL__ */
#ifndef __KERNEL__
/** Return the domain index of a given domain strucure
*
* Return the domain index of a given domain strucure. Usage inside of the
* RTDM Interface
*
* \return Index of the domain strucure
*
*/
unsigned int ecrt_domain_index(
ec_domain_t *domain
);
#endif // #ifndef __KERNEL__
/** Creates a new process data domain.
*
* For process data exchange, at least one process data domain is needed.
@ -515,6 +585,7 @@ ec_domain_t *ecrt_master_create_domain(
ec_master_t *master /**< EtherCAT master. */
);
/** Obtains a slave configuration.
*
* Creates a slave configuration object for the given \a alias and \a position
@ -784,15 +855,6 @@ void ecrt_master_receive(
ec_master_t *master /**< EtherCAT master. */
);
/** Sends non-application datagrams.
*
* This method has to be called in the send callback function passed via
* ecrt_master_callbacks() to allow the sending of non-application datagrams.
*/
void ecrt_master_send_ext(
ec_master_t *master /**< EtherCAT master. */
);
/** Reads the current master state.
*
* Stores the master state information in the given \a state structure.
@ -802,17 +864,29 @@ void ecrt_master_state(
ec_master_state_t *state /**< Structure to store the information. */
);
/** Reads the current master state and the al_state of all configured slaves.
*
* use this function instead of ecrt_master_state if there are unused
* slaves on the bus
* Stores the master state information in the given \a state structure.
* \see ecrt_master_state()
*/
void ecrt_master_configured_slaves_state(
const ec_master_t *master, /**< EtherCAT master. */
ec_master_state_t *state /**< Structure to store the information. */
);
/** Sets the application time.
*
* The master has to know the application's time when operating slaves with
* distributed clocks. The time is not incremented by the master itself, so
* this method has to be called cyclically.
*
*
* The time is used when setting the slaves' <tt>System Time Offset</tt> and
* <tt>Cyclic Operation Start Time</tt> registers and when synchronizing the
* DC reference clock to the application time via
* ecrt_master_sync_reference_clock().
*
*
* The time is defined as nanoseconds from 2000-01-01 00:00. Converting an
* epoch time can be done with the EC_TIMEVAL2NANO() macro.
*/
@ -904,6 +978,17 @@ void ecrt_slave_config_watchdog(
*/
);
/** Configure wether a slave allows overlapping PDOs.
*
* Overlapping PDOs allows inputs to use the same space as outputs on the frame.
* This reduces the frame length.
*/
void ecrt_slave_config_overlapping_pdos(
ec_slave_config_t *sc, /**< Slave configuration. */
uint8_t allow_overlapping_pdos /**< Allow overlapping PDOs */
);
/** Add a PDO to a sync manager's PDO assignment.
*
* \see ecrt_slave_config_pdos()
@ -921,7 +1006,7 @@ int ecrt_slave_config_pdo_assign_add(
* This can be called before assigning PDOs via
* ecrt_slave_config_pdo_assign_add(), to clear the default assignment of a
* sync manager.
*
*
* \see ecrt_slave_config_pdos()
*/
void ecrt_slave_config_pdo_assign_clear(
@ -975,28 +1060,28 @@ void ecrt_slave_config_pdo_mapping_clear(
* {0x3101, 1, 8}, // status
* {0x3101, 2, 16} // value
* };
*
*
* ec_pdo_entry_info_t el3162_channel2[] = {
* {0x3102, 1, 8}, // status
* {0x3102, 2, 16} // value
* };
*
*
* ec_pdo_info_t el3162_pdos[] = {
* {0x1A00, 2, el3162_channel1},
* {0x1A01, 2, el3162_channel2}
* };
*
*
* ec_sync_info_t el3162_syncs[] = {
* {2, EC_DIR_OUTPUT},
* {3, EC_DIR_INPUT, 2, el3162_pdos},
* {0xff}
* };
*
*
* if (ecrt_slave_config_pdos(sc_ana_in, EC_END, el3162_syncs)) {
* // handle error
* }
* \endcode
*
*
* The next example shows, how to configure the PDO assignment only. The
* entries for each assigned PDO are taken from the PDO's default mapping.
* Please note, that PDO entry registration will fail, if the PDO
@ -1007,11 +1092,11 @@ void ecrt_slave_config_pdo_mapping_clear(
* {0x1600}, // Channel 1
* {0x1601} // Channel 2
* };
*
*
* ec_sync_info_t syncs[] = {
* {3, EC_DIR_INPUT, 2, pdos},
* };
*
*
* if (ecrt_slave_config_pdos(slave_config_ana_in, 1, syncs)) {
* // handle error
* }
@ -1053,7 +1138,7 @@ int ecrt_slave_config_reg_pdo_entry(
uint16_t entry_index, /**< Index of the PDO entry to register. */
uint8_t entry_subindex, /**< Subindex of the PDO entry to register. */
ec_domain_t *domain, /**< Domain. */
unsigned int *bit_position /**< Optional address if bit addressing
unsigned int *bit_position /**< Optional address if bit addressing
is desired */
);

View File

@ -52,6 +52,13 @@ void ec_domain_clear(ec_domain_t *domain)
// nothing to do
}
/*****************************************************************************/
unsigned int ecrt_domain_index(ec_domain_t *domain)
{
return domain->index;
}
/*****************************************************************************/
int ecrt_domain_reg_pdo_entry_list(ec_domain_t *domain,

View File

@ -1,11 +1,11 @@
/******************************************************************************
*
*
* $Id$
*
*
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
*
*
* This file is part of the IgH EtherCAT master userspace library.
*
*
* The IgH EtherCAT master userspace library is free software; you can
* redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation; version 2.1
@ -19,9 +19,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with the IgH EtherCAT master userspace library. If not, see
* <http://www.gnu.org/licenses/>.
*
*
* ---
*
*
* The license mentioned above concerns the source code only. Using the
* EtherCAT technology and brand is only permitted in compliance with the
* industrial property and similar rights of Beckhoff Automation GmbH.
@ -118,12 +118,12 @@ ec_domain_t *ecrt_master_create_domain(ec_master_t *master)
fprintf(stderr, "Failed to allocate memory.\n");
return 0;
}
index = ioctl(master->fd, EC_IOCTL_CREATE_DOMAIN, NULL);
if (index == -1) {
fprintf(stderr, "Failed to create domain: %s\n", strerror(errno));
free(domain);
return 0;
return 0;
}
domain->next = NULL;
@ -166,17 +166,17 @@ ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
fprintf(stderr, "Failed to allocate memory.\n");
return 0;
}
data.alias = alias;
data.position = position;
data.vendor_id = vendor_id;
data.product_code = product_code;
if (ioctl(master->fd, EC_IOCTL_CREATE_SLAVE_CONFIG, &data) == -1) {
fprintf(stderr, "Failed to create slave config: %s\n",
strerror(errno));
free(sc);
return 0;
return 0;
}
sc->next = NULL;
@ -216,7 +216,7 @@ int ecrt_master_get_slave(ec_master_t *master, uint16_t slave_position,
ec_slave_info_t *slave_info)
{
ec_ioctl_slave_t data;
int index;
int index, i;
data.position = slave_position;
@ -232,6 +232,15 @@ int ecrt_master_get_slave(ec_master_t *master, uint16_t slave_position,
slave_info->serial_number = data.serial_number;
slave_info->alias = data.alias;
slave_info->current_on_ebus = data.current_on_ebus;
for ( i = 0; i < EC_MAX_PORTS; i++ ) {
slave_info->ports[i].desc = data.ports[i].desc;
slave_info->ports[i].link.link_up = data.ports[i].link.link_up;
slave_info->ports[i].link.loop_closed = data.ports[i].link.loop_closed;
slave_info->ports[i].link.signal_detected = data.ports[i].link.signal_detected;
slave_info->ports[i].receive_time = data.ports[i].receive_time;
slave_info->ports[i].next_slave = data.ports[i].next_slave;
slave_info->ports[i].delay_to_next_dc = data.ports[i].delay_to_next_dc;
}
slave_info->al_state = data.al_state;
slave_info->error_flag = data.error_flag;
slave_info->sync_count = data.sync_count;
@ -455,7 +464,7 @@ int ecrt_master_activate(ec_master_t *master)
}
// Access the mapped region to cause the initial page fault
master->process_data[0] = 0x00;
memset(master->process_data, 0, master->process_data_size);
}
return 0;
@ -515,6 +524,16 @@ void ecrt_master_state(const ec_master_t *master, ec_master_state_t *state)
/*****************************************************************************/
void ecrt_master_configured_slaves_state(const ec_master_t *master,
ec_master_state_t *state)
{
if (ioctl(master->fd, EC_IOCTL_MASTER_SC_STATE, state) == -1) {
fprintf(stderr, "Failed to get master state: %s\n", strerror(errno));
}
}
/*****************************************************************************/
void ecrt_master_application_time(ec_master_t *master, uint64_t app_time)
{
ec_ioctl_app_time_t data;

View File

@ -110,6 +110,23 @@ void ecrt_slave_config_watchdog(ec_slave_config_t *sc,
/*****************************************************************************/
void ecrt_slave_config_overlapping_pdos(ec_slave_config_t *sc,
uint8_t allow_overlapping_pdos)
{
ec_ioctl_config_t data;
memset(&data, 0x00, sizeof(ec_ioctl_config_t));
data.config_index = sc->index;
data.allow_overlapping_pdos = allow_overlapping_pdos;
if (ioctl(sc->master->fd, EC_IOCTL_SC_OVERLAPPING_IO, &data) == -1) {
fprintf(stderr, "Failed to config overlapping PDOs: %s\n",
strerror(errno));
}
}
/*****************************************************************************/
int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc,
uint8_t sync_index, uint16_t pdo_index)
{
@ -415,7 +432,7 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(ec_slave_config_t *sc,
if (size) {
req->data = malloc(size);
if (!req->data) {
fprintf(stderr, "Failed to allocate %u bytes of SDO data"
fprintf(stderr, "Failed to allocate %zu bytes of SDO data"
" memory.\n", size);
free(req);
return 0;
@ -484,7 +501,7 @@ ec_voe_handler_t *ecrt_slave_config_create_voe_handler(ec_slave_config_t *sc,
if (size) {
voe->data = malloc(size);
if (!voe->data) {
fprintf(stderr, "Failed to allocate %u bytes of VoE data"
fprintf(stderr, "Failed to allocate %zu bytes of VoE data"
" memory.\n", size);
free(voe);
return 0;

File diff suppressed because it is too large Load Diff

View File

@ -87,13 +87,17 @@ static const char *type_strings[] = {
*/
void ec_datagram_init(ec_datagram_t *datagram /**< EtherCAT datagram. */)
{
INIT_LIST_HEAD(&datagram->list); // mark as unqueued
INIT_LIST_HEAD(&datagram->queue); // mark as unqueued
INIT_LIST_HEAD(&datagram->fsm_queue); // mark as unqueued
INIT_LIST_HEAD(&datagram->sent); // mark as unqueued
datagram->type = EC_DATAGRAM_NONE;
memset(datagram->address, 0x00, EC_ADDR_LEN);
datagram->data = NULL;
datagram->data_origin = EC_ORIG_INTERNAL;
datagram->mem_size = 0;
datagram->data_size = 0;
datagram->domain = NULL;
datagram->index = 0x00;
datagram->working_counter = 0x0000;
datagram->state = EC_DATAGRAM_INIT;
@ -130,6 +134,9 @@ void ec_datagram_clear(ec_datagram_t *datagram /**< EtherCAT datagram. */)
*/
void ec_datagram_unqueue(ec_datagram_t *datagram /**< EtherCAT datagram. */)
{
if (!list_empty(&datagram->fsm_queue)) {
list_del_init(&datagram->fsm_queue);
}
if (!list_empty(&datagram->queue)) {
list_del_init(&datagram->queue);
}

View File

@ -86,7 +86,8 @@ typedef enum {
*/
typedef struct {
struct list_head list; /**< Needed by domain datagram lists. */
struct list_head queue; /**< Master datagram queue item. */
struct list_head queue; /**< Master datagram send-receive queue item. */
struct list_head fsm_queue; /**< Master datagram fsm queue item. */
struct list_head sent; /**< Master list item for sent datagrams. */
ec_datagram_type_t type; /**< Datagram type (APRD, BWR, etc.). */
uint8_t address[EC_ADDR_LEN]; /**< Recipient address. */
@ -94,6 +95,7 @@ typedef struct {
ec_origin_t data_origin; /**< Origin of the \a data memory. */
size_t mem_size; /**< Datagram \a data memory size. */
size_t data_size; /**< Size of the data in \a data. */
ec_domain_t *domain; /**< Owning domain (may be null for non-domain datagrams) */
uint8_t index; /**< Index (set by master). */
uint16_t working_counter; /**< Working counter. */
ec_datagram_state_t state; /**< State. */

View File

@ -501,9 +501,9 @@ void ecdev_withdraw(ec_device_t *device /**< EtherCAT device */)
ec_mac_print(device->dev->dev_addr, str);
EC_MASTER_INFO(master, "Releasing main device %s.\n", str);
down(&master->device_sem);
ec_mutex_lock(&master->device_mutex);
ec_device_detach(device);
up(&master->device_sem);
ec_mutex_unlock(&master->device_mutex);
}
/*****************************************************************************/

View File

@ -60,6 +60,7 @@ void ec_domain_init(
domain->index = index;
INIT_LIST_HEAD(&domain->fmmu_configs);
domain->data_size = 0;
domain->tx_size = 0;
domain->data = NULL;
domain->data_origin = EC_ORIG_INTERNAL;
domain->logical_base_address = 0x00000000;
@ -113,6 +114,7 @@ void ec_domain_add_fmmu_config(
fmmu->domain = domain;
domain->data_size += fmmu->data_size;
domain->tx_size += fmmu->tx_size;
list_add_tail(&fmmu->list, &domain->fmmu_configs);
EC_MASTER_DBG(domain->master, 1, "Domain %u:"
@ -179,6 +181,7 @@ int ec_domain_add_datagram(
ec_datagram_zero(datagram);
list_add_tail(&datagram->list, &domain->datagrams);
datagram->domain = domain;
return 0;
}
@ -238,6 +241,7 @@ int ec_domain_finish(
list_for_each_entry(fmmu, &domain->fmmu_configs, list) {
// Correct logical FMMU address
fmmu->logical_start_address += base_address;
fmmu->domain_address += base_address;
// Increment Input/Output counter to determine datagram types
// and calculate expected working counters
@ -249,7 +253,7 @@ int ec_domain_finish(
// If the current FMMU's data do not fit in the current datagram,
// allocate a new one.
if (datagram_size + fmmu->data_size > EC_MAX_DATA_SIZE) {
if (datagram_size + fmmu->tx_size > EC_MAX_DATA_SIZE) {
ret = ec_domain_add_datagram(domain,
domain->logical_base_address + datagram_offset,
datagram_size, domain->data + datagram_offset,
@ -267,7 +271,7 @@ int ec_domain_finish(
}
}
datagram_size += fmmu->data_size;
datagram_size += fmmu->tx_size;
}
// Allocate last datagram, if data are left (this is also the case if the
@ -377,14 +381,14 @@ void ecrt_domain_external_memory(ec_domain_t *domain, uint8_t *mem)
EC_MASTER_DBG(domain->master, 1, "ecrt_domain_external_memory("
"domain = 0x%p, mem = 0x%p)\n", domain, mem);
down(&domain->master->master_sem);
ec_mutex_lock(&domain->master->master_mutex);
ec_domain_clear_data(domain);
domain->data = mem;
domain->data_origin = EC_ORIG_EXTERNAL;
up(&domain->master->master_sem);
ec_mutex_unlock(&domain->master->master_mutex);
}
/*****************************************************************************/

View File

@ -59,6 +59,7 @@ struct ec_domain
struct list_head fmmu_configs; /**< FMMU configurations contained. */
size_t data_size; /**< Size of the process data. */
size_t tx_size; /**< Size of the transmitted data. */
uint8_t *data; /**< Memory for the process data. */
ec_origin_t data_origin; /**< Origin of the \a data memory. */
uint32_t logical_base_address; /**< Logical offset address of the

View File

@ -111,6 +111,7 @@ int ec_eoe_init(
eoe->slave = slave;
ec_datagram_init(&eoe->datagram);
ec_mbox_init(&eoe->mbox,&eoe->datagram);
eoe->queue_datagram = 0;
eoe->state = ec_eoe_state_rx_start;
eoe->opened = 0;
@ -122,7 +123,7 @@ int ec_eoe_init(
eoe->tx_queue_size = EC_EOE_TX_QUEUE_SIZE;
eoe->tx_queued_frames = 0;
sema_init(&eoe->tx_queue_sem, 1);
ec_mutex_init(&eoe->tx_queue_mutex);
eoe->tx_frame_number = 0xFF;
memset(&eoe->stats, 0, sizeof(struct net_device_stats));
@ -220,6 +221,7 @@ void ec_eoe_clear(ec_eoe_t *eoe /**< EoE handler */)
free_netdev(eoe->dev);
ec_mbox_clear(&eoe->mbox);
ec_datagram_clear(&eoe->datagram);
}
@ -231,7 +233,7 @@ void ec_eoe_flush(ec_eoe_t *eoe /**< EoE handler */)
{
ec_eoe_frame_t *frame, *next;
down(&eoe->tx_queue_sem);
ec_mutex_lock(&eoe->tx_queue_mutex);
list_for_each_entry_safe(frame, next, &eoe->tx_queue, queue) {
list_del(&frame->queue);
@ -240,7 +242,7 @@ void ec_eoe_flush(ec_eoe_t *eoe /**< EoE handler */)
}
eoe->tx_queued_frames = 0;
up(&eoe->tx_queue_sem);
ec_mutex_unlock(&eoe->tx_queue_mutex);
}
/*****************************************************************************/
@ -294,7 +296,7 @@ int ec_eoe_send(ec_eoe_t *eoe /**< EoE handler */)
printk("\n");
#endif
data = ec_slave_mbox_prepare_send(eoe->slave, &eoe->datagram,
data = ec_slave_mbox_prepare_send(eoe->slave, &eoe->mbox,
0x02, current_size + 4);
if (IS_ERR(data))
return PTR_ERR(data);
@ -323,7 +325,9 @@ void ec_eoe_run(ec_eoe_t *eoe /**< EoE handler */)
return;
// if the datagram was not sent, or is not yet received, skip this cycle
if (eoe->queue_datagram || eoe->datagram.state == EC_DATAGRAM_SENT)
if (eoe->queue_datagram ||
ec_mbox_is_datagram_state(&eoe->mbox,EC_DATAGRAM_QUEUED) ||
ec_mbox_is_datagram_state(&eoe->mbox,EC_DATAGRAM_SENT))
return;
// call state function
@ -348,7 +352,7 @@ void ec_eoe_run(ec_eoe_t *eoe /**< EoE handler */)
void ec_eoe_queue(ec_eoe_t *eoe /**< EoE handler */)
{
if (eoe->queue_datagram) {
ec_master_queue_datagram_ext(eoe->slave->master, &eoe->datagram);
ec_master_mbox_queue_datagrams(eoe->slave->master, &eoe->mbox);
eoe->queue_datagram = 0;
}
}
@ -394,7 +398,7 @@ void ec_eoe_state_rx_start(ec_eoe_t *eoe /**< EoE handler */)
return;
}
ec_slave_mbox_prepare_check(eoe->slave, &eoe->datagram);
ec_slave_mbox_prepare_check(eoe->slave, &eoe->mbox);
eoe->queue_datagram = 1;
eoe->state = ec_eoe_state_rx_check;
}
@ -408,7 +412,7 @@ void ec_eoe_state_rx_start(ec_eoe_t *eoe /**< EoE handler */)
*/
void ec_eoe_state_rx_check(ec_eoe_t *eoe /**< EoE handler */)
{
if (eoe->datagram.state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(&eoe->mbox,EC_DATAGRAM_RECEIVED)) {
eoe->stats.rx_errors++;
#if EOE_DEBUG_LEVEL >= 1
EC_SLAVE_WARN(eoe->slave, "Failed to receive mbox"
@ -418,14 +422,14 @@ void ec_eoe_state_rx_check(ec_eoe_t *eoe /**< EoE handler */)
return;
}
if (!ec_slave_mbox_check(&eoe->datagram)) {
if (!ec_slave_mbox_check(&eoe->mbox)) {
eoe->rx_idle = 1;
eoe->state = ec_eoe_state_tx_start;
return;
}
eoe->rx_idle = 0;
ec_slave_mbox_prepare_fetch(eoe->slave, &eoe->datagram);
ec_slave_mbox_prepare_fetch(eoe->slave, &eoe->mbox);
eoe->queue_datagram = 1;
eoe->state = ec_eoe_state_rx_fetch;
}
@ -447,7 +451,7 @@ void ec_eoe_state_rx_fetch(ec_eoe_t *eoe /**< EoE handler */)
unsigned int i;
#endif
if (eoe->datagram.state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(&eoe->mbox,EC_DATAGRAM_RECEIVED)) {
eoe->stats.rx_errors++;
#if EOE_DEBUG_LEVEL >= 1
EC_SLAVE_WARN(eoe->slave, "Failed to receive mbox"
@ -457,7 +461,7 @@ void ec_eoe_state_rx_fetch(ec_eoe_t *eoe /**< EoE handler */)
return;
}
data = ec_slave_mbox_fetch(eoe->slave, &eoe->datagram,
data = ec_slave_mbox_fetch(eoe->slave, &eoe->mbox,
&mbox_prot, &rec_size);
if (IS_ERR(data)) {
eoe->stats.rx_errors++;
@ -620,10 +624,10 @@ void ec_eoe_state_tx_start(ec_eoe_t *eoe /**< EoE handler */)
return;
}
down(&eoe->tx_queue_sem);
ec_mutex_lock(&eoe->tx_queue_mutex);
if (!eoe->tx_queued_frames || list_empty(&eoe->tx_queue)) {
up(&eoe->tx_queue_sem);
ec_mutex_unlock(&eoe->tx_queue_mutex);
eoe->tx_idle = 1;
// no data available.
// start a new receive immediately.
@ -644,7 +648,7 @@ void ec_eoe_state_tx_start(ec_eoe_t *eoe /**< EoE handler */)
}
eoe->tx_queued_frames--;
up(&eoe->tx_queue_sem);
ec_mutex_unlock(&eoe->tx_queue_mutex);
eoe->tx_idle = 0;
@ -684,7 +688,7 @@ void ec_eoe_state_tx_start(ec_eoe_t *eoe /**< EoE handler */)
*/
void ec_eoe_state_tx_sent(ec_eoe_t *eoe /**< EoE handler */)
{
if (eoe->datagram.state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(&eoe->mbox,EC_DATAGRAM_RECEIVED)) {
if (eoe->tries) {
eoe->tries--; // try again
eoe->queue_datagram = 1;
@ -700,7 +704,7 @@ void ec_eoe_state_tx_sent(ec_eoe_t *eoe /**< EoE handler */)
return;
}
if (eoe->datagram.working_counter != 1) {
if (!ec_mbox_is_datagram_wc(&eoe->mbox,1)) {
if (eoe->tries) {
eoe->tries--; // try again
eoe->queue_datagram = 1;
@ -812,14 +816,14 @@ int ec_eoedev_tx(struct sk_buff *skb, /**< transmit socket buffer */
frame->skb = skb;
down(&eoe->tx_queue_sem);
ec_mutex_lock(&eoe->tx_queue_mutex);
list_add_tail(&frame->queue, &eoe->tx_queue);
eoe->tx_queued_frames++;
if (eoe->tx_queued_frames == eoe->tx_queue_size) {
netif_stop_queue(dev);
eoe->tx_queue_active = 0;
}
up(&eoe->tx_queue_sem);
ec_mutex_unlock(&eoe->tx_queue_mutex);
#if EOE_DEBUG_LEVEL >= 2
EC_SLAVE_DBG(eoe->slave, 0, "EoE %s TX queued frame"

View File

@ -73,6 +73,7 @@ struct ec_eoe
struct list_head list; /**< list item */
ec_slave_t *slave; /**< pointer to the corresponding slave */
ec_datagram_t datagram; /**< datagram */
ec_mailbox_t mbox; /**< mailbox */
unsigned int queue_datagram; /**< the datagram is ready for queuing */
void (*state)(ec_eoe_t *); /**< state function for the state machine */
struct net_device *dev; /**< net_device for virtual ethernet device */
@ -92,7 +93,7 @@ struct ec_eoe
unsigned int tx_queue_size; /**< Transmit queue size. */
unsigned int tx_queue_active; /**< kernel netif queue started */
unsigned int tx_queued_frames; /**< number of frames in the queue */
struct semaphore tx_queue_sem; /**< Semaphore for the send queue. */
struct ec_mutex_t tx_queue_mutex; /**< Mutex for the send queue. */
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 */

View File

@ -43,14 +43,12 @@
/** FMMU configuration constructor.
*
* Inits an FMMU configuration, sets the logical start address and adds the
* process data size for the mapped PDOs of the given direction to the domain
* data size.
* Inits an FMMU configuration and the process data size forthe mapped PDOs
* of the given direction to the domain data size.
*/
void ec_fmmu_config_init(
ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */
ec_slave_config_t *sc, /**< EtherCAT slave configuration. */
ec_domain_t *domain, /**< EtherCAT domain. */
uint8_t sync_index, /**< Sync manager index to use. */
ec_direction_t dir /**< PDO direction. */
)
@ -59,14 +57,32 @@ void ec_fmmu_config_init(
fmmu->sc = sc;
fmmu->sync_index = sync_index;
fmmu->dir = dir;
fmmu->logical_start_address = domain->data_size;
fmmu->data_size = ec_pdo_list_total_size(
&sc->sync_configs[sync_index].pdos);
}
/*****************************************************************************/
/** Sets FMMU domain
*
* Sets the logical start address and the size of the transmitted data
*/
void ec_fmmu_config_domain(
ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */
ec_domain_t *domain, /**< EtherCAT domain. */
uint32_t logical_start_address, /**< FMMU logical start address. */
size_t tx_size /**< Size of transmitted data */
)
{
fmmu->domain = domain;
fmmu->domain_address = domain->data_size;
fmmu->logical_start_address = logical_start_address;
fmmu->tx_size = tx_size;
ec_domain_add_fmmu_config(domain, fmmu);
}
/*****************************************************************************/
/** Initializes an FMMU configuration page.
@ -79,9 +95,11 @@ void ec_fmmu_config_page(
uint8_t *data /**> Configuration page memory. */
)
{
EC_CONFIG_DBG(fmmu->sc, 1, "FMMU: LogAddr 0x%08X, Size %3u,"
EC_CONFIG_DBG(fmmu->sc, 1, "FMMU: LogAddr 0x%08X, DomAddr 0x%08X,"
" Size %3u, Tx %3u"
" PhysAddr 0x%04X, SM%u, Dir %s\n",
fmmu->logical_start_address, fmmu->data_size,
fmmu->logical_start_address, fmmu->domain_address,
fmmu->data_size, fmmu->data_size,
sync->physical_start_address, fmmu->sync_index,
fmmu->dir == EC_DIR_INPUT ? "in" : "out");

View File

@ -50,13 +50,18 @@ typedef struct {
uint8_t sync_index; /**< Index of sync manager to use. */
ec_direction_t dir; /**< FMMU direction. */
uint32_t logical_start_address; /**< Logical start address. */
size_t tx_size; /**< Transmitted (bus) size. */
uint32_t domain_address; /** Domain start address */
unsigned int data_size; /**< Covered PDO size. */
} ec_fmmu_config_t;
/*****************************************************************************/
void ec_fmmu_config_init(ec_fmmu_config_t *, ec_slave_config_t *,
ec_domain_t *, uint8_t, ec_direction_t);
uint8_t, ec_direction_t);
void ec_fmmu_config_domain(ec_fmmu_config_t *, ec_domain_t *,
uint32_t , size_t);
void ec_fmmu_config_page(const ec_fmmu_config_t *, const ec_sync_t *,
uint8_t *);

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,7 @@
#include "globals.h"
#include "datagram.h"
#include "mailbox.h"
#include "slave.h"
#include "sdo.h"
#include "sdo_request.h"
@ -51,7 +52,7 @@ typedef struct ec_fsm_coe ec_fsm_coe_t; /**< \see ec_fsm_coe */
*/
struct ec_fsm_coe {
ec_slave_t *slave; /**< slave the FSM runs on */
ec_datagram_t *datagram; /**< datagram used in the state machine */
ec_mailbox_t *mbox; /**< mailbox used in the state machine */
unsigned int retries; /**< retries upon datagram timeout */
void (*state)(ec_fsm_coe_t *); /**< CoE state function */
@ -67,7 +68,7 @@ struct ec_fsm_coe {
/*****************************************************************************/
void ec_fsm_coe_init(ec_fsm_coe_t *, ec_datagram_t *);
void ec_fsm_coe_init(ec_fsm_coe_t *, ec_mailbox_t *);
void ec_fsm_coe_clear(ec_fsm_coe_t *);
void ec_fsm_coe_dictionary(ec_fsm_coe_t *, ec_slave_t *);

View File

@ -107,11 +107,11 @@ void ec_fsm_foe_read_start(ec_fsm_foe_t *);
/** Constructor.
*/
void ec_fsm_foe_init(ec_fsm_foe_t *fsm, /**< finite state machine */
ec_datagram_t *datagram /**< datagram */
ec_mailbox_t *mbox /**< mailbox */
)
{
fsm->state = NULL;
fsm->datagram = datagram;
fsm->state = NULL;
fsm->mbox = mbox;
}
/*****************************************************************************/
@ -207,7 +207,7 @@ int ec_foe_prepare_data_send(ec_fsm_foe_t *fsm)
}
data = ec_slave_mbox_prepare_send(fsm->slave,
fsm->datagram, EC_MBOX_TYPE_FILEACCESS,
fsm->mbox,EC_MBOX_TYPE_FILEACCESS,
current_size + EC_FOE_HEADER_SIZE);
if (IS_ERR(data))
return -1;
@ -238,7 +238,7 @@ int ec_foe_prepare_wrq_send(ec_fsm_foe_t *fsm)
current_size = fsm->tx_filename_len;
data = ec_slave_mbox_prepare_send(fsm->slave, fsm->datagram,
data = ec_slave_mbox_prepare_send(fsm->slave, fsm->mbox,
EC_MBOX_TYPE_FILEACCESS, current_size + EC_FOE_HEADER_SIZE);
if (IS_ERR(data))
return -1;
@ -308,21 +308,22 @@ void ec_fsm_foe_state_ack_check(
ec_fsm_foe_t *fsm /**< FoE statemachine. */
)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_datagram_t *datagram = mbox->datagram;
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
printk("ec_fsm_foe_ack_check()\n");
#endif
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR);
EC_SLAVE_ERR(slave, "Failed to receive FoE mailbox check datagram: ");
ec_datagram_print_state(datagram);
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
// slave did not put anything in the mailbox yet
ec_foe_set_rx_error(fsm, FOE_WC_ERROR);
EC_SLAVE_ERR(slave, "Reception of FoE mailbox check datagram"
@ -331,7 +332,7 @@ void ec_fsm_foe_state_ack_check(
return;
}
if (!ec_slave_mbox_check(datagram)) {
if (!ec_slave_mbox_check(mbox)) {
unsigned long diff_ms =
(datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
if (diff_ms >= EC_FSM_FOE_TIMEOUT) {
@ -340,13 +341,13 @@ void ec_fsm_foe_state_ack_check(
return;
}
ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
ec_slave_mbox_prepare_check(slave, mbox); // can not fail.
fsm->retries = EC_FSM_RETRIES;
return;
}
// Fetch response
ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
ec_slave_mbox_prepare_fetch(slave, mbox); // can not fail.
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_foe_state_ack_read;
@ -360,7 +361,8 @@ void ec_fsm_foe_state_ack_read(
ec_fsm_foe_t *fsm /**< FoE statemachine. */
)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_datagram_t *datagram = mbox->datagram;
ec_slave_t *slave = fsm->slave;
uint8_t *data, mbox_prot;
uint8_t opCode;
@ -370,21 +372,21 @@ void ec_fsm_foe_state_ack_read(
printk("ec_fsm_foe_ack_read()\n");
#endif
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR);
EC_SLAVE_ERR(slave, "Failed to receive FoE ack response datagram: ");
ec_datagram_print_state(datagram);
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
ec_foe_set_rx_error(fsm, FOE_WC_ERROR);
EC_SLAVE_ERR(slave, "Reception of FoE ack response failed: ");
ec_datagram_print_wc_error(datagram);
return;
}
if (!(data = ec_slave_mbox_fetch(fsm->slave, datagram,
if (!(data = ec_slave_mbox_fetch(fsm->slave, fsm->mbox,
&mbox_prot, &rec_size))) {
ec_foe_set_tx_error(fsm, FOE_PROT_ERROR);
return;
@ -440,21 +442,22 @@ void ec_fsm_foe_state_wrq_sent(
ec_fsm_foe_t *fsm /**< FoE statemachine. */
)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_datagram_t *datagram = mbox->datagram;
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
printk("ec_foe_state_sent_wrq()\n");
#endif
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR);
EC_SLAVE_ERR(slave, "Failed to send FoE WRQ: ");
ec_datagram_print_state(datagram);
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
// slave did not put anything in the mailbox yet
ec_foe_set_rx_error(fsm, FOE_WC_ERROR);
EC_SLAVE_ERR(slave, "Reception of FoE WRQ failed: ");
@ -464,7 +467,7 @@ void ec_fsm_foe_state_wrq_sent(
fsm->jiffies_start = datagram->jiffies_sent;
ec_slave_mbox_prepare_check(fsm->slave, datagram); // can not fail.
ec_slave_mbox_prepare_check(fsm->slave, fsm->mbox); // can not fail.
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_foe_state_ack_check;
@ -481,28 +484,29 @@ void ec_fsm_foe_state_data_sent(
ec_fsm_foe_t *fsm /**< Foe statemachine. */
)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_datagram_t *datagram = mbox->datagram;
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
printk("ec_fsm_foe_state_data_sent()\n");
#endif
if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
ec_foe_set_tx_error(fsm, FOE_RECEIVE_ERROR);
EC_SLAVE_ERR(slave, "Failed to receive FoE ack response datagram: ");
ec_datagram_print_state(datagram);
return;
}
if (fsm->datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
ec_foe_set_tx_error(fsm, FOE_WC_ERROR);
EC_SLAVE_ERR(slave, "Reception of FoE data send failed: ");
ec_datagram_print_wc_error(datagram);
return;
}
ec_slave_mbox_prepare_check(fsm->slave, fsm->datagram);
ec_slave_mbox_prepare_check(slave, mbox);
fsm->jiffies_start = jiffies;
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_foe_state_ack_check;
@ -519,7 +523,7 @@ int ec_foe_prepare_rrq_send(ec_fsm_foe_t *fsm)
current_size = fsm->rx_filename_len;
data = ec_slave_mbox_prepare_send(fsm->slave, fsm->datagram,
data = ec_slave_mbox_prepare_send(fsm->slave, fsm->mbox,
EC_MBOX_TYPE_FILEACCESS, current_size + EC_FOE_HEADER_SIZE);
if (IS_ERR(data))
return -1;
@ -546,7 +550,7 @@ int ec_foe_prepare_send_ack(
{
uint8_t *data;
data = ec_slave_mbox_prepare_send(foe->slave, foe->datagram,
data = ec_slave_mbox_prepare_send(foe->slave, foe->mbox,
EC_MBOX_TYPE_FILEACCESS, EC_FOE_HEADER_SIZE);
if (IS_ERR(data))
return -1;
@ -568,21 +572,22 @@ void ec_fsm_foe_state_rrq_sent(
ec_fsm_foe_t *fsm /**< FoE statemachine. */
)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_datagram_t *datagram = mbox->datagram;
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
printk("ec_foe_state_rrq_sent()\n");
#endif
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR);
EC_SLAVE_ERR(slave, "Failed to send FoE RRQ: ");
ec_datagram_print_state(datagram);
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
// slave did not put anything in the mailbox yet
ec_foe_set_rx_error(fsm, FOE_WC_ERROR);
EC_SLAVE_ERR(slave, "Reception of FoE RRQ failed: ");
@ -592,7 +597,7 @@ void ec_fsm_foe_state_rrq_sent(
fsm->jiffies_start = datagram->jiffies_sent;
ec_slave_mbox_prepare_check(fsm->slave, datagram); // can not fail.
ec_slave_mbox_prepare_check(fsm->slave, fsm->mbox); // can not fail.
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_foe_state_data_check;
@ -657,28 +662,29 @@ void ec_fsm_foe_state_data_check(
ec_fsm_foe_t *fsm /**< FoE statemachine. */
)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_datagram_t *datagram = mbox->datagram;
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
printk("ec_fsm_foe_state_data_check()\n");
#endif
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR);
EC_SLAVE_ERR(slave, "Failed to send FoE DATA READ: ");
ec_datagram_print_state(datagram);
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
ec_foe_set_rx_error(fsm, FOE_WC_ERROR);
EC_SLAVE_ERR(slave, "Reception of FoE DATA READ: ");
ec_datagram_print_wc_error(datagram);
return;
}
if (!ec_slave_mbox_check(datagram)) {
if (!ec_slave_mbox_check(mbox)) {
unsigned long diff_ms =
(datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
if (diff_ms >= EC_FSM_FOE_TIMEOUT) {
@ -687,13 +693,13 @@ void ec_fsm_foe_state_data_check(
return;
}
ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
ec_slave_mbox_prepare_check(slave, mbox); // can not fail.
fsm->retries = EC_FSM_RETRIES;
return;
}
// Fetch response
ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
ec_slave_mbox_prepare_fetch(slave, mbox); // can not fail.
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_foe_state_data_read;
@ -711,28 +717,29 @@ void ec_fsm_foe_state_data_read(
size_t rec_size;
uint8_t *data, opCode, packet_no, mbox_prot;
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_datagram_t *datagram = mbox->datagram;
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
printk("ec_fsm_foe_state_data_read()\n");
#endif
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR);
EC_SLAVE_ERR(slave, "Failed to receive FoE DATA READ datagram: ");
ec_datagram_print_state(datagram);
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
ec_foe_set_rx_error(fsm, FOE_WC_ERROR);
EC_SLAVE_ERR(slave, "Reception of FoE DATA READ failed: ");
ec_datagram_print_wc_error(datagram);
return;
}
if (!(data = ec_slave_mbox_fetch(slave, datagram, &mbox_prot, &rec_size))) {
if (!(data = ec_slave_mbox_fetch(slave, mbox, &mbox_prot, &rec_size))) {
ec_foe_set_rx_error(fsm, FOE_MBOX_FETCH_ERROR);
return;
}
@ -831,21 +838,22 @@ void ec_fsm_foe_state_sent_ack(
ec_fsm_foe_t *fsm /**< FoE statemachine. */
)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_datagram_t *datagram = mbox->datagram;
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
printk("ec_foe_state_sent_ack()\n");
#endif
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR);
EC_SLAVE_ERR(slave, "Failed to send FoE ACK: ");
ec_datagram_print_state(datagram);
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
// slave did not put anything into the mailbox yet
ec_foe_set_rx_error(fsm, FOE_WC_ERROR);
EC_SLAVE_ERR(slave, "Reception of FoE ACK failed: ");
@ -855,7 +863,7 @@ void ec_fsm_foe_state_sent_ack(
fsm->jiffies_start = datagram->jiffies_sent;
ec_slave_mbox_prepare_check(fsm->slave, datagram); // can not fail.
ec_slave_mbox_prepare_check(fsm->slave, fsm->mbox); // can not fail.
if (fsm->rx_last_packet) {
fsm->rx_expected_packet_no = 0;

View File

@ -51,7 +51,7 @@ typedef struct ec_fsm_foe ec_fsm_foe_t; /**< \see ec_fsm_foe */
*/
struct ec_fsm_foe {
ec_slave_t *slave; /**< slave the FSM runs on */
ec_datagram_t *datagram; /**< datagram used in the state machine */
ec_mailbox_t *mbox; /**< mailbox used in the state machine */
unsigned int retries; /**< retries upon datagram timeout */
void (*state)(ec_fsm_foe_t *); /**< FoE state function */
@ -80,7 +80,7 @@ struct ec_fsm_foe {
/*****************************************************************************/
void ec_fsm_foe_init(ec_fsm_foe_t *, ec_datagram_t *);
void ec_fsm_foe_init(ec_fsm_foe_t *, ec_mailbox_t *);
void ec_fsm_foe_clear(ec_fsm_foe_t *);
int ec_fsm_foe_exec(ec_fsm_foe_t *);

View File

@ -48,7 +48,11 @@
/** Time difference [ns] to tolerate without setting a new system time offset.
*/
#ifdef EC_HAVE_CYCLES
#define EC_SYSTEM_TIME_TOLERANCE_NS 10000
#else
#define EC_SYSTEM_TIME_TOLERANCE_NS 100000000
#endif
/*****************************************************************************/
@ -81,6 +85,7 @@ void ec_fsm_master_init(
{
fsm->master = master;
fsm->datagram = datagram;
fsm->mbox = &master->fsm_mbox;
fsm->state = ec_fsm_master_state_start;
fsm->idle = 0;
fsm->link_state = 0;
@ -89,7 +94,7 @@ void ec_fsm_master_init(
fsm->slave_states = EC_SLAVE_STATE_UNKNOWN;
// init sub-state-machines
ec_fsm_coe_init(&fsm->fsm_coe, fsm->datagram);
ec_fsm_coe_init(&fsm->fsm_coe, fsm->mbox);
ec_fsm_pdo_init(&fsm->fsm_pdo, &fsm->fsm_coe);
ec_fsm_change_init(&fsm->fsm_change, fsm->datagram);
ec_fsm_slave_config_init(&fsm->fsm_slave_config, fsm->datagram,
@ -129,12 +134,11 @@ int ec_fsm_master_exec(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
if (fsm->datagram->state == EC_DATAGRAM_SENT
|| fsm->datagram->state == EC_DATAGRAM_QUEUED) {
if (ec_mbox_is_datagram_state(fsm->mbox,EC_DATAGRAM_QUEUED)
|| ec_mbox_is_datagram_state(fsm->mbox,EC_DATAGRAM_SENT)) {
// datagram was not sent or received yet.
return 0;
}
fsm->state(fsm);
return 1;
}
@ -211,10 +215,6 @@ void ec_fsm_master_state_broadcast(
EC_MASTER_DBG(master, 1, "Master state machine detected "
"link down. Clearing slave list.\n");
#ifdef EC_EOE
ec_master_eoe_stop(master);
ec_master_clear_eoe_handlers(master);
#endif
ec_master_clear_slaves(master);
fsm->slave_states = 0x00;
}
@ -238,12 +238,12 @@ void ec_fsm_master_state_broadcast(
}
if (fsm->rescan_required) {
down(&master->scan_sem);
ec_mutex_lock(&master->scan_mutex);
if (!master->allow_scan) {
up(&master->scan_sem);
ec_mutex_unlock(&master->scan_mutex);
} else {
master->scan_busy = 1;
up(&master->scan_sem);
ec_mutex_unlock(&master->scan_mutex);
// clear all slaves and scan the bus
fsm->rescan_required = 0;
@ -251,7 +251,6 @@ void ec_fsm_master_state_broadcast(
fsm->scan_jiffies = jiffies;
#ifdef EC_EOE
ec_master_eoe_stop(master);
ec_master_clear_eoe_handlers(master);
#endif
ec_master_clear_slaves(master);
@ -392,6 +391,7 @@ int ec_fsm_master_action_process_register(
"datagram size (%zu)!\n", request->length,
fsm->datagram->mem_size);
request->state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_reg_request_release);
wake_up(&master->reg_queue);
continue;
}
@ -571,12 +571,12 @@ void ec_fsm_master_action_configure(
|| slave->force_config) && !slave->error_flag) {
// Start slave configuration, if it is allowed.
down(&master->config_sem);
ec_mutex_lock(&master->config_mutex);
if (!master->allow_config) {
up(&master->config_sem);
ec_mutex_unlock(&master->config_mutex);
} else {
master->config_busy = 1;
up(&master->config_sem);
ec_mutex_unlock(&master->config_mutex);
if (master->debug_level) {
char old_state[EC_STATE_STRING_SIZE],
@ -802,11 +802,6 @@ void ec_fsm_master_state_scan_slave(
// Attach slave configurations
ec_master_attach_slave_configs(master);
#ifdef EC_EOE
// check if EoE processing has to be started
ec_master_eoe_start(master);
#endif
if (master->slave_count) {
fsm->slave = master->slaves; // begin with first slave
ec_fsm_master_enter_write_system_times(fsm);
@ -889,26 +884,27 @@ u64 ec_fsm_master_dc_offset32(
ec_fsm_master_t *fsm, /**< Master state machine. */
u64 system_time, /**< System time register. */
u64 old_offset, /**< Time offset register. */
unsigned long jiffies_since_read /**< Jiffies for correction. */
u64 correction /**< Correction. */
)
{
ec_slave_t *slave = fsm->slave;
u32 correction, system_time32, old_offset32, new_offset;
u32 correction32, system_time32, old_offset32, new_offset;
s32 time_diff;
system_time32 = (u32) system_time;
old_offset32 = (u32) old_offset;
system_time32 = (u32) system_time;
// correct read system time by elapsed time between read operation
// and app_time set time
correction32 = (u32)correction;
system_time32 -= correction32;
old_offset32 = (u32) old_offset;
// correct read system time by elapsed time since read operation
correction = jiffies_since_read * 1000 / HZ * 1000000;
system_time32 += correction;
time_diff = (u32) slave->master->app_time - system_time32;
time_diff = (u32) slave->master->app_start_time - system_time32;
EC_SLAVE_DBG(slave, 1, "DC system time offset calculation:"
" system_time=%u (corrected with %u),"
" app_time=%llu, diff=%i\n",
system_time32, correction,
slave->master->app_time, time_diff);
" app_start_time=%llu, diff=%i\n",
system_time32, correction32,
slave->master->app_start_time, time_diff);
if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) {
new_offset = time_diff + old_offset32;
@ -929,23 +925,23 @@ u64 ec_fsm_master_dc_offset64(
ec_fsm_master_t *fsm, /**< Master state machine. */
u64 system_time, /**< System time register. */
u64 old_offset, /**< Time offset register. */
unsigned long jiffies_since_read /**< Jiffies for correction. */
u64 correction /**< Correction. */
)
{
ec_slave_t *slave = fsm->slave;
u64 new_offset, correction;
u64 new_offset;
s64 time_diff;
// correct read system time by elapsed time since read operation
correction = (u64) (jiffies_since_read * 1000 / HZ) * 1000000;
system_time += correction;
time_diff = fsm->slave->master->app_time - system_time;
// correct read system time by elapsed time between read operation
// and app_time set time
system_time -= correction;
time_diff = fsm->slave->master->app_start_time - system_time;
EC_SLAVE_DBG(slave, 1, "DC system time offset calculation:"
" system_time=%llu (corrected with %llu),"
" app_time=%llu, diff=%lli\n",
" app_start_time=%llu, diff=%lli\n",
system_time, correction,
slave->master->app_time, time_diff);
slave->master->app_start_time, time_diff);
if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) {
new_offset = time_diff + old_offset;
@ -969,8 +965,7 @@ void ec_fsm_master_state_dc_read_offset(
{
ec_datagram_t *datagram = fsm->datagram;
ec_slave_t *slave = fsm->slave;
u64 system_time, old_offset, new_offset;
unsigned long jiffies_since_read;
u64 system_time, old_offset, new_offset, correction;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
return;
@ -993,14 +988,25 @@ void ec_fsm_master_state_dc_read_offset(
system_time = EC_READ_U64(datagram->data); // 0x0910
old_offset = EC_READ_U64(datagram->data + 16); // 0x0920
jiffies_since_read = jiffies - datagram->jiffies_sent;
/* correct read system time by elapsed time since read operation
and the app_time set time */
#ifdef EC_HAVE_CYCLES
correction =
(datagram->cycles_sent - slave->master->dc_cycles_app_start_time)
* 1000000LL;
do_div(correction,cpu_khz);
#else
correction =
(u64) ((datagram->jiffies_sent-slave->master->dc_jiffies_app_start_time) * 1000 / HZ)
* 1000000;
#endif
if (slave->base_dc_range == EC_DC_32) {
new_offset = ec_fsm_master_dc_offset32(fsm,
system_time, old_offset, jiffies_since_read);
system_time, old_offset, correction);
} else {
new_offset = ec_fsm_master_dc_offset64(fsm,
system_time, old_offset, jiffies_since_read);
system_time, old_offset, correction);
}
// set DC system time offset and transmission delay
@ -1063,6 +1069,7 @@ void ec_fsm_master_state_write_sii(
if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
EC_SLAVE_ERR(slave, "Failed to write SII data.\n");
request->state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_sii_write_request_release);
wake_up(&master->sii_queue);
ec_fsm_master_restart(fsm);
return;
@ -1091,6 +1098,7 @@ void ec_fsm_master_state_write_sii(
// TODO: Evaluate other SII contents!
request->state = EC_INT_REQUEST_SUCCESS;
kref_put(&request->refcount,ec_master_sii_write_request_release);
wake_up(&master->sii_queue);
// check for another SII write request
@ -1184,6 +1192,7 @@ void ec_fsm_master_state_reg_request(
" request datagram: ");
ec_datagram_print_state(datagram);
request->state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_reg_request_release);
wake_up(&master->reg_queue);
ec_fsm_master_restart(fsm);
return;
@ -1198,6 +1207,7 @@ void ec_fsm_master_state_reg_request(
EC_MASTER_ERR(master, "Failed to allocate %zu bytes"
" of memory for register data.\n", request->length);
request->state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_reg_request_release);
wake_up(&master->reg_queue);
ec_fsm_master_restart(fsm);
return;
@ -1212,6 +1222,7 @@ void ec_fsm_master_state_reg_request(
EC_MASTER_ERR(master, "Register request failed.\n");
}
kref_put(&request->refcount,ec_master_reg_request_release);
wake_up(&master->reg_queue);
// check for another register request
@ -1222,3 +1233,72 @@ void ec_fsm_master_state_reg_request(
}
/*****************************************************************************/
/** called by kref_put if the SII write request's refcount becomes zero.
*
*/
void ec_master_sii_write_request_release(struct kref *ref)
{
ec_sii_write_request_t *request = container_of(ref, ec_sii_write_request_t, refcount);
if (request->slave)
EC_SLAVE_DBG(request->slave, 1, "Releasing SII write request %p.\n",request);
kfree(request->words);
kfree(request);
}
/*****************************************************************************/
/** called by kref_put if the reg request's refcount becomes zero.
*
*/
void ec_master_reg_request_release(struct kref *ref)
{
ec_reg_request_t *request = container_of(ref, ec_reg_request_t, refcount);
if (request->slave)
EC_SLAVE_DBG(request->slave, 1, "Releasing reg request %p.\n",request);
if (request->data)
kfree(request->data);
kfree(request);
}
/*****************************************************************************/
/** called by kref_put if the SDO request's refcount becomes zero.
*
*/
void ec_master_sdo_request_release(struct kref *ref)
{
ec_master_sdo_request_t *request = container_of(ref, ec_master_sdo_request_t, refcount);
if (request->slave)
EC_SLAVE_DBG(request->slave, 1, "Releasing SDO request %p.\n",request);
ec_sdo_request_clear(&request->req);
kfree(request);
}
/*****************************************************************************/
/** called by kref_put if the FoE request's refcount becomes zero.
*
*/
void ec_master_foe_request_release(struct kref *ref)
{
ec_master_foe_request_t *request = container_of(ref, ec_master_foe_request_t, refcount);
if (request->slave)
EC_SLAVE_DBG(request->slave, 1, "Releasing FoE request %p.\n",request);
ec_foe_request_clear(&request->req);
kfree(request);
}
/*****************************************************************************/
/** called by kref_put if the SoE request's refcount becomes zero.
*
*/
void ec_master_soe_request_release(struct kref *ref)
{
ec_master_soe_request_t *request = container_of(ref, ec_master_soe_request_t, refcount);
if (request->slave)
EC_SLAVE_DBG(request->slave, 1, "Releasing SoE request %p.\n",request);
ec_soe_request_clear(&request->req);
kfree(request);
}

View File

@ -39,6 +39,7 @@
#include "globals.h"
#include "datagram.h"
#include "mailbox.h"
#include "foe_request.h"
#include "sdo_request.h"
#include "soe_request.h"
@ -57,8 +58,11 @@ typedef struct {
size_t nwords; /**< Number of words. */
const uint16_t *words; /**< Pointer to the data words. */
ec_internal_request_state_t state; /**< State of the request. */
struct kref refcount;
} ec_sii_write_request_t;
void ec_master_sii_write_request_release(struct kref *);
/*****************************************************************************/
/** Register request.
@ -71,8 +75,11 @@ typedef struct {
size_t length; /**< Number of bytes. */
uint8_t *data; /**< Data to write / memory for read data. */
ec_internal_request_state_t state; /**< State of the request. */
struct kref refcount;
} ec_reg_request_t;
void ec_master_reg_request_release(struct kref *);
/*****************************************************************************/
/** Slave/SDO request record for master's SDO request list.
@ -81,8 +88,11 @@ typedef struct {
struct list_head list; /**< List element. */
ec_slave_t *slave; /**< Slave. */
ec_sdo_request_t req; /**< SDO request. */
struct kref refcount;
} ec_master_sdo_request_t;
void ec_master_sdo_request_release(struct kref *);
/*****************************************************************************/
/** FoE request.
@ -91,8 +101,11 @@ typedef struct {
struct list_head list; /**< List head. */
ec_slave_t *slave; /**< EtherCAT slave. */
ec_foe_request_t req; /**< FoE request. */
struct kref refcount;
} ec_master_foe_request_t;
void ec_master_foe_request_release(struct kref *);
/*****************************************************************************/
/** SoE request.
@ -101,8 +114,11 @@ typedef struct {
struct list_head list; /**< List head. */
ec_slave_t *slave; /**< EtherCAT slave. */
ec_soe_request_t req; /**< SoE request. */
struct kref refcount;
} ec_master_soe_request_t;
void ec_master_soe_request_release(struct kref *);
/*****************************************************************************/
typedef struct ec_fsm_master ec_fsm_master_t; /**< \see ec_fsm_master */
@ -112,6 +128,7 @@ typedef struct ec_fsm_master ec_fsm_master_t; /**< \see ec_fsm_master */
struct ec_fsm_master {
ec_master_t *master; /**< master the FSM runs on */
ec_datagram_t *datagram; /**< datagram used in the state machine */
ec_mailbox_t* mbox; /**< mailbox used in the CoE state machine */
unsigned int retries; /**< retries on datagram timeout. */
void (*state)(ec_fsm_master_t *); /**< master state function */

View File

@ -57,21 +57,21 @@ void ec_fsm_slave_state_soe_request(ec_fsm_slave_t *);
void ec_fsm_slave_init(
ec_fsm_slave_t *fsm, /**< Slave state machine. */
ec_slave_t *slave, /**< EtherCAT slave. */
ec_datagram_t *datagram /**< Datagram object to use. */
ec_mailbox_t *mbox/**< Datagram object to use. */
)
{
fsm->slave = slave;
fsm->datagram = datagram;
fsm->datagram->data_size = 0;
fsm->mbox = mbox;
slave->datagram.data_size = 0;
EC_SLAVE_DBG(slave, 1, "Init FSM.\n");
fsm->state = ec_fsm_slave_state_idle;
// init sub-state-machines
ec_fsm_coe_init(&fsm->fsm_coe, fsm->datagram);
ec_fsm_foe_init(&fsm->fsm_foe, fsm->datagram);
ec_fsm_soe_init(&fsm->fsm_soe, fsm->datagram);
ec_fsm_coe_init(&fsm->fsm_coe, fsm->mbox);
ec_fsm_foe_init(&fsm->fsm_foe, fsm->mbox);
ec_fsm_soe_init(&fsm->fsm_soe, fsm->mbox);
}
/*****************************************************************************/
@ -94,19 +94,21 @@ void ec_fsm_slave_clear(
*
* If the state machine's datagram is not sent or received yet, the execution
* of the state machine is delayed to the next cycle.
*
* \return true, if the state machine was executed
*/
void ec_fsm_slave_exec(
int ec_fsm_slave_exec(
ec_fsm_slave_t *fsm /**< Slave state machine. */
)
{
if (fsm->datagram->state == EC_DATAGRAM_SENT
|| fsm->datagram->state == EC_DATAGRAM_QUEUED) {
if (ec_mbox_is_datagram_state(fsm->mbox,EC_DATAGRAM_QUEUED)
|| ec_mbox_is_datagram_state(fsm->mbox,EC_DATAGRAM_SENT)) {
// datagram was not sent or received yet.
return;
return 0;
}
fsm->state(fsm);
return;
return 1;
}
/*****************************************************************************/
@ -176,9 +178,10 @@ int ec_fsm_slave_action_process_sdo(
list_del_init(&request->list); // dequeue
if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) {
EC_SLAVE_WARN(slave, "Aborting SDO request,"
" slave has error flag set.\n");
EC_SLAVE_WARN(slave, "Aborting SDO request %p,"
" slave has error flag set.\n",request);
request->req.state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_sdo_request_release);
wake_up(&slave->sdo_queue);
fsm->sdo_request = NULL;
fsm->state = ec_fsm_slave_state_idle;
@ -186,8 +189,9 @@ int ec_fsm_slave_action_process_sdo(
}
if (slave->current_state == EC_SLAVE_STATE_INIT) {
EC_SLAVE_WARN(slave, "Aborting SDO request, slave is in INIT.\n");
EC_SLAVE_WARN(slave, "Aborting SDO request %p, slave is in INIT.\n",request);
request->req.state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_sdo_request_release);
wake_up(&slave->sdo_queue);
fsm->sdo_request = NULL;
fsm->state = ec_fsm_slave_state_idle;
@ -197,14 +201,14 @@ int ec_fsm_slave_action_process_sdo(
request->req.state = EC_INT_REQUEST_BUSY;
// Found pending SDO request. Execute it!
EC_SLAVE_DBG(slave, 1, "Processing SDO request...\n");
EC_SLAVE_DBG(slave, 1, "Processing SDO request %p...\n",request);
// Start SDO transfer
fsm->sdo_request = &request->req;
fsm->sdo_request = request;
fsm->state = ec_fsm_slave_state_sdo_request;
ec_fsm_coe_transfer(&fsm->fsm_coe, slave, &request->req);
ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately
ec_master_queue_external_datagram(fsm->slave->master,fsm->datagram);
ec_slave_mbox_queue_datagrams(slave, fsm->mbox);
return 1;
}
return 0;
@ -219,26 +223,28 @@ void ec_fsm_slave_state_sdo_request(
)
{
ec_slave_t *slave = fsm->slave;
ec_sdo_request_t *request = fsm->sdo_request;
ec_master_sdo_request_t *request = fsm->sdo_request;
if (ec_fsm_coe_exec(&fsm->fsm_coe))
{
ec_master_queue_external_datagram(fsm->slave->master,fsm->datagram);
ec_slave_mbox_queue_datagrams(slave, fsm->mbox);
return;
}
if (!ec_fsm_coe_success(&fsm->fsm_coe)) {
EC_SLAVE_ERR(slave, "Failed to process SDO request.\n");
request->state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_ERR(slave, "Failed to process SDO request %p.\n",request);
request->req.state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_sdo_request_release);
wake_up(&slave->sdo_queue);
fsm->sdo_request = NULL;
fsm->state = ec_fsm_slave_state_idle;
return;
}
EC_SLAVE_DBG(slave, 1, "Finished SDO request.\n");
EC_SLAVE_DBG(slave, 1, "Finished SDO request %p.\n",request);
// SDO request finished
request->state = EC_INT_REQUEST_SUCCESS;
request->req.state = EC_INT_REQUEST_SUCCESS;
kref_put(&request->refcount,ec_master_sdo_request_release);
wake_up(&slave->sdo_queue);
fsm->sdo_request = NULL;
@ -261,10 +267,11 @@ int ec_fsm_slave_action_process_foe(
// search the first request to be processed
list_for_each_entry_safe(request, next, &slave->foe_requests, list) {
if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) {
EC_SLAVE_WARN(slave, "Aborting FOE request,"
" slave has error flag set.\n");
EC_SLAVE_WARN(slave, "Aborting FOE request %p,"
" slave has error flag set.\n",request);
request->req.state = EC_INT_REQUEST_FAILURE;
wake_up(&slave->sdo_queue);
kref_put(&request->refcount,ec_master_foe_request_release);
wake_up(&slave->foe_queue);
fsm->sdo_request = NULL;
fsm->state = ec_fsm_slave_state_idle;
return 0;
@ -272,13 +279,13 @@ int ec_fsm_slave_action_process_foe(
list_del_init(&request->list); // dequeue
request->req.state = EC_INT_REQUEST_BUSY;
EC_SLAVE_DBG(slave, 1, "Processing FoE request.\n");
EC_SLAVE_DBG(slave, 1, "Processing FoE request %p.\n",request);
fsm->foe_request = &request->req;
fsm->foe_request = request;
fsm->state = ec_fsm_slave_state_foe_request;
ec_fsm_foe_transfer(&fsm->fsm_foe, slave, &request->req);
ec_fsm_foe_exec(&fsm->fsm_foe);
ec_master_queue_external_datagram(fsm->slave->master,fsm->datagram);
ec_slave_mbox_queue_datagrams(slave, fsm->mbox);
return 1;
}
return 0;
@ -293,17 +300,18 @@ void ec_fsm_slave_state_foe_request(
)
{
ec_slave_t *slave = fsm->slave;
ec_foe_request_t *request = fsm->foe_request;
ec_master_foe_request_t *request = fsm->foe_request;
if (ec_fsm_foe_exec(&fsm->fsm_foe))
{
ec_master_queue_external_datagram(fsm->slave->master,fsm->datagram);
ec_slave_mbox_queue_datagrams(slave, fsm->mbox);
return;
}
if (!ec_fsm_foe_success(&fsm->fsm_foe)) {
EC_SLAVE_ERR(slave, "Failed to handle FoE request.\n");
request->state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_ERR(slave, "Failed to handle FoE request %p.\n",request);
request->req.state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_foe_request_release);
wake_up(&slave->foe_queue);
fsm->foe_request = NULL;
fsm->state = ec_fsm_slave_state_idle;
@ -311,10 +319,11 @@ void ec_fsm_slave_state_foe_request(
}
// finished transferring FoE
EC_SLAVE_DBG(slave, 1, "Successfully transferred %zu bytes of FoE"
" data.\n", request->data_size);
EC_SLAVE_DBG(slave, 1, "FoE request %p successfully transferred %zu bytes.\n",
request,request->req.data_size);
request->state = EC_INT_REQUEST_SUCCESS;
request->req.state = EC_INT_REQUEST_SUCCESS;
kref_put(&request->refcount,ec_master_foe_request_release);
wake_up(&slave->foe_queue);
fsm->foe_request = NULL;
@ -332,16 +341,17 @@ int ec_fsm_slave_action_process_soe(
)
{
ec_slave_t *slave = fsm->slave;
ec_master_soe_request_t *req, *next;
ec_master_soe_request_t *request, *next;
// search the first request to be processed
list_for_each_entry_safe(req, next, &slave->soe_requests, list) {
list_for_each_entry_safe(request, next, &slave->soe_requests, list) {
list_del_init(&req->list); // dequeue
list_del_init(&request->list); // dequeue
if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) {
EC_SLAVE_WARN(slave, "Aborting SoE request,"
" slave has error flag set.\n");
req->req.state = EC_INT_REQUEST_FAILURE;
request->req.state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_soe_request_release);
wake_up(&slave->soe_queue);
fsm->state = ec_fsm_slave_state_idle;
return 0;
@ -349,23 +359,24 @@ int ec_fsm_slave_action_process_soe(
if (slave->current_state == EC_SLAVE_STATE_INIT) {
EC_SLAVE_WARN(slave, "Aborting SoE request, slave is in INIT.\n");
req->req.state = EC_INT_REQUEST_FAILURE;
request->req.state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_soe_request_release);
wake_up(&slave->soe_queue);
fsm->state = ec_fsm_slave_state_idle;
return 0;
}
req->req.state = EC_INT_REQUEST_BUSY;
request->req.state = EC_INT_REQUEST_BUSY;
// Found pending request. Execute it!
EC_SLAVE_DBG(slave, 1, "Processing SoE request...\n");
// Start SoE transfer
fsm->soe_request = &req->req;
fsm->soe_request = request;
fsm->state = ec_fsm_slave_state_soe_request;
ec_fsm_soe_transfer(&fsm->fsm_soe, slave, &req->req);
ec_fsm_soe_transfer(&fsm->fsm_soe, slave, &request->req);
ec_fsm_soe_exec(&fsm->fsm_soe); // execute immediately
ec_master_queue_external_datagram(fsm->slave->master, fsm->datagram);
ec_slave_mbox_queue_datagrams(slave, fsm->mbox);
return 1;
}
return 0;
@ -380,16 +391,17 @@ void ec_fsm_slave_state_soe_request(
)
{
ec_slave_t *slave = fsm->slave;
ec_soe_request_t *request = fsm->soe_request;
ec_master_soe_request_t *request = fsm->soe_request;
if (ec_fsm_soe_exec(&fsm->fsm_soe)) {
ec_master_queue_external_datagram(fsm->slave->master, fsm->datagram);
ec_slave_mbox_queue_datagrams(slave, fsm->mbox);
return;
}
if (!ec_fsm_soe_success(&fsm->fsm_soe)) {
EC_SLAVE_ERR(slave, "Failed to process SoE request.\n");
request->state = EC_INT_REQUEST_FAILURE;
request->req.state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_soe_request_release);
wake_up(&slave->soe_queue);
fsm->soe_request = NULL;
fsm->state = ec_fsm_slave_state_idle;
@ -399,7 +411,8 @@ void ec_fsm_slave_state_soe_request(
EC_SLAVE_DBG(slave, 1, "Finished SoE request.\n");
// SoE request finished
request->state = EC_INT_REQUEST_SUCCESS;
request->req.state = EC_INT_REQUEST_SUCCESS;
kref_put(&request->refcount,ec_master_soe_request_release);
wake_up(&slave->soe_queue);
fsm->soe_request = NULL;

View File

@ -42,6 +42,7 @@
#include "fsm_coe.h"
#include "fsm_foe.h"
#include "fsm_soe.h"
#include "fsm_master.h"
typedef struct ec_fsm_slave ec_fsm_slave_t; /**< \see ec_fsm_slave */
@ -49,13 +50,13 @@ typedef struct ec_fsm_slave ec_fsm_slave_t; /**< \see ec_fsm_slave */
*/
struct ec_fsm_slave {
ec_slave_t *slave; /**< slave the FSM runs on */
ec_datagram_t *datagram; /**< datagram used in the state machine */
ec_mailbox_t *mbox; /**< mailbox used in the state machine */
void (*state)(ec_fsm_slave_t *); /**< master state function */
ec_sdo_request_t *sdo_request; /**< SDO request to process. */
ec_foe_request_t *foe_request; /**< FoE request to process. */
ec_master_sdo_request_t *sdo_request; /**< SDO request to process. */
ec_master_foe_request_t *foe_request; /**< FoE request to process. */
off_t foe_index; /**< index to FoE write request data */
ec_soe_request_t *soe_request; /**< SoE request to process. */
ec_master_soe_request_t *soe_request; /**< SoE request to process. */
ec_fsm_coe_t fsm_coe; /**< CoE state machine */
ec_fsm_foe_t fsm_foe; /**< FoE state machine */
@ -64,10 +65,10 @@ struct ec_fsm_slave {
/*****************************************************************************/
void ec_fsm_slave_init(ec_fsm_slave_t *, ec_slave_t *, ec_datagram_t *);
void ec_fsm_slave_init(ec_fsm_slave_t *, ec_slave_t *, ec_mailbox_t *);
void ec_fsm_slave_clear(ec_fsm_slave_t *);
void ec_fsm_slave_exec(ec_fsm_slave_t *);
int ec_fsm_slave_exec(ec_fsm_slave_t *);
void ec_fsm_slave_ready(ec_fsm_slave_t *);
/*****************************************************************************/

View File

@ -177,8 +177,8 @@ int ec_fsm_slave_config_exec(
ec_fsm_slave_config_t *fsm /**< slave state machine */
)
{
if (fsm->datagram->state == EC_DATAGRAM_SENT
|| fsm->datagram->state == EC_DATAGRAM_QUEUED) {
if (fsm->datagram->state == EC_DATAGRAM_QUEUED
|| fsm->datagram->state == EC_DATAGRAM_SENT) {
// datagram was not sent or received yet.
return ec_fsm_slave_config_running(fsm);
}
@ -738,8 +738,7 @@ void ec_fsm_slave_config_enter_soe_conf_preop(
ec_soe_request_write(&fsm->soe_request_copy);
ec_fsm_soe_transfer(fsm_soe, fsm->slave, &fsm->soe_request_copy);
ec_fsm_soe_exec(fsm_soe); // execute immediately
ec_master_queue_external_datagram(slave->master,
fsm_soe->datagram);
ec_slave_mbox_queue_datagrams(slave, fsm_soe->mbox);
return;
}
}
@ -760,7 +759,7 @@ void ec_fsm_slave_config_state_soe_conf_preop(
ec_fsm_soe_t *fsm_soe = &slave->fsm.fsm_soe;
if (ec_fsm_soe_exec(fsm_soe)) {
ec_master_queue_external_datagram(slave->master, fsm_soe->datagram);
ec_slave_mbox_queue_datagrams(slave, fsm_soe->mbox);
return;
}
@ -785,8 +784,7 @@ void ec_fsm_slave_config_state_soe_conf_preop(
ec_soe_request_write(&fsm->soe_request_copy);
ec_fsm_soe_transfer(fsm_soe, fsm->slave, &fsm->soe_request_copy);
ec_fsm_soe_exec(fsm_soe); // execute immediately
ec_master_queue_external_datagram(slave->master,
fsm_soe->datagram);
ec_slave_mbox_queue_datagrams(slave, fsm_soe->mbox);
return;
}
}
@ -1248,7 +1246,7 @@ void ec_fsm_slave_config_state_dc_sync_check(
abs_sync_diff = EC_READ_U32(datagram->data) & 0x7fffffff;
diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) {
if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) {
if (diff_ms >= EC_DC_SYNC_WAIT_MS) {
EC_SLAVE_WARN(slave, "Slave did not sync after %lu ms.\n",
@ -1454,8 +1452,7 @@ void ec_fsm_slave_config_enter_soe_conf_safeop(
ec_soe_request_write(&fsm->soe_request_copy);
ec_fsm_soe_transfer(fsm_soe, fsm->slave, &fsm->soe_request_copy);
ec_fsm_soe_exec(fsm_soe); // execute immediately
ec_master_queue_external_datagram(slave->master,
fsm_soe->datagram);
ec_slave_mbox_queue_datagrams(slave, fsm_soe->mbox);
return;
}
}
@ -1476,7 +1473,7 @@ void ec_fsm_slave_config_state_soe_conf_safeop(
ec_fsm_soe_t *fsm_soe = &slave->fsm.fsm_soe;
if (ec_fsm_soe_exec(fsm_soe)) {
ec_master_queue_external_datagram(slave->master, fsm_soe->datagram);
ec_slave_mbox_queue_datagrams(slave, fsm_soe->mbox);
return;
}
@ -1501,8 +1498,7 @@ void ec_fsm_slave_config_state_soe_conf_safeop(
ec_soe_request_write(&fsm->soe_request_copy);
ec_fsm_soe_transfer(fsm_soe, fsm->slave, &fsm->soe_request_copy);
ec_fsm_soe_exec(fsm_soe); // execute immediately
ec_master_queue_external_datagram(slave->master,
fsm_soe->datagram);
ec_slave_mbox_queue_datagrams(slave, fsm_soe->mbox);
return;
}
}

View File

@ -137,8 +137,8 @@ int ec_fsm_slave_scan_running(const ec_fsm_slave_scan_t *fsm /**< slave state ma
int ec_fsm_slave_scan_exec(ec_fsm_slave_scan_t *fsm /**< slave state machine */)
{
if (fsm->datagram->state == EC_DATAGRAM_SENT
|| fsm->datagram->state == EC_DATAGRAM_QUEUED) {
if (fsm->datagram->state == EC_DATAGRAM_QUEUED
|| fsm->datagram->state == EC_DATAGRAM_SENT) {
// datagram was not sent or received yet.
return ec_fsm_slave_scan_running(fsm);
}

View File

@ -106,11 +106,11 @@ void ec_print_soe_error(const ec_slave_t *slave, uint16_t error_code)
*/
void ec_fsm_soe_init(
ec_fsm_soe_t *fsm, /**< finite state machine */
ec_datagram_t *datagram /**< datagram */
ec_mailbox_t *mbox /**< mailbox */
)
{
fsm->state = NULL;
fsm->datagram = datagram;
fsm->mbox = mbox;
}
/*****************************************************************************/
@ -195,7 +195,7 @@ void ec_fsm_soe_print_error(ec_fsm_soe_t *fsm /**< Finite state machine */)
*/
void ec_fsm_soe_read_start(ec_fsm_soe_t *fsm /**< finite state machine */)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_slave_t *slave = fsm->slave;
ec_master_t *master = slave->master;
ec_soe_request_t *request = fsm->request;
@ -211,7 +211,7 @@ void ec_fsm_soe_read_start(ec_fsm_soe_t *fsm /**< finite state machine */)
return;
}
data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_SOE,
data = ec_slave_mbox_prepare_send(slave, mbox, EC_MBOX_TYPE_SOE,
EC_SOE_SIZE);
if (IS_ERR(data)) {
fsm->state = ec_fsm_soe_error;
@ -240,25 +240,25 @@ void ec_fsm_soe_read_start(ec_fsm_soe_t *fsm /**< finite state machine */)
*/
void ec_fsm_soe_read_request(ec_fsm_soe_t *fsm /**< finite state machine */)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_slave_t *slave = fsm->slave;
unsigned long diff_ms;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
if (ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_TIMED_OUT) && fsm->retries--)
return; // FIXME: check for response first?
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Failed to receive SoE read request: ");
ec_datagram_print_state(datagram);
ec_datagram_print_state(mbox->datagram);
ec_fsm_soe_print_error(fsm);
return;
}
diff_ms = (jiffies - fsm->request->jiffies_sent) * 1000 / HZ;
if (datagram->working_counter != 1) {
if (!datagram->working_counter) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
if (ec_mbox_is_datagram_wc(mbox,0)) {
if (diff_ms < EC_SOE_RESPONSE_TIMEOUT) {
// no response; send request datagram again
return;
@ -267,13 +267,13 @@ void ec_fsm_soe_read_request(ec_fsm_soe_t *fsm /**< finite state machine */)
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Reception of SoE read request"
" failed after %lu ms: ", diff_ms);
ec_datagram_print_wc_error(datagram);
ec_datagram_print_wc_error(mbox->datagram);
ec_fsm_soe_print_error(fsm);
return;
}
fsm->jiffies_start = datagram->jiffies_sent;
ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
fsm->jiffies_start = mbox->datagram->jiffies_sent;
ec_slave_mbox_prepare_check(slave, mbox); // can not fail.
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_soe_read_check;
}
@ -284,32 +284,32 @@ void ec_fsm_soe_read_request(ec_fsm_soe_t *fsm /**< finite state machine */)
*/
void ec_fsm_soe_read_check(ec_fsm_soe_t *fsm /**< finite state machine */)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_slave_t *slave = fsm->slave;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
if (ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_TIMED_OUT) && fsm->retries--)
return;
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Failed to receive SoE mailbox check datagram: ");
ec_datagram_print_state(datagram);
ec_datagram_print_state(mbox->datagram);
ec_fsm_soe_print_error(fsm);
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Reception of SoE mailbox check"
" datagram failed: ");
ec_datagram_print_wc_error(datagram);
ec_datagram_print_wc_error(mbox->datagram);
ec_fsm_soe_print_error(fsm);
return;
}
if (!ec_slave_mbox_check(datagram)) {
if (!ec_slave_mbox_check(mbox)) {
unsigned long diff_ms =
(datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
(mbox->datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
if (diff_ms >= EC_SOE_RESPONSE_TIMEOUT) {
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Timeout after %lu ms while waiting for"
@ -318,13 +318,13 @@ void ec_fsm_soe_read_check(ec_fsm_soe_t *fsm /**< finite state machine */)
return;
}
ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
ec_slave_mbox_prepare_check(slave, mbox); // can not fail.
fsm->retries = EC_FSM_RETRIES;
return;
}
// Fetch response
ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
ec_slave_mbox_prepare_fetch(slave, mbox); // can not fail.
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_soe_read_response;
}
@ -335,7 +335,7 @@ void ec_fsm_soe_read_check(ec_fsm_soe_t *fsm /**< finite state machine */)
*/
void ec_fsm_soe_read_response(ec_fsm_soe_t *fsm /**< finite state machine */)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_slave_t *slave = fsm->slave;
ec_master_t *master = slave->master;
uint8_t *data, mbox_prot, header, opcode, incomplete, error_flag,
@ -343,26 +343,26 @@ void ec_fsm_soe_read_response(ec_fsm_soe_t *fsm /**< finite state machine */)
size_t rec_size, data_size;
ec_soe_request_t *req = fsm->request;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
if (ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_TIMED_OUT) && fsm->retries--)
return; // FIXME: request again?
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Failed to receive SoE read response datagram: ");
ec_datagram_print_state(datagram);
ec_datagram_print_state(mbox->datagram);
ec_fsm_soe_print_error(fsm);
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Reception of SoE read response failed: ");
ec_datagram_print_wc_error(datagram);
ec_datagram_print_wc_error(mbox->datagram);
ec_fsm_soe_print_error(fsm);
return;
}
data = ec_slave_mbox_fetch(slave, datagram, &mbox_prot, &rec_size);
data = ec_slave_mbox_fetch(slave, mbox, &mbox_prot, &rec_size);
if (IS_ERR(data)) {
fsm->state = ec_fsm_soe_error;
ec_fsm_soe_print_error(fsm);
@ -435,8 +435,8 @@ void ec_fsm_soe_read_response(ec_fsm_soe_t *fsm /**< finite state machine */)
if (incomplete) {
EC_SLAVE_DBG(slave, 1, "SoE data incomplete. Waiting for fragment"
" at offset %zu.\n", req->data_size);
fsm->jiffies_start = datagram->jiffies_sent;
ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
fsm->jiffies_start = mbox->datagram->jiffies_sent;
ec_slave_mbox_prepare_check(slave, mbox); // can not fail.
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_soe_read_check;
} else {
@ -459,7 +459,7 @@ void ec_fsm_soe_write_next_fragment(
ec_fsm_soe_t *fsm /**< finite state machine */
)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_slave_t *slave = fsm->slave;
ec_master_t *master = slave->master;
ec_soe_request_t *req = fsm->request;
@ -485,7 +485,7 @@ void ec_fsm_soe_write_next_fragment(
fragments_left++;
}
data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_SOE,
data = ec_slave_mbox_prepare_send(slave, mbox, EC_MBOX_TYPE_SOE,
EC_SOE_SIZE + fragment_size);
if (IS_ERR(data)) {
fsm->state = ec_fsm_soe_error;
@ -539,25 +539,25 @@ void ec_fsm_soe_write_start(ec_fsm_soe_t *fsm /**< finite state machine */)
*/
void ec_fsm_soe_write_request(ec_fsm_soe_t *fsm /**< finite state machine */)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_slave_t *slave = fsm->slave;
unsigned long diff_ms;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
if (ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_TIMED_OUT) && fsm->retries--)
return; // FIXME: check for response first?
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Failed to receive SoE write request: ");
ec_datagram_print_state(datagram);
ec_datagram_print_state(mbox->datagram);
ec_fsm_soe_print_error(fsm);
return;
}
diff_ms = (jiffies - fsm->request->jiffies_sent) * 1000 / HZ;
if (datagram->working_counter != 1) {
if (!datagram->working_counter) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
if (ec_mbox_is_datagram_wc(mbox,0)) {
if (diff_ms < EC_SOE_RESPONSE_TIMEOUT) {
// no response; send request datagram again
return;
@ -566,14 +566,14 @@ void ec_fsm_soe_write_request(ec_fsm_soe_t *fsm /**< finite state machine */)
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Reception of SoE write request"
" failed after %lu ms: ", diff_ms);
ec_datagram_print_wc_error(datagram);
ec_datagram_print_wc_error(mbox->datagram);
ec_fsm_soe_print_error(fsm);
return;
}
fsm->jiffies_start = datagram->jiffies_sent;
fsm->jiffies_start = mbox->datagram->jiffies_sent;
ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
ec_slave_mbox_prepare_check(slave, mbox); // can not fail.
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_soe_write_check;
}
@ -584,25 +584,25 @@ void ec_fsm_soe_write_request(ec_fsm_soe_t *fsm /**< finite state machine */)
*/
void ec_fsm_soe_write_check(ec_fsm_soe_t *fsm /**< finite state machine */)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_slave_t *slave = fsm->slave;
ec_soe_request_t *req = fsm->request;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
if (ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_TIMED_OUT) && fsm->retries--)
return;
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Failed to receive SoE write request datagram: ");
ec_datagram_print_state(datagram);
ec_datagram_print_state(mbox->datagram);
ec_fsm_soe_print_error(fsm);
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Reception of SoE write request datagram: ");
ec_datagram_print_wc_error(datagram);
ec_datagram_print_wc_error(mbox->datagram);
ec_fsm_soe_print_error(fsm);
return;
}
@ -610,9 +610,9 @@ void ec_fsm_soe_write_check(ec_fsm_soe_t *fsm /**< finite state machine */)
if (fsm->offset < req->data_size) {
ec_fsm_soe_write_next_fragment(fsm);
} else {
if (!ec_slave_mbox_check(datagram)) {
if (!ec_slave_mbox_check(mbox)) {
unsigned long diff_ms =
(datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
(mbox->datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
if (diff_ms >= EC_SOE_RESPONSE_TIMEOUT) {
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Timeout after %lu ms while waiting"
@ -621,13 +621,13 @@ void ec_fsm_soe_write_check(ec_fsm_soe_t *fsm /**< finite state machine */)
return;
}
ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
ec_slave_mbox_prepare_check(slave, mbox); // can not fail.
fsm->retries = EC_FSM_RETRIES;
return;
}
// Fetch response
ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
ec_slave_mbox_prepare_fetch(slave, mbox); // can not fail.
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_soe_write_response;
}
@ -639,7 +639,7 @@ void ec_fsm_soe_write_check(ec_fsm_soe_t *fsm /**< finite state machine */)
*/
void ec_fsm_soe_write_response(ec_fsm_soe_t *fsm /**< finite state machine */)
{
ec_datagram_t *datagram = fsm->datagram;
ec_mailbox_t *mbox = fsm->mbox;
ec_slave_t *slave = fsm->slave;
ec_master_t *master = slave->master;
ec_soe_request_t *req = fsm->request;
@ -647,27 +647,27 @@ void ec_fsm_soe_write_response(ec_fsm_soe_t *fsm /**< finite state machine */)
uint16_t idn;
size_t rec_size;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
if (ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_TIMED_OUT) && fsm->retries--)
return; // FIXME: request again?
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Failed to receive SoE write"
" response datagram: ");
ec_datagram_print_state(datagram);
ec_datagram_print_state(mbox->datagram);
ec_fsm_soe_print_error(fsm);
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
fsm->state = ec_fsm_soe_error;
EC_SLAVE_ERR(slave, "Reception of SoE write response failed: ");
ec_datagram_print_wc_error(datagram);
ec_datagram_print_wc_error(mbox->datagram);
ec_fsm_soe_print_error(fsm);
return;
}
data = ec_slave_mbox_fetch(slave, datagram, &mbox_prot, &rec_size);
data = ec_slave_mbox_fetch(slave, mbox, &mbox_prot, &rec_size);
if (IS_ERR(data)) {
fsm->state = ec_fsm_soe_error;
ec_fsm_soe_print_error(fsm);

View File

@ -50,7 +50,7 @@ typedef struct ec_fsm_soe ec_fsm_soe_t; /**< \see ec_fsm_soe */
*/
struct ec_fsm_soe {
ec_slave_t *slave; /**< slave the FSM runs on */
ec_datagram_t *datagram; /**< datagram used in the state machine */
ec_mailbox_t *mbox; /**< mailbox used in the state machine */
unsigned int retries; /**< retries upon datagram timeout */
void (*state)(ec_fsm_soe_t *); /**< CoE state function */
@ -61,7 +61,7 @@ struct ec_fsm_soe {
/*****************************************************************************/
void ec_fsm_soe_init(ec_fsm_soe_t *, ec_datagram_t *);
void ec_fsm_soe_init(ec_fsm_soe_t *, ec_mailbox_t *);
void ec_fsm_soe_clear(ec_fsm_soe_t *);
void ec_fsm_soe_transfer(ec_fsm_soe_t *, ec_slave_t *, ec_soe_request_t *);

View File

@ -39,6 +39,17 @@
#include "../globals.h"
#include "../include/ecrt.h"
#ifdef __KERNEL__
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
#include <linux/rtmutex.h>
#endif // KERNEL_VERSION(2,6,24)
#endif // __KERNEL__
#ifdef CONFIG_TRACING
//#define USE_TRACE_PRINTK
#endif
/******************************************************************************
* EtherCAT master
*****************************************************************************/
@ -46,8 +57,8 @@
/** Datagram timeout in microseconds. */
#define EC_IO_TIMEOUT 500
/** SDO injection timeout in microseconds. */
#define EC_SDO_INJECTION_TIMEOUT 10000
/** FSM injection timeout in microseconds. */
#define EC_FSM_INJECTION_TIMEOUT 10000
/** Time to send a byte in nanoseconds.
*
@ -97,9 +108,6 @@
/** Word offset of first SII category. */
#define EC_FIRST_SII_CATEGORY_OFFSET 0x40
/** Maximum number of slave ports. */
#define EC_MAX_PORTS 4
/** Size of a sync manager configuration page. */
#define EC_SYNC_PAGE_SIZE 8
@ -173,23 +181,6 @@ typedef struct {
uint8_t enable_not_lrw : 1; /**< Slave does not support LRW. */
} ec_sii_general_flags_t;
/** EtherCAT slave port descriptor.
*/
typedef enum {
EC_PORT_NOT_IMPLEMENTED,
EC_PORT_NOT_CONFIGURED,
EC_PORT_EBUS,
EC_PORT_MII
} ec_slave_port_desc_t;
/** EtherCAT slave port information.
*/
typedef struct {
uint8_t link_up; /**< Link detected. */
uint8_t loop_closed; /**< Loop closed. */
uint8_t signal_detected; /**< Detected signal on RX port. */
} ec_slave_port_link_t;
/** EtherCAT slave distributed clocks range.
*/
typedef enum {
@ -325,4 +316,60 @@ typedef struct ec_slave ec_slave_t; /**< \see ec_slave. */
/*****************************************************************************/
/*****************************************************************************/
#ifdef __KERNEL__
/** Mutual exclusion helpers.
*
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
#define ec_mutex_t rt_mutex
static inline void ec_mutex_init(struct ec_mutex_t *mutex)
{
rt_mutex_init(mutex);
}
static inline void ec_mutex_lock(struct ec_mutex_t *mutex)
{
rt_mutex_lock(mutex);
}
static inline int ec_mutex_trylock(struct ec_mutex_t *mutex)
{
return rt_mutex_trylock(mutex);
}
static inline int ec_mutex_lock_interruptible(struct ec_mutex_t *mutex)
{
return rt_mutex_lock_interruptible(mutex,0);
}
static inline void ec_mutex_unlock(struct ec_mutex_t *mutex)
{
rt_mutex_unlock(mutex);
}
#else // < KERNEL_VERSION(2,6,24)
#define ec_mutex_t semaphore
static inline void ec_mutex_init(struct ec_mutex_t *sem)
{
sema_init(sem, 1);
}
static inline void ec_mutex_lock(struct ec_mutex_t *sem)
{
down(sem);
}
static inline int ec_mutex_trylock(struct ec_mutex_t *sem)
{
down(sem);
return 1;
}
static inline int ec_mutex_lock_interruptible(struct ec_mutex_t *sem)
{
return down_interruptible(sem);
}
static inline void ec_mutex_unlock(struct ec_mutex_t *sem)
{
up(sem);
}
#endif // KERNEL_VERSION(2,6,24)
#endif // __KERNEL__
#endif

View File

@ -56,7 +56,7 @@
*
* Increment this when changing the ioctl interface!
*/
#define EC_IOCTL_VERSION_MAGIC 11
#define EC_IOCTL_VERSION_MAGIC 12
// Command-line tool
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
@ -137,6 +137,8 @@
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x47, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_DATA EC_IOWR(0x48, ec_ioctl_voe_t)
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x49, size_t)
#define EC_IOCTL_MASTER_SC_STATE EC_IOR(0x50, ec_master_state_t)
#define EC_IOCTL_SC_OVERLAPPING_IO EC_IOW(0x51, ec_ioctl_config_t)
/*****************************************************************************/
@ -278,6 +280,7 @@ typedef struct {
// outputs
uint32_t data_size;
uint32_t tx_size;
uint32_t logical_base_address;
uint16_t working_counter;
uint16_t expected_working_counter;
@ -297,6 +300,7 @@ typedef struct {
uint8_t sync_index;
ec_direction_t dir;
uint32_t logical_address;
uint32_t domain_address;
uint32_t data_size;
} ec_ioctl_domain_fmmu_t;
@ -459,6 +463,7 @@ typedef struct {
} syncs[EC_MAX_SYNC_MANAGERS];
uint16_t watchdog_divider;
uint16_t watchdog_intervals;
uint8_t allow_overlapping_pdos;
uint32_t sdo_count;
uint32_t idn_count;
int32_t slave_position;

View File

@ -37,10 +37,84 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include "slave.h"
#include "mailbox.h"
#include "datagram.h"
#include "master.h"
/*****************************************************************************/
/**
Mailbox constructor.
*/
void ec_mbox_init(ec_mailbox_t* mbox, /** mailbox */
ec_datagram_t* datagram /**< Datagram used for the mailbox content. */
)
{
mbox->datagram = datagram;
#ifdef EC_REDUCE_MBOXFRAMESIZE
ec_datagram_init(&mbox->end_datagram);
#endif
}
/*****************************************************************************/
/**
Clears mailbox datagrams.
*/
void ec_mbox_clear(ec_mailbox_t* mbox /** mailbox */
)
{
#ifdef EC_REDUCE_MBOXFRAMESIZE
ec_datagram_clear(&mbox->end_datagram);
#endif
}
/*****************************************************************************/
/**
Queues the slave datagrams.
*/
void ec_slave_mbox_queue_datagrams(const ec_slave_t* slave, /** slave */
ec_mailbox_t* mbox /** mailbox */
)
{
ec_master_queue_request_fsm_datagram(slave->master, mbox->datagram);
#ifdef EC_REDUCE_MBOXFRAMESIZE
if (mbox->end_datagram.type != EC_DATAGRAM_NONE)
{
ec_master_queue_request_fsm_datagram(slave->master, &mbox->end_datagram);
}
#endif
}
/*****************************************************************************/
/**
Queues the datagrams.
*/
void ec_master_mbox_queue_datagrams(ec_master_t* master, /** master */
ec_mailbox_t* mbox /** mailbox */
)
{
ec_master_queue_fsm_datagram(master, mbox->datagram);
#ifdef EC_REDUCE_MBOXFRAMESIZE
if (mbox->end_datagram.type != EC_DATAGRAM_NONE)
{
ec_master_queue_fsm_datagram(master, &mbox->end_datagram);
}
#endif
}
/*****************************************************************************/
/**
@ -48,12 +122,13 @@
\return Pointer to mailbox datagram data, or ERR_PTR() code.
*/
uint8_t *ec_slave_mbox_prepare_send(const ec_slave_t *slave, /**< slave */
ec_datagram_t *datagram, /**< datagram */
uint8_t *ec_slave_mbox_prepare_send(const ec_slave_t* slave, /** slave */
ec_mailbox_t* mbox, /** mailbox */
uint8_t type, /**< mailbox protocol */
size_t size /**< size of the data */
)
{
ec_datagram_t* datagram = mbox->datagram;
size_t total_size;
int ret;
@ -72,8 +147,13 @@ uint8_t *ec_slave_mbox_prepare_send(const ec_slave_t *slave, /**< slave */
}
ret = ec_datagram_fpwr(datagram, slave->station_address,
slave->configured_rx_mailbox_offset,
slave->configured_rx_mailbox_size);
slave->configured_rx_mailbox_offset,
#ifdef EC_REDUCE_MBOXFRAMESIZE
total_size
#else
slave->configured_rx_mailbox_size
#endif
);
if (ret)
return ERR_PTR(ret);
@ -82,6 +162,17 @@ uint8_t *ec_slave_mbox_prepare_send(const ec_slave_t *slave, /**< slave */
EC_WRITE_U8 (datagram->data + 4, 0x00); // channel & priority
EC_WRITE_U8 (datagram->data + 5, type); // underlying protocol type
#ifdef EC_REDUCE_MBOXFRAMESIZE
/* in order to fulfil the ESC's mailbox protocol,
at least the last byte of the mailbox must be written */
if (total_size < slave->configured_rx_mailbox_size) {
ret = ec_datagram_fpwr(&mbox->end_datagram, slave->station_address,
slave->configured_rx_mailbox_offset+slave->configured_rx_mailbox_size-1,
1);
if (ret)
return ERR_PTR(ret);
}
#endif
return datagram->data + EC_MBOX_HEADER_SIZE;
}
@ -93,15 +184,19 @@ uint8_t *ec_slave_mbox_prepare_send(const ec_slave_t *slave, /**< slave */
\return 0 in case of success, else < 0
*/
int ec_slave_mbox_prepare_check(const ec_slave_t *slave, /**< slave */
ec_datagram_t *datagram /**< datagram */
int ec_slave_mbox_prepare_check(const ec_slave_t* slave, /** slave */
ec_mailbox_t* mbox /** mailbox */
)
{
ec_datagram_t* datagram = mbox->datagram;
int ret = ec_datagram_fprd(datagram, slave->station_address, 0x808, 8);
if (ret)
return ret;
ec_datagram_zero(datagram);
#ifdef EC_REDUCE_MBOXFRAMESIZE
mbox->end_datagram.type = EC_DATAGRAM_NONE;
#endif
return 0;
}
@ -112,9 +207,9 @@ int ec_slave_mbox_prepare_check(const ec_slave_t *slave, /**< slave */
\return 0 in case of success, else < 0
*/
int ec_slave_mbox_check(const ec_datagram_t *datagram /**< datagram */)
int ec_slave_mbox_check(ec_mailbox_t* mbox /** mailbox */)
{
return EC_READ_U8(datagram->data + 5) & 8 ? 1 : 0;
return EC_READ_U8(mbox->datagram->data + 5) & 8 ? 1 : 0;
}
/*****************************************************************************/
@ -124,10 +219,11 @@ int ec_slave_mbox_check(const ec_datagram_t *datagram /**< datagram */)
\return 0 in case of success, else < 0
*/
int ec_slave_mbox_prepare_fetch(const ec_slave_t *slave, /**< slave */
ec_datagram_t *datagram /**< datagram */
int ec_slave_mbox_prepare_fetch(const ec_slave_t* slave, /** slave */
ec_mailbox_t* mbox /** mailbox */
)
{
ec_datagram_t* datagram = mbox->datagram;
int ret = ec_datagram_fprd(datagram, slave->station_address,
slave->configured_tx_mailbox_offset,
slave->configured_tx_mailbox_size);
@ -135,6 +231,9 @@ int ec_slave_mbox_prepare_fetch(const ec_slave_t *slave, /**< slave */
return ret;
ec_datagram_zero(datagram);
#ifdef EC_REDUCE_MBOXFRAMESIZE
mbox->end_datagram.type = EC_DATAGRAM_NONE;
#endif
return 0;
}
@ -162,12 +261,13 @@ const ec_code_msg_t mbox_error_messages[] = {
*
* \return Pointer to the received data, or ERR_PTR() code.
*/
uint8_t *ec_slave_mbox_fetch(const ec_slave_t *slave, /**< slave */
ec_datagram_t *datagram, /**< datagram */
uint8_t *ec_slave_mbox_fetch(const ec_slave_t* slave, /** slave */
ec_mailbox_t* mbox, /** mailbox */
uint8_t *type, /**< expected mailbox protocol */
size_t *size /**< size of the received data */
)
{
ec_datagram_t* datagram = mbox->datagram;
size_t data_size;
data_size = EC_READ_U16(datagram->data);

View File

@ -37,7 +37,8 @@
#ifndef __EC_MAILBOX_H__
#define __EC_MAILBOX_H__
#include "slave.h"
#include "globals.h"
#include "datagram.h"
/*****************************************************************************/
@ -47,12 +48,53 @@
/*****************************************************************************/
uint8_t *ec_slave_mbox_prepare_send(const ec_slave_t *, ec_datagram_t *,
/** EtherCAT slave mailbox.
*/
struct ec_mailbox
{
ec_datagram_t* datagram; /**< Datagram used for the mailbox content. */
#ifdef EC_REDUCE_MBOXFRAMESIZE
ec_datagram_t end_datagram; /**< Datagram used for writing the end byte to the mailbox. */
#endif
};
typedef struct ec_mailbox ec_mailbox_t; /**< \see ec_mailbox. */
/*****************************************************************************/
void ec_mbox_init(ec_mailbox_t *, ec_datagram_t*);
void ec_mbox_clear(ec_mailbox_t*);
/**
Checks the datagrams states.
*/
static inline int ec_mbox_is_datagram_state(ec_mailbox_t*mbox,
ec_datagram_state_t state) {
return (mbox->datagram->state == state)
#ifdef EC_REDUCE_MBOXFRAMESIZE
&& (mbox->end_datagram.type == EC_DATAGRAM_NONE || mbox->end_datagram.state == state)
#endif
;
}
/**
Checks the datagrams working counter.
*/
static inline int ec_mbox_is_datagram_wc(ec_mailbox_t*mbox,
size_t wc) {
return (mbox->datagram->working_counter == wc)
#ifdef EC_REDUCE_MBOXFRAMESIZE
&& (mbox->end_datagram.type == EC_DATAGRAM_NONE || mbox->end_datagram.working_counter == wc)
#endif
;
}
void ec_slave_mbox_queue_datagrams(const ec_slave_t*,ec_mailbox_t*);
void ec_master_mbox_queue_datagrams(ec_master_t*, ec_mailbox_t*);
uint8_t *ec_slave_mbox_prepare_send(const ec_slave_t*,ec_mailbox_t *,
uint8_t, size_t);
int ec_slave_mbox_prepare_check(const ec_slave_t *, ec_datagram_t *);
int ec_slave_mbox_check(const ec_datagram_t *);
int ec_slave_mbox_prepare_fetch(const ec_slave_t *, ec_datagram_t *);
uint8_t *ec_slave_mbox_fetch(const ec_slave_t *, ec_datagram_t *,
int ec_slave_mbox_prepare_check(const ec_slave_t*,ec_mailbox_t *);
int ec_slave_mbox_check(ec_mailbox_t *);
int ec_slave_mbox_prepare_fetch(const ec_slave_t*,ec_mailbox_t *);
uint8_t *ec_slave_mbox_fetch(const ec_slave_t*,ec_mailbox_t *,
uint8_t *, size_t *);
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

View File

@ -43,18 +43,13 @@
#include <linux/wait.h>
#include <linux/kthread.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
#include <linux/semaphore.h>
#else
#include <asm/semaphore.h>
#endif
#include "device.h"
#include "domain.h"
#include "ethernet.h"
#include "fsm_master.h"
#include "cdev.h"
/*****************************************************************************/
/** Convenience macro for printing master-specific information to syslog.
@ -66,8 +61,16 @@
* \param fmt format string (like in printf())
* \param args arguments (optional)
*/
#ifdef USE_TRACE_PRINTK
#define EC_MASTER_INFO(master, fmt, args...) \
do { \
__trace_printk(_THIS_IP_,"EtherCAT %u: " fmt, master->index, ##args); \
printk(KERN_INFO "EtherCAT %u: " fmt, master->index, ##args); \
} while (0)
#else
#define EC_MASTER_INFO(master, fmt, args...) \
printk(KERN_INFO "EtherCAT %u: " fmt, master->index, ##args)
#endif
/** Convenience macro for printing master-specific errors to syslog.
*
@ -78,8 +81,16 @@
* \param fmt format string (like in printf())
* \param args arguments (optional)
*/
#ifdef USE_TRACE_PRINTK
#define EC_MASTER_ERR(master, fmt, args...) \
do { \
__trace_printk(_THIS_IP_,"EtherCAT ERROR %u: " fmt, master->index, ##args); \
printk(KERN_ERR "EtherCAT ERROR %u: " fmt, master->index, ##args); \
} while (0)
#else
#define EC_MASTER_ERR(master, fmt, args...) \
printk(KERN_ERR "EtherCAT ERROR %u: " fmt, master->index, ##args)
#endif
/** Convenience macro for printing master-specific warnings to syslog.
*
@ -90,8 +101,16 @@
* \param fmt format string (like in printf())
* \param args arguments (optional)
*/
#ifdef USE_TRACE_PRINTK
#define EC_MASTER_WARN(master, fmt, args...) \
do { \
__trace_printk(_THIS_IP_,"EtherCAT WARNING %u: " fmt, master->index, ##args); \
printk(KERN_WARNING "EtherCAT WARNING %u: " fmt, master->index, ##args); \
} while (0)
#else
#define EC_MASTER_WARN(master, fmt, args...) \
printk(KERN_WARNING "EtherCAT WARNING %u: " fmt, master->index, ##args)
#endif
/** Convenience macro for printing master-specific debug messages to syslog.
*
@ -102,6 +121,17 @@
* \param fmt format string (like in printf())
* \param args arguments (optional)
*/
#ifdef USE_TRACE_PRINTK
#define EC_MASTER_DBG(master, level, fmt, args...) \
do { \
__trace_printk(_THIS_IP_,"EtherCAT DEBUG%u %u: " fmt, \
level,master->index, ##args); \
if (master->debug_level >= level) { \
printk(KERN_DEBUG "EtherCAT DEBUG %u: " fmt, \
master->index, ##args); \
} \
} while (0)
#else
#define EC_MASTER_DBG(master, level, fmt, args...) \
do { \
if (master->debug_level >= level) { \
@ -109,6 +139,7 @@
master->index, ##args); \
} \
} while (0)
#endif
/*****************************************************************************/
@ -152,16 +183,17 @@ struct ec_master {
struct class_device *class_device; /**< Master class device. */
#endif
struct semaphore master_sem; /**< Master semaphore. */
struct ec_mutex_t master_mutex; /**< Master mutex. */
ec_device_t main_device; /**< EtherCAT main device. */
const uint8_t *main_mac; /**< MAC address of main device. */
ec_device_t backup_device; /**< EtherCAT backup device. */
const uint8_t *backup_mac; /**< MAC address of backup device. */
struct semaphore device_sem; /**< Device semaphore. */
struct ec_mutex_t device_mutex; /**< Device mutex. */
ec_fsm_master_t fsm; /**< Master state machine. */
ec_datagram_t fsm_datagram; /**< Datagram used for state machines. */
ec_mailbox_t fsm_mbox; /**< Mailbox used for state machines. */
ec_master_phase_t phase; /**< Master phase. */
unsigned int active; /**< Master has been activated. */
unsigned int config_changed; /**< The configuration changed. */
@ -187,10 +219,14 @@ struct ec_master {
ec_datagram_t sync_mon_datagram; /**< Datagram used for DC synchronisation
monitoring. */
ec_slave_t *dc_ref_clock; /**< DC reference clock slave. */
#ifdef EC_HAVE_CYCLES
cycles_t dc_cycles_app_start_time; /** cycles at last ecrt_master_sync() call.*/
#endif
unsigned long dc_jiffies_app_start_time;/** jiffies at last
ecrt_master_sync() call.*/
unsigned int scan_busy; /**< Current scan state. */
unsigned int allow_scan; /**< \a True, if slave scanning is allowed. */
struct semaphore scan_sem; /**< Semaphore protecting the \a scan_busy
struct ec_mutex_t scan_mutex; /**< Mutex protecting the \a scan_busy
variable and the \a allow_scan flag. */
wait_queue_head_t scan_queue; /**< Queue for processes that wait for
slave scanning. */
@ -198,7 +234,7 @@ struct ec_master {
unsigned int config_busy; /**< State of slave configuration. */
unsigned int allow_config; /**< \a True, if slave configuration is
allowed. */
struct semaphore config_sem; /**< Semaphore protecting the \a config_busy
struct ec_mutex_t config_mutex; /**< Mutex protecting the \a config_busy
variable and the allow_config flag. */
wait_queue_head_t config_queue; /**< Queue for processes that wait for
slave configuration. */
@ -206,12 +242,10 @@ struct ec_master {
struct list_head datagram_queue; /**< Datagram queue. */
uint8_t datagram_index; /**< Current datagram index. */
struct list_head ext_datagram_queue; /**< Queue for non-application
datagrams. */
struct semaphore ext_queue_sem; /**< Semaphore protecting the \a
ext_datagram_queue. */
struct ec_mutex_t fsm_queue_mutex; /**< Mutex protecting the \a
fsm_datagram_queue. */
struct list_head fsm_datagram_queue; /**< External Datagram queue. */
struct list_head external_datagram_queue; /**< External Datagram queue. */
unsigned int send_interval; /**< Interval between calls to ecrt_master_send */
size_t max_queue_size; /**< Maximum size of datagram queue */
@ -225,16 +259,14 @@ struct ec_master {
struct list_head eoe_handlers; /**< Ethernet over EtherCAT handlers. */
#endif
struct semaphore io_sem; /**< Semaphore used in \a IDLE phase. */
struct ec_mutex_t io_mutex; /**< Mutex used in \a IDLE phase. */
void (*send_cb)(void *); /**< Current send datagrams callback. */
void (*receive_cb)(void *); /**< Current receive datagrams callback. */
void *cb_data; /**< Current callback data. */
void (*app_send_cb)(void *); /**< Application's send datagrams
callback. */
void (*app_receive_cb)(void *); /**< Application's receive datagrams
callback. */
void *app_cb_data; /**< Application callback data. */
void (*fsm_queue_lock_cb)(void *); /**< FSM queue lock callback. */
void (*fsm_queue_unlock_cb)(void *); /**< FSM queue unlock callback. */
void *fsm_queue_locking_data; /**< Data parameter of fsm queue locking callbacks. */
void (*app_fsm_queue_lock_cb)(void *); /**< App's FSM queue lock callback. */
void (*app_fsm_queue_unlock_cb)(void *); /**< App's FSM queue unlock callback. */
void *app_fsm_queue_locking_data; /**< App's data parameter of fsm queue locking callbacks. */
struct list_head sii_requests; /**< SII write requests. */
wait_queue_head_t sii_queue; /**< Wait queue for SII
@ -260,18 +292,12 @@ void ec_master_leave_idle_phase(ec_master_t *);
int ec_master_enter_operation_phase(ec_master_t *);
void ec_master_leave_operation_phase(ec_master_t *);
#ifdef EC_EOE
// EoE
void ec_master_eoe_start(ec_master_t *);
void ec_master_eoe_stop(ec_master_t *);
#endif
// datagram IO
void ec_master_receive_datagrams(ec_master_t *, const uint8_t *, size_t);
void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *);
void ec_master_queue_datagram_ext(ec_master_t *, ec_datagram_t *);
void ec_master_queue_external_datagram(ec_master_t *, ec_datagram_t *);
void ec_master_inject_external_datagrams(ec_master_t *);
void ec_master_queue_request_fsm_datagram(ec_master_t *, ec_datagram_t *);
void ec_master_queue_fsm_datagram(ec_master_t *, ec_datagram_t *);
void ec_master_inject_fsm_datagrams(ec_master_t *);
// misc.
void ec_master_set_send_interval(ec_master_t *, unsigned int);
@ -308,9 +334,6 @@ ec_slave_config_t *ecrt_master_slave_config_err(ec_master_t *, uint16_t,
void ec_master_calc_dc(ec_master_t *);
void ec_master_request_op(ec_master_t *);
void ec_master_internal_send_cb(void *);
void ec_master_internal_receive_cb(void *);
/*****************************************************************************/
#endif

View File

@ -61,7 +61,7 @@ static unsigned int backup_count; /**< Number of backup devices. */
static unsigned int debug_level; /**< Debug level parameter. */
static ec_master_t *masters; /**< Array of masters. */
static struct semaphore master_sem; /**< Master semaphore. */
static struct ec_mutex_t master_mutex; /**< Master mutex. */
dev_t device_number; /**< Device number for master cdevs. */
struct class *class; /**< Device class. */
@ -101,7 +101,7 @@ int __init ec_init_module(void)
EC_INFO("Master driver %s\n", EC_MASTER_VERSION);
sema_init(&master_sem, 1);
ec_mutex_init(&master_mutex);
if (master_count) {
if (alloc_chrdev_region(&device_number,
@ -468,9 +468,9 @@ ec_device_t *ecdev_offer(
for (i = 0; i < master_count; i++) {
master = &masters[i];
down(&master->device_sem);
ec_mutex_lock(&master->device_mutex);
if (master->main_device.dev) { // master already has a device
up(&master->device_sem);
ec_mutex_unlock(&master->device_mutex);
continue;
}
@ -481,14 +481,14 @@ ec_device_t *ecdev_offer(
str, master->index);
ec_device_attach(&master->main_device, net_dev, poll, module);
up(&master->device_sem);
ec_mutex_unlock(&master->device_mutex);
snprintf(net_dev->name, IFNAMSIZ, "ec%u", master->index);
return &master->main_device; // offer accepted
}
else {
up(&master->device_sem);
ec_mutex_unlock(&master->device_mutex);
if (master->debug_level) {
ec_mac_print(net_dev->dev_addr, str);
@ -524,40 +524,40 @@ ec_master_t *ecrt_request_master_err(
}
master = &masters[master_index];
if (down_interruptible(&master_sem)) {
if (ec_mutex_lock_interruptible(&master_mutex)) {
errptr = ERR_PTR(-EINTR);
goto out_return;
}
if (master->reserved) {
up(&master_sem);
ec_mutex_unlock(&master_mutex);
EC_MASTER_ERR(master, "Master already in use!\n");
errptr = ERR_PTR(-EBUSY);
goto out_return;
}
master->reserved = 1;
up(&master_sem);
ec_mutex_unlock(&master_mutex);
if (down_interruptible(&master->device_sem)) {
if (ec_mutex_lock_interruptible(&master->device_mutex)) {
errptr = ERR_PTR(-EINTR);
goto out_release;
}
if (master->phase != EC_IDLE) {
up(&master->device_sem);
ec_mutex_unlock(&master->device_mutex);
EC_MASTER_ERR(master, "Master still waiting for devices!\n");
errptr = ERR_PTR(-ENODEV);
goto out_release;
}
if (!try_module_get(master->main_device.module)) {
up(&master->device_sem);
ec_mutex_unlock(&master->device_mutex);
EC_ERR("Device module is unloading!\n");
errptr = ERR_PTR(-ENODEV);
goto out_release;
}
up(&master->device_sem);
ec_mutex_unlock(&master->device_mutex);
if (ec_master_enter_operation_phase(master)) {
EC_MASTER_ERR(master, "Failed to enter OPERATION phase!\n");
@ -611,6 +611,37 @@ unsigned int ecrt_version_magic(void)
return ECRT_VERSION_MAGIC;
}
/** Return pointer to running master
/*****************************************************************************/
ec_master_t *ecrt_attach_master(unsigned int master_index)
{
ec_master_t *master = NULL;
EC_INFO("Requesting master %u...\n", master_index);
if (master_index >= master_count) {
EC_ERR("Invalid master index %u.\n", master_index);
return master;
}
master = &masters[master_index];
if (master->reserved)
{
// ok master is attached
EC_INFO("attaching Master %u!\n", master_index);
}
else
{
EC_ERR("No Master %u in use!\n", master_index);
master = NULL;
}
return master;
}
/*****************************************************************************/
/** Global request state type translation table.
@ -637,6 +668,7 @@ EXPORT_SYMBOL(ecdev_offer);
EXPORT_SYMBOL(ecrt_request_master);
EXPORT_SYMBOL(ecrt_release_master);
EXPORT_SYMBOL(ecrt_version_magic);
EXPORT_SYMBOL(ecrt_attach_master);
/** \endcond */

View File

@ -159,19 +159,20 @@ void ec_slave_init(
INIT_LIST_HEAD(&slave->soe_requests);
init_waitqueue_head(&slave->soe_queue);
// init state machine datagram
ec_datagram_init(&slave->fsm_datagram);
snprintf(slave->fsm_datagram.name, EC_DATAGRAM_NAME_SIZE,
// init datagram
ec_datagram_init(&slave->datagram);
snprintf(slave->datagram.name, EC_DATAGRAM_NAME_SIZE,
"slave%u-fsm", slave->ring_position);
ret = ec_datagram_prealloc(&slave->fsm_datagram, EC_MAX_DATA_SIZE);
ret = ec_datagram_prealloc(&slave->datagram, EC_MAX_DATA_SIZE);
if (ret < 0) {
ec_datagram_clear(&slave->fsm_datagram);
ec_datagram_clear(&slave->datagram);
EC_SLAVE_ERR(slave, "Failed to allocate FSM datagram.\n");
return;
}
ec_mbox_init(&slave->mbox,&slave->datagram);
// create state machine object
ec_fsm_slave_init(&slave->fsm, slave, &slave->fsm_datagram);
ec_fsm_slave_init(&slave->fsm, slave, &slave->mbox);
}
/*****************************************************************************/
@ -194,9 +195,10 @@ void ec_slave_clear(ec_slave_t *slave /**< EtherCAT slave */)
list_entry(slave->slave_sdo_requests.next,
ec_master_sdo_request_t, list);
list_del_init(&request->list); // dequeue
EC_SLAVE_WARN(slave, "Discarding SDO request,"
" slave about to be deleted.\n");
EC_SLAVE_WARN(slave, "Discarding SDO request %p,"
" slave about to be deleted.\n",request);
request->req.state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_sdo_request_release);
wake_up(&slave->sdo_queue);
}
@ -208,6 +210,7 @@ void ec_slave_clear(ec_slave_t *slave /**< EtherCAT slave */)
EC_SLAVE_WARN(slave, "Discarding FoE request,"
" slave about to be deleted.\n");
request->req.state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_foe_request_release);
wake_up(&slave->foe_queue);
}
@ -219,6 +222,7 @@ void ec_slave_clear(ec_slave_t *slave /**< EtherCAT slave */)
EC_SLAVE_WARN(slave, "Discarding SoE request,"
" slave about to be deleted.\n");
request->req.state = EC_INT_REQUEST_FAILURE;
kref_put(&request->refcount,ec_master_soe_request_release);
wake_up(&slave->soe_queue);
}
@ -252,7 +256,7 @@ void ec_slave_clear(ec_slave_t *slave /**< EtherCAT slave */)
if (slave->sii_words)
kfree(slave->sii_words);
ec_fsm_slave_clear(&slave->fsm);
ec_datagram_clear(&slave->fsm_datagram);
ec_mbox_clear(&slave->mbox);
}
/*****************************************************************************/
@ -801,6 +805,59 @@ void ec_slave_attach_pdo_names(
}
}
/*****************************************************************************/
/** returns the previous connected port of a given port.
*/
unsigned int ec_slave_get_previous_port(
ec_slave_t *slave, /**< EtherCAT slave. */
unsigned int i /**< Port index */
)
{
do
{
switch (i)
{
case 0: i = 2; break;
case 1: i = 3; break;
case 2: i = 1; break;
case 3:
default:i = 0; break;
}
if (slave->ports[i].next_slave)
return i;
} while (i);
return 0;
}
/*****************************************************************************/
/** returns the next connected port of a given port.
*/
unsigned int ec_slave_get_next_port(
ec_slave_t *slave, /**< EtherCAT slave. */
unsigned int i /**< Port index */
)
{
do
{
switch (i)
{
case 0: i = 3; break;
case 1: i = 2; break;
case 3: i = 1; break;
case 2:
default:i = 0; break;
}
if (slave->ports[i].next_slave)
return i;
} while (i);
return 0;
}
/*****************************************************************************/
/** Calculates the sum of round-trip-times of connected ports 1-3.
@ -810,13 +867,11 @@ uint32_t ec_slave_calc_rtt_sum(
)
{
uint32_t rtt_sum = 0, rtt;
unsigned int i;
for (i = 1; i < EC_MAX_PORTS; i++) {
if (slave->ports[i].next_slave) {
rtt = slave->ports[i].receive_time - slave->ports[i - 1].receive_time;
rtt_sum += rtt;
}
unsigned int i = ec_slave_get_next_port(slave,0);
while (i != 0) {
rtt = slave->ports[i].receive_time - slave->ports[ec_slave_get_previous_port(slave,i)].receive_time;
rtt_sum += rtt;
i = ec_slave_get_next_port(slave,i);
}
return rtt_sum;
@ -830,20 +885,21 @@ ec_slave_t *ec_slave_find_next_dc_slave(
ec_slave_t *slave /**< EtherCAT slave. */
)
{
unsigned int i;
ec_slave_t *dc_slave = NULL;
if (slave->base_dc_supported) {
dc_slave = slave;
} else {
unsigned int i;
for (i = 1; i < EC_MAX_PORTS; i++) {
i = ec_slave_get_next_port(slave,0);
while (i != 0) {
ec_slave_t *next = slave->ports[i].next_slave;
if (next) {
dc_slave = ec_slave_find_next_dc_slave(next);
if (dc_slave)
break;
}
i = ec_slave_get_next_port(slave,i);
}
}
@ -859,32 +915,30 @@ void ec_slave_calc_port_delays(
)
{
unsigned int i;
ec_slave_t *next, *next_dc;
ec_slave_t *next_dc;
uint32_t rtt, next_rtt_sum;
if (!slave->base_dc_supported)
return;
for (i = 1; i < EC_MAX_PORTS; i++) {
next = slave->ports[i].next_slave;
if (!next)
continue;
next_dc = ec_slave_find_next_dc_slave(next);
if (!next_dc)
continue;
i = ec_slave_get_next_port(slave,0);
while (i != 0) {
next_dc = ec_slave_find_next_dc_slave(slave->ports[i].next_slave);
if (next_dc) {
rtt = slave->ports[i].receive_time - slave->ports[ec_slave_get_previous_port(slave,i)].receive_time;
next_rtt_sum = ec_slave_calc_rtt_sum(next_dc);
rtt = slave->ports[i].receive_time - slave->ports[i - 1].receive_time;
next_rtt_sum = ec_slave_calc_rtt_sum(next_dc);
slave->ports[i].delay_to_next_dc = (rtt - next_rtt_sum) / 2; // FIXME
next_dc->ports[0].delay_to_next_dc = (rtt - next_rtt_sum) / 2;
slave->ports[i].delay_to_next_dc = (rtt - next_rtt_sum) / 2; // FIXME
next_dc->ports[0].delay_to_next_dc = (rtt - next_rtt_sum) / 2;
#if 0
EC_SLAVE_DBG(slave, 1, "delay %u:%u rtt=%u"
" next_rtt_sum=%u delay=%u\n",
slave->ring_position, i, rtt, next_rtt_sum,
slave->ports[i].delay_to_next_dc);
EC_SLAVE_DBG(slave, 1, "delay %u:%u rtt=%u"
" next_rtt_sum=%u delay=%u\n",
slave->ring_position, i, rtt, next_rtt_sum,
slave->ports[i].delay_to_next_dc);
#endif
}
i = ec_slave_get_next_port(slave,i);
}
}
@ -898,28 +952,26 @@ void ec_slave_calc_transmission_delays_rec(
)
{
unsigned int i;
ec_slave_t *next, *next_dc;
ec_slave_t *next_dc;
#if 0
#if 1
EC_SLAVE_DBG(slave, 1, "%u\n", *delay);
#endif
slave->transmission_delay = *delay;
for (i = 1; i < EC_MAX_PORTS; i++) {
i = ec_slave_get_next_port(slave,0);
while (i != 0) {
ec_slave_port_t *port = &slave->ports[i];
next = port->next_slave;
if (!next)
continue;
next_dc = ec_slave_find_next_dc_slave(next);
if (!next_dc)
continue;
*delay = *delay + port->delay_to_next_dc;
next_dc = ec_slave_find_next_dc_slave(port->next_slave);
if (next_dc) {
*delay = *delay + port->delay_to_next_dc;
#if 0
EC_SLAVE_DBG(slave, 1, "%u:%u %u\n", slave->ring_position, i, *delay);
EC_SLAVE_DBG(slave, 1, "%u:%u %u\n", slave->ring_position, i, *delay);
#endif
ec_slave_calc_transmission_delays_rec(next_dc, delay);
ec_slave_calc_transmission_delays_rec(next_dc, delay);
}
i = ec_slave_get_next_port(slave,i);
}
*delay = *delay + slave->ports[0].delay_to_next_dc;

View File

@ -46,6 +46,7 @@
#include "sync.h"
#include "sdo.h"
#include "fsm_slave.h"
#include "mailbox.h"
/*****************************************************************************/
@ -59,9 +60,19 @@
* \param fmt format string (like in printf())
* \param args arguments (optional)
*/
#ifdef USE_TRACE_PRINTK
#define EC_SLAVE_INFO(slave, fmt, args...) \
do { \
__trace_printk(_THIS_IP_,"EtherCAT %u-%u: " fmt, slave->master->index, \
slave->ring_position, ##args); \
printk(KERN_INFO "EtherCAT %u-%u: " fmt, slave->master->index, \
slave->ring_position, ##args); \
} while (0)
#else
#define EC_SLAVE_INFO(slave, fmt, args...) \
printk(KERN_INFO "EtherCAT %u-%u: " fmt, slave->master->index, \
slave->ring_position, ##args)
#endif
/** Convenience macro for printing slave-specific errors to syslog.
*
@ -73,9 +84,19 @@
* \param fmt format string (like in printf())
* \param args arguments (optional)
*/
#ifdef USE_TRACE_PRINTK
#define EC_SLAVE_ERR(slave, fmt, args...) \
do { \
__trace_printk(_THIS_IP_,"EtherCAT ERROR %u-%u: " fmt, slave->master->index, \
slave->ring_position, ##args); \
printk(KERN_ERR "EtherCAT ERROR %u-%u: " fmt, slave->master->index, \
slave->ring_position, ##args); \
} while (0)
#else
#define EC_SLAVE_ERR(slave, fmt, args...) \
printk(KERN_ERR "EtherCAT ERROR %u-%u: " fmt, slave->master->index, \
slave->ring_position, ##args)
#endif
/** Convenience macro for printing slave-specific warnings to syslog.
*
@ -87,9 +108,19 @@
* \param fmt format string (like in printf())
* \param args arguments (optional)
*/
#ifdef USE_TRACE_PRINTK
#define EC_SLAVE_WARN(slave, fmt, args...) \
do { \
__trace_printk(_THIS_IP_,"EtherCAT WARNING %u-%u: " fmt, \
slave->master->index, slave->ring_position, ##args); \
printk(KERN_WARNING "EtherCAT WARNING %u-%u: " fmt, \
slave->master->index, slave->ring_position, ##args); \
} while (0)
#else
#define EC_SLAVE_WARN(slave, fmt, args...) \
printk(KERN_WARNING "EtherCAT WARNING %u-%u: " fmt, \
slave->master->index, slave->ring_position, ##args)
#endif
/** Convenience macro for printing slave-specific debug messages to syslog.
*
@ -101,6 +132,17 @@
* \param fmt format string (like in printf())
* \param args arguments (optional)
*/
#ifdef USE_TRACE_PRINTK
#define EC_SLAVE_DBG(slave, level, fmt, args...) \
do { \
__trace_printk(_THIS_IP_,"EtherCAT DEBUG%u %u-%u: " fmt, \
level,slave->master->index, slave->ring_position, ##args); \
if (slave->master->debug_level >= level) { \
printk(KERN_DEBUG "EtherCAT DEBUG %u-%u: " fmt, \
slave->master->index, slave->ring_position, ##args); \
} \
} while (0)
#else
#define EC_SLAVE_DBG(slave, level, fmt, args...) \
do { \
if (slave->master->debug_level >= level) { \
@ -108,6 +150,7 @@
slave->master->index, slave->ring_position, ##args); \
} \
} while (0)
#endif
/*****************************************************************************/
@ -232,7 +275,8 @@ struct ec_slave
wait_queue_head_t soe_queue; /**< Wait queue for SoE requests from user
space. */
ec_fsm_slave_t fsm; /**< Slave state machine. */
ec_datagram_t fsm_datagram; /**< Datagram used for state machines. */
ec_datagram_t datagram; /** Datagram used for data transfers */
ec_mailbox_t mbox; /**< Mailbox used for data transfers. */
};
/*****************************************************************************/

View File

@ -70,7 +70,7 @@ void ec_slave_config_init(
sc->product_code = product_code;
sc->watchdog_divider = 0; // use default
sc->watchdog_intervals = 0; // use default
sc->allow_overlapping_pdos = 0; // default not allowed
sc->slave = NULL;
for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++)
@ -164,12 +164,15 @@ int ec_slave_config_prepare_fmmu(
{
unsigned int i;
ec_fmmu_config_t *fmmu;
ec_fmmu_config_t *prev_fmmu;
uint32_t fmmu_logical_start_address;
size_t tx_size, old_prev_tx_size;
// FMMU configuration already prepared?
for (i = 0; i < sc->used_fmmus; i++) {
fmmu = &sc->fmmu_configs[i];
if (fmmu->domain == domain && fmmu->sync_index == sync_index)
return fmmu->logical_start_address;
return fmmu->domain_address;
}
if (sc->used_fmmus == EC_MAX_FMMUS) {
@ -177,13 +180,29 @@ int ec_slave_config_prepare_fmmu(
return -EOVERFLOW;
}
fmmu = &sc->fmmu_configs[sc->used_fmmus++];
fmmu = &sc->fmmu_configs[sc->used_fmmus];
down(&sc->master->master_sem);
ec_fmmu_config_init(fmmu, sc, domain, sync_index, dir);
up(&sc->master->master_sem);
ec_mutex_lock(&sc->master->master_mutex);
ec_fmmu_config_init(fmmu, sc, sync_index, dir);
fmmu_logical_start_address = domain->tx_size;
tx_size = fmmu->data_size;
if (sc->allow_overlapping_pdos && sc->used_fmmus > 0) {
prev_fmmu = &sc->fmmu_configs[sc->used_fmmus-1];
if (fmmu->dir != prev_fmmu->dir && prev_fmmu->tx_size != 0) {
// prev fmmu has opposite direction
// and is not already paired with prev-prev fmmu
old_prev_tx_size = prev_fmmu->tx_size;
prev_fmmu->tx_size = max(fmmu->data_size,prev_fmmu->data_size);
domain->tx_size += prev_fmmu->tx_size - old_prev_tx_size;
tx_size = 0;
fmmu_logical_start_address = prev_fmmu->logical_start_address;
}
}
ec_fmmu_config_domain(fmmu,domain,fmmu_logical_start_address,tx_size);
ec_mutex_unlock(&sc->master->master_mutex);
return fmmu->logical_start_address;
++sc->used_fmmus;
return fmmu->domain_address;
}
/*****************************************************************************/
@ -227,8 +246,6 @@ int ec_slave_config_attach(
slave->config = sc;
sc->slave = slave;
ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
EC_CONFIG_DBG(sc, 1, "Attached slave %u.\n", slave->ring_position);
return 0;
@ -494,6 +511,18 @@ void ecrt_slave_config_watchdog(ec_slave_config_t *sc,
/*****************************************************************************/
void ecrt_slave_config_overlapping_pdos(ec_slave_config_t *sc,
uint8_t allow_overlapping_pdos )
{
if (sc->master->debug_level)
EC_DBG("%s(sc = 0x%p, allow_overlapping_pdos = %u)\n",
__func__, sc, allow_overlapping_pdos);
sc->allow_overlapping_pdos = allow_overlapping_pdos;
}
/*****************************************************************************/
int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc,
uint8_t sync_index, uint16_t pdo_index)
{
@ -507,18 +536,18 @@ int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc,
return -EINVAL;
}
down(&sc->master->master_sem);
ec_mutex_lock(&sc->master->master_mutex);
pdo = ec_pdo_list_add_pdo(&sc->sync_configs[sync_index].pdos, pdo_index);
if (IS_ERR(pdo)) {
up(&sc->master->master_sem);
ec_mutex_unlock(&sc->master->master_mutex);
return PTR_ERR(pdo);
}
pdo->sync_index = sync_index;
ec_slave_config_load_default_mapping(sc, pdo);
up(&sc->master->master_sem);
ec_mutex_unlock(&sc->master->master_mutex);
return 0;
}
@ -535,9 +564,9 @@ void ecrt_slave_config_pdo_assign_clear(ec_slave_config_t *sc,
return;
}
down(&sc->master->master_sem);
ec_mutex_lock(&sc->master->master_mutex);
ec_pdo_list_clear_pdos(&sc->sync_configs[sync_index].pdos);
up(&sc->master->master_sem);
ec_mutex_unlock(&sc->master->master_mutex);
}
/*****************************************************************************/
@ -563,10 +592,10 @@ int ecrt_slave_config_pdo_mapping_add(ec_slave_config_t *sc,
break;
if (pdo) {
down(&sc->master->master_sem);
ec_mutex_lock(&sc->master->master_mutex);
entry = ec_pdo_add_entry(pdo, entry_index, entry_subindex,
entry_bit_length);
up(&sc->master->master_sem);
ec_mutex_unlock(&sc->master->master_mutex);
if (IS_ERR(entry))
retval = PTR_ERR(entry);
} else {
@ -594,9 +623,9 @@ void ecrt_slave_config_pdo_mapping_clear(ec_slave_config_t *sc,
break;
if (pdo) {
down(&sc->master->master_sem);
ec_mutex_lock(&sc->master->master_mutex);
ec_pdo_clear_entries(pdo);
up(&sc->master->master_sem);
ec_mutex_unlock(&sc->master->master_mutex);
} else {
EC_CONFIG_WARN(sc, "PDO 0x%04X is not assigned.\n", pdo_index);
}
@ -685,10 +714,6 @@ int ecrt_slave_config_reg_pdo_entry(
ec_pdo_entry_t *entry;
int sync_offset;
EC_CONFIG_DBG(sc, 1, "%s(sc = 0x%p, index = 0x%04X, "
"subindex = 0x%02X, domain = 0x%p, bit_position = 0x%p)\n",
__func__, sc, index, subindex, domain, bit_position);
for (sync_index = 0; sync_index < EC_MAX_SYNC_MANAGERS; sync_index++) {
sync_config = &sc->sync_configs[sync_index];
bit_offset = 0;
@ -712,7 +737,11 @@ int ecrt_slave_config_reg_pdo_entry(
if (sync_offset < 0)
return sync_offset;
return sync_offset + bit_offset / 8;
EC_CONFIG_DBG(sc, 1, "%s(index = 0x%04X, "
"subindex = 0x%02X, domain = %u, bytepos=%u, bitpos=%u)\n",
__func__,index, subindex,
domain->index, sync_offset + bit_offset / 8, bit_pos);
return sync_offset + bit_offset / 8;
}
}
}
@ -776,9 +805,9 @@ int ecrt_slave_config_sdo(ec_slave_config_t *sc, uint16_t index,
return ret;
}
down(&sc->master->master_sem);
ec_mutex_lock(&sc->master->master_mutex);
list_add_tail(&req->list, &sc->sdo_configs);
up(&sc->master->master_sem);
ec_mutex_unlock(&sc->master->master_mutex);
return 0;
}
@ -861,9 +890,9 @@ int ecrt_slave_config_complete_sdo(ec_slave_config_t *sc, uint16_t index,
return ret;
}
down(&sc->master->master_sem);
ec_mutex_lock(&sc->master->master_mutex);
list_add_tail(&req->list, &sc->sdo_configs);
up(&sc->master->master_sem);
ec_mutex_unlock(&sc->master->master_mutex);
return 0;
}
@ -902,9 +931,9 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request_err(
memset(req->data, 0x00, size);
req->data_size = size;
down(&sc->master->master_sem);
ec_mutex_lock(&sc->master->master_mutex);
list_add_tail(&req->list, &sc->sdo_requests);
up(&sc->master->master_sem);
ec_mutex_unlock(&sc->master->master_mutex);
return req;
}
@ -944,9 +973,9 @@ ec_voe_handler_t *ecrt_slave_config_create_voe_handler_err(
return ERR_PTR(ret);
}
down(&sc->master->master_sem);
ec_mutex_lock(&sc->master->master_mutex);
list_add_tail(&voe->list, &sc->voe_handlers);
up(&sc->master->master_sem);
ec_mutex_unlock(&sc->master->master_mutex);
return voe;
}
@ -1027,9 +1056,9 @@ int ecrt_slave_config_idn(ec_slave_config_t *sc, uint8_t drive_no,
return ret;
}
down(&sc->master->master_sem);
ec_mutex_lock(&sc->master->master_mutex);
list_add_tail(&req->list, &sc->soe_configs);
up(&sc->master->master_sem);
ec_mutex_unlock(&sc->master->master_mutex);
return 0;
}
@ -1039,6 +1068,7 @@ int ecrt_slave_config_idn(ec_slave_config_t *sc, uint8_t drive_no,
EXPORT_SYMBOL(ecrt_slave_config_sync_manager);
EXPORT_SYMBOL(ecrt_slave_config_watchdog);
EXPORT_SYMBOL(ecrt_slave_config_overlapping_pdos);
EXPORT_SYMBOL(ecrt_slave_config_pdo_assign_add);
EXPORT_SYMBOL(ecrt_slave_config_pdo_assign_clear);
EXPORT_SYMBOL(ecrt_slave_config_pdo_mapping_add);

View File

@ -126,7 +126,8 @@ struct ec_slave_config {
intervals (see spec. reg. 0x0400). */
uint16_t watchdog_intervals; /**< Process data watchdog intervals (see
spec. reg. 0x0420). */
uint8_t allow_overlapping_pdos; /**< Allow input PDOs use the same frame space
as output PDOs. */
ec_slave_t *slave; /**< Slave pointer. This is \a NULL, if the slave is
offline. */

View File

@ -88,6 +88,7 @@ int ec_voe_handler_init(
voe->request_state = EC_INT_REQUEST_INIT;
ec_datagram_init(&voe->datagram);
ec_mbox_init(&voe->mbox,&voe->datagram);
return ec_datagram_prealloc(&voe->datagram,
size + EC_MBOX_HEADER_SIZE + EC_VOE_HEADER_SIZE);
}
@ -100,6 +101,7 @@ void ec_voe_handler_clear(
ec_voe_handler_t *voe /**< VoE handler. */
)
{
ec_mbox_clear(&voe->mbox);
ec_datagram_clear(&voe->datagram);
}
@ -191,7 +193,7 @@ ec_request_state_t ecrt_voe_handler_execute(ec_voe_handler_t *voe)
if (voe->config->slave) { // FIXME locking?
voe->state(voe);
if (voe->request_state == EC_INT_REQUEST_BUSY)
ec_master_queue_datagram(voe->config->master, &voe->datagram);
ec_slave_mbox_queue_datagrams(voe->config->slave,&voe->mbox);
} else {
voe->state = ec_voe_handler_state_error;
voe->request_state = EC_INT_REQUEST_FAILURE;
@ -224,7 +226,7 @@ void ec_voe_handler_state_write_start(ec_voe_handler_t *voe)
return;
}
data = ec_slave_mbox_prepare_send(slave, &voe->datagram,
data = ec_slave_mbox_prepare_send(slave, &voe->mbox,
EC_MBOX_TYPE_VOE, EC_VOE_HEADER_SIZE + voe->data_size);
if (IS_ERR(data)) {
voe->state = ec_voe_handler_state_error;
@ -247,22 +249,22 @@ void ec_voe_handler_state_write_start(ec_voe_handler_t *voe)
*/
void ec_voe_handler_state_write_response(ec_voe_handler_t *voe)
{
ec_datagram_t *datagram = &voe->datagram;
ec_mailbox_t *mbox = &voe->mbox;
ec_slave_t *slave = voe->config->slave;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
if (ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_TIMED_OUT) && voe->retries--)
return;
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
voe->state = ec_voe_handler_state_error;
voe->request_state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_ERR(slave, "Failed to receive VoE write request datagram: ");
ec_datagram_print_state(datagram);
ec_datagram_print_state(mbox->datagram);
return;
}
if (datagram->working_counter != 1) {
if (!datagram->working_counter) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
if (ec_mbox_is_datagram_wc(mbox,0)) {
unsigned long diff_ms =
(jiffies - voe->jiffies_start) * 1000 / HZ;
if (diff_ms < EC_VOE_RESPONSE_TIMEOUT) {
@ -276,7 +278,7 @@ void ec_voe_handler_state_write_response(ec_voe_handler_t *voe)
voe->state = ec_voe_handler_state_error;
voe->request_state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_ERR(slave, "Reception of VoE write request failed: ");
ec_datagram_print_wc_error(datagram);
ec_datagram_print_wc_error(mbox->datagram);
return;
}
@ -292,7 +294,7 @@ void ec_voe_handler_state_write_response(ec_voe_handler_t *voe)
*/
void ec_voe_handler_state_read_start(ec_voe_handler_t *voe)
{
ec_datagram_t *datagram = &voe->datagram;
ec_mailbox_t *mbox = &voe->mbox;
ec_slave_t *slave = voe->config->slave;
EC_SLAVE_DBG(slave, 1, "Reading VoE data.\n");
@ -304,7 +306,7 @@ void ec_voe_handler_state_read_start(ec_voe_handler_t *voe)
return;
}
ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
ec_slave_mbox_prepare_check(slave, mbox); // can not fail.
voe->jiffies_start = jiffies;
voe->retries = EC_FSM_RETRIES;
@ -317,32 +319,32 @@ void ec_voe_handler_state_read_start(ec_voe_handler_t *voe)
*/
void ec_voe_handler_state_read_check(ec_voe_handler_t *voe)
{
ec_datagram_t *datagram = &voe->datagram;
ec_mailbox_t *mbox = &voe->mbox;
ec_slave_t *slave = voe->config->slave;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
if (ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_TIMED_OUT) && voe->retries--)
return;
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
voe->state = ec_voe_handler_state_error;
voe->request_state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_ERR(slave, "Failed to receive VoE mailbox check datagram: ");
ec_datagram_print_state(datagram);
ec_datagram_print_state(mbox->datagram);
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
voe->state = ec_voe_handler_state_error;
voe->request_state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_ERR(slave, "Reception of VoE mailbox check"
" datagram failed: ");
ec_datagram_print_wc_error(datagram);
ec_datagram_print_wc_error(mbox->datagram);
return;
}
if (!ec_slave_mbox_check(datagram)) {
if (!ec_slave_mbox_check(mbox)) {
unsigned long diff_ms =
(datagram->jiffies_received - voe->jiffies_start) * 1000 / HZ;
(mbox->datagram->jiffies_received - voe->jiffies_start) * 1000 / HZ;
if (diff_ms >= EC_VOE_RESPONSE_TIMEOUT) {
voe->state = ec_voe_handler_state_error;
voe->request_state = EC_INT_REQUEST_FAILURE;
@ -350,13 +352,13 @@ void ec_voe_handler_state_read_check(ec_voe_handler_t *voe)
return;
}
ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
ec_slave_mbox_prepare_check(slave, mbox); // can not fail.
voe->retries = EC_FSM_RETRIES;
return;
}
// Fetch response
ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
ec_slave_mbox_prepare_fetch(slave, mbox); // can not fail.
voe->retries = EC_FSM_RETRIES;
voe->state = ec_voe_handler_state_read_response;
}
@ -367,32 +369,32 @@ void ec_voe_handler_state_read_check(ec_voe_handler_t *voe)
*/
void ec_voe_handler_state_read_response(ec_voe_handler_t *voe)
{
ec_datagram_t *datagram = &voe->datagram;
ec_mailbox_t *mbox = &voe->mbox;
ec_slave_t *slave = voe->config->slave;
ec_master_t *master = voe->config->master;
uint8_t *data, mbox_prot;
size_t rec_size;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
if (ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_TIMED_OUT) && voe->retries--)
return;
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
voe->state = ec_voe_handler_state_error;
voe->request_state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_ERR(slave, "Failed to receive VoE read datagram: ");
ec_datagram_print_state(datagram);
ec_datagram_print_state(mbox->datagram);
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
voe->state = ec_voe_handler_state_error;
voe->request_state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_ERR(slave, "Reception of VoE read response failed: ");
ec_datagram_print_wc_error(datagram);
ec_datagram_print_wc_error(mbox->datagram);
return;
}
data = ec_slave_mbox_fetch(slave, datagram, &mbox_prot, &rec_size);
data = ec_slave_mbox_fetch(slave, mbox, &mbox_prot, &rec_size);
if (IS_ERR(data)) {
voe->state = ec_voe_handler_state_error;
voe->request_state = EC_INT_REQUEST_FAILURE;
@ -432,7 +434,7 @@ void ec_voe_handler_state_read_response(ec_voe_handler_t *voe)
*/
void ec_voe_handler_state_read_nosync_start(ec_voe_handler_t *voe)
{
ec_datagram_t *datagram = &voe->datagram;
ec_mailbox_t *mbox = &voe->mbox;
ec_slave_t *slave = voe->config->slave;
EC_SLAVE_DBG(slave, 1, "Reading VoE data.\n");
@ -444,7 +446,7 @@ void ec_voe_handler_state_read_nosync_start(ec_voe_handler_t *voe)
return;
}
ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
ec_slave_mbox_prepare_fetch(slave, mbox); // can not fail.
voe->jiffies_start = jiffies;
voe->retries = EC_FSM_RETRIES;
@ -458,39 +460,39 @@ void ec_voe_handler_state_read_nosync_start(ec_voe_handler_t *voe)
*/
void ec_voe_handler_state_read_nosync_response(ec_voe_handler_t *voe)
{
ec_datagram_t *datagram = &voe->datagram;
ec_mailbox_t *mbox = &voe->mbox;
ec_slave_t *slave = voe->config->slave;
ec_master_t *master = voe->config->master;
uint8_t *data, mbox_prot;
size_t rec_size;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
if (ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_TIMED_OUT) && voe->retries--)
return;
if (datagram->state != EC_DATAGRAM_RECEIVED) {
if (!ec_mbox_is_datagram_state(mbox,EC_DATAGRAM_RECEIVED)) {
voe->state = ec_voe_handler_state_error;
voe->request_state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_ERR(slave, "Failed to receive VoE read datagram: ");
ec_datagram_print_state(datagram);
ec_datagram_print_state(mbox->datagram);
return;
}
if (datagram->working_counter == 0) {
if (ec_mbox_is_datagram_wc(mbox,0)) {
voe->state = ec_voe_handler_state_error;
voe->request_state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_DBG(slave, 1, "Slave did not send VoE data.\n");
return;
}
if (datagram->working_counter != 1) {
if (!ec_mbox_is_datagram_wc(mbox,1)) {
voe->state = ec_voe_handler_state_error;
voe->request_state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_WARN(slave, "Reception of VoE read response failed: ");
ec_datagram_print_wc_error(datagram);
ec_datagram_print_wc_error(mbox->datagram);
return;
}
if (!(data = ec_slave_mbox_fetch(slave, datagram,
if (!(data = ec_slave_mbox_fetch(slave, mbox,
&mbox_prot, &rec_size))) {
voe->state = ec_voe_handler_state_error;
voe->request_state = EC_INT_REQUEST_FAILURE;

Some files were not shown because too many files have changed in this diff Show More