Merge ../linus
[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_port *port = netdev_priv(netdev);
44         struct net_device_stats *stats = &port->net_stats;
45
46         memset(stats, 0, sizeof(*stats));
47
48         /* total packets received   */
49         stats->rx_packets = port->stats.no_rcv;
50         /* total packets transmitted    */
51         stats->tx_packets = port->stats.xmitedframes + port->stats.xmitfinished;
52         /* total bytes received     */
53         stats->rx_bytes = port->stats.rxbytes;
54         /* total bytes transmitted  */
55         stats->tx_bytes = port->stats.txbytes;
56         /* bad packets received     */
57         stats->rx_errors = port->stats.rcvdbadskb;
58         /* packet transmit problems */
59         stats->tx_errors = port->stats.nocmddescriptor;
60         /* no space in linux buffers    */
61         stats->rx_dropped = port->stats.updropped;
62         /* no space available in linux  */
63         stats->tx_dropped = port->stats.txdropped;
64
65         return stats;
66 }
67
68 void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno,
69                                  u32 link)
70 {
71         struct net_device *netdev = (adapter->port[portno])->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 portno,
80                             u32 enable)
81 {
82         __le32 int_src;
83         struct netxen_port *port;
84
85         /*  This should clear the interrupt source */
86         if (adapter->phy_read)
87                 adapter->phy_read(adapter, portno,
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, portno);
96
97         port = adapter->port[portno];
98
99         if (netxen_get_phy_int_jabber(int_src))
100                 DPRINTK(INFO, "Jabber interrupt \n");
101
102         if (netxen_get_phy_int_polarity_changed(int_src))
103                 DPRINTK(INFO, "POLARITY CHANGED int \n");
104
105         if (netxen_get_phy_int_energy_detect(int_src))
106                 DPRINTK(INFO, "ENERGY DETECT INT \n");
107
108         if (netxen_get_phy_int_downshift(int_src))
109                 DPRINTK(INFO, "DOWNSHIFT INT \n");
110         /* write it down later.. */
111         if ((netxen_get_phy_int_speed_changed(int_src))
112             || (netxen_get_phy_int_link_status_changed(int_src))) {
113                 __le32 status;
114
115                 DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n");
116
117                 if (adapter->phy_read
118                     && adapter->phy_read(adapter, portno,
119                                          NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
120                                          &status) == 0) {
121                         if (netxen_get_phy_int_link_status_changed(int_src)) {
122                                 if (netxen_get_phy_link(status)) {
123                                         netxen_niu_gbe_init_port(adapter,
124                                                                  portno);
125                                         printk("%s: %s Link UP\n",
126                                                netxen_nic_driver_name,
127                                                port->netdev->name);
128
129                                 } else {
130                                         printk("%s: %s Link DOWN\n",
131                                                netxen_nic_driver_name,
132                                                port->netdev->name);
133                                 }
134                                 netxen_indicate_link_status(adapter, portno,
135                                                             netxen_get_phy_link
136                                                             (status));
137                         }
138                 }
139         }
140         if (adapter->enable_phy_interrupts)
141                 adapter->enable_phy_interrupts(adapter, portno);
142 }
143
144 void netxen_nic_isr_other(struct netxen_adapter *adapter)
145 {
146         u32 portno;
147         u32 val, linkup, qg_linksup;
148
149         /* verify the offset */
150         val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
151         if (val == adapter->ahw.qg_linksup)
152                 return;
153
154         qg_linksup = adapter->ahw.qg_linksup;
155         adapter->ahw.qg_linksup = val;
156         DPRINTK(INFO, "link update 0x%08x\n", val);
157         for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) {
158                 linkup = val & 1;
159                 if (linkup != (qg_linksup & 1)) {
160                         printk(KERN_INFO "%s: PORT %d link %s\n",
161                                netxen_nic_driver_name, portno,
162                                ((linkup == 0) ? "down" : "up"));
163                         netxen_indicate_link_status(adapter, portno, linkup);
164                         if (linkup)
165                                 netxen_nic_set_link_parameters(adapter->
166                                                                port[portno]);
167
168                 }
169                 val = val >> 1;
170                 qg_linksup = qg_linksup >> 1;
171         }
172
173         adapter->stats.otherints++;
174
175 }
176
177 void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter)
178 {
179         netxen_nic_isr_other(adapter);
180 }
181
182 void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter)
183 {
184         struct net_device *netdev = adapter->port[0]->netdev;
185         u32 val;
186
187         /* WINDOW = 1 */
188         val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
189
190         if (adapter->ahw.xg_linkup == 1 && val != XG_LINK_UP) {
191                 printk(KERN_INFO "%s: %s NIC Link is down\n",
192                        netxen_nic_driver_name, netdev->name);
193                 adapter->ahw.xg_linkup = 0;
194                 /* read twice to clear sticky bits */
195                 /* WINDOW = 0 */
196                 netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val);
197                 netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val);
198
199                 if ((val & 0xffb) != 0xffb) {
200                         printk(KERN_INFO "%s ISR: Sync/Align BAD: 0x%08x\n",
201                                netxen_nic_driver_name, val);
202                 }
203         } else if (adapter->ahw.xg_linkup == 0 && val == XG_LINK_UP) {
204                 printk(KERN_INFO "%s: %s NIC Link is up\n",
205                        netxen_nic_driver_name, netdev->name);
206                 adapter->ahw.xg_linkup = 1;
207         }
208 }