Merge branch 'task_killable' of git://git.kernel.org/pub/scm/linux/kernel/git/willy...
[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 static void netxen_indicate_link_status(struct netxen_adapter *adapter,
70                                         u32 link)
71 {
72         struct net_device *netdev = adapter->netdev;
73
74         if (link)
75                 netif_carrier_on(netdev);
76         else
77                 netif_carrier_off(netdev);
78 }
79
80 #if 0
81 void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable)
82 {
83         __u32 int_src;
84
85         /*  This should clear the interrupt source */
86         if (adapter->phy_read)
87                 adapter->phy_read(adapter,
88                                   NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
89                                   &int_src);
90         if (int_src == 0) {
91                 DPRINTK(INFO, "No phy interrupts for port #%d\n", portno);
92                 return;
93         }
94         if (adapter->disable_phy_interrupts)
95                 adapter->disable_phy_interrupts(adapter);
96
97         if (netxen_get_phy_int_jabber(int_src))
98                 DPRINTK(INFO, "Jabber interrupt \n");
99
100         if (netxen_get_phy_int_polarity_changed(int_src))
101                 DPRINTK(INFO, "POLARITY CHANGED int \n");
102
103         if (netxen_get_phy_int_energy_detect(int_src))
104                 DPRINTK(INFO, "ENERGY DETECT INT \n");
105
106         if (netxen_get_phy_int_downshift(int_src))
107                 DPRINTK(INFO, "DOWNSHIFT INT \n");
108         /* write it down later.. */
109         if ((netxen_get_phy_int_speed_changed(int_src))
110             || (netxen_get_phy_int_link_status_changed(int_src))) {
111                 __u32 status;
112
113                 DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n");
114
115                 if (adapter->phy_read
116                     && adapter->phy_read(adapter,
117                                          NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
118                                          &status) == 0) {
119                         if (netxen_get_phy_int_link_status_changed(int_src)) {
120                                 if (netxen_get_phy_link(status)) {
121                                         printk(KERN_INFO "%s: %s Link UP\n",
122                                                netxen_nic_driver_name,
123                                                adapter->netdev->name);
124
125                                 } else {
126                                         printk(KERN_INFO "%s: %s Link DOWN\n",
127                                                netxen_nic_driver_name,
128                                                adapter->netdev->name);
129                                 }
130                                 netxen_indicate_link_status(adapter,
131                                                             netxen_get_phy_link
132                                                             (status));
133                         }
134                 }
135         }
136         if (adapter->enable_phy_interrupts)
137                 adapter->enable_phy_interrupts(adapter);
138 }
139 #endif  /*  0  */
140
141 static void netxen_nic_isr_other(struct netxen_adapter *adapter)
142 {
143         int portno = adapter->portnum;
144         u32 val, linkup, qg_linksup;
145
146         /* verify the offset */
147         val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
148         val = val >> physical_port[adapter->portnum];
149         if (val == adapter->ahw.qg_linksup)
150                 return;
151
152         qg_linksup = adapter->ahw.qg_linksup;
153         adapter->ahw.qg_linksup = val;
154         DPRINTK(INFO, "link update 0x%08x\n", val);
155
156         linkup = val & 1;
157
158         if (linkup != (qg_linksup & 1)) {
159                 printk(KERN_INFO "%s: %s PORT %d link %s\n",
160                        adapter->netdev->name,
161                        netxen_nic_driver_name, portno,
162                        ((linkup == 0) ? "down" : "up"));
163                 netxen_indicate_link_status(adapter, linkup);
164                 if (linkup)
165                         netxen_nic_set_link_parameters(adapter);
166
167         }
168 }
169
170 void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter)
171 {
172         netxen_nic_isr_other(adapter);
173 }
174
175 int netxen_nic_link_ok(struct netxen_adapter *adapter)
176 {
177         switch (adapter->ahw.board_type) {
178         case NETXEN_NIC_GBE:
179                 return ((adapter->ahw.qg_linksup) & 1);
180
181         case NETXEN_NIC_XGBE:
182                 return ((adapter->ahw.xg_linkup) & 1);
183
184         default:
185                 printk(KERN_ERR"%s: Function: %s, Unknown board type\n",
186                         netxen_nic_driver_name, __FUNCTION__);
187                 break;
188         }
189
190         return 0;
191 }
192
193 void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter)
194 {
195         struct net_device *netdev = adapter->netdev;
196         u32 val, val1;
197
198         /* WINDOW = 1 */
199         val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
200         val >>= (physical_port[adapter->portnum] * 8);
201         val1 = val & 0xff;
202
203         if (adapter->ahw.xg_linkup == 1 && val1 != XG_LINK_UP) {
204                 printk(KERN_INFO "%s: %s NIC Link is down\n",
205                        netxen_nic_driver_name, netdev->name);
206                 adapter->ahw.xg_linkup = 0;
207                 if (netif_running(netdev)) {
208                         netif_carrier_off(netdev);
209                         netif_stop_queue(netdev);
210                 }
211                 /* read twice to clear sticky bits */
212                 /* WINDOW = 0 */
213                 netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1);
214                 netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1);
215
216                 if ((val & 0xffb) != 0xffb) {
217                         printk(KERN_INFO "%s ISR: Sync/Align BAD: 0x%08x\n",
218                                netxen_nic_driver_name, val1);
219                 }
220         } else if (adapter->ahw.xg_linkup == 0 && val1 == XG_LINK_UP) {
221                 printk(KERN_INFO "%s: %s NIC Link is up\n",
222                        netxen_nic_driver_name, netdev->name);
223                 adapter->ahw.xg_linkup = 1;
224                 netif_carrier_on(netdev);
225                 netif_wake_queue(netdev);
226         }
227 }