blob: d355c826b9b992633d8e3ad7be9a5d7c0f908d31 [file] [log] [blame]
Divy Le Ray4d22de32007-01-18 22:04:14 -05001/*
Divy Le Ray1d68e932007-01-30 19:44:35 -08002 * Copyright (c) 2003-2007 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>
40#include <linux/mii.h>
41#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 Ray4d22de32007-01-18 22:04:14 -050093 {0,}
94};
95
96MODULE_DESCRIPTION(DRV_DESC);
97MODULE_AUTHOR("Chelsio Communications");
Divy Le Ray1d68e932007-01-30 19:44:35 -080098MODULE_LICENSE("Dual BSD/GPL");
Divy Le Ray4d22de32007-01-18 22:04:14 -050099MODULE_VERSION(DRV_VERSION);
100MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl);
101
102static int dflt_msg_enable = DFLT_MSG_ENABLE;
103
104module_param(dflt_msg_enable, int, 0644);
105MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap");
106
107/*
108 * The driver uses the best interrupt scheme available on a platform in the
109 * order MSI-X, MSI, legacy pin interrupts. This parameter determines which
110 * of these schemes the driver may consider as follows:
111 *
112 * msi = 2: choose from among all three options
113 * msi = 1: only consider MSI and pin interrupts
114 * msi = 0: force pin interrupts
115 */
116static int msi = 2;
117
118module_param(msi, int, 0644);
119MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X");
120
121/*
122 * The driver enables offload as a default.
123 * To disable it, use ofld_disable = 1.
124 */
125
126static int ofld_disable = 0;
127
128module_param(ofld_disable, int, 0644);
129MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not");
130
131/*
132 * We have work elements that we need to cancel when an interface is taken
133 * down. Normally the work elements would be executed by keventd but that
134 * can deadlock because of linkwatch. If our close method takes the rtnl
135 * lock and linkwatch is ahead of our work elements in keventd, linkwatch
136 * will block keventd as it needs the rtnl lock, and we'll deadlock waiting
137 * for our work to complete. Get our own work queue to solve this.
138 */
139static struct workqueue_struct *cxgb3_wq;
140
141/**
142 * link_report - show link status and link speed/duplex
143 * @p: the port whose settings are to be reported
144 *
145 * Shows the link status, speed, and duplex of a port.
146 */
147static void link_report(struct net_device *dev)
148{
149 if (!netif_carrier_ok(dev))
150 printk(KERN_INFO "%s: link down\n", dev->name);
151 else {
152 const char *s = "10Mbps";
153 const struct port_info *p = netdev_priv(dev);
154
155 switch (p->link_config.speed) {
156 case SPEED_10000:
157 s = "10Gbps";
158 break;
159 case SPEED_1000:
160 s = "1000Mbps";
161 break;
162 case SPEED_100:
163 s = "100Mbps";
164 break;
165 }
166
167 printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s,
168 p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
169 }
170}
171
172/**
173 * t3_os_link_changed - handle link status changes
174 * @adapter: the adapter associated with the link change
175 * @port_id: the port index whose limk status has changed
176 * @link_stat: the new status of the link
177 * @speed: the new speed setting
178 * @duplex: the new duplex setting
179 * @pause: the new flow-control setting
180 *
181 * This is the OS-dependent handler for link status changes. The OS
182 * neutral handler takes care of most of the processing for these events,
183 * then calls this handler for any OS-specific processing.
184 */
185void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
186 int speed, int duplex, int pause)
187{
188 struct net_device *dev = adapter->port[port_id];
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700189 struct port_info *pi = netdev_priv(dev);
190 struct cmac *mac = &pi->mac;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500191
192 /* Skip changes from disabled ports. */
193 if (!netif_running(dev))
194 return;
195
196 if (link_stat != netif_carrier_ok(dev)) {
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700197 if (link_stat) {
Divy Le Ray59cf8102007-04-09 20:10:27 -0700198 t3_mac_enable(mac, MAC_DIRECTION_RX);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500199 netif_carrier_on(dev);
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700200 } else {
Divy Le Ray4d22de32007-01-18 22:04:14 -0500201 netif_carrier_off(dev);
Divy Le Ray59cf8102007-04-09 20:10:27 -0700202 pi->phy.ops->power_down(&pi->phy, 1);
203 t3_mac_disable(mac, MAC_DIRECTION_RX);
204 t3_link_start(&pi->phy, mac, &pi->link_config);
Divy Le Ray6d6daba2007-03-31 00:23:24 -0700205 }
206
Divy Le Ray4d22de32007-01-18 22:04:14 -0500207 link_report(dev);
208 }
209}
210
211static void cxgb_set_rxmode(struct net_device *dev)
212{
213 struct t3_rx_mode rm;
214 struct port_info *pi = netdev_priv(dev);
215
216 init_rx_mode(&rm, dev, dev->mc_list);
217 t3_mac_set_rx_mode(&pi->mac, &rm);
218}
219
220/**
221 * link_start - enable a port
222 * @dev: the device to enable
223 *
224 * Performs the MAC and PHY actions needed to enable a port.
225 */
226static void link_start(struct net_device *dev)
227{
228 struct t3_rx_mode rm;
229 struct port_info *pi = netdev_priv(dev);
230 struct cmac *mac = &pi->mac;
231
232 init_rx_mode(&rm, dev, dev->mc_list);
233 t3_mac_reset(mac);
234 t3_mac_set_mtu(mac, dev->mtu);
235 t3_mac_set_address(mac, 0, dev->dev_addr);
236 t3_mac_set_rx_mode(mac, &rm);
237 t3_link_start(&pi->phy, mac, &pi->link_config);
238 t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
239}
240
241static inline void cxgb_disable_msi(struct adapter *adapter)
242{
243 if (adapter->flags & USING_MSIX) {
244 pci_disable_msix(adapter->pdev);
245 adapter->flags &= ~USING_MSIX;
246 } else if (adapter->flags & USING_MSI) {
247 pci_disable_msi(adapter->pdev);
248 adapter->flags &= ~USING_MSI;
249 }
250}
251
252/*
253 * Interrupt handler for asynchronous events used with MSI-X.
254 */
255static irqreturn_t t3_async_intr_handler(int irq, void *cookie)
256{
257 t3_slow_intr_handler(cookie);
258 return IRQ_HANDLED;
259}
260
261/*
262 * Name the MSI-X interrupts.
263 */
264static void name_msix_vecs(struct adapter *adap)
265{
266 int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1;
267
268 snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
269 adap->msix_info[0].desc[n] = 0;
270
271 for_each_port(adap, j) {
272 struct net_device *d = adap->port[j];
273 const struct port_info *pi = netdev_priv(d);
274
275 for (i = 0; i < pi->nqsets; i++, msi_idx++) {
276 snprintf(adap->msix_info[msi_idx].desc, n,
277 "%s (queue %d)", d->name, i);
278 adap->msix_info[msi_idx].desc[n] = 0;
279 }
280 }
281}
282
283static int request_msix_data_irqs(struct adapter *adap)
284{
285 int i, j, err, qidx = 0;
286
287 for_each_port(adap, i) {
288 int nqsets = adap2pinfo(adap, i)->nqsets;
289
290 for (j = 0; j < nqsets; ++j) {
291 err = request_irq(adap->msix_info[qidx + 1].vec,
292 t3_intr_handler(adap,
293 adap->sge.qs[qidx].
294 rspq.polling), 0,
295 adap->msix_info[qidx + 1].desc,
296 &adap->sge.qs[qidx]);
297 if (err) {
298 while (--qidx >= 0)
299 free_irq(adap->msix_info[qidx + 1].vec,
300 &adap->sge.qs[qidx]);
301 return err;
302 }
303 qidx++;
304 }
305 }
306 return 0;
307}
308
Divy Le Rayb8819552007-12-17 18:47:31 -0800309static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
310 unsigned long n)
311{
312 int attempts = 5;
313
314 while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
315 if (!--attempts)
316 return -ETIMEDOUT;
317 msleep(10);
318 }
319 return 0;
320}
321
322static int init_tp_parity(struct adapter *adap)
323{
324 int i;
325 struct sk_buff *skb;
326 struct cpl_set_tcb_field *greq;
327 unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
328
329 t3_tp_set_offload_mode(adap, 1);
330
331 for (i = 0; i < 16; i++) {
332 struct cpl_smt_write_req *req;
333
334 skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
335 req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
336 memset(req, 0, sizeof(*req));
337 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
338 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
339 req->iff = i;
340 t3_mgmt_tx(adap, skb);
341 }
342
343 for (i = 0; i < 2048; i++) {
344 struct cpl_l2t_write_req *req;
345
346 skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
347 req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
348 memset(req, 0, sizeof(*req));
349 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
350 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
351 req->params = htonl(V_L2T_W_IDX(i));
352 t3_mgmt_tx(adap, skb);
353 }
354
355 for (i = 0; i < 2048; i++) {
356 struct cpl_rte_write_req *req;
357
358 skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
359 req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req));
360 memset(req, 0, sizeof(*req));
361 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
362 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
363 req->l2t_idx = htonl(V_L2T_W_IDX(i));
364 t3_mgmt_tx(adap, skb);
365 }
366
367 skb = alloc_skb(sizeof(*greq), GFP_KERNEL | __GFP_NOFAIL);
368 greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq));
369 memset(greq, 0, sizeof(*greq));
370 greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
371 OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
372 greq->mask = cpu_to_be64(1);
373 t3_mgmt_tx(adap, skb);
374
375 i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
376 t3_tp_set_offload_mode(adap, 0);
377 return i;
378}
379
Divy Le Ray4d22de32007-01-18 22:04:14 -0500380/**
381 * setup_rss - configure RSS
382 * @adap: the adapter
383 *
384 * Sets up RSS to distribute packets to multiple receive queues. We
385 * configure the RSS CPU lookup table to distribute to the number of HW
386 * receive queues, and the response queue lookup table to narrow that
387 * down to the response queues actually configured for each port.
388 * We always configure the RSS mapping for two ports since the mapping
389 * table has plenty of entries.
390 */
391static void setup_rss(struct adapter *adap)
392{
393 int i;
394 unsigned int nq0 = adap2pinfo(adap, 0)->nqsets;
395 unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1;
396 u8 cpus[SGE_QSETS + 1];
397 u16 rspq_map[RSS_TABLE_SIZE];
398
399 for (i = 0; i < SGE_QSETS; ++i)
400 cpus[i] = i;
401 cpus[SGE_QSETS] = 0xff; /* terminator */
402
403 for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
404 rspq_map[i] = i % nq0;
405 rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0;
406 }
407
408 t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
409 F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
Divy Le Raya2604be2007-11-16 11:22:16 -0800410 V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500411}
412
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700413static void init_napi(struct adapter *adap)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500414{
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700415 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500416
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700417 for (i = 0; i < SGE_QSETS; i++) {
418 struct sge_qset *qs = &adap->sge.qs[i];
Divy Le Ray4d22de32007-01-18 22:04:14 -0500419
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700420 if (qs->adap)
421 netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll,
422 64);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500423 }
Divy Le Ray48c4b6d2008-05-06 19:25:56 -0700424
425 /*
426 * netif_napi_add() can be called only once per napi_struct because it
427 * adds each new napi_struct to a list. Be careful not to call it a
428 * second time, e.g., during EEH recovery, by making a note of it.
429 */
430 adap->flags |= NAPI_INIT;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500431}
432
433/*
434 * Wait until all NAPI handlers are descheduled. This includes the handlers of
435 * both netdevices representing interfaces and the dummy ones for the extra
436 * queues.
437 */
438static void quiesce_rx(struct adapter *adap)
439{
440 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500441
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700442 for (i = 0; i < SGE_QSETS; i++)
443 if (adap->sge.qs[i].adap)
444 napi_disable(&adap->sge.qs[i].napi);
445}
Divy Le Ray4d22de32007-01-18 22:04:14 -0500446
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700447static void enable_all_napi(struct adapter *adap)
448{
449 int i;
450 for (i = 0; i < SGE_QSETS; i++)
451 if (adap->sge.qs[i].adap)
452 napi_enable(&adap->sge.qs[i].napi);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500453}
454
455/**
456 * setup_sge_qsets - configure SGE Tx/Rx/response queues
457 * @adap: the adapter
458 *
459 * Determines how many sets of SGE queues to use and initializes them.
460 * We support multiple queue sets per port if we have MSI-X, otherwise
461 * just one queue set per port.
462 */
463static int setup_sge_qsets(struct adapter *adap)
464{
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700465 int i, j, err, irq_idx = 0, qset_idx = 0;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -0700466 unsigned int ntxq = SGE_TXQ_PER_SET;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500467
468 if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
469 irq_idx = -1;
470
471 for_each_port(adap, i) {
472 struct net_device *dev = adap->port[i];
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700473 struct port_info *pi = netdev_priv(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500474
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700475 pi->qs = &adap->sge.qs[pi->first_qset];
Divy Le Ray4d22de32007-01-18 22:04:14 -0500476 for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
477 err = t3_sge_alloc_qset(adap, qset_idx, 1,
478 (adap->flags & USING_MSIX) ? qset_idx + 1 :
479 irq_idx,
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700480 &adap->params.sge.qset[qset_idx], ntxq, dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500481 if (err) {
Divy Le Ray0ca41c02008-09-25 14:05:28 +0000482 t3_stop_sge_timers(adap);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500483 t3_free_sge_resources(adap);
484 return err;
485 }
486 }
487 }
488
489 return 0;
490}
491
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800492static ssize_t attr_show(struct device *d, char *buf,
Divy Le Ray896392e2007-02-24 16:43:50 -0800493 ssize_t(*format) (struct net_device *, char *))
Divy Le Ray4d22de32007-01-18 22:04:14 -0500494{
495 ssize_t len;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500496
497 /* Synchronize with ioctls that may shut down the device */
498 rtnl_lock();
Divy Le Ray896392e2007-02-24 16:43:50 -0800499 len = (*format) (to_net_dev(d), buf);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500500 rtnl_unlock();
501 return len;
502}
503
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800504static ssize_t attr_store(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800505 const char *buf, size_t len,
Divy Le Ray896392e2007-02-24 16:43:50 -0800506 ssize_t(*set) (struct net_device *, unsigned int),
Divy Le Ray4d22de32007-01-18 22:04:14 -0500507 unsigned int min_val, unsigned int max_val)
508{
509 char *endp;
510 ssize_t ret;
511 unsigned int val;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500512
513 if (!capable(CAP_NET_ADMIN))
514 return -EPERM;
515
516 val = simple_strtoul(buf, &endp, 0);
517 if (endp == buf || val < min_val || val > max_val)
518 return -EINVAL;
519
520 rtnl_lock();
Divy Le Ray896392e2007-02-24 16:43:50 -0800521 ret = (*set) (to_net_dev(d), val);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500522 if (!ret)
523 ret = len;
524 rtnl_unlock();
525 return ret;
526}
527
528#define CXGB3_SHOW(name, val_expr) \
Divy Le Ray896392e2007-02-24 16:43:50 -0800529static ssize_t format_##name(struct net_device *dev, char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500530{ \
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700531 struct port_info *pi = netdev_priv(dev); \
532 struct adapter *adap = pi->adapter; \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500533 return sprintf(buf, "%u\n", val_expr); \
534} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800535static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
536 char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500537{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800538 return attr_show(d, buf, format_##name); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500539}
540
Divy Le Ray896392e2007-02-24 16:43:50 -0800541static ssize_t set_nfilters(struct net_device *dev, unsigned int val)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500542{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700543 struct port_info *pi = netdev_priv(dev);
544 struct adapter *adap = pi->adapter;
Divy Le Ray9f238482007-03-31 00:23:13 -0700545 int min_tids = is_offload(adap) ? MC5_MIN_TIDS : 0;
Divy Le Ray896392e2007-02-24 16:43:50 -0800546
Divy Le Ray4d22de32007-01-18 22:04:14 -0500547 if (adap->flags & FULL_INIT_DONE)
548 return -EBUSY;
549 if (val && adap->params.rev == 0)
550 return -EINVAL;
Divy Le Ray9f238482007-03-31 00:23:13 -0700551 if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
552 min_tids)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500553 return -EINVAL;
554 adap->params.mc5.nfilters = val;
555 return 0;
556}
557
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800558static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
559 const char *buf, size_t len)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500560{
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800561 return attr_store(d, buf, len, set_nfilters, 0, ~0);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500562}
563
Divy Le Ray896392e2007-02-24 16:43:50 -0800564static ssize_t set_nservers(struct net_device *dev, unsigned int val)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500565{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700566 struct port_info *pi = netdev_priv(dev);
567 struct adapter *adap = pi->adapter;
Divy Le Ray896392e2007-02-24 16:43:50 -0800568
Divy Le Ray4d22de32007-01-18 22:04:14 -0500569 if (adap->flags & FULL_INIT_DONE)
570 return -EBUSY;
Divy Le Ray9f238482007-03-31 00:23:13 -0700571 if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters -
572 MC5_MIN_TIDS)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500573 return -EINVAL;
574 adap->params.mc5.nservers = val;
575 return 0;
576}
577
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800578static ssize_t store_nservers(struct device *d, struct device_attribute *attr,
579 const char *buf, size_t len)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500580{
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800581 return attr_store(d, buf, len, set_nservers, 0, ~0);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500582}
583
584#define CXGB3_ATTR_R(name, val_expr) \
585CXGB3_SHOW(name, val_expr) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800586static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500587
588#define CXGB3_ATTR_RW(name, val_expr, store_method) \
589CXGB3_SHOW(name, val_expr) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800590static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500591
592CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));
593CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);
594CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);
595
596static struct attribute *cxgb3_attrs[] = {
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800597 &dev_attr_cam_size.attr,
598 &dev_attr_nfilters.attr,
599 &dev_attr_nservers.attr,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500600 NULL
601};
602
603static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
604
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800605static ssize_t tm_attr_show(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800606 char *buf, int sched)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500607{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700608 struct port_info *pi = netdev_priv(to_net_dev(d));
609 struct adapter *adap = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500610 unsigned int v, addr, bpt, cpt;
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700611 ssize_t len;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500612
613 addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
614 rtnl_lock();
615 t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
616 v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
617 if (sched & 1)
618 v >>= 16;
619 bpt = (v >> 8) & 0xff;
620 cpt = v & 0xff;
621 if (!cpt)
622 len = sprintf(buf, "disabled\n");
623 else {
624 v = (adap->params.vpd.cclk * 1000) / cpt;
625 len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125);
626 }
627 rtnl_unlock();
628 return len;
629}
630
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800631static ssize_t tm_attr_store(struct device *d,
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800632 const char *buf, size_t len, int sched)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500633{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700634 struct port_info *pi = netdev_priv(to_net_dev(d));
635 struct adapter *adap = pi->adapter;
636 unsigned int val;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500637 char *endp;
638 ssize_t ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500639
640 if (!capable(CAP_NET_ADMIN))
641 return -EPERM;
642
643 val = simple_strtoul(buf, &endp, 0);
644 if (endp == buf || val > 10000000)
645 return -EINVAL;
646
647 rtnl_lock();
648 ret = t3_config_sched(adap, val, sched);
649 if (!ret)
650 ret = len;
651 rtnl_unlock();
652 return ret;
653}
654
655#define TM_ATTR(name, sched) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800656static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
657 char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500658{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800659 return tm_attr_show(d, buf, sched); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500660} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800661static ssize_t store_##name(struct device *d, struct device_attribute *attr, \
662 const char *buf, size_t len) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500663{ \
Divy Le Ray3e5192e2007-11-16 11:22:10 -0800664 return tm_attr_store(d, buf, len, sched); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500665} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800666static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500667
668TM_ATTR(sched0, 0);
669TM_ATTR(sched1, 1);
670TM_ATTR(sched2, 2);
671TM_ATTR(sched3, 3);
672TM_ATTR(sched4, 4);
673TM_ATTR(sched5, 5);
674TM_ATTR(sched6, 6);
675TM_ATTR(sched7, 7);
676
677static struct attribute *offload_attrs[] = {
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800678 &dev_attr_sched0.attr,
679 &dev_attr_sched1.attr,
680 &dev_attr_sched2.attr,
681 &dev_attr_sched3.attr,
682 &dev_attr_sched4.attr,
683 &dev_attr_sched5.attr,
684 &dev_attr_sched6.attr,
685 &dev_attr_sched7.attr,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500686 NULL
687};
688
689static struct attribute_group offload_attr_group = {.attrs = offload_attrs };
690
691/*
692 * Sends an sk_buff to an offload queue driver
693 * after dealing with any active network taps.
694 */
695static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
696{
697 int ret;
698
699 local_bh_disable();
700 ret = t3_offload_tx(tdev, skb);
701 local_bh_enable();
702 return ret;
703}
704
705static int write_smt_entry(struct adapter *adapter, int idx)
706{
707 struct cpl_smt_write_req *req;
708 struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);
709
710 if (!skb)
711 return -ENOMEM;
712
713 req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
714 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
715 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
716 req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */
717 req->iff = idx;
718 memset(req->src_mac1, 0, sizeof(req->src_mac1));
719 memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);
720 skb->priority = 1;
721 offload_tx(&adapter->tdev, skb);
722 return 0;
723}
724
725static int init_smt(struct adapter *adapter)
726{
727 int i;
728
729 for_each_port(adapter, i)
730 write_smt_entry(adapter, i);
731 return 0;
732}
733
734static void init_port_mtus(struct adapter *adapter)
735{
736 unsigned int mtus = adapter->port[0]->mtu;
737
738 if (adapter->port[1])
739 mtus |= adapter->port[1]->mtu << 16;
740 t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
741}
742
Divy Le Ray14ab9892007-01-30 19:43:50 -0800743static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
744 int hi, int port)
745{
746 struct sk_buff *skb;
747 struct mngt_pktsched_wr *req;
748
749 skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
750 req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
751 req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
752 req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
753 req->sched = sched;
754 req->idx = qidx;
755 req->min = lo;
756 req->max = hi;
757 req->binding = port;
758 t3_mgmt_tx(adap, skb);
759}
760
761static void bind_qsets(struct adapter *adap)
762{
763 int i, j;
764
765 for_each_port(adap, i) {
766 const struct port_info *pi = adap2pinfo(adap, i);
767
768 for (j = 0; j < pi->nqsets; ++j)
769 send_pktsched_cmd(adap, 1, pi->first_qset + j, -1,
770 -1, i);
771 }
772}
773
Divy Le Ray7f672cf2007-03-31 00:23:30 -0700774#define FW_FNAME "t3fw-%d.%d.%d.bin"
Divy Le Ray47330072007-08-29 19:15:52 -0700775#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin"
Divy Le Ray2e283962007-03-18 13:10:06 -0700776
777static int upgrade_fw(struct adapter *adap)
778{
779 int ret;
780 char buf[64];
781 const struct firmware *fw;
782 struct device *dev = &adap->pdev->dev;
783
784 snprintf(buf, sizeof(buf), FW_FNAME, FW_VERSION_MAJOR,
Divy Le Ray7f672cf2007-03-31 00:23:30 -0700785 FW_VERSION_MINOR, FW_VERSION_MICRO);
Divy Le Ray2e283962007-03-18 13:10:06 -0700786 ret = request_firmware(&fw, buf, dev);
787 if (ret < 0) {
788 dev_err(dev, "could not upgrade firmware: unable to load %s\n",
789 buf);
790 return ret;
791 }
792 ret = t3_load_fw(adap, fw->data, fw->size);
793 release_firmware(fw);
Divy Le Ray47330072007-08-29 19:15:52 -0700794
795 if (ret == 0)
796 dev_info(dev, "successful upgrade to firmware %d.%d.%d\n",
797 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
798 else
799 dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n",
800 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
Jeff Garzik2eab17a2007-11-23 21:59:45 -0500801
Divy Le Ray47330072007-08-29 19:15:52 -0700802 return ret;
803}
804
805static inline char t3rev2char(struct adapter *adapter)
806{
807 char rev = 0;
808
809 switch(adapter->params.rev) {
810 case T3_REV_B:
811 case T3_REV_B2:
812 rev = 'b';
813 break;
Divy Le Ray1aafee22007-09-05 15:58:36 -0700814 case T3_REV_C:
815 rev = 'c';
816 break;
Divy Le Ray47330072007-08-29 19:15:52 -0700817 }
818 return rev;
819}
820
Stephen Hemminger9265fab2007-10-08 16:22:29 -0700821static int update_tpsram(struct adapter *adap)
Divy Le Ray47330072007-08-29 19:15:52 -0700822{
823 const struct firmware *tpsram;
824 char buf[64];
825 struct device *dev = &adap->pdev->dev;
826 int ret;
827 char rev;
Jeff Garzik2eab17a2007-11-23 21:59:45 -0500828
Divy Le Ray47330072007-08-29 19:15:52 -0700829 rev = t3rev2char(adap);
830 if (!rev)
831 return 0;
832
833 snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
834 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
835
836 ret = request_firmware(&tpsram, buf, dev);
837 if (ret < 0) {
838 dev_err(dev, "could not load TP SRAM: unable to load %s\n",
839 buf);
840 return ret;
841 }
Jeff Garzik2eab17a2007-11-23 21:59:45 -0500842
Divy Le Ray47330072007-08-29 19:15:52 -0700843 ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
844 if (ret)
Jeff Garzik2eab17a2007-11-23 21:59:45 -0500845 goto release_tpsram;
Divy Le Ray47330072007-08-29 19:15:52 -0700846
847 ret = t3_set_proto_sram(adap, tpsram->data);
848 if (ret == 0)
849 dev_info(dev,
850 "successful update of protocol engine "
851 "to %d.%d.%d\n",
852 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
853 else
854 dev_err(dev, "failed to update of protocol engine %d.%d.%d\n",
855 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
856 if (ret)
857 dev_err(dev, "loading protocol SRAM failed\n");
858
859release_tpsram:
860 release_firmware(tpsram);
Jeff Garzik2eab17a2007-11-23 21:59:45 -0500861
Divy Le Ray2e283962007-03-18 13:10:06 -0700862 return ret;
863}
864
Divy Le Ray4d22de32007-01-18 22:04:14 -0500865/**
866 * cxgb_up - enable the adapter
867 * @adapter: adapter being enabled
868 *
869 * Called when the first port is enabled, this function performs the
870 * actions necessary to make an adapter operational, such as completing
871 * the initialization of HW modules, and enabling interrupts.
872 *
873 * Must be called with the rtnl lock held.
874 */
875static int cxgb_up(struct adapter *adap)
876{
Denis Chengc54f5c22007-07-18 15:24:49 +0800877 int err;
Divy Le Ray47330072007-08-29 19:15:52 -0700878 int must_load;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500879
880 if (!(adap->flags & FULL_INIT_DONE)) {
Divy Le Raya5a3b462007-09-05 15:58:09 -0700881 err = t3_check_fw_version(adap, &must_load);
882 if (err == -EINVAL) {
Divy Le Ray2e283962007-03-18 13:10:06 -0700883 err = upgrade_fw(adap);
Divy Le Raya5a3b462007-09-05 15:58:09 -0700884 if (err && must_load)
885 goto out;
886 }
Divy Le Ray4d22de32007-01-18 22:04:14 -0500887
Divy Le Ray47330072007-08-29 19:15:52 -0700888 err = t3_check_tpsram_version(adap, &must_load);
889 if (err == -EINVAL) {
890 err = update_tpsram(adap);
891 if (err && must_load)
892 goto out;
893 }
894
Divy Le Ray4d22de32007-01-18 22:04:14 -0500895 err = t3_init_hw(adap, 0);
896 if (err)
897 goto out;
898
Divy Le Rayb8819552007-12-17 18:47:31 -0800899 t3_set_reg_field(adap, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
Divy Le Ray6cdbd772007-04-09 20:10:33 -0700900 t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700901
Divy Le Ray4d22de32007-01-18 22:04:14 -0500902 err = setup_sge_qsets(adap);
903 if (err)
904 goto out;
905
906 setup_rss(adap);
Divy Le Ray48c4b6d2008-05-06 19:25:56 -0700907 if (!(adap->flags & NAPI_INIT))
908 init_napi(adap);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500909 adap->flags |= FULL_INIT_DONE;
910 }
911
912 t3_intr_clear(adap);
913
914 if (adap->flags & USING_MSIX) {
915 name_msix_vecs(adap);
916 err = request_irq(adap->msix_info[0].vec,
917 t3_async_intr_handler, 0,
918 adap->msix_info[0].desc, adap);
919 if (err)
920 goto irq_err;
921
Divy Le Ray42256f52007-11-16 11:21:39 -0800922 err = request_msix_data_irqs(adap);
923 if (err) {
Divy Le Ray4d22de32007-01-18 22:04:14 -0500924 free_irq(adap->msix_info[0].vec, adap);
925 goto irq_err;
926 }
927 } else if ((err = request_irq(adap->pdev->irq,
928 t3_intr_handler(adap,
929 adap->sge.qs[0].rspq.
930 polling),
Thomas Gleixner2db63462007-02-14 00:33:20 -0800931 (adap->flags & USING_MSI) ?
932 0 : IRQF_SHARED,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500933 adap->name, adap)))
934 goto irq_err;
935
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700936 enable_all_napi(adap);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500937 t3_sge_start(adap);
938 t3_intr_enable(adap);
Divy Le Ray14ab9892007-01-30 19:43:50 -0800939
Divy Le Rayb8819552007-12-17 18:47:31 -0800940 if (adap->params.rev >= T3_REV_C && !(adap->flags & TP_PARITY_INIT) &&
941 is_offload(adap) && init_tp_parity(adap) == 0)
942 adap->flags |= TP_PARITY_INIT;
943
944 if (adap->flags & TP_PARITY_INIT) {
945 t3_write_reg(adap, A_TP_INT_CAUSE,
946 F_CMCACHEPERR | F_ARPLUTPERR);
947 t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff);
948 }
949
Divy Le Ray14ab9892007-01-30 19:43:50 -0800950 if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
951 bind_qsets(adap);
952 adap->flags |= QUEUES_BOUND;
953
Divy Le Ray4d22de32007-01-18 22:04:14 -0500954out:
955 return err;
956irq_err:
957 CH_ERR(adap, "request_irq failed, err %d\n", err);
958 goto out;
959}
960
961/*
962 * Release resources when all the ports and offloading have been stopped.
963 */
964static void cxgb_down(struct adapter *adapter)
965{
966 t3_sge_stop(adapter);
967 spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */
968 t3_intr_disable(adapter);
969 spin_unlock_irq(&adapter->work_lock);
970
971 if (adapter->flags & USING_MSIX) {
972 int i, n = 0;
973
974 free_irq(adapter->msix_info[0].vec, adapter);
975 for_each_port(adapter, i)
976 n += adap2pinfo(adapter, i)->nqsets;
977
978 for (i = 0; i < n; ++i)
979 free_irq(adapter->msix_info[i + 1].vec,
980 &adapter->sge.qs[i]);
981 } else
982 free_irq(adapter->pdev->irq, adapter);
983
984 flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */
985 quiesce_rx(adapter);
986}
987
988static void schedule_chk_task(struct adapter *adap)
989{
990 unsigned int timeo;
991
992 timeo = adap->params.linkpoll_period ?
993 (HZ * adap->params.linkpoll_period) / 10 :
994 adap->params.stats_update_period * HZ;
995 if (timeo)
996 queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo);
997}
998
999static int offload_open(struct net_device *dev)
1000{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001001 struct port_info *pi = netdev_priv(dev);
1002 struct adapter *adapter = pi->adapter;
1003 struct t3cdev *tdev = dev2t3cdev(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001004 int adap_up = adapter->open_device_map & PORT_MASK;
Denis Chengc54f5c22007-07-18 15:24:49 +08001005 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001006
1007 if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
1008 return 0;
1009
1010 if (!adap_up && (err = cxgb_up(adapter)) < 0)
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001011 goto out;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001012
1013 t3_tp_set_offload_mode(adapter, 1);
1014 tdev->lldev = adapter->port[0];
1015 err = cxgb3_offload_activate(adapter);
1016 if (err)
1017 goto out;
1018
1019 init_port_mtus(adapter);
1020 t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
1021 adapter->params.b_wnd,
1022 adapter->params.rev == 0 ?
1023 adapter->port[0]->mtu : 0xffff);
1024 init_smt(adapter);
1025
Dan Noed96a51f2008-04-12 22:34:38 -04001026 if (sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group))
1027 dev_dbg(&dev->dev, "cannot create sysfs group\n");
Divy Le Ray4d22de32007-01-18 22:04:14 -05001028
1029 /* Call back all registered clients */
1030 cxgb3_add_clients(tdev);
1031
1032out:
1033 /* restore them in case the offload module has changed them */
1034 if (err) {
1035 t3_tp_set_offload_mode(adapter, 0);
1036 clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
1037 cxgb3_set_dummy_ops(tdev);
1038 }
1039 return err;
1040}
1041
1042static int offload_close(struct t3cdev *tdev)
1043{
1044 struct adapter *adapter = tdev2adap(tdev);
1045
1046 if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
1047 return 0;
1048
1049 /* Call back all registered clients */
1050 cxgb3_remove_clients(tdev);
1051
Divy Le Ray0ee8d332007-02-08 16:55:59 -08001052 sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001053
1054 tdev->lldev = NULL;
1055 cxgb3_set_dummy_ops(tdev);
1056 t3_tp_set_offload_mode(adapter, 0);
1057 clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
1058
1059 if (!adapter->open_device_map)
1060 cxgb_down(adapter);
1061
1062 cxgb3_offload_deactivate(adapter);
1063 return 0;
1064}
1065
1066static int cxgb_open(struct net_device *dev)
1067{
Divy Le Ray4d22de32007-01-18 22:04:14 -05001068 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001069 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001070 int other_ports = adapter->open_device_map & PORT_MASK;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001071 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001072
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07001073 if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001074 return err;
1075
1076 set_bit(pi->port_id, &adapter->open_device_map);
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07001077 if (is_offload(adapter) && !ofld_disable) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001078 err = offload_open(dev);
1079 if (err)
1080 printk(KERN_WARNING
1081 "Could not initialize offload capabilities\n");
1082 }
1083
1084 link_start(dev);
1085 t3_port_intr_enable(adapter, pi->port_id);
1086 netif_start_queue(dev);
1087 if (!other_ports)
1088 schedule_chk_task(adapter);
1089
1090 return 0;
1091}
1092
1093static int cxgb_close(struct net_device *dev)
1094{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001095 struct port_info *pi = netdev_priv(dev);
1096 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001097
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001098 t3_port_intr_disable(adapter, pi->port_id);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001099 netif_stop_queue(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001100 pi->phy.ops->power_down(&pi->phy, 1);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001101 netif_carrier_off(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001102 t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001103
1104 spin_lock(&adapter->work_lock); /* sync with update task */
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001105 clear_bit(pi->port_id, &adapter->open_device_map);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001106 spin_unlock(&adapter->work_lock);
1107
1108 if (!(adapter->open_device_map & PORT_MASK))
1109 cancel_rearming_delayed_workqueue(cxgb3_wq,
1110 &adapter->adap_check_task);
1111
1112 if (!adapter->open_device_map)
1113 cxgb_down(adapter);
1114
1115 return 0;
1116}
1117
1118static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
1119{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001120 struct port_info *pi = netdev_priv(dev);
1121 struct adapter *adapter = pi->adapter;
1122 struct net_device_stats *ns = &pi->netstats;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001123 const struct mac_stats *pstats;
1124
1125 spin_lock(&adapter->stats_lock);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001126 pstats = t3_mac_update_stats(&pi->mac);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001127 spin_unlock(&adapter->stats_lock);
1128
1129 ns->tx_bytes = pstats->tx_octets;
1130 ns->tx_packets = pstats->tx_frames;
1131 ns->rx_bytes = pstats->rx_octets;
1132 ns->rx_packets = pstats->rx_frames;
1133 ns->multicast = pstats->rx_mcast_frames;
1134
1135 ns->tx_errors = pstats->tx_underrun;
1136 ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs +
1137 pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short +
1138 pstats->rx_fifo_ovfl;
1139
1140 /* detailed rx_errors */
1141 ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long;
1142 ns->rx_over_errors = 0;
1143 ns->rx_crc_errors = pstats->rx_fcs_errs;
1144 ns->rx_frame_errors = pstats->rx_symbol_errs;
1145 ns->rx_fifo_errors = pstats->rx_fifo_ovfl;
1146 ns->rx_missed_errors = pstats->rx_cong_drops;
1147
1148 /* detailed tx_errors */
1149 ns->tx_aborted_errors = 0;
1150 ns->tx_carrier_errors = 0;
1151 ns->tx_fifo_errors = pstats->tx_underrun;
1152 ns->tx_heartbeat_errors = 0;
1153 ns->tx_window_errors = 0;
1154 return ns;
1155}
1156
1157static u32 get_msglevel(struct net_device *dev)
1158{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001159 struct port_info *pi = netdev_priv(dev);
1160 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001161
1162 return adapter->msg_enable;
1163}
1164
1165static void set_msglevel(struct net_device *dev, u32 val)
1166{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001167 struct port_info *pi = netdev_priv(dev);
1168 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001169
1170 adapter->msg_enable = val;
1171}
1172
1173static char stats_strings[][ETH_GSTRING_LEN] = {
1174 "TxOctetsOK ",
1175 "TxFramesOK ",
1176 "TxMulticastFramesOK",
1177 "TxBroadcastFramesOK",
1178 "TxPauseFrames ",
1179 "TxUnderrun ",
1180 "TxExtUnderrun ",
1181
1182 "TxFrames64 ",
1183 "TxFrames65To127 ",
1184 "TxFrames128To255 ",
1185 "TxFrames256To511 ",
1186 "TxFrames512To1023 ",
1187 "TxFrames1024To1518 ",
1188 "TxFrames1519ToMax ",
1189
1190 "RxOctetsOK ",
1191 "RxFramesOK ",
1192 "RxMulticastFramesOK",
1193 "RxBroadcastFramesOK",
1194 "RxPauseFrames ",
1195 "RxFCSErrors ",
1196 "RxSymbolErrors ",
1197 "RxShortErrors ",
1198 "RxJabberErrors ",
1199 "RxLengthErrors ",
1200 "RxFIFOoverflow ",
1201
1202 "RxFrames64 ",
1203 "RxFrames65To127 ",
1204 "RxFrames128To255 ",
1205 "RxFrames256To511 ",
1206 "RxFrames512To1023 ",
1207 "RxFrames1024To1518 ",
1208 "RxFrames1519ToMax ",
1209
1210 "PhyFIFOErrors ",
1211 "TSO ",
1212 "VLANextractions ",
1213 "VLANinsertions ",
1214 "TxCsumOffload ",
1215 "RxCsumGood ",
Divy Le Rayb47385b2008-05-21 18:56:26 -07001216 "LroAggregated ",
1217 "LroFlushed ",
1218 "LroNoDesc ",
Divy Le Rayfc906642007-03-18 13:10:12 -07001219 "RxDrops ",
1220
1221 "CheckTXEnToggled ",
1222 "CheckResets ",
1223
Divy Le Ray4d22de32007-01-18 22:04:14 -05001224};
1225
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001226static int get_sset_count(struct net_device *dev, int sset)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001227{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001228 switch (sset) {
1229 case ETH_SS_STATS:
1230 return ARRAY_SIZE(stats_strings);
1231 default:
1232 return -EOPNOTSUPP;
1233 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001234}
1235
1236#define T3_REGMAP_SIZE (3 * 1024)
1237
1238static int get_regs_len(struct net_device *dev)
1239{
1240 return T3_REGMAP_SIZE;
1241}
1242
1243static int get_eeprom_len(struct net_device *dev)
1244{
1245 return EEPROMSIZE;
1246}
1247
1248static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
1249{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001250 struct port_info *pi = netdev_priv(dev);
1251 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001252 u32 fw_vers = 0;
Divy Le Ray47330072007-08-29 19:15:52 -07001253 u32 tp_vers = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001254
1255 t3_get_fw_version(adapter, &fw_vers);
Divy Le Ray47330072007-08-29 19:15:52 -07001256 t3_get_tp_version(adapter, &tp_vers);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001257
1258 strcpy(info->driver, DRV_NAME);
1259 strcpy(info->version, DRV_VERSION);
1260 strcpy(info->bus_info, pci_name(adapter->pdev));
1261 if (!fw_vers)
1262 strcpy(info->fw_version, "N/A");
Divy Le Ray4aac3892007-01-30 19:43:45 -08001263 else {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001264 snprintf(info->fw_version, sizeof(info->fw_version),
Divy Le Ray47330072007-08-29 19:15:52 -07001265 "%s %u.%u.%u TP %u.%u.%u",
Divy Le Ray4aac3892007-01-30 19:43:45 -08001266 G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
1267 G_FW_VERSION_MAJOR(fw_vers),
1268 G_FW_VERSION_MINOR(fw_vers),
Divy Le Ray47330072007-08-29 19:15:52 -07001269 G_FW_VERSION_MICRO(fw_vers),
1270 G_TP_VERSION_MAJOR(tp_vers),
1271 G_TP_VERSION_MINOR(tp_vers),
1272 G_TP_VERSION_MICRO(tp_vers));
Divy Le Ray4aac3892007-01-30 19:43:45 -08001273 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001274}
1275
1276static void get_strings(struct net_device *dev, u32 stringset, u8 * data)
1277{
1278 if (stringset == ETH_SS_STATS)
1279 memcpy(data, stats_strings, sizeof(stats_strings));
1280}
1281
1282static unsigned long collect_sge_port_stats(struct adapter *adapter,
1283 struct port_info *p, int idx)
1284{
1285 int i;
1286 unsigned long tot = 0;
1287
1288 for (i = 0; i < p->nqsets; ++i)
1289 tot += adapter->sge.qs[i + p->first_qset].port_stats[idx];
1290 return tot;
1291}
1292
1293static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
1294 u64 *data)
1295{
Divy Le Ray4d22de32007-01-18 22:04:14 -05001296 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001297 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001298 const struct mac_stats *s;
1299
1300 spin_lock(&adapter->stats_lock);
1301 s = t3_mac_update_stats(&pi->mac);
1302 spin_unlock(&adapter->stats_lock);
1303
1304 *data++ = s->tx_octets;
1305 *data++ = s->tx_frames;
1306 *data++ = s->tx_mcast_frames;
1307 *data++ = s->tx_bcast_frames;
1308 *data++ = s->tx_pause;
1309 *data++ = s->tx_underrun;
1310 *data++ = s->tx_fifo_urun;
1311
1312 *data++ = s->tx_frames_64;
1313 *data++ = s->tx_frames_65_127;
1314 *data++ = s->tx_frames_128_255;
1315 *data++ = s->tx_frames_256_511;
1316 *data++ = s->tx_frames_512_1023;
1317 *data++ = s->tx_frames_1024_1518;
1318 *data++ = s->tx_frames_1519_max;
1319
1320 *data++ = s->rx_octets;
1321 *data++ = s->rx_frames;
1322 *data++ = s->rx_mcast_frames;
1323 *data++ = s->rx_bcast_frames;
1324 *data++ = s->rx_pause;
1325 *data++ = s->rx_fcs_errs;
1326 *data++ = s->rx_symbol_errs;
1327 *data++ = s->rx_short;
1328 *data++ = s->rx_jabber;
1329 *data++ = s->rx_too_long;
1330 *data++ = s->rx_fifo_ovfl;
1331
1332 *data++ = s->rx_frames_64;
1333 *data++ = s->rx_frames_65_127;
1334 *data++ = s->rx_frames_128_255;
1335 *data++ = s->rx_frames_256_511;
1336 *data++ = s->rx_frames_512_1023;
1337 *data++ = s->rx_frames_1024_1518;
1338 *data++ = s->rx_frames_1519_max;
1339
1340 *data++ = pi->phy.fifo_errors;
1341
1342 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO);
1343 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX);
1344 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
1345 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
1346 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
Divy Le Rayb47385b2008-05-21 18:56:26 -07001347 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_AGGR);
1348 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_FLUSHED);
1349 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_NO_DESC);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001350 *data++ = s->rx_cong_drops;
Divy Le Rayfc906642007-03-18 13:10:12 -07001351
1352 *data++ = s->num_toggled;
1353 *data++ = s->num_resets;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001354}
1355
1356static inline void reg_block_dump(struct adapter *ap, void *buf,
1357 unsigned int start, unsigned int end)
1358{
1359 u32 *p = buf + start;
1360
1361 for (; start <= end; start += sizeof(u32))
1362 *p++ = t3_read_reg(ap, start);
1363}
1364
1365static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
1366 void *buf)
1367{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001368 struct port_info *pi = netdev_priv(dev);
1369 struct adapter *ap = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001370
1371 /*
1372 * Version scheme:
1373 * bits 0..9: chip version
1374 * bits 10..15: chip revision
1375 * bit 31: set for PCIe cards
1376 */
1377 regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31);
1378
1379 /*
1380 * We skip the MAC statistics registers because they are clear-on-read.
1381 * Also reading multi-register stats would need to synchronize with the
1382 * periodic mac stats accumulation. Hard to justify the complexity.
1383 */
1384 memset(buf, 0, T3_REGMAP_SIZE);
1385 reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
1386 reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
1387 reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
1388 reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
1389 reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
1390 reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0,
1391 XGM_REG(A_XGM_SERDES_STAT3, 1));
1392 reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
1393 XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
1394}
1395
1396static int restart_autoneg(struct net_device *dev)
1397{
1398 struct port_info *p = netdev_priv(dev);
1399
1400 if (!netif_running(dev))
1401 return -EAGAIN;
1402 if (p->link_config.autoneg != AUTONEG_ENABLE)
1403 return -EINVAL;
1404 p->phy.ops->autoneg_restart(&p->phy);
1405 return 0;
1406}
1407
1408static int cxgb3_phys_id(struct net_device *dev, u32 data)
1409{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001410 struct port_info *pi = netdev_priv(dev);
1411 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001412 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001413
1414 if (data == 0)
1415 data = 2;
1416
1417 for (i = 0; i < data * 2; i++) {
1418 t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
1419 (i & 1) ? F_GPIO0_OUT_VAL : 0);
1420 if (msleep_interruptible(500))
1421 break;
1422 }
1423 t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
1424 F_GPIO0_OUT_VAL);
1425 return 0;
1426}
1427
1428static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1429{
1430 struct port_info *p = netdev_priv(dev);
1431
1432 cmd->supported = p->link_config.supported;
1433 cmd->advertising = p->link_config.advertising;
1434
1435 if (netif_carrier_ok(dev)) {
1436 cmd->speed = p->link_config.speed;
1437 cmd->duplex = p->link_config.duplex;
1438 } else {
1439 cmd->speed = -1;
1440 cmd->duplex = -1;
1441 }
1442
1443 cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
1444 cmd->phy_address = p->phy.addr;
1445 cmd->transceiver = XCVR_EXTERNAL;
1446 cmd->autoneg = p->link_config.autoneg;
1447 cmd->maxtxpkt = 0;
1448 cmd->maxrxpkt = 0;
1449 return 0;
1450}
1451
1452static int speed_duplex_to_caps(int speed, int duplex)
1453{
1454 int cap = 0;
1455
1456 switch (speed) {
1457 case SPEED_10:
1458 if (duplex == DUPLEX_FULL)
1459 cap = SUPPORTED_10baseT_Full;
1460 else
1461 cap = SUPPORTED_10baseT_Half;
1462 break;
1463 case SPEED_100:
1464 if (duplex == DUPLEX_FULL)
1465 cap = SUPPORTED_100baseT_Full;
1466 else
1467 cap = SUPPORTED_100baseT_Half;
1468 break;
1469 case SPEED_1000:
1470 if (duplex == DUPLEX_FULL)
1471 cap = SUPPORTED_1000baseT_Full;
1472 else
1473 cap = SUPPORTED_1000baseT_Half;
1474 break;
1475 case SPEED_10000:
1476 if (duplex == DUPLEX_FULL)
1477 cap = SUPPORTED_10000baseT_Full;
1478 }
1479 return cap;
1480}
1481
1482#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1483 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1484 ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
1485 ADVERTISED_10000baseT_Full)
1486
1487static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1488{
1489 struct port_info *p = netdev_priv(dev);
1490 struct link_config *lc = &p->link_config;
1491
1492 if (!(lc->supported & SUPPORTED_Autoneg))
1493 return -EOPNOTSUPP; /* can't change speed/duplex */
1494
1495 if (cmd->autoneg == AUTONEG_DISABLE) {
1496 int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
1497
1498 if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
1499 return -EINVAL;
1500 lc->requested_speed = cmd->speed;
1501 lc->requested_duplex = cmd->duplex;
1502 lc->advertising = 0;
1503 } else {
1504 cmd->advertising &= ADVERTISED_MASK;
1505 cmd->advertising &= lc->supported;
1506 if (!cmd->advertising)
1507 return -EINVAL;
1508 lc->requested_speed = SPEED_INVALID;
1509 lc->requested_duplex = DUPLEX_INVALID;
1510 lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
1511 }
1512 lc->autoneg = cmd->autoneg;
1513 if (netif_running(dev))
1514 t3_link_start(&p->phy, &p->mac, lc);
1515 return 0;
1516}
1517
1518static void get_pauseparam(struct net_device *dev,
1519 struct ethtool_pauseparam *epause)
1520{
1521 struct port_info *p = netdev_priv(dev);
1522
1523 epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
1524 epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0;
1525 epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0;
1526}
1527
1528static int set_pauseparam(struct net_device *dev,
1529 struct ethtool_pauseparam *epause)
1530{
1531 struct port_info *p = netdev_priv(dev);
1532 struct link_config *lc = &p->link_config;
1533
1534 if (epause->autoneg == AUTONEG_DISABLE)
1535 lc->requested_fc = 0;
1536 else if (lc->supported & SUPPORTED_Autoneg)
1537 lc->requested_fc = PAUSE_AUTONEG;
1538 else
1539 return -EINVAL;
1540
1541 if (epause->rx_pause)
1542 lc->requested_fc |= PAUSE_RX;
1543 if (epause->tx_pause)
1544 lc->requested_fc |= PAUSE_TX;
1545 if (lc->autoneg == AUTONEG_ENABLE) {
1546 if (netif_running(dev))
1547 t3_link_start(&p->phy, &p->mac, lc);
1548 } else {
1549 lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1550 if (netif_running(dev))
1551 t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc);
1552 }
1553 return 0;
1554}
1555
1556static u32 get_rx_csum(struct net_device *dev)
1557{
1558 struct port_info *p = netdev_priv(dev);
1559
1560 return p->rx_csum_offload;
1561}
1562
1563static int set_rx_csum(struct net_device *dev, u32 data)
1564{
1565 struct port_info *p = netdev_priv(dev);
1566
1567 p->rx_csum_offload = data;
Divy Le Rayb47385b2008-05-21 18:56:26 -07001568 if (!data) {
1569 struct adapter *adap = p->adapter;
1570 int i;
1571
1572 for (i = p->first_qset; i < p->first_qset + p->nqsets; i++)
1573 adap->sge.qs[i].lro_enabled = 0;
1574 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001575 return 0;
1576}
1577
1578static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
1579{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001580 struct port_info *pi = netdev_priv(dev);
1581 struct adapter *adapter = pi->adapter;
Divy Le Ray05b97b32007-03-18 13:10:01 -07001582 const struct qset_params *q = &adapter->params.sge.qset[pi->first_qset];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001583
1584 e->rx_max_pending = MAX_RX_BUFFERS;
1585 e->rx_mini_max_pending = 0;
1586 e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
1587 e->tx_max_pending = MAX_TXQ_ENTRIES;
1588
Divy Le Ray05b97b32007-03-18 13:10:01 -07001589 e->rx_pending = q->fl_size;
1590 e->rx_mini_pending = q->rspq_size;
1591 e->rx_jumbo_pending = q->jumbo_size;
1592 e->tx_pending = q->txq_size[0];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001593}
1594
1595static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
1596{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001597 struct port_info *pi = netdev_priv(dev);
1598 struct adapter *adapter = pi->adapter;
Divy Le Ray05b97b32007-03-18 13:10:01 -07001599 struct qset_params *q;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001600 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001601
1602 if (e->rx_pending > MAX_RX_BUFFERS ||
1603 e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
1604 e->tx_pending > MAX_TXQ_ENTRIES ||
1605 e->rx_mini_pending > MAX_RSPQ_ENTRIES ||
1606 e->rx_mini_pending < MIN_RSPQ_ENTRIES ||
1607 e->rx_pending < MIN_FL_ENTRIES ||
1608 e->rx_jumbo_pending < MIN_FL_ENTRIES ||
1609 e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES)
1610 return -EINVAL;
1611
1612 if (adapter->flags & FULL_INIT_DONE)
1613 return -EBUSY;
1614
Divy Le Ray05b97b32007-03-18 13:10:01 -07001615 q = &adapter->params.sge.qset[pi->first_qset];
1616 for (i = 0; i < pi->nqsets; ++i, ++q) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001617 q->rspq_size = e->rx_mini_pending;
1618 q->fl_size = e->rx_pending;
1619 q->jumbo_size = e->rx_jumbo_pending;
1620 q->txq_size[0] = e->tx_pending;
1621 q->txq_size[1] = e->tx_pending;
1622 q->txq_size[2] = e->tx_pending;
1623 }
1624 return 0;
1625}
1626
1627static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
1628{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001629 struct port_info *pi = netdev_priv(dev);
1630 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001631 struct qset_params *qsp = &adapter->params.sge.qset[0];
1632 struct sge_qset *qs = &adapter->sge.qs[0];
1633
1634 if (c->rx_coalesce_usecs * 10 > M_NEWTIMER)
1635 return -EINVAL;
1636
1637 qsp->coalesce_usecs = c->rx_coalesce_usecs;
1638 t3_update_qset_coalesce(qs, qsp);
1639 return 0;
1640}
1641
1642static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
1643{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001644 struct port_info *pi = netdev_priv(dev);
1645 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001646 struct qset_params *q = adapter->params.sge.qset;
1647
1648 c->rx_coalesce_usecs = q->coalesce_usecs;
1649 return 0;
1650}
1651
1652static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
1653 u8 * data)
1654{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001655 struct port_info *pi = netdev_priv(dev);
1656 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001657 int i, err = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001658
1659 u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
1660 if (!buf)
1661 return -ENOMEM;
1662
1663 e->magic = EEPROM_MAGIC;
1664 for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
Al Viro05e5c112007-12-22 18:56:23 +00001665 err = t3_seeprom_read(adapter, i, (__le32 *) & buf[i]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001666
1667 if (!err)
1668 memcpy(data, buf + e->offset, e->len);
1669 kfree(buf);
1670 return err;
1671}
1672
1673static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
1674 u8 * data)
1675{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001676 struct port_info *pi = netdev_priv(dev);
1677 struct adapter *adapter = pi->adapter;
Al Viro05e5c112007-12-22 18:56:23 +00001678 u32 aligned_offset, aligned_len;
1679 __le32 *p;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001680 u8 *buf;
Denis Chengc54f5c22007-07-18 15:24:49 +08001681 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001682
1683 if (eeprom->magic != EEPROM_MAGIC)
1684 return -EINVAL;
1685
1686 aligned_offset = eeprom->offset & ~3;
1687 aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
1688
1689 if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
1690 buf = kmalloc(aligned_len, GFP_KERNEL);
1691 if (!buf)
1692 return -ENOMEM;
Al Viro05e5c112007-12-22 18:56:23 +00001693 err = t3_seeprom_read(adapter, aligned_offset, (__le32 *) buf);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001694 if (!err && aligned_len > 4)
1695 err = t3_seeprom_read(adapter,
1696 aligned_offset + aligned_len - 4,
Al Viro05e5c112007-12-22 18:56:23 +00001697 (__le32 *) & buf[aligned_len - 4]);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001698 if (err)
1699 goto out;
1700 memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
1701 } else
1702 buf = data;
1703
1704 err = t3_seeprom_wp(adapter, 0);
1705 if (err)
1706 goto out;
1707
Al Viro05e5c112007-12-22 18:56:23 +00001708 for (p = (__le32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001709 err = t3_seeprom_write(adapter, aligned_offset, *p);
1710 aligned_offset += 4;
1711 }
1712
1713 if (!err)
1714 err = t3_seeprom_wp(adapter, 1);
1715out:
1716 if (buf != data)
1717 kfree(buf);
1718 return err;
1719}
1720
1721static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1722{
1723 wol->supported = 0;
1724 wol->wolopts = 0;
1725 memset(&wol->sopass, 0, sizeof(wol->sopass));
1726}
1727
1728static const struct ethtool_ops cxgb_ethtool_ops = {
1729 .get_settings = get_settings,
1730 .set_settings = set_settings,
1731 .get_drvinfo = get_drvinfo,
1732 .get_msglevel = get_msglevel,
1733 .set_msglevel = set_msglevel,
1734 .get_ringparam = get_sge_param,
1735 .set_ringparam = set_sge_param,
1736 .get_coalesce = get_coalesce,
1737 .set_coalesce = set_coalesce,
1738 .get_eeprom_len = get_eeprom_len,
1739 .get_eeprom = get_eeprom,
1740 .set_eeprom = set_eeprom,
1741 .get_pauseparam = get_pauseparam,
1742 .set_pauseparam = set_pauseparam,
1743 .get_rx_csum = get_rx_csum,
1744 .set_rx_csum = set_rx_csum,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001745 .set_tx_csum = ethtool_op_set_tx_csum,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001746 .set_sg = ethtool_op_set_sg,
1747 .get_link = ethtool_op_get_link,
1748 .get_strings = get_strings,
1749 .phys_id = cxgb3_phys_id,
1750 .nway_reset = restart_autoneg,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001751 .get_sset_count = get_sset_count,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001752 .get_ethtool_stats = get_stats,
1753 .get_regs_len = get_regs_len,
1754 .get_regs = get_regs,
1755 .get_wol = get_wol,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001756 .set_tso = ethtool_op_set_tso,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001757};
1758
1759static int in_range(int val, int lo, int hi)
1760{
1761 return val < 0 || (val <= hi && val >= lo);
1762}
1763
1764static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
1765{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001766 struct port_info *pi = netdev_priv(dev);
1767 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001768 u32 cmd;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001769 int ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001770
1771 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
1772 return -EFAULT;
1773
1774 switch (cmd) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001775 case CHELSIO_SET_QSET_PARAMS:{
1776 int i;
1777 struct qset_params *q;
1778 struct ch_qset_params t;
1779
1780 if (!capable(CAP_NET_ADMIN))
1781 return -EPERM;
1782 if (copy_from_user(&t, useraddr, sizeof(t)))
1783 return -EFAULT;
1784 if (t.qset_idx >= SGE_QSETS)
1785 return -EINVAL;
1786 if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
1787 !in_range(t.cong_thres, 0, 255) ||
1788 !in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
1789 MAX_TXQ_ENTRIES) ||
1790 !in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
1791 MAX_TXQ_ENTRIES) ||
1792 !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
1793 MAX_CTRL_TXQ_ENTRIES) ||
1794 !in_range(t.fl_size[0], MIN_FL_ENTRIES,
1795 MAX_RX_BUFFERS)
1796 || !in_range(t.fl_size[1], MIN_FL_ENTRIES,
1797 MAX_RX_JUMBO_BUFFERS)
1798 || !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
1799 MAX_RSPQ_ENTRIES))
1800 return -EINVAL;
1801 if ((adapter->flags & FULL_INIT_DONE) &&
1802 (t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
1803 t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
1804 t.txq_size[1] >= 0 || t.txq_size[2] >= 0 ||
1805 t.polling >= 0 || t.cong_thres >= 0))
1806 return -EBUSY;
1807
1808 q = &adapter->params.sge.qset[t.qset_idx];
1809
1810 if (t.rspq_size >= 0)
1811 q->rspq_size = t.rspq_size;
1812 if (t.fl_size[0] >= 0)
1813 q->fl_size = t.fl_size[0];
1814 if (t.fl_size[1] >= 0)
1815 q->jumbo_size = t.fl_size[1];
1816 if (t.txq_size[0] >= 0)
1817 q->txq_size[0] = t.txq_size[0];
1818 if (t.txq_size[1] >= 0)
1819 q->txq_size[1] = t.txq_size[1];
1820 if (t.txq_size[2] >= 0)
1821 q->txq_size[2] = t.txq_size[2];
1822 if (t.cong_thres >= 0)
1823 q->cong_thres = t.cong_thres;
1824 if (t.intr_lat >= 0) {
1825 struct sge_qset *qs =
1826 &adapter->sge.qs[t.qset_idx];
1827
1828 q->coalesce_usecs = t.intr_lat;
1829 t3_update_qset_coalesce(qs, q);
1830 }
1831 if (t.polling >= 0) {
1832 if (adapter->flags & USING_MSIX)
1833 q->polling = t.polling;
1834 else {
1835 /* No polling with INTx for T3A */
1836 if (adapter->params.rev == 0 &&
1837 !(adapter->flags & USING_MSI))
1838 t.polling = 0;
1839
1840 for (i = 0; i < SGE_QSETS; i++) {
1841 q = &adapter->params.sge.
1842 qset[i];
1843 q->polling = t.polling;
1844 }
1845 }
1846 }
Divy Le Rayb47385b2008-05-21 18:56:26 -07001847 if (t.lro >= 0) {
1848 struct sge_qset *qs = &adapter->sge.qs[t.qset_idx];
1849 q->lro = t.lro;
1850 qs->lro_enabled = t.lro;
1851 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001852 break;
1853 }
1854 case CHELSIO_GET_QSET_PARAMS:{
1855 struct qset_params *q;
1856 struct ch_qset_params t;
1857
1858 if (copy_from_user(&t, useraddr, sizeof(t)))
1859 return -EFAULT;
1860 if (t.qset_idx >= SGE_QSETS)
1861 return -EINVAL;
1862
1863 q = &adapter->params.sge.qset[t.qset_idx];
1864 t.rspq_size = q->rspq_size;
1865 t.txq_size[0] = q->txq_size[0];
1866 t.txq_size[1] = q->txq_size[1];
1867 t.txq_size[2] = q->txq_size[2];
1868 t.fl_size[0] = q->fl_size;
1869 t.fl_size[1] = q->jumbo_size;
1870 t.polling = q->polling;
Divy Le Rayb47385b2008-05-21 18:56:26 -07001871 t.lro = q->lro;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001872 t.intr_lat = q->coalesce_usecs;
1873 t.cong_thres = q->cong_thres;
1874
1875 if (copy_to_user(useraddr, &t, sizeof(t)))
1876 return -EFAULT;
1877 break;
1878 }
1879 case CHELSIO_SET_QSET_NUM:{
1880 struct ch_reg edata;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001881 unsigned int i, first_qset = 0, other_qsets = 0;
1882
1883 if (!capable(CAP_NET_ADMIN))
1884 return -EPERM;
1885 if (adapter->flags & FULL_INIT_DONE)
1886 return -EBUSY;
1887 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1888 return -EFAULT;
1889 if (edata.val < 1 ||
1890 (edata.val > 1 && !(adapter->flags & USING_MSIX)))
1891 return -EINVAL;
1892
1893 for_each_port(adapter, i)
1894 if (adapter->port[i] && adapter->port[i] != dev)
1895 other_qsets += adap2pinfo(adapter, i)->nqsets;
1896
1897 if (edata.val + other_qsets > SGE_QSETS)
1898 return -EINVAL;
1899
1900 pi->nqsets = edata.val;
1901
1902 for_each_port(adapter, i)
1903 if (adapter->port[i]) {
1904 pi = adap2pinfo(adapter, i);
1905 pi->first_qset = first_qset;
1906 first_qset += pi->nqsets;
1907 }
1908 break;
1909 }
1910 case CHELSIO_GET_QSET_NUM:{
1911 struct ch_reg edata;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001912
1913 edata.cmd = CHELSIO_GET_QSET_NUM;
1914 edata.val = pi->nqsets;
1915 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1916 return -EFAULT;
1917 break;
1918 }
1919 case CHELSIO_LOAD_FW:{
1920 u8 *fw_data;
1921 struct ch_mem_range t;
1922
Alan Cox1b3aa7a2008-04-29 14:29:30 +01001923 if (!capable(CAP_SYS_RAWIO))
Divy Le Ray4d22de32007-01-18 22:04:14 -05001924 return -EPERM;
1925 if (copy_from_user(&t, useraddr, sizeof(t)))
1926 return -EFAULT;
Alan Cox1b3aa7a2008-04-29 14:29:30 +01001927 /* Check t.len sanity ? */
Divy Le Ray4d22de32007-01-18 22:04:14 -05001928 fw_data = kmalloc(t.len, GFP_KERNEL);
1929 if (!fw_data)
1930 return -ENOMEM;
1931
1932 if (copy_from_user
1933 (fw_data, useraddr + sizeof(t), t.len)) {
1934 kfree(fw_data);
1935 return -EFAULT;
1936 }
1937
1938 ret = t3_load_fw(adapter, fw_data, t.len);
1939 kfree(fw_data);
1940 if (ret)
1941 return ret;
1942 break;
1943 }
1944 case CHELSIO_SETMTUTAB:{
1945 struct ch_mtus m;
1946 int i;
1947
1948 if (!is_offload(adapter))
1949 return -EOPNOTSUPP;
1950 if (!capable(CAP_NET_ADMIN))
1951 return -EPERM;
1952 if (offload_running(adapter))
1953 return -EBUSY;
1954 if (copy_from_user(&m, useraddr, sizeof(m)))
1955 return -EFAULT;
1956 if (m.nmtus != NMTUS)
1957 return -EINVAL;
1958 if (m.mtus[0] < 81) /* accommodate SACK */
1959 return -EINVAL;
1960
1961 /* MTUs must be in ascending order */
1962 for (i = 1; i < NMTUS; ++i)
1963 if (m.mtus[i] < m.mtus[i - 1])
1964 return -EINVAL;
1965
1966 memcpy(adapter->params.mtus, m.mtus,
1967 sizeof(adapter->params.mtus));
1968 break;
1969 }
1970 case CHELSIO_GET_PM:{
1971 struct tp_params *p = &adapter->params.tp;
1972 struct ch_pm m = {.cmd = CHELSIO_GET_PM };
1973
1974 if (!is_offload(adapter))
1975 return -EOPNOTSUPP;
1976 m.tx_pg_sz = p->tx_pg_size;
1977 m.tx_num_pg = p->tx_num_pgs;
1978 m.rx_pg_sz = p->rx_pg_size;
1979 m.rx_num_pg = p->rx_num_pgs;
1980 m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan;
1981 if (copy_to_user(useraddr, &m, sizeof(m)))
1982 return -EFAULT;
1983 break;
1984 }
1985 case CHELSIO_SET_PM:{
1986 struct ch_pm m;
1987 struct tp_params *p = &adapter->params.tp;
1988
1989 if (!is_offload(adapter))
1990 return -EOPNOTSUPP;
1991 if (!capable(CAP_NET_ADMIN))
1992 return -EPERM;
1993 if (adapter->flags & FULL_INIT_DONE)
1994 return -EBUSY;
1995 if (copy_from_user(&m, useraddr, sizeof(m)))
1996 return -EFAULT;
vignesh babud9da4662007-07-09 11:50:22 -07001997 if (!is_power_of_2(m.rx_pg_sz) ||
1998 !is_power_of_2(m.tx_pg_sz))
Divy Le Ray4d22de32007-01-18 22:04:14 -05001999 return -EINVAL; /* not power of 2 */
2000 if (!(m.rx_pg_sz & 0x14000))
2001 return -EINVAL; /* not 16KB or 64KB */
2002 if (!(m.tx_pg_sz & 0x1554000))
2003 return -EINVAL;
2004 if (m.tx_num_pg == -1)
2005 m.tx_num_pg = p->tx_num_pgs;
2006 if (m.rx_num_pg == -1)
2007 m.rx_num_pg = p->rx_num_pgs;
2008 if (m.tx_num_pg % 24 || m.rx_num_pg % 24)
2009 return -EINVAL;
2010 if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size ||
2011 m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size)
2012 return -EINVAL;
2013 p->rx_pg_size = m.rx_pg_sz;
2014 p->tx_pg_size = m.tx_pg_sz;
2015 p->rx_num_pgs = m.rx_num_pg;
2016 p->tx_num_pgs = m.tx_num_pg;
2017 break;
2018 }
2019 case CHELSIO_GET_MEM:{
2020 struct ch_mem_range t;
2021 struct mc7 *mem;
2022 u64 buf[32];
2023
2024 if (!is_offload(adapter))
2025 return -EOPNOTSUPP;
2026 if (!(adapter->flags & FULL_INIT_DONE))
2027 return -EIO; /* need the memory controllers */
2028 if (copy_from_user(&t, useraddr, sizeof(t)))
2029 return -EFAULT;
2030 if ((t.addr & 7) || (t.len & 7))
2031 return -EINVAL;
2032 if (t.mem_id == MEM_CM)
2033 mem = &adapter->cm;
2034 else if (t.mem_id == MEM_PMRX)
2035 mem = &adapter->pmrx;
2036 else if (t.mem_id == MEM_PMTX)
2037 mem = &adapter->pmtx;
2038 else
2039 return -EINVAL;
2040
2041 /*
Divy Le Ray18254942007-02-24 16:43:56 -08002042 * Version scheme:
2043 * bits 0..9: chip version
2044 * bits 10..15: chip revision
2045 */
Divy Le Ray4d22de32007-01-18 22:04:14 -05002046 t.version = 3 | (adapter->params.rev << 10);
2047 if (copy_to_user(useraddr, &t, sizeof(t)))
2048 return -EFAULT;
2049
2050 /*
2051 * Read 256 bytes at a time as len can be large and we don't
2052 * want to use huge intermediate buffers.
2053 */
2054 useraddr += sizeof(t); /* advance to start of buffer */
2055 while (t.len) {
2056 unsigned int chunk =
2057 min_t(unsigned int, t.len, sizeof(buf));
2058
2059 ret =
2060 t3_mc7_bd_read(mem, t.addr / 8, chunk / 8,
2061 buf);
2062 if (ret)
2063 return ret;
2064 if (copy_to_user(useraddr, buf, chunk))
2065 return -EFAULT;
2066 useraddr += chunk;
2067 t.addr += chunk;
2068 t.len -= chunk;
2069 }
2070 break;
2071 }
2072 case CHELSIO_SET_TRACE_FILTER:{
2073 struct ch_trace t;
2074 const struct trace_params *tp;
2075
2076 if (!capable(CAP_NET_ADMIN))
2077 return -EPERM;
2078 if (!offload_running(adapter))
2079 return -EAGAIN;
2080 if (copy_from_user(&t, useraddr, sizeof(t)))
2081 return -EFAULT;
2082
2083 tp = (const struct trace_params *)&t.sip;
2084 if (t.config_tx)
2085 t3_config_trace_filter(adapter, tp, 0,
2086 t.invert_match,
2087 t.trace_tx);
2088 if (t.config_rx)
2089 t3_config_trace_filter(adapter, tp, 1,
2090 t.invert_match,
2091 t.trace_rx);
2092 break;
2093 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002094 default:
2095 return -EOPNOTSUPP;
2096 }
2097 return 0;
2098}
2099
2100static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
2101{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002102 struct mii_ioctl_data *data = if_mii(req);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002103 struct port_info *pi = netdev_priv(dev);
2104 struct adapter *adapter = pi->adapter;
2105 int ret, mmd;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002106
2107 switch (cmd) {
2108 case SIOCGMIIPHY:
2109 data->phy_id = pi->phy.addr;
2110 /* FALLTHRU */
2111 case SIOCGMIIREG:{
2112 u32 val;
2113 struct cphy *phy = &pi->phy;
2114
2115 if (!phy->mdio_read)
2116 return -EOPNOTSUPP;
2117 if (is_10G(adapter)) {
2118 mmd = data->phy_id >> 8;
2119 if (!mmd)
2120 mmd = MDIO_DEV_PCS;
2121 else if (mmd > MDIO_DEV_XGXS)
2122 return -EINVAL;
2123
2124 ret =
2125 phy->mdio_read(adapter, data->phy_id & 0x1f,
2126 mmd, data->reg_num, &val);
2127 } else
2128 ret =
2129 phy->mdio_read(adapter, data->phy_id & 0x1f,
2130 0, data->reg_num & 0x1f,
2131 &val);
2132 if (!ret)
2133 data->val_out = val;
2134 break;
2135 }
2136 case SIOCSMIIREG:{
2137 struct cphy *phy = &pi->phy;
2138
2139 if (!capable(CAP_NET_ADMIN))
2140 return -EPERM;
2141 if (!phy->mdio_write)
2142 return -EOPNOTSUPP;
2143 if (is_10G(adapter)) {
2144 mmd = data->phy_id >> 8;
2145 if (!mmd)
2146 mmd = MDIO_DEV_PCS;
2147 else if (mmd > MDIO_DEV_XGXS)
2148 return -EINVAL;
2149
2150 ret =
2151 phy->mdio_write(adapter,
2152 data->phy_id & 0x1f, mmd,
2153 data->reg_num,
2154 data->val_in);
2155 } else
2156 ret =
2157 phy->mdio_write(adapter,
2158 data->phy_id & 0x1f, 0,
2159 data->reg_num & 0x1f,
2160 data->val_in);
2161 break;
2162 }
2163 case SIOCCHIOCTL:
2164 return cxgb_extension_ioctl(dev, req->ifr_data);
2165 default:
2166 return -EOPNOTSUPP;
2167 }
2168 return ret;
2169}
2170
2171static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
2172{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002173 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002174 struct adapter *adapter = pi->adapter;
2175 int ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002176
2177 if (new_mtu < 81) /* accommodate SACK */
2178 return -EINVAL;
2179 if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu)))
2180 return ret;
2181 dev->mtu = new_mtu;
2182 init_port_mtus(adapter);
2183 if (adapter->params.rev == 0 && offload_running(adapter))
2184 t3_load_mtus(adapter, adapter->params.mtus,
2185 adapter->params.a_wnd, adapter->params.b_wnd,
2186 adapter->port[0]->mtu);
2187 return 0;
2188}
2189
2190static int cxgb_set_mac_addr(struct net_device *dev, void *p)
2191{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002192 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002193 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002194 struct sockaddr *addr = p;
2195
2196 if (!is_valid_ether_addr(addr->sa_data))
2197 return -EINVAL;
2198
2199 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
2200 t3_mac_set_address(&pi->mac, 0, dev->dev_addr);
2201 if (offload_running(adapter))
2202 write_smt_entry(adapter, pi->port_id);
2203 return 0;
2204}
2205
2206/**
2207 * t3_synchronize_rx - wait for current Rx processing on a port to complete
2208 * @adap: the adapter
2209 * @p: the port
2210 *
2211 * Ensures that current Rx processing on any of the queues associated with
2212 * the given port completes before returning. We do this by acquiring and
2213 * releasing the locks of the response queues associated with the port.
2214 */
2215static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
2216{
2217 int i;
2218
2219 for (i = 0; i < p->nqsets; i++) {
2220 struct sge_rspq *q = &adap->sge.qs[i + p->first_qset].rspq;
2221
2222 spin_lock_irq(&q->lock);
2223 spin_unlock_irq(&q->lock);
2224 }
2225}
2226
2227static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
2228{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002229 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002230 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002231
2232 pi->vlan_grp = grp;
2233 if (adapter->params.rev > 0)
2234 t3_set_vlan_accel(adapter, 1 << pi->port_id, grp != NULL);
2235 else {
2236 /* single control for all ports */
2237 unsigned int i, have_vlans = 0;
2238 for_each_port(adapter, i)
2239 have_vlans |= adap2pinfo(adapter, i)->vlan_grp != NULL;
2240
2241 t3_set_vlan_accel(adapter, 1, have_vlans);
2242 }
2243 t3_synchronize_rx(adapter, pi);
2244}
2245
Divy Le Ray4d22de32007-01-18 22:04:14 -05002246#ifdef CONFIG_NET_POLL_CONTROLLER
2247static void cxgb_netpoll(struct net_device *dev)
2248{
Divy Le Ray890de332007-05-30 10:01:34 -07002249 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002250 struct adapter *adapter = pi->adapter;
Divy Le Ray890de332007-05-30 10:01:34 -07002251 int qidx;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002252
Divy Le Ray890de332007-05-30 10:01:34 -07002253 for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) {
2254 struct sge_qset *qs = &adapter->sge.qs[qidx];
2255 void *source;
Jeff Garzik2eab17a2007-11-23 21:59:45 -05002256
Divy Le Ray890de332007-05-30 10:01:34 -07002257 if (adapter->flags & USING_MSIX)
2258 source = qs;
2259 else
2260 source = adapter;
2261
2262 t3_intr_handler(adapter, qs->rspq.polling) (0, source);
2263 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002264}
2265#endif
2266
2267/*
2268 * Periodic accumulation of MAC statistics.
2269 */
2270static void mac_stats_update(struct adapter *adapter)
2271{
2272 int i;
2273
2274 for_each_port(adapter, i) {
2275 struct net_device *dev = adapter->port[i];
2276 struct port_info *p = netdev_priv(dev);
2277
2278 if (netif_running(dev)) {
2279 spin_lock(&adapter->stats_lock);
2280 t3_mac_update_stats(&p->mac);
2281 spin_unlock(&adapter->stats_lock);
2282 }
2283 }
2284}
2285
2286static void check_link_status(struct adapter *adapter)
2287{
2288 int i;
2289
2290 for_each_port(adapter, i) {
2291 struct net_device *dev = adapter->port[i];
2292 struct port_info *p = netdev_priv(dev);
2293
2294 if (!(p->port_type->caps & SUPPORTED_IRQ) && netif_running(dev))
2295 t3_link_changed(adapter, i);
2296 }
2297}
2298
Divy Le Rayfc906642007-03-18 13:10:12 -07002299static void check_t3b2_mac(struct adapter *adapter)
2300{
2301 int i;
2302
Divy Le Rayf2d961c2007-04-09 20:10:22 -07002303 if (!rtnl_trylock()) /* synchronize with ifdown */
2304 return;
2305
Divy Le Rayfc906642007-03-18 13:10:12 -07002306 for_each_port(adapter, i) {
2307 struct net_device *dev = adapter->port[i];
2308 struct port_info *p = netdev_priv(dev);
2309 int status;
2310
2311 if (!netif_running(dev))
2312 continue;
2313
2314 status = 0;
Divy Le Ray6d6daba2007-03-31 00:23:24 -07002315 if (netif_running(dev) && netif_carrier_ok(dev))
Divy Le Rayfc906642007-03-18 13:10:12 -07002316 status = t3b2_mac_watchdog_task(&p->mac);
2317 if (status == 1)
2318 p->mac.stats.num_toggled++;
2319 else if (status == 2) {
2320 struct cmac *mac = &p->mac;
2321
2322 t3_mac_set_mtu(mac, dev->mtu);
2323 t3_mac_set_address(mac, 0, dev->dev_addr);
2324 cxgb_set_rxmode(dev);
2325 t3_link_start(&p->phy, mac, &p->link_config);
2326 t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
2327 t3_port_intr_enable(adapter, p->port_id);
2328 p->mac.stats.num_resets++;
2329 }
2330 }
2331 rtnl_unlock();
2332}
2333
2334
Divy Le Ray4d22de32007-01-18 22:04:14 -05002335static void t3_adap_check_task(struct work_struct *work)
2336{
2337 struct adapter *adapter = container_of(work, struct adapter,
2338 adap_check_task.work);
2339 const struct adapter_params *p = &adapter->params;
2340
2341 adapter->check_task_cnt++;
2342
2343 /* Check link status for PHYs without interrupts */
2344 if (p->linkpoll_period)
2345 check_link_status(adapter);
2346
2347 /* Accumulate MAC stats if needed */
2348 if (!p->linkpoll_period ||
2349 (adapter->check_task_cnt * p->linkpoll_period) / 10 >=
2350 p->stats_update_period) {
2351 mac_stats_update(adapter);
2352 adapter->check_task_cnt = 0;
2353 }
2354
Divy Le Rayfc906642007-03-18 13:10:12 -07002355 if (p->rev == T3_REV_B2)
2356 check_t3b2_mac(adapter);
2357
Divy Le Ray4d22de32007-01-18 22:04:14 -05002358 /* Schedule the next check update if any port is active. */
2359 spin_lock(&adapter->work_lock);
2360 if (adapter->open_device_map & PORT_MASK)
2361 schedule_chk_task(adapter);
2362 spin_unlock(&adapter->work_lock);
2363}
2364
2365/*
2366 * Processes external (PHY) interrupts in process context.
2367 */
2368static void ext_intr_task(struct work_struct *work)
2369{
2370 struct adapter *adapter = container_of(work, struct adapter,
2371 ext_intr_handler_task);
2372
2373 t3_phy_intr_handler(adapter);
2374
2375 /* Now reenable external interrupts */
2376 spin_lock_irq(&adapter->work_lock);
2377 if (adapter->slow_intr_mask) {
2378 adapter->slow_intr_mask |= F_T3DBG;
2379 t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG);
2380 t3_write_reg(adapter, A_PL_INT_ENABLE0,
2381 adapter->slow_intr_mask);
2382 }
2383 spin_unlock_irq(&adapter->work_lock);
2384}
2385
2386/*
2387 * Interrupt-context handler for external (PHY) interrupts.
2388 */
2389void t3_os_ext_intr_handler(struct adapter *adapter)
2390{
2391 /*
2392 * Schedule a task to handle external interrupts as they may be slow
2393 * and we use a mutex to protect MDIO registers. We disable PHY
2394 * interrupts in the meantime and let the task reenable them when
2395 * it's done.
2396 */
2397 spin_lock(&adapter->work_lock);
2398 if (adapter->slow_intr_mask) {
2399 adapter->slow_intr_mask &= ~F_T3DBG;
2400 t3_write_reg(adapter, A_PL_INT_ENABLE0,
2401 adapter->slow_intr_mask);
2402 queue_work(cxgb3_wq, &adapter->ext_intr_handler_task);
2403 }
2404 spin_unlock(&adapter->work_lock);
2405}
2406
2407void t3_fatal_err(struct adapter *adapter)
2408{
2409 unsigned int fw_status[4];
2410
2411 if (adapter->flags & FULL_INIT_DONE) {
2412 t3_sge_stop(adapter);
Divy Le Rayc64c2ea2007-08-21 20:49:31 -07002413 t3_write_reg(adapter, A_XGM_TX_CTRL, 0);
2414 t3_write_reg(adapter, A_XGM_RX_CTRL, 0);
2415 t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0);
2416 t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002417 t3_intr_disable(adapter);
2418 }
2419 CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
2420 if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
2421 CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
2422 fw_status[0], fw_status[1],
2423 fw_status[2], fw_status[3]);
2424
2425}
2426
Divy Le Ray91a6b502007-11-16 11:21:55 -08002427/**
2428 * t3_io_error_detected - called when PCI error is detected
2429 * @pdev: Pointer to PCI device
2430 * @state: The current pci connection state
2431 *
2432 * This function is called after a PCI bus error affecting
2433 * this device has been detected.
2434 */
2435static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
2436 pci_channel_state_t state)
2437{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08002438 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002439 int i;
2440
2441 /* Stop all ports */
2442 for_each_port(adapter, i) {
2443 struct net_device *netdev = adapter->port[i];
2444
2445 if (netif_running(netdev))
2446 cxgb_close(netdev);
2447 }
2448
Jeff Garzik2eab17a2007-11-23 21:59:45 -05002449 if (is_offload(adapter) &&
Divy Le Ray91a6b502007-11-16 11:21:55 -08002450 test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
2451 offload_close(&adapter->tdev);
2452
Divy Le Ray0ca41c02008-09-25 14:05:28 +00002453 /* Stop SGE timers */
2454 t3_stop_sge_timers(adapter);
2455
Divy Le Ray91a6b502007-11-16 11:21:55 -08002456 adapter->flags &= ~FULL_INIT_DONE;
2457
2458 pci_disable_device(pdev);
2459
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07002460 /* Request a slot reset. */
Divy Le Ray91a6b502007-11-16 11:21:55 -08002461 return PCI_ERS_RESULT_NEED_RESET;
2462}
2463
2464/**
2465 * t3_io_slot_reset - called after the pci bus has been reset.
2466 * @pdev: Pointer to PCI device
2467 *
2468 * Restart the card from scratch, as if from a cold-boot.
2469 */
2470static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev)
2471{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08002472 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002473
2474 if (pci_enable_device(pdev)) {
2475 dev_err(&pdev->dev,
2476 "Cannot re-enable PCI device after reset.\n");
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07002477 goto err;
Divy Le Ray91a6b502007-11-16 11:21:55 -08002478 }
2479 pci_set_master(pdev);
Divy Le Ray204e2f92008-05-06 19:26:01 -07002480 pci_restore_state(pdev);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002481
Divy Le Ray204e2f92008-05-06 19:26:01 -07002482 /* Free sge resources */
2483 t3_free_sge_resources(adapter);
2484
2485 if (t3_replay_prep_adapter(adapter))
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07002486 goto err;
Divy Le Ray91a6b502007-11-16 11:21:55 -08002487
2488 return PCI_ERS_RESULT_RECOVERED;
Divy Le Ray48c4b6d2008-05-06 19:25:56 -07002489err:
2490 return PCI_ERS_RESULT_DISCONNECT;
Divy Le Ray91a6b502007-11-16 11:21:55 -08002491}
2492
2493/**
2494 * t3_io_resume - called when traffic can start flowing again.
2495 * @pdev: Pointer to PCI device
2496 *
2497 * This callback is called when the error recovery driver tells us that
2498 * its OK to resume normal operation.
2499 */
2500static void t3_io_resume(struct pci_dev *pdev)
2501{
Divy Le Raybc4b6b52007-12-17 18:47:41 -08002502 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray91a6b502007-11-16 11:21:55 -08002503 int i;
2504
2505 /* Restart the ports */
2506 for_each_port(adapter, i) {
2507 struct net_device *netdev = adapter->port[i];
2508
2509 if (netif_running(netdev)) {
2510 if (cxgb_open(netdev)) {
2511 dev_err(&pdev->dev,
2512 "can't bring device back up"
2513 " after reset\n");
2514 continue;
2515 }
2516 netif_device_attach(netdev);
2517 }
2518 }
Divy Le Ray91a6b502007-11-16 11:21:55 -08002519}
2520
2521static struct pci_error_handlers t3_err_handler = {
2522 .error_detected = t3_io_error_detected,
2523 .slot_reset = t3_io_slot_reset,
2524 .resume = t3_io_resume,
2525};
2526
Divy Le Ray4d22de32007-01-18 22:04:14 -05002527static int __devinit cxgb_enable_msix(struct adapter *adap)
2528{
2529 struct msix_entry entries[SGE_QSETS + 1];
2530 int i, err;
2531
2532 for (i = 0; i < ARRAY_SIZE(entries); ++i)
2533 entries[i].entry = i;
2534
2535 err = pci_enable_msix(adap->pdev, entries, ARRAY_SIZE(entries));
2536 if (!err) {
2537 for (i = 0; i < ARRAY_SIZE(entries); ++i)
2538 adap->msix_info[i].vec = entries[i].vector;
2539 } else if (err > 0)
2540 dev_info(&adap->pdev->dev,
2541 "only %d MSI-X vectors left, not using MSI-X\n", err);
2542 return err;
2543}
2544
2545static void __devinit print_port_info(struct adapter *adap,
2546 const struct adapter_info *ai)
2547{
2548 static const char *pci_variant[] = {
2549 "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express"
2550 };
2551
2552 int i;
2553 char buf[80];
2554
2555 if (is_pcie(adap))
2556 snprintf(buf, sizeof(buf), "%s x%d",
2557 pci_variant[adap->params.pci.variant],
2558 adap->params.pci.width);
2559 else
2560 snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit",
2561 pci_variant[adap->params.pci.variant],
2562 adap->params.pci.speed, adap->params.pci.width);
2563
2564 for_each_port(adap, i) {
2565 struct net_device *dev = adap->port[i];
2566 const struct port_info *pi = netdev_priv(dev);
2567
2568 if (!test_bit(i, &adap->registered_device_map))
2569 continue;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07002570 printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n",
Divy Le Ray4d22de32007-01-18 22:04:14 -05002571 dev->name, ai->desc, pi->port_type->desc,
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07002572 is_offload(adap) ? "R" : "", adap->params.rev, buf,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002573 (adap->flags & USING_MSIX) ? " MSI-X" :
2574 (adap->flags & USING_MSI) ? " MSI" : "");
2575 if (adap->name == dev->name && adap->params.vpd.mclk)
Divy Le Ray167cdf52007-08-21 20:49:36 -07002576 printk(KERN_INFO
2577 "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
Divy Le Ray4d22de32007-01-18 22:04:14 -05002578 adap->name, t3_mc7_size(&adap->cm) >> 20,
2579 t3_mc7_size(&adap->pmtx) >> 20,
Divy Le Ray167cdf52007-08-21 20:49:36 -07002580 t3_mc7_size(&adap->pmrx) >> 20,
2581 adap->params.vpd.sn);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002582 }
2583}
2584
2585static int __devinit init_one(struct pci_dev *pdev,
2586 const struct pci_device_id *ent)
2587{
2588 static int version_printed;
2589
2590 int i, err, pci_using_dac = 0;
2591 unsigned long mmio_start, mmio_len;
2592 const struct adapter_info *ai;
2593 struct adapter *adapter = NULL;
2594 struct port_info *pi;
2595
2596 if (!version_printed) {
2597 printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
2598 ++version_printed;
2599 }
2600
2601 if (!cxgb3_wq) {
2602 cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
2603 if (!cxgb3_wq) {
2604 printk(KERN_ERR DRV_NAME
2605 ": cannot initialize work queue\n");
2606 return -ENOMEM;
2607 }
2608 }
2609
2610 err = pci_request_regions(pdev, DRV_NAME);
2611 if (err) {
2612 /* Just info, some other driver may have claimed the device. */
2613 dev_info(&pdev->dev, "cannot obtain PCI resources\n");
2614 return err;
2615 }
2616
2617 err = pci_enable_device(pdev);
2618 if (err) {
2619 dev_err(&pdev->dev, "cannot enable PCI device\n");
2620 goto out_release_regions;
2621 }
2622
2623 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
2624 pci_using_dac = 1;
2625 err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
2626 if (err) {
2627 dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
2628 "coherent allocations\n");
2629 goto out_disable_device;
2630 }
2631 } else if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
2632 dev_err(&pdev->dev, "no usable DMA configuration\n");
2633 goto out_disable_device;
2634 }
2635
2636 pci_set_master(pdev);
Divy Le Ray204e2f92008-05-06 19:26:01 -07002637 pci_save_state(pdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002638
2639 mmio_start = pci_resource_start(pdev, 0);
2640 mmio_len = pci_resource_len(pdev, 0);
2641 ai = t3_get_adapter_info(ent->driver_data);
2642
2643 adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
2644 if (!adapter) {
2645 err = -ENOMEM;
2646 goto out_disable_device;
2647 }
2648
2649 adapter->regs = ioremap_nocache(mmio_start, mmio_len);
2650 if (!adapter->regs) {
2651 dev_err(&pdev->dev, "cannot map device registers\n");
2652 err = -ENOMEM;
2653 goto out_free_adapter;
2654 }
2655
2656 adapter->pdev = pdev;
2657 adapter->name = pci_name(pdev);
2658 adapter->msg_enable = dflt_msg_enable;
2659 adapter->mmio_len = mmio_len;
2660
2661 mutex_init(&adapter->mdio_lock);
2662 spin_lock_init(&adapter->work_lock);
2663 spin_lock_init(&adapter->stats_lock);
2664
2665 INIT_LIST_HEAD(&adapter->adapter_list);
2666 INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
2667 INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
2668
2669 for (i = 0; i < ai->nports; ++i) {
2670 struct net_device *netdev;
2671
2672 netdev = alloc_etherdev(sizeof(struct port_info));
2673 if (!netdev) {
2674 err = -ENOMEM;
2675 goto out_free_dev;
2676 }
2677
Divy Le Ray4d22de32007-01-18 22:04:14 -05002678 SET_NETDEV_DEV(netdev, &pdev->dev);
2679
2680 adapter->port[i] = netdev;
2681 pi = netdev_priv(netdev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002682 pi->adapter = adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002683 pi->rx_csum_offload = 1;
2684 pi->nqsets = 1;
2685 pi->first_qset = i;
2686 pi->activity = 0;
2687 pi->port_id = i;
2688 netif_carrier_off(netdev);
2689 netdev->irq = pdev->irq;
2690 netdev->mem_start = mmio_start;
2691 netdev->mem_end = mmio_start + mmio_len - 1;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002692 netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
2693 netdev->features |= NETIF_F_LLTX;
2694 if (pci_using_dac)
2695 netdev->features |= NETIF_F_HIGHDMA;
2696
2697 netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
2698 netdev->vlan_rx_register = vlan_rx_register;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002699
2700 netdev->open = cxgb_open;
2701 netdev->stop = cxgb_close;
2702 netdev->hard_start_xmit = t3_eth_xmit;
2703 netdev->get_stats = cxgb_get_stats;
2704 netdev->set_multicast_list = cxgb_set_rxmode;
2705 netdev->do_ioctl = cxgb_ioctl;
2706 netdev->change_mtu = cxgb_change_mtu;
2707 netdev->set_mac_address = cxgb_set_mac_addr;
2708#ifdef CONFIG_NET_POLL_CONTROLLER
2709 netdev->poll_controller = cxgb_netpoll;
2710#endif
Divy Le Ray4d22de32007-01-18 22:04:14 -05002711
2712 SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
2713 }
2714
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002715 pci_set_drvdata(pdev, adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002716 if (t3_prep_adapter(adapter, ai, 1) < 0) {
2717 err = -ENODEV;
2718 goto out_free_dev;
2719 }
Jeff Garzik2eab17a2007-11-23 21:59:45 -05002720
Divy Le Ray4d22de32007-01-18 22:04:14 -05002721 /*
2722 * The card is now ready to go. If any errors occur during device
2723 * registration we do not fail the whole card but rather proceed only
2724 * with the ports we manage to register successfully. However we must
2725 * register at least one net device.
2726 */
2727 for_each_port(adapter, i) {
2728 err = register_netdev(adapter->port[i]);
2729 if (err)
2730 dev_warn(&pdev->dev,
2731 "cannot register net device %s, skipping\n",
2732 adapter->port[i]->name);
2733 else {
2734 /*
2735 * Change the name we use for messages to the name of
2736 * the first successfully registered interface.
2737 */
2738 if (!adapter->registered_device_map)
2739 adapter->name = adapter->port[i]->name;
2740
2741 __set_bit(i, &adapter->registered_device_map);
2742 }
2743 }
2744 if (!adapter->registered_device_map) {
2745 dev_err(&pdev->dev, "could not register any net devices\n");
2746 goto out_free_dev;
2747 }
2748
2749 /* Driver's ready. Reflect it on LEDs */
2750 t3_led_ready(adapter);
2751
2752 if (is_offload(adapter)) {
2753 __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
2754 cxgb3_adapter_ofld(adapter);
2755 }
2756
2757 /* See what interrupts we'll be using */
2758 if (msi > 1 && cxgb_enable_msix(adapter) == 0)
2759 adapter->flags |= USING_MSIX;
2760 else if (msi > 0 && pci_enable_msi(pdev) == 0)
2761 adapter->flags |= USING_MSI;
2762
Divy Le Ray0ee8d332007-02-08 16:55:59 -08002763 err = sysfs_create_group(&adapter->port[0]->dev.kobj,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002764 &cxgb3_attr_group);
2765
2766 print_port_info(adapter, ai);
2767 return 0;
2768
2769out_free_dev:
2770 iounmap(adapter->regs);
2771 for (i = ai->nports - 1; i >= 0; --i)
2772 if (adapter->port[i])
2773 free_netdev(adapter->port[i]);
2774
2775out_free_adapter:
2776 kfree(adapter);
2777
2778out_disable_device:
2779 pci_disable_device(pdev);
2780out_release_regions:
2781 pci_release_regions(pdev);
2782 pci_set_drvdata(pdev, NULL);
2783 return err;
2784}
2785
2786static void __devexit remove_one(struct pci_dev *pdev)
2787{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002788 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002789
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002790 if (adapter) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05002791 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002792
2793 t3_sge_stop(adapter);
Divy Le Ray0ee8d332007-02-08 16:55:59 -08002794 sysfs_remove_group(&adapter->port[0]->dev.kobj,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002795 &cxgb3_attr_group);
2796
Divy Le Ray4d22de32007-01-18 22:04:14 -05002797 if (is_offload(adapter)) {
2798 cxgb3_adapter_unofld(adapter);
2799 if (test_bit(OFFLOAD_DEVMAP_BIT,
2800 &adapter->open_device_map))
2801 offload_close(&adapter->tdev);
2802 }
2803
Divy Le Ray67d92ab2007-11-16 11:21:50 -08002804 for_each_port(adapter, i)
2805 if (test_bit(i, &adapter->registered_device_map))
2806 unregister_netdev(adapter->port[i]);
2807
Divy Le Ray0ca41c02008-09-25 14:05:28 +00002808 t3_stop_sge_timers(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002809 t3_free_sge_resources(adapter);
2810 cxgb_disable_msi(adapter);
2811
Divy Le Ray4d22de32007-01-18 22:04:14 -05002812 for_each_port(adapter, i)
2813 if (adapter->port[i])
2814 free_netdev(adapter->port[i]);
2815
2816 iounmap(adapter->regs);
2817 kfree(adapter);
2818 pci_release_regions(pdev);
2819 pci_disable_device(pdev);
2820 pci_set_drvdata(pdev, NULL);
2821 }
2822}
2823
2824static struct pci_driver driver = {
2825 .name = DRV_NAME,
2826 .id_table = cxgb3_pci_tbl,
2827 .probe = init_one,
2828 .remove = __devexit_p(remove_one),
Divy Le Ray91a6b502007-11-16 11:21:55 -08002829 .err_handler = &t3_err_handler,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002830};
2831
2832static int __init cxgb3_init_module(void)
2833{
2834 int ret;
2835
2836 cxgb3_offload_init();
2837
2838 ret = pci_register_driver(&driver);
2839 return ret;
2840}
2841
2842static void __exit cxgb3_cleanup_module(void)
2843{
2844 pci_unregister_driver(&driver);
2845 if (cxgb3_wq)
2846 destroy_workqueue(cxgb3_wq);
2847}
2848
2849module_init(cxgb3_init_module);
2850module_exit(cxgb3_cleanup_module);