1/* 2 * Copyright (C) 2003 - 2006 NetXen, Inc. 3 * All rights reserved. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License 7 * as published by the Free Software Foundation; either version 2 8 * of the License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 18 * MA 02111-1307, USA. 19 * 20 * The full GNU General Public License is included in this distribution 21 * in the file called LICENSE. 22 * 23 * Contact Information: 24 * info@netxen.com 25 * NetXen, 26 * 3965 Freedom Circle, Fourth floor, 27 * Santa Clara, CA 95054 28 */ 29 30#include <linux/netdevice.h> 31#include <linux/delay.h> 32 33#include "netxen_nic.h" 34#include "netxen_nic_hw.h" 35#include "netxen_nic_phan_reg.h" 36 37/* 38 * netxen_nic_get_stats - Get System Network Statistics 39 * @netdev: network interface device structure 40 */ 41struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) 42{ 43 struct netxen_adapter *adapter = netdev_priv(netdev); 44 struct net_device_stats *stats = &adapter->net_stats; 45 46 memset(stats, 0, sizeof(*stats)); 47 48 /* total packets received */ 49 stats->rx_packets = adapter->stats.no_rcv; 50 /* total packets transmitted */ 51 stats->tx_packets = adapter->stats.xmitedframes + 52 adapter->stats.xmitfinished; 53 /* total bytes received */ 54 stats->rx_bytes = adapter->stats.rxbytes; 55 /* total bytes transmitted */ 56 stats->tx_bytes = adapter->stats.txbytes; 57 /* bad packets received */ 58 stats->rx_errors = adapter->stats.rcvdbadskb; 59 /* packet transmit problems */ 60 stats->tx_errors = adapter->stats.nocmddescriptor; 61 /* no space in linux buffers */ 62 stats->rx_dropped = adapter->stats.updropped; 63 /* no space available in linux */ 64 stats->tx_dropped = adapter->stats.txdropped; 65 66 return stats; 67} 68 69void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link) 70{ 71 struct net_device *netdev = adapter->netdev; 72 73 if (link) 74 netif_carrier_on(netdev); 75 else 76 netif_carrier_off(netdev); 77} 78 79void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable) 80{ 81 __u32 int_src; 82 83 /* This should clear the interrupt source */ 84 if (adapter->phy_read) 85 adapter->phy_read(adapter, 86 NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, 87 &int_src); 88 if (int_src == 0) { 89 DPRINTK(INFO, "No phy interrupts for port #%d\n", portno); 90 return; 91 } 92 if (adapter->disable_phy_interrupts) 93 adapter->disable_phy_interrupts(adapter); 94 95 if (netxen_get_phy_int_jabber(int_src)) 96 DPRINTK(INFO, "Jabber interrupt \n"); 97 98 if (netxen_get_phy_int_polarity_changed(int_src)) 99 DPRINTK(INFO, "POLARITY CHANGED int \n"); 100 101 if (netxen_get_phy_int_energy_detect(int_src)) 102 DPRINTK(INFO, "ENERGY DETECT INT \n"); 103 104 if (netxen_get_phy_int_downshift(int_src)) 105 DPRINTK(INFO, "DOWNSHIFT INT \n"); 106 /* write it down later.. */ 107 if ((netxen_get_phy_int_speed_changed(int_src)) 108 || (netxen_get_phy_int_link_status_changed(int_src))) { 109 __u32 status; 110 111 DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n"); 112 113 if (adapter->phy_read 114 && adapter->phy_read(adapter, 115 NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, 116 &status) == 0) { 117 if (netxen_get_phy_int_link_status_changed(int_src)) { 118 if (netxen_get_phy_link(status)) { 119 printk(KERN_INFO "%s: %s Link UP\n", 120 netxen_nic_driver_name, 121 adapter->netdev->name); 122 123 } else { 124 printk(KERN_INFO "%s: %s Link DOWN\n", 125 netxen_nic_driver_name, 126 adapter->netdev->name); 127 } 128 netxen_indicate_link_status(adapter, 129 netxen_get_phy_link 130 (status)); 131 } 132 } 133 } 134 if (adapter->enable_phy_interrupts) 135 adapter->enable_phy_interrupts(adapter); 136} 137 138void netxen_nic_isr_other(struct netxen_adapter *adapter) 139{ 140 int portno = adapter->portnum; 141 u32 val, linkup, qg_linksup; 142 143 /* verify the offset */ 144 val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE)); 145 val = val >> physical_port[adapter->portnum]; 146 if (val == adapter->ahw.qg_linksup) 147 return; 148 149 qg_linksup = adapter->ahw.qg_linksup; 150 adapter->ahw.qg_linksup = val; 151 DPRINTK(INFO, "link update 0x%08x\n", val); 152 153 linkup = val & 1; 154 155 if (linkup != (qg_linksup & 1)) { 156 printk(KERN_INFO "%s: %s PORT %d link %s\n", 157 adapter->netdev->name, 158 netxen_nic_driver_name, portno, 159 ((linkup == 0) ? "down" : "up")); 160 netxen_indicate_link_status(adapter, linkup); 161 if (linkup) 162 netxen_nic_set_link_parameters(adapter); 163 164 } 165} 166 167void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter) 168{ 169 netxen_nic_isr_other(adapter); 170} 171 172int netxen_nic_link_ok(struct netxen_adapter *adapter) 173{ 174 switch (adapter->ahw.board_type) { 175 case NETXEN_NIC_GBE: 176 return ((adapter->ahw.qg_linksup) & 1); 177 178 case NETXEN_NIC_XGBE: 179 return ((adapter->ahw.xg_linkup) & 1); 180 181 default: 182 printk(KERN_ERR"%s: Function: %s, Unknown board type\n", 183 netxen_nic_driver_name, __FUNCTION__); 184 break; 185 } 186 187 return 0; 188} 189 190void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter) 191{ 192 struct net_device *netdev = adapter->netdev; 193 u32 val, val1; 194 195 /* WINDOW = 1 */ 196 val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE)); 197 val >>= (physical_port[adapter->portnum] * 8); 198 val1 = val & 0xff; 199 200 if (adapter->ahw.xg_linkup == 1 && val1 != XG_LINK_UP) { 201 printk(KERN_INFO "%s: %s NIC Link is down\n", 202 netxen_nic_driver_name, netdev->name); 203 adapter->ahw.xg_linkup = 0; 204 if (netif_running(netdev)) { 205 netif_carrier_off(netdev); 206 netif_stop_queue(netdev); 207 } 208 /* read twice to clear sticky bits */ 209 /* WINDOW = 0 */ 210 netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1); 211 netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1); 212 213 if ((val & 0xffb) != 0xffb) { 214 printk(KERN_INFO "%s ISR: Sync/Align BAD: 0x%08x\n", 215 netxen_nic_driver_name, val1); 216 } 217 } else if (adapter->ahw.xg_linkup == 0 && val1 == XG_LINK_UP) { 218 printk(KERN_INFO "%s: %s NIC Link is up\n", 219 netxen_nic_driver_name, netdev->name); 220 adapter->ahw.xg_linkup = 1; 221 netif_carrier_on(netdev); 222 netif_wake_queue(netdev); 223 } 224} 225