diff options
Diffstat (limited to 'drivers/net/netxen/netxen_nic_niu.c')
-rw-r--r-- | drivers/net/netxen/netxen_nic_niu.c | 898 |
1 files changed, 898 insertions, 0 deletions
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c new file mode 100644 index 00000000000..4987dc765d9 --- /dev/null +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -0,0 +1,898 @@ +/* + * 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 0x00000020 + +static 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 phy, + long reg, __le32 * readval) +{ + long timeout = 0; + long result = 0; + long restore = 0; + __le32 address; + __le32 command; + __le32 status; + __le32 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)) { + __le32 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 phy, long reg, __le32 val) +{ + long timeout = 0; + long result = 0; + long restore = 0; + __le32 address; + __le32 command; + __le32 status; + __le32 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)) { + __le32 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, + int port) +{ + netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x3f); + return 0; +} + +int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter, + int port) +{ + int result = 0; + __le32 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, port, + NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, + enable)) + result = -EIO; + + return result; +} + +int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter, + int port) +{ + netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x7f); + return 0; +} + +int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter, + int port) +{ + int result = 0; + if (0 != + netxen_niu_gbe_phy_write(adapter, port, + NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, 0)) + result = -EIO; + + return result; +} + +int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter, + int port) +{ + netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1); + return 0; +} + +int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter, + int port) +{ + int result = 0; + if (0 != + netxen_niu_gbe_phy_write(adapter, port, + 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, port)) + printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); + if (netxen_niu_gbe_clear_phy_interrupts(adapter, port)) + 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, port)) + printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); + if (netxen_niu_gbe_clear_phy_interrupts(adapter, port)) + printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); +} + +int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) +{ + int result = 0; + __le32 status; + if (adapter->disable_phy_interrupts) + adapter->disable_phy_interrupts(adapter, port); + mdelay(2); + + if (0 == + netxen_niu_gbe_phy_read(adapter, port, + NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + (__le32 *) & 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, port)) + printk(KERN_ERR PFX + "ERROR clearing PHY interrupts\n"); + if (netxen_niu_gbe_enable_phy_interrupts(adapter, port)) + printk(KERN_ERR PFX + "ERROR enabling PHY interrupts\n"); + if (netxen_niu_gbe_clear_phy_interrupts(adapter, port)) + 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) +{ + long reg = 0, ret = 0; + + if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) { + netxen_crb_writelit_adapter(adapter, + NETXEN_NIU_XG1_CONFIG_0, 0x5); + /* XXX hack for Mez cards: both ports in promisc mode */ + netxen_nic_hw_read_wx(adapter, + NETXEN_NIU_XGE_CONFIG_1, ®, 4); + reg = (reg | 0x2000UL); + netxen_crb_writelit_adapter(adapter, + NETXEN_NIU_XGE_CONFIG_1, reg); + reg = 0; + netxen_nic_hw_read_wx(adapter, + NETXEN_NIU_XG1_CONFIG_1, ®, 4); + reg = (reg | 0x2000UL); + netxen_crb_writelit_adapter(adapter, + NETXEN_NIU_XG1_CONFIG_1, reg); + } + + return ret; +} + +/* + * netxen_niu_gbe_handle_phy_interrupt - Handles GbE PHY interrupts + * @param enable 0 means don't enable the port + * 1 means enable (or re-enable) the port + */ +int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, + int port, long enable) +{ + int result = 0; + __le32 int_src; + + printk(KERN_INFO PFX "NETXEN: Handling PHY interrupt on port %d" + " (device enable = %d)\n", (int)port, (int)enable); + + /* + * The read of the PHY INT status will clear the pending + * interrupt status + */ + if (netxen_niu_gbe_phy_read(adapter, port, + NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, + &int_src) != 0) + result = -EINVAL; + else { + printk(KERN_INFO PFX "PHY Interrupt source = 0x%x \n", int_src); + if (netxen_get_phy_int_jabber(int_src)) + printk(KERN_INFO PFX "jabber Interrupt "); + if (netxen_get_phy_int_polarity_changed(int_src)) + printk(KERN_INFO PFX "polarity changed "); + if (netxen_get_phy_int_energy_detect(int_src)) + printk(KERN_INFO PFX "energy detect \n"); + if (netxen_get_phy_int_downshift(int_src)) + printk(KERN_INFO PFX "downshift \n"); + if (netxen_get_phy_int_mdi_xover_changed(int_src)) + printk(KERN_INFO PFX "mdi_xover_changed "); + if (netxen_get_phy_int_fifo_over_underflow(int_src)) + printk(KERN_INFO PFX "fifo_over_underflow "); + if (netxen_get_phy_int_false_carrier(int_src)) + printk(KERN_INFO PFX "false_carrier "); + if (netxen_get_phy_int_symbol_error(int_src)) + printk(KERN_INFO PFX "symbol_error "); + if (netxen_get_phy_int_autoneg_completed(int_src)) + printk(KERN_INFO PFX "autoneg_completed "); + if (netxen_get_phy_int_page_received(int_src)) + printk(KERN_INFO PFX "page_received "); + if (netxen_get_phy_int_duplex_changed(int_src)) + printk(KERN_INFO PFX "duplex_changed "); + if (netxen_get_phy_int_autoneg_error(int_src)) + printk(KERN_INFO PFX "autoneg_error "); + if ((netxen_get_phy_int_speed_changed(int_src)) + || (netxen_get_phy_int_link_status_changed(int_src))) { + __le32 status; + + printk(KERN_INFO PFX + "speed_changed or link status changed"); + if (netxen_niu_gbe_phy_read + (adapter, port, + NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + &status) == 0) { + if (netxen_get_phy_speed(status) == 2) { + printk + (KERN_INFO PFX "Link speed changed" + " to 1000 Mbps\n"); + netxen_niu_gbe_set_gmii_mode(adapter, + port, + enable); + } else if (netxen_get_phy_speed(status) == 1) { + printk + (KERN_INFO PFX "Link speed changed" + " to 100 Mbps\n"); + netxen_niu_gbe_set_mii_mode(adapter, + port, + enable); + } else if (netxen_get_phy_speed(status) == 0) { + printk + (KERN_INFO PFX "Link speed changed" + " to 10 Mbps\n"); + netxen_niu_gbe_set_mii_mode(adapter, + port, + enable); + } else { + printk(KERN_ERR PFX "ERROR reading" + "PHY status. Illegal speed.\n"); + result = -1; + } + } else { + printk(KERN_ERR PFX + "ERROR reading PHY status.\n"); + result = -1; + } + + } + printk(KERN_INFO "\n"); + } + return result; +} + +/* + * Return the current station MAC address. + * Note that the passed-in value must already be in network byte order. + */ +int netxen_niu_macaddr_get(struct netxen_adapter *adapter, + int phy, netxen_ethernet_macaddr_t * addr) +{ + u64 result = 0; + __le32 stationhigh; + __le32 stationlow; + + if (addr == NULL) + return -EINVAL; + if ((phy < 0) || (phy > 3)) + return -EINVAL; + + if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), + &stationhigh, 4)) + return -EIO; + if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), + &stationlow, 4)) + return -EIO; + + result = (u64) netxen_gb_get_stationaddress_low(stationlow); + result |= (u64) stationhigh << 16; + memcpy(*addr, &result, sizeof(netxen_ethernet_macaddr_t)); + + return 0; +} + +/* + * Set the station MAC address. + * Note that the passed-in value must already be in network byte order. + */ +int netxen_niu_macaddr_set(struct netxen_port *port, + netxen_ethernet_macaddr_t addr) +{ + __le32 temp = 0; + struct netxen_adapter *adapter = port->adapter; + int phy = port->portnum; + unsigned char mac_addr[6]; + int i; + + for (i = 0; i < 10; i++) { + memcpy(&temp, addr, 2); + temp <<= 16; + if (netxen_nic_hw_write_wx + (adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), &temp, 4)) + return -EIO; + + temp = 0; + + memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); + if (netxen_nic_hw_write_wx + (adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &temp, 4)) + return -2; + + netxen_niu_macaddr_get(adapter, phy, + (netxen_ethernet_macaddr_t *) mac_addr); + if (memcmp(mac_addr, addr, 6) == 0) + break; + } + + if (i == 10) { + printk(KERN_ERR "%s: cannot set Mac addr for %s\n", + netxen_nic_driver_name, port->netdev->name); + printk(KERN_ERR "MAC address set: " + "%02x:%02x:%02x:%02x:%02x:%02x.\n", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + + printk(KERN_ERR "MAC address get: " + "%02x:%02x:%02x:%02x:%02x:%02x.\n", + mac_addr[0], + mac_addr[1], + mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + } + return 0; +} + +/* Enable a GbE interface */ +int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter, + int port, netxen_niu_gbe_ifmode_t mode) +{ + __le32 mac_cfg0; + __le32 mac_cfg1; + __le32 mii_cfg; + + if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) + return -EINVAL; + + mac_cfg0 = 0; + netxen_gb_soft_reset(mac_cfg0); + if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), + &mac_cfg0, 4)) + return -EIO; + mac_cfg0 = 0; + netxen_gb_enable_tx(mac_cfg0); + netxen_gb_enable_rx(mac_cfg0); + netxen_gb_unset_rx_flowctl(mac_cfg0); + netxen_gb_tx_reset_pb(mac_cfg0); + netxen_gb_rx_reset_pb(mac_cfg0); + netxen_gb_tx_reset_mac(mac_cfg0); + netxen_gb_rx_reset_mac(mac_cfg0); + + if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), + &mac_cfg0, 4)) + return -EIO; + mac_cfg1 = 0; + netxen_gb_set_preamblelen(mac_cfg1, 0xf); + netxen_gb_set_duplex(mac_cfg1); + netxen_gb_set_crc_enable(mac_cfg1); + netxen_gb_set_padshort(mac_cfg1); + netxen_gb_set_checklength(mac_cfg1); + netxen_gb_set_hugeframes(mac_cfg1); + + if (mode == NETXEN_NIU_10_100_MB) { + netxen_gb_set_intfmode(mac_cfg1, 1); + if (netxen_nic_hw_write_wx(adapter, + NETXEN_NIU_GB_MAC_CONFIG_1(port), + &mac_cfg1, 4)) + return -EIO; + + /* set mii mode */ + 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); + + } else if (mode == NETXEN_NIU_1000_MB) { + netxen_gb_set_intfmode(mac_cfg1, 2); + if (netxen_nic_hw_write_wx(adapter, + NETXEN_NIU_GB_MAC_CONFIG_1(port), + &mac_cfg1, 4)) + return -EIO; + /* set gmii mode */ + 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); + } + mii_cfg = 0; + netxen_gb_set_mii_mgmt_clockselect(mii_cfg, 7); + if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port), + &mii_cfg, 4)) + return -EIO; + mac_cfg0 = 0; + netxen_gb_enable_tx(mac_cfg0); + netxen_gb_enable_rx(mac_cfg0); + netxen_gb_unset_rx_flowctl(mac_cfg0); + netxen_gb_unset_tx_flowctl(mac_cfg0); + + if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), + &mac_cfg0, 4)) + return -EIO; + return 0; +} + +/* Disable a GbE interface */ +int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port) +{ + __le32 mac_cfg0; + + if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) + return -EINVAL; + + mac_cfg0 = 0; + netxen_gb_soft_reset(mac_cfg0); + if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), + &mac_cfg0, 4)) + return -EIO; + return 0; +} + +/* Disable an XG interface */ +int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port) +{ + __le32 mac_cfg; + + if (port != 0) + return -EINVAL; + + mac_cfg = 0; + netxen_xg_soft_reset(mac_cfg); + if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_CONFIG_0, + &mac_cfg, 4)) + return -EIO; + return 0; +} + +/* Set promiscuous mode for a GbE interface */ +int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port, + netxen_niu_prom_mode_t mode) +{ + __le32 reg; + + if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) + return -EINVAL; + + /* save previous contents */ + if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, + ®, 4)) + return -EIO; + if (mode == NETXEN_NIU_PROMISC_MODE) { + switch (port) { + case 0: + netxen_clear_gb_drop_gb0(reg); + break; + case 1: + netxen_clear_gb_drop_gb1(reg); + break; + case 2: + netxen_clear_gb_drop_gb2(reg); + break; + case 3: + netxen_clear_gb_drop_gb3(reg); + break; + default: + return -EIO; + } + } else { + switch (port) { + case 0: + netxen_set_gb_drop_gb0(reg); + break; + case 1: + netxen_set_gb_drop_gb1(reg); + break; + case 2: + netxen_set_gb_drop_gb2(reg); + break; + case 3: + netxen_set_gb_drop_gb3(reg); + break; + default: + return -EIO; + } + } + if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, + ®, 4)) + return -EIO; + return 0; +} + +/* + * Set the MAC address for an XG port + * Note that the passed-in value must already be in network byte order. + */ +int netxen_niu_xg_macaddr_set(struct netxen_port *port, + netxen_ethernet_macaddr_t addr) +{ + __le32 temp = 0; + struct netxen_adapter *adapter = port->adapter; + + memcpy(&temp, addr, 2); + temp = cpu_to_le32(temp); + temp <<= 16; + if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, + &temp, 4)) + return -EIO; + + temp = 0; + + memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); + temp = cpu_to_le32(temp); + if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, + &temp, 4)) + return -EIO; + + return 0; +} + +/* + * Return the current station MAC address. + * Note that the passed-in value must already be in network byte order. + */ +int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy, + netxen_ethernet_macaddr_t * addr) +{ + __le32 stationhigh; + __le32 stationlow; + u64 result; + + if (addr == NULL) + return -EINVAL; + if (phy != 0) + return -EINVAL; + + if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, + &stationhigh, 4)) + return -EIO; + if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, + &stationlow, 4)) + return -EIO; + + result = ((u64) stationlow) >> 16; + result |= (u64) stationhigh << 16; + memcpy(*addr, &result, sizeof(netxen_ethernet_macaddr_t)); + + return 0; +} + +int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, + int port, netxen_niu_prom_mode_t mode) +{ + __le32 reg; + + if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) + return -EINVAL; + + if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_CONFIG_1, ®, 4)) + return -EIO; + if (mode == NETXEN_NIU_PROMISC_MODE) + reg = (reg | 0x2000UL); + else + reg = (reg & ~0x2000UL); + + netxen_crb_writelit_adapter(adapter, NETXEN_NIU_XGE_CONFIG_1, reg); + + return 0; +} |