/*
* ks8842.c timberdale KS8842 ethernet driver
* Copyright (c) 2009 Intel Corporation
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Supports:
* The Micrel KS8842 behind the timberdale FPGA
* The genuine Micrel KS8841/42 device with ISA 16/32bit bus interface
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/ks8842.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#define DRV_NAME "ks8842"
/* Timberdale specific Registers */
#define REG_TIMB_RST 0x1c
#define REG_TIMB_FIFO 0x20
#define REG_TIMB_ISR 0x24
#define REG_TIMB_IER 0x28
#define REG_TIMB_IAR 0x2C
#define REQ_TIMB_DMA_RESUME 0x30
/* KS8842 registers */
#define REG_SELECT_BANK 0x0e
/* bank 0 registers */
#define REG_QRFCR 0x04
/* bank 2 registers */
#define REG_MARL 0x00
#define REG_MARM 0x02
#define REG_MARH 0x04
/* bank 3 registers */
#define REG_GRR 0x06
/* bank 16 registers */
#define REG_TXCR 0x00
#define REG_TXSR 0x02
#define REG_RXCR 0x04
#define REG_TXMIR 0x08
#define REG_RXMIR 0x0A
/* bank 17 registers */
#define REG_TXQCR 0x00
#define REG_RXQCR 0x02
#define REG_TXFDPR 0x04
#define REG_RXFDPR 0x06
#define REG_QMU_DATA_LO 0x08
#define REG_QMU_DATA_HI 0x0A
/* bank 18 registers */
#define REG_IER 0x00
#define IRQ_LINK_CHANGE 0x8000
#define IRQ_TX 0x4000
#define IRQ_RX 0x2000
#define IRQ_RX_OVERRUN 0x0800
#define IRQ_TX_STOPPED 0x0200
#define IRQ_RX_STOPPED 0x0100
#define IRQ_RX_ERROR 0x0080
#define ENABLED_IRQS (IRQ_LINK_CHANGE | IRQ_TX | IRQ_RX | IRQ_RX_STOPPED | \
IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR)
/* When running via timberdale in DMA mode, the RX interrupt should be
enabled in the KS8842, but not in the FPGA IP, since the IP handles
RX DMA internally.
TX interrupts are not needed it is handled by the FPGA the driver is
notified via DMA callbacks.
*/
#define ENABLED_IRQS_DMA_IP (IRQ_LINK_CHANGE | IRQ_RX_STOPPED | \
IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR)
#define ENABLED_IRQS_DMA (ENABLED_IRQS_DMA_IP | IRQ_RX)
#define REG_ISR 0x02
#define REG_RXSR 0x04
#define RXSR_VALID 0x8000
#define RXSR_BROADCAST 0x80
#define RXSR_MULTICAST 0x40
#define RXSR_UNICAST 0x20
#define RXSR_FRAMETYPE 0x08
#define RXSR_TOO_LONG 0x04
#define RXSR_RUNT 0x02
#define RXSR_CRC_ERROR 0x01
#define RXSR_ERROR (RXSR_TOO_LONG | RXSR_RUNT | RXSR_CRC_ERROR)
/* bank 32 registers */
#define REG_SW_ID_AND_ENABLE 0x00
#define REG_SGCR1 0x02
#define REG_SGCR2 0x04
#define REG_SGCR3 0x06
/* bank 39 registers */
#define REG_MACAR1 0x00
#define REG_MACAR2 0x02
#define REG_MACAR3 0x04
/* bank 45 registers */
#define REG_P1MBCR 0x00
#define REG_P1MBSR 0x02
/* bank 46 registers */
#define REG_P2MBCR 0x00
#define REG_P2MBSR 0x02
/* bank 48 registers */
#define REG_P1CR2 0x02
/* bank 49 registers */
#define REG_P1CR4 0x02
#define REG_P1SR 0x04
/* flags passed by platform_device for configuration */
#define MICREL_KS884X 0x01 /* 0=Timeberdale(FPGA), 1=Micrel */
#define KS884X_16BIT 0x02 /* 1=16bit, 0=32bit */
#define DMA_BUFFER_SIZE 2048
struct ks8842_tx_dma_ctl {
struct dma_chan *chan;
struct dma_async_tx_descriptor *adesc;
void *buf;
struct scatterlist sg;
int channel;
};
struct ks8842_rx_dma_ctl {
struct dma_chan *chan;
struct dma_async_tx_descriptor *adesc;
struct sk_buff *skb;
struct scatterlist sg;
struct tasklet_struct tasklet;
int channel;
};
#define KS8842_USE_DMA(adapter) (((adapter)->dma_tx.channel != -1) && \
((adapter)->dma_rx.channel != -1))
struct ks8842_adapter {
void __iomem *hw_addr;
int irq;
unsigned long conf_flags; /* copy of platform_device config */
struct tasklet_struct tasklet;
spinlock_t lock; /* spinlock to be interrupt safe */
struct work_struct timeout_work;
struct net_device *netdev;
struct device *dev;
struct ks8842_tx_dma_ctl dma_tx;
struct ks8842_rx_dma_ctl dma_rx;
};
static void ks8842_dma_rx_cb(void *data);
static void ks8842_dma_tx_cb(void *data);
static