Merged
This commit is contained in:
commit
82ea99132c
2
INSTALL
2
INSTALL
|
|
@ -18,6 +18,8 @@ section of the documentation available from http://etherlab.org/en/ethercat.
|
|||
|
||||
For the impatient: The procedure mainly consists of calling
|
||||
|
||||
$ ./boostrap # to create the configure script, if downloaded from the repo
|
||||
|
||||
$ ./configure
|
||||
$ make all modules
|
||||
|
||||
|
|
|
|||
4
NEWS
4
NEWS
|
|
@ -28,8 +28,8 @@ Changes since 1.4.0:
|
|||
- Added e100 driver for 2.6.31.
|
||||
* Added 8139too driver for kernels 2.6.25 (F. Pose), 2.6.26 (M. Luescher),
|
||||
2.6.27, 2.6.28 and 2.6.29 (M. Goetze).
|
||||
* Added e1000 driver for 2.6.26 (M. Luescher).
|
||||
* Added r8169 driver for 2.6.24, 2.6.28 and 2.6.29.
|
||||
* Added e1000 driver for 2.6.26 (M. Luescher) and 2.6.27.
|
||||
* Added r8169 driver for 2.6.24, 2.6.27, 2.6.28, 2.6.29 and 2.6.31.
|
||||
* Debug interfaces are created with the Ethernet addresses of the attached
|
||||
physical device.
|
||||
* Improved error case return codes of many functions.
|
||||
|
|
|
|||
15
TODO
15
TODO
|
|
@ -13,11 +13,9 @@ Version 1.5.0:
|
|||
* Ethernet drivers:
|
||||
- Fix link detection in generic driver.
|
||||
- Add native drivers from 2.6.24 up to 2.6.31.
|
||||
* Remove byte-swapping functions from user space.
|
||||
* Use ec_datagram_zero() wherever possible.
|
||||
* Finish library implementation.
|
||||
- Remove stdio uses?
|
||||
* Rescan command.
|
||||
* Document ec_fsm_foe members.
|
||||
* Change SDO index at runtime for SDO request.
|
||||
* Output skipped datagrams again.
|
||||
* Output warning on unmatched slave configuration.
|
||||
|
|
@ -27,11 +25,11 @@ Version 1.5.0:
|
|||
* Check for Enable SDO Complete Access flag.
|
||||
* Remove allow_scanning flag.
|
||||
* ethercat tool:
|
||||
- Output error after usage.
|
||||
- Data type abbreviations.
|
||||
- Implement ranges for slaves and domains.
|
||||
- Add -x switch for hex display.
|
||||
- Implement CompleteAccess
|
||||
- Output hexadecimal values in xml command.
|
||||
- Implement --output-file argument in foe_read.
|
||||
- Fix arguments of reg_read.
|
||||
- Number layout for reg_read.
|
||||
|
|
@ -40,6 +38,12 @@ Version 1.5.0:
|
|||
- Implement indent in 'ethercat ma'
|
||||
- Implement 0xXXXX:YY format for specifying SDOs.
|
||||
- Implement reading from stream for soe_write.
|
||||
- Fix AL state display if error bit set.
|
||||
* recompile tool/CommandVersion.cpp if revision changes.
|
||||
* Log SoE IDNs with real name ([SP]-x-yyyy).
|
||||
* Output SoE IDN configurations in 'ethercat config'.
|
||||
* Output AL status error flag correctly in 'ethercat slaves'.
|
||||
* Fix casting away constness during expected WC calculation.
|
||||
|
||||
Future issues:
|
||||
|
||||
|
|
@ -48,7 +52,6 @@ Future issues:
|
|||
* Override sync manager size?
|
||||
* Show Record / Array / List type of SDOs.
|
||||
* Distributed clocks:
|
||||
- Check 32/64 bit operations.
|
||||
- Use vendor correction factors when calculating transmission delays.
|
||||
- Skip setting system time offset when application detached.
|
||||
- How to use the SYNC1 shift time?
|
||||
|
|
@ -75,8 +78,10 @@ Future issues:
|
|||
* ethercat tool:
|
||||
- Add a -n (numeric) switch.
|
||||
- Check for unwanted options.
|
||||
- Fix number of digits in negative integer hex output.
|
||||
* Simplify master fsm by introducing a common request state to handle external
|
||||
requests (replace write_sii, sdo_request, etc).
|
||||
* Write PDO mapping/assignment by default?
|
||||
|
||||
Smaller issues:
|
||||
|
||||
|
|
|
|||
|
|
@ -77,10 +77,14 @@ noinst_HEADERS = \
|
|||
generic.c \
|
||||
r8169-2.6.24-ethercat.c \
|
||||
r8169-2.6.24-orig.c \
|
||||
r8169-2.6.27-ethercat.c \
|
||||
r8169-2.6.27-orig.c \
|
||||
r8169-2.6.28-ethercat.c \
|
||||
r8169-2.6.28-orig.c \
|
||||
r8169-2.6.29-ethercat.c \
|
||||
r8169-2.6.29-orig.c
|
||||
r8169-2.6.29-orig.c \
|
||||
r8169-2.6.31-ethercat.c \
|
||||
r8169-2.6.31-orig.c
|
||||
|
||||
EXTRA_DIST = \
|
||||
Kbuild.in
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ EXTRA_DIST = \
|
|||
e1000-2.6.24-orig.h \
|
||||
e1000-2.6.26-ethercat.h \
|
||||
e1000-2.6.26-orig.h \
|
||||
e1000-2.6.27-ethercat.h \
|
||||
e1000-2.6.27-orig.h \
|
||||
e1000_ethtool-2.6.13-ethercat.c \
|
||||
e1000_ethtool-2.6.13-orig.c \
|
||||
e1000_ethtool-2.6.18-ethercat.c \
|
||||
|
|
@ -54,6 +56,8 @@ EXTRA_DIST = \
|
|||
e1000_ethtool-2.6.24-orig.c \
|
||||
e1000_ethtool-2.6.26-ethercat.c \
|
||||
e1000_ethtool-2.6.26-orig.c \
|
||||
e1000_ethtool-2.6.27-ethercat.c \
|
||||
e1000_ethtool-2.6.27-orig.c \
|
||||
e1000_hw-2.6.13-ethercat.c \
|
||||
e1000_hw-2.6.13-ethercat.h \
|
||||
e1000_hw-2.6.13-orig.c \
|
||||
|
|
@ -78,6 +82,10 @@ EXTRA_DIST = \
|
|||
e1000_hw-2.6.26-ethercat.h \
|
||||
e1000_hw-2.6.26-orig.c \
|
||||
e1000_hw-2.6.26-orig.h \
|
||||
e1000_hw-2.6.27-ethercat.c \
|
||||
e1000_hw-2.6.27-ethercat.h \
|
||||
e1000_hw-2.6.27-orig.c \
|
||||
e1000_hw-2.6.27-orig.h \
|
||||
e1000_main-2.6.13-ethercat.c \
|
||||
e1000_main-2.6.13-orig.c \
|
||||
e1000_main-2.6.18-ethercat.c \
|
||||
|
|
@ -90,6 +98,8 @@ EXTRA_DIST = \
|
|||
e1000_main-2.6.24-orig.c \
|
||||
e1000_main-2.6.26-ethercat.c \
|
||||
e1000_main-2.6.26-orig.c \
|
||||
e1000_main-2.6.27-ethercat.c \
|
||||
e1000_main-2.6.27-orig.c \
|
||||
e1000_osdep-2.6.13-ethercat.h \
|
||||
e1000_osdep-2.6.13-orig.h \
|
||||
e1000_osdep-2.6.18-ethercat.h \
|
||||
|
|
@ -102,6 +112,8 @@ EXTRA_DIST = \
|
|||
e1000_osdep-2.6.24-orig.h \
|
||||
e1000_osdep-2.6.26-ethercat.h \
|
||||
e1000_osdep-2.6.26-orig.h \
|
||||
e1000_osdep-2.6.27-ethercat.h \
|
||||
e1000_osdep-2.6.27-orig.h \
|
||||
e1000_param-2.6.13-ethercat.c \
|
||||
e1000_param-2.6.13-orig.c \
|
||||
e1000_param-2.6.18-ethercat.c \
|
||||
|
|
@ -113,7 +125,9 @@ EXTRA_DIST = \
|
|||
e1000_param-2.6.24-ethercat.c \
|
||||
e1000_param-2.6.24-orig.c \
|
||||
e1000_param-2.6.26-ethercat.c \
|
||||
e1000_param-2.6.26-orig.c
|
||||
e1000_param-2.6.26-orig.c \
|
||||
e1000_param-2.6.27-ethercat.c \
|
||||
e1000_param-2.6.27-orig.c
|
||||
|
||||
BUILT_SOURCES = \
|
||||
Kbuild
|
||||
|
|
|
|||
|
|
@ -0,0 +1,378 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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.27-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)
|
||||
/* Number of packet split data buffers (not including the header buffer) */
|
||||
#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 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_ps_page {
|
||||
struct page *ps_page[PS_PAGE_BUFFERS];
|
||||
};
|
||||
|
||||
struct e1000_ps_page_dma {
|
||||
u64 ps_page_dma[PS_PAGE_BUFFERS];
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
spinlock_t tx_lock;
|
||||
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;
|
||||
/* arrays of page information for packet split */
|
||||
struct e1000_ps_page *ps_page;
|
||||
struct e1000_ps_page_dma *ps_page_dma;
|
||||
|
||||
/* 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_PS(R, i) \
|
||||
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
|
||||
#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;
|
||||
spinlock_t tx_queue_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;
|
||||
struct net_device *polling_netdev; /* One per active queue */
|
||||
|
||||
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;
|
||||
unsigned int rx_ps_pages;
|
||||
u32 gorcl;
|
||||
u64 gorcl_old;
|
||||
u16 rx_ps_bsize0;
|
||||
|
||||
/* 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,
|
||||
__E1000_DISCARDING
|
||||
};
|
||||
|
||||
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_ */
|
||||
|
|
@ -0,0 +1,373 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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)
|
||||
/* Number of packet split data buffers (not including the header buffer) */
|
||||
#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 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_ps_page {
|
||||
struct page *ps_page[PS_PAGE_BUFFERS];
|
||||
};
|
||||
|
||||
struct e1000_ps_page_dma {
|
||||
u64 ps_page_dma[PS_PAGE_BUFFERS];
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
spinlock_t tx_lock;
|
||||
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;
|
||||
/* arrays of page information for packet split */
|
||||
struct e1000_ps_page *ps_page;
|
||||
struct e1000_ps_page_dma *ps_page_dma;
|
||||
|
||||
/* 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_PS(R, i) \
|
||||
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
|
||||
#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;
|
||||
spinlock_t tx_queue_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;
|
||||
struct net_device *polling_netdev; /* One per active queue */
|
||||
|
||||
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;
|
||||
unsigned int rx_ps_pages;
|
||||
u32 gorcl;
|
||||
u64 gorcl_old;
|
||||
u16 rx_ps_bsize0;
|
||||
|
||||
/* 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,
|
||||
__E1000_DISCARDING
|
||||
};
|
||||
|
||||
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
|
|
@ -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_ */
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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.27-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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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.27-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");
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -2392,8 +2392,6 @@ static void rtl_hw_start_8169(struct net_device *dev)
|
|||
void __iomem *ioaddr = tp->mmio_addr;
|
||||
struct pci_dev *pdev = tp->pci_dev;
|
||||
|
||||
printk(KERN_INFO "%s\n", __func__);
|
||||
|
||||
if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
|
||||
RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
|
||||
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
|
||||
|
|
|
|||
|
|
@ -2212,12 +2212,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
|
||||
rtl8169_init_phy(dev, tp);
|
||||
device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
|
||||
|
||||
if (tp->ecdev && ecdev_open(tp->ecdev)) {
|
||||
ecdev_withdraw(tp->ecdev);
|
||||
goto err_out_msi_5;
|
||||
}
|
||||
|
||||
|
||||
out:
|
||||
return rc;
|
||||
|
||||
|
|
@ -2428,8 +2428,6 @@ static void rtl_hw_start_8169(struct net_device *dev)
|
|||
void __iomem *ioaddr = tp->mmio_addr;
|
||||
struct pci_dev *pdev = tp->pci_dev;
|
||||
|
||||
printk(KERN_INFO "%s\n", __func__);
|
||||
|
||||
if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
|
||||
RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
|
||||
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@
|
|||
#define TX_BUFFS_AVAIL(tp) \
|
||||
(tp->dirty_tx + NUM_TX_DESC - tp->cur_tx - 1)
|
||||
|
||||
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
|
||||
static const int max_interrupt_work = 20;
|
||||
|
||||
/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
|
||||
The RTL chips use a 64 element hash table based on the Ethernet CRC. */
|
||||
static const int multicast_filter_limit = 32;
|
||||
|
|
@ -68,6 +71,7 @@ static const int multicast_filter_limit = 32;
|
|||
#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
|
||||
#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
|
||||
#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
|
||||
#define RxPacketMaxSize 0x3FE8 /* 16K - 1 - ETH_HLEN - VLAN - CRC... */
|
||||
#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */
|
||||
#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
|
||||
|
||||
|
|
@ -95,7 +99,6 @@ static const int multicast_filter_limit = 32;
|
|||
#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
|
||||
|
||||
enum mac_version {
|
||||
RTL_GIGA_MAC_NONE = 0x00,
|
||||
RTL_GIGA_MAC_VER_01 = 0x01, // 8169
|
||||
RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
|
||||
RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
|
||||
|
|
@ -440,22 +443,6 @@ enum features {
|
|||
RTL_FEATURE_GMII = (1 << 2),
|
||||
};
|
||||
|
||||
struct rtl8169_counters {
|
||||
__le64 tx_packets;
|
||||
__le64 rx_packets;
|
||||
__le64 tx_errors;
|
||||
__le32 rx_errors;
|
||||
__le16 rx_missed;
|
||||
__le16 align_errors;
|
||||
__le32 tx_one_collision;
|
||||
__le32 tx_multi_collision;
|
||||
__le64 rx_unicast;
|
||||
__le64 rx_broadcast;
|
||||
__le32 rx_multicast;
|
||||
__le16 tx_aborted;
|
||||
__le16 tx_underun;
|
||||
};
|
||||
|
||||
struct rtl8169_private {
|
||||
void __iomem *mmio_addr; /* memory map physical address */
|
||||
struct pci_dev *pci_dev; /* Index of PCI device */
|
||||
|
|
@ -482,6 +469,7 @@ struct rtl8169_private {
|
|||
u16 intr_event;
|
||||
u16 napi_event;
|
||||
u16 intr_mask;
|
||||
int phy_auto_nego_reg;
|
||||
int phy_1000_ctrl_reg;
|
||||
#ifdef CONFIG_R8169_VLAN
|
||||
struct vlan_group *vlgrp;
|
||||
|
|
@ -492,13 +480,11 @@ struct rtl8169_private {
|
|||
void (*hw_start)(struct net_device *);
|
||||
unsigned int (*phy_reset_pending)(void __iomem *);
|
||||
unsigned int (*link_ok)(void __iomem *);
|
||||
int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd);
|
||||
int pcie_cap;
|
||||
struct delayed_work task;
|
||||
unsigned features;
|
||||
|
||||
struct mii_if_info mii;
|
||||
struct rtl8169_counters counters;
|
||||
|
||||
ec_device_t *ecdev;
|
||||
unsigned long ec_watchdog_jiffies;
|
||||
|
|
@ -854,81 +840,76 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
|
|||
{
|
||||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
void __iomem *ioaddr = tp->mmio_addr;
|
||||
int giga_ctrl, bmcr;
|
||||
int auto_nego, giga_ctrl;
|
||||
|
||||
auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
|
||||
auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
|
||||
ADVERTISE_100HALF | ADVERTISE_100FULL);
|
||||
giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
|
||||
giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
|
||||
|
||||
if (autoneg == AUTONEG_ENABLE) {
|
||||
int auto_nego;
|
||||
|
||||
auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
|
||||
auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
|
||||
ADVERTISE_100HALF | ADVERTISE_100FULL);
|
||||
auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
|
||||
|
||||
giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
|
||||
giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
|
||||
|
||||
/* The 8100e/8101e/8102e do Fast Ethernet only. */
|
||||
if ((tp->mac_version != RTL_GIGA_MAC_VER_07) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_08) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_09) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_10) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_13) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_14) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_15) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_16)) {
|
||||
giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
|
||||
} else {
|
||||
if (speed == SPEED_10)
|
||||
auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL;
|
||||
else if (speed == SPEED_100)
|
||||
auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL;
|
||||
else if (speed == SPEED_1000)
|
||||
giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
|
||||
} else if (netif_msg_link(tp)) {
|
||||
|
||||
if (duplex == DUPLEX_HALF)
|
||||
auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL);
|
||||
|
||||
if (duplex == DUPLEX_FULL)
|
||||
auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF);
|
||||
|
||||
/* This tweak comes straight from Realtek's driver. */
|
||||
if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) &&
|
||||
((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_16))) {
|
||||
auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA;
|
||||
}
|
||||
}
|
||||
|
||||
/* The 8100e/8101e/8102e do Fast Ethernet only. */
|
||||
if ((tp->mac_version == RTL_GIGA_MAC_VER_07) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_08) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_09) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_10) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_13) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_14) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_15) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_16)) {
|
||||
if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) &&
|
||||
netif_msg_link(tp)) {
|
||||
printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n",
|
||||
dev->name);
|
||||
}
|
||||
|
||||
bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
|
||||
|
||||
if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_12) ||
|
||||
(tp->mac_version >= RTL_GIGA_MAC_VER_17)) {
|
||||
/*
|
||||
* Wake up the PHY.
|
||||
* Vendor specific (0x1f) and reserved (0x0e) MII
|
||||
* registers.
|
||||
*/
|
||||
mdio_write(ioaddr, 0x1f, 0x0000);
|
||||
mdio_write(ioaddr, 0x0e, 0x0000);
|
||||
}
|
||||
|
||||
mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
|
||||
mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
|
||||
} else {
|
||||
giga_ctrl = 0;
|
||||
|
||||
if (speed == SPEED_10)
|
||||
bmcr = 0;
|
||||
else if (speed == SPEED_100)
|
||||
bmcr = BMCR_SPEED100;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (duplex == DUPLEX_FULL)
|
||||
bmcr |= BMCR_FULLDPLX;
|
||||
|
||||
mdio_write(ioaddr, 0x1f, 0x0000);
|
||||
giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
|
||||
}
|
||||
|
||||
auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
|
||||
|
||||
if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_12) ||
|
||||
(tp->mac_version >= RTL_GIGA_MAC_VER_17)) {
|
||||
/*
|
||||
* Wake up the PHY.
|
||||
* Vendor specific (0x1f) and reserved (0x0e) MII registers.
|
||||
*/
|
||||
mdio_write(ioaddr, 0x1f, 0x0000);
|
||||
mdio_write(ioaddr, 0x0e, 0x0000);
|
||||
}
|
||||
|
||||
tp->phy_auto_nego_reg = auto_nego;
|
||||
tp->phy_1000_ctrl_reg = giga_ctrl;
|
||||
|
||||
mdio_write(ioaddr, MII_BMCR, bmcr);
|
||||
|
||||
if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_03)) {
|
||||
if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) {
|
||||
mdio_write(ioaddr, 0x17, 0x2138);
|
||||
mdio_write(ioaddr, 0x0e, 0x0260);
|
||||
} else {
|
||||
mdio_write(ioaddr, 0x17, 0x2108);
|
||||
mdio_write(ioaddr, 0x0e, 0x0000);
|
||||
}
|
||||
}
|
||||
|
||||
mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
|
||||
mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
|
||||
mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1132,6 +1113,22 @@ static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = {
|
|||
"tx_underrun",
|
||||
};
|
||||
|
||||
struct rtl8169_counters {
|
||||
__le64 tx_packets;
|
||||
__le64 rx_packets;
|
||||
__le64 tx_errors;
|
||||
__le32 rx_errors;
|
||||
__le16 rx_missed;
|
||||
__le16 align_errors;
|
||||
__le32 tx_one_collision;
|
||||
__le32 tx_multi_collision;
|
||||
__le64 rx_unicast;
|
||||
__le64 rx_broadcast;
|
||||
__le32 rx_multicast;
|
||||
__le16 tx_aborted;
|
||||
__le16 tx_underun;
|
||||
};
|
||||
|
||||
static int rtl8169_get_sset_count(struct net_device *dev, int sset)
|
||||
{
|
||||
switch (sset) {
|
||||
|
|
@ -1142,70 +1139,51 @@ static int rtl8169_get_sset_count(struct net_device *dev, int sset)
|
|||
}
|
||||
}
|
||||
|
||||
static void rtl8169_update_counters(struct net_device *dev)
|
||||
static void rtl8169_get_ethtool_stats(struct net_device *dev,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
void __iomem *ioaddr = tp->mmio_addr;
|
||||
struct rtl8169_counters *counters;
|
||||
dma_addr_t paddr;
|
||||
u32 cmd;
|
||||
int wait = 1000;
|
||||
|
||||
/*
|
||||
* Some chips are unable to dump tally counters when the receiver
|
||||
* is disabled.
|
||||
*/
|
||||
if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0)
|
||||
return;
|
||||
ASSERT_RTNL();
|
||||
|
||||
counters = pci_alloc_consistent(tp->pci_dev, sizeof(*counters), &paddr);
|
||||
if (!counters)
|
||||
return;
|
||||
|
||||
RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
|
||||
cmd = (u64)paddr & DMA_BIT_MASK(32);
|
||||
cmd = (u64)paddr & DMA_32BIT_MASK;
|
||||
RTL_W32(CounterAddrLow, cmd);
|
||||
RTL_W32(CounterAddrLow, cmd | CounterDump);
|
||||
|
||||
while (wait--) {
|
||||
if ((RTL_R32(CounterAddrLow) & CounterDump) == 0) {
|
||||
/* copy updated counters */
|
||||
memcpy(&tp->counters, counters, sizeof(*counters));
|
||||
while (RTL_R32(CounterAddrLow) & CounterDump) {
|
||||
if (msleep_interruptible(1))
|
||||
break;
|
||||
}
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
RTL_W32(CounterAddrLow, 0);
|
||||
RTL_W32(CounterAddrHigh, 0);
|
||||
|
||||
data[0] = le64_to_cpu(counters->tx_packets);
|
||||
data[1] = le64_to_cpu(counters->rx_packets);
|
||||
data[2] = le64_to_cpu(counters->tx_errors);
|
||||
data[3] = le32_to_cpu(counters->rx_errors);
|
||||
data[4] = le16_to_cpu(counters->rx_missed);
|
||||
data[5] = le16_to_cpu(counters->align_errors);
|
||||
data[6] = le32_to_cpu(counters->tx_one_collision);
|
||||
data[7] = le32_to_cpu(counters->tx_multi_collision);
|
||||
data[8] = le64_to_cpu(counters->rx_unicast);
|
||||
data[9] = le64_to_cpu(counters->rx_broadcast);
|
||||
data[10] = le32_to_cpu(counters->rx_multicast);
|
||||
data[11] = le16_to_cpu(counters->tx_aborted);
|
||||
data[12] = le16_to_cpu(counters->tx_underun);
|
||||
|
||||
pci_free_consistent(tp->pci_dev, sizeof(*counters), counters, paddr);
|
||||
}
|
||||
|
||||
static void rtl8169_get_ethtool_stats(struct net_device *dev,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
rtl8169_update_counters(dev);
|
||||
|
||||
data[0] = le64_to_cpu(tp->counters.tx_packets);
|
||||
data[1] = le64_to_cpu(tp->counters.rx_packets);
|
||||
data[2] = le64_to_cpu(tp->counters.tx_errors);
|
||||
data[3] = le32_to_cpu(tp->counters.rx_errors);
|
||||
data[4] = le16_to_cpu(tp->counters.rx_missed);
|
||||
data[5] = le16_to_cpu(tp->counters.align_errors);
|
||||
data[6] = le32_to_cpu(tp->counters.tx_one_collision);
|
||||
data[7] = le32_to_cpu(tp->counters.tx_multi_collision);
|
||||
data[8] = le64_to_cpu(tp->counters.rx_unicast);
|
||||
data[9] = le64_to_cpu(tp->counters.rx_broadcast);
|
||||
data[10] = le32_to_cpu(tp->counters.rx_multicast);
|
||||
data[11] = le16_to_cpu(tp->counters.tx_aborted);
|
||||
data[12] = le16_to_cpu(tp->counters.tx_underun);
|
||||
}
|
||||
|
||||
static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
|
||||
{
|
||||
switch(stringset) {
|
||||
|
|
@ -1311,8 +1289,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
|
|||
{ 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
|
||||
{ 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
|
||||
|
||||
/* Catch-all */
|
||||
{ 0x00000000, 0x00000000, RTL_GIGA_MAC_NONE }
|
||||
{ 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */
|
||||
}, *p = mac_info;
|
||||
u32 reg;
|
||||
|
||||
|
|
@ -1320,6 +1297,12 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
|
|||
while ((reg & p->mask) != p->val)
|
||||
p++;
|
||||
tp->mac_version = p->mac_version;
|
||||
|
||||
if (p->mask == 0x00000000) {
|
||||
struct pci_dev *pdev = tp->pci_dev;
|
||||
|
||||
dev_info(&pdev->dev, "unknown MAC (%08x)\n", reg);
|
||||
}
|
||||
}
|
||||
|
||||
static void rtl8169_print_mac_version(struct rtl8169_private *tp)
|
||||
|
|
@ -1863,11 +1846,9 @@ static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
struct mii_ioctl_data *data = if_mii(ifr);
|
||||
|
||||
return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV;
|
||||
}
|
||||
if (!netif_running(dev))
|
||||
return -ENODEV;
|
||||
|
||||
static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case SIOCGMIIPHY:
|
||||
data->phy_id = 32; /* Internal PHY */
|
||||
|
|
@ -1886,11 +1867,6 @@ static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *dat
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int rtl_tbi_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const struct rtl_cfg_info {
|
||||
void (*hw_start)(struct net_device *);
|
||||
unsigned int region;
|
||||
|
|
@ -1898,7 +1874,6 @@ static const struct rtl_cfg_info {
|
|||
u16 intr_event;
|
||||
u16 napi_event;
|
||||
unsigned features;
|
||||
u8 default_ver;
|
||||
} rtl_cfg_infos [] = {
|
||||
[RTL_CFG_0] = {
|
||||
.hw_start = rtl_hw_start_8169,
|
||||
|
|
@ -1907,8 +1882,7 @@ static const struct rtl_cfg_info {
|
|||
.intr_event = SYSErr | LinkChg | RxOverflow |
|
||||
RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
|
||||
.napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
|
||||
.features = RTL_FEATURE_GMII,
|
||||
.default_ver = RTL_GIGA_MAC_VER_01,
|
||||
.features = RTL_FEATURE_GMII
|
||||
},
|
||||
[RTL_CFG_1] = {
|
||||
.hw_start = rtl_hw_start_8168,
|
||||
|
|
@ -1917,8 +1891,7 @@ static const struct rtl_cfg_info {
|
|||
.intr_event = SYSErr | LinkChg | RxOverflow |
|
||||
TxErr | TxOK | RxOK | RxErr,
|
||||
.napi_event = TxErr | TxOK | RxOK | RxOverflow,
|
||||
.features = RTL_FEATURE_GMII | RTL_FEATURE_MSI,
|
||||
.default_ver = RTL_GIGA_MAC_VER_11,
|
||||
.features = RTL_FEATURE_GMII | RTL_FEATURE_MSI
|
||||
},
|
||||
[RTL_CFG_2] = {
|
||||
.hw_start = rtl_hw_start_8101,
|
||||
|
|
@ -1927,8 +1900,7 @@ static const struct rtl_cfg_info {
|
|||
.intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout |
|
||||
RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
|
||||
.napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
|
||||
.features = RTL_FEATURE_MSI,
|
||||
.default_ver = RTL_GIGA_MAC_VER_13,
|
||||
.features = RTL_FEATURE_MSI
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1960,26 +1932,6 @@ static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp)
|
|||
}
|
||||
}
|
||||
|
||||
static const struct net_device_ops rtl8169_netdev_ops = {
|
||||
.ndo_open = rtl8169_open,
|
||||
.ndo_stop = rtl8169_close,
|
||||
.ndo_get_stats = rtl8169_get_stats,
|
||||
.ndo_start_xmit = rtl8169_start_xmit,
|
||||
.ndo_tx_timeout = rtl8169_tx_timeout,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_change_mtu = rtl8169_change_mtu,
|
||||
.ndo_set_mac_address = rtl_set_mac_address,
|
||||
.ndo_do_ioctl = rtl8169_ioctl,
|
||||
.ndo_set_multicast_list = rtl_set_rx_mode,
|
||||
#ifdef CONFIG_R8169_VLAN
|
||||
.ndo_vlan_rx_register = rtl8169_vlan_rx_register,
|
||||
#endif
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = rtl8169_netpoll,
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
static int __devinit
|
||||
rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
|
|
@ -2006,7 +1958,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
}
|
||||
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
dev->netdev_ops = &rtl8169_netdev_ops;
|
||||
tp = netdev_priv(dev);
|
||||
tp->dev = dev;
|
||||
tp->pci_dev = pdev;
|
||||
|
|
@ -2063,11 +2014,11 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
tp->cp_cmd = PCIMulRW | RxChkSum;
|
||||
|
||||
if ((sizeof(dma_addr_t) > 4) &&
|
||||
!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {
|
||||
!pci_set_dma_mask(pdev, DMA_64BIT_MASK) && use_dac) {
|
||||
tp->cp_cmd |= PCIDAC;
|
||||
dev->features |= NETIF_F_HIGHDMA;
|
||||
} else {
|
||||
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
|
||||
if (rc < 0) {
|
||||
if (netif_msg_probe(tp)) {
|
||||
dev_err(&pdev->dev,
|
||||
|
|
@ -2077,6 +2028,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
}
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
/* ioremap MMIO region */
|
||||
ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);
|
||||
if (!ioaddr) {
|
||||
|
|
@ -2104,20 +2057,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
|
||||
RTL_W16(IntrStatus, 0xffff);
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
/* Identify chip attached to board */
|
||||
rtl8169_get_mac_version(tp, ioaddr);
|
||||
|
||||
/* Use appropriate default if unknown */
|
||||
if (tp->mac_version == RTL_GIGA_MAC_NONE) {
|
||||
if (netif_msg_probe(tp)) {
|
||||
dev_notice(&pdev->dev,
|
||||
"unknown MAC, using family default\n");
|
||||
}
|
||||
tp->mac_version = cfg->default_ver;
|
||||
}
|
||||
|
||||
rtl8169_print_mac_version(tp);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rtl_chip_info); i++) {
|
||||
|
|
@ -2125,9 +2067,13 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(rtl_chip_info)) {
|
||||
dev_err(&pdev->dev,
|
||||
"driver bug, MAC version not found in rtl_chip_info\n");
|
||||
goto err_out_msi_5;
|
||||
/* Unknown chip: assume array element #0, original RTL-8169 */
|
||||
if (netif_msg_probe(tp)) {
|
||||
dev_printk(KERN_DEBUG, &pdev->dev,
|
||||
"unknown chip version, assuming %s\n",
|
||||
rtl_chip_info[0].name);
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
tp->chipset = i;
|
||||
|
||||
|
|
@ -2148,7 +2094,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
tp->phy_reset_enable = rtl8169_tbi_reset_enable;
|
||||
tp->phy_reset_pending = rtl8169_tbi_reset_pending;
|
||||
tp->link_ok = rtl8169_tbi_link_ok;
|
||||
tp->do_ioctl = rtl_tbi_ioctl;
|
||||
|
||||
tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */
|
||||
} else {
|
||||
|
|
@ -2157,7 +2102,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
tp->phy_reset_enable = rtl8169_xmii_reset_enable;
|
||||
tp->phy_reset_pending = rtl8169_xmii_reset_pending;
|
||||
tp->link_ok = rtl8169_xmii_link_ok;
|
||||
tp->do_ioctl = rtl_xmii_ioctl;
|
||||
|
||||
dev->do_ioctl = rtl8169_ioctl;
|
||||
}
|
||||
|
||||
spin_lock_init(&tp->lock);
|
||||
|
|
@ -2169,15 +2115,28 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
dev->dev_addr[i] = RTL_R8(MAC0 + i);
|
||||
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
|
||||
|
||||
dev->open = rtl8169_open;
|
||||
dev->hard_start_xmit = rtl8169_start_xmit;
|
||||
dev->get_stats = rtl8169_get_stats;
|
||||
SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
|
||||
dev->stop = rtl8169_close;
|
||||
dev->tx_timeout = rtl8169_tx_timeout;
|
||||
dev->set_multicast_list = rtl_set_rx_mode;
|
||||
dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
|
||||
dev->irq = pdev->irq;
|
||||
dev->base_addr = (unsigned long) ioaddr;
|
||||
dev->change_mtu = rtl8169_change_mtu;
|
||||
dev->set_mac_address = rtl_set_mac_address;
|
||||
|
||||
netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);
|
||||
|
||||
#ifdef CONFIG_R8169_VLAN
|
||||
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
||||
dev->vlan_rx_register = rtl8169_vlan_rx_register;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
dev->poll_controller = rtl8169_netpoll;
|
||||
#endif
|
||||
|
||||
tp->intr_mask = 0xffff;
|
||||
|
|
@ -2217,12 +2176,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
|
||||
rtl8169_init_phy(dev, tp);
|
||||
device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
|
||||
|
||||
if (tp->ecdev && ecdev_open(tp->ecdev)) {
|
||||
ecdev_withdraw(tp->ecdev);
|
||||
goto err_out_msi_5;
|
||||
}
|
||||
|
||||
|
||||
out:
|
||||
return rc;
|
||||
|
||||
|
|
@ -2305,8 +2264,8 @@ static int rtl8169_open(struct net_device *dev)
|
|||
goto err_release_ring_2;
|
||||
|
||||
napi_enable(&tp->napi);
|
||||
|
||||
}
|
||||
|
||||
rtl_hw_start(dev);
|
||||
|
||||
rtl8169_request_timer(dev);
|
||||
|
|
@ -2383,9 +2342,9 @@ static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
|
|||
* Switching from MMIO to I/O access fixes the issue as well.
|
||||
*/
|
||||
RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
|
||||
RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
|
||||
RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_32BIT_MASK);
|
||||
RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
|
||||
RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
|
||||
RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_32BIT_MASK);
|
||||
}
|
||||
|
||||
static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
|
||||
|
|
@ -2397,10 +2356,10 @@ static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
|
|||
return cmd;
|
||||
}
|
||||
|
||||
static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz)
|
||||
static void rtl_set_rx_max_size(void __iomem *ioaddr)
|
||||
{
|
||||
/* Low hurts. Let's disable the filtering. */
|
||||
RTL_W16(RxMaxSize, rx_buf_sz);
|
||||
RTL_W16(RxMaxSize, 16383);
|
||||
}
|
||||
|
||||
static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
|
||||
|
|
@ -2433,8 +2392,6 @@ static void rtl_hw_start_8169(struct net_device *dev)
|
|||
void __iomem *ioaddr = tp->mmio_addr;
|
||||
struct pci_dev *pdev = tp->pci_dev;
|
||||
|
||||
printk(KERN_INFO "%s\n", __func__);
|
||||
|
||||
if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
|
||||
RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
|
||||
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
|
||||
|
|
@ -2449,7 +2406,7 @@ static void rtl_hw_start_8169(struct net_device *dev)
|
|||
|
||||
RTL_W8(EarlyTxThres, EarlyTxThld);
|
||||
|
||||
rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz);
|
||||
rtl_set_rx_max_size(ioaddr);
|
||||
|
||||
if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_02) ||
|
||||
|
|
@ -2711,7 +2668,7 @@ static void rtl_hw_start_8168(struct net_device *dev)
|
|||
|
||||
RTL_W8(EarlyTxThres, EarlyTxThld);
|
||||
|
||||
rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz);
|
||||
rtl_set_rx_max_size(ioaddr);
|
||||
|
||||
tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
|
||||
|
||||
|
|
@ -2890,7 +2847,7 @@ static void rtl_hw_start_8101(struct net_device *dev)
|
|||
|
||||
RTL_W8(EarlyTxThres, EarlyTxThld);
|
||||
|
||||
rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz);
|
||||
rtl_set_rx_max_size(ioaddr);
|
||||
|
||||
tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
|
||||
|
||||
|
|
@ -3303,6 +3260,13 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
opts1 |= FirstFrag;
|
||||
} else {
|
||||
len = skb->len;
|
||||
|
||||
if (unlikely(len < ETH_ZLEN)) {
|
||||
if (skb_padto(skb, ETH_ZLEN))
|
||||
goto err_update_stats;
|
||||
len = ETH_ZLEN;
|
||||
}
|
||||
|
||||
opts1 |= FirstFrag | LastFrag;
|
||||
tp->tx_skb[entry].skb = skb;
|
||||
}
|
||||
|
|
@ -3319,6 +3283,8 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
|
||||
txd->opts1 = cpu_to_le32(status);
|
||||
|
||||
dev->trans_start = jiffies;
|
||||
|
||||
tp->cur_tx += frags + 1;
|
||||
|
||||
smp_wmb();
|
||||
|
|
@ -3341,6 +3307,7 @@ err_stop:
|
|||
if (!tp->ecdev)
|
||||
netif_stop_queue(dev);
|
||||
ret = NETDEV_TX_BUSY;
|
||||
err_update_stats:
|
||||
dev->stats.tx_dropped++;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -3423,7 +3390,7 @@ static void rtl8169_tx_interrupt(struct net_device *dev,
|
|||
|
||||
if (status & LastFrag) {
|
||||
if (!tp->ecdev)
|
||||
dev_kfree_skb(tx_skb->skb);
|
||||
dev_kfree_skb_irq(tx_skb->skb);
|
||||
tx_skb->skb = NULL;
|
||||
}
|
||||
dirty_tx++;
|
||||
|
|
@ -3580,6 +3547,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
|
|||
netif_receive_skb(skb);
|
||||
}
|
||||
|
||||
dev->last_rx = jiffies;
|
||||
dev->stats.rx_bytes += pkt_size;
|
||||
dev->stats.rx_packets++;
|
||||
}
|
||||
|
|
@ -3626,64 +3594,54 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
|
|||
int handled = 0;
|
||||
int status;
|
||||
|
||||
/* loop handling interrupts until we have no new ones or
|
||||
* we hit a invalid/hotplug case.
|
||||
*/
|
||||
status = RTL_R16(IntrStatus);
|
||||
while (status && status != 0xffff) {
|
||||
handled = 1;
|
||||
|
||||
/* Handle all of the error cases first. These will reset
|
||||
* the chip, so just exit the loop.
|
||||
*/
|
||||
if (unlikely(!tp->ecdev && !netif_running(dev))) {
|
||||
rtl8169_asic_down(ioaddr);
|
||||
break;
|
||||
}
|
||||
/* hotplug/major error/no more work/shared irq */
|
||||
if ((status == 0xffff) || !status)
|
||||
goto out;
|
||||
|
||||
/* Work around for rx fifo overflow */
|
||||
if (unlikely(status & RxFIFOOver) &&
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_11)) {
|
||||
netif_stop_queue(dev);
|
||||
rtl8169_tx_timeout(dev);
|
||||
break;
|
||||
}
|
||||
handled = 1;
|
||||
|
||||
if (unlikely(status & SYSErr)) {
|
||||
rtl8169_pcierr_interrupt(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
if (status & LinkChg)
|
||||
rtl8169_check_link_status(dev, tp, ioaddr);
|
||||
|
||||
/* We need to see the lastest version of tp->intr_mask to
|
||||
* avoid ignoring an MSI interrupt and having to wait for
|
||||
* another event which may never come.
|
||||
*/
|
||||
smp_rmb();
|
||||
if (status & tp->intr_mask & tp->napi_event) {
|
||||
RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
|
||||
tp->intr_mask = ~tp->napi_event;
|
||||
|
||||
if (likely(napi_schedule_prep(&tp->napi)))
|
||||
__napi_schedule(&tp->napi);
|
||||
else if (netif_msg_intr(tp)) {
|
||||
printk(KERN_INFO "%s: interrupt %04x in poll\n",
|
||||
dev->name, status);
|
||||
}
|
||||
}
|
||||
|
||||
/* We only get a new MSI interrupt when all active irq
|
||||
* sources on the chip have been acknowledged. So, ack
|
||||
* everything we've seen and check if new sources have become
|
||||
* active to avoid blocking all interrupts from the chip.
|
||||
*/
|
||||
RTL_W16(IntrStatus,
|
||||
(status & RxFIFOOver) ? (status | RxOverflow) : status);
|
||||
status = RTL_R16(IntrStatus);
|
||||
if (unlikely(!tp->ecdev && !netif_running(dev))) {
|
||||
rtl8169_asic_down(ioaddr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
status &= tp->intr_mask;
|
||||
RTL_W16(IntrStatus,
|
||||
(status & RxFIFOOver) ? (status | RxOverflow) : status);
|
||||
|
||||
if (!(status & tp->intr_event))
|
||||
goto out;
|
||||
|
||||
/* Work around for rx fifo overflow */
|
||||
if (unlikely(status & RxFIFOOver) &&
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_11)) {
|
||||
netif_stop_queue(dev);
|
||||
rtl8169_tx_timeout(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(status & SYSErr)) {
|
||||
rtl8169_pcierr_interrupt(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (status & LinkChg)
|
||||
rtl8169_check_link_status(dev, tp, ioaddr);
|
||||
|
||||
if (status & tp->napi_event) {
|
||||
RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
|
||||
tp->intr_mask = ~tp->napi_event;
|
||||
|
||||
if (likely(netif_rx_schedule_prep(dev, &tp->napi)))
|
||||
__netif_rx_schedule(dev, &tp->napi);
|
||||
else if (netif_msg_intr(tp)) {
|
||||
printk(KERN_INFO "%s: interrupt %04x in poll\n",
|
||||
dev->name, status);
|
||||
}
|
||||
}
|
||||
out:
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
|
|
@ -3713,16 +3671,14 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
|
|||
rtl8169_tx_interrupt(dev, tp, ioaddr);
|
||||
|
||||
if (work_done < budget) {
|
||||
napi_complete(napi);
|
||||
|
||||
/* We need for force the visibility of tp->intr_mask
|
||||
* for other CPUs, as we can loose an MSI interrupt
|
||||
* and potentially wait for a retransmit timeout if we don't.
|
||||
* The posted write to IntrMask is safe, as it will
|
||||
* eventually make it to the chip and we won't loose anything
|
||||
* until it does.
|
||||
*/
|
||||
netif_rx_complete(dev, napi);
|
||||
tp->intr_mask = 0xffff;
|
||||
/*
|
||||
* 20040426: the barrier is not strictly required but the
|
||||
* behavior of the irq handler could be less predictable
|
||||
* without it. Btw, the lack of flush for the posted pci
|
||||
* write is safe - FR
|
||||
*/
|
||||
smp_wmb();
|
||||
RTL_W16(IntrMask, tp->intr_event);
|
||||
}
|
||||
|
|
@ -3753,8 +3709,8 @@ static void rtl8169_down(struct net_device *dev)
|
|||
netif_stop_queue(dev);
|
||||
|
||||
napi_disable(&tp->napi);
|
||||
|
||||
}
|
||||
|
||||
core_down:
|
||||
if (!tp->ecdev)
|
||||
spin_lock_irq(&tp->lock);
|
||||
|
|
@ -3799,9 +3755,6 @@ static int rtl8169_close(struct net_device *dev)
|
|||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
struct pci_dev *pdev = tp->pci_dev;
|
||||
|
||||
/* update counters before going down */
|
||||
rtl8169_update_counters(dev);
|
||||
|
||||
rtl8169_down(dev);
|
||||
|
||||
if (!tp->ecdev)
|
||||
|
|
@ -3896,40 +3849,52 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev)
|
|||
return &dev->stats;
|
||||
}
|
||||
|
||||
static void rtl8169_net_suspend(struct net_device *dev)
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
void __iomem *ioaddr = tp->mmio_addr;
|
||||
|
||||
if (tp->ecdev)
|
||||
return -EBUSY;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return;
|
||||
goto out_pci_suspend;
|
||||
|
||||
netif_device_detach(dev);
|
||||
netif_stop_queue(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
spin_lock_irq(&tp->lock);
|
||||
|
||||
static int rtl8169_suspend(struct device *device)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(device);
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
|
||||
if (tp->ecdev)
|
||||
return -EBUSY;
|
||||
rtl8169_asic_down(ioaddr);
|
||||
|
||||
rtl8169_net_suspend(dev);
|
||||
rtl8169_rx_missed(dev, ioaddr);
|
||||
|
||||
spin_unlock_irq(&tp->lock);
|
||||
|
||||
out_pci_suspend:
|
||||
pci_save_state(pdev);
|
||||
pci_enable_wake(pdev, pci_choose_state(pdev, state),
|
||||
(tp->features & RTL_FEATURE_WOL) ? 1 : 0);
|
||||
pci_set_power_state(pdev, pci_choose_state(pdev, state));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8169_resume(struct device *device)
|
||||
static int rtl8169_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(device);
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
|
||||
|
||||
if (tp->ecdev)
|
||||
return -EBUSY;
|
||||
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
pci_enable_wake(pdev, PCI_D0, 0);
|
||||
|
||||
if (!netif_running(dev))
|
||||
goto out;
|
||||
|
||||
|
|
@ -3940,59 +3905,23 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct dev_pm_ops rtl8169_pm_ops = {
|
||||
.suspend = rtl8169_suspend,
|
||||
.resume = rtl8169_resume,
|
||||
.freeze = rtl8169_suspend,
|
||||
.thaw = rtl8169_resume,
|
||||
.poweroff = rtl8169_suspend,
|
||||
.restore = rtl8169_resume,
|
||||
};
|
||||
|
||||
#define RTL8169_PM_OPS (&rtl8169_pm_ops)
|
||||
|
||||
#else /* !CONFIG_PM */
|
||||
|
||||
#define RTL8169_PM_OPS NULL
|
||||
|
||||
#endif /* !CONFIG_PM */
|
||||
|
||||
static void rtl_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
void __iomem *ioaddr = tp->mmio_addr;
|
||||
|
||||
rtl8169_net_suspend(dev);
|
||||
|
||||
spin_lock_irq(&tp->lock);
|
||||
|
||||
rtl8169_asic_down(ioaddr);
|
||||
|
||||
spin_unlock_irq(&tp->lock);
|
||||
|
||||
if (system_state == SYSTEM_POWER_OFF) {
|
||||
/* WoL fails with some 8168 when the receiver is disabled. */
|
||||
if (tp->features & RTL_FEATURE_WOL) {
|
||||
pci_clear_master(pdev);
|
||||
|
||||
RTL_W8(ChipCmd, CmdRxEnb);
|
||||
/* PCI commit */
|
||||
RTL_R8(ChipCmd);
|
||||
}
|
||||
|
||||
pci_wake_from_d3(pdev, true);
|
||||
pci_set_power_state(pdev, PCI_D3hot);
|
||||
}
|
||||
rtl8169_suspend(pdev, PMSG_SUSPEND);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct pci_driver rtl8169_pci_driver = {
|
||||
.name = MODULENAME,
|
||||
.id_table = rtl8169_pci_tbl,
|
||||
.probe = rtl8169_init_one,
|
||||
.remove = __devexit_p(rtl8169_remove_one),
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = rtl8169_suspend,
|
||||
.resume = rtl8169_resume,
|
||||
.shutdown = rtl_shutdown,
|
||||
.driver.pm = RTL8169_PM_OPS,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init rtl8169_init_module(void)
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@
|
|||
#define TX_BUFFS_AVAIL(tp) \
|
||||
(tp->dirty_tx + NUM_TX_DESC - tp->cur_tx - 1)
|
||||
|
||||
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
|
||||
static const int max_interrupt_work = 20;
|
||||
|
||||
/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
|
||||
The RTL chips use a 64 element hash table based on the Ethernet CRC. */
|
||||
static const int multicast_filter_limit = 32;
|
||||
|
|
@ -63,6 +66,7 @@ static const int multicast_filter_limit = 32;
|
|||
#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
|
||||
#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
|
||||
#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
|
||||
#define RxPacketMaxSize 0x3FE8 /* 16K - 1 - ETH_HLEN - VLAN - CRC... */
|
||||
#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */
|
||||
#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
|
||||
|
||||
|
|
@ -90,7 +94,6 @@ static const int multicast_filter_limit = 32;
|
|||
#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
|
||||
|
||||
enum mac_version {
|
||||
RTL_GIGA_MAC_NONE = 0x00,
|
||||
RTL_GIGA_MAC_VER_01 = 0x01, // 8169
|
||||
RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
|
||||
RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
|
||||
|
|
@ -434,22 +437,6 @@ enum features {
|
|||
RTL_FEATURE_GMII = (1 << 2),
|
||||
};
|
||||
|
||||
struct rtl8169_counters {
|
||||
__le64 tx_packets;
|
||||
__le64 rx_packets;
|
||||
__le64 tx_errors;
|
||||
__le32 rx_errors;
|
||||
__le16 rx_missed;
|
||||
__le16 align_errors;
|
||||
__le32 tx_one_collision;
|
||||
__le32 tx_multi_collision;
|
||||
__le64 rx_unicast;
|
||||
__le64 rx_broadcast;
|
||||
__le32 rx_multicast;
|
||||
__le16 tx_aborted;
|
||||
__le16 tx_underun;
|
||||
};
|
||||
|
||||
struct rtl8169_private {
|
||||
void __iomem *mmio_addr; /* memory map physical address */
|
||||
struct pci_dev *pci_dev; /* Index of PCI device */
|
||||
|
|
@ -476,6 +463,7 @@ struct rtl8169_private {
|
|||
u16 intr_event;
|
||||
u16 napi_event;
|
||||
u16 intr_mask;
|
||||
int phy_auto_nego_reg;
|
||||
int phy_1000_ctrl_reg;
|
||||
#ifdef CONFIG_R8169_VLAN
|
||||
struct vlan_group *vlgrp;
|
||||
|
|
@ -486,13 +474,11 @@ struct rtl8169_private {
|
|||
void (*hw_start)(struct net_device *);
|
||||
unsigned int (*phy_reset_pending)(void __iomem *);
|
||||
unsigned int (*link_ok)(void __iomem *);
|
||||
int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd);
|
||||
int pcie_cap;
|
||||
struct delayed_work task;
|
||||
unsigned features;
|
||||
|
||||
struct mii_if_info mii;
|
||||
struct rtl8169_counters counters;
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
|
||||
|
|
@ -840,81 +826,76 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
|
|||
{
|
||||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
void __iomem *ioaddr = tp->mmio_addr;
|
||||
int giga_ctrl, bmcr;
|
||||
int auto_nego, giga_ctrl;
|
||||
|
||||
auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
|
||||
auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
|
||||
ADVERTISE_100HALF | ADVERTISE_100FULL);
|
||||
giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
|
||||
giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
|
||||
|
||||
if (autoneg == AUTONEG_ENABLE) {
|
||||
int auto_nego;
|
||||
|
||||
auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
|
||||
auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
|
||||
ADVERTISE_100HALF | ADVERTISE_100FULL);
|
||||
auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
|
||||
|
||||
giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
|
||||
giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
|
||||
|
||||
/* The 8100e/8101e/8102e do Fast Ethernet only. */
|
||||
if ((tp->mac_version != RTL_GIGA_MAC_VER_07) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_08) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_09) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_10) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_13) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_14) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_15) &&
|
||||
(tp->mac_version != RTL_GIGA_MAC_VER_16)) {
|
||||
giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
|
||||
} else {
|
||||
if (speed == SPEED_10)
|
||||
auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL;
|
||||
else if (speed == SPEED_100)
|
||||
auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL;
|
||||
else if (speed == SPEED_1000)
|
||||
giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
|
||||
} else if (netif_msg_link(tp)) {
|
||||
|
||||
if (duplex == DUPLEX_HALF)
|
||||
auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL);
|
||||
|
||||
if (duplex == DUPLEX_FULL)
|
||||
auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF);
|
||||
|
||||
/* This tweak comes straight from Realtek's driver. */
|
||||
if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) &&
|
||||
((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_16))) {
|
||||
auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA;
|
||||
}
|
||||
}
|
||||
|
||||
/* The 8100e/8101e/8102e do Fast Ethernet only. */
|
||||
if ((tp->mac_version == RTL_GIGA_MAC_VER_07) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_08) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_09) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_10) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_13) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_14) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_15) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_16)) {
|
||||
if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) &&
|
||||
netif_msg_link(tp)) {
|
||||
printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n",
|
||||
dev->name);
|
||||
}
|
||||
|
||||
bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
|
||||
|
||||
if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_12) ||
|
||||
(tp->mac_version >= RTL_GIGA_MAC_VER_17)) {
|
||||
/*
|
||||
* Wake up the PHY.
|
||||
* Vendor specific (0x1f) and reserved (0x0e) MII
|
||||
* registers.
|
||||
*/
|
||||
mdio_write(ioaddr, 0x1f, 0x0000);
|
||||
mdio_write(ioaddr, 0x0e, 0x0000);
|
||||
}
|
||||
|
||||
mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
|
||||
mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
|
||||
} else {
|
||||
giga_ctrl = 0;
|
||||
|
||||
if (speed == SPEED_10)
|
||||
bmcr = 0;
|
||||
else if (speed == SPEED_100)
|
||||
bmcr = BMCR_SPEED100;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (duplex == DUPLEX_FULL)
|
||||
bmcr |= BMCR_FULLDPLX;
|
||||
|
||||
mdio_write(ioaddr, 0x1f, 0x0000);
|
||||
giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
|
||||
}
|
||||
|
||||
auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
|
||||
|
||||
if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_12) ||
|
||||
(tp->mac_version >= RTL_GIGA_MAC_VER_17)) {
|
||||
/*
|
||||
* Wake up the PHY.
|
||||
* Vendor specific (0x1f) and reserved (0x0e) MII registers.
|
||||
*/
|
||||
mdio_write(ioaddr, 0x1f, 0x0000);
|
||||
mdio_write(ioaddr, 0x0e, 0x0000);
|
||||
}
|
||||
|
||||
tp->phy_auto_nego_reg = auto_nego;
|
||||
tp->phy_1000_ctrl_reg = giga_ctrl;
|
||||
|
||||
mdio_write(ioaddr, MII_BMCR, bmcr);
|
||||
|
||||
if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_03)) {
|
||||
if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) {
|
||||
mdio_write(ioaddr, 0x17, 0x2138);
|
||||
mdio_write(ioaddr, 0x0e, 0x0260);
|
||||
} else {
|
||||
mdio_write(ioaddr, 0x17, 0x2108);
|
||||
mdio_write(ioaddr, 0x0e, 0x0000);
|
||||
}
|
||||
}
|
||||
|
||||
mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
|
||||
mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
|
||||
mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1118,6 +1099,22 @@ static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = {
|
|||
"tx_underrun",
|
||||
};
|
||||
|
||||
struct rtl8169_counters {
|
||||
__le64 tx_packets;
|
||||
__le64 rx_packets;
|
||||
__le64 tx_errors;
|
||||
__le32 rx_errors;
|
||||
__le16 rx_missed;
|
||||
__le16 align_errors;
|
||||
__le32 tx_one_collision;
|
||||
__le32 tx_multi_collision;
|
||||
__le64 rx_unicast;
|
||||
__le64 rx_broadcast;
|
||||
__le32 rx_multicast;
|
||||
__le16 tx_aborted;
|
||||
__le16 tx_underun;
|
||||
};
|
||||
|
||||
static int rtl8169_get_sset_count(struct net_device *dev, int sset)
|
||||
{
|
||||
switch (sset) {
|
||||
|
|
@ -1128,70 +1125,51 @@ static int rtl8169_get_sset_count(struct net_device *dev, int sset)
|
|||
}
|
||||
}
|
||||
|
||||
static void rtl8169_update_counters(struct net_device *dev)
|
||||
static void rtl8169_get_ethtool_stats(struct net_device *dev,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
void __iomem *ioaddr = tp->mmio_addr;
|
||||
struct rtl8169_counters *counters;
|
||||
dma_addr_t paddr;
|
||||
u32 cmd;
|
||||
int wait = 1000;
|
||||
|
||||
/*
|
||||
* Some chips are unable to dump tally counters when the receiver
|
||||
* is disabled.
|
||||
*/
|
||||
if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0)
|
||||
return;
|
||||
ASSERT_RTNL();
|
||||
|
||||
counters = pci_alloc_consistent(tp->pci_dev, sizeof(*counters), &paddr);
|
||||
if (!counters)
|
||||
return;
|
||||
|
||||
RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
|
||||
cmd = (u64)paddr & DMA_BIT_MASK(32);
|
||||
cmd = (u64)paddr & DMA_32BIT_MASK;
|
||||
RTL_W32(CounterAddrLow, cmd);
|
||||
RTL_W32(CounterAddrLow, cmd | CounterDump);
|
||||
|
||||
while (wait--) {
|
||||
if ((RTL_R32(CounterAddrLow) & CounterDump) == 0) {
|
||||
/* copy updated counters */
|
||||
memcpy(&tp->counters, counters, sizeof(*counters));
|
||||
while (RTL_R32(CounterAddrLow) & CounterDump) {
|
||||
if (msleep_interruptible(1))
|
||||
break;
|
||||
}
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
RTL_W32(CounterAddrLow, 0);
|
||||
RTL_W32(CounterAddrHigh, 0);
|
||||
|
||||
data[0] = le64_to_cpu(counters->tx_packets);
|
||||
data[1] = le64_to_cpu(counters->rx_packets);
|
||||
data[2] = le64_to_cpu(counters->tx_errors);
|
||||
data[3] = le32_to_cpu(counters->rx_errors);
|
||||
data[4] = le16_to_cpu(counters->rx_missed);
|
||||
data[5] = le16_to_cpu(counters->align_errors);
|
||||
data[6] = le32_to_cpu(counters->tx_one_collision);
|
||||
data[7] = le32_to_cpu(counters->tx_multi_collision);
|
||||
data[8] = le64_to_cpu(counters->rx_unicast);
|
||||
data[9] = le64_to_cpu(counters->rx_broadcast);
|
||||
data[10] = le32_to_cpu(counters->rx_multicast);
|
||||
data[11] = le16_to_cpu(counters->tx_aborted);
|
||||
data[12] = le16_to_cpu(counters->tx_underun);
|
||||
|
||||
pci_free_consistent(tp->pci_dev, sizeof(*counters), counters, paddr);
|
||||
}
|
||||
|
||||
static void rtl8169_get_ethtool_stats(struct net_device *dev,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
rtl8169_update_counters(dev);
|
||||
|
||||
data[0] = le64_to_cpu(tp->counters.tx_packets);
|
||||
data[1] = le64_to_cpu(tp->counters.rx_packets);
|
||||
data[2] = le64_to_cpu(tp->counters.tx_errors);
|
||||
data[3] = le32_to_cpu(tp->counters.rx_errors);
|
||||
data[4] = le16_to_cpu(tp->counters.rx_missed);
|
||||
data[5] = le16_to_cpu(tp->counters.align_errors);
|
||||
data[6] = le32_to_cpu(tp->counters.tx_one_collision);
|
||||
data[7] = le32_to_cpu(tp->counters.tx_multi_collision);
|
||||
data[8] = le64_to_cpu(tp->counters.rx_unicast);
|
||||
data[9] = le64_to_cpu(tp->counters.rx_broadcast);
|
||||
data[10] = le32_to_cpu(tp->counters.rx_multicast);
|
||||
data[11] = le16_to_cpu(tp->counters.tx_aborted);
|
||||
data[12] = le16_to_cpu(tp->counters.tx_underun);
|
||||
}
|
||||
|
||||
static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
|
||||
{
|
||||
switch(stringset) {
|
||||
|
|
@ -1297,8 +1275,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
|
|||
{ 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
|
||||
{ 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
|
||||
|
||||
/* Catch-all */
|
||||
{ 0x00000000, 0x00000000, RTL_GIGA_MAC_NONE }
|
||||
{ 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */
|
||||
}, *p = mac_info;
|
||||
u32 reg;
|
||||
|
||||
|
|
@ -1306,6 +1283,12 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
|
|||
while ((reg & p->mask) != p->val)
|
||||
p++;
|
||||
tp->mac_version = p->mac_version;
|
||||
|
||||
if (p->mask == 0x00000000) {
|
||||
struct pci_dev *pdev = tp->pci_dev;
|
||||
|
||||
dev_info(&pdev->dev, "unknown MAC (%08x)\n", reg);
|
||||
}
|
||||
}
|
||||
|
||||
static void rtl8169_print_mac_version(struct rtl8169_private *tp)
|
||||
|
|
@ -1846,11 +1829,9 @@ static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
struct mii_ioctl_data *data = if_mii(ifr);
|
||||
|
||||
return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV;
|
||||
}
|
||||
if (!netif_running(dev))
|
||||
return -ENODEV;
|
||||
|
||||
static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case SIOCGMIIPHY:
|
||||
data->phy_id = 32; /* Internal PHY */
|
||||
|
|
@ -1869,11 +1850,6 @@ static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *dat
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int rtl_tbi_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const struct rtl_cfg_info {
|
||||
void (*hw_start)(struct net_device *);
|
||||
unsigned int region;
|
||||
|
|
@ -1881,7 +1857,6 @@ static const struct rtl_cfg_info {
|
|||
u16 intr_event;
|
||||
u16 napi_event;
|
||||
unsigned features;
|
||||
u8 default_ver;
|
||||
} rtl_cfg_infos [] = {
|
||||
[RTL_CFG_0] = {
|
||||
.hw_start = rtl_hw_start_8169,
|
||||
|
|
@ -1890,8 +1865,7 @@ static const struct rtl_cfg_info {
|
|||
.intr_event = SYSErr | LinkChg | RxOverflow |
|
||||
RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
|
||||
.napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
|
||||
.features = RTL_FEATURE_GMII,
|
||||
.default_ver = RTL_GIGA_MAC_VER_01,
|
||||
.features = RTL_FEATURE_GMII
|
||||
},
|
||||
[RTL_CFG_1] = {
|
||||
.hw_start = rtl_hw_start_8168,
|
||||
|
|
@ -1900,8 +1874,7 @@ static const struct rtl_cfg_info {
|
|||
.intr_event = SYSErr | LinkChg | RxOverflow |
|
||||
TxErr | TxOK | RxOK | RxErr,
|
||||
.napi_event = TxErr | TxOK | RxOK | RxOverflow,
|
||||
.features = RTL_FEATURE_GMII | RTL_FEATURE_MSI,
|
||||
.default_ver = RTL_GIGA_MAC_VER_11,
|
||||
.features = RTL_FEATURE_GMII | RTL_FEATURE_MSI
|
||||
},
|
||||
[RTL_CFG_2] = {
|
||||
.hw_start = rtl_hw_start_8101,
|
||||
|
|
@ -1910,8 +1883,7 @@ static const struct rtl_cfg_info {
|
|||
.intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout |
|
||||
RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
|
||||
.napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
|
||||
.features = RTL_FEATURE_MSI,
|
||||
.default_ver = RTL_GIGA_MAC_VER_13,
|
||||
.features = RTL_FEATURE_MSI
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1943,26 +1915,6 @@ static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp)
|
|||
}
|
||||
}
|
||||
|
||||
static const struct net_device_ops rtl8169_netdev_ops = {
|
||||
.ndo_open = rtl8169_open,
|
||||
.ndo_stop = rtl8169_close,
|
||||
.ndo_get_stats = rtl8169_get_stats,
|
||||
.ndo_start_xmit = rtl8169_start_xmit,
|
||||
.ndo_tx_timeout = rtl8169_tx_timeout,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_change_mtu = rtl8169_change_mtu,
|
||||
.ndo_set_mac_address = rtl_set_mac_address,
|
||||
.ndo_do_ioctl = rtl8169_ioctl,
|
||||
.ndo_set_multicast_list = rtl_set_rx_mode,
|
||||
#ifdef CONFIG_R8169_VLAN
|
||||
.ndo_vlan_rx_register = rtl8169_vlan_rx_register,
|
||||
#endif
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = rtl8169_netpoll,
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
static int __devinit
|
||||
rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
|
|
@ -1989,7 +1941,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
}
|
||||
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
dev->netdev_ops = &rtl8169_netdev_ops;
|
||||
tp = netdev_priv(dev);
|
||||
tp->dev = dev;
|
||||
tp->pci_dev = pdev;
|
||||
|
|
@ -2046,11 +1997,11 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
tp->cp_cmd = PCIMulRW | RxChkSum;
|
||||
|
||||
if ((sizeof(dma_addr_t) > 4) &&
|
||||
!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {
|
||||
!pci_set_dma_mask(pdev, DMA_64BIT_MASK) && use_dac) {
|
||||
tp->cp_cmd |= PCIDAC;
|
||||
dev->features |= NETIF_F_HIGHDMA;
|
||||
} else {
|
||||
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
|
||||
if (rc < 0) {
|
||||
if (netif_msg_probe(tp)) {
|
||||
dev_err(&pdev->dev,
|
||||
|
|
@ -2060,6 +2011,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
}
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
/* ioremap MMIO region */
|
||||
ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);
|
||||
if (!ioaddr) {
|
||||
|
|
@ -2087,20 +2040,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
|
||||
RTL_W16(IntrStatus, 0xffff);
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
/* Identify chip attached to board */
|
||||
rtl8169_get_mac_version(tp, ioaddr);
|
||||
|
||||
/* Use appropriate default if unknown */
|
||||
if (tp->mac_version == RTL_GIGA_MAC_NONE) {
|
||||
if (netif_msg_probe(tp)) {
|
||||
dev_notice(&pdev->dev,
|
||||
"unknown MAC, using family default\n");
|
||||
}
|
||||
tp->mac_version = cfg->default_ver;
|
||||
}
|
||||
|
||||
rtl8169_print_mac_version(tp);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rtl_chip_info); i++) {
|
||||
|
|
@ -2108,9 +2050,13 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(rtl_chip_info)) {
|
||||
dev_err(&pdev->dev,
|
||||
"driver bug, MAC version not found in rtl_chip_info\n");
|
||||
goto err_out_msi_5;
|
||||
/* Unknown chip: assume array element #0, original RTL-8169 */
|
||||
if (netif_msg_probe(tp)) {
|
||||
dev_printk(KERN_DEBUG, &pdev->dev,
|
||||
"unknown chip version, assuming %s\n",
|
||||
rtl_chip_info[0].name);
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
tp->chipset = i;
|
||||
|
||||
|
|
@ -2131,7 +2077,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
tp->phy_reset_enable = rtl8169_tbi_reset_enable;
|
||||
tp->phy_reset_pending = rtl8169_tbi_reset_pending;
|
||||
tp->link_ok = rtl8169_tbi_link_ok;
|
||||
tp->do_ioctl = rtl_tbi_ioctl;
|
||||
|
||||
tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */
|
||||
} else {
|
||||
|
|
@ -2140,7 +2085,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
tp->phy_reset_enable = rtl8169_xmii_reset_enable;
|
||||
tp->phy_reset_pending = rtl8169_xmii_reset_pending;
|
||||
tp->link_ok = rtl8169_xmii_link_ok;
|
||||
tp->do_ioctl = rtl_xmii_ioctl;
|
||||
|
||||
dev->do_ioctl = rtl8169_ioctl;
|
||||
}
|
||||
|
||||
spin_lock_init(&tp->lock);
|
||||
|
|
@ -2152,15 +2098,28 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
dev->dev_addr[i] = RTL_R8(MAC0 + i);
|
||||
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
|
||||
|
||||
dev->open = rtl8169_open;
|
||||
dev->hard_start_xmit = rtl8169_start_xmit;
|
||||
dev->get_stats = rtl8169_get_stats;
|
||||
SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
|
||||
dev->stop = rtl8169_close;
|
||||
dev->tx_timeout = rtl8169_tx_timeout;
|
||||
dev->set_multicast_list = rtl_set_rx_mode;
|
||||
dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
|
||||
dev->irq = pdev->irq;
|
||||
dev->base_addr = (unsigned long) ioaddr;
|
||||
dev->change_mtu = rtl8169_change_mtu;
|
||||
dev->set_mac_address = rtl_set_mac_address;
|
||||
|
||||
netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);
|
||||
|
||||
#ifdef CONFIG_R8169_VLAN
|
||||
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
||||
dev->vlan_rx_register = rtl8169_vlan_rx_register;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
dev->poll_controller = rtl8169_netpoll;
|
||||
#endif
|
||||
|
||||
tp->intr_mask = 0xffff;
|
||||
|
|
@ -2348,9 +2307,9 @@ static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
|
|||
* Switching from MMIO to I/O access fixes the issue as well.
|
||||
*/
|
||||
RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
|
||||
RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
|
||||
RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_32BIT_MASK);
|
||||
RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
|
||||
RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
|
||||
RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_32BIT_MASK);
|
||||
}
|
||||
|
||||
static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
|
||||
|
|
@ -2362,10 +2321,10 @@ static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
|
|||
return cmd;
|
||||
}
|
||||
|
||||
static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz)
|
||||
static void rtl_set_rx_max_size(void __iomem *ioaddr)
|
||||
{
|
||||
/* Low hurts. Let's disable the filtering. */
|
||||
RTL_W16(RxMaxSize, rx_buf_sz);
|
||||
RTL_W16(RxMaxSize, 16383);
|
||||
}
|
||||
|
||||
static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
|
||||
|
|
@ -2412,7 +2371,7 @@ static void rtl_hw_start_8169(struct net_device *dev)
|
|||
|
||||
RTL_W8(EarlyTxThres, EarlyTxThld);
|
||||
|
||||
rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz);
|
||||
rtl_set_rx_max_size(ioaddr);
|
||||
|
||||
if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_02) ||
|
||||
|
|
@ -2673,7 +2632,7 @@ static void rtl_hw_start_8168(struct net_device *dev)
|
|||
|
||||
RTL_W8(EarlyTxThres, EarlyTxThld);
|
||||
|
||||
rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz);
|
||||
rtl_set_rx_max_size(ioaddr);
|
||||
|
||||
tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
|
||||
|
||||
|
|
@ -2851,7 +2810,7 @@ static void rtl_hw_start_8101(struct net_device *dev)
|
|||
|
||||
RTL_W8(EarlyTxThres, EarlyTxThld);
|
||||
|
||||
rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz);
|
||||
rtl_set_rx_max_size(ioaddr);
|
||||
|
||||
tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
|
||||
|
||||
|
|
@ -3259,6 +3218,13 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
opts1 |= FirstFrag;
|
||||
} else {
|
||||
len = skb->len;
|
||||
|
||||
if (unlikely(len < ETH_ZLEN)) {
|
||||
if (skb_padto(skb, ETH_ZLEN))
|
||||
goto err_update_stats;
|
||||
len = ETH_ZLEN;
|
||||
}
|
||||
|
||||
opts1 |= FirstFrag | LastFrag;
|
||||
tp->tx_skb[entry].skb = skb;
|
||||
}
|
||||
|
|
@ -3275,6 +3241,8 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
|
||||
txd->opts1 = cpu_to_le32(status);
|
||||
|
||||
dev->trans_start = jiffies;
|
||||
|
||||
tp->cur_tx += frags + 1;
|
||||
|
||||
smp_wmb();
|
||||
|
|
@ -3294,6 +3262,7 @@ out:
|
|||
err_stop:
|
||||
netif_stop_queue(dev);
|
||||
ret = NETDEV_TX_BUSY;
|
||||
err_update_stats:
|
||||
dev->stats.tx_dropped++;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -3375,7 +3344,7 @@ static void rtl8169_tx_interrupt(struct net_device *dev,
|
|||
rtl8169_unmap_tx_skb(tp->pci_dev, tx_skb, tp->TxDescArray + entry);
|
||||
|
||||
if (status & LastFrag) {
|
||||
dev_kfree_skb(tx_skb->skb);
|
||||
dev_kfree_skb_irq(tx_skb->skb);
|
||||
tx_skb->skb = NULL;
|
||||
}
|
||||
dirty_tx++;
|
||||
|
|
@ -3516,6 +3485,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
|
|||
if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0)
|
||||
netif_receive_skb(skb);
|
||||
|
||||
dev->last_rx = jiffies;
|
||||
dev->stats.rx_bytes += pkt_size;
|
||||
dev->stats.rx_packets++;
|
||||
}
|
||||
|
|
@ -3557,64 +3527,54 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
|
|||
int handled = 0;
|
||||
int status;
|
||||
|
||||
/* loop handling interrupts until we have no new ones or
|
||||
* we hit a invalid/hotplug case.
|
||||
*/
|
||||
status = RTL_R16(IntrStatus);
|
||||
while (status && status != 0xffff) {
|
||||
handled = 1;
|
||||
|
||||
/* Handle all of the error cases first. These will reset
|
||||
* the chip, so just exit the loop.
|
||||
*/
|
||||
if (unlikely(!netif_running(dev))) {
|
||||
rtl8169_asic_down(ioaddr);
|
||||
break;
|
||||
}
|
||||
/* hotplug/major error/no more work/shared irq */
|
||||
if ((status == 0xffff) || !status)
|
||||
goto out;
|
||||
|
||||
/* Work around for rx fifo overflow */
|
||||
if (unlikely(status & RxFIFOOver) &&
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_11)) {
|
||||
netif_stop_queue(dev);
|
||||
rtl8169_tx_timeout(dev);
|
||||
break;
|
||||
}
|
||||
handled = 1;
|
||||
|
||||
if (unlikely(status & SYSErr)) {
|
||||
rtl8169_pcierr_interrupt(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
if (status & LinkChg)
|
||||
rtl8169_check_link_status(dev, tp, ioaddr);
|
||||
|
||||
/* We need to see the lastest version of tp->intr_mask to
|
||||
* avoid ignoring an MSI interrupt and having to wait for
|
||||
* another event which may never come.
|
||||
*/
|
||||
smp_rmb();
|
||||
if (status & tp->intr_mask & tp->napi_event) {
|
||||
RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
|
||||
tp->intr_mask = ~tp->napi_event;
|
||||
|
||||
if (likely(napi_schedule_prep(&tp->napi)))
|
||||
__napi_schedule(&tp->napi);
|
||||
else if (netif_msg_intr(tp)) {
|
||||
printk(KERN_INFO "%s: interrupt %04x in poll\n",
|
||||
dev->name, status);
|
||||
}
|
||||
}
|
||||
|
||||
/* We only get a new MSI interrupt when all active irq
|
||||
* sources on the chip have been acknowledged. So, ack
|
||||
* everything we've seen and check if new sources have become
|
||||
* active to avoid blocking all interrupts from the chip.
|
||||
*/
|
||||
RTL_W16(IntrStatus,
|
||||
(status & RxFIFOOver) ? (status | RxOverflow) : status);
|
||||
status = RTL_R16(IntrStatus);
|
||||
if (unlikely(!netif_running(dev))) {
|
||||
rtl8169_asic_down(ioaddr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
status &= tp->intr_mask;
|
||||
RTL_W16(IntrStatus,
|
||||
(status & RxFIFOOver) ? (status | RxOverflow) : status);
|
||||
|
||||
if (!(status & tp->intr_event))
|
||||
goto out;
|
||||
|
||||
/* Work around for rx fifo overflow */
|
||||
if (unlikely(status & RxFIFOOver) &&
|
||||
(tp->mac_version == RTL_GIGA_MAC_VER_11)) {
|
||||
netif_stop_queue(dev);
|
||||
rtl8169_tx_timeout(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(status & SYSErr)) {
|
||||
rtl8169_pcierr_interrupt(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (status & LinkChg)
|
||||
rtl8169_check_link_status(dev, tp, ioaddr);
|
||||
|
||||
if (status & tp->napi_event) {
|
||||
RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
|
||||
tp->intr_mask = ~tp->napi_event;
|
||||
|
||||
if (likely(netif_rx_schedule_prep(dev, &tp->napi)))
|
||||
__netif_rx_schedule(dev, &tp->napi);
|
||||
else if (netif_msg_intr(tp)) {
|
||||
printk(KERN_INFO "%s: interrupt %04x in poll\n",
|
||||
dev->name, status);
|
||||
}
|
||||
}
|
||||
out:
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
|
|
@ -3629,16 +3589,14 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
|
|||
rtl8169_tx_interrupt(dev, tp, ioaddr);
|
||||
|
||||
if (work_done < budget) {
|
||||
napi_complete(napi);
|
||||
|
||||
/* We need for force the visibility of tp->intr_mask
|
||||
* for other CPUs, as we can loose an MSI interrupt
|
||||
* and potentially wait for a retransmit timeout if we don't.
|
||||
* The posted write to IntrMask is safe, as it will
|
||||
* eventually make it to the chip and we won't loose anything
|
||||
* until it does.
|
||||
*/
|
||||
netif_rx_complete(dev, napi);
|
||||
tp->intr_mask = 0xffff;
|
||||
/*
|
||||
* 20040426: the barrier is not strictly required but the
|
||||
* behavior of the irq handler could be less predictable
|
||||
* without it. Btw, the lack of flush for the posted pci
|
||||
* write is safe - FR
|
||||
*/
|
||||
smp_wmb();
|
||||
RTL_W16(IntrMask, tp->intr_event);
|
||||
}
|
||||
|
|
@ -3710,9 +3668,6 @@ static int rtl8169_close(struct net_device *dev)
|
|||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
struct pci_dev *pdev = tp->pci_dev;
|
||||
|
||||
/* update counters before going down */
|
||||
rtl8169_update_counters(dev);
|
||||
|
||||
rtl8169_down(dev);
|
||||
|
||||
free_irq(dev->irq, dev);
|
||||
|
|
@ -3806,32 +3761,45 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev)
|
|||
return &dev->stats;
|
||||
}
|
||||
|
||||
static void rtl8169_net_suspend(struct net_device *dev)
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
void __iomem *ioaddr = tp->mmio_addr;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return;
|
||||
goto out_pci_suspend;
|
||||
|
||||
netif_device_detach(dev);
|
||||
netif_stop_queue(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
spin_lock_irq(&tp->lock);
|
||||
|
||||
static int rtl8169_suspend(struct device *device)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(device);
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
rtl8169_asic_down(ioaddr);
|
||||
|
||||
rtl8169_net_suspend(dev);
|
||||
rtl8169_rx_missed(dev, ioaddr);
|
||||
|
||||
spin_unlock_irq(&tp->lock);
|
||||
|
||||
out_pci_suspend:
|
||||
pci_save_state(pdev);
|
||||
pci_enable_wake(pdev, pci_choose_state(pdev, state),
|
||||
(tp->features & RTL_FEATURE_WOL) ? 1 : 0);
|
||||
pci_set_power_state(pdev, pci_choose_state(pdev, state));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8169_resume(struct device *device)
|
||||
static int rtl8169_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(device);
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
pci_enable_wake(pdev, PCI_D0, 0);
|
||||
|
||||
if (!netif_running(dev))
|
||||
goto out;
|
||||
|
||||
|
|
@ -3842,59 +3810,23 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct dev_pm_ops rtl8169_pm_ops = {
|
||||
.suspend = rtl8169_suspend,
|
||||
.resume = rtl8169_resume,
|
||||
.freeze = rtl8169_suspend,
|
||||
.thaw = rtl8169_resume,
|
||||
.poweroff = rtl8169_suspend,
|
||||
.restore = rtl8169_resume,
|
||||
};
|
||||
|
||||
#define RTL8169_PM_OPS (&rtl8169_pm_ops)
|
||||
|
||||
#else /* !CONFIG_PM */
|
||||
|
||||
#define RTL8169_PM_OPS NULL
|
||||
|
||||
#endif /* !CONFIG_PM */
|
||||
|
||||
static void rtl_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
void __iomem *ioaddr = tp->mmio_addr;
|
||||
|
||||
rtl8169_net_suspend(dev);
|
||||
|
||||
spin_lock_irq(&tp->lock);
|
||||
|
||||
rtl8169_asic_down(ioaddr);
|
||||
|
||||
spin_unlock_irq(&tp->lock);
|
||||
|
||||
if (system_state == SYSTEM_POWER_OFF) {
|
||||
/* WoL fails with some 8168 when the receiver is disabled. */
|
||||
if (tp->features & RTL_FEATURE_WOL) {
|
||||
pci_clear_master(pdev);
|
||||
|
||||
RTL_W8(ChipCmd, CmdRxEnb);
|
||||
/* PCI commit */
|
||||
RTL_R8(ChipCmd);
|
||||
}
|
||||
|
||||
pci_wake_from_d3(pdev, true);
|
||||
pci_set_power_state(pdev, PCI_D3hot);
|
||||
}
|
||||
rtl8169_suspend(pdev, PMSG_SUSPEND);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct pci_driver rtl8169_pci_driver = {
|
||||
.name = MODULENAME,
|
||||
.id_table = rtl8169_pci_tbl,
|
||||
.probe = rtl8169_init_one,
|
||||
.remove = __devexit_p(rtl8169_remove_one),
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = rtl8169_suspend,
|
||||
.resume = rtl8169_resume,
|
||||
.shutdown = rtl_shutdown,
|
||||
.driver.pm = RTL8169_PM_OPS,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init rtl8169_init_module(void)
|
||||
|
|
|
|||
|
|
@ -75,7 +75,9 @@
|
|||
* - Removed 'const' from argument of ecrt_sdo_request_state(), because the
|
||||
* userspace library has to modify object internals.
|
||||
* - Added 64-bit data access macros.
|
||||
* - Added ecrt_slave_config_idn() method for storing SoE IDN configurations.
|
||||
* - Added ecrt_slave_config_idn() method for storing SoE IDN configurations,
|
||||
* and ecrt_master_read_idn() and ecrt_master_write_idn() to read/write IDNs
|
||||
* ad-hoc via the user-space library.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
|
@ -661,6 +663,44 @@ int ecrt_master_sdo_upload(
|
|||
uint32_t *abort_code /**< Abort code of the SDO upload. */
|
||||
);
|
||||
|
||||
/** Executes an SoE write request.
|
||||
*
|
||||
* Starts writing an IDN and blocks until the request was processed, or an
|
||||
* error occurred.
|
||||
*
|
||||
* \retval 0 Success.
|
||||
* \retval -1 An error occured.
|
||||
*/
|
||||
int ecrt_master_write_idn(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
uint16_t slave_position, /**< Slave position. */
|
||||
uint16_t idn, /**< SoE IDN (see ecrt_slave_config_idn()). */
|
||||
uint8_t *data, /**< Pointer to data to write. */
|
||||
size_t data_size, /**< Size of data to write. */
|
||||
uint32_t *error_code /**< Pointer to variable, where an SoE error code
|
||||
can be stored. */
|
||||
);
|
||||
|
||||
/** Executes an SoE read request.
|
||||
*
|
||||
* Starts reading an IDN and blocks until the request was processed, or an
|
||||
* error occurred.
|
||||
*
|
||||
* \retval 0 Success.
|
||||
* \retval -1 An error occured.
|
||||
*/
|
||||
int ecrt_master_read_idn(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
uint16_t slave_position, /**< Slave position. */
|
||||
uint16_t idn, /**< SoE IDN (see ecrt_slave_config_idn()). */
|
||||
uint8_t *target, /**< Pointer to memory where the read data can be
|
||||
stored. */
|
||||
size_t target_size, /**< Size of the memory \a target points to. */
|
||||
size_t *result_size, /**< Actual size of the received data. */
|
||||
uint32_t *error_code /**< Pointer to variable, where an SoE error code
|
||||
can be stored. */
|
||||
);
|
||||
|
||||
#endif /* #ifndef __KERNEL__ */
|
||||
|
||||
/** Finishes the configuration phase and prepares for cyclic operation.
|
||||
|
|
@ -1140,7 +1180,12 @@ ec_voe_handler_t *ecrt_slave_config_create_voe_handler(
|
|||
|
||||
/** Outputs the state of the slave configuration.
|
||||
*
|
||||
* Stores the state information in the given \a state structure.
|
||||
* Stores the state information in the given \a state structure. The state
|
||||
* information is updated by the master state machine, so it may take a few
|
||||
* cycles, until it changes.
|
||||
*
|
||||
* \attention If the state of process data exchange shall be monitored in
|
||||
* realtime, ecrt_domain_state() should be used.
|
||||
*/
|
||||
void ecrt_slave_config_state(
|
||||
const ec_slave_config_t *sc, /**< Slave configuration */
|
||||
|
|
@ -1256,6 +1301,8 @@ void ecrt_domain_queue(
|
|||
/** Reads the state of a domain.
|
||||
*
|
||||
* Stores the domain state in the given \a state structure.
|
||||
*
|
||||
* Using this method, the process data exchange can be monitored in realtime.
|
||||
*/
|
||||
void ecrt_domain_state(
|
||||
const ec_domain_t *domain, /**< Domain. */
|
||||
|
|
|
|||
|
|
@ -51,12 +51,13 @@
|
|||
struct ec_tty;
|
||||
typedef struct ec_tty ec_tty_t; /**< \see ec_tty */
|
||||
|
||||
/**
|
||||
* \param cflag_changed This callback function is called when the serial
|
||||
* settings shall be changed. The \a cflag argument contains the new settings.
|
||||
/** Operations on the virtual TTY interface.
|
||||
*/
|
||||
typedef struct {
|
||||
int (*cflag_changed)(void *, tcflag_t);
|
||||
int (*cflag_changed)(void *, tcflag_t); /**< Called when the serial
|
||||
* settings shall be changed. The
|
||||
* \a cflag argument contains the
|
||||
* new settings. */
|
||||
} ec_tty_operations_t;
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
|||
60
lib/master.c
60
lib/master.c
|
|
@ -264,10 +264,8 @@ int ecrt_master_sdo_download(ec_master_t *master, uint16_t slave_position,
|
|||
download.data = data;
|
||||
|
||||
if (ioctl(master->fd, EC_IOCTL_SLAVE_SDO_DOWNLOAD, &download) == -1) {
|
||||
if (errno == -EIO) {
|
||||
if (abort_code) {
|
||||
*abort_code = download.abort_code;
|
||||
}
|
||||
if (errno == EIO && abort_code) {
|
||||
*abort_code = download.abort_code;
|
||||
}
|
||||
fprintf(stderr, "Failed to execute SDO download: %s\n",
|
||||
strerror(errno));
|
||||
|
|
@ -292,10 +290,8 @@ int ecrt_master_sdo_upload(ec_master_t *master, uint16_t slave_position,
|
|||
upload.target = target;
|
||||
|
||||
if (ioctl(master->fd, EC_IOCTL_SLAVE_SDO_UPLOAD, &upload) == -1) {
|
||||
if (errno == -EIO) {
|
||||
if (abort_code) {
|
||||
*abort_code = upload.abort_code;
|
||||
}
|
||||
if (errno == EIO && abort_code) {
|
||||
*abort_code = upload.abort_code;
|
||||
}
|
||||
fprintf(stderr, "Failed to execute SDO upload: %s\n",
|
||||
strerror(errno));
|
||||
|
|
@ -308,6 +304,54 @@ int ecrt_master_sdo_upload(ec_master_t *master, uint16_t slave_position,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_master_write_idn(ec_master_t *master, uint16_t slave_position,
|
||||
uint16_t idn, uint8_t *data, size_t data_size, uint32_t *error_code)
|
||||
{
|
||||
ec_ioctl_slave_soe_write_t io;
|
||||
|
||||
io.slave_position = slave_position;
|
||||
io.idn = idn;
|
||||
io.data_size = data_size;
|
||||
io.data = data;
|
||||
|
||||
if (ioctl(master->fd, EC_IOCTL_SLAVE_SOE_WRITE, &io) == -1) {
|
||||
if (errno == EIO && error_code) {
|
||||
*error_code = io.error_code;
|
||||
}
|
||||
fprintf(stderr, "Failed to write IDN: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_master_read_idn(ec_master_t *master, uint16_t slave_position,
|
||||
uint16_t idn, uint8_t *target, size_t target_size,
|
||||
size_t *result_size, uint32_t *error_code)
|
||||
{
|
||||
ec_ioctl_slave_soe_read_t io;
|
||||
|
||||
io.slave_position = slave_position;
|
||||
io.idn = idn;
|
||||
io.mem_size = target_size;
|
||||
io.data = target;
|
||||
|
||||
if (ioctl(master->fd, EC_IOCTL_SLAVE_SOE_READ, &io) == -1) {
|
||||
if (errno == EIO && error_code) {
|
||||
*error_code = io.error_code;
|
||||
}
|
||||
fprintf(stderr, "Failed to read IDN: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
*result_size = io.data_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_master_activate(ec_master_t *master)
|
||||
{
|
||||
if (ioctl(master->fd, EC_IOCTL_ACTIVATE,
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ ec_master-objs := \
|
|||
sdo_request.o \
|
||||
slave.o \
|
||||
slave_config.o \
|
||||
soe_errors.o \
|
||||
soe_request.o \
|
||||
sync.o \
|
||||
sync_config.o \
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ noinst_HEADERS = \
|
|||
sdo_request.c sdo_request.h \
|
||||
slave.c slave.h \
|
||||
slave_config.c slave_config.h \
|
||||
soe_errors.c \
|
||||
soe_request.c soe_request.h \
|
||||
sync.c sync.h \
|
||||
sync_config.c sync_config.h \
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ int ec_cdev_ioctl_slave(
|
|||
data.product_code = slave->sii.product_code;
|
||||
data.revision_number = slave->sii.revision_number;
|
||||
data.serial_number = slave->sii.serial_number;
|
||||
data.alias = slave->sii.alias;
|
||||
data.alias = slave->effective_alias;
|
||||
data.boot_rx_mailbox_offset = slave->sii.boot_rx_mailbox_offset;
|
||||
data.boot_rx_mailbox_size = slave->sii.boot_rx_mailbox_size;
|
||||
data.boot_tx_mailbox_offset = slave->sii.boot_tx_mailbox_offset;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ int ec_dbgdev_tx(struct sk_buff *, struct net_device *);
|
|||
struct net_device_stats *ec_dbgdev_stats(struct net_device *);
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
|
||||
/** Device operations for debug interfaces.
|
||||
*/
|
||||
static const struct net_device_ops ec_dbg_netdev_ops =
|
||||
{
|
||||
.ndo_open = ec_dbgdev_open,
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@
|
|||
} while (0)
|
||||
#endif
|
||||
|
||||
/** List of intervals for frame statistics [s].
|
||||
*/
|
||||
static const unsigned int rate_intervals[] = {
|
||||
1, 10, 60
|
||||
};
|
||||
|
|
|
|||
|
|
@ -226,10 +226,13 @@ int ec_domain_finish(
|
|||
datagram_count = 0;
|
||||
datagram_used[EC_DIR_OUTPUT] = 0;
|
||||
datagram_used[EC_DIR_INPUT] = 0;
|
||||
|
||||
list_for_each_entry(fmmu_temp, &domain->fmmu_configs, list) {
|
||||
ec_slave_config_t *sc = (ec_slave_config_t *)fmmu_temp->sc; // we have to remove the constness, sorry
|
||||
sc->used_for_fmmu_datagram[fmmu_temp->dir] = 0;
|
||||
// we have to remove the constness, sorry FIXME
|
||||
ec_slave_config_t *sc = (ec_slave_config_t *) fmmu_temp->sc;
|
||||
sc->used_for_fmmu_datagram[fmmu_temp->dir] = 0;
|
||||
}
|
||||
|
||||
list_for_each_entry(fmmu, &domain->fmmu_configs, list) {
|
||||
// Correct logical FMMU address
|
||||
fmmu->logical_start_address += base_address;
|
||||
|
|
@ -241,6 +244,7 @@ int ec_domain_finish(
|
|||
datagram_used[fmmu->dir]++;
|
||||
sc->used_for_fmmu_datagram[fmmu->dir] = 1;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ struct net_device_stats *ec_eoedev_stats(struct net_device *);
|
|||
/*****************************************************************************/
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
|
||||
/** Device operations for EoE interfaces.
|
||||
*/
|
||||
static const struct net_device_ops ec_eoedev_ops = {
|
||||
.ndo_open = ec_eoedev_open,
|
||||
.ndo_stop = ec_eoedev_stop,
|
||||
|
|
@ -134,9 +136,9 @@ int ec_eoe_init(
|
|||
|
||||
/* device name eoe<MASTER>[as]<SLAVE>, because networking scripts don't
|
||||
* like hyphens etc. in interface names. */
|
||||
if (slave->sii.alias) {
|
||||
if (slave->effective_alias) {
|
||||
snprintf(name, EC_DATAGRAM_NAME_SIZE,
|
||||
"eoe%ua%u", slave->master->index, slave->sii.alias);
|
||||
"eoe%ua%u", slave->master->index, slave->effective_alias);
|
||||
} else {
|
||||
snprintf(name, EC_DATAGRAM_NAME_SIZE,
|
||||
"eoe%us%u", slave->master->index, slave->ring_position);
|
||||
|
|
|
|||
|
|
@ -335,7 +335,9 @@ void ec_fsm_change_state_status(ec_fsm_change_t *fsm
|
|||
*/
|
||||
|
||||
const ec_code_msg_t al_status_messages[] = {
|
||||
{0x0000, "No error"},
|
||||
{0x0001, "Unspecified error"},
|
||||
{0x0002, "No Memory"},
|
||||
{0x0011, "Invalid requested state change"},
|
||||
{0x0012, "Unknown requested state"},
|
||||
{0x0013, "Bootstrap not supported"},
|
||||
|
|
@ -345,7 +347,7 @@ const ec_code_msg_t al_status_messages[] = {
|
|||
{0x0017, "Invalid sync manager configuration"},
|
||||
{0x0018, "No valid inputs available"},
|
||||
{0x0019, "No valid outputs"},
|
||||
{0x001A, "Synchronisation error"},
|
||||
{0x001A, "Synchronization error"},
|
||||
{0x001B, "Sync manager watchdog"},
|
||||
{0x001C, "Invalid sync manager types"},
|
||||
{0x001D, "Invalid output configuration"},
|
||||
|
|
@ -355,19 +357,37 @@ const ec_code_msg_t al_status_messages[] = {
|
|||
{0x0021, "Slave needs INIT"},
|
||||
{0x0022, "Slave needs PREOP"},
|
||||
{0x0023, "Slave needs SAFEOP"},
|
||||
{0x0024, "Invalid Input Mapping"},
|
||||
{0x0025, "Invalid Output Mapping"},
|
||||
{0x0026, "Inconsistent Settings"},
|
||||
{0x0027, "Freerun not supported"},
|
||||
{0x0028, "Synchronization not supported"},
|
||||
{0x0029, "Freerun needs 3 Buffer Mode"},
|
||||
{0x002A, "Background Watchdog"},
|
||||
{0x002B, "No Valid Inputs and Outputs"},
|
||||
{0x002C, "Fatal Sync Error"},
|
||||
{0x002D, "No Sync Error"},
|
||||
{0x0030, "Invalid DC SYNCH configuration"},
|
||||
{0x0031, "Invalid DC latch configuration"},
|
||||
{0x0032, "PLL error"},
|
||||
{0x0033, "Invalid DC IO error"},
|
||||
{0x0034, "Invalid DC timeout error"},
|
||||
{0x0042, "MBOX EOE"},
|
||||
{0x0043, "MBOX COE"},
|
||||
{0x0044, "MBOX FOE"},
|
||||
{0x0045, "MBOX SOE"},
|
||||
{0x004F, "MBOX VOE"},
|
||||
{}
|
||||
{0x0033, "DC Sync IO Error"},
|
||||
{0x0034, "DC Sync Timeout Error"},
|
||||
{0x0035, "DC Invalid Sync Cycle Time"},
|
||||
{0x0036, "DC Sync0 Cycle Time"},
|
||||
{0x0037, "DC Sync1 Cycle Time"},
|
||||
{0x0041, "MBX_AOE"},
|
||||
{0x0042, "MBX_EOE"},
|
||||
{0x0043, "MBX_COE"},
|
||||
{0x0044, "MBX_FOE"},
|
||||
{0x0045, "MBX_SOE"},
|
||||
{0x004F, "MBX_VOE"},
|
||||
{0x0050, "EEPROM No Access"},
|
||||
{0x0051, "EEPROM Error"},
|
||||
{0x0060, "Slave Restarted Locally"},
|
||||
{0xffff}
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
|
|
@ -397,7 +417,7 @@ void ec_fsm_change_state_code(ec_fsm_change_t *fsm
|
|||
ec_datagram_print_wc_error(datagram);
|
||||
} else {
|
||||
code = EC_READ_U16(datagram->data);
|
||||
for (al_msg = al_status_messages; al_msg->code; al_msg++) {
|
||||
for (al_msg = al_status_messages; al_msg->code != 0xffff; al_msg++) {
|
||||
if (al_msg->code != code) continue;
|
||||
EC_ERR("AL status message 0x%04X: \"%s\".\n",
|
||||
al_msg->code, al_msg->message);
|
||||
|
|
|
|||
|
|
@ -45,11 +45,24 @@
|
|||
*/
|
||||
#define EC_FSM_COE_DICT_TIMEOUT 1000
|
||||
|
||||
#define EC_COE_DOWN_REQ_HEADER_SIZE 10
|
||||
#define EC_COE_DOWN_SEG_REQ_HEADER_SIZE 3
|
||||
#define EC_COE_DOWN_SEG_MIN_DATA_SIZE 7
|
||||
/** CoE download request header size.
|
||||
*/
|
||||
#define EC_COE_DOWN_REQ_HEADER_SIZE 10
|
||||
|
||||
/** CoE download segment request header size.
|
||||
*/
|
||||
#define EC_COE_DOWN_SEG_REQ_HEADER_SIZE 3
|
||||
|
||||
/** Minimum size of download segment.
|
||||
*/
|
||||
#define EC_COE_DOWN_SEG_MIN_DATA_SIZE 7
|
||||
|
||||
/** Enable debug output for CoE retries.
|
||||
*/
|
||||
#define DEBUG_RETRIES 0
|
||||
|
||||
/** Enable warning output if transfers take too long.
|
||||
*/
|
||||
#define DEBUG_LONG 0
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -1256,10 +1269,8 @@ void ec_fsm_coe_down_request(ec_fsm_coe_t *fsm /**< finite state machine */)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
CoE state: DOWN CHECK.
|
||||
*/
|
||||
|
||||
/** CoE state: DOWN CHECK.
|
||||
*/
|
||||
void ec_fsm_coe_down_check(ec_fsm_coe_t *fsm /**< finite state machine */)
|
||||
{
|
||||
ec_datagram_t *datagram = fsm->datagram;
|
||||
|
|
@ -1309,6 +1320,8 @@ void ec_fsm_coe_down_check(ec_fsm_coe_t *fsm /**< finite state machine */)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Prepare a download segment request.
|
||||
*/
|
||||
void ec_fsm_coe_down_prepare_segment_request(
|
||||
ec_fsm_coe_t *fsm /**< finite state machine */
|
||||
)
|
||||
|
|
|
|||
|
|
@ -104,37 +104,29 @@ void ec_fsm_foe_read_start(ec_fsm_foe_t *);
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Constructor.
|
||||
*/
|
||||
|
||||
/** Constructor.
|
||||
*/
|
||||
void ec_fsm_foe_init(ec_fsm_foe_t *fsm, /**< finite state machine */
|
||||
ec_datagram_t *datagram /**< datagram */
|
||||
)
|
||||
{
|
||||
fsm->state = NULL;
|
||||
fsm->datagram = datagram;
|
||||
fsm->rx_errors = 0;
|
||||
fsm->tx_errors = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Destructor.
|
||||
*/
|
||||
|
||||
/** Destructor.
|
||||
*/
|
||||
void ec_fsm_foe_clear(ec_fsm_foe_t *fsm /**< finite state machine */)
|
||||
{
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Executes the current state of the state machine.
|
||||
\return false, if state machine has terminated
|
||||
*/
|
||||
|
||||
/** Executes the current state of the state machine.
|
||||
* \return false, if state machine has terminated
|
||||
*/
|
||||
int ec_fsm_foe_exec(ec_fsm_foe_t *fsm /**< finite state machine */)
|
||||
{
|
||||
fsm->state(fsm);
|
||||
|
|
@ -144,11 +136,9 @@ int ec_fsm_foe_exec(ec_fsm_foe_t *fsm /**< finite state machine */)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Returns, if the state machine terminated with success.
|
||||
\return non-zero if successful.
|
||||
*/
|
||||
|
||||
/** Returns, if the state machine terminated with success.
|
||||
* \return non-zero if successful.
|
||||
*/
|
||||
int ec_fsm_foe_success(ec_fsm_foe_t *fsm /**< Finite state machine */)
|
||||
{
|
||||
return fsm->state == ec_fsm_foe_end;
|
||||
|
|
@ -176,10 +166,8 @@ void ec_fsm_foe_transfer(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
State: ERROR.
|
||||
*/
|
||||
|
||||
/** State: ERROR.
|
||||
*/
|
||||
void ec_fsm_foe_error(ec_fsm_foe_t *fsm /**< finite state machine */)
|
||||
{
|
||||
#ifdef DEBUG_FOE
|
||||
|
|
@ -189,10 +177,8 @@ void ec_fsm_foe_error(ec_fsm_foe_t *fsm /**< finite state machine */)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
State: END.
|
||||
*/
|
||||
|
||||
/** State: END.
|
||||
*/
|
||||
void ec_fsm_foe_end(ec_fsm_foe_t *fsm /**< finite state machine */)
|
||||
{
|
||||
#ifdef DEBUG_FOE
|
||||
|
|
@ -201,10 +187,9 @@ void ec_fsm_foe_end(ec_fsm_foe_t *fsm /**< finite state machine */)
|
|||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
Sends a file or the next fragment.
|
||||
*/
|
||||
|
||||
/** Sends a file or the next fragment.
|
||||
*/
|
||||
int ec_foe_prepare_data_send(ec_fsm_foe_t *fsm)
|
||||
{
|
||||
size_t remaining_size, current_size;
|
||||
|
|
@ -238,10 +223,9 @@ int ec_foe_prepare_data_send(ec_fsm_foe_t *fsm)
|
|||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
Prepare a write request (WRQ) with filename
|
||||
*/
|
||||
|
||||
/** Prepare a write request (WRQ) with filename
|
||||
*/
|
||||
int ec_foe_prepare_wrq_send(ec_fsm_foe_t *fsm)
|
||||
{
|
||||
size_t current_size;
|
||||
|
|
@ -532,10 +516,9 @@ void ec_fsm_foe_state_data_sent(
|
|||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
Prepare a read request (RRQ) with filename
|
||||
*/
|
||||
|
||||
/** Prepare a read request (RRQ) with filename
|
||||
*/
|
||||
int ec_foe_prepare_rrq_send(ec_fsm_foe_t *fsm)
|
||||
{
|
||||
size_t current_size;
|
||||
|
|
@ -560,7 +543,6 @@ int ec_foe_prepare_rrq_send(ec_fsm_foe_t *fsm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Prepare to send an acknowledge.
|
||||
|
|
@ -653,8 +635,6 @@ void ec_fsm_foe_read_start(
|
|||
ec_slave_t *slave = fsm->slave;
|
||||
|
||||
fsm->rx_buffer_offset = 0;
|
||||
fsm->rx_current_size = 0;
|
||||
fsm->rx_packet_no = 0;
|
||||
fsm->rx_expected_packet_no = 1;
|
||||
fsm->rx_last_packet = 0;
|
||||
|
||||
|
|
@ -914,7 +894,6 @@ void ec_foe_set_tx_error(
|
|||
uint32_t errorcode /**< FoE error code. */
|
||||
)
|
||||
{
|
||||
fsm->tx_errors++;
|
||||
fsm->request->result = errorcode;
|
||||
fsm->state = ec_fsm_foe_error;
|
||||
}
|
||||
|
|
@ -928,7 +907,6 @@ void ec_foe_set_rx_error(
|
|||
uint32_t errorcode /**< FoE error code. */
|
||||
)
|
||||
{
|
||||
fsm->rx_errors++;
|
||||
fsm->request->result = errorcode;
|
||||
fsm->state = ec_fsm_foe_error;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,31 +60,22 @@ struct ec_fsm_foe {
|
|||
ec_foe_request_t *request; /**< FoE request */
|
||||
uint8_t toggle; /**< toggle bit for segment commands */
|
||||
|
||||
/** \cond */
|
||||
uint8_t *tx_buffer; /**< Buffer with data to transmit. */
|
||||
uint32_t tx_buffer_size; /**< Size of data to transmit. */
|
||||
uint32_t tx_buffer_offset; /**< Offset of data to tranmit next. */
|
||||
uint32_t tx_last_packet; /**< Current packet is last one to send. */
|
||||
uint32_t tx_packet_no; /**< FoE packet number. */
|
||||
uint32_t tx_current_size; /**< Size of current packet to send. */
|
||||
uint8_t *tx_filename; /**< Name of file to transmit. */
|
||||
uint32_t tx_filename_len; /**< Lenth of transmit file name. */
|
||||
|
||||
uint32_t tx_errors;
|
||||
uint8_t *tx_buffer;
|
||||
uint32_t tx_buffer_size;
|
||||
uint32_t tx_buffer_offset;
|
||||
uint32_t tx_last_packet;
|
||||
uint32_t tx_packet_no;
|
||||
uint32_t tx_current_size;
|
||||
uint8_t *tx_filename;
|
||||
uint32_t tx_filename_len;
|
||||
|
||||
|
||||
uint32_t rx_errors;
|
||||
uint8_t *rx_buffer;
|
||||
uint32_t rx_buffer_size;
|
||||
uint32_t rx_buffer_offset;
|
||||
uint32_t rx_current_size;
|
||||
uint32_t rx_packet_no;
|
||||
uint32_t rx_expected_packet_no;
|
||||
uint32_t rx_last_packet;
|
||||
uint8_t *rx_filename;
|
||||
uint32_t rx_filename_len;
|
||||
|
||||
/** \endcond */
|
||||
uint8_t *rx_buffer; /**< Buffer for received data. */
|
||||
uint32_t rx_buffer_size; /**< Size of receive buffer. */
|
||||
uint32_t rx_buffer_offset; /**< Offset in receive buffer. */
|
||||
uint32_t rx_expected_packet_no; /**< Expected receive packet number. */
|
||||
uint32_t rx_last_packet; /**< Current packet is the last to receive. */
|
||||
uint8_t *rx_filename; /**< Name of the file to receive. */
|
||||
uint32_t rx_filename_len; /**< Length of the receive file name. */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -426,8 +426,8 @@ int ec_fsm_master_action_process_sdo(
|
|||
if (ec_sdo_request_timed_out(req)) {
|
||||
req->state = EC_INT_REQUEST_FAILURE;
|
||||
if (master->debug_level)
|
||||
EC_DBG("Internal SDO request for slave %u"
|
||||
" timed out...\n", slave->ring_position);
|
||||
EC_DBG("Internal SDO request for slave %u"
|
||||
" timed out...\n", slave->ring_position);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -877,6 +877,7 @@ void ec_fsm_master_state_write_sii(
|
|||
// alias was written
|
||||
slave->sii.alias = EC_READ_U16(request->words + 4);
|
||||
// TODO: read alias from register 0x0012
|
||||
slave->effective_alias = slave->sii.alias;
|
||||
}
|
||||
// TODO: Evaluate other SII contents!
|
||||
|
||||
|
|
@ -998,8 +999,12 @@ void ec_fsm_master_state_reg_request(
|
|||
}
|
||||
|
||||
request->state = EC_INT_REQUEST_SUCCESS;
|
||||
if (master->debug_level) {
|
||||
EC_DBG("Register request successful.\n");
|
||||
}
|
||||
} else {
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
EC_ERR("Register request failed.\n");
|
||||
}
|
||||
|
||||
wake_up(&master->reg_queue);
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ void ec_fsm_slave_state_sdo_request(
|
|||
return;
|
||||
}
|
||||
if (!ec_fsm_coe_success(&fsm->fsm_coe)) {
|
||||
EC_DBG("Failed to process SDO request for slave %u.\n",
|
||||
EC_ERR("Failed to process SDO request for slave %u.\n",
|
||||
fsm->slave->ring_position);
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&slave->sdo_queue);
|
||||
|
|
@ -411,7 +411,7 @@ void ec_fsm_slave_state_soe_request(
|
|||
}
|
||||
|
||||
if (!ec_fsm_soe_success(&fsm->fsm_soe)) {
|
||||
EC_DBG("Failed to process SoE request for slave %u.\n",
|
||||
EC_ERR("Failed to process SoE request for slave %u.\n",
|
||||
fsm->slave->ring_position);
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&slave->soe_queue);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Time difference [ns] to tolerate without setting a new system time offset.
|
||||
*/
|
||||
#define EC_SYSTEM_TIME_TOLERANCE_NS 100000000
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_fsm_slave_config_state_start(ec_fsm_slave_config_t *);
|
||||
void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *);
|
||||
void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *);
|
||||
|
|
@ -310,7 +316,7 @@ void ec_fsm_slave_config_enter_clear_sync(
|
|||
|
||||
// clear sync manager configurations
|
||||
ec_datagram_fpwr(datagram, slave->station_address, 0x0800, sync_size);
|
||||
memset(datagram->data, 0x00, sync_size);
|
||||
ec_datagram_zero(datagram);
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
fsm->state = ec_fsm_slave_config_state_clear_sync;
|
||||
}
|
||||
|
|
@ -400,7 +406,9 @@ void ec_fsm_slave_config_state_dc_clear_assign(
|
|||
ec_datagram_print_wc_error(datagram);
|
||||
}
|
||||
|
||||
// read DC system time and system time offset
|
||||
// read DC system time (0x0910, 64 bit)
|
||||
// gap (64 bit)
|
||||
// and time offset (0x0920, 64 bit)
|
||||
ec_datagram_fprd(fsm->datagram, fsm->slave->station_address, 0x0910, 24);
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
fsm->state = ec_fsm_slave_config_state_dc_read_offset;
|
||||
|
|
@ -408,6 +416,91 @@ void ec_fsm_slave_config_state_dc_clear_assign(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Configure 32 bit time offset.
|
||||
*/
|
||||
u64 ec_fsm_slave_config_dc_offset32(
|
||||
ec_fsm_slave_config_t *fsm, /**< slave state machine */
|
||||
u64 system_time, /**< System time register. */
|
||||
u64 old_offset, /**< Time offset register. */
|
||||
unsigned long jiffies_since_read /**< Jiffies for correction. */
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
u32 correction, system_time32, old_offset32, new_offset;
|
||||
s32 time_diff;
|
||||
|
||||
system_time32 = (u32) system_time;
|
||||
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;
|
||||
|
||||
if (slave->master->debug_level)
|
||||
EC_DBG("Slave %u: system_time=%u (corrected with %u),"
|
||||
" app_time=%u, diff=%i\n",
|
||||
slave->ring_position, system_time32, correction,
|
||||
(u32) slave->master->app_time, time_diff);
|
||||
|
||||
if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) {
|
||||
new_offset = time_diff + old_offset32;
|
||||
if (slave->master->debug_level)
|
||||
EC_DBG("Slave %u: Setting time offset to %u (was %u)\n",
|
||||
slave->ring_position, new_offset, old_offset32);
|
||||
return (u64) new_offset;
|
||||
} else {
|
||||
if (slave->master->debug_level)
|
||||
EC_DBG("Slave %u: Not touching time offset.\n",
|
||||
slave->ring_position);
|
||||
return old_offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Configure 64 bit time offset.
|
||||
*/
|
||||
u64 ec_fsm_slave_config_dc_offset64(
|
||||
ec_fsm_slave_config_t *fsm, /**< slave state machine */
|
||||
u64 system_time, /**< System time register. */
|
||||
u64 old_offset, /**< Time offset register. */
|
||||
unsigned long jiffies_since_read /**< Jiffies for correction. */
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
u64 new_offset, correction;
|
||||
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;
|
||||
|
||||
if (slave->master->debug_level)
|
||||
EC_DBG("Slave %u: system_time=%llu (corrected with %llu),"
|
||||
" app_time=%llu, diff=%lli\n",
|
||||
slave->ring_position, system_time, correction,
|
||||
slave->master->app_time, time_diff);
|
||||
|
||||
|
||||
if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) {
|
||||
new_offset = time_diff + old_offset;
|
||||
if (slave->master->debug_level)
|
||||
EC_DBG("Slave %u: Setting time offset to %llu (was %llu)\n",
|
||||
slave->ring_position, new_offset, old_offset);
|
||||
} else {
|
||||
new_offset = old_offset;
|
||||
if (slave->master->debug_level)
|
||||
EC_DBG("Slave %u: Not touching time offset.\n",
|
||||
slave->ring_position);
|
||||
}
|
||||
|
||||
return new_offset;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Slave configuration state: DC READ OFFSET.
|
||||
*/
|
||||
void ec_fsm_slave_config_state_dc_read_offset(
|
||||
|
|
@ -417,6 +510,7 @@ void ec_fsm_slave_config_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;
|
||||
|
||||
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
|
||||
return;
|
||||
|
|
@ -438,15 +532,17 @@ void ec_fsm_slave_config_state_dc_read_offset(
|
|||
return;
|
||||
}
|
||||
|
||||
system_time = EC_READ_U64(datagram->data);
|
||||
old_offset = EC_READ_U64(datagram->data + 16);
|
||||
new_offset = slave->master->app_time - system_time + old_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;
|
||||
|
||||
if (slave->master->debug_level)
|
||||
EC_DBG("Slave %u: DC system_time=%llu old_offset=%llu, "
|
||||
"app_time=%llu, new_offset=%llu\n",
|
||||
slave->ring_position, system_time, old_offset,
|
||||
slave->master->app_time, new_offset);
|
||||
if (slave->base_dc_range == EC_DC_32) {
|
||||
new_offset = ec_fsm_slave_config_dc_offset32(fsm,
|
||||
system_time, old_offset, jiffies_since_read);
|
||||
} else {
|
||||
new_offset = ec_fsm_slave_config_dc_offset64(fsm,
|
||||
system_time, old_offset, jiffies_since_read);
|
||||
}
|
||||
|
||||
// set DC system time offset and transmission delay
|
||||
ec_datagram_fpwr(datagram, slave->station_address, 0x0920, 12);
|
||||
|
|
@ -532,7 +628,7 @@ void ec_fsm_slave_config_enter_mbox_sync(
|
|||
|
||||
ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
|
||||
EC_SYNC_PAGE_SIZE * 2);
|
||||
memset(datagram->data, 0x00, EC_SYNC_PAGE_SIZE * 2);
|
||||
ec_datagram_zero(datagram);
|
||||
|
||||
ec_sync_init(&sync, slave);
|
||||
sync.physical_start_address = slave->sii.boot_rx_mailbox_offset;
|
||||
|
|
@ -812,7 +908,7 @@ void ec_fsm_slave_config_state_sdo_conf(
|
|||
}
|
||||
|
||||
// All SDOs are now configured.
|
||||
ec_fsm_slave_config_enter_soe_conf(fsm);
|
||||
ec_fsm_slave_config_enter_soe_conf(fsm);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -824,7 +920,7 @@ void ec_fsm_slave_config_enter_soe_conf(
|
|||
)
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
ec_fsm_soe_t *fsm_soe = &slave->fsm.fsm_soe;
|
||||
ec_fsm_soe_t *fsm_soe = &slave->fsm.fsm_soe;
|
||||
|
||||
if (!slave->config) {
|
||||
ec_fsm_slave_config_enter_pdo_sync(fsm);
|
||||
|
|
@ -842,9 +938,10 @@ void ec_fsm_slave_config_enter_soe_conf(
|
|||
fsm->soe_request = list_entry(fsm->slave->config->soe_configs.next,
|
||||
ec_soe_request_t, list);
|
||||
ec_soe_request_copy(&fsm->soe_request_copy, fsm->soe_request);
|
||||
ec_soe_request_write(&fsm->soe_request_copy);
|
||||
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);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -856,11 +953,12 @@ void ec_fsm_slave_config_state_soe_conf(
|
|||
)
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
ec_fsm_soe_t *fsm_soe = &slave->fsm.fsm_soe;
|
||||
ec_fsm_soe_t *fsm_soe = &slave->fsm.fsm_soe;
|
||||
|
||||
if (ec_fsm_soe_exec(fsm_soe)) {
|
||||
return;
|
||||
}
|
||||
ec_master_queue_external_datagram(slave->master, fsm_soe->datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ec_fsm_soe_success(fsm_soe)) {
|
||||
EC_ERR("SoE configuration failed for slave %u.\n",
|
||||
|
|
@ -883,6 +981,7 @@ void ec_fsm_slave_config_state_soe_conf(
|
|||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -609,6 +609,7 @@ void ec_fsm_slave_scan_state_sii_data(ec_fsm_slave_scan_t *fsm /**< slave state
|
|||
|
||||
slave->sii.alias =
|
||||
EC_READ_U16(slave->sii_words + 0x0004);
|
||||
slave->effective_alias = slave->sii.alias;
|
||||
slave->sii.vendor_id =
|
||||
EC_READ_U32(slave->sii_words + 0x0008);
|
||||
slave->sii.product_code =
|
||||
|
|
@ -738,9 +739,9 @@ void ec_fsm_slave_scan_enter_regalias(
|
|||
ec_datagram_t *datagram = fsm->datagram;
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
|
||||
// read alias from register 0x0012
|
||||
// read alias from register
|
||||
if (slave->master->debug_level)
|
||||
EC_DBG("Reading alias from register 0x0012 of slave %u.\n",
|
||||
EC_DBG("Reading alias from register of slave %u.\n",
|
||||
slave->ring_position);
|
||||
ec_datagram_fprd(datagram, slave->station_address, 0x0012, 2);
|
||||
ec_datagram_zero(datagram);
|
||||
|
|
@ -775,10 +776,10 @@ void ec_fsm_slave_scan_state_regalias(
|
|||
EC_WARN("Failed to read reg alias of slave %u.\n",
|
||||
fsm->slave->ring_position);
|
||||
} else {
|
||||
slave->sii.alias = EC_READ_U16(datagram->data);
|
||||
slave->effective_alias = EC_READ_U16(datagram->data);
|
||||
if (slave->master->debug_level)
|
||||
EC_DBG("Alias of slave %u is %u.\n",
|
||||
slave->ring_position,slave->sii.alias);
|
||||
EC_DBG("Read alias %u from register of slave %u.\n",
|
||||
slave->effective_alias, slave->ring_position);
|
||||
}
|
||||
if (slave->sii.mailbox_protocols & EC_MBOX_COE) {
|
||||
ec_fsm_slave_scan_enter_preop(fsm);
|
||||
|
|
|
|||
288
master/fsm_soe.c
288
master/fsm_soe.c
|
|
@ -45,16 +45,21 @@
|
|||
*/
|
||||
#define EC_MBOX_TYPE_SOE 0x05
|
||||
|
||||
#define EC_SOE_OPCODE_READ_REQUEST 0x01
|
||||
#define EC_SOE_OPCODE_READ_RESPONSE 0x02
|
||||
#define EC_SOE_OPCODE_WRITE_REQUEST 0x03
|
||||
#define EC_SOE_OPCODE_WRITE_RESPONSE 0x04
|
||||
/** SoE operations
|
||||
*/
|
||||
enum ec_soe_opcodes {
|
||||
OPCODE_READ_REQUEST = 0x01, /**< Read request. */
|
||||
OPCODE_READ_RESPONSE = 0x02, /**< Read response. */
|
||||
OPCODE_WRITE_REQUEST = 0x03, /**< Write request. */
|
||||
OPCODE_WRITE_RESPONSE = 0x04 /**< Write response. */
|
||||
};
|
||||
|
||||
#define EC_SOE_READ_REQUEST_SIZE 0x04
|
||||
#define EC_SOE_READ_RESPONSE_SIZE 0x04
|
||||
#define EC_SOE_WRITE_REQUEST_SIZE 0x04
|
||||
#define EC_SOE_WRITE_RESPONSE_SIZE 0x04
|
||||
/** Size of all SoE headers.
|
||||
*/
|
||||
#define EC_SOE_SIZE 0x04
|
||||
|
||||
/** SoE response timeout [ms].
|
||||
*/
|
||||
#define EC_SOE_RESPONSE_TIMEOUT 1000
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -74,12 +79,35 @@ void ec_fsm_soe_error(ec_fsm_soe_t *);
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
extern const ec_code_msg_t soe_error_codes[];
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Outputs an SoE error code.
|
||||
*/
|
||||
void ec_print_soe_error(uint16_t error_code)
|
||||
{
|
||||
const ec_code_msg_t *error_msg;
|
||||
|
||||
for (error_msg = soe_error_codes; error_msg->code; error_msg++) {
|
||||
if (error_msg->code == error_code) {
|
||||
EC_ERR("SoE error 0x%04X: \"%s\".\n",
|
||||
error_msg->code, error_msg->message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EC_ERR("Unknown SoE error 0x%04X.\n", error_code);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Constructor.
|
||||
*/
|
||||
void ec_fsm_soe_init(
|
||||
ec_fsm_soe_t *fsm, /**< finite state machine */
|
||||
ec_datagram_t *datagram /**< datagram */
|
||||
)
|
||||
ec_fsm_soe_t *fsm, /**< finite state machine */
|
||||
ec_datagram_t *datagram /**< datagram */
|
||||
)
|
||||
{
|
||||
fsm->state = NULL;
|
||||
fsm->datagram = datagram;
|
||||
|
|
@ -90,8 +118,8 @@ void ec_fsm_soe_init(
|
|||
/** Destructor.
|
||||
*/
|
||||
void ec_fsm_soe_clear(
|
||||
ec_fsm_soe_t *fsm /**< finite state machine */
|
||||
)
|
||||
ec_fsm_soe_t *fsm /**< finite state machine */
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -109,9 +137,9 @@ void ec_fsm_soe_transfer(
|
|||
fsm->request = request;
|
||||
if (request->dir == EC_DIR_OUTPUT) {
|
||||
fsm->state = ec_fsm_soe_write_start;
|
||||
} else {
|
||||
} else {
|
||||
fsm->state = ec_fsm_soe_read_start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -140,6 +168,26 @@ int ec_fsm_soe_success(ec_fsm_soe_t *fsm /**< Finite state machine */)
|
|||
return fsm->state == ec_fsm_soe_end;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Output information about a failed SoE transfer.
|
||||
*/
|
||||
void ec_fsm_soe_print_error(ec_fsm_soe_t *fsm /**< Finite state machine */)
|
||||
{
|
||||
ec_soe_request_t *request = fsm->request;
|
||||
|
||||
EC_ERR("");
|
||||
|
||||
if (request->dir == EC_DIR_OUTPUT) {
|
||||
printk("Writing");
|
||||
} else {
|
||||
printk("Reading");
|
||||
}
|
||||
|
||||
printk(" IDN 0x%04X failed on slave %u.\n",
|
||||
request->idn, fsm->slave->ring_position);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* SoE read state machine
|
||||
*****************************************************************************/
|
||||
|
|
@ -159,25 +207,27 @@ void ec_fsm_soe_read_start(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
request->idn, slave->ring_position);
|
||||
|
||||
if (!(slave->sii.mailbox_protocols & EC_MBOX_SOE)) {
|
||||
EC_ERR("Slave %u does not support SoE!\n", slave->ring_position);
|
||||
EC_ERR("Slave does not support SoE!\n");
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_SOE,
|
||||
EC_SOE_READ_REQUEST_SIZE);
|
||||
EC_SOE_SIZE);
|
||||
if (IS_ERR(data)) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
EC_WRITE_U8(data, EC_SOE_OPCODE_READ_REQUEST);
|
||||
EC_WRITE_U8(data, OPCODE_READ_REQUEST);
|
||||
EC_WRITE_U8(data + 1, 1 << 6); // request value
|
||||
EC_WRITE_U16(data + 2, request->idn);
|
||||
|
||||
if (master->debug_level) {
|
||||
EC_DBG("SCC read request:\n");
|
||||
ec_print_data(data, EC_SOE_READ_REQUEST_SIZE);
|
||||
ec_print_data(data, EC_SOE_SIZE);
|
||||
}
|
||||
|
||||
fsm->request->data_size = 0;
|
||||
|
|
@ -201,9 +251,9 @@ void ec_fsm_soe_read_request(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
|
||||
if (datagram->state != EC_DATAGRAM_RECEIVED) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Failed to receive SoE read request for slave %u: ",
|
||||
slave->ring_position);
|
||||
EC_ERR("Failed to receive SoE read request: ");
|
||||
ec_datagram_print_state(datagram);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -217,11 +267,10 @@ void ec_fsm_soe_read_request(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
}
|
||||
}
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Reception of SoE read request for IDN 0x%04x failed"
|
||||
" after %u ms on slave %u: ",
|
||||
fsm->request->idn, (u32) diff_ms,
|
||||
fsm->slave->ring_position);
|
||||
EC_ERR("Reception of SoE read request failed after %u ms: ",
|
||||
(u32) diff_ms);
|
||||
ec_datagram_print_wc_error(datagram);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -245,17 +294,17 @@ void ec_fsm_soe_read_check(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
|
||||
if (datagram->state != EC_DATAGRAM_RECEIVED) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Failed to receive SoE mailbox check datagram from slave %u: ",
|
||||
slave->ring_position);
|
||||
EC_ERR("Failed to receive SoE mailbox check datagram: ");
|
||||
ec_datagram_print_state(datagram);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (datagram->working_counter != 1) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Reception of SoE mailbox check datagram failed on slave %u: ",
|
||||
slave->ring_position);
|
||||
EC_ERR("Reception of SoE mailbox check datagram failed: ");
|
||||
ec_datagram_print_wc_error(datagram);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -264,9 +313,9 @@ void ec_fsm_soe_read_check(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
(datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
|
||||
if (diff_ms >= EC_SOE_RESPONSE_TIMEOUT) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Timeout after %u ms while waiting for IDN 0x%04x"
|
||||
" read response on slave %u.\n", (u32) diff_ms,
|
||||
fsm->request->idn, slave->ring_position);
|
||||
EC_ERR("Timeout after %u ms while waiting for read response.\n",
|
||||
(u32) diff_ms);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -300,23 +349,24 @@ void ec_fsm_soe_read_response(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
|
||||
if (datagram->state != EC_DATAGRAM_RECEIVED) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Failed to receive SoE read response datagram for"
|
||||
" slave %u: ", slave->ring_position);
|
||||
EC_ERR("Failed to receive SoE read response datagram: ");
|
||||
ec_datagram_print_state(datagram);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (datagram->working_counter != 1) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Reception of SoE read response failed on slave %u: ",
|
||||
slave->ring_position);
|
||||
EC_ERR("Reception of SoE read response failed: ");
|
||||
ec_datagram_print_wc_error(datagram);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
data = ec_slave_mbox_fetch(slave, datagram, &mbox_prot, &rec_size);
|
||||
if (IS_ERR(data)) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -327,53 +377,59 @@ void ec_fsm_soe_read_response(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
|
||||
if (mbox_prot != EC_MBOX_TYPE_SOE) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
|
||||
EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rec_size < EC_SOE_READ_RESPONSE_SIZE) {
|
||||
if (rec_size < EC_SOE_SIZE) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Received currupted SoE read response (%zu bytes)!\n",
|
||||
rec_size);
|
||||
EC_ERR("Received currupted SoE read response"
|
||||
" (%zu bytes)!\n", rec_size);
|
||||
ec_print_data(data, rec_size);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
header = EC_READ_U8(data);
|
||||
opcode = header & 0x7;
|
||||
opcode = header & 0x7;
|
||||
incomplete = (header >> 3) & 1;
|
||||
error_flag = (header >> 4) & 1;
|
||||
error_flag = (header >> 4) & 1;
|
||||
|
||||
if (opcode != EC_SOE_OPCODE_READ_RESPONSE) {
|
||||
if (opcode != OPCODE_READ_RESPONSE) {
|
||||
EC_ERR("Received no read response (opcode %x).\n", opcode);
|
||||
ec_print_data(data, rec_size);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
return;
|
||||
}
|
||||
|
||||
if (error_flag) {
|
||||
req->error_code = EC_READ_U16(data + rec_size - 2);
|
||||
EC_ERR("Received error response: 0x%04x.\n",
|
||||
req->error_code);
|
||||
if (error_flag) {
|
||||
req->error_code = EC_READ_U16(data + rec_size - 2);
|
||||
EC_ERR("Received error response:\n");
|
||||
ec_print_soe_error(req->error_code);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
return;
|
||||
} else {
|
||||
req->error_code = 0x0000;
|
||||
}
|
||||
} else {
|
||||
req->error_code = 0x0000;
|
||||
}
|
||||
|
||||
value_included = (EC_READ_U8(data + 1) >> 6) & 1;
|
||||
if (!value_included) {
|
||||
EC_ERR("No value included!\n");
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
return;
|
||||
}
|
||||
value_included = (EC_READ_U8(data + 1) >> 6) & 1;
|
||||
if (!value_included) {
|
||||
EC_ERR("No value included!\n");
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
return;
|
||||
}
|
||||
|
||||
data_size = rec_size - EC_SOE_READ_RESPONSE_SIZE;
|
||||
if (ec_soe_request_append_data(req,
|
||||
data + EC_SOE_READ_RESPONSE_SIZE, data_size)) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
return;
|
||||
}
|
||||
data_size = rec_size - EC_SOE_SIZE;
|
||||
if (ec_soe_request_append_data(req,
|
||||
data + EC_SOE_SIZE, data_size)) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (incomplete) {
|
||||
if (master->debug_level) {
|
||||
|
|
@ -412,11 +468,12 @@ void ec_fsm_soe_write_next_fragment(
|
|||
size_t header_size, max_fragment_size, remaining_size, fragment_size;
|
||||
uint16_t fragments_left;
|
||||
|
||||
header_size = EC_MBOX_HEADER_SIZE + EC_SOE_WRITE_REQUEST_SIZE;
|
||||
header_size = EC_MBOX_HEADER_SIZE + EC_SOE_SIZE;
|
||||
if (slave->configured_rx_mailbox_size <= header_size) {
|
||||
EC_ERR("Mailbox size (%u) too small for SoE write.\n",
|
||||
slave->configured_rx_mailbox_size);
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -430,21 +487,22 @@ void ec_fsm_soe_write_next_fragment(
|
|||
}
|
||||
|
||||
data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_SOE,
|
||||
EC_SOE_WRITE_REQUEST_SIZE + fragment_size);
|
||||
EC_SOE_SIZE + fragment_size);
|
||||
if (IS_ERR(data)) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
EC_WRITE_U8(data, EC_SOE_OPCODE_WRITE_REQUEST | incomplete << 3);
|
||||
EC_WRITE_U8(data, OPCODE_WRITE_REQUEST | incomplete << 3);
|
||||
EC_WRITE_U8(data + 1, 1 << 6); // only value included
|
||||
EC_WRITE_U16(data + 2, incomplete ? fragments_left : req->idn);
|
||||
memcpy(data + 4, req->data + fsm->offset, fragment_size);
|
||||
memcpy(data + 4, req->data + fsm->offset, fragment_size);
|
||||
fsm->offset += fragment_size;
|
||||
|
||||
if (master->debug_level) {
|
||||
EC_DBG("SCC write request:\n");
|
||||
ec_print_data(data, EC_SOE_WRITE_REQUEST_SIZE + fragment_size);
|
||||
ec_print_data(data, EC_SOE_SIZE + fragment_size);
|
||||
}
|
||||
|
||||
req->jiffies_sent = jiffies;
|
||||
|
|
@ -467,8 +525,9 @@ void ec_fsm_soe_write_start(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
req->idn, req->data_size, slave->ring_position);
|
||||
|
||||
if (!(slave->sii.mailbox_protocols & EC_MBOX_SOE)) {
|
||||
EC_ERR("Slave %u does not support SoE!\n", slave->ring_position);
|
||||
EC_ERR("Slave does not support SoE!\n");
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -491,9 +550,9 @@ void ec_fsm_soe_write_request(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
|
||||
if (datagram->state != EC_DATAGRAM_RECEIVED) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Failed to receive SoE write request for slave %u: ",
|
||||
slave->ring_position);
|
||||
EC_ERR("Failed to receive SoE write request: ");
|
||||
ec_datagram_print_state(datagram);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -507,11 +566,10 @@ void ec_fsm_soe_write_request(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
}
|
||||
}
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Reception of SoE write request for IDN 0x%04x failed"
|
||||
" after %u ms on slave %u: ",
|
||||
fsm->request->idn, (u32) diff_ms,
|
||||
fsm->slave->ring_position);
|
||||
EC_ERR("Reception of SoE write request failed after %u ms: ",
|
||||
(u32) diff_ms);
|
||||
ec_datagram_print_wc_error(datagram);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -537,17 +595,17 @@ void ec_fsm_soe_write_check(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
|
||||
if (datagram->state != EC_DATAGRAM_RECEIVED) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Failed to receive SoE write request datagram from slave %u: ",
|
||||
slave->ring_position);
|
||||
EC_ERR("Failed to receive SoE write request datagram: ");
|
||||
ec_datagram_print_state(datagram);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (datagram->working_counter != 1) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Reception of SoE write request datagram failed on slave %u: ",
|
||||
slave->ring_position);
|
||||
EC_ERR("Reception of SoE write request datagram: ");
|
||||
ec_datagram_print_wc_error(datagram);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -559,9 +617,9 @@ void ec_fsm_soe_write_check(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
(datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
|
||||
if (diff_ms >= EC_SOE_RESPONSE_TIMEOUT) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Timeout after %u ms while waiting for IDN 0x%04x"
|
||||
" write response on slave %u.\n", (u32) diff_ms,
|
||||
fsm->request->idn, slave->ring_position);
|
||||
EC_ERR("Timeout after %u ms while waiting"
|
||||
" for write response.\n", (u32) diff_ms);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -588,7 +646,7 @@ void ec_fsm_soe_write_response(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
ec_master_t *master = slave->master;
|
||||
ec_soe_request_t *req = fsm->request;
|
||||
uint8_t *data, mbox_prot, opcode, error_flag;
|
||||
uint16_t idn;
|
||||
uint16_t idn;
|
||||
size_t rec_size;
|
||||
|
||||
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
|
||||
|
|
@ -596,23 +654,24 @@ void ec_fsm_soe_write_response(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
|
||||
if (datagram->state != EC_DATAGRAM_RECEIVED) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Failed to receive SoE write response datagram for"
|
||||
" slave %u: ", slave->ring_position);
|
||||
EC_ERR("Failed to receive SoE write response datagram: ");
|
||||
ec_datagram_print_state(datagram);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (datagram->working_counter != 1) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Reception of SoE write response failed on slave %u: ",
|
||||
slave->ring_position);
|
||||
EC_ERR("Reception of SoE write response failed: ");
|
||||
ec_datagram_print_wc_error(datagram);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
data = ec_slave_mbox_fetch(slave, datagram, &mbox_prot, &rec_size);
|
||||
if (IS_ERR(data)) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -623,50 +682,55 @@ void ec_fsm_soe_write_response(ec_fsm_soe_t *fsm /**< finite state machine */)
|
|||
|
||||
if (mbox_prot != EC_MBOX_TYPE_SOE) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
|
||||
EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rec_size < EC_SOE_WRITE_RESPONSE_SIZE) {
|
||||
if (rec_size < EC_SOE_SIZE) {
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
EC_ERR("Received currupted SoE write response (%zu bytes)!\n",
|
||||
rec_size);
|
||||
rec_size);
|
||||
ec_print_data(data, rec_size);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
opcode = EC_READ_U8(data) & 0x7;
|
||||
if (opcode != EC_SOE_OPCODE_WRITE_RESPONSE) {
|
||||
opcode = EC_READ_U8(data) & 0x7;
|
||||
if (opcode != OPCODE_WRITE_RESPONSE) {
|
||||
EC_ERR("Received no write response (opcode %x).\n", opcode);
|
||||
ec_print_data(data, rec_size);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
return;
|
||||
}
|
||||
|
||||
idn = EC_READ_U16(data + 2);
|
||||
if (idn != req->idn) {
|
||||
EC_ERR("Received response for wrong IDN 0x%04x.\n", idn);
|
||||
idn = EC_READ_U16(data + 2);
|
||||
if (idn != req->idn) {
|
||||
EC_ERR("Received response for wrong IDN 0x%04x.\n", idn);
|
||||
ec_print_data(data, rec_size);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
return;
|
||||
}
|
||||
|
||||
error_flag = (EC_READ_U8(data) >> 4) & 1;
|
||||
if (error_flag) {
|
||||
if (rec_size < EC_SOE_WRITE_RESPONSE_SIZE + 2) {
|
||||
EC_ERR("Received corrupted error response - error flag set,"
|
||||
" but received size is %zu.\n", rec_size);
|
||||
} else {
|
||||
req->error_code = EC_READ_U16(data + EC_SOE_WRITE_RESPONSE_SIZE);
|
||||
EC_ERR("Received error response: 0x%04x.\n",
|
||||
req->error_code);
|
||||
}
|
||||
ec_print_data(data, rec_size);
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
return;
|
||||
} else {
|
||||
req->error_code = 0x0000;
|
||||
}
|
||||
}
|
||||
|
||||
error_flag = (EC_READ_U8(data) >> 4) & 1;
|
||||
if (error_flag) {
|
||||
if (rec_size < EC_SOE_SIZE + 2) {
|
||||
EC_ERR("Received corrupted error response - error flag set,"
|
||||
" but received size is %zu.\n", rec_size);
|
||||
} else {
|
||||
req->error_code = EC_READ_U16(data + EC_SOE_SIZE);
|
||||
EC_ERR("Received error response:\n");
|
||||
ec_print_soe_error(req->error_code);
|
||||
}
|
||||
ec_print_data(data, rec_size);
|
||||
ec_fsm_soe_print_error(fsm);
|
||||
fsm->state = ec_fsm_soe_error;
|
||||
return;
|
||||
} else {
|
||||
req->error_code = 0x0000;
|
||||
}
|
||||
|
||||
fsm->state = ec_fsm_soe_end; // success
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,8 +36,6 @@
|
|||
#ifndef __EC_MASTER_GLOBALS_H__
|
||||
#define __EC_MASTER_GLOBALS_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
|
|
@ -262,6 +260,12 @@ enum {
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Absolute value.
|
||||
*/
|
||||
#define EC_ABS(X) ((X) >= 0 ? (X) : -(X))
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
extern char *ec_master_version_str;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Size of the mailbox header.
|
||||
*/
|
||||
#define EC_MBOX_HEADER_SIZE 6
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
* EtherCAT technology and brand is only permitted in compliance with the
|
||||
* industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
*
|
||||
* vim: expandtab
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
|
|
@ -63,13 +65,20 @@
|
|||
/** Frame timeout in cycles.
|
||||
*/
|
||||
static cycles_t timeout_cycles;
|
||||
static cycles_t sdo_injection_timeout_cycles;
|
||||
|
||||
/** Timeout for external datagram injection [cycles].
|
||||
*/
|
||||
static cycles_t ext_injection_timeout_cycles;
|
||||
|
||||
#else
|
||||
|
||||
/** Frame timeout in jiffies.
|
||||
*/
|
||||
static unsigned long timeout_jiffies;
|
||||
static unsigned long sdo_injection_timeout_jiffies;
|
||||
|
||||
/** Timeout for external datagram injection [jiffies].
|
||||
*/
|
||||
static unsigned long ext_injection_timeout_jiffies;
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -92,11 +101,11 @@ void ec_master_init_static(void)
|
|||
{
|
||||
#ifdef EC_HAVE_CYCLES
|
||||
timeout_cycles = (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000);
|
||||
sdo_injection_timeout_cycles = (cycles_t) EC_SDO_INJECTION_TIMEOUT /* us */ * (cpu_khz / 1000);
|
||||
ext_injection_timeout_cycles = (cycles_t) EC_SDO_INJECTION_TIMEOUT /* us */ * (cpu_khz / 1000);
|
||||
#else
|
||||
// one jiffy may always elapse between time measurement
|
||||
timeout_jiffies = max(EC_IO_TIMEOUT * HZ / 1000000, 1);
|
||||
sdo_injection_timeout_jiffies = max(EC_SDO_INJECTION_TIMEOUT * HZ / 1000000, 1);
|
||||
ext_injection_timeout_jiffies = max(EC_SDO_INJECTION_TIMEOUT * HZ / 1000000, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -417,7 +426,7 @@ void ec_master_clear_slaves(ec_master_t *master)
|
|||
ec_master_sdo_request_t, list);
|
||||
list_del_init(&request->list); // dequeue
|
||||
EC_INFO("Discarding SDO request,"
|
||||
" slave %u does not exist anymore.\n",
|
||||
" slave %u does not exist anymore.\n",
|
||||
slave->ring_position);
|
||||
request->req.state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&slave->sdo_queue);
|
||||
|
|
@ -432,7 +441,7 @@ void ec_master_clear_slaves(ec_master_t *master)
|
|||
ec_master_foe_request_t, list);
|
||||
list_del_init(&request->list); // dequeue
|
||||
EC_INFO("Discarding FoE request,"
|
||||
" slave %u does not exist anymore.\n",
|
||||
" slave %u does not exist anymore.\n",
|
||||
slave->ring_position);
|
||||
request->req.state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&slave->foe_queue);
|
||||
|
|
@ -447,7 +456,7 @@ void ec_master_clear_slaves(ec_master_t *master)
|
|||
ec_master_soe_request_t, list);
|
||||
list_del_init(&request->list); // dequeue
|
||||
EC_INFO("Discarding SoE request,"
|
||||
" slave %u does not exist anymore.\n",
|
||||
" slave %u does not exist anymore.\n",
|
||||
slave->ring_position);
|
||||
request->req.state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&slave->soe_queue);
|
||||
|
|
@ -751,10 +760,10 @@ void ec_master_inject_external_datagrams(
|
|||
cycles_t cycles_now = get_cycles();
|
||||
|
||||
if (cycles_now - datagram->cycles_sent
|
||||
> sdo_injection_timeout_cycles)
|
||||
> ext_injection_timeout_cycles)
|
||||
#else
|
||||
if (jiffies - datagram->jiffies_sent
|
||||
> sdo_injection_timeout_jiffies)
|
||||
> ext_injection_timeout_jiffies)
|
||||
#endif
|
||||
{
|
||||
unsigned int time_us;
|
||||
|
|
@ -1517,7 +1526,7 @@ void ec_master_attach_slave_configs(
|
|||
if (alias) { \
|
||||
for (; slave < master->slaves + master->slave_count; \
|
||||
slave++) { \
|
||||
if (slave->sii.alias == alias) \
|
||||
if (slave->effective_alias == alias) \
|
||||
break; \
|
||||
} \
|
||||
if (slave == master->slaves + master->slave_count) \
|
||||
|
|
@ -1932,6 +1941,9 @@ int ecrt_master_activate(ec_master_t *master)
|
|||
uint32_t domain_offset;
|
||||
ec_domain_t *domain;
|
||||
int ret;
|
||||
#ifdef EC_EOE
|
||||
int eoe_was_running;
|
||||
#endif
|
||||
|
||||
if (master->debug_level)
|
||||
EC_DBG("ecrt_master_activate(master = 0x%p)\n", master);
|
||||
|
|
@ -1963,10 +1975,12 @@ int ecrt_master_activate(ec_master_t *master)
|
|||
up(&master->master_sem);
|
||||
|
||||
// restart EoE process and master thread with new locking
|
||||
|
||||
ec_master_thread_stop(master);
|
||||
#ifdef EC_EOE
|
||||
eoe_was_running = master->eoe_thread != NULL;
|
||||
ec_master_eoe_stop(master);
|
||||
#endif
|
||||
ec_master_thread_stop(master);
|
||||
|
||||
if (master->debug_level)
|
||||
EC_DBG("FSM datagram is %p.\n", &master->fsm_datagram);
|
||||
|
|
@ -1978,15 +1992,17 @@ int ecrt_master_activate(ec_master_t *master)
|
|||
master->receive_cb = master->app_receive_cb;
|
||||
master->cb_data = master->app_cb_data;
|
||||
|
||||
#ifdef EC_EOE
|
||||
if (eoe_was_running) {
|
||||
ec_master_eoe_start(master);
|
||||
}
|
||||
#endif
|
||||
ret = ec_master_thread_start(master, ec_master_operation_thread,
|
||||
"EtherCAT-OP");
|
||||
if (ret < 0) {
|
||||
EC_ERR("Failed to start master thread!\n");
|
||||
return ret;
|
||||
}
|
||||
#ifdef EC_EOE
|
||||
ec_master_eoe_start(master);
|
||||
#endif
|
||||
|
||||
master->allow_config = 1; // request the current configuration
|
||||
master->allow_scan = 1; // allow re-scanning on topology change
|
||||
|
|
@ -2001,6 +2017,7 @@ void ecrt_master_deactivate(ec_master_t *master)
|
|||
ec_slave_t *slave;
|
||||
#ifdef EC_EOE
|
||||
ec_eoe_t *eoe;
|
||||
int eoe_was_running;
|
||||
#endif
|
||||
|
||||
if (master->debug_level)
|
||||
|
|
@ -2011,10 +2028,11 @@ void ecrt_master_deactivate(ec_master_t *master)
|
|||
return;
|
||||
}
|
||||
|
||||
ec_master_thread_stop(master);
|
||||
#ifdef EC_EOE
|
||||
eoe_was_running = master->eoe_thread != NULL;
|
||||
ec_master_eoe_stop(master);
|
||||
#endif
|
||||
ec_master_thread_stop(master);
|
||||
|
||||
master->send_cb = ec_master_internal_send_cb;
|
||||
master->receive_cb = ec_master_internal_receive_cb;
|
||||
|
|
@ -2050,12 +2068,14 @@ void ecrt_master_deactivate(ec_master_t *master)
|
|||
master->app_start_time = 0ULL;
|
||||
master->has_start_time = 0;
|
||||
|
||||
#ifdef EC_EOE
|
||||
if (eoe_was_running) {
|
||||
ec_master_eoe_start(master);
|
||||
}
|
||||
#endif
|
||||
if (ec_master_thread_start(master, ec_master_idle_thread,
|
||||
"EtherCAT-IDLE"))
|
||||
EC_WARN("Failed to restart master thread!\n");
|
||||
#ifdef EC_EOE
|
||||
ec_master_eoe_start(master);
|
||||
#endif
|
||||
|
||||
master->allow_scan = 1;
|
||||
master->allow_config = 1;
|
||||
|
|
@ -2253,7 +2273,7 @@ int ecrt_master_get_slave(ec_master_t *master, uint16_t slave_position,
|
|||
slave_info->product_code = slave->sii.product_code;
|
||||
slave_info->revision_number = slave->sii.revision_number;
|
||||
slave_info->serial_number = slave->sii.serial_number;
|
||||
slave_info->alias = slave->sii.alias;
|
||||
slave_info->alias = slave->effective_alias;
|
||||
slave_info->current_on_ebus = slave->sii.current_on_ebus;
|
||||
slave_info->al_state = slave->current_state;
|
||||
slave_info->error_flag = slave->error_flag;
|
||||
|
|
|
|||
|
|
@ -155,8 +155,8 @@ struct ec_master {
|
|||
ext_datagram_queue. */
|
||||
|
||||
struct list_head external_datagram_queue; /**< External Datagram queue. */
|
||||
size_t send_interval; /* interval between calls to ecrt_master_send */
|
||||
size_t max_queue_size; /** max. size of datagram queue */
|
||||
size_t send_interval; /**< Interval between calls to ecrt_master_send */
|
||||
size_t max_queue_size; /**< Maximum size of datagram queue */
|
||||
struct list_head domains; /**< List of domains. */
|
||||
|
||||
unsigned int debug_level; /**< Master debug level. */
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ void ec_slave_init(
|
|||
slave->master = master;
|
||||
slave->ring_position = ring_position;
|
||||
slave->station_address = station_address;
|
||||
slave->effective_alias = 0x0000;
|
||||
|
||||
slave->config = NULL;
|
||||
slave->requested_state = EC_SLAVE_STATE_PREOP;
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ struct ec_slave
|
|||
// addresses
|
||||
uint16_t ring_position; /**< Ring position. */
|
||||
uint16_t station_address; /**< Configured station address. */
|
||||
uint16_t effective_alias; /**< Effective alias address. */
|
||||
|
||||
ec_slave_port_t ports[EC_MAX_PORTS]; /**< Ports. */
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
* EtherCAT technology and brand is only permitted in compliance with the
|
||||
* industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
*
|
||||
* vim: expandtab
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
|
|
@ -960,7 +962,7 @@ void ecrt_slave_config_state(const ec_slave_config_t *sc,
|
|||
/*****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_idn(ec_slave_config_t *sc, uint16_t idn,
|
||||
const uint8_t *data, size_t size)
|
||||
const uint8_t *data, size_t size)
|
||||
{
|
||||
ec_slave_t *slave = sc->slave;
|
||||
ec_soe_request_t *req;
|
||||
|
|
|
|||
|
|
@ -70,7 +70,9 @@ struct ec_slave_config {
|
|||
configurations. */
|
||||
ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]; /**< FMMU configurations. */
|
||||
uint8_t used_fmmus; /**< Number of FMMUs used. */
|
||||
unsigned int used_for_fmmu_datagram[EC_DIR_COUNT];
|
||||
unsigned int used_for_fmmu_datagram[EC_DIR_COUNT]; /**< Number of FMMUs
|
||||
used for process data
|
||||
exchange datagrams. */
|
||||
uint16_t dc_assign_activate; /**< Vendor-specific AssignActivate word. */
|
||||
ec_sync_signal_t dc_sync[EC_SYNC_SIGNAL_COUNT]; /**< DC sync signals. */
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT SoE errors.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** SoE error codes.
|
||||
*/
|
||||
const ec_code_msg_t soe_error_codes[] = {
|
||||
{0x1001, "No IDN"},
|
||||
{0x1009, "Invalid access to element 1"},
|
||||
{0x2001, "No name"},
|
||||
{0x2002, "Name transmission too short"},
|
||||
{0x2003, "Name transmission too long"},
|
||||
{0x2004, "Name cannot be changed, read only"},
|
||||
{0x2005, "Name is write protected at this time"},
|
||||
{0x3002, "Attribute transmission too short"},
|
||||
{0x3003, "Attribute transmission too long"},
|
||||
{0x3004, "Attribute cannot be changed, read only"},
|
||||
{0x3005, "Attribute is write protected at this time"},
|
||||
{0x4001, "No unit"},
|
||||
{0x4002, "Unit transmission too short"},
|
||||
{0x4003, "Unit transmission too long"},
|
||||
{0x4004, "Unit cannot be changed, read only"},
|
||||
{0x4005, "Unit is write proteced at this time"},
|
||||
{0x5001, "No minimum input value"},
|
||||
{0x5002, "Minimum input value transmission too short"},
|
||||
{0x5003, "Minimum input value transmission too long"},
|
||||
{0x5004, "Minimum input value cannot be changed, read only"},
|
||||
{0x5005, "Minimum input value is write protected at this time"},
|
||||
{0x6001, "No maximum input value"},
|
||||
{0x6002, "Maximum input value transmission too short"},
|
||||
{0x6003, "Maximum input value transmission too long"},
|
||||
{0x6004, "Maximum input value cannot be changed, read only"},
|
||||
{0x6005, "Maximum input value is write protected at this time"},
|
||||
{0x7002, "Operation data value transmission too short"},
|
||||
{0x7003, "Operation data value transmission too long"},
|
||||
{0x7004, "Operation data value cannot be changed, read only"},
|
||||
{0x7005, "Operation data value is write protected at this time"},
|
||||
{0x7006, "Operation data value is smaller than the minimum input value"},
|
||||
{0x7007, "Operation data value is greater than the minimum input value"},
|
||||
{0x7008, "Invalid operation data"},
|
||||
{0x7009, "Operation data is write protected by a password"},
|
||||
{0x700A, "Operation data is write protected"},
|
||||
{0x700B, "Invalid indirect addressing"},
|
||||
{0x700C, "Operation data is write protected due to other settings"},
|
||||
{0x700D, "Reserved"},
|
||||
{0x7010, "Procedure command already active"},
|
||||
{0x7011, "Procedure command not interruptible"},
|
||||
{0x7012, "Procedure command is at this time not executable"},
|
||||
{0x7013, "Procedure command not executable"},
|
||||
{0x7014, "No data state"},
|
||||
{0x8001, "No default value"},
|
||||
{0x8002, "Default value transmission too long"},
|
||||
{0x8004, "Default value cannot be changed, read only"},
|
||||
{0x800A, "Invalid drive number"},
|
||||
{0x800B, "General error"},
|
||||
{0x800C, "No element addressed"},
|
||||
{}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -206,7 +206,11 @@ int ec_soe_request_append_data(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_soe_request_read(ec_soe_request_t *req)
|
||||
/** Request a read operation.
|
||||
*/
|
||||
void ec_soe_request_read(
|
||||
ec_soe_request_t *req /**< SoE request. */
|
||||
)
|
||||
{
|
||||
req->dir = EC_DIR_INPUT;
|
||||
req->state = EC_INT_REQUEST_QUEUED;
|
||||
|
|
@ -215,7 +219,11 @@ void ec_soe_request_read(ec_soe_request_t *req)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_soe_request_write(ec_soe_request_t *req)
|
||||
/** Request a write operation.
|
||||
*/
|
||||
void ec_soe_request_write(
|
||||
ec_soe_request_t *req /**< SoE request. */
|
||||
)
|
||||
{
|
||||
req->dir = EC_DIR_OUTPUT;
|
||||
req->state = EC_INT_REQUEST_QUEUED;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
* EtherCAT technology and brand is only permitted in compliance with the
|
||||
* industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
*
|
||||
* vim: expandtab
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "Command.h"
|
||||
|
|
@ -189,35 +191,35 @@ void Command::throwSingleSlaveRequired(unsigned int size) const
|
|||
|
||||
Command::MasterIndexList Command::getMasterIndices() const
|
||||
{
|
||||
MasterIndexList indices;
|
||||
MasterIndexList indices;
|
||||
|
||||
try {
|
||||
MasterIndexParser p;
|
||||
indices = p.parse(masters.c_str());
|
||||
} catch (MasterDeviceException &e) {
|
||||
stringstream err;
|
||||
err << "Failed to obtain number of masters: " << e.what();
|
||||
throwCommandException(err);
|
||||
stringstream err;
|
||||
err << "Failed to obtain number of masters: " << e.what();
|
||||
throwCommandException(err);
|
||||
} catch (runtime_error &e) {
|
||||
stringstream err;
|
||||
stringstream err;
|
||||
err << "Invalid master argument '" << masters << "': " << e.what();
|
||||
throwInvalidUsageException(err);
|
||||
throwInvalidUsageException(err);
|
||||
}
|
||||
|
||||
return indices;
|
||||
return indices;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned int Command::getSingleMasterIndex() const
|
||||
{
|
||||
MasterIndexList masterIndices = getMasterIndices();
|
||||
MasterIndexList masterIndices = getMasterIndices();
|
||||
if (masterIndices.size() != 1) {
|
||||
stringstream err;
|
||||
stringstream err;
|
||||
err << getName() << " requires to select a single master!";
|
||||
throwInvalidUsageException(err);
|
||||
}
|
||||
return masterIndices.front();
|
||||
return masterIndices.front();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
* EtherCAT technology and brand is only permitted in compliance with the
|
||||
* industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
*
|
||||
* vim: expandtab
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
|
|
@ -70,7 +72,7 @@ string CommandCStruct::helpString() const
|
|||
|
||||
void CommandCStruct::execute(const StringVector &args)
|
||||
{
|
||||
MasterIndexList masterIndices;
|
||||
MasterIndexList masterIndices;
|
||||
SlaveList slaves;
|
||||
SlaveList::const_iterator si;
|
||||
|
||||
|
|
@ -80,7 +82,7 @@ void CommandCStruct::execute(const StringVector &args)
|
|||
throwInvalidUsageException(err);
|
||||
}
|
||||
|
||||
masterIndices = getMasterIndices();
|
||||
masterIndices = getMasterIndices();
|
||||
MasterIndexList::const_iterator mi;
|
||||
for (mi = masterIndices.begin();
|
||||
mi != masterIndices.end(); mi++) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
* EtherCAT technology and brand is only permitted in compliance with the
|
||||
* industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
*
|
||||
* vim: expandtab
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <list>
|
||||
|
|
@ -104,7 +106,7 @@ string CommandConfig::helpString() const
|
|||
*/
|
||||
void CommandConfig::execute(const StringVector &args)
|
||||
{
|
||||
MasterIndexList masterIndices;
|
||||
MasterIndexList masterIndices;
|
||||
bool doIndent;
|
||||
ConfigList configs;
|
||||
|
||||
|
|
@ -114,7 +116,7 @@ void CommandConfig::execute(const StringVector &args)
|
|||
throwInvalidUsageException(err);
|
||||
}
|
||||
|
||||
masterIndices = getMasterIndices();
|
||||
masterIndices = getMasterIndices();
|
||||
doIndent = masterIndices.size() > 1;
|
||||
MasterIndexList::const_iterator mi;
|
||||
for (mi = masterIndices.begin();
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
* EtherCAT technology and brand is only permitted in compliance with the
|
||||
* industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
*
|
||||
* vim: expandtab
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
|
|
@ -66,7 +68,7 @@ string CommandData::helpString() const
|
|||
|
||||
void CommandData::execute(const StringVector &args)
|
||||
{
|
||||
MasterIndexList masterIndices;
|
||||
MasterIndexList masterIndices;
|
||||
DomainList domains;
|
||||
DomainList::const_iterator di;
|
||||
|
||||
|
|
@ -76,7 +78,7 @@ void CommandData::execute(const StringVector &args)
|
|||
throwInvalidUsageException(err);
|
||||
}
|
||||
|
||||
masterIndices = getMasterIndices();
|
||||
masterIndices = getMasterIndices();
|
||||
MasterIndexList::const_iterator mi;
|
||||
for (mi = masterIndices.begin();
|
||||
mi != masterIndices.end(); mi++) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
* EtherCAT technology and brand is only permitted in compliance with the
|
||||
* industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
*
|
||||
* vim: expandtab
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <sstream>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
using namespace std;
|
||||
|
||||
#include "CommandSoeRead.h"
|
||||
|
|
@ -127,8 +126,7 @@ void CommandSoeRead::execute(const StringVector &args)
|
|||
m.readSoe(&ioctl);
|
||||
} catch (MasterDeviceSoeException &e) {
|
||||
delete [] ioctl.data;
|
||||
err << "SoE read command aborted with code 0x"
|
||||
<< setfill('0') << hex << setw(4) << e.errorCode;
|
||||
err << "SoE read command failed with code " << errorMsg(e.errorCode);
|
||||
throwCommandException(err);
|
||||
} catch (MasterDeviceException &e) {
|
||||
delete [] ioctl.data;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
using namespace std;
|
||||
|
||||
#include "CommandSoeWrite.h"
|
||||
|
|
@ -148,8 +147,7 @@ void CommandSoeWrite::execute(const StringVector &args)
|
|||
m.writeSoe(&ioctl);
|
||||
} catch (MasterDeviceSoeException &e) {
|
||||
delete [] ioctl.data;
|
||||
err << "SoE write command aborted with code 0x"
|
||||
<< setfill('0') << hex << setw(4) << e.errorCode << ".";
|
||||
err << "SoE write command failed with code " << errorMsg(e.errorCode);
|
||||
throwCommandException(err);
|
||||
} catch (MasterDeviceException &e) {
|
||||
delete [] ioctl.data;
|
||||
|
|
|
|||
|
|
@ -143,9 +143,9 @@ void CommandXml::generateSlaveXml(
|
|||
|
||||
cout
|
||||
<< in << " <Sm Enable=\"" << dec << (unsigned int) sync.enable
|
||||
<< "\" StartAddress=\"" << sync.physical_start_address
|
||||
<< "\" ControlByte=\"" << (unsigned int) sync.control_register
|
||||
<< "\" DefaultSize=\"" << sync.default_size
|
||||
<< "\" StartAddress=\"#x" << hex << sync.physical_start_address
|
||||
<< "\" ControlByte=\"#x" << hex << (unsigned int) sync.control_register
|
||||
<< "\" DefaultSize=\"" << dec << sync.default_size
|
||||
<< "\" />" << endl;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,9 @@ string DataTypeHandler::typeInfo()
|
|||
<< " int8, int16, int32, int64," << endl
|
||||
<< " uint8, uint16, uint32, uint64," << endl
|
||||
<< " float, double" << endl
|
||||
<< " string, octet_string, unicode_string." << endl;
|
||||
<< " string, octet_string, unicode_string." << endl
|
||||
<< "For sign-and-magnitude coding, use the following types:" << endl
|
||||
<< " sm8, sm16, sm32, sm64" << endl;
|
||||
return s.str();
|
||||
}
|
||||
|
||||
|
|
@ -232,6 +234,17 @@ size_t DataTypeHandler::interpretAsType(
|
|||
throw runtime_error(err.str());
|
||||
}
|
||||
|
||||
case 0xfffb: // sm8
|
||||
case 0xfffc: // sm16
|
||||
case 0xfffd: // sm32
|
||||
case 0xfffe: // sm64
|
||||
{
|
||||
stringstream err;
|
||||
err << "Sign-and-magitude types not yet"
|
||||
" implemented for input direction.";
|
||||
throw runtime_error(err.str());
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
stringstream err;
|
||||
|
|
@ -256,12 +269,19 @@ void DataTypeHandler::outputData(
|
|||
size_t dataSize
|
||||
)
|
||||
{
|
||||
if (type->byteSize && dataSize != type->byteSize) {
|
||||
stringstream err;
|
||||
err << "Data type mismatch. Expected " << type->name
|
||||
<< " with " << type->byteSize << " byte, but got "
|
||||
<< dataSize << " byte.";
|
||||
throw SizeException(err.str());
|
||||
uint16_t typeCode;
|
||||
|
||||
if (type) {
|
||||
if (type->byteSize && dataSize != type->byteSize) {
|
||||
stringstream err;
|
||||
err << "Data type mismatch. Expected " << type->name
|
||||
<< " with " << type->byteSize << " byte, but got "
|
||||
<< dataSize << " byte.";
|
||||
throw SizeException(err.str());
|
||||
}
|
||||
typeCode = type->code;
|
||||
} else {
|
||||
typeCode = 0xffff; // raw data
|
||||
}
|
||||
|
||||
o << setfill('0');
|
||||
|
|
@ -327,7 +347,7 @@ void DataTypeHandler::outputData(
|
|||
o << string((const char *) data, dataSize) << endl;
|
||||
break;
|
||||
case 0x000a: // octet_string
|
||||
o << string((const char *) data, dataSize) << endl;
|
||||
o << string((const char *) data, dataSize) << flush;
|
||||
break;
|
||||
case 0x000b: // unicode_string
|
||||
// FIXME encoding
|
||||
|
|
@ -354,6 +374,43 @@ void DataTypeHandler::outputData(
|
|||
<< " " << dec << val << endl;
|
||||
}
|
||||
break;
|
||||
case 0xfffb: // sm8
|
||||
{
|
||||
int8_t val = *(uint8_t *) data;
|
||||
int8_t smval = val < 0 ? (val & 0x7f) * -1 : val;
|
||||
|
||||
o << "0x" << hex << setw(2) << (int) val
|
||||
<< " " << dec << (int) smval << endl;
|
||||
}
|
||||
break;
|
||||
case 0xfffc: // sm16
|
||||
{
|
||||
int16_t val = le16_to_cpup(data);
|
||||
int16_t smval = val < 0 ? (val & 0x7fff) * -1 : val;
|
||||
|
||||
o << "0x" << hex << setw(4) << val
|
||||
<< " " << dec << smval << endl;
|
||||
}
|
||||
break;
|
||||
case 0xfffd: // sm32
|
||||
{
|
||||
int32_t val = le32_to_cpup(data);
|
||||
int32_t smval = val < 0 ? (val & 0x7fffffffUL) * -1 : val;
|
||||
|
||||
o << "0x" << hex << setw(8) << val
|
||||
<< " " << dec << smval << endl;
|
||||
}
|
||||
break;
|
||||
case 0xfffe: // sm64
|
||||
{
|
||||
int64_t val = le64_to_cpup(data);
|
||||
int64_t smval =
|
||||
val < 0 ? (val & 0x7fffffffffffffffULL) * -1 : val;
|
||||
|
||||
o << "0x" << hex << setw(16) << val
|
||||
<< " " << dec << smval << endl;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printRawData(o, (const uint8_t *) data, dataSize); // FIXME
|
||||
|
|
@ -406,6 +463,10 @@ const DataTypeHandler::DataType DataTypeHandler::dataTypes[] = {
|
|||
{"uint56", 0x001a, 7},
|
||||
{"uint64", 0x001b, 8},
|
||||
// reserved 0x001c-0x001f
|
||||
{"sm8", 0xfffb, 1}, // sign-and-magnitude coding
|
||||
{"sm16", 0xfffc, 2}, // sign-and-magnitude coding
|
||||
{"sm32", 0xfffd, 4}, // sign-and-magnitude coding
|
||||
{"sm64", 0xfffe, 8}, // sign-and-magnitude coding
|
||||
{"raw", 0xffff, 0},
|
||||
{}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ EXTRA_DIST =
|
|||
bin_PROGRAMS = ethercat
|
||||
|
||||
ethercat_SOURCES = \
|
||||
../master/soe_errors.c \
|
||||
Command.cpp \
|
||||
CommandAlias.cpp \
|
||||
CommandCStruct.cpp \
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ using namespace std;
|
|||
|
||||
#include "SoeCommand.h"
|
||||
|
||||
extern const ec_code_msg_t soe_error_codes[];
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
SoeCommand::SoeCommand(const string &name, const string &briefDesc):
|
||||
|
|
@ -105,4 +107,26 @@ uint16_t SoeCommand::parseIdn(const string &str)
|
|||
return idn;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Outputs an SoE error code.
|
||||
*/
|
||||
std::string SoeCommand::errorMsg(uint16_t code)
|
||||
{
|
||||
const ec_code_msg_t *error_msg;
|
||||
stringstream str;
|
||||
|
||||
str << "0x" << hex << setfill('0') << setw(4) << code << ": ";
|
||||
|
||||
for (error_msg = soe_error_codes; error_msg->code; error_msg++) {
|
||||
if (error_msg->code == code) {
|
||||
str << error_msg->message;
|
||||
return str.str();
|
||||
}
|
||||
}
|
||||
|
||||
str << "(Unknown)";
|
||||
return str.str();
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
* EtherCAT technology and brand is only permitted in compliance with the
|
||||
* industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
*
|
||||
* vim: expandtab
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __SOECOMMAND_H__
|
||||
|
|
@ -44,6 +46,7 @@ class SoeCommand:
|
|||
|
||||
protected:
|
||||
static uint16_t parseIdn(const string &);
|
||||
static std::string errorMsg(uint16_t);
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -545,9 +545,6 @@ static int ec_tty_ioctl(struct tty_struct *tty, struct file *file,
|
|||
}
|
||||
break;
|
||||
|
||||
case TIOCSSERIAL: // TODO
|
||||
break;
|
||||
|
||||
default:
|
||||
#if EC_TTY_DEBUG >= 2
|
||||
printk(KERN_INFO PFX "no ioctl() -> handled by tty core!\n");
|
||||
|
|
|
|||
Loading…
Reference in New Issue