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

📄 niu.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	struct net_device *dev = np->dev;	unsigned long flags;	if (!netif_carrier_ok(dev) && link_up) {		niuinfo(LINK, "%s: Link is up at %s, %s duplex\n",		       dev->name,		       (lp->active_speed == SPEED_10000 ?			"10Gb/sec" :			(lp->active_speed == SPEED_1000 ?			 "1Gb/sec" :			 (lp->active_speed == SPEED_100 ?			  "100Mbit/sec" : "10Mbit/sec"))),		       (lp->active_duplex == DUPLEX_FULL ?			"full" : "half"));		spin_lock_irqsave(&np->lock, flags);		niu_init_xif(np);		niu_handle_led(np, 1);		spin_unlock_irqrestore(&np->lock, flags);		netif_carrier_on(dev);	} else if (netif_carrier_ok(dev) && !link_up) {		niuwarn(LINK, "%s: Link is down\n", dev->name);		spin_lock_irqsave(&np->lock, flags);		niu_handle_led(np, 0);		spin_unlock_irqrestore(&np->lock, flags);		netif_carrier_off(dev);	}	return 0;}static int link_status_10g_mrvl(struct niu *np, int *link_up_p){	int err, link_up, pma_status, pcs_status;	link_up = 0;	err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,			MRVL88X2011_10G_PMD_STATUS_2);	if (err < 0)		goto out;	/* Check PMA/PMD Register: 1.0001.2 == 1 */	err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,			MRVL88X2011_PMA_PMD_STATUS_1);	if (err < 0)		goto out;	pma_status = ((err & MRVL88X2011_LNK_STATUS_OK) ? 1 : 0);        /* Check PMC Register : 3.0001.2 == 1: read twice */	err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,			MRVL88X2011_PMA_PMD_STATUS_1);	if (err < 0)		goto out;	err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,			MRVL88X2011_PMA_PMD_STATUS_1);	if (err < 0)		goto out;	pcs_status = ((err & MRVL88X2011_LNK_STATUS_OK) ? 1 : 0);        /* Check XGXS Register : 4.0018.[0-3,12] */	err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV4_ADDR,			MRVL88X2011_10G_XGXS_LANE_STAT);	if (err < 0)		goto out;	if (err == (PHYXS_XGXS_LANE_STAT_ALINGED | PHYXS_XGXS_LANE_STAT_LANE3 |		    PHYXS_XGXS_LANE_STAT_LANE2 | PHYXS_XGXS_LANE_STAT_LANE1 |		    PHYXS_XGXS_LANE_STAT_LANE0 | PHYXS_XGXS_LANE_STAT_MAGIC |		    0x800))		link_up = (pma_status && pcs_status) ? 1 : 0;	np->link_config.active_speed = SPEED_10000;	np->link_config.active_duplex = DUPLEX_FULL;	err = 0;out:	mrvl88x2011_act_led(np, (link_up ?				 MRVL88X2011_LED_CTL_PCS_ACT :				 MRVL88X2011_LED_CTL_OFF));	*link_up_p = link_up;	return err;}static int link_status_10g_bcom(struct niu *np, int *link_up_p){	int err, link_up;	link_up = 0;	err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,			BCM8704_PMD_RCV_SIGDET);	if (err < 0)		goto out;	if (!(err & PMD_RCV_SIGDET_GLOBAL)) {		err = 0;		goto out;	}	err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,			BCM8704_PCS_10G_R_STATUS);	if (err < 0)		goto out;	if (!(err & PCS_10G_R_STATUS_BLK_LOCK)) {		err = 0;		goto out;	}	err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,			BCM8704_PHYXS_XGXS_LANE_STAT);	if (err < 0)		goto out;	if (err != (PHYXS_XGXS_LANE_STAT_ALINGED |		    PHYXS_XGXS_LANE_STAT_MAGIC |		    PHYXS_XGXS_LANE_STAT_LANE3 |		    PHYXS_XGXS_LANE_STAT_LANE2 |		    PHYXS_XGXS_LANE_STAT_LANE1 |		    PHYXS_XGXS_LANE_STAT_LANE0)) {		err = 0;		goto out;	}	link_up = 1;	np->link_config.active_speed = SPEED_10000;	np->link_config.active_duplex = DUPLEX_FULL;	err = 0;out:	*link_up_p = link_up;	return err;}static int link_status_10g(struct niu *np, int *link_up_p){	unsigned long flags;	int err = -EINVAL;	spin_lock_irqsave(&np->lock, flags);	if (np->link_config.loopback_mode == LOOPBACK_DISABLED) {		int phy_id;		phy_id = phy_decode(np->parent->port_phy, np->port);		phy_id = np->parent->phy_probe_info.phy_id[phy_id][np->port];		/* handle different phy types */		switch (phy_id & NIU_PHY_ID_MASK) {		case NIU_PHY_ID_MRVL88X2011:			err = link_status_10g_mrvl(np, link_up_p);			break;		default: /* bcom 8704 */			err = link_status_10g_bcom(np, link_up_p);			break;		}	}	spin_unlock_irqrestore(&np->lock, flags);	return err;}static int link_status_1g(struct niu *np, int *link_up_p){	struct niu_link_config *lp = &np->link_config;	u16 current_speed, bmsr;	unsigned long flags;	u8 current_duplex;	int err, link_up;	link_up = 0;	current_speed = SPEED_INVALID;	current_duplex = DUPLEX_INVALID;	spin_lock_irqsave(&np->lock, flags);	err = -EINVAL;	if (np->link_config.loopback_mode != LOOPBACK_DISABLED)		goto out;	err = mii_read(np, np->phy_addr, MII_BMSR);	if (err < 0)		goto out;	bmsr = err;	if (bmsr & BMSR_LSTATUS) {		u16 adv, lpa, common, estat;		err = mii_read(np, np->phy_addr, MII_ADVERTISE);		if (err < 0)			goto out;		adv = err;		err = mii_read(np, np->phy_addr, MII_LPA);		if (err < 0)			goto out;		lpa = err;		common = adv & lpa;		err = mii_read(np, np->phy_addr, MII_ESTATUS);		if (err < 0)			goto out;		estat = err;		link_up = 1;		if (estat & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) {			current_speed = SPEED_1000;			if (estat & ESTATUS_1000_TFULL)				current_duplex = DUPLEX_FULL;			else				current_duplex = DUPLEX_HALF;		} else {			if (common & ADVERTISE_100BASE4) {				current_speed = SPEED_100;				current_duplex = DUPLEX_HALF;			} else if (common & ADVERTISE_100FULL) {				current_speed = SPEED_100;				current_duplex = DUPLEX_FULL;			} else if (common & ADVERTISE_100HALF) {				current_speed = SPEED_100;				current_duplex = DUPLEX_HALF;			} else if (common & ADVERTISE_10FULL) {				current_speed = SPEED_10;				current_duplex = DUPLEX_FULL;			} else if (common & ADVERTISE_10HALF) {				current_speed = SPEED_10;				current_duplex = DUPLEX_HALF;			} else				link_up = 0;		}	}	lp->active_speed = current_speed;	lp->active_duplex = current_duplex;	err = 0;out:	spin_unlock_irqrestore(&np->lock, flags);	*link_up_p = link_up;	return err;}static int niu_link_status(struct niu *np, int *link_up_p){	const struct niu_phy_ops *ops = np->phy_ops;	int err;	err = 0;	if (ops->link_status)		err = ops->link_status(np, link_up_p);	return err;}static void niu_timer(unsigned long __opaque){	struct niu *np = (struct niu *) __opaque;	unsigned long off;	int err, link_up;	err = niu_link_status(np, &link_up);	if (!err)		niu_link_status_common(np, link_up);	if (netif_carrier_ok(np->dev))		off = 5 * HZ;	else		off = 1 * HZ;	np->timer.expires = jiffies + off;	add_timer(&np->timer);}static const struct niu_phy_ops phy_ops_10g_fiber_niu = {	.serdes_init		= serdes_init_niu,	.xcvr_init		= xcvr_init_10g,	.link_status		= link_status_10g,};static const struct niu_phy_ops phy_ops_10g_fiber = {	.serdes_init		= serdes_init_10g,	.xcvr_init		= xcvr_init_10g,	.link_status		= link_status_10g,};static const struct niu_phy_ops phy_ops_10g_copper = {	.serdes_init		= serdes_init_10g,	.link_status		= link_status_10g, /* XXX */};static const struct niu_phy_ops phy_ops_1g_fiber = {	.serdes_init		= serdes_init_1g,	.xcvr_init		= xcvr_init_1g,	.link_status		= link_status_1g,};static const struct niu_phy_ops phy_ops_1g_copper = {	.xcvr_init		= xcvr_init_1g,	.link_status		= link_status_1g,};struct niu_phy_template {	const struct niu_phy_ops	*ops;	u32				phy_addr_base;};static const struct niu_phy_template phy_template_niu = {	.ops		= &phy_ops_10g_fiber_niu,	.phy_addr_base	= 16,};static const struct niu_phy_template phy_template_10g_fiber = {	.ops		= &phy_ops_10g_fiber,	.phy_addr_base	= 8,};static const struct niu_phy_template phy_template_10g_copper = {	.ops		= &phy_ops_10g_copper,	.phy_addr_base	= 10,};static const struct niu_phy_template phy_template_1g_fiber = {	.ops		= &phy_ops_1g_fiber,	.phy_addr_base	= 0,};static const struct niu_phy_template phy_template_1g_copper = {	.ops		= &phy_ops_1g_copper,	.phy_addr_base	= 0,};static int niu_determine_phy_disposition(struct niu *np){	struct niu_parent *parent = np->parent;	u8 plat_type = parent->plat_type;	const struct niu_phy_template *tp;	u32 phy_addr_off = 0;	if (plat_type == PLAT_TYPE_NIU) {		tp = &phy_template_niu;		phy_addr_off += np->port;	} else {		switch (np->flags & (NIU_FLAGS_10G | NIU_FLAGS_FIBER)) {		case 0:			/* 1G copper */			tp = &phy_template_1g_copper;			if (plat_type == PLAT_TYPE_VF_P0)				phy_addr_off = 10;			else if (plat_type == PLAT_TYPE_VF_P1)				phy_addr_off = 26;			phy_addr_off += (np->port ^ 0x3);			break;		case NIU_FLAGS_10G:			/* 10G copper */			tp = &phy_template_1g_copper;			break;		case NIU_FLAGS_FIBER:			/* 1G fiber */			tp = &phy_template_1g_fiber;			break;		case NIU_FLAGS_10G | NIU_FLAGS_FIBER:			/* 10G fiber */			tp = &phy_template_10g_fiber;			if (plat_type == PLAT_TYPE_VF_P0 ||			    plat_type == PLAT_TYPE_VF_P1)				phy_addr_off = 8;			phy_addr_off += np->port;			break;		default:			return -EINVAL;		}	}	np->phy_ops = tp->ops;	np->phy_addr = tp->phy_addr_base + phy_addr_off;	return 0;}static int niu_init_link(struct niu *np){	struct niu_parent *parent = np->parent;	int err, ignore;	if (parent->plat_type == PLAT_TYPE_NIU) {		err = niu_xcvr_init(np);		if (err)			return err;		msleep(200);	}	err = niu_serdes_init(np);	if (err)		return err;	msleep(200);	err = niu_xcvr_init(np);	if (!err)		niu_link_status(np, &ignore);	return 0;}static void niu_set_primary_mac(struct niu *np, unsigned char *addr){	u16 reg0 = addr[4] << 8 | addr[5];	u16 reg1 = addr[2] << 8 | addr[3];	u16 reg2 = addr[0] << 8 | addr[1];	if (np->flags & NIU_FLAGS_XMAC) {		nw64_mac(XMAC_ADDR0, reg0);		nw64_mac(XMAC_ADDR1, reg1);		nw64_mac(XMAC_ADDR2, reg2);	} else {		nw64_mac(BMAC_ADDR0, reg0);		nw64_mac(BMAC_ADDR1, reg1);		nw64_mac(BMAC_ADDR2, reg2);	}}static int niu_num_alt_addr(struct niu *np){	if (np->flags & NIU_FLAGS_XMAC)		return XMAC_NUM_ALT_ADDR;	else		return BMAC_NUM_ALT_ADDR;}static int niu_set_alt_mac(struct niu *np, int index, unsigned char *addr){	u16 reg0 = addr[4] << 8 | addr[5];	u16 reg1 = addr[2] << 8 | addr[3];	u16 reg2 = addr[0] << 8 | addr[1];	if (index >= niu_num_alt_addr(np))		return -EINVAL;	if (np->flags & NIU_FLAGS_XMAC) {		nw64_mac(XMAC_ALT_ADDR0(index), reg0);		nw64_mac(XMAC_ALT_ADDR1(index), reg1);		nw64_mac(XMAC_ALT_ADDR2(index), reg2);	} else {		nw64_mac(BMAC_ALT_ADDR0(index), reg0);		nw64_mac(BMAC_ALT_ADDR1(index), reg1);		nw64_mac(BMAC_ALT_ADDR2(index), reg2);	}	return 0;}static int niu_enable_alt_mac(struct niu *np, int index, int on){	unsigned long reg;	u64 val, mask;	if (index >= niu_num_alt_addr(np))		return -EINVAL;	if (np->flags & NIU_FLAGS_XMAC)		reg = XMAC_ADDR_CMPEN;	else		reg = BMAC_ADDR_CMPEN;	mask = 1 << index;	val = nr64_mac(reg);	if (on)		val |= mask;	else		val &= ~mask;	nw64_mac(reg, val);	return 0;}static void __set_rdc_table_num_hw(struct niu *np, unsigned long reg,				   int num, int mac_pref){	u64 val = nr64_mac(reg);	val &= ~(HOST_INFO_MACRDCTBLN | HOST_INFO_MPR);	val |= num;	if (mac_pref)		val |= HOST_INFO_MPR;	nw64_mac(reg, val);}static int __set_rdc_table_num(struct niu *np,			       int xmac_index, int bmac_index,			       int rdc_table_num, int mac_pref){	unsigned long reg;	if (rdc_table_num & ~HOST_INFO_MACRDCTBLN)		return -EINVAL;	if (np->flags & NIU_FLAGS_XMAC)		reg = XMAC_HOST_INFO(xmac_index);	else		reg = BMAC_HOST_INFO(bmac_index);	__set_rdc_table_num_hw(np, reg, rdc_table_num, mac_pref);	return 0;}static int niu_set_primary_mac_rdc_table(struct niu *np, int table_num,					 int mac_pref){	return __set_rdc_table_num(np, 17, 0, table_num, mac_pref);}static int niu_set_multicast_mac_rdc_table(struct niu *np, int table_num,					   int mac_pref){	return __set_rdc_table_num(np, 16, 8, table_num, mac_pref);}static int niu_set_alt_mac_rdc_table(struct niu *np, int idx,				     int table_num, int mac_pref){	if (idx >= niu_num_alt_addr(np))		return -EINVAL;	return __set_rdc_table_num(np, idx, idx + 1, table_num, mac_pref);}static u64 vlan_entry_set_parity(u64 reg_val){	u64 port01_mask;	u64 port23_mask;	port01_mask = 0x00ff;	port23_mask = 0xff00;	if (hweight64(reg_val & port01_mask) & 1)		reg_val |= ENET_VLAN_TBL_PARITY0;	else		reg_val &= ~ENET_VLAN_TBL_PARITY0;	if (hweight64(reg_val & port23_mask) & 1)		reg_val |= ENET_VLAN_TBL_PARITY1;	else		reg_val &= ~ENET_VLAN_TBL_PARITY1;	return reg_val;}static void vlan_tbl_write(struct niu *np, unsigned long index,			   int port, int vpr, int rdc_table){	u64 reg_val = nr64(ENET_VLAN_TBL(index));	reg_val &= ~((ENET_VLAN_TBL_VPR |		      ENET_VLAN_TBL_VLANRDCTBLN) <<		     ENET_VLAN_TBL_SHIFT(port));	if (vpr)		reg_val |= (ENET_VLAN_TBL_VPR <<			    ENET_VLAN_TBL_SHIFT(port));	reg_val |= (rdc_table << ENET_VLAN_TBL_SHIFT(port));	reg_val = vlan_entry_set_parity(reg_val);	nw64(ENET_VLAN_TBL(index), reg_val);}static void vlan_tbl_clear(struct niu *np){	int i;	for (i = 0; i < ENET_VLAN_TBL_NUM_ENTRIES; i++)		nw64(ENET_VLAN_TBL(i), 0);}

⌨️ 快捷键说明

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