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