p@2550: /**
p@2550: Network Driver for Beckhoff CCAT communication controller
p@2636: Copyright (C) 2014 - 2015 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: #include
p@2550: #include
p@2550: #include
p@2550: #include
p@2550:
p@2636: #ifdef CONFIG_PCI
p@2636: #include
p@2636: #else
p@2636: #define free_dma(X)
p@2636: #define request_dma(X, Y) ((int)(-EINVAL))
p@2636: #endif
p@2636:
p@2550: #include "module.h"
p@2550:
p@2550: /**
p@2550: * EtherCAT frame to enable forwarding on EtherCAT Terminals
p@2550: */
p@2567: static const u8 frameForwardEthernetFrames[] = {
p@2550: 0x01, 0x01, 0x05, 0x01, 0x00, 0x00,
p@2550: 0x00, 0x1b, 0x21, 0x36, 0x1b, 0xce,
p@2550: 0x88, 0xa4, 0x0e, 0x10,
p@2550: 0x08,
p@2550: 0x00,
p@2550: 0x00, 0x00,
p@2550: 0x00, 0x01,
p@2550: 0x02, 0x00,
p@2550: 0x00, 0x00,
p@2550: 0x00, 0x00,
p@2550: 0x00, 0x00
p@2550: };
p@2550:
p@2550: #define FIFO_LENGTH 64
p@2636: #define POLL_TIME ktime_set(0, 50 * NSEC_PER_USEC)
p@2636:
p@2636: struct ccat_dma_frame_hdr {
p@2636: __le32 reserved1;
p@2636: __le32 rx_flags;
p@2636: #define CCAT_FRAME_RECEIVED 0x1
p@2636: __le16 length;
p@2636: __le16 reserved3;
p@2636: __le32 tx_flags;
p@2636: #define CCAT_FRAME_SENT 0x1
p@2636: __le64 timestamp;
p@2636: };
p@2636:
p@2636: struct ccat_eim_frame_hdr {
p@2636: __le16 length;
p@2636: __le16 reserved3;
p@2636: __le32 tx_flags;
p@2636: __le64 timestamp;
p@2636: };
p@2636:
p@2636: struct ccat_eth_frame {
p@2636: u8 placeholder[0x800];
p@2636: };
p@2636:
p@2636: struct ccat_dma_frame {
p@2636: struct ccat_dma_frame_hdr hdr;
p@2636: u8 data[sizeof(struct ccat_eth_frame) -
p@2636: sizeof(struct ccat_dma_frame_hdr)];
p@2636: };
p@2636:
p@2636: struct ccat_eim_frame {
p@2636: struct ccat_eim_frame_hdr hdr;
p@2636: u8 data[sizeof(struct ccat_eth_frame) -
p@2636: sizeof(struct ccat_eim_frame_hdr)];
p@2636: };
p@2636:
p@2636: #define MAX_PAYLOAD_SIZE \
p@2636: (sizeof(struct ccat_eth_frame) - max(sizeof(struct ccat_dma_frame_hdr), sizeof(struct ccat_eim_frame_hdr)))
p@2636:
p@2636: /**
p@2636: * struct ccat_eth_register - CCAT register addresses in the PCI BAR
p@2636: * @mii: address of the CCAT management interface register
p@2636: * @tx_fifo: address of the CCAT TX DMA fifo register
p@2636: * @rx_fifo: address of the CCAT RX DMA fifo register
p@2636: * @mac: address of the CCAT media access control register
p@2636: * @rx_mem: address of the CCAT register holding the RX DMA address
p@2636: * @tx_mem: address of the CCAT register holding the TX DMA address
p@2636: * @misc: address of a CCAT register holding miscellaneous information
p@2636: */
p@2636: struct ccat_eth_register {
p@2636: void __iomem *mii;
p@2636: void __iomem *tx_fifo;
p@2636: void __iomem *rx_fifo;
p@2636: void __iomem *mac;
p@2636: void __iomem *rx_mem;
p@2636: void __iomem *tx_mem;
p@2636: void __iomem *misc;
p@2636: };
p@2636:
p@2636: /**
p@2636: * struct ccat_dma - CCAT DMA channel configuration
p@2636: * @phys: device-viewed address(physical) of the associated DMA memory
p@2636: * @start: CPU-viewed address(virtual) of the associated DMA memory
p@2636: * @size: number of bytes in the associated DMA memory
p@2636: * @channel: CCAT DMA channel number
p@2636: * @dev: valid struct device pointer
p@2636: */
p@2636: struct ccat_dma {
p@2636: struct ccat_dma_frame *next;
p@2636: void *start;
p@2636: size_t size;
p@2636: dma_addr_t phys;
p@2636: size_t channel;
p@2636: struct device *dev;
p@2636: };
p@2636:
p@2636: struct ccat_eim {
p@2636: struct ccat_eim_frame __iomem *next;
p@2636: void __iomem *start;
p@2636: size_t size;
p@2636: };
p@2636:
p@2636: struct ccat_mem {
p@2636: struct ccat_eth_frame *next;
p@2636: void *start;
p@2636: };
p@2636:
p@2636: /**
p@2636: * struct ccat_eth_fifo - CCAT RX or TX DMA fifo
p@2636: * @add: callback used to add a frame to this fifo
p@2636: * @reg: PCI register address of this DMA fifo
p@2636: * @dma: information about the associated DMA memory
p@2636: */
p@2636: struct ccat_eth_fifo {
p@2636: void (*add) (struct ccat_eth_fifo *);
p@2636: void (*copy_to_skb) (struct ccat_eth_fifo *, struct sk_buff *, size_t);
p@2636: void (*queue_skb) (struct ccat_eth_fifo * const, struct sk_buff *);
p@2636: void __iomem *reg;
p@2636: const struct ccat_eth_frame *end;
p@2636: union {
p@2636: struct ccat_mem mem;
p@2636: struct ccat_dma dma;
p@2636: struct ccat_eim eim;
p@2636: };
p@2636: };
p@2636:
p@2636: /**
p@2636: * same as: typedef struct _CCatInfoBlockOffs from CCatDefinitions.h
p@2636: */
p@2636: struct ccat_mac_infoblock {
p@2636: u32 reserved;
p@2636: u32 mii;
p@2636: u32 tx_fifo;
p@2636: u32 mac;
p@2636: u32 rx_mem;
p@2636: u32 tx_mem;
p@2636: u32 misc;
p@2636: };
p@2636:
p@2636: /**
p@2636: * struct ccat_eth_priv - CCAT Ethernet/EtherCAT Master function (netdev)
p@2636: * @func: pointer to the parent struct ccat_function
p@2636: * @netdev: the net_device structure used by the kernel networking stack
p@2636: * @info: holds a copy of the CCAT Ethernet/EtherCAT Master function information block (read from PCI config space)
p@2636: * @reg: register addresses in PCI config space of the Ethernet/EtherCAT Master function
p@2636: * @rx_fifo: DMA fifo used for RX DMA descriptors
p@2636: * @tx_fifo: DMA fifo used for TX DMA descriptors
p@2636: * @poll_timer: interval timer used to poll CCAT for events like link changed, rx done, tx done
p@2636: * @rx_bytes: number of bytes received -> reported with ndo_get_stats64()
p@2636: * @rx_dropped: number of received frames, which were dropped -> reported with ndo_get_stats64()
p@2636: * @tx_bytes: number of bytes send -> reported with ndo_get_stats64()
p@2636: * @tx_dropped: number of frames requested to send, which were dropped -> reported with ndo_get_stats64()
p@2636: */
p@2636: struct ccat_eth_priv {
p@2636: void (*free) (struct ccat_eth_priv *);
p@2636: bool(*tx_ready) (const struct ccat_eth_priv *);
p@2636: size_t(*rx_ready) (struct ccat_eth_fifo *);
p@2636: struct ccat_function *func;
p@2636: struct net_device *netdev;
p@2636: struct ccat_eth_register reg;
p@2636: struct ccat_eth_fifo rx_fifo;
p@2636: struct ccat_eth_fifo tx_fifo;
p@2636: struct hrtimer poll_timer;
p@2636: atomic64_t rx_bytes;
p@2636: atomic64_t rx_dropped;
p@2636: atomic64_t tx_bytes;
p@2636: atomic64_t tx_dropped;
p@2636: ec_device_t *ecdev;
p@2636: void (*carrier_off) (struct net_device * netdev);
p@2636: bool(*carrier_ok) (const struct net_device * netdev);
p@2636: void (*carrier_on) (struct net_device * netdev);
p@2636: void (*kfree_skb_any) (struct sk_buff * skb);
p@2636: void (*receive) (struct ccat_eth_priv *, size_t);
p@2636: void (*start_queue) (struct net_device * netdev);
p@2636: void (*stop_queue) (struct net_device * netdev);
p@2636: void (*unregister) (struct net_device * netdev);
p@2636: };
p@2636:
p@2636: struct ccat_mac_register {
p@2636: /** MAC error register @+0x0 */
p@2636: u8 frame_len_err;
p@2636: u8 rx_err;
p@2636: u8 crc_err;
p@2636: u8 link_lost_err;
p@2636: u32 reserved1;
p@2636: /** Buffer overflow errors @+0x8 */
p@2636: u8 rx_mem_full;
p@2636: u8 reserved2[7];
p@2636: /** MAC frame counter @+0x10 */
p@2636: u32 tx_frames;
p@2636: u32 rx_frames;
p@2636: u64 reserved3;
p@2636: /** MAC fifo level @+0x20 */
p@2636: u8 tx_fifo_level:7;
p@2636: u8 reserved4:1;
p@2636: u8 reserved5[7];
p@2636: /** TX memory full error @+0x28 */
p@2636: u8 tx_mem_full;
p@2636: u8 reserved6[7];
p@2636: u64 reserved8[9];
p@2636: /** Connection @+0x78 */
p@2636: u8 mii_connected;
p@2636: };
p@2636:
p@2636: static void ccat_dma_free(struct ccat_dma *const dma)
p@2636: {
p@2636: const struct ccat_dma tmp = *dma;
p@2636:
p@2636: free_dma(dma->channel);
p@2636: memset(dma, 0, sizeof(*dma));
p@2636: dma_free_coherent(tmp.dev, tmp.size, tmp.start, tmp.phys);
p@2636: }
p@2636:
p@2636: /**
p@2636: * ccat_dma_init() - Initialize CCAT and host memory for DMA transfer
p@2636: * @dma object for management data which will be initialized
p@2636: * @channel number of the DMA channel
p@2636: * @ioaddr of the pci bar2 configspace used to calculate the address of the pci dma configuration
p@2636: * @dev which should be configured for DMA
p@2636: */
p@2636: static int ccat_dma_init(struct ccat_dma *const dma, size_t channel,
p@2636: void __iomem * const ioaddr, struct device *const dev)
p@2636: {
p@2636: void *frame;
p@2636: u64 addr;
p@2636: u32 translateAddr;
p@2636: u32 memTranslate;
p@2636: u32 memSize;
p@2636: u32 data = 0xffffffff;
p@2636: u32 offset = (sizeof(u64) * channel) + 0x1000;
p@2636:
p@2636: dma->channel = channel;
p@2636: dma->dev = dev;
p@2636:
p@2636: /* calculate size and alignments */
p@2636: iowrite32(data, ioaddr + offset);
p@2636: wmb();
p@2636: data = ioread32(ioaddr + offset);
p@2636: memTranslate = data & 0xfffffffc;
p@2636: memSize = (~memTranslate) + 1;
p@2636: dma->size = 2 * memSize - PAGE_SIZE;
p@2636: dma->start =
p@2636: dma_zalloc_coherent(dev, dma->size, &dma->phys, GFP_KERNEL);
p@2636: if (!dma->start || !dma->phys) {
p@2636: pr_info("init DMA%llu memory failed.\n", (u64) channel);
p@2636: return -ENOMEM;
p@2636: }
p@2636:
p@2636: if (request_dma(channel, KBUILD_MODNAME)) {
p@2636: pr_info("request dma channel %llu failed\n", (u64) channel);
p@2636: ccat_dma_free(dma);
p@2636: return -EINVAL;
p@2636: }
p@2636:
p@2636: translateAddr = (dma->phys + memSize - PAGE_SIZE) & memTranslate;
p@2636: addr = translateAddr;
p@2636: memcpy_toio(ioaddr + offset, &addr, sizeof(addr));
p@2636: frame = dma->start + translateAddr - dma->phys;
p@2636: pr_debug
p@2636: ("DMA%llu mem initialized\n start: 0x%p\n phys: 0x%llx\n translated: 0x%llx\n pci addr: 0x%08x%x\n memTranslate: 0x%x\n size: %llu bytes.\n",
p@2636: (u64) channel, dma->start, (u64) (dma->phys), addr,
p@2636: ioread32(ioaddr + offset + 4), ioread32(ioaddr + offset),
p@2636: memTranslate, (u64) dma->size);
p@2636: return 0;
p@2576: }
p@2550:
p@2550: static void ecdev_kfree_skb_any(struct sk_buff *skb)
p@2550: {
p@2550: /* never release a skb in EtherCAT mode */
p@2550: }
p@2550:
p@2570: static bool ecdev_carrier_ok(const struct net_device *const netdev)
p@2567: {
p@2567: struct ccat_eth_priv *const priv = netdev_priv(netdev);
p@2567: return ecdev_get_link(priv->ecdev);
p@2567: }
p@2567:
p@2550: static void ecdev_carrier_on(struct net_device *const netdev)
p@2550: {
p@2550: struct ccat_eth_priv *const priv = netdev_priv(netdev);
p@2550: ecdev_set_link(priv->ecdev, 1);
p@2550: }
p@2550:
p@2550: static void ecdev_carrier_off(struct net_device *const netdev)
p@2550: {
p@2550: struct ccat_eth_priv *const priv = netdev_priv(netdev);
p@2550: ecdev_set_link(priv->ecdev, 0);
p@2550: }
p@2550:
p@2550: static void ecdev_nop(struct net_device *const netdev)
p@2550: {
p@2550: /* dummy called if nothing has to be done in EtherCAT operation mode */
p@2550: }
p@2550:
p@2636: static void ecdev_receive_dma(struct ccat_eth_priv *const priv, size_t len)
p@2636: {
p@2636: ecdev_receive(priv->ecdev, priv->rx_fifo.dma.next->data, len);
p@2636: }
p@2636:
p@2636: static void ecdev_receive_eim(struct ccat_eth_priv *const priv, size_t len)
p@2636: {
p@2636: ecdev_receive(priv->ecdev, priv->rx_fifo.eim.next->data, len);
p@2636: }
p@2636:
p@2550: static void unregister_ecdev(struct net_device *const netdev)
p@2550: {
p@2550: struct ccat_eth_priv *const priv = netdev_priv(netdev);
p@2550: ecdev_close(priv->ecdev);
p@2550: ecdev_withdraw(priv->ecdev);
p@2550: }
p@2550:
p@2636: static inline bool fifo_eim_tx_ready(const struct ccat_eth_priv *const priv)
p@2636: {
p@2636: static const size_t TX_FIFO_LEVEL_OFFSET = 0x20;
p@2636: static const u8 TX_FIFO_LEVEL_MASK = 0x3F;
p@2636: void __iomem *addr = priv->reg.mac + TX_FIFO_LEVEL_OFFSET;
p@2636:
p@2636: return !(ioread8(addr) & TX_FIFO_LEVEL_MASK);
p@2636: }
p@2636:
p@2636: static inline size_t fifo_eim_rx_ready(struct ccat_eth_fifo *const fifo)
p@2636: {
p@2636: static const size_t OVERHEAD = sizeof(struct ccat_eim_frame_hdr);
p@2636: const size_t len = ioread16(&fifo->eim.next->hdr.length);
p@2636:
p@2636: return (len < OVERHEAD) ? 0 : len - OVERHEAD;
p@2636: }
p@2636:
p@2636: static void ccat_eth_fifo_inc(struct ccat_eth_fifo *fifo)
p@2636: {
p@2636: if (++fifo->mem.next > fifo->end)
p@2636: fifo->mem.next = fifo->mem.start;
p@2636: }
p@2636:
p@2636: static void fifo_eim_rx_add(struct ccat_eth_fifo *const fifo)
p@2636: {
p@2636: struct ccat_eim_frame __iomem *frame = fifo->eim.next;
p@2636: iowrite16(0, frame);
p@2636: wmb();
p@2636: }
p@2636:
p@2636: static void fifo_eim_tx_add(struct ccat_eth_fifo *const fifo)
p@2636: {
p@2636: }
p@2636:
p@2636: #define memcpy_from_ccat(DEST, SRC, LEN) memcpy(DEST,(__force void*)(SRC), LEN)
p@2636: #define memcpy_to_ccat(DEST, SRC, LEN) memcpy((__force void*)(DEST),SRC, LEN)
p@2636: static void fifo_eim_copy_to_linear_skb(struct ccat_eth_fifo *const fifo,
p@2636: struct sk_buff *skb, const size_t len)
p@2636: {
p@2636: memcpy_from_ccat(skb->data, fifo->eim.next->data, len);
p@2636: }
p@2636:
p@2636: static void fifo_eim_queue_skb(struct ccat_eth_fifo *const fifo,
p@2636: struct sk_buff *skb)
p@2636: {
p@2636: struct ccat_eim_frame __iomem *frame = fifo->eim.next;
p@2636: const u32 addr_and_length =
p@2636: (void __iomem *)frame - (void __iomem *)fifo->eim.start;
p@2636:
p@2636: const __le16 length = cpu_to_le16(skb->len);
p@2636: memcpy_to_ccat(&frame->hdr.length, &length, sizeof(length));
p@2636: memcpy_to_ccat(frame->data, skb->data, skb->len);
p@2636: iowrite32(addr_and_length, fifo->reg);
p@2636: }
p@2636:
p@2636: static void ccat_eth_priv_free_eim(struct ccat_eth_priv *priv)
p@2636: {
p@2636: /* reset hw fifo's */
p@2636: iowrite32(0, priv->tx_fifo.reg + 0x8);
p@2636: wmb();
p@2636: }
p@2636:
p@2636: static void ccat_eth_fifo_reset(struct ccat_eth_fifo *const fifo)
p@2636: {
p@2636: /* reset hw fifo */
p@2636: if (fifo->reg) {
p@2636: iowrite32(0, fifo->reg + 0x8);
p@2636: wmb();
p@2636: }
p@2636:
p@2636: if (fifo->add) {
p@2636: fifo->mem.next = fifo->mem.start;
p@2636: do {
p@2636: fifo->add(fifo);
p@2636: ccat_eth_fifo_inc(fifo);
p@2636: } while (fifo->mem.next != fifo->mem.start);
p@2636: }
p@2636: }
p@2636:
p@2636: static inline bool fifo_dma_tx_ready(const struct ccat_eth_priv *const priv)
p@2636: {
p@2636: const struct ccat_dma_frame *frame = priv->tx_fifo.dma.next;
p@2636: return le32_to_cpu(frame->hdr.tx_flags) & CCAT_FRAME_SENT;
p@2636: }
p@2636:
p@2636: static inline size_t fifo_dma_rx_ready(struct ccat_eth_fifo *const fifo)
p@2636: {
p@2636: static const size_t OVERHEAD =
p@2636: offsetof(struct ccat_dma_frame_hdr, rx_flags);
p@2636: const struct ccat_dma_frame *const frame = fifo->dma.next;
p@2636:
p@2636: if (le32_to_cpu(frame->hdr.rx_flags) & CCAT_FRAME_RECEIVED) {
p@2636: const size_t len = le16_to_cpu(frame->hdr.length);
p@2636: return (len < OVERHEAD) ? 0 : len - OVERHEAD;
p@2636: }
p@2636: return 0;
p@2636: }
p@2636:
p@2636: static void ccat_eth_rx_fifo_dma_add(struct ccat_eth_fifo *const fifo)
p@2636: {
p@2636: struct ccat_dma_frame *const frame = fifo->dma.next;
p@2636: const size_t offset = (void *)frame - fifo->dma.start;
p@2567: const u32 addr_and_length = (1 << 31) | offset;
p@2567:
p@2636: frame->hdr.rx_flags = cpu_to_le32(0);
p@2550: iowrite32(addr_and_length, fifo->reg);
p@2550: }
p@2550:
p@2636: static void ccat_eth_tx_fifo_dma_add_free(struct ccat_eth_fifo *const fifo)
p@2550: {
p@2550: /* mark frame as ready to use for tx */
p@2636: fifo->dma.next->hdr.tx_flags = cpu_to_le32(CCAT_FRAME_SENT);
p@2636: }
p@2636:
p@2636: static void fifo_dma_copy_to_linear_skb(struct ccat_eth_fifo *const fifo,
p@2636: struct sk_buff *skb, const size_t len)
p@2636: {
p@2636: skb_copy_to_linear_data(skb, fifo->dma.next->data, len);
p@2636: }
p@2636:
p@2636: static void fifo_dma_queue_skb(struct ccat_eth_fifo *const fifo,
p@2636: struct sk_buff *skb)
p@2636: {
p@2636: struct ccat_dma_frame *frame = fifo->dma.next;
p@2636: u32 addr_and_length;
p@2636:
p@2636: frame->hdr.tx_flags = cpu_to_le32(0);
p@2636: frame->hdr.length = cpu_to_le16(skb->len);
p@2636:
p@2636: memcpy(frame->data, skb->data, skb->len);
p@2636:
p@2636: /* Queue frame into CCAT TX-FIFO, CCAT ignores the first 8 bytes of the tx descriptor */
p@2636: addr_and_length = offsetof(struct ccat_dma_frame_hdr, length);
p@2636: addr_and_length += ((void *)frame - fifo->dma.start);
p@2636: addr_and_length +=
p@2636: ((skb->len + sizeof(struct ccat_dma_frame_hdr)) / 8) << 24;
p@2636: iowrite32(addr_and_length, fifo->reg);
p@2636: }
p@2636:
p@2550: static void ccat_eth_priv_free_dma(struct ccat_eth_priv *priv)
p@2550: {
p@2550: /* reset hw fifo's */
p@2550: iowrite32(0, priv->rx_fifo.reg + 0x8);
p@2550: iowrite32(0, priv->tx_fifo.reg + 0x8);
p@2550: wmb();
p@2550:
p@2550: /* release dma */
p@2550: ccat_dma_free(&priv->rx_fifo.dma);
p@2550: ccat_dma_free(&priv->tx_fifo.dma);
p@2550: }
p@2550:
p@2550: /**
p@2550: * Initalizes both (Rx/Tx) DMA fifo's and related management structures
p@2550: */
p@2550: static int ccat_eth_priv_init_dma(struct ccat_eth_priv *priv)
p@2550: {
p@2636: struct ccat_function *const func = priv->func;
p@2636: struct pci_dev *pdev = func->ccat->pdev;
p@2636: int status = 0;
p@2636: priv->rx_ready = fifo_dma_rx_ready;
p@2636: priv->tx_ready = fifo_dma_tx_ready;
p@2636: priv->free = ccat_eth_priv_free_dma;
p@2636:
p@2636: status =
p@2636: ccat_dma_init(&priv->rx_fifo.dma, func->info.rx_dma_chan,
p@2636: func->ccat->bar_2, &pdev->dev);
p@2636: if (status) {
p@2636: pr_info("init RX DMA memory failed.\n");
p@2636: return status;
p@2636: }
p@2636:
p@2636: status =
p@2636: ccat_dma_init(&priv->tx_fifo.dma, func->info.tx_dma_chan,
p@2636: func->ccat->bar_2, &pdev->dev);
p@2636: if (status) {
p@2636: pr_info("init TX DMA memory failed.\n");
p@2550: ccat_dma_free(&priv->rx_fifo.dma);
p@2636: return status;
p@2636: }
p@2636:
p@2636: priv->rx_fifo.add = ccat_eth_rx_fifo_dma_add;
p@2636: priv->rx_fifo.copy_to_skb = fifo_dma_copy_to_linear_skb;
p@2636: priv->rx_fifo.queue_skb = NULL;
p@2636: priv->rx_fifo.end =
p@2636: ((struct ccat_eth_frame *)priv->rx_fifo.dma.start) + FIFO_LENGTH -
p@2636: 1;
p@2636: priv->rx_fifo.reg = priv->reg.rx_fifo;
p@2636: ccat_eth_fifo_reset(&priv->rx_fifo);
p@2636:
p@2636: priv->tx_fifo.add = ccat_eth_tx_fifo_dma_add_free;
p@2636: priv->tx_fifo.copy_to_skb = NULL;
p@2636: priv->tx_fifo.queue_skb = fifo_dma_queue_skb;
p@2636: priv->tx_fifo.end =
p@2636: ((struct ccat_eth_frame *)priv->tx_fifo.dma.start) + FIFO_LENGTH -
p@2636: 1;
p@2636: priv->tx_fifo.reg = priv->reg.tx_fifo;
p@2636: ccat_eth_fifo_reset(&priv->tx_fifo);
p@2550:
p@2550: /* disable MAC filter */
p@2550: iowrite8(0, priv->reg.mii + 0x8 + 6);
p@2550: wmb();
p@2550: return 0;
p@2550: }
p@2550:
p@2636: static int ccat_eth_priv_init_eim(struct ccat_eth_priv *priv)
p@2636: {
p@2636: priv->rx_ready = fifo_eim_rx_ready;
p@2636: priv->tx_ready = fifo_eim_tx_ready;
p@2636: priv->free = ccat_eth_priv_free_eim;
p@2636:
p@2636: priv->rx_fifo.eim.start = priv->reg.rx_mem;
p@2636: priv->rx_fifo.eim.size = priv->func->info.rx_size;
p@2636:
p@2636: priv->rx_fifo.add = fifo_eim_rx_add;
p@2636: priv->rx_fifo.copy_to_skb = fifo_eim_copy_to_linear_skb;
p@2636: priv->rx_fifo.queue_skb = NULL;
p@2636: priv->rx_fifo.end = priv->rx_fifo.dma.start;
p@2636: priv->rx_fifo.reg = NULL;
p@2636: ccat_eth_fifo_reset(&priv->rx_fifo);
p@2636:
p@2636: priv->tx_fifo.eim.start = priv->reg.tx_mem;
p@2636: priv->tx_fifo.eim.size = priv->func->info.tx_size;
p@2636:
p@2636: priv->tx_fifo.add = fifo_eim_tx_add;
p@2636: priv->tx_fifo.copy_to_skb = NULL;
p@2636: priv->tx_fifo.queue_skb = fifo_eim_queue_skb;
p@2636: priv->tx_fifo.end =
p@2636: priv->tx_fifo.dma.start + priv->tx_fifo.dma.size -
p@2636: sizeof(struct ccat_eth_frame);
p@2636: priv->tx_fifo.reg = priv->reg.tx_fifo;
p@2636: ccat_eth_fifo_reset(&priv->tx_fifo);
p@2636:
p@2636: /* disable MAC filter */
p@2636: iowrite8(0, priv->reg.mii + 0x8 + 6);
p@2636: wmb();
p@2636: return 0;
p@2636: }
p@2636:
p@2636: /**
p@2636: * Initializes a struct ccat_eth_register with data from a corresponding
p@2636: * CCAT function.
p@2636: */
p@2636: static void ccat_eth_priv_init_reg(struct ccat_eth_register *const reg,
p@2636: const struct ccat_function *const func)
p@2550: {
p@2569: struct ccat_mac_infoblock offsets;
p@2636: void __iomem *const func_base = func->ccat->bar_0 + func->info.addr;
p@2636:
p@2636: /* struct ccat_eth_fifo contains a union of ccat_dma, ccat_eim and ccat_mem
p@2636: * the members next, start and size have to overlay the exact same memory,
p@2636: * to support 'polymorphic' usage of them */
p@2636: BUILD_BUG_ON(offsetof(struct ccat_dma, next) !=
p@2636: offsetof(struct ccat_mem, next));
p@2636: BUILD_BUG_ON(offsetof(struct ccat_dma, start) !=
p@2636: offsetof(struct ccat_mem, start));
p@2636: BUILD_BUG_ON(offsetof(struct ccat_dma, next) !=
p@2636: offsetof(struct ccat_eim, next));
p@2636: BUILD_BUG_ON(offsetof(struct ccat_dma, start) !=
p@2636: offsetof(struct ccat_eim, start));
p@2636: BUILD_BUG_ON(offsetof(struct ccat_dma, size) !=
p@2636: offsetof(struct ccat_eim, size));
p@2567:
p@2550: memcpy_fromio(&offsets, func_base, sizeof(offsets));
p@2636: reg->mii = func_base + offsets.mii;
p@2636: reg->tx_fifo = func_base + offsets.tx_fifo;
p@2636: reg->rx_fifo = func_base + offsets.tx_fifo + 0x10;
p@2636: reg->mac = func_base + offsets.mac;
p@2636: reg->rx_mem = func_base + offsets.rx_mem;
p@2636: reg->tx_mem = func_base + offsets.tx_mem;
p@2636: reg->misc = func_base + offsets.misc;
p@2550: }
p@2550:
p@2572: static netdev_tx_t ccat_eth_start_xmit(struct sk_buff *skb,
p@2572: struct net_device *dev)
p@2572: {
p@2576: struct ccat_eth_priv *const priv = netdev_priv(dev);
p@2636: struct ccat_eth_fifo *const fifo = &priv->tx_fifo;
p@2572:
p@2572: if (skb_is_nonlinear(skb)) {
p@2572: pr_warn("Non linear skb not supported -> drop frame.\n");
p@2572: atomic64_inc(&priv->tx_dropped);
p@2572: priv->kfree_skb_any(skb);
p@2572: return NETDEV_TX_OK;
p@2572: }
p@2572:
p@2636: if (skb->len > MAX_PAYLOAD_SIZE) {
p@2572: pr_warn("skb.len %llu exceeds dma buffer %llu -> drop frame.\n",
p@2636: (u64) skb->len, (u64) MAX_PAYLOAD_SIZE);
p@2572: atomic64_inc(&priv->tx_dropped);
p@2572: priv->kfree_skb_any(skb);
p@2572: return NETDEV_TX_OK;
p@2572: }
p@2572:
p@2636: if (!priv->tx_ready(priv)) {
p@2572: netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
p@2576: priv->stop_queue(priv->netdev);
p@2572: return NETDEV_TX_BUSY;
p@2572: }
p@2572:
p@2572: /* prepare frame in DMA memory */
p@2636: fifo->queue_skb(fifo, skb);
p@2576:
p@2576: /* update stats */
p@2576: atomic64_add(skb->len, &priv->tx_bytes);
p@2572:
p@2572: priv->kfree_skb_any(skb);
p@2572:
p@2576: ccat_eth_fifo_inc(fifo);
p@2572: /* stop queue if tx ring is full */
p@2636:
p@2636: if (!priv->tx_ready(priv)) {
p@2576: priv->stop_queue(priv->netdev);
p@2572: }
p@2572: return NETDEV_TX_OK;
p@2572: }
p@2572:
p@2572: /**
p@2572: * Function to transmit a raw buffer to the network (f.e. frameForwardEthernetFrames)
p@2572: * @dev a valid net_device
p@2572: * @data pointer to your raw buffer
p@2572: * @len number of bytes in the raw buffer to transmit
p@2572: */
p@2572: static void ccat_eth_xmit_raw(struct net_device *dev, const char *const data,
p@2572: size_t len)
p@2572: {
p@2572: struct sk_buff *skb = dev_alloc_skb(len);
p@2572:
p@2572: skb->dev = dev;
p@2572: skb_copy_to_linear_data(skb, data, len);
p@2572: skb_put(skb, len);
p@2572: ccat_eth_start_xmit(skb, dev);
p@2572: }
p@2572:
p@2636: static void ccat_eth_receive(struct ccat_eth_priv *const priv, const size_t len)
p@2576: {
p@2576: struct sk_buff *const skb = dev_alloc_skb(len + NET_IP_ALIGN);
p@2636: struct net_device *const dev = priv->netdev;
p@2572:
p@2572: if (!skb) {
p@2572: pr_info("%s() out of memory :-(\n", __FUNCTION__);
p@2572: atomic64_inc(&priv->rx_dropped);
p@2572: return;
p@2572: }
p@2572: skb->dev = dev;
p@2572: skb_reserve(skb, NET_IP_ALIGN);
p@2636: priv->rx_fifo.copy_to_skb(&priv->rx_fifo, skb, len);
p@2572: skb_put(skb, len);
p@2572: skb->protocol = eth_type_trans(skb, dev);
p@2572: skb->ip_summed = CHECKSUM_UNNECESSARY;
p@2572: atomic64_add(len, &priv->rx_bytes);
p@2572: netif_rx(skb);
p@2572: }
p@2572:
p@2576: static void ccat_eth_link_down(struct net_device *const dev)
p@2572: {
p@2572: struct ccat_eth_priv *const priv = netdev_priv(dev);
p@2572:
p@2572: priv->stop_queue(dev);
p@2572: priv->carrier_off(dev);
p@2572: netdev_info(dev, "NIC Link is Down\n");
p@2572: }
p@2572:
p@2572: static void ccat_eth_link_up(struct net_device *const dev)
p@2572: {
p@2572: struct ccat_eth_priv *const priv = netdev_priv(dev);
p@2572:
p@2572: netdev_info(dev, "NIC Link is Up\n");
p@2572: /* TODO netdev_info(dev, "NIC Link is Up %u Mbps %s Duplex\n",
p@2572: speed == SPEED_100 ? 100 : 10,
p@2572: cmd.duplex == DUPLEX_FULL ? "Full" : "Half"); */
p@2572:
p@2636: ccat_eth_fifo_reset(&priv->rx_fifo);
p@2636: ccat_eth_fifo_reset(&priv->tx_fifo);
p@2572:
p@2572: /* TODO reset CCAT MAC register */
p@2572:
p@2572: ccat_eth_xmit_raw(dev, frameForwardEthernetFrames,
p@2572: sizeof(frameForwardEthernetFrames));
p@2572: priv->carrier_on(dev);
p@2572: priv->start_queue(dev);
p@2572: }
p@2572:
p@2550: /**
p@2550: * Read link state from CCAT hardware
p@2550: * @return 1 if link is up, 0 if not
p@2550: */
p@2550: inline static size_t ccat_eth_priv_read_link_state(const struct ccat_eth_priv
p@2550: *const priv)
p@2550: {
p@2550: return (1 << 24) == (ioread32(priv->reg.mii + 0x8 + 4) & (1 << 24));
p@2550: }
p@2550:
p@2572: /**
p@2572: * Poll for link state changes
p@2572: */
p@2572: static void poll_link(struct ccat_eth_priv *const priv)
p@2572: {
p@2572: const size_t link = ccat_eth_priv_read_link_state(priv);
p@2572:
p@2572: if (link != priv->carrier_ok(priv->netdev)) {
p@2572: if (link)
p@2572: ccat_eth_link_up(priv->netdev);
p@2572: else
p@2572: ccat_eth_link_down(priv->netdev);
p@2572: }
p@2572: }
p@2572:
p@2572: /**
p@2576: * Poll for available rx dma descriptors in ethernet operating mode
p@2576: */
p@2576: static void poll_rx(struct ccat_eth_priv *const priv)
p@2576: {
p@2636: struct ccat_eth_fifo *const fifo = &priv->rx_fifo;
p@2636: size_t rx_per_poll = FIFO_LENGTH / 2;
p@2636: size_t len = priv->rx_ready(fifo);
p@2636:
p@2636: while (len && --rx_per_poll) {
p@2636: priv->receive(priv, len);
p@2636: fifo->add(fifo);
p@2576: ccat_eth_fifo_inc(fifo);
p@2636: len = priv->rx_ready(fifo);
p@2576: }
p@2576: }
p@2576:
p@2572: static void ec_poll_rx(struct net_device *dev)
p@2572: {
p@2576: struct ccat_eth_priv *const priv = netdev_priv(dev);
p@2576: poll_rx(priv);
p@2572: }
p@2572:
p@2572: /**
p@2572: * Poll for available tx dma descriptors in ethernet operating mode
p@2572: */
p@2572: static void poll_tx(struct ccat_eth_priv *const priv)
p@2572: {
p@2636: if (priv->tx_ready(priv)) {
p@2572: netif_wake_queue(priv->netdev);
p@2572: }
p@2572: }
p@2572:
p@2572: /**
p@2572: * Since CCAT doesn't support interrupts until now, we have to poll
p@2572: * some status bits to recognize things like link change etc.
p@2572: */
p@2572: static enum hrtimer_restart poll_timer_callback(struct hrtimer *timer)
p@2572: {
p@2576: struct ccat_eth_priv *const priv =
p@2576: container_of(timer, struct ccat_eth_priv, poll_timer);
p@2572:
p@2572: poll_link(priv);
p@2636: if (!priv->ecdev) {
p@2572: poll_rx(priv);
p@2576: poll_tx(priv);
p@2576: }
p@2576: hrtimer_forward_now(timer, POLL_TIME);
p@2572: return HRTIMER_RESTART;
p@2572: }
p@2572:
p@2550: static struct rtnl_link_stats64 *ccat_eth_get_stats64(struct net_device *dev, struct rtnl_link_stats64
p@2550: *storage)
p@2550: {
p@2550: struct ccat_eth_priv *const priv = netdev_priv(dev);
p@2569: struct ccat_mac_register mac;
p@2550: memcpy_fromio(&mac, priv->reg.mac, sizeof(mac));
p@2569: storage->rx_packets = mac.rx_frames; /* total packets received */
p@2569: storage->tx_packets = mac.tx_frames; /* total packets transmitted */
p@2550: storage->rx_bytes = atomic64_read(&priv->rx_bytes); /* total bytes received */
p@2550: storage->tx_bytes = atomic64_read(&priv->tx_bytes); /* total bytes transmitted */
p@2569: storage->rx_errors = mac.frame_len_err + mac.rx_mem_full + mac.crc_err + mac.rx_err; /* bad packets received */
p@2573: storage->tx_errors = mac.tx_mem_full; /* packet transmit problems */
p@2550: storage->rx_dropped = atomic64_read(&priv->rx_dropped); /* no space in linux buffers */
p@2550: storage->tx_dropped = atomic64_read(&priv->tx_dropped); /* no space available in linux */
p@2550: //TODO __u64 multicast; /* multicast packets received */
p@2550: //TODO __u64 collisions;
p@2550:
p@2550: /* detailed rx_errors: */
p@2569: storage->rx_length_errors = mac.frame_len_err;
p@2569: storage->rx_over_errors = mac.rx_mem_full; /* receiver ring buff overflow */
p@2569: storage->rx_crc_errors = mac.crc_err; /* recved pkt with crc error */
p@2569: storage->rx_frame_errors = mac.rx_err; /* recv'd frame alignment error */
p@2569: storage->rx_fifo_errors = mac.rx_mem_full; /* recv'r fifo overrun */
p@2550: //TODO __u64 rx_missed_errors; /* receiver missed packet */
p@2550:
p@2550: /* detailed tx_errors */
p@2550: //TODO __u64 tx_aborted_errors;
p@2550: //TODO __u64 tx_carrier_errors;
p@2550: //TODO __u64 tx_fifo_errors;
p@2550: //TODO __u64 tx_heartbeat_errors;
p@2550: //TODO __u64 tx_window_errors;
p@2550:
p@2550: /* for cslip etc */
p@2550: //TODO __u64 rx_compressed;
p@2550: //TODO __u64 tx_compressed;
p@2550: return storage;
p@2550: }
p@2550:
p@2572: static int ccat_eth_open(struct net_device *dev)
p@2572: {
p@2572: struct ccat_eth_priv *const priv = netdev_priv(dev);
p@2572:
p@2572: hrtimer_init(&priv->poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
p@2572: priv->poll_timer.function = poll_timer_callback;
p@2576: hrtimer_start(&priv->poll_timer, POLL_TIME, HRTIMER_MODE_REL);
p@2572: return 0;
p@2572: }
p@2572:
p@2572: static int ccat_eth_stop(struct net_device *dev)
p@2572: {
p@2572: struct ccat_eth_priv *const priv = netdev_priv(dev);
p@2572:
p@2572: priv->stop_queue(dev);
p@2572: hrtimer_cancel(&priv->poll_timer);
p@2572: return 0;
p@2572: }
p@2572:
p@2572: static const struct net_device_ops ccat_eth_netdev_ops = {
p@2572: .ndo_get_stats64 = ccat_eth_get_stats64,
p@2572: .ndo_open = ccat_eth_open,
p@2572: .ndo_start_xmit = ccat_eth_start_xmit,
p@2572: .ndo_stop = ccat_eth_stop,
p@2572: };
p@2572:
p@2636: static struct ccat_eth_priv *ccat_eth_alloc_netdev(struct ccat_function *func)
p@2636: {
p@2636: struct ccat_eth_priv *priv = NULL;
p@2550: struct net_device *const netdev = alloc_etherdev(sizeof(*priv));
p@2567:
p@2636: if (netdev) {
p@2636: priv = netdev_priv(netdev);
p@2636: memset(priv, 0, sizeof(*priv));
p@2636: priv->netdev = netdev;
p@2636: priv->func = func;
p@2636: ccat_eth_priv_init_reg(&priv->reg, func);
p@2636: }
p@2636: return priv;
p@2636: }
p@2636:
p@2636: static int ccat_eth_init_netdev(struct ccat_eth_priv *priv)
p@2636: {
p@2636: int status;
p@2550:
p@2550: /* init netdev with MAC and stack callbacks */
p@2636: memcpy_fromio(priv->netdev->dev_addr, priv->reg.mii + 8,
p@2636: priv->netdev->addr_len);
p@2636: priv->netdev->netdev_ops = &ccat_eth_netdev_ops;
p@2550:
p@2550: /* use as EtherCAT device? */
p@2636: priv->carrier_off = ecdev_carrier_off;
p@2636: priv->carrier_ok = ecdev_carrier_ok;
p@2636: priv->carrier_on = ecdev_carrier_on;
p@2636: priv->kfree_skb_any = ecdev_kfree_skb_any;
p@2636:
p@2636: /* It would be more intuitive to check for:
p@2636: * if (priv->func->drv->type == CCATINFO_ETHERCAT_MASTER_DMA) {
p@2636: * unfortunately priv->func->drv is not initialized until probe() returns.
p@2636: * So we check if there is a rx dma fifo registered to determine dma/io mode */
p@2636: if (priv->rx_fifo.reg) {
p@2636: priv->receive = ecdev_receive_dma;
p@2636: } else {
p@2636: priv->receive = ecdev_receive_eim;
p@2636: }
p@2636: priv->start_queue = ecdev_nop;
p@2636: priv->stop_queue = ecdev_nop;
p@2636: priv->unregister = unregister_ecdev;
p@2636: priv->ecdev = ecdev_offer(priv->netdev, ec_poll_rx, THIS_MODULE);
p@2550: if (priv->ecdev) {
p@2636: priv->carrier_off(priv->netdev);
p@2550: if (ecdev_open(priv->ecdev)) {
p@2550: pr_info("unable to register network device.\n");
p@2550: ecdev_withdraw(priv->ecdev);
p@2636: priv->free(priv);
p@2636: free_netdev(priv->netdev);
p@2636: return -1; // TODO return better error code
p@2550: }
p@2636: priv->func->private_data = priv;
p@2636: return 0;
p@2550: }
p@2550:
p@2550: /* EtherCAT disabled -> prepare normal ethernet mode */
p@2550: priv->carrier_off = netif_carrier_off;
p@2567: priv->carrier_ok = netif_carrier_ok;
p@2550: priv->carrier_on = netif_carrier_on;
p@2550: priv->kfree_skb_any = dev_kfree_skb_any;
p@2636: priv->receive = ccat_eth_receive;
p@2550: priv->start_queue = netif_start_queue;
p@2550: priv->stop_queue = netif_stop_queue;
p@2550: priv->unregister = unregister_netdev;
p@2636: priv->carrier_off(priv->netdev);
p@2636:
p@2636: status = register_netdev(priv->netdev);
p@2636: if (status) {
p@2550: pr_info("unable to register network device.\n");
p@2636: priv->free(priv);
p@2636: free_netdev(priv->netdev);
p@2636: return status;
p@2636: }
p@2636: pr_info("registered %s as network device.\n", priv->netdev->name);
p@2636: priv->func->private_data = priv;
p@2636: return 0;
p@2636: }
p@2636:
p@2636: static int ccat_eth_dma_probe(struct ccat_function *func)
p@2636: {
p@2636: struct ccat_eth_priv *priv = ccat_eth_alloc_netdev(func);
p@2636: int status;
p@2636:
p@2636: if (!priv)
p@2636: return -ENOMEM;
p@2636:
p@2636: status = ccat_eth_priv_init_dma(priv);
p@2636: if (status) {
p@2636: pr_warn("%s(): DMA initialization failed.\n", __FUNCTION__);
p@2636: free_netdev(priv->netdev);
p@2636: return status;
p@2636: }
p@2636: return ccat_eth_init_netdev(priv);
p@2636: }
p@2636:
p@2636: static void ccat_eth_dma_remove(struct ccat_function *func)
p@2636: {
p@2636: struct ccat_eth_priv *const eth = func->private_data;
p@2636: eth->unregister(eth->netdev);
p@2636: eth->free(eth);
p@2636: free_netdev(eth->netdev);
p@2636: }
p@2636:
p@2636: struct ccat_driver eth_dma_driver = {
p@2636: .type = CCATINFO_ETHERCAT_MASTER_DMA,
p@2636: .probe = ccat_eth_dma_probe,
p@2636: .remove = ccat_eth_dma_remove,
p@2636: };
p@2636:
p@2636: static int ccat_eth_eim_probe(struct ccat_function *func)
p@2636: {
p@2636: struct ccat_eth_priv *priv = ccat_eth_alloc_netdev(func);
p@2636: int status;
p@2636:
p@2636: if (!priv)
p@2636: return -ENOMEM;
p@2636:
p@2636: status = ccat_eth_priv_init_eim(priv);
p@2636: if (status) {
p@2636: pr_warn("%s(): memory initialization failed.\n", __FUNCTION__);
p@2636: free_netdev(priv->netdev);
p@2636: return status;
p@2636: }
p@2636: return ccat_eth_init_netdev(priv);
p@2636: }
p@2636:
p@2636: static void ccat_eth_eim_remove(struct ccat_function *func)
p@2636: {
p@2636: struct ccat_eth_priv *const eth = func->private_data;
p@2636: eth->unregister(eth->netdev);
p@2636: eth->free(eth);
p@2636: free_netdev(eth->netdev);
p@2636: }
p@2636:
p@2636: struct ccat_driver eth_eim_driver = {
p@2636: .type = CCATINFO_ETHERCAT_NODMA,
p@2636: .probe = ccat_eth_eim_probe,
p@2636: .remove = ccat_eth_eim_remove,
p@2636: };