blob: 37945fce7fa50d9c4b2a3b7c2beeae8f9ca396fb [file] [log] [blame]
Divy Le Ray4d22de32007-01-18 22:04:14 -05001/*
Divy Le Raya02d44a2008-10-13 18:47:30 -07002 * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
Divy Le Ray4d22de32007-01-18 22:04:14 -05003 *
Divy Le Ray1d68e932007-01-30 19:44:35 -08004 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
Divy Le Ray4d22de32007-01-18 22:04:14 -05009 *
Divy Le Ray1d68e932007-01-30 19:44:35 -080010 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
Divy Le Ray4d22de32007-01-18 22:04:14 -050031 */
Divy Le Ray4d22de32007-01-18 22:04:14 -050032#include <linux/module.h>
33#include <linux/moduleparam.h>
34#include <linux/init.h>
35#include <linux/pci.h>
36#include <linux/dma-mapping.h>
37#include <linux/netdevice.h>
38#include <linux/etherdevice.h>
39#include <linux/if_vlan.h>
Ben Hutchings0f07c4e2009-04-29 08:07:20 +000040#include <linux/mdio.h>
Divy Le Ray4d22de32007-01-18 22:04:14 -050041#include <linux/sockios.h>
42#include <linux/workqueue.h>
43#include <linux/proc_fs.h>
44#include <linux/rtnetlink.h>
Divy Le Ray2e283962007-03-18 13:10:06 -070045#include <linux/firmware.h>
vignesh babud9da4662007-07-09 11:50:22 -070046#include <linux/log2.h>
Ben Hutchings34336ec2009-11-07 11:53:52 +000047#include <linux/stringify.h>
Steve Wisee998f242010-01-27 17:03:34 +000048#include <linux/sched.h>
Divy Le Ray4d22de32007-01-18 22:04:14 -050049#include <asm/uaccess.h>
50
51#include "common.h"
52#include "cxgb3_ioctl.h"
53#include "regs.h"
54#include "cxgb3_offload.h"
55#include "version.h"
56
57#include "cxgb3_ctl_defs.h"
58#include "t3_cpl.h"
59#include "firmware_exports.h"
60
61enum {
62 MAX_TXQ_ENTRIES = 16384,
63 MAX_CTRL_TXQ_ENTRIES = 1024,
64 MAX_RSPQ_ENTRIES = 16384,
65 MAX_RX_BUFFERS = 16384,
66 MAX_RX_JUMBO_BUFFERS = 16384,
67 MIN_TXQ_ENTRIES = 4,
68 MIN_CTRL_TXQ_ENTRIES = 4,
69 MIN_RSPQ_ENTRIES = 32,
70 MIN_FL_ENTRIES = 32
71};
72
73#define PORT_MASK ((1 << MAX_NPORTS) - 1)
74
75#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
76 NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
77 NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
78
79#define EEPROM_MAGIC 0x38E2F10C
80
Divy Le Ray678771d2007-11-16 14:26:44 -080081#define CH_DEVICE(devid, idx) \
82 { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx }
Divy Le Ray4d22de32007-01-18 22:04:14 -050083
84static const struct pci_device_id cxgb3_pci_tbl[] = {
Divy Le Ray678771d2007-11-16 14:26:44 -080085 CH_DEVICE(0x20, 0), /* PE9000 */
86 CH_DEVICE(0x21, 1), /* T302E */
87 CH_DEVICE(0x22, 2), /* T310E */
88 CH_DEVICE(0x23, 3), /* T320X */
89 CH_DEVICE(0x24, 1), /* T302X */
90 CH_DEVICE(0x25, 3), /* T320E */
91 CH_DEVICE(0x26, 2), /* T310X */
92 CH_DEVICE(0x30, 2), /* T3B10 */
93 CH_DEVICE(0x31, 3), /* T3B20 */
94 CH_DEVICE(0x32, 1), /* T3B02 */
Divy Le Rayce03aad2009-02-18 17:47:57 -080095 CH_DEVICE(0x35, 6), /* T3C20-derived T3C10 */
Divy Le Ray74451422009-05-29 12:52:44 +000096 CH_DEVICE(0x36, 3), /* S320E-CR */
97 CH_DEVICE(0x37, 7), /* N320E-G2 */
Divy Le Ray4d22de32007-01-18 22:04:14 -050098 {0,}
99};
100
101MODULE_DESCRIPTION(DRV_DESC);
102MODULE_AUTHOR("Chelsio Communications");
Divy Le Ray1d68e932007-01-30 19:44:35 -0800103MODULE_LICENSE("Dual BSD/GPL");
Divy Le Ray4d22de32007-01-18 22:04:14 -0500104MODULE_VERSION(DRV_VERSION);
105MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl);
106
107static int dflt_msg_enable = DFLT_MSG_ENABLE;
108
109module_param(dflt_msg_enable, int, 0644);
110MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap");
111
112/*
113 * The driver uses the best interrupt scheme available on a platform in the
114 * order MSI-X, MSI, legacy pin interrupts. This parameter determines which
115 * of these schemes the driver may consider as follows:
116 *
117 * msi = 2: choose from among all three options
118 * msi = 1: only consider MSI and pin interrupts
119 * msi = 0: force pin interrupts
120 */
121static int msi = 2;
122
123module_param(msi, int, 0644);
124MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X");
125
126/*
127 * The driver enables offload as a default.
128 * To disable it, use ofld_disable = 1.
129 */
130
131static int ofld_disable = 0;
132
133module_param(ofld_disable, int, 0644);
134MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not");
135
136/*
137 * We have work elements that we need to cancel when an interface is taken
138 * down. Normally the work elements would be executed by keventd but that
139 * can deadlock because of linkwatch. If our close method takes the rtnl
140 * lock and linkwatch is ahead of our work elements in keventd, linkwatch
141 * will block keventd as it needs the rtnl lock, and we'll deadlock waiting
142 * for our work to complete. Get our own work queue to solve this.
143 */
Steve Wisee998f242010-01-27 17:03:34 +0000144struct workqueue_struct *cxgb3_wq;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500145
146/**
147 * link_report - show link status and link speed/duplex
148 * @p: the port whose settings are to be reported
149 *
150 * Shows the link status, speed, and duplex of a port.
151 */
152static void link_report(struct net_device *dev)
153{
154 if (!netif_carrier_ok(dev))
155 printk(KERN_INFO "%s: link down\n", dev->name);
156 else {
157 const char *s = "10Mbps";
158 const struct port_info *p = netdev_priv(dev);
159
160 switch (p->link_config.speed) {
161 case SPEED_10000:
162 s = "10Gbps";
163 break;
164 case SPEED_1000:
165 s = "1000Mbps";
166 break;
167 case SPEED_100:
168 s = "100Mbps";
169 break;
170 }
171
172 printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s,
173 p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
174 }
175}
176
Divy Le Ray34701fd2009-07-07 19:48:32 +0000177static void enable_tx_fifo_drain(struct adapter *adapter,
178 struct port_info *pi)
179{
180 t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0,
181 F_ENDROPPKT);
182 t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0);
183 t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN);
184 t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN);
185}
186
187static void disable_tx_fifo_drain(struct adapter *adapter,
188 struct port_info *pi)
189{
190 t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
191 F_ENDROPPKT, 0);
192}
193
Divy Le Raybf792092009-03-12 21:14:19 +0000194void t3_os_link_fault(struct adapter *adap, int port_id, int state)
195{
196 struct net_device *dev = adap->port[port_id];
197 struct port_info *pi = netdev_priv(dev);
198
199 if (state == netif_carrier_ok(dev))
200 return;
201
202 if (state) {
203 struct cmac *mac = &pi->mac;
204
205 netif_carrier_on(dev);
206
Divy Le Ray34701fd2009-07-07 19:48:32 +0000207 disable_tx_fifo_drain(adap, pi);
208
Divy Le Raybf792092009-03-12 21:14:19 +0000209 /* Clear local faults */
210 t3_xgm_intr_disable(adap, pi->port_id);
211 t3_read_reg(adap, A_XGM_INT_STATUS +
212 pi->mac.offset);
213 t3_write_reg(adap,
214 A_XGM_INT_CAUSE + pi->mac.offset,
215 F_XGM_INT);
216
217 t3_set_reg_field(adap,
218 A_XGM_INT_ENABLE +
219 pi->mac.offset,
220 F_XGM_INT, F_XGM_INT);
221 t3_xgm_intr_enable(adap, pi->port_id);
222
223 t3_mac_enable(mac, MAC_DIRECTION_TX);
Divy Le Ray34701fd2009-07-07 19:48:32 +0000224 } else {
Divy Le Raybf792092009-03-12 21:14:19 +0000225 netif_carrier_off(dev);
226
Divy Le Ray34701fd2009-07-07 19:48:32 +0000227 /* Flush TX FIFO */
228 enable_tx_fifo_drain(adap, pi);
229 }
Divy Le Raybf792092009-03-12 21:14:19 +0000230 link_report(dev);
231}
232
Divy Le Ray4d22de32007-01-18 22:04:14 -0500233/**
234 * t3_os_link_changed - handle link status changes
235 * @adapter: the adapter associated with the link change
236 * @port_id: the port index whose limk status has changed
237 * @link_stat: the new status of the link
238 * @speed: the new speed setting
239 * @duplex: the new duplex setting
240 * @pause: the new flow-control setting
241 *
242 * This is the OS-dependent handler for link status changes. The OS
243 * neutral handler takes care of most of the processing for these events,
244 * then calls this handler for any OS-specific processing.
245 */
246void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
247 int speed, int duplex, int pause)
248{
249 struct net_device *dev = adapter->port[port_id];
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700250 struct port_info *pi = netdev_priv(dev);
251 struct cmac *mac = &pi->mac;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500252
253 /* Skip changes from disabled ports. */
254 if (!netif_running(dev))
255 return;
256
257 if (link_stat != netif_carrier_ok(dev)) {
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700258 if (link_stat) {
Divy Le Ray34701fd2009-07-07 19:48:32 +0000259 disable_tx_fifo_drain(adapter, pi);
260
Divy Le Ray59cf8102007-04-09 20:10:27 -0700261 t3_mac_enable(mac, MAC_DIRECTION_RX);
Divy Le Raybf792092009-03-12 21:14:19 +0000262
263 /* Clear local faults */
264 t3_xgm_intr_disable(adapter, pi->port_id);
265 t3_read_reg(adapter, A_XGM_INT_STATUS +
266 pi->mac.offset);
267 t3_write_reg(adapter,
268 A_XGM_INT_CAUSE + pi->mac.offset,
269 F_XGM_INT);
270
271 t3_set_reg_field(adapter,
272 A_XGM_INT_ENABLE + pi->mac.offset,
273 F_XGM_INT, F_XGM_INT);
274 t3_xgm_intr_enable(adapter, pi->port_id);
275
Divy Le Ray4d22de32007-01-18 22:04:14 -0500276 netif_carrier_on(dev);
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700277 } else {
Divy Le Ray4d22de32007-01-18 22:04:14 -0500278 netif_carrier_off(dev);
Divy Le Raybf792092009-03-12 21:14:19 +0000279
280 t3_xgm_intr_disable(adapter, pi->port_id);
281 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
282 t3_set_reg_field(adapter,
283 A_XGM_INT_ENABLE + pi->mac.offset,
284 F_XGM_INT, 0);
285
286 if (is_10G(adapter))
287 pi->phy.ops->power_down(&pi->phy, 1);
288
289 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
Divy Le Ray59cf8102007-04-09 20:10:27 -0700290 t3_mac_disable(mac, MAC_DIRECTION_RX);
291 t3_link_start(&pi->phy, mac, &pi->link_config);
Divy Le Ray34701fd2009-07-07 19:48:32 +0000292
293 /* Flush TX FIFO */
294 enable_tx_fifo_drain(adapter, pi);
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700295 }
296
Divy Le Ray4d22de32007-01-18 22:04:14 -0500297 link_report(dev);
298 }
299}
300
Divy Le Ray1e882022008-10-08 17:40:07 -0700301/**
302 * t3_os_phymod_changed - handle PHY module changes
303 * @phy: the PHY reporting the module change
304 * @mod_type: new module type
305 *
306 * This is the OS-dependent handler for PHY module changes. It is
307 * invoked when a PHY module is removed or inserted for any OS-specific
308 * processing.
309 */
310void t3_os_phymod_changed(struct adapter *adap, int port_id)
311{
312 static const char *mod_str[] = {
313 NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown"
314 };
315
316 const struct net_device *dev = adap->port[port_id];
317 const struct port_info *pi = netdev_priv(dev);
318
319 if (pi->phy.modtype == phy_modtype_none)
320 printk(KERN_INFO "%s: PHY module unplugged\n", dev->name);
321 else
322 printk(KERN_INFO "%s: %s PHY module inserted\n", dev->name,
323 mod_str[pi->phy.modtype]);
324}
325
Divy Le Ray4d22de32007-01-18 22:04:14 -0500326static void cxgb_set_rxmode(struct net_device *dev)
327{
328 struct t3_rx_mode rm;
329 struct port_info *pi = netdev_priv(dev);
330
331 init_rx_mode(&rm, dev, dev->mc_list);
332 t3_mac_set_rx_mode(&pi->mac, &rm);
333}
334
335/**
336 * link_start - enable a port
337 * @dev: the device to enable
338 *
339 * Performs the MAC and PHY actions needed to enable a port.
340 */
341static void link_start(struct net_device *dev)
342{
343 struct t3_rx_mode rm;
344 struct port_info *pi = netdev_priv(dev);
345 struct cmac *mac = &pi->mac;
346
347 init_rx_mode(&rm, dev, dev->mc_list);
348 t3_mac_reset(mac);
Karen Xief14d42f2009-10-08 09:11:05 +0000349 t3_mac_set_num_ucast(mac, MAX_MAC_IDX);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500350 t3_mac_set_mtu(mac, dev->mtu);
Karen Xief14d42f2009-10-08 09:11:05 +0000351 t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr);
352 t3_mac_set_address(mac, SAN_MAC_IDX, pi->iscsic.mac_addr);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500353 t3_mac_set_rx_mode(mac, &rm);
354 t3_link_start(&pi->phy, mac, &pi->link_config);
355 t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
356}
357
358static inline void cxgb_disable_msi(struct adapter *adapter)
359{
360 if (adapter->flags & USING_MSIX) {
361 pci_disable_msix(adapter->pdev);
362 adapter->flags &= ~USING_MSIX;
363 } else if (adapter->flags & USING_MSI) {
364 pci_disable_msi(adapter->pdev);
365 adapter->flags &= ~USING_MSI;
366 }
367}
368
369/*
370 * Interrupt handler for asynchronous events used with MSI-X.
371 */
372static irqreturn_t t3_async_intr_handler(int irq, void *cookie)
373{
374 t3_slow_intr_handler(cookie);
375 return IRQ_HANDLED;
376}
377
378/*
379 * Name the MSI-X interrupts.
380 */
381static void name_msix_vecs(struct adapter *adap)
382{
383 int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1;
384
385 snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
386 adap->msix_info[0].desc[n] = 0;
387
388 for_each_port(adap, j) {
389 struct net_device *d = adap->port[j];
390 const struct port_info *pi = netdev_priv(d);
391
392 for (i = 0; i < pi->nqsets; i++, msi_idx++) {
393 snprintf(adap->msix_info[msi_idx].desc, n,
Divy Le Ray8c263762008-10-08 17:37:33 -0700394 "%s-%d", d->name, pi->first_qset + i);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500395 adap->msix_info[msi_idx].desc[n] = 0;
396 }
Divy Le Ray8c263762008-10-08 17:37:33 -0700397 }
Divy Le Ray4d22de32007-01-18 22:04:14 -0500398}
399
400static int request_msix_data_irqs(struct adapter *adap)
401{
402 int i, j, err, qidx = 0;
403
404 for_each_port(adap, i) {
405 int nqsets = adap2pinfo(adap, i)->nqsets;
406
407 for (j = 0; j < nqsets; ++j) {
408 err = request_irq(adap->msix_info[qidx + 1].vec,
409 t3_intr_handler(adap,
410 adap->sge.qs[qidx].
411 rspq.polling), 0,
412 adap->msix_info[qidx + 1].desc,
413 &adap->sge.qs[qidx]);
414 if (err) {
415 while (--qidx >= 0)
416 free_irq(adap->msix_info[qidx + 1].vec,
417 &adap->sge.qs[qidx]);
418 return err;
419 }
420 qidx++;
421 }
422 }
423 return 0;
424}
425
Divy Le Ray8c263762008-10-08 17:37:33 -0700426static void free_irq_resources(struct adapter *adapter)
427{
428 if (adapter->flags & USING_MSIX) {
429 int i, n = 0;
430
431 free_irq(adapter->msix_info[0].vec, adapter);
432 for_each_port(adapter, i)
Divy Le Ray5cda9362009-01-18 21:29:40 -0800433 n += adap2pinfo(adapter, i)->nqsets;
Divy Le Ray8c263762008-10-08 17:37:33 -0700434
435 for (i = 0; i < n; ++i)
436 free_irq(adapter->msix_info[i + 1].vec,
437 &adapter->sge.qs[i]);
438 } else
439 free_irq(adapter->pdev->irq, adapter);
440}
441
Divy Le Rayb8819552007-12-17 18:47:31 -0800442static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
443 unsigned long n)
444{
445 int attempts = 5;
446
447 while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
448 if (!--attempts)
449 return -ETIMEDOUT;
450 msleep(10);
451 }
452 return 0;
453}
454
455static int init_tp_parity(struct adapter *adap)
456{
457 int i;
458 struct sk_buff *skb;
459 struct cpl_set_tcb_field *greq;
460 unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
461
462 t3_tp_set_offload_mode(adap, 1);
463
464 for (i = 0; i < 16; i++) {
465 struct cpl_smt_write_req *req;
466
Divy Le Ray74b793e2009-06-09 23:25:21 +0000467 skb = alloc_skb(sizeof(*req), GFP_KERNEL);
468 if (!skb)
469 skb = adap->nofail_skb;
470 if (!skb)
471 goto alloc_skb_fail;
472
Divy Le Rayb8819552007-12-17 18:47:31 -0800473 req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
474 memset(req, 0, sizeof(*req));
475 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
476 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
Divy Le Raydce7d1d2009-07-07 19:48:59 +0000477 req->mtu_idx = NMTUS - 1;
Divy Le Rayb8819552007-12-17 18:47:31 -0800478 req->iff = i;
479 t3_mgmt_tx(adap, skb);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000480 if (skb == adap->nofail_skb) {
481 await_mgmt_replies(adap, cnt, i + 1);
482 adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
483 if (!adap->nofail_skb)
484 goto alloc_skb_fail;
485 }
Divy Le Rayb8819552007-12-17 18:47:31 -0800486 }
487
488 for (i = 0; i < 2048; i++) {
489 struct cpl_l2t_write_req *req;
490
Divy Le Ray74b793e2009-06-09 23:25:21 +0000491 skb = alloc_skb(sizeof(*req), GFP_KERNEL);
492 if (!skb)
493 skb = adap->nofail_skb;
494 if (!skb)
495 goto alloc_skb_fail;
496
Divy Le Rayb8819552007-12-17 18:47:31 -0800497 req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
498 memset(req, 0, sizeof(*req));
499 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
500 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
501 req->params = htonl(V_L2T_W_IDX(i));
502 t3_mgmt_tx(adap, skb);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000503 if (skb == adap->nofail_skb) {
504 await_mgmt_replies(adap, cnt, 16 + i + 1);
505 adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
506 if (!adap->nofail_skb)
507 goto alloc_skb_fail;
508 }
Divy Le Rayb8819552007-12-17 18:47:31 -0800509 }
510
511 for (i = 0; i < 2048; i++) {
512 struct cpl_rte_write_req *req;
513
Divy Le Ray74b793e2009-06-09 23:25:21 +0000514 skb = alloc_skb(sizeof(*req), GFP_KERNEL);
515 if (!skb)
516 skb = adap->nofail_skb;
517 if (!skb)
518 goto alloc_skb_fail;
519
Divy Le Rayb8819552007-12-17 18:47:31 -0800520 req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req));
521 memset(req, 0, sizeof(*req));
522 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
523 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
524 req->l2t_idx = htonl(V_L2T_W_IDX(i));
525 t3_mgmt_tx(adap, skb);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000526 if (skb == adap->nofail_skb) {
527 await_mgmt_replies(adap, cnt, 16 + 2048 + i + 1);
528 adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
529 if (!adap->nofail_skb)
530 goto alloc_skb_fail;
531 }
Divy Le Rayb8819552007-12-17 18:47:31 -0800532 }
533
Divy Le Ray74b793e2009-06-09 23:25:21 +0000534 skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
535 if (!skb)
536 skb = adap->nofail_skb;
537 if (!skb)
538 goto alloc_skb_fail;
539
Divy Le Rayb8819552007-12-17 18:47:31 -0800540 greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq));
541 memset(greq, 0, sizeof(*greq));
542 greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
543 OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
544 greq->mask = cpu_to_be64(1);
545 t3_mgmt_tx(adap, skb);
546
547 i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000548 if (skb == adap->nofail_skb) {
549 i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
550 adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
551 }
552
Divy Le Rayb8819552007-12-17 18:47:31 -0800553 t3_tp_set_offload_mode(adap, 0);
554 return i;
Divy Le Ray74b793e2009-06-09 23:25:21 +0000555
556alloc_skb_fail:
557 t3_tp_set_offload_mode(adap, 0);
558 return -ENOMEM;
Divy Le Rayb8819552007-12-17 18:47:31 -0800559}
560
Divy Le Ray4d22de32007-01-18 22:04:14 -0500561/**
562 * setup_rss - configure RSS
563 * @adap: the adapter
564 *
565 * Sets up RSS to distribute packets to multiple receive queues. We
566 * configure the RSS CPU lookup table to distribute to the number of HW
567 * receive queues, and the response queue lookup table to narrow that
568 * down to the response queues actually configured for each port.
569 * We always configure the RSS mapping for two ports since the mapping
570 * table has plenty of entries.
571 */
572static void setup_rss(struct adapter *adap)
573{
574 int i;
575 unsigned int nq0 = adap2pinfo(adap, 0)->nqsets;
576 unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1;
577 u8 cpus[SGE_QSETS + 1];
578 u16 rspq_map[RSS_TABLE_SIZE];
579
580 for (i = 0; i < SGE_QSETS; ++i)
581 cpus[i] = i;
582 cpus[SGE_QSETS] = 0xff; /* terminator */
583
584 for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
585 rspq_map[i] = i % nq0;
586 rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0;
587 }
588
589 t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
590 F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
Divy Le Raya2604be2007-11-16 11:22:16 -0800591 V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500592}
593
Steve Wisee998f242010-01-27 17:03:34 +0000594static void ring_dbs(struct adapter *adap)
595{
596 int i, j;
597
598 for (i = 0; i < SGE_QSETS; i++) {
599 struct sge_qset *qs = &adap->sge.qs[i];
600
601 if (qs->adap)
602 for (j = 0; j < SGE_TXQ_PER_SET; j++)
603 t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | V_EGRCNTX(qs->txq[j].cntxt_id));
604 }
605}
606
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700607static void init_napi(struct adapter *adap)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500608{
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700609 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500610
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700611 for (i = 0; i < SGE_QSETS; i++) {
612 struct sge_qset *qs = &adap->sge.qs[i];
Divy Le Ray4d22de32007-01-18 22:04:14 -0500613
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700614 if (qs->adap)
615 netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll,
616 64);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500617 }
Divy Le Ray48c4b6d2008-05-06 19:25:56 -0700618
619 /*
620 * netif_napi_add() can be called only once per napi_struct because it
621 * adds each new napi_struct to a list. Be careful not to call it a
622 * second time, e.g., during EEH recovery, by making a note of it.
623 */
624 adap->flags |= NAPI_INIT;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500625}
626
627/*
628 * Wait until all NAPI handlers are descheduled. This includes the handlers of
629 * both netdevices representing interfaces and the dummy ones for the extra
630 * queues.
631 */
632static void quiesce_rx(struct adapter *adap)
633{
634 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500635
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700636 for (i = 0; i < SGE_QSETS; i++)
637 if (adap->sge.qs[i].adap)
638 napi_disable(&adap->sge.qs[i].napi);
639}
Divy Le Ray4d22de32007-01-18 22:04:14 -0500640
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700641static void enable_all_napi(struct adapter *adap)
642{
643 int i;
644 for (i = 0; i < SGE_QSETS; i++)
645 if (adap->sge.qs[i].adap)
646 napi_enable(&adap->sge.qs[i].napi);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500647}
648
649/**
Divy Le Ray04ecb072008-10-28 22:40:32 -0700650 * set_qset_lro - Turn a queue set's LRO capability on and off
651 * @dev: the device the qset is attached to
652 * @qset_idx: the queue set index
653 * @val: the LRO switch
654 *
655 * Sets LRO on or off for a particular queue set.
656 * the device's features flag is updated to reflect the LRO
657 * capability when all queues belonging to the device are
658 * in the same state.
659 */
660static void set_qset_lro(struct net_device *dev, int qset_idx, int val)
661{
662 struct port_info *pi = netdev_priv(dev);
663 struct adapter *adapter = pi->adapter;
Divy Le Ray04ecb072008-10-28 22:40:32 -0700664
665 adapter->params.sge.qset[qset_idx].lro = !!val;
666 adapter->sge.qs[qset_idx].lro_enabled = !!val;
Divy Le Ray04ecb072008-10-28 22:40:32 -0700667}
668
669/**
Divy Le Ray4d22de32007-01-18 22:04:14 -0500670 * setup_sge_qsets - configure SGE Tx/Rx/response queues
671 * @adap: the adapter
672 *
673 * Determines how many sets of SGE queues to use and initializes them.
674 * We support multiple queue sets per port if we have MSI-X, otherwise
675 * just one queue set per port.
676 */
677static int setup_sge_qsets(struct adapter *adap)
678{
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700679 int i, j, err, irq_idx = 0, qset_idx = 0;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -0700680 unsigned int ntxq = SGE_TXQ_PER_SET;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500681
682 if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
683 irq_idx = -1;
684
685 for_each_port(adap, i) {
686 struct net_device *dev = adap->port[i];
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700687 struct port_info *pi = netdev_priv(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500688
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700689 pi->qs = &adap->sge.qs[pi->first_qset];
Roland Dreiere594e962009-07-09 09:30:25 +0000690 for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
Roland Dreier47fd23f2009-01-11 00:19:36 -0800691 set_qset_lro(dev, qset_idx, pi->rx_offload & T3_LRO);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500692 err = t3_sge_alloc_qset(adap, qset_idx, 1,
693 (adap->flags & USING_MSIX) ? qset_idx + 1 :
694 irq_idx,
Divy Le Ray82ad3322008-12-16 01:09:39 -0800695 &adap->params.sge.qset[qset_idx], ntxq, dev,
696 netdev_get_tx_queue(dev, j));
Divy Le Ray4d22de32007-01-18 22:04:14 -0500697 if (err) {
698 t3_free_sge_resources(adap);
699 return err;
700 }
701 }
702 }
703
704 return 0;
705}
706
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800707static ssize_t attr_show(struct device *d, char *buf,
Divy Le Ray896392e2007-02-24 16:43:50 -0800708 ssize_t(*format) (struct net_device *, char *))
Divy Le Ray4d22de32007-01-18 22:04:14 -0500709{
710 ssize_t len;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500711
712 /* Synchronize with ioctls that may shut down the device */
713 rtnl_lock();
Divy Le Ray896392e2007-02-24 16:43:50 -0800714 len = (*format) (to_net_dev(d), buf);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500715 rtnl_unlock();
716 return len;
717}
718
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800719static ssize_t attr_store(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800720 const char *buf, size_t len,
Divy Le Ray896392e2007-02-24 16:43:50 -0800721 ssize_t(*set) (struct net_device *, unsigned int),
Divy Le Ray4d22de32007-01-18 22:04:14 -0500722 unsigned int min_val, unsigned int max_val)
723{
724 char *endp;
725 ssize_t ret;
726 unsigned int val;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500727
728 if (!capable(CAP_NET_ADMIN))
729 return -EPERM;
730
731 val = simple_strtoul(buf, &endp, 0);
732 if (endp == buf || val < min_val || val > max_val)
733 return -EINVAL;
734
735 rtnl_lock();
Divy Le Ray896392e2007-02-24 16:43:50 -0800736 ret = (*set) (to_net_dev(d), val);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500737 if (!ret)
738 ret = len;
739 rtnl_unlock();
740 return ret;
741}
742
743#define CXGB3_SHOW(name, val_expr) \
Divy Le Ray896392e2007-02-24 16:43:50 -0800744static ssize_t format_##name(struct net_device *dev, char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500745{ \
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700746 struct port_info *pi = netdev_priv(dev); \
747 struct adapter *adap = pi->adapter; \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500748 return sprintf(buf, "%u\n", val_expr); \
749} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800750static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
751 char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500752{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800753 return attr_show(d, buf, format_##name); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500754}
755
Divy Le Ray896392e2007-02-24 16:43:50 -0800756static ssize_t set_nfilters(struct net_device *dev, unsigned int val)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500757{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700758 struct port_info *pi = netdev_priv(dev);
759 struct adapter *adap = pi->adapter;
Divy Le Ray9f238482007-03-31 00:23:13 -0700760 int min_tids = is_offload(adap) ? MC5_MIN_TIDS : 0;
Divy Le Ray896392e2007-02-24 16:43:50 -0800761
Divy Le Ray4d22de32007-01-18 22:04:14 -0500762 if (adap->flags & FULL_INIT_DONE)
763 return -EBUSY;
764 if (val && adap->params.rev == 0)
765 return -EINVAL;
Divy Le Ray9f238482007-03-31 00:23:13 -0700766 if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
767 min_tids)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500768 return -EINVAL;
769 adap->params.mc5.nfilters = val;
770 return 0;
771}
772
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800773static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
774 const char *buf, size_t len)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500775{
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800776 return attr_store(d, buf, len, set_nfilters, 0, ~0);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500777}
778
Divy Le Ray896392e2007-02-24 16:43:50 -0800779static ssize_t set_nservers(struct net_device *dev, unsigned int val)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500780{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700781 struct port_info *pi = netdev_priv(dev);
782 struct adapter *adap = pi->adapter;
Divy Le Ray896392e2007-02-24 16:43:50 -0800783
Divy Le Ray4d22de32007-01-18 22:04:14 -0500784 if (adap->flags & FULL_INIT_DONE)
785 return -EBUSY;
Divy Le Ray9f238482007-03-31 00:23:13 -0700786 if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters -
787 MC5_MIN_TIDS)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500788 return -EINVAL;
789 adap->params.mc5.nservers = val;
790 return 0;
791}
792
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800793static ssize_t store_nservers(struct device *d, struct device_attribute *attr,
794 const char *buf, size_t len)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500795{
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800796 return attr_store(d, buf, len, set_nservers, 0, ~0);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500797}
798
799#define CXGB3_ATTR_R(name, val_expr) \
800CXGB3_SHOW(name, val_expr) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800801static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500802
803#define CXGB3_ATTR_RW(name, val_expr, store_method) \
804CXGB3_SHOW(name, val_expr) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800805static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500806
807CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));
808CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);
809CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);
810
811static struct attribute *cxgb3_attrs[] = {
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800812 &dev_attr_cam_size.attr,
813 &dev_attr_nfilters.attr,
814 &dev_attr_nservers.attr,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500815 NULL
816};
817
818static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
819
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800820static ssize_t tm_attr_show(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800821 char *buf, int sched)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500822{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700823 struct port_info *pi = netdev_priv(to_net_dev(d));
824 struct adapter *adap = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500825 unsigned int v, addr, bpt, cpt;
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700826 ssize_t len;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500827
828 addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
829 rtnl_lock();
830 t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
831 v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
832 if (sched & 1)
833 v >>= 16;
834 bpt = (v >> 8) & 0xff;
835 cpt = v & 0xff;
836 if (!cpt)
837 len = sprintf(buf, "disabled\n");
838 else {
839 v = (adap->params.vpd.cclk * 1000) / cpt;
840 len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125);
841 }
842 rtnl_unlock();
843 return len;
844}
845
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800846static ssize_t tm_attr_store(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800847 const char *buf, size_t len, int sched)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500848{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700849 struct port_info *pi = netdev_priv(to_net_dev(d));
850 struct adapter *adap = pi->adapter;
851 unsigned int val;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500852 char *endp;
853 ssize_t ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500854
855 if (!capable(CAP_NET_ADMIN))
856 return -EPERM;
857
858 val = simple_strtoul(buf, &endp, 0);
859 if (endp == buf || val > 10000000)
860 return -EINVAL;
861
862 rtnl_lock();
863 ret = t3_config_sched(adap, val, sched);
864 if (!ret)
865 ret = len;
866 rtnl_unlock();
867 return ret;
868}
869
870#define TM_ATTR(name, sched) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800871static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
872 char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500873{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800874 return tm_attr_show(d, buf, sched); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500875} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800876static ssize_t store_##name(struct device *d, struct device_attribute *attr, \
877 const char *buf, size_t len) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500878{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800879 return tm_attr_store(d, buf, len, sched); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500880} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800881static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500882
883TM_ATTR(sched0, 0);
884TM_ATTR(sched1, 1);
885TM_ATTR(sched2, 2);
886TM_ATTR(sched3, 3);
887TM_ATTR(sched4, 4);
888TM_ATTR(sched5, 5);
889TM_ATTR(sched6, 6);
890TM_ATTR(sched7, 7);
891
892static struct attribute *offload_attrs[] = {
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800893 &dev_attr_sched0.attr,
894 &dev_attr_sched1.attr,
895 &dev_attr_sched2.attr,
896 &dev_attr_sched3.attr,
897 &dev_attr_sched4.attr,
898 &dev_attr_sched5.attr,
899 &dev_attr_sched6.attr,
900 &dev_attr_sched7.attr,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500901 NULL
902};
903
904static struct attribute_group offload_attr_group = {.attrs = offload_attrs };
905
906/*
907 * Sends an sk_buff to an offload queue driver
908 * after dealing with any active network taps.
909 */
910static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
911{
912 int ret;
913
914 local_bh_disable();
915 ret = t3_offload_tx(tdev, skb);
916 local_bh_enable();
917 return ret;
918}
919
920static int write_smt_entry(struct adapter *adapter, int idx)
921{
922 struct cpl_smt_write_req *req;
Karen Xief14d42f2009-10-08 09:11:05 +0000923 struct port_info *pi = netdev_priv(adapter->port[idx]);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500924 struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);
925
926 if (!skb)
927 return -ENOMEM;
928
929 req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
930 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
931 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
932 req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */
933 req->iff = idx;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500934 memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);
Karen Xief14d42f2009-10-08 09:11:05 +0000935 memcpy(req->src_mac1, pi->iscsic.mac_addr, ETH_ALEN);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500936 skb->priority = 1;
937 offload_tx(&adapter->tdev, skb);
938 return 0;
939}
940
941static int init_smt(struct adapter *adapter)
942{
943 int i;
944
945 for_each_port(adapter, i)
946 write_smt_entry(adapter, i);
947 return 0;
948}
949
950static void init_port_mtus(struct adapter *adapter)
951{
952 unsigned int mtus = adapter->port[0]->mtu;
953
954 if (adapter->port[1])
955 mtus |= adapter->port[1]->mtu << 16;
956 t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
957}
958
Divy Le Ray8c263762008-10-08 17:37:33 -0700959static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
Divy Le Ray14ab9892007-01-30 19:43:50 -0800960 int hi, int port)
961{
962 struct sk_buff *skb;
963 struct mngt_pktsched_wr *req;
Divy Le Ray8c263762008-10-08 17:37:33 -0700964 int ret;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800965
Divy Le Ray74b793e2009-06-09 23:25:21 +0000966 skb = alloc_skb(sizeof(*req), GFP_KERNEL);
967 if (!skb)
968 skb = adap->nofail_skb;
969 if (!skb)
970 return -ENOMEM;
971
Divy Le Ray14ab9892007-01-30 19:43:50 -0800972 req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
973 req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
974 req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
975 req->sched = sched;
976 req->idx = qidx;
977 req->min = lo;
978 req->max = hi;
979 req->binding = port;
Divy Le Ray8c263762008-10-08 17:37:33 -0700980 ret = t3_mgmt_tx(adap, skb);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000981 if (skb == adap->nofail_skb) {
982 adap->nofail_skb = alloc_skb(sizeof(struct cpl_set_tcb_field),
983 GFP_KERNEL);
984 if (!adap->nofail_skb)
985 ret = -ENOMEM;
986 }
Divy Le Ray8c263762008-10-08 17:37:33 -0700987
988 return ret;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800989}
990
Divy Le Ray8c263762008-10-08 17:37:33 -0700991static int bind_qsets(struct adapter *adap)
Divy Le Ray14ab9892007-01-30 19:43:50 -0800992{
Divy Le Ray8c263762008-10-08 17:37:33 -0700993 int i, j, err = 0;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800994
995 for_each_port(adap, i) {
996 const struct port_info *pi = adap2pinfo(adap, i);
997
Divy Le Ray8c263762008-10-08 17:37:33 -0700998 for (j = 0; j < pi->nqsets; ++j) {
999 int ret = send_pktsched_cmd(adap, 1,
1000 pi->first_qset + j, -1,
1001 -1, i);
1002 if (ret)
1003 err = ret;
1004 }
Divy Le Ray14ab9892007-01-30 19:43:50 -08001005 }
Divy Le Ray8c263762008-10-08 17:37:33 -07001006
1007 return err;
Divy Le Ray14ab9892007-01-30 19:43:50 -08001008}
1009
Ben Hutchings34336ec2009-11-07 11:53:52 +00001010#define FW_VERSION __stringify(FW_VERSION_MAJOR) "." \
1011 __stringify(FW_VERSION_MINOR) "." __stringify(FW_VERSION_MICRO)
1012#define FW_FNAME "cxgb3/t3fw-" FW_VERSION ".bin"
1013#define TPSRAM_VERSION __stringify(TP_VERSION_MAJOR) "." \
1014 __stringify(TP_VERSION_MINOR) "." __stringify(TP_VERSION_MICRO)
1015#define TPSRAM_NAME "cxgb3/t3%c_psram-" TPSRAM_VERSION ".bin"
Divy Le Ray2e8c07c2009-07-07 19:49:09 +00001016#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin"
1017#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin"
Divy Le Ray94505262009-07-30 21:23:34 +00001018#define AEL2020_TWX_EDC_NAME "cxgb3/ael2020_twx_edc.bin"
Ben Hutchings34336ec2009-11-07 11:53:52 +00001019MODULE_FIRMWARE(FW_FNAME);
1020MODULE_FIRMWARE("cxgb3/t3b_psram-" TPSRAM_VERSION ".bin");
1021MODULE_FIRMWARE("cxgb3/t3c_psram-" TPSRAM_VERSION ".bin");
1022MODULE_FIRMWARE(AEL2005_OPT_EDC_NAME);
1023MODULE_FIRMWARE(AEL2005_TWX_EDC_NAME);
1024MODULE_FIRMWARE(AEL2020_TWX_EDC_NAME);
Divy Le Ray2e8c07c2009-07-07 19:49:09 +00001025
1026static inline const char *get_edc_fw_name(int edc_idx)
1027{
1028 const char *fw_name = NULL;
1029
1030 switch (edc_idx) {
1031 case EDC_OPT_AEL2005:
1032 fw_name = AEL2005_OPT_EDC_NAME;
1033 break;
1034 case EDC_TWX_AEL2005:
1035 fw_name = AEL2005_TWX_EDC_NAME;
1036 break;
1037 case EDC_TWX_AEL2020:
1038 fw_name = AEL2020_TWX_EDC_NAME;
1039 break;
1040 }
1041 return fw_name;
1042}
1043
1044int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size)
1045{
1046 struct adapter *adapter = phy->adapter;
1047 const struct firmware *fw;
1048 char buf[64];
1049 u32 csum;
1050 const __be32 *p;
1051 u16 *cache = phy->phy_cache;
1052 int i, ret;
1053
1054 snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx));
1055
1056 ret = request_firmware(&fw, buf, &adapter->pdev->dev);
1057 if (ret < 0) {
1058 dev_err(&adapter->pdev->dev,
1059 "could not upgrade firmware: unable to load %s\n",
1060 buf);
1061 return ret;
1062 }
1063
1064 /* check size, take checksum in account */
1065 if (fw->size > size + 4) {
1066 CH_ERR(adapter, "firmware image too large %u, expected %d\n",
1067 (unsigned int)fw->size, size + 4);
1068 ret = -EINVAL;
1069 }
1070
1071 /* compute checksum */
1072 p = (const __be32 *)fw->data;
1073 for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++)
1074 csum += ntohl(p[i]);
1075
1076 if (csum != 0xffffffff) {
1077 CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
1078 csum);
1079 ret = -EINVAL;
1080 }
1081
1082 for (i = 0; i < size / 4 ; i++) {
1083 *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16;
1084 *cache++ = be32_to_cpu(p[i]) & 0xffff;
1085 }
1086
1087 release_firmware(fw);
1088
1089 return ret;
1090}
Divy Le Ray2e283962007-03-18 13:10:06 -07001091
1092static int upgrade_fw(struct adapter *adap)
1093{
1094 int ret;
Divy Le Ray2e283962007-03-18 13:10:06 -07001095 const struct firmware *fw;
1096 struct device *dev = &adap->pdev->dev;
1097
Ben Hutchings34336ec2009-11-07 11:53:52 +00001098 ret = request_firmware(&fw, FW_FNAME, dev);
Divy Le Ray2e283962007-03-18 13:10:06 -07001099 if (ret < 0) {
1100 dev_err(dev, "could not upgrade firmware: unable to load %s\n",
Ben Hutchings34336ec2009-11-07 11:53:52 +00001101 FW_FNAME);
Divy Le Ray2e283962007-03-18 13:10:06 -07001102 return ret;
1103 }
1104 ret = t3_load_fw(adap, fw->data, fw->size);
1105 release_firmware(fw);
Divy Le Ray47330072007-08-29 19:15:52 -07001106
1107 if (ret == 0)
1108 dev_info(dev, "successful upgrade to firmware %d.%d.%d\n",
1109 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
1110 else
1111 dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n",
1112 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001113
Divy Le Ray47330072007-08-29 19:15:52 -07001114 return ret;
1115}
1116
1117static inline char t3rev2char(struct adapter *adapter)
1118{
1119 char rev = 0;
1120
1121 switch(adapter->params.rev) {
1122 case T3_REV_B:
1123 case T3_REV_B2:
1124 rev = 'b';
1125 break;
Divy Le Ray1aafee22007-09-05 15:58:36 -07001126 case T3_REV_C:
1127 rev = 'c';
1128 break;
Divy Le Ray47330072007-08-29 19:15:52 -07001129 }
1130 return rev;
1131}
1132
Stephen Hemminger9265fab2007-10-08 16:22:29 -07001133static int update_tpsram(struct adapter *adap)
Divy Le Ray47330072007-08-29 19:15:52 -07001134{
1135 const struct firmware *tpsram;
1136 char buf[64];
1137 struct device *dev = &adap->pdev->dev;
1138 int ret;
1139 char rev;
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001140
Divy Le Ray47330072007-08-29 19:15:52 -07001141 rev = t3rev2char(adap);
1142 if (!rev)
1143 return 0;
1144
Ben Hutchings34336ec2009-11-07 11:53:52 +00001145 snprintf(buf, sizeof(buf), TPSRAM_NAME, rev);
Divy Le Ray47330072007-08-29 19:15:52 -07001146
1147 ret = request_firmware(&tpsram, buf, dev);
1148 if (ret < 0) {
1149 dev_err(dev, "could not load TP SRAM: unable to load %s\n",
1150 buf);
1151 return ret;
1152 }
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001153
Divy Le Ray47330072007-08-29 19:15:52 -07001154 ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
1155 if (ret)
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001156 goto release_tpsram;
Divy Le Ray47330072007-08-29 19:15:52 -07001157
1158 ret = t3_set_proto_sram(adap, tpsram->data);
1159 if (ret == 0)
1160 dev_info(dev,
1161 "successful update of protocol engine "
1162 "to %d.%d.%d\n",
1163 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1164 else
1165 dev_err(dev, "failed to update of protocol engine %d.%d.%d\n",
1166 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1167 if (ret)
1168 dev_err(dev, "loading protocol SRAM failed\n");
1169
1170release_tpsram:
1171 release_firmware(tpsram);
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001172
Divy Le Ray2e283962007-03-18 13:10:06 -07001173 return ret;
1174}
1175
Divy Le Ray4d22de32007-01-18 22:04:14 -05001176/**
1177 * cxgb_up - enable the adapter
1178 * @adapter: adapter being enabled
1179 *
1180 * Called when the first port is enabled, this function performs the
1181 * actions necessary to make an adapter operational, such as completing
1182 * the initialization of HW modules, and enabling interrupts.
1183 *
1184 * Must be called with the rtnl lock held.
1185 */
1186static int cxgb_up(struct adapter *adap)
1187{
Denis Chengc54f5c22007-07-18 15:24:49 +08001188 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001189
1190 if (!(adap->flags & FULL_INIT_DONE)) {
Divy Le Ray8207bef2008-12-16 01:51:47 -08001191 err = t3_check_fw_version(adap);
Divy Le Raya5a3b462007-09-05 15:58:09 -07001192 if (err == -EINVAL) {
Divy Le Ray2e283962007-03-18 13:10:06 -07001193 err = upgrade_fw(adap);
Divy Le Ray8207bef2008-12-16 01:51:47 -08001194 CH_WARN(adap, "FW upgrade to %d.%d.%d %s\n",
1195 FW_VERSION_MAJOR, FW_VERSION_MINOR,
1196 FW_VERSION_MICRO, err ? "failed" : "succeeded");
Divy Le Raya5a3b462007-09-05 15:58:09 -07001197 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001198
Divy Le Ray8207bef2008-12-16 01:51:47 -08001199 err = t3_check_tpsram_version(adap);
Divy Le Ray47330072007-08-29 19:15:52 -07001200 if (err == -EINVAL) {
1201 err = update_tpsram(adap);
Divy Le Ray8207bef2008-12-16 01:51:47 -08001202 CH_WARN(adap, "TP upgrade to %d.%d.%d %s\n",
1203 TP_VERSION_MAJOR, TP_VERSION_MINOR,
1204 TP_VERSION_MICRO, err ? "failed" : "succeeded");
Divy Le Ray47330072007-08-29 19:15:52 -07001205 }
1206
Divy Le Ray20d3fc12008-10-08 17:36:03 -07001207 /*
1208 * Clear interrupts now to catch errors if t3_init_hw fails.
1209 * We clear them again later as initialization may trigger
1210 * conditions that can interrupt.
1211 */
1212 t3_intr_clear(adap);
1213
Divy Le Ray4d22de32007-01-18 22:04:14 -05001214 err = t3_init_hw(adap, 0);
1215 if (err)
1216 goto out;
1217
Divy Le Rayb8819552007-12-17 18:47:31 -08001218 t3_set_reg_field(adap, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
Divy Le Ray6cdbd772007-04-09 20:10:33 -07001219 t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
Stephen Hemmingerbea33482007-10-03 16:41:36 -07001220
Divy Le Ray4d22de32007-01-18 22:04:14 -05001221 err = setup_sge_qsets(adap);
1222 if (err)
1223 goto out;
1224
1225 setup_rss(adap);
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001226 if (!(adap->flags & NAPI_INIT))
1227 init_napi(adap);
Divy Le Ray31563782009-03-26 16:39:09 +00001228
1229 t3_start_sge_timers(adap);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001230 adap->flags |= FULL_INIT_DONE;
1231 }
1232
1233 t3_intr_clear(adap);
1234
1235 if (adap->flags & USING_MSIX) {
1236 name_msix_vecs(adap);
1237 err = request_irq(adap->msix_info[0].vec,
1238 t3_async_intr_handler, 0,
1239 adap->msix_info[0].desc, adap);
1240 if (err)
1241 goto irq_err;
1242
Divy Le Ray42256f52007-11-16 11:21:39 -08001243 err = request_msix_data_irqs(adap);
1244 if (err) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001245 free_irq(adap->msix_info[0].vec, adap);
1246 goto irq_err;
1247 }
1248 } else if ((err = request_irq(adap->pdev->irq,
1249 t3_intr_handler(adap,
1250 adap->sge.qs[0].rspq.
1251 polling),
Thomas Gleixner2db63462007-02-14 00:33:20 -08001252 (adap->flags & USING_MSI) ?
1253 0 : IRQF_SHARED,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001254 adap->name, adap)))
1255 goto irq_err;
1256
Stephen Hemmingerbea33482007-10-03 16:41:36 -07001257 enable_all_napi(adap);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001258 t3_sge_start(adap);
1259 t3_intr_enable(adap);
Divy Le Ray14ab9892007-01-30 19:43:50 -08001260
Divy Le Rayb8819552007-12-17 18:47:31 -08001261 if (adap->params.rev >= T3_REV_C && !(adap->flags & TP_PARITY_INIT) &&
1262 is_offload(adap) && init_tp_parity(adap) == 0)
1263 adap->flags |= TP_PARITY_INIT;
1264
1265 if (adap->flags & TP_PARITY_INIT) {
1266 t3_write_reg(adap, A_TP_INT_CAUSE,
1267 F_CMCACHEPERR | F_ARPLUTPERR);
1268 t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff);
1269 }
1270
Divy Le Ray8c263762008-10-08 17:37:33 -07001271 if (!(adap->flags & QUEUES_BOUND)) {
1272 err = bind_qsets(adap);
1273 if (err) {
1274 CH_ERR(adap, "failed to bind qsets, err %d\n", err);
1275 t3_intr_disable(adap);
1276 free_irq_resources(adap);
1277 goto out;
1278 }
1279 adap->flags |= QUEUES_BOUND;
1280 }
Divy Le Ray14ab9892007-01-30 19:43:50 -08001281
Divy Le Ray4d22de32007-01-18 22:04:14 -05001282out:
1283 return err;
1284irq_err:
1285 CH_ERR(adap, "request_irq failed, err %d\n", err);
1286 goto out;
1287}
1288
1289/*
1290 * Release resources when all the ports and offloading have been stopped.
1291 */
1292static void cxgb_down(struct adapter *adapter)
1293{
1294 t3_sge_stop(adapter);
1295 spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */
1296 t3_intr_disable(adapter);
1297 spin_unlock_irq(&adapter->work_lock);
1298
Divy Le Ray8c263762008-10-08 17:37:33 -07001299 free_irq_resources(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001300 quiesce_rx(adapter);
Divy Le Rayc80b0c22009-04-17 12:21:17 +00001301 flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */
Divy Le Ray4d22de32007-01-18 22:04:14 -05001302}
1303
1304static void schedule_chk_task(struct adapter *adap)
1305{
1306 unsigned int timeo;
1307
1308 timeo = adap->params.linkpoll_period ?
1309 (HZ * adap->params.linkpoll_period) / 10 :
1310 adap->params.stats_update_period * HZ;
1311 if (timeo)
1312 queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo);
1313}
1314
1315static int offload_open(struct net_device *dev)
1316{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001317 struct port_info *pi = netdev_priv(dev);
1318 struct adapter *adapter = pi->adapter;
1319 struct t3cdev *tdev = dev2t3cdev(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001320 int adap_up = adapter->open_device_map & PORT_MASK;
Denis Chengc54f5c22007-07-18 15:24:49 +08001321 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001322
1323 if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
1324 return 0;
1325
1326 if (!adap_up && (err = cxgb_up(adapter)) < 0)
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001327 goto out;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001328
1329 t3_tp_set_offload_mode(adapter, 1);
1330 tdev->lldev = adapter->port[0];
1331 err = cxgb3_offload_activate(adapter);
1332 if (err)
1333 goto out;
1334
1335 init_port_mtus(adapter);
1336 t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
1337 adapter->params.b_wnd,
1338 adapter->params.rev == 0 ?
1339 adapter->port[0]->mtu : 0xffff);
1340 init_smt(adapter);
1341
Dan Noed96a51f2008-04-12 22:34:38 -04001342 if (sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group))
1343 dev_dbg(&dev->dev, "cannot create sysfs group\n");
Divy Le Ray4d22de32007-01-18 22:04:14 -05001344
1345 /* Call back all registered clients */
1346 cxgb3_add_clients(tdev);
1347
1348out:
1349 /* restore them in case the offload module has changed them */
1350 if (err) {
1351 t3_tp_set_offload_mode(adapter, 0);
1352 clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
1353 cxgb3_set_dummy_ops(tdev);
1354 }
1355 return err;
1356}
1357
1358static int offload_close(struct t3cdev *tdev)
1359{
1360 struct adapter *adapter = tdev2adap(tdev);
1361
1362 if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
1363 return 0;
1364
1365 /* Call back all registered clients */
1366 cxgb3_remove_clients(tdev);
1367
Divy Le Ray0ee8d332007-02-08 16:55:59 -08001368 sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001369
Divy Le Rayc80b0c22009-04-17 12:21:17 +00001370 /* Flush work scheduled while releasing TIDs */
1371 flush_scheduled_work();
1372
Divy Le Ray4d22de32007-01-18 22:04:14 -05001373 tdev->lldev = NULL;
1374 cxgb3_set_dummy_ops(tdev);
1375 t3_tp_set_offload_mode(adapter, 0);
1376 clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
1377
1378 if (!adapter->open_device_map)
1379 cxgb_down(adapter);
1380
1381 cxgb3_offload_deactivate(adapter);
1382 return 0;
1383}
1384
1385static int cxgb_open(struct net_device *dev)
1386{
Divy Le Ray4d22de32007-01-18 22:04:14 -05001387 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001388 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001389 int other_ports = adapter->open_device_map & PORT_MASK;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001390 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001391
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001392 if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001393 return err;
1394
1395 set_bit(pi->port_id, &adapter->open_device_map);
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07001396 if (is_offload(adapter) && !ofld_disable) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001397 err = offload_open(dev);
1398 if (err)
1399 printk(KERN_WARNING
1400 "Could not initialize offload capabilities\n");
1401 }
1402
Divy Le Ray82ad3322008-12-16 01:09:39 -08001403 dev->real_num_tx_queues = pi->nqsets;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001404 link_start(dev);
1405 t3_port_intr_enable(adapter, pi->port_id);
Divy Le Ray82ad3322008-12-16 01:09:39 -08001406 netif_tx_start_all_queues(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001407 if (!other_ports)
1408 schedule_chk_task(adapter);
1409
Steve Wisefa0d4c12009-09-05 20:22:38 -07001410 cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_UP, pi->port_id);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001411 return 0;
1412}
1413
1414static int cxgb_close(struct net_device *dev)
1415{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001416 struct port_info *pi = netdev_priv(dev);
1417 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001418
Divy Le Raye8d19372009-04-17 12:21:27 +00001419
1420 if (!adapter->open_device_map)
1421 return 0;
1422
Divy Le Raybf792092009-03-12 21:14:19 +00001423 /* Stop link fault interrupts */
1424 t3_xgm_intr_disable(adapter, pi->port_id);
1425 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
1426
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001427 t3_port_intr_disable(adapter, pi->port_id);
Divy Le Ray82ad3322008-12-16 01:09:39 -08001428 netif_tx_stop_all_queues(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001429 pi->phy.ops->power_down(&pi->phy, 1);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001430 netif_carrier_off(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001431 t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001432
Divy Le Ray20d3fc12008-10-08 17:36:03 -07001433 spin_lock_irq(&adapter->work_lock); /* sync with update task */
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001434 clear_bit(pi->port_id, &adapter->open_device_map);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07001435 spin_unlock_irq(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001436
1437 if (!(adapter->open_device_map & PORT_MASK))
Divy Le Rayc80b0c22009-04-17 12:21:17 +00001438 cancel_delayed_work_sync(&adapter->adap_check_task);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001439
1440 if (!adapter->open_device_map)
1441 cxgb_down(adapter);
1442
Steve Wisefa0d4c12009-09-05 20:22:38 -07001443 cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_DOWN, pi->port_id);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001444 return 0;
1445}
1446
1447static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
1448{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001449 struct port_info *pi = netdev_priv(dev);
1450 struct adapter *adapter = pi->adapter;
1451 struct net_device_stats *ns = &pi->netstats;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001452 const struct mac_stats *pstats;
1453
1454 spin_lock(&adapter->stats_lock);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001455 pstats = t3_mac_update_stats(&pi->mac);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001456 spin_unlock(&adapter->stats_lock);
1457
1458 ns->tx_bytes = pstats->tx_octets;
1459 ns->tx_packets = pstats->tx_frames;
1460 ns->rx_bytes = pstats->rx_octets;
1461 ns->rx_packets = pstats->rx_frames;
1462 ns->multicast = pstats->rx_mcast_frames;
1463
1464 ns->tx_errors = pstats->tx_underrun;
1465 ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs +
1466 pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short +
1467 pstats->rx_fifo_ovfl;
1468
1469 /* detailed rx_errors */
1470 ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long;
1471 ns->rx_over_errors = 0;
1472 ns->rx_crc_errors = pstats->rx_fcs_errs;
1473 ns->rx_frame_errors = pstats->rx_symbol_errs;
1474 ns->rx_fifo_errors = pstats->rx_fifo_ovfl;
1475 ns->rx_missed_errors = pstats->rx_cong_drops;
1476
1477 /* detailed tx_errors */
1478 ns->tx_aborted_errors = 0;
1479 ns->tx_carrier_errors = 0;
1480 ns->tx_fifo_errors = pstats->tx_underrun;
1481 ns->tx_heartbeat_errors = 0;
1482 ns->tx_window_errors = 0;
1483 return ns;
1484}
1485
1486static u32 get_msglevel(struct net_device *dev)
1487{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001488 struct port_info *pi = netdev_priv(dev);
1489 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001490
1491 return adapter->msg_enable;
1492}
1493
1494static void set_msglevel(struct net_device *dev, u32 val)
1495{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001496 struct port_info *pi = netdev_priv(dev);
1497 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001498
1499 adapter->msg_enable = val;
1500}
1501
1502static char stats_strings[][ETH_GSTRING_LEN] = {
1503 "TxOctetsOK ",
1504 "TxFramesOK ",
1505 "TxMulticastFramesOK",
1506 "TxBroadcastFramesOK",
1507 "TxPauseFrames ",
1508 "TxUnderrun ",
1509 "TxExtUnderrun ",
1510
1511 "TxFrames64 ",
1512 "TxFrames65To127 ",
1513 "TxFrames128To255 ",
1514 "TxFrames256To511 ",
1515 "TxFrames512To1023 ",
1516 "TxFrames1024To1518 ",
1517 "TxFrames1519ToMax ",
1518
1519 "RxOctetsOK ",
1520 "RxFramesOK ",
1521 "RxMulticastFramesOK",
1522 "RxBroadcastFramesOK",
1523 "RxPauseFrames ",
1524 "RxFCSErrors ",
1525 "RxSymbolErrors ",
1526 "RxShortErrors ",
1527 "RxJabberErrors ",
1528 "RxLengthErrors ",
1529 "RxFIFOoverflow ",
1530
1531 "RxFrames64 ",
1532 "RxFrames65To127 ",
1533 "RxFrames128To255 ",
1534 "RxFrames256To511 ",
1535 "RxFrames512To1023 ",
1536 "RxFrames1024To1518 ",
1537 "RxFrames1519ToMax ",
1538
1539 "PhyFIFOErrors ",
1540 "TSO ",
1541 "VLANextractions ",
1542 "VLANinsertions ",
1543 "TxCsumOffload ",
1544 "RxCsumGood ",
Divy Le Rayb47385b2008-05-21 18:56:26 -07001545 "LroAggregated ",
1546 "LroFlushed ",
1547 "LroNoDesc ",
Divy Le Rayfc906642007-03-18 13:10:12 -07001548 "RxDrops ",
1549
1550 "CheckTXEnToggled ",
1551 "CheckResets ",
1552
Divy Le Raybf792092009-03-12 21:14:19 +00001553 "LinkFaults ",
Divy Le Ray4d22de32007-01-18 22:04:14 -05001554};
1555
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001556static int get_sset_count(struct net_device *dev, int sset)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001557{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001558 switch (sset) {
1559 case ETH_SS_STATS:
1560 return ARRAY_SIZE(stats_strings);
1561 default:
1562 return -EOPNOTSUPP;
1563 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001564}
1565
1566#define T3_REGMAP_SIZE (3 * 1024)
1567
1568static int get_regs_len(struct net_device *dev)
1569{
1570 return T3_REGMAP_SIZE;
1571}
1572
1573static int get_eeprom_len(struct net_device *dev)
1574{
1575 return EEPROMSIZE;
1576}
1577
1578static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
1579{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001580 struct port_info *pi = netdev_priv(dev);
1581 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001582 u32 fw_vers = 0;
Divy Le Ray47330072007-08-29 19:15:52 -07001583 u32 tp_vers = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001584
Steve Wisecf3760d2008-11-06 17:06:42 -06001585 spin_lock(&adapter->stats_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001586 t3_get_fw_version(adapter, &fw_vers);
Divy Le Ray47330072007-08-29 19:15:52 -07001587 t3_get_tp_version(adapter, &tp_vers);
Steve Wisecf3760d2008-11-06 17:06:42 -06001588 spin_unlock(&adapter->stats_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001589
1590 strcpy(info->driver, DRV_NAME);
1591 strcpy(info->version, DRV_VERSION);
1592 strcpy(info->bus_info, pci_name(adapter->pdev));
1593 if (!fw_vers)
1594 strcpy(info->fw_version, "N/A");
Divy Le Ray4aac3892007-01-30 19:43:45 -08001595 else {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001596 snprintf(info->fw_version, sizeof(info->fw_version),
Divy Le Ray47330072007-08-29 19:15:52 -07001597 "%s %u.%u.%u TP %u.%u.%u",
Divy Le Ray4aac3892007-01-30 19:43:45 -08001598 G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
1599 G_FW_VERSION_MAJOR(fw_vers),
1600 G_FW_VERSION_MINOR(fw_vers),
Divy Le Ray47330072007-08-29 19:15:52 -07001601 G_FW_VERSION_MICRO(fw_vers),
1602 G_TP_VERSION_MAJOR(tp_vers),
1603 G_TP_VERSION_MINOR(tp_vers),
1604 G_TP_VERSION_MICRO(tp_vers));
Divy Le Ray4aac3892007-01-30 19:43:45 -08001605 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001606}
1607
1608static void get_strings(struct net_device *dev, u32 stringset, u8 * data)
1609{
1610 if (stringset == ETH_SS_STATS)
1611 memcpy(data, stats_strings, sizeof(stats_strings));
1612}
1613
1614static unsigned long collect_sge_port_stats(struct adapter *adapter,
1615 struct port_info *p, int idx)
1616{
1617 int i;
1618 unsigned long tot = 0;
1619
Divy Le Ray8c263762008-10-08 17:37:33 -07001620 for (i = p->first_qset; i < p->first_qset + p->nqsets; ++i)
1621 tot += adapter->sge.qs[i].port_stats[idx];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001622 return tot;
1623}
1624
1625static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
1626 u64 *data)
1627{
Divy Le Ray4d22de32007-01-18 22:04:14 -05001628 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001629 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001630 const struct mac_stats *s;
1631
1632 spin_lock(&adapter->stats_lock);
1633 s = t3_mac_update_stats(&pi->mac);
1634 spin_unlock(&adapter->stats_lock);
1635
1636 *data++ = s->tx_octets;
1637 *data++ = s->tx_frames;
1638 *data++ = s->tx_mcast_frames;
1639 *data++ = s->tx_bcast_frames;
1640 *data++ = s->tx_pause;
1641 *data++ = s->tx_underrun;
1642 *data++ = s->tx_fifo_urun;
1643
1644 *data++ = s->tx_frames_64;
1645 *data++ = s->tx_frames_65_127;
1646 *data++ = s->tx_frames_128_255;
1647 *data++ = s->tx_frames_256_511;
1648 *data++ = s->tx_frames_512_1023;
1649 *data++ = s->tx_frames_1024_1518;
1650 *data++ = s->tx_frames_1519_max;
1651
1652 *data++ = s->rx_octets;
1653 *data++ = s->rx_frames;
1654 *data++ = s->rx_mcast_frames;
1655 *data++ = s->rx_bcast_frames;
1656 *data++ = s->rx_pause;
1657 *data++ = s->rx_fcs_errs;
1658 *data++ = s->rx_symbol_errs;
1659 *data++ = s->rx_short;
1660 *data++ = s->rx_jabber;
1661 *data++ = s->rx_too_long;
1662 *data++ = s->rx_fifo_ovfl;
1663
1664 *data++ = s->rx_frames_64;
1665 *data++ = s->rx_frames_65_127;
1666 *data++ = s->rx_frames_128_255;
1667 *data++ = s->rx_frames_256_511;
1668 *data++ = s->rx_frames_512_1023;
1669 *data++ = s->rx_frames_1024_1518;
1670 *data++ = s->rx_frames_1519_max;
1671
1672 *data++ = pi->phy.fifo_errors;
1673
1674 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO);
1675 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX);
1676 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
1677 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
1678 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
Herbert Xu7be2df42009-01-21 14:39:13 -08001679 *data++ = 0;
1680 *data++ = 0;
1681 *data++ = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001682 *data++ = s->rx_cong_drops;
Divy Le Rayfc906642007-03-18 13:10:12 -07001683
1684 *data++ = s->num_toggled;
1685 *data++ = s->num_resets;
Divy Le Raybf792092009-03-12 21:14:19 +00001686
1687 *data++ = s->link_faults;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001688}
1689
1690static inline void reg_block_dump(struct adapter *ap, void *buf,
1691 unsigned int start, unsigned int end)
1692{
1693 u32 *p = buf + start;
1694
1695 for (; start <= end; start += sizeof(u32))
1696 *p++ = t3_read_reg(ap, start);
1697}
1698
1699static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
1700 void *buf)
1701{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001702 struct port_info *pi = netdev_priv(dev);
1703 struct adapter *ap = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001704
1705 /*
1706 * Version scheme:
1707 * bits 0..9: chip version
1708 * bits 10..15: chip revision
1709 * bit 31: set for PCIe cards
1710 */
1711 regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31);
1712
1713 /*
1714 * We skip the MAC statistics registers because they are clear-on-read.
1715 * Also reading multi-register stats would need to synchronize with the
1716 * periodic mac stats accumulation. Hard to justify the complexity.
1717 */
1718 memset(buf, 0, T3_REGMAP_SIZE);
1719 reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
1720 reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
1721 reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
1722 reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
1723 reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
1724 reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0,
1725 XGM_REG(A_XGM_SERDES_STAT3, 1));
1726 reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
1727 XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
1728}
1729
1730static int restart_autoneg(struct net_device *dev)
1731{
1732 struct port_info *p = netdev_priv(dev);
1733
1734 if (!netif_running(dev))
1735 return -EAGAIN;
1736 if (p->link_config.autoneg != AUTONEG_ENABLE)
1737 return -EINVAL;
1738 p->phy.ops->autoneg_restart(&p->phy);
1739 return 0;
1740}
1741
1742static int cxgb3_phys_id(struct net_device *dev, u32 data)
1743{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001744 struct port_info *pi = netdev_priv(dev);
1745 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001746 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001747
1748 if (data == 0)
1749 data = 2;
1750
1751 for (i = 0; i < data * 2; i++) {
1752 t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
1753 (i & 1) ? F_GPIO0_OUT_VAL : 0);
1754 if (msleep_interruptible(500))
1755 break;
1756 }
1757 t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
1758 F_GPIO0_OUT_VAL);
1759 return 0;
1760}
1761
1762static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1763{
1764 struct port_info *p = netdev_priv(dev);
1765
1766 cmd->supported = p->link_config.supported;
1767 cmd->advertising = p->link_config.advertising;
1768
1769 if (netif_carrier_ok(dev)) {
1770 cmd->speed = p->link_config.speed;
1771 cmd->duplex = p->link_config.duplex;
1772 } else {
1773 cmd->speed = -1;
1774 cmd->duplex = -1;
1775 }
1776
1777 cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
Ben Hutchings0f07c4e2009-04-29 08:07:20 +00001778 cmd->phy_address = p->phy.mdio.prtad;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001779 cmd->transceiver = XCVR_EXTERNAL;
1780 cmd->autoneg = p->link_config.autoneg;
1781 cmd->maxtxpkt = 0;
1782 cmd->maxrxpkt = 0;
1783 return 0;
1784}
1785
1786static int speed_duplex_to_caps(int speed, int duplex)
1787{
1788 int cap = 0;
1789
1790 switch (speed) {
1791 case SPEED_10:
1792 if (duplex == DUPLEX_FULL)
1793 cap = SUPPORTED_10baseT_Full;
1794 else
1795 cap = SUPPORTED_10baseT_Half;
1796 break;
1797 case SPEED_100:
1798 if (duplex == DUPLEX_FULL)
1799 cap = SUPPORTED_100baseT_Full;
1800 else
1801 cap = SUPPORTED_100baseT_Half;
1802 break;
1803 case SPEED_1000:
1804 if (duplex == DUPLEX_FULL)
1805 cap = SUPPORTED_1000baseT_Full;
1806 else
1807 cap = SUPPORTED_1000baseT_Half;
1808 break;
1809 case SPEED_10000:
1810 if (duplex == DUPLEX_FULL)
1811 cap = SUPPORTED_10000baseT_Full;
1812 }
1813 return cap;
1814}
1815
1816#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1817 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1818 ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
1819 ADVERTISED_10000baseT_Full)
1820
1821static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1822{
1823 struct port_info *p = netdev_priv(dev);
1824 struct link_config *lc = &p->link_config;
1825
Divy Le Ray9b1e3652008-10-08 17:39:31 -07001826 if (!(lc->supported & SUPPORTED_Autoneg)) {
1827 /*
1828 * PHY offers a single speed/duplex. See if that's what's
1829 * being requested.
1830 */
1831 if (cmd->autoneg == AUTONEG_DISABLE) {
Hannes Eder97915b52009-02-14 11:16:04 +00001832 int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
Divy Le Ray9b1e3652008-10-08 17:39:31 -07001833 if (lc->supported & cap)
1834 return 0;
1835 }
1836 return -EINVAL;
1837 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001838
1839 if (cmd->autoneg == AUTONEG_DISABLE) {
1840 int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
1841
1842 if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
1843 return -EINVAL;
1844 lc->requested_speed = cmd->speed;
1845 lc->requested_duplex = cmd->duplex;
1846 lc->advertising = 0;
1847 } else {
1848 cmd->advertising &= ADVERTISED_MASK;
1849 cmd->advertising &= lc->supported;
1850 if (!cmd->advertising)
1851 return -EINVAL;
1852 lc->requested_speed = SPEED_INVALID;
1853 lc->requested_duplex = DUPLEX_INVALID;
1854 lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
1855 }
1856 lc->autoneg = cmd->autoneg;
1857 if (netif_running(dev))
1858 t3_link_start(&p->phy, &p->mac, lc);
1859 return 0;
1860}
1861
1862static void get_pauseparam(struct net_device *dev,
1863 struct ethtool_pauseparam *epause)
1864{
1865 struct port_info *p = netdev_priv(dev);
1866
1867 epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
1868 epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0;
1869 epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0;
1870}
1871
1872static int set_pauseparam(struct net_device *dev,
1873 struct ethtool_pauseparam *epause)
1874{
1875 struct port_info *p = netdev_priv(dev);
1876 struct link_config *lc = &p->link_config;
1877
1878 if (epause->autoneg == AUTONEG_DISABLE)
1879 lc->requested_fc = 0;
1880 else if (lc->supported & SUPPORTED_Autoneg)
1881 lc->requested_fc = PAUSE_AUTONEG;
1882 else
1883 return -EINVAL;
1884
1885 if (epause->rx_pause)
1886 lc->requested_fc |= PAUSE_RX;
1887 if (epause->tx_pause)
1888 lc->requested_fc |= PAUSE_TX;
1889 if (lc->autoneg == AUTONEG_ENABLE) {
1890 if (netif_running(dev))
1891 t3_link_start(&p->phy, &p->mac, lc);
1892 } else {
1893 lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1894 if (netif_running(dev))
1895 t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc);
1896 }
1897 return 0;
1898}
1899
1900static u32 get_rx_csum(struct net_device *dev)
1901{
1902 struct port_info *p = netdev_priv(dev);
1903
Roland Dreier47fd23f2009-01-11 00:19:36 -08001904 return p->rx_offload & T3_RX_CSUM;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001905}
1906
1907static int set_rx_csum(struct net_device *dev, u32 data)
1908{
1909 struct port_info *p = netdev_priv(dev);
1910
Roland Dreier47fd23f2009-01-11 00:19:36 -08001911 if (data) {
1912 p->rx_offload |= T3_RX_CSUM;
1913 } else {
Divy Le Rayb47385b2008-05-21 18:56:26 -07001914 int i;
1915
Roland Dreier47fd23f2009-01-11 00:19:36 -08001916 p->rx_offload &= ~(T3_RX_CSUM | T3_LRO);
Divy Le Ray04ecb072008-10-28 22:40:32 -07001917 for (i = p->first_qset; i < p->first_qset + p->nqsets; i++)
1918 set_qset_lro(dev, i, 0);
Divy Le Rayb47385b2008-05-21 18:56:26 -07001919 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001920 return 0;
1921}
1922
1923static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
1924{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001925 struct port_info *pi = netdev_priv(dev);
1926 struct adapter *adapter = pi->adapter;
Divy Le Ray05b97b32007-03-18 13:10:01 -07001927 const struct qset_params *q = &adapter->params.sge.qset[pi->first_qset];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001928
1929 e->rx_max_pending = MAX_RX_BUFFERS;
1930 e->rx_mini_max_pending = 0;
1931 e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
1932 e->tx_max_pending = MAX_TXQ_ENTRIES;
1933
Divy Le Ray05b97b32007-03-18 13:10:01 -07001934 e->rx_pending = q->fl_size;
1935 e->rx_mini_pending = q->rspq_size;
1936 e->rx_jumbo_pending = q->jumbo_size;
1937 e->tx_pending = q->txq_size[0];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001938}
1939
1940static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
1941{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001942 struct port_info *pi = netdev_priv(dev);
1943 struct adapter *adapter = pi->adapter;
Divy Le Ray05b97b32007-03-18 13:10:01 -07001944 struct qset_params *q;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001945 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001946
1947 if (e->rx_pending > MAX_RX_BUFFERS ||
1948 e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
1949 e->tx_pending > MAX_TXQ_ENTRIES ||
1950 e->rx_mini_pending > MAX_RSPQ_ENTRIES ||
1951 e->rx_mini_pending < MIN_RSPQ_ENTRIES ||
1952 e->rx_pending < MIN_FL_ENTRIES ||
1953 e->rx_jumbo_pending < MIN_FL_ENTRIES ||
1954 e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES)
1955 return -EINVAL;
1956
1957 if (adapter->flags & FULL_INIT_DONE)
1958 return -EBUSY;
1959
Divy Le Ray05b97b32007-03-18 13:10:01 -07001960 q = &adapter->params.sge.qset[pi->first_qset];
1961 for (i = 0; i < pi->nqsets; ++i, ++q) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001962 q->rspq_size = e->rx_mini_pending;
1963 q->fl_size = e->rx_pending;
1964 q->jumbo_size = e->rx_jumbo_pending;
1965 q->txq_size[0] = e->tx_pending;
1966 q->txq_size[1] = e->tx_pending;
1967 q->txq_size[2] = e->tx_pending;
1968 }
1969 return 0;
1970}
1971
1972static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
1973{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001974 struct port_info *pi = netdev_priv(dev);
1975 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001976 struct qset_params *qsp = &adapter->params.sge.qset[0];
1977 struct sge_qset *qs = &adapter->sge.qs[0];
1978
1979 if (c->rx_coalesce_usecs * 10 > M_NEWTIMER)
1980 return -EINVAL;
1981
1982 qsp->coalesce_usecs = c->rx_coalesce_usecs;
1983 t3_update_qset_coalesce(qs, qsp);
1984 return 0;
1985}
1986
1987static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
1988{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001989 struct port_info *pi = netdev_priv(dev);
1990 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001991 struct qset_params *q = adapter->params.sge.qset;
1992
1993 c->rx_coalesce_usecs = q->coalesce_usecs;
1994 return 0;
1995}
1996
1997static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
1998 u8 * data)
1999{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002000 struct port_info *pi = netdev_priv(dev);
2001 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002002 int i, err = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002003
2004 u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
2005 if (!buf)
2006 return -ENOMEM;
2007
2008 e->magic = EEPROM_MAGIC;
2009 for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
Al Viro05e5c112007-12-22 18:56:23 +00002010 err = t3_seeprom_read(adapter, i, (__le32 *) & buf[i]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002011
2012 if (!err)
2013 memcpy(data, buf + e->offset, e->len);
2014 kfree(buf);
2015 return err;
2016}
2017
2018static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
2019 u8 * data)
2020{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002021 struct port_info *pi = netdev_priv(dev);
2022 struct adapter *adapter = pi->adapter;
Al Viro05e5c112007-12-22 18:56:23 +00002023 u32 aligned_offset, aligned_len;
2024 __le32 *p;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002025 u8 *buf;
Denis Chengc54f5c22007-07-18 15:24:49 +08002026 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002027
2028 if (eeprom->magic != EEPROM_MAGIC)
2029 return -EINVAL;
2030
2031 aligned_offset = eeprom->offset & ~3;
2032 aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
2033
2034 if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
2035 buf = kmalloc(aligned_len, GFP_KERNEL);
2036 if (!buf)
2037 return -ENOMEM;
Al Viro05e5c112007-12-22 18:56:23 +00002038 err = t3_seeprom_read(adapter, aligned_offset, (__le32 *) buf);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002039 if (!err && aligned_len > 4)
2040 err = t3_seeprom_read(adapter,
2041 aligned_offset + aligned_len - 4,
Al Viro05e5c112007-12-22 18:56:23 +00002042 (__le32 *) & buf[aligned_len - 4]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002043 if (err)
2044 goto out;
2045 memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
2046 } else
2047 buf = data;
2048
2049 err = t3_seeprom_wp(adapter, 0);
2050 if (err)
2051 goto out;
2052
Al Viro05e5c112007-12-22 18:56:23 +00002053 for (p = (__le32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05002054 err = t3_seeprom_write(adapter, aligned_offset, *p);
2055 aligned_offset += 4;
2056 }
2057
2058 if (!err)
2059 err = t3_seeprom_wp(adapter, 1);
2060out:
2061 if (buf != data)
2062 kfree(buf);
2063 return err;
2064}
2065
2066static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
2067{
2068 wol->supported = 0;
2069 wol->wolopts = 0;
2070 memset(&wol->sopass, 0, sizeof(wol->sopass));
2071}
2072
2073static const struct ethtool_ops cxgb_ethtool_ops = {
2074 .get_settings = get_settings,
2075 .set_settings = set_settings,
2076 .get_drvinfo = get_drvinfo,
2077 .get_msglevel = get_msglevel,
2078 .set_msglevel = set_msglevel,
2079 .get_ringparam = get_sge_param,
2080 .set_ringparam = set_sge_param,
2081 .get_coalesce = get_coalesce,
2082 .set_coalesce = set_coalesce,
2083 .get_eeprom_len = get_eeprom_len,
2084 .get_eeprom = get_eeprom,
2085 .set_eeprom = set_eeprom,
2086 .get_pauseparam = get_pauseparam,
2087 .set_pauseparam = set_pauseparam,
2088 .get_rx_csum = get_rx_csum,
2089 .set_rx_csum = set_rx_csum,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002090 .set_tx_csum = ethtool_op_set_tx_csum,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002091 .set_sg = ethtool_op_set_sg,
2092 .get_link = ethtool_op_get_link,
2093 .get_strings = get_strings,
2094 .phys_id = cxgb3_phys_id,
2095 .nway_reset = restart_autoneg,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07002096 .get_sset_count = get_sset_count,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002097 .get_ethtool_stats = get_stats,
2098 .get_regs_len = get_regs_len,
2099 .get_regs = get_regs,
2100 .get_wol = get_wol,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002101 .set_tso = ethtool_op_set_tso,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002102};
2103
2104static int in_range(int val, int lo, int hi)
2105{
2106 return val < 0 || (val <= hi && val >= lo);
2107}
2108
2109static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
2110{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002111 struct port_info *pi = netdev_priv(dev);
2112 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002113 u32 cmd;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002114 int ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002115
2116 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
2117 return -EFAULT;
2118
2119 switch (cmd) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05002120 case CHELSIO_SET_QSET_PARAMS:{
2121 int i;
2122 struct qset_params *q;
2123 struct ch_qset_params t;
Divy Le Ray8c263762008-10-08 17:37:33 -07002124 int q1 = pi->first_qset;
2125 int nqsets = pi->nqsets;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002126
2127 if (!capable(CAP_NET_ADMIN))
2128 return -EPERM;
2129 if (copy_from_user(&t, useraddr, sizeof(t)))
2130 return -EFAULT;
2131 if (t.qset_idx >= SGE_QSETS)
2132 return -EINVAL;
2133 if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
Joe Perches8e95a202009-12-03 07:58:21 +00002134 !in_range(t.cong_thres, 0, 255) ||
2135 !in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
2136 MAX_TXQ_ENTRIES) ||
2137 !in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
2138 MAX_TXQ_ENTRIES) ||
2139 !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
2140 MAX_CTRL_TXQ_ENTRIES) ||
2141 !in_range(t.fl_size[0], MIN_FL_ENTRIES,
2142 MAX_RX_BUFFERS) ||
2143 !in_range(t.fl_size[1], MIN_FL_ENTRIES,
2144 MAX_RX_JUMBO_BUFFERS) ||
2145 !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
2146 MAX_RSPQ_ENTRIES))
Divy Le Ray4d22de32007-01-18 22:04:14 -05002147 return -EINVAL;
Divy Le Ray8c263762008-10-08 17:37:33 -07002148
2149 if ((adapter->flags & FULL_INIT_DONE) && t.lro > 0)
2150 for_each_port(adapter, i) {
2151 pi = adap2pinfo(adapter, i);
2152 if (t.qset_idx >= pi->first_qset &&
2153 t.qset_idx < pi->first_qset + pi->nqsets &&
Roland Dreier47fd23f2009-01-11 00:19:36 -08002154 !(pi->rx_offload & T3_RX_CSUM))
Divy Le Ray8c263762008-10-08 17:37:33 -07002155 return -EINVAL;
2156 }
2157
Divy Le Ray4d22de32007-01-18 22:04:14 -05002158 if ((adapter->flags & FULL_INIT_DONE) &&
2159 (t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
2160 t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
2161 t.txq_size[1] >= 0 || t.txq_size[2] >= 0 ||
2162 t.polling >= 0 || t.cong_thres >= 0))
2163 return -EBUSY;
2164
Divy Le Ray8c263762008-10-08 17:37:33 -07002165 /* Allow setting of any available qset when offload enabled */
2166 if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
2167 q1 = 0;
2168 for_each_port(adapter, i) {
2169 pi = adap2pinfo(adapter, i);
2170 nqsets += pi->first_qset + pi->nqsets;
2171 }
2172 }
2173
2174 if (t.qset_idx < q1)
2175 return -EINVAL;
2176 if (t.qset_idx > q1 + nqsets - 1)
2177 return -EINVAL;
2178
Divy Le Ray4d22de32007-01-18 22:04:14 -05002179 q = &adapter->params.sge.qset[t.qset_idx];
2180
2181 if (t.rspq_size >= 0)
2182 q->rspq_size = t.rspq_size;
2183 if (t.fl_size[0] >= 0)
2184 q->fl_size = t.fl_size[0];
2185 if (t.fl_size[1] >= 0)
2186 q->jumbo_size = t.fl_size[1];
2187 if (t.txq_size[0] >= 0)
2188 q->txq_size[0] = t.txq_size[0];
2189 if (t.txq_size[1] >= 0)
2190 q->txq_size[1] = t.txq_size[1];
2191 if (t.txq_size[2] >= 0)
2192 q->txq_size[2] = t.txq_size[2];
2193 if (t.cong_thres >= 0)
2194 q->cong_thres = t.cong_thres;
2195 if (t.intr_lat >= 0) {
2196 struct sge_qset *qs =
2197 &adapter->sge.qs[t.qset_idx];
2198
2199 q->coalesce_usecs = t.intr_lat;
2200 t3_update_qset_coalesce(qs, q);
2201 }
2202 if (t.polling >= 0) {
2203 if (adapter->flags & USING_MSIX)
2204 q->polling = t.polling;
2205 else {
2206 /* No polling with INTx for T3A */
2207 if (adapter->params.rev == 0 &&
2208 !(adapter->flags & USING_MSI))
2209 t.polling = 0;
2210
2211 for (i = 0; i < SGE_QSETS; i++) {
2212 q = &adapter->params.sge.
2213 qset[i];
2214 q->polling = t.polling;
2215 }
2216 }
2217 }
Divy Le Ray04ecb072008-10-28 22:40:32 -07002218 if (t.lro >= 0)
2219 set_qset_lro(dev, t.qset_idx, t.lro);
2220
Divy Le Ray4d22de32007-01-18 22:04:14 -05002221 break;
2222 }
2223 case CHELSIO_GET_QSET_PARAMS:{
2224 struct qset_params *q;
2225 struct ch_qset_params t;
Divy Le Ray8c263762008-10-08 17:37:33 -07002226 int q1 = pi->first_qset;
2227 int nqsets = pi->nqsets;
2228 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002229
2230 if (copy_from_user(&t, useraddr, sizeof(t)))
2231 return -EFAULT;
Divy Le Ray8c263762008-10-08 17:37:33 -07002232
2233 /* Display qsets for all ports when offload enabled */
2234 if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
2235 q1 = 0;
2236 for_each_port(adapter, i) {
2237 pi = adap2pinfo(adapter, i);
2238 nqsets = pi->first_qset + pi->nqsets;
2239 }
2240 }
2241
2242 if (t.qset_idx >= nqsets)
Divy Le Ray4d22de32007-01-18 22:04:14 -05002243 return -EINVAL;
2244
Divy Le Ray8c263762008-10-08 17:37:33 -07002245 q = &adapter->params.sge.qset[q1 + t.qset_idx];
Divy Le Ray4d22de32007-01-18 22:04:14 -05002246 t.rspq_size = q->rspq_size;
2247 t.txq_size[0] = q->txq_size[0];
2248 t.txq_size[1] = q->txq_size[1];
2249 t.txq_size[2] = q->txq_size[2];
2250 t.fl_size[0] = q->fl_size;
2251 t.fl_size[1] = q->jumbo_size;
2252 t.polling = q->polling;
Divy Le Rayb47385b2008-05-21 18:56:26 -07002253 t.lro = q->lro;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002254 t.intr_lat = q->coalesce_usecs;
2255 t.cong_thres = q->cong_thres;
Divy Le Ray8c263762008-10-08 17:37:33 -07002256 t.qnum = q1;
2257
2258 if (adapter->flags & USING_MSIX)
2259 t.vector = adapter->msix_info[q1 + t.qset_idx + 1].vec;
2260 else
2261 t.vector = adapter->pdev->irq;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002262
2263 if (copy_to_user(useraddr, &t, sizeof(t)))
2264 return -EFAULT;
2265 break;
2266 }
2267 case CHELSIO_SET_QSET_NUM:{
2268 struct ch_reg edata;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002269 unsigned int i, first_qset = 0, other_qsets = 0;
2270
2271 if (!capable(CAP_NET_ADMIN))
2272 return -EPERM;
2273 if (adapter->flags & FULL_INIT_DONE)
2274 return -EBUSY;
2275 if (copy_from_user(&edata, useraddr, sizeof(edata)))
2276 return -EFAULT;
2277 if (edata.val < 1 ||
2278 (edata.val > 1 && !(adapter->flags & USING_MSIX)))
2279 return -EINVAL;
2280
2281 for_each_port(adapter, i)
2282 if (adapter->port[i] && adapter->port[i] != dev)
2283 other_qsets += adap2pinfo(adapter, i)->nqsets;
2284
2285 if (edata.val + other_qsets > SGE_QSETS)
2286 return -EINVAL;
2287
2288 pi->nqsets = edata.val;
2289
2290 for_each_port(adapter, i)
2291 if (adapter->port[i]) {
2292 pi = adap2pinfo(adapter, i);
2293 pi->first_qset = first_qset;
2294 first_qset += pi->nqsets;
2295 }
2296 break;
2297 }
2298 case CHELSIO_GET_QSET_NUM:{
2299 struct ch_reg edata;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002300
2301 edata.cmd = CHELSIO_GET_QSET_NUM;
2302 edata.val = pi->nqsets;
2303 if (copy_to_user(useraddr, &edata, sizeof(edata)))
2304 return -EFAULT;
2305 break;
2306 }
2307 case CHELSIO_LOAD_FW:{
2308 u8 *fw_data;
2309 struct ch_mem_range t;
2310
Alan Cox1b3aa7a2008-04-29 14:29:30 +01002311 if (!capable(CAP_SYS_RAWIO))
Divy Le Ray4d22de32007-01-18 22:04:14 -05002312 return -EPERM;
2313 if (copy_from_user(&t, useraddr, sizeof(t)))
2314 return -EFAULT;
Alan Cox1b3aa7a2008-04-29 14:29:30 +01002315 /* Check t.len sanity ? */
Divy Le Ray4d22de32007-01-18 22:04:14 -05002316 fw_data = kmalloc(t.len, GFP_KERNEL);
2317 if (!fw_data)
2318 return -ENOMEM;
2319
2320 if (copy_from_user
2321 (fw_data, useraddr + sizeof(t), t.len)) {
2322 kfree(fw_data);
2323 return -EFAULT;
2324 }
2325
2326 ret = t3_load_fw(adapter, fw_data, t.len);
2327 kfree(fw_data);
2328 if (ret)
2329 return ret;
2330 break;
2331 }
2332 case CHELSIO_SETMTUTAB:{
2333 struct ch_mtus m;
2334 int i;
2335
2336 if (!is_offload(adapter))
2337 return -EOPNOTSUPP;
2338 if (!capable(CAP_NET_ADMIN))
2339 return -EPERM;
2340 if (offload_running(adapter))
2341 return -EBUSY;
2342 if (copy_from_user(&m, useraddr, sizeof(m)))
2343 return -EFAULT;
2344 if (m.nmtus != NMTUS)
2345 return -EINVAL;
2346 if (m.mtus[0] < 81) /* accommodate SACK */
2347 return -EINVAL;
2348
2349 /* MTUs must be in ascending order */
2350 for (i = 1; i < NMTUS; ++i)
2351 if (m.mtus[i] < m.mtus[i - 1])
2352 return -EINVAL;
2353
2354 memcpy(adapter->params.mtus, m.mtus,
2355 sizeof(adapter->params.mtus));
2356 break;
2357 }
2358 case CHELSIO_GET_PM:{
2359 struct tp_params *p = &adapter->params.tp;
2360 struct ch_pm m = {.cmd = CHELSIO_GET_PM };
2361
2362 if (!is_offload(adapter))
2363 return -EOPNOTSUPP;
2364 m.tx_pg_sz = p->tx_pg_size;
2365 m.tx_num_pg = p->tx_num_pgs;
2366 m.rx_pg_sz = p->rx_pg_size;
2367 m.rx_num_pg = p->rx_num_pgs;
2368 m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan;
2369 if (copy_to_user(useraddr, &m, sizeof(m)))
2370 return -EFAULT;
2371 break;
2372 }
2373 case CHELSIO_SET_PM:{
2374 struct ch_pm m;
2375 struct tp_params *p = &adapter->params.tp;
2376
2377 if (!is_offload(adapter))
2378 return -EOPNOTSUPP;
2379 if (!capable(CAP_NET_ADMIN))
2380 return -EPERM;
2381 if (adapter->flags & FULL_INIT_DONE)
2382 return -EBUSY;
2383 if (copy_from_user(&m, useraddr, sizeof(m)))
2384 return -EFAULT;
vignesh babud9da4662007-07-09 11:50:22 -07002385 if (!is_power_of_2(m.rx_pg_sz) ||
2386 !is_power_of_2(m.tx_pg_sz))
Divy Le Ray4d22de32007-01-18 22:04:14 -05002387 return -EINVAL; /* not power of 2 */
2388 if (!(m.rx_pg_sz & 0x14000))
2389 return -EINVAL; /* not 16KB or 64KB */
2390 if (!(m.tx_pg_sz & 0x1554000))
2391 return -EINVAL;
2392 if (m.tx_num_pg == -1)
2393 m.tx_num_pg = p->tx_num_pgs;
2394 if (m.rx_num_pg == -1)
2395 m.rx_num_pg = p->rx_num_pgs;
2396 if (m.tx_num_pg % 24 || m.rx_num_pg % 24)
2397 return -EINVAL;
2398 if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size ||
2399 m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size)
2400 return -EINVAL;
2401 p->rx_pg_size = m.rx_pg_sz;
2402 p->tx_pg_size = m.tx_pg_sz;
2403 p->rx_num_pgs = m.rx_num_pg;
2404 p->tx_num_pgs = m.tx_num_pg;
2405 break;
2406 }
2407 case CHELSIO_GET_MEM:{
2408 struct ch_mem_range t;
2409 struct mc7 *mem;
2410 u64 buf[32];
2411
2412 if (!is_offload(adapter))
2413 return -EOPNOTSUPP;
2414 if (!(adapter->flags & FULL_INIT_DONE))
2415 return -EIO; /* need the memory controllers */
2416 if (copy_from_user(&t, useraddr, sizeof(t)))
2417 return -EFAULT;
2418 if ((t.addr & 7) || (t.len & 7))
2419 return -EINVAL;
2420 if (t.mem_id == MEM_CM)
2421 mem = &adapter->cm;
2422 else if (t.mem_id == MEM_PMRX)
2423 mem = &adapter->pmrx;
2424 else if (t.mem_id == MEM_PMTX)
2425 mem = &adapter->pmtx;
2426 else
2427 return -EINVAL;
2428
2429 /*
Divy Le Ray18254942007-02-24 16:43:56 -08002430 * Version scheme:
2431 * bits 0..9: chip version
2432 * bits 10..15: chip revision
2433 */
Divy Le Ray4d22de32007-01-18 22:04:14 -05002434 t.version = 3 | (adapter->params.rev << 10);
2435 if (copy_to_user(useraddr, &t, sizeof(t)))
2436 return -EFAULT;
2437
2438 /*
2439 * Read 256 bytes at a time as len can be large and we don't
2440 * want to use huge intermediate buffers.
2441 */
2442 useraddr += sizeof(t); /* advance to start of buffer */
2443 while (t.len) {
2444 unsigned int chunk =
2445 min_t(unsigned int, t.len, sizeof(buf));
2446
2447 ret =
2448 t3_mc7_bd_read(mem, t.addr / 8, chunk / 8,
2449 buf);
2450 if (ret)
2451 return ret;
2452 if (copy_to_user(useraddr, buf, chunk))
2453 return -EFAULT;
2454 useraddr += chunk;
2455 t.addr += chunk;
2456 t.len -= chunk;
2457 }
2458 break;
2459 }
2460 case CHELSIO_SET_TRACE_FILTER:{
2461 struct ch_trace t;
2462 const struct trace_params *tp;
2463
2464 if (!capable(CAP_NET_ADMIN))
2465 return -EPERM;
2466 if (!offload_running(adapter))
2467 return -EAGAIN;
2468 if (copy_from_user(&t, useraddr, sizeof(t)))
2469 return -EFAULT;
2470
2471 tp = (const struct trace_params *)&t.sip;
2472 if (t.config_tx)
2473 t3_config_trace_filter(adapter, tp, 0,
2474 t.invert_match,
2475 t.trace_tx);
2476 if (t.config_rx)
2477 t3_config_trace_filter(adapter, tp, 1,
2478 t.invert_match,
2479 t.trace_rx);
2480 break;
2481 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002482 default:
2483 return -EOPNOTSUPP;
2484 }
2485 return 0;
2486}
2487
2488static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
2489{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002490 struct mii_ioctl_data *data = if_mii(req);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002491 struct port_info *pi = netdev_priv(dev);
2492 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002493
2494 switch (cmd) {
Ben Hutchings0f07c4e2009-04-29 08:07:20 +00002495 case SIOCGMIIREG:
2496 case SIOCSMIIREG:
2497 /* Convert phy_id from older PRTAD/DEVAD format */
2498 if (is_10G(adapter) &&
2499 !mdio_phy_id_is_c45(data->phy_id) &&
2500 (data->phy_id & 0x1f00) &&
2501 !(data->phy_id & 0xe0e0))
2502 data->phy_id = mdio_phy_id_c45(data->phy_id >> 8,
2503 data->phy_id & 0x1f);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002504 /* FALLTHRU */
Ben Hutchings0f07c4e2009-04-29 08:07:20 +00002505 case SIOCGMIIPHY:
2506 return mdio_mii_ioctl(&pi->phy.mdio, data, cmd);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002507 case SIOCCHIOCTL:
2508 return cxgb_extension_ioctl(dev, req->ifr_data);
2509 default:
2510 return -EOPNOTSUPP;
2511 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002512}
2513
2514static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
2515{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002516 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002517 struct adapter *adapter = pi->adapter;
2518 int ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002519
2520 if (new_mtu < 81) /* accommodate SACK */
2521 return -EINVAL;
2522 if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu)))
2523 return ret;
2524 dev->mtu = new_mtu;
2525 init_port_mtus(adapter);
2526 if (adapter->params.rev == 0 && offload_running(adapter))
2527 t3_load_mtus(adapter, adapter->params.mtus,
2528 adapter->params.a_wnd, adapter->params.b_wnd,
2529 adapter->port[0]->mtu);
2530 return 0;
2531}
2532
2533static int cxgb_set_mac_addr(struct net_device *dev, void *p)
2534{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002535 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002536 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002537 struct sockaddr *addr = p;
2538
2539 if (!is_valid_ether_addr(addr->sa_data))
2540 return -EINVAL;
2541
2542 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
Karen Xief14d42f2009-10-08 09:11:05 +00002543 t3_mac_set_address(&pi->mac, LAN_MAC_IDX, dev->dev_addr);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002544 if (offload_running(adapter))
2545 write_smt_entry(adapter, pi->port_id);
2546 return 0;
2547}
2548
2549/**
2550 * t3_synchronize_rx - wait for current Rx processing on a port to complete
2551 * @adap: the adapter
2552 * @p: the port
2553 *
2554 * Ensures that current Rx processing on any of the queues associated with
2555 * the given port completes before returning. We do this by acquiring and
2556 * releasing the locks of the response queues associated with the port.
2557 */
2558static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
2559{
2560 int i;
2561
Divy Le Ray8c263762008-10-08 17:37:33 -07002562 for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
2563 struct sge_rspq *q = &adap->sge.qs[i].rspq;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002564
2565 spin_lock_irq(&q->lock);
2566 spin_unlock_irq(&q->lock);
2567 }
2568}
2569
2570static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
2571{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002572 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002573 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002574
2575 pi->vlan_grp = grp;
2576 if (adapter->params.rev > 0)
2577 t3_set_vlan_accel(adapter, 1 << pi->port_id, grp != NULL);
2578 else {
2579 /* single control for all ports */
2580 unsigned int i, have_vlans = 0;
2581 for_each_port(adapter, i)
2582 have_vlans |= adap2pinfo(adapter, i)->vlan_grp != NULL;
2583
2584 t3_set_vlan_accel(adapter, 1, have_vlans);
2585 }
2586 t3_synchronize_rx(adapter, pi);
2587}
2588
Divy Le Ray4d22de32007-01-18 22:04:14 -05002589#ifdef CONFIG_NET_POLL_CONTROLLER
2590static void cxgb_netpoll(struct net_device *dev)
2591{
Divy Le Ray890de332007-05-30 10:01:34 -07002592 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002593 struct adapter *adapter = pi->adapter;
Divy Le Ray890de332007-05-30 10:01:34 -07002594 int qidx;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002595
Divy Le Ray890de332007-05-30 10:01:34 -07002596 for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) {
2597 struct sge_qset *qs = &adapter->sge.qs[qidx];
2598 void *source;
Jeff Garzik2eab17a2007-11-23 21:59:45 -05002599
Divy Le Ray890de332007-05-30 10:01:34 -07002600 if (adapter->flags & USING_MSIX)
2601 source = qs;
2602 else
2603 source = adapter;
2604
2605 t3_intr_handler(adapter, qs->rspq.polling) (0, source);
2606 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002607}
2608#endif
2609
2610/*
2611 * Periodic accumulation of MAC statistics.
2612 */
2613static void mac_stats_update(struct adapter *adapter)
2614{
2615 int i;
2616
2617 for_each_port(adapter, i) {
2618 struct net_device *dev = adapter->port[i];
2619 struct port_info *p = netdev_priv(dev);
2620
2621 if (netif_running(dev)) {
2622 spin_lock(&adapter->stats_lock);
2623 t3_mac_update_stats(&p->mac);
2624 spin_unlock(&adapter->stats_lock);
2625 }
2626 }
2627}
2628
2629static void check_link_status(struct adapter *adapter)
2630{
2631 int i;
2632
2633 for_each_port(adapter, i) {
2634 struct net_device *dev = adapter->port[i];
2635 struct port_info *p = netdev_priv(dev);
Divy Le Rayc22c8142009-05-28 11:23:08 +00002636 int link_fault;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002637
Divy Le Raybf792092009-03-12 21:14:19 +00002638 spin_lock_irq(&adapter->work_lock);
Divy Le Rayc22c8142009-05-28 11:23:08 +00002639 link_fault = p->link_fault;
2640 spin_unlock_irq(&adapter->work_lock);
2641
2642 if (link_fault) {
Divy Le Ray3851c662009-04-17 12:21:11 +00002643 t3_link_fault(adapter, i);
Divy Le Raybf792092009-03-12 21:14:19 +00002644 continue;
2645 }
Divy Le Raybf792092009-03-12 21:14:19 +00002646
2647 if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) {
2648 t3_xgm_intr_disable(adapter, i);
2649 t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
2650
Divy Le Ray4d22de32007-01-18 22:04:14 -05002651 t3_link_changed(adapter, i);
Divy Le Raybf792092009-03-12 21:14:19 +00002652 t3_xgm_intr_enable(adapter, i);
2653 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002654 }
2655}
2656
Divy Le Rayfc906642007-03-18 13:10:12 -07002657static void check_t3b2_mac(struct adapter *adapter)
2658{
2659 int i;
2660
Divy Le Rayf2d961c2007-04-09 20:10:22 -07002661 if (!rtnl_trylock()) /* synchronize with ifdown */
2662 return;
2663
Divy Le Rayfc906642007-03-18 13:10:12 -07002664 for_each_port(adapter, i) {
2665 struct net_device *dev = adapter->port[i];
2666 struct port_info *p = netdev_priv(dev);
2667 int status;
2668
2669 if (!netif_running(dev))
2670 continue;
2671
2672 status = 0;
Divy Le Ray6d6daba2007-03-31 00:23:24 -07002673 if (netif_running(dev) && netif_carrier_ok(dev))
Divy Le Rayfc906642007-03-18 13:10:12 -07002674 status = t3b2_mac_watchdog_task(&p->mac);
2675 if (status == 1)
2676 p->mac.stats.num_toggled++;
2677 else if (status == 2) {
2678 struct cmac *mac = &p->mac;
2679
2680 t3_mac_set_mtu(mac, dev->mtu);
Karen Xief14d42f2009-10-08 09:11:05 +00002681 t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr);
Divy Le Rayfc906642007-03-18 13:10:12 -07002682 cxgb_set_rxmode(dev);
2683 t3_link_start(&p->phy, mac, &p->link_config);
2684 t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
2685 t3_port_intr_enable(adapter, p->port_id);
2686 p->mac.stats.num_resets++;
2687 }
2688 }
2689 rtnl_unlock();
2690}
2691
2692
Divy Le Ray4d22de32007-01-18 22:04:14 -05002693static void t3_adap_check_task(struct work_struct *work)
2694{
2695 struct adapter *adapter = container_of(work, struct adapter,
2696 adap_check_task.work);
2697 const struct adapter_params *p = &adapter->params;
Divy Le Rayfc882192009-03-12 21:14:09 +00002698 int port;
2699 unsigned int v, status, reset;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002700
2701 adapter->check_task_cnt++;
2702
Divy Le Ray3851c662009-04-17 12:21:11 +00002703 check_link_status(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002704
2705 /* Accumulate MAC stats if needed */
2706 if (!p->linkpoll_period ||
2707 (adapter->check_task_cnt * p->linkpoll_period) / 10 >=
2708 p->stats_update_period) {
2709 mac_stats_update(adapter);
2710 adapter->check_task_cnt = 0;
2711 }
2712
Divy Le Rayfc906642007-03-18 13:10:12 -07002713 if (p->rev == T3_REV_B2)
2714 check_t3b2_mac(adapter);
2715
Divy Le Rayfc882192009-03-12 21:14:09 +00002716 /*
2717 * Scan the XGMAC's to check for various conditions which we want to
2718 * monitor in a periodic polling manner rather than via an interrupt
2719 * condition. This is used for conditions which would otherwise flood
2720 * the system with interrupts and we only really need to know that the
2721 * conditions are "happening" ... For each condition we count the
2722 * detection of the condition and reset it for the next polling loop.
2723 */
2724 for_each_port(adapter, port) {
2725 struct cmac *mac = &adap2pinfo(adapter, port)->mac;
2726 u32 cause;
2727
2728 cause = t3_read_reg(adapter, A_XGM_INT_CAUSE + mac->offset);
2729 reset = 0;
2730 if (cause & F_RXFIFO_OVERFLOW) {
2731 mac->stats.rx_fifo_ovfl++;
2732 reset |= F_RXFIFO_OVERFLOW;
2733 }
2734
2735 t3_write_reg(adapter, A_XGM_INT_CAUSE + mac->offset, reset);
2736 }
2737
2738 /*
2739 * We do the same as above for FL_EMPTY interrupts.
2740 */
2741 status = t3_read_reg(adapter, A_SG_INT_CAUSE);
2742 reset = 0;
2743
2744 if (status & F_FLEMPTY) {
2745 struct sge_qset *qs = &adapter->sge.qs[0];
2746 int i = 0;
2747
2748 reset |= F_FLEMPTY;
2749
2750 v = (t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS) >> S_FL0EMPTY) &
2751 0xffff;
2752
2753 while (v) {
2754 qs->fl[i].empty += (v & 1);
2755 if (i)
2756 qs++;
2757 i ^= 1;
2758 v >>= 1;
2759 }
2760 }
2761
2762 t3_write_reg(adapter, A_SG_INT_CAUSE, reset);
2763
Divy Le Ray4d22de32007-01-18 22:04:14 -05002764 /* Schedule the next check update if any port is active. */
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002765 spin_lock_irq(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002766 if (adapter->open_device_map & PORT_MASK)
2767 schedule_chk_task(adapter);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002768 spin_unlock_irq(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002769}
2770
Steve Wisee998f242010-01-27 17:03:34 +00002771static void db_full_task(struct work_struct *work)
2772{
2773 struct adapter *adapter = container_of(work, struct adapter,
2774 db_full_task);
2775
2776 cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_FULL, 0);
2777}
2778
2779static void db_empty_task(struct work_struct *work)
2780{
2781 struct adapter *adapter = container_of(work, struct adapter,
2782 db_empty_task);
2783
2784 cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_EMPTY, 0);
2785}
2786
2787static void db_drop_task(struct work_struct *work)
2788{
2789 struct adapter *adapter = container_of(work, struct adapter,
2790 db_drop_task);
2791 unsigned long delay = 1000;
2792 unsigned short r;
2793
2794 cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_DROP, 0);
2795
2796 /*
2797 * Sleep a while before ringing the driver qset dbs.
2798 * The delay is between 1000-2023 usecs.
2799 */
2800 get_random_bytes(&r, 2);
2801 delay += r & 1023;
2802 set_current_state(TASK_UNINTERRUPTIBLE);
2803 schedule_timeout(usecs_to_jiffies(delay));
2804 ring_dbs(adapter);
2805}
2806
Divy Le Ray4d22de32007-01-18 22:04:14 -05002807/*
2808 * Processes external (PHY) interrupts in process context.
2809 */
2810static void ext_intr_task(struct work_struct *work)
2811{
2812 struct adapter *adapter = container_of(work, struct adapter,
2813 ext_intr_handler_task);
Divy Le Raybf792092009-03-12 21:14:19 +00002814 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002815
Divy Le Raybf792092009-03-12 21:14:19 +00002816 /* Disable link fault interrupts */
2817 for_each_port(adapter, i) {
2818 struct net_device *dev = adapter->port[i];
2819 struct port_info *p = netdev_priv(dev);
2820
2821 t3_xgm_intr_disable(adapter, i);
2822 t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
2823 }
2824
2825 /* Re-enable link fault interrupts */
Divy Le Ray4d22de32007-01-18 22:04:14 -05002826 t3_phy_intr_handler(adapter);
2827
Divy Le Raybf792092009-03-12 21:14:19 +00002828 for_each_port(adapter, i)
2829 t3_xgm_intr_enable(adapter, i);
2830
Divy Le Ray4d22de32007-01-18 22:04:14 -05002831 /* Now reenable external interrupts */
2832 spin_lock_irq(&adapter->work_lock);
2833 if (adapter->slow_intr_mask) {
2834 adapter->slow_intr_mask |= F_T3DBG;
2835 t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG);
2836 t3_write_reg(adapter, A_PL_INT_ENABLE0,
2837 adapter->slow_intr_mask);
2838 }
2839 spin_unlock_irq(&adapter->work_lock);
2840}
2841
2842/*
2843 * Interrupt-context handler for external (PHY) interrupts.
2844 */
2845void t3_os_ext_intr_handler(struct adapter *adapter)
2846{
2847 /*
2848 * Schedule a task to handle external interrupts as they may be slow
2849 * and we use a mutex to protect MDIO registers. We disable PHY
2850 * interrupts in the meantime and let the task reenable them when
2851 * it's done.
2852 */
2853 spin_lock(&adapter->work_lock);
2854 if (adapter->slow_intr_mask) {
2855 adapter->slow_intr_mask &= ~F_T3DBG;
2856 t3_write_reg(adapter, A_PL_INT_ENABLE0,
2857 adapter->slow_intr_mask);
2858 queue_work(cxgb3_wq, &adapter->ext_intr_handler_task);
2859 }
2860 spin_unlock(&adapter->work_lock);
2861}
2862
Divy Le Raybf792092009-03-12 21:14:19 +00002863void t3_os_link_fault_handler(struct adapter *adapter, int port_id)
2864{
2865 struct net_device *netdev = adapter->port[port_id];
2866 struct port_info *pi = netdev_priv(netdev);
2867
2868 spin_lock(&adapter->work_lock);
2869 pi->link_fault = 1;
Divy Le Raybf792092009-03-12 21:14:19 +00002870 spin_unlock(&adapter->work_lock);
2871}
2872
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002873static int t3_adapter_error(struct adapter *adapter, int reset)
2874{
2875 int i, ret = 0;
2876
Divy Le Raycb0bc202009-01-26 22:21:59 -08002877 if (is_offload(adapter) &&
2878 test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
Steve Wisefa0d4c12009-09-05 20:22:38 -07002879 cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_DOWN, 0);
Divy Le Raycb0bc202009-01-26 22:21:59 -08002880 offload_close(&adapter->tdev);
2881 }
2882
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002883 /* Stop all ports */
2884 for_each_port(adapter, i) {
2885 struct net_device *netdev = adapter->port[i];
2886
2887 if (netif_running(netdev))
2888 cxgb_close(netdev);
2889 }
2890
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002891 /* Stop SGE timers */
2892 t3_stop_sge_timers(adapter);
2893
2894 adapter->flags &= ~FULL_INIT_DONE;
2895
2896 if (reset)
2897 ret = t3_reset_adapter(adapter);
2898
2899 pci_disable_device(adapter->pdev);
2900
2901 return ret;
2902}
2903
2904static int t3_reenable_adapter(struct adapter *adapter)
2905{
2906 if (pci_enable_device(adapter->pdev)) {
2907 dev_err(&adapter->pdev->dev,
2908 "Cannot re-enable PCI device after reset.\n");
2909 goto err;
2910 }
2911 pci_set_master(adapter->pdev);
2912 pci_restore_state(adapter->pdev);
Breno Leitaoccdddf52009-12-10 09:03:37 +00002913 pci_save_state(adapter->pdev);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002914
2915 /* Free sge resources */
2916 t3_free_sge_resources(adapter);
2917
2918 if (t3_replay_prep_adapter(adapter))
2919 goto err;
2920
2921 return 0;
2922err:
2923 return -1;
2924}
2925
2926static void t3_resume_ports(struct adapter *adapter)
2927{
2928 int i;
2929
2930 /* Restart the ports */
2931 for_each_port(adapter, i) {
2932 struct net_device *netdev = adapter->port[i];
2933
2934 if (netif_running(netdev)) {
2935 if (cxgb_open(netdev)) {
2936 dev_err(&adapter->pdev->dev,
2937 "can't bring device back up"
2938 " after reset\n");
2939 continue;
2940 }
2941 }
2942 }
Divy Le Raycb0bc202009-01-26 22:21:59 -08002943
2944 if (is_offload(adapter) && !ofld_disable)
Steve Wisefa0d4c12009-09-05 20:22:38 -07002945 cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_UP, 0);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002946}
2947
2948/*
2949 * processes a fatal error.
2950 * Bring the ports down, reset the chip, bring the ports back up.
2951 */
2952static void fatal_error_task(struct work_struct *work)
2953{
2954 struct adapter *adapter = container_of(work, struct adapter,
2955 fatal_error_handler_task);
2956 int err = 0;
2957
2958 rtnl_lock();
2959 err = t3_adapter_error(adapter, 1);
2960 if (!err)
2961 err = t3_reenable_adapter(adapter);
2962 if (!err)
2963 t3_resume_ports(adapter);
2964
2965 CH_ALERT(adapter, "adapter reset %s\n", err ? "failed" : "succeeded");
2966 rtnl_unlock();
2967}
2968
Divy Le Ray4d22de32007-01-18 22:04:14 -05002969void t3_fatal_err(struct adapter *adapter)
2970{
2971 unsigned int fw_status[4];
2972
2973 if (adapter->flags & FULL_INIT_DONE) {
2974 t3_sge_stop(adapter);
Divy Le Rayc64c2ea2007-08-21 20:49:31 -07002975 t3_write_reg(adapter, A_XGM_TX_CTRL, 0);
2976 t3_write_reg(adapter, A_XGM_RX_CTRL, 0);
2977 t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0);
2978 t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002979
2980 spin_lock(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002981 t3_intr_disable(adapter);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002982 queue_work(cxgb3_wq, &adapter->fatal_error_handler_task);
2983 spin_unlock(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002984 }
2985 CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
2986 if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
2987 CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
2988 fw_status[0], fw_status[1],
2989 fw_status[2], fw_status[3]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002990}
2991
Divy Le Ray91a6b502007-11-16 11:21:55 -08002992/**
2993 * t3_io_error_detected - called when PCI error is detected
2994 * @pdev: Pointer to PCI device
2995 * @state: The current pci connection state
2996 *
2997 * This function is called after a PCI bus error affecting
2998 * this device has been detected.
2999 */
3000static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
3001 pci_channel_state_t state)
3002{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08003003 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07003004 int ret;
Divy Le Ray91a6b502007-11-16 11:21:55 -08003005
Divy Le Raye8d19372009-04-17 12:21:27 +00003006 if (state == pci_channel_io_perm_failure)
3007 return PCI_ERS_RESULT_DISCONNECT;
3008
Divy Le Ray20d3fc12008-10-08 17:36:03 -07003009 ret = t3_adapter_error(adapter, 0);
Divy Le Ray91a6b502007-11-16 11:21:55 -08003010
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07003011 /* Request a slot reset. */
Divy Le Ray91a6b502007-11-16 11:21:55 -08003012 return PCI_ERS_RESULT_NEED_RESET;
3013}
3014
3015/**
3016 * t3_io_slot_reset - called after the pci bus has been reset.
3017 * @pdev: Pointer to PCI device
3018 *
3019 * Restart the card from scratch, as if from a cold-boot.
3020 */
3021static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev)
3022{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08003023 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray91a6b502007-11-16 11:21:55 -08003024
Divy Le Ray20d3fc12008-10-08 17:36:03 -07003025 if (!t3_reenable_adapter(adapter))
3026 return PCI_ERS_RESULT_RECOVERED;
Divy Le Ray91a6b502007-11-16 11:21:55 -08003027
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07003028 return PCI_ERS_RESULT_DISCONNECT;
Divy Le Ray91a6b502007-11-16 11:21:55 -08003029}
3030
3031/**
3032 * t3_io_resume - called when traffic can start flowing again.
3033 * @pdev: Pointer to PCI device
3034 *
3035 * This callback is called when the error recovery driver tells us that
3036 * its OK to resume normal operation.
3037 */
3038static void t3_io_resume(struct pci_dev *pdev)
3039{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08003040 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray91a6b502007-11-16 11:21:55 -08003041
Divy Le Ray68f40c12009-03-26 16:39:19 +00003042 CH_ALERT(adapter, "adapter recovering, PEX ERR 0x%x\n",
3043 t3_read_reg(adapter, A_PCIE_PEX_ERR));
3044
Divy Le Ray20d3fc12008-10-08 17:36:03 -07003045 t3_resume_ports(adapter);
Divy Le Ray91a6b502007-11-16 11:21:55 -08003046}
3047
3048static struct pci_error_handlers t3_err_handler = {
3049 .error_detected = t3_io_error_detected,
3050 .slot_reset = t3_io_slot_reset,
3051 .resume = t3_io_resume,
3052};
3053
Divy Le Ray8c263762008-10-08 17:37:33 -07003054/*
3055 * Set the number of qsets based on the number of CPUs and the number of ports,
3056 * not to exceed the number of available qsets, assuming there are enough qsets
3057 * per port in HW.
3058 */
3059static void set_nqsets(struct adapter *adap)
3060{
3061 int i, j = 0;
3062 int num_cpus = num_online_cpus();
3063 int hwports = adap->params.nports;
Divy Le Ray5cda9362009-01-18 21:29:40 -08003064 int nqsets = adap->msix_nvectors - 1;
Divy Le Ray8c263762008-10-08 17:37:33 -07003065
Divy Le Rayf9ee3882008-11-09 00:55:33 -08003066 if (adap->params.rev > 0 && adap->flags & USING_MSIX) {
Divy Le Ray8c263762008-10-08 17:37:33 -07003067 if (hwports == 2 &&
3068 (hwports * nqsets > SGE_QSETS ||
3069 num_cpus >= nqsets / hwports))
3070 nqsets /= hwports;
3071 if (nqsets > num_cpus)
3072 nqsets = num_cpus;
3073 if (nqsets < 1 || hwports == 4)
3074 nqsets = 1;
3075 } else
3076 nqsets = 1;
3077
3078 for_each_port(adap, i) {
3079 struct port_info *pi = adap2pinfo(adap, i);
3080
3081 pi->first_qset = j;
3082 pi->nqsets = nqsets;
3083 j = pi->first_qset + nqsets;
3084
3085 dev_info(&adap->pdev->dev,
3086 "Port %d using %d queue sets.\n", i, nqsets);
3087 }
3088}
3089
Divy Le Ray4d22de32007-01-18 22:04:14 -05003090static int __devinit cxgb_enable_msix(struct adapter *adap)
3091{
3092 struct msix_entry entries[SGE_QSETS + 1];
Divy Le Ray5cda9362009-01-18 21:29:40 -08003093 int vectors;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003094 int i, err;
3095
Divy Le Ray5cda9362009-01-18 21:29:40 -08003096 vectors = ARRAY_SIZE(entries);
3097 for (i = 0; i < vectors; ++i)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003098 entries[i].entry = i;
3099
Divy Le Ray5cda9362009-01-18 21:29:40 -08003100 while ((err = pci_enable_msix(adap->pdev, entries, vectors)) > 0)
3101 vectors = err;
3102
Divy Le Ray2c2f4092009-04-17 12:21:22 +00003103 if (err < 0)
3104 pci_disable_msix(adap->pdev);
3105
3106 if (!err && vectors < (adap->params.nports + 1)) {
3107 pci_disable_msix(adap->pdev);
Divy Le Ray5cda9362009-01-18 21:29:40 -08003108 err = -1;
Divy Le Ray2c2f4092009-04-17 12:21:22 +00003109 }
Divy Le Ray5cda9362009-01-18 21:29:40 -08003110
Divy Le Ray4d22de32007-01-18 22:04:14 -05003111 if (!err) {
Divy Le Ray5cda9362009-01-18 21:29:40 -08003112 for (i = 0; i < vectors; ++i)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003113 adap->msix_info[i].vec = entries[i].vector;
Divy Le Ray5cda9362009-01-18 21:29:40 -08003114 adap->msix_nvectors = vectors;
3115 }
3116
Divy Le Ray4d22de32007-01-18 22:04:14 -05003117 return err;
3118}
3119
3120static void __devinit print_port_info(struct adapter *adap,
3121 const struct adapter_info *ai)
3122{
3123 static const char *pci_variant[] = {
3124 "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express"
3125 };
3126
3127 int i;
3128 char buf[80];
3129
3130 if (is_pcie(adap))
3131 snprintf(buf, sizeof(buf), "%s x%d",
3132 pci_variant[adap->params.pci.variant],
3133 adap->params.pci.width);
3134 else
3135 snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit",
3136 pci_variant[adap->params.pci.variant],
3137 adap->params.pci.speed, adap->params.pci.width);
3138
3139 for_each_port(adap, i) {
3140 struct net_device *dev = adap->port[i];
3141 const struct port_info *pi = netdev_priv(dev);
3142
3143 if (!test_bit(i, &adap->registered_device_map))
3144 continue;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07003145 printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n",
Divy Le Ray04497982008-10-08 17:38:29 -07003146 dev->name, ai->desc, pi->phy.desc,
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07003147 is_offload(adap) ? "R" : "", adap->params.rev, buf,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003148 (adap->flags & USING_MSIX) ? " MSI-X" :
3149 (adap->flags & USING_MSI) ? " MSI" : "");
3150 if (adap->name == dev->name && adap->params.vpd.mclk)
Divy Le Ray167cdf52007-08-21 20:49:36 -07003151 printk(KERN_INFO
3152 "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
Divy Le Ray4d22de32007-01-18 22:04:14 -05003153 adap->name, t3_mc7_size(&adap->cm) >> 20,
3154 t3_mc7_size(&adap->pmtx) >> 20,
Divy Le Ray167cdf52007-08-21 20:49:36 -07003155 t3_mc7_size(&adap->pmrx) >> 20,
3156 adap->params.vpd.sn);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003157 }
3158}
3159
Stephen Hemmingerdd752692008-11-19 22:15:39 -08003160static const struct net_device_ops cxgb_netdev_ops = {
3161 .ndo_open = cxgb_open,
3162 .ndo_stop = cxgb_close,
Divy Le Ray43a944f2008-11-26 15:35:26 -08003163 .ndo_start_xmit = t3_eth_xmit,
Stephen Hemmingerdd752692008-11-19 22:15:39 -08003164 .ndo_get_stats = cxgb_get_stats,
3165 .ndo_validate_addr = eth_validate_addr,
3166 .ndo_set_multicast_list = cxgb_set_rxmode,
3167 .ndo_do_ioctl = cxgb_ioctl,
3168 .ndo_change_mtu = cxgb_change_mtu,
3169 .ndo_set_mac_address = cxgb_set_mac_addr,
3170 .ndo_vlan_rx_register = vlan_rx_register,
3171#ifdef CONFIG_NET_POLL_CONTROLLER
3172 .ndo_poll_controller = cxgb_netpoll,
3173#endif
3174};
3175
Karen Xief14d42f2009-10-08 09:11:05 +00003176static void __devinit cxgb3_init_iscsi_mac(struct net_device *dev)
3177{
3178 struct port_info *pi = netdev_priv(dev);
3179
3180 memcpy(pi->iscsic.mac_addr, dev->dev_addr, ETH_ALEN);
3181 pi->iscsic.mac_addr[3] |= 0x80;
3182}
3183
Divy Le Ray4d22de32007-01-18 22:04:14 -05003184static int __devinit init_one(struct pci_dev *pdev,
3185 const struct pci_device_id *ent)
3186{
3187 static int version_printed;
3188
3189 int i, err, pci_using_dac = 0;
Divy Le Ray68f40c12009-03-26 16:39:19 +00003190 resource_size_t mmio_start, mmio_len;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003191 const struct adapter_info *ai;
3192 struct adapter *adapter = NULL;
3193 struct port_info *pi;
3194
3195 if (!version_printed) {
3196 printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
3197 ++version_printed;
3198 }
3199
3200 if (!cxgb3_wq) {
3201 cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
3202 if (!cxgb3_wq) {
3203 printk(KERN_ERR DRV_NAME
3204 ": cannot initialize work queue\n");
3205 return -ENOMEM;
3206 }
3207 }
3208
3209 err = pci_request_regions(pdev, DRV_NAME);
3210 if (err) {
3211 /* Just info, some other driver may have claimed the device. */
3212 dev_info(&pdev->dev, "cannot obtain PCI resources\n");
3213 return err;
3214 }
3215
3216 err = pci_enable_device(pdev);
3217 if (err) {
3218 dev_err(&pdev->dev, "cannot enable PCI device\n");
3219 goto out_release_regions;
3220 }
3221
Yang Hongyang6a355282009-04-06 19:01:13 -07003222 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003223 pci_using_dac = 1;
Yang Hongyang6a355282009-04-06 19:01:13 -07003224 err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
Divy Le Ray4d22de32007-01-18 22:04:14 -05003225 if (err) {
3226 dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
3227 "coherent allocations\n");
3228 goto out_disable_device;
3229 }
Yang Hongyang284901a2009-04-06 19:01:15 -07003230 } else if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003231 dev_err(&pdev->dev, "no usable DMA configuration\n");
3232 goto out_disable_device;
3233 }
3234
3235 pci_set_master(pdev);
Divy Le Ray204e2f92008-05-06 19:26:01 -07003236 pci_save_state(pdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003237
3238 mmio_start = pci_resource_start(pdev, 0);
3239 mmio_len = pci_resource_len(pdev, 0);
3240 ai = t3_get_adapter_info(ent->driver_data);
3241
3242 adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
3243 if (!adapter) {
3244 err = -ENOMEM;
3245 goto out_disable_device;
3246 }
3247
Divy Le Ray74b793e2009-06-09 23:25:21 +00003248 adapter->nofail_skb =
3249 alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_KERNEL);
3250 if (!adapter->nofail_skb) {
3251 dev_err(&pdev->dev, "cannot allocate nofail buffer\n");
3252 err = -ENOMEM;
3253 goto out_free_adapter;
3254 }
3255
Divy Le Ray4d22de32007-01-18 22:04:14 -05003256 adapter->regs = ioremap_nocache(mmio_start, mmio_len);
3257 if (!adapter->regs) {
3258 dev_err(&pdev->dev, "cannot map device registers\n");
3259 err = -ENOMEM;
3260 goto out_free_adapter;
3261 }
3262
3263 adapter->pdev = pdev;
3264 adapter->name = pci_name(pdev);
3265 adapter->msg_enable = dflt_msg_enable;
3266 adapter->mmio_len = mmio_len;
3267
3268 mutex_init(&adapter->mdio_lock);
3269 spin_lock_init(&adapter->work_lock);
3270 spin_lock_init(&adapter->stats_lock);
3271
3272 INIT_LIST_HEAD(&adapter->adapter_list);
3273 INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07003274 INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task);
Steve Wisee998f242010-01-27 17:03:34 +00003275
3276 INIT_WORK(&adapter->db_full_task, db_full_task);
3277 INIT_WORK(&adapter->db_empty_task, db_empty_task);
3278 INIT_WORK(&adapter->db_drop_task, db_drop_task);
3279
Divy Le Ray4d22de32007-01-18 22:04:14 -05003280 INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
3281
Divy Le Ray952cdf32009-03-26 16:39:24 +00003282 for (i = 0; i < ai->nports0 + ai->nports1; ++i) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003283 struct net_device *netdev;
3284
Divy Le Ray82ad3322008-12-16 01:09:39 -08003285 netdev = alloc_etherdev_mq(sizeof(struct port_info), SGE_QSETS);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003286 if (!netdev) {
3287 err = -ENOMEM;
3288 goto out_free_dev;
3289 }
3290
Divy Le Ray4d22de32007-01-18 22:04:14 -05003291 SET_NETDEV_DEV(netdev, &pdev->dev);
3292
3293 adapter->port[i] = netdev;
3294 pi = netdev_priv(netdev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003295 pi->adapter = adapter;
Roland Dreier47fd23f2009-01-11 00:19:36 -08003296 pi->rx_offload = T3_RX_CSUM | T3_LRO;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003297 pi->port_id = i;
3298 netif_carrier_off(netdev);
Divy Le Ray82ad3322008-12-16 01:09:39 -08003299 netif_tx_stop_all_queues(netdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003300 netdev->irq = pdev->irq;
3301 netdev->mem_start = mmio_start;
3302 netdev->mem_end = mmio_start + mmio_len - 1;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003303 netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
Herbert Xu7be2df42009-01-21 14:39:13 -08003304 netdev->features |= NETIF_F_GRO;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003305 if (pci_using_dac)
3306 netdev->features |= NETIF_F_HIGHDMA;
3307
3308 netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
Stephen Hemmingerdd752692008-11-19 22:15:39 -08003309 netdev->netdev_ops = &cxgb_netdev_ops;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003310 SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
3311 }
3312
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003313 pci_set_drvdata(pdev, adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003314 if (t3_prep_adapter(adapter, ai, 1) < 0) {
3315 err = -ENODEV;
3316 goto out_free_dev;
3317 }
Jeff Garzik2eab17a2007-11-23 21:59:45 -05003318
Divy Le Ray4d22de32007-01-18 22:04:14 -05003319 /*
3320 * The card is now ready to go. If any errors occur during device
3321 * registration we do not fail the whole card but rather proceed only
3322 * with the ports we manage to register successfully. However we must
3323 * register at least one net device.
3324 */
3325 for_each_port(adapter, i) {
3326 err = register_netdev(adapter->port[i]);
3327 if (err)
3328 dev_warn(&pdev->dev,
3329 "cannot register net device %s, skipping\n",
3330 adapter->port[i]->name);
3331 else {
3332 /*
3333 * Change the name we use for messages to the name of
3334 * the first successfully registered interface.
3335 */
3336 if (!adapter->registered_device_map)
3337 adapter->name = adapter->port[i]->name;
3338
3339 __set_bit(i, &adapter->registered_device_map);
3340 }
3341 }
3342 if (!adapter->registered_device_map) {
3343 dev_err(&pdev->dev, "could not register any net devices\n");
3344 goto out_free_dev;
3345 }
3346
Karen Xief14d42f2009-10-08 09:11:05 +00003347 for_each_port(adapter, i)
3348 cxgb3_init_iscsi_mac(adapter->port[i]);
3349
Divy Le Ray4d22de32007-01-18 22:04:14 -05003350 /* Driver's ready. Reflect it on LEDs */
3351 t3_led_ready(adapter);
3352
3353 if (is_offload(adapter)) {
3354 __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
3355 cxgb3_adapter_ofld(adapter);
3356 }
3357
3358 /* See what interrupts we'll be using */
3359 if (msi > 1 && cxgb_enable_msix(adapter) == 0)
3360 adapter->flags |= USING_MSIX;
3361 else if (msi > 0 && pci_enable_msi(pdev) == 0)
3362 adapter->flags |= USING_MSI;
3363
Divy Le Ray8c263762008-10-08 17:37:33 -07003364 set_nqsets(adapter);
3365
Divy Le Ray0ee8d332007-02-08 16:55:59 -08003366 err = sysfs_create_group(&adapter->port[0]->dev.kobj,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003367 &cxgb3_attr_group);
3368
3369 print_port_info(adapter, ai);
3370 return 0;
3371
3372out_free_dev:
3373 iounmap(adapter->regs);
Divy Le Ray952cdf32009-03-26 16:39:24 +00003374 for (i = ai->nports0 + ai->nports1 - 1; i >= 0; --i)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003375 if (adapter->port[i])
3376 free_netdev(adapter->port[i]);
3377
3378out_free_adapter:
3379 kfree(adapter);
3380
3381out_disable_device:
3382 pci_disable_device(pdev);
3383out_release_regions:
3384 pci_release_regions(pdev);
3385 pci_set_drvdata(pdev, NULL);
3386 return err;
3387}
3388
3389static void __devexit remove_one(struct pci_dev *pdev)
3390{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003391 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003392
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003393 if (adapter) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003394 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003395
3396 t3_sge_stop(adapter);
Divy Le Ray0ee8d332007-02-08 16:55:59 -08003397 sysfs_remove_group(&adapter->port[0]->dev.kobj,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003398 &cxgb3_attr_group);
3399
Divy Le Ray4d22de32007-01-18 22:04:14 -05003400 if (is_offload(adapter)) {
3401 cxgb3_adapter_unofld(adapter);
3402 if (test_bit(OFFLOAD_DEVMAP_BIT,
3403 &adapter->open_device_map))
3404 offload_close(&adapter->tdev);
3405 }
3406
Divy Le Ray67d92ab2007-11-16 11:21:50 -08003407 for_each_port(adapter, i)
3408 if (test_bit(i, &adapter->registered_device_map))
3409 unregister_netdev(adapter->port[i]);
3410
Divy Le Ray0ca41c02008-09-25 14:05:28 +00003411 t3_stop_sge_timers(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003412 t3_free_sge_resources(adapter);
3413 cxgb_disable_msi(adapter);
3414
Divy Le Ray4d22de32007-01-18 22:04:14 -05003415 for_each_port(adapter, i)
3416 if (adapter->port[i])
3417 free_netdev(adapter->port[i]);
3418
3419 iounmap(adapter->regs);
Divy Le Ray74b793e2009-06-09 23:25:21 +00003420 if (adapter->nofail_skb)
3421 kfree_skb(adapter->nofail_skb);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003422 kfree(adapter);
3423 pci_release_regions(pdev);
3424 pci_disable_device(pdev);
3425 pci_set_drvdata(pdev, NULL);
3426 }
3427}
3428
3429static struct pci_driver driver = {
3430 .name = DRV_NAME,
3431 .id_table = cxgb3_pci_tbl,
3432 .probe = init_one,
3433 .remove = __devexit_p(remove_one),
Divy Le Ray91a6b502007-11-16 11:21:55 -08003434 .err_handler = &t3_err_handler,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003435};
3436
3437static int __init cxgb3_init_module(void)
3438{
3439 int ret;
3440
3441 cxgb3_offload_init();
3442
3443 ret = pci_register_driver(&driver);
3444 return ret;
3445}
3446
3447static void __exit cxgb3_cleanup_module(void)
3448{
3449 pci_unregister_driver(&driver);
3450 if (cxgb3_wq)
3451 destroy_workqueue(cxgb3_wq);
3452}
3453
3454module_init(cxgb3_init_module);
3455module_exit(cxgb3_cleanup_module);