1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-12-01 14:21:54 +02:00
openwrt-xburst/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h
nbd 5cc1f4bcf3 ar71xx: add a new driver for the ar7240 switch using swconfig.
hooks directly into the ethernet driver, as MAC resets also require switch reinitializations and the switch is part of the cpu core anyway
switch only tl-wr741nd (and other devices using this board file, such as tl-wr841nd) over to using this by default, as other devices are still untested
fixes #7563

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@22675 3c298f89-4303-0410-b956-a3cf2f4a3e73
2010-08-16 19:21:57 +00:00

507 lines
14 KiB
C

/*
* Atheros AR71xx built-in ethernet mac driver
*
* Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
*
* Based on Atheros' AG7100 driver
*
* 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.
*/
#ifndef __AG71XX_H
#define __AG71XX_H
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/random.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
#include <linux/phy.h>
#include <linux/skbuff.h>
#include <linux/dma-mapping.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>
#include <asm/mach-ar71xx/ar71xx.h>
#include <asm/mach-ar71xx/platform.h>
#define ETH_FCS_LEN 4
#define AG71XX_DRV_NAME "ag71xx"
#define AG71XX_DRV_VERSION "0.5.35"
#define AG71XX_NAPI_WEIGHT 64
#define AG71XX_OOM_REFILL (1 + HZ/10)
#define AG71XX_INT_ERR (AG71XX_INT_RX_BE | AG71XX_INT_TX_BE)
#define AG71XX_INT_TX (AG71XX_INT_TX_PS)
#define AG71XX_INT_RX (AG71XX_INT_RX_PR | AG71XX_INT_RX_OF)
#define AG71XX_INT_POLL (AG71XX_INT_RX | AG71XX_INT_TX)
#define AG71XX_INT_INIT (AG71XX_INT_ERR | AG71XX_INT_POLL)
#define AG71XX_TX_FIFO_LEN 2048
#define AG71XX_TX_MTU_LEN 1540
#define AG71XX_RX_PKT_RESERVE 64
#define AG71XX_RX_PKT_SIZE \
(AG71XX_RX_PKT_RESERVE + ETH_HLEN + ETH_FRAME_LEN + ETH_FCS_LEN)
#define AG71XX_TX_RING_SIZE 64
#define AG71XX_TX_THRES_STOP (AG71XX_TX_RING_SIZE - 4)
#define AG71XX_TX_THRES_WAKEUP \
(AG71XX_TX_RING_SIZE - (AG71XX_TX_RING_SIZE / 4))
#define AG71XX_RX_RING_SIZE 128
#ifdef CONFIG_AG71XX_DEBUG
#define DBG(fmt, args...) printk(KERN_DEBUG fmt, ## args)
#else
#define DBG(fmt, args...) do {} while (0)
#endif
#define ag71xx_assert(_cond) \
do { \
if (_cond) \
break; \
printk("%s,%d: assertion failed\n", __FILE__, __LINE__); \
BUG(); \
} while (0)
struct ag71xx_desc {
u32 data;
u32 ctrl;
#define DESC_EMPTY BIT(31)
#define DESC_MORE BIT(24)
#define DESC_PKTLEN_M 0xfff
u32 next;
u32 pad;
} __attribute__((aligned(4)));
struct ag71xx_buf {
struct sk_buff *skb;
struct ag71xx_desc *desc;
dma_addr_t dma_addr;
u32 pad;
};
struct ag71xx_ring {
struct ag71xx_buf *buf;
u8 *descs_cpu;
dma_addr_t descs_dma;
unsigned int desc_size;
unsigned int curr;
unsigned int dirty;
unsigned int size;
};
struct ag71xx_mdio {
struct mii_bus *mii_bus;
int mii_irq[PHY_MAX_ADDR];
void __iomem *mdio_base;
struct ag71xx_mdio_platform_data *pdata;
};
struct ag71xx_int_stats {
unsigned long rx_pr;
unsigned long rx_be;
unsigned long rx_of;
unsigned long tx_ps;
unsigned long tx_be;
unsigned long tx_ur;
unsigned long total;
};
struct ag71xx_napi_stats {
unsigned long napi_calls;
unsigned long rx_count;
unsigned long rx_packets;
unsigned long rx_packets_max;
unsigned long tx_count;
unsigned long tx_packets;
unsigned long tx_packets_max;
unsigned long rx[AG71XX_NAPI_WEIGHT + 1];
unsigned long tx[AG71XX_NAPI_WEIGHT + 1];
};
struct ag71xx_debug {
struct dentry *debugfs_dir;
struct dentry *debugfs_int_stats;
struct dentry *debugfs_napi_stats;
struct ag71xx_int_stats int_stats;
struct ag71xx_napi_stats napi_stats;
};
struct ag71xx {
void __iomem *mac_base;
void __iomem *mii_ctrl;
spinlock_t lock;
struct platform_device *pdev;
struct net_device *dev;
struct napi_struct napi;
u32 msg_enable;
struct ag71xx_ring rx_ring;
struct ag71xx_ring tx_ring;
struct mii_bus *mii_bus;
struct phy_device *phy_dev;
void *phy_priv;
unsigned int link;
unsigned int speed;
int duplex;
struct work_struct restart_work;
struct timer_list oom_timer;
#ifdef CONFIG_AG71XX_DEBUG_FS
struct ag71xx_debug debug;
#endif
};
extern struct ethtool_ops ag71xx_ethtool_ops;
void ag71xx_link_adjust(struct ag71xx *ag);
int ag71xx_mdio_driver_init(void) __init;
void ag71xx_mdio_driver_exit(void);
int ag71xx_phy_connect(struct ag71xx *ag);
void ag71xx_phy_disconnect(struct ag71xx *ag);
void ag71xx_phy_start(struct ag71xx *ag);
void ag71xx_phy_stop(struct ag71xx *ag);
static inline struct ag71xx_platform_data *ag71xx_get_pdata(struct ag71xx *ag)
{
return ag->pdev->dev.platform_data;
}
static inline int ag71xx_desc_empty(struct ag71xx_desc *desc)
{
return ((desc->ctrl & DESC_EMPTY) != 0);
}
static inline int ag71xx_desc_pktlen(struct ag71xx_desc *desc)
{
return (desc->ctrl & DESC_PKTLEN_M);
}
/* Register offsets */
#define AG71XX_REG_MAC_CFG1 0x0000
#define AG71XX_REG_MAC_CFG2 0x0004
#define AG71XX_REG_MAC_IPG 0x0008
#define AG71XX_REG_MAC_HDX 0x000c
#define AG71XX_REG_MAC_MFL 0x0010
#define AG71XX_REG_MII_CFG 0x0020
#define AG71XX_REG_MII_CMD 0x0024
#define AG71XX_REG_MII_ADDR 0x0028
#define AG71XX_REG_MII_CTRL 0x002c
#define AG71XX_REG_MII_STATUS 0x0030
#define AG71XX_REG_MII_IND 0x0034
#define AG71XX_REG_MAC_IFCTL 0x0038
#define AG71XX_REG_MAC_ADDR1 0x0040
#define AG71XX_REG_MAC_ADDR2 0x0044
#define AG71XX_REG_FIFO_CFG0 0x0048
#define AG71XX_REG_FIFO_CFG1 0x004c
#define AG71XX_REG_FIFO_CFG2 0x0050
#define AG71XX_REG_FIFO_CFG3 0x0054
#define AG71XX_REG_FIFO_CFG4 0x0058
#define AG71XX_REG_FIFO_CFG5 0x005c
#define AG71XX_REG_FIFO_RAM0 0x0060
#define AG71XX_REG_FIFO_RAM1 0x0064
#define AG71XX_REG_FIFO_RAM2 0x0068
#define AG71XX_REG_FIFO_RAM3 0x006c
#define AG71XX_REG_FIFO_RAM4 0x0070
#define AG71XX_REG_FIFO_RAM5 0x0074
#define AG71XX_REG_FIFO_RAM6 0x0078
#define AG71XX_REG_FIFO_RAM7 0x007c
#define AG71XX_REG_TX_CTRL 0x0180
#define AG71XX_REG_TX_DESC 0x0184
#define AG71XX_REG_TX_STATUS 0x0188
#define AG71XX_REG_RX_CTRL 0x018c
#define AG71XX_REG_RX_DESC 0x0190
#define AG71XX_REG_RX_STATUS 0x0194
#define AG71XX_REG_INT_ENABLE 0x0198
#define AG71XX_REG_INT_STATUS 0x019c
#define MAC_CFG1_TXE BIT(0) /* Tx Enable */
#define MAC_CFG1_STX BIT(1) /* Synchronize Tx Enable */
#define MAC_CFG1_RXE BIT(2) /* Rx Enable */
#define MAC_CFG1_SRX BIT(3) /* Synchronize Rx Enable */
#define MAC_CFG1_TFC BIT(4) /* Tx Flow Control Enable */
#define MAC_CFG1_RFC BIT(5) /* Rx Flow Control Enable */
#define MAC_CFG1_LB BIT(8) /* Loopback mode */
#define MAC_CFG1_SR BIT(31) /* Soft Reset */
#define MAC_CFG2_FDX BIT(0)
#define MAC_CFG2_CRC_EN BIT(1)
#define MAC_CFG2_PAD_CRC_EN BIT(2)
#define MAC_CFG2_LEN_CHECK BIT(4)
#define MAC_CFG2_HUGE_FRAME_EN BIT(5)
#define MAC_CFG2_IF_1000 BIT(9)
#define MAC_CFG2_IF_10_100 BIT(8)
#define FIFO_CFG0_WTM BIT(0) /* Watermark Module */
#define FIFO_CFG0_RXS BIT(1) /* Rx System Module */
#define FIFO_CFG0_RXF BIT(2) /* Rx Fabric Module */
#define FIFO_CFG0_TXS BIT(3) /* Tx System Module */
#define FIFO_CFG0_TXF BIT(4) /* Tx Fabric Module */
#define FIFO_CFG0_ALL (FIFO_CFG0_WTM | FIFO_CFG0_RXS | FIFO_CFG0_RXF \
| FIFO_CFG0_TXS | FIFO_CFG0_TXF)
#define FIFO_CFG0_ENABLE_SHIFT 8
#define FIFO_CFG4_DE BIT(0) /* Drop Event */
#define FIFO_CFG4_DV BIT(1) /* RX_DV Event */
#define FIFO_CFG4_FC BIT(2) /* False Carrier */
#define FIFO_CFG4_CE BIT(3) /* Code Error */
#define FIFO_CFG4_CR BIT(4) /* CRC error */
#define FIFO_CFG4_LM BIT(5) /* Length Mismatch */
#define FIFO_CFG4_LO BIT(6) /* Length out of range */
#define FIFO_CFG4_OK BIT(7) /* Packet is OK */
#define FIFO_CFG4_MC BIT(8) /* Multicast Packet */
#define FIFO_CFG4_BC BIT(9) /* Broadcast Packet */
#define FIFO_CFG4_DR BIT(10) /* Dribble */
#define FIFO_CFG4_LE BIT(11) /* Long Event */
#define FIFO_CFG4_CF BIT(12) /* Control Frame */
#define FIFO_CFG4_PF BIT(13) /* Pause Frame */
#define FIFO_CFG4_UO BIT(14) /* Unsupported Opcode */
#define FIFO_CFG4_VT BIT(15) /* VLAN tag detected */
#define FIFO_CFG4_FT BIT(16) /* Frame Truncated */
#define FIFO_CFG4_UC BIT(17) /* Unicast Packet */
#define FIFO_CFG5_DE BIT(0) /* Drop Event */
#define FIFO_CFG5_DV BIT(1) /* RX_DV Event */
#define FIFO_CFG5_FC BIT(2) /* False Carrier */
#define FIFO_CFG5_CE BIT(3) /* Code Error */
#define FIFO_CFG5_LM BIT(4) /* Length Mismatch */
#define FIFO_CFG5_LO BIT(5) /* Length Out of Range */
#define FIFO_CFG5_OK BIT(6) /* Packet is OK */
#define FIFO_CFG5_MC BIT(7) /* Multicast Packet */
#define FIFO_CFG5_BC BIT(8) /* Broadcast Packet */
#define FIFO_CFG5_DR BIT(9) /* Dribble */
#define FIFO_CFG5_CF BIT(10) /* Control Frame */
#define FIFO_CFG5_PF BIT(11) /* Pause Frame */
#define FIFO_CFG5_UO BIT(12) /* Unsupported Opcode */
#define FIFO_CFG5_VT BIT(13) /* VLAN tag detected */
#define FIFO_CFG5_LE BIT(14) /* Long Event */
#define FIFO_CFG5_FT BIT(15) /* Frame Truncated */
#define FIFO_CFG5_16 BIT(16) /* unknown */
#define FIFO_CFG5_17 BIT(17) /* unknown */
#define FIFO_CFG5_SF BIT(18) /* Short Frame */
#define FIFO_CFG5_BM BIT(19) /* Byte Mode */
#define AG71XX_INT_TX_PS BIT(0)
#define AG71XX_INT_TX_UR BIT(1)
#define AG71XX_INT_TX_BE BIT(3)
#define AG71XX_INT_RX_PR BIT(4)
#define AG71XX_INT_RX_OF BIT(6)
#define AG71XX_INT_RX_BE BIT(7)
#define MAC_IFCTL_SPEED BIT(16)
#define MII_CFG_CLK_DIV_4 0
#define MII_CFG_CLK_DIV_6 2
#define MII_CFG_CLK_DIV_8 3
#define MII_CFG_CLK_DIV_10 4
#define MII_CFG_CLK_DIV_14 5
#define MII_CFG_CLK_DIV_20 6
#define MII_CFG_CLK_DIV_28 7
#define MII_CFG_RESET BIT(31)
#define MII_CMD_WRITE 0x0
#define MII_CMD_READ 0x1
#define MII_ADDR_SHIFT 8
#define MII_IND_BUSY BIT(0)
#define MII_IND_INVALID BIT(2)
#define TX_CTRL_TXE BIT(0) /* Tx Enable */
#define TX_STATUS_PS BIT(0) /* Packet Sent */
#define TX_STATUS_UR BIT(1) /* Tx Underrun */
#define TX_STATUS_BE BIT(3) /* Bus Error */
#define RX_CTRL_RXE BIT(0) /* Rx Enable */
#define RX_STATUS_PR BIT(0) /* Packet Received */
#define RX_STATUS_OF BIT(2) /* Rx Overflow */
#define RX_STATUS_BE BIT(3) /* Bus Error */
#define MII_CTRL_IF_MASK 3
#define MII_CTRL_SPEED_SHIFT 4
#define MII_CTRL_SPEED_MASK 3
#define MII_CTRL_SPEED_10 0
#define MII_CTRL_SPEED_100 1
#define MII_CTRL_SPEED_1000 2
static inline void ag71xx_check_reg_offset(struct ag71xx *ag, unsigned reg)
{
switch (reg) {
case AG71XX_REG_MAC_CFG1 ... AG71XX_REG_MAC_MFL:
case AG71XX_REG_MAC_IFCTL ... AG71XX_REG_INT_STATUS:
break;
default:
BUG();
}
}
static inline void ag71xx_wr(struct ag71xx *ag, unsigned reg, u32 value)
{
ag71xx_check_reg_offset(ag, reg);
__raw_writel(value, ag->mac_base + reg);
/* flush write */
(void) __raw_readl(ag->mac_base + reg);
}
static inline u32 ag71xx_rr(struct ag71xx *ag, unsigned reg)
{
ag71xx_check_reg_offset(ag, reg);
return __raw_readl(ag->mac_base + reg);
}
static inline void ag71xx_sb(struct ag71xx *ag, unsigned reg, u32 mask)
{
void __iomem *r;
ag71xx_check_reg_offset(ag, reg);
r = ag->mac_base + reg;
__raw_writel(__raw_readl(r) | mask, r);
/* flush write */
(void)__raw_readl(r);
}
static inline void ag71xx_cb(struct ag71xx *ag, unsigned reg, u32 mask)
{
void __iomem *r;
ag71xx_check_reg_offset(ag, reg);
r = ag->mac_base + reg;
__raw_writel(__raw_readl(r) & ~mask, r);
/* flush write */
(void) __raw_readl(r);
}
static inline void ag71xx_int_enable(struct ag71xx *ag, u32 ints)
{
ag71xx_sb(ag, AG71XX_REG_INT_ENABLE, ints);
}
static inline void ag71xx_int_disable(struct ag71xx *ag, u32 ints)
{
ag71xx_cb(ag, AG71XX_REG_INT_ENABLE, ints);
}
static inline void ag71xx_mii_ctrl_wr(struct ag71xx *ag, u32 value)
{
struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
if (pdata->is_ar724x)
return;
__raw_writel(value, ag->mii_ctrl);
/* flush write */
__raw_readl(ag->mii_ctrl);
}
static inline u32 ag71xx_mii_ctrl_rr(struct ag71xx *ag)
{
struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
if (pdata->is_ar724x)
return 0xffffffff;
return __raw_readl(ag->mii_ctrl);
}
static void inline ag71xx_mii_ctrl_set_if(struct ag71xx *ag,
unsigned int mii_if)
{
u32 t;
t = ag71xx_mii_ctrl_rr(ag);
t &= ~(MII_CTRL_IF_MASK);
t |= (mii_if & MII_CTRL_IF_MASK);
ag71xx_mii_ctrl_wr(ag, t);
}
static void inline ag71xx_mii_ctrl_set_speed(struct ag71xx *ag,
unsigned int speed)
{
u32 t;
t = ag71xx_mii_ctrl_rr(ag);
t &= ~(MII_CTRL_SPEED_MASK << MII_CTRL_SPEED_SHIFT);
t |= (speed & MII_CTRL_SPEED_MASK) << MII_CTRL_SPEED_SHIFT;
ag71xx_mii_ctrl_wr(ag, t);
}
#ifdef CONFIG_AG71XX_AR8216_SUPPORT
void ag71xx_add_ar8216_header(struct ag71xx *ag, struct sk_buff *skb);
int ag71xx_remove_ar8216_header(struct ag71xx *ag, struct sk_buff *skb,
int pktlen);
static inline int ag71xx_has_ar8216(struct ag71xx *ag)
{
return ag71xx_get_pdata(ag)->has_ar8216;
}
#else
static inline void ag71xx_add_ar8216_header(struct ag71xx *ag,
struct sk_buff *skb)
{
}
static inline int ag71xx_remove_ar8216_header(struct ag71xx *ag,
struct sk_buff *skb,
int pktlen)
{
return 0;
}
static inline int ag71xx_has_ar8216(struct ag71xx *ag)
{
return 0;
}
#endif
#ifdef CONFIG_AG71XX_DEBUG_FS
int ag71xx_debugfs_root_init(void);
void ag71xx_debugfs_root_exit(void);
int ag71xx_debugfs_init(struct ag71xx *ag);
void ag71xx_debugfs_exit(struct ag71xx *ag);
void ag71xx_debugfs_update_int_stats(struct ag71xx *ag, u32 status);
void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag, int rx, int tx);
#else
static inline int ag71xx_debugfs_root_init(void) { return 0; }
static inline void ag71xx_debugfs_root_exit(void) {}
static inline int ag71xx_debugfs_init(struct ag71xx *ag) { return 0; }
static inline void ag71xx_debugfs_exit(struct ag71xx *ag) {}
static inline void ag71xx_debugfs_update_int_stats(struct ag71xx *ag,
u32 status) {}
static inline void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag,
int rx, int tx) {}
#endif /* CONFIG_AG71XX_DEBUG_FS */
void ag71xx_ar7240_start(struct ag71xx *ag);
void ag71xx_ar7240_stop(struct ag71xx *ag);
int ag71xx_ar7240_init(struct ag71xx *ag);
void ag71xx_ar7240_cleanup(struct ag71xx *ag);
#endif /* _AG71XX_H */