blob: cecdec1551db6eb485da32c39b87add1390c63f7 [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>
Divy Le Ray4d22de32007-01-18 22:04:14 -050048#include <asm/uaccess.h>
49
50#include "common.h"
51#include "cxgb3_ioctl.h"
52#include "regs.h"
53#include "cxgb3_offload.h"
54#include "version.h"
55
56#include "cxgb3_ctl_defs.h"
57#include "t3_cpl.h"
58#include "firmware_exports.h"
59
60enum {
61 MAX_TXQ_ENTRIES = 16384,
62 MAX_CTRL_TXQ_ENTRIES = 1024,
63 MAX_RSPQ_ENTRIES = 16384,
64 MAX_RX_BUFFERS = 16384,
65 MAX_RX_JUMBO_BUFFERS = 16384,
66 MIN_TXQ_ENTRIES = 4,
67 MIN_CTRL_TXQ_ENTRIES = 4,
68 MIN_RSPQ_ENTRIES = 32,
69 MIN_FL_ENTRIES = 32
70};
71
72#define PORT_MASK ((1 << MAX_NPORTS) - 1)
73
74#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
75 NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
76 NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
77
78#define EEPROM_MAGIC 0x38E2F10C
79
Divy Le Ray678771d2007-11-16 14:26:44 -080080#define CH_DEVICE(devid, idx) \
81 { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx }
Divy Le Ray4d22de32007-01-18 22:04:14 -050082
Alexey Dobriyana3aa1882010-01-07 11:58:11 +000083static DEFINE_PCI_DEVICE_TABLE(cxgb3_pci_tbl) = {
Divy Le Ray678771d2007-11-16 14:26:44 -080084 CH_DEVICE(0x20, 0), /* PE9000 */
85 CH_DEVICE(0x21, 1), /* T302E */
86 CH_DEVICE(0x22, 2), /* T310E */
87 CH_DEVICE(0x23, 3), /* T320X */
88 CH_DEVICE(0x24, 1), /* T302X */
89 CH_DEVICE(0x25, 3), /* T320E */
90 CH_DEVICE(0x26, 2), /* T310X */
91 CH_DEVICE(0x30, 2), /* T3B10 */
92 CH_DEVICE(0x31, 3), /* T3B20 */
93 CH_DEVICE(0x32, 1), /* T3B02 */
Divy Le Rayce03aad2009-02-18 17:47:57 -080094 CH_DEVICE(0x35, 6), /* T3C20-derived T3C10 */
Divy Le Ray74451422009-05-29 12:52:44 +000095 CH_DEVICE(0x36, 3), /* S320E-CR */
96 CH_DEVICE(0x37, 7), /* N320E-G2 */
Divy Le Ray4d22de32007-01-18 22:04:14 -050097 {0,}
98};
99
100MODULE_DESCRIPTION(DRV_DESC);
101MODULE_AUTHOR("Chelsio Communications");
Divy Le Ray1d68e932007-01-30 19:44:35 -0800102MODULE_LICENSE("Dual BSD/GPL");
Divy Le Ray4d22de32007-01-18 22:04:14 -0500103MODULE_VERSION(DRV_VERSION);
104MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl);
105
106static int dflt_msg_enable = DFLT_MSG_ENABLE;
107
108module_param(dflt_msg_enable, int, 0644);
109MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap");
110
111/*
112 * The driver uses the best interrupt scheme available on a platform in the
113 * order MSI-X, MSI, legacy pin interrupts. This parameter determines which
114 * of these schemes the driver may consider as follows:
115 *
116 * msi = 2: choose from among all three options
117 * msi = 1: only consider MSI and pin interrupts
118 * msi = 0: force pin interrupts
119 */
120static int msi = 2;
121
122module_param(msi, int, 0644);
123MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X");
124
125/*
126 * The driver enables offload as a default.
127 * To disable it, use ofld_disable = 1.
128 */
129
130static int ofld_disable = 0;
131
132module_param(ofld_disable, int, 0644);
133MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not");
134
135/*
136 * We have work elements that we need to cancel when an interface is taken
137 * down. Normally the work elements would be executed by keventd but that
138 * can deadlock because of linkwatch. If our close method takes the rtnl
139 * lock and linkwatch is ahead of our work elements in keventd, linkwatch
140 * will block keventd as it needs the rtnl lock, and we'll deadlock waiting
141 * for our work to complete. Get our own work queue to solve this.
142 */
143static struct workqueue_struct *cxgb3_wq;
144
145/**
146 * link_report - show link status and link speed/duplex
147 * @p: the port whose settings are to be reported
148 *
149 * Shows the link status, speed, and duplex of a port.
150 */
151static void link_report(struct net_device *dev)
152{
153 if (!netif_carrier_ok(dev))
154 printk(KERN_INFO "%s: link down\n", dev->name);
155 else {
156 const char *s = "10Mbps";
157 const struct port_info *p = netdev_priv(dev);
158
159 switch (p->link_config.speed) {
160 case SPEED_10000:
161 s = "10Gbps";
162 break;
163 case SPEED_1000:
164 s = "1000Mbps";
165 break;
166 case SPEED_100:
167 s = "100Mbps";
168 break;
169 }
170
171 printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s,
172 p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
173 }
174}
175
Divy Le Ray34701fd2009-07-07 19:48:32 +0000176static void enable_tx_fifo_drain(struct adapter *adapter,
177 struct port_info *pi)
178{
179 t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0,
180 F_ENDROPPKT);
181 t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0);
182 t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN);
183 t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN);
184}
185
186static void disable_tx_fifo_drain(struct adapter *adapter,
187 struct port_info *pi)
188{
189 t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
190 F_ENDROPPKT, 0);
191}
192
Divy Le Raybf792092009-03-12 21:14:19 +0000193void t3_os_link_fault(struct adapter *adap, int port_id, int state)
194{
195 struct net_device *dev = adap->port[port_id];
196 struct port_info *pi = netdev_priv(dev);
197
198 if (state == netif_carrier_ok(dev))
199 return;
200
201 if (state) {
202 struct cmac *mac = &pi->mac;
203
204 netif_carrier_on(dev);
205
Divy Le Ray34701fd2009-07-07 19:48:32 +0000206 disable_tx_fifo_drain(adap, pi);
207
Divy Le Raybf792092009-03-12 21:14:19 +0000208 /* Clear local faults */
209 t3_xgm_intr_disable(adap, pi->port_id);
210 t3_read_reg(adap, A_XGM_INT_STATUS +
211 pi->mac.offset);
212 t3_write_reg(adap,
213 A_XGM_INT_CAUSE + pi->mac.offset,
214 F_XGM_INT);
215
216 t3_set_reg_field(adap,
217 A_XGM_INT_ENABLE +
218 pi->mac.offset,
219 F_XGM_INT, F_XGM_INT);
220 t3_xgm_intr_enable(adap, pi->port_id);
221
222 t3_mac_enable(mac, MAC_DIRECTION_TX);
Divy Le Ray34701fd2009-07-07 19:48:32 +0000223 } else {
Divy Le Raybf792092009-03-12 21:14:19 +0000224 netif_carrier_off(dev);
225
Divy Le Ray34701fd2009-07-07 19:48:32 +0000226 /* Flush TX FIFO */
227 enable_tx_fifo_drain(adap, pi);
228 }
Divy Le Raybf792092009-03-12 21:14:19 +0000229 link_report(dev);
230}
231
Divy Le Ray4d22de32007-01-18 22:04:14 -0500232/**
233 * t3_os_link_changed - handle link status changes
234 * @adapter: the adapter associated with the link change
235 * @port_id: the port index whose limk status has changed
236 * @link_stat: the new status of the link
237 * @speed: the new speed setting
238 * @duplex: the new duplex setting
239 * @pause: the new flow-control setting
240 *
241 * This is the OS-dependent handler for link status changes. The OS
242 * neutral handler takes care of most of the processing for these events,
243 * then calls this handler for any OS-specific processing.
244 */
245void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
246 int speed, int duplex, int pause)
247{
248 struct net_device *dev = adapter->port[port_id];
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700249 struct port_info *pi = netdev_priv(dev);
250 struct cmac *mac = &pi->mac;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500251
252 /* Skip changes from disabled ports. */
253 if (!netif_running(dev))
254 return;
255
256 if (link_stat != netif_carrier_ok(dev)) {
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700257 if (link_stat) {
Divy Le Ray34701fd2009-07-07 19:48:32 +0000258 disable_tx_fifo_drain(adapter, pi);
259
Divy Le Ray59cf8102007-04-09 20:10:27 -0700260 t3_mac_enable(mac, MAC_DIRECTION_RX);
Divy Le Raybf792092009-03-12 21:14:19 +0000261
262 /* Clear local faults */
263 t3_xgm_intr_disable(adapter, pi->port_id);
264 t3_read_reg(adapter, A_XGM_INT_STATUS +
265 pi->mac.offset);
266 t3_write_reg(adapter,
267 A_XGM_INT_CAUSE + pi->mac.offset,
268 F_XGM_INT);
269
270 t3_set_reg_field(adapter,
271 A_XGM_INT_ENABLE + pi->mac.offset,
272 F_XGM_INT, F_XGM_INT);
273 t3_xgm_intr_enable(adapter, pi->port_id);
274
Divy Le Ray4d22de32007-01-18 22:04:14 -0500275 netif_carrier_on(dev);
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700276 } else {
Divy Le Ray4d22de32007-01-18 22:04:14 -0500277 netif_carrier_off(dev);
Divy Le Raybf792092009-03-12 21:14:19 +0000278
279 t3_xgm_intr_disable(adapter, pi->port_id);
280 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
281 t3_set_reg_field(adapter,
282 A_XGM_INT_ENABLE + pi->mac.offset,
283 F_XGM_INT, 0);
284
285 if (is_10G(adapter))
286 pi->phy.ops->power_down(&pi->phy, 1);
287
288 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
Divy Le Ray59cf8102007-04-09 20:10:27 -0700289 t3_mac_disable(mac, MAC_DIRECTION_RX);
290 t3_link_start(&pi->phy, mac, &pi->link_config);
Divy Le Ray34701fd2009-07-07 19:48:32 +0000291
292 /* Flush TX FIFO */
293 enable_tx_fifo_drain(adapter, pi);
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700294 }
295
Divy Le Ray4d22de32007-01-18 22:04:14 -0500296 link_report(dev);
297 }
298}
299
Divy Le Ray1e882022008-10-08 17:40:07 -0700300/**
301 * t3_os_phymod_changed - handle PHY module changes
302 * @phy: the PHY reporting the module change
303 * @mod_type: new module type
304 *
305 * This is the OS-dependent handler for PHY module changes. It is
306 * invoked when a PHY module is removed or inserted for any OS-specific
307 * processing.
308 */
309void t3_os_phymod_changed(struct adapter *adap, int port_id)
310{
311 static const char *mod_str[] = {
312 NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown"
313 };
314
315 const struct net_device *dev = adap->port[port_id];
316 const struct port_info *pi = netdev_priv(dev);
317
318 if (pi->phy.modtype == phy_modtype_none)
319 printk(KERN_INFO "%s: PHY module unplugged\n", dev->name);
320 else
321 printk(KERN_INFO "%s: %s PHY module inserted\n", dev->name,
322 mod_str[pi->phy.modtype]);
323}
324
Divy Le Ray4d22de32007-01-18 22:04:14 -0500325static void cxgb_set_rxmode(struct net_device *dev)
326{
Divy Le Ray4d22de32007-01-18 22:04:14 -0500327 struct port_info *pi = netdev_priv(dev);
328
Jiri Pirko0988d262010-02-17 12:27:14 +0000329 t3_mac_set_rx_mode(&pi->mac, dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500330}
331
332/**
333 * link_start - enable a port
334 * @dev: the device to enable
335 *
336 * Performs the MAC and PHY actions needed to enable a port.
337 */
338static void link_start(struct net_device *dev)
339{
Divy Le Ray4d22de32007-01-18 22:04:14 -0500340 struct port_info *pi = netdev_priv(dev);
341 struct cmac *mac = &pi->mac;
342
Divy Le Ray4d22de32007-01-18 22:04:14 -0500343 t3_mac_reset(mac);
Karen Xief14d42f2009-10-08 09:11:05 +0000344 t3_mac_set_num_ucast(mac, MAX_MAC_IDX);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500345 t3_mac_set_mtu(mac, dev->mtu);
Karen Xief14d42f2009-10-08 09:11:05 +0000346 t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr);
347 t3_mac_set_address(mac, SAN_MAC_IDX, pi->iscsic.mac_addr);
Jiri Pirko0988d262010-02-17 12:27:14 +0000348 t3_mac_set_rx_mode(mac, dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500349 t3_link_start(&pi->phy, mac, &pi->link_config);
350 t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
351}
352
353static inline void cxgb_disable_msi(struct adapter *adapter)
354{
355 if (adapter->flags & USING_MSIX) {
356 pci_disable_msix(adapter->pdev);
357 adapter->flags &= ~USING_MSIX;
358 } else if (adapter->flags & USING_MSI) {
359 pci_disable_msi(adapter->pdev);
360 adapter->flags &= ~USING_MSI;
361 }
362}
363
364/*
365 * Interrupt handler for asynchronous events used with MSI-X.
366 */
367static irqreturn_t t3_async_intr_handler(int irq, void *cookie)
368{
369 t3_slow_intr_handler(cookie);
370 return IRQ_HANDLED;
371}
372
373/*
374 * Name the MSI-X interrupts.
375 */
376static void name_msix_vecs(struct adapter *adap)
377{
378 int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1;
379
380 snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
381 adap->msix_info[0].desc[n] = 0;
382
383 for_each_port(adap, j) {
384 struct net_device *d = adap->port[j];
385 const struct port_info *pi = netdev_priv(d);
386
387 for (i = 0; i < pi->nqsets; i++, msi_idx++) {
388 snprintf(adap->msix_info[msi_idx].desc, n,
Divy Le Ray8c263762008-10-08 17:37:33 -0700389 "%s-%d", d->name, pi->first_qset + i);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500390 adap->msix_info[msi_idx].desc[n] = 0;
391 }
Divy Le Ray8c263762008-10-08 17:37:33 -0700392 }
Divy Le Ray4d22de32007-01-18 22:04:14 -0500393}
394
395static int request_msix_data_irqs(struct adapter *adap)
396{
397 int i, j, err, qidx = 0;
398
399 for_each_port(adap, i) {
400 int nqsets = adap2pinfo(adap, i)->nqsets;
401
402 for (j = 0; j < nqsets; ++j) {
403 err = request_irq(adap->msix_info[qidx + 1].vec,
404 t3_intr_handler(adap,
405 adap->sge.qs[qidx].
406 rspq.polling), 0,
407 adap->msix_info[qidx + 1].desc,
408 &adap->sge.qs[qidx]);
409 if (err) {
410 while (--qidx >= 0)
411 free_irq(adap->msix_info[qidx + 1].vec,
412 &adap->sge.qs[qidx]);
413 return err;
414 }
415 qidx++;
416 }
417 }
418 return 0;
419}
420
Divy Le Ray8c263762008-10-08 17:37:33 -0700421static void free_irq_resources(struct adapter *adapter)
422{
423 if (adapter->flags & USING_MSIX) {
424 int i, n = 0;
425
426 free_irq(adapter->msix_info[0].vec, adapter);
427 for_each_port(adapter, i)
Divy Le Ray5cda9362009-01-18 21:29:40 -0800428 n += adap2pinfo(adapter, i)->nqsets;
Divy Le Ray8c263762008-10-08 17:37:33 -0700429
430 for (i = 0; i < n; ++i)
431 free_irq(adapter->msix_info[i + 1].vec,
432 &adapter->sge.qs[i]);
433 } else
434 free_irq(adapter->pdev->irq, adapter);
435}
436
Divy Le Rayb8819552007-12-17 18:47:31 -0800437static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
438 unsigned long n)
439{
440 int attempts = 5;
441
442 while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
443 if (!--attempts)
444 return -ETIMEDOUT;
445 msleep(10);
446 }
447 return 0;
448}
449
450static int init_tp_parity(struct adapter *adap)
451{
452 int i;
453 struct sk_buff *skb;
454 struct cpl_set_tcb_field *greq;
455 unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
456
457 t3_tp_set_offload_mode(adap, 1);
458
459 for (i = 0; i < 16; i++) {
460 struct cpl_smt_write_req *req;
461
Divy Le Ray74b793e2009-06-09 23:25:21 +0000462 skb = alloc_skb(sizeof(*req), GFP_KERNEL);
463 if (!skb)
464 skb = adap->nofail_skb;
465 if (!skb)
466 goto alloc_skb_fail;
467
Divy Le Rayb8819552007-12-17 18:47:31 -0800468 req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
469 memset(req, 0, sizeof(*req));
470 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
471 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
Divy Le Raydce7d1d2009-07-07 19:48:59 +0000472 req->mtu_idx = NMTUS - 1;
Divy Le Rayb8819552007-12-17 18:47:31 -0800473 req->iff = i;
474 t3_mgmt_tx(adap, skb);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000475 if (skb == adap->nofail_skb) {
476 await_mgmt_replies(adap, cnt, i + 1);
477 adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
478 if (!adap->nofail_skb)
479 goto alloc_skb_fail;
480 }
Divy Le Rayb8819552007-12-17 18:47:31 -0800481 }
482
483 for (i = 0; i < 2048; i++) {
484 struct cpl_l2t_write_req *req;
485
Divy Le Ray74b793e2009-06-09 23:25:21 +0000486 skb = alloc_skb(sizeof(*req), GFP_KERNEL);
487 if (!skb)
488 skb = adap->nofail_skb;
489 if (!skb)
490 goto alloc_skb_fail;
491
Divy Le Rayb8819552007-12-17 18:47:31 -0800492 req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
493 memset(req, 0, sizeof(*req));
494 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
495 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
496 req->params = htonl(V_L2T_W_IDX(i));
497 t3_mgmt_tx(adap, skb);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000498 if (skb == adap->nofail_skb) {
499 await_mgmt_replies(adap, cnt, 16 + i + 1);
500 adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
501 if (!adap->nofail_skb)
502 goto alloc_skb_fail;
503 }
Divy Le Rayb8819552007-12-17 18:47:31 -0800504 }
505
506 for (i = 0; i < 2048; i++) {
507 struct cpl_rte_write_req *req;
508
Divy Le Ray74b793e2009-06-09 23:25:21 +0000509 skb = alloc_skb(sizeof(*req), GFP_KERNEL);
510 if (!skb)
511 skb = adap->nofail_skb;
512 if (!skb)
513 goto alloc_skb_fail;
514
Divy Le Rayb8819552007-12-17 18:47:31 -0800515 req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req));
516 memset(req, 0, sizeof(*req));
517 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
518 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
519 req->l2t_idx = htonl(V_L2T_W_IDX(i));
520 t3_mgmt_tx(adap, skb);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000521 if (skb == adap->nofail_skb) {
522 await_mgmt_replies(adap, cnt, 16 + 2048 + i + 1);
523 adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
524 if (!adap->nofail_skb)
525 goto alloc_skb_fail;
526 }
Divy Le Rayb8819552007-12-17 18:47:31 -0800527 }
528
Divy Le Ray74b793e2009-06-09 23:25:21 +0000529 skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
530 if (!skb)
531 skb = adap->nofail_skb;
532 if (!skb)
533 goto alloc_skb_fail;
534
Divy Le Rayb8819552007-12-17 18:47:31 -0800535 greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq));
536 memset(greq, 0, sizeof(*greq));
537 greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
538 OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
539 greq->mask = cpu_to_be64(1);
540 t3_mgmt_tx(adap, skb);
541
542 i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000543 if (skb == adap->nofail_skb) {
544 i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
545 adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
546 }
547
Divy Le Rayb8819552007-12-17 18:47:31 -0800548 t3_tp_set_offload_mode(adap, 0);
549 return i;
Divy Le Ray74b793e2009-06-09 23:25:21 +0000550
551alloc_skb_fail:
552 t3_tp_set_offload_mode(adap, 0);
553 return -ENOMEM;
Divy Le Rayb8819552007-12-17 18:47:31 -0800554}
555
Divy Le Ray4d22de32007-01-18 22:04:14 -0500556/**
557 * setup_rss - configure RSS
558 * @adap: the adapter
559 *
560 * Sets up RSS to distribute packets to multiple receive queues. We
561 * configure the RSS CPU lookup table to distribute to the number of HW
562 * receive queues, and the response queue lookup table to narrow that
563 * down to the response queues actually configured for each port.
564 * We always configure the RSS mapping for two ports since the mapping
565 * table has plenty of entries.
566 */
567static void setup_rss(struct adapter *adap)
568{
569 int i;
570 unsigned int nq0 = adap2pinfo(adap, 0)->nqsets;
571 unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1;
572 u8 cpus[SGE_QSETS + 1];
573 u16 rspq_map[RSS_TABLE_SIZE];
574
575 for (i = 0; i < SGE_QSETS; ++i)
576 cpus[i] = i;
577 cpus[SGE_QSETS] = 0xff; /* terminator */
578
579 for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
580 rspq_map[i] = i % nq0;
581 rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0;
582 }
583
584 t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
585 F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
Divy Le Raya2604be2007-11-16 11:22:16 -0800586 V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500587}
588
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700589static void init_napi(struct adapter *adap)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500590{
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700591 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500592
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700593 for (i = 0; i < SGE_QSETS; i++) {
594 struct sge_qset *qs = &adap->sge.qs[i];
Divy Le Ray4d22de32007-01-18 22:04:14 -0500595
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700596 if (qs->adap)
597 netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll,
598 64);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500599 }
Divy Le Ray48c4b6d2008-05-06 19:25:56 -0700600
601 /*
602 * netif_napi_add() can be called only once per napi_struct because it
603 * adds each new napi_struct to a list. Be careful not to call it a
604 * second time, e.g., during EEH recovery, by making a note of it.
605 */
606 adap->flags |= NAPI_INIT;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500607}
608
609/*
610 * Wait until all NAPI handlers are descheduled. This includes the handlers of
611 * both netdevices representing interfaces and the dummy ones for the extra
612 * queues.
613 */
614static void quiesce_rx(struct adapter *adap)
615{
616 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500617
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700618 for (i = 0; i < SGE_QSETS; i++)
619 if (adap->sge.qs[i].adap)
620 napi_disable(&adap->sge.qs[i].napi);
621}
Divy Le Ray4d22de32007-01-18 22:04:14 -0500622
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700623static void enable_all_napi(struct adapter *adap)
624{
625 int i;
626 for (i = 0; i < SGE_QSETS; i++)
627 if (adap->sge.qs[i].adap)
628 napi_enable(&adap->sge.qs[i].napi);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500629}
630
631/**
Divy Le Ray04ecb072008-10-28 22:40:32 -0700632 * set_qset_lro - Turn a queue set's LRO capability on and off
633 * @dev: the device the qset is attached to
634 * @qset_idx: the queue set index
635 * @val: the LRO switch
636 *
637 * Sets LRO on or off for a particular queue set.
638 * the device's features flag is updated to reflect the LRO
639 * capability when all queues belonging to the device are
640 * in the same state.
641 */
642static void set_qset_lro(struct net_device *dev, int qset_idx, int val)
643{
644 struct port_info *pi = netdev_priv(dev);
645 struct adapter *adapter = pi->adapter;
Divy Le Ray04ecb072008-10-28 22:40:32 -0700646
647 adapter->params.sge.qset[qset_idx].lro = !!val;
648 adapter->sge.qs[qset_idx].lro_enabled = !!val;
Divy Le Ray04ecb072008-10-28 22:40:32 -0700649}
650
651/**
Divy Le Ray4d22de32007-01-18 22:04:14 -0500652 * setup_sge_qsets - configure SGE Tx/Rx/response queues
653 * @adap: the adapter
654 *
655 * Determines how many sets of SGE queues to use and initializes them.
656 * We support multiple queue sets per port if we have MSI-X, otherwise
657 * just one queue set per port.
658 */
659static int setup_sge_qsets(struct adapter *adap)
660{
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700661 int i, j, err, irq_idx = 0, qset_idx = 0;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -0700662 unsigned int ntxq = SGE_TXQ_PER_SET;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500663
664 if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
665 irq_idx = -1;
666
667 for_each_port(adap, i) {
668 struct net_device *dev = adap->port[i];
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700669 struct port_info *pi = netdev_priv(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500670
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700671 pi->qs = &adap->sge.qs[pi->first_qset];
Roland Dreiere594e962009-07-09 09:30:25 +0000672 for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
Roland Dreier47fd23f2009-01-11 00:19:36 -0800673 set_qset_lro(dev, qset_idx, pi->rx_offload & T3_LRO);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500674 err = t3_sge_alloc_qset(adap, qset_idx, 1,
675 (adap->flags & USING_MSIX) ? qset_idx + 1 :
676 irq_idx,
Divy Le Ray82ad3322008-12-16 01:09:39 -0800677 &adap->params.sge.qset[qset_idx], ntxq, dev,
678 netdev_get_tx_queue(dev, j));
Divy Le Ray4d22de32007-01-18 22:04:14 -0500679 if (err) {
680 t3_free_sge_resources(adap);
681 return err;
682 }
683 }
684 }
685
686 return 0;
687}
688
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800689static ssize_t attr_show(struct device *d, char *buf,
Divy Le Ray896392e2007-02-24 16:43:50 -0800690 ssize_t(*format) (struct net_device *, char *))
Divy Le Ray4d22de32007-01-18 22:04:14 -0500691{
692 ssize_t len;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500693
694 /* Synchronize with ioctls that may shut down the device */
695 rtnl_lock();
Divy Le Ray896392e2007-02-24 16:43:50 -0800696 len = (*format) (to_net_dev(d), buf);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500697 rtnl_unlock();
698 return len;
699}
700
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800701static ssize_t attr_store(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800702 const char *buf, size_t len,
Divy Le Ray896392e2007-02-24 16:43:50 -0800703 ssize_t(*set) (struct net_device *, unsigned int),
Divy Le Ray4d22de32007-01-18 22:04:14 -0500704 unsigned int min_val, unsigned int max_val)
705{
706 char *endp;
707 ssize_t ret;
708 unsigned int val;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500709
710 if (!capable(CAP_NET_ADMIN))
711 return -EPERM;
712
713 val = simple_strtoul(buf, &endp, 0);
714 if (endp == buf || val < min_val || val > max_val)
715 return -EINVAL;
716
717 rtnl_lock();
Divy Le Ray896392e2007-02-24 16:43:50 -0800718 ret = (*set) (to_net_dev(d), val);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500719 if (!ret)
720 ret = len;
721 rtnl_unlock();
722 return ret;
723}
724
725#define CXGB3_SHOW(name, val_expr) \
Divy Le Ray896392e2007-02-24 16:43:50 -0800726static ssize_t format_##name(struct net_device *dev, char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500727{ \
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700728 struct port_info *pi = netdev_priv(dev); \
729 struct adapter *adap = pi->adapter; \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500730 return sprintf(buf, "%u\n", val_expr); \
731} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800732static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
733 char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500734{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800735 return attr_show(d, buf, format_##name); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500736}
737
Divy Le Ray896392e2007-02-24 16:43:50 -0800738static ssize_t set_nfilters(struct net_device *dev, unsigned int val)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500739{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700740 struct port_info *pi = netdev_priv(dev);
741 struct adapter *adap = pi->adapter;
Divy Le Ray9f238482007-03-31 00:23:13 -0700742 int min_tids = is_offload(adap) ? MC5_MIN_TIDS : 0;
Divy Le Ray896392e2007-02-24 16:43:50 -0800743
Divy Le Ray4d22de32007-01-18 22:04:14 -0500744 if (adap->flags & FULL_INIT_DONE)
745 return -EBUSY;
746 if (val && adap->params.rev == 0)
747 return -EINVAL;
Divy Le Ray9f238482007-03-31 00:23:13 -0700748 if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
749 min_tids)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500750 return -EINVAL;
751 adap->params.mc5.nfilters = val;
752 return 0;
753}
754
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800755static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
756 const char *buf, size_t len)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500757{
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800758 return attr_store(d, buf, len, set_nfilters, 0, ~0);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500759}
760
Divy Le Ray896392e2007-02-24 16:43:50 -0800761static ssize_t set_nservers(struct net_device *dev, unsigned int val)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500762{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700763 struct port_info *pi = netdev_priv(dev);
764 struct adapter *adap = pi->adapter;
Divy Le Ray896392e2007-02-24 16:43:50 -0800765
Divy Le Ray4d22de32007-01-18 22:04:14 -0500766 if (adap->flags & FULL_INIT_DONE)
767 return -EBUSY;
Divy Le Ray9f238482007-03-31 00:23:13 -0700768 if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters -
769 MC5_MIN_TIDS)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500770 return -EINVAL;
771 adap->params.mc5.nservers = val;
772 return 0;
773}
774
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800775static ssize_t store_nservers(struct device *d, struct device_attribute *attr,
776 const char *buf, size_t len)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500777{
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800778 return attr_store(d, buf, len, set_nservers, 0, ~0);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500779}
780
781#define CXGB3_ATTR_R(name, val_expr) \
782CXGB3_SHOW(name, val_expr) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800783static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500784
785#define CXGB3_ATTR_RW(name, val_expr, store_method) \
786CXGB3_SHOW(name, val_expr) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800787static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500788
789CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));
790CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);
791CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);
792
793static struct attribute *cxgb3_attrs[] = {
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800794 &dev_attr_cam_size.attr,
795 &dev_attr_nfilters.attr,
796 &dev_attr_nservers.attr,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500797 NULL
798};
799
800static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
801
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800802static ssize_t tm_attr_show(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800803 char *buf, int sched)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500804{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700805 struct port_info *pi = netdev_priv(to_net_dev(d));
806 struct adapter *adap = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500807 unsigned int v, addr, bpt, cpt;
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700808 ssize_t len;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500809
810 addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
811 rtnl_lock();
812 t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
813 v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
814 if (sched & 1)
815 v >>= 16;
816 bpt = (v >> 8) & 0xff;
817 cpt = v & 0xff;
818 if (!cpt)
819 len = sprintf(buf, "disabled\n");
820 else {
821 v = (adap->params.vpd.cclk * 1000) / cpt;
822 len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125);
823 }
824 rtnl_unlock();
825 return len;
826}
827
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800828static ssize_t tm_attr_store(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800829 const char *buf, size_t len, int sched)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500830{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700831 struct port_info *pi = netdev_priv(to_net_dev(d));
832 struct adapter *adap = pi->adapter;
833 unsigned int val;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500834 char *endp;
835 ssize_t ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500836
837 if (!capable(CAP_NET_ADMIN))
838 return -EPERM;
839
840 val = simple_strtoul(buf, &endp, 0);
841 if (endp == buf || val > 10000000)
842 return -EINVAL;
843
844 rtnl_lock();
845 ret = t3_config_sched(adap, val, sched);
846 if (!ret)
847 ret = len;
848 rtnl_unlock();
849 return ret;
850}
851
852#define TM_ATTR(name, sched) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800853static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
854 char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500855{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800856 return tm_attr_show(d, buf, sched); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500857} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800858static ssize_t store_##name(struct device *d, struct device_attribute *attr, \
859 const char *buf, size_t len) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500860{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800861 return tm_attr_store(d, buf, len, sched); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500862} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800863static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500864
865TM_ATTR(sched0, 0);
866TM_ATTR(sched1, 1);
867TM_ATTR(sched2, 2);
868TM_ATTR(sched3, 3);
869TM_ATTR(sched4, 4);
870TM_ATTR(sched5, 5);
871TM_ATTR(sched6, 6);
872TM_ATTR(sched7, 7);
873
874static struct attribute *offload_attrs[] = {
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800875 &dev_attr_sched0.attr,
876 &dev_attr_sched1.attr,
877 &dev_attr_sched2.attr,
878 &dev_attr_sched3.attr,
879 &dev_attr_sched4.attr,
880 &dev_attr_sched5.attr,
881 &dev_attr_sched6.attr,
882 &dev_attr_sched7.attr,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500883 NULL
884};
885
886static struct attribute_group offload_attr_group = {.attrs = offload_attrs };
887
888/*
889 * Sends an sk_buff to an offload queue driver
890 * after dealing with any active network taps.
891 */
892static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
893{
894 int ret;
895
896 local_bh_disable();
897 ret = t3_offload_tx(tdev, skb);
898 local_bh_enable();
899 return ret;
900}
901
902static int write_smt_entry(struct adapter *adapter, int idx)
903{
904 struct cpl_smt_write_req *req;
Karen Xief14d42f2009-10-08 09:11:05 +0000905 struct port_info *pi = netdev_priv(adapter->port[idx]);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500906 struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);
907
908 if (!skb)
909 return -ENOMEM;
910
911 req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
912 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
913 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
914 req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */
915 req->iff = idx;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500916 memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);
Karen Xief14d42f2009-10-08 09:11:05 +0000917 memcpy(req->src_mac1, pi->iscsic.mac_addr, ETH_ALEN);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500918 skb->priority = 1;
919 offload_tx(&adapter->tdev, skb);
920 return 0;
921}
922
923static int init_smt(struct adapter *adapter)
924{
925 int i;
926
927 for_each_port(adapter, i)
928 write_smt_entry(adapter, i);
929 return 0;
930}
931
932static void init_port_mtus(struct adapter *adapter)
933{
934 unsigned int mtus = adapter->port[0]->mtu;
935
936 if (adapter->port[1])
937 mtus |= adapter->port[1]->mtu << 16;
938 t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
939}
940
Divy Le Ray8c263762008-10-08 17:37:33 -0700941static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
Divy Le Ray14ab9892007-01-30 19:43:50 -0800942 int hi, int port)
943{
944 struct sk_buff *skb;
945 struct mngt_pktsched_wr *req;
Divy Le Ray8c263762008-10-08 17:37:33 -0700946 int ret;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800947
Divy Le Ray74b793e2009-06-09 23:25:21 +0000948 skb = alloc_skb(sizeof(*req), GFP_KERNEL);
949 if (!skb)
950 skb = adap->nofail_skb;
951 if (!skb)
952 return -ENOMEM;
953
Divy Le Ray14ab9892007-01-30 19:43:50 -0800954 req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
955 req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
956 req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
957 req->sched = sched;
958 req->idx = qidx;
959 req->min = lo;
960 req->max = hi;
961 req->binding = port;
Divy Le Ray8c263762008-10-08 17:37:33 -0700962 ret = t3_mgmt_tx(adap, skb);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000963 if (skb == adap->nofail_skb) {
964 adap->nofail_skb = alloc_skb(sizeof(struct cpl_set_tcb_field),
965 GFP_KERNEL);
966 if (!adap->nofail_skb)
967 ret = -ENOMEM;
968 }
Divy Le Ray8c263762008-10-08 17:37:33 -0700969
970 return ret;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800971}
972
Divy Le Ray8c263762008-10-08 17:37:33 -0700973static int bind_qsets(struct adapter *adap)
Divy Le Ray14ab9892007-01-30 19:43:50 -0800974{
Divy Le Ray8c263762008-10-08 17:37:33 -0700975 int i, j, err = 0;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800976
977 for_each_port(adap, i) {
978 const struct port_info *pi = adap2pinfo(adap, i);
979
Divy Le Ray8c263762008-10-08 17:37:33 -0700980 for (j = 0; j < pi->nqsets; ++j) {
981 int ret = send_pktsched_cmd(adap, 1,
982 pi->first_qset + j, -1,
983 -1, i);
984 if (ret)
985 err = ret;
986 }
Divy Le Ray14ab9892007-01-30 19:43:50 -0800987 }
Divy Le Ray8c263762008-10-08 17:37:33 -0700988
989 return err;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800990}
991
Ben Hutchings34336ec2009-11-07 11:53:52 +0000992#define FW_VERSION __stringify(FW_VERSION_MAJOR) "." \
993 __stringify(FW_VERSION_MINOR) "." __stringify(FW_VERSION_MICRO)
994#define FW_FNAME "cxgb3/t3fw-" FW_VERSION ".bin"
995#define TPSRAM_VERSION __stringify(TP_VERSION_MAJOR) "." \
996 __stringify(TP_VERSION_MINOR) "." __stringify(TP_VERSION_MICRO)
997#define TPSRAM_NAME "cxgb3/t3%c_psram-" TPSRAM_VERSION ".bin"
Divy Le Ray2e8c07c2009-07-07 19:49:09 +0000998#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin"
999#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin"
Divy Le Ray94505262009-07-30 21:23:34 +00001000#define AEL2020_TWX_EDC_NAME "cxgb3/ael2020_twx_edc.bin"
Ben Hutchings34336ec2009-11-07 11:53:52 +00001001MODULE_FIRMWARE(FW_FNAME);
1002MODULE_FIRMWARE("cxgb3/t3b_psram-" TPSRAM_VERSION ".bin");
1003MODULE_FIRMWARE("cxgb3/t3c_psram-" TPSRAM_VERSION ".bin");
1004MODULE_FIRMWARE(AEL2005_OPT_EDC_NAME);
1005MODULE_FIRMWARE(AEL2005_TWX_EDC_NAME);
1006MODULE_FIRMWARE(AEL2020_TWX_EDC_NAME);
Divy Le Ray2e8c07c2009-07-07 19:49:09 +00001007
1008static inline const char *get_edc_fw_name(int edc_idx)
1009{
1010 const char *fw_name = NULL;
1011
1012 switch (edc_idx) {
1013 case EDC_OPT_AEL2005:
1014 fw_name = AEL2005_OPT_EDC_NAME;
1015 break;
1016 case EDC_TWX_AEL2005:
1017 fw_name = AEL2005_TWX_EDC_NAME;
1018 break;
1019 case EDC_TWX_AEL2020:
1020 fw_name = AEL2020_TWX_EDC_NAME;
1021 break;
1022 }
1023 return fw_name;
1024}
1025
1026int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size)
1027{
1028 struct adapter *adapter = phy->adapter;
1029 const struct firmware *fw;
1030 char buf[64];
1031 u32 csum;
1032 const __be32 *p;
1033 u16 *cache = phy->phy_cache;
1034 int i, ret;
1035
1036 snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx));
1037
1038 ret = request_firmware(&fw, buf, &adapter->pdev->dev);
1039 if (ret < 0) {
1040 dev_err(&adapter->pdev->dev,
1041 "could not upgrade firmware: unable to load %s\n",
1042 buf);
1043 return ret;
1044 }
1045
1046 /* check size, take checksum in account */
1047 if (fw->size > size + 4) {
1048 CH_ERR(adapter, "firmware image too large %u, expected %d\n",
1049 (unsigned int)fw->size, size + 4);
1050 ret = -EINVAL;
1051 }
1052
1053 /* compute checksum */
1054 p = (const __be32 *)fw->data;
1055 for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++)
1056 csum += ntohl(p[i]);
1057
1058 if (csum != 0xffffffff) {
1059 CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
1060 csum);
1061 ret = -EINVAL;
1062 }
1063
1064 for (i = 0; i < size / 4 ; i++) {
1065 *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16;
1066 *cache++ = be32_to_cpu(p[i]) & 0xffff;
1067 }
1068
1069 release_firmware(fw);
1070
1071 return ret;
1072}
Divy Le Ray2e283962007-03-18 13:10:06 -07001073
1074static int upgrade_fw(struct adapter *adap)
1075{
1076 int ret;
Divy Le Ray2e283962007-03-18 13:10:06 -07001077 const struct firmware *fw;
1078 struct device *dev = &adap->pdev->dev;
1079
Ben Hutchings34336ec2009-11-07 11:53:52 +00001080 ret = request_firmware(&fw, FW_FNAME, dev);
Divy Le Ray2e283962007-03-18 13:10:06 -07001081 if (ret < 0) {
1082 dev_err(dev, "could not upgrade firmware: unable to load %s\n",
Ben Hutchings34336ec2009-11-07 11:53:52 +00001083 FW_FNAME);
Divy Le Ray2e283962007-03-18 13:10:06 -07001084 return ret;
1085 }
1086 ret = t3_load_fw(adap, fw->data, fw->size);
1087 release_firmware(fw);
Divy Le Ray47330072007-08-29 19:15:52 -07001088
1089 if (ret == 0)
1090 dev_info(dev, "successful upgrade to firmware %d.%d.%d\n",
1091 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
1092 else
1093 dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n",
1094 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001095
Divy Le Ray47330072007-08-29 19:15:52 -07001096 return ret;
1097}
1098
1099static inline char t3rev2char(struct adapter *adapter)
1100{
1101 char rev = 0;
1102
1103 switch(adapter->params.rev) {
1104 case T3_REV_B:
1105 case T3_REV_B2:
1106 rev = 'b';
1107 break;
Divy Le Ray1aafee22007-09-05 15:58:36 -07001108 case T3_REV_C:
1109 rev = 'c';
1110 break;
Divy Le Ray47330072007-08-29 19:15:52 -07001111 }
1112 return rev;
1113}
1114
Stephen Hemminger9265fab2007-10-08 16:22:29 -07001115static int update_tpsram(struct adapter *adap)
Divy Le Ray47330072007-08-29 19:15:52 -07001116{
1117 const struct firmware *tpsram;
1118 char buf[64];
1119 struct device *dev = &adap->pdev->dev;
1120 int ret;
1121 char rev;
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001122
Divy Le Ray47330072007-08-29 19:15:52 -07001123 rev = t3rev2char(adap);
1124 if (!rev)
1125 return 0;
1126
Ben Hutchings34336ec2009-11-07 11:53:52 +00001127 snprintf(buf, sizeof(buf), TPSRAM_NAME, rev);
Divy Le Ray47330072007-08-29 19:15:52 -07001128
1129 ret = request_firmware(&tpsram, buf, dev);
1130 if (ret < 0) {
1131 dev_err(dev, "could not load TP SRAM: unable to load %s\n",
1132 buf);
1133 return ret;
1134 }
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001135
Divy Le Ray47330072007-08-29 19:15:52 -07001136 ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
1137 if (ret)
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001138 goto release_tpsram;
Divy Le Ray47330072007-08-29 19:15:52 -07001139
1140 ret = t3_set_proto_sram(adap, tpsram->data);
1141 if (ret == 0)
1142 dev_info(dev,
1143 "successful update of protocol engine "
1144 "to %d.%d.%d\n",
1145 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1146 else
1147 dev_err(dev, "failed to update of protocol engine %d.%d.%d\n",
1148 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1149 if (ret)
1150 dev_err(dev, "loading protocol SRAM failed\n");
1151
1152release_tpsram:
1153 release_firmware(tpsram);
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001154
Divy Le Ray2e283962007-03-18 13:10:06 -07001155 return ret;
1156}
1157
Divy Le Ray4d22de32007-01-18 22:04:14 -05001158/**
1159 * cxgb_up - enable the adapter
1160 * @adapter: adapter being enabled
1161 *
1162 * Called when the first port is enabled, this function performs the
1163 * actions necessary to make an adapter operational, such as completing
1164 * the initialization of HW modules, and enabling interrupts.
1165 *
1166 * Must be called with the rtnl lock held.
1167 */
1168static int cxgb_up(struct adapter *adap)
1169{
Denis Chengc54f5c22007-07-18 15:24:49 +08001170 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001171
1172 if (!(adap->flags & FULL_INIT_DONE)) {
Divy Le Ray8207bef2008-12-16 01:51:47 -08001173 err = t3_check_fw_version(adap);
Divy Le Raya5a3b462007-09-05 15:58:09 -07001174 if (err == -EINVAL) {
Divy Le Ray2e283962007-03-18 13:10:06 -07001175 err = upgrade_fw(adap);
Divy Le Ray8207bef2008-12-16 01:51:47 -08001176 CH_WARN(adap, "FW upgrade to %d.%d.%d %s\n",
1177 FW_VERSION_MAJOR, FW_VERSION_MINOR,
1178 FW_VERSION_MICRO, err ? "failed" : "succeeded");
Divy Le Raya5a3b462007-09-05 15:58:09 -07001179 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001180
Divy Le Ray8207bef2008-12-16 01:51:47 -08001181 err = t3_check_tpsram_version(adap);
Divy Le Ray47330072007-08-29 19:15:52 -07001182 if (err == -EINVAL) {
1183 err = update_tpsram(adap);
Divy Le Ray8207bef2008-12-16 01:51:47 -08001184 CH_WARN(adap, "TP upgrade to %d.%d.%d %s\n",
1185 TP_VERSION_MAJOR, TP_VERSION_MINOR,
1186 TP_VERSION_MICRO, err ? "failed" : "succeeded");
Divy Le Ray47330072007-08-29 19:15:52 -07001187 }
1188
Divy Le Ray20d3fc12008-10-08 17:36:03 -07001189 /*
1190 * Clear interrupts now to catch errors if t3_init_hw fails.
1191 * We clear them again later as initialization may trigger
1192 * conditions that can interrupt.
1193 */
1194 t3_intr_clear(adap);
1195
Divy Le Ray4d22de32007-01-18 22:04:14 -05001196 err = t3_init_hw(adap, 0);
1197 if (err)
1198 goto out;
1199
Divy Le Rayb8819552007-12-17 18:47:31 -08001200 t3_set_reg_field(adap, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
Divy Le Ray6cdbd772007-04-09 20:10:33 -07001201 t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
Stephen Hemmingerbea33482007-10-03 16:41:36 -07001202
Divy Le Ray4d22de32007-01-18 22:04:14 -05001203 err = setup_sge_qsets(adap);
1204 if (err)
1205 goto out;
1206
1207 setup_rss(adap);
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001208 if (!(adap->flags & NAPI_INIT))
1209 init_napi(adap);
Divy Le Ray31563782009-03-26 16:39:09 +00001210
1211 t3_start_sge_timers(adap);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001212 adap->flags |= FULL_INIT_DONE;
1213 }
1214
1215 t3_intr_clear(adap);
1216
1217 if (adap->flags & USING_MSIX) {
1218 name_msix_vecs(adap);
1219 err = request_irq(adap->msix_info[0].vec,
1220 t3_async_intr_handler, 0,
1221 adap->msix_info[0].desc, adap);
1222 if (err)
1223 goto irq_err;
1224
Divy Le Ray42256f52007-11-16 11:21:39 -08001225 err = request_msix_data_irqs(adap);
1226 if (err) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001227 free_irq(adap->msix_info[0].vec, adap);
1228 goto irq_err;
1229 }
1230 } else if ((err = request_irq(adap->pdev->irq,
1231 t3_intr_handler(adap,
1232 adap->sge.qs[0].rspq.
1233 polling),
Thomas Gleixner2db63462007-02-14 00:33:20 -08001234 (adap->flags & USING_MSI) ?
1235 0 : IRQF_SHARED,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001236 adap->name, adap)))
1237 goto irq_err;
1238
Stephen Hemmingerbea33482007-10-03 16:41:36 -07001239 enable_all_napi(adap);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001240 t3_sge_start(adap);
1241 t3_intr_enable(adap);
Divy Le Ray14ab9892007-01-30 19:43:50 -08001242
Divy Le Rayb8819552007-12-17 18:47:31 -08001243 if (adap->params.rev >= T3_REV_C && !(adap->flags & TP_PARITY_INIT) &&
1244 is_offload(adap) && init_tp_parity(adap) == 0)
1245 adap->flags |= TP_PARITY_INIT;
1246
1247 if (adap->flags & TP_PARITY_INIT) {
1248 t3_write_reg(adap, A_TP_INT_CAUSE,
1249 F_CMCACHEPERR | F_ARPLUTPERR);
1250 t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff);
1251 }
1252
Divy Le Ray8c263762008-10-08 17:37:33 -07001253 if (!(adap->flags & QUEUES_BOUND)) {
1254 err = bind_qsets(adap);
1255 if (err) {
1256 CH_ERR(adap, "failed to bind qsets, err %d\n", err);
1257 t3_intr_disable(adap);
1258 free_irq_resources(adap);
1259 goto out;
1260 }
1261 adap->flags |= QUEUES_BOUND;
1262 }
Divy Le Ray14ab9892007-01-30 19:43:50 -08001263
Divy Le Ray4d22de32007-01-18 22:04:14 -05001264out:
1265 return err;
1266irq_err:
1267 CH_ERR(adap, "request_irq failed, err %d\n", err);
1268 goto out;
1269}
1270
1271/*
1272 * Release resources when all the ports and offloading have been stopped.
1273 */
1274static void cxgb_down(struct adapter *adapter)
1275{
1276 t3_sge_stop(adapter);
1277 spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */
1278 t3_intr_disable(adapter);
1279 spin_unlock_irq(&adapter->work_lock);
1280
Divy Le Ray8c263762008-10-08 17:37:33 -07001281 free_irq_resources(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001282 quiesce_rx(adapter);
Divy Le Raya6f018e2010-03-03 09:49:47 +00001283 t3_sge_stop(adapter);
Divy Le Rayc80b0c22009-04-17 12:21:17 +00001284 flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */
Divy Le Ray4d22de32007-01-18 22:04:14 -05001285}
1286
1287static void schedule_chk_task(struct adapter *adap)
1288{
1289 unsigned int timeo;
1290
1291 timeo = adap->params.linkpoll_period ?
1292 (HZ * adap->params.linkpoll_period) / 10 :
1293 adap->params.stats_update_period * HZ;
1294 if (timeo)
1295 queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo);
1296}
1297
1298static int offload_open(struct net_device *dev)
1299{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001300 struct port_info *pi = netdev_priv(dev);
1301 struct adapter *adapter = pi->adapter;
1302 struct t3cdev *tdev = dev2t3cdev(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001303 int adap_up = adapter->open_device_map & PORT_MASK;
Denis Chengc54f5c22007-07-18 15:24:49 +08001304 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001305
1306 if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
1307 return 0;
1308
1309 if (!adap_up && (err = cxgb_up(adapter)) < 0)
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001310 goto out;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001311
1312 t3_tp_set_offload_mode(adapter, 1);
1313 tdev->lldev = adapter->port[0];
1314 err = cxgb3_offload_activate(adapter);
1315 if (err)
1316 goto out;
1317
1318 init_port_mtus(adapter);
1319 t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
1320 adapter->params.b_wnd,
1321 adapter->params.rev == 0 ?
1322 adapter->port[0]->mtu : 0xffff);
1323 init_smt(adapter);
1324
Dan Noed96a51f2008-04-12 22:34:38 -04001325 if (sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group))
1326 dev_dbg(&dev->dev, "cannot create sysfs group\n");
Divy Le Ray4d22de32007-01-18 22:04:14 -05001327
1328 /* Call back all registered clients */
1329 cxgb3_add_clients(tdev);
1330
1331out:
1332 /* restore them in case the offload module has changed them */
1333 if (err) {
1334 t3_tp_set_offload_mode(adapter, 0);
1335 clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
1336 cxgb3_set_dummy_ops(tdev);
1337 }
1338 return err;
1339}
1340
1341static int offload_close(struct t3cdev *tdev)
1342{
1343 struct adapter *adapter = tdev2adap(tdev);
1344
1345 if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
1346 return 0;
1347
1348 /* Call back all registered clients */
1349 cxgb3_remove_clients(tdev);
1350
Divy Le Ray0ee8d332007-02-08 16:55:59 -08001351 sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001352
Divy Le Rayc80b0c22009-04-17 12:21:17 +00001353 /* Flush work scheduled while releasing TIDs */
1354 flush_scheduled_work();
1355
Divy Le Ray4d22de32007-01-18 22:04:14 -05001356 tdev->lldev = NULL;
1357 cxgb3_set_dummy_ops(tdev);
1358 t3_tp_set_offload_mode(adapter, 0);
1359 clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
1360
1361 if (!adapter->open_device_map)
1362 cxgb_down(adapter);
1363
1364 cxgb3_offload_deactivate(adapter);
1365 return 0;
1366}
1367
1368static int cxgb_open(struct net_device *dev)
1369{
Divy Le Ray4d22de32007-01-18 22:04:14 -05001370 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001371 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001372 int other_ports = adapter->open_device_map & PORT_MASK;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001373 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001374
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001375 if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001376 return err;
1377
1378 set_bit(pi->port_id, &adapter->open_device_map);
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07001379 if (is_offload(adapter) && !ofld_disable) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001380 err = offload_open(dev);
1381 if (err)
1382 printk(KERN_WARNING
1383 "Could not initialize offload capabilities\n");
1384 }
1385
Divy Le Ray82ad3322008-12-16 01:09:39 -08001386 dev->real_num_tx_queues = pi->nqsets;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001387 link_start(dev);
1388 t3_port_intr_enable(adapter, pi->port_id);
Divy Le Ray82ad3322008-12-16 01:09:39 -08001389 netif_tx_start_all_queues(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001390 if (!other_ports)
1391 schedule_chk_task(adapter);
1392
Steve Wisefa0d4c12009-09-05 20:22:38 -07001393 cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_UP, pi->port_id);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001394 return 0;
1395}
1396
1397static int cxgb_close(struct net_device *dev)
1398{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001399 struct port_info *pi = netdev_priv(dev);
1400 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001401
Divy Le Raye8d19372009-04-17 12:21:27 +00001402
1403 if (!adapter->open_device_map)
1404 return 0;
1405
Divy Le Raybf792092009-03-12 21:14:19 +00001406 /* Stop link fault interrupts */
1407 t3_xgm_intr_disable(adapter, pi->port_id);
1408 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
1409
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001410 t3_port_intr_disable(adapter, pi->port_id);
Divy Le Ray82ad3322008-12-16 01:09:39 -08001411 netif_tx_stop_all_queues(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001412 pi->phy.ops->power_down(&pi->phy, 1);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001413 netif_carrier_off(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001414 t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001415
Divy Le Ray20d3fc12008-10-08 17:36:03 -07001416 spin_lock_irq(&adapter->work_lock); /* sync with update task */
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001417 clear_bit(pi->port_id, &adapter->open_device_map);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07001418 spin_unlock_irq(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001419
1420 if (!(adapter->open_device_map & PORT_MASK))
Divy Le Rayc80b0c22009-04-17 12:21:17 +00001421 cancel_delayed_work_sync(&adapter->adap_check_task);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001422
1423 if (!adapter->open_device_map)
1424 cxgb_down(adapter);
1425
Steve Wisefa0d4c12009-09-05 20:22:38 -07001426 cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_DOWN, pi->port_id);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001427 return 0;
1428}
1429
1430static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
1431{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001432 struct port_info *pi = netdev_priv(dev);
1433 struct adapter *adapter = pi->adapter;
1434 struct net_device_stats *ns = &pi->netstats;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001435 const struct mac_stats *pstats;
1436
1437 spin_lock(&adapter->stats_lock);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001438 pstats = t3_mac_update_stats(&pi->mac);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001439 spin_unlock(&adapter->stats_lock);
1440
1441 ns->tx_bytes = pstats->tx_octets;
1442 ns->tx_packets = pstats->tx_frames;
1443 ns->rx_bytes = pstats->rx_octets;
1444 ns->rx_packets = pstats->rx_frames;
1445 ns->multicast = pstats->rx_mcast_frames;
1446
1447 ns->tx_errors = pstats->tx_underrun;
1448 ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs +
1449 pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short +
1450 pstats->rx_fifo_ovfl;
1451
1452 /* detailed rx_errors */
1453 ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long;
1454 ns->rx_over_errors = 0;
1455 ns->rx_crc_errors = pstats->rx_fcs_errs;
1456 ns->rx_frame_errors = pstats->rx_symbol_errs;
1457 ns->rx_fifo_errors = pstats->rx_fifo_ovfl;
1458 ns->rx_missed_errors = pstats->rx_cong_drops;
1459
1460 /* detailed tx_errors */
1461 ns->tx_aborted_errors = 0;
1462 ns->tx_carrier_errors = 0;
1463 ns->tx_fifo_errors = pstats->tx_underrun;
1464 ns->tx_heartbeat_errors = 0;
1465 ns->tx_window_errors = 0;
1466 return ns;
1467}
1468
1469static u32 get_msglevel(struct net_device *dev)
1470{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001471 struct port_info *pi = netdev_priv(dev);
1472 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001473
1474 return adapter->msg_enable;
1475}
1476
1477static void set_msglevel(struct net_device *dev, u32 val)
1478{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001479 struct port_info *pi = netdev_priv(dev);
1480 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001481
1482 adapter->msg_enable = val;
1483}
1484
1485static char stats_strings[][ETH_GSTRING_LEN] = {
1486 "TxOctetsOK ",
1487 "TxFramesOK ",
1488 "TxMulticastFramesOK",
1489 "TxBroadcastFramesOK",
1490 "TxPauseFrames ",
1491 "TxUnderrun ",
1492 "TxExtUnderrun ",
1493
1494 "TxFrames64 ",
1495 "TxFrames65To127 ",
1496 "TxFrames128To255 ",
1497 "TxFrames256To511 ",
1498 "TxFrames512To1023 ",
1499 "TxFrames1024To1518 ",
1500 "TxFrames1519ToMax ",
1501
1502 "RxOctetsOK ",
1503 "RxFramesOK ",
1504 "RxMulticastFramesOK",
1505 "RxBroadcastFramesOK",
1506 "RxPauseFrames ",
1507 "RxFCSErrors ",
1508 "RxSymbolErrors ",
1509 "RxShortErrors ",
1510 "RxJabberErrors ",
1511 "RxLengthErrors ",
1512 "RxFIFOoverflow ",
1513
1514 "RxFrames64 ",
1515 "RxFrames65To127 ",
1516 "RxFrames128To255 ",
1517 "RxFrames256To511 ",
1518 "RxFrames512To1023 ",
1519 "RxFrames1024To1518 ",
1520 "RxFrames1519ToMax ",
1521
1522 "PhyFIFOErrors ",
1523 "TSO ",
1524 "VLANextractions ",
1525 "VLANinsertions ",
1526 "TxCsumOffload ",
1527 "RxCsumGood ",
Divy Le Rayb47385b2008-05-21 18:56:26 -07001528 "LroAggregated ",
1529 "LroFlushed ",
1530 "LroNoDesc ",
Divy Le Rayfc906642007-03-18 13:10:12 -07001531 "RxDrops ",
1532
1533 "CheckTXEnToggled ",
1534 "CheckResets ",
1535
Divy Le Raybf792092009-03-12 21:14:19 +00001536 "LinkFaults ",
Divy Le Ray4d22de32007-01-18 22:04:14 -05001537};
1538
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001539static int get_sset_count(struct net_device *dev, int sset)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001540{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001541 switch (sset) {
1542 case ETH_SS_STATS:
1543 return ARRAY_SIZE(stats_strings);
1544 default:
1545 return -EOPNOTSUPP;
1546 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001547}
1548
1549#define T3_REGMAP_SIZE (3 * 1024)
1550
1551static int get_regs_len(struct net_device *dev)
1552{
1553 return T3_REGMAP_SIZE;
1554}
1555
1556static int get_eeprom_len(struct net_device *dev)
1557{
1558 return EEPROMSIZE;
1559}
1560
1561static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
1562{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001563 struct port_info *pi = netdev_priv(dev);
1564 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001565 u32 fw_vers = 0;
Divy Le Ray47330072007-08-29 19:15:52 -07001566 u32 tp_vers = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001567
Steve Wisecf3760d2008-11-06 17:06:42 -06001568 spin_lock(&adapter->stats_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001569 t3_get_fw_version(adapter, &fw_vers);
Divy Le Ray47330072007-08-29 19:15:52 -07001570 t3_get_tp_version(adapter, &tp_vers);
Steve Wisecf3760d2008-11-06 17:06:42 -06001571 spin_unlock(&adapter->stats_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001572
1573 strcpy(info->driver, DRV_NAME);
1574 strcpy(info->version, DRV_VERSION);
1575 strcpy(info->bus_info, pci_name(adapter->pdev));
1576 if (!fw_vers)
1577 strcpy(info->fw_version, "N/A");
Divy Le Ray4aac3892007-01-30 19:43:45 -08001578 else {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001579 snprintf(info->fw_version, sizeof(info->fw_version),
Divy Le Ray47330072007-08-29 19:15:52 -07001580 "%s %u.%u.%u TP %u.%u.%u",
Divy Le Ray4aac3892007-01-30 19:43:45 -08001581 G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
1582 G_FW_VERSION_MAJOR(fw_vers),
1583 G_FW_VERSION_MINOR(fw_vers),
Divy Le Ray47330072007-08-29 19:15:52 -07001584 G_FW_VERSION_MICRO(fw_vers),
1585 G_TP_VERSION_MAJOR(tp_vers),
1586 G_TP_VERSION_MINOR(tp_vers),
1587 G_TP_VERSION_MICRO(tp_vers));
Divy Le Ray4aac3892007-01-30 19:43:45 -08001588 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001589}
1590
1591static void get_strings(struct net_device *dev, u32 stringset, u8 * data)
1592{
1593 if (stringset == ETH_SS_STATS)
1594 memcpy(data, stats_strings, sizeof(stats_strings));
1595}
1596
1597static unsigned long collect_sge_port_stats(struct adapter *adapter,
1598 struct port_info *p, int idx)
1599{
1600 int i;
1601 unsigned long tot = 0;
1602
Divy Le Ray8c263762008-10-08 17:37:33 -07001603 for (i = p->first_qset; i < p->first_qset + p->nqsets; ++i)
1604 tot += adapter->sge.qs[i].port_stats[idx];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001605 return tot;
1606}
1607
1608static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
1609 u64 *data)
1610{
Divy Le Ray4d22de32007-01-18 22:04:14 -05001611 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001612 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001613 const struct mac_stats *s;
1614
1615 spin_lock(&adapter->stats_lock);
1616 s = t3_mac_update_stats(&pi->mac);
1617 spin_unlock(&adapter->stats_lock);
1618
1619 *data++ = s->tx_octets;
1620 *data++ = s->tx_frames;
1621 *data++ = s->tx_mcast_frames;
1622 *data++ = s->tx_bcast_frames;
1623 *data++ = s->tx_pause;
1624 *data++ = s->tx_underrun;
1625 *data++ = s->tx_fifo_urun;
1626
1627 *data++ = s->tx_frames_64;
1628 *data++ = s->tx_frames_65_127;
1629 *data++ = s->tx_frames_128_255;
1630 *data++ = s->tx_frames_256_511;
1631 *data++ = s->tx_frames_512_1023;
1632 *data++ = s->tx_frames_1024_1518;
1633 *data++ = s->tx_frames_1519_max;
1634
1635 *data++ = s->rx_octets;
1636 *data++ = s->rx_frames;
1637 *data++ = s->rx_mcast_frames;
1638 *data++ = s->rx_bcast_frames;
1639 *data++ = s->rx_pause;
1640 *data++ = s->rx_fcs_errs;
1641 *data++ = s->rx_symbol_errs;
1642 *data++ = s->rx_short;
1643 *data++ = s->rx_jabber;
1644 *data++ = s->rx_too_long;
1645 *data++ = s->rx_fifo_ovfl;
1646
1647 *data++ = s->rx_frames_64;
1648 *data++ = s->rx_frames_65_127;
1649 *data++ = s->rx_frames_128_255;
1650 *data++ = s->rx_frames_256_511;
1651 *data++ = s->rx_frames_512_1023;
1652 *data++ = s->rx_frames_1024_1518;
1653 *data++ = s->rx_frames_1519_max;
1654
1655 *data++ = pi->phy.fifo_errors;
1656
1657 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO);
1658 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX);
1659 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
1660 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
1661 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
Herbert Xu7be2df42009-01-21 14:39:13 -08001662 *data++ = 0;
1663 *data++ = 0;
1664 *data++ = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001665 *data++ = s->rx_cong_drops;
Divy Le Rayfc906642007-03-18 13:10:12 -07001666
1667 *data++ = s->num_toggled;
1668 *data++ = s->num_resets;
Divy Le Raybf792092009-03-12 21:14:19 +00001669
1670 *data++ = s->link_faults;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001671}
1672
1673static inline void reg_block_dump(struct adapter *ap, void *buf,
1674 unsigned int start, unsigned int end)
1675{
1676 u32 *p = buf + start;
1677
1678 for (; start <= end; start += sizeof(u32))
1679 *p++ = t3_read_reg(ap, start);
1680}
1681
1682static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
1683 void *buf)
1684{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001685 struct port_info *pi = netdev_priv(dev);
1686 struct adapter *ap = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001687
1688 /*
1689 * Version scheme:
1690 * bits 0..9: chip version
1691 * bits 10..15: chip revision
1692 * bit 31: set for PCIe cards
1693 */
1694 regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31);
1695
1696 /*
1697 * We skip the MAC statistics registers because they are clear-on-read.
1698 * Also reading multi-register stats would need to synchronize with the
1699 * periodic mac stats accumulation. Hard to justify the complexity.
1700 */
1701 memset(buf, 0, T3_REGMAP_SIZE);
1702 reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
1703 reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
1704 reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
1705 reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
1706 reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
1707 reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0,
1708 XGM_REG(A_XGM_SERDES_STAT3, 1));
1709 reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
1710 XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
1711}
1712
1713static int restart_autoneg(struct net_device *dev)
1714{
1715 struct port_info *p = netdev_priv(dev);
1716
1717 if (!netif_running(dev))
1718 return -EAGAIN;
1719 if (p->link_config.autoneg != AUTONEG_ENABLE)
1720 return -EINVAL;
1721 p->phy.ops->autoneg_restart(&p->phy);
1722 return 0;
1723}
1724
1725static int cxgb3_phys_id(struct net_device *dev, u32 data)
1726{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001727 struct port_info *pi = netdev_priv(dev);
1728 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001729 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001730
1731 if (data == 0)
1732 data = 2;
1733
1734 for (i = 0; i < data * 2; i++) {
1735 t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
1736 (i & 1) ? F_GPIO0_OUT_VAL : 0);
1737 if (msleep_interruptible(500))
1738 break;
1739 }
1740 t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
1741 F_GPIO0_OUT_VAL);
1742 return 0;
1743}
1744
1745static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1746{
1747 struct port_info *p = netdev_priv(dev);
1748
1749 cmd->supported = p->link_config.supported;
1750 cmd->advertising = p->link_config.advertising;
1751
1752 if (netif_carrier_ok(dev)) {
1753 cmd->speed = p->link_config.speed;
1754 cmd->duplex = p->link_config.duplex;
1755 } else {
1756 cmd->speed = -1;
1757 cmd->duplex = -1;
1758 }
1759
1760 cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
Ben Hutchings0f07c4e2009-04-29 08:07:20 +00001761 cmd->phy_address = p->phy.mdio.prtad;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001762 cmd->transceiver = XCVR_EXTERNAL;
1763 cmd->autoneg = p->link_config.autoneg;
1764 cmd->maxtxpkt = 0;
1765 cmd->maxrxpkt = 0;
1766 return 0;
1767}
1768
1769static int speed_duplex_to_caps(int speed, int duplex)
1770{
1771 int cap = 0;
1772
1773 switch (speed) {
1774 case SPEED_10:
1775 if (duplex == DUPLEX_FULL)
1776 cap = SUPPORTED_10baseT_Full;
1777 else
1778 cap = SUPPORTED_10baseT_Half;
1779 break;
1780 case SPEED_100:
1781 if (duplex == DUPLEX_FULL)
1782 cap = SUPPORTED_100baseT_Full;
1783 else
1784 cap = SUPPORTED_100baseT_Half;
1785 break;
1786 case SPEED_1000:
1787 if (duplex == DUPLEX_FULL)
1788 cap = SUPPORTED_1000baseT_Full;
1789 else
1790 cap = SUPPORTED_1000baseT_Half;
1791 break;
1792 case SPEED_10000:
1793 if (duplex == DUPLEX_FULL)
1794 cap = SUPPORTED_10000baseT_Full;
1795 }
1796 return cap;
1797}
1798
1799#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1800 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1801 ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
1802 ADVERTISED_10000baseT_Full)
1803
1804static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1805{
1806 struct port_info *p = netdev_priv(dev);
1807 struct link_config *lc = &p->link_config;
1808
Divy Le Ray9b1e3652008-10-08 17:39:31 -07001809 if (!(lc->supported & SUPPORTED_Autoneg)) {
1810 /*
1811 * PHY offers a single speed/duplex. See if that's what's
1812 * being requested.
1813 */
1814 if (cmd->autoneg == AUTONEG_DISABLE) {
Hannes Eder97915b52009-02-14 11:16:04 +00001815 int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
Divy Le Ray9b1e3652008-10-08 17:39:31 -07001816 if (lc->supported & cap)
1817 return 0;
1818 }
1819 return -EINVAL;
1820 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001821
1822 if (cmd->autoneg == AUTONEG_DISABLE) {
1823 int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
1824
1825 if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
1826 return -EINVAL;
1827 lc->requested_speed = cmd->speed;
1828 lc->requested_duplex = cmd->duplex;
1829 lc->advertising = 0;
1830 } else {
1831 cmd->advertising &= ADVERTISED_MASK;
1832 cmd->advertising &= lc->supported;
1833 if (!cmd->advertising)
1834 return -EINVAL;
1835 lc->requested_speed = SPEED_INVALID;
1836 lc->requested_duplex = DUPLEX_INVALID;
1837 lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
1838 }
1839 lc->autoneg = cmd->autoneg;
1840 if (netif_running(dev))
1841 t3_link_start(&p->phy, &p->mac, lc);
1842 return 0;
1843}
1844
1845static void get_pauseparam(struct net_device *dev,
1846 struct ethtool_pauseparam *epause)
1847{
1848 struct port_info *p = netdev_priv(dev);
1849
1850 epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
1851 epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0;
1852 epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0;
1853}
1854
1855static int set_pauseparam(struct net_device *dev,
1856 struct ethtool_pauseparam *epause)
1857{
1858 struct port_info *p = netdev_priv(dev);
1859 struct link_config *lc = &p->link_config;
1860
1861 if (epause->autoneg == AUTONEG_DISABLE)
1862 lc->requested_fc = 0;
1863 else if (lc->supported & SUPPORTED_Autoneg)
1864 lc->requested_fc = PAUSE_AUTONEG;
1865 else
1866 return -EINVAL;
1867
1868 if (epause->rx_pause)
1869 lc->requested_fc |= PAUSE_RX;
1870 if (epause->tx_pause)
1871 lc->requested_fc |= PAUSE_TX;
1872 if (lc->autoneg == AUTONEG_ENABLE) {
1873 if (netif_running(dev))
1874 t3_link_start(&p->phy, &p->mac, lc);
1875 } else {
1876 lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1877 if (netif_running(dev))
1878 t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc);
1879 }
1880 return 0;
1881}
1882
1883static u32 get_rx_csum(struct net_device *dev)
1884{
1885 struct port_info *p = netdev_priv(dev);
1886
Roland Dreier47fd23f2009-01-11 00:19:36 -08001887 return p->rx_offload & T3_RX_CSUM;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001888}
1889
1890static int set_rx_csum(struct net_device *dev, u32 data)
1891{
1892 struct port_info *p = netdev_priv(dev);
1893
Roland Dreier47fd23f2009-01-11 00:19:36 -08001894 if (data) {
1895 p->rx_offload |= T3_RX_CSUM;
1896 } else {
Divy Le Rayb47385b2008-05-21 18:56:26 -07001897 int i;
1898
Roland Dreier47fd23f2009-01-11 00:19:36 -08001899 p->rx_offload &= ~(T3_RX_CSUM | T3_LRO);
Divy Le Ray04ecb072008-10-28 22:40:32 -07001900 for (i = p->first_qset; i < p->first_qset + p->nqsets; i++)
1901 set_qset_lro(dev, i, 0);
Divy Le Rayb47385b2008-05-21 18:56:26 -07001902 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001903 return 0;
1904}
1905
1906static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
1907{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001908 struct port_info *pi = netdev_priv(dev);
1909 struct adapter *adapter = pi->adapter;
Divy Le Ray05b97b32007-03-18 13:10:01 -07001910 const struct qset_params *q = &adapter->params.sge.qset[pi->first_qset];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001911
1912 e->rx_max_pending = MAX_RX_BUFFERS;
1913 e->rx_mini_max_pending = 0;
1914 e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
1915 e->tx_max_pending = MAX_TXQ_ENTRIES;
1916
Divy Le Ray05b97b32007-03-18 13:10:01 -07001917 e->rx_pending = q->fl_size;
1918 e->rx_mini_pending = q->rspq_size;
1919 e->rx_jumbo_pending = q->jumbo_size;
1920 e->tx_pending = q->txq_size[0];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001921}
1922
1923static int set_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 struct qset_params *q;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001928 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001929
1930 if (e->rx_pending > MAX_RX_BUFFERS ||
1931 e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
1932 e->tx_pending > MAX_TXQ_ENTRIES ||
1933 e->rx_mini_pending > MAX_RSPQ_ENTRIES ||
1934 e->rx_mini_pending < MIN_RSPQ_ENTRIES ||
1935 e->rx_pending < MIN_FL_ENTRIES ||
1936 e->rx_jumbo_pending < MIN_FL_ENTRIES ||
1937 e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES)
1938 return -EINVAL;
1939
1940 if (adapter->flags & FULL_INIT_DONE)
1941 return -EBUSY;
1942
Divy Le Ray05b97b32007-03-18 13:10:01 -07001943 q = &adapter->params.sge.qset[pi->first_qset];
1944 for (i = 0; i < pi->nqsets; ++i, ++q) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001945 q->rspq_size = e->rx_mini_pending;
1946 q->fl_size = e->rx_pending;
1947 q->jumbo_size = e->rx_jumbo_pending;
1948 q->txq_size[0] = e->tx_pending;
1949 q->txq_size[1] = e->tx_pending;
1950 q->txq_size[2] = e->tx_pending;
1951 }
1952 return 0;
1953}
1954
1955static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
1956{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001957 struct port_info *pi = netdev_priv(dev);
1958 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001959 struct qset_params *qsp = &adapter->params.sge.qset[0];
1960 struct sge_qset *qs = &adapter->sge.qs[0];
1961
1962 if (c->rx_coalesce_usecs * 10 > M_NEWTIMER)
1963 return -EINVAL;
1964
1965 qsp->coalesce_usecs = c->rx_coalesce_usecs;
1966 t3_update_qset_coalesce(qs, qsp);
1967 return 0;
1968}
1969
1970static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
1971{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001972 struct port_info *pi = netdev_priv(dev);
1973 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001974 struct qset_params *q = adapter->params.sge.qset;
1975
1976 c->rx_coalesce_usecs = q->coalesce_usecs;
1977 return 0;
1978}
1979
1980static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
1981 u8 * data)
1982{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001983 struct port_info *pi = netdev_priv(dev);
1984 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001985 int i, err = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001986
1987 u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
1988 if (!buf)
1989 return -ENOMEM;
1990
1991 e->magic = EEPROM_MAGIC;
1992 for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
Al Viro05e5c112007-12-22 18:56:23 +00001993 err = t3_seeprom_read(adapter, i, (__le32 *) & buf[i]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001994
1995 if (!err)
1996 memcpy(data, buf + e->offset, e->len);
1997 kfree(buf);
1998 return err;
1999}
2000
2001static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
2002 u8 * data)
2003{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002004 struct port_info *pi = netdev_priv(dev);
2005 struct adapter *adapter = pi->adapter;
Al Viro05e5c112007-12-22 18:56:23 +00002006 u32 aligned_offset, aligned_len;
2007 __le32 *p;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002008 u8 *buf;
Denis Chengc54f5c22007-07-18 15:24:49 +08002009 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002010
2011 if (eeprom->magic != EEPROM_MAGIC)
2012 return -EINVAL;
2013
2014 aligned_offset = eeprom->offset & ~3;
2015 aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
2016
2017 if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
2018 buf = kmalloc(aligned_len, GFP_KERNEL);
2019 if (!buf)
2020 return -ENOMEM;
Al Viro05e5c112007-12-22 18:56:23 +00002021 err = t3_seeprom_read(adapter, aligned_offset, (__le32 *) buf);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002022 if (!err && aligned_len > 4)
2023 err = t3_seeprom_read(adapter,
2024 aligned_offset + aligned_len - 4,
Al Viro05e5c112007-12-22 18:56:23 +00002025 (__le32 *) & buf[aligned_len - 4]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002026 if (err)
2027 goto out;
2028 memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
2029 } else
2030 buf = data;
2031
2032 err = t3_seeprom_wp(adapter, 0);
2033 if (err)
2034 goto out;
2035
Al Viro05e5c112007-12-22 18:56:23 +00002036 for (p = (__le32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05002037 err = t3_seeprom_write(adapter, aligned_offset, *p);
2038 aligned_offset += 4;
2039 }
2040
2041 if (!err)
2042 err = t3_seeprom_wp(adapter, 1);
2043out:
2044 if (buf != data)
2045 kfree(buf);
2046 return err;
2047}
2048
2049static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
2050{
2051 wol->supported = 0;
2052 wol->wolopts = 0;
2053 memset(&wol->sopass, 0, sizeof(wol->sopass));
2054}
2055
2056static const struct ethtool_ops cxgb_ethtool_ops = {
2057 .get_settings = get_settings,
2058 .set_settings = set_settings,
2059 .get_drvinfo = get_drvinfo,
2060 .get_msglevel = get_msglevel,
2061 .set_msglevel = set_msglevel,
2062 .get_ringparam = get_sge_param,
2063 .set_ringparam = set_sge_param,
2064 .get_coalesce = get_coalesce,
2065 .set_coalesce = set_coalesce,
2066 .get_eeprom_len = get_eeprom_len,
2067 .get_eeprom = get_eeprom,
2068 .set_eeprom = set_eeprom,
2069 .get_pauseparam = get_pauseparam,
2070 .set_pauseparam = set_pauseparam,
2071 .get_rx_csum = get_rx_csum,
2072 .set_rx_csum = set_rx_csum,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002073 .set_tx_csum = ethtool_op_set_tx_csum,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002074 .set_sg = ethtool_op_set_sg,
2075 .get_link = ethtool_op_get_link,
2076 .get_strings = get_strings,
2077 .phys_id = cxgb3_phys_id,
2078 .nway_reset = restart_autoneg,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07002079 .get_sset_count = get_sset_count,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002080 .get_ethtool_stats = get_stats,
2081 .get_regs_len = get_regs_len,
2082 .get_regs = get_regs,
2083 .get_wol = get_wol,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002084 .set_tso = ethtool_op_set_tso,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002085};
2086
2087static int in_range(int val, int lo, int hi)
2088{
2089 return val < 0 || (val <= hi && val >= lo);
2090}
2091
2092static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
2093{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002094 struct port_info *pi = netdev_priv(dev);
2095 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002096 u32 cmd;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002097 int ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002098
2099 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
2100 return -EFAULT;
2101
2102 switch (cmd) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05002103 case CHELSIO_SET_QSET_PARAMS:{
2104 int i;
2105 struct qset_params *q;
2106 struct ch_qset_params t;
Divy Le Ray8c263762008-10-08 17:37:33 -07002107 int q1 = pi->first_qset;
2108 int nqsets = pi->nqsets;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002109
2110 if (!capable(CAP_NET_ADMIN))
2111 return -EPERM;
2112 if (copy_from_user(&t, useraddr, sizeof(t)))
2113 return -EFAULT;
2114 if (t.qset_idx >= SGE_QSETS)
2115 return -EINVAL;
2116 if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
Joe Perches8e95a202009-12-03 07:58:21 +00002117 !in_range(t.cong_thres, 0, 255) ||
2118 !in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
2119 MAX_TXQ_ENTRIES) ||
2120 !in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
2121 MAX_TXQ_ENTRIES) ||
2122 !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
2123 MAX_CTRL_TXQ_ENTRIES) ||
2124 !in_range(t.fl_size[0], MIN_FL_ENTRIES,
2125 MAX_RX_BUFFERS) ||
2126 !in_range(t.fl_size[1], MIN_FL_ENTRIES,
2127 MAX_RX_JUMBO_BUFFERS) ||
2128 !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
2129 MAX_RSPQ_ENTRIES))
Divy Le Ray4d22de32007-01-18 22:04:14 -05002130 return -EINVAL;
Divy Le Ray8c263762008-10-08 17:37:33 -07002131
2132 if ((adapter->flags & FULL_INIT_DONE) && t.lro > 0)
2133 for_each_port(adapter, i) {
2134 pi = adap2pinfo(adapter, i);
2135 if (t.qset_idx >= pi->first_qset &&
2136 t.qset_idx < pi->first_qset + pi->nqsets &&
Roland Dreier47fd23f2009-01-11 00:19:36 -08002137 !(pi->rx_offload & T3_RX_CSUM))
Divy Le Ray8c263762008-10-08 17:37:33 -07002138 return -EINVAL;
2139 }
2140
Divy Le Ray4d22de32007-01-18 22:04:14 -05002141 if ((adapter->flags & FULL_INIT_DONE) &&
2142 (t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
2143 t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
2144 t.txq_size[1] >= 0 || t.txq_size[2] >= 0 ||
2145 t.polling >= 0 || t.cong_thres >= 0))
2146 return -EBUSY;
2147
Divy Le Ray8c263762008-10-08 17:37:33 -07002148 /* Allow setting of any available qset when offload enabled */
2149 if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
2150 q1 = 0;
2151 for_each_port(adapter, i) {
2152 pi = adap2pinfo(adapter, i);
2153 nqsets += pi->first_qset + pi->nqsets;
2154 }
2155 }
2156
2157 if (t.qset_idx < q1)
2158 return -EINVAL;
2159 if (t.qset_idx > q1 + nqsets - 1)
2160 return -EINVAL;
2161
Divy Le Ray4d22de32007-01-18 22:04:14 -05002162 q = &adapter->params.sge.qset[t.qset_idx];
2163
2164 if (t.rspq_size >= 0)
2165 q->rspq_size = t.rspq_size;
2166 if (t.fl_size[0] >= 0)
2167 q->fl_size = t.fl_size[0];
2168 if (t.fl_size[1] >= 0)
2169 q->jumbo_size = t.fl_size[1];
2170 if (t.txq_size[0] >= 0)
2171 q->txq_size[0] = t.txq_size[0];
2172 if (t.txq_size[1] >= 0)
2173 q->txq_size[1] = t.txq_size[1];
2174 if (t.txq_size[2] >= 0)
2175 q->txq_size[2] = t.txq_size[2];
2176 if (t.cong_thres >= 0)
2177 q->cong_thres = t.cong_thres;
2178 if (t.intr_lat >= 0) {
2179 struct sge_qset *qs =
2180 &adapter->sge.qs[t.qset_idx];
2181
2182 q->coalesce_usecs = t.intr_lat;
2183 t3_update_qset_coalesce(qs, q);
2184 }
2185 if (t.polling >= 0) {
2186 if (adapter->flags & USING_MSIX)
2187 q->polling = t.polling;
2188 else {
2189 /* No polling with INTx for T3A */
2190 if (adapter->params.rev == 0 &&
2191 !(adapter->flags & USING_MSI))
2192 t.polling = 0;
2193
2194 for (i = 0; i < SGE_QSETS; i++) {
2195 q = &adapter->params.sge.
2196 qset[i];
2197 q->polling = t.polling;
2198 }
2199 }
2200 }
Divy Le Ray04ecb072008-10-28 22:40:32 -07002201 if (t.lro >= 0)
2202 set_qset_lro(dev, t.qset_idx, t.lro);
2203
Divy Le Ray4d22de32007-01-18 22:04:14 -05002204 break;
2205 }
2206 case CHELSIO_GET_QSET_PARAMS:{
2207 struct qset_params *q;
2208 struct ch_qset_params t;
Divy Le Ray8c263762008-10-08 17:37:33 -07002209 int q1 = pi->first_qset;
2210 int nqsets = pi->nqsets;
2211 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002212
2213 if (copy_from_user(&t, useraddr, sizeof(t)))
2214 return -EFAULT;
Divy Le Ray8c263762008-10-08 17:37:33 -07002215
2216 /* Display qsets for all ports when offload enabled */
2217 if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
2218 q1 = 0;
2219 for_each_port(adapter, i) {
2220 pi = adap2pinfo(adapter, i);
2221 nqsets = pi->first_qset + pi->nqsets;
2222 }
2223 }
2224
2225 if (t.qset_idx >= nqsets)
Divy Le Ray4d22de32007-01-18 22:04:14 -05002226 return -EINVAL;
2227
Divy Le Ray8c263762008-10-08 17:37:33 -07002228 q = &adapter->params.sge.qset[q1 + t.qset_idx];
Divy Le Ray4d22de32007-01-18 22:04:14 -05002229 t.rspq_size = q->rspq_size;
2230 t.txq_size[0] = q->txq_size[0];
2231 t.txq_size[1] = q->txq_size[1];
2232 t.txq_size[2] = q->txq_size[2];
2233 t.fl_size[0] = q->fl_size;
2234 t.fl_size[1] = q->jumbo_size;
2235 t.polling = q->polling;
Divy Le Rayb47385b2008-05-21 18:56:26 -07002236 t.lro = q->lro;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002237 t.intr_lat = q->coalesce_usecs;
2238 t.cong_thres = q->cong_thres;
Divy Le Ray8c263762008-10-08 17:37:33 -07002239 t.qnum = q1;
2240
2241 if (adapter->flags & USING_MSIX)
2242 t.vector = adapter->msix_info[q1 + t.qset_idx + 1].vec;
2243 else
2244 t.vector = adapter->pdev->irq;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002245
2246 if (copy_to_user(useraddr, &t, sizeof(t)))
2247 return -EFAULT;
2248 break;
2249 }
2250 case CHELSIO_SET_QSET_NUM:{
2251 struct ch_reg edata;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002252 unsigned int i, first_qset = 0, other_qsets = 0;
2253
2254 if (!capable(CAP_NET_ADMIN))
2255 return -EPERM;
2256 if (adapter->flags & FULL_INIT_DONE)
2257 return -EBUSY;
2258 if (copy_from_user(&edata, useraddr, sizeof(edata)))
2259 return -EFAULT;
2260 if (edata.val < 1 ||
2261 (edata.val > 1 && !(adapter->flags & USING_MSIX)))
2262 return -EINVAL;
2263
2264 for_each_port(adapter, i)
2265 if (adapter->port[i] && adapter->port[i] != dev)
2266 other_qsets += adap2pinfo(adapter, i)->nqsets;
2267
2268 if (edata.val + other_qsets > SGE_QSETS)
2269 return -EINVAL;
2270
2271 pi->nqsets = edata.val;
2272
2273 for_each_port(adapter, i)
2274 if (adapter->port[i]) {
2275 pi = adap2pinfo(adapter, i);
2276 pi->first_qset = first_qset;
2277 first_qset += pi->nqsets;
2278 }
2279 break;
2280 }
2281 case CHELSIO_GET_QSET_NUM:{
2282 struct ch_reg edata;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002283
2284 edata.cmd = CHELSIO_GET_QSET_NUM;
2285 edata.val = pi->nqsets;
2286 if (copy_to_user(useraddr, &edata, sizeof(edata)))
2287 return -EFAULT;
2288 break;
2289 }
2290 case CHELSIO_LOAD_FW:{
2291 u8 *fw_data;
2292 struct ch_mem_range t;
2293
Alan Cox1b3aa7a2008-04-29 14:29:30 +01002294 if (!capable(CAP_SYS_RAWIO))
Divy Le Ray4d22de32007-01-18 22:04:14 -05002295 return -EPERM;
2296 if (copy_from_user(&t, useraddr, sizeof(t)))
2297 return -EFAULT;
Alan Cox1b3aa7a2008-04-29 14:29:30 +01002298 /* Check t.len sanity ? */
Divy Le Ray4d22de32007-01-18 22:04:14 -05002299 fw_data = kmalloc(t.len, GFP_KERNEL);
2300 if (!fw_data)
2301 return -ENOMEM;
2302
2303 if (copy_from_user
2304 (fw_data, useraddr + sizeof(t), t.len)) {
2305 kfree(fw_data);
2306 return -EFAULT;
2307 }
2308
2309 ret = t3_load_fw(adapter, fw_data, t.len);
2310 kfree(fw_data);
2311 if (ret)
2312 return ret;
2313 break;
2314 }
2315 case CHELSIO_SETMTUTAB:{
2316 struct ch_mtus m;
2317 int i;
2318
2319 if (!is_offload(adapter))
2320 return -EOPNOTSUPP;
2321 if (!capable(CAP_NET_ADMIN))
2322 return -EPERM;
2323 if (offload_running(adapter))
2324 return -EBUSY;
2325 if (copy_from_user(&m, useraddr, sizeof(m)))
2326 return -EFAULT;
2327 if (m.nmtus != NMTUS)
2328 return -EINVAL;
2329 if (m.mtus[0] < 81) /* accommodate SACK */
2330 return -EINVAL;
2331
2332 /* MTUs must be in ascending order */
2333 for (i = 1; i < NMTUS; ++i)
2334 if (m.mtus[i] < m.mtus[i - 1])
2335 return -EINVAL;
2336
2337 memcpy(adapter->params.mtus, m.mtus,
2338 sizeof(adapter->params.mtus));
2339 break;
2340 }
2341 case CHELSIO_GET_PM:{
2342 struct tp_params *p = &adapter->params.tp;
2343 struct ch_pm m = {.cmd = CHELSIO_GET_PM };
2344
2345 if (!is_offload(adapter))
2346 return -EOPNOTSUPP;
2347 m.tx_pg_sz = p->tx_pg_size;
2348 m.tx_num_pg = p->tx_num_pgs;
2349 m.rx_pg_sz = p->rx_pg_size;
2350 m.rx_num_pg = p->rx_num_pgs;
2351 m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan;
2352 if (copy_to_user(useraddr, &m, sizeof(m)))
2353 return -EFAULT;
2354 break;
2355 }
2356 case CHELSIO_SET_PM:{
2357 struct ch_pm m;
2358 struct tp_params *p = &adapter->params.tp;
2359
2360 if (!is_offload(adapter))
2361 return -EOPNOTSUPP;
2362 if (!capable(CAP_NET_ADMIN))
2363 return -EPERM;
2364 if (adapter->flags & FULL_INIT_DONE)
2365 return -EBUSY;
2366 if (copy_from_user(&m, useraddr, sizeof(m)))
2367 return -EFAULT;
vignesh babud9da4662007-07-09 11:50:22 -07002368 if (!is_power_of_2(m.rx_pg_sz) ||
2369 !is_power_of_2(m.tx_pg_sz))
Divy Le Ray4d22de32007-01-18 22:04:14 -05002370 return -EINVAL; /* not power of 2 */
2371 if (!(m.rx_pg_sz & 0x14000))
2372 return -EINVAL; /* not 16KB or 64KB */
2373 if (!(m.tx_pg_sz & 0x1554000))
2374 return -EINVAL;
2375 if (m.tx_num_pg == -1)
2376 m.tx_num_pg = p->tx_num_pgs;
2377 if (m.rx_num_pg == -1)
2378 m.rx_num_pg = p->rx_num_pgs;
2379 if (m.tx_num_pg % 24 || m.rx_num_pg % 24)
2380 return -EINVAL;
2381 if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size ||
2382 m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size)
2383 return -EINVAL;
2384 p->rx_pg_size = m.rx_pg_sz;
2385 p->tx_pg_size = m.tx_pg_sz;
2386 p->rx_num_pgs = m.rx_num_pg;
2387 p->tx_num_pgs = m.tx_num_pg;
2388 break;
2389 }
2390 case CHELSIO_GET_MEM:{
2391 struct ch_mem_range t;
2392 struct mc7 *mem;
2393 u64 buf[32];
2394
2395 if (!is_offload(adapter))
2396 return -EOPNOTSUPP;
2397 if (!(adapter->flags & FULL_INIT_DONE))
2398 return -EIO; /* need the memory controllers */
2399 if (copy_from_user(&t, useraddr, sizeof(t)))
2400 return -EFAULT;
2401 if ((t.addr & 7) || (t.len & 7))
2402 return -EINVAL;
2403 if (t.mem_id == MEM_CM)
2404 mem = &adapter->cm;
2405 else if (t.mem_id == MEM_PMRX)
2406 mem = &adapter->pmrx;
2407 else if (t.mem_id == MEM_PMTX)
2408 mem = &adapter->pmtx;
2409 else
2410 return -EINVAL;
2411
2412 /*
Divy Le Ray18254942007-02-24 16:43:56 -08002413 * Version scheme:
2414 * bits 0..9: chip version
2415 * bits 10..15: chip revision
2416 */
Divy Le Ray4d22de32007-01-18 22:04:14 -05002417 t.version = 3 | (adapter->params.rev << 10);
2418 if (copy_to_user(useraddr, &t, sizeof(t)))
2419 return -EFAULT;
2420
2421 /*
2422 * Read 256 bytes at a time as len can be large and we don't
2423 * want to use huge intermediate buffers.
2424 */
2425 useraddr += sizeof(t); /* advance to start of buffer */
2426 while (t.len) {
2427 unsigned int chunk =
2428 min_t(unsigned int, t.len, sizeof(buf));
2429
2430 ret =
2431 t3_mc7_bd_read(mem, t.addr / 8, chunk / 8,
2432 buf);
2433 if (ret)
2434 return ret;
2435 if (copy_to_user(useraddr, buf, chunk))
2436 return -EFAULT;
2437 useraddr += chunk;
2438 t.addr += chunk;
2439 t.len -= chunk;
2440 }
2441 break;
2442 }
2443 case CHELSIO_SET_TRACE_FILTER:{
2444 struct ch_trace t;
2445 const struct trace_params *tp;
2446
2447 if (!capable(CAP_NET_ADMIN))
2448 return -EPERM;
2449 if (!offload_running(adapter))
2450 return -EAGAIN;
2451 if (copy_from_user(&t, useraddr, sizeof(t)))
2452 return -EFAULT;
2453
2454 tp = (const struct trace_params *)&t.sip;
2455 if (t.config_tx)
2456 t3_config_trace_filter(adapter, tp, 0,
2457 t.invert_match,
2458 t.trace_tx);
2459 if (t.config_rx)
2460 t3_config_trace_filter(adapter, tp, 1,
2461 t.invert_match,
2462 t.trace_rx);
2463 break;
2464 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002465 default:
2466 return -EOPNOTSUPP;
2467 }
2468 return 0;
2469}
2470
2471static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
2472{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002473 struct mii_ioctl_data *data = if_mii(req);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002474 struct port_info *pi = netdev_priv(dev);
2475 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002476
2477 switch (cmd) {
Ben Hutchings0f07c4e2009-04-29 08:07:20 +00002478 case SIOCGMIIREG:
2479 case SIOCSMIIREG:
2480 /* Convert phy_id from older PRTAD/DEVAD format */
2481 if (is_10G(adapter) &&
2482 !mdio_phy_id_is_c45(data->phy_id) &&
2483 (data->phy_id & 0x1f00) &&
2484 !(data->phy_id & 0xe0e0))
2485 data->phy_id = mdio_phy_id_c45(data->phy_id >> 8,
2486 data->phy_id & 0x1f);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002487 /* FALLTHRU */
Ben Hutchings0f07c4e2009-04-29 08:07:20 +00002488 case SIOCGMIIPHY:
2489 return mdio_mii_ioctl(&pi->phy.mdio, data, cmd);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002490 case SIOCCHIOCTL:
2491 return cxgb_extension_ioctl(dev, req->ifr_data);
2492 default:
2493 return -EOPNOTSUPP;
2494 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002495}
2496
2497static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
2498{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002499 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002500 struct adapter *adapter = pi->adapter;
2501 int ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002502
2503 if (new_mtu < 81) /* accommodate SACK */
2504 return -EINVAL;
2505 if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu)))
2506 return ret;
2507 dev->mtu = new_mtu;
2508 init_port_mtus(adapter);
2509 if (adapter->params.rev == 0 && offload_running(adapter))
2510 t3_load_mtus(adapter, adapter->params.mtus,
2511 adapter->params.a_wnd, adapter->params.b_wnd,
2512 adapter->port[0]->mtu);
2513 return 0;
2514}
2515
2516static int cxgb_set_mac_addr(struct net_device *dev, void *p)
2517{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002518 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002519 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002520 struct sockaddr *addr = p;
2521
2522 if (!is_valid_ether_addr(addr->sa_data))
2523 return -EINVAL;
2524
2525 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
Karen Xief14d42f2009-10-08 09:11:05 +00002526 t3_mac_set_address(&pi->mac, LAN_MAC_IDX, dev->dev_addr);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002527 if (offload_running(adapter))
2528 write_smt_entry(adapter, pi->port_id);
2529 return 0;
2530}
2531
2532/**
2533 * t3_synchronize_rx - wait for current Rx processing on a port to complete
2534 * @adap: the adapter
2535 * @p: the port
2536 *
2537 * Ensures that current Rx processing on any of the queues associated with
2538 * the given port completes before returning. We do this by acquiring and
2539 * releasing the locks of the response queues associated with the port.
2540 */
2541static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
2542{
2543 int i;
2544
Divy Le Ray8c263762008-10-08 17:37:33 -07002545 for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
2546 struct sge_rspq *q = &adap->sge.qs[i].rspq;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002547
2548 spin_lock_irq(&q->lock);
2549 spin_unlock_irq(&q->lock);
2550 }
2551}
2552
2553static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
2554{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002555 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002556 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002557
2558 pi->vlan_grp = grp;
2559 if (adapter->params.rev > 0)
2560 t3_set_vlan_accel(adapter, 1 << pi->port_id, grp != NULL);
2561 else {
2562 /* single control for all ports */
2563 unsigned int i, have_vlans = 0;
2564 for_each_port(adapter, i)
2565 have_vlans |= adap2pinfo(adapter, i)->vlan_grp != NULL;
2566
2567 t3_set_vlan_accel(adapter, 1, have_vlans);
2568 }
2569 t3_synchronize_rx(adapter, pi);
2570}
2571
Divy Le Ray4d22de32007-01-18 22:04:14 -05002572#ifdef CONFIG_NET_POLL_CONTROLLER
2573static void cxgb_netpoll(struct net_device *dev)
2574{
Divy Le Ray890de3322007-05-30 10:01:34 -07002575 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002576 struct adapter *adapter = pi->adapter;
Divy Le Ray890de3322007-05-30 10:01:34 -07002577 int qidx;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002578
Divy Le Ray890de3322007-05-30 10:01:34 -07002579 for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) {
2580 struct sge_qset *qs = &adapter->sge.qs[qidx];
2581 void *source;
Jeff Garzik2eab17a2007-11-23 21:59:45 -05002582
Divy Le Ray890de3322007-05-30 10:01:34 -07002583 if (adapter->flags & USING_MSIX)
2584 source = qs;
2585 else
2586 source = adapter;
2587
2588 t3_intr_handler(adapter, qs->rspq.polling) (0, source);
2589 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002590}
2591#endif
2592
2593/*
2594 * Periodic accumulation of MAC statistics.
2595 */
2596static void mac_stats_update(struct adapter *adapter)
2597{
2598 int i;
2599
2600 for_each_port(adapter, i) {
2601 struct net_device *dev = adapter->port[i];
2602 struct port_info *p = netdev_priv(dev);
2603
2604 if (netif_running(dev)) {
2605 spin_lock(&adapter->stats_lock);
2606 t3_mac_update_stats(&p->mac);
2607 spin_unlock(&adapter->stats_lock);
2608 }
2609 }
2610}
2611
2612static void check_link_status(struct adapter *adapter)
2613{
2614 int i;
2615
2616 for_each_port(adapter, i) {
2617 struct net_device *dev = adapter->port[i];
2618 struct port_info *p = netdev_priv(dev);
Divy Le Rayc22c8142009-05-28 11:23:08 +00002619 int link_fault;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002620
Divy Le Raybf792092009-03-12 21:14:19 +00002621 spin_lock_irq(&adapter->work_lock);
Divy Le Rayc22c8142009-05-28 11:23:08 +00002622 link_fault = p->link_fault;
2623 spin_unlock_irq(&adapter->work_lock);
2624
2625 if (link_fault) {
Divy Le Ray3851c662009-04-17 12:21:11 +00002626 t3_link_fault(adapter, i);
Divy Le Raybf792092009-03-12 21:14:19 +00002627 continue;
2628 }
Divy Le Raybf792092009-03-12 21:14:19 +00002629
2630 if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) {
2631 t3_xgm_intr_disable(adapter, i);
2632 t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
2633
Divy Le Ray4d22de32007-01-18 22:04:14 -05002634 t3_link_changed(adapter, i);
Divy Le Raybf792092009-03-12 21:14:19 +00002635 t3_xgm_intr_enable(adapter, i);
2636 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002637 }
2638}
2639
Divy Le Rayfc906642007-03-18 13:10:12 -07002640static void check_t3b2_mac(struct adapter *adapter)
2641{
2642 int i;
2643
Divy Le Rayf2d961c2007-04-09 20:10:22 -07002644 if (!rtnl_trylock()) /* synchronize with ifdown */
2645 return;
2646
Divy Le Rayfc906642007-03-18 13:10:12 -07002647 for_each_port(adapter, i) {
2648 struct net_device *dev = adapter->port[i];
2649 struct port_info *p = netdev_priv(dev);
2650 int status;
2651
2652 if (!netif_running(dev))
2653 continue;
2654
2655 status = 0;
Divy Le Ray6d6daba2007-03-31 00:23:24 -07002656 if (netif_running(dev) && netif_carrier_ok(dev))
Divy Le Rayfc906642007-03-18 13:10:12 -07002657 status = t3b2_mac_watchdog_task(&p->mac);
2658 if (status == 1)
2659 p->mac.stats.num_toggled++;
2660 else if (status == 2) {
2661 struct cmac *mac = &p->mac;
2662
2663 t3_mac_set_mtu(mac, dev->mtu);
Karen Xief14d42f2009-10-08 09:11:05 +00002664 t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr);
Divy Le Rayfc906642007-03-18 13:10:12 -07002665 cxgb_set_rxmode(dev);
2666 t3_link_start(&p->phy, mac, &p->link_config);
2667 t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
2668 t3_port_intr_enable(adapter, p->port_id);
2669 p->mac.stats.num_resets++;
2670 }
2671 }
2672 rtnl_unlock();
2673}
2674
2675
Divy Le Ray4d22de32007-01-18 22:04:14 -05002676static void t3_adap_check_task(struct work_struct *work)
2677{
2678 struct adapter *adapter = container_of(work, struct adapter,
2679 adap_check_task.work);
2680 const struct adapter_params *p = &adapter->params;
Divy Le Rayfc882192009-03-12 21:14:09 +00002681 int port;
2682 unsigned int v, status, reset;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002683
2684 adapter->check_task_cnt++;
2685
Divy Le Ray3851c662009-04-17 12:21:11 +00002686 check_link_status(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002687
2688 /* Accumulate MAC stats if needed */
2689 if (!p->linkpoll_period ||
2690 (adapter->check_task_cnt * p->linkpoll_period) / 10 >=
2691 p->stats_update_period) {
2692 mac_stats_update(adapter);
2693 adapter->check_task_cnt = 0;
2694 }
2695
Divy Le Rayfc906642007-03-18 13:10:12 -07002696 if (p->rev == T3_REV_B2)
2697 check_t3b2_mac(adapter);
2698
Divy Le Rayfc882192009-03-12 21:14:09 +00002699 /*
2700 * Scan the XGMAC's to check for various conditions which we want to
2701 * monitor in a periodic polling manner rather than via an interrupt
2702 * condition. This is used for conditions which would otherwise flood
2703 * the system with interrupts and we only really need to know that the
2704 * conditions are "happening" ... For each condition we count the
2705 * detection of the condition and reset it for the next polling loop.
2706 */
2707 for_each_port(adapter, port) {
2708 struct cmac *mac = &adap2pinfo(adapter, port)->mac;
2709 u32 cause;
2710
2711 cause = t3_read_reg(adapter, A_XGM_INT_CAUSE + mac->offset);
2712 reset = 0;
2713 if (cause & F_RXFIFO_OVERFLOW) {
2714 mac->stats.rx_fifo_ovfl++;
2715 reset |= F_RXFIFO_OVERFLOW;
2716 }
2717
2718 t3_write_reg(adapter, A_XGM_INT_CAUSE + mac->offset, reset);
2719 }
2720
2721 /*
2722 * We do the same as above for FL_EMPTY interrupts.
2723 */
2724 status = t3_read_reg(adapter, A_SG_INT_CAUSE);
2725 reset = 0;
2726
2727 if (status & F_FLEMPTY) {
2728 struct sge_qset *qs = &adapter->sge.qs[0];
2729 int i = 0;
2730
2731 reset |= F_FLEMPTY;
2732
2733 v = (t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS) >> S_FL0EMPTY) &
2734 0xffff;
2735
2736 while (v) {
2737 qs->fl[i].empty += (v & 1);
2738 if (i)
2739 qs++;
2740 i ^= 1;
2741 v >>= 1;
2742 }
2743 }
2744
2745 t3_write_reg(adapter, A_SG_INT_CAUSE, reset);
2746
Divy Le Ray4d22de32007-01-18 22:04:14 -05002747 /* Schedule the next check update if any port is active. */
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002748 spin_lock_irq(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002749 if (adapter->open_device_map & PORT_MASK)
2750 schedule_chk_task(adapter);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002751 spin_unlock_irq(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002752}
2753
2754/*
2755 * Processes external (PHY) interrupts in process context.
2756 */
2757static void ext_intr_task(struct work_struct *work)
2758{
2759 struct adapter *adapter = container_of(work, struct adapter,
2760 ext_intr_handler_task);
Divy Le Raybf792092009-03-12 21:14:19 +00002761 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002762
Divy Le Raybf792092009-03-12 21:14:19 +00002763 /* Disable link fault interrupts */
2764 for_each_port(adapter, i) {
2765 struct net_device *dev = adapter->port[i];
2766 struct port_info *p = netdev_priv(dev);
2767
2768 t3_xgm_intr_disable(adapter, i);
2769 t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
2770 }
2771
2772 /* Re-enable link fault interrupts */
Divy Le Ray4d22de32007-01-18 22:04:14 -05002773 t3_phy_intr_handler(adapter);
2774
Divy Le Raybf792092009-03-12 21:14:19 +00002775 for_each_port(adapter, i)
2776 t3_xgm_intr_enable(adapter, i);
2777
Divy Le Ray4d22de32007-01-18 22:04:14 -05002778 /* Now reenable external interrupts */
2779 spin_lock_irq(&adapter->work_lock);
2780 if (adapter->slow_intr_mask) {
2781 adapter->slow_intr_mask |= F_T3DBG;
2782 t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG);
2783 t3_write_reg(adapter, A_PL_INT_ENABLE0,
2784 adapter->slow_intr_mask);
2785 }
2786 spin_unlock_irq(&adapter->work_lock);
2787}
2788
2789/*
2790 * Interrupt-context handler for external (PHY) interrupts.
2791 */
2792void t3_os_ext_intr_handler(struct adapter *adapter)
2793{
2794 /*
2795 * Schedule a task to handle external interrupts as they may be slow
2796 * and we use a mutex to protect MDIO registers. We disable PHY
2797 * interrupts in the meantime and let the task reenable them when
2798 * it's done.
2799 */
2800 spin_lock(&adapter->work_lock);
2801 if (adapter->slow_intr_mask) {
2802 adapter->slow_intr_mask &= ~F_T3DBG;
2803 t3_write_reg(adapter, A_PL_INT_ENABLE0,
2804 adapter->slow_intr_mask);
2805 queue_work(cxgb3_wq, &adapter->ext_intr_handler_task);
2806 }
2807 spin_unlock(&adapter->work_lock);
2808}
2809
Divy Le Raybf792092009-03-12 21:14:19 +00002810void t3_os_link_fault_handler(struct adapter *adapter, int port_id)
2811{
2812 struct net_device *netdev = adapter->port[port_id];
2813 struct port_info *pi = netdev_priv(netdev);
2814
2815 spin_lock(&adapter->work_lock);
2816 pi->link_fault = 1;
Divy Le Raybf792092009-03-12 21:14:19 +00002817 spin_unlock(&adapter->work_lock);
2818}
2819
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002820static int t3_adapter_error(struct adapter *adapter, int reset)
2821{
2822 int i, ret = 0;
2823
Divy Le Raycb0bc202009-01-26 22:21:59 -08002824 if (is_offload(adapter) &&
2825 test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
Steve Wisefa0d4c12009-09-05 20:22:38 -07002826 cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_DOWN, 0);
Divy Le Raycb0bc202009-01-26 22:21:59 -08002827 offload_close(&adapter->tdev);
2828 }
2829
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002830 /* Stop all ports */
2831 for_each_port(adapter, i) {
2832 struct net_device *netdev = adapter->port[i];
2833
2834 if (netif_running(netdev))
2835 cxgb_close(netdev);
2836 }
2837
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002838 /* Stop SGE timers */
2839 t3_stop_sge_timers(adapter);
2840
2841 adapter->flags &= ~FULL_INIT_DONE;
2842
2843 if (reset)
2844 ret = t3_reset_adapter(adapter);
2845
2846 pci_disable_device(adapter->pdev);
2847
2848 return ret;
2849}
2850
2851static int t3_reenable_adapter(struct adapter *adapter)
2852{
2853 if (pci_enable_device(adapter->pdev)) {
2854 dev_err(&adapter->pdev->dev,
2855 "Cannot re-enable PCI device after reset.\n");
2856 goto err;
2857 }
2858 pci_set_master(adapter->pdev);
2859 pci_restore_state(adapter->pdev);
Breno Leitaoccdddf52009-12-10 09:03:37 +00002860 pci_save_state(adapter->pdev);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002861
2862 /* Free sge resources */
2863 t3_free_sge_resources(adapter);
2864
2865 if (t3_replay_prep_adapter(adapter))
2866 goto err;
2867
2868 return 0;
2869err:
2870 return -1;
2871}
2872
2873static void t3_resume_ports(struct adapter *adapter)
2874{
2875 int i;
2876
2877 /* Restart the ports */
2878 for_each_port(adapter, i) {
2879 struct net_device *netdev = adapter->port[i];
2880
2881 if (netif_running(netdev)) {
2882 if (cxgb_open(netdev)) {
2883 dev_err(&adapter->pdev->dev,
2884 "can't bring device back up"
2885 " after reset\n");
2886 continue;
2887 }
2888 }
2889 }
Divy Le Raycb0bc202009-01-26 22:21:59 -08002890
2891 if (is_offload(adapter) && !ofld_disable)
Steve Wisefa0d4c12009-09-05 20:22:38 -07002892 cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_UP, 0);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002893}
2894
2895/*
2896 * processes a fatal error.
2897 * Bring the ports down, reset the chip, bring the ports back up.
2898 */
2899static void fatal_error_task(struct work_struct *work)
2900{
2901 struct adapter *adapter = container_of(work, struct adapter,
2902 fatal_error_handler_task);
2903 int err = 0;
2904
2905 rtnl_lock();
2906 err = t3_adapter_error(adapter, 1);
2907 if (!err)
2908 err = t3_reenable_adapter(adapter);
2909 if (!err)
2910 t3_resume_ports(adapter);
2911
2912 CH_ALERT(adapter, "adapter reset %s\n", err ? "failed" : "succeeded");
2913 rtnl_unlock();
2914}
2915
Divy Le Ray4d22de32007-01-18 22:04:14 -05002916void t3_fatal_err(struct adapter *adapter)
2917{
2918 unsigned int fw_status[4];
2919
2920 if (adapter->flags & FULL_INIT_DONE) {
2921 t3_sge_stop(adapter);
Divy Le Rayc64c2ea2007-08-21 20:49:31 -07002922 t3_write_reg(adapter, A_XGM_TX_CTRL, 0);
2923 t3_write_reg(adapter, A_XGM_RX_CTRL, 0);
2924 t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0);
2925 t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002926
2927 spin_lock(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002928 t3_intr_disable(adapter);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002929 queue_work(cxgb3_wq, &adapter->fatal_error_handler_task);
2930 spin_unlock(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002931 }
2932 CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
2933 if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
2934 CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
2935 fw_status[0], fw_status[1],
2936 fw_status[2], fw_status[3]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002937}
2938
Divy Le Ray91a6b502007-11-16 11:21:55 -08002939/**
2940 * t3_io_error_detected - called when PCI error is detected
2941 * @pdev: Pointer to PCI device
2942 * @state: The current pci connection state
2943 *
2944 * This function is called after a PCI bus error affecting
2945 * this device has been detected.
2946 */
2947static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
2948 pci_channel_state_t state)
2949{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08002950 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002951 int ret;
Divy Le Ray91a6b502007-11-16 11:21:55 -08002952
Divy Le Raye8d19372009-04-17 12:21:27 +00002953 if (state == pci_channel_io_perm_failure)
2954 return PCI_ERS_RESULT_DISCONNECT;
2955
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002956 ret = t3_adapter_error(adapter, 0);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002957
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07002958 /* Request a slot reset. */
Divy Le Ray91a6b502007-11-16 11:21:55 -08002959 return PCI_ERS_RESULT_NEED_RESET;
2960}
2961
2962/**
2963 * t3_io_slot_reset - called after the pci bus has been reset.
2964 * @pdev: Pointer to PCI device
2965 *
2966 * Restart the card from scratch, as if from a cold-boot.
2967 */
2968static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev)
2969{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08002970 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002971
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002972 if (!t3_reenable_adapter(adapter))
2973 return PCI_ERS_RESULT_RECOVERED;
Divy Le Ray91a6b502007-11-16 11:21:55 -08002974
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07002975 return PCI_ERS_RESULT_DISCONNECT;
Divy Le Ray91a6b502007-11-16 11:21:55 -08002976}
2977
2978/**
2979 * t3_io_resume - called when traffic can start flowing again.
2980 * @pdev: Pointer to PCI device
2981 *
2982 * This callback is called when the error recovery driver tells us that
2983 * its OK to resume normal operation.
2984 */
2985static void t3_io_resume(struct pci_dev *pdev)
2986{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08002987 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002988
Divy Le Ray68f40c12009-03-26 16:39:19 +00002989 CH_ALERT(adapter, "adapter recovering, PEX ERR 0x%x\n",
2990 t3_read_reg(adapter, A_PCIE_PEX_ERR));
2991
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002992 t3_resume_ports(adapter);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002993}
2994
2995static struct pci_error_handlers t3_err_handler = {
2996 .error_detected = t3_io_error_detected,
2997 .slot_reset = t3_io_slot_reset,
2998 .resume = t3_io_resume,
2999};
3000
Divy Le Ray8c263762008-10-08 17:37:33 -07003001/*
3002 * Set the number of qsets based on the number of CPUs and the number of ports,
3003 * not to exceed the number of available qsets, assuming there are enough qsets
3004 * per port in HW.
3005 */
3006static void set_nqsets(struct adapter *adap)
3007{
3008 int i, j = 0;
3009 int num_cpus = num_online_cpus();
3010 int hwports = adap->params.nports;
Divy Le Ray5cda9362009-01-18 21:29:40 -08003011 int nqsets = adap->msix_nvectors - 1;
Divy Le Ray8c263762008-10-08 17:37:33 -07003012
Divy Le Rayf9ee3882008-11-09 00:55:33 -08003013 if (adap->params.rev > 0 && adap->flags & USING_MSIX) {
Divy Le Ray8c263762008-10-08 17:37:33 -07003014 if (hwports == 2 &&
3015 (hwports * nqsets > SGE_QSETS ||
3016 num_cpus >= nqsets / hwports))
3017 nqsets /= hwports;
3018 if (nqsets > num_cpus)
3019 nqsets = num_cpus;
3020 if (nqsets < 1 || hwports == 4)
3021 nqsets = 1;
3022 } else
3023 nqsets = 1;
3024
3025 for_each_port(adap, i) {
3026 struct port_info *pi = adap2pinfo(adap, i);
3027
3028 pi->first_qset = j;
3029 pi->nqsets = nqsets;
3030 j = pi->first_qset + nqsets;
3031
3032 dev_info(&adap->pdev->dev,
3033 "Port %d using %d queue sets.\n", i, nqsets);
3034 }
3035}
3036
Divy Le Ray4d22de32007-01-18 22:04:14 -05003037static int __devinit cxgb_enable_msix(struct adapter *adap)
3038{
3039 struct msix_entry entries[SGE_QSETS + 1];
Divy Le Ray5cda9362009-01-18 21:29:40 -08003040 int vectors;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003041 int i, err;
3042
Divy Le Ray5cda9362009-01-18 21:29:40 -08003043 vectors = ARRAY_SIZE(entries);
3044 for (i = 0; i < vectors; ++i)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003045 entries[i].entry = i;
3046
Divy Le Ray5cda9362009-01-18 21:29:40 -08003047 while ((err = pci_enable_msix(adap->pdev, entries, vectors)) > 0)
3048 vectors = err;
3049
Divy Le Ray2c2f4092009-04-17 12:21:22 +00003050 if (err < 0)
3051 pci_disable_msix(adap->pdev);
3052
3053 if (!err && vectors < (adap->params.nports + 1)) {
3054 pci_disable_msix(adap->pdev);
Divy Le Ray5cda9362009-01-18 21:29:40 -08003055 err = -1;
Divy Le Ray2c2f4092009-04-17 12:21:22 +00003056 }
Divy Le Ray5cda9362009-01-18 21:29:40 -08003057
Divy Le Ray4d22de32007-01-18 22:04:14 -05003058 if (!err) {
Divy Le Ray5cda9362009-01-18 21:29:40 -08003059 for (i = 0; i < vectors; ++i)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003060 adap->msix_info[i].vec = entries[i].vector;
Divy Le Ray5cda9362009-01-18 21:29:40 -08003061 adap->msix_nvectors = vectors;
3062 }
3063
Divy Le Ray4d22de32007-01-18 22:04:14 -05003064 return err;
3065}
3066
3067static void __devinit print_port_info(struct adapter *adap,
3068 const struct adapter_info *ai)
3069{
3070 static const char *pci_variant[] = {
3071 "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express"
3072 };
3073
3074 int i;
3075 char buf[80];
3076
3077 if (is_pcie(adap))
3078 snprintf(buf, sizeof(buf), "%s x%d",
3079 pci_variant[adap->params.pci.variant],
3080 adap->params.pci.width);
3081 else
3082 snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit",
3083 pci_variant[adap->params.pci.variant],
3084 adap->params.pci.speed, adap->params.pci.width);
3085
3086 for_each_port(adap, i) {
3087 struct net_device *dev = adap->port[i];
3088 const struct port_info *pi = netdev_priv(dev);
3089
3090 if (!test_bit(i, &adap->registered_device_map))
3091 continue;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07003092 printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n",
Divy Le Ray04497982008-10-08 17:38:29 -07003093 dev->name, ai->desc, pi->phy.desc,
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07003094 is_offload(adap) ? "R" : "", adap->params.rev, buf,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003095 (adap->flags & USING_MSIX) ? " MSI-X" :
3096 (adap->flags & USING_MSI) ? " MSI" : "");
3097 if (adap->name == dev->name && adap->params.vpd.mclk)
Divy Le Ray167cdf52007-08-21 20:49:36 -07003098 printk(KERN_INFO
3099 "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
Divy Le Ray4d22de32007-01-18 22:04:14 -05003100 adap->name, t3_mc7_size(&adap->cm) >> 20,
3101 t3_mc7_size(&adap->pmtx) >> 20,
Divy Le Ray167cdf52007-08-21 20:49:36 -07003102 t3_mc7_size(&adap->pmrx) >> 20,
3103 adap->params.vpd.sn);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003104 }
3105}
3106
Stephen Hemmingerdd752692008-11-19 22:15:39 -08003107static const struct net_device_ops cxgb_netdev_ops = {
3108 .ndo_open = cxgb_open,
3109 .ndo_stop = cxgb_close,
Divy Le Ray43a944f2008-11-26 15:35:26 -08003110 .ndo_start_xmit = t3_eth_xmit,
Stephen Hemmingerdd752692008-11-19 22:15:39 -08003111 .ndo_get_stats = cxgb_get_stats,
3112 .ndo_validate_addr = eth_validate_addr,
3113 .ndo_set_multicast_list = cxgb_set_rxmode,
3114 .ndo_do_ioctl = cxgb_ioctl,
3115 .ndo_change_mtu = cxgb_change_mtu,
3116 .ndo_set_mac_address = cxgb_set_mac_addr,
3117 .ndo_vlan_rx_register = vlan_rx_register,
3118#ifdef CONFIG_NET_POLL_CONTROLLER
3119 .ndo_poll_controller = cxgb_netpoll,
3120#endif
3121};
3122
Karen Xief14d42f2009-10-08 09:11:05 +00003123static void __devinit cxgb3_init_iscsi_mac(struct net_device *dev)
3124{
3125 struct port_info *pi = netdev_priv(dev);
3126
3127 memcpy(pi->iscsic.mac_addr, dev->dev_addr, ETH_ALEN);
3128 pi->iscsic.mac_addr[3] |= 0x80;
3129}
3130
Divy Le Ray4d22de32007-01-18 22:04:14 -05003131static int __devinit init_one(struct pci_dev *pdev,
3132 const struct pci_device_id *ent)
3133{
3134 static int version_printed;
3135
3136 int i, err, pci_using_dac = 0;
Divy Le Ray68f40c12009-03-26 16:39:19 +00003137 resource_size_t mmio_start, mmio_len;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003138 const struct adapter_info *ai;
3139 struct adapter *adapter = NULL;
3140 struct port_info *pi;
3141
3142 if (!version_printed) {
3143 printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
3144 ++version_printed;
3145 }
3146
3147 if (!cxgb3_wq) {
3148 cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
3149 if (!cxgb3_wq) {
3150 printk(KERN_ERR DRV_NAME
3151 ": cannot initialize work queue\n");
3152 return -ENOMEM;
3153 }
3154 }
3155
3156 err = pci_request_regions(pdev, DRV_NAME);
3157 if (err) {
3158 /* Just info, some other driver may have claimed the device. */
3159 dev_info(&pdev->dev, "cannot obtain PCI resources\n");
3160 return err;
3161 }
3162
3163 err = pci_enable_device(pdev);
3164 if (err) {
3165 dev_err(&pdev->dev, "cannot enable PCI device\n");
3166 goto out_release_regions;
3167 }
3168
Yang Hongyang6a355282009-04-06 19:01:13 -07003169 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003170 pci_using_dac = 1;
Yang Hongyang6a355282009-04-06 19:01:13 -07003171 err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
Divy Le Ray4d22de32007-01-18 22:04:14 -05003172 if (err) {
3173 dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
3174 "coherent allocations\n");
3175 goto out_disable_device;
3176 }
Yang Hongyang284901a2009-04-06 19:01:15 -07003177 } else if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003178 dev_err(&pdev->dev, "no usable DMA configuration\n");
3179 goto out_disable_device;
3180 }
3181
3182 pci_set_master(pdev);
Divy Le Ray204e2f92008-05-06 19:26:01 -07003183 pci_save_state(pdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003184
3185 mmio_start = pci_resource_start(pdev, 0);
3186 mmio_len = pci_resource_len(pdev, 0);
3187 ai = t3_get_adapter_info(ent->driver_data);
3188
3189 adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
3190 if (!adapter) {
3191 err = -ENOMEM;
3192 goto out_disable_device;
3193 }
3194
Divy Le Ray74b793e2009-06-09 23:25:21 +00003195 adapter->nofail_skb =
3196 alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_KERNEL);
3197 if (!adapter->nofail_skb) {
3198 dev_err(&pdev->dev, "cannot allocate nofail buffer\n");
3199 err = -ENOMEM;
3200 goto out_free_adapter;
3201 }
3202
Divy Le Ray4d22de32007-01-18 22:04:14 -05003203 adapter->regs = ioremap_nocache(mmio_start, mmio_len);
3204 if (!adapter->regs) {
3205 dev_err(&pdev->dev, "cannot map device registers\n");
3206 err = -ENOMEM;
3207 goto out_free_adapter;
3208 }
3209
3210 adapter->pdev = pdev;
3211 adapter->name = pci_name(pdev);
3212 adapter->msg_enable = dflt_msg_enable;
3213 adapter->mmio_len = mmio_len;
3214
3215 mutex_init(&adapter->mdio_lock);
3216 spin_lock_init(&adapter->work_lock);
3217 spin_lock_init(&adapter->stats_lock);
3218
3219 INIT_LIST_HEAD(&adapter->adapter_list);
3220 INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07003221 INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003222 INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
3223
Divy Le Ray952cdf32009-03-26 16:39:24 +00003224 for (i = 0; i < ai->nports0 + ai->nports1; ++i) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003225 struct net_device *netdev;
3226
Divy Le Ray82ad3322008-12-16 01:09:39 -08003227 netdev = alloc_etherdev_mq(sizeof(struct port_info), SGE_QSETS);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003228 if (!netdev) {
3229 err = -ENOMEM;
3230 goto out_free_dev;
3231 }
3232
Divy Le Ray4d22de32007-01-18 22:04:14 -05003233 SET_NETDEV_DEV(netdev, &pdev->dev);
3234
3235 adapter->port[i] = netdev;
3236 pi = netdev_priv(netdev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003237 pi->adapter = adapter;
Roland Dreier47fd23f2009-01-11 00:19:36 -08003238 pi->rx_offload = T3_RX_CSUM | T3_LRO;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003239 pi->port_id = i;
3240 netif_carrier_off(netdev);
Divy Le Ray82ad3322008-12-16 01:09:39 -08003241 netif_tx_stop_all_queues(netdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003242 netdev->irq = pdev->irq;
3243 netdev->mem_start = mmio_start;
3244 netdev->mem_end = mmio_start + mmio_len - 1;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003245 netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
Herbert Xu7be2df42009-01-21 14:39:13 -08003246 netdev->features |= NETIF_F_GRO;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003247 if (pci_using_dac)
3248 netdev->features |= NETIF_F_HIGHDMA;
3249
3250 netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
Stephen Hemmingerdd752692008-11-19 22:15:39 -08003251 netdev->netdev_ops = &cxgb_netdev_ops;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003252 SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
3253 }
3254
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003255 pci_set_drvdata(pdev, adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003256 if (t3_prep_adapter(adapter, ai, 1) < 0) {
3257 err = -ENODEV;
3258 goto out_free_dev;
3259 }
Jeff Garzik2eab17a2007-11-23 21:59:45 -05003260
Divy Le Ray4d22de32007-01-18 22:04:14 -05003261 /*
3262 * The card is now ready to go. If any errors occur during device
3263 * registration we do not fail the whole card but rather proceed only
3264 * with the ports we manage to register successfully. However we must
3265 * register at least one net device.
3266 */
3267 for_each_port(adapter, i) {
3268 err = register_netdev(adapter->port[i]);
3269 if (err)
3270 dev_warn(&pdev->dev,
3271 "cannot register net device %s, skipping\n",
3272 adapter->port[i]->name);
3273 else {
3274 /*
3275 * Change the name we use for messages to the name of
3276 * the first successfully registered interface.
3277 */
3278 if (!adapter->registered_device_map)
3279 adapter->name = adapter->port[i]->name;
3280
3281 __set_bit(i, &adapter->registered_device_map);
3282 }
3283 }
3284 if (!adapter->registered_device_map) {
3285 dev_err(&pdev->dev, "could not register any net devices\n");
3286 goto out_free_dev;
3287 }
3288
Karen Xief14d42f2009-10-08 09:11:05 +00003289 for_each_port(adapter, i)
3290 cxgb3_init_iscsi_mac(adapter->port[i]);
3291
Divy Le Ray4d22de32007-01-18 22:04:14 -05003292 /* Driver's ready. Reflect it on LEDs */
3293 t3_led_ready(adapter);
3294
3295 if (is_offload(adapter)) {
3296 __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
3297 cxgb3_adapter_ofld(adapter);
3298 }
3299
3300 /* See what interrupts we'll be using */
3301 if (msi > 1 && cxgb_enable_msix(adapter) == 0)
3302 adapter->flags |= USING_MSIX;
3303 else if (msi > 0 && pci_enable_msi(pdev) == 0)
3304 adapter->flags |= USING_MSI;
3305
Divy Le Ray8c263762008-10-08 17:37:33 -07003306 set_nqsets(adapter);
3307
Divy Le Ray0ee8d332007-02-08 16:55:59 -08003308 err = sysfs_create_group(&adapter->port[0]->dev.kobj,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003309 &cxgb3_attr_group);
3310
3311 print_port_info(adapter, ai);
3312 return 0;
3313
3314out_free_dev:
3315 iounmap(adapter->regs);
Divy Le Ray952cdf32009-03-26 16:39:24 +00003316 for (i = ai->nports0 + ai->nports1 - 1; i >= 0; --i)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003317 if (adapter->port[i])
3318 free_netdev(adapter->port[i]);
3319
3320out_free_adapter:
3321 kfree(adapter);
3322
3323out_disable_device:
3324 pci_disable_device(pdev);
3325out_release_regions:
3326 pci_release_regions(pdev);
3327 pci_set_drvdata(pdev, NULL);
3328 return err;
3329}
3330
3331static void __devexit remove_one(struct pci_dev *pdev)
3332{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003333 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003334
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003335 if (adapter) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003336 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003337
3338 t3_sge_stop(adapter);
Divy Le Ray0ee8d332007-02-08 16:55:59 -08003339 sysfs_remove_group(&adapter->port[0]->dev.kobj,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003340 &cxgb3_attr_group);
3341
Divy Le Ray4d22de32007-01-18 22:04:14 -05003342 if (is_offload(adapter)) {
3343 cxgb3_adapter_unofld(adapter);
3344 if (test_bit(OFFLOAD_DEVMAP_BIT,
3345 &adapter->open_device_map))
3346 offload_close(&adapter->tdev);
3347 }
3348
Divy Le Ray67d92ab2007-11-16 11:21:50 -08003349 for_each_port(adapter, i)
3350 if (test_bit(i, &adapter->registered_device_map))
3351 unregister_netdev(adapter->port[i]);
3352
Divy Le Ray0ca41c02008-09-25 14:05:28 +00003353 t3_stop_sge_timers(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003354 t3_free_sge_resources(adapter);
3355 cxgb_disable_msi(adapter);
3356
Divy Le Ray4d22de32007-01-18 22:04:14 -05003357 for_each_port(adapter, i)
3358 if (adapter->port[i])
3359 free_netdev(adapter->port[i]);
3360
3361 iounmap(adapter->regs);
Divy Le Ray74b793e2009-06-09 23:25:21 +00003362 if (adapter->nofail_skb)
3363 kfree_skb(adapter->nofail_skb);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003364 kfree(adapter);
3365 pci_release_regions(pdev);
3366 pci_disable_device(pdev);
3367 pci_set_drvdata(pdev, NULL);
3368 }
3369}
3370
3371static struct pci_driver driver = {
3372 .name = DRV_NAME,
3373 .id_table = cxgb3_pci_tbl,
3374 .probe = init_one,
3375 .remove = __devexit_p(remove_one),
Divy Le Ray91a6b502007-11-16 11:21:55 -08003376 .err_handler = &t3_err_handler,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003377};
3378
3379static int __init cxgb3_init_module(void)
3380{
3381 int ret;
3382
3383 cxgb3_offload_init();
3384
3385 ret = pci_register_driver(&driver);
3386 return ret;
3387}
3388
3389static void __exit cxgb3_cleanup_module(void)
3390{
3391 pci_unregister_driver(&driver);
3392 if (cxgb3_wq)
3393 destroy_workqueue(cxgb3_wq);
3394}
3395
3396module_init(cxgb3_init_module);
3397module_exit(cxgb3_cleanup_module);