diff -Naru linux-2.6.16_orig/drivers/net/netxen/netxen_nic_isr.c
linux-2.6.16/drivers/net/netxen/netxen_nic_isr.c
--- linux-2.6.16_orig/drivers/net/netxen/netxen_nic_isr.c 1969-12-31
16:00:00.000000000 -0800
+++ linux-2.6.16/drivers/net/netxen/netxen_nic_isr.c 2006-03-24
14:13:57.000000000 -0800
@@ -0,0 +1,364 @@
+/*
+ * 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:
+ * [EMAIL PROTECTED]
+ * NetXen, 3965 Freedom Circle, Fourth Floor,
+ * Santa Clara, CA 95054
+ */
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+
+#include "netxen_nic.h"
+#include "netxen_nic_hw.h"
+#include "nic_cmn.h"
+#include "nic_phan_reg.h"
+
+extern struct netxen_adapter_s *g_adapter;
+extern spinlock_t hal_lock;
+
+long
+netxen_nic_enable_phy_interrupts (netxen_adapter *adapter, long portno)
+{
+ long result = 0;
+ unsigned long flags;
+
+ switch (adapter->ahw.board_type) {
+ case NetXen_NIC_GBE:
+ spin_lock_irqsave(&hal_lock, flags);
+ g_adapter = adapter;
+ result = netxen_niu_gbe_enable_phy_interrupts (portno);
+ spin_unlock_irqrestore(&hal_lock, flags);
+ break;
+
+ case NetXen_NIC_XGBE:
+ spin_lock_irqsave(&hal_lock, flags);
+ g_adapter = adapter;
+ result = netxen_niu_xg_enable_phy_interrupts (portno);
+ spin_unlock_irqrestore(&hal_lock, flags);
+ break;
+
+ default:
+ printk(KERN_ERR "%s: Unknown board
type\n",netxen_nic_driver_name);
+ }
+
+ return result;
+}
+
+long
+netxen_nic_disable_phy_interrupts (netxen_adapter *adapter, long portno)
+{
+ long result = 0;
+ unsigned long flags;
+
+ switch (adapter->ahw.board_type) {
+ case NetXen_NIC_GBE:
+ spin_lock_irqsave(&hal_lock, flags);
+ g_adapter = adapter;
+ result = netxen_niu_gbe_disable_phy_interrupts (portno);
+ spin_unlock_irqrestore(&hal_lock, flags);
+ break;
+
+ case NetXen_NIC_XGBE:
+ spin_lock_irqsave(&hal_lock, flags);
+ g_adapter = adapter;
+ result = netxen_niu_xg_disable_phy_interrupts (portno);
+ spin_unlock_irqrestore(&hal_lock, flags);
+ break;
+
+ default:
+ printk(KERN_ERR "%s: Unknown board
type\n",netxen_nic_driver_name);
+ }
+
+ return result;
+}
+
+long
+netxen_nic_clear_phy_interrupts (netxen_adapter *adapter, long portno)
+{
+ long result = 0;
+ unsigned long flags;
+
+ switch (adapter->ahw.board_type) {
+ case NetXen_NIC_GBE:
+ spin_lock_irqsave(&hal_lock, flags);
+ g_adapter = adapter;
+ result = netxen_niu_gbe_clear_phy_interrupts (portno);
+ spin_unlock_irqrestore(&hal_lock, flags);
+
+ break;
+
+ case NetXen_NIC_XGBE:
+ spin_lock_irqsave(&hal_lock, flags);
+ g_adapter = adapter;
+ result = netxen_niu_xg_disable_phy_interrupts (portno);
+ spin_unlock_irqrestore(&hal_lock, flags);
+
+ break;
+
+ default:
+ printk(KERN_ERR "%s: Unknown board
type\n",netxen_nic_driver_name);
+ }
+
+ return result;
+}
+
+void
+netxen_nic_set_mii_mode (netxen_adapter *adapter, long portno, long enable)
+{
+ unsigned long flags;
+
+ switch (adapter->ahw.board_type) {
+ case NetXen_NIC_GBE:
+ spin_lock_irqsave(&hal_lock, flags);
+ g_adapter = adapter;
+ netxen_niu_gbe_set_mii_mode (portno, enable);
+ spin_unlock_irqrestore(&hal_lock, flags);
+
+ break;
+
+ case NetXen_NIC_XGBE:
+ printk(KERN_ERR "%s: Function %s is not implemented for XG\n",
+ netxen_nic_driver_name,__FUNCTION__);
+ break;
+
+ default:
+ printk(KERN_ERR "%s: Unknown board
type\n",netxen_nic_driver_name);
+ }
+
+ return;
+}
+
+void
+netxen_nic_set_gmii_mode(netxen_adapter *adapter, long portno, long enable)
+{
+ unsigned long flags;
+
+ switch (adapter->ahw.board_type) {
+ case NetXen_NIC_GBE:
+ spin_lock_irqsave(&hal_lock, flags);
+ g_adapter = adapter;
+ netxen_niu_gbe_set_gmii_mode (portno, enable);
+ spin_unlock_irqrestore(&hal_lock, flags);
+ break;
+
+ case NetXen_NIC_XGBE:
+ printk(KERN_ERR "%s: Function %s is not implemented for XG\n",
+ netxen_nic_driver_name,__FUNCTION__);
+ break;
+
+ default:
+ printk(KERN_ERR "%s: Unknown board
type\n",netxen_nic_driver_name);
+ }
+
+ return;
+}
+
+void
+netxen_indicate_link_status(netxen_adapter *adapter, u32 portno, u32 link)
+{
+ struct netxen_port *pport = adapter->port[portno];
+ struct net_device *netdev = pport->netdev;
+
+ if(link)
+ netif_carrier_on(netdev);
+ else
+ netif_carrier_off(netdev);
+}
+
+void
+netxen_handle_port_int(netxen_adapter *adapter,u32 portno, u32 enable)
+{
+ u32 intr;
+ netxen_niu_phy_interrupt_t *int_src;
+ struct netxen_port *port;
+ unsigned long flags;
+
+ DPRINTK(1,INFO,"INSIDE handle port int for Port = %d \n",portno);
+
+ /* This should clear the interrupt source */
+
netxen_nic_phy_read(adapter,portno,NetXen_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
+ &intr);
+ if (intr == 0) {
+ DPRINTK(1, INFO, "No phy interrupts for port #%d\n", portno);
+ return;
+ }
+ int_src = (netxen_niu_phy_interrupt_t *)&intr;
+ netxen_nic_disable_phy_interrupts (adapter, portno);
+
+ port = adapter->port[portno];
+
+ /* IND for testing print out all the interrupts received */
+ if(int_src->jabber)
+ DPRINTK(2,INFO,"NetXen: %s Jabber interrupt \n",
+ port->netdev->name);
+
+ if(int_src->polarity_changed)
+ DPRINTK(2,INFO,"NetXen: %s POLARITY CHANGED int \n",
+ port->netdev->name);
+
+ if(int_src->energy_detect)
+ DPRINTK(2,INFO,"NetXen: %s ENERGY DETECT INT \n",
+ port->netdev->name);
+
+ if(int_src->downshift)
+ DPRINTK(2,INFO,"NetXen: %s DOWNSHIFT INT \n",
+ port->netdev->name);
+ // write it down later..
+
+ if ((int_src->speed_changed) || (int_src->link_status_changed)) {
+ netxen_niu_phy_status_t status;
+
+ DPRINTK(2, INFO, "NetXen: %s SPEED CHANGED OR"
+ " LINK STATUS CHANGED \n",
+ port->netdev->name);
+
+ if (netxen_nic_phy_read(adapter,portno,
+ NetXen_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
+ (netxen_crbword_t *)&status) == 0) {
+ if(int_src->link_status_changed) {
+ if(status.link) {
+ spin_lock_irqsave(&hal_lock, flags);
+ g_adapter = adapter;
+ netxen_niu_gbe_init_port(portno);
+ spin_unlock_irqrestore(&hal_lock,
flags);
+ printk("%s: %s Link UP\n",
+ netxen_nic_driver_name,
+ port->netdev->name);
+
+ } else {
+ printk("%s: %s Link DOWN\n",
+ netxen_nic_driver_name,
+ port->netdev->name);
+ }
+ netxen_indicate_link_status(adapter, portno,
+ status.link);
+ }
+ }
+ }
+ netxen_nic_enable_phy_interrupts (adapter, portno);
+}
+
+void
+netxen_nic_isr_other(struct netxen_adapter_s *adapter)
+{
+ u32 enable, portno;
+ u32 i2qhi;
+
+ /*
+ * bit 3 is for i2qInt, if high its enabled
+ * check for phy interrupts
+ * read vector and check for bit 45 for phy
+ * clear int by writing the same value into ISR_INT_VECTOR REG
+ */
+
+ DPRINTK(1, INFO, "I2Q is the source of INT \n");
+
+ // IND verify the offset
+ //netxen_nic_hw_read(adapter,NetXen_I2Q_CLR_PCI_HI,&i2qhi,4);
+ read_lock(&adapter->adapter_lock);
+ i2qhi =
NetXen_NIC_PCI_READ_32(CRB_NORMALIZE(adapter,NetXen_I2Q_CLR_PCI_HI));
+ read_unlock(&adapter->adapter_lock);
+
+ DPRINTK(1, INFO, "isr NetXen_I2Q_CLR_PCI_HI = 0x%x \n",i2qhi);
+
+ if (i2qhi & 0x4000) {
+ for (portno = 0; portno < NetXen_NIU_MAX_GBE_PORTS; portno++) {
+ DPRINTK(1, INFO, "External PHY interrupt ON PORT %d\n",
+ portno);
+
+ enable = 1;
+ netxen_handle_port_int(adapter, portno, enable);
+ }
+
+ /* Clear the interrupt on I2Q */
+ //netxen_nic_hw_write(adapter,NetXen_I2Q_CLR_PCI_HI ,&i2qhi,4);
+ read_lock(&adapter->adapter_lock);
+ NetXen_NIC_PCI_WRITE_32((__uint32_t) i2qhi,
+ CRB_NORMALIZE(adapter, NetXen_I2Q_CLR_PCI_HI));
+ read_unlock(&adapter->adapter_lock);
+
+ }
+}
+
+void
+netxen_nic_handle_phy_intr(struct netxen_adapter_s *adapter)
+{
+ uint32_t val, val1;
+
+ switch (adapter->ahw.board_type) {
+ case NetXen_NIC_GBE:
+ //_netxen_nic_read_crb_wx(adapter, ISR_INT_VECTOR, &val);
+ val = NetXen_NIC_PCI_READ_32(CRB_NORMALIZE(adapter,
ISR_INT_VECTOR));
+ if (val & 0x4) {
+ adapter->stats.otherints++;
+ netxen_nic_isr_other(adapter);
+ }
+ break;
+
+ case NetXen_NIC_XGBE:
+ {
+ struct net_device *netdev = adapter->port[0]->netdev;
+
+ /* WINDOW = 1 */
+ //netxen_nic_read_crb_w1(adapter, CRB_XG_STATE, &val1);
+ read_lock(&adapter->adapter_lock);
+ val1 = NetXen_NIC_PCI_READ_32(
+ CRB_NORMALIZE(adapter, CRB_XG_STATE));
+ read_unlock(&adapter->adapter_lock);
+
+ if (adapter->ahw.xg_linkup == 1 && val1 != XG_LINK_UP) {
+ printk(KERN_INFO "%s: %s NIC Link is down\n",
+ netxen_nic_driver_name, netdev->name);
+ adapter->ahw.xg_linkup= 0;
+ /* read twice to clear sticky bits */
+ /* WINDOW = 0 */
+ /*netxen_nic_read_crb_w0(adapter, NetXen_NIU_XG_STATUS,
+ &val1);
+ netxen_nic_read_crb_w0(adapter, NetXen_NIU_XG_STATUS,
+ &val1);*/
+ netxen_nic_read_w0(adapter, NetXen_NIU_XG_STATUS,
+ &val1);
+ netxen_nic_read_w0(adapter, NetXen_NIU_XG_STATUS,
+ &val1);
+
+ if ((val1 & 0xffb ) != 0xffb) {
+ printk(KERN_INFO "%s ISR: Sync/Align BAD:
0x%08x\n",
+ netxen_nic_driver_name, val1);
+ }
+
+ } else if(adapter->ahw.xg_linkup == 0 && val1 == XG_LINK_UP) {
+ printk(KERN_INFO "%s: %s NIC Link is up\n",
+ netxen_nic_driver_name, netdev->name);
+ adapter->ahw.xg_linkup= 1;
+ }
+
+ }
+ break;
+
+ default:
+ printk(KERN_ERR "%s ISR: Unknown board type\n",
+ netxen_nic_driver_name);
+ }
+
+ return;
+}
diff -Naru linux-2.6.16_orig/drivers/net/netxen/xge_mdio.c
linux-2.6.16/drivers/net/netxen/xge_mdio.c
--- linux-2.6.16_orig/drivers/net/netxen/xge_mdio.c 1969-12-31
16:00:00.000000000 -0800
+++ linux-2.6.16/drivers/net/netxen/xge_mdio.c 2006-03-24 14:13:57.000000000
-0800
@@ -0,0 +1,362 @@
+/*
+ * 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:
+ * [EMAIL PROTECTED]
+ * NetXen, 3965 Freedom Circle, Fourth Floor,
+ * Santa Clara, CA 95054
+ */
+/******************************************************************************
+*
+* xge_mdio.c Routines to control the Management Data Input Ouput (MDIO) port
+* for the Aeluros 10Gps Transceiver connected to Phantom II's
+* XGe interface.
+*
+*******************************************************************************
+*/
+
+#include "netxen_inc.h"
+
+/* opcodes defines by Aerulos */
+#define OPCODE_ADDR 0
+#define OPCODE_WRITE 1
+#define OPCODE_RINCR 2
+#define OPCODE_READ 3
+
+/* The MDC/MDIO signals are hooked up to the follwing Phantom GPIO signals */
+#define MDC_GPIO 7
+#define MDIO_GPIO 8
+
+/* Bit 1 of the GPIO reg is Output Enable */
+#define GPIO_OE 2
+
+/* Bit 0 of GPIO reg is data bit */
+#define GPIO_LO 0
+#define GPIO_HI 1
+
+/* Set MDC high or low for clocking data */
+#define MDC_LOW() NetXen_CRB_WRITELIT(NetXen_ROMUSB_GPIO(MDC_GPIO),(GPIO_OE |
GPIO_LO))
+#define MDC_HI() NetXen_CRB_WRITELIT(NetXen_ROMUSB_GPIO(MDC_GPIO), (GPIO_OE |
GPIO_HI))
+
+/* set the data bit */
+#define SET_MDIO(bit)
NetXen_CRB_WRITELIT(NetXen_ROMUSB_GPIO(MDIO_GPIO),(GPIO_OE | (bit)))
+
+/* If necessary, delay beteen each clock */
+#define MDIO_DELAY()
+
+/* The preamble is 32 clocks of high data */
+void PREAMBLE(void) {
+ long i;
+ for (i=0; i< 32;i++) {
+ MDC_LOW();
+ SET_MDIO(1);
+ MDIO_DELAY();
+ MDC_HI();
+ MDIO_DELAY();
+ }
+}
+
+/* data transitions when MDC is low */
+void CLOCK_IN_BITS(long data,long len) {
+ long i;
+ for (i=0;i<len;i++) {
+ MDC_LOW();
+ SET_MDIO((data >>(len - (i + 1))) & 1);
+ MDIO_DELAY();
+ MDC_HI();
+ MDIO_DELAY();
+ }
+}
+
+#define GET_BIT() ((NetXen_CRB_READ_VAL(NetXen_ROMUSB_GLB_PAD_GPIO_I) >>
MDIO_GPIO) & 1)
+
+/* data transitions when MDC is low */
+long CLOCK_OUT_BITS(void) {
+ long i;
+ long result=0;
+
+ /* Don't drive MDIO output */
+ NetXen_CRB_WRITELIT(NetXen_ROMUSB_GPIO(MDIO_GPIO),0x0);\
+
+ for (i=0;i<16;i++) {
+ MDC_LOW();
+ MDIO_DELAY();
+ result |= (GET_BIT() << (15-i));
+ MDIO_DELAY();
+ MDC_HI();
+ MDIO_DELAY();
+ }
+ return result;
+}
+
+/* Turn off Output Enable on the GPIO */
+#define HI_Z() \
+ do {\
+ NetXen_CRB_WRITELIT(NetXen_ROMUSB_GPIO(MDC_GPIO),0x0);\
+ NetXen_CRB_WRITELIT(NetXen_ROMUSB_GPIO(MDIO_GPIO),0x0);\
+ } while(0)
+
+
+/* The STart of Frame (SOF) is two clocks of low data */
+#define SOF() CLOCK_IN_BITS(0,2)
+
+/* The opcode is two bits, high bit first */
+#define OPCODE(opcode) CLOCK_IN_BITS((opcode),2)
+
+/* The port is five bits, high bit first */
+#define PORT_ADDRESS(port) CLOCK_IN_BITS((port),5)
+
+/* The devaddr is five bits, high bit first */
+#define DEV_ADDRESS(dev) CLOCK_IN_BITS((dev),5)
+
+/* The turnaround is two clocks - high, then low */
+#define TURNAROUND() CLOCK_IN_BITS(2,2)
+
+#define ADDR_DATA(addr_data) CLOCK_IN_BITS((addr_data),16)
+
+#define MDIO_WR_CYCLE(opcode, port, dev, addr_data) \
+ do { \
+ PREAMBLE(); \
+ SOF(); \
+ OPCODE((opcode)); \
+ PORT_ADDRESS((port)); \
+ DEV_ADDRESS((dev)); \
+ TURNAROUND(); \
+ ADDR_DATA((addr_data)); \
+ } while (0)
+
+#define RD_DATA() CLOCK_OUT_BITS()
+
+#define MDIO_RD_CYCLE(opcode, port, dev, data) \
+ do { \
+ PREAMBLE(); \
+ SOF(); \
+ OPCODE((opcode)); \
+ PORT_ADDRESS((port)); \
+ DEV_ADDRESS((dev)); \
+ TURNAROUND(); \
+ data = RD_DATA(); \
+ } while (0)
+
+void netxen_xge_mdio_wr (long devaddr, long addr, long data) {
+
+ /* first, write the address */
+ MDIO_WR_CYCLE(OPCODE_ADDR,0,devaddr,addr);
+
+ /* then, write the data */
+ MDIO_WR_CYCLE(OPCODE_WRITE,0,devaddr,data);
+}
+
+long netxen_xge_mdio_rd (long devaddr, long addr) {
+ long data;
+
+ /* first, write the address */
+ MDIO_WR_CYCLE(OPCODE_ADDR,0,devaddr,addr);
+
+ /* then, read the data */
+ MDIO_RD_CYCLE(OPCODE_READ,0,devaddr,data);
+
+ return data;
+}
+
+
+/* AEL1002 supports 3 device addresses: 1(PMA/PMD), 3(PCS), and 4(PHY XS) */
+#define DEV_PMA_PMD 1
+#define DEV_PCS 3
+#define DEV_PHY_XS 4
+
+/* Aeluros-specific registers use device address 1 */
+#define AEL_POWERDOWN_REG 0xc011
+#define AEL_TX_CONFIG_REG_1 0xc002
+#define AEL_LOOPBACK_EN_REG 0xc017
+#define AEL_MODE_SEL_REG 0xc001
+
+#define PMD_RESET 0
+#define PMD_STATUS 1
+#define PMD_IDENTIFIER 2
+#define PCS_STATUS_REG 0x20
+
+#define PMD_ID_QUAKE 0x43
+#define PMD_ID_MYSTICOM 0x240
+#define PCS_CONTROL 0
+
+#define PHY_XS_LANE_STATUS_REG 0x18
+
+/* Turn on the GPIO lines used for MDC/MDIO. They can alternately be used as
+ * test mux data.
+ */
+void netxen_xge_mdio_enable(void) {
+ long data;
+
+ /* GPIO bits are [31:16] in the test mux sel register */
+ /* Turn off the bit to enable GPIO */
+ data = NetXen_CRB_READ_VAL(NetXen_ROMUSB_GLB_TEST_MUX_SEL);
+ data &= ~(0x10000 << MDC_GPIO);
+ data &= ~(0x10000 << MDIO_GPIO);
+ NetXen_CRB_WRITELIT(NetXen_ROMUSB_GLB_TEST_MUX_SEL,data);
+
+ /* Turn off OE for MDC and MDIO */
+ HI_Z();
+}
+
+long xge_link_status (void) {
+ long rv = XG_LINK_DOWN;
+ long data;
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD,PMD_IDENTIFIER);
+ if (data == PMD_ID_QUAKE || data == PMD_ID_MYSTICOM) {
+ /* Quake PHY */
+
+ /* check link - read twice to clear sticky bits */
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD,PMD_STATUS);
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD,PMD_STATUS);
+
+ if (data & 0x4) {
+ /* Rx link is up */
+ rv = XG_LINK_UP;
+ } else {
+ rv = XG_LINK_DOWN;
+ }
+
+ } else {
+ data = netxen_xge_mdio_rd(DEV_PCS,PCS_STATUS_REG);
+ if ((data & 0x1000) == 0x1000) {
+ rv = XG_LINK_UP;
+ }
+ }
+ return rv;
+}
+
+/* For Mysticom M3128 */
+void xge_m3128_clear_int(void) {
+ /* For Mysticom M3128, clear 3.c005 that shows link up/down event. */
+ netxen_xge_mdio_wr(3, 0xc005, -1);
+}
+/* Initialize the Aeluros device. To be done when link first comes up */
+long xge_mdio_init(void) {
+ long rv=0;
+ long data;
+
+ netxen_xge_mdio_enable();
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD,PMD_IDENTIFIER);
+ if (data == PMD_ID_QUAKE ) {
+ /* Quake PHY */
+ /* reset PHY */
+ netxen_xge_mdio_wr(DEV_PCS,PCS_CONTROL, 0x8000 );
+
+ /* check link - read twice to clear sticky bits */
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD,PMD_STATUS);
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD,PMD_STATUS);
+
+ if(! (data & 0x4)) {
+ rv |= 2;
+ }
+
+ } else if (data == PMD_ID_MYSTICOM) {
+ /* Mysticom PHY */
+ /* reset PHY */
+ netxen_xge_mdio_wr(DEV_PCS,PCS_CONTROL, 0x8000 );
+
+ /* check link - read twice to clear sticky bits */
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD,PMD_STATUS);
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD,PMD_STATUS);
+
+ if(!(data & 0x4)) {
+ rv |= 2;
+ }
+
+ xge_m3128_clear_int();
+
+ /* Enable the mask for link up/down events in 3.c006 */
+ netxen_xge_mdio_wr(3, 0xc006, 0xc000);
+
+ } else {
+
+ netxen_xge_mdio_wr(DEV_PMA_PMD,AEL_POWERDOWN_REG, 0);
+ netxen_xge_mdio_wr(DEV_PMA_PMD,AEL_TX_CONFIG_REG_1,1);
+ netxen_xge_mdio_wr(DEV_PMA_PMD,AEL_LOOPBACK_EN_REG,0xfe30);
+ netxen_xge_mdio_wr(DEV_PMA_PMD,AEL_MODE_SEL_REG, 0x24);
+
+ data = netxen_xge_mdio_rd(DEV_PCS,PCS_STATUS_REG);
+
+ if (!(data & 0x1000)) {
+ rv |= 2;
+ }
+
+ data = netxen_xge_mdio_rd(DEV_PHY_XS,PHY_XS_LANE_STATUS_REG);
+
+ if (!(data & 0x000f)) {
+ rv |= 1;
+ }
+
+ }
+
+ return rv;
+
+}
+
+void xge_loopback(int on)
+{
+ long data;
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD,PMD_IDENTIFIER);
+
+ switch (data) {
+ case PMD_ID_QUAKE:
+ if (on) {
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD, 0);
+ netxen_xge_mdio_wr(DEV_PMA_PMD, 0, data | 1);
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD, 0xC001);
+ netxen_xge_mdio_wr(DEV_PMA_PMD, 0xC001, data |
0x8000);
+ } else {
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD, 0xC001);
+ netxen_xge_mdio_wr(DEV_PMA_PMD, 0xC001, data &
~0x8000);
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD, 0);
+ netxen_xge_mdio_wr(DEV_PMA_PMD, 0, data & ~1);
+ }
+ break;
+
+ case PMD_ID_MYSTICOM:
+ if (on) {
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD, 0);
+ netxen_xge_mdio_wr(DEV_PMA_PMD, 0, data | 0x40);
+ } else {
+ netxen_xge_mdio_wr(DEV_PMA_PMD, 0, data &
~0x40);
+ }
+ break;
+
+ /* Puma PHY */
+ default:
+ if (on) {
+ /* Get - read twice to clear sticky bits */
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD,
AEL_LOOPBACK_EN_REG);
+ netxen_xge_mdio_wr(DEV_PMA_PMD,
AEL_LOOPBACK_EN_REG, data | 4);
+ data = netxen_xge_mdio_rd(DEV_PHY_XS, 0xC000);
+ netxen_xge_mdio_wr(DEV_PHY_XS, 0xC000, data |
0x8000);
+ } else {
+ data = netxen_xge_mdio_rd(DEV_PHY_XS, 0xC000);
+ netxen_xge_mdio_wr(DEV_PHY_XS, 0xC000, data &
~0x8000);
+ data = netxen_xge_mdio_rd(DEV_PMA_PMD,
AEL_LOOPBACK_EN_REG);
+ netxen_xge_mdio_wr(DEV_PMA_PMD,
AEL_LOOPBACK_EN_REG, data & ~4);
+ }
+ break;
+ }
+}
+
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html