Merge /pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / drivers / net / netxen / netxen_nic_isr.c
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  */
41 struct 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
69 void 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
79 void 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
138 void 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
167 void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter)
168 {
169         netxen_nic_isr_other(adapter);
170 }
171
172 void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter)
173 {
174         struct net_device *netdev = adapter->netdev;
175         u32 val, val1;
176
177         /* WINDOW = 1 */
178         val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
179         val >>= (physical_port[adapter->portnum] * 8);
180         val1 = val & 0xff;
181
182         if (adapter->ahw.xg_linkup == 1 && val1 != XG_LINK_UP) {
183                 printk(KERN_INFO "%s: %s NIC Link is down\n",
184                        netxen_nic_driver_name, netdev->name);
185                 adapter->ahw.xg_linkup = 0;
186                 /* read twice to clear sticky bits */
187                 /* WINDOW = 0 */
188                 netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1);
189                 netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1);
190
191                 if ((val & 0xffb) != 0xffb) {
192                         printk(KERN_INFO "%s ISR: Sync/Align BAD: 0x%08x\n",
193                                netxen_nic_driver_name, val1);
194                 }
195         } else if (adapter->ahw.xg_linkup == 0 && val1 == XG_LINK_UP) {
196                 printk(KERN_INFO "%s: %s NIC Link is up\n",
197                        netxen_nic_driver_name, netdev->name);
198                 adapter->ahw.xg_linkup = 1;
199         }
200 }