netxen_nic_isr.c 6.0 KB
Newer Older
A
Amit S. Kale 已提交
1 2 3
/*
 * Copyright (C) 2003 - 2006 NetXen, Inc.
 * All rights reserved.
4
 *
A
Amit S. Kale 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * 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.
19
 *
A
Amit S. Kale 已提交
20 21
 * The full GNU General Public License is included in this distribution
 * in the file called LICENSE.
22
 *
A
Amit S. Kale 已提交
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
 * Contact Information:
 *    info@netxen.com
 * 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 "netxen_nic_phan_reg.h"

/*
 * netxen_nic_get_stats - Get System Network Statistics
 * @netdev: network interface device structure
 */
struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
{
	struct netxen_port *port = netdev_priv(netdev);
	struct net_device_stats *stats = &port->net_stats;

	memset(stats, 0, sizeof(*stats));

	/* total packets received   */
	stats->rx_packets = port->stats.no_rcv;
	/* total packets transmitted    */
	stats->tx_packets = port->stats.xmitedframes + port->stats.xmitfinished;
	/* total bytes received     */
	stats->rx_bytes = port->stats.rxbytes;
	/* total bytes transmitted  */
	stats->tx_bytes = port->stats.txbytes;
	/* bad packets received     */
	stats->rx_errors = port->stats.rcvdbadskb;
	/* packet transmit problems */
	stats->tx_errors = port->stats.nocmddescriptor;
	/* no space in linux buffers    */
	stats->rx_dropped = port->stats.updropped;
	/* no space available in linux  */
	stats->tx_dropped = port->stats.txdropped;

	return stats;
}

void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno,
				 u32 link)
{
71
	struct net_device *netdev = (adapter->port[portno])->netdev;
A
Amit S. Kale 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84 85

	if (link)
		netif_carrier_on(netdev);
	else
		netif_carrier_off(netdev);
}

void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno,
			    u32 enable)
{
	__le32 int_src;
	struct netxen_port *port;

	/*  This should clear the interrupt source */
86 87 88 89
	if (adapter->phy_read)
		adapter->phy_read(adapter, portno,
				  NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
				  &int_src);
A
Amit S. Kale 已提交
90 91 92 93
	if (int_src == 0) {
		DPRINTK(INFO, "No phy interrupts for port #%d\n", portno);
		return;
	}
94 95
	if (adapter->disable_phy_interrupts)
		adapter->disable_phy_interrupts(adapter, portno);
A
Amit S. Kale 已提交
96 97 98 99

	port = adapter->port[portno];

	if (netxen_get_phy_int_jabber(int_src))
100
		DPRINTK(INFO, "Jabber interrupt \n");
A
Amit S. Kale 已提交
101 102

	if (netxen_get_phy_int_polarity_changed(int_src))
103
		DPRINTK(INFO, "POLARITY CHANGED int \n");
A
Amit S. Kale 已提交
104 105

	if (netxen_get_phy_int_energy_detect(int_src))
106
		DPRINTK(INFO, "ENERGY DETECT INT \n");
A
Amit S. Kale 已提交
107 108

	if (netxen_get_phy_int_downshift(int_src))
109
		DPRINTK(INFO, "DOWNSHIFT INT \n");
A
Amit S. Kale 已提交
110 111 112 113 114
	/* write it down later.. */
	if ((netxen_get_phy_int_speed_changed(int_src))
	    || (netxen_get_phy_int_link_status_changed(int_src))) {
		__le32 status;

115
		DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n");
A
Amit S. Kale 已提交
116

117 118 119 120
		if (adapter->phy_read
		    && adapter->phy_read(adapter, portno,
					 NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
					 &status) == 0) {
A
Amit S. Kale 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
			if (netxen_get_phy_int_link_status_changed(int_src)) {
				if (netxen_get_phy_link(status)) {
					netxen_niu_gbe_init_port(adapter,
								 portno);
					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,
							    netxen_get_phy_link
							    (status));
			}
		}
	}
140 141
	if (adapter->enable_phy_interrupts)
		adapter->enable_phy_interrupts(adapter, portno);
A
Amit S. Kale 已提交
142 143 144 145
}

void netxen_nic_isr_other(struct netxen_adapter *adapter)
{
146 147
	u32 portno;
	u32 val, linkup, qg_linksup;
A
Amit S. Kale 已提交
148 149

	/* verify the offset */
150 151 152
	val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
	if (val == adapter->ahw.qg_linksup)
		return;
A
Amit S. Kale 已提交
153

154 155
	qg_linksup = adapter->ahw.qg_linksup;
	adapter->ahw.qg_linksup = val;
156
	DPRINTK(INFO, "link update 0x%08x\n", val);
157 158 159 160 161 162 163 164 165 166
	for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) {
		linkup = val & 1;
		if (linkup != (qg_linksup & 1)) {
			printk(KERN_INFO "%s: PORT %d link %s\n",
			       netxen_nic_driver_name, portno,
			       ((linkup == 0) ? "down" : "up"));
			netxen_indicate_link_status(adapter, portno, linkup);
			if (linkup)
				netxen_nic_set_link_parameters(adapter->
							       port[portno]);
A
Amit S. Kale 已提交
167 168

		}
169 170 171
		val = val >> 1;
		qg_linksup = qg_linksup >> 1;
	}
A
Amit S. Kale 已提交
172

173
	adapter->stats.otherints++;
A
Amit S. Kale 已提交
174 175 176 177 178

}

void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter)
{
179
	netxen_nic_isr_other(adapter);
A
Amit S. Kale 已提交
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
}

void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter)
{
	struct net_device *netdev = adapter->port[0]->netdev;
	u32 val;

	/* WINDOW = 1 */
	val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));

	if (adapter->ahw.xg_linkup == 1 && val != 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_w0(adapter, NETXEN_NIU_XG_STATUS, &val);
		netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val);

		if ((val & 0xffb) != 0xffb) {
			printk(KERN_INFO "%s ISR: Sync/Align BAD: 0x%08x\n",
			       netxen_nic_driver_name, val);
		}
	} else if (adapter->ahw.xg_linkup == 0 && val == XG_LINK_UP) {
		printk(KERN_INFO "%s: %s NIC Link is up\n",
		       netxen_nic_driver_name, netdev->name);
		adapter->ahw.xg_linkup = 1;
	}
}