netxen_nic_niu.c

来自「linux 内核源代码」· C语言 代码 · 共 909 行 · 第 1/2 页

C
909
字号
/* * Copyright (C) 2003 - 2006 NetXen, Inc. * All rights reserved. * * 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. * * 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. * * The full GNU General Public License is included in this distribution * in the file called LICENSE. * * Contact Information: *    info@netxen.com * NetXen, * 3965 Freedom Circle, Fourth floor, * Santa Clara, CA 95054 * * * Provides access to the Network Interface Unit h/w block. * */#include "netxen_nic.h"#define NETXEN_GB_MAC_SOFT_RESET	0x80000000#define NETXEN_GB_MAC_RESET_PROT_BLK   0x000F0000#define NETXEN_GB_MAC_ENABLE_TX_RX     0x00000005#define NETXEN_GB_MAC_PAUSED_FRMS      0x00000020static long phy_lock_timeout = 100000000;static inline int phy_lock(struct netxen_adapter *adapter){	int i;	int done = 0, timeout = 0;	while (!done) {		done =		    readl(pci_base_offset			  (adapter, NETXEN_PCIE_REG(PCIE_SEM3_LOCK)));		if (done == 1)			break;		if (timeout >= phy_lock_timeout) {			return -1;		}		timeout++;		if (!in_atomic())			schedule();		else {			for (i = 0; i < 20; i++)				cpu_relax();		}	}	writel(PHY_LOCK_DRIVER,	       NETXEN_CRB_NORMALIZE(adapter, NETXEN_PHY_LOCK_ID));	return 0;}static inline int phy_unlock(struct netxen_adapter *adapter){	readl(pci_base_offset(adapter, NETXEN_PCIE_REG(PCIE_SEM3_UNLOCK)));	return 0;}/*  * netxen_niu_gbe_phy_read - read a register from the GbE PHY via * mii management interface. * * Note: The MII management interface goes through port 0. *	Individual phys are addressed as follows: * @param phy  [15:8]  phy id * @param reg  [7:0]   register number * * @returns  0 on success *	  -1 on error * */int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, 				__u32 * readval){	long timeout = 0;	long result = 0;	long restore = 0;	long phy = physical_port[adapter->portnum];	__u32 address;	__u32 command;	__u32 status;	__u32 mac_cfg0;	if (phy_lock(adapter) != 0) {		return -1;	}	/*	 * MII mgmt all goes through port 0 MAC interface,	 * so it cannot be in reset	 */	if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0),				  &mac_cfg0, 4))		return -EIO;	if (netxen_gb_get_soft_reset(mac_cfg0)) {		__u32 temp;		temp = 0;		netxen_gb_tx_reset_pb(temp);		netxen_gb_rx_reset_pb(temp);		netxen_gb_tx_reset_mac(temp);		netxen_gb_rx_reset_mac(temp);		if (netxen_nic_hw_write_wx(adapter,					   NETXEN_NIU_GB_MAC_CONFIG_0(0),					   &temp, 4))			return -EIO;		restore = 1;	}	address = 0;	netxen_gb_mii_mgmt_reg_addr(address, reg);	netxen_gb_mii_mgmt_phy_addr(address, phy);	if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0),				   &address, 4))		return -EIO;	command = 0;		/* turn off any prior activity */	if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0),				   &command, 4))		return -EIO;	/* send read command */	netxen_gb_mii_mgmt_set_read_cycle(command);	if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0),				   &command, 4))		return -EIO;	status = 0;	do {		if (netxen_nic_hw_read_wx(adapter,					  NETXEN_NIU_GB_MII_MGMT_INDICATE(0),					  &status, 4))			return -EIO;		timeout++;	} while ((netxen_get_gb_mii_mgmt_busy(status)		  || netxen_get_gb_mii_mgmt_notvalid(status))		 && (timeout++ < NETXEN_NIU_PHY_WAITMAX));	if (timeout < NETXEN_NIU_PHY_WAITMAX) {		if (netxen_nic_hw_read_wx(adapter,					  NETXEN_NIU_GB_MII_MGMT_STATUS(0),					  readval, 4))			return -EIO;		result = 0;	} else		result = -1;	if (restore)		if (netxen_nic_hw_write_wx(adapter,					   NETXEN_NIU_GB_MAC_CONFIG_0(0),					   &mac_cfg0, 4))			return -EIO;	phy_unlock(adapter);	return result;}/*  * netxen_niu_gbe_phy_write - write a register to the GbE PHY via * mii management interface. * * Note: The MII management interface goes through port 0. *	Individual phys are addressed as follows: * @param phy      [15:8]  phy id * @param reg      [7:0]   register number * * @returns  0 on success *	  -1 on error * */int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, 				__u32 val){	long timeout = 0;	long result = 0;	long restore = 0;	long phy = physical_port[adapter->portnum];	__u32 address;	__u32 command;	__u32 status;	__u32 mac_cfg0;	/*	 * MII mgmt all goes through port 0 MAC interface, so it	 * cannot be in reset	 */	if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0),				  &mac_cfg0, 4))		return -EIO;	if (netxen_gb_get_soft_reset(mac_cfg0)) {		__u32 temp;		temp = 0;		netxen_gb_tx_reset_pb(temp);		netxen_gb_rx_reset_pb(temp);		netxen_gb_tx_reset_mac(temp);		netxen_gb_rx_reset_mac(temp);		if (netxen_nic_hw_write_wx(adapter,					   NETXEN_NIU_GB_MAC_CONFIG_0(0),					   &temp, 4))			return -EIO;		restore = 1;	}	command = 0;		/* turn off any prior activity */	if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0),				   &command, 4))		return -EIO;	address = 0;	netxen_gb_mii_mgmt_reg_addr(address, reg);	netxen_gb_mii_mgmt_phy_addr(address, phy);	if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0),				   &address, 4))		return -EIO;	if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_CTRL(0),				   &val, 4))		return -EIO;	status = 0;	do {		if (netxen_nic_hw_read_wx(adapter,					  NETXEN_NIU_GB_MII_MGMT_INDICATE(0),					  &status, 4))			return -EIO;		timeout++;	} while ((netxen_get_gb_mii_mgmt_busy(status))		 && (timeout++ < NETXEN_NIU_PHY_WAITMAX));	if (timeout < NETXEN_NIU_PHY_WAITMAX)		result = 0;	else		result = -EIO;	/* restore the state of port 0 MAC in case we tampered with it */	if (restore)		if (netxen_nic_hw_write_wx(adapter,					   NETXEN_NIU_GB_MAC_CONFIG_0(0),					   &mac_cfg0, 4))			return -EIO;	return result;}int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter){	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x3f);	return 0;}int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter){	int result = 0;	__u32 enable = 0;	netxen_set_phy_int_link_status_changed(enable);	netxen_set_phy_int_autoneg_completed(enable);	netxen_set_phy_int_speed_changed(enable);	if (0 !=	    netxen_niu_gbe_phy_write(adapter, 				     NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE,				     enable))		result = -EIO;	return result;}int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter){	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x7f);	return 0;}int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter){	int result = 0;	if (0 !=	    netxen_niu_gbe_phy_write(adapter,				     NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, 0))		result = -EIO;	return result;}int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter){	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1);	return 0;}int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter){	int result = 0;	if (0 !=	    netxen_niu_gbe_phy_write(adapter, 				     NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,				     -EIO))		result = -EIO;	return result;}/*  * netxen_niu_gbe_set_mii_mode- Set 10/100 Mbit Mode for GbE MAC * */void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter,				 int port, long enable){	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2);	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),				    0x80000000);	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),				    0x0000f0025);	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port),				    0xf1ff);	netxen_crb_writelit_adapter(adapter,				    NETXEN_NIU_GB0_GMII_MODE + (port << 3), 0);	netxen_crb_writelit_adapter(adapter,				    NETXEN_NIU_GB0_MII_MODE + (port << 3), 1);	netxen_crb_writelit_adapter(adapter,				    (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0);	netxen_crb_writelit_adapter(adapter,				    NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7);	if (enable) {		/* 		 * Do NOT enable flow control until a suitable solution for 		 *  shutting down pause frames is found. 		 */		netxen_crb_writelit_adapter(adapter,					    NETXEN_NIU_GB_MAC_CONFIG_0(port),					    0x5);	}	if (netxen_niu_gbe_enable_phy_interrupts(adapter))		printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n");	if (netxen_niu_gbe_clear_phy_interrupts(adapter))		printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n");}/*  * netxen_niu_gbe_set_gmii_mode- Set GbE Mode for GbE MAC */void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter,				  int port, long enable){	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2);	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),				    0x80000000);	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),				    0x0000f0025);	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port),				    0xf2ff);	netxen_crb_writelit_adapter(adapter,				    NETXEN_NIU_GB0_MII_MODE + (port << 3), 0);	netxen_crb_writelit_adapter(adapter,				    NETXEN_NIU_GB0_GMII_MODE + (port << 3), 1);	netxen_crb_writelit_adapter(adapter,				    (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0);	netxen_crb_writelit_adapter(adapter,				    NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7);	if (enable) {		/* 		 * Do NOT enable flow control until a suitable solution for 		 *  shutting down pause frames is found. 		 */		netxen_crb_writelit_adapter(adapter,					    NETXEN_NIU_GB_MAC_CONFIG_0(port),					    0x5);	}	if (netxen_niu_gbe_enable_phy_interrupts(adapter))		printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n");	if (netxen_niu_gbe_clear_phy_interrupts(adapter))		printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n");}int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port){	int result = 0;	__u32 status;	if (adapter->disable_phy_interrupts)		adapter->disable_phy_interrupts(adapter);	mdelay(2);	if (0 ==	    netxen_niu_gbe_phy_read(adapter,				    NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,				    &status)) {		if (netxen_get_phy_link(status)) {			if (netxen_get_phy_speed(status) == 2) {				netxen_niu_gbe_set_gmii_mode(adapter, port, 1);			} else if ((netxen_get_phy_speed(status) == 1)				   || (netxen_get_phy_speed(status) == 0)) {				netxen_niu_gbe_set_mii_mode(adapter, port, 1);			} else {				result = -1;			}		} else {			/*			 * We don't have link. Cable  must be unconnected.			 * Enable phy interrupts so we take action when			 * plugged in.			 */			netxen_crb_writelit_adapter(adapter,						    NETXEN_NIU_GB_MAC_CONFIG_0						    (port),						    NETXEN_GB_MAC_SOFT_RESET);			netxen_crb_writelit_adapter(adapter,						    NETXEN_NIU_GB_MAC_CONFIG_0						    (port),						    NETXEN_GB_MAC_RESET_PROT_BLK						    | NETXEN_GB_MAC_ENABLE_TX_RX						    |						    NETXEN_GB_MAC_PAUSED_FRMS);			if (netxen_niu_gbe_clear_phy_interrupts(adapter))				printk(KERN_ERR PFX				       "ERROR clearing PHY interrupts\n");			if (netxen_niu_gbe_enable_phy_interrupts(adapter))				printk(KERN_ERR PFX				       "ERROR enabling PHY interrupts\n");			if (netxen_niu_gbe_clear_phy_interrupts(adapter))				printk(KERN_ERR PFX				       "ERROR clearing PHY interrupts\n");			result = -1;		}	} else {		result = -EIO;	}	return result;}int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)

⌨️ 快捷键说明

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