⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 niu.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* niu.c: Neptune ethernet driver. * * Copyright (C) 2007 David S. Miller (davem@davemloft.net) */#include <linux/module.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/dma-mapping.h>#include <linux/netdevice.h>#include <linux/ethtool.h>#include <linux/etherdevice.h>#include <linux/platform_device.h>#include <linux/delay.h>#include <linux/bitops.h>#include <linux/mii.h>#include <linux/if_ether.h>#include <linux/if_vlan.h>#include <linux/ip.h>#include <linux/in.h>#include <linux/ipv6.h>#include <linux/log2.h>#include <linux/jiffies.h>#include <linux/crc32.h>#include <linux/io.h>#ifdef CONFIG_SPARC64#include <linux/of_device.h>#endif#include "niu.h"#define DRV_MODULE_NAME		"niu"#define PFX DRV_MODULE_NAME	": "#define DRV_MODULE_VERSION	"0.6"#define DRV_MODULE_RELDATE	"January 5, 2008"static char version[] __devinitdata =	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");MODULE_DESCRIPTION("NIU ethernet driver");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_MODULE_VERSION);#ifndef DMA_44BIT_MASK#define DMA_44BIT_MASK	0x00000fffffffffffULL#endif#ifndef readqstatic u64 readq(void __iomem *reg){	return (((u64)readl(reg + 0x4UL) << 32) |		(u64)readl(reg));}static void writeq(u64 val, void __iomem *reg){	writel(val & 0xffffffff, reg);	writel(val >> 32, reg + 0x4UL);}#endifstatic struct pci_device_id niu_pci_tbl[] = {	{PCI_DEVICE(PCI_VENDOR_ID_SUN, 0xabcd)},	{}};MODULE_DEVICE_TABLE(pci, niu_pci_tbl);#define NIU_TX_TIMEOUT			(5 * HZ)#define nr64(reg)		readq(np->regs + (reg))#define nw64(reg, val)		writeq((val), np->regs + (reg))#define nr64_mac(reg)		readq(np->mac_regs + (reg))#define nw64_mac(reg, val)	writeq((val), np->mac_regs + (reg))#define nr64_ipp(reg)		readq(np->regs + np->ipp_off + (reg))#define nw64_ipp(reg, val)	writeq((val), np->regs + np->ipp_off + (reg))#define nr64_pcs(reg)		readq(np->regs + np->pcs_off + (reg))#define nw64_pcs(reg, val)	writeq((val), np->regs + np->pcs_off + (reg))#define nr64_xpcs(reg)		readq(np->regs + np->xpcs_off + (reg))#define nw64_xpcs(reg, val)	writeq((val), np->regs + np->xpcs_off + (reg))#define NIU_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)static int niu_debug;static int debug = -1;module_param(debug, int, 0);MODULE_PARM_DESC(debug, "NIU debug level");#define niudbg(TYPE, f, a...) \do {	if ((np)->msg_enable & NETIF_MSG_##TYPE) \		printk(KERN_DEBUG PFX f, ## a); \} while (0)#define niuinfo(TYPE, f, a...) \do {	if ((np)->msg_enable & NETIF_MSG_##TYPE) \		printk(KERN_INFO PFX f, ## a); \} while (0)#define niuwarn(TYPE, f, a...) \do {	if ((np)->msg_enable & NETIF_MSG_##TYPE) \		printk(KERN_WARNING PFX f, ## a); \} while (0)#define niu_lock_parent(np, flags) \	spin_lock_irqsave(&np->parent->lock, flags)#define niu_unlock_parent(np, flags) \	spin_unlock_irqrestore(&np->parent->lock, flags)static int __niu_wait_bits_clear_mac(struct niu *np, unsigned long reg,				     u64 bits, int limit, int delay){	while (--limit >= 0) {		u64 val = nr64_mac(reg);		if (!(val & bits))			break;		udelay(delay);	}	if (limit < 0)		return -ENODEV;	return 0;}static int __niu_set_and_wait_clear_mac(struct niu *np, unsigned long reg,					u64 bits, int limit, int delay,					const char *reg_name){	int err;	nw64_mac(reg, bits);	err = __niu_wait_bits_clear_mac(np, reg, bits, limit, delay);	if (err)		dev_err(np->device, PFX "%s: bits (%llx) of register %s "			"would not clear, val[%llx]\n",			np->dev->name, (unsigned long long) bits, reg_name,			(unsigned long long) nr64_mac(reg));	return err;}#define niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \({	BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \	__niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \})static int __niu_wait_bits_clear_ipp(struct niu *np, unsigned long reg,				     u64 bits, int limit, int delay){	while (--limit >= 0) {		u64 val = nr64_ipp(reg);		if (!(val & bits))			break;		udelay(delay);	}	if (limit < 0)		return -ENODEV;	return 0;}static int __niu_set_and_wait_clear_ipp(struct niu *np, unsigned long reg,					u64 bits, int limit, int delay,					const char *reg_name){	int err;	u64 val;	val = nr64_ipp(reg);	val |= bits;	nw64_ipp(reg, val);	err = __niu_wait_bits_clear_ipp(np, reg, bits, limit, delay);	if (err)		dev_err(np->device, PFX "%s: bits (%llx) of register %s "			"would not clear, val[%llx]\n",			np->dev->name, (unsigned long long) bits, reg_name,			(unsigned long long) nr64_ipp(reg));	return err;}#define niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \({	BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \	__niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \})static int __niu_wait_bits_clear(struct niu *np, unsigned long reg,				 u64 bits, int limit, int delay){	while (--limit >= 0) {		u64 val = nr64(reg);		if (!(val & bits))			break;		udelay(delay);	}	if (limit < 0)		return -ENODEV;	return 0;}#define niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY) \({	BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \	__niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY); \})static int __niu_set_and_wait_clear(struct niu *np, unsigned long reg,				    u64 bits, int limit, int delay,				    const char *reg_name){	int err;	nw64(reg, bits);	err = __niu_wait_bits_clear(np, reg, bits, limit, delay);	if (err)		dev_err(np->device, PFX "%s: bits (%llx) of register %s "			"would not clear, val[%llx]\n",			np->dev->name, (unsigned long long) bits, reg_name,			(unsigned long long) nr64(reg));	return err;}#define niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \({	BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \	__niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \})static void niu_ldg_rearm(struct niu *np, struct niu_ldg *lp, int on){	u64 val = (u64) lp->timer;	if (on)		val |= LDG_IMGMT_ARM;	nw64(LDG_IMGMT(lp->ldg_num), val);}static int niu_ldn_irq_enable(struct niu *np, int ldn, int on){	unsigned long mask_reg, bits;	u64 val;	if (ldn < 0 || ldn > LDN_MAX)		return -EINVAL;	if (ldn < 64) {		mask_reg = LD_IM0(ldn);		bits = LD_IM0_MASK;	} else {		mask_reg = LD_IM1(ldn - 64);		bits = LD_IM1_MASK;	}	val = nr64(mask_reg);	if (on)		val &= ~bits;	else		val |= bits;	nw64(mask_reg, val);	return 0;}static int niu_enable_ldn_in_ldg(struct niu *np, struct niu_ldg *lp, int on){	struct niu_parent *parent = np->parent;	int i;	for (i = 0; i <= LDN_MAX; i++) {		int err;		if (parent->ldg_map[i] != lp->ldg_num)			continue;		err = niu_ldn_irq_enable(np, i, on);		if (err)			return err;	}	return 0;}static int niu_enable_interrupts(struct niu *np, int on){	int i;	for (i = 0; i < np->num_ldg; i++) {		struct niu_ldg *lp = &np->ldg[i];		int err;		err = niu_enable_ldn_in_ldg(np, lp, on);		if (err)			return err;	}	for (i = 0; i < np->num_ldg; i++)		niu_ldg_rearm(np, &np->ldg[i], on);	return 0;}static u32 phy_encode(u32 type, int port){	return (type << (port * 2));}static u32 phy_decode(u32 val, int port){	return (val >> (port * 2)) & PORT_TYPE_MASK;}static int mdio_wait(struct niu *np){	int limit = 1000;	u64 val;	while (--limit > 0) {		val = nr64(MIF_FRAME_OUTPUT);		if ((val >> MIF_FRAME_OUTPUT_TA_SHIFT) & 0x1)			return val & MIF_FRAME_OUTPUT_DATA;		udelay(10);	}	return -ENODEV;}static int mdio_read(struct niu *np, int port, int dev, int reg){	int err;	nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg));	err = mdio_wait(np);	if (err < 0)		return err;	nw64(MIF_FRAME_OUTPUT, MDIO_READ_OP(port, dev));	return mdio_wait(np);}static int mdio_write(struct niu *np, int port, int dev, int reg, int data){	int err;	nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg));	err = mdio_wait(np);	if (err < 0)		return err;	nw64(MIF_FRAME_OUTPUT, MDIO_WRITE_OP(port, dev, data));	err = mdio_wait(np);	if (err < 0)		return err;	return 0;}static int mii_read(struct niu *np, int port, int reg){	nw64(MIF_FRAME_OUTPUT, MII_READ_OP(port, reg));	return mdio_wait(np);}static int mii_write(struct niu *np, int port, int reg, int data){	int err;	nw64(MIF_FRAME_OUTPUT, MII_WRITE_OP(port, reg, data));	err = mdio_wait(np);	if (err < 0)		return err;	return 0;}static int esr2_set_tx_cfg(struct niu *np, unsigned long channel, u32 val){	int err;	err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,			 ESR2_TI_PLL_TX_CFG_L(channel),			 val & 0xffff);	if (!err)		err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,				 ESR2_TI_PLL_TX_CFG_H(channel),				 val >> 16);	return err;}static int esr2_set_rx_cfg(struct niu *np, unsigned long channel, u32 val){	int err;	err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,			 ESR2_TI_PLL_RX_CFG_L(channel),			 val & 0xffff);	if (!err)		err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,				 ESR2_TI_PLL_RX_CFG_H(channel),				 val >> 16);	return err;}/* Mode is always 10G fiber.  */static int serdes_init_niu(struct niu *np){	struct niu_link_config *lp = &np->link_config;	u32 tx_cfg, rx_cfg;	unsigned long i;	tx_cfg = (PLL_TX_CFG_ENTX | PLL_TX_CFG_SWING_1375MV);	rx_cfg = (PLL_RX_CFG_ENRX | PLL_RX_CFG_TERM_0P8VDDT |		  PLL_RX_CFG_ALIGN_ENA | PLL_RX_CFG_LOS_LTHRESH |		  PLL_RX_CFG_EQ_LP_ADAPTIVE);	if (lp->loopback_mode == LOOPBACK_PHY) {		u16 test_cfg = PLL_TEST_CFG_LOOPBACK_CML_DIS;		mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,			   ESR2_TI_PLL_TEST_CFG_L, test_cfg);		tx_cfg |= PLL_TX_CFG_ENTEST;		rx_cfg |= PLL_RX_CFG_ENTEST;	}	/* Initialize all 4 lanes of the SERDES.  */	for (i = 0; i < 4; i++) {		int err = esr2_set_tx_cfg(np, i, tx_cfg);		if (err)			return err;	}	for (i = 0; i < 4; i++) {		int err = esr2_set_rx_cfg(np, i, rx_cfg);		if (err)			return err;	}	return 0;}static int esr_read_rxtx_ctrl(struct niu *np, unsigned long chan, u32 *val){	int err;	err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, ESR_RXTX_CTRL_L(chan));	if (err >= 0) {		*val = (err & 0xffff);		err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,				ESR_RXTX_CTRL_H(chan));		if (err >= 0)			*val |= ((err & 0xffff) << 16);		err = 0;	}	return err;}static int esr_read_glue0(struct niu *np, unsigned long chan, u32 *val){	int err;	err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,			ESR_GLUE_CTRL0_L(chan));	if (err >= 0) {		*val = (err & 0xffff);		err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,				ESR_GLUE_CTRL0_H(chan));		if (err >= 0) {			*val |= ((err & 0xffff) << 16);			err = 0;		}	}	return err;}static int esr_read_reset(struct niu *np, u32 *val){	int err;	err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,			ESR_RXTX_RESET_CTRL_L);	if (err >= 0) {		*val = (err & 0xffff);		err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,				ESR_RXTX_RESET_CTRL_H);		if (err >= 0) {			*val |= ((err & 0xffff) << 16);			err = 0;		}	}	return err;}static int esr_write_rxtx_ctrl(struct niu *np, unsigned long chan, u32 val){	int err;	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,			 ESR_RXTX_CTRL_L(chan), val & 0xffff);	if (!err)		err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,				 ESR_RXTX_CTRL_H(chan), (val >> 16));	return err;}static int esr_write_glue0(struct niu *np, unsigned long chan, u32 val){	int err;	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,			ESR_GLUE_CTRL0_L(chan), val & 0xffff);	if (!err)		err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,				 ESR_GLUE_CTRL0_H(chan), (val >> 16));	return err;}static int esr_reset(struct niu *np){	u32 reset;	int err;	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,			 ESR_RXTX_RESET_CTRL_L, 0x0000);	if (err)		return err;	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,			 ESR_RXTX_RESET_CTRL_H, 0xffff);	if (err)		return err;	udelay(200);	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,			 ESR_RXTX_RESET_CTRL_L, 0xffff);	if (err)		return err;	udelay(200);	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,			 ESR_RXTX_RESET_CTRL_H, 0x0000);	if (err)		return err;	udelay(200);	err = esr_read_reset(np, &reset);	if (err)		return err;	if (reset != 0) {		dev_err(np->device, PFX "Port %u ESR_RESET "			"did not clear [%08x]\n",			np->port, reset);		return -ENODEV;	}	return 0;}static int serdes_init_10g(struct niu *np){	struct niu_link_config *lp = &np->link_config;	unsigned long ctrl_reg, test_cfg_reg, i;	u64 ctrl_val, test_cfg_val, sig, mask, val;	int err;	switch (np->port) {	case 0:		ctrl_reg = ENET_SERDES_0_CTRL_CFG;		test_cfg_reg = ENET_SERDES_0_TEST_CFG;		break;	case 1:		ctrl_reg = ENET_SERDES_1_CTRL_CFG;		test_cfg_reg = ENET_SERDES_1_TEST_CFG;		break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -