p@2550: /**
p@2550: Network Driver for Beckhoff CCAT communication controller
p@2550: Copyright (C) 2014 Beckhoff Automation GmbH
p@2550: Author: Patrick Bruenn
p@2550:
p@2550: This program is free software; you can redistribute it and/or modify
p@2550: it under the terms of the GNU General Public License as published by
p@2550: the Free Software Foundation; either version 2 of the License, or
p@2550: (at your option) any later version.
p@2550:
p@2550: This program is distributed in the hope that it will be useful,
p@2550: but WITHOUT ANY WARRANTY; without even the implied warranty of
p@2550: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
p@2550: GNU General Public License for more details.
p@2550:
p@2550: You should have received a copy of the GNU General Public License along
p@2550: with this program; if not, write to the Free Software Foundation, Inc.,
p@2550: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
p@2550: */
p@2550:
p@2550: #ifndef _CCAT_H_
p@2550: #define _CCAT_H_
p@2550:
p@2550: #include
p@2567: #include
p@2550: #include
p@2550: #include
p@2550: #include "../ecdev.h"
p@2550:
p@2550: #define DRV_EXTRAVERSION "-ec"
p@2565: #define DRV_VERSION "0.9" DRV_EXTRAVERSION
p@2550: #define DRV_DESCRIPTION "Beckhoff CCAT Ethernet/EtherCAT Network Driver"
p@2550:
p@2551: #undef pr_fmt
p@2551: #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
p@2551:
p@2550: /**
p@2569: * CCAT function type identifiers (u16)
p@2569: */
p@2569: enum ccat_info_t {
p@2569: CCATINFO_NOTUSED = 0,
p@2569: CCATINFO_EPCS_PROM = 0xf,
p@2569: CCATINFO_ETHERCAT_MASTER_DMA = 0x14,
p@2569: CCATINFO_COPY_BLOCK = 0x17,
p@2569: CCATINFO_MAX
p@2569: };
p@2569:
p@2569: /**
p@2550: * struct ccat_bar - CCAT PCI Base Address Register(BAR) configuration
p@2550: * @start: start address of this BAR
p@2550: * @end: end address of this BAR
p@2550: * @len: length of this BAR
p@2550: * @flags: flags set on this BAR
p@2550: * @ioaddr: ioremapped address of this bar
p@2550: */
p@2550: struct ccat_bar {
p@2550: unsigned long start;
p@2550: unsigned long end;
p@2550: unsigned long len;
p@2550: unsigned long flags;
p@2550: void __iomem *ioaddr;
p@2550: };
p@2550:
p@2550: /**
p@2550: * struct ccat_dma - CCAT DMA channel configuration
p@2550: * @phys: device-viewed address(physical) of the associated DMA memory
p@2550: * @virt: CPU-viewed address(virtual) of the associated DMA memory
p@2550: * @size: number of bytes in the associated DMA memory
p@2550: * @channel: CCAT DMA channel number
p@2550: * @dev: valid struct device pointer
p@2550: */
p@2550: struct ccat_dma {
p@2550: dma_addr_t phys;
p@2550: void *virt;
p@2550: size_t size;
p@2550: size_t channel;
p@2550: struct device *dev;
p@2550: };
p@2550:
p@2550: extern void ccat_dma_free(struct ccat_dma *const dma);
p@2550: extern int ccat_dma_init(struct ccat_dma *const dma, size_t channel,
p@2550: void __iomem * const ioaddr, struct device *const dev);
p@2550:
p@2550: /**
p@2550: * struct ccat_eth_frame - Ethernet frame with DMA descriptor header in front
p@2550: * @reservedn: is not used and should always be set to 0
p@2550: * @received: used for reception, is set to 1 by the CCAT when data was written
p@2550: * @length: number of bytes in the frame including the DMA header
p@2550: * @sent: is set to 1 by the CCAT when data was transmitted
p@2550: * @timestamp: a 64 bit EtherCAT timestamp
p@2550: * @data: the bytes of the ethernet frame
p@2550: */
p@2550: struct ccat_eth_frame {
p@2576: __le32 reserved1;
p@2576: __le32 rx_flags;
p@2576: #define CCAT_FRAME_RECEIVED 0x1
p@2576: __le16 length;
p@2576: __le16 reserved3;
p@2576: __le32 tx_flags;
p@2576: #define CCAT_FRAME_SENT 0x1
p@2576: __le64 timestamp;
p@2567: u8 data[0x800 - 3 * sizeof(u64)];
p@2569: #define CCAT_ETH_FRAME_HEAD_LEN offsetof(struct ccat_eth_frame, data)
p@2550: };
p@2550:
p@2550: /**
p@2550: * struct ccat_eth_register - CCAT register addresses in the PCI BAR
p@2550: * @mii: address of the CCAT management interface register
p@2550: * @tx_fifo: address of the CCAT TX DMA fifo register
p@2550: * @rx_fifo: address of the CCAT RX DMA fifo register
p@2550: * @mac: address of the CCAT media access control register
p@2550: * @rx_mem: address of the CCAT register holding the RX DMA address
p@2550: * @tx_mem: address of the CCAT register holding the TX DMA address
p@2550: * @misc: address of a CCAT register holding miscellaneous information
p@2550: */
p@2550: struct ccat_eth_register {
p@2550: void __iomem *mii;
p@2550: void __iomem *tx_fifo;
p@2550: void __iomem *rx_fifo;
p@2550: void __iomem *mac;
p@2550: void __iomem *rx_mem;
p@2550: void __iomem *tx_mem;
p@2550: void __iomem *misc;
p@2550: };
p@2550:
p@2550: /**
p@2550: * struct ccat_eth_dma_fifo - CCAT RX or TX DMA fifo
p@2550: * @add: callback used to add a frame to this fifo
p@2550: * @reg: PCI register address of this DMA fifo
p@2550: * @dma: information about the associated DMA memory
p@2550: */
p@2550: struct ccat_eth_dma_fifo {
p@2576: void (*add) (struct ccat_eth_dma_fifo *, struct ccat_eth_frame *);
p@2550: void __iomem *reg;
p@2576: const struct ccat_eth_frame *end;
p@2576: struct ccat_eth_frame *next;
p@2550: struct ccat_dma dma;
p@2550: };
p@2550:
p@2550: /**
p@2550: * struct ccat_device - CCAT device representation
p@2550: * @pdev: pointer to the pci object allocated by the kernel
p@2550: * @ethdev: CCAT Ethernet/EtherCAT Master (with DMA) function, NULL if function is not available or failed to initialize
p@2550: * @update: CCAT Update function, NULL if function is not available or failed to initialize
p@2550: * @bar [0] and [2] holding information about PCI BARs 0 and 2.
p@2550: *
p@2550: * One instance of a ccat_device should represent a physical CCAT. Since
p@2550: * a CCAT is implemented as FPGA the available functions can vary so
p@2550: * the function object pointers can be NULL.
p@2550: * Extra note: you will recognize that PCI BAR1 is not used and is a
p@2550: * waste of memory, thats true but right now, its very easy to use it
p@2550: * this way. So we might optimize it later.
p@2550: */
p@2550: struct ccat_device {
p@2550: struct pci_dev *pdev;
p@2550: struct ccat_eth_priv *ethdev;
p@2550: struct ccat_update *update;
p@2550: struct ccat_bar bar[3]; //TODO optimize this
p@2550: };
p@2550:
p@2573: struct ccat_info_block {
p@2569: u16 type;
p@2569: u16 rev;
p@2569: union {
p@2569: u32 config;
p@2569: struct {
p@2569: u8 tx_dma_chan;
p@2569: u8 rx_dma_chan;
p@2569: };
p@2569: };
p@2569: u32 addr;
p@2569: u32 size;
p@2569: };
p@2569:
p@2550: /**
p@2550: * struct ccat_eth_priv - CCAT Ethernet/EtherCAT Master function (netdev)
p@2550: * @ccatdev: pointer to the parent struct ccat_device
p@2550: * @netdev: the net_device structure used by the kernel networking stack
p@2550: * @info: holds a copy of the CCAT Ethernet/EtherCAT Master function information block (read from PCI config space)
p@2550: * @reg: register addresses in PCI config space of the Ethernet/EtherCAT Master function
p@2550: * @rx_fifo: DMA fifo used for RX DMA descriptors
p@2550: * @tx_fifo: DMA fifo used for TX DMA descriptors
p@2567: * @poll_timer: interval timer used to poll CCAT for events like link changed, rx done, tx done
p@2550: * @rx_bytes: number of bytes received -> reported with ndo_get_stats64()
p@2550: * @rx_dropped: number of received frames, which were dropped -> reported with ndo_get_stats64()
p@2550: * @tx_bytes: number of bytes send -> reported with ndo_get_stats64()
p@2550: * @tx_dropped: number of frames requested to send, which were dropped -> reported with ndo_get_stats64()
p@2550: */
p@2550: struct ccat_eth_priv {
p@2550: const struct ccat_device *ccatdev;
p@2550: struct net_device *netdev;
p@2569: struct ccat_info_block info;
p@2550: struct ccat_eth_register reg;
p@2550: struct ccat_eth_dma_fifo rx_fifo;
p@2550: struct ccat_eth_dma_fifo tx_fifo;
p@2567: struct hrtimer poll_timer;
p@2550: atomic64_t rx_bytes;
p@2550: atomic64_t rx_dropped;
p@2550: atomic64_t tx_bytes;
p@2550: atomic64_t tx_dropped;
p@2550: ec_device_t *ecdev;
p@2570: void (*carrier_off) (struct net_device * netdev);
p@2570: bool (*carrier_ok) (const struct net_device * netdev);
p@2570: void (*carrier_on) (struct net_device * netdev);
p@2550: void (*kfree_skb_any) (struct sk_buff * skb);
p@2570: void (*start_queue) (struct net_device * netdev);
p@2570: void (*stop_queue) (struct net_device * netdev);
p@2570: void (*unregister) (struct net_device * netdev);
p@2550: };
p@2550:
p@2550: /**
p@2569: * same as: typedef struct _CCatInfoBlockOffs from CCatDefinitions.h
p@2569: * TODO add some checking facility outside of the linux tree
p@2569: */
p@2569: struct ccat_mac_infoblock {
p@2569: u32 reserved;
p@2573: u32 mii;
p@2573: u32 tx_fifo;
p@2573: u32 mac;
p@2573: u32 rx_mem;
p@2573: u32 tx_mem;
p@2573: u32 misc;
p@2573: };
p@2573:
p@2573: struct ccat_mac_register {
p@2569: /** MAC error register @+0x0 */
p@2569: u8 frame_len_err;
p@2569: u8 rx_err;
p@2569: u8 crc_err;
p@2569: u8 link_lost_err;
p@2569: u32 reserved1;
p@2569: /** Buffer overflow errors @+0x8 */
p@2569: u8 rx_mem_full;
p@2569: u8 reserved2[7];
p@2569: /** MAC frame counter @+0x10 */
p@2569: u32 tx_frames;
p@2569: u32 rx_frames;
p@2569: u64 reserved3;
p@2569: /** MAC fifo level @+0x20 */
p@2573: u8 tx_fifo_level:7;
p@2573: u8 reserved4:1;
p@2569: u8 reserved5[7];
p@2569: /** TX memory full error @+0x28 */
p@2569: u8 tx_mem_full;
p@2569: u8 reserved6[7];
p@2569: u64 reserved8[9];
p@2569: /** Connection @+0x78 */
p@2569: u8 mii_connected;
p@2569: };
p@2569:
p@2569: /**
p@2550: * struct ccat_update - CCAT Update function (update)
p@2550: * @ccatdev: pointer to the parent struct ccat_device
p@2550: * @ioaddr: PCI base address of the CCAT Update function
p@2550: * dev: device number for this update function
p@2550: * cdev: character device used for the CCAT Update function
p@2550: * class: pointer to a device class used when registering the CCAT Update device
p@2550: * @info: holds a copy of the CCAT Update function information block (read from PCI config space)
p@2550: */
p@2550: struct ccat_update {
p@2550: struct kref refcount;
p@2550: void __iomem *ioaddr;
p@2550: dev_t dev;
p@2550: struct cdev cdev;
p@2550: struct class *class;
p@2569: struct ccat_info_block info;
p@2550: };
p@2550: #endif /* #ifndef _CCAT_H_ */