blob: 0b87fee023f5282f56c66c72f46736867e257157 [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>
Divy Le Ray4d22de32007-01-18 22:04:14 -050047#include <asm/uaccess.h>
48
49#include "common.h"
50#include "cxgb3_ioctl.h"
51#include "regs.h"
52#include "cxgb3_offload.h"
53#include "version.h"
54
55#include "cxgb3_ctl_defs.h"
56#include "t3_cpl.h"
57#include "firmware_exports.h"
58
59enum {
60 MAX_TXQ_ENTRIES = 16384,
61 MAX_CTRL_TXQ_ENTRIES = 1024,
62 MAX_RSPQ_ENTRIES = 16384,
63 MAX_RX_BUFFERS = 16384,
64 MAX_RX_JUMBO_BUFFERS = 16384,
65 MIN_TXQ_ENTRIES = 4,
66 MIN_CTRL_TXQ_ENTRIES = 4,
67 MIN_RSPQ_ENTRIES = 32,
68 MIN_FL_ENTRIES = 32
69};
70
71#define PORT_MASK ((1 << MAX_NPORTS) - 1)
72
73#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
74 NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
75 NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
76
77#define EEPROM_MAGIC 0x38E2F10C
78
Divy Le Ray678771d2007-11-16 14:26:44 -080079#define CH_DEVICE(devid, idx) \
80 { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx }
Divy Le Ray4d22de32007-01-18 22:04:14 -050081
82static const struct pci_device_id cxgb3_pci_tbl[] = {
Divy Le Ray678771d2007-11-16 14:26:44 -080083 CH_DEVICE(0x20, 0), /* PE9000 */
84 CH_DEVICE(0x21, 1), /* T302E */
85 CH_DEVICE(0x22, 2), /* T310E */
86 CH_DEVICE(0x23, 3), /* T320X */
87 CH_DEVICE(0x24, 1), /* T302X */
88 CH_DEVICE(0x25, 3), /* T320E */
89 CH_DEVICE(0x26, 2), /* T310X */
90 CH_DEVICE(0x30, 2), /* T3B10 */
91 CH_DEVICE(0x31, 3), /* T3B20 */
92 CH_DEVICE(0x32, 1), /* T3B02 */
Divy Le Rayce03aad2009-02-18 17:47:57 -080093 CH_DEVICE(0x35, 6), /* T3C20-derived T3C10 */
Divy Le Ray4d22de32007-01-18 22:04:14 -050094 {0,}
95};
96
97MODULE_DESCRIPTION(DRV_DESC);
98MODULE_AUTHOR("Chelsio Communications");
Divy Le Ray1d68e932007-01-30 19:44:35 -080099MODULE_LICENSE("Dual BSD/GPL");
Divy Le Ray4d22de32007-01-18 22:04:14 -0500100MODULE_VERSION(DRV_VERSION);
101MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl);
102
103static int dflt_msg_enable = DFLT_MSG_ENABLE;
104
105module_param(dflt_msg_enable, int, 0644);
106MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap");
107
108/*
109 * The driver uses the best interrupt scheme available on a platform in the
110 * order MSI-X, MSI, legacy pin interrupts. This parameter determines which
111 * of these schemes the driver may consider as follows:
112 *
113 * msi = 2: choose from among all three options
114 * msi = 1: only consider MSI and pin interrupts
115 * msi = 0: force pin interrupts
116 */
117static int msi = 2;
118
119module_param(msi, int, 0644);
120MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X");
121
122/*
123 * The driver enables offload as a default.
124 * To disable it, use ofld_disable = 1.
125 */
126
127static int ofld_disable = 0;
128
129module_param(ofld_disable, int, 0644);
130MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not");
131
132/*
133 * We have work elements that we need to cancel when an interface is taken
134 * down. Normally the work elements would be executed by keventd but that
135 * can deadlock because of linkwatch. If our close method takes the rtnl
136 * lock and linkwatch is ahead of our work elements in keventd, linkwatch
137 * will block keventd as it needs the rtnl lock, and we'll deadlock waiting
138 * for our work to complete. Get our own work queue to solve this.
139 */
140static struct workqueue_struct *cxgb3_wq;
141
142/**
143 * link_report - show link status and link speed/duplex
144 * @p: the port whose settings are to be reported
145 *
146 * Shows the link status, speed, and duplex of a port.
147 */
148static void link_report(struct net_device *dev)
149{
150 if (!netif_carrier_ok(dev))
151 printk(KERN_INFO "%s: link down\n", dev->name);
152 else {
153 const char *s = "10Mbps";
154 const struct port_info *p = netdev_priv(dev);
155
156 switch (p->link_config.speed) {
157 case SPEED_10000:
158 s = "10Gbps";
159 break;
160 case SPEED_1000:
161 s = "1000Mbps";
162 break;
163 case SPEED_100:
164 s = "100Mbps";
165 break;
166 }
167
168 printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s,
169 p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
170 }
171}
172
Divy Le Raybf792092009-03-12 21:14:19 +0000173void t3_os_link_fault(struct adapter *adap, int port_id, int state)
174{
175 struct net_device *dev = adap->port[port_id];
176 struct port_info *pi = netdev_priv(dev);
177
178 if (state == netif_carrier_ok(dev))
179 return;
180
181 if (state) {
182 struct cmac *mac = &pi->mac;
183
184 netif_carrier_on(dev);
185
186 /* Clear local faults */
187 t3_xgm_intr_disable(adap, pi->port_id);
188 t3_read_reg(adap, A_XGM_INT_STATUS +
189 pi->mac.offset);
190 t3_write_reg(adap,
191 A_XGM_INT_CAUSE + pi->mac.offset,
192 F_XGM_INT);
193
194 t3_set_reg_field(adap,
195 A_XGM_INT_ENABLE +
196 pi->mac.offset,
197 F_XGM_INT, F_XGM_INT);
198 t3_xgm_intr_enable(adap, pi->port_id);
199
200 t3_mac_enable(mac, MAC_DIRECTION_TX);
201 } else
202 netif_carrier_off(dev);
203
204 link_report(dev);
205}
206
Divy Le Ray4d22de32007-01-18 22:04:14 -0500207/**
208 * t3_os_link_changed - handle link status changes
209 * @adapter: the adapter associated with the link change
210 * @port_id: the port index whose limk status has changed
211 * @link_stat: the new status of the link
212 * @speed: the new speed setting
213 * @duplex: the new duplex setting
214 * @pause: the new flow-control setting
215 *
216 * This is the OS-dependent handler for link status changes. The OS
217 * neutral handler takes care of most of the processing for these events,
218 * then calls this handler for any OS-specific processing.
219 */
220void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
221 int speed, int duplex, int pause)
222{
223 struct net_device *dev = adapter->port[port_id];
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700224 struct port_info *pi = netdev_priv(dev);
225 struct cmac *mac = &pi->mac;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500226
227 /* Skip changes from disabled ports. */
228 if (!netif_running(dev))
229 return;
230
231 if (link_stat != netif_carrier_ok(dev)) {
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700232 if (link_stat) {
Divy Le Ray59cf8102007-04-09 20:10:27 -0700233 t3_mac_enable(mac, MAC_DIRECTION_RX);
Divy Le Raybf792092009-03-12 21:14:19 +0000234
235 /* Clear local faults */
236 t3_xgm_intr_disable(adapter, pi->port_id);
237 t3_read_reg(adapter, A_XGM_INT_STATUS +
238 pi->mac.offset);
239 t3_write_reg(adapter,
240 A_XGM_INT_CAUSE + pi->mac.offset,
241 F_XGM_INT);
242
243 t3_set_reg_field(adapter,
244 A_XGM_INT_ENABLE + pi->mac.offset,
245 F_XGM_INT, F_XGM_INT);
246 t3_xgm_intr_enable(adapter, pi->port_id);
247
Divy Le Ray4d22de32007-01-18 22:04:14 -0500248 netif_carrier_on(dev);
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700249 } else {
Divy Le Ray4d22de32007-01-18 22:04:14 -0500250 netif_carrier_off(dev);
Divy Le Raybf792092009-03-12 21:14:19 +0000251
252 t3_xgm_intr_disable(adapter, pi->port_id);
253 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
254 t3_set_reg_field(adapter,
255 A_XGM_INT_ENABLE + pi->mac.offset,
256 F_XGM_INT, 0);
257
258 if (is_10G(adapter))
259 pi->phy.ops->power_down(&pi->phy, 1);
260
261 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
Divy Le Ray59cf8102007-04-09 20:10:27 -0700262 t3_mac_disable(mac, MAC_DIRECTION_RX);
263 t3_link_start(&pi->phy, mac, &pi->link_config);
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700264 }
265
Divy Le Ray4d22de32007-01-18 22:04:14 -0500266 link_report(dev);
267 }
268}
269
Divy Le Ray1e882022008-10-08 17:40:07 -0700270/**
271 * t3_os_phymod_changed - handle PHY module changes
272 * @phy: the PHY reporting the module change
273 * @mod_type: new module type
274 *
275 * This is the OS-dependent handler for PHY module changes. It is
276 * invoked when a PHY module is removed or inserted for any OS-specific
277 * processing.
278 */
279void t3_os_phymod_changed(struct adapter *adap, int port_id)
280{
281 static const char *mod_str[] = {
282 NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown"
283 };
284
285 const struct net_device *dev = adap->port[port_id];
286 const struct port_info *pi = netdev_priv(dev);
287
288 if (pi->phy.modtype == phy_modtype_none)
289 printk(KERN_INFO "%s: PHY module unplugged\n", dev->name);
290 else
291 printk(KERN_INFO "%s: %s PHY module inserted\n", dev->name,
292 mod_str[pi->phy.modtype]);
293}
294
Divy Le Ray4d22de32007-01-18 22:04:14 -0500295static void cxgb_set_rxmode(struct net_device *dev)
296{
297 struct t3_rx_mode rm;
298 struct port_info *pi = netdev_priv(dev);
299
300 init_rx_mode(&rm, dev, dev->mc_list);
301 t3_mac_set_rx_mode(&pi->mac, &rm);
302}
303
304/**
305 * link_start - enable a port
306 * @dev: the device to enable
307 *
308 * Performs the MAC and PHY actions needed to enable a port.
309 */
310static void link_start(struct net_device *dev)
311{
312 struct t3_rx_mode rm;
313 struct port_info *pi = netdev_priv(dev);
314 struct cmac *mac = &pi->mac;
315
316 init_rx_mode(&rm, dev, dev->mc_list);
317 t3_mac_reset(mac);
318 t3_mac_set_mtu(mac, dev->mtu);
319 t3_mac_set_address(mac, 0, dev->dev_addr);
320 t3_mac_set_rx_mode(mac, &rm);
321 t3_link_start(&pi->phy, mac, &pi->link_config);
322 t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
323}
324
325static inline void cxgb_disable_msi(struct adapter *adapter)
326{
327 if (adapter->flags & USING_MSIX) {
328 pci_disable_msix(adapter->pdev);
329 adapter->flags &= ~USING_MSIX;
330 } else if (adapter->flags & USING_MSI) {
331 pci_disable_msi(adapter->pdev);
332 adapter->flags &= ~USING_MSI;
333 }
334}
335
336/*
337 * Interrupt handler for asynchronous events used with MSI-X.
338 */
339static irqreturn_t t3_async_intr_handler(int irq, void *cookie)
340{
341 t3_slow_intr_handler(cookie);
342 return IRQ_HANDLED;
343}
344
345/*
346 * Name the MSI-X interrupts.
347 */
348static void name_msix_vecs(struct adapter *adap)
349{
350 int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1;
351
352 snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
353 adap->msix_info[0].desc[n] = 0;
354
355 for_each_port(adap, j) {
356 struct net_device *d = adap->port[j];
357 const struct port_info *pi = netdev_priv(d);
358
359 for (i = 0; i < pi->nqsets; i++, msi_idx++) {
360 snprintf(adap->msix_info[msi_idx].desc, n,
Divy Le Ray8c263762008-10-08 17:37:33 -0700361 "%s-%d", d->name, pi->first_qset + i);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500362 adap->msix_info[msi_idx].desc[n] = 0;
363 }
Divy Le Ray8c263762008-10-08 17:37:33 -0700364 }
Divy Le Ray4d22de32007-01-18 22:04:14 -0500365}
366
367static int request_msix_data_irqs(struct adapter *adap)
368{
369 int i, j, err, qidx = 0;
370
371 for_each_port(adap, i) {
372 int nqsets = adap2pinfo(adap, i)->nqsets;
373
374 for (j = 0; j < nqsets; ++j) {
375 err = request_irq(adap->msix_info[qidx + 1].vec,
376 t3_intr_handler(adap,
377 adap->sge.qs[qidx].
378 rspq.polling), 0,
379 adap->msix_info[qidx + 1].desc,
380 &adap->sge.qs[qidx]);
381 if (err) {
382 while (--qidx >= 0)
383 free_irq(adap->msix_info[qidx + 1].vec,
384 &adap->sge.qs[qidx]);
385 return err;
386 }
387 qidx++;
388 }
389 }
390 return 0;
391}
392
Divy Le Ray8c263762008-10-08 17:37:33 -0700393static void free_irq_resources(struct adapter *adapter)
394{
395 if (adapter->flags & USING_MSIX) {
396 int i, n = 0;
397
398 free_irq(adapter->msix_info[0].vec, adapter);
399 for_each_port(adapter, i)
Divy Le Ray5cda9362009-01-18 21:29:40 -0800400 n += adap2pinfo(adapter, i)->nqsets;
Divy Le Ray8c263762008-10-08 17:37:33 -0700401
402 for (i = 0; i < n; ++i)
403 free_irq(adapter->msix_info[i + 1].vec,
404 &adapter->sge.qs[i]);
405 } else
406 free_irq(adapter->pdev->irq, adapter);
407}
408
Divy Le Rayb8819552007-12-17 18:47:31 -0800409static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
410 unsigned long n)
411{
412 int attempts = 5;
413
414 while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
415 if (!--attempts)
416 return -ETIMEDOUT;
417 msleep(10);
418 }
419 return 0;
420}
421
422static int init_tp_parity(struct adapter *adap)
423{
424 int i;
425 struct sk_buff *skb;
426 struct cpl_set_tcb_field *greq;
427 unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
428
429 t3_tp_set_offload_mode(adap, 1);
430
431 for (i = 0; i < 16; i++) {
432 struct cpl_smt_write_req *req;
433
434 skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
435 req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
436 memset(req, 0, sizeof(*req));
437 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
438 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
439 req->iff = i;
440 t3_mgmt_tx(adap, skb);
441 }
442
443 for (i = 0; i < 2048; i++) {
444 struct cpl_l2t_write_req *req;
445
446 skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
447 req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
448 memset(req, 0, sizeof(*req));
449 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
450 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
451 req->params = htonl(V_L2T_W_IDX(i));
452 t3_mgmt_tx(adap, skb);
453 }
454
455 for (i = 0; i < 2048; i++) {
456 struct cpl_rte_write_req *req;
457
458 skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
459 req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req));
460 memset(req, 0, sizeof(*req));
461 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
462 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
463 req->l2t_idx = htonl(V_L2T_W_IDX(i));
464 t3_mgmt_tx(adap, skb);
465 }
466
467 skb = alloc_skb(sizeof(*greq), GFP_KERNEL | __GFP_NOFAIL);
468 greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq));
469 memset(greq, 0, sizeof(*greq));
470 greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
471 OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
472 greq->mask = cpu_to_be64(1);
473 t3_mgmt_tx(adap, skb);
474
475 i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
476 t3_tp_set_offload_mode(adap, 0);
477 return i;
478}
479
Divy Le Ray4d22de32007-01-18 22:04:14 -0500480/**
481 * setup_rss - configure RSS
482 * @adap: the adapter
483 *
484 * Sets up RSS to distribute packets to multiple receive queues. We
485 * configure the RSS CPU lookup table to distribute to the number of HW
486 * receive queues, and the response queue lookup table to narrow that
487 * down to the response queues actually configured for each port.
488 * We always configure the RSS mapping for two ports since the mapping
489 * table has plenty of entries.
490 */
491static void setup_rss(struct adapter *adap)
492{
493 int i;
494 unsigned int nq0 = adap2pinfo(adap, 0)->nqsets;
495 unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1;
496 u8 cpus[SGE_QSETS + 1];
497 u16 rspq_map[RSS_TABLE_SIZE];
498
499 for (i = 0; i < SGE_QSETS; ++i)
500 cpus[i] = i;
501 cpus[SGE_QSETS] = 0xff; /* terminator */
502
503 for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
504 rspq_map[i] = i % nq0;
505 rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0;
506 }
507
508 t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
509 F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
Divy Le Raya2604be2007-11-16 11:22:16 -0800510 V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500511}
512
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700513static void init_napi(struct adapter *adap)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500514{
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700515 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500516
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700517 for (i = 0; i < SGE_QSETS; i++) {
518 struct sge_qset *qs = &adap->sge.qs[i];
Divy Le Ray4d22de32007-01-18 22:04:14 -0500519
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700520 if (qs->adap)
521 netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll,
522 64);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500523 }
Divy Le Ray48c4b6d2008-05-06 19:25:56 -0700524
525 /*
526 * netif_napi_add() can be called only once per napi_struct because it
527 * adds each new napi_struct to a list. Be careful not to call it a
528 * second time, e.g., during EEH recovery, by making a note of it.
529 */
530 adap->flags |= NAPI_INIT;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500531}
532
533/*
534 * Wait until all NAPI handlers are descheduled. This includes the handlers of
535 * both netdevices representing interfaces and the dummy ones for the extra
536 * queues.
537 */
538static void quiesce_rx(struct adapter *adap)
539{
540 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500541
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700542 for (i = 0; i < SGE_QSETS; i++)
543 if (adap->sge.qs[i].adap)
544 napi_disable(&adap->sge.qs[i].napi);
545}
Divy Le Ray4d22de32007-01-18 22:04:14 -0500546
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700547static void enable_all_napi(struct adapter *adap)
548{
549 int i;
550 for (i = 0; i < SGE_QSETS; i++)
551 if (adap->sge.qs[i].adap)
552 napi_enable(&adap->sge.qs[i].napi);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500553}
554
555/**
Divy Le Ray04ecb072008-10-28 22:40:32 -0700556 * set_qset_lro - Turn a queue set's LRO capability on and off
557 * @dev: the device the qset is attached to
558 * @qset_idx: the queue set index
559 * @val: the LRO switch
560 *
561 * Sets LRO on or off for a particular queue set.
562 * the device's features flag is updated to reflect the LRO
563 * capability when all queues belonging to the device are
564 * in the same state.
565 */
566static void set_qset_lro(struct net_device *dev, int qset_idx, int val)
567{
568 struct port_info *pi = netdev_priv(dev);
569 struct adapter *adapter = pi->adapter;
Divy Le Ray04ecb072008-10-28 22:40:32 -0700570
571 adapter->params.sge.qset[qset_idx].lro = !!val;
572 adapter->sge.qs[qset_idx].lro_enabled = !!val;
Divy Le Ray04ecb072008-10-28 22:40:32 -0700573}
574
575/**
Divy Le Ray4d22de32007-01-18 22:04:14 -0500576 * setup_sge_qsets - configure SGE Tx/Rx/response queues
577 * @adap: the adapter
578 *
579 * Determines how many sets of SGE queues to use and initializes them.
580 * We support multiple queue sets per port if we have MSI-X, otherwise
581 * just one queue set per port.
582 */
583static int setup_sge_qsets(struct adapter *adap)
584{
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700585 int i, j, err, irq_idx = 0, qset_idx = 0;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -0700586 unsigned int ntxq = SGE_TXQ_PER_SET;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500587
588 if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
589 irq_idx = -1;
590
591 for_each_port(adap, i) {
592 struct net_device *dev = adap->port[i];
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700593 struct port_info *pi = netdev_priv(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500594
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700595 pi->qs = &adap->sge.qs[pi->first_qset];
Divy Le Ray8c263762008-10-08 17:37:33 -0700596 for (j = pi->first_qset; j < pi->first_qset + pi->nqsets;
597 ++j, ++qset_idx) {
Roland Dreier47fd23f2009-01-11 00:19:36 -0800598 set_qset_lro(dev, qset_idx, pi->rx_offload & T3_LRO);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500599 err = t3_sge_alloc_qset(adap, qset_idx, 1,
600 (adap->flags & USING_MSIX) ? qset_idx + 1 :
601 irq_idx,
Divy Le Ray82ad3322008-12-16 01:09:39 -0800602 &adap->params.sge.qset[qset_idx], ntxq, dev,
603 netdev_get_tx_queue(dev, j));
Divy Le Ray4d22de32007-01-18 22:04:14 -0500604 if (err) {
605 t3_free_sge_resources(adap);
606 return err;
607 }
608 }
609 }
610
611 return 0;
612}
613
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800614static ssize_t attr_show(struct device *d, char *buf,
Divy Le Ray896392e2007-02-24 16:43:50 -0800615 ssize_t(*format) (struct net_device *, char *))
Divy Le Ray4d22de32007-01-18 22:04:14 -0500616{
617 ssize_t len;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500618
619 /* Synchronize with ioctls that may shut down the device */
620 rtnl_lock();
Divy Le Ray896392e2007-02-24 16:43:50 -0800621 len = (*format) (to_net_dev(d), buf);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500622 rtnl_unlock();
623 return len;
624}
625
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800626static ssize_t attr_store(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800627 const char *buf, size_t len,
Divy Le Ray896392e2007-02-24 16:43:50 -0800628 ssize_t(*set) (struct net_device *, unsigned int),
Divy Le Ray4d22de32007-01-18 22:04:14 -0500629 unsigned int min_val, unsigned int max_val)
630{
631 char *endp;
632 ssize_t ret;
633 unsigned int val;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500634
635 if (!capable(CAP_NET_ADMIN))
636 return -EPERM;
637
638 val = simple_strtoul(buf, &endp, 0);
639 if (endp == buf || val < min_val || val > max_val)
640 return -EINVAL;
641
642 rtnl_lock();
Divy Le Ray896392e2007-02-24 16:43:50 -0800643 ret = (*set) (to_net_dev(d), val);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500644 if (!ret)
645 ret = len;
646 rtnl_unlock();
647 return ret;
648}
649
650#define CXGB3_SHOW(name, val_expr) \
Divy Le Ray896392e2007-02-24 16:43:50 -0800651static ssize_t format_##name(struct net_device *dev, char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500652{ \
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700653 struct port_info *pi = netdev_priv(dev); \
654 struct adapter *adap = pi->adapter; \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500655 return sprintf(buf, "%u\n", val_expr); \
656} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800657static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
658 char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500659{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800660 return attr_show(d, buf, format_##name); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500661}
662
Divy Le Ray896392e2007-02-24 16:43:50 -0800663static ssize_t set_nfilters(struct net_device *dev, unsigned int val)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500664{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700665 struct port_info *pi = netdev_priv(dev);
666 struct adapter *adap = pi->adapter;
Divy Le Ray9f238482007-03-31 00:23:13 -0700667 int min_tids = is_offload(adap) ? MC5_MIN_TIDS : 0;
Divy Le Ray896392e2007-02-24 16:43:50 -0800668
Divy Le Ray4d22de32007-01-18 22:04:14 -0500669 if (adap->flags & FULL_INIT_DONE)
670 return -EBUSY;
671 if (val && adap->params.rev == 0)
672 return -EINVAL;
Divy Le Ray9f238482007-03-31 00:23:13 -0700673 if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
674 min_tids)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500675 return -EINVAL;
676 adap->params.mc5.nfilters = val;
677 return 0;
678}
679
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800680static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
681 const char *buf, size_t len)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500682{
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800683 return attr_store(d, buf, len, set_nfilters, 0, ~0);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500684}
685
Divy Le Ray896392e2007-02-24 16:43:50 -0800686static ssize_t set_nservers(struct net_device *dev, unsigned int val)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500687{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700688 struct port_info *pi = netdev_priv(dev);
689 struct adapter *adap = pi->adapter;
Divy Le Ray896392e2007-02-24 16:43:50 -0800690
Divy Le Ray4d22de32007-01-18 22:04:14 -0500691 if (adap->flags & FULL_INIT_DONE)
692 return -EBUSY;
Divy Le Ray9f238482007-03-31 00:23:13 -0700693 if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters -
694 MC5_MIN_TIDS)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500695 return -EINVAL;
696 adap->params.mc5.nservers = val;
697 return 0;
698}
699
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800700static ssize_t store_nservers(struct device *d, struct device_attribute *attr,
701 const char *buf, size_t len)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500702{
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800703 return attr_store(d, buf, len, set_nservers, 0, ~0);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500704}
705
706#define CXGB3_ATTR_R(name, val_expr) \
707CXGB3_SHOW(name, val_expr) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800708static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500709
710#define CXGB3_ATTR_RW(name, val_expr, store_method) \
711CXGB3_SHOW(name, val_expr) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800712static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500713
714CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));
715CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);
716CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);
717
718static struct attribute *cxgb3_attrs[] = {
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800719 &dev_attr_cam_size.attr,
720 &dev_attr_nfilters.attr,
721 &dev_attr_nservers.attr,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500722 NULL
723};
724
725static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
726
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800727static ssize_t tm_attr_show(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800728 char *buf, int sched)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500729{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700730 struct port_info *pi = netdev_priv(to_net_dev(d));
731 struct adapter *adap = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500732 unsigned int v, addr, bpt, cpt;
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700733 ssize_t len;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500734
735 addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
736 rtnl_lock();
737 t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
738 v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
739 if (sched & 1)
740 v >>= 16;
741 bpt = (v >> 8) & 0xff;
742 cpt = v & 0xff;
743 if (!cpt)
744 len = sprintf(buf, "disabled\n");
745 else {
746 v = (adap->params.vpd.cclk * 1000) / cpt;
747 len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125);
748 }
749 rtnl_unlock();
750 return len;
751}
752
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800753static ssize_t tm_attr_store(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800754 const char *buf, size_t len, int sched)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500755{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700756 struct port_info *pi = netdev_priv(to_net_dev(d));
757 struct adapter *adap = pi->adapter;
758 unsigned int val;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500759 char *endp;
760 ssize_t ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500761
762 if (!capable(CAP_NET_ADMIN))
763 return -EPERM;
764
765 val = simple_strtoul(buf, &endp, 0);
766 if (endp == buf || val > 10000000)
767 return -EINVAL;
768
769 rtnl_lock();
770 ret = t3_config_sched(adap, val, sched);
771 if (!ret)
772 ret = len;
773 rtnl_unlock();
774 return ret;
775}
776
777#define TM_ATTR(name, sched) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800778static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
779 char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500780{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800781 return tm_attr_show(d, buf, sched); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500782} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800783static ssize_t store_##name(struct device *d, struct device_attribute *attr, \
784 const char *buf, size_t len) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500785{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800786 return tm_attr_store(d, buf, len, sched); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500787} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800788static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500789
790TM_ATTR(sched0, 0);
791TM_ATTR(sched1, 1);
792TM_ATTR(sched2, 2);
793TM_ATTR(sched3, 3);
794TM_ATTR(sched4, 4);
795TM_ATTR(sched5, 5);
796TM_ATTR(sched6, 6);
797TM_ATTR(sched7, 7);
798
799static struct attribute *offload_attrs[] = {
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800800 &dev_attr_sched0.attr,
801 &dev_attr_sched1.attr,
802 &dev_attr_sched2.attr,
803 &dev_attr_sched3.attr,
804 &dev_attr_sched4.attr,
805 &dev_attr_sched5.attr,
806 &dev_attr_sched6.attr,
807 &dev_attr_sched7.attr,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500808 NULL
809};
810
811static struct attribute_group offload_attr_group = {.attrs = offload_attrs };
812
813/*
814 * Sends an sk_buff to an offload queue driver
815 * after dealing with any active network taps.
816 */
817static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
818{
819 int ret;
820
821 local_bh_disable();
822 ret = t3_offload_tx(tdev, skb);
823 local_bh_enable();
824 return ret;
825}
826
827static int write_smt_entry(struct adapter *adapter, int idx)
828{
829 struct cpl_smt_write_req *req;
830 struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);
831
832 if (!skb)
833 return -ENOMEM;
834
835 req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
836 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
837 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
838 req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */
839 req->iff = idx;
840 memset(req->src_mac1, 0, sizeof(req->src_mac1));
841 memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);
842 skb->priority = 1;
843 offload_tx(&adapter->tdev, skb);
844 return 0;
845}
846
847static int init_smt(struct adapter *adapter)
848{
849 int i;
850
851 for_each_port(adapter, i)
852 write_smt_entry(adapter, i);
853 return 0;
854}
855
856static void init_port_mtus(struct adapter *adapter)
857{
858 unsigned int mtus = adapter->port[0]->mtu;
859
860 if (adapter->port[1])
861 mtus |= adapter->port[1]->mtu << 16;
862 t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
863}
864
Divy Le Ray8c263762008-10-08 17:37:33 -0700865static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
Divy Le Ray14ab9892007-01-30 19:43:50 -0800866 int hi, int port)
867{
868 struct sk_buff *skb;
869 struct mngt_pktsched_wr *req;
Divy Le Ray8c263762008-10-08 17:37:33 -0700870 int ret;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800871
872 skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
873 req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
874 req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
875 req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
876 req->sched = sched;
877 req->idx = qidx;
878 req->min = lo;
879 req->max = hi;
880 req->binding = port;
Divy Le Ray8c263762008-10-08 17:37:33 -0700881 ret = t3_mgmt_tx(adap, skb);
882
883 return ret;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800884}
885
Divy Le Ray8c263762008-10-08 17:37:33 -0700886static int bind_qsets(struct adapter *adap)
Divy Le Ray14ab9892007-01-30 19:43:50 -0800887{
Divy Le Ray8c263762008-10-08 17:37:33 -0700888 int i, j, err = 0;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800889
890 for_each_port(adap, i) {
891 const struct port_info *pi = adap2pinfo(adap, i);
892
Divy Le Ray8c263762008-10-08 17:37:33 -0700893 for (j = 0; j < pi->nqsets; ++j) {
894 int ret = send_pktsched_cmd(adap, 1,
895 pi->first_qset + j, -1,
896 -1, i);
897 if (ret)
898 err = ret;
899 }
Divy Le Ray14ab9892007-01-30 19:43:50 -0800900 }
Divy Le Ray8c263762008-10-08 17:37:33 -0700901
902 return err;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800903}
904
Divy Le Ray851fd7b2008-11-26 15:38:36 -0800905#define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin"
906#define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin"
Divy Le Ray2e283962007-03-18 13:10:06 -0700907
908static int upgrade_fw(struct adapter *adap)
909{
910 int ret;
911 char buf[64];
912 const struct firmware *fw;
913 struct device *dev = &adap->pdev->dev;
914
915 snprintf(buf, sizeof(buf), FW_FNAME, FW_VERSION_MAJOR,
Divy Le Ray7f672cf2007-03-31 00:23:30 -0700916 FW_VERSION_MINOR, FW_VERSION_MICRO);
Divy Le Ray2e283962007-03-18 13:10:06 -0700917 ret = request_firmware(&fw, buf, dev);
918 if (ret < 0) {
919 dev_err(dev, "could not upgrade firmware: unable to load %s\n",
920 buf);
921 return ret;
922 }
923 ret = t3_load_fw(adap, fw->data, fw->size);
924 release_firmware(fw);
Divy Le Ray47330072007-08-29 19:15:52 -0700925
926 if (ret == 0)
927 dev_info(dev, "successful upgrade to firmware %d.%d.%d\n",
928 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
929 else
930 dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n",
931 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
Jeff Garzik2eab17a2007-11-23 21:59:45 -0500932
Divy Le Ray47330072007-08-29 19:15:52 -0700933 return ret;
934}
935
936static inline char t3rev2char(struct adapter *adapter)
937{
938 char rev = 0;
939
940 switch(adapter->params.rev) {
941 case T3_REV_B:
942 case T3_REV_B2:
943 rev = 'b';
944 break;
Divy Le Ray1aafee22007-09-05 15:58:36 -0700945 case T3_REV_C:
946 rev = 'c';
947 break;
Divy Le Ray47330072007-08-29 19:15:52 -0700948 }
949 return rev;
950}
951
Stephen Hemminger9265fab2007-10-08 16:22:29 -0700952static int update_tpsram(struct adapter *adap)
Divy Le Ray47330072007-08-29 19:15:52 -0700953{
954 const struct firmware *tpsram;
955 char buf[64];
956 struct device *dev = &adap->pdev->dev;
957 int ret;
958 char rev;
Jeff Garzik2eab17a2007-11-23 21:59:45 -0500959
Divy Le Ray47330072007-08-29 19:15:52 -0700960 rev = t3rev2char(adap);
961 if (!rev)
962 return 0;
963
964 snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
965 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
966
967 ret = request_firmware(&tpsram, buf, dev);
968 if (ret < 0) {
969 dev_err(dev, "could not load TP SRAM: unable to load %s\n",
970 buf);
971 return ret;
972 }
Jeff Garzik2eab17a2007-11-23 21:59:45 -0500973
Divy Le Ray47330072007-08-29 19:15:52 -0700974 ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
975 if (ret)
Jeff Garzik2eab17a2007-11-23 21:59:45 -0500976 goto release_tpsram;
Divy Le Ray47330072007-08-29 19:15:52 -0700977
978 ret = t3_set_proto_sram(adap, tpsram->data);
979 if (ret == 0)
980 dev_info(dev,
981 "successful update of protocol engine "
982 "to %d.%d.%d\n",
983 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
984 else
985 dev_err(dev, "failed to update of protocol engine %d.%d.%d\n",
986 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
987 if (ret)
988 dev_err(dev, "loading protocol SRAM failed\n");
989
990release_tpsram:
991 release_firmware(tpsram);
Jeff Garzik2eab17a2007-11-23 21:59:45 -0500992
Divy Le Ray2e283962007-03-18 13:10:06 -0700993 return ret;
994}
995
Divy Le Ray4d22de32007-01-18 22:04:14 -0500996/**
997 * cxgb_up - enable the adapter
998 * @adapter: adapter being enabled
999 *
1000 * Called when the first port is enabled, this function performs the
1001 * actions necessary to make an adapter operational, such as completing
1002 * the initialization of HW modules, and enabling interrupts.
1003 *
1004 * Must be called with the rtnl lock held.
1005 */
1006static int cxgb_up(struct adapter *adap)
1007{
Denis Chengc54f5c22007-07-18 15:24:49 +08001008 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001009
1010 if (!(adap->flags & FULL_INIT_DONE)) {
Divy Le Ray8207bef2008-12-16 01:51:47 -08001011 err = t3_check_fw_version(adap);
Divy Le Raya5a3b462007-09-05 15:58:09 -07001012 if (err == -EINVAL) {
Divy Le Ray2e283962007-03-18 13:10:06 -07001013 err = upgrade_fw(adap);
Divy Le Ray8207bef2008-12-16 01:51:47 -08001014 CH_WARN(adap, "FW upgrade to %d.%d.%d %s\n",
1015 FW_VERSION_MAJOR, FW_VERSION_MINOR,
1016 FW_VERSION_MICRO, err ? "failed" : "succeeded");
Divy Le Raya5a3b462007-09-05 15:58:09 -07001017 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001018
Divy Le Ray8207bef2008-12-16 01:51:47 -08001019 err = t3_check_tpsram_version(adap);
Divy Le Ray47330072007-08-29 19:15:52 -07001020 if (err == -EINVAL) {
1021 err = update_tpsram(adap);
Divy Le Ray8207bef2008-12-16 01:51:47 -08001022 CH_WARN(adap, "TP upgrade to %d.%d.%d %s\n",
1023 TP_VERSION_MAJOR, TP_VERSION_MINOR,
1024 TP_VERSION_MICRO, err ? "failed" : "succeeded");
Divy Le Ray47330072007-08-29 19:15:52 -07001025 }
1026
Divy Le Ray20d3fc12008-10-08 17:36:03 -07001027 /*
1028 * Clear interrupts now to catch errors if t3_init_hw fails.
1029 * We clear them again later as initialization may trigger
1030 * conditions that can interrupt.
1031 */
1032 t3_intr_clear(adap);
1033
Divy Le Ray4d22de32007-01-18 22:04:14 -05001034 err = t3_init_hw(adap, 0);
1035 if (err)
1036 goto out;
1037
Divy Le Rayb8819552007-12-17 18:47:31 -08001038 t3_set_reg_field(adap, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
Divy Le Ray6cdbd772007-04-09 20:10:33 -07001039 t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
Stephen Hemmingerbea33482007-10-03 16:41:36 -07001040
Divy Le Ray4d22de32007-01-18 22:04:14 -05001041 err = setup_sge_qsets(adap);
1042 if (err)
1043 goto out;
1044
1045 setup_rss(adap);
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001046 if (!(adap->flags & NAPI_INIT))
1047 init_napi(adap);
Divy Le Ray31563782009-03-26 16:39:09 +00001048
1049 t3_start_sge_timers(adap);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001050 adap->flags |= FULL_INIT_DONE;
1051 }
1052
1053 t3_intr_clear(adap);
1054
1055 if (adap->flags & USING_MSIX) {
1056 name_msix_vecs(adap);
1057 err = request_irq(adap->msix_info[0].vec,
1058 t3_async_intr_handler, 0,
1059 adap->msix_info[0].desc, adap);
1060 if (err)
1061 goto irq_err;
1062
Divy Le Ray42256f52007-11-16 11:21:39 -08001063 err = request_msix_data_irqs(adap);
1064 if (err) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001065 free_irq(adap->msix_info[0].vec, adap);
1066 goto irq_err;
1067 }
1068 } else if ((err = request_irq(adap->pdev->irq,
1069 t3_intr_handler(adap,
1070 adap->sge.qs[0].rspq.
1071 polling),
Thomas Gleixner2db63462007-02-14 00:33:20 -08001072 (adap->flags & USING_MSI) ?
1073 0 : IRQF_SHARED,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001074 adap->name, adap)))
1075 goto irq_err;
1076
Stephen Hemmingerbea33482007-10-03 16:41:36 -07001077 enable_all_napi(adap);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001078 t3_sge_start(adap);
1079 t3_intr_enable(adap);
Divy Le Ray14ab9892007-01-30 19:43:50 -08001080
Divy Le Rayb8819552007-12-17 18:47:31 -08001081 if (adap->params.rev >= T3_REV_C && !(adap->flags & TP_PARITY_INIT) &&
1082 is_offload(adap) && init_tp_parity(adap) == 0)
1083 adap->flags |= TP_PARITY_INIT;
1084
1085 if (adap->flags & TP_PARITY_INIT) {
1086 t3_write_reg(adap, A_TP_INT_CAUSE,
1087 F_CMCACHEPERR | F_ARPLUTPERR);
1088 t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff);
1089 }
1090
Divy Le Ray8c263762008-10-08 17:37:33 -07001091 if (!(adap->flags & QUEUES_BOUND)) {
1092 err = bind_qsets(adap);
1093 if (err) {
1094 CH_ERR(adap, "failed to bind qsets, err %d\n", err);
1095 t3_intr_disable(adap);
1096 free_irq_resources(adap);
1097 goto out;
1098 }
1099 adap->flags |= QUEUES_BOUND;
1100 }
Divy Le Ray14ab9892007-01-30 19:43:50 -08001101
Divy Le Ray4d22de32007-01-18 22:04:14 -05001102out:
1103 return err;
1104irq_err:
1105 CH_ERR(adap, "request_irq failed, err %d\n", err);
1106 goto out;
1107}
1108
1109/*
1110 * Release resources when all the ports and offloading have been stopped.
1111 */
1112static void cxgb_down(struct adapter *adapter)
1113{
1114 t3_sge_stop(adapter);
1115 spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */
1116 t3_intr_disable(adapter);
1117 spin_unlock_irq(&adapter->work_lock);
1118
Divy Le Ray8c263762008-10-08 17:37:33 -07001119 free_irq_resources(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001120 quiesce_rx(adapter);
Divy Le Rayc80b0c22009-04-17 12:21:17 +00001121 flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */
Divy Le Ray4d22de32007-01-18 22:04:14 -05001122}
1123
1124static void schedule_chk_task(struct adapter *adap)
1125{
1126 unsigned int timeo;
1127
1128 timeo = adap->params.linkpoll_period ?
1129 (HZ * adap->params.linkpoll_period) / 10 :
1130 adap->params.stats_update_period * HZ;
1131 if (timeo)
1132 queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo);
1133}
1134
1135static int offload_open(struct net_device *dev)
1136{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001137 struct port_info *pi = netdev_priv(dev);
1138 struct adapter *adapter = pi->adapter;
1139 struct t3cdev *tdev = dev2t3cdev(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001140 int adap_up = adapter->open_device_map & PORT_MASK;
Denis Chengc54f5c22007-07-18 15:24:49 +08001141 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001142
1143 if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
1144 return 0;
1145
1146 if (!adap_up && (err = cxgb_up(adapter)) < 0)
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001147 goto out;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001148
1149 t3_tp_set_offload_mode(adapter, 1);
1150 tdev->lldev = adapter->port[0];
1151 err = cxgb3_offload_activate(adapter);
1152 if (err)
1153 goto out;
1154
1155 init_port_mtus(adapter);
1156 t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
1157 adapter->params.b_wnd,
1158 adapter->params.rev == 0 ?
1159 adapter->port[0]->mtu : 0xffff);
1160 init_smt(adapter);
1161
Dan Noed96a51f2008-04-12 22:34:38 -04001162 if (sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group))
1163 dev_dbg(&dev->dev, "cannot create sysfs group\n");
Divy Le Ray4d22de32007-01-18 22:04:14 -05001164
1165 /* Call back all registered clients */
1166 cxgb3_add_clients(tdev);
1167
1168out:
1169 /* restore them in case the offload module has changed them */
1170 if (err) {
1171 t3_tp_set_offload_mode(adapter, 0);
1172 clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
1173 cxgb3_set_dummy_ops(tdev);
1174 }
1175 return err;
1176}
1177
1178static int offload_close(struct t3cdev *tdev)
1179{
1180 struct adapter *adapter = tdev2adap(tdev);
1181
1182 if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
1183 return 0;
1184
1185 /* Call back all registered clients */
1186 cxgb3_remove_clients(tdev);
1187
Divy Le Ray0ee8d332007-02-08 16:55:59 -08001188 sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001189
Divy Le Rayc80b0c22009-04-17 12:21:17 +00001190 /* Flush work scheduled while releasing TIDs */
1191 flush_scheduled_work();
1192
Divy Le Ray4d22de32007-01-18 22:04:14 -05001193 tdev->lldev = NULL;
1194 cxgb3_set_dummy_ops(tdev);
1195 t3_tp_set_offload_mode(adapter, 0);
1196 clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
1197
1198 if (!adapter->open_device_map)
1199 cxgb_down(adapter);
1200
1201 cxgb3_offload_deactivate(adapter);
1202 return 0;
1203}
1204
1205static int cxgb_open(struct net_device *dev)
1206{
Divy Le Ray4d22de32007-01-18 22:04:14 -05001207 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001208 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001209 int other_ports = adapter->open_device_map & PORT_MASK;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001210 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001211
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001212 if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001213 return err;
1214
1215 set_bit(pi->port_id, &adapter->open_device_map);
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07001216 if (is_offload(adapter) && !ofld_disable) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001217 err = offload_open(dev);
1218 if (err)
1219 printk(KERN_WARNING
1220 "Could not initialize offload capabilities\n");
1221 }
1222
Divy Le Ray82ad3322008-12-16 01:09:39 -08001223 dev->real_num_tx_queues = pi->nqsets;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001224 link_start(dev);
1225 t3_port_intr_enable(adapter, pi->port_id);
Divy Le Ray82ad3322008-12-16 01:09:39 -08001226 netif_tx_start_all_queues(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001227 if (!other_ports)
1228 schedule_chk_task(adapter);
1229
1230 return 0;
1231}
1232
1233static int cxgb_close(struct net_device *dev)
1234{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001235 struct port_info *pi = netdev_priv(dev);
1236 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001237
Divy Le Raye8d19372009-04-17 12:21:27 +00001238
1239 if (!adapter->open_device_map)
1240 return 0;
1241
Divy Le Raybf792092009-03-12 21:14:19 +00001242 /* Stop link fault interrupts */
1243 t3_xgm_intr_disable(adapter, pi->port_id);
1244 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
1245
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001246 t3_port_intr_disable(adapter, pi->port_id);
Divy Le Ray82ad3322008-12-16 01:09:39 -08001247 netif_tx_stop_all_queues(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001248 pi->phy.ops->power_down(&pi->phy, 1);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001249 netif_carrier_off(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001250 t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001251
Divy Le Ray20d3fc12008-10-08 17:36:03 -07001252 spin_lock_irq(&adapter->work_lock); /* sync with update task */
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001253 clear_bit(pi->port_id, &adapter->open_device_map);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07001254 spin_unlock_irq(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001255
1256 if (!(adapter->open_device_map & PORT_MASK))
Divy Le Rayc80b0c22009-04-17 12:21:17 +00001257 cancel_delayed_work_sync(&adapter->adap_check_task);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001258
1259 if (!adapter->open_device_map)
1260 cxgb_down(adapter);
1261
1262 return 0;
1263}
1264
1265static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
1266{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001267 struct port_info *pi = netdev_priv(dev);
1268 struct adapter *adapter = pi->adapter;
1269 struct net_device_stats *ns = &pi->netstats;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001270 const struct mac_stats *pstats;
1271
1272 spin_lock(&adapter->stats_lock);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001273 pstats = t3_mac_update_stats(&pi->mac);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001274 spin_unlock(&adapter->stats_lock);
1275
1276 ns->tx_bytes = pstats->tx_octets;
1277 ns->tx_packets = pstats->tx_frames;
1278 ns->rx_bytes = pstats->rx_octets;
1279 ns->rx_packets = pstats->rx_frames;
1280 ns->multicast = pstats->rx_mcast_frames;
1281
1282 ns->tx_errors = pstats->tx_underrun;
1283 ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs +
1284 pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short +
1285 pstats->rx_fifo_ovfl;
1286
1287 /* detailed rx_errors */
1288 ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long;
1289 ns->rx_over_errors = 0;
1290 ns->rx_crc_errors = pstats->rx_fcs_errs;
1291 ns->rx_frame_errors = pstats->rx_symbol_errs;
1292 ns->rx_fifo_errors = pstats->rx_fifo_ovfl;
1293 ns->rx_missed_errors = pstats->rx_cong_drops;
1294
1295 /* detailed tx_errors */
1296 ns->tx_aborted_errors = 0;
1297 ns->tx_carrier_errors = 0;
1298 ns->tx_fifo_errors = pstats->tx_underrun;
1299 ns->tx_heartbeat_errors = 0;
1300 ns->tx_window_errors = 0;
1301 return ns;
1302}
1303
1304static u32 get_msglevel(struct net_device *dev)
1305{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001306 struct port_info *pi = netdev_priv(dev);
1307 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001308
1309 return adapter->msg_enable;
1310}
1311
1312static void set_msglevel(struct net_device *dev, u32 val)
1313{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001314 struct port_info *pi = netdev_priv(dev);
1315 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001316
1317 adapter->msg_enable = val;
1318}
1319
1320static char stats_strings[][ETH_GSTRING_LEN] = {
1321 "TxOctetsOK ",
1322 "TxFramesOK ",
1323 "TxMulticastFramesOK",
1324 "TxBroadcastFramesOK",
1325 "TxPauseFrames ",
1326 "TxUnderrun ",
1327 "TxExtUnderrun ",
1328
1329 "TxFrames64 ",
1330 "TxFrames65To127 ",
1331 "TxFrames128To255 ",
1332 "TxFrames256To511 ",
1333 "TxFrames512To1023 ",
1334 "TxFrames1024To1518 ",
1335 "TxFrames1519ToMax ",
1336
1337 "RxOctetsOK ",
1338 "RxFramesOK ",
1339 "RxMulticastFramesOK",
1340 "RxBroadcastFramesOK",
1341 "RxPauseFrames ",
1342 "RxFCSErrors ",
1343 "RxSymbolErrors ",
1344 "RxShortErrors ",
1345 "RxJabberErrors ",
1346 "RxLengthErrors ",
1347 "RxFIFOoverflow ",
1348
1349 "RxFrames64 ",
1350 "RxFrames65To127 ",
1351 "RxFrames128To255 ",
1352 "RxFrames256To511 ",
1353 "RxFrames512To1023 ",
1354 "RxFrames1024To1518 ",
1355 "RxFrames1519ToMax ",
1356
1357 "PhyFIFOErrors ",
1358 "TSO ",
1359 "VLANextractions ",
1360 "VLANinsertions ",
1361 "TxCsumOffload ",
1362 "RxCsumGood ",
Divy Le Rayb47385b2008-05-21 18:56:26 -07001363 "LroAggregated ",
1364 "LroFlushed ",
1365 "LroNoDesc ",
Divy Le Rayfc906642007-03-18 13:10:12 -07001366 "RxDrops ",
1367
1368 "CheckTXEnToggled ",
1369 "CheckResets ",
1370
Divy Le Raybf792092009-03-12 21:14:19 +00001371 "LinkFaults ",
Divy Le Ray4d22de32007-01-18 22:04:14 -05001372};
1373
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001374static int get_sset_count(struct net_device *dev, int sset)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001375{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001376 switch (sset) {
1377 case ETH_SS_STATS:
1378 return ARRAY_SIZE(stats_strings);
1379 default:
1380 return -EOPNOTSUPP;
1381 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001382}
1383
1384#define T3_REGMAP_SIZE (3 * 1024)
1385
1386static int get_regs_len(struct net_device *dev)
1387{
1388 return T3_REGMAP_SIZE;
1389}
1390
1391static int get_eeprom_len(struct net_device *dev)
1392{
1393 return EEPROMSIZE;
1394}
1395
1396static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
1397{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001398 struct port_info *pi = netdev_priv(dev);
1399 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001400 u32 fw_vers = 0;
Divy Le Ray47330072007-08-29 19:15:52 -07001401 u32 tp_vers = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001402
Steve Wisecf3760d2008-11-06 17:06:42 -06001403 spin_lock(&adapter->stats_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001404 t3_get_fw_version(adapter, &fw_vers);
Divy Le Ray47330072007-08-29 19:15:52 -07001405 t3_get_tp_version(adapter, &tp_vers);
Steve Wisecf3760d2008-11-06 17:06:42 -06001406 spin_unlock(&adapter->stats_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001407
1408 strcpy(info->driver, DRV_NAME);
1409 strcpy(info->version, DRV_VERSION);
1410 strcpy(info->bus_info, pci_name(adapter->pdev));
1411 if (!fw_vers)
1412 strcpy(info->fw_version, "N/A");
Divy Le Ray4aac3892007-01-30 19:43:45 -08001413 else {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001414 snprintf(info->fw_version, sizeof(info->fw_version),
Divy Le Ray47330072007-08-29 19:15:52 -07001415 "%s %u.%u.%u TP %u.%u.%u",
Divy Le Ray4aac3892007-01-30 19:43:45 -08001416 G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
1417 G_FW_VERSION_MAJOR(fw_vers),
1418 G_FW_VERSION_MINOR(fw_vers),
Divy Le Ray47330072007-08-29 19:15:52 -07001419 G_FW_VERSION_MICRO(fw_vers),
1420 G_TP_VERSION_MAJOR(tp_vers),
1421 G_TP_VERSION_MINOR(tp_vers),
1422 G_TP_VERSION_MICRO(tp_vers));
Divy Le Ray4aac3892007-01-30 19:43:45 -08001423 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001424}
1425
1426static void get_strings(struct net_device *dev, u32 stringset, u8 * data)
1427{
1428 if (stringset == ETH_SS_STATS)
1429 memcpy(data, stats_strings, sizeof(stats_strings));
1430}
1431
1432static unsigned long collect_sge_port_stats(struct adapter *adapter,
1433 struct port_info *p, int idx)
1434{
1435 int i;
1436 unsigned long tot = 0;
1437
Divy Le Ray8c263762008-10-08 17:37:33 -07001438 for (i = p->first_qset; i < p->first_qset + p->nqsets; ++i)
1439 tot += adapter->sge.qs[i].port_stats[idx];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001440 return tot;
1441}
1442
1443static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
1444 u64 *data)
1445{
Divy Le Ray4d22de32007-01-18 22:04:14 -05001446 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001447 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001448 const struct mac_stats *s;
1449
1450 spin_lock(&adapter->stats_lock);
1451 s = t3_mac_update_stats(&pi->mac);
1452 spin_unlock(&adapter->stats_lock);
1453
1454 *data++ = s->tx_octets;
1455 *data++ = s->tx_frames;
1456 *data++ = s->tx_mcast_frames;
1457 *data++ = s->tx_bcast_frames;
1458 *data++ = s->tx_pause;
1459 *data++ = s->tx_underrun;
1460 *data++ = s->tx_fifo_urun;
1461
1462 *data++ = s->tx_frames_64;
1463 *data++ = s->tx_frames_65_127;
1464 *data++ = s->tx_frames_128_255;
1465 *data++ = s->tx_frames_256_511;
1466 *data++ = s->tx_frames_512_1023;
1467 *data++ = s->tx_frames_1024_1518;
1468 *data++ = s->tx_frames_1519_max;
1469
1470 *data++ = s->rx_octets;
1471 *data++ = s->rx_frames;
1472 *data++ = s->rx_mcast_frames;
1473 *data++ = s->rx_bcast_frames;
1474 *data++ = s->rx_pause;
1475 *data++ = s->rx_fcs_errs;
1476 *data++ = s->rx_symbol_errs;
1477 *data++ = s->rx_short;
1478 *data++ = s->rx_jabber;
1479 *data++ = s->rx_too_long;
1480 *data++ = s->rx_fifo_ovfl;
1481
1482 *data++ = s->rx_frames_64;
1483 *data++ = s->rx_frames_65_127;
1484 *data++ = s->rx_frames_128_255;
1485 *data++ = s->rx_frames_256_511;
1486 *data++ = s->rx_frames_512_1023;
1487 *data++ = s->rx_frames_1024_1518;
1488 *data++ = s->rx_frames_1519_max;
1489
1490 *data++ = pi->phy.fifo_errors;
1491
1492 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO);
1493 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX);
1494 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
1495 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
1496 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
Herbert Xu7be2df42009-01-21 14:39:13 -08001497 *data++ = 0;
1498 *data++ = 0;
1499 *data++ = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001500 *data++ = s->rx_cong_drops;
Divy Le Rayfc906642007-03-18 13:10:12 -07001501
1502 *data++ = s->num_toggled;
1503 *data++ = s->num_resets;
Divy Le Raybf792092009-03-12 21:14:19 +00001504
1505 *data++ = s->link_faults;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001506}
1507
1508static inline void reg_block_dump(struct adapter *ap, void *buf,
1509 unsigned int start, unsigned int end)
1510{
1511 u32 *p = buf + start;
1512
1513 for (; start <= end; start += sizeof(u32))
1514 *p++ = t3_read_reg(ap, start);
1515}
1516
1517static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
1518 void *buf)
1519{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001520 struct port_info *pi = netdev_priv(dev);
1521 struct adapter *ap = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001522
1523 /*
1524 * Version scheme:
1525 * bits 0..9: chip version
1526 * bits 10..15: chip revision
1527 * bit 31: set for PCIe cards
1528 */
1529 regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31);
1530
1531 /*
1532 * We skip the MAC statistics registers because they are clear-on-read.
1533 * Also reading multi-register stats would need to synchronize with the
1534 * periodic mac stats accumulation. Hard to justify the complexity.
1535 */
1536 memset(buf, 0, T3_REGMAP_SIZE);
1537 reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
1538 reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
1539 reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
1540 reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
1541 reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
1542 reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0,
1543 XGM_REG(A_XGM_SERDES_STAT3, 1));
1544 reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
1545 XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
1546}
1547
1548static int restart_autoneg(struct net_device *dev)
1549{
1550 struct port_info *p = netdev_priv(dev);
1551
1552 if (!netif_running(dev))
1553 return -EAGAIN;
1554 if (p->link_config.autoneg != AUTONEG_ENABLE)
1555 return -EINVAL;
1556 p->phy.ops->autoneg_restart(&p->phy);
1557 return 0;
1558}
1559
1560static int cxgb3_phys_id(struct net_device *dev, u32 data)
1561{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001562 struct port_info *pi = netdev_priv(dev);
1563 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001564 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001565
1566 if (data == 0)
1567 data = 2;
1568
1569 for (i = 0; i < data * 2; i++) {
1570 t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
1571 (i & 1) ? F_GPIO0_OUT_VAL : 0);
1572 if (msleep_interruptible(500))
1573 break;
1574 }
1575 t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
1576 F_GPIO0_OUT_VAL);
1577 return 0;
1578}
1579
1580static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1581{
1582 struct port_info *p = netdev_priv(dev);
1583
1584 cmd->supported = p->link_config.supported;
1585 cmd->advertising = p->link_config.advertising;
1586
1587 if (netif_carrier_ok(dev)) {
1588 cmd->speed = p->link_config.speed;
1589 cmd->duplex = p->link_config.duplex;
1590 } else {
1591 cmd->speed = -1;
1592 cmd->duplex = -1;
1593 }
1594
1595 cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
Ben Hutchings0f07c4e2009-04-29 08:07:20 +00001596 cmd->phy_address = p->phy.mdio.prtad;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001597 cmd->transceiver = XCVR_EXTERNAL;
1598 cmd->autoneg = p->link_config.autoneg;
1599 cmd->maxtxpkt = 0;
1600 cmd->maxrxpkt = 0;
1601 return 0;
1602}
1603
1604static int speed_duplex_to_caps(int speed, int duplex)
1605{
1606 int cap = 0;
1607
1608 switch (speed) {
1609 case SPEED_10:
1610 if (duplex == DUPLEX_FULL)
1611 cap = SUPPORTED_10baseT_Full;
1612 else
1613 cap = SUPPORTED_10baseT_Half;
1614 break;
1615 case SPEED_100:
1616 if (duplex == DUPLEX_FULL)
1617 cap = SUPPORTED_100baseT_Full;
1618 else
1619 cap = SUPPORTED_100baseT_Half;
1620 break;
1621 case SPEED_1000:
1622 if (duplex == DUPLEX_FULL)
1623 cap = SUPPORTED_1000baseT_Full;
1624 else
1625 cap = SUPPORTED_1000baseT_Half;
1626 break;
1627 case SPEED_10000:
1628 if (duplex == DUPLEX_FULL)
1629 cap = SUPPORTED_10000baseT_Full;
1630 }
1631 return cap;
1632}
1633
1634#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1635 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1636 ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
1637 ADVERTISED_10000baseT_Full)
1638
1639static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1640{
1641 struct port_info *p = netdev_priv(dev);
1642 struct link_config *lc = &p->link_config;
1643
Divy Le Ray9b1e3652008-10-08 17:39:31 -07001644 if (!(lc->supported & SUPPORTED_Autoneg)) {
1645 /*
1646 * PHY offers a single speed/duplex. See if that's what's
1647 * being requested.
1648 */
1649 if (cmd->autoneg == AUTONEG_DISABLE) {
Hannes Eder97915b52009-02-14 11:16:04 +00001650 int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
Divy Le Ray9b1e3652008-10-08 17:39:31 -07001651 if (lc->supported & cap)
1652 return 0;
1653 }
1654 return -EINVAL;
1655 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001656
1657 if (cmd->autoneg == AUTONEG_DISABLE) {
1658 int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
1659
1660 if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
1661 return -EINVAL;
1662 lc->requested_speed = cmd->speed;
1663 lc->requested_duplex = cmd->duplex;
1664 lc->advertising = 0;
1665 } else {
1666 cmd->advertising &= ADVERTISED_MASK;
1667 cmd->advertising &= lc->supported;
1668 if (!cmd->advertising)
1669 return -EINVAL;
1670 lc->requested_speed = SPEED_INVALID;
1671 lc->requested_duplex = DUPLEX_INVALID;
1672 lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
1673 }
1674 lc->autoneg = cmd->autoneg;
1675 if (netif_running(dev))
1676 t3_link_start(&p->phy, &p->mac, lc);
1677 return 0;
1678}
1679
1680static void get_pauseparam(struct net_device *dev,
1681 struct ethtool_pauseparam *epause)
1682{
1683 struct port_info *p = netdev_priv(dev);
1684
1685 epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
1686 epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0;
1687 epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0;
1688}
1689
1690static int set_pauseparam(struct net_device *dev,
1691 struct ethtool_pauseparam *epause)
1692{
1693 struct port_info *p = netdev_priv(dev);
1694 struct link_config *lc = &p->link_config;
1695
1696 if (epause->autoneg == AUTONEG_DISABLE)
1697 lc->requested_fc = 0;
1698 else if (lc->supported & SUPPORTED_Autoneg)
1699 lc->requested_fc = PAUSE_AUTONEG;
1700 else
1701 return -EINVAL;
1702
1703 if (epause->rx_pause)
1704 lc->requested_fc |= PAUSE_RX;
1705 if (epause->tx_pause)
1706 lc->requested_fc |= PAUSE_TX;
1707 if (lc->autoneg == AUTONEG_ENABLE) {
1708 if (netif_running(dev))
1709 t3_link_start(&p->phy, &p->mac, lc);
1710 } else {
1711 lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1712 if (netif_running(dev))
1713 t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc);
1714 }
1715 return 0;
1716}
1717
1718static u32 get_rx_csum(struct net_device *dev)
1719{
1720 struct port_info *p = netdev_priv(dev);
1721
Roland Dreier47fd23f2009-01-11 00:19:36 -08001722 return p->rx_offload & T3_RX_CSUM;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001723}
1724
1725static int set_rx_csum(struct net_device *dev, u32 data)
1726{
1727 struct port_info *p = netdev_priv(dev);
1728
Roland Dreier47fd23f2009-01-11 00:19:36 -08001729 if (data) {
1730 p->rx_offload |= T3_RX_CSUM;
1731 } else {
Divy Le Rayb47385b2008-05-21 18:56:26 -07001732 int i;
1733
Roland Dreier47fd23f2009-01-11 00:19:36 -08001734 p->rx_offload &= ~(T3_RX_CSUM | T3_LRO);
Divy Le Ray04ecb072008-10-28 22:40:32 -07001735 for (i = p->first_qset; i < p->first_qset + p->nqsets; i++)
1736 set_qset_lro(dev, i, 0);
Divy Le Rayb47385b2008-05-21 18:56:26 -07001737 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001738 return 0;
1739}
1740
1741static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
1742{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001743 struct port_info *pi = netdev_priv(dev);
1744 struct adapter *adapter = pi->adapter;
Divy Le Ray05b97b32007-03-18 13:10:01 -07001745 const struct qset_params *q = &adapter->params.sge.qset[pi->first_qset];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001746
1747 e->rx_max_pending = MAX_RX_BUFFERS;
1748 e->rx_mini_max_pending = 0;
1749 e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
1750 e->tx_max_pending = MAX_TXQ_ENTRIES;
1751
Divy Le Ray05b97b32007-03-18 13:10:01 -07001752 e->rx_pending = q->fl_size;
1753 e->rx_mini_pending = q->rspq_size;
1754 e->rx_jumbo_pending = q->jumbo_size;
1755 e->tx_pending = q->txq_size[0];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001756}
1757
1758static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
1759{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001760 struct port_info *pi = netdev_priv(dev);
1761 struct adapter *adapter = pi->adapter;
Divy Le Ray05b97b32007-03-18 13:10:01 -07001762 struct qset_params *q;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001763 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001764
1765 if (e->rx_pending > MAX_RX_BUFFERS ||
1766 e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
1767 e->tx_pending > MAX_TXQ_ENTRIES ||
1768 e->rx_mini_pending > MAX_RSPQ_ENTRIES ||
1769 e->rx_mini_pending < MIN_RSPQ_ENTRIES ||
1770 e->rx_pending < MIN_FL_ENTRIES ||
1771 e->rx_jumbo_pending < MIN_FL_ENTRIES ||
1772 e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES)
1773 return -EINVAL;
1774
1775 if (adapter->flags & FULL_INIT_DONE)
1776 return -EBUSY;
1777
Divy Le Ray05b97b32007-03-18 13:10:01 -07001778 q = &adapter->params.sge.qset[pi->first_qset];
1779 for (i = 0; i < pi->nqsets; ++i, ++q) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001780 q->rspq_size = e->rx_mini_pending;
1781 q->fl_size = e->rx_pending;
1782 q->jumbo_size = e->rx_jumbo_pending;
1783 q->txq_size[0] = e->tx_pending;
1784 q->txq_size[1] = e->tx_pending;
1785 q->txq_size[2] = e->tx_pending;
1786 }
1787 return 0;
1788}
1789
1790static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
1791{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001792 struct port_info *pi = netdev_priv(dev);
1793 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001794 struct qset_params *qsp = &adapter->params.sge.qset[0];
1795 struct sge_qset *qs = &adapter->sge.qs[0];
1796
1797 if (c->rx_coalesce_usecs * 10 > M_NEWTIMER)
1798 return -EINVAL;
1799
1800 qsp->coalesce_usecs = c->rx_coalesce_usecs;
1801 t3_update_qset_coalesce(qs, qsp);
1802 return 0;
1803}
1804
1805static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
1806{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001807 struct port_info *pi = netdev_priv(dev);
1808 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001809 struct qset_params *q = adapter->params.sge.qset;
1810
1811 c->rx_coalesce_usecs = q->coalesce_usecs;
1812 return 0;
1813}
1814
1815static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
1816 u8 * data)
1817{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001818 struct port_info *pi = netdev_priv(dev);
1819 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001820 int i, err = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001821
1822 u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
1823 if (!buf)
1824 return -ENOMEM;
1825
1826 e->magic = EEPROM_MAGIC;
1827 for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
Al Viro05e5c112007-12-22 18:56:23 +00001828 err = t3_seeprom_read(adapter, i, (__le32 *) & buf[i]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001829
1830 if (!err)
1831 memcpy(data, buf + e->offset, e->len);
1832 kfree(buf);
1833 return err;
1834}
1835
1836static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
1837 u8 * data)
1838{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001839 struct port_info *pi = netdev_priv(dev);
1840 struct adapter *adapter = pi->adapter;
Al Viro05e5c112007-12-22 18:56:23 +00001841 u32 aligned_offset, aligned_len;
1842 __le32 *p;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001843 u8 *buf;
Denis Chengc54f5c22007-07-18 15:24:49 +08001844 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001845
1846 if (eeprom->magic != EEPROM_MAGIC)
1847 return -EINVAL;
1848
1849 aligned_offset = eeprom->offset & ~3;
1850 aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
1851
1852 if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
1853 buf = kmalloc(aligned_len, GFP_KERNEL);
1854 if (!buf)
1855 return -ENOMEM;
Al Viro05e5c112007-12-22 18:56:23 +00001856 err = t3_seeprom_read(adapter, aligned_offset, (__le32 *) buf);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001857 if (!err && aligned_len > 4)
1858 err = t3_seeprom_read(adapter,
1859 aligned_offset + aligned_len - 4,
Al Viro05e5c112007-12-22 18:56:23 +00001860 (__le32 *) & buf[aligned_len - 4]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001861 if (err)
1862 goto out;
1863 memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
1864 } else
1865 buf = data;
1866
1867 err = t3_seeprom_wp(adapter, 0);
1868 if (err)
1869 goto out;
1870
Al Viro05e5c112007-12-22 18:56:23 +00001871 for (p = (__le32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001872 err = t3_seeprom_write(adapter, aligned_offset, *p);
1873 aligned_offset += 4;
1874 }
1875
1876 if (!err)
1877 err = t3_seeprom_wp(adapter, 1);
1878out:
1879 if (buf != data)
1880 kfree(buf);
1881 return err;
1882}
1883
1884static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1885{
1886 wol->supported = 0;
1887 wol->wolopts = 0;
1888 memset(&wol->sopass, 0, sizeof(wol->sopass));
1889}
1890
1891static const struct ethtool_ops cxgb_ethtool_ops = {
1892 .get_settings = get_settings,
1893 .set_settings = set_settings,
1894 .get_drvinfo = get_drvinfo,
1895 .get_msglevel = get_msglevel,
1896 .set_msglevel = set_msglevel,
1897 .get_ringparam = get_sge_param,
1898 .set_ringparam = set_sge_param,
1899 .get_coalesce = get_coalesce,
1900 .set_coalesce = set_coalesce,
1901 .get_eeprom_len = get_eeprom_len,
1902 .get_eeprom = get_eeprom,
1903 .set_eeprom = set_eeprom,
1904 .get_pauseparam = get_pauseparam,
1905 .set_pauseparam = set_pauseparam,
1906 .get_rx_csum = get_rx_csum,
1907 .set_rx_csum = set_rx_csum,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001908 .set_tx_csum = ethtool_op_set_tx_csum,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001909 .set_sg = ethtool_op_set_sg,
1910 .get_link = ethtool_op_get_link,
1911 .get_strings = get_strings,
1912 .phys_id = cxgb3_phys_id,
1913 .nway_reset = restart_autoneg,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001914 .get_sset_count = get_sset_count,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001915 .get_ethtool_stats = get_stats,
1916 .get_regs_len = get_regs_len,
1917 .get_regs = get_regs,
1918 .get_wol = get_wol,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001919 .set_tso = ethtool_op_set_tso,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001920};
1921
1922static int in_range(int val, int lo, int hi)
1923{
1924 return val < 0 || (val <= hi && val >= lo);
1925}
1926
1927static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
1928{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001929 struct port_info *pi = netdev_priv(dev);
1930 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001931 u32 cmd;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001932 int ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001933
1934 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
1935 return -EFAULT;
1936
1937 switch (cmd) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001938 case CHELSIO_SET_QSET_PARAMS:{
1939 int i;
1940 struct qset_params *q;
1941 struct ch_qset_params t;
Divy Le Ray8c263762008-10-08 17:37:33 -07001942 int q1 = pi->first_qset;
1943 int nqsets = pi->nqsets;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001944
1945 if (!capable(CAP_NET_ADMIN))
1946 return -EPERM;
1947 if (copy_from_user(&t, useraddr, sizeof(t)))
1948 return -EFAULT;
1949 if (t.qset_idx >= SGE_QSETS)
1950 return -EINVAL;
1951 if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
1952 !in_range(t.cong_thres, 0, 255) ||
1953 !in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
1954 MAX_TXQ_ENTRIES) ||
1955 !in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
1956 MAX_TXQ_ENTRIES) ||
1957 !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
1958 MAX_CTRL_TXQ_ENTRIES) ||
1959 !in_range(t.fl_size[0], MIN_FL_ENTRIES,
1960 MAX_RX_BUFFERS)
1961 || !in_range(t.fl_size[1], MIN_FL_ENTRIES,
1962 MAX_RX_JUMBO_BUFFERS)
1963 || !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
1964 MAX_RSPQ_ENTRIES))
1965 return -EINVAL;
Divy Le Ray8c263762008-10-08 17:37:33 -07001966
1967 if ((adapter->flags & FULL_INIT_DONE) && t.lro > 0)
1968 for_each_port(adapter, i) {
1969 pi = adap2pinfo(adapter, i);
1970 if (t.qset_idx >= pi->first_qset &&
1971 t.qset_idx < pi->first_qset + pi->nqsets &&
Roland Dreier47fd23f2009-01-11 00:19:36 -08001972 !(pi->rx_offload & T3_RX_CSUM))
Divy Le Ray8c263762008-10-08 17:37:33 -07001973 return -EINVAL;
1974 }
1975
Divy Le Ray4d22de32007-01-18 22:04:14 -05001976 if ((adapter->flags & FULL_INIT_DONE) &&
1977 (t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
1978 t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
1979 t.txq_size[1] >= 0 || t.txq_size[2] >= 0 ||
1980 t.polling >= 0 || t.cong_thres >= 0))
1981 return -EBUSY;
1982
Divy Le Ray8c263762008-10-08 17:37:33 -07001983 /* Allow setting of any available qset when offload enabled */
1984 if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
1985 q1 = 0;
1986 for_each_port(adapter, i) {
1987 pi = adap2pinfo(adapter, i);
1988 nqsets += pi->first_qset + pi->nqsets;
1989 }
1990 }
1991
1992 if (t.qset_idx < q1)
1993 return -EINVAL;
1994 if (t.qset_idx > q1 + nqsets - 1)
1995 return -EINVAL;
1996
Divy Le Ray4d22de32007-01-18 22:04:14 -05001997 q = &adapter->params.sge.qset[t.qset_idx];
1998
1999 if (t.rspq_size >= 0)
2000 q->rspq_size = t.rspq_size;
2001 if (t.fl_size[0] >= 0)
2002 q->fl_size = t.fl_size[0];
2003 if (t.fl_size[1] >= 0)
2004 q->jumbo_size = t.fl_size[1];
2005 if (t.txq_size[0] >= 0)
2006 q->txq_size[0] = t.txq_size[0];
2007 if (t.txq_size[1] >= 0)
2008 q->txq_size[1] = t.txq_size[1];
2009 if (t.txq_size[2] >= 0)
2010 q->txq_size[2] = t.txq_size[2];
2011 if (t.cong_thres >= 0)
2012 q->cong_thres = t.cong_thres;
2013 if (t.intr_lat >= 0) {
2014 struct sge_qset *qs =
2015 &adapter->sge.qs[t.qset_idx];
2016
2017 q->coalesce_usecs = t.intr_lat;
2018 t3_update_qset_coalesce(qs, q);
2019 }
2020 if (t.polling >= 0) {
2021 if (adapter->flags & USING_MSIX)
2022 q->polling = t.polling;
2023 else {
2024 /* No polling with INTx for T3A */
2025 if (adapter->params.rev == 0 &&
2026 !(adapter->flags & USING_MSI))
2027 t.polling = 0;
2028
2029 for (i = 0; i < SGE_QSETS; i++) {
2030 q = &adapter->params.sge.
2031 qset[i];
2032 q->polling = t.polling;
2033 }
2034 }
2035 }
Divy Le Ray04ecb072008-10-28 22:40:32 -07002036 if (t.lro >= 0)
2037 set_qset_lro(dev, t.qset_idx, t.lro);
2038
Divy Le Ray4d22de32007-01-18 22:04:14 -05002039 break;
2040 }
2041 case CHELSIO_GET_QSET_PARAMS:{
2042 struct qset_params *q;
2043 struct ch_qset_params t;
Divy Le Ray8c263762008-10-08 17:37:33 -07002044 int q1 = pi->first_qset;
2045 int nqsets = pi->nqsets;
2046 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002047
2048 if (copy_from_user(&t, useraddr, sizeof(t)))
2049 return -EFAULT;
Divy Le Ray8c263762008-10-08 17:37:33 -07002050
2051 /* Display qsets for all ports when offload enabled */
2052 if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
2053 q1 = 0;
2054 for_each_port(adapter, i) {
2055 pi = adap2pinfo(adapter, i);
2056 nqsets = pi->first_qset + pi->nqsets;
2057 }
2058 }
2059
2060 if (t.qset_idx >= nqsets)
Divy Le Ray4d22de32007-01-18 22:04:14 -05002061 return -EINVAL;
2062
Divy Le Ray8c263762008-10-08 17:37:33 -07002063 q = &adapter->params.sge.qset[q1 + t.qset_idx];
Divy Le Ray4d22de32007-01-18 22:04:14 -05002064 t.rspq_size = q->rspq_size;
2065 t.txq_size[0] = q->txq_size[0];
2066 t.txq_size[1] = q->txq_size[1];
2067 t.txq_size[2] = q->txq_size[2];
2068 t.fl_size[0] = q->fl_size;
2069 t.fl_size[1] = q->jumbo_size;
2070 t.polling = q->polling;
Divy Le Rayb47385b2008-05-21 18:56:26 -07002071 t.lro = q->lro;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002072 t.intr_lat = q->coalesce_usecs;
2073 t.cong_thres = q->cong_thres;
Divy Le Ray8c263762008-10-08 17:37:33 -07002074 t.qnum = q1;
2075
2076 if (adapter->flags & USING_MSIX)
2077 t.vector = adapter->msix_info[q1 + t.qset_idx + 1].vec;
2078 else
2079 t.vector = adapter->pdev->irq;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002080
2081 if (copy_to_user(useraddr, &t, sizeof(t)))
2082 return -EFAULT;
2083 break;
2084 }
2085 case CHELSIO_SET_QSET_NUM:{
2086 struct ch_reg edata;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002087 unsigned int i, first_qset = 0, other_qsets = 0;
2088
2089 if (!capable(CAP_NET_ADMIN))
2090 return -EPERM;
2091 if (adapter->flags & FULL_INIT_DONE)
2092 return -EBUSY;
2093 if (copy_from_user(&edata, useraddr, sizeof(edata)))
2094 return -EFAULT;
2095 if (edata.val < 1 ||
2096 (edata.val > 1 && !(adapter->flags & USING_MSIX)))
2097 return -EINVAL;
2098
2099 for_each_port(adapter, i)
2100 if (adapter->port[i] && adapter->port[i] != dev)
2101 other_qsets += adap2pinfo(adapter, i)->nqsets;
2102
2103 if (edata.val + other_qsets > SGE_QSETS)
2104 return -EINVAL;
2105
2106 pi->nqsets = edata.val;
2107
2108 for_each_port(adapter, i)
2109 if (adapter->port[i]) {
2110 pi = adap2pinfo(adapter, i);
2111 pi->first_qset = first_qset;
2112 first_qset += pi->nqsets;
2113 }
2114 break;
2115 }
2116 case CHELSIO_GET_QSET_NUM:{
2117 struct ch_reg edata;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002118
2119 edata.cmd = CHELSIO_GET_QSET_NUM;
2120 edata.val = pi->nqsets;
2121 if (copy_to_user(useraddr, &edata, sizeof(edata)))
2122 return -EFAULT;
2123 break;
2124 }
2125 case CHELSIO_LOAD_FW:{
2126 u8 *fw_data;
2127 struct ch_mem_range t;
2128
Alan Cox1b3aa7a2008-04-29 14:29:30 +01002129 if (!capable(CAP_SYS_RAWIO))
Divy Le Ray4d22de32007-01-18 22:04:14 -05002130 return -EPERM;
2131 if (copy_from_user(&t, useraddr, sizeof(t)))
2132 return -EFAULT;
Alan Cox1b3aa7a2008-04-29 14:29:30 +01002133 /* Check t.len sanity ? */
Divy Le Ray4d22de32007-01-18 22:04:14 -05002134 fw_data = kmalloc(t.len, GFP_KERNEL);
2135 if (!fw_data)
2136 return -ENOMEM;
2137
2138 if (copy_from_user
2139 (fw_data, useraddr + sizeof(t), t.len)) {
2140 kfree(fw_data);
2141 return -EFAULT;
2142 }
2143
2144 ret = t3_load_fw(adapter, fw_data, t.len);
2145 kfree(fw_data);
2146 if (ret)
2147 return ret;
2148 break;
2149 }
2150 case CHELSIO_SETMTUTAB:{
2151 struct ch_mtus m;
2152 int i;
2153
2154 if (!is_offload(adapter))
2155 return -EOPNOTSUPP;
2156 if (!capable(CAP_NET_ADMIN))
2157 return -EPERM;
2158 if (offload_running(adapter))
2159 return -EBUSY;
2160 if (copy_from_user(&m, useraddr, sizeof(m)))
2161 return -EFAULT;
2162 if (m.nmtus != NMTUS)
2163 return -EINVAL;
2164 if (m.mtus[0] < 81) /* accommodate SACK */
2165 return -EINVAL;
2166
2167 /* MTUs must be in ascending order */
2168 for (i = 1; i < NMTUS; ++i)
2169 if (m.mtus[i] < m.mtus[i - 1])
2170 return -EINVAL;
2171
2172 memcpy(adapter->params.mtus, m.mtus,
2173 sizeof(adapter->params.mtus));
2174 break;
2175 }
2176 case CHELSIO_GET_PM:{
2177 struct tp_params *p = &adapter->params.tp;
2178 struct ch_pm m = {.cmd = CHELSIO_GET_PM };
2179
2180 if (!is_offload(adapter))
2181 return -EOPNOTSUPP;
2182 m.tx_pg_sz = p->tx_pg_size;
2183 m.tx_num_pg = p->tx_num_pgs;
2184 m.rx_pg_sz = p->rx_pg_size;
2185 m.rx_num_pg = p->rx_num_pgs;
2186 m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan;
2187 if (copy_to_user(useraddr, &m, sizeof(m)))
2188 return -EFAULT;
2189 break;
2190 }
2191 case CHELSIO_SET_PM:{
2192 struct ch_pm m;
2193 struct tp_params *p = &adapter->params.tp;
2194
2195 if (!is_offload(adapter))
2196 return -EOPNOTSUPP;
2197 if (!capable(CAP_NET_ADMIN))
2198 return -EPERM;
2199 if (adapter->flags & FULL_INIT_DONE)
2200 return -EBUSY;
2201 if (copy_from_user(&m, useraddr, sizeof(m)))
2202 return -EFAULT;
vignesh babud9da4662007-07-09 11:50:22 -07002203 if (!is_power_of_2(m.rx_pg_sz) ||
2204 !is_power_of_2(m.tx_pg_sz))
Divy Le Ray4d22de32007-01-18 22:04:14 -05002205 return -EINVAL; /* not power of 2 */
2206 if (!(m.rx_pg_sz & 0x14000))
2207 return -EINVAL; /* not 16KB or 64KB */
2208 if (!(m.tx_pg_sz & 0x1554000))
2209 return -EINVAL;
2210 if (m.tx_num_pg == -1)
2211 m.tx_num_pg = p->tx_num_pgs;
2212 if (m.rx_num_pg == -1)
2213 m.rx_num_pg = p->rx_num_pgs;
2214 if (m.tx_num_pg % 24 || m.rx_num_pg % 24)
2215 return -EINVAL;
2216 if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size ||
2217 m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size)
2218 return -EINVAL;
2219 p->rx_pg_size = m.rx_pg_sz;
2220 p->tx_pg_size = m.tx_pg_sz;
2221 p->rx_num_pgs = m.rx_num_pg;
2222 p->tx_num_pgs = m.tx_num_pg;
2223 break;
2224 }
2225 case CHELSIO_GET_MEM:{
2226 struct ch_mem_range t;
2227 struct mc7 *mem;
2228 u64 buf[32];
2229
2230 if (!is_offload(adapter))
2231 return -EOPNOTSUPP;
2232 if (!(adapter->flags & FULL_INIT_DONE))
2233 return -EIO; /* need the memory controllers */
2234 if (copy_from_user(&t, useraddr, sizeof(t)))
2235 return -EFAULT;
2236 if ((t.addr & 7) || (t.len & 7))
2237 return -EINVAL;
2238 if (t.mem_id == MEM_CM)
2239 mem = &adapter->cm;
2240 else if (t.mem_id == MEM_PMRX)
2241 mem = &adapter->pmrx;
2242 else if (t.mem_id == MEM_PMTX)
2243 mem = &adapter->pmtx;
2244 else
2245 return -EINVAL;
2246
2247 /*
Divy Le Ray18254942007-02-24 16:43:56 -08002248 * Version scheme:
2249 * bits 0..9: chip version
2250 * bits 10..15: chip revision
2251 */
Divy Le Ray4d22de32007-01-18 22:04:14 -05002252 t.version = 3 | (adapter->params.rev << 10);
2253 if (copy_to_user(useraddr, &t, sizeof(t)))
2254 return -EFAULT;
2255
2256 /*
2257 * Read 256 bytes at a time as len can be large and we don't
2258 * want to use huge intermediate buffers.
2259 */
2260 useraddr += sizeof(t); /* advance to start of buffer */
2261 while (t.len) {
2262 unsigned int chunk =
2263 min_t(unsigned int, t.len, sizeof(buf));
2264
2265 ret =
2266 t3_mc7_bd_read(mem, t.addr / 8, chunk / 8,
2267 buf);
2268 if (ret)
2269 return ret;
2270 if (copy_to_user(useraddr, buf, chunk))
2271 return -EFAULT;
2272 useraddr += chunk;
2273 t.addr += chunk;
2274 t.len -= chunk;
2275 }
2276 break;
2277 }
2278 case CHELSIO_SET_TRACE_FILTER:{
2279 struct ch_trace t;
2280 const struct trace_params *tp;
2281
2282 if (!capable(CAP_NET_ADMIN))
2283 return -EPERM;
2284 if (!offload_running(adapter))
2285 return -EAGAIN;
2286 if (copy_from_user(&t, useraddr, sizeof(t)))
2287 return -EFAULT;
2288
2289 tp = (const struct trace_params *)&t.sip;
2290 if (t.config_tx)
2291 t3_config_trace_filter(adapter, tp, 0,
2292 t.invert_match,
2293 t.trace_tx);
2294 if (t.config_rx)
2295 t3_config_trace_filter(adapter, tp, 1,
2296 t.invert_match,
2297 t.trace_rx);
2298 break;
2299 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002300 default:
2301 return -EOPNOTSUPP;
2302 }
2303 return 0;
2304}
2305
2306static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
2307{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002308 struct mii_ioctl_data *data = if_mii(req);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002309 struct port_info *pi = netdev_priv(dev);
2310 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002311
2312 switch (cmd) {
Ben Hutchings0f07c4e2009-04-29 08:07:20 +00002313 case SIOCGMIIREG:
2314 case SIOCSMIIREG:
2315 /* Convert phy_id from older PRTAD/DEVAD format */
2316 if (is_10G(adapter) &&
2317 !mdio_phy_id_is_c45(data->phy_id) &&
2318 (data->phy_id & 0x1f00) &&
2319 !(data->phy_id & 0xe0e0))
2320 data->phy_id = mdio_phy_id_c45(data->phy_id >> 8,
2321 data->phy_id & 0x1f);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002322 /* FALLTHRU */
Ben Hutchings0f07c4e2009-04-29 08:07:20 +00002323 case SIOCGMIIPHY:
2324 return mdio_mii_ioctl(&pi->phy.mdio, data, cmd);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002325 case SIOCCHIOCTL:
2326 return cxgb_extension_ioctl(dev, req->ifr_data);
2327 default:
2328 return -EOPNOTSUPP;
2329 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002330}
2331
2332static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
2333{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002334 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002335 struct adapter *adapter = pi->adapter;
2336 int ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002337
2338 if (new_mtu < 81) /* accommodate SACK */
2339 return -EINVAL;
2340 if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu)))
2341 return ret;
2342 dev->mtu = new_mtu;
2343 init_port_mtus(adapter);
2344 if (adapter->params.rev == 0 && offload_running(adapter))
2345 t3_load_mtus(adapter, adapter->params.mtus,
2346 adapter->params.a_wnd, adapter->params.b_wnd,
2347 adapter->port[0]->mtu);
2348 return 0;
2349}
2350
2351static int cxgb_set_mac_addr(struct net_device *dev, void *p)
2352{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002353 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002354 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002355 struct sockaddr *addr = p;
2356
2357 if (!is_valid_ether_addr(addr->sa_data))
2358 return -EINVAL;
2359
2360 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
2361 t3_mac_set_address(&pi->mac, 0, dev->dev_addr);
2362 if (offload_running(adapter))
2363 write_smt_entry(adapter, pi->port_id);
2364 return 0;
2365}
2366
2367/**
2368 * t3_synchronize_rx - wait for current Rx processing on a port to complete
2369 * @adap: the adapter
2370 * @p: the port
2371 *
2372 * Ensures that current Rx processing on any of the queues associated with
2373 * the given port completes before returning. We do this by acquiring and
2374 * releasing the locks of the response queues associated with the port.
2375 */
2376static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
2377{
2378 int i;
2379
Divy Le Ray8c263762008-10-08 17:37:33 -07002380 for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
2381 struct sge_rspq *q = &adap->sge.qs[i].rspq;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002382
2383 spin_lock_irq(&q->lock);
2384 spin_unlock_irq(&q->lock);
2385 }
2386}
2387
2388static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
2389{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002390 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002391 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002392
2393 pi->vlan_grp = grp;
2394 if (adapter->params.rev > 0)
2395 t3_set_vlan_accel(adapter, 1 << pi->port_id, grp != NULL);
2396 else {
2397 /* single control for all ports */
2398 unsigned int i, have_vlans = 0;
2399 for_each_port(adapter, i)
2400 have_vlans |= adap2pinfo(adapter, i)->vlan_grp != NULL;
2401
2402 t3_set_vlan_accel(adapter, 1, have_vlans);
2403 }
2404 t3_synchronize_rx(adapter, pi);
2405}
2406
Divy Le Ray4d22de32007-01-18 22:04:14 -05002407#ifdef CONFIG_NET_POLL_CONTROLLER
2408static void cxgb_netpoll(struct net_device *dev)
2409{
Divy Le Ray890de332007-05-30 10:01:34 -07002410 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002411 struct adapter *adapter = pi->adapter;
Divy Le Ray890de332007-05-30 10:01:34 -07002412 int qidx;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002413
Divy Le Ray890de332007-05-30 10:01:34 -07002414 for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) {
2415 struct sge_qset *qs = &adapter->sge.qs[qidx];
2416 void *source;
Jeff Garzik2eab17a2007-11-23 21:59:45 -05002417
Divy Le Ray890de332007-05-30 10:01:34 -07002418 if (adapter->flags & USING_MSIX)
2419 source = qs;
2420 else
2421 source = adapter;
2422
2423 t3_intr_handler(adapter, qs->rspq.polling) (0, source);
2424 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002425}
2426#endif
2427
2428/*
2429 * Periodic accumulation of MAC statistics.
2430 */
2431static void mac_stats_update(struct adapter *adapter)
2432{
2433 int i;
2434
2435 for_each_port(adapter, i) {
2436 struct net_device *dev = adapter->port[i];
2437 struct port_info *p = netdev_priv(dev);
2438
2439 if (netif_running(dev)) {
2440 spin_lock(&adapter->stats_lock);
2441 t3_mac_update_stats(&p->mac);
2442 spin_unlock(&adapter->stats_lock);
2443 }
2444 }
2445}
2446
2447static void check_link_status(struct adapter *adapter)
2448{
2449 int i;
2450
2451 for_each_port(adapter, i) {
2452 struct net_device *dev = adapter->port[i];
2453 struct port_info *p = netdev_priv(dev);
2454
Divy Le Raybf792092009-03-12 21:14:19 +00002455 spin_lock_irq(&adapter->work_lock);
2456 if (p->link_fault) {
Divy Le Ray3851c662009-04-17 12:21:11 +00002457 t3_link_fault(adapter, i);
Divy Le Raybf792092009-03-12 21:14:19 +00002458 spin_unlock_irq(&adapter->work_lock);
2459 continue;
2460 }
2461 spin_unlock_irq(&adapter->work_lock);
2462
2463 if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) {
2464 t3_xgm_intr_disable(adapter, i);
2465 t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
2466
Divy Le Ray4d22de32007-01-18 22:04:14 -05002467 t3_link_changed(adapter, i);
Divy Le Raybf792092009-03-12 21:14:19 +00002468 t3_xgm_intr_enable(adapter, i);
2469 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002470 }
2471}
2472
Divy Le Rayfc906642007-03-18 13:10:12 -07002473static void check_t3b2_mac(struct adapter *adapter)
2474{
2475 int i;
2476
Divy Le Rayf2d961c2007-04-09 20:10:22 -07002477 if (!rtnl_trylock()) /* synchronize with ifdown */
2478 return;
2479
Divy Le Rayfc906642007-03-18 13:10:12 -07002480 for_each_port(adapter, i) {
2481 struct net_device *dev = adapter->port[i];
2482 struct port_info *p = netdev_priv(dev);
2483 int status;
2484
2485 if (!netif_running(dev))
2486 continue;
2487
2488 status = 0;
Divy Le Ray6d6daba2007-03-31 00:23:24 -07002489 if (netif_running(dev) && netif_carrier_ok(dev))
Divy Le Rayfc906642007-03-18 13:10:12 -07002490 status = t3b2_mac_watchdog_task(&p->mac);
2491 if (status == 1)
2492 p->mac.stats.num_toggled++;
2493 else if (status == 2) {
2494 struct cmac *mac = &p->mac;
2495
2496 t3_mac_set_mtu(mac, dev->mtu);
2497 t3_mac_set_address(mac, 0, dev->dev_addr);
2498 cxgb_set_rxmode(dev);
2499 t3_link_start(&p->phy, mac, &p->link_config);
2500 t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
2501 t3_port_intr_enable(adapter, p->port_id);
2502 p->mac.stats.num_resets++;
2503 }
2504 }
2505 rtnl_unlock();
2506}
2507
2508
Divy Le Ray4d22de32007-01-18 22:04:14 -05002509static void t3_adap_check_task(struct work_struct *work)
2510{
2511 struct adapter *adapter = container_of(work, struct adapter,
2512 adap_check_task.work);
2513 const struct adapter_params *p = &adapter->params;
Divy Le Rayfc882192009-03-12 21:14:09 +00002514 int port;
2515 unsigned int v, status, reset;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002516
2517 adapter->check_task_cnt++;
2518
Divy Le Ray3851c662009-04-17 12:21:11 +00002519 check_link_status(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002520
2521 /* Accumulate MAC stats if needed */
2522 if (!p->linkpoll_period ||
2523 (adapter->check_task_cnt * p->linkpoll_period) / 10 >=
2524 p->stats_update_period) {
2525 mac_stats_update(adapter);
2526 adapter->check_task_cnt = 0;
2527 }
2528
Divy Le Rayfc906642007-03-18 13:10:12 -07002529 if (p->rev == T3_REV_B2)
2530 check_t3b2_mac(adapter);
2531
Divy Le Rayfc882192009-03-12 21:14:09 +00002532 /*
2533 * Scan the XGMAC's to check for various conditions which we want to
2534 * monitor in a periodic polling manner rather than via an interrupt
2535 * condition. This is used for conditions which would otherwise flood
2536 * the system with interrupts and we only really need to know that the
2537 * conditions are "happening" ... For each condition we count the
2538 * detection of the condition and reset it for the next polling loop.
2539 */
2540 for_each_port(adapter, port) {
2541 struct cmac *mac = &adap2pinfo(adapter, port)->mac;
2542 u32 cause;
2543
2544 cause = t3_read_reg(adapter, A_XGM_INT_CAUSE + mac->offset);
2545 reset = 0;
2546 if (cause & F_RXFIFO_OVERFLOW) {
2547 mac->stats.rx_fifo_ovfl++;
2548 reset |= F_RXFIFO_OVERFLOW;
2549 }
2550
2551 t3_write_reg(adapter, A_XGM_INT_CAUSE + mac->offset, reset);
2552 }
2553
2554 /*
2555 * We do the same as above for FL_EMPTY interrupts.
2556 */
2557 status = t3_read_reg(adapter, A_SG_INT_CAUSE);
2558 reset = 0;
2559
2560 if (status & F_FLEMPTY) {
2561 struct sge_qset *qs = &adapter->sge.qs[0];
2562 int i = 0;
2563
2564 reset |= F_FLEMPTY;
2565
2566 v = (t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS) >> S_FL0EMPTY) &
2567 0xffff;
2568
2569 while (v) {
2570 qs->fl[i].empty += (v & 1);
2571 if (i)
2572 qs++;
2573 i ^= 1;
2574 v >>= 1;
2575 }
2576 }
2577
2578 t3_write_reg(adapter, A_SG_INT_CAUSE, reset);
2579
Divy Le Ray4d22de32007-01-18 22:04:14 -05002580 /* Schedule the next check update if any port is active. */
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002581 spin_lock_irq(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002582 if (adapter->open_device_map & PORT_MASK)
2583 schedule_chk_task(adapter);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002584 spin_unlock_irq(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002585}
2586
2587/*
2588 * Processes external (PHY) interrupts in process context.
2589 */
2590static void ext_intr_task(struct work_struct *work)
2591{
2592 struct adapter *adapter = container_of(work, struct adapter,
2593 ext_intr_handler_task);
Divy Le Raybf792092009-03-12 21:14:19 +00002594 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002595
Divy Le Raybf792092009-03-12 21:14:19 +00002596 /* Disable link fault interrupts */
2597 for_each_port(adapter, i) {
2598 struct net_device *dev = adapter->port[i];
2599 struct port_info *p = netdev_priv(dev);
2600
2601 t3_xgm_intr_disable(adapter, i);
2602 t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
2603 }
2604
2605 /* Re-enable link fault interrupts */
Divy Le Ray4d22de32007-01-18 22:04:14 -05002606 t3_phy_intr_handler(adapter);
2607
Divy Le Raybf792092009-03-12 21:14:19 +00002608 for_each_port(adapter, i)
2609 t3_xgm_intr_enable(adapter, i);
2610
Divy Le Ray4d22de32007-01-18 22:04:14 -05002611 /* Now reenable external interrupts */
2612 spin_lock_irq(&adapter->work_lock);
2613 if (adapter->slow_intr_mask) {
2614 adapter->slow_intr_mask |= F_T3DBG;
2615 t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG);
2616 t3_write_reg(adapter, A_PL_INT_ENABLE0,
2617 adapter->slow_intr_mask);
2618 }
2619 spin_unlock_irq(&adapter->work_lock);
2620}
2621
2622/*
2623 * Interrupt-context handler for external (PHY) interrupts.
2624 */
2625void t3_os_ext_intr_handler(struct adapter *adapter)
2626{
2627 /*
2628 * Schedule a task to handle external interrupts as they may be slow
2629 * and we use a mutex to protect MDIO registers. We disable PHY
2630 * interrupts in the meantime and let the task reenable them when
2631 * it's done.
2632 */
2633 spin_lock(&adapter->work_lock);
2634 if (adapter->slow_intr_mask) {
2635 adapter->slow_intr_mask &= ~F_T3DBG;
2636 t3_write_reg(adapter, A_PL_INT_ENABLE0,
2637 adapter->slow_intr_mask);
2638 queue_work(cxgb3_wq, &adapter->ext_intr_handler_task);
2639 }
2640 spin_unlock(&adapter->work_lock);
2641}
2642
Divy Le Raybf792092009-03-12 21:14:19 +00002643void t3_os_link_fault_handler(struct adapter *adapter, int port_id)
2644{
2645 struct net_device *netdev = adapter->port[port_id];
2646 struct port_info *pi = netdev_priv(netdev);
2647
2648 spin_lock(&adapter->work_lock);
2649 pi->link_fault = 1;
Divy Le Raybf792092009-03-12 21:14:19 +00002650 spin_unlock(&adapter->work_lock);
2651}
2652
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002653static int t3_adapter_error(struct adapter *adapter, int reset)
2654{
2655 int i, ret = 0;
2656
Divy Le Raycb0bc202009-01-26 22:21:59 -08002657 if (is_offload(adapter) &&
2658 test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
2659 cxgb3_err_notify(&adapter->tdev, OFFLOAD_STATUS_DOWN, 0);
2660 offload_close(&adapter->tdev);
2661 }
2662
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002663 /* Stop all ports */
2664 for_each_port(adapter, i) {
2665 struct net_device *netdev = adapter->port[i];
2666
2667 if (netif_running(netdev))
2668 cxgb_close(netdev);
2669 }
2670
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002671 /* Stop SGE timers */
2672 t3_stop_sge_timers(adapter);
2673
2674 adapter->flags &= ~FULL_INIT_DONE;
2675
2676 if (reset)
2677 ret = t3_reset_adapter(adapter);
2678
2679 pci_disable_device(adapter->pdev);
2680
2681 return ret;
2682}
2683
2684static int t3_reenable_adapter(struct adapter *adapter)
2685{
2686 if (pci_enable_device(adapter->pdev)) {
2687 dev_err(&adapter->pdev->dev,
2688 "Cannot re-enable PCI device after reset.\n");
2689 goto err;
2690 }
2691 pci_set_master(adapter->pdev);
2692 pci_restore_state(adapter->pdev);
2693
2694 /* Free sge resources */
2695 t3_free_sge_resources(adapter);
2696
2697 if (t3_replay_prep_adapter(adapter))
2698 goto err;
2699
2700 return 0;
2701err:
2702 return -1;
2703}
2704
2705static void t3_resume_ports(struct adapter *adapter)
2706{
2707 int i;
2708
2709 /* Restart the ports */
2710 for_each_port(adapter, i) {
2711 struct net_device *netdev = adapter->port[i];
2712
2713 if (netif_running(netdev)) {
2714 if (cxgb_open(netdev)) {
2715 dev_err(&adapter->pdev->dev,
2716 "can't bring device back up"
2717 " after reset\n");
2718 continue;
2719 }
2720 }
2721 }
Divy Le Raycb0bc202009-01-26 22:21:59 -08002722
2723 if (is_offload(adapter) && !ofld_disable)
2724 cxgb3_err_notify(&adapter->tdev, OFFLOAD_STATUS_UP, 0);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002725}
2726
2727/*
2728 * processes a fatal error.
2729 * Bring the ports down, reset the chip, bring the ports back up.
2730 */
2731static void fatal_error_task(struct work_struct *work)
2732{
2733 struct adapter *adapter = container_of(work, struct adapter,
2734 fatal_error_handler_task);
2735 int err = 0;
2736
2737 rtnl_lock();
2738 err = t3_adapter_error(adapter, 1);
2739 if (!err)
2740 err = t3_reenable_adapter(adapter);
2741 if (!err)
2742 t3_resume_ports(adapter);
2743
2744 CH_ALERT(adapter, "adapter reset %s\n", err ? "failed" : "succeeded");
2745 rtnl_unlock();
2746}
2747
Divy Le Ray4d22de32007-01-18 22:04:14 -05002748void t3_fatal_err(struct adapter *adapter)
2749{
2750 unsigned int fw_status[4];
2751
2752 if (adapter->flags & FULL_INIT_DONE) {
2753 t3_sge_stop(adapter);
Divy Le Rayc64c2ea2007-08-21 20:49:31 -07002754 t3_write_reg(adapter, A_XGM_TX_CTRL, 0);
2755 t3_write_reg(adapter, A_XGM_RX_CTRL, 0);
2756 t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0);
2757 t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002758
2759 spin_lock(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002760 t3_intr_disable(adapter);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002761 queue_work(cxgb3_wq, &adapter->fatal_error_handler_task);
2762 spin_unlock(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002763 }
2764 CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
2765 if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
2766 CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
2767 fw_status[0], fw_status[1],
2768 fw_status[2], fw_status[3]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002769}
2770
Divy Le Ray91a6b502007-11-16 11:21:55 -08002771/**
2772 * t3_io_error_detected - called when PCI error is detected
2773 * @pdev: Pointer to PCI device
2774 * @state: The current pci connection state
2775 *
2776 * This function is called after a PCI bus error affecting
2777 * this device has been detected.
2778 */
2779static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
2780 pci_channel_state_t state)
2781{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08002782 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002783 int ret;
Divy Le Ray91a6b502007-11-16 11:21:55 -08002784
Divy Le Raye8d19372009-04-17 12:21:27 +00002785 if (state == pci_channel_io_perm_failure)
2786 return PCI_ERS_RESULT_DISCONNECT;
2787
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002788 ret = t3_adapter_error(adapter, 0);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002789
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07002790 /* Request a slot reset. */
Divy Le Ray91a6b502007-11-16 11:21:55 -08002791 return PCI_ERS_RESULT_NEED_RESET;
2792}
2793
2794/**
2795 * t3_io_slot_reset - called after the pci bus has been reset.
2796 * @pdev: Pointer to PCI device
2797 *
2798 * Restart the card from scratch, as if from a cold-boot.
2799 */
2800static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev)
2801{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08002802 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002803
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002804 if (!t3_reenable_adapter(adapter))
2805 return PCI_ERS_RESULT_RECOVERED;
Divy Le Ray91a6b502007-11-16 11:21:55 -08002806
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07002807 return PCI_ERS_RESULT_DISCONNECT;
Divy Le Ray91a6b502007-11-16 11:21:55 -08002808}
2809
2810/**
2811 * t3_io_resume - called when traffic can start flowing again.
2812 * @pdev: Pointer to PCI device
2813 *
2814 * This callback is called when the error recovery driver tells us that
2815 * its OK to resume normal operation.
2816 */
2817static void t3_io_resume(struct pci_dev *pdev)
2818{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08002819 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002820
Divy Le Ray68f40c12009-03-26 16:39:19 +00002821 CH_ALERT(adapter, "adapter recovering, PEX ERR 0x%x\n",
2822 t3_read_reg(adapter, A_PCIE_PEX_ERR));
2823
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002824 t3_resume_ports(adapter);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002825}
2826
2827static struct pci_error_handlers t3_err_handler = {
2828 .error_detected = t3_io_error_detected,
2829 .slot_reset = t3_io_slot_reset,
2830 .resume = t3_io_resume,
2831};
2832
Divy Le Ray8c263762008-10-08 17:37:33 -07002833/*
2834 * Set the number of qsets based on the number of CPUs and the number of ports,
2835 * not to exceed the number of available qsets, assuming there are enough qsets
2836 * per port in HW.
2837 */
2838static void set_nqsets(struct adapter *adap)
2839{
2840 int i, j = 0;
2841 int num_cpus = num_online_cpus();
2842 int hwports = adap->params.nports;
Divy Le Ray5cda9362009-01-18 21:29:40 -08002843 int nqsets = adap->msix_nvectors - 1;
Divy Le Ray8c263762008-10-08 17:37:33 -07002844
Divy Le Rayf9ee3882008-11-09 00:55:33 -08002845 if (adap->params.rev > 0 && adap->flags & USING_MSIX) {
Divy Le Ray8c263762008-10-08 17:37:33 -07002846 if (hwports == 2 &&
2847 (hwports * nqsets > SGE_QSETS ||
2848 num_cpus >= nqsets / hwports))
2849 nqsets /= hwports;
2850 if (nqsets > num_cpus)
2851 nqsets = num_cpus;
2852 if (nqsets < 1 || hwports == 4)
2853 nqsets = 1;
2854 } else
2855 nqsets = 1;
2856
2857 for_each_port(adap, i) {
2858 struct port_info *pi = adap2pinfo(adap, i);
2859
2860 pi->first_qset = j;
2861 pi->nqsets = nqsets;
2862 j = pi->first_qset + nqsets;
2863
2864 dev_info(&adap->pdev->dev,
2865 "Port %d using %d queue sets.\n", i, nqsets);
2866 }
2867}
2868
Divy Le Ray4d22de32007-01-18 22:04:14 -05002869static int __devinit cxgb_enable_msix(struct adapter *adap)
2870{
2871 struct msix_entry entries[SGE_QSETS + 1];
Divy Le Ray5cda9362009-01-18 21:29:40 -08002872 int vectors;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002873 int i, err;
2874
Divy Le Ray5cda9362009-01-18 21:29:40 -08002875 vectors = ARRAY_SIZE(entries);
2876 for (i = 0; i < vectors; ++i)
Divy Le Ray4d22de32007-01-18 22:04:14 -05002877 entries[i].entry = i;
2878
Divy Le Ray5cda9362009-01-18 21:29:40 -08002879 while ((err = pci_enable_msix(adap->pdev, entries, vectors)) > 0)
2880 vectors = err;
2881
Divy Le Ray2c2f4092009-04-17 12:21:22 +00002882 if (err < 0)
2883 pci_disable_msix(adap->pdev);
2884
2885 if (!err && vectors < (adap->params.nports + 1)) {
2886 pci_disable_msix(adap->pdev);
Divy Le Ray5cda9362009-01-18 21:29:40 -08002887 err = -1;
Divy Le Ray2c2f4092009-04-17 12:21:22 +00002888 }
Divy Le Ray5cda9362009-01-18 21:29:40 -08002889
Divy Le Ray4d22de32007-01-18 22:04:14 -05002890 if (!err) {
Divy Le Ray5cda9362009-01-18 21:29:40 -08002891 for (i = 0; i < vectors; ++i)
Divy Le Ray4d22de32007-01-18 22:04:14 -05002892 adap->msix_info[i].vec = entries[i].vector;
Divy Le Ray5cda9362009-01-18 21:29:40 -08002893 adap->msix_nvectors = vectors;
2894 }
2895
Divy Le Ray4d22de32007-01-18 22:04:14 -05002896 return err;
2897}
2898
2899static void __devinit print_port_info(struct adapter *adap,
2900 const struct adapter_info *ai)
2901{
2902 static const char *pci_variant[] = {
2903 "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express"
2904 };
2905
2906 int i;
2907 char buf[80];
2908
2909 if (is_pcie(adap))
2910 snprintf(buf, sizeof(buf), "%s x%d",
2911 pci_variant[adap->params.pci.variant],
2912 adap->params.pci.width);
2913 else
2914 snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit",
2915 pci_variant[adap->params.pci.variant],
2916 adap->params.pci.speed, adap->params.pci.width);
2917
2918 for_each_port(adap, i) {
2919 struct net_device *dev = adap->port[i];
2920 const struct port_info *pi = netdev_priv(dev);
2921
2922 if (!test_bit(i, &adap->registered_device_map))
2923 continue;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07002924 printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n",
Divy Le Ray04497982008-10-08 17:38:29 -07002925 dev->name, ai->desc, pi->phy.desc,
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07002926 is_offload(adap) ? "R" : "", adap->params.rev, buf,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002927 (adap->flags & USING_MSIX) ? " MSI-X" :
2928 (adap->flags & USING_MSI) ? " MSI" : "");
2929 if (adap->name == dev->name && adap->params.vpd.mclk)
Divy Le Ray167cdf52007-08-21 20:49:36 -07002930 printk(KERN_INFO
2931 "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
Divy Le Ray4d22de32007-01-18 22:04:14 -05002932 adap->name, t3_mc7_size(&adap->cm) >> 20,
2933 t3_mc7_size(&adap->pmtx) >> 20,
Divy Le Ray167cdf52007-08-21 20:49:36 -07002934 t3_mc7_size(&adap->pmrx) >> 20,
2935 adap->params.vpd.sn);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002936 }
2937}
2938
Stephen Hemmingerdd752692008-11-19 22:15:39 -08002939static const struct net_device_ops cxgb_netdev_ops = {
2940 .ndo_open = cxgb_open,
2941 .ndo_stop = cxgb_close,
Divy Le Ray43a944f2008-11-26 15:35:26 -08002942 .ndo_start_xmit = t3_eth_xmit,
Stephen Hemmingerdd752692008-11-19 22:15:39 -08002943 .ndo_get_stats = cxgb_get_stats,
2944 .ndo_validate_addr = eth_validate_addr,
2945 .ndo_set_multicast_list = cxgb_set_rxmode,
2946 .ndo_do_ioctl = cxgb_ioctl,
2947 .ndo_change_mtu = cxgb_change_mtu,
2948 .ndo_set_mac_address = cxgb_set_mac_addr,
2949 .ndo_vlan_rx_register = vlan_rx_register,
2950#ifdef CONFIG_NET_POLL_CONTROLLER
2951 .ndo_poll_controller = cxgb_netpoll,
2952#endif
2953};
2954
Divy Le Ray4d22de32007-01-18 22:04:14 -05002955static int __devinit init_one(struct pci_dev *pdev,
2956 const struct pci_device_id *ent)
2957{
2958 static int version_printed;
2959
2960 int i, err, pci_using_dac = 0;
Divy Le Ray68f40c12009-03-26 16:39:19 +00002961 resource_size_t mmio_start, mmio_len;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002962 const struct adapter_info *ai;
2963 struct adapter *adapter = NULL;
2964 struct port_info *pi;
2965
2966 if (!version_printed) {
2967 printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
2968 ++version_printed;
2969 }
2970
2971 if (!cxgb3_wq) {
2972 cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
2973 if (!cxgb3_wq) {
2974 printk(KERN_ERR DRV_NAME
2975 ": cannot initialize work queue\n");
2976 return -ENOMEM;
2977 }
2978 }
2979
2980 err = pci_request_regions(pdev, DRV_NAME);
2981 if (err) {
2982 /* Just info, some other driver may have claimed the device. */
2983 dev_info(&pdev->dev, "cannot obtain PCI resources\n");
2984 return err;
2985 }
2986
2987 err = pci_enable_device(pdev);
2988 if (err) {
2989 dev_err(&pdev->dev, "cannot enable PCI device\n");
2990 goto out_release_regions;
2991 }
2992
Yang Hongyang6a355282009-04-06 19:01:13 -07002993 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05002994 pci_using_dac = 1;
Yang Hongyang6a355282009-04-06 19:01:13 -07002995 err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
Divy Le Ray4d22de32007-01-18 22:04:14 -05002996 if (err) {
2997 dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
2998 "coherent allocations\n");
2999 goto out_disable_device;
3000 }
Yang Hongyang284901a2009-04-06 19:01:15 -07003001 } else if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003002 dev_err(&pdev->dev, "no usable DMA configuration\n");
3003 goto out_disable_device;
3004 }
3005
3006 pci_set_master(pdev);
Divy Le Ray204e2f92008-05-06 19:26:01 -07003007 pci_save_state(pdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003008
3009 mmio_start = pci_resource_start(pdev, 0);
3010 mmio_len = pci_resource_len(pdev, 0);
3011 ai = t3_get_adapter_info(ent->driver_data);
3012
3013 adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
3014 if (!adapter) {
3015 err = -ENOMEM;
3016 goto out_disable_device;
3017 }
3018
3019 adapter->regs = ioremap_nocache(mmio_start, mmio_len);
3020 if (!adapter->regs) {
3021 dev_err(&pdev->dev, "cannot map device registers\n");
3022 err = -ENOMEM;
3023 goto out_free_adapter;
3024 }
3025
3026 adapter->pdev = pdev;
3027 adapter->name = pci_name(pdev);
3028 adapter->msg_enable = dflt_msg_enable;
3029 adapter->mmio_len = mmio_len;
3030
3031 mutex_init(&adapter->mdio_lock);
3032 spin_lock_init(&adapter->work_lock);
3033 spin_lock_init(&adapter->stats_lock);
3034
3035 INIT_LIST_HEAD(&adapter->adapter_list);
3036 INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07003037 INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003038 INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
3039
Divy Le Ray952cdf32009-03-26 16:39:24 +00003040 for (i = 0; i < ai->nports0 + ai->nports1; ++i) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003041 struct net_device *netdev;
3042
Divy Le Ray82ad3322008-12-16 01:09:39 -08003043 netdev = alloc_etherdev_mq(sizeof(struct port_info), SGE_QSETS);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003044 if (!netdev) {
3045 err = -ENOMEM;
3046 goto out_free_dev;
3047 }
3048
Divy Le Ray4d22de32007-01-18 22:04:14 -05003049 SET_NETDEV_DEV(netdev, &pdev->dev);
3050
3051 adapter->port[i] = netdev;
3052 pi = netdev_priv(netdev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003053 pi->adapter = adapter;
Roland Dreier47fd23f2009-01-11 00:19:36 -08003054 pi->rx_offload = T3_RX_CSUM | T3_LRO;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003055 pi->port_id = i;
3056 netif_carrier_off(netdev);
Divy Le Ray82ad3322008-12-16 01:09:39 -08003057 netif_tx_stop_all_queues(netdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003058 netdev->irq = pdev->irq;
3059 netdev->mem_start = mmio_start;
3060 netdev->mem_end = mmio_start + mmio_len - 1;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003061 netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
3062 netdev->features |= NETIF_F_LLTX;
Herbert Xu7be2df42009-01-21 14:39:13 -08003063 netdev->features |= NETIF_F_GRO;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003064 if (pci_using_dac)
3065 netdev->features |= NETIF_F_HIGHDMA;
3066
3067 netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
Stephen Hemmingerdd752692008-11-19 22:15:39 -08003068 netdev->netdev_ops = &cxgb_netdev_ops;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003069 SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
3070 }
3071
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003072 pci_set_drvdata(pdev, adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003073 if (t3_prep_adapter(adapter, ai, 1) < 0) {
3074 err = -ENODEV;
3075 goto out_free_dev;
3076 }
Jeff Garzik2eab17a2007-11-23 21:59:45 -05003077
Divy Le Ray4d22de32007-01-18 22:04:14 -05003078 /*
3079 * The card is now ready to go. If any errors occur during device
3080 * registration we do not fail the whole card but rather proceed only
3081 * with the ports we manage to register successfully. However we must
3082 * register at least one net device.
3083 */
3084 for_each_port(adapter, i) {
3085 err = register_netdev(adapter->port[i]);
3086 if (err)
3087 dev_warn(&pdev->dev,
3088 "cannot register net device %s, skipping\n",
3089 adapter->port[i]->name);
3090 else {
3091 /*
3092 * Change the name we use for messages to the name of
3093 * the first successfully registered interface.
3094 */
3095 if (!adapter->registered_device_map)
3096 adapter->name = adapter->port[i]->name;
3097
3098 __set_bit(i, &adapter->registered_device_map);
3099 }
3100 }
3101 if (!adapter->registered_device_map) {
3102 dev_err(&pdev->dev, "could not register any net devices\n");
3103 goto out_free_dev;
3104 }
3105
3106 /* Driver's ready. Reflect it on LEDs */
3107 t3_led_ready(adapter);
3108
3109 if (is_offload(adapter)) {
3110 __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
3111 cxgb3_adapter_ofld(adapter);
3112 }
3113
3114 /* See what interrupts we'll be using */
3115 if (msi > 1 && cxgb_enable_msix(adapter) == 0)
3116 adapter->flags |= USING_MSIX;
3117 else if (msi > 0 && pci_enable_msi(pdev) == 0)
3118 adapter->flags |= USING_MSI;
3119
Divy Le Ray8c263762008-10-08 17:37:33 -07003120 set_nqsets(adapter);
3121
Divy Le Ray0ee8d332007-02-08 16:55:59 -08003122 err = sysfs_create_group(&adapter->port[0]->dev.kobj,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003123 &cxgb3_attr_group);
3124
3125 print_port_info(adapter, ai);
3126 return 0;
3127
3128out_free_dev:
3129 iounmap(adapter->regs);
Divy Le Ray952cdf32009-03-26 16:39:24 +00003130 for (i = ai->nports0 + ai->nports1 - 1; i >= 0; --i)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003131 if (adapter->port[i])
3132 free_netdev(adapter->port[i]);
3133
3134out_free_adapter:
3135 kfree(adapter);
3136
3137out_disable_device:
3138 pci_disable_device(pdev);
3139out_release_regions:
3140 pci_release_regions(pdev);
3141 pci_set_drvdata(pdev, NULL);
3142 return err;
3143}
3144
3145static void __devexit remove_one(struct pci_dev *pdev)
3146{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003147 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003148
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003149 if (adapter) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003150 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003151
3152 t3_sge_stop(adapter);
Divy Le Ray0ee8d332007-02-08 16:55:59 -08003153 sysfs_remove_group(&adapter->port[0]->dev.kobj,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003154 &cxgb3_attr_group);
3155
Divy Le Ray4d22de32007-01-18 22:04:14 -05003156 if (is_offload(adapter)) {
3157 cxgb3_adapter_unofld(adapter);
3158 if (test_bit(OFFLOAD_DEVMAP_BIT,
3159 &adapter->open_device_map))
3160 offload_close(&adapter->tdev);
3161 }
3162
Divy Le Ray67d92ab2007-11-16 11:21:50 -08003163 for_each_port(adapter, i)
3164 if (test_bit(i, &adapter->registered_device_map))
3165 unregister_netdev(adapter->port[i]);
3166
Divy Le Ray0ca41c02008-09-25 14:05:28 +00003167 t3_stop_sge_timers(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003168 t3_free_sge_resources(adapter);
3169 cxgb_disable_msi(adapter);
3170
Divy Le Ray4d22de32007-01-18 22:04:14 -05003171 for_each_port(adapter, i)
3172 if (adapter->port[i])
3173 free_netdev(adapter->port[i]);
3174
3175 iounmap(adapter->regs);
3176 kfree(adapter);
3177 pci_release_regions(pdev);
3178 pci_disable_device(pdev);
3179 pci_set_drvdata(pdev, NULL);
3180 }
3181}
3182
3183static struct pci_driver driver = {
3184 .name = DRV_NAME,
3185 .id_table = cxgb3_pci_tbl,
3186 .probe = init_one,
3187 .remove = __devexit_p(remove_one),
Divy Le Ray91a6b502007-11-16 11:21:55 -08003188 .err_handler = &t3_err_handler,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003189};
3190
3191static int __init cxgb3_init_module(void)
3192{
3193 int ret;
3194
3195 cxgb3_offload_init();
3196
3197 ret = pci_register_driver(&driver);
3198 return ret;
3199}
3200
3201static void __exit cxgb3_cleanup_module(void)
3202{
3203 pci_unregister_driver(&driver);
3204 if (cxgb3_wq)
3205 destroy_workqueue(cxgb3_wq);
3206}
3207
3208module_init(cxgb3_init_module);
3209module_exit(cxgb3_cleanup_module);