blob: c9113d3297eeffc71b60ad7650b8e446525648e9 [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 Ray74451422009-05-29 12:52:44 +000094 CH_DEVICE(0x36, 3), /* S320E-CR */
95 CH_DEVICE(0x37, 7), /* N320E-G2 */
Divy Le Ray4d22de32007-01-18 22:04:14 -050096 {0,}
97};
98
99MODULE_DESCRIPTION(DRV_DESC);
100MODULE_AUTHOR("Chelsio Communications");
Divy Le Ray1d68e932007-01-30 19:44:35 -0800101MODULE_LICENSE("Dual BSD/GPL");
Divy Le Ray4d22de32007-01-18 22:04:14 -0500102MODULE_VERSION(DRV_VERSION);
103MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl);
104
105static int dflt_msg_enable = DFLT_MSG_ENABLE;
106
107module_param(dflt_msg_enable, int, 0644);
108MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap");
109
110/*
111 * The driver uses the best interrupt scheme available on a platform in the
112 * order MSI-X, MSI, legacy pin interrupts. This parameter determines which
113 * of these schemes the driver may consider as follows:
114 *
115 * msi = 2: choose from among all three options
116 * msi = 1: only consider MSI and pin interrupts
117 * msi = 0: force pin interrupts
118 */
119static int msi = 2;
120
121module_param(msi, int, 0644);
122MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X");
123
124/*
125 * The driver enables offload as a default.
126 * To disable it, use ofld_disable = 1.
127 */
128
129static int ofld_disable = 0;
130
131module_param(ofld_disable, int, 0644);
132MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not");
133
134/*
135 * We have work elements that we need to cancel when an interface is taken
136 * down. Normally the work elements would be executed by keventd but that
137 * can deadlock because of linkwatch. If our close method takes the rtnl
138 * lock and linkwatch is ahead of our work elements in keventd, linkwatch
139 * will block keventd as it needs the rtnl lock, and we'll deadlock waiting
140 * for our work to complete. Get our own work queue to solve this.
141 */
142static struct workqueue_struct *cxgb3_wq;
143
144/**
145 * link_report - show link status and link speed/duplex
146 * @p: the port whose settings are to be reported
147 *
148 * Shows the link status, speed, and duplex of a port.
149 */
150static void link_report(struct net_device *dev)
151{
152 if (!netif_carrier_ok(dev))
153 printk(KERN_INFO "%s: link down\n", dev->name);
154 else {
155 const char *s = "10Mbps";
156 const struct port_info *p = netdev_priv(dev);
157
158 switch (p->link_config.speed) {
159 case SPEED_10000:
160 s = "10Gbps";
161 break;
162 case SPEED_1000:
163 s = "1000Mbps";
164 break;
165 case SPEED_100:
166 s = "100Mbps";
167 break;
168 }
169
170 printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s,
171 p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
172 }
173}
174
Divy Le Ray34701fd2009-07-07 19:48:32 +0000175static void enable_tx_fifo_drain(struct adapter *adapter,
176 struct port_info *pi)
177{
178 t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0,
179 F_ENDROPPKT);
180 t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0);
181 t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN);
182 t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN);
183}
184
185static void disable_tx_fifo_drain(struct adapter *adapter,
186 struct port_info *pi)
187{
188 t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
189 F_ENDROPPKT, 0);
190}
191
Divy Le Raybf792092009-03-12 21:14:19 +0000192void t3_os_link_fault(struct adapter *adap, int port_id, int state)
193{
194 struct net_device *dev = adap->port[port_id];
195 struct port_info *pi = netdev_priv(dev);
196
197 if (state == netif_carrier_ok(dev))
198 return;
199
200 if (state) {
201 struct cmac *mac = &pi->mac;
202
203 netif_carrier_on(dev);
204
Divy Le Ray34701fd2009-07-07 19:48:32 +0000205 disable_tx_fifo_drain(adap, pi);
206
Divy Le Raybf792092009-03-12 21:14:19 +0000207 /* Clear local faults */
208 t3_xgm_intr_disable(adap, pi->port_id);
209 t3_read_reg(adap, A_XGM_INT_STATUS +
210 pi->mac.offset);
211 t3_write_reg(adap,
212 A_XGM_INT_CAUSE + pi->mac.offset,
213 F_XGM_INT);
214
215 t3_set_reg_field(adap,
216 A_XGM_INT_ENABLE +
217 pi->mac.offset,
218 F_XGM_INT, F_XGM_INT);
219 t3_xgm_intr_enable(adap, pi->port_id);
220
221 t3_mac_enable(mac, MAC_DIRECTION_TX);
Divy Le Ray34701fd2009-07-07 19:48:32 +0000222 } else {
Divy Le Raybf792092009-03-12 21:14:19 +0000223 netif_carrier_off(dev);
224
Divy Le Ray34701fd2009-07-07 19:48:32 +0000225 /* Flush TX FIFO */
226 enable_tx_fifo_drain(adap, pi);
227 }
Divy Le Raybf792092009-03-12 21:14:19 +0000228 link_report(dev);
229}
230
Divy Le Ray4d22de32007-01-18 22:04:14 -0500231/**
232 * t3_os_link_changed - handle link status changes
233 * @adapter: the adapter associated with the link change
234 * @port_id: the port index whose limk status has changed
235 * @link_stat: the new status of the link
236 * @speed: the new speed setting
237 * @duplex: the new duplex setting
238 * @pause: the new flow-control setting
239 *
240 * This is the OS-dependent handler for link status changes. The OS
241 * neutral handler takes care of most of the processing for these events,
242 * then calls this handler for any OS-specific processing.
243 */
244void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
245 int speed, int duplex, int pause)
246{
247 struct net_device *dev = adapter->port[port_id];
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700248 struct port_info *pi = netdev_priv(dev);
249 struct cmac *mac = &pi->mac;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500250
251 /* Skip changes from disabled ports. */
252 if (!netif_running(dev))
253 return;
254
255 if (link_stat != netif_carrier_ok(dev)) {
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700256 if (link_stat) {
Divy Le Ray34701fd2009-07-07 19:48:32 +0000257 disable_tx_fifo_drain(adapter, pi);
258
Divy Le Ray59cf8102007-04-09 20:10:27 -0700259 t3_mac_enable(mac, MAC_DIRECTION_RX);
Divy Le Raybf792092009-03-12 21:14:19 +0000260
261 /* Clear local faults */
262 t3_xgm_intr_disable(adapter, pi->port_id);
263 t3_read_reg(adapter, A_XGM_INT_STATUS +
264 pi->mac.offset);
265 t3_write_reg(adapter,
266 A_XGM_INT_CAUSE + pi->mac.offset,
267 F_XGM_INT);
268
269 t3_set_reg_field(adapter,
270 A_XGM_INT_ENABLE + pi->mac.offset,
271 F_XGM_INT, F_XGM_INT);
272 t3_xgm_intr_enable(adapter, pi->port_id);
273
Divy Le Ray4d22de32007-01-18 22:04:14 -0500274 netif_carrier_on(dev);
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700275 } else {
Divy Le Ray4d22de32007-01-18 22:04:14 -0500276 netif_carrier_off(dev);
Divy Le Raybf792092009-03-12 21:14:19 +0000277
278 t3_xgm_intr_disable(adapter, pi->port_id);
279 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
280 t3_set_reg_field(adapter,
281 A_XGM_INT_ENABLE + pi->mac.offset,
282 F_XGM_INT, 0);
283
284 if (is_10G(adapter))
285 pi->phy.ops->power_down(&pi->phy, 1);
286
287 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
Divy Le Ray59cf8102007-04-09 20:10:27 -0700288 t3_mac_disable(mac, MAC_DIRECTION_RX);
289 t3_link_start(&pi->phy, mac, &pi->link_config);
Divy Le Ray34701fd2009-07-07 19:48:32 +0000290
291 /* Flush TX FIFO */
292 enable_tx_fifo_drain(adapter, pi);
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700293 }
294
Divy Le Ray4d22de32007-01-18 22:04:14 -0500295 link_report(dev);
296 }
297}
298
Divy Le Ray1e882022008-10-08 17:40:07 -0700299/**
300 * t3_os_phymod_changed - handle PHY module changes
301 * @phy: the PHY reporting the module change
302 * @mod_type: new module type
303 *
304 * This is the OS-dependent handler for PHY module changes. It is
305 * invoked when a PHY module is removed or inserted for any OS-specific
306 * processing.
307 */
308void t3_os_phymod_changed(struct adapter *adap, int port_id)
309{
310 static const char *mod_str[] = {
311 NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown"
312 };
313
314 const struct net_device *dev = adap->port[port_id];
315 const struct port_info *pi = netdev_priv(dev);
316
317 if (pi->phy.modtype == phy_modtype_none)
318 printk(KERN_INFO "%s: PHY module unplugged\n", dev->name);
319 else
320 printk(KERN_INFO "%s: %s PHY module inserted\n", dev->name,
321 mod_str[pi->phy.modtype]);
322}
323
Divy Le Ray4d22de32007-01-18 22:04:14 -0500324static void cxgb_set_rxmode(struct net_device *dev)
325{
326 struct t3_rx_mode rm;
327 struct port_info *pi = netdev_priv(dev);
328
329 init_rx_mode(&rm, dev, dev->mc_list);
330 t3_mac_set_rx_mode(&pi->mac, &rm);
331}
332
333/**
334 * link_start - enable a port
335 * @dev: the device to enable
336 *
337 * Performs the MAC and PHY actions needed to enable a port.
338 */
339static void link_start(struct net_device *dev)
340{
341 struct t3_rx_mode rm;
342 struct port_info *pi = netdev_priv(dev);
343 struct cmac *mac = &pi->mac;
344
345 init_rx_mode(&rm, dev, dev->mc_list);
346 t3_mac_reset(mac);
Karen Xief14d42f2009-10-08 09:11:05 +0000347 t3_mac_set_num_ucast(mac, MAX_MAC_IDX);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500348 t3_mac_set_mtu(mac, dev->mtu);
Karen Xief14d42f2009-10-08 09:11:05 +0000349 t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr);
350 t3_mac_set_address(mac, SAN_MAC_IDX, pi->iscsic.mac_addr);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500351 t3_mac_set_rx_mode(mac, &rm);
352 t3_link_start(&pi->phy, mac, &pi->link_config);
353 t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
354}
355
356static inline void cxgb_disable_msi(struct adapter *adapter)
357{
358 if (adapter->flags & USING_MSIX) {
359 pci_disable_msix(adapter->pdev);
360 adapter->flags &= ~USING_MSIX;
361 } else if (adapter->flags & USING_MSI) {
362 pci_disable_msi(adapter->pdev);
363 adapter->flags &= ~USING_MSI;
364 }
365}
366
367/*
368 * Interrupt handler for asynchronous events used with MSI-X.
369 */
370static irqreturn_t t3_async_intr_handler(int irq, void *cookie)
371{
372 t3_slow_intr_handler(cookie);
373 return IRQ_HANDLED;
374}
375
376/*
377 * Name the MSI-X interrupts.
378 */
379static void name_msix_vecs(struct adapter *adap)
380{
381 int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1;
382
383 snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
384 adap->msix_info[0].desc[n] = 0;
385
386 for_each_port(adap, j) {
387 struct net_device *d = adap->port[j];
388 const struct port_info *pi = netdev_priv(d);
389
390 for (i = 0; i < pi->nqsets; i++, msi_idx++) {
391 snprintf(adap->msix_info[msi_idx].desc, n,
Divy Le Ray8c263762008-10-08 17:37:33 -0700392 "%s-%d", d->name, pi->first_qset + i);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500393 adap->msix_info[msi_idx].desc[n] = 0;
394 }
Divy Le Ray8c263762008-10-08 17:37:33 -0700395 }
Divy Le Ray4d22de32007-01-18 22:04:14 -0500396}
397
398static int request_msix_data_irqs(struct adapter *adap)
399{
400 int i, j, err, qidx = 0;
401
402 for_each_port(adap, i) {
403 int nqsets = adap2pinfo(adap, i)->nqsets;
404
405 for (j = 0; j < nqsets; ++j) {
406 err = request_irq(adap->msix_info[qidx + 1].vec,
407 t3_intr_handler(adap,
408 adap->sge.qs[qidx].
409 rspq.polling), 0,
410 adap->msix_info[qidx + 1].desc,
411 &adap->sge.qs[qidx]);
412 if (err) {
413 while (--qidx >= 0)
414 free_irq(adap->msix_info[qidx + 1].vec,
415 &adap->sge.qs[qidx]);
416 return err;
417 }
418 qidx++;
419 }
420 }
421 return 0;
422}
423
Divy Le Ray8c263762008-10-08 17:37:33 -0700424static void free_irq_resources(struct adapter *adapter)
425{
426 if (adapter->flags & USING_MSIX) {
427 int i, n = 0;
428
429 free_irq(adapter->msix_info[0].vec, adapter);
430 for_each_port(adapter, i)
Divy Le Ray5cda9362009-01-18 21:29:40 -0800431 n += adap2pinfo(adapter, i)->nqsets;
Divy Le Ray8c263762008-10-08 17:37:33 -0700432
433 for (i = 0; i < n; ++i)
434 free_irq(adapter->msix_info[i + 1].vec,
435 &adapter->sge.qs[i]);
436 } else
437 free_irq(adapter->pdev->irq, adapter);
438}
439
Divy Le Rayb8819552007-12-17 18:47:31 -0800440static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
441 unsigned long n)
442{
443 int attempts = 5;
444
445 while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
446 if (!--attempts)
447 return -ETIMEDOUT;
448 msleep(10);
449 }
450 return 0;
451}
452
453static int init_tp_parity(struct adapter *adap)
454{
455 int i;
456 struct sk_buff *skb;
457 struct cpl_set_tcb_field *greq;
458 unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
459
460 t3_tp_set_offload_mode(adap, 1);
461
462 for (i = 0; i < 16; i++) {
463 struct cpl_smt_write_req *req;
464
Divy Le Ray74b793e2009-06-09 23:25:21 +0000465 skb = alloc_skb(sizeof(*req), GFP_KERNEL);
466 if (!skb)
467 skb = adap->nofail_skb;
468 if (!skb)
469 goto alloc_skb_fail;
470
Divy Le Rayb8819552007-12-17 18:47:31 -0800471 req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
472 memset(req, 0, sizeof(*req));
473 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
474 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
Divy Le Raydce7d1d2009-07-07 19:48:59 +0000475 req->mtu_idx = NMTUS - 1;
Divy Le Rayb8819552007-12-17 18:47:31 -0800476 req->iff = i;
477 t3_mgmt_tx(adap, skb);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000478 if (skb == adap->nofail_skb) {
479 await_mgmt_replies(adap, cnt, i + 1);
480 adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
481 if (!adap->nofail_skb)
482 goto alloc_skb_fail;
483 }
Divy Le Rayb8819552007-12-17 18:47:31 -0800484 }
485
486 for (i = 0; i < 2048; i++) {
487 struct cpl_l2t_write_req *req;
488
Divy Le Ray74b793e2009-06-09 23:25:21 +0000489 skb = alloc_skb(sizeof(*req), GFP_KERNEL);
490 if (!skb)
491 skb = adap->nofail_skb;
492 if (!skb)
493 goto alloc_skb_fail;
494
Divy Le Rayb8819552007-12-17 18:47:31 -0800495 req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
496 memset(req, 0, sizeof(*req));
497 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
498 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
499 req->params = htonl(V_L2T_W_IDX(i));
500 t3_mgmt_tx(adap, skb);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000501 if (skb == adap->nofail_skb) {
502 await_mgmt_replies(adap, cnt, 16 + i + 1);
503 adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
504 if (!adap->nofail_skb)
505 goto alloc_skb_fail;
506 }
Divy Le Rayb8819552007-12-17 18:47:31 -0800507 }
508
509 for (i = 0; i < 2048; i++) {
510 struct cpl_rte_write_req *req;
511
Divy Le Ray74b793e2009-06-09 23:25:21 +0000512 skb = alloc_skb(sizeof(*req), GFP_KERNEL);
513 if (!skb)
514 skb = adap->nofail_skb;
515 if (!skb)
516 goto alloc_skb_fail;
517
Divy Le Rayb8819552007-12-17 18:47:31 -0800518 req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req));
519 memset(req, 0, sizeof(*req));
520 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
521 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
522 req->l2t_idx = htonl(V_L2T_W_IDX(i));
523 t3_mgmt_tx(adap, skb);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000524 if (skb == adap->nofail_skb) {
525 await_mgmt_replies(adap, cnt, 16 + 2048 + i + 1);
526 adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
527 if (!adap->nofail_skb)
528 goto alloc_skb_fail;
529 }
Divy Le Rayb8819552007-12-17 18:47:31 -0800530 }
531
Divy Le Ray74b793e2009-06-09 23:25:21 +0000532 skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
533 if (!skb)
534 skb = adap->nofail_skb;
535 if (!skb)
536 goto alloc_skb_fail;
537
Divy Le Rayb8819552007-12-17 18:47:31 -0800538 greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq));
539 memset(greq, 0, sizeof(*greq));
540 greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
541 OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
542 greq->mask = cpu_to_be64(1);
543 t3_mgmt_tx(adap, skb);
544
545 i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000546 if (skb == adap->nofail_skb) {
547 i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
548 adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
549 }
550
Divy Le Rayb8819552007-12-17 18:47:31 -0800551 t3_tp_set_offload_mode(adap, 0);
552 return i;
Divy Le Ray74b793e2009-06-09 23:25:21 +0000553
554alloc_skb_fail:
555 t3_tp_set_offload_mode(adap, 0);
556 return -ENOMEM;
Divy Le Rayb8819552007-12-17 18:47:31 -0800557}
558
Divy Le Ray4d22de32007-01-18 22:04:14 -0500559/**
560 * setup_rss - configure RSS
561 * @adap: the adapter
562 *
563 * Sets up RSS to distribute packets to multiple receive queues. We
564 * configure the RSS CPU lookup table to distribute to the number of HW
565 * receive queues, and the response queue lookup table to narrow that
566 * down to the response queues actually configured for each port.
567 * We always configure the RSS mapping for two ports since the mapping
568 * table has plenty of entries.
569 */
570static void setup_rss(struct adapter *adap)
571{
572 int i;
573 unsigned int nq0 = adap2pinfo(adap, 0)->nqsets;
574 unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1;
575 u8 cpus[SGE_QSETS + 1];
576 u16 rspq_map[RSS_TABLE_SIZE];
577
578 for (i = 0; i < SGE_QSETS; ++i)
579 cpus[i] = i;
580 cpus[SGE_QSETS] = 0xff; /* terminator */
581
582 for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
583 rspq_map[i] = i % nq0;
584 rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0;
585 }
586
587 t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
588 F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
Divy Le Raya2604be2007-11-16 11:22:16 -0800589 V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500590}
591
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700592static void init_napi(struct adapter *adap)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500593{
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700594 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500595
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700596 for (i = 0; i < SGE_QSETS; i++) {
597 struct sge_qset *qs = &adap->sge.qs[i];
Divy Le Ray4d22de32007-01-18 22:04:14 -0500598
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700599 if (qs->adap)
600 netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll,
601 64);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500602 }
Divy Le Ray48c4b6d2008-05-06 19:25:56 -0700603
604 /*
605 * netif_napi_add() can be called only once per napi_struct because it
606 * adds each new napi_struct to a list. Be careful not to call it a
607 * second time, e.g., during EEH recovery, by making a note of it.
608 */
609 adap->flags |= NAPI_INIT;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500610}
611
612/*
613 * Wait until all NAPI handlers are descheduled. This includes the handlers of
614 * both netdevices representing interfaces and the dummy ones for the extra
615 * queues.
616 */
617static void quiesce_rx(struct adapter *adap)
618{
619 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500620
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700621 for (i = 0; i < SGE_QSETS; i++)
622 if (adap->sge.qs[i].adap)
623 napi_disable(&adap->sge.qs[i].napi);
624}
Divy Le Ray4d22de32007-01-18 22:04:14 -0500625
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700626static void enable_all_napi(struct adapter *adap)
627{
628 int i;
629 for (i = 0; i < SGE_QSETS; i++)
630 if (adap->sge.qs[i].adap)
631 napi_enable(&adap->sge.qs[i].napi);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500632}
633
634/**
Divy Le Ray04ecb072008-10-28 22:40:32 -0700635 * set_qset_lro - Turn a queue set's LRO capability on and off
636 * @dev: the device the qset is attached to
637 * @qset_idx: the queue set index
638 * @val: the LRO switch
639 *
640 * Sets LRO on or off for a particular queue set.
641 * the device's features flag is updated to reflect the LRO
642 * capability when all queues belonging to the device are
643 * in the same state.
644 */
645static void set_qset_lro(struct net_device *dev, int qset_idx, int val)
646{
647 struct port_info *pi = netdev_priv(dev);
648 struct adapter *adapter = pi->adapter;
Divy Le Ray04ecb072008-10-28 22:40:32 -0700649
650 adapter->params.sge.qset[qset_idx].lro = !!val;
651 adapter->sge.qs[qset_idx].lro_enabled = !!val;
Divy Le Ray04ecb072008-10-28 22:40:32 -0700652}
653
654/**
Divy Le Ray4d22de32007-01-18 22:04:14 -0500655 * setup_sge_qsets - configure SGE Tx/Rx/response queues
656 * @adap: the adapter
657 *
658 * Determines how many sets of SGE queues to use and initializes them.
659 * We support multiple queue sets per port if we have MSI-X, otherwise
660 * just one queue set per port.
661 */
662static int setup_sge_qsets(struct adapter *adap)
663{
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700664 int i, j, err, irq_idx = 0, qset_idx = 0;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -0700665 unsigned int ntxq = SGE_TXQ_PER_SET;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500666
667 if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
668 irq_idx = -1;
669
670 for_each_port(adap, i) {
671 struct net_device *dev = adap->port[i];
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700672 struct port_info *pi = netdev_priv(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500673
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700674 pi->qs = &adap->sge.qs[pi->first_qset];
Roland Dreiere594e962009-07-09 09:30:25 +0000675 for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
Roland Dreier47fd23f2009-01-11 00:19:36 -0800676 set_qset_lro(dev, qset_idx, pi->rx_offload & T3_LRO);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500677 err = t3_sge_alloc_qset(adap, qset_idx, 1,
678 (adap->flags & USING_MSIX) ? qset_idx + 1 :
679 irq_idx,
Divy Le Ray82ad3322008-12-16 01:09:39 -0800680 &adap->params.sge.qset[qset_idx], ntxq, dev,
681 netdev_get_tx_queue(dev, j));
Divy Le Ray4d22de32007-01-18 22:04:14 -0500682 if (err) {
683 t3_free_sge_resources(adap);
684 return err;
685 }
686 }
687 }
688
689 return 0;
690}
691
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800692static ssize_t attr_show(struct device *d, char *buf,
Divy Le Ray896392e2007-02-24 16:43:50 -0800693 ssize_t(*format) (struct net_device *, char *))
Divy Le Ray4d22de32007-01-18 22:04:14 -0500694{
695 ssize_t len;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500696
697 /* Synchronize with ioctls that may shut down the device */
698 rtnl_lock();
Divy Le Ray896392e2007-02-24 16:43:50 -0800699 len = (*format) (to_net_dev(d), buf);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500700 rtnl_unlock();
701 return len;
702}
703
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800704static ssize_t attr_store(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800705 const char *buf, size_t len,
Divy Le Ray896392e2007-02-24 16:43:50 -0800706 ssize_t(*set) (struct net_device *, unsigned int),
Divy Le Ray4d22de32007-01-18 22:04:14 -0500707 unsigned int min_val, unsigned int max_val)
708{
709 char *endp;
710 ssize_t ret;
711 unsigned int val;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500712
713 if (!capable(CAP_NET_ADMIN))
714 return -EPERM;
715
716 val = simple_strtoul(buf, &endp, 0);
717 if (endp == buf || val < min_val || val > max_val)
718 return -EINVAL;
719
720 rtnl_lock();
Divy Le Ray896392e2007-02-24 16:43:50 -0800721 ret = (*set) (to_net_dev(d), val);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500722 if (!ret)
723 ret = len;
724 rtnl_unlock();
725 return ret;
726}
727
728#define CXGB3_SHOW(name, val_expr) \
Divy Le Ray896392e2007-02-24 16:43:50 -0800729static ssize_t format_##name(struct net_device *dev, char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500730{ \
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700731 struct port_info *pi = netdev_priv(dev); \
732 struct adapter *adap = pi->adapter; \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500733 return sprintf(buf, "%u\n", val_expr); \
734} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800735static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
736 char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500737{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800738 return attr_show(d, buf, format_##name); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500739}
740
Divy Le Ray896392e2007-02-24 16:43:50 -0800741static ssize_t set_nfilters(struct net_device *dev, unsigned int val)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500742{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700743 struct port_info *pi = netdev_priv(dev);
744 struct adapter *adap = pi->adapter;
Divy Le Ray9f238482007-03-31 00:23:13 -0700745 int min_tids = is_offload(adap) ? MC5_MIN_TIDS : 0;
Divy Le Ray896392e2007-02-24 16:43:50 -0800746
Divy Le Ray4d22de32007-01-18 22:04:14 -0500747 if (adap->flags & FULL_INIT_DONE)
748 return -EBUSY;
749 if (val && adap->params.rev == 0)
750 return -EINVAL;
Divy Le Ray9f238482007-03-31 00:23:13 -0700751 if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
752 min_tids)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500753 return -EINVAL;
754 adap->params.mc5.nfilters = val;
755 return 0;
756}
757
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800758static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
759 const char *buf, size_t len)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500760{
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800761 return attr_store(d, buf, len, set_nfilters, 0, ~0);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500762}
763
Divy Le Ray896392e2007-02-24 16:43:50 -0800764static ssize_t set_nservers(struct net_device *dev, unsigned int val)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500765{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700766 struct port_info *pi = netdev_priv(dev);
767 struct adapter *adap = pi->adapter;
Divy Le Ray896392e2007-02-24 16:43:50 -0800768
Divy Le Ray4d22de32007-01-18 22:04:14 -0500769 if (adap->flags & FULL_INIT_DONE)
770 return -EBUSY;
Divy Le Ray9f238482007-03-31 00:23:13 -0700771 if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters -
772 MC5_MIN_TIDS)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500773 return -EINVAL;
774 adap->params.mc5.nservers = val;
775 return 0;
776}
777
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800778static ssize_t store_nservers(struct device *d, struct device_attribute *attr,
779 const char *buf, size_t len)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500780{
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800781 return attr_store(d, buf, len, set_nservers, 0, ~0);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500782}
783
784#define CXGB3_ATTR_R(name, val_expr) \
785CXGB3_SHOW(name, val_expr) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800786static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500787
788#define CXGB3_ATTR_RW(name, val_expr, store_method) \
789CXGB3_SHOW(name, val_expr) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800790static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500791
792CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));
793CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);
794CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);
795
796static struct attribute *cxgb3_attrs[] = {
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800797 &dev_attr_cam_size.attr,
798 &dev_attr_nfilters.attr,
799 &dev_attr_nservers.attr,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500800 NULL
801};
802
803static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
804
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800805static ssize_t tm_attr_show(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800806 char *buf, int sched)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500807{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700808 struct port_info *pi = netdev_priv(to_net_dev(d));
809 struct adapter *adap = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500810 unsigned int v, addr, bpt, cpt;
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700811 ssize_t len;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500812
813 addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
814 rtnl_lock();
815 t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
816 v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
817 if (sched & 1)
818 v >>= 16;
819 bpt = (v >> 8) & 0xff;
820 cpt = v & 0xff;
821 if (!cpt)
822 len = sprintf(buf, "disabled\n");
823 else {
824 v = (adap->params.vpd.cclk * 1000) / cpt;
825 len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125);
826 }
827 rtnl_unlock();
828 return len;
829}
830
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800831static ssize_t tm_attr_store(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800832 const char *buf, size_t len, int sched)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500833{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700834 struct port_info *pi = netdev_priv(to_net_dev(d));
835 struct adapter *adap = pi->adapter;
836 unsigned int val;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500837 char *endp;
838 ssize_t ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500839
840 if (!capable(CAP_NET_ADMIN))
841 return -EPERM;
842
843 val = simple_strtoul(buf, &endp, 0);
844 if (endp == buf || val > 10000000)
845 return -EINVAL;
846
847 rtnl_lock();
848 ret = t3_config_sched(adap, val, sched);
849 if (!ret)
850 ret = len;
851 rtnl_unlock();
852 return ret;
853}
854
855#define TM_ATTR(name, sched) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800856static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
857 char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500858{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800859 return tm_attr_show(d, buf, sched); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500860} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800861static ssize_t store_##name(struct device *d, struct device_attribute *attr, \
862 const char *buf, size_t len) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500863{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800864 return tm_attr_store(d, buf, len, sched); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500865} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800866static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500867
868TM_ATTR(sched0, 0);
869TM_ATTR(sched1, 1);
870TM_ATTR(sched2, 2);
871TM_ATTR(sched3, 3);
872TM_ATTR(sched4, 4);
873TM_ATTR(sched5, 5);
874TM_ATTR(sched6, 6);
875TM_ATTR(sched7, 7);
876
877static struct attribute *offload_attrs[] = {
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800878 &dev_attr_sched0.attr,
879 &dev_attr_sched1.attr,
880 &dev_attr_sched2.attr,
881 &dev_attr_sched3.attr,
882 &dev_attr_sched4.attr,
883 &dev_attr_sched5.attr,
884 &dev_attr_sched6.attr,
885 &dev_attr_sched7.attr,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500886 NULL
887};
888
889static struct attribute_group offload_attr_group = {.attrs = offload_attrs };
890
891/*
892 * Sends an sk_buff to an offload queue driver
893 * after dealing with any active network taps.
894 */
895static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
896{
897 int ret;
898
899 local_bh_disable();
900 ret = t3_offload_tx(tdev, skb);
901 local_bh_enable();
902 return ret;
903}
904
905static int write_smt_entry(struct adapter *adapter, int idx)
906{
907 struct cpl_smt_write_req *req;
Karen Xief14d42f2009-10-08 09:11:05 +0000908 struct port_info *pi = netdev_priv(adapter->port[idx]);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500909 struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);
910
911 if (!skb)
912 return -ENOMEM;
913
914 req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
915 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
916 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
917 req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */
918 req->iff = idx;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500919 memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);
Karen Xief14d42f2009-10-08 09:11:05 +0000920 memcpy(req->src_mac1, pi->iscsic.mac_addr, ETH_ALEN);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500921 skb->priority = 1;
922 offload_tx(&adapter->tdev, skb);
923 return 0;
924}
925
926static int init_smt(struct adapter *adapter)
927{
928 int i;
929
930 for_each_port(adapter, i)
931 write_smt_entry(adapter, i);
932 return 0;
933}
934
935static void init_port_mtus(struct adapter *adapter)
936{
937 unsigned int mtus = adapter->port[0]->mtu;
938
939 if (adapter->port[1])
940 mtus |= adapter->port[1]->mtu << 16;
941 t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
942}
943
Divy Le Ray8c263762008-10-08 17:37:33 -0700944static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
Divy Le Ray14ab9892007-01-30 19:43:50 -0800945 int hi, int port)
946{
947 struct sk_buff *skb;
948 struct mngt_pktsched_wr *req;
Divy Le Ray8c263762008-10-08 17:37:33 -0700949 int ret;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800950
Divy Le Ray74b793e2009-06-09 23:25:21 +0000951 skb = alloc_skb(sizeof(*req), GFP_KERNEL);
952 if (!skb)
953 skb = adap->nofail_skb;
954 if (!skb)
955 return -ENOMEM;
956
Divy Le Ray14ab9892007-01-30 19:43:50 -0800957 req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
958 req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
959 req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
960 req->sched = sched;
961 req->idx = qidx;
962 req->min = lo;
963 req->max = hi;
964 req->binding = port;
Divy Le Ray8c263762008-10-08 17:37:33 -0700965 ret = t3_mgmt_tx(adap, skb);
Divy Le Ray74b793e2009-06-09 23:25:21 +0000966 if (skb == adap->nofail_skb) {
967 adap->nofail_skb = alloc_skb(sizeof(struct cpl_set_tcb_field),
968 GFP_KERNEL);
969 if (!adap->nofail_skb)
970 ret = -ENOMEM;
971 }
Divy Le Ray8c263762008-10-08 17:37:33 -0700972
973 return ret;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800974}
975
Divy Le Ray8c263762008-10-08 17:37:33 -0700976static int bind_qsets(struct adapter *adap)
Divy Le Ray14ab9892007-01-30 19:43:50 -0800977{
Divy Le Ray8c263762008-10-08 17:37:33 -0700978 int i, j, err = 0;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800979
980 for_each_port(adap, i) {
981 const struct port_info *pi = adap2pinfo(adap, i);
982
Divy Le Ray8c263762008-10-08 17:37:33 -0700983 for (j = 0; j < pi->nqsets; ++j) {
984 int ret = send_pktsched_cmd(adap, 1,
985 pi->first_qset + j, -1,
986 -1, i);
987 if (ret)
988 err = ret;
989 }
Divy Le Ray14ab9892007-01-30 19:43:50 -0800990 }
Divy Le Ray8c263762008-10-08 17:37:33 -0700991
992 return err;
Divy Le Ray14ab9892007-01-30 19:43:50 -0800993}
994
Divy Le Ray851fd7b2008-11-26 15:38:36 -0800995#define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin"
996#define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin"
Divy Le Ray2e8c07c2009-07-07 19:49:09 +0000997#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin"
998#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin"
Divy Le Ray94505262009-07-30 21:23:34 +0000999#define AEL2020_TWX_EDC_NAME "cxgb3/ael2020_twx_edc.bin"
Divy Le Ray2e8c07c2009-07-07 19:49:09 +00001000
1001static inline const char *get_edc_fw_name(int edc_idx)
1002{
1003 const char *fw_name = NULL;
1004
1005 switch (edc_idx) {
1006 case EDC_OPT_AEL2005:
1007 fw_name = AEL2005_OPT_EDC_NAME;
1008 break;
1009 case EDC_TWX_AEL2005:
1010 fw_name = AEL2005_TWX_EDC_NAME;
1011 break;
1012 case EDC_TWX_AEL2020:
1013 fw_name = AEL2020_TWX_EDC_NAME;
1014 break;
1015 }
1016 return fw_name;
1017}
1018
1019int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size)
1020{
1021 struct adapter *adapter = phy->adapter;
1022 const struct firmware *fw;
1023 char buf[64];
1024 u32 csum;
1025 const __be32 *p;
1026 u16 *cache = phy->phy_cache;
1027 int i, ret;
1028
1029 snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx));
1030
1031 ret = request_firmware(&fw, buf, &adapter->pdev->dev);
1032 if (ret < 0) {
1033 dev_err(&adapter->pdev->dev,
1034 "could not upgrade firmware: unable to load %s\n",
1035 buf);
1036 return ret;
1037 }
1038
1039 /* check size, take checksum in account */
1040 if (fw->size > size + 4) {
1041 CH_ERR(adapter, "firmware image too large %u, expected %d\n",
1042 (unsigned int)fw->size, size + 4);
1043 ret = -EINVAL;
1044 }
1045
1046 /* compute checksum */
1047 p = (const __be32 *)fw->data;
1048 for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++)
1049 csum += ntohl(p[i]);
1050
1051 if (csum != 0xffffffff) {
1052 CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
1053 csum);
1054 ret = -EINVAL;
1055 }
1056
1057 for (i = 0; i < size / 4 ; i++) {
1058 *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16;
1059 *cache++ = be32_to_cpu(p[i]) & 0xffff;
1060 }
1061
1062 release_firmware(fw);
1063
1064 return ret;
1065}
Divy Le Ray2e283962007-03-18 13:10:06 -07001066
1067static int upgrade_fw(struct adapter *adap)
1068{
1069 int ret;
1070 char buf[64];
1071 const struct firmware *fw;
1072 struct device *dev = &adap->pdev->dev;
1073
1074 snprintf(buf, sizeof(buf), FW_FNAME, FW_VERSION_MAJOR,
Divy Le Ray7f672cf2007-03-31 00:23:30 -07001075 FW_VERSION_MINOR, FW_VERSION_MICRO);
Divy Le Ray2e283962007-03-18 13:10:06 -07001076 ret = request_firmware(&fw, buf, dev);
1077 if (ret < 0) {
1078 dev_err(dev, "could not upgrade firmware: unable to load %s\n",
1079 buf);
1080 return ret;
1081 }
1082 ret = t3_load_fw(adap, fw->data, fw->size);
1083 release_firmware(fw);
Divy Le Ray47330072007-08-29 19:15:52 -07001084
1085 if (ret == 0)
1086 dev_info(dev, "successful upgrade to firmware %d.%d.%d\n",
1087 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
1088 else
1089 dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n",
1090 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001091
Divy Le Ray47330072007-08-29 19:15:52 -07001092 return ret;
1093}
1094
1095static inline char t3rev2char(struct adapter *adapter)
1096{
1097 char rev = 0;
1098
1099 switch(adapter->params.rev) {
1100 case T3_REV_B:
1101 case T3_REV_B2:
1102 rev = 'b';
1103 break;
Divy Le Ray1aafee22007-09-05 15:58:36 -07001104 case T3_REV_C:
1105 rev = 'c';
1106 break;
Divy Le Ray47330072007-08-29 19:15:52 -07001107 }
1108 return rev;
1109}
1110
Stephen Hemminger9265fab2007-10-08 16:22:29 -07001111static int update_tpsram(struct adapter *adap)
Divy Le Ray47330072007-08-29 19:15:52 -07001112{
1113 const struct firmware *tpsram;
1114 char buf[64];
1115 struct device *dev = &adap->pdev->dev;
1116 int ret;
1117 char rev;
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001118
Divy Le Ray47330072007-08-29 19:15:52 -07001119 rev = t3rev2char(adap);
1120 if (!rev)
1121 return 0;
1122
1123 snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
1124 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1125
1126 ret = request_firmware(&tpsram, buf, dev);
1127 if (ret < 0) {
1128 dev_err(dev, "could not load TP SRAM: unable to load %s\n",
1129 buf);
1130 return ret;
1131 }
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001132
Divy Le Ray47330072007-08-29 19:15:52 -07001133 ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
1134 if (ret)
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001135 goto release_tpsram;
Divy Le Ray47330072007-08-29 19:15:52 -07001136
1137 ret = t3_set_proto_sram(adap, tpsram->data);
1138 if (ret == 0)
1139 dev_info(dev,
1140 "successful update of protocol engine "
1141 "to %d.%d.%d\n",
1142 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1143 else
1144 dev_err(dev, "failed to update of protocol engine %d.%d.%d\n",
1145 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1146 if (ret)
1147 dev_err(dev, "loading protocol SRAM failed\n");
1148
1149release_tpsram:
1150 release_firmware(tpsram);
Jeff Garzik2eab17a2007-11-23 21:59:45 -05001151
Divy Le Ray2e283962007-03-18 13:10:06 -07001152 return ret;
1153}
1154
Divy Le Ray4d22de32007-01-18 22:04:14 -05001155/**
1156 * cxgb_up - enable the adapter
1157 * @adapter: adapter being enabled
1158 *
1159 * Called when the first port is enabled, this function performs the
1160 * actions necessary to make an adapter operational, such as completing
1161 * the initialization of HW modules, and enabling interrupts.
1162 *
1163 * Must be called with the rtnl lock held.
1164 */
1165static int cxgb_up(struct adapter *adap)
1166{
Denis Chengc54f5c22007-07-18 15:24:49 +08001167 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001168
1169 if (!(adap->flags & FULL_INIT_DONE)) {
Divy Le Ray8207bef2008-12-16 01:51:47 -08001170 err = t3_check_fw_version(adap);
Divy Le Raya5a3b462007-09-05 15:58:09 -07001171 if (err == -EINVAL) {
Divy Le Ray2e283962007-03-18 13:10:06 -07001172 err = upgrade_fw(adap);
Divy Le Ray8207bef2008-12-16 01:51:47 -08001173 CH_WARN(adap, "FW upgrade to %d.%d.%d %s\n",
1174 FW_VERSION_MAJOR, FW_VERSION_MINOR,
1175 FW_VERSION_MICRO, err ? "failed" : "succeeded");
Divy Le Raya5a3b462007-09-05 15:58:09 -07001176 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001177
Divy Le Ray8207bef2008-12-16 01:51:47 -08001178 err = t3_check_tpsram_version(adap);
Divy Le Ray47330072007-08-29 19:15:52 -07001179 if (err == -EINVAL) {
1180 err = update_tpsram(adap);
Divy Le Ray8207bef2008-12-16 01:51:47 -08001181 CH_WARN(adap, "TP upgrade to %d.%d.%d %s\n",
1182 TP_VERSION_MAJOR, TP_VERSION_MINOR,
1183 TP_VERSION_MICRO, err ? "failed" : "succeeded");
Divy Le Ray47330072007-08-29 19:15:52 -07001184 }
1185
Divy Le Ray20d3fc12008-10-08 17:36:03 -07001186 /*
1187 * Clear interrupts now to catch errors if t3_init_hw fails.
1188 * We clear them again later as initialization may trigger
1189 * conditions that can interrupt.
1190 */
1191 t3_intr_clear(adap);
1192
Divy Le Ray4d22de32007-01-18 22:04:14 -05001193 err = t3_init_hw(adap, 0);
1194 if (err)
1195 goto out;
1196
Divy Le Rayb8819552007-12-17 18:47:31 -08001197 t3_set_reg_field(adap, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
Divy Le Ray6cdbd772007-04-09 20:10:33 -07001198 t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
Stephen Hemmingerbea33482007-10-03 16:41:36 -07001199
Divy Le Ray4d22de32007-01-18 22:04:14 -05001200 err = setup_sge_qsets(adap);
1201 if (err)
1202 goto out;
1203
1204 setup_rss(adap);
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001205 if (!(adap->flags & NAPI_INIT))
1206 init_napi(adap);
Divy Le Ray31563782009-03-26 16:39:09 +00001207
1208 t3_start_sge_timers(adap);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001209 adap->flags |= FULL_INIT_DONE;
1210 }
1211
1212 t3_intr_clear(adap);
1213
1214 if (adap->flags & USING_MSIX) {
1215 name_msix_vecs(adap);
1216 err = request_irq(adap->msix_info[0].vec,
1217 t3_async_intr_handler, 0,
1218 adap->msix_info[0].desc, adap);
1219 if (err)
1220 goto irq_err;
1221
Divy Le Ray42256f52007-11-16 11:21:39 -08001222 err = request_msix_data_irqs(adap);
1223 if (err) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001224 free_irq(adap->msix_info[0].vec, adap);
1225 goto irq_err;
1226 }
1227 } else if ((err = request_irq(adap->pdev->irq,
1228 t3_intr_handler(adap,
1229 adap->sge.qs[0].rspq.
1230 polling),
Thomas Gleixner2db63462007-02-14 00:33:20 -08001231 (adap->flags & USING_MSI) ?
1232 0 : IRQF_SHARED,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001233 adap->name, adap)))
1234 goto irq_err;
1235
Stephen Hemmingerbea33482007-10-03 16:41:36 -07001236 enable_all_napi(adap);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001237 t3_sge_start(adap);
1238 t3_intr_enable(adap);
Divy Le Ray14ab9892007-01-30 19:43:50 -08001239
Divy Le Rayb8819552007-12-17 18:47:31 -08001240 if (adap->params.rev >= T3_REV_C && !(adap->flags & TP_PARITY_INIT) &&
1241 is_offload(adap) && init_tp_parity(adap) == 0)
1242 adap->flags |= TP_PARITY_INIT;
1243
1244 if (adap->flags & TP_PARITY_INIT) {
1245 t3_write_reg(adap, A_TP_INT_CAUSE,
1246 F_CMCACHEPERR | F_ARPLUTPERR);
1247 t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff);
1248 }
1249
Divy Le Ray8c263762008-10-08 17:37:33 -07001250 if (!(adap->flags & QUEUES_BOUND)) {
1251 err = bind_qsets(adap);
1252 if (err) {
1253 CH_ERR(adap, "failed to bind qsets, err %d\n", err);
1254 t3_intr_disable(adap);
1255 free_irq_resources(adap);
1256 goto out;
1257 }
1258 adap->flags |= QUEUES_BOUND;
1259 }
Divy Le Ray14ab9892007-01-30 19:43:50 -08001260
Divy Le Ray4d22de32007-01-18 22:04:14 -05001261out:
1262 return err;
1263irq_err:
1264 CH_ERR(adap, "request_irq failed, err %d\n", err);
1265 goto out;
1266}
1267
1268/*
1269 * Release resources when all the ports and offloading have been stopped.
1270 */
1271static void cxgb_down(struct adapter *adapter)
1272{
1273 t3_sge_stop(adapter);
1274 spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */
1275 t3_intr_disable(adapter);
1276 spin_unlock_irq(&adapter->work_lock);
1277
Divy Le Ray8c263762008-10-08 17:37:33 -07001278 free_irq_resources(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001279 quiesce_rx(adapter);
Divy Le Rayc80b0c22009-04-17 12:21:17 +00001280 flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */
Divy Le Ray4d22de32007-01-18 22:04:14 -05001281}
1282
1283static void schedule_chk_task(struct adapter *adap)
1284{
1285 unsigned int timeo;
1286
1287 timeo = adap->params.linkpoll_period ?
1288 (HZ * adap->params.linkpoll_period) / 10 :
1289 adap->params.stats_update_period * HZ;
1290 if (timeo)
1291 queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo);
1292}
1293
1294static int offload_open(struct net_device *dev)
1295{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001296 struct port_info *pi = netdev_priv(dev);
1297 struct adapter *adapter = pi->adapter;
1298 struct t3cdev *tdev = dev2t3cdev(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001299 int adap_up = adapter->open_device_map & PORT_MASK;
Denis Chengc54f5c22007-07-18 15:24:49 +08001300 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001301
1302 if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
1303 return 0;
1304
1305 if (!adap_up && (err = cxgb_up(adapter)) < 0)
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001306 goto out;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001307
1308 t3_tp_set_offload_mode(adapter, 1);
1309 tdev->lldev = adapter->port[0];
1310 err = cxgb3_offload_activate(adapter);
1311 if (err)
1312 goto out;
1313
1314 init_port_mtus(adapter);
1315 t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
1316 adapter->params.b_wnd,
1317 adapter->params.rev == 0 ?
1318 adapter->port[0]->mtu : 0xffff);
1319 init_smt(adapter);
1320
Dan Noed96a51f2008-04-12 22:34:38 -04001321 if (sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group))
1322 dev_dbg(&dev->dev, "cannot create sysfs group\n");
Divy Le Ray4d22de32007-01-18 22:04:14 -05001323
1324 /* Call back all registered clients */
1325 cxgb3_add_clients(tdev);
1326
1327out:
1328 /* restore them in case the offload module has changed them */
1329 if (err) {
1330 t3_tp_set_offload_mode(adapter, 0);
1331 clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
1332 cxgb3_set_dummy_ops(tdev);
1333 }
1334 return err;
1335}
1336
1337static int offload_close(struct t3cdev *tdev)
1338{
1339 struct adapter *adapter = tdev2adap(tdev);
1340
1341 if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
1342 return 0;
1343
1344 /* Call back all registered clients */
1345 cxgb3_remove_clients(tdev);
1346
Divy Le Ray0ee8d332007-02-08 16:55:59 -08001347 sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001348
Divy Le Rayc80b0c22009-04-17 12:21:17 +00001349 /* Flush work scheduled while releasing TIDs */
1350 flush_scheduled_work();
1351
Divy Le Ray4d22de32007-01-18 22:04:14 -05001352 tdev->lldev = NULL;
1353 cxgb3_set_dummy_ops(tdev);
1354 t3_tp_set_offload_mode(adapter, 0);
1355 clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
1356
1357 if (!adapter->open_device_map)
1358 cxgb_down(adapter);
1359
1360 cxgb3_offload_deactivate(adapter);
1361 return 0;
1362}
1363
1364static int cxgb_open(struct net_device *dev)
1365{
Divy Le Ray4d22de32007-01-18 22:04:14 -05001366 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001367 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001368 int other_ports = adapter->open_device_map & PORT_MASK;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001369 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001370
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001371 if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001372 return err;
1373
1374 set_bit(pi->port_id, &adapter->open_device_map);
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07001375 if (is_offload(adapter) && !ofld_disable) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001376 err = offload_open(dev);
1377 if (err)
1378 printk(KERN_WARNING
1379 "Could not initialize offload capabilities\n");
1380 }
1381
Divy Le Ray82ad3322008-12-16 01:09:39 -08001382 dev->real_num_tx_queues = pi->nqsets;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001383 link_start(dev);
1384 t3_port_intr_enable(adapter, pi->port_id);
Divy Le Ray82ad3322008-12-16 01:09:39 -08001385 netif_tx_start_all_queues(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001386 if (!other_ports)
1387 schedule_chk_task(adapter);
1388
Steve Wisefa0d4c12009-09-05 20:22:38 -07001389 cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_UP, pi->port_id);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001390 return 0;
1391}
1392
1393static int cxgb_close(struct net_device *dev)
1394{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001395 struct port_info *pi = netdev_priv(dev);
1396 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001397
Divy Le Raye8d19372009-04-17 12:21:27 +00001398
1399 if (!adapter->open_device_map)
1400 return 0;
1401
Divy Le Raybf792092009-03-12 21:14:19 +00001402 /* Stop link fault interrupts */
1403 t3_xgm_intr_disable(adapter, pi->port_id);
1404 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
1405
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001406 t3_port_intr_disable(adapter, pi->port_id);
Divy Le Ray82ad3322008-12-16 01:09:39 -08001407 netif_tx_stop_all_queues(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001408 pi->phy.ops->power_down(&pi->phy, 1);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001409 netif_carrier_off(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001410 t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001411
Divy Le Ray20d3fc12008-10-08 17:36:03 -07001412 spin_lock_irq(&adapter->work_lock); /* sync with update task */
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001413 clear_bit(pi->port_id, &adapter->open_device_map);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07001414 spin_unlock_irq(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001415
1416 if (!(adapter->open_device_map & PORT_MASK))
Divy Le Rayc80b0c22009-04-17 12:21:17 +00001417 cancel_delayed_work_sync(&adapter->adap_check_task);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001418
1419 if (!adapter->open_device_map)
1420 cxgb_down(adapter);
1421
Steve Wisefa0d4c12009-09-05 20:22:38 -07001422 cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_DOWN, pi->port_id);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001423 return 0;
1424}
1425
1426static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
1427{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001428 struct port_info *pi = netdev_priv(dev);
1429 struct adapter *adapter = pi->adapter;
1430 struct net_device_stats *ns = &pi->netstats;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001431 const struct mac_stats *pstats;
1432
1433 spin_lock(&adapter->stats_lock);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001434 pstats = t3_mac_update_stats(&pi->mac);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001435 spin_unlock(&adapter->stats_lock);
1436
1437 ns->tx_bytes = pstats->tx_octets;
1438 ns->tx_packets = pstats->tx_frames;
1439 ns->rx_bytes = pstats->rx_octets;
1440 ns->rx_packets = pstats->rx_frames;
1441 ns->multicast = pstats->rx_mcast_frames;
1442
1443 ns->tx_errors = pstats->tx_underrun;
1444 ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs +
1445 pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short +
1446 pstats->rx_fifo_ovfl;
1447
1448 /* detailed rx_errors */
1449 ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long;
1450 ns->rx_over_errors = 0;
1451 ns->rx_crc_errors = pstats->rx_fcs_errs;
1452 ns->rx_frame_errors = pstats->rx_symbol_errs;
1453 ns->rx_fifo_errors = pstats->rx_fifo_ovfl;
1454 ns->rx_missed_errors = pstats->rx_cong_drops;
1455
1456 /* detailed tx_errors */
1457 ns->tx_aborted_errors = 0;
1458 ns->tx_carrier_errors = 0;
1459 ns->tx_fifo_errors = pstats->tx_underrun;
1460 ns->tx_heartbeat_errors = 0;
1461 ns->tx_window_errors = 0;
1462 return ns;
1463}
1464
1465static u32 get_msglevel(struct net_device *dev)
1466{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001467 struct port_info *pi = netdev_priv(dev);
1468 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001469
1470 return adapter->msg_enable;
1471}
1472
1473static void set_msglevel(struct net_device *dev, u32 val)
1474{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001475 struct port_info *pi = netdev_priv(dev);
1476 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001477
1478 adapter->msg_enable = val;
1479}
1480
1481static char stats_strings[][ETH_GSTRING_LEN] = {
1482 "TxOctetsOK ",
1483 "TxFramesOK ",
1484 "TxMulticastFramesOK",
1485 "TxBroadcastFramesOK",
1486 "TxPauseFrames ",
1487 "TxUnderrun ",
1488 "TxExtUnderrun ",
1489
1490 "TxFrames64 ",
1491 "TxFrames65To127 ",
1492 "TxFrames128To255 ",
1493 "TxFrames256To511 ",
1494 "TxFrames512To1023 ",
1495 "TxFrames1024To1518 ",
1496 "TxFrames1519ToMax ",
1497
1498 "RxOctetsOK ",
1499 "RxFramesOK ",
1500 "RxMulticastFramesOK",
1501 "RxBroadcastFramesOK",
1502 "RxPauseFrames ",
1503 "RxFCSErrors ",
1504 "RxSymbolErrors ",
1505 "RxShortErrors ",
1506 "RxJabberErrors ",
1507 "RxLengthErrors ",
1508 "RxFIFOoverflow ",
1509
1510 "RxFrames64 ",
1511 "RxFrames65To127 ",
1512 "RxFrames128To255 ",
1513 "RxFrames256To511 ",
1514 "RxFrames512To1023 ",
1515 "RxFrames1024To1518 ",
1516 "RxFrames1519ToMax ",
1517
1518 "PhyFIFOErrors ",
1519 "TSO ",
1520 "VLANextractions ",
1521 "VLANinsertions ",
1522 "TxCsumOffload ",
1523 "RxCsumGood ",
Divy Le Rayb47385b2008-05-21 18:56:26 -07001524 "LroAggregated ",
1525 "LroFlushed ",
1526 "LroNoDesc ",
Divy Le Rayfc906642007-03-18 13:10:12 -07001527 "RxDrops ",
1528
1529 "CheckTXEnToggled ",
1530 "CheckResets ",
1531
Divy Le Raybf792092009-03-12 21:14:19 +00001532 "LinkFaults ",
Divy Le Ray4d22de32007-01-18 22:04:14 -05001533};
1534
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001535static int get_sset_count(struct net_device *dev, int sset)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001536{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001537 switch (sset) {
1538 case ETH_SS_STATS:
1539 return ARRAY_SIZE(stats_strings);
1540 default:
1541 return -EOPNOTSUPP;
1542 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001543}
1544
1545#define T3_REGMAP_SIZE (3 * 1024)
1546
1547static int get_regs_len(struct net_device *dev)
1548{
1549 return T3_REGMAP_SIZE;
1550}
1551
1552static int get_eeprom_len(struct net_device *dev)
1553{
1554 return EEPROMSIZE;
1555}
1556
1557static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
1558{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001559 struct port_info *pi = netdev_priv(dev);
1560 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001561 u32 fw_vers = 0;
Divy Le Ray47330072007-08-29 19:15:52 -07001562 u32 tp_vers = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001563
Steve Wisecf3760d2008-11-06 17:06:42 -06001564 spin_lock(&adapter->stats_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001565 t3_get_fw_version(adapter, &fw_vers);
Divy Le Ray47330072007-08-29 19:15:52 -07001566 t3_get_tp_version(adapter, &tp_vers);
Steve Wisecf3760d2008-11-06 17:06:42 -06001567 spin_unlock(&adapter->stats_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001568
1569 strcpy(info->driver, DRV_NAME);
1570 strcpy(info->version, DRV_VERSION);
1571 strcpy(info->bus_info, pci_name(adapter->pdev));
1572 if (!fw_vers)
1573 strcpy(info->fw_version, "N/A");
Divy Le Ray4aac3892007-01-30 19:43:45 -08001574 else {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001575 snprintf(info->fw_version, sizeof(info->fw_version),
Divy Le Ray47330072007-08-29 19:15:52 -07001576 "%s %u.%u.%u TP %u.%u.%u",
Divy Le Ray4aac3892007-01-30 19:43:45 -08001577 G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
1578 G_FW_VERSION_MAJOR(fw_vers),
1579 G_FW_VERSION_MINOR(fw_vers),
Divy Le Ray47330072007-08-29 19:15:52 -07001580 G_FW_VERSION_MICRO(fw_vers),
1581 G_TP_VERSION_MAJOR(tp_vers),
1582 G_TP_VERSION_MINOR(tp_vers),
1583 G_TP_VERSION_MICRO(tp_vers));
Divy Le Ray4aac3892007-01-30 19:43:45 -08001584 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001585}
1586
1587static void get_strings(struct net_device *dev, u32 stringset, u8 * data)
1588{
1589 if (stringset == ETH_SS_STATS)
1590 memcpy(data, stats_strings, sizeof(stats_strings));
1591}
1592
1593static unsigned long collect_sge_port_stats(struct adapter *adapter,
1594 struct port_info *p, int idx)
1595{
1596 int i;
1597 unsigned long tot = 0;
1598
Divy Le Ray8c263762008-10-08 17:37:33 -07001599 for (i = p->first_qset; i < p->first_qset + p->nqsets; ++i)
1600 tot += adapter->sge.qs[i].port_stats[idx];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001601 return tot;
1602}
1603
1604static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
1605 u64 *data)
1606{
Divy Le Ray4d22de32007-01-18 22:04:14 -05001607 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001608 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001609 const struct mac_stats *s;
1610
1611 spin_lock(&adapter->stats_lock);
1612 s = t3_mac_update_stats(&pi->mac);
1613 spin_unlock(&adapter->stats_lock);
1614
1615 *data++ = s->tx_octets;
1616 *data++ = s->tx_frames;
1617 *data++ = s->tx_mcast_frames;
1618 *data++ = s->tx_bcast_frames;
1619 *data++ = s->tx_pause;
1620 *data++ = s->tx_underrun;
1621 *data++ = s->tx_fifo_urun;
1622
1623 *data++ = s->tx_frames_64;
1624 *data++ = s->tx_frames_65_127;
1625 *data++ = s->tx_frames_128_255;
1626 *data++ = s->tx_frames_256_511;
1627 *data++ = s->tx_frames_512_1023;
1628 *data++ = s->tx_frames_1024_1518;
1629 *data++ = s->tx_frames_1519_max;
1630
1631 *data++ = s->rx_octets;
1632 *data++ = s->rx_frames;
1633 *data++ = s->rx_mcast_frames;
1634 *data++ = s->rx_bcast_frames;
1635 *data++ = s->rx_pause;
1636 *data++ = s->rx_fcs_errs;
1637 *data++ = s->rx_symbol_errs;
1638 *data++ = s->rx_short;
1639 *data++ = s->rx_jabber;
1640 *data++ = s->rx_too_long;
1641 *data++ = s->rx_fifo_ovfl;
1642
1643 *data++ = s->rx_frames_64;
1644 *data++ = s->rx_frames_65_127;
1645 *data++ = s->rx_frames_128_255;
1646 *data++ = s->rx_frames_256_511;
1647 *data++ = s->rx_frames_512_1023;
1648 *data++ = s->rx_frames_1024_1518;
1649 *data++ = s->rx_frames_1519_max;
1650
1651 *data++ = pi->phy.fifo_errors;
1652
1653 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO);
1654 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX);
1655 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
1656 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
1657 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
Herbert Xu7be2df42009-01-21 14:39:13 -08001658 *data++ = 0;
1659 *data++ = 0;
1660 *data++ = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001661 *data++ = s->rx_cong_drops;
Divy Le Rayfc906642007-03-18 13:10:12 -07001662
1663 *data++ = s->num_toggled;
1664 *data++ = s->num_resets;
Divy Le Raybf792092009-03-12 21:14:19 +00001665
1666 *data++ = s->link_faults;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001667}
1668
1669static inline void reg_block_dump(struct adapter *ap, void *buf,
1670 unsigned int start, unsigned int end)
1671{
1672 u32 *p = buf + start;
1673
1674 for (; start <= end; start += sizeof(u32))
1675 *p++ = t3_read_reg(ap, start);
1676}
1677
1678static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
1679 void *buf)
1680{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001681 struct port_info *pi = netdev_priv(dev);
1682 struct adapter *ap = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001683
1684 /*
1685 * Version scheme:
1686 * bits 0..9: chip version
1687 * bits 10..15: chip revision
1688 * bit 31: set for PCIe cards
1689 */
1690 regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31);
1691
1692 /*
1693 * We skip the MAC statistics registers because they are clear-on-read.
1694 * Also reading multi-register stats would need to synchronize with the
1695 * periodic mac stats accumulation. Hard to justify the complexity.
1696 */
1697 memset(buf, 0, T3_REGMAP_SIZE);
1698 reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
1699 reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
1700 reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
1701 reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
1702 reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
1703 reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0,
1704 XGM_REG(A_XGM_SERDES_STAT3, 1));
1705 reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
1706 XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
1707}
1708
1709static int restart_autoneg(struct net_device *dev)
1710{
1711 struct port_info *p = netdev_priv(dev);
1712
1713 if (!netif_running(dev))
1714 return -EAGAIN;
1715 if (p->link_config.autoneg != AUTONEG_ENABLE)
1716 return -EINVAL;
1717 p->phy.ops->autoneg_restart(&p->phy);
1718 return 0;
1719}
1720
1721static int cxgb3_phys_id(struct net_device *dev, u32 data)
1722{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001723 struct port_info *pi = netdev_priv(dev);
1724 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001725 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001726
1727 if (data == 0)
1728 data = 2;
1729
1730 for (i = 0; i < data * 2; i++) {
1731 t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
1732 (i & 1) ? F_GPIO0_OUT_VAL : 0);
1733 if (msleep_interruptible(500))
1734 break;
1735 }
1736 t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
1737 F_GPIO0_OUT_VAL);
1738 return 0;
1739}
1740
1741static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1742{
1743 struct port_info *p = netdev_priv(dev);
1744
1745 cmd->supported = p->link_config.supported;
1746 cmd->advertising = p->link_config.advertising;
1747
1748 if (netif_carrier_ok(dev)) {
1749 cmd->speed = p->link_config.speed;
1750 cmd->duplex = p->link_config.duplex;
1751 } else {
1752 cmd->speed = -1;
1753 cmd->duplex = -1;
1754 }
1755
1756 cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
Ben Hutchings0f07c4e2009-04-29 08:07:20 +00001757 cmd->phy_address = p->phy.mdio.prtad;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001758 cmd->transceiver = XCVR_EXTERNAL;
1759 cmd->autoneg = p->link_config.autoneg;
1760 cmd->maxtxpkt = 0;
1761 cmd->maxrxpkt = 0;
1762 return 0;
1763}
1764
1765static int speed_duplex_to_caps(int speed, int duplex)
1766{
1767 int cap = 0;
1768
1769 switch (speed) {
1770 case SPEED_10:
1771 if (duplex == DUPLEX_FULL)
1772 cap = SUPPORTED_10baseT_Full;
1773 else
1774 cap = SUPPORTED_10baseT_Half;
1775 break;
1776 case SPEED_100:
1777 if (duplex == DUPLEX_FULL)
1778 cap = SUPPORTED_100baseT_Full;
1779 else
1780 cap = SUPPORTED_100baseT_Half;
1781 break;
1782 case SPEED_1000:
1783 if (duplex == DUPLEX_FULL)
1784 cap = SUPPORTED_1000baseT_Full;
1785 else
1786 cap = SUPPORTED_1000baseT_Half;
1787 break;
1788 case SPEED_10000:
1789 if (duplex == DUPLEX_FULL)
1790 cap = SUPPORTED_10000baseT_Full;
1791 }
1792 return cap;
1793}
1794
1795#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1796 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1797 ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
1798 ADVERTISED_10000baseT_Full)
1799
1800static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1801{
1802 struct port_info *p = netdev_priv(dev);
1803 struct link_config *lc = &p->link_config;
1804
Divy Le Ray9b1e3652008-10-08 17:39:31 -07001805 if (!(lc->supported & SUPPORTED_Autoneg)) {
1806 /*
1807 * PHY offers a single speed/duplex. See if that's what's
1808 * being requested.
1809 */
1810 if (cmd->autoneg == AUTONEG_DISABLE) {
Hannes Eder97915b52009-02-14 11:16:04 +00001811 int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
Divy Le Ray9b1e3652008-10-08 17:39:31 -07001812 if (lc->supported & cap)
1813 return 0;
1814 }
1815 return -EINVAL;
1816 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001817
1818 if (cmd->autoneg == AUTONEG_DISABLE) {
1819 int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
1820
1821 if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
1822 return -EINVAL;
1823 lc->requested_speed = cmd->speed;
1824 lc->requested_duplex = cmd->duplex;
1825 lc->advertising = 0;
1826 } else {
1827 cmd->advertising &= ADVERTISED_MASK;
1828 cmd->advertising &= lc->supported;
1829 if (!cmd->advertising)
1830 return -EINVAL;
1831 lc->requested_speed = SPEED_INVALID;
1832 lc->requested_duplex = DUPLEX_INVALID;
1833 lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
1834 }
1835 lc->autoneg = cmd->autoneg;
1836 if (netif_running(dev))
1837 t3_link_start(&p->phy, &p->mac, lc);
1838 return 0;
1839}
1840
1841static void get_pauseparam(struct net_device *dev,
1842 struct ethtool_pauseparam *epause)
1843{
1844 struct port_info *p = netdev_priv(dev);
1845
1846 epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
1847 epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0;
1848 epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0;
1849}
1850
1851static int set_pauseparam(struct net_device *dev,
1852 struct ethtool_pauseparam *epause)
1853{
1854 struct port_info *p = netdev_priv(dev);
1855 struct link_config *lc = &p->link_config;
1856
1857 if (epause->autoneg == AUTONEG_DISABLE)
1858 lc->requested_fc = 0;
1859 else if (lc->supported & SUPPORTED_Autoneg)
1860 lc->requested_fc = PAUSE_AUTONEG;
1861 else
1862 return -EINVAL;
1863
1864 if (epause->rx_pause)
1865 lc->requested_fc |= PAUSE_RX;
1866 if (epause->tx_pause)
1867 lc->requested_fc |= PAUSE_TX;
1868 if (lc->autoneg == AUTONEG_ENABLE) {
1869 if (netif_running(dev))
1870 t3_link_start(&p->phy, &p->mac, lc);
1871 } else {
1872 lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1873 if (netif_running(dev))
1874 t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc);
1875 }
1876 return 0;
1877}
1878
1879static u32 get_rx_csum(struct net_device *dev)
1880{
1881 struct port_info *p = netdev_priv(dev);
1882
Roland Dreier47fd23f2009-01-11 00:19:36 -08001883 return p->rx_offload & T3_RX_CSUM;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001884}
1885
1886static int set_rx_csum(struct net_device *dev, u32 data)
1887{
1888 struct port_info *p = netdev_priv(dev);
1889
Roland Dreier47fd23f2009-01-11 00:19:36 -08001890 if (data) {
1891 p->rx_offload |= T3_RX_CSUM;
1892 } else {
Divy Le Rayb47385b2008-05-21 18:56:26 -07001893 int i;
1894
Roland Dreier47fd23f2009-01-11 00:19:36 -08001895 p->rx_offload &= ~(T3_RX_CSUM | T3_LRO);
Divy Le Ray04ecb072008-10-28 22:40:32 -07001896 for (i = p->first_qset; i < p->first_qset + p->nqsets; i++)
1897 set_qset_lro(dev, i, 0);
Divy Le Rayb47385b2008-05-21 18:56:26 -07001898 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001899 return 0;
1900}
1901
1902static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
1903{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001904 struct port_info *pi = netdev_priv(dev);
1905 struct adapter *adapter = pi->adapter;
Divy Le Ray05b97b32007-03-18 13:10:01 -07001906 const struct qset_params *q = &adapter->params.sge.qset[pi->first_qset];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001907
1908 e->rx_max_pending = MAX_RX_BUFFERS;
1909 e->rx_mini_max_pending = 0;
1910 e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
1911 e->tx_max_pending = MAX_TXQ_ENTRIES;
1912
Divy Le Ray05b97b32007-03-18 13:10:01 -07001913 e->rx_pending = q->fl_size;
1914 e->rx_mini_pending = q->rspq_size;
1915 e->rx_jumbo_pending = q->jumbo_size;
1916 e->tx_pending = q->txq_size[0];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001917}
1918
1919static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
1920{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001921 struct port_info *pi = netdev_priv(dev);
1922 struct adapter *adapter = pi->adapter;
Divy Le Ray05b97b32007-03-18 13:10:01 -07001923 struct qset_params *q;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001924 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001925
1926 if (e->rx_pending > MAX_RX_BUFFERS ||
1927 e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
1928 e->tx_pending > MAX_TXQ_ENTRIES ||
1929 e->rx_mini_pending > MAX_RSPQ_ENTRIES ||
1930 e->rx_mini_pending < MIN_RSPQ_ENTRIES ||
1931 e->rx_pending < MIN_FL_ENTRIES ||
1932 e->rx_jumbo_pending < MIN_FL_ENTRIES ||
1933 e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES)
1934 return -EINVAL;
1935
1936 if (adapter->flags & FULL_INIT_DONE)
1937 return -EBUSY;
1938
Divy Le Ray05b97b32007-03-18 13:10:01 -07001939 q = &adapter->params.sge.qset[pi->first_qset];
1940 for (i = 0; i < pi->nqsets; ++i, ++q) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001941 q->rspq_size = e->rx_mini_pending;
1942 q->fl_size = e->rx_pending;
1943 q->jumbo_size = e->rx_jumbo_pending;
1944 q->txq_size[0] = e->tx_pending;
1945 q->txq_size[1] = e->tx_pending;
1946 q->txq_size[2] = e->tx_pending;
1947 }
1948 return 0;
1949}
1950
1951static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
1952{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001953 struct port_info *pi = netdev_priv(dev);
1954 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001955 struct qset_params *qsp = &adapter->params.sge.qset[0];
1956 struct sge_qset *qs = &adapter->sge.qs[0];
1957
1958 if (c->rx_coalesce_usecs * 10 > M_NEWTIMER)
1959 return -EINVAL;
1960
1961 qsp->coalesce_usecs = c->rx_coalesce_usecs;
1962 t3_update_qset_coalesce(qs, qsp);
1963 return 0;
1964}
1965
1966static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
1967{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001968 struct port_info *pi = netdev_priv(dev);
1969 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001970 struct qset_params *q = adapter->params.sge.qset;
1971
1972 c->rx_coalesce_usecs = q->coalesce_usecs;
1973 return 0;
1974}
1975
1976static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
1977 u8 * data)
1978{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001979 struct port_info *pi = netdev_priv(dev);
1980 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001981 int i, err = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001982
1983 u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
1984 if (!buf)
1985 return -ENOMEM;
1986
1987 e->magic = EEPROM_MAGIC;
1988 for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
Al Viro05e5c112007-12-22 18:56:23 +00001989 err = t3_seeprom_read(adapter, i, (__le32 *) & buf[i]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001990
1991 if (!err)
1992 memcpy(data, buf + e->offset, e->len);
1993 kfree(buf);
1994 return err;
1995}
1996
1997static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
1998 u8 * data)
1999{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002000 struct port_info *pi = netdev_priv(dev);
2001 struct adapter *adapter = pi->adapter;
Al Viro05e5c112007-12-22 18:56:23 +00002002 u32 aligned_offset, aligned_len;
2003 __le32 *p;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002004 u8 *buf;
Denis Chengc54f5c22007-07-18 15:24:49 +08002005 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002006
2007 if (eeprom->magic != EEPROM_MAGIC)
2008 return -EINVAL;
2009
2010 aligned_offset = eeprom->offset & ~3;
2011 aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
2012
2013 if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
2014 buf = kmalloc(aligned_len, GFP_KERNEL);
2015 if (!buf)
2016 return -ENOMEM;
Al Viro05e5c112007-12-22 18:56:23 +00002017 err = t3_seeprom_read(adapter, aligned_offset, (__le32 *) buf);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002018 if (!err && aligned_len > 4)
2019 err = t3_seeprom_read(adapter,
2020 aligned_offset + aligned_len - 4,
Al Viro05e5c112007-12-22 18:56:23 +00002021 (__le32 *) & buf[aligned_len - 4]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002022 if (err)
2023 goto out;
2024 memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
2025 } else
2026 buf = data;
2027
2028 err = t3_seeprom_wp(adapter, 0);
2029 if (err)
2030 goto out;
2031
Al Viro05e5c112007-12-22 18:56:23 +00002032 for (p = (__le32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05002033 err = t3_seeprom_write(adapter, aligned_offset, *p);
2034 aligned_offset += 4;
2035 }
2036
2037 if (!err)
2038 err = t3_seeprom_wp(adapter, 1);
2039out:
2040 if (buf != data)
2041 kfree(buf);
2042 return err;
2043}
2044
2045static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
2046{
2047 wol->supported = 0;
2048 wol->wolopts = 0;
2049 memset(&wol->sopass, 0, sizeof(wol->sopass));
2050}
2051
2052static const struct ethtool_ops cxgb_ethtool_ops = {
2053 .get_settings = get_settings,
2054 .set_settings = set_settings,
2055 .get_drvinfo = get_drvinfo,
2056 .get_msglevel = get_msglevel,
2057 .set_msglevel = set_msglevel,
2058 .get_ringparam = get_sge_param,
2059 .set_ringparam = set_sge_param,
2060 .get_coalesce = get_coalesce,
2061 .set_coalesce = set_coalesce,
2062 .get_eeprom_len = get_eeprom_len,
2063 .get_eeprom = get_eeprom,
2064 .set_eeprom = set_eeprom,
2065 .get_pauseparam = get_pauseparam,
2066 .set_pauseparam = set_pauseparam,
2067 .get_rx_csum = get_rx_csum,
2068 .set_rx_csum = set_rx_csum,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002069 .set_tx_csum = ethtool_op_set_tx_csum,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002070 .set_sg = ethtool_op_set_sg,
2071 .get_link = ethtool_op_get_link,
2072 .get_strings = get_strings,
2073 .phys_id = cxgb3_phys_id,
2074 .nway_reset = restart_autoneg,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07002075 .get_sset_count = get_sset_count,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002076 .get_ethtool_stats = get_stats,
2077 .get_regs_len = get_regs_len,
2078 .get_regs = get_regs,
2079 .get_wol = get_wol,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002080 .set_tso = ethtool_op_set_tso,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002081};
2082
2083static int in_range(int val, int lo, int hi)
2084{
2085 return val < 0 || (val <= hi && val >= lo);
2086}
2087
2088static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
2089{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002090 struct port_info *pi = netdev_priv(dev);
2091 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002092 u32 cmd;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002093 int ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002094
2095 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
2096 return -EFAULT;
2097
2098 switch (cmd) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05002099 case CHELSIO_SET_QSET_PARAMS:{
2100 int i;
2101 struct qset_params *q;
2102 struct ch_qset_params t;
Divy Le Ray8c263762008-10-08 17:37:33 -07002103 int q1 = pi->first_qset;
2104 int nqsets = pi->nqsets;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002105
2106 if (!capable(CAP_NET_ADMIN))
2107 return -EPERM;
2108 if (copy_from_user(&t, useraddr, sizeof(t)))
2109 return -EFAULT;
2110 if (t.qset_idx >= SGE_QSETS)
2111 return -EINVAL;
2112 if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
2113 !in_range(t.cong_thres, 0, 255) ||
2114 !in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
2115 MAX_TXQ_ENTRIES) ||
2116 !in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
2117 MAX_TXQ_ENTRIES) ||
2118 !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
2119 MAX_CTRL_TXQ_ENTRIES) ||
2120 !in_range(t.fl_size[0], MIN_FL_ENTRIES,
2121 MAX_RX_BUFFERS)
2122 || !in_range(t.fl_size[1], MIN_FL_ENTRIES,
2123 MAX_RX_JUMBO_BUFFERS)
2124 || !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
2125 MAX_RSPQ_ENTRIES))
2126 return -EINVAL;
Divy Le Ray8c263762008-10-08 17:37:33 -07002127
2128 if ((adapter->flags & FULL_INIT_DONE) && t.lro > 0)
2129 for_each_port(adapter, i) {
2130 pi = adap2pinfo(adapter, i);
2131 if (t.qset_idx >= pi->first_qset &&
2132 t.qset_idx < pi->first_qset + pi->nqsets &&
Roland Dreier47fd23f2009-01-11 00:19:36 -08002133 !(pi->rx_offload & T3_RX_CSUM))
Divy Le Ray8c263762008-10-08 17:37:33 -07002134 return -EINVAL;
2135 }
2136
Divy Le Ray4d22de32007-01-18 22:04:14 -05002137 if ((adapter->flags & FULL_INIT_DONE) &&
2138 (t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
2139 t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
2140 t.txq_size[1] >= 0 || t.txq_size[2] >= 0 ||
2141 t.polling >= 0 || t.cong_thres >= 0))
2142 return -EBUSY;
2143
Divy Le Ray8c263762008-10-08 17:37:33 -07002144 /* Allow setting of any available qset when offload enabled */
2145 if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
2146 q1 = 0;
2147 for_each_port(adapter, i) {
2148 pi = adap2pinfo(adapter, i);
2149 nqsets += pi->first_qset + pi->nqsets;
2150 }
2151 }
2152
2153 if (t.qset_idx < q1)
2154 return -EINVAL;
2155 if (t.qset_idx > q1 + nqsets - 1)
2156 return -EINVAL;
2157
Divy Le Ray4d22de32007-01-18 22:04:14 -05002158 q = &adapter->params.sge.qset[t.qset_idx];
2159
2160 if (t.rspq_size >= 0)
2161 q->rspq_size = t.rspq_size;
2162 if (t.fl_size[0] >= 0)
2163 q->fl_size = t.fl_size[0];
2164 if (t.fl_size[1] >= 0)
2165 q->jumbo_size = t.fl_size[1];
2166 if (t.txq_size[0] >= 0)
2167 q->txq_size[0] = t.txq_size[0];
2168 if (t.txq_size[1] >= 0)
2169 q->txq_size[1] = t.txq_size[1];
2170 if (t.txq_size[2] >= 0)
2171 q->txq_size[2] = t.txq_size[2];
2172 if (t.cong_thres >= 0)
2173 q->cong_thres = t.cong_thres;
2174 if (t.intr_lat >= 0) {
2175 struct sge_qset *qs =
2176 &adapter->sge.qs[t.qset_idx];
2177
2178 q->coalesce_usecs = t.intr_lat;
2179 t3_update_qset_coalesce(qs, q);
2180 }
2181 if (t.polling >= 0) {
2182 if (adapter->flags & USING_MSIX)
2183 q->polling = t.polling;
2184 else {
2185 /* No polling with INTx for T3A */
2186 if (adapter->params.rev == 0 &&
2187 !(adapter->flags & USING_MSI))
2188 t.polling = 0;
2189
2190 for (i = 0; i < SGE_QSETS; i++) {
2191 q = &adapter->params.sge.
2192 qset[i];
2193 q->polling = t.polling;
2194 }
2195 }
2196 }
Divy Le Ray04ecb072008-10-28 22:40:32 -07002197 if (t.lro >= 0)
2198 set_qset_lro(dev, t.qset_idx, t.lro);
2199
Divy Le Ray4d22de32007-01-18 22:04:14 -05002200 break;
2201 }
2202 case CHELSIO_GET_QSET_PARAMS:{
2203 struct qset_params *q;
2204 struct ch_qset_params t;
Divy Le Ray8c263762008-10-08 17:37:33 -07002205 int q1 = pi->first_qset;
2206 int nqsets = pi->nqsets;
2207 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002208
2209 if (copy_from_user(&t, useraddr, sizeof(t)))
2210 return -EFAULT;
Divy Le Ray8c263762008-10-08 17:37:33 -07002211
2212 /* Display qsets for all ports when offload enabled */
2213 if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
2214 q1 = 0;
2215 for_each_port(adapter, i) {
2216 pi = adap2pinfo(adapter, i);
2217 nqsets = pi->first_qset + pi->nqsets;
2218 }
2219 }
2220
2221 if (t.qset_idx >= nqsets)
Divy Le Ray4d22de32007-01-18 22:04:14 -05002222 return -EINVAL;
2223
Divy Le Ray8c263762008-10-08 17:37:33 -07002224 q = &adapter->params.sge.qset[q1 + t.qset_idx];
Divy Le Ray4d22de32007-01-18 22:04:14 -05002225 t.rspq_size = q->rspq_size;
2226 t.txq_size[0] = q->txq_size[0];
2227 t.txq_size[1] = q->txq_size[1];
2228 t.txq_size[2] = q->txq_size[2];
2229 t.fl_size[0] = q->fl_size;
2230 t.fl_size[1] = q->jumbo_size;
2231 t.polling = q->polling;
Divy Le Rayb47385b2008-05-21 18:56:26 -07002232 t.lro = q->lro;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002233 t.intr_lat = q->coalesce_usecs;
2234 t.cong_thres = q->cong_thres;
Divy Le Ray8c263762008-10-08 17:37:33 -07002235 t.qnum = q1;
2236
2237 if (adapter->flags & USING_MSIX)
2238 t.vector = adapter->msix_info[q1 + t.qset_idx + 1].vec;
2239 else
2240 t.vector = adapter->pdev->irq;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002241
2242 if (copy_to_user(useraddr, &t, sizeof(t)))
2243 return -EFAULT;
2244 break;
2245 }
2246 case CHELSIO_SET_QSET_NUM:{
2247 struct ch_reg edata;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002248 unsigned int i, first_qset = 0, other_qsets = 0;
2249
2250 if (!capable(CAP_NET_ADMIN))
2251 return -EPERM;
2252 if (adapter->flags & FULL_INIT_DONE)
2253 return -EBUSY;
2254 if (copy_from_user(&edata, useraddr, sizeof(edata)))
2255 return -EFAULT;
2256 if (edata.val < 1 ||
2257 (edata.val > 1 && !(adapter->flags & USING_MSIX)))
2258 return -EINVAL;
2259
2260 for_each_port(adapter, i)
2261 if (adapter->port[i] && adapter->port[i] != dev)
2262 other_qsets += adap2pinfo(adapter, i)->nqsets;
2263
2264 if (edata.val + other_qsets > SGE_QSETS)
2265 return -EINVAL;
2266
2267 pi->nqsets = edata.val;
2268
2269 for_each_port(adapter, i)
2270 if (adapter->port[i]) {
2271 pi = adap2pinfo(adapter, i);
2272 pi->first_qset = first_qset;
2273 first_qset += pi->nqsets;
2274 }
2275 break;
2276 }
2277 case CHELSIO_GET_QSET_NUM:{
2278 struct ch_reg edata;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002279
2280 edata.cmd = CHELSIO_GET_QSET_NUM;
2281 edata.val = pi->nqsets;
2282 if (copy_to_user(useraddr, &edata, sizeof(edata)))
2283 return -EFAULT;
2284 break;
2285 }
2286 case CHELSIO_LOAD_FW:{
2287 u8 *fw_data;
2288 struct ch_mem_range t;
2289
Alan Cox1b3aa7a2008-04-29 14:29:30 +01002290 if (!capable(CAP_SYS_RAWIO))
Divy Le Ray4d22de32007-01-18 22:04:14 -05002291 return -EPERM;
2292 if (copy_from_user(&t, useraddr, sizeof(t)))
2293 return -EFAULT;
Alan Cox1b3aa7a2008-04-29 14:29:30 +01002294 /* Check t.len sanity ? */
Divy Le Ray4d22de32007-01-18 22:04:14 -05002295 fw_data = kmalloc(t.len, GFP_KERNEL);
2296 if (!fw_data)
2297 return -ENOMEM;
2298
2299 if (copy_from_user
2300 (fw_data, useraddr + sizeof(t), t.len)) {
2301 kfree(fw_data);
2302 return -EFAULT;
2303 }
2304
2305 ret = t3_load_fw(adapter, fw_data, t.len);
2306 kfree(fw_data);
2307 if (ret)
2308 return ret;
2309 break;
2310 }
2311 case CHELSIO_SETMTUTAB:{
2312 struct ch_mtus m;
2313 int i;
2314
2315 if (!is_offload(adapter))
2316 return -EOPNOTSUPP;
2317 if (!capable(CAP_NET_ADMIN))
2318 return -EPERM;
2319 if (offload_running(adapter))
2320 return -EBUSY;
2321 if (copy_from_user(&m, useraddr, sizeof(m)))
2322 return -EFAULT;
2323 if (m.nmtus != NMTUS)
2324 return -EINVAL;
2325 if (m.mtus[0] < 81) /* accommodate SACK */
2326 return -EINVAL;
2327
2328 /* MTUs must be in ascending order */
2329 for (i = 1; i < NMTUS; ++i)
2330 if (m.mtus[i] < m.mtus[i - 1])
2331 return -EINVAL;
2332
2333 memcpy(adapter->params.mtus, m.mtus,
2334 sizeof(adapter->params.mtus));
2335 break;
2336 }
2337 case CHELSIO_GET_PM:{
2338 struct tp_params *p = &adapter->params.tp;
2339 struct ch_pm m = {.cmd = CHELSIO_GET_PM };
2340
2341 if (!is_offload(adapter))
2342 return -EOPNOTSUPP;
2343 m.tx_pg_sz = p->tx_pg_size;
2344 m.tx_num_pg = p->tx_num_pgs;
2345 m.rx_pg_sz = p->rx_pg_size;
2346 m.rx_num_pg = p->rx_num_pgs;
2347 m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan;
2348 if (copy_to_user(useraddr, &m, sizeof(m)))
2349 return -EFAULT;
2350 break;
2351 }
2352 case CHELSIO_SET_PM:{
2353 struct ch_pm m;
2354 struct tp_params *p = &adapter->params.tp;
2355
2356 if (!is_offload(adapter))
2357 return -EOPNOTSUPP;
2358 if (!capable(CAP_NET_ADMIN))
2359 return -EPERM;
2360 if (adapter->flags & FULL_INIT_DONE)
2361 return -EBUSY;
2362 if (copy_from_user(&m, useraddr, sizeof(m)))
2363 return -EFAULT;
vignesh babud9da4662007-07-09 11:50:22 -07002364 if (!is_power_of_2(m.rx_pg_sz) ||
2365 !is_power_of_2(m.tx_pg_sz))
Divy Le Ray4d22de32007-01-18 22:04:14 -05002366 return -EINVAL; /* not power of 2 */
2367 if (!(m.rx_pg_sz & 0x14000))
2368 return -EINVAL; /* not 16KB or 64KB */
2369 if (!(m.tx_pg_sz & 0x1554000))
2370 return -EINVAL;
2371 if (m.tx_num_pg == -1)
2372 m.tx_num_pg = p->tx_num_pgs;
2373 if (m.rx_num_pg == -1)
2374 m.rx_num_pg = p->rx_num_pgs;
2375 if (m.tx_num_pg % 24 || m.rx_num_pg % 24)
2376 return -EINVAL;
2377 if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size ||
2378 m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size)
2379 return -EINVAL;
2380 p->rx_pg_size = m.rx_pg_sz;
2381 p->tx_pg_size = m.tx_pg_sz;
2382 p->rx_num_pgs = m.rx_num_pg;
2383 p->tx_num_pgs = m.tx_num_pg;
2384 break;
2385 }
2386 case CHELSIO_GET_MEM:{
2387 struct ch_mem_range t;
2388 struct mc7 *mem;
2389 u64 buf[32];
2390
2391 if (!is_offload(adapter))
2392 return -EOPNOTSUPP;
2393 if (!(adapter->flags & FULL_INIT_DONE))
2394 return -EIO; /* need the memory controllers */
2395 if (copy_from_user(&t, useraddr, sizeof(t)))
2396 return -EFAULT;
2397 if ((t.addr & 7) || (t.len & 7))
2398 return -EINVAL;
2399 if (t.mem_id == MEM_CM)
2400 mem = &adapter->cm;
2401 else if (t.mem_id == MEM_PMRX)
2402 mem = &adapter->pmrx;
2403 else if (t.mem_id == MEM_PMTX)
2404 mem = &adapter->pmtx;
2405 else
2406 return -EINVAL;
2407
2408 /*
Divy Le Ray18254942007-02-24 16:43:56 -08002409 * Version scheme:
2410 * bits 0..9: chip version
2411 * bits 10..15: chip revision
2412 */
Divy Le Ray4d22de32007-01-18 22:04:14 -05002413 t.version = 3 | (adapter->params.rev << 10);
2414 if (copy_to_user(useraddr, &t, sizeof(t)))
2415 return -EFAULT;
2416
2417 /*
2418 * Read 256 bytes at a time as len can be large and we don't
2419 * want to use huge intermediate buffers.
2420 */
2421 useraddr += sizeof(t); /* advance to start of buffer */
2422 while (t.len) {
2423 unsigned int chunk =
2424 min_t(unsigned int, t.len, sizeof(buf));
2425
2426 ret =
2427 t3_mc7_bd_read(mem, t.addr / 8, chunk / 8,
2428 buf);
2429 if (ret)
2430 return ret;
2431 if (copy_to_user(useraddr, buf, chunk))
2432 return -EFAULT;
2433 useraddr += chunk;
2434 t.addr += chunk;
2435 t.len -= chunk;
2436 }
2437 break;
2438 }
2439 case CHELSIO_SET_TRACE_FILTER:{
2440 struct ch_trace t;
2441 const struct trace_params *tp;
2442
2443 if (!capable(CAP_NET_ADMIN))
2444 return -EPERM;
2445 if (!offload_running(adapter))
2446 return -EAGAIN;
2447 if (copy_from_user(&t, useraddr, sizeof(t)))
2448 return -EFAULT;
2449
2450 tp = (const struct trace_params *)&t.sip;
2451 if (t.config_tx)
2452 t3_config_trace_filter(adapter, tp, 0,
2453 t.invert_match,
2454 t.trace_tx);
2455 if (t.config_rx)
2456 t3_config_trace_filter(adapter, tp, 1,
2457 t.invert_match,
2458 t.trace_rx);
2459 break;
2460 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002461 default:
2462 return -EOPNOTSUPP;
2463 }
2464 return 0;
2465}
2466
2467static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
2468{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002469 struct mii_ioctl_data *data = if_mii(req);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002470 struct port_info *pi = netdev_priv(dev);
2471 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002472
2473 switch (cmd) {
Ben Hutchings0f07c4e2009-04-29 08:07:20 +00002474 case SIOCGMIIREG:
2475 case SIOCSMIIREG:
2476 /* Convert phy_id from older PRTAD/DEVAD format */
2477 if (is_10G(adapter) &&
2478 !mdio_phy_id_is_c45(data->phy_id) &&
2479 (data->phy_id & 0x1f00) &&
2480 !(data->phy_id & 0xe0e0))
2481 data->phy_id = mdio_phy_id_c45(data->phy_id >> 8,
2482 data->phy_id & 0x1f);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002483 /* FALLTHRU */
Ben Hutchings0f07c4e2009-04-29 08:07:20 +00002484 case SIOCGMIIPHY:
2485 return mdio_mii_ioctl(&pi->phy.mdio, data, cmd);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002486 case SIOCCHIOCTL:
2487 return cxgb_extension_ioctl(dev, req->ifr_data);
2488 default:
2489 return -EOPNOTSUPP;
2490 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002491}
2492
2493static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
2494{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002495 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002496 struct adapter *adapter = pi->adapter;
2497 int ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002498
2499 if (new_mtu < 81) /* accommodate SACK */
2500 return -EINVAL;
2501 if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu)))
2502 return ret;
2503 dev->mtu = new_mtu;
2504 init_port_mtus(adapter);
2505 if (adapter->params.rev == 0 && offload_running(adapter))
2506 t3_load_mtus(adapter, adapter->params.mtus,
2507 adapter->params.a_wnd, adapter->params.b_wnd,
2508 adapter->port[0]->mtu);
2509 return 0;
2510}
2511
2512static int cxgb_set_mac_addr(struct net_device *dev, void *p)
2513{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002514 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002515 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002516 struct sockaddr *addr = p;
2517
2518 if (!is_valid_ether_addr(addr->sa_data))
2519 return -EINVAL;
2520
2521 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
Karen Xief14d42f2009-10-08 09:11:05 +00002522 t3_mac_set_address(&pi->mac, LAN_MAC_IDX, dev->dev_addr);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002523 if (offload_running(adapter))
2524 write_smt_entry(adapter, pi->port_id);
2525 return 0;
2526}
2527
2528/**
2529 * t3_synchronize_rx - wait for current Rx processing on a port to complete
2530 * @adap: the adapter
2531 * @p: the port
2532 *
2533 * Ensures that current Rx processing on any of the queues associated with
2534 * the given port completes before returning. We do this by acquiring and
2535 * releasing the locks of the response queues associated with the port.
2536 */
2537static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
2538{
2539 int i;
2540
Divy Le Ray8c263762008-10-08 17:37:33 -07002541 for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
2542 struct sge_rspq *q = &adap->sge.qs[i].rspq;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002543
2544 spin_lock_irq(&q->lock);
2545 spin_unlock_irq(&q->lock);
2546 }
2547}
2548
2549static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
2550{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002551 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002552 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002553
2554 pi->vlan_grp = grp;
2555 if (adapter->params.rev > 0)
2556 t3_set_vlan_accel(adapter, 1 << pi->port_id, grp != NULL);
2557 else {
2558 /* single control for all ports */
2559 unsigned int i, have_vlans = 0;
2560 for_each_port(adapter, i)
2561 have_vlans |= adap2pinfo(adapter, i)->vlan_grp != NULL;
2562
2563 t3_set_vlan_accel(adapter, 1, have_vlans);
2564 }
2565 t3_synchronize_rx(adapter, pi);
2566}
2567
Divy Le Ray4d22de32007-01-18 22:04:14 -05002568#ifdef CONFIG_NET_POLL_CONTROLLER
2569static void cxgb_netpoll(struct net_device *dev)
2570{
Divy Le Ray890de332007-05-30 10:01:34 -07002571 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002572 struct adapter *adapter = pi->adapter;
Divy Le Ray890de332007-05-30 10:01:34 -07002573 int qidx;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002574
Divy Le Ray890de332007-05-30 10:01:34 -07002575 for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) {
2576 struct sge_qset *qs = &adapter->sge.qs[qidx];
2577 void *source;
Jeff Garzik2eab17a2007-11-23 21:59:45 -05002578
Divy Le Ray890de332007-05-30 10:01:34 -07002579 if (adapter->flags & USING_MSIX)
2580 source = qs;
2581 else
2582 source = adapter;
2583
2584 t3_intr_handler(adapter, qs->rspq.polling) (0, source);
2585 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002586}
2587#endif
2588
2589/*
2590 * Periodic accumulation of MAC statistics.
2591 */
2592static void mac_stats_update(struct adapter *adapter)
2593{
2594 int i;
2595
2596 for_each_port(adapter, i) {
2597 struct net_device *dev = adapter->port[i];
2598 struct port_info *p = netdev_priv(dev);
2599
2600 if (netif_running(dev)) {
2601 spin_lock(&adapter->stats_lock);
2602 t3_mac_update_stats(&p->mac);
2603 spin_unlock(&adapter->stats_lock);
2604 }
2605 }
2606}
2607
2608static void check_link_status(struct adapter *adapter)
2609{
2610 int i;
2611
2612 for_each_port(adapter, i) {
2613 struct net_device *dev = adapter->port[i];
2614 struct port_info *p = netdev_priv(dev);
Divy Le Rayc22c8142009-05-28 11:23:08 +00002615 int link_fault;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002616
Divy Le Raybf792092009-03-12 21:14:19 +00002617 spin_lock_irq(&adapter->work_lock);
Divy Le Rayc22c8142009-05-28 11:23:08 +00002618 link_fault = p->link_fault;
2619 spin_unlock_irq(&adapter->work_lock);
2620
2621 if (link_fault) {
Divy Le Ray3851c662009-04-17 12:21:11 +00002622 t3_link_fault(adapter, i);
Divy Le Raybf792092009-03-12 21:14:19 +00002623 continue;
2624 }
Divy Le Raybf792092009-03-12 21:14:19 +00002625
2626 if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) {
2627 t3_xgm_intr_disable(adapter, i);
2628 t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
2629
Divy Le Ray4d22de32007-01-18 22:04:14 -05002630 t3_link_changed(adapter, i);
Divy Le Raybf792092009-03-12 21:14:19 +00002631 t3_xgm_intr_enable(adapter, i);
2632 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002633 }
2634}
2635
Divy Le Rayfc906642007-03-18 13:10:12 -07002636static void check_t3b2_mac(struct adapter *adapter)
2637{
2638 int i;
2639
Divy Le Rayf2d961c2007-04-09 20:10:22 -07002640 if (!rtnl_trylock()) /* synchronize with ifdown */
2641 return;
2642
Divy Le Rayfc906642007-03-18 13:10:12 -07002643 for_each_port(adapter, i) {
2644 struct net_device *dev = adapter->port[i];
2645 struct port_info *p = netdev_priv(dev);
2646 int status;
2647
2648 if (!netif_running(dev))
2649 continue;
2650
2651 status = 0;
Divy Le Ray6d6daba2007-03-31 00:23:24 -07002652 if (netif_running(dev) && netif_carrier_ok(dev))
Divy Le Rayfc906642007-03-18 13:10:12 -07002653 status = t3b2_mac_watchdog_task(&p->mac);
2654 if (status == 1)
2655 p->mac.stats.num_toggled++;
2656 else if (status == 2) {
2657 struct cmac *mac = &p->mac;
2658
2659 t3_mac_set_mtu(mac, dev->mtu);
Karen Xief14d42f2009-10-08 09:11:05 +00002660 t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr);
Divy Le Rayfc906642007-03-18 13:10:12 -07002661 cxgb_set_rxmode(dev);
2662 t3_link_start(&p->phy, mac, &p->link_config);
2663 t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
2664 t3_port_intr_enable(adapter, p->port_id);
2665 p->mac.stats.num_resets++;
2666 }
2667 }
2668 rtnl_unlock();
2669}
2670
2671
Divy Le Ray4d22de32007-01-18 22:04:14 -05002672static void t3_adap_check_task(struct work_struct *work)
2673{
2674 struct adapter *adapter = container_of(work, struct adapter,
2675 adap_check_task.work);
2676 const struct adapter_params *p = &adapter->params;
Divy Le Rayfc882192009-03-12 21:14:09 +00002677 int port;
2678 unsigned int v, status, reset;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002679
2680 adapter->check_task_cnt++;
2681
Divy Le Ray3851c662009-04-17 12:21:11 +00002682 check_link_status(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002683
2684 /* Accumulate MAC stats if needed */
2685 if (!p->linkpoll_period ||
2686 (adapter->check_task_cnt * p->linkpoll_period) / 10 >=
2687 p->stats_update_period) {
2688 mac_stats_update(adapter);
2689 adapter->check_task_cnt = 0;
2690 }
2691
Divy Le Rayfc906642007-03-18 13:10:12 -07002692 if (p->rev == T3_REV_B2)
2693 check_t3b2_mac(adapter);
2694
Divy Le Rayfc882192009-03-12 21:14:09 +00002695 /*
2696 * Scan the XGMAC's to check for various conditions which we want to
2697 * monitor in a periodic polling manner rather than via an interrupt
2698 * condition. This is used for conditions which would otherwise flood
2699 * the system with interrupts and we only really need to know that the
2700 * conditions are "happening" ... For each condition we count the
2701 * detection of the condition and reset it for the next polling loop.
2702 */
2703 for_each_port(adapter, port) {
2704 struct cmac *mac = &adap2pinfo(adapter, port)->mac;
2705 u32 cause;
2706
2707 cause = t3_read_reg(adapter, A_XGM_INT_CAUSE + mac->offset);
2708 reset = 0;
2709 if (cause & F_RXFIFO_OVERFLOW) {
2710 mac->stats.rx_fifo_ovfl++;
2711 reset |= F_RXFIFO_OVERFLOW;
2712 }
2713
2714 t3_write_reg(adapter, A_XGM_INT_CAUSE + mac->offset, reset);
2715 }
2716
2717 /*
2718 * We do the same as above for FL_EMPTY interrupts.
2719 */
2720 status = t3_read_reg(adapter, A_SG_INT_CAUSE);
2721 reset = 0;
2722
2723 if (status & F_FLEMPTY) {
2724 struct sge_qset *qs = &adapter->sge.qs[0];
2725 int i = 0;
2726
2727 reset |= F_FLEMPTY;
2728
2729 v = (t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS) >> S_FL0EMPTY) &
2730 0xffff;
2731
2732 while (v) {
2733 qs->fl[i].empty += (v & 1);
2734 if (i)
2735 qs++;
2736 i ^= 1;
2737 v >>= 1;
2738 }
2739 }
2740
2741 t3_write_reg(adapter, A_SG_INT_CAUSE, reset);
2742
Divy Le Ray4d22de32007-01-18 22:04:14 -05002743 /* Schedule the next check update if any port is active. */
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002744 spin_lock_irq(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002745 if (adapter->open_device_map & PORT_MASK)
2746 schedule_chk_task(adapter);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002747 spin_unlock_irq(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002748}
2749
2750/*
2751 * Processes external (PHY) interrupts in process context.
2752 */
2753static void ext_intr_task(struct work_struct *work)
2754{
2755 struct adapter *adapter = container_of(work, struct adapter,
2756 ext_intr_handler_task);
Divy Le Raybf792092009-03-12 21:14:19 +00002757 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002758
Divy Le Raybf792092009-03-12 21:14:19 +00002759 /* Disable link fault interrupts */
2760 for_each_port(adapter, i) {
2761 struct net_device *dev = adapter->port[i];
2762 struct port_info *p = netdev_priv(dev);
2763
2764 t3_xgm_intr_disable(adapter, i);
2765 t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
2766 }
2767
2768 /* Re-enable link fault interrupts */
Divy Le Ray4d22de32007-01-18 22:04:14 -05002769 t3_phy_intr_handler(adapter);
2770
Divy Le Raybf792092009-03-12 21:14:19 +00002771 for_each_port(adapter, i)
2772 t3_xgm_intr_enable(adapter, i);
2773
Divy Le Ray4d22de32007-01-18 22:04:14 -05002774 /* Now reenable external interrupts */
2775 spin_lock_irq(&adapter->work_lock);
2776 if (adapter->slow_intr_mask) {
2777 adapter->slow_intr_mask |= F_T3DBG;
2778 t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG);
2779 t3_write_reg(adapter, A_PL_INT_ENABLE0,
2780 adapter->slow_intr_mask);
2781 }
2782 spin_unlock_irq(&adapter->work_lock);
2783}
2784
2785/*
2786 * Interrupt-context handler for external (PHY) interrupts.
2787 */
2788void t3_os_ext_intr_handler(struct adapter *adapter)
2789{
2790 /*
2791 * Schedule a task to handle external interrupts as they may be slow
2792 * and we use a mutex to protect MDIO registers. We disable PHY
2793 * interrupts in the meantime and let the task reenable them when
2794 * it's done.
2795 */
2796 spin_lock(&adapter->work_lock);
2797 if (adapter->slow_intr_mask) {
2798 adapter->slow_intr_mask &= ~F_T3DBG;
2799 t3_write_reg(adapter, A_PL_INT_ENABLE0,
2800 adapter->slow_intr_mask);
2801 queue_work(cxgb3_wq, &adapter->ext_intr_handler_task);
2802 }
2803 spin_unlock(&adapter->work_lock);
2804}
2805
Divy Le Raybf792092009-03-12 21:14:19 +00002806void t3_os_link_fault_handler(struct adapter *adapter, int port_id)
2807{
2808 struct net_device *netdev = adapter->port[port_id];
2809 struct port_info *pi = netdev_priv(netdev);
2810
2811 spin_lock(&adapter->work_lock);
2812 pi->link_fault = 1;
Divy Le Raybf792092009-03-12 21:14:19 +00002813 spin_unlock(&adapter->work_lock);
2814}
2815
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002816static int t3_adapter_error(struct adapter *adapter, int reset)
2817{
2818 int i, ret = 0;
2819
Divy Le Raycb0bc202009-01-26 22:21:59 -08002820 if (is_offload(adapter) &&
2821 test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
Steve Wisefa0d4c12009-09-05 20:22:38 -07002822 cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_DOWN, 0);
Divy Le Raycb0bc202009-01-26 22:21:59 -08002823 offload_close(&adapter->tdev);
2824 }
2825
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002826 /* Stop all ports */
2827 for_each_port(adapter, i) {
2828 struct net_device *netdev = adapter->port[i];
2829
2830 if (netif_running(netdev))
2831 cxgb_close(netdev);
2832 }
2833
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002834 /* Stop SGE timers */
2835 t3_stop_sge_timers(adapter);
2836
2837 adapter->flags &= ~FULL_INIT_DONE;
2838
2839 if (reset)
2840 ret = t3_reset_adapter(adapter);
2841
2842 pci_disable_device(adapter->pdev);
2843
2844 return ret;
2845}
2846
2847static int t3_reenable_adapter(struct adapter *adapter)
2848{
2849 if (pci_enable_device(adapter->pdev)) {
2850 dev_err(&adapter->pdev->dev,
2851 "Cannot re-enable PCI device after reset.\n");
2852 goto err;
2853 }
2854 pci_set_master(adapter->pdev);
2855 pci_restore_state(adapter->pdev);
2856
2857 /* Free sge resources */
2858 t3_free_sge_resources(adapter);
2859
2860 if (t3_replay_prep_adapter(adapter))
2861 goto err;
2862
2863 return 0;
2864err:
2865 return -1;
2866}
2867
2868static void t3_resume_ports(struct adapter *adapter)
2869{
2870 int i;
2871
2872 /* Restart the ports */
2873 for_each_port(adapter, i) {
2874 struct net_device *netdev = adapter->port[i];
2875
2876 if (netif_running(netdev)) {
2877 if (cxgb_open(netdev)) {
2878 dev_err(&adapter->pdev->dev,
2879 "can't bring device back up"
2880 " after reset\n");
2881 continue;
2882 }
2883 }
2884 }
Divy Le Raycb0bc202009-01-26 22:21:59 -08002885
2886 if (is_offload(adapter) && !ofld_disable)
Steve Wisefa0d4c12009-09-05 20:22:38 -07002887 cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_UP, 0);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002888}
2889
2890/*
2891 * processes a fatal error.
2892 * Bring the ports down, reset the chip, bring the ports back up.
2893 */
2894static void fatal_error_task(struct work_struct *work)
2895{
2896 struct adapter *adapter = container_of(work, struct adapter,
2897 fatal_error_handler_task);
2898 int err = 0;
2899
2900 rtnl_lock();
2901 err = t3_adapter_error(adapter, 1);
2902 if (!err)
2903 err = t3_reenable_adapter(adapter);
2904 if (!err)
2905 t3_resume_ports(adapter);
2906
2907 CH_ALERT(adapter, "adapter reset %s\n", err ? "failed" : "succeeded");
2908 rtnl_unlock();
2909}
2910
Divy Le Ray4d22de32007-01-18 22:04:14 -05002911void t3_fatal_err(struct adapter *adapter)
2912{
2913 unsigned int fw_status[4];
2914
2915 if (adapter->flags & FULL_INIT_DONE) {
2916 t3_sge_stop(adapter);
Divy Le Rayc64c2ea2007-08-21 20:49:31 -07002917 t3_write_reg(adapter, A_XGM_TX_CTRL, 0);
2918 t3_write_reg(adapter, A_XGM_RX_CTRL, 0);
2919 t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0);
2920 t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002921
2922 spin_lock(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002923 t3_intr_disable(adapter);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002924 queue_work(cxgb3_wq, &adapter->fatal_error_handler_task);
2925 spin_unlock(&adapter->work_lock);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002926 }
2927 CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
2928 if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
2929 CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
2930 fw_status[0], fw_status[1],
2931 fw_status[2], fw_status[3]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002932}
2933
Divy Le Ray91a6b502007-11-16 11:21:55 -08002934/**
2935 * t3_io_error_detected - called when PCI error is detected
2936 * @pdev: Pointer to PCI device
2937 * @state: The current pci connection state
2938 *
2939 * This function is called after a PCI bus error affecting
2940 * this device has been detected.
2941 */
2942static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
2943 pci_channel_state_t state)
2944{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08002945 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002946 int ret;
Divy Le Ray91a6b502007-11-16 11:21:55 -08002947
Divy Le Raye8d19372009-04-17 12:21:27 +00002948 if (state == pci_channel_io_perm_failure)
2949 return PCI_ERS_RESULT_DISCONNECT;
2950
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002951 ret = t3_adapter_error(adapter, 0);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002952
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07002953 /* Request a slot reset. */
Divy Le Ray91a6b502007-11-16 11:21:55 -08002954 return PCI_ERS_RESULT_NEED_RESET;
2955}
2956
2957/**
2958 * t3_io_slot_reset - called after the pci bus has been reset.
2959 * @pdev: Pointer to PCI device
2960 *
2961 * Restart the card from scratch, as if from a cold-boot.
2962 */
2963static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev)
2964{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08002965 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002966
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002967 if (!t3_reenable_adapter(adapter))
2968 return PCI_ERS_RESULT_RECOVERED;
Divy Le Ray91a6b502007-11-16 11:21:55 -08002969
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07002970 return PCI_ERS_RESULT_DISCONNECT;
Divy Le Ray91a6b502007-11-16 11:21:55 -08002971}
2972
2973/**
2974 * t3_io_resume - called when traffic can start flowing again.
2975 * @pdev: Pointer to PCI device
2976 *
2977 * This callback is called when the error recovery driver tells us that
2978 * its OK to resume normal operation.
2979 */
2980static void t3_io_resume(struct pci_dev *pdev)
2981{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08002982 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002983
Divy Le Ray68f40c12009-03-26 16:39:19 +00002984 CH_ALERT(adapter, "adapter recovering, PEX ERR 0x%x\n",
2985 t3_read_reg(adapter, A_PCIE_PEX_ERR));
2986
Divy Le Ray20d3fc12008-10-08 17:36:03 -07002987 t3_resume_ports(adapter);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002988}
2989
2990static struct pci_error_handlers t3_err_handler = {
2991 .error_detected = t3_io_error_detected,
2992 .slot_reset = t3_io_slot_reset,
2993 .resume = t3_io_resume,
2994};
2995
Divy Le Ray8c263762008-10-08 17:37:33 -07002996/*
2997 * Set the number of qsets based on the number of CPUs and the number of ports,
2998 * not to exceed the number of available qsets, assuming there are enough qsets
2999 * per port in HW.
3000 */
3001static void set_nqsets(struct adapter *adap)
3002{
3003 int i, j = 0;
3004 int num_cpus = num_online_cpus();
3005 int hwports = adap->params.nports;
Divy Le Ray5cda9362009-01-18 21:29:40 -08003006 int nqsets = adap->msix_nvectors - 1;
Divy Le Ray8c263762008-10-08 17:37:33 -07003007
Divy Le Rayf9ee3882008-11-09 00:55:33 -08003008 if (adap->params.rev > 0 && adap->flags & USING_MSIX) {
Divy Le Ray8c263762008-10-08 17:37:33 -07003009 if (hwports == 2 &&
3010 (hwports * nqsets > SGE_QSETS ||
3011 num_cpus >= nqsets / hwports))
3012 nqsets /= hwports;
3013 if (nqsets > num_cpus)
3014 nqsets = num_cpus;
3015 if (nqsets < 1 || hwports == 4)
3016 nqsets = 1;
3017 } else
3018 nqsets = 1;
3019
3020 for_each_port(adap, i) {
3021 struct port_info *pi = adap2pinfo(adap, i);
3022
3023 pi->first_qset = j;
3024 pi->nqsets = nqsets;
3025 j = pi->first_qset + nqsets;
3026
3027 dev_info(&adap->pdev->dev,
3028 "Port %d using %d queue sets.\n", i, nqsets);
3029 }
3030}
3031
Divy Le Ray4d22de32007-01-18 22:04:14 -05003032static int __devinit cxgb_enable_msix(struct adapter *adap)
3033{
3034 struct msix_entry entries[SGE_QSETS + 1];
Divy Le Ray5cda9362009-01-18 21:29:40 -08003035 int vectors;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003036 int i, err;
3037
Divy Le Ray5cda9362009-01-18 21:29:40 -08003038 vectors = ARRAY_SIZE(entries);
3039 for (i = 0; i < vectors; ++i)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003040 entries[i].entry = i;
3041
Divy Le Ray5cda9362009-01-18 21:29:40 -08003042 while ((err = pci_enable_msix(adap->pdev, entries, vectors)) > 0)
3043 vectors = err;
3044
Divy Le Ray2c2f4092009-04-17 12:21:22 +00003045 if (err < 0)
3046 pci_disable_msix(adap->pdev);
3047
3048 if (!err && vectors < (adap->params.nports + 1)) {
3049 pci_disable_msix(adap->pdev);
Divy Le Ray5cda9362009-01-18 21:29:40 -08003050 err = -1;
Divy Le Ray2c2f4092009-04-17 12:21:22 +00003051 }
Divy Le Ray5cda9362009-01-18 21:29:40 -08003052
Divy Le Ray4d22de32007-01-18 22:04:14 -05003053 if (!err) {
Divy Le Ray5cda9362009-01-18 21:29:40 -08003054 for (i = 0; i < vectors; ++i)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003055 adap->msix_info[i].vec = entries[i].vector;
Divy Le Ray5cda9362009-01-18 21:29:40 -08003056 adap->msix_nvectors = vectors;
3057 }
3058
Divy Le Ray4d22de32007-01-18 22:04:14 -05003059 return err;
3060}
3061
3062static void __devinit print_port_info(struct adapter *adap,
3063 const struct adapter_info *ai)
3064{
3065 static const char *pci_variant[] = {
3066 "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express"
3067 };
3068
3069 int i;
3070 char buf[80];
3071
3072 if (is_pcie(adap))
3073 snprintf(buf, sizeof(buf), "%s x%d",
3074 pci_variant[adap->params.pci.variant],
3075 adap->params.pci.width);
3076 else
3077 snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit",
3078 pci_variant[adap->params.pci.variant],
3079 adap->params.pci.speed, adap->params.pci.width);
3080
3081 for_each_port(adap, i) {
3082 struct net_device *dev = adap->port[i];
3083 const struct port_info *pi = netdev_priv(dev);
3084
3085 if (!test_bit(i, &adap->registered_device_map))
3086 continue;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07003087 printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n",
Divy Le Ray04497982008-10-08 17:38:29 -07003088 dev->name, ai->desc, pi->phy.desc,
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07003089 is_offload(adap) ? "R" : "", adap->params.rev, buf,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003090 (adap->flags & USING_MSIX) ? " MSI-X" :
3091 (adap->flags & USING_MSI) ? " MSI" : "");
3092 if (adap->name == dev->name && adap->params.vpd.mclk)
Divy Le Ray167cdf52007-08-21 20:49:36 -07003093 printk(KERN_INFO
3094 "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
Divy Le Ray4d22de32007-01-18 22:04:14 -05003095 adap->name, t3_mc7_size(&adap->cm) >> 20,
3096 t3_mc7_size(&adap->pmtx) >> 20,
Divy Le Ray167cdf52007-08-21 20:49:36 -07003097 t3_mc7_size(&adap->pmrx) >> 20,
3098 adap->params.vpd.sn);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003099 }
3100}
3101
Stephen Hemmingerdd752692008-11-19 22:15:39 -08003102static const struct net_device_ops cxgb_netdev_ops = {
3103 .ndo_open = cxgb_open,
3104 .ndo_stop = cxgb_close,
Divy Le Ray43a944f2008-11-26 15:35:26 -08003105 .ndo_start_xmit = t3_eth_xmit,
Stephen Hemmingerdd752692008-11-19 22:15:39 -08003106 .ndo_get_stats = cxgb_get_stats,
3107 .ndo_validate_addr = eth_validate_addr,
3108 .ndo_set_multicast_list = cxgb_set_rxmode,
3109 .ndo_do_ioctl = cxgb_ioctl,
3110 .ndo_change_mtu = cxgb_change_mtu,
3111 .ndo_set_mac_address = cxgb_set_mac_addr,
3112 .ndo_vlan_rx_register = vlan_rx_register,
3113#ifdef CONFIG_NET_POLL_CONTROLLER
3114 .ndo_poll_controller = cxgb_netpoll,
3115#endif
3116};
3117
Karen Xief14d42f2009-10-08 09:11:05 +00003118static void __devinit cxgb3_init_iscsi_mac(struct net_device *dev)
3119{
3120 struct port_info *pi = netdev_priv(dev);
3121
3122 memcpy(pi->iscsic.mac_addr, dev->dev_addr, ETH_ALEN);
3123 pi->iscsic.mac_addr[3] |= 0x80;
3124}
3125
Divy Le Ray4d22de32007-01-18 22:04:14 -05003126static int __devinit init_one(struct pci_dev *pdev,
3127 const struct pci_device_id *ent)
3128{
3129 static int version_printed;
3130
3131 int i, err, pci_using_dac = 0;
Divy Le Ray68f40c12009-03-26 16:39:19 +00003132 resource_size_t mmio_start, mmio_len;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003133 const struct adapter_info *ai;
3134 struct adapter *adapter = NULL;
3135 struct port_info *pi;
3136
3137 if (!version_printed) {
3138 printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
3139 ++version_printed;
3140 }
3141
3142 if (!cxgb3_wq) {
3143 cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
3144 if (!cxgb3_wq) {
3145 printk(KERN_ERR DRV_NAME
3146 ": cannot initialize work queue\n");
3147 return -ENOMEM;
3148 }
3149 }
3150
3151 err = pci_request_regions(pdev, DRV_NAME);
3152 if (err) {
3153 /* Just info, some other driver may have claimed the device. */
3154 dev_info(&pdev->dev, "cannot obtain PCI resources\n");
3155 return err;
3156 }
3157
3158 err = pci_enable_device(pdev);
3159 if (err) {
3160 dev_err(&pdev->dev, "cannot enable PCI device\n");
3161 goto out_release_regions;
3162 }
3163
Yang Hongyang6a355282009-04-06 19:01:13 -07003164 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003165 pci_using_dac = 1;
Yang Hongyang6a355282009-04-06 19:01:13 -07003166 err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
Divy Le Ray4d22de32007-01-18 22:04:14 -05003167 if (err) {
3168 dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
3169 "coherent allocations\n");
3170 goto out_disable_device;
3171 }
Yang Hongyang284901a2009-04-06 19:01:15 -07003172 } else if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003173 dev_err(&pdev->dev, "no usable DMA configuration\n");
3174 goto out_disable_device;
3175 }
3176
3177 pci_set_master(pdev);
Divy Le Ray204e2f92008-05-06 19:26:01 -07003178 pci_save_state(pdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003179
3180 mmio_start = pci_resource_start(pdev, 0);
3181 mmio_len = pci_resource_len(pdev, 0);
3182 ai = t3_get_adapter_info(ent->driver_data);
3183
3184 adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
3185 if (!adapter) {
3186 err = -ENOMEM;
3187 goto out_disable_device;
3188 }
3189
Divy Le Ray74b793e2009-06-09 23:25:21 +00003190 adapter->nofail_skb =
3191 alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_KERNEL);
3192 if (!adapter->nofail_skb) {
3193 dev_err(&pdev->dev, "cannot allocate nofail buffer\n");
3194 err = -ENOMEM;
3195 goto out_free_adapter;
3196 }
3197
Divy Le Ray4d22de32007-01-18 22:04:14 -05003198 adapter->regs = ioremap_nocache(mmio_start, mmio_len);
3199 if (!adapter->regs) {
3200 dev_err(&pdev->dev, "cannot map device registers\n");
3201 err = -ENOMEM;
3202 goto out_free_adapter;
3203 }
3204
3205 adapter->pdev = pdev;
3206 adapter->name = pci_name(pdev);
3207 adapter->msg_enable = dflt_msg_enable;
3208 adapter->mmio_len = mmio_len;
3209
3210 mutex_init(&adapter->mdio_lock);
3211 spin_lock_init(&adapter->work_lock);
3212 spin_lock_init(&adapter->stats_lock);
3213
3214 INIT_LIST_HEAD(&adapter->adapter_list);
3215 INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
Divy Le Ray20d3fc12008-10-08 17:36:03 -07003216 INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003217 INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
3218
Divy Le Ray952cdf32009-03-26 16:39:24 +00003219 for (i = 0; i < ai->nports0 + ai->nports1; ++i) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003220 struct net_device *netdev;
3221
Divy Le Ray82ad3322008-12-16 01:09:39 -08003222 netdev = alloc_etherdev_mq(sizeof(struct port_info), SGE_QSETS);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003223 if (!netdev) {
3224 err = -ENOMEM;
3225 goto out_free_dev;
3226 }
3227
Divy Le Ray4d22de32007-01-18 22:04:14 -05003228 SET_NETDEV_DEV(netdev, &pdev->dev);
3229
3230 adapter->port[i] = netdev;
3231 pi = netdev_priv(netdev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003232 pi->adapter = adapter;
Roland Dreier47fd23f2009-01-11 00:19:36 -08003233 pi->rx_offload = T3_RX_CSUM | T3_LRO;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003234 pi->port_id = i;
3235 netif_carrier_off(netdev);
Divy Le Ray82ad3322008-12-16 01:09:39 -08003236 netif_tx_stop_all_queues(netdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003237 netdev->irq = pdev->irq;
3238 netdev->mem_start = mmio_start;
3239 netdev->mem_end = mmio_start + mmio_len - 1;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003240 netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
Herbert Xu7be2df42009-01-21 14:39:13 -08003241 netdev->features |= NETIF_F_GRO;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003242 if (pci_using_dac)
3243 netdev->features |= NETIF_F_HIGHDMA;
3244
3245 netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
Stephen Hemmingerdd752692008-11-19 22:15:39 -08003246 netdev->netdev_ops = &cxgb_netdev_ops;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003247 SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
3248 }
3249
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003250 pci_set_drvdata(pdev, adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003251 if (t3_prep_adapter(adapter, ai, 1) < 0) {
3252 err = -ENODEV;
3253 goto out_free_dev;
3254 }
Jeff Garzik2eab17a2007-11-23 21:59:45 -05003255
Divy Le Ray4d22de32007-01-18 22:04:14 -05003256 /*
3257 * The card is now ready to go. If any errors occur during device
3258 * registration we do not fail the whole card but rather proceed only
3259 * with the ports we manage to register successfully. However we must
3260 * register at least one net device.
3261 */
3262 for_each_port(adapter, i) {
3263 err = register_netdev(adapter->port[i]);
3264 if (err)
3265 dev_warn(&pdev->dev,
3266 "cannot register net device %s, skipping\n",
3267 adapter->port[i]->name);
3268 else {
3269 /*
3270 * Change the name we use for messages to the name of
3271 * the first successfully registered interface.
3272 */
3273 if (!adapter->registered_device_map)
3274 adapter->name = adapter->port[i]->name;
3275
3276 __set_bit(i, &adapter->registered_device_map);
3277 }
3278 }
3279 if (!adapter->registered_device_map) {
3280 dev_err(&pdev->dev, "could not register any net devices\n");
3281 goto out_free_dev;
3282 }
3283
Karen Xief14d42f2009-10-08 09:11:05 +00003284 for_each_port(adapter, i)
3285 cxgb3_init_iscsi_mac(adapter->port[i]);
3286
Divy Le Ray4d22de32007-01-18 22:04:14 -05003287 /* Driver's ready. Reflect it on LEDs */
3288 t3_led_ready(adapter);
3289
3290 if (is_offload(adapter)) {
3291 __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
3292 cxgb3_adapter_ofld(adapter);
3293 }
3294
3295 /* See what interrupts we'll be using */
3296 if (msi > 1 && cxgb_enable_msix(adapter) == 0)
3297 adapter->flags |= USING_MSIX;
3298 else if (msi > 0 && pci_enable_msi(pdev) == 0)
3299 adapter->flags |= USING_MSI;
3300
Divy Le Ray8c263762008-10-08 17:37:33 -07003301 set_nqsets(adapter);
3302
Divy Le Ray0ee8d332007-02-08 16:55:59 -08003303 err = sysfs_create_group(&adapter->port[0]->dev.kobj,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003304 &cxgb3_attr_group);
3305
3306 print_port_info(adapter, ai);
3307 return 0;
3308
3309out_free_dev:
3310 iounmap(adapter->regs);
Divy Le Ray952cdf32009-03-26 16:39:24 +00003311 for (i = ai->nports0 + ai->nports1 - 1; i >= 0; --i)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003312 if (adapter->port[i])
3313 free_netdev(adapter->port[i]);
3314
3315out_free_adapter:
3316 kfree(adapter);
3317
3318out_disable_device:
3319 pci_disable_device(pdev);
3320out_release_regions:
3321 pci_release_regions(pdev);
3322 pci_set_drvdata(pdev, NULL);
3323 return err;
3324}
3325
3326static void __devexit remove_one(struct pci_dev *pdev)
3327{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003328 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003329
Divy Le Ray5fbf8162007-08-29 19:15:47 -07003330 if (adapter) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003331 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003332
3333 t3_sge_stop(adapter);
Divy Le Ray0ee8d332007-02-08 16:55:59 -08003334 sysfs_remove_group(&adapter->port[0]->dev.kobj,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003335 &cxgb3_attr_group);
3336
Divy Le Ray4d22de32007-01-18 22:04:14 -05003337 if (is_offload(adapter)) {
3338 cxgb3_adapter_unofld(adapter);
3339 if (test_bit(OFFLOAD_DEVMAP_BIT,
3340 &adapter->open_device_map))
3341 offload_close(&adapter->tdev);
3342 }
3343
Divy Le Ray67d92ab2007-11-16 11:21:50 -08003344 for_each_port(adapter, i)
3345 if (test_bit(i, &adapter->registered_device_map))
3346 unregister_netdev(adapter->port[i]);
3347
Divy Le Ray0ca41c02008-09-25 14:05:28 +00003348 t3_stop_sge_timers(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003349 t3_free_sge_resources(adapter);
3350 cxgb_disable_msi(adapter);
3351
Divy Le Ray4d22de32007-01-18 22:04:14 -05003352 for_each_port(adapter, i)
3353 if (adapter->port[i])
3354 free_netdev(adapter->port[i]);
3355
3356 iounmap(adapter->regs);
Divy Le Ray74b793e2009-06-09 23:25:21 +00003357 if (adapter->nofail_skb)
3358 kfree_skb(adapter->nofail_skb);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003359 kfree(adapter);
3360 pci_release_regions(pdev);
3361 pci_disable_device(pdev);
3362 pci_set_drvdata(pdev, NULL);
3363 }
3364}
3365
3366static struct pci_driver driver = {
3367 .name = DRV_NAME,
3368 .id_table = cxgb3_pci_tbl,
3369 .probe = init_one,
3370 .remove = __devexit_p(remove_one),
Divy Le Ray91a6b502007-11-16 11:21:55 -08003371 .err_handler = &t3_err_handler,
Divy Le Ray4d22de32007-01-18 22:04:14 -05003372};
3373
3374static int __init cxgb3_init_module(void)
3375{
3376 int ret;
3377
3378 cxgb3_offload_init();
3379
3380 ret = pci_register_driver(&driver);
3381 return ret;
3382}
3383
3384static void __exit cxgb3_cleanup_module(void)
3385{
3386 pci_unregister_driver(&driver);
3387 if (cxgb3_wq)
3388 destroy_workqueue(cxgb3_wq);
3389}
3390
3391module_init(cxgb3_init_module);
3392module_exit(cxgb3_cleanup_module);