diff options
author | John Crispin <john@openwrt.org> | 2012-11-02 20:07:02 +0000 |
---|---|---|
committer | John Crispin <john@openwrt.org> | 2012-11-02 20:07:02 +0000 |
commit | 736835343c20f3ca495b73d2adf24d240f471676 (patch) | |
tree | bbf0787170ac715eaa9f8eabf8317cfe56fc17b3 /target/linux/lantiq/files/drivers/net/ethernet | |
parent | fa316620a7bd49e4d08bf1a410da98db54a83327 (diff) | |
download | upstream-736835343c20f3ca495b73d2adf24d240f471676.tar.gz upstream-736835343c20f3ca495b73d2adf24d240f471676.tar.bz2 upstream-736835343c20f3ca495b73d2adf24d240f471676.zip |
move files/ -> files-3.3/
SVN-Revision: 34060
Diffstat (limited to 'target/linux/lantiq/files/drivers/net/ethernet')
3 files changed, 0 insertions, 2340 deletions
diff --git a/target/linux/lantiq/files/drivers/net/ethernet/lantiq_vrx200.c b/target/linux/lantiq/files/drivers/net/ethernet/lantiq_vrx200.c deleted file mode 100644 index d79d3803cc..0000000000 --- a/target/linux/lantiq/files/drivers/net/ethernet/lantiq_vrx200.c +++ /dev/null @@ -1,1358 +0,0 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) 2011 John Crispin <blogic@openwrt.org> - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/uaccess.h> -#include <linux/in.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/phy.h> -#include <linux/ip.h> -#include <linux/tcp.h> -#include <linux/skbuff.h> -#include <linux/mm.h> -#include <linux/platform_device.h> -#include <linux/ethtool.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/dma-mapping.h> -#include <linux/module.h> -#include <linux/clk.h> - -#include <asm/checksum.h> - -#include <lantiq_soc.h> -#include <xway_dma.h> -#include <lantiq_platform.h> - -#define LTQ_SWITCH_BASE 0x1E108000 -#define LTQ_SWITCH_CORE_BASE LTQ_SWITCH_BASE -#define LTQ_SWITCH_TOP_PDI_BASE LTQ_SWITCH_CORE_BASE -#define LTQ_SWITCH_BM_PDI_BASE (LTQ_SWITCH_CORE_BASE + 4 * 0x40) -#define LTQ_SWITCH_MAC_PDI_0_BASE (LTQ_SWITCH_CORE_BASE + 4 * 0x900) -#define LTQ_SWITCH_MAC_PDI_X_BASE(x) (LTQ_SWITCH_MAC_PDI_0_BASE + x * 0x30) -#define LTQ_SWITCH_TOPLEVEL_BASE (LTQ_SWITCH_BASE + 4 * 0xC40) -#define LTQ_SWITCH_MDIO_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE) -#define LTQ_SWITCH_MII_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE + 4 * 0x36) -#define LTQ_SWITCH_PMAC_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE + 4 * 0x82) - -#define LTQ_ETHSW_MAC_CTRL0_PADEN (1 << 8) -#define LTQ_ETHSW_MAC_CTRL0_FCS (1 << 7) -#define LTQ_ETHSW_MAC_CTRL1_SHORTPRE (1 << 8) -#define LTQ_ETHSW_MAC_CTRL2_MLEN (1 << 3) -#define LTQ_ETHSW_MAC_CTRL2_LCHKL (1 << 2) -#define LTQ_ETHSW_MAC_CTRL2_LCHKS_DIS 0 -#define LTQ_ETHSW_MAC_CTRL2_LCHKS_UNTAG 1 -#define LTQ_ETHSW_MAC_CTRL2_LCHKS_TAG 2 -#define LTQ_ETHSW_MAC_CTRL6_RBUF_DLY_WP_SHIFT 9 -#define LTQ_ETHSW_MAC_CTRL6_RXBUF_BYPASS (1 << 6) -#define LTQ_ETHSW_GLOB_CTRL_SE (1 << 15) -#define LTQ_ETHSW_MDC_CFG1_MCEN (1 << 8) -#define LTQ_ETHSW_PMAC_HD_CTL_FC (1 << 10) -#define LTQ_ETHSW_PMAC_HD_CTL_RC (1 << 4) -#define LTQ_ETHSW_PMAC_HD_CTL_AC (1 << 2) -#define ADVERTIZE_MPD (1 << 10) - -#define MDIO_DEVAD_NONE (-1) - -#define LTQ_ETH_RX_BUFFER_CNT PKTBUFSRX - -#define LTQ_MDIO_DRV_NAME "ltq-mdio" -#define LTQ_ETH_DRV_NAME "ltq-eth" - -#define LTQ_ETHSW_MAX_GMAC 1 -#define LTQ_ETHSW_PMAC 1 - -#define ltq_setbits(a, set) \ - ltq_w32(ltq_r32(a) | (set), a) - -enum ltq_reset_modules { - LTQ_RESET_CORE, - LTQ_RESET_DMA, - LTQ_RESET_ETH, - LTQ_RESET_PHY, - LTQ_RESET_HARD, - LTQ_RESET_SOFT, -}; - -static inline void -dbg_ltq_writel(void *a, unsigned int b) -{ - ltq_w32(b, a); -} - -int ltq_reset_once(enum ltq_reset_modules module, ulong usec); - -struct ltq_ethsw_mac_pdi_x_regs { - u32 pstat; /* Port status */ - u32 pisr; /* Interrupt status */ - u32 pier; /* Interrupt enable */ - u32 ctrl_0; /* Control 0 */ - u32 ctrl_1; /* Control 1 */ - u32 ctrl_2; /* Control 2 */ - u32 ctrl_3; /* Control 3 */ - u32 ctrl_4; /* Control 4 */ - u32 ctrl_5; /* Control 5 */ - u32 ctrl_6; /* Control 6 */ - u32 bufst; /* TX/RX buffer control */ - u32 testen; /* Test enable */ -}; - -struct ltq_ethsw_mac_pdi_regs { - struct ltq_ethsw_mac_pdi_x_regs mac[12]; -}; - -struct ltq_ethsw_mdio_pdi_regs { - u32 glob_ctrl; /* Global control 0 */ - u32 rsvd0[7]; - u32 mdio_ctrl; /* MDIO control */ - u32 mdio_read; /* MDIO read data */ - u32 mdio_write; /* MDIO write data */ - u32 mdc_cfg_0; /* MDC clock configuration 0 */ - u32 mdc_cfg_1; /* MDC clock configuration 1 */ - u32 rsvd[3]; - u32 phy_addr_5; /* PHY address port 5 */ - u32 phy_addr_4; /* PHY address port 4 */ - u32 phy_addr_3; /* PHY address port 3 */ - u32 phy_addr_2; /* PHY address port 2 */ - u32 phy_addr_1; /* PHY address port 1 */ - u32 phy_addr_0; /* PHY address port 0 */ - u32 mdio_stat_0; /* MDIO PHY polling status port 0 */ - u32 mdio_stat_1; /* MDIO PHY polling status port 1 */ - u32 mdio_stat_2; /* MDIO PHY polling status port 2 */ - u32 mdio_stat_3; /* MDIO PHY polling status port 3 */ - u32 mdio_stat_4; /* MDIO PHY polling status port 4 */ - u32 mdio_stat_5; /* MDIO PHY polling status port 5 */ -}; - -struct ltq_ethsw_mii_pdi_regs { - u32 mii_cfg0; /* xMII port 0 configuration */ - u32 pcdu0; /* Port 0 clock delay configuration */ - u32 mii_cfg1; /* xMII port 1 configuration */ - u32 pcdu1; /* Port 1 clock delay configuration */ - u32 mii_cfg2; /* xMII port 2 configuration */ - u32 rsvd0; - u32 mii_cfg3; /* xMII port 3 configuration */ - u32 rsvd1; - u32 mii_cfg4; /* xMII port 4 configuration */ - u32 rsvd2; - u32 mii_cfg5; /* xMII port 5 configuration */ - u32 pcdu5; /* Port 5 clock delay configuration */ -}; - -struct ltq_ethsw_pmac_pdi_regs { - u32 hd_ctl; /* PMAC header control */ - u32 tl; /* PMAC type/length */ - u32 sa1; /* PMAC source address 1 */ - u32 sa2; /* PMAC source address 2 */ - u32 sa3; /* PMAC source address 3 */ - u32 da1; /* PMAC destination address 1 */ - u32 da2; /* PMAC destination address 2 */ - u32 da3; /* PMAC destination address 3 */ - u32 vlan; /* PMAC VLAN */ - u32 rx_ipg; /* PMAC interpacket gap in RX direction */ - u32 st_etype; /* PMAC special tag ethertype */ - u32 ewan; /* PMAC ethernet WAN group */ -}; - -struct ltq_mdio_phy_addr_reg { - union { - struct { - unsigned rsvd:1; - unsigned lnkst:2; /* Link status control */ - unsigned speed:2; /* Speed control */ - unsigned fdup:2; /* Full duplex control */ - unsigned fcontx:2; /* Flow control mode TX */ - unsigned fconrx:2; /* Flow control mode RX */ - unsigned addr:5; /* PHY address */ - } bits; - u16 val; - }; -}; - -enum ltq_mdio_phy_addr_lnkst { - LTQ_MDIO_PHY_ADDR_LNKST_AUTO = 0, - LTQ_MDIO_PHY_ADDR_LNKST_UP = 1, - LTQ_MDIO_PHY_ADDR_LNKST_DOWN = 2, -}; - -enum ltq_mdio_phy_addr_speed { - LTQ_MDIO_PHY_ADDR_SPEED_M10 = 0, - LTQ_MDIO_PHY_ADDR_SPEED_M100 = 1, - LTQ_MDIO_PHY_ADDR_SPEED_G1 = 2, - LTQ_MDIO_PHY_ADDR_SPEED_AUTO = 3, -}; - -enum ltq_mdio_phy_addr_fdup { - LTQ_MDIO_PHY_ADDR_FDUP_AUTO = 0, - LTQ_MDIO_PHY_ADDR_FDUP_ENABLE = 1, - LTQ_MDIO_PHY_ADDR_FDUP_DISABLE = 3, -}; - -enum ltq_mdio_phy_addr_fcon { - LTQ_MDIO_PHY_ADDR_FCON_AUTO = 0, - LTQ_MDIO_PHY_ADDR_FCON_ENABLE = 1, - LTQ_MDIO_PHY_ADDR_FCON_DISABLE = 3, -}; - -struct ltq_mii_mii_cfg_reg { - union { - struct { - unsigned res:1; /* Hardware reset */ - unsigned en:1; /* xMII interface enable */ - unsigned isol:1; /* xMII interface isolate */ - unsigned ldclkdis:1; /* Link down clock disable */ - unsigned rsvd:1; - unsigned crs:2; /* CRS sensitivity config */ - unsigned rgmii_ibs:1; /* RGMII In Band status */ - unsigned rmii:1; /* RMII ref clock direction */ - unsigned miirate:3; /* xMII interface clock rate */ - unsigned miimode:4; /* xMII interface mode */ - } bits; - u16 val; - }; -}; - -enum ltq_mii_mii_cfg_miirate { - LTQ_MII_MII_CFG_MIIRATE_M2P5 = 0, - LTQ_MII_MII_CFG_MIIRATE_M25 = 1, - LTQ_MII_MII_CFG_MIIRATE_M125 = 2, - LTQ_MII_MII_CFG_MIIRATE_M50 = 3, - LTQ_MII_MII_CFG_MIIRATE_AUTO = 4, -}; - -enum ltq_mii_mii_cfg_miimode { - LTQ_MII_MII_CFG_MIIMODE_MIIP = 0, - LTQ_MII_MII_CFG_MIIMODE_MIIM = 1, - LTQ_MII_MII_CFG_MIIMODE_RMIIP = 2, - LTQ_MII_MII_CFG_MIIMODE_RMIIM = 3, - LTQ_MII_MII_CFG_MIIMODE_RGMII = 4, -}; - -struct ltq_eth_priv { - struct ltq_dma_device *dma_dev; - struct mii_dev *bus; - struct eth_device *dev; - struct phy_device *phymap[LTQ_ETHSW_MAX_GMAC]; - int rx_num; -}; - -enum ltq_mdio_mbusy { - LTQ_MDIO_MBUSY_IDLE = 0, - LTQ_MDIO_MBUSY_BUSY = 1, -}; - -enum ltq_mdio_op { - LTQ_MDIO_OP_WRITE = 1, - LTQ_MDIO_OP_READ = 2, -}; - -struct ltq_mdio_access { - union { - struct { - unsigned rsvd:3; - unsigned mbusy:1; - unsigned op:2; - unsigned phyad:5; - unsigned regad:5; - } bits; - u16 val; - }; -}; - -enum LTQ_ETH_PORT_FLAGS { - LTQ_ETH_PORT_NONE = 0, - LTQ_ETH_PORT_PHY = 1, - LTQ_ETH_PORT_SWITCH = (1 << 1), - LTQ_ETH_PORT_MAC = (1 << 2), -}; - -struct ltq_eth_port_config { - u8 num; - u8 phy_addr; - u16 flags; - phy_interface_t phy_if; -}; - -struct ltq_eth_board_config { - const struct ltq_eth_port_config *ports; - int num_ports; -}; - -static const struct ltq_eth_port_config eth_port_config[] = { - /* GMAC0: external Lantiq PEF7071 10/100/1000 PHY for LAN port 0 */ - { 0, 0x0, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII }, - /* GMAC1: external Lantiq PEF7071 10/100/1000 PHY for LAN port 1 */ - { 1, 0x1, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII }, -}; - -static const struct ltq_eth_board_config board_config = { - .ports = eth_port_config, - .num_ports = ARRAY_SIZE(eth_port_config), -}; - -static struct ltq_ethsw_mac_pdi_regs *ltq_ethsw_mac_pdi_regs = - (struct ltq_ethsw_mac_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_MAC_PDI_0_BASE); - -static struct ltq_ethsw_mdio_pdi_regs *ltq_ethsw_mdio_pdi_regs = - (struct ltq_ethsw_mdio_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_MDIO_PDI_BASE); - -static struct ltq_ethsw_mii_pdi_regs *ltq_ethsw_mii_pdi_regs = - (struct ltq_ethsw_mii_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_MII_PDI_BASE); - -static struct ltq_ethsw_pmac_pdi_regs *ltq_ethsw_pmac_pdi_regs = - (struct ltq_ethsw_pmac_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_PMAC_PDI_BASE); - - -#define MAX_DMA_CHAN 0x8 -#define MAX_DMA_CRC_LEN 0x4 -#define MAX_DMA_DATA_LEN 0x600 - -/* use 2 static channels for TX/RX - depending on the SoC we need to use different DMA channels for ethernet */ -#define LTQ_ETOP_TX_CHANNEL 1 -#define LTQ_ETOP_RX_CHANNEL 0 - -#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL) -#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL) - -#define DRV_VERSION "1.0" - -static void __iomem *ltq_vrx200_membase; - -struct ltq_vrx200_chan { - int idx; - int tx_free; - struct net_device *netdev; - struct napi_struct napi; - struct ltq_dma_channel dma; - struct sk_buff *skb[LTQ_DESC_NUM]; -}; - -struct ltq_vrx200_priv { - struct net_device *netdev; - struct ltq_eth_data *pldata; - struct resource *res; - - struct mii_bus *mii_bus; - struct phy_device *phydev; - - struct ltq_vrx200_chan ch[MAX_DMA_CHAN]; - int tx_free[MAX_DMA_CHAN >> 1]; - - spinlock_t lock; - - struct clk *clk_ppe; -}; - -static int ltq_vrx200_mdio_wr(struct mii_bus *bus, int phy_addr, - int phy_reg, u16 phy_data); - -static int -ltq_vrx200_alloc_skb(struct ltq_vrx200_chan *ch) -{ - ch->skb[ch->dma.desc] = dev_alloc_skb(MAX_DMA_DATA_LEN); - if (!ch->skb[ch->dma.desc]) - return -ENOMEM; - ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(NULL, - ch->skb[ch->dma.desc]->data, MAX_DMA_DATA_LEN, - DMA_FROM_DEVICE); - ch->dma.desc_base[ch->dma.desc].addr = - CPHYSADDR(ch->skb[ch->dma.desc]->data); - ch->dma.desc_base[ch->dma.desc].ctl = - LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) | - MAX_DMA_DATA_LEN; - skb_reserve(ch->skb[ch->dma.desc], NET_IP_ALIGN); - return 0; -} - -static void -ltq_vrx200_hw_receive(struct ltq_vrx200_chan *ch) -{ - struct ltq_vrx200_priv *priv = netdev_priv(ch->netdev); - struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; - struct sk_buff *skb = ch->skb[ch->dma.desc]; - int len = (desc->ctl & LTQ_DMA_SIZE_MASK) - MAX_DMA_CRC_LEN; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (ltq_vrx200_alloc_skb(ch)) { - netdev_err(ch->netdev, - "failed to allocate new rx buffer, stopping DMA\n"); - ltq_dma_close(&ch->dma); - } - ch->dma.desc++; - ch->dma.desc %= LTQ_DESC_NUM; - spin_unlock_irqrestore(&priv->lock, flags); - - skb_put(skb, len); - skb->dev = ch->netdev; - skb->protocol = eth_type_trans(skb, ch->netdev); - netif_receive_skb(skb); -} - -static int -ltq_vrx200_poll_rx(struct napi_struct *napi, int budget) -{ - struct ltq_vrx200_chan *ch = container_of(napi, - struct ltq_vrx200_chan, napi); - struct ltq_vrx200_priv *priv = netdev_priv(ch->netdev); - int rx = 0; - int complete = 0; - unsigned long flags; - - while ((rx < budget) && !complete) { - struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; - - if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { - ltq_vrx200_hw_receive(ch); - rx++; - } else { - complete = 1; - } - } - if (complete || !rx) { - napi_complete(&ch->napi); - spin_lock_irqsave(&priv->lock, flags); - ltq_dma_ack_irq(&ch->dma); - spin_unlock_irqrestore(&priv->lock, flags); - } - return rx; -} - -static int -ltq_vrx200_poll_tx(struct napi_struct *napi, int budget) -{ - struct ltq_vrx200_chan *ch = - container_of(napi, struct ltq_vrx200_chan, napi); - struct ltq_vrx200_priv *priv = netdev_priv(ch->netdev); - struct netdev_queue *txq = - netdev_get_tx_queue(ch->netdev, ch->idx >> 1); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - while ((ch->dma.desc_base[ch->tx_free].ctl & - (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { - dev_kfree_skb_any(ch->skb[ch->tx_free]); - ch->skb[ch->tx_free] = NULL; - memset(&ch->dma.desc_base[ch->tx_free], 0, - sizeof(struct ltq_dma_desc)); - ch->tx_free++; - ch->tx_free %= LTQ_DESC_NUM; - } - spin_unlock_irqrestore(&priv->lock, flags); - - if (netif_tx_queue_stopped(txq)) - netif_tx_start_queue(txq); - napi_complete(&ch->napi); - spin_lock_irqsave(&priv->lock, flags); - ltq_dma_ack_irq(&ch->dma); - spin_unlock_irqrestore(&priv->lock, flags); - return 1; -} - -static irqreturn_t -ltq_vrx200_dma_irq(int irq, void *_priv) -{ - struct ltq_vrx200_priv *priv = _priv; - int ch = irq - LTQ_DMA_ETOP; - - napi_schedule(&priv->ch[ch].napi); - return IRQ_HANDLED; -} - -static void -ltq_vrx200_free_channel(struct net_device *dev, struct ltq_vrx200_chan *ch) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - - ltq_dma_free(&ch->dma); - if (ch->dma.irq) - free_irq(ch->dma.irq, priv); - if (IS_RX(ch->idx)) { - int desc; - for (desc = 0; desc < LTQ_DESC_NUM; desc++) - dev_kfree_skb_any(ch->skb[ch->dma.desc]); - } -} - -static void -ltq_vrx200_hw_exit(struct net_device *dev) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - int i; - - clk_disable(priv->clk_ppe); - - for (i = 0; i < MAX_DMA_CHAN; i++) - if (IS_TX(i) || IS_RX(i)) - ltq_vrx200_free_channel(dev, &priv->ch[i]); -} - -static void *ltq_eth_phy_addr_reg(int num) -{ - switch (num) { - case 0: - return <q_ethsw_mdio_pdi_regs->phy_addr_0; - case 1: - return <q_ethsw_mdio_pdi_regs->phy_addr_1; - case 2: - return <q_ethsw_mdio_pdi_regs->phy_addr_2; - case 3: - return <q_ethsw_mdio_pdi_regs->phy_addr_3; - case 4: - return <q_ethsw_mdio_pdi_regs->phy_addr_4; - case 5: - return <q_ethsw_mdio_pdi_regs->phy_addr_5; - } - - return NULL; -} - -static void *ltq_eth_mii_cfg_reg(int num) -{ - switch (num) { - case 0: - return <q_ethsw_mii_pdi_regs->mii_cfg0; - case 1: - return <q_ethsw_mii_pdi_regs->mii_cfg1; - case 2: - return <q_ethsw_mii_pdi_regs->mii_cfg2; - case 3: - return <q_ethsw_mii_pdi_regs->mii_cfg3; - case 4: - return <q_ethsw_mii_pdi_regs->mii_cfg4; - case 5: - return <q_ethsw_mii_pdi_regs->mii_cfg5; - } - - return NULL; -} - -static void ltq_eth_gmac_update(struct phy_device *phydev, int num) -{ - struct ltq_mdio_phy_addr_reg phy_addr_reg; - struct ltq_mii_mii_cfg_reg mii_cfg_reg; - void *phy_addr = ltq_eth_phy_addr_reg(num); - void *mii_cfg = ltq_eth_mii_cfg_reg(num); - - phy_addr_reg.val = ltq_r32(phy_addr); - mii_cfg_reg.val = ltq_r32(mii_cfg); - - phy_addr_reg.bits.addr = phydev->addr; - - if (phydev->link) - phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_UP; - else - phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_DOWN; - - switch (phydev->speed) { - case SPEED_1000: - phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_G1; - mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M125; - break; - case SPEED_100: - phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M100; - switch (mii_cfg_reg.bits.miimode) { - case LTQ_MII_MII_CFG_MIIMODE_RMIIM: - case LTQ_MII_MII_CFG_MIIMODE_RMIIP: - mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M50; - break; - default: - mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M25; - break; - } - break; - default: - phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M10; - mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M2P5; - break; - } - - if (phydev->duplex == DUPLEX_FULL) - phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_ENABLE; - else - phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_DISABLE; - - dbg_ltq_writel(phy_addr, phy_addr_reg.val); - dbg_ltq_writel(mii_cfg, mii_cfg_reg.val); - udelay(1); -} - - -static void ltq_eth_port_config(struct ltq_vrx200_priv *priv, - const struct ltq_eth_port_config *port) -{ - struct ltq_mii_mii_cfg_reg mii_cfg_reg; - void *mii_cfg = ltq_eth_mii_cfg_reg(port->num); - int setup_gpio = 0; - - mii_cfg_reg.val = ltq_r32(mii_cfg); - - - switch (port->num) { - case 0: /* xMII0 */ - case 1: /* xMII1 */ - switch (port->phy_if) { - case PHY_INTERFACE_MODE_MII: - if (port->flags & LTQ_ETH_PORT_PHY) - /* MII MAC mode, connected to external PHY */ - mii_cfg_reg.bits.miimode = - LTQ_MII_MII_CFG_MIIMODE_MIIM; - else - /* MII PHY mode, connected to external MAC */ - mii_cfg_reg.bits.miimode = - LTQ_MII_MII_CFG_MIIMODE_MIIP; - setup_gpio = 1; - break; - case PHY_INTERFACE_MODE_RMII: - if (port->flags & LTQ_ETH_PORT_PHY) - /* RMII MAC mode, connected to external PHY */ - mii_cfg_reg.bits.miimode = - LTQ_MII_MII_CFG_MIIMODE_RMIIM; - else - /* RMII PHY mode, connected to external MAC */ - mii_cfg_reg.bits.miimode = - LTQ_MII_MII_CFG_MIIMODE_RMIIP; - setup_gpio = 1; - break; - case PHY_INTERFACE_MODE_RGMII: - /* RGMII MAC mode, connected to external PHY */ - mii_cfg_reg.bits.miimode = - LTQ_MII_MII_CFG_MIIMODE_RGMII; - setup_gpio = 1; - break; - default: - break; - } - break; - case 2: /* internal GPHY0 */ - case 3: /* internal GPHY0 */ - case 4: /* internal GPHY1 */ - switch (port->phy_if) { - case PHY_INTERFACE_MODE_MII: - case PHY_INTERFACE_MODE_GMII: - /* MII MAC mode, connected to internal GPHY */ - mii_cfg_reg.bits.miimode = - LTQ_MII_MII_CFG_MIIMODE_MIIM; - setup_gpio = 1; - break; - default: - break; - } - break; - case 5: /* internal GPHY1 or xMII2 */ - switch (port->phy_if) { - case PHY_INTERFACE_MODE_MII: - /* MII MAC mode, connected to internal GPHY */ - mii_cfg_reg.bits.miimode = - LTQ_MII_MII_CFG_MIIMODE_MIIM; - setup_gpio = 1; - break; - case PHY_INTERFACE_MODE_RGMII: - /* RGMII MAC mode, connected to external PHY */ - mii_cfg_reg.bits.miimode = - LTQ_MII_MII_CFG_MIIMODE_RGMII; - setup_gpio = 1; - break; - default: - break; - } - break; - default: - break; - } - - /* Enable MII interface */ - mii_cfg_reg.bits.en = port->flags ? 1 : 0; - dbg_ltq_writel(mii_cfg, mii_cfg_reg.val); - -} - -static void ltq_eth_gmac_init(int num) -{ - struct ltq_mdio_phy_addr_reg phy_addr_reg; - struct ltq_mii_mii_cfg_reg mii_cfg_reg; - void *phy_addr = ltq_eth_phy_addr_reg(num); - void *mii_cfg = ltq_eth_mii_cfg_reg(num); - struct ltq_ethsw_mac_pdi_x_regs *mac_pdi_regs; - - mac_pdi_regs = <q_ethsw_mac_pdi_regs->mac[num]; - - /* Reset PHY status to link down */ - phy_addr_reg.val = ltq_r32(phy_addr); - phy_addr_reg.bits.addr = num; - phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_DOWN; - phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M10; - phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_DISABLE; - dbg_ltq_writel(phy_addr, phy_addr_reg.val); - - /* Reset and disable MII interface */ - mii_cfg_reg.val = ltq_r32(mii_cfg); - mii_cfg_reg.bits.en = 0; - mii_cfg_reg.bits.res = 1; - mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M2P5; - dbg_ltq_writel(mii_cfg, mii_cfg_reg.val); - - /* - * Enable padding of short frames, enable frame checksum generation - * in transmit direction - */ - dbg_ltq_writel(&mac_pdi_regs->ctrl_0, LTQ_ETHSW_MAC_CTRL0_PADEN | - LTQ_ETHSW_MAC_CTRL0_FCS); - - /* Set inter packet gap size to 12 bytes */ - dbg_ltq_writel(&mac_pdi_regs->ctrl_1, 12); - - /* - * Configure frame length checks: - * - allow jumbo frames - * - enable long length check - * - enable short length without VLAN tags - */ - dbg_ltq_writel(&mac_pdi_regs->ctrl_2, LTQ_ETHSW_MAC_CTRL2_MLEN | - LTQ_ETHSW_MAC_CTRL2_LCHKL | - LTQ_ETHSW_MAC_CTRL2_LCHKS_UNTAG); -} - - -static void ltq_eth_pmac_init(void) -{ - struct ltq_ethsw_mac_pdi_x_regs *mac_pdi_regs; - - mac_pdi_regs = <q_ethsw_mac_pdi_regs->mac[LTQ_ETHSW_PMAC]; - - /* - * Enable padding of short frames, enable frame checksum generation - * in transmit direction - */ - dbg_ltq_writel(&mac_pdi_regs->ctrl_0, LTQ_ETHSW_MAC_CTRL0_PADEN | - LTQ_ETHSW_MAC_CTRL0_FCS); - - /* - * Configure frame length checks: - * - allow jumbo frames - * - enable long length check - * - enable short length without VLAN tags - */ - dbg_ltq_writel(&mac_pdi_regs->ctrl_2, LTQ_ETHSW_MAC_CTRL2_MLEN | - LTQ_ETHSW_MAC_CTRL2_LCHKL | - LTQ_ETHSW_MAC_CTRL2_LCHKS_UNTAG); - - /* - * Apply workaround for buffer congestion: - * - shorten preambel to 1 byte - * - set minimum inter packet gap size to 7 bytes - * - enable receive buffer bypass mode - */ - dbg_ltq_writel(&mac_pdi_regs->ctrl_1, LTQ_ETHSW_MAC_CTRL1_SHORTPRE | 7); - dbg_ltq_writel(&mac_pdi_regs->ctrl_6, - (6 << LTQ_ETHSW_MAC_CTRL6_RBUF_DLY_WP_SHIFT) | - LTQ_ETHSW_MAC_CTRL6_RXBUF_BYPASS); - - /* Set request assertion threshold to 8, IPG counter to 11 */ - dbg_ltq_writel(<q_ethsw_pmac_pdi_regs->rx_ipg, 0x8B); - - /* - * Configure frame header control: - * - enable reaction on pause frames (flow control) - * - remove CRC for packets from PMAC to DMA - * - add CRC for packets from DMA to PMAC - */ - dbg_ltq_writel(<q_ethsw_pmac_pdi_regs->hd_ctl, LTQ_ETHSW_PMAC_HD_CTL_FC | - /*LTQ_ETHSW_PMAC_HD_CTL_RC | */LTQ_ETHSW_PMAC_HD_CTL_AC); -} - -static int -ltq_vrx200_hw_init(struct net_device *dev) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - int err = 0; - int i; - - netdev_info(dev, "setting up dma\n"); - ltq_dma_init_port(DMA_PORT_ETOP); - - netdev_info(dev, "setting up pmu\n"); - clk_enable(priv->clk_ppe); - - /* Reset ethernet and switch subsystems */ - netdev_info(dev, "reset core\n"); - ltq_reset_once(BIT(8), 10); - - /* Enable switch macro */ - ltq_setbits(<q_ethsw_mdio_pdi_regs->glob_ctrl, - LTQ_ETHSW_GLOB_CTRL_SE); - - /* Disable MDIO auto-polling for all ports */ - dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdc_cfg_0, 0); - - /* - * Enable and set MDIO management clock to 2.5 MHz. This is the - * maximum clock for FE PHYs. - * Formula for clock is: - * - * 50 MHz - * x = ----------- - 1 - * 2 * f_MDC - */ - dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdc_cfg_1, - LTQ_ETHSW_MDC_CFG1_MCEN | 9); - - /* Init MAC connected to CPU */ - ltq_eth_pmac_init(); - - /* Init MACs connected to external MII interfaces */ - for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) - ltq_eth_gmac_init(i); - - for (i = 0; i < MAX_DMA_CHAN && !err; i++) { - int irq = LTQ_DMA_ETOP + i; - struct ltq_vrx200_chan *ch = &priv->ch[i]; - - ch->idx = ch->dma.nr = i; - - if (IS_TX(i)) { - ltq_dma_alloc_tx(&ch->dma); - err = request_irq(irq, ltq_vrx200_dma_irq, IRQF_DISABLED, - "vrx200_tx", priv); - } else if (IS_RX(i)) { - ltq_dma_alloc_rx(&ch->dma); - for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM; - ch->dma.desc++) - if (ltq_vrx200_alloc_skb(ch)) - err = -ENOMEM; - ch->dma.desc = 0; - err = request_irq(irq, ltq_vrx200_dma_irq, IRQF_DISABLED, - "vrx200_rx", priv); - } - if (!err) - ch->dma.irq = irq; - } - for (i = 0; i < board_config.num_ports; i++) - ltq_eth_port_config(priv, &board_config.ports[i]); - return err; -} - -static void -ltq_vrx200_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strcpy(info->driver, "Lantiq ETOP"); - strcpy(info->bus_info, "internal"); - strcpy(info->version, DRV_VERSION); -} - -static int -ltq_vrx200_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - - return phy_ethtool_gset(priv->phydev, cmd); -} - -static int -ltq_vrx200_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - - return phy_ethtool_sset(priv->phydev, cmd); -} - -static int -ltq_vrx200_nway_reset(struct net_device *dev) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - - return phy_start_aneg(priv->phydev); -} - -static const struct ethtool_ops ltq_vrx200_ethtool_ops = { - .get_drvinfo = ltq_vrx200_get_drvinfo, - .get_settings = ltq_vrx200_get_settings, - .set_settings = ltq_vrx200_set_settings, - .nway_reset = ltq_vrx200_nway_reset, -}; - -static inline int ltq_mdio_poll(struct mii_bus *bus) -{ - struct ltq_mdio_access acc; - unsigned cnt = 10000; - - while (likely(cnt--)) { - acc.val = ltq_r32(<q_ethsw_mdio_pdi_regs->mdio_ctrl); - if (!acc.bits.mbusy) - return 0; - } - - return 1; -} - -static int -ltq_vrx200_mdio_wr(struct mii_bus *bus, int addr, int regnum, u16 val) -{ - struct ltq_mdio_access acc; - int ret; - - acc.val = 0; - acc.bits.mbusy = LTQ_MDIO_MBUSY_BUSY; - acc.bits.op = LTQ_MDIO_OP_WRITE; - acc.bits.phyad = addr; - acc.bits.regad = regnum; - - ret = ltq_mdio_poll(bus); - if (ret) - return ret; - - dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdio_write, val); - dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdio_ctrl, acc.val); - - return 0; -} - -static int -ltq_vrx200_mdio_rd(struct mii_bus *bus, int addr, int regnum) -{ - struct ltq_mdio_access acc; - int ret; - - acc.val = 0; - acc.bits.mbusy = LTQ_MDIO_MBUSY_BUSY; - acc.bits.op = LTQ_MDIO_OP_READ; - acc.bits.phyad = addr; - acc.bits.regad = regnum; - - ret = ltq_mdio_poll(bus); - if (ret) - goto timeout; - - dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdio_ctrl, acc.val); - - ret = ltq_mdio_poll(bus); - if (ret) - goto timeout; - - ret = ltq_r32(<q_ethsw_mdio_pdi_regs->mdio_read); - - return ret; -timeout: - return -1; -} - -static void -ltq_vrx200_mdio_link(struct net_device *dev) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - ltq_eth_gmac_update(priv->phydev, 0); -} - -static int -ltq_vrx200_mdio_probe(struct net_device *dev) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - struct phy_device *phydev = NULL; - int val; - - phydev = priv->mii_bus->phy_map[0]; - - if (!phydev) { - netdev_err(dev, "no PHY found\n"); - return -ENODEV; - } - - phydev = phy_connect(dev, dev_name(&phydev->dev), <q_vrx200_mdio_link, - 0, 0); - - if (IS_ERR(phydev)) { - netdev_err(dev, "Could not attach to PHY\n"); - return PTR_ERR(phydev); - } - - phydev->supported &= (SUPPORTED_10baseT_Half - | SUPPORTED_10baseT_Full - | SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full - | SUPPORTED_1000baseT_Half - | SUPPORTED_1000baseT_Full - | SUPPORTED_Autoneg - | SUPPORTED_MII - | SUPPORTED_TP); - phydev->advertising = phydev->supported; - priv->phydev = phydev; - - pr_info("%s: attached PHY [%s] (phy_addr=%s, irq=%d)\n", - dev->name, phydev->drv->name, - dev_name(&phydev->dev), phydev->irq); - - val = ltq_vrx200_mdio_rd(priv->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000); - val |= ADVERTIZE_MPD; - ltq_vrx200_mdio_wr(priv->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000, val); - ltq_vrx200_mdio_wr(priv->mii_bus, 0, 0, 0x1040); - - phy_start_aneg(phydev); - - return 0; -} - -static int -ltq_vrx200_mdio_init(struct net_device *dev) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - int i; - int err; - - priv->mii_bus = mdiobus_alloc(); - if (!priv->mii_bus) { - netdev_err(dev, "failed to allocate mii bus\n"); - err = -ENOMEM; - goto err_out; - } - - priv->mii_bus->priv = dev; - priv->mii_bus->read = ltq_vrx200_mdio_rd; - priv->mii_bus->write = ltq_vrx200_mdio_wr; - priv->mii_bus->name = "ltq_mii"; - snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); - priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); - if (!priv->mii_bus->irq) { - err = -ENOMEM; - goto err_out_free_mdiobus; - } - - for (i = 0; i < PHY_MAX_ADDR; ++i) - priv->mii_bus->irq[i] = PHY_POLL; - - if (mdiobus_register(priv->mii_bus)) { - err = -ENXIO; - goto err_out_free_mdio_irq; - } - - if (ltq_vrx200_mdio_probe(dev)) { - err = -ENXIO; - goto err_out_unregister_bus; - } - return 0; - -err_out_unregister_bus: - mdiobus_unregister(priv->mii_bus); -err_out_free_mdio_irq: - kfree(priv->mii_bus->irq); -err_out_free_mdiobus: - mdiobus_free(priv->mii_bus); -err_out: - return err; -} - -static void -ltq_vrx200_mdio_cleanup(struct net_device *dev) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - - phy_disconnect(priv->phydev); - mdiobus_unregister(priv->mii_bus); - kfree(priv->mii_bus->irq); - mdiobus_free(priv->mii_bus); -} - -void phy_dump(struct net_device *dev) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - int i; - for (i = 0; i < 0x1F; i++) { - unsigned int val = ltq_vrx200_mdio_rd(priv->mii_bus, 0, i); - printk("%d %4X\n", i, val); - } -} - -static int -ltq_vrx200_open(struct net_device *dev) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - int i; - unsigned long flags; - - for (i = 0; i < MAX_DMA_CHAN; i++) { - struct ltq_vrx200_chan *ch = &priv->ch[i]; - - if (!IS_TX(i) && (!IS_RX(i))) - continue; - napi_enable(&ch->napi); - spin_lock_irqsave(&priv->lock, flags); - ltq_dma_open(&ch->dma); - spin_unlock_irqrestore(&priv->lock, flags); - } - if (priv->phydev) { - phy_start(priv->phydev); - phy_dump(dev); - } - netif_tx_start_all_queues(dev); - return 0; -} - -static int -ltq_vrx200_stop(struct net_device *dev) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - int i; - unsigned long flags; - - netif_tx_stop_all_queues(dev); - if (priv->phydev) - phy_stop(priv->phydev); - for (i = 0; i < MAX_DMA_CHAN; i++) { - struct ltq_vrx200_chan *ch = &priv->ch[i]; - - if (!IS_RX(i) && !IS_TX(i)) - continue; - napi_disable(&ch->napi); - spin_lock_irqsave(&priv->lock, flags); - ltq_dma_close(&ch->dma); - spin_unlock_irqrestore(&priv->lock, flags); - } - return 0; -} - -static int -ltq_vrx200_tx(struct sk_buff *skb, struct net_device *dev) -{ - int queue = skb_get_queue_mapping(skb); - struct netdev_queue *txq = netdev_get_tx_queue(dev, queue); - struct ltq_vrx200_priv *priv = netdev_priv(dev); - struct ltq_vrx200_chan *ch = &priv->ch[(queue << 1) | 1]; - struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; - unsigned long flags; - u32 byte_offset; - int len; - - len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; - - if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) { - netdev_err(dev, "tx ring full\n"); - netif_tx_stop_queue(txq); - return NETDEV_TX_BUSY; - } - - /* dma needs to start on a 16 byte aligned address */ - byte_offset = CPHYSADDR(skb->data) % 16; - ch->skb[ch->dma.desc] = skb; - - dev->trans_start = jiffies; - - spin_lock_irqsave(&priv->lock, flags); - desc->addr = ((unsigned int) dma_map_single(NULL, skb->data, len, - DMA_TO_DEVICE)) - byte_offset; - wmb(); - desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP | - LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK); - ch->dma.desc++; - ch->dma.desc %= LTQ_DESC_NUM; - spin_unlock_irqrestore(&priv->lock, flags); - - if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN) - netif_tx_stop_queue(txq); - - return NETDEV_TX_OK; -} - -static int -ltq_vrx200_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - - /* TODO: mii-toll reports "No MII transceiver present!." ?!*/ - return phy_mii_ioctl(priv->phydev, rq, cmd); -} - -static u16 -ltq_vrx200_select_queue(struct net_device *dev, struct sk_buff *skb) -{ - /* we are currently only using the first queue */ - return 0; -} - -static int -ltq_vrx200_init(struct net_device *dev) -{ - struct ltq_vrx200_priv *priv = netdev_priv(dev); - struct sockaddr mac; - int err; - - ether_setup(dev); - dev->watchdog_timeo = 10 * HZ; - - err = ltq_vrx200_hw_init(dev); - if (err) - goto err_hw; - - memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr)); - if (!is_valid_ether_addr(mac.sa_data)) { - pr_warn("vrx200: invalid MAC, using random\n"); - random_ether_addr(mac.sa_data); - } - eth_mac_addr(dev, &mac); - - if (!ltq_vrx200_mdio_init(dev)) - dev->ethtool_ops = <q_vrx200_ethtool_ops; - else - pr_warn("vrx200: mdio probe failed\n");; - return 0; - -err_hw: - ltq_vrx200_hw_exit(dev); - return err; -} - -static void -ltq_vrx200_tx_timeout(struct net_device *dev) -{ - int err; - - ltq_vrx200_hw_exit(dev); - err = ltq_vrx200_hw_init(dev); - if (err) - goto err_hw; - dev->trans_start = jiffies; - netif_wake_queue(dev); - return; - -err_hw: - ltq_vrx200_hw_exit(dev); - netdev_err(dev, "failed to restart vrx200 after TX timeout\n"); -} - -static const struct net_device_ops ltq_eth_netdev_ops = { - .ndo_open = ltq_vrx200_open, - .ndo_stop = ltq_vrx200_stop, - .ndo_start_xmit = ltq_vrx200_tx, - .ndo_change_mtu = eth_change_mtu, - .ndo_do_ioctl = ltq_vrx200_ioctl, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_select_queue = ltq_vrx200_select_queue, - .ndo_init = ltq_vrx200_init, - .ndo_tx_timeout = ltq_vrx200_tx_timeout, -}; - -static int __devinit -ltq_vrx200_probe(struct platform_device *pdev) -{ - struct net_device *dev; - struct ltq_vrx200_priv *priv; - struct resource *res; - int err; - int i; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get vrx200 resource\n"); - err = -ENOENT; - goto err_out; - } - - res = devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), dev_name(&pdev->dev)); - if (!res) { - dev_err(&pdev->dev, "failed to request vrx200 resource\n"); - err = -EBUSY; - goto err_out; - } - - ltq_vrx200_membase = devm_ioremap_nocache(&pdev->dev, - res->start, resource_size(res)); - if (!ltq_vrx200_membase) { - dev_err(&pdev->dev, "failed to remap vrx200 engine %d\n", - pdev->id); - err = -ENOMEM; - goto err_out; - } - - if (ltq_gpio_request(&pdev->dev, 42, 2, 1, "MDIO") || - ltq_gpio_request(&pdev->dev, 43, 2, 1, "MDC")) { - dev_err(&pdev->dev, "failed to request MDIO gpios\n"); - err = -EBUSY; - goto err_out; - } - - dev = alloc_etherdev_mq(sizeof(struct ltq_vrx200_priv), 4); - strcpy(dev->name, "eth%d"); - dev->netdev_ops = <q_eth_netdev_ops; - priv = netdev_priv(dev); - priv->res = res; - priv->pldata = dev_get_platdata(&pdev->dev); - priv->netdev = dev; - - priv->clk_ppe = clk_get(&pdev->dev, NULL); - if (IS_ERR(priv->clk_ppe)) - return PTR_ERR(priv->clk_ppe); - - spin_lock_init(&priv->lock); - - for (i = 0; i < MAX_DMA_CHAN; i++) { - if (IS_TX(i)) - netif_napi_add(dev, &priv->ch[i].napi, - ltq_vrx200_poll_tx, 8); - else if (IS_RX(i)) - netif_napi_add(dev, &priv->ch[i].napi, - ltq_vrx200_poll_rx, 32); - priv->ch[i].netdev = dev; - } - - err = register_netdev(dev); - if (err) - goto err_free; - - platform_set_drvdata(pdev, dev); - return 0; - -err_free: - kfree(dev); -err_out: - return err; -} - -static int __devexit -ltq_vrx200_remove(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - - if (dev) { - netif_tx_stop_all_queues(dev); - ltq_vrx200_hw_exit(dev); - ltq_vrx200_mdio_cleanup(dev); - unregister_netdev(dev); - } - return 0; -} - -static struct platform_driver ltq_mii_driver = { - .probe = ltq_vrx200_probe, - .remove = __devexit_p(ltq_vrx200_remove), - .driver = { - .name = "ltq_vrx200", - .owner = THIS_MODULE, - }, -}; - -module_platform_driver(ltq_mii_driver); - -MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); -MODULE_DESCRIPTION("Lantiq SoC ETOP"); -MODULE_LICENSE("GPL"); diff --git a/target/linux/lantiq/files/drivers/net/ethernet/svip_eth.c b/target/linux/lantiq/files/drivers/net/ethernet/svip_eth.c deleted file mode 100644 index 1e25795a2a..0000000000 --- a/target/linux/lantiq/files/drivers/net/ethernet/svip_eth.c +++ /dev/null @@ -1,636 +0,0 @@ -/************************************************************************ - * - * Copyright (c) 2005 - * Infineon Technologies AG - * St. Martin Strasse 53; 81669 Muenchen; Germany - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - ************************************************************************/ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/uaccess.h> -#include <linux/in.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ip.h> -#include <linux/tcp.h> -#include <linux/skbuff.h> -#include <linux/mm.h> -#include <linux/platform_device.h> -#include <linux/ethtool.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <asm/checksum.h> - -#if 1 /** TODO: MOVE TO APPROPRIATE PLACE */ - -#define ETHERNET_PACKET_DMA_BUFFER_SIZE 0x600 -#define REV_MII_MODE 2 - -#endif - -#define DRV_NAME "ifxmips_mii0" - -#include <lantiq_soc.h> -#include <svip_dma.h> - -#ifdef CONFIG_DEBUG_MINI_BOOT -#define IKOS_MINI_BOOT -#endif - -/* debugging */ -#undef INCAIP2_SW_DUMP - -#define INCAIP2_SW_EMSG(fmt,args...) printk("%s: " fmt, __FUNCTION__ , ##args) - -#define INCAIP2_SW_CHIP_NO 1 -#define INCAIP2_SW_CHIP_ID 0 -#define INCAIP2_SW_DEVICE_NO 1 - -#ifdef INCAIP2_SW_DEBUG_MSG -#define INCAIP2_SW_DMSG(fmt,args...) printk("%s: " fmt, __FUNCTION__ , ##args) -#else -#define INCAIP2_SW_DMSG(fmt,args...) -#endif - -/************************** Module Parameters *****************************/ -static char *mode = "bridge"; -module_param(mode, charp, 0000); -MODULE_PARM_DESC(mode, "<description>"); - -#ifdef HAVE_TX_TIMEOUT -static int timeout = 10*HZ; -module_param(timeout, int, 0); -MODULE_PARM_DESC(timeout, "Transmission watchdog timeout in seconds>"); -#endif - -#ifdef IKOS_MINI_BOOT -#ifdef CONFIG_INCAIP2 -extern s32 incaip2_sw_to_mbx(struct sk_buff* skb); -#endif -extern s32 svip_sw_to_mbx(struct sk_buff* skb); -#endif - -struct svip_mii_priv { - struct net_device_stats stats; - struct dma_device_info *dma_device; - struct sk_buff *skb; -}; - -static struct net_device *svip_mii0_dev; -static unsigned char mac_addr[MAX_ADDR_LEN]; -static unsigned char my_ethaddr[MAX_ADDR_LEN]; - -/** - * Initialize MAC address. - * This function copies the ethernet address from kernel command line. - * - * \param line Pointer to parameter - * \return 0 OK - * \ingroup Internal - */ -static int __init svip_eth_ethaddr_setup(char *line) -{ - char *ep; - int i; - - memset(my_ethaddr, 0, MAX_ADDR_LEN); - /* there should really be routines to do this stuff */ - for (i = 0; i < 6; i++) - { - my_ethaddr[i] = line ? simple_strtoul(line, &ep, 16) : 0; - if (line) - line = (*ep) ? ep+1 : ep; - } - INCAIP2_SW_DMSG("mac address %2x-%2x-%2x-%2x-%2x-%2x \n" - ,my_ethaddr[0] - ,my_ethaddr[1] - ,my_ethaddr[2] - ,my_ethaddr[3] - ,my_ethaddr[4] - ,my_ethaddr[5]); - return 0; -} -__setup("ethaddr=", svip_eth_ethaddr_setup); - - -/** - * Open RX DMA channels. - * This function opens all DMA rx channels. - * - * \param dma_dev pointer to DMA device information - * \ingroup Internal - */ -static void svip_eth_open_rx_dma(struct dma_device_info *dma_dev) -{ - int i; - - for(i=0; i<dma_dev->num_rx_chan; i++) - { - dma_dev->rx_chan[i]->open(dma_dev->rx_chan[i]); - } -} - - -/** - * Open TX DMA channels. - * This function opens all DMA tx channels. - * - * \param dev pointer to net device structure that comprises - * DMA device information pointed to by it's priv field. - * \ingroup Internal - */ -static void svip_eth_open_tx_dma(struct dma_device_info *dma_dev) -{ - int i; - - for (i=0; i<dma_dev->num_tx_chan; i++) - { - dma_dev->tx_chan[i]->open(dma_dev->tx_chan[i]); - } -} - - -#ifdef CONFIG_NET_HW_FLOWCONTROL -/** - * Enable receiving DMA. - * This function enables the receiving DMA channel. - * - * \param dev pointer to net device structure that comprises - * DMA device information pointed to by it's priv field. - * \ingroup Internal - */ -void svip_eth_xon(struct net_device *dev) -{ - struct switch_priv *sw_dev = (struct switch_priv *)dev->priv; - struct dma_device_info* dma_dev = - (struct dma_device_info *)sw_dev->dma_device; - unsigned long flag; - - local_irq_save(flag); - - INCAIP2_SW_DMSG("wakeup\n"); - svip_eth_open_rx_dma(dma_dev); - - local_irq_restore(flag); -} -#endif /* CONFIG_NET_HW_FLOWCONTROL */ - - -/** - * Open network device. - * This functions opens the network device and starts the interface queue. - * - * \param dev Device structure for Ethernet device - * \return 0 OK, device opened - * \return -1 Error, registering DMA device - * \ingroup API - */ -int svip_mii_open(struct net_device *dev) -{ - struct svip_mii_priv *priv = netdev_priv(dev); - struct dma_device_info *dma_dev = priv->dma_device; - - svip_eth_open_rx_dma(dma_dev); - svip_eth_open_tx_dma(dma_dev); - - netif_start_queue(dev); - return 0; -} - - -/** - * Close network device. - * This functions closes the network device, which will also stop the interface - * queue. - * - * \param dev Device structure for Ethernet device - * \return 0 OK, device closed (cannot fail) - * \ingroup API - */ -int svip_mii_release(struct net_device *dev) -{ - struct svip_mii_priv *priv = netdev_priv(dev); - struct dma_device_info *dma_dev = priv->dma_device; - int i; - - for (i = 0; i < dma_dev->max_rx_chan_num; i++) - dma_dev->rx_chan[i]->close(dma_dev->rx_chan[i]); - netif_stop_queue(dev); - return 0; -} - - -/** - * Read data from DMA device. - * This function reads data from the DMA device. The function is called by - * the switch/DMA pseudo interrupt handler dma_intr_handler on occurence of - * a DMA receive interrupt. - * - * \param dev Pointer to network device structure - * \param dma_dev Pointer to dma device structure - * \return OK In case of successful data reception from dma - * -EIO Incorrect opt pointer provided by device - * \ingroup Internal - */ -int svip_mii_hw_receive(struct net_device *dev, struct dma_device_info *dma_dev) -{ - struct svip_mii_priv *priv = netdev_priv(dev); - unsigned char *buf = NULL; - struct sk_buff *skb = NULL; - int len = 0; - - len = dma_device_read(dma_dev, &buf, (void **)&skb); - - if (len >= ETHERNET_PACKET_DMA_BUFFER_SIZE) { - printk(KERN_INFO DRV_NAME ": packet too large %d\n", len); - goto mii_hw_receive_err_exit; - } - - if (skb == NULL) { - printk(KERN_INFO DRV_NAME ": cannot restore pointer\n"); - goto mii_hw_receive_err_exit; - } - - if (len > (skb->end - skb->tail)) { - printk(KERN_INFO DRV_NAME ": BUG, len:%d end:%p tail:%p\n", - len, skb->end, skb->tail); - goto mii_hw_receive_err_exit; - } - - skb_put(skb, len); - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - - priv->stats.rx_packets++; - priv->stats.rx_bytes += len; - return 0; - -mii_hw_receive_err_exit: - if (len == 0) { - if (skb) - dev_kfree_skb_any(skb); - priv->stats.rx_errors++; - priv->stats.rx_dropped++; - return -EIO; - } else { - return len; - } -} - - -/** - * Write data to Ethernet switch. - * This function writes the data comprised in skb structure via DMA to the - * Ethernet Switch. It is installed as the switch driver's hard_start_xmit - * method. - * - * \param skb Pointer to socket buffer structure that contains the data - * to be sent - * \param dev Pointer to network device structure which is used for - * data transmission - * \return 1 Transmission error - * \return 0 OK, successful data transmission - * \ingroup API - */ -static int svip_mii_hw_tx(char *buf, int len, struct net_device *dev) -{ - int ret = 0; - struct svip_mii_priv *priv = netdev_priv(dev); - struct dma_device_info *dma_dev = priv->dma_device; - ret = dma_device_write(dma_dev, buf, len, priv->skb); - return ret; -} - -static int svip_mii_tx(struct sk_buff *skb, struct net_device *dev) -{ - int len; - char *data; - struct svip_mii_priv *priv = netdev_priv(dev); - struct dma_device_info *dma_dev = priv->dma_device; - - len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; - data = skb->data; - priv->skb = skb; - dev->trans_start = jiffies; - /* TODO: we got more than 1 dma channel, - so we should do something intelligent here to select one */ - dma_dev->current_tx_chan = 0; - - wmb(); - - if (svip_mii_hw_tx(data, len, dev) != len) { - dev_kfree_skb_any(skb); - priv->stats.tx_errors++; - priv->stats.tx_dropped++; - } else { - priv->stats.tx_packets++; - priv->stats.tx_bytes += len; - } - - return 0; -} - - -/** - * Transmission timeout callback. - * This functions is called when a trasmission timeout occurs. It will wake up - * the interface queue again. - * - * \param dev Device structure for Ethernet device - * \ingroup API - */ -void svip_mii_tx_timeout(struct net_device *dev) -{ - int i; - struct svip_mii_priv *priv = netdev_priv(dev); - - priv->stats.tx_errors++; - for (i = 0; i < priv->dma_device->max_tx_chan_num; i++) - priv->dma_device->tx_chan[i]->disable_irq(priv->dma_device->tx_chan[i]); - netif_wake_queue(dev); - return; -} - - -/** - * Get device statistics. - * This functions returns the device statistics, stored in the device structure. - * - * \param dev Device structure for Ethernet device - * \return stats Pointer to statistics structure - * \ingroup API - */ -static struct net_device_stats *svip_get_stats(struct net_device *dev) -{ - struct svip_mii_priv *priv = netdev_priv(dev); - return &priv->stats; -} - - -/** - * Pseudo Interrupt handler for DMA. - * This function processes DMA interrupts notified to the switch device driver. - * The function is installed at the DMA core as interrupt handler for the - * switch dma device. - * It handles the following DMA interrupts: - * passes received data to the upper layer in case of rx interrupt, - * In case of a dma receive interrupt the received data is passed to the upper layer. - * In case of a transmit buffer full interrupt the transmit queue is stopped. - * In case of a transmission complete interrupt the transmit queue is restarted. - * - * \param dma_dev pointer to dma device structure - * \param status type of interrupt being notified (RCV_INT: dma receive - * interrupt, TX_BUF_FULL_INT: transmit buffer full interrupt, - * TRANSMIT_CPT_INT: transmission complete interrupt) - * \return OK In case of successful data reception from dma - * \ingroup Internal - */ -int dma_intr_handler(struct dma_device_info *dma_dev, int status) -{ - int i; - - switch (status) { - case RCV_INT: - svip_mii_hw_receive(svip_mii0_dev, dma_dev); - break; - - case TX_BUF_FULL_INT: - printk(KERN_INFO DRV_NAME ": tx buffer full\n"); - netif_stop_queue(svip_mii0_dev); - for (i = 0; i < dma_dev->max_tx_chan_num; i++) { - if ((dma_dev->tx_chan[i])->control == LTQ_DMA_CH_ON) - dma_dev->tx_chan[i]->enable_irq(dma_dev->tx_chan[i]); - } - break; - - case TRANSMIT_CPT_INT: - -#if 0 - for (i = 0; i < dma_dev->max_tx_chan_num; i++) -#if 0 - dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i]); -#else - dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i], (char *)__FUNCTION__); -#endif - netif_wake_queue(svip_mii0_dev); -#endif - break; - } - - return 0; -} - - -/** - * Allocates buffer sufficient for Ethernet Frame. - * This function is installed as DMA callback function to be called on DMA - * receive interrupt. - * - * \param len Unused - * \param *byte_offset Pointer to byte offset - * \param **opt pointer to skb structure - * \return NULL In case of buffer allocation fails - * buffer Pointer to allocated memory - * \ingroup Internal - */ -unsigned char *svip_etop_dma_buffer_alloc(int len, int *byte_offset, void **opt) -{ - unsigned char *buffer = NULL; - struct sk_buff *skb = NULL; - - skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE); - if (skb == NULL) - return NULL; - - buffer = (unsigned char *)(skb->data); - skb_reserve(skb, 2); - *(int *)opt = (int)skb; - *byte_offset = 2; - - return buffer; -} - - -/** - * Free DMA buffer. - * This function frees a buffer, which can be either a data buffer or an - * skb structure. - * - * \param *dataptr Pointer to data buffer - * \param *opt Pointer to skb structure - * \return 0 OK - * \ingroup Internal - */ -void svip_etop_dma_buffer_free(unsigned char *dataptr, void *opt) -{ - struct sk_buff *skb = NULL; - - if (opt == NULL) { - kfree(dataptr); - } else { - skb = (struct sk_buff *)opt; - dev_kfree_skb_any(skb); - } -} - -static int svip_mii_dev_init(struct net_device *dev); - -static const struct net_device_ops svip_eth_netdev_ops = { - .ndo_init = svip_mii_dev_init, - .ndo_open = svip_mii_open, - .ndo_stop = svip_mii_release, - .ndo_start_xmit = svip_mii_tx, - .ndo_get_stats = svip_get_stats, - .ndo_tx_timeout = svip_mii_tx_timeout, -}; - -//#include <linux/device.h> - -/** - * Initialize switch driver. - * This functions initializes the switch driver structures and registers the - * Ethernet device. - * - * \param dev Device structure for Ethernet device - * \return 0 OK - * \return ENOMEM No memory for structures available - * \return -1 Error during DMA init or Ethernet address configuration. - * \ingroup API - */ -static int svip_mii_dev_init(struct net_device *dev) -{ - int i; - struct svip_mii_priv *priv = netdev_priv(dev); - - - ether_setup(dev); - printk(KERN_INFO DRV_NAME ": %s is up\n", dev->name); - dev->watchdog_timeo = 10 * HZ; - memset(priv, 0, sizeof(*priv)); - priv->dma_device = dma_device_reserve("SW"); - if (!priv->dma_device) { - BUG(); - return -ENODEV; - } - priv->dma_device->buffer_alloc = svip_etop_dma_buffer_alloc; - priv->dma_device->buffer_free = svip_etop_dma_buffer_free; - priv->dma_device->intr_handler = dma_intr_handler; - - for (i = 0; i < priv->dma_device->max_rx_chan_num; i++) - priv->dma_device->rx_chan[i]->packet_size = - ETHERNET_PACKET_DMA_BUFFER_SIZE; - - for (i = 0; i < priv->dma_device->max_tx_chan_num; i++) { - priv->dma_device->tx_chan[i]->tx_weight=DEFAULT_SW_CHANNEL_WEIGHT; - priv->dma_device->tx_chan[i]->packet_size = - ETHERNET_PACKET_DMA_BUFFER_SIZE; - } - - dma_device_register(priv->dma_device); - - printk(KERN_INFO DRV_NAME ": using mac="); - - for (i = 0; i < 6; i++) { - dev->dev_addr[i] = mac_addr[i]; - printk("%02X%c", dev->dev_addr[i], (i == 5) ? ('\n') : (':')); - } - - return 0; -} - -static void svip_mii_chip_init(int mode) -{ -} - -static int svip_mii_probe(struct platform_device *dev) -{ - int result = 0; - unsigned char *mac = (unsigned char *)dev->dev.platform_data; - svip_mii0_dev = alloc_etherdev(sizeof(struct svip_mii_priv)); - svip_mii0_dev->netdev_ops = &svip_eth_netdev_ops; - memcpy(mac_addr, mac, 6); - strcpy(svip_mii0_dev->name, "eth%d"); - svip_mii_chip_init(REV_MII_MODE); - result = register_netdev(svip_mii0_dev); - if (result) { - printk(KERN_INFO DRV_NAME - ": error %i registering device \"%s\"\n", - result, svip_mii0_dev->name); - goto out; - } - printk(KERN_INFO DRV_NAME ": driver loaded!\n"); - -out: - return result; -} - -static int svip_mii_remove(struct platform_device *dev) -{ - struct svip_mii_priv *priv = netdev_priv(svip_mii0_dev); - - printk(KERN_INFO DRV_NAME ": cleanup\n"); - - dma_device_unregister(priv->dma_device); - dma_device_release(priv->dma_device); - kfree(priv->dma_device); - unregister_netdev(svip_mii0_dev); - free_netdev(svip_mii0_dev); - return 0; -} - - -static struct platform_driver svip_mii_driver = { - .probe = svip_mii_probe, - .remove = svip_mii_remove, - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - }, -}; - - -/** - * Initialize switch driver as module. - * This functions initializes the switch driver structures and registers the - * Ethernet device for module usage. - * - * \return 0 OK - * \return ENODEV An error occured during initialization - * \ingroup API - */ -int __init svip_mii_init(void) -{ - int ret = platform_driver_register(&svip_mii_driver); - if (ret) - printk(KERN_INFO DRV_NAME - ": Error registering platfom driver!\n"); - return ret; -} - - -/** - * Remove driver module. - * This functions removes the driver and unregisters all devices. - * - * \ingroup API - */ -static void __exit svip_mii_cleanup(void) -{ - platform_driver_unregister(&svip_mii_driver); -} - -module_init(svip_mii_init); -module_exit(svip_mii_cleanup); - -MODULE_LICENSE("GPL"); diff --git a/target/linux/lantiq/files/drivers/net/ethernet/svip_virtual_eth.c b/target/linux/lantiq/files/drivers/net/ethernet/svip_virtual_eth.c deleted file mode 100644 index 6de0cfab8b..0000000000 --- a/target/linux/lantiq/files/drivers/net/ethernet/svip_virtual_eth.c +++ /dev/null @@ -1,346 +0,0 @@ -/****************************************************************************** - - Copyright (c) 2007 - Infineon Technologies AG - Am Campeon 1-12; 81726 Munich, Germany - - THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE, - WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS - SOFTWARE IS FREE OF CHARGE. - - THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS - ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING - WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP, - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE - OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD - PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL - PROPERTY INFRINGEMENT. - - EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT - FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM - OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - **************************************************************************** -Module : svip_virtual_eth.c - -Description : This file contains network driver implementation for a -Virtual Ethernet interface. The Virtual Ethernet interface -is part of Infineon's VINETIC-SVIP Linux BSP. - *******************************************************************************/ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/netdevice.h> -#include <linux/platform_device.h> -#include <linux/etherdevice.h> -#include <linux/init.h> - -#define SVIP_VETH_VER_STR "3.0" -#define SVIP_VETH_INFO_STR \ - "@(#)SVIP virtual ethernet interface, version " SVIP_VETH_VER_STR - -/****************************************************************************** - * Local define/macro definitions - ******************************************************************************/ -struct svip_ve_priv -{ - struct net_device_stats stats; -}; - -/****************************************************************************** - * Global function declarations - ******************************************************************************/ -int svip_ve_rx(struct sk_buff *skb); - -/****************************************************************************** - * Local variable declarations - ******************************************************************************/ -static struct net_device *svip_ve_dev; -static int watchdog_timeout = 10*HZ; -static int (*svip_ve_mps_xmit)(struct sk_buff *skb) = NULL; - - -/****************************************************************************** - * Global function declarations - ******************************************************************************/ - -/** - * Called by MPS driver to register a transmit routine called for each outgoing - * VoFW0 message. - * - * \param mps_xmit pointer to transmit routine - * - * \return none - * - * \ingroup Internal - */ -void register_mps_xmit_routine(int (*mps_xmit)(struct sk_buff *skb)) -{ - svip_ve_mps_xmit = mps_xmit; -} -EXPORT_SYMBOL(register_mps_xmit_routine); - -/** - * Returns a pointer to the routine used to deliver an incoming packet/message - * from the MPS mailbox to the networking layer. This routine is called by MPS - * driver during initialisation time. - * - * \param skb pointer to incoming socket buffer - * - * \return svip_ve_rx pointer to incoming messages delivering routine - * - * \ingroup Internal - */ -int (*register_mps_recv_routine(void)) (struct sk_buff *skb) -{ - return svip_ve_rx; -} - -/** - * Used to deliver outgoing packets to VoFW0 module through the MPS driver. - * Upon loading/initialisation the MPS driver is registering a transmitting - * routine, which is called here to deliver the packet to the VoFW0 module. - * - * \param skb pointer to skb containing outgoing data - * \param dev pointer to this networking device's data - * - * \return 0 on success - * \return non-zero on error - * - * \ingroup Internal - */ -static int svip_ve_xmit(struct sk_buff *skb, struct net_device *dev) -{ - int err; - struct svip_ve_priv *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - - stats->tx_packets++; - stats->tx_bytes += skb->len; - - if (svip_ve_mps_xmit) - { - err = svip_ve_mps_xmit(skb); - if (err) - stats->tx_errors++; - dev->trans_start = jiffies; - return err; - } - else - printk(KERN_ERR "%s: MPS driver not registered, outgoing packet not delivered\n", dev->name); - - dev_kfree_skb(skb); - - return -1; -} - -/** - * Called by MPS driver upon receipt of a new message from VoFW0 module in - * the data inbox. The packet is pushed up the IP module for further processing. - * - * \param skb pointer to skb containing the incoming message - * - * \return 0 on success - * \return non-zero on error - * - * \ingroup Internal - */ -int svip_ve_rx(struct sk_buff *skb) -{ - int err; - struct svip_ve_priv *priv = netdev_priv(svip_ve_dev); - struct net_device_stats *stats = &priv->stats; - - skb->dev = svip_ve_dev; - skb->protocol = eth_type_trans(skb, svip_ve_dev); - - stats->rx_packets++; - stats->rx_bytes += skb->len; - - err = netif_rx(skb); - switch (err) - { - case NET_RX_SUCCESS: - return 0; - break; - case NET_RX_DROP: - default: - stats->rx_dropped++; - break; - } - - return 1; -} -EXPORT_SYMBOL(svip_ve_rx); - -/** - * Returns a pointer to the device's networking statistics data - * - * \param dev pointer to this networking device's data - * - * \return stats pointer to this network device's statistics data - * - * \ingroup Internal - */ -static struct net_device_stats *svip_ve_get_stats(struct net_device *dev) -{ - struct svip_ve_priv *priv = netdev_priv(dev); - - return &priv->stats; -} - -static void svip_ve_tx_timeout(struct net_device *dev) -{ - struct svip_ve_priv *priv = netdev_priv(dev); - - priv->stats.tx_errors++; - netif_wake_queue(dev); -} - -/** - * Device open routine. Called e.g. upon setting of an IP address using, - * 'ifconfig veth0 YYY.YYY.YYY.YYY netmask ZZZ.ZZZ.ZZZ.ZZZ' or - * 'ifconfig veth0 up' - * - * \param dev pointer to this network device's data - * - * \return 0 on success - * \return non-zero on error - * - * \ingroup Internal - */ -int svip_ve_open(struct net_device *dev) -{ - netif_start_queue(dev); - return 0; -} - -/** - * Device close routine. Called e.g. upon calling - * 'ifconfig veth0 down' - * - * \param dev pointer to this network device's data - * - * \return 0 on success - * \return non-zero on error - * - * \ingroup Internal - */ - -int svip_ve_release(struct net_device *dev) -{ - netif_stop_queue(dev); - return 0; -} - -static int svip_ve_dev_init(struct net_device *dev); - -static const struct net_device_ops svip_virtual_eth_netdev_ops = { - .ndo_init = svip_ve_dev_init, - .ndo_open = svip_ve_open, - .ndo_stop = svip_ve_release, - .ndo_start_xmit = svip_ve_xmit, - .ndo_get_stats = svip_ve_get_stats, - .ndo_tx_timeout = svip_ve_tx_timeout, -}; - - -/** - * Device initialisation routine which registers device interface routines. - * It is called upon execution of 'register_netdev' routine. - * - * \param dev pointer to this network device's data - * - * \return 0 on success - * \return non-zero on error - * - * \ingroup Internal - */ -static int svip_ve_dev_init(struct net_device *dev) -{ - ether_setup(dev); /* assign some of the fields */ - - dev->watchdog_timeo = watchdog_timeout; - memset(netdev_priv(dev), 0, sizeof(struct svip_ve_priv)); - dev->flags |= IFF_NOARP|IFF_PROMISC; - dev->flags &= ~IFF_MULTICAST; - - /* dedicated MAC address to veth0, 00:03:19:00:15:80 */ - dev->dev_addr[0] = 0x00; - dev->dev_addr[1] = 0x03; - dev->dev_addr[2] = 0x19; - dev->dev_addr[3] = 0x00; - dev->dev_addr[4] = 0x15; - dev->dev_addr[5] = 0x80; - - return 0; -} - -static int svip_ve_probe(struct platform_device *dev) -{ - int result = 0; - - svip_ve_dev = alloc_etherdev(sizeof(struct svip_ve_priv)); - svip_ve_dev->netdev_ops = &svip_virtual_eth_netdev_ops; - - strcpy(svip_ve_dev->name, "veth%d"); - - result = register_netdev(svip_ve_dev); - if (result) - { - printk(KERN_INFO "error %i registering device \"%s\"\n", result, svip_ve_dev->name); - goto out; - } - - printk (KERN_INFO "%s, (c) 2009, Lantiq Deutschland GmbH\n", &SVIP_VETH_INFO_STR[4]); - -out: - return result; -} - -static int svip_ve_remove(struct platform_device *dev) -{ - unregister_netdev(svip_ve_dev); - free_netdev(svip_ve_dev); - - printk(KERN_INFO "%s removed\n", svip_ve_dev->name); - return 0; -} - -static struct platform_driver svip_ve_driver = { - .probe = svip_ve_probe, - .remove = svip_ve_remove, - .driver = { - .name = "ifxmips_svip_ve", - .owner = THIS_MODULE, - }, -}; - -/** - * Module/driver entry routine - */ -static int __init svip_ve_init_module(void) -{ - int ret; - - ret = platform_driver_register(&svip_ve_driver); - if (ret) - printk(KERN_INFO "SVIP: error(%d) registering virtual Ethernet driver!\n", ret); - return ret; -} - -/** - * Module exit routine (never called for statically linked driver) - */ -static void __exit svip_ve_cleanup_module(void) -{ - platform_driver_unregister(&svip_ve_driver); -} - -module_init(svip_ve_init_module); -module_exit(svip_ve_cleanup_module); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("virtual ethernet driver for LANTIQ SVIP system"); - -EXPORT_SYMBOL(register_mps_recv_routine); |