blob: e22d06531051b98f6e52597baa7671a2e76f86af [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 Ray4d22de32007-01-18 22:04:14 -050079#define CH_DEVICE(devid, ssid, idx) \
80 { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx }
81
82static const struct pci_device_id cxgb3_pci_tbl[] = {
83 CH_DEVICE(0x20, 1, 0), /* PE9000 */
84 CH_DEVICE(0x21, 1, 1), /* T302E */
85 CH_DEVICE(0x22, 1, 2), /* T310E */
86 CH_DEVICE(0x23, 1, 3), /* T320X */
87 CH_DEVICE(0x24, 1, 1), /* T302X */
88 CH_DEVICE(0x25, 1, 3), /* T320E */
89 CH_DEVICE(0x26, 1, 2), /* T310X */
90 CH_DEVICE(0x30, 1, 2), /* T3B10 */
91 CH_DEVICE(0x31, 1, 3), /* T3B20 */
92 CH_DEVICE(0x32, 1, 1), /* T3B02 */
93 {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
309/**
310 * setup_rss - configure RSS
311 * @adap: the adapter
312 *
313 * Sets up RSS to distribute packets to multiple receive queues. We
314 * configure the RSS CPU lookup table to distribute to the number of HW
315 * receive queues, and the response queue lookup table to narrow that
316 * down to the response queues actually configured for each port.
317 * We always configure the RSS mapping for two ports since the mapping
318 * table has plenty of entries.
319 */
320static void setup_rss(struct adapter *adap)
321{
322 int i;
323 unsigned int nq0 = adap2pinfo(adap, 0)->nqsets;
324 unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1;
325 u8 cpus[SGE_QSETS + 1];
326 u16 rspq_map[RSS_TABLE_SIZE];
327
328 for (i = 0; i < SGE_QSETS; ++i)
329 cpus[i] = i;
330 cpus[SGE_QSETS] = 0xff; /* terminator */
331
332 for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
333 rspq_map[i] = i % nq0;
334 rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0;
335 }
336
337 t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
338 F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
339 V_RRCPLCPUSIZE(6), cpus, rspq_map);
340}
341
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700342static void init_napi(struct adapter *adap)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500343{
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700344 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500345
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700346 for (i = 0; i < SGE_QSETS; i++) {
347 struct sge_qset *qs = &adap->sge.qs[i];
Divy Le Ray4d22de32007-01-18 22:04:14 -0500348
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700349 if (qs->adap)
350 netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll,
351 64);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500352 }
Divy Le Ray4d22de32007-01-18 22:04:14 -0500353}
354
355/*
356 * Wait until all NAPI handlers are descheduled. This includes the handlers of
357 * both netdevices representing interfaces and the dummy ones for the extra
358 * queues.
359 */
360static void quiesce_rx(struct adapter *adap)
361{
362 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500363
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700364 for (i = 0; i < SGE_QSETS; i++)
365 if (adap->sge.qs[i].adap)
366 napi_disable(&adap->sge.qs[i].napi);
367}
Divy Le Ray4d22de32007-01-18 22:04:14 -0500368
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700369static void enable_all_napi(struct adapter *adap)
370{
371 int i;
372 for (i = 0; i < SGE_QSETS; i++)
373 if (adap->sge.qs[i].adap)
374 napi_enable(&adap->sge.qs[i].napi);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500375}
376
377/**
378 * setup_sge_qsets - configure SGE Tx/Rx/response queues
379 * @adap: the adapter
380 *
381 * Determines how many sets of SGE queues to use and initializes them.
382 * We support multiple queue sets per port if we have MSI-X, otherwise
383 * just one queue set per port.
384 */
385static int setup_sge_qsets(struct adapter *adap)
386{
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700387 int i, j, err, irq_idx = 0, qset_idx = 0;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -0700388 unsigned int ntxq = SGE_TXQ_PER_SET;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500389
390 if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
391 irq_idx = -1;
392
393 for_each_port(adap, i) {
394 struct net_device *dev = adap->port[i];
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700395 struct port_info *pi = netdev_priv(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500396
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700397 pi->qs = &adap->sge.qs[pi->first_qset];
Divy Le Ray4d22de32007-01-18 22:04:14 -0500398 for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
399 err = t3_sge_alloc_qset(adap, qset_idx, 1,
400 (adap->flags & USING_MSIX) ? qset_idx + 1 :
401 irq_idx,
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700402 &adap->params.sge.qset[qset_idx], ntxq, dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500403 if (err) {
404 t3_free_sge_resources(adap);
405 return err;
406 }
407 }
408 }
409
410 return 0;
411}
412
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800413static ssize_t attr_show(struct device *d, struct device_attribute *attr,
414 char *buf,
Divy Le Ray896392e2007-02-24 16:43:50 -0800415 ssize_t(*format) (struct net_device *, char *))
Divy Le Ray4d22de32007-01-18 22:04:14 -0500416{
417 ssize_t len;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500418
419 /* Synchronize with ioctls that may shut down the device */
420 rtnl_lock();
Divy Le Ray896392e2007-02-24 16:43:50 -0800421 len = (*format) (to_net_dev(d), buf);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500422 rtnl_unlock();
423 return len;
424}
425
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800426static ssize_t attr_store(struct device *d, struct device_attribute *attr,
427 const char *buf, size_t len,
Divy Le Ray896392e2007-02-24 16:43:50 -0800428 ssize_t(*set) (struct net_device *, unsigned int),
Divy Le Ray4d22de32007-01-18 22:04:14 -0500429 unsigned int min_val, unsigned int max_val)
430{
431 char *endp;
432 ssize_t ret;
433 unsigned int val;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500434
435 if (!capable(CAP_NET_ADMIN))
436 return -EPERM;
437
438 val = simple_strtoul(buf, &endp, 0);
439 if (endp == buf || val < min_val || val > max_val)
440 return -EINVAL;
441
442 rtnl_lock();
Divy Le Ray896392e2007-02-24 16:43:50 -0800443 ret = (*set) (to_net_dev(d), val);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500444 if (!ret)
445 ret = len;
446 rtnl_unlock();
447 return ret;
448}
449
450#define CXGB3_SHOW(name, val_expr) \
Divy Le Ray896392e2007-02-24 16:43:50 -0800451static ssize_t format_##name(struct net_device *dev, char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500452{ \
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700453 struct port_info *pi = netdev_priv(dev); \
454 struct adapter *adap = pi->adapter; \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500455 return sprintf(buf, "%u\n", val_expr); \
456} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800457static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
458 char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500459{ \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800460 return attr_show(d, attr, buf, format_##name); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500461}
462
Divy Le Ray896392e2007-02-24 16:43:50 -0800463static ssize_t set_nfilters(struct net_device *dev, unsigned int val)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500464{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700465 struct port_info *pi = netdev_priv(dev);
466 struct adapter *adap = pi->adapter;
Divy Le Ray9f238482007-03-31 00:23:13 -0700467 int min_tids = is_offload(adap) ? MC5_MIN_TIDS : 0;
Divy Le Ray896392e2007-02-24 16:43:50 -0800468
Divy Le Ray4d22de32007-01-18 22:04:14 -0500469 if (adap->flags & FULL_INIT_DONE)
470 return -EBUSY;
471 if (val && adap->params.rev == 0)
472 return -EINVAL;
Divy Le Ray9f238482007-03-31 00:23:13 -0700473 if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
474 min_tids)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500475 return -EINVAL;
476 adap->params.mc5.nfilters = val;
477 return 0;
478}
479
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800480static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
481 const char *buf, size_t len)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500482{
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800483 return attr_store(d, attr, buf, len, set_nfilters, 0, ~0);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500484}
485
Divy Le Ray896392e2007-02-24 16:43:50 -0800486static ssize_t set_nservers(struct net_device *dev, unsigned int val)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500487{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700488 struct port_info *pi = netdev_priv(dev);
489 struct adapter *adap = pi->adapter;
Divy Le Ray896392e2007-02-24 16:43:50 -0800490
Divy Le Ray4d22de32007-01-18 22:04:14 -0500491 if (adap->flags & FULL_INIT_DONE)
492 return -EBUSY;
Divy Le Ray9f238482007-03-31 00:23:13 -0700493 if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters -
494 MC5_MIN_TIDS)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500495 return -EINVAL;
496 adap->params.mc5.nservers = val;
497 return 0;
498}
499
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800500static ssize_t store_nservers(struct device *d, struct device_attribute *attr,
501 const char *buf, size_t len)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500502{
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800503 return attr_store(d, attr, buf, len, set_nservers, 0, ~0);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500504}
505
506#define CXGB3_ATTR_R(name, val_expr) \
507CXGB3_SHOW(name, val_expr) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800508static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500509
510#define CXGB3_ATTR_RW(name, val_expr, store_method) \
511CXGB3_SHOW(name, val_expr) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800512static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500513
514CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));
515CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);
516CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);
517
518static struct attribute *cxgb3_attrs[] = {
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800519 &dev_attr_cam_size.attr,
520 &dev_attr_nfilters.attr,
521 &dev_attr_nservers.attr,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500522 NULL
523};
524
525static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
526
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800527static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,
528 char *buf, int sched)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500529{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700530 struct port_info *pi = netdev_priv(to_net_dev(d));
531 struct adapter *adap = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500532 unsigned int v, addr, bpt, cpt;
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700533 ssize_t len;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500534
535 addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
536 rtnl_lock();
537 t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
538 v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
539 if (sched & 1)
540 v >>= 16;
541 bpt = (v >> 8) & 0xff;
542 cpt = v & 0xff;
543 if (!cpt)
544 len = sprintf(buf, "disabled\n");
545 else {
546 v = (adap->params.vpd.cclk * 1000) / cpt;
547 len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125);
548 }
549 rtnl_unlock();
550 return len;
551}
552
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800553static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr,
554 const char *buf, size_t len, int sched)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500555{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700556 struct port_info *pi = netdev_priv(to_net_dev(d));
557 struct adapter *adap = pi->adapter;
558 unsigned int val;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500559 char *endp;
560 ssize_t ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500561
562 if (!capable(CAP_NET_ADMIN))
563 return -EPERM;
564
565 val = simple_strtoul(buf, &endp, 0);
566 if (endp == buf || val > 10000000)
567 return -EINVAL;
568
569 rtnl_lock();
570 ret = t3_config_sched(adap, val, sched);
571 if (!ret)
572 ret = len;
573 rtnl_unlock();
574 return ret;
575}
576
577#define TM_ATTR(name, sched) \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800578static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
579 char *buf) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500580{ \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800581 return tm_attr_show(d, attr, buf, sched); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500582} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800583static ssize_t store_##name(struct device *d, struct device_attribute *attr, \
584 const char *buf, size_t len) \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500585{ \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800586 return tm_attr_store(d, attr, buf, len, sched); \
Divy Le Ray4d22de32007-01-18 22:04:14 -0500587} \
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800588static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500589
590TM_ATTR(sched0, 0);
591TM_ATTR(sched1, 1);
592TM_ATTR(sched2, 2);
593TM_ATTR(sched3, 3);
594TM_ATTR(sched4, 4);
595TM_ATTR(sched5, 5);
596TM_ATTR(sched6, 6);
597TM_ATTR(sched7, 7);
598
599static struct attribute *offload_attrs[] = {
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800600 &dev_attr_sched0.attr,
601 &dev_attr_sched1.attr,
602 &dev_attr_sched2.attr,
603 &dev_attr_sched3.attr,
604 &dev_attr_sched4.attr,
605 &dev_attr_sched5.attr,
606 &dev_attr_sched6.attr,
607 &dev_attr_sched7.attr,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500608 NULL
609};
610
611static struct attribute_group offload_attr_group = {.attrs = offload_attrs };
612
613/*
614 * Sends an sk_buff to an offload queue driver
615 * after dealing with any active network taps.
616 */
617static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
618{
619 int ret;
620
621 local_bh_disable();
622 ret = t3_offload_tx(tdev, skb);
623 local_bh_enable();
624 return ret;
625}
626
627static int write_smt_entry(struct adapter *adapter, int idx)
628{
629 struct cpl_smt_write_req *req;
630 struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);
631
632 if (!skb)
633 return -ENOMEM;
634
635 req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
636 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
637 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
638 req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */
639 req->iff = idx;
640 memset(req->src_mac1, 0, sizeof(req->src_mac1));
641 memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);
642 skb->priority = 1;
643 offload_tx(&adapter->tdev, skb);
644 return 0;
645}
646
647static int init_smt(struct adapter *adapter)
648{
649 int i;
650
651 for_each_port(adapter, i)
652 write_smt_entry(adapter, i);
653 return 0;
654}
655
656static void init_port_mtus(struct adapter *adapter)
657{
658 unsigned int mtus = adapter->port[0]->mtu;
659
660 if (adapter->port[1])
661 mtus |= adapter->port[1]->mtu << 16;
662 t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
663}
664
Divy Le Ray14ab9892007-01-30 19:43:50 -0800665static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
666 int hi, int port)
667{
668 struct sk_buff *skb;
669 struct mngt_pktsched_wr *req;
670
671 skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
672 req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
673 req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
674 req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
675 req->sched = sched;
676 req->idx = qidx;
677 req->min = lo;
678 req->max = hi;
679 req->binding = port;
680 t3_mgmt_tx(adap, skb);
681}
682
683static void bind_qsets(struct adapter *adap)
684{
685 int i, j;
686
687 for_each_port(adap, i) {
688 const struct port_info *pi = adap2pinfo(adap, i);
689
690 for (j = 0; j < pi->nqsets; ++j)
691 send_pktsched_cmd(adap, 1, pi->first_qset + j, -1,
692 -1, i);
693 }
694}
695
Divy Le Ray7f672cf2007-03-31 00:23:30 -0700696#define FW_FNAME "t3fw-%d.%d.%d.bin"
Divy Le Ray47330072007-08-29 19:15:52 -0700697#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin"
Divy Le Ray2e283962007-03-18 13:10:06 -0700698
699static int upgrade_fw(struct adapter *adap)
700{
701 int ret;
702 char buf[64];
703 const struct firmware *fw;
704 struct device *dev = &adap->pdev->dev;
705
706 snprintf(buf, sizeof(buf), FW_FNAME, FW_VERSION_MAJOR,
Divy Le Ray7f672cf2007-03-31 00:23:30 -0700707 FW_VERSION_MINOR, FW_VERSION_MICRO);
Divy Le Ray2e283962007-03-18 13:10:06 -0700708 ret = request_firmware(&fw, buf, dev);
709 if (ret < 0) {
710 dev_err(dev, "could not upgrade firmware: unable to load %s\n",
711 buf);
712 return ret;
713 }
714 ret = t3_load_fw(adap, fw->data, fw->size);
715 release_firmware(fw);
Divy Le Ray47330072007-08-29 19:15:52 -0700716
717 if (ret == 0)
718 dev_info(dev, "successful upgrade to firmware %d.%d.%d\n",
719 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
720 else
721 dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n",
722 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
723
724 return ret;
725}
726
727static inline char t3rev2char(struct adapter *adapter)
728{
729 char rev = 0;
730
731 switch(adapter->params.rev) {
732 case T3_REV_B:
733 case T3_REV_B2:
734 rev = 'b';
735 break;
Divy Le Ray1aafee22007-09-05 15:58:36 -0700736 case T3_REV_C:
737 rev = 'c';
738 break;
Divy Le Ray47330072007-08-29 19:15:52 -0700739 }
740 return rev;
741}
742
743int update_tpsram(struct adapter *adap)
744{
745 const struct firmware *tpsram;
746 char buf[64];
747 struct device *dev = &adap->pdev->dev;
748 int ret;
749 char rev;
750
751 rev = t3rev2char(adap);
752 if (!rev)
753 return 0;
754
755 snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
756 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
757
758 ret = request_firmware(&tpsram, buf, dev);
759 if (ret < 0) {
760 dev_err(dev, "could not load TP SRAM: unable to load %s\n",
761 buf);
762 return ret;
763 }
764
765 ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
766 if (ret)
767 goto release_tpsram;
768
769 ret = t3_set_proto_sram(adap, tpsram->data);
770 if (ret == 0)
771 dev_info(dev,
772 "successful update of protocol engine "
773 "to %d.%d.%d\n",
774 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
775 else
776 dev_err(dev, "failed to update of protocol engine %d.%d.%d\n",
777 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
778 if (ret)
779 dev_err(dev, "loading protocol SRAM failed\n");
780
781release_tpsram:
782 release_firmware(tpsram);
783
Divy Le Ray2e283962007-03-18 13:10:06 -0700784 return ret;
785}
786
Divy Le Ray4d22de32007-01-18 22:04:14 -0500787/**
788 * cxgb_up - enable the adapter
789 * @adapter: adapter being enabled
790 *
791 * Called when the first port is enabled, this function performs the
792 * actions necessary to make an adapter operational, such as completing
793 * the initialization of HW modules, and enabling interrupts.
794 *
795 * Must be called with the rtnl lock held.
796 */
797static int cxgb_up(struct adapter *adap)
798{
Denis Chengc54f5c22007-07-18 15:24:49 +0800799 int err;
Divy Le Ray47330072007-08-29 19:15:52 -0700800 int must_load;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500801
802 if (!(adap->flags & FULL_INIT_DONE)) {
Divy Le Raya5a3b462007-09-05 15:58:09 -0700803 err = t3_check_fw_version(adap, &must_load);
804 if (err == -EINVAL) {
Divy Le Ray2e283962007-03-18 13:10:06 -0700805 err = upgrade_fw(adap);
Divy Le Raya5a3b462007-09-05 15:58:09 -0700806 if (err && must_load)
807 goto out;
808 }
Divy Le Ray4d22de32007-01-18 22:04:14 -0500809
Divy Le Ray47330072007-08-29 19:15:52 -0700810 err = t3_check_tpsram_version(adap, &must_load);
811 if (err == -EINVAL) {
812 err = update_tpsram(adap);
813 if (err && must_load)
814 goto out;
815 }
816
Divy Le Ray4d22de32007-01-18 22:04:14 -0500817 err = t3_init_hw(adap, 0);
818 if (err)
819 goto out;
820
Divy Le Ray6cdbd772007-04-09 20:10:33 -0700821 t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700822
Divy Le Ray4d22de32007-01-18 22:04:14 -0500823 err = setup_sge_qsets(adap);
824 if (err)
825 goto out;
826
827 setup_rss(adap);
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700828 init_napi(adap);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500829 adap->flags |= FULL_INIT_DONE;
830 }
831
832 t3_intr_clear(adap);
833
834 if (adap->flags & USING_MSIX) {
835 name_msix_vecs(adap);
836 err = request_irq(adap->msix_info[0].vec,
837 t3_async_intr_handler, 0,
838 adap->msix_info[0].desc, adap);
839 if (err)
840 goto irq_err;
841
842 if (request_msix_data_irqs(adap)) {
843 free_irq(adap->msix_info[0].vec, adap);
844 goto irq_err;
845 }
846 } else if ((err = request_irq(adap->pdev->irq,
847 t3_intr_handler(adap,
848 adap->sge.qs[0].rspq.
849 polling),
Thomas Gleixner2db63462007-02-14 00:33:20 -0800850 (adap->flags & USING_MSI) ?
851 0 : IRQF_SHARED,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500852 adap->name, adap)))
853 goto irq_err;
854
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700855 enable_all_napi(adap);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500856 t3_sge_start(adap);
857 t3_intr_enable(adap);
Divy Le Ray14ab9892007-01-30 19:43:50 -0800858
859 if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
860 bind_qsets(adap);
861 adap->flags |= QUEUES_BOUND;
862
Divy Le Ray4d22de32007-01-18 22:04:14 -0500863out:
864 return err;
865irq_err:
866 CH_ERR(adap, "request_irq failed, err %d\n", err);
867 goto out;
868}
869
870/*
871 * Release resources when all the ports and offloading have been stopped.
872 */
873static void cxgb_down(struct adapter *adapter)
874{
875 t3_sge_stop(adapter);
876 spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */
877 t3_intr_disable(adapter);
878 spin_unlock_irq(&adapter->work_lock);
879
880 if (adapter->flags & USING_MSIX) {
881 int i, n = 0;
882
883 free_irq(adapter->msix_info[0].vec, adapter);
884 for_each_port(adapter, i)
885 n += adap2pinfo(adapter, i)->nqsets;
886
887 for (i = 0; i < n; ++i)
888 free_irq(adapter->msix_info[i + 1].vec,
889 &adapter->sge.qs[i]);
890 } else
891 free_irq(adapter->pdev->irq, adapter);
892
893 flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */
894 quiesce_rx(adapter);
895}
896
897static void schedule_chk_task(struct adapter *adap)
898{
899 unsigned int timeo;
900
901 timeo = adap->params.linkpoll_period ?
902 (HZ * adap->params.linkpoll_period) / 10 :
903 adap->params.stats_update_period * HZ;
904 if (timeo)
905 queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo);
906}
907
908static int offload_open(struct net_device *dev)
909{
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700910 struct port_info *pi = netdev_priv(dev);
911 struct adapter *adapter = pi->adapter;
912 struct t3cdev *tdev = dev2t3cdev(dev);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500913 int adap_up = adapter->open_device_map & PORT_MASK;
Denis Chengc54f5c22007-07-18 15:24:49 +0800914 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500915
916 if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
917 return 0;
918
919 if (!adap_up && (err = cxgb_up(adapter)) < 0)
920 return err;
921
922 t3_tp_set_offload_mode(adapter, 1);
923 tdev->lldev = adapter->port[0];
924 err = cxgb3_offload_activate(adapter);
925 if (err)
926 goto out;
927
928 init_port_mtus(adapter);
929 t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
930 adapter->params.b_wnd,
931 adapter->params.rev == 0 ?
932 adapter->port[0]->mtu : 0xffff);
933 init_smt(adapter);
934
935 /* Never mind if the next step fails */
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800936 sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500937
938 /* Call back all registered clients */
939 cxgb3_add_clients(tdev);
940
941out:
942 /* restore them in case the offload module has changed them */
943 if (err) {
944 t3_tp_set_offload_mode(adapter, 0);
945 clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
946 cxgb3_set_dummy_ops(tdev);
947 }
948 return err;
949}
950
951static int offload_close(struct t3cdev *tdev)
952{
953 struct adapter *adapter = tdev2adap(tdev);
954
955 if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
956 return 0;
957
958 /* Call back all registered clients */
959 cxgb3_remove_clients(tdev);
960
Divy Le Ray0ee8d332007-02-08 16:55:59 -0800961 sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500962
963 tdev->lldev = NULL;
964 cxgb3_set_dummy_ops(tdev);
965 t3_tp_set_offload_mode(adapter, 0);
966 clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
967
968 if (!adapter->open_device_map)
969 cxgb_down(adapter);
970
971 cxgb3_offload_deactivate(adapter);
972 return 0;
973}
974
975static int cxgb_open(struct net_device *dev)
976{
Divy Le Ray4d22de32007-01-18 22:04:14 -0500977 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700978 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500979 int other_ports = adapter->open_device_map & PORT_MASK;
Divy Le Ray5fbf8162007-08-29 19:15:47 -0700980 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500981
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700982 if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) {
983 quiesce_rx(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500984 return err;
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700985 }
Divy Le Ray4d22de32007-01-18 22:04:14 -0500986
987 set_bit(pi->port_id, &adapter->open_device_map);
Divy Le Ray8ac3ba62007-03-31 00:23:19 -0700988 if (is_offload(adapter) && !ofld_disable) {
Divy Le Ray4d22de32007-01-18 22:04:14 -0500989 err = offload_open(dev);
990 if (err)
991 printk(KERN_WARNING
992 "Could not initialize offload capabilities\n");
993 }
994
995 link_start(dev);
996 t3_port_intr_enable(adapter, pi->port_id);
997 netif_start_queue(dev);
998 if (!other_ports)
999 schedule_chk_task(adapter);
1000
1001 return 0;
1002}
1003
1004static int cxgb_close(struct net_device *dev)
1005{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001006 struct port_info *pi = netdev_priv(dev);
1007 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001008
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001009 t3_port_intr_disable(adapter, pi->port_id);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001010 netif_stop_queue(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001011 pi->phy.ops->power_down(&pi->phy, 1);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001012 netif_carrier_off(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001013 t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001014
1015 spin_lock(&adapter->work_lock); /* sync with update task */
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001016 clear_bit(pi->port_id, &adapter->open_device_map);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001017 spin_unlock(&adapter->work_lock);
1018
1019 if (!(adapter->open_device_map & PORT_MASK))
1020 cancel_rearming_delayed_workqueue(cxgb3_wq,
1021 &adapter->adap_check_task);
1022
1023 if (!adapter->open_device_map)
1024 cxgb_down(adapter);
1025
1026 return 0;
1027}
1028
1029static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
1030{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001031 struct port_info *pi = netdev_priv(dev);
1032 struct adapter *adapter = pi->adapter;
1033 struct net_device_stats *ns = &pi->netstats;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001034 const struct mac_stats *pstats;
1035
1036 spin_lock(&adapter->stats_lock);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001037 pstats = t3_mac_update_stats(&pi->mac);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001038 spin_unlock(&adapter->stats_lock);
1039
1040 ns->tx_bytes = pstats->tx_octets;
1041 ns->tx_packets = pstats->tx_frames;
1042 ns->rx_bytes = pstats->rx_octets;
1043 ns->rx_packets = pstats->rx_frames;
1044 ns->multicast = pstats->rx_mcast_frames;
1045
1046 ns->tx_errors = pstats->tx_underrun;
1047 ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs +
1048 pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short +
1049 pstats->rx_fifo_ovfl;
1050
1051 /* detailed rx_errors */
1052 ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long;
1053 ns->rx_over_errors = 0;
1054 ns->rx_crc_errors = pstats->rx_fcs_errs;
1055 ns->rx_frame_errors = pstats->rx_symbol_errs;
1056 ns->rx_fifo_errors = pstats->rx_fifo_ovfl;
1057 ns->rx_missed_errors = pstats->rx_cong_drops;
1058
1059 /* detailed tx_errors */
1060 ns->tx_aborted_errors = 0;
1061 ns->tx_carrier_errors = 0;
1062 ns->tx_fifo_errors = pstats->tx_underrun;
1063 ns->tx_heartbeat_errors = 0;
1064 ns->tx_window_errors = 0;
1065 return ns;
1066}
1067
1068static u32 get_msglevel(struct net_device *dev)
1069{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001070 struct port_info *pi = netdev_priv(dev);
1071 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001072
1073 return adapter->msg_enable;
1074}
1075
1076static void set_msglevel(struct net_device *dev, u32 val)
1077{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001078 struct port_info *pi = netdev_priv(dev);
1079 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001080
1081 adapter->msg_enable = val;
1082}
1083
1084static char stats_strings[][ETH_GSTRING_LEN] = {
1085 "TxOctetsOK ",
1086 "TxFramesOK ",
1087 "TxMulticastFramesOK",
1088 "TxBroadcastFramesOK",
1089 "TxPauseFrames ",
1090 "TxUnderrun ",
1091 "TxExtUnderrun ",
1092
1093 "TxFrames64 ",
1094 "TxFrames65To127 ",
1095 "TxFrames128To255 ",
1096 "TxFrames256To511 ",
1097 "TxFrames512To1023 ",
1098 "TxFrames1024To1518 ",
1099 "TxFrames1519ToMax ",
1100
1101 "RxOctetsOK ",
1102 "RxFramesOK ",
1103 "RxMulticastFramesOK",
1104 "RxBroadcastFramesOK",
1105 "RxPauseFrames ",
1106 "RxFCSErrors ",
1107 "RxSymbolErrors ",
1108 "RxShortErrors ",
1109 "RxJabberErrors ",
1110 "RxLengthErrors ",
1111 "RxFIFOoverflow ",
1112
1113 "RxFrames64 ",
1114 "RxFrames65To127 ",
1115 "RxFrames128To255 ",
1116 "RxFrames256To511 ",
1117 "RxFrames512To1023 ",
1118 "RxFrames1024To1518 ",
1119 "RxFrames1519ToMax ",
1120
1121 "PhyFIFOErrors ",
1122 "TSO ",
1123 "VLANextractions ",
1124 "VLANinsertions ",
1125 "TxCsumOffload ",
1126 "RxCsumGood ",
Divy Le Rayfc906642007-03-18 13:10:12 -07001127 "RxDrops ",
1128
1129 "CheckTXEnToggled ",
1130 "CheckResets ",
1131
Divy Le Ray4d22de32007-01-18 22:04:14 -05001132};
1133
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001134static int get_sset_count(struct net_device *dev, int sset)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001135{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001136 switch (sset) {
1137 case ETH_SS_STATS:
1138 return ARRAY_SIZE(stats_strings);
1139 default:
1140 return -EOPNOTSUPP;
1141 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001142}
1143
1144#define T3_REGMAP_SIZE (3 * 1024)
1145
1146static int get_regs_len(struct net_device *dev)
1147{
1148 return T3_REGMAP_SIZE;
1149}
1150
1151static int get_eeprom_len(struct net_device *dev)
1152{
1153 return EEPROMSIZE;
1154}
1155
1156static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
1157{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001158 struct port_info *pi = netdev_priv(dev);
1159 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001160 u32 fw_vers = 0;
Divy Le Ray47330072007-08-29 19:15:52 -07001161 u32 tp_vers = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001162
1163 t3_get_fw_version(adapter, &fw_vers);
Divy Le Ray47330072007-08-29 19:15:52 -07001164 t3_get_tp_version(adapter, &tp_vers);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001165
1166 strcpy(info->driver, DRV_NAME);
1167 strcpy(info->version, DRV_VERSION);
1168 strcpy(info->bus_info, pci_name(adapter->pdev));
1169 if (!fw_vers)
1170 strcpy(info->fw_version, "N/A");
Divy Le Ray4aac3892007-01-30 19:43:45 -08001171 else {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001172 snprintf(info->fw_version, sizeof(info->fw_version),
Divy Le Ray47330072007-08-29 19:15:52 -07001173 "%s %u.%u.%u TP %u.%u.%u",
Divy Le Ray4aac3892007-01-30 19:43:45 -08001174 G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
1175 G_FW_VERSION_MAJOR(fw_vers),
1176 G_FW_VERSION_MINOR(fw_vers),
Divy Le Ray47330072007-08-29 19:15:52 -07001177 G_FW_VERSION_MICRO(fw_vers),
1178 G_TP_VERSION_MAJOR(tp_vers),
1179 G_TP_VERSION_MINOR(tp_vers),
1180 G_TP_VERSION_MICRO(tp_vers));
Divy Le Ray4aac3892007-01-30 19:43:45 -08001181 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001182}
1183
1184static void get_strings(struct net_device *dev, u32 stringset, u8 * data)
1185{
1186 if (stringset == ETH_SS_STATS)
1187 memcpy(data, stats_strings, sizeof(stats_strings));
1188}
1189
1190static unsigned long collect_sge_port_stats(struct adapter *adapter,
1191 struct port_info *p, int idx)
1192{
1193 int i;
1194 unsigned long tot = 0;
1195
1196 for (i = 0; i < p->nqsets; ++i)
1197 tot += adapter->sge.qs[i + p->first_qset].port_stats[idx];
1198 return tot;
1199}
1200
1201static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
1202 u64 *data)
1203{
Divy Le Ray4d22de32007-01-18 22:04:14 -05001204 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001205 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001206 const struct mac_stats *s;
1207
1208 spin_lock(&adapter->stats_lock);
1209 s = t3_mac_update_stats(&pi->mac);
1210 spin_unlock(&adapter->stats_lock);
1211
1212 *data++ = s->tx_octets;
1213 *data++ = s->tx_frames;
1214 *data++ = s->tx_mcast_frames;
1215 *data++ = s->tx_bcast_frames;
1216 *data++ = s->tx_pause;
1217 *data++ = s->tx_underrun;
1218 *data++ = s->tx_fifo_urun;
1219
1220 *data++ = s->tx_frames_64;
1221 *data++ = s->tx_frames_65_127;
1222 *data++ = s->tx_frames_128_255;
1223 *data++ = s->tx_frames_256_511;
1224 *data++ = s->tx_frames_512_1023;
1225 *data++ = s->tx_frames_1024_1518;
1226 *data++ = s->tx_frames_1519_max;
1227
1228 *data++ = s->rx_octets;
1229 *data++ = s->rx_frames;
1230 *data++ = s->rx_mcast_frames;
1231 *data++ = s->rx_bcast_frames;
1232 *data++ = s->rx_pause;
1233 *data++ = s->rx_fcs_errs;
1234 *data++ = s->rx_symbol_errs;
1235 *data++ = s->rx_short;
1236 *data++ = s->rx_jabber;
1237 *data++ = s->rx_too_long;
1238 *data++ = s->rx_fifo_ovfl;
1239
1240 *data++ = s->rx_frames_64;
1241 *data++ = s->rx_frames_65_127;
1242 *data++ = s->rx_frames_128_255;
1243 *data++ = s->rx_frames_256_511;
1244 *data++ = s->rx_frames_512_1023;
1245 *data++ = s->rx_frames_1024_1518;
1246 *data++ = s->rx_frames_1519_max;
1247
1248 *data++ = pi->phy.fifo_errors;
1249
1250 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO);
1251 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX);
1252 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
1253 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
1254 *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
1255 *data++ = s->rx_cong_drops;
Divy Le Rayfc906642007-03-18 13:10:12 -07001256
1257 *data++ = s->num_toggled;
1258 *data++ = s->num_resets;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001259}
1260
1261static inline void reg_block_dump(struct adapter *ap, void *buf,
1262 unsigned int start, unsigned int end)
1263{
1264 u32 *p = buf + start;
1265
1266 for (; start <= end; start += sizeof(u32))
1267 *p++ = t3_read_reg(ap, start);
1268}
1269
1270static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
1271 void *buf)
1272{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001273 struct port_info *pi = netdev_priv(dev);
1274 struct adapter *ap = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001275
1276 /*
1277 * Version scheme:
1278 * bits 0..9: chip version
1279 * bits 10..15: chip revision
1280 * bit 31: set for PCIe cards
1281 */
1282 regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31);
1283
1284 /*
1285 * We skip the MAC statistics registers because they are clear-on-read.
1286 * Also reading multi-register stats would need to synchronize with the
1287 * periodic mac stats accumulation. Hard to justify the complexity.
1288 */
1289 memset(buf, 0, T3_REGMAP_SIZE);
1290 reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
1291 reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
1292 reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
1293 reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
1294 reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
1295 reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0,
1296 XGM_REG(A_XGM_SERDES_STAT3, 1));
1297 reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
1298 XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
1299}
1300
1301static int restart_autoneg(struct net_device *dev)
1302{
1303 struct port_info *p = netdev_priv(dev);
1304
1305 if (!netif_running(dev))
1306 return -EAGAIN;
1307 if (p->link_config.autoneg != AUTONEG_ENABLE)
1308 return -EINVAL;
1309 p->phy.ops->autoneg_restart(&p->phy);
1310 return 0;
1311}
1312
1313static int cxgb3_phys_id(struct net_device *dev, u32 data)
1314{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001315 struct port_info *pi = netdev_priv(dev);
1316 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001317 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001318
1319 if (data == 0)
1320 data = 2;
1321
1322 for (i = 0; i < data * 2; i++) {
1323 t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
1324 (i & 1) ? F_GPIO0_OUT_VAL : 0);
1325 if (msleep_interruptible(500))
1326 break;
1327 }
1328 t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
1329 F_GPIO0_OUT_VAL);
1330 return 0;
1331}
1332
1333static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1334{
1335 struct port_info *p = netdev_priv(dev);
1336
1337 cmd->supported = p->link_config.supported;
1338 cmd->advertising = p->link_config.advertising;
1339
1340 if (netif_carrier_ok(dev)) {
1341 cmd->speed = p->link_config.speed;
1342 cmd->duplex = p->link_config.duplex;
1343 } else {
1344 cmd->speed = -1;
1345 cmd->duplex = -1;
1346 }
1347
1348 cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
1349 cmd->phy_address = p->phy.addr;
1350 cmd->transceiver = XCVR_EXTERNAL;
1351 cmd->autoneg = p->link_config.autoneg;
1352 cmd->maxtxpkt = 0;
1353 cmd->maxrxpkt = 0;
1354 return 0;
1355}
1356
1357static int speed_duplex_to_caps(int speed, int duplex)
1358{
1359 int cap = 0;
1360
1361 switch (speed) {
1362 case SPEED_10:
1363 if (duplex == DUPLEX_FULL)
1364 cap = SUPPORTED_10baseT_Full;
1365 else
1366 cap = SUPPORTED_10baseT_Half;
1367 break;
1368 case SPEED_100:
1369 if (duplex == DUPLEX_FULL)
1370 cap = SUPPORTED_100baseT_Full;
1371 else
1372 cap = SUPPORTED_100baseT_Half;
1373 break;
1374 case SPEED_1000:
1375 if (duplex == DUPLEX_FULL)
1376 cap = SUPPORTED_1000baseT_Full;
1377 else
1378 cap = SUPPORTED_1000baseT_Half;
1379 break;
1380 case SPEED_10000:
1381 if (duplex == DUPLEX_FULL)
1382 cap = SUPPORTED_10000baseT_Full;
1383 }
1384 return cap;
1385}
1386
1387#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1388 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1389 ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
1390 ADVERTISED_10000baseT_Full)
1391
1392static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1393{
1394 struct port_info *p = netdev_priv(dev);
1395 struct link_config *lc = &p->link_config;
1396
1397 if (!(lc->supported & SUPPORTED_Autoneg))
1398 return -EOPNOTSUPP; /* can't change speed/duplex */
1399
1400 if (cmd->autoneg == AUTONEG_DISABLE) {
1401 int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
1402
1403 if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
1404 return -EINVAL;
1405 lc->requested_speed = cmd->speed;
1406 lc->requested_duplex = cmd->duplex;
1407 lc->advertising = 0;
1408 } else {
1409 cmd->advertising &= ADVERTISED_MASK;
1410 cmd->advertising &= lc->supported;
1411 if (!cmd->advertising)
1412 return -EINVAL;
1413 lc->requested_speed = SPEED_INVALID;
1414 lc->requested_duplex = DUPLEX_INVALID;
1415 lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
1416 }
1417 lc->autoneg = cmd->autoneg;
1418 if (netif_running(dev))
1419 t3_link_start(&p->phy, &p->mac, lc);
1420 return 0;
1421}
1422
1423static void get_pauseparam(struct net_device *dev,
1424 struct ethtool_pauseparam *epause)
1425{
1426 struct port_info *p = netdev_priv(dev);
1427
1428 epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
1429 epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0;
1430 epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0;
1431}
1432
1433static int set_pauseparam(struct net_device *dev,
1434 struct ethtool_pauseparam *epause)
1435{
1436 struct port_info *p = netdev_priv(dev);
1437 struct link_config *lc = &p->link_config;
1438
1439 if (epause->autoneg == AUTONEG_DISABLE)
1440 lc->requested_fc = 0;
1441 else if (lc->supported & SUPPORTED_Autoneg)
1442 lc->requested_fc = PAUSE_AUTONEG;
1443 else
1444 return -EINVAL;
1445
1446 if (epause->rx_pause)
1447 lc->requested_fc |= PAUSE_RX;
1448 if (epause->tx_pause)
1449 lc->requested_fc |= PAUSE_TX;
1450 if (lc->autoneg == AUTONEG_ENABLE) {
1451 if (netif_running(dev))
1452 t3_link_start(&p->phy, &p->mac, lc);
1453 } else {
1454 lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1455 if (netif_running(dev))
1456 t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc);
1457 }
1458 return 0;
1459}
1460
1461static u32 get_rx_csum(struct net_device *dev)
1462{
1463 struct port_info *p = netdev_priv(dev);
1464
1465 return p->rx_csum_offload;
1466}
1467
1468static int set_rx_csum(struct net_device *dev, u32 data)
1469{
1470 struct port_info *p = netdev_priv(dev);
1471
1472 p->rx_csum_offload = data;
1473 return 0;
1474}
1475
1476static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
1477{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001478 struct port_info *pi = netdev_priv(dev);
1479 struct adapter *adapter = pi->adapter;
Divy Le Ray05b97b32007-03-18 13:10:01 -07001480 const struct qset_params *q = &adapter->params.sge.qset[pi->first_qset];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001481
1482 e->rx_max_pending = MAX_RX_BUFFERS;
1483 e->rx_mini_max_pending = 0;
1484 e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
1485 e->tx_max_pending = MAX_TXQ_ENTRIES;
1486
Divy Le Ray05b97b32007-03-18 13:10:01 -07001487 e->rx_pending = q->fl_size;
1488 e->rx_mini_pending = q->rspq_size;
1489 e->rx_jumbo_pending = q->jumbo_size;
1490 e->tx_pending = q->txq_size[0];
Divy Le Ray4d22de32007-01-18 22:04:14 -05001491}
1492
1493static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
1494{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001495 struct port_info *pi = netdev_priv(dev);
1496 struct adapter *adapter = pi->adapter;
Divy Le Ray05b97b32007-03-18 13:10:01 -07001497 struct qset_params *q;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001498 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001499
1500 if (e->rx_pending > MAX_RX_BUFFERS ||
1501 e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
1502 e->tx_pending > MAX_TXQ_ENTRIES ||
1503 e->rx_mini_pending > MAX_RSPQ_ENTRIES ||
1504 e->rx_mini_pending < MIN_RSPQ_ENTRIES ||
1505 e->rx_pending < MIN_FL_ENTRIES ||
1506 e->rx_jumbo_pending < MIN_FL_ENTRIES ||
1507 e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES)
1508 return -EINVAL;
1509
1510 if (adapter->flags & FULL_INIT_DONE)
1511 return -EBUSY;
1512
Divy Le Ray05b97b32007-03-18 13:10:01 -07001513 q = &adapter->params.sge.qset[pi->first_qset];
1514 for (i = 0; i < pi->nqsets; ++i, ++q) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001515 q->rspq_size = e->rx_mini_pending;
1516 q->fl_size = e->rx_pending;
1517 q->jumbo_size = e->rx_jumbo_pending;
1518 q->txq_size[0] = e->tx_pending;
1519 q->txq_size[1] = e->tx_pending;
1520 q->txq_size[2] = e->tx_pending;
1521 }
1522 return 0;
1523}
1524
1525static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
1526{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001527 struct port_info *pi = netdev_priv(dev);
1528 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001529 struct qset_params *qsp = &adapter->params.sge.qset[0];
1530 struct sge_qset *qs = &adapter->sge.qs[0];
1531
1532 if (c->rx_coalesce_usecs * 10 > M_NEWTIMER)
1533 return -EINVAL;
1534
1535 qsp->coalesce_usecs = c->rx_coalesce_usecs;
1536 t3_update_qset_coalesce(qs, qsp);
1537 return 0;
1538}
1539
1540static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
1541{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001542 struct port_info *pi = netdev_priv(dev);
1543 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001544 struct qset_params *q = adapter->params.sge.qset;
1545
1546 c->rx_coalesce_usecs = q->coalesce_usecs;
1547 return 0;
1548}
1549
1550static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
1551 u8 * data)
1552{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001553 struct port_info *pi = netdev_priv(dev);
1554 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001555 int i, err = 0;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001556
1557 u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
1558 if (!buf)
1559 return -ENOMEM;
1560
1561 e->magic = EEPROM_MAGIC;
1562 for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
1563 err = t3_seeprom_read(adapter, i, (u32 *) & buf[i]);
1564
1565 if (!err)
1566 memcpy(data, buf + e->offset, e->len);
1567 kfree(buf);
1568 return err;
1569}
1570
1571static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
1572 u8 * data)
1573{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001574 struct port_info *pi = netdev_priv(dev);
1575 struct adapter *adapter = pi->adapter;
1576 u32 aligned_offset, aligned_len, *p;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001577 u8 *buf;
Denis Chengc54f5c22007-07-18 15:24:49 +08001578 int err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001579
1580 if (eeprom->magic != EEPROM_MAGIC)
1581 return -EINVAL;
1582
1583 aligned_offset = eeprom->offset & ~3;
1584 aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
1585
1586 if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
1587 buf = kmalloc(aligned_len, GFP_KERNEL);
1588 if (!buf)
1589 return -ENOMEM;
1590 err = t3_seeprom_read(adapter, aligned_offset, (u32 *) buf);
1591 if (!err && aligned_len > 4)
1592 err = t3_seeprom_read(adapter,
1593 aligned_offset + aligned_len - 4,
1594 (u32 *) & buf[aligned_len - 4]);
1595 if (err)
1596 goto out;
1597 memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
1598 } else
1599 buf = data;
1600
1601 err = t3_seeprom_wp(adapter, 0);
1602 if (err)
1603 goto out;
1604
1605 for (p = (u32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
1606 err = t3_seeprom_write(adapter, aligned_offset, *p);
1607 aligned_offset += 4;
1608 }
1609
1610 if (!err)
1611 err = t3_seeprom_wp(adapter, 1);
1612out:
1613 if (buf != data)
1614 kfree(buf);
1615 return err;
1616}
1617
1618static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1619{
1620 wol->supported = 0;
1621 wol->wolopts = 0;
1622 memset(&wol->sopass, 0, sizeof(wol->sopass));
1623}
1624
1625static const struct ethtool_ops cxgb_ethtool_ops = {
1626 .get_settings = get_settings,
1627 .set_settings = set_settings,
1628 .get_drvinfo = get_drvinfo,
1629 .get_msglevel = get_msglevel,
1630 .set_msglevel = set_msglevel,
1631 .get_ringparam = get_sge_param,
1632 .set_ringparam = set_sge_param,
1633 .get_coalesce = get_coalesce,
1634 .set_coalesce = set_coalesce,
1635 .get_eeprom_len = get_eeprom_len,
1636 .get_eeprom = get_eeprom,
1637 .set_eeprom = set_eeprom,
1638 .get_pauseparam = get_pauseparam,
1639 .set_pauseparam = set_pauseparam,
1640 .get_rx_csum = get_rx_csum,
1641 .set_rx_csum = set_rx_csum,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001642 .set_tx_csum = ethtool_op_set_tx_csum,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001643 .set_sg = ethtool_op_set_sg,
1644 .get_link = ethtool_op_get_link,
1645 .get_strings = get_strings,
1646 .phys_id = cxgb3_phys_id,
1647 .nway_reset = restart_autoneg,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001648 .get_sset_count = get_sset_count,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001649 .get_ethtool_stats = get_stats,
1650 .get_regs_len = get_regs_len,
1651 .get_regs = get_regs,
1652 .get_wol = get_wol,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001653 .set_tso = ethtool_op_set_tso,
Divy Le Ray4d22de32007-01-18 22:04:14 -05001654};
1655
1656static int in_range(int val, int lo, int hi)
1657{
1658 return val < 0 || (val <= hi && val >= lo);
1659}
1660
1661static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
1662{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001663 struct port_info *pi = netdev_priv(dev);
1664 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001665 u32 cmd;
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001666 int ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001667
1668 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
1669 return -EFAULT;
1670
1671 switch (cmd) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001672 case CHELSIO_SET_QSET_PARAMS:{
1673 int i;
1674 struct qset_params *q;
1675 struct ch_qset_params t;
1676
1677 if (!capable(CAP_NET_ADMIN))
1678 return -EPERM;
1679 if (copy_from_user(&t, useraddr, sizeof(t)))
1680 return -EFAULT;
1681 if (t.qset_idx >= SGE_QSETS)
1682 return -EINVAL;
1683 if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
1684 !in_range(t.cong_thres, 0, 255) ||
1685 !in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
1686 MAX_TXQ_ENTRIES) ||
1687 !in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
1688 MAX_TXQ_ENTRIES) ||
1689 !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
1690 MAX_CTRL_TXQ_ENTRIES) ||
1691 !in_range(t.fl_size[0], MIN_FL_ENTRIES,
1692 MAX_RX_BUFFERS)
1693 || !in_range(t.fl_size[1], MIN_FL_ENTRIES,
1694 MAX_RX_JUMBO_BUFFERS)
1695 || !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
1696 MAX_RSPQ_ENTRIES))
1697 return -EINVAL;
1698 if ((adapter->flags & FULL_INIT_DONE) &&
1699 (t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
1700 t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
1701 t.txq_size[1] >= 0 || t.txq_size[2] >= 0 ||
1702 t.polling >= 0 || t.cong_thres >= 0))
1703 return -EBUSY;
1704
1705 q = &adapter->params.sge.qset[t.qset_idx];
1706
1707 if (t.rspq_size >= 0)
1708 q->rspq_size = t.rspq_size;
1709 if (t.fl_size[0] >= 0)
1710 q->fl_size = t.fl_size[0];
1711 if (t.fl_size[1] >= 0)
1712 q->jumbo_size = t.fl_size[1];
1713 if (t.txq_size[0] >= 0)
1714 q->txq_size[0] = t.txq_size[0];
1715 if (t.txq_size[1] >= 0)
1716 q->txq_size[1] = t.txq_size[1];
1717 if (t.txq_size[2] >= 0)
1718 q->txq_size[2] = t.txq_size[2];
1719 if (t.cong_thres >= 0)
1720 q->cong_thres = t.cong_thres;
1721 if (t.intr_lat >= 0) {
1722 struct sge_qset *qs =
1723 &adapter->sge.qs[t.qset_idx];
1724
1725 q->coalesce_usecs = t.intr_lat;
1726 t3_update_qset_coalesce(qs, q);
1727 }
1728 if (t.polling >= 0) {
1729 if (adapter->flags & USING_MSIX)
1730 q->polling = t.polling;
1731 else {
1732 /* No polling with INTx for T3A */
1733 if (adapter->params.rev == 0 &&
1734 !(adapter->flags & USING_MSI))
1735 t.polling = 0;
1736
1737 for (i = 0; i < SGE_QSETS; i++) {
1738 q = &adapter->params.sge.
1739 qset[i];
1740 q->polling = t.polling;
1741 }
1742 }
1743 }
1744 break;
1745 }
1746 case CHELSIO_GET_QSET_PARAMS:{
1747 struct qset_params *q;
1748 struct ch_qset_params t;
1749
1750 if (copy_from_user(&t, useraddr, sizeof(t)))
1751 return -EFAULT;
1752 if (t.qset_idx >= SGE_QSETS)
1753 return -EINVAL;
1754
1755 q = &adapter->params.sge.qset[t.qset_idx];
1756 t.rspq_size = q->rspq_size;
1757 t.txq_size[0] = q->txq_size[0];
1758 t.txq_size[1] = q->txq_size[1];
1759 t.txq_size[2] = q->txq_size[2];
1760 t.fl_size[0] = q->fl_size;
1761 t.fl_size[1] = q->jumbo_size;
1762 t.polling = q->polling;
1763 t.intr_lat = q->coalesce_usecs;
1764 t.cong_thres = q->cong_thres;
1765
1766 if (copy_to_user(useraddr, &t, sizeof(t)))
1767 return -EFAULT;
1768 break;
1769 }
1770 case CHELSIO_SET_QSET_NUM:{
1771 struct ch_reg edata;
1772 struct port_info *pi = netdev_priv(dev);
1773 unsigned int i, first_qset = 0, other_qsets = 0;
1774
1775 if (!capable(CAP_NET_ADMIN))
1776 return -EPERM;
1777 if (adapter->flags & FULL_INIT_DONE)
1778 return -EBUSY;
1779 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1780 return -EFAULT;
1781 if (edata.val < 1 ||
1782 (edata.val > 1 && !(adapter->flags & USING_MSIX)))
1783 return -EINVAL;
1784
1785 for_each_port(adapter, i)
1786 if (adapter->port[i] && adapter->port[i] != dev)
1787 other_qsets += adap2pinfo(adapter, i)->nqsets;
1788
1789 if (edata.val + other_qsets > SGE_QSETS)
1790 return -EINVAL;
1791
1792 pi->nqsets = edata.val;
1793
1794 for_each_port(adapter, i)
1795 if (adapter->port[i]) {
1796 pi = adap2pinfo(adapter, i);
1797 pi->first_qset = first_qset;
1798 first_qset += pi->nqsets;
1799 }
1800 break;
1801 }
1802 case CHELSIO_GET_QSET_NUM:{
1803 struct ch_reg edata;
1804 struct port_info *pi = netdev_priv(dev);
1805
1806 edata.cmd = CHELSIO_GET_QSET_NUM;
1807 edata.val = pi->nqsets;
1808 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1809 return -EFAULT;
1810 break;
1811 }
1812 case CHELSIO_LOAD_FW:{
1813 u8 *fw_data;
1814 struct ch_mem_range t;
1815
1816 if (!capable(CAP_NET_ADMIN))
1817 return -EPERM;
1818 if (copy_from_user(&t, useraddr, sizeof(t)))
1819 return -EFAULT;
1820
1821 fw_data = kmalloc(t.len, GFP_KERNEL);
1822 if (!fw_data)
1823 return -ENOMEM;
1824
1825 if (copy_from_user
1826 (fw_data, useraddr + sizeof(t), t.len)) {
1827 kfree(fw_data);
1828 return -EFAULT;
1829 }
1830
1831 ret = t3_load_fw(adapter, fw_data, t.len);
1832 kfree(fw_data);
1833 if (ret)
1834 return ret;
1835 break;
1836 }
1837 case CHELSIO_SETMTUTAB:{
1838 struct ch_mtus m;
1839 int i;
1840
1841 if (!is_offload(adapter))
1842 return -EOPNOTSUPP;
1843 if (!capable(CAP_NET_ADMIN))
1844 return -EPERM;
1845 if (offload_running(adapter))
1846 return -EBUSY;
1847 if (copy_from_user(&m, useraddr, sizeof(m)))
1848 return -EFAULT;
1849 if (m.nmtus != NMTUS)
1850 return -EINVAL;
1851 if (m.mtus[0] < 81) /* accommodate SACK */
1852 return -EINVAL;
1853
1854 /* MTUs must be in ascending order */
1855 for (i = 1; i < NMTUS; ++i)
1856 if (m.mtus[i] < m.mtus[i - 1])
1857 return -EINVAL;
1858
1859 memcpy(adapter->params.mtus, m.mtus,
1860 sizeof(adapter->params.mtus));
1861 break;
1862 }
1863 case CHELSIO_GET_PM:{
1864 struct tp_params *p = &adapter->params.tp;
1865 struct ch_pm m = {.cmd = CHELSIO_GET_PM };
1866
1867 if (!is_offload(adapter))
1868 return -EOPNOTSUPP;
1869 m.tx_pg_sz = p->tx_pg_size;
1870 m.tx_num_pg = p->tx_num_pgs;
1871 m.rx_pg_sz = p->rx_pg_size;
1872 m.rx_num_pg = p->rx_num_pgs;
1873 m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan;
1874 if (copy_to_user(useraddr, &m, sizeof(m)))
1875 return -EFAULT;
1876 break;
1877 }
1878 case CHELSIO_SET_PM:{
1879 struct ch_pm m;
1880 struct tp_params *p = &adapter->params.tp;
1881
1882 if (!is_offload(adapter))
1883 return -EOPNOTSUPP;
1884 if (!capable(CAP_NET_ADMIN))
1885 return -EPERM;
1886 if (adapter->flags & FULL_INIT_DONE)
1887 return -EBUSY;
1888 if (copy_from_user(&m, useraddr, sizeof(m)))
1889 return -EFAULT;
vignesh babud9da4662007-07-09 11:50:22 -07001890 if (!is_power_of_2(m.rx_pg_sz) ||
1891 !is_power_of_2(m.tx_pg_sz))
Divy Le Ray4d22de32007-01-18 22:04:14 -05001892 return -EINVAL; /* not power of 2 */
1893 if (!(m.rx_pg_sz & 0x14000))
1894 return -EINVAL; /* not 16KB or 64KB */
1895 if (!(m.tx_pg_sz & 0x1554000))
1896 return -EINVAL;
1897 if (m.tx_num_pg == -1)
1898 m.tx_num_pg = p->tx_num_pgs;
1899 if (m.rx_num_pg == -1)
1900 m.rx_num_pg = p->rx_num_pgs;
1901 if (m.tx_num_pg % 24 || m.rx_num_pg % 24)
1902 return -EINVAL;
1903 if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size ||
1904 m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size)
1905 return -EINVAL;
1906 p->rx_pg_size = m.rx_pg_sz;
1907 p->tx_pg_size = m.tx_pg_sz;
1908 p->rx_num_pgs = m.rx_num_pg;
1909 p->tx_num_pgs = m.tx_num_pg;
1910 break;
1911 }
1912 case CHELSIO_GET_MEM:{
1913 struct ch_mem_range t;
1914 struct mc7 *mem;
1915 u64 buf[32];
1916
1917 if (!is_offload(adapter))
1918 return -EOPNOTSUPP;
1919 if (!(adapter->flags & FULL_INIT_DONE))
1920 return -EIO; /* need the memory controllers */
1921 if (copy_from_user(&t, useraddr, sizeof(t)))
1922 return -EFAULT;
1923 if ((t.addr & 7) || (t.len & 7))
1924 return -EINVAL;
1925 if (t.mem_id == MEM_CM)
1926 mem = &adapter->cm;
1927 else if (t.mem_id == MEM_PMRX)
1928 mem = &adapter->pmrx;
1929 else if (t.mem_id == MEM_PMTX)
1930 mem = &adapter->pmtx;
1931 else
1932 return -EINVAL;
1933
1934 /*
Divy Le Ray18254942007-02-24 16:43:56 -08001935 * Version scheme:
1936 * bits 0..9: chip version
1937 * bits 10..15: chip revision
1938 */
Divy Le Ray4d22de32007-01-18 22:04:14 -05001939 t.version = 3 | (adapter->params.rev << 10);
1940 if (copy_to_user(useraddr, &t, sizeof(t)))
1941 return -EFAULT;
1942
1943 /*
1944 * Read 256 bytes at a time as len can be large and we don't
1945 * want to use huge intermediate buffers.
1946 */
1947 useraddr += sizeof(t); /* advance to start of buffer */
1948 while (t.len) {
1949 unsigned int chunk =
1950 min_t(unsigned int, t.len, sizeof(buf));
1951
1952 ret =
1953 t3_mc7_bd_read(mem, t.addr / 8, chunk / 8,
1954 buf);
1955 if (ret)
1956 return ret;
1957 if (copy_to_user(useraddr, buf, chunk))
1958 return -EFAULT;
1959 useraddr += chunk;
1960 t.addr += chunk;
1961 t.len -= chunk;
1962 }
1963 break;
1964 }
1965 case CHELSIO_SET_TRACE_FILTER:{
1966 struct ch_trace t;
1967 const struct trace_params *tp;
1968
1969 if (!capable(CAP_NET_ADMIN))
1970 return -EPERM;
1971 if (!offload_running(adapter))
1972 return -EAGAIN;
1973 if (copy_from_user(&t, useraddr, sizeof(t)))
1974 return -EFAULT;
1975
1976 tp = (const struct trace_params *)&t.sip;
1977 if (t.config_tx)
1978 t3_config_trace_filter(adapter, tp, 0,
1979 t.invert_match,
1980 t.trace_tx);
1981 if (t.config_rx)
1982 t3_config_trace_filter(adapter, tp, 1,
1983 t.invert_match,
1984 t.trace_rx);
1985 break;
1986 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001987 default:
1988 return -EOPNOTSUPP;
1989 }
1990 return 0;
1991}
1992
1993static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
1994{
Divy Le Ray4d22de32007-01-18 22:04:14 -05001995 struct mii_ioctl_data *data = if_mii(req);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07001996 struct port_info *pi = netdev_priv(dev);
1997 struct adapter *adapter = pi->adapter;
1998 int ret, mmd;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001999
2000 switch (cmd) {
2001 case SIOCGMIIPHY:
2002 data->phy_id = pi->phy.addr;
2003 /* FALLTHRU */
2004 case SIOCGMIIREG:{
2005 u32 val;
2006 struct cphy *phy = &pi->phy;
2007
2008 if (!phy->mdio_read)
2009 return -EOPNOTSUPP;
2010 if (is_10G(adapter)) {
2011 mmd = data->phy_id >> 8;
2012 if (!mmd)
2013 mmd = MDIO_DEV_PCS;
2014 else if (mmd > MDIO_DEV_XGXS)
2015 return -EINVAL;
2016
2017 ret =
2018 phy->mdio_read(adapter, data->phy_id & 0x1f,
2019 mmd, data->reg_num, &val);
2020 } else
2021 ret =
2022 phy->mdio_read(adapter, data->phy_id & 0x1f,
2023 0, data->reg_num & 0x1f,
2024 &val);
2025 if (!ret)
2026 data->val_out = val;
2027 break;
2028 }
2029 case SIOCSMIIREG:{
2030 struct cphy *phy = &pi->phy;
2031
2032 if (!capable(CAP_NET_ADMIN))
2033 return -EPERM;
2034 if (!phy->mdio_write)
2035 return -EOPNOTSUPP;
2036 if (is_10G(adapter)) {
2037 mmd = data->phy_id >> 8;
2038 if (!mmd)
2039 mmd = MDIO_DEV_PCS;
2040 else if (mmd > MDIO_DEV_XGXS)
2041 return -EINVAL;
2042
2043 ret =
2044 phy->mdio_write(adapter,
2045 data->phy_id & 0x1f, mmd,
2046 data->reg_num,
2047 data->val_in);
2048 } else
2049 ret =
2050 phy->mdio_write(adapter,
2051 data->phy_id & 0x1f, 0,
2052 data->reg_num & 0x1f,
2053 data->val_in);
2054 break;
2055 }
2056 case SIOCCHIOCTL:
2057 return cxgb_extension_ioctl(dev, req->ifr_data);
2058 default:
2059 return -EOPNOTSUPP;
2060 }
2061 return ret;
2062}
2063
2064static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
2065{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002066 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002067 struct adapter *adapter = pi->adapter;
2068 int ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002069
2070 if (new_mtu < 81) /* accommodate SACK */
2071 return -EINVAL;
2072 if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu)))
2073 return ret;
2074 dev->mtu = new_mtu;
2075 init_port_mtus(adapter);
2076 if (adapter->params.rev == 0 && offload_running(adapter))
2077 t3_load_mtus(adapter, adapter->params.mtus,
2078 adapter->params.a_wnd, adapter->params.b_wnd,
2079 adapter->port[0]->mtu);
2080 return 0;
2081}
2082
2083static int cxgb_set_mac_addr(struct net_device *dev, void *p)
2084{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002085 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002086 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002087 struct sockaddr *addr = p;
2088
2089 if (!is_valid_ether_addr(addr->sa_data))
2090 return -EINVAL;
2091
2092 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
2093 t3_mac_set_address(&pi->mac, 0, dev->dev_addr);
2094 if (offload_running(adapter))
2095 write_smt_entry(adapter, pi->port_id);
2096 return 0;
2097}
2098
2099/**
2100 * t3_synchronize_rx - wait for current Rx processing on a port to complete
2101 * @adap: the adapter
2102 * @p: the port
2103 *
2104 * Ensures that current Rx processing on any of the queues associated with
2105 * the given port completes before returning. We do this by acquiring and
2106 * releasing the locks of the response queues associated with the port.
2107 */
2108static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
2109{
2110 int i;
2111
2112 for (i = 0; i < p->nqsets; i++) {
2113 struct sge_rspq *q = &adap->sge.qs[i + p->first_qset].rspq;
2114
2115 spin_lock_irq(&q->lock);
2116 spin_unlock_irq(&q->lock);
2117 }
2118}
2119
2120static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
2121{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002122 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002123 struct adapter *adapter = pi->adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002124
2125 pi->vlan_grp = grp;
2126 if (adapter->params.rev > 0)
2127 t3_set_vlan_accel(adapter, 1 << pi->port_id, grp != NULL);
2128 else {
2129 /* single control for all ports */
2130 unsigned int i, have_vlans = 0;
2131 for_each_port(adapter, i)
2132 have_vlans |= adap2pinfo(adapter, i)->vlan_grp != NULL;
2133
2134 t3_set_vlan_accel(adapter, 1, have_vlans);
2135 }
2136 t3_synchronize_rx(adapter, pi);
2137}
2138
Divy Le Ray4d22de32007-01-18 22:04:14 -05002139#ifdef CONFIG_NET_POLL_CONTROLLER
2140static void cxgb_netpoll(struct net_device *dev)
2141{
Divy Le Ray890de332007-05-30 10:01:34 -07002142 struct port_info *pi = netdev_priv(dev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002143 struct adapter *adapter = pi->adapter;
Divy Le Ray890de332007-05-30 10:01:34 -07002144 int qidx;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002145
Divy Le Ray890de332007-05-30 10:01:34 -07002146 for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) {
2147 struct sge_qset *qs = &adapter->sge.qs[qidx];
2148 void *source;
2149
2150 if (adapter->flags & USING_MSIX)
2151 source = qs;
2152 else
2153 source = adapter;
2154
2155 t3_intr_handler(adapter, qs->rspq.polling) (0, source);
2156 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05002157}
2158#endif
2159
2160/*
2161 * Periodic accumulation of MAC statistics.
2162 */
2163static void mac_stats_update(struct adapter *adapter)
2164{
2165 int i;
2166
2167 for_each_port(adapter, i) {
2168 struct net_device *dev = adapter->port[i];
2169 struct port_info *p = netdev_priv(dev);
2170
2171 if (netif_running(dev)) {
2172 spin_lock(&adapter->stats_lock);
2173 t3_mac_update_stats(&p->mac);
2174 spin_unlock(&adapter->stats_lock);
2175 }
2176 }
2177}
2178
2179static void check_link_status(struct adapter *adapter)
2180{
2181 int i;
2182
2183 for_each_port(adapter, i) {
2184 struct net_device *dev = adapter->port[i];
2185 struct port_info *p = netdev_priv(dev);
2186
2187 if (!(p->port_type->caps & SUPPORTED_IRQ) && netif_running(dev))
2188 t3_link_changed(adapter, i);
2189 }
2190}
2191
Divy Le Rayfc906642007-03-18 13:10:12 -07002192static void check_t3b2_mac(struct adapter *adapter)
2193{
2194 int i;
2195
Divy Le Rayf2d961c2007-04-09 20:10:22 -07002196 if (!rtnl_trylock()) /* synchronize with ifdown */
2197 return;
2198
Divy Le Rayfc906642007-03-18 13:10:12 -07002199 for_each_port(adapter, i) {
2200 struct net_device *dev = adapter->port[i];
2201 struct port_info *p = netdev_priv(dev);
2202 int status;
2203
2204 if (!netif_running(dev))
2205 continue;
2206
2207 status = 0;
Divy Le Ray6d6daba2007-03-31 00:23:24 -07002208 if (netif_running(dev) && netif_carrier_ok(dev))
Divy Le Rayfc906642007-03-18 13:10:12 -07002209 status = t3b2_mac_watchdog_task(&p->mac);
2210 if (status == 1)
2211 p->mac.stats.num_toggled++;
2212 else if (status == 2) {
2213 struct cmac *mac = &p->mac;
2214
2215 t3_mac_set_mtu(mac, dev->mtu);
2216 t3_mac_set_address(mac, 0, dev->dev_addr);
2217 cxgb_set_rxmode(dev);
2218 t3_link_start(&p->phy, mac, &p->link_config);
2219 t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
2220 t3_port_intr_enable(adapter, p->port_id);
2221 p->mac.stats.num_resets++;
2222 }
2223 }
2224 rtnl_unlock();
2225}
2226
2227
Divy Le Ray4d22de32007-01-18 22:04:14 -05002228static void t3_adap_check_task(struct work_struct *work)
2229{
2230 struct adapter *adapter = container_of(work, struct adapter,
2231 adap_check_task.work);
2232 const struct adapter_params *p = &adapter->params;
2233
2234 adapter->check_task_cnt++;
2235
2236 /* Check link status for PHYs without interrupts */
2237 if (p->linkpoll_period)
2238 check_link_status(adapter);
2239
2240 /* Accumulate MAC stats if needed */
2241 if (!p->linkpoll_period ||
2242 (adapter->check_task_cnt * p->linkpoll_period) / 10 >=
2243 p->stats_update_period) {
2244 mac_stats_update(adapter);
2245 adapter->check_task_cnt = 0;
2246 }
2247
Divy Le Rayfc906642007-03-18 13:10:12 -07002248 if (p->rev == T3_REV_B2)
2249 check_t3b2_mac(adapter);
2250
Divy Le Ray4d22de32007-01-18 22:04:14 -05002251 /* Schedule the next check update if any port is active. */
2252 spin_lock(&adapter->work_lock);
2253 if (adapter->open_device_map & PORT_MASK)
2254 schedule_chk_task(adapter);
2255 spin_unlock(&adapter->work_lock);
2256}
2257
2258/*
2259 * Processes external (PHY) interrupts in process context.
2260 */
2261static void ext_intr_task(struct work_struct *work)
2262{
2263 struct adapter *adapter = container_of(work, struct adapter,
2264 ext_intr_handler_task);
2265
2266 t3_phy_intr_handler(adapter);
2267
2268 /* Now reenable external interrupts */
2269 spin_lock_irq(&adapter->work_lock);
2270 if (adapter->slow_intr_mask) {
2271 adapter->slow_intr_mask |= F_T3DBG;
2272 t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG);
2273 t3_write_reg(adapter, A_PL_INT_ENABLE0,
2274 adapter->slow_intr_mask);
2275 }
2276 spin_unlock_irq(&adapter->work_lock);
2277}
2278
2279/*
2280 * Interrupt-context handler for external (PHY) interrupts.
2281 */
2282void t3_os_ext_intr_handler(struct adapter *adapter)
2283{
2284 /*
2285 * Schedule a task to handle external interrupts as they may be slow
2286 * and we use a mutex to protect MDIO registers. We disable PHY
2287 * interrupts in the meantime and let the task reenable them when
2288 * it's done.
2289 */
2290 spin_lock(&adapter->work_lock);
2291 if (adapter->slow_intr_mask) {
2292 adapter->slow_intr_mask &= ~F_T3DBG;
2293 t3_write_reg(adapter, A_PL_INT_ENABLE0,
2294 adapter->slow_intr_mask);
2295 queue_work(cxgb3_wq, &adapter->ext_intr_handler_task);
2296 }
2297 spin_unlock(&adapter->work_lock);
2298}
2299
2300void t3_fatal_err(struct adapter *adapter)
2301{
2302 unsigned int fw_status[4];
2303
2304 if (adapter->flags & FULL_INIT_DONE) {
2305 t3_sge_stop(adapter);
Divy Le Rayc64c2ea2007-08-21 20:49:31 -07002306 t3_write_reg(adapter, A_XGM_TX_CTRL, 0);
2307 t3_write_reg(adapter, A_XGM_RX_CTRL, 0);
2308 t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0);
2309 t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002310 t3_intr_disable(adapter);
2311 }
2312 CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
2313 if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
2314 CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
2315 fw_status[0], fw_status[1],
2316 fw_status[2], fw_status[3]);
2317
2318}
2319
2320static int __devinit cxgb_enable_msix(struct adapter *adap)
2321{
2322 struct msix_entry entries[SGE_QSETS + 1];
2323 int i, err;
2324
2325 for (i = 0; i < ARRAY_SIZE(entries); ++i)
2326 entries[i].entry = i;
2327
2328 err = pci_enable_msix(adap->pdev, entries, ARRAY_SIZE(entries));
2329 if (!err) {
2330 for (i = 0; i < ARRAY_SIZE(entries); ++i)
2331 adap->msix_info[i].vec = entries[i].vector;
2332 } else if (err > 0)
2333 dev_info(&adap->pdev->dev,
2334 "only %d MSI-X vectors left, not using MSI-X\n", err);
2335 return err;
2336}
2337
2338static void __devinit print_port_info(struct adapter *adap,
2339 const struct adapter_info *ai)
2340{
2341 static const char *pci_variant[] = {
2342 "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express"
2343 };
2344
2345 int i;
2346 char buf[80];
2347
2348 if (is_pcie(adap))
2349 snprintf(buf, sizeof(buf), "%s x%d",
2350 pci_variant[adap->params.pci.variant],
2351 adap->params.pci.width);
2352 else
2353 snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit",
2354 pci_variant[adap->params.pci.variant],
2355 adap->params.pci.speed, adap->params.pci.width);
2356
2357 for_each_port(adap, i) {
2358 struct net_device *dev = adap->port[i];
2359 const struct port_info *pi = netdev_priv(dev);
2360
2361 if (!test_bit(i, &adap->registered_device_map))
2362 continue;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07002363 printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n",
Divy Le Ray4d22de32007-01-18 22:04:14 -05002364 dev->name, ai->desc, pi->port_type->desc,
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07002365 is_offload(adap) ? "R" : "", adap->params.rev, buf,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002366 (adap->flags & USING_MSIX) ? " MSI-X" :
2367 (adap->flags & USING_MSI) ? " MSI" : "");
2368 if (adap->name == dev->name && adap->params.vpd.mclk)
Divy Le Ray167cdf52007-08-21 20:49:36 -07002369 printk(KERN_INFO
2370 "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
Divy Le Ray4d22de32007-01-18 22:04:14 -05002371 adap->name, t3_mc7_size(&adap->cm) >> 20,
2372 t3_mc7_size(&adap->pmtx) >> 20,
Divy Le Ray167cdf52007-08-21 20:49:36 -07002373 t3_mc7_size(&adap->pmrx) >> 20,
2374 adap->params.vpd.sn);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002375 }
2376}
2377
2378static int __devinit init_one(struct pci_dev *pdev,
2379 const struct pci_device_id *ent)
2380{
2381 static int version_printed;
2382
2383 int i, err, pci_using_dac = 0;
2384 unsigned long mmio_start, mmio_len;
2385 const struct adapter_info *ai;
2386 struct adapter *adapter = NULL;
2387 struct port_info *pi;
2388
2389 if (!version_printed) {
2390 printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
2391 ++version_printed;
2392 }
2393
2394 if (!cxgb3_wq) {
2395 cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
2396 if (!cxgb3_wq) {
2397 printk(KERN_ERR DRV_NAME
2398 ": cannot initialize work queue\n");
2399 return -ENOMEM;
2400 }
2401 }
2402
2403 err = pci_request_regions(pdev, DRV_NAME);
2404 if (err) {
2405 /* Just info, some other driver may have claimed the device. */
2406 dev_info(&pdev->dev, "cannot obtain PCI resources\n");
2407 return err;
2408 }
2409
2410 err = pci_enable_device(pdev);
2411 if (err) {
2412 dev_err(&pdev->dev, "cannot enable PCI device\n");
2413 goto out_release_regions;
2414 }
2415
2416 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
2417 pci_using_dac = 1;
2418 err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
2419 if (err) {
2420 dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
2421 "coherent allocations\n");
2422 goto out_disable_device;
2423 }
2424 } else if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
2425 dev_err(&pdev->dev, "no usable DMA configuration\n");
2426 goto out_disable_device;
2427 }
2428
2429 pci_set_master(pdev);
2430
2431 mmio_start = pci_resource_start(pdev, 0);
2432 mmio_len = pci_resource_len(pdev, 0);
2433 ai = t3_get_adapter_info(ent->driver_data);
2434
2435 adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
2436 if (!adapter) {
2437 err = -ENOMEM;
2438 goto out_disable_device;
2439 }
2440
2441 adapter->regs = ioremap_nocache(mmio_start, mmio_len);
2442 if (!adapter->regs) {
2443 dev_err(&pdev->dev, "cannot map device registers\n");
2444 err = -ENOMEM;
2445 goto out_free_adapter;
2446 }
2447
2448 adapter->pdev = pdev;
2449 adapter->name = pci_name(pdev);
2450 adapter->msg_enable = dflt_msg_enable;
2451 adapter->mmio_len = mmio_len;
2452
2453 mutex_init(&adapter->mdio_lock);
2454 spin_lock_init(&adapter->work_lock);
2455 spin_lock_init(&adapter->stats_lock);
2456
2457 INIT_LIST_HEAD(&adapter->adapter_list);
2458 INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
2459 INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
2460
2461 for (i = 0; i < ai->nports; ++i) {
2462 struct net_device *netdev;
2463
2464 netdev = alloc_etherdev(sizeof(struct port_info));
2465 if (!netdev) {
2466 err = -ENOMEM;
2467 goto out_free_dev;
2468 }
2469
Divy Le Ray4d22de32007-01-18 22:04:14 -05002470 SET_NETDEV_DEV(netdev, &pdev->dev);
2471
2472 adapter->port[i] = netdev;
2473 pi = netdev_priv(netdev);
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002474 pi->adapter = adapter;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002475 pi->rx_csum_offload = 1;
2476 pi->nqsets = 1;
2477 pi->first_qset = i;
2478 pi->activity = 0;
2479 pi->port_id = i;
2480 netif_carrier_off(netdev);
2481 netdev->irq = pdev->irq;
2482 netdev->mem_start = mmio_start;
2483 netdev->mem_end = mmio_start + mmio_len - 1;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002484 netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
2485 netdev->features |= NETIF_F_LLTX;
2486 if (pci_using_dac)
2487 netdev->features |= NETIF_F_HIGHDMA;
2488
2489 netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
2490 netdev->vlan_rx_register = vlan_rx_register;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002491
2492 netdev->open = cxgb_open;
2493 netdev->stop = cxgb_close;
2494 netdev->hard_start_xmit = t3_eth_xmit;
2495 netdev->get_stats = cxgb_get_stats;
2496 netdev->set_multicast_list = cxgb_set_rxmode;
2497 netdev->do_ioctl = cxgb_ioctl;
2498 netdev->change_mtu = cxgb_change_mtu;
2499 netdev->set_mac_address = cxgb_set_mac_addr;
2500#ifdef CONFIG_NET_POLL_CONTROLLER
2501 netdev->poll_controller = cxgb_netpoll;
2502#endif
Divy Le Ray4d22de32007-01-18 22:04:14 -05002503
2504 SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
2505 }
2506
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002507 pci_set_drvdata(pdev, adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002508 if (t3_prep_adapter(adapter, ai, 1) < 0) {
2509 err = -ENODEV;
2510 goto out_free_dev;
2511 }
Divy Le Ray480fe1a2007-05-30 21:10:58 -07002512
Divy Le Ray4d22de32007-01-18 22:04:14 -05002513 /*
2514 * The card is now ready to go. If any errors occur during device
2515 * registration we do not fail the whole card but rather proceed only
2516 * with the ports we manage to register successfully. However we must
2517 * register at least one net device.
2518 */
2519 for_each_port(adapter, i) {
2520 err = register_netdev(adapter->port[i]);
2521 if (err)
2522 dev_warn(&pdev->dev,
2523 "cannot register net device %s, skipping\n",
2524 adapter->port[i]->name);
2525 else {
2526 /*
2527 * Change the name we use for messages to the name of
2528 * the first successfully registered interface.
2529 */
2530 if (!adapter->registered_device_map)
2531 adapter->name = adapter->port[i]->name;
2532
2533 __set_bit(i, &adapter->registered_device_map);
2534 }
2535 }
2536 if (!adapter->registered_device_map) {
2537 dev_err(&pdev->dev, "could not register any net devices\n");
2538 goto out_free_dev;
2539 }
2540
2541 /* Driver's ready. Reflect it on LEDs */
2542 t3_led_ready(adapter);
2543
2544 if (is_offload(adapter)) {
2545 __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
2546 cxgb3_adapter_ofld(adapter);
2547 }
2548
2549 /* See what interrupts we'll be using */
2550 if (msi > 1 && cxgb_enable_msix(adapter) == 0)
2551 adapter->flags |= USING_MSIX;
2552 else if (msi > 0 && pci_enable_msi(pdev) == 0)
2553 adapter->flags |= USING_MSI;
2554
Divy Le Ray0ee8d332007-02-08 16:55:59 -08002555 err = sysfs_create_group(&adapter->port[0]->dev.kobj,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002556 &cxgb3_attr_group);
2557
2558 print_port_info(adapter, ai);
2559 return 0;
2560
2561out_free_dev:
2562 iounmap(adapter->regs);
2563 for (i = ai->nports - 1; i >= 0; --i)
2564 if (adapter->port[i])
2565 free_netdev(adapter->port[i]);
2566
2567out_free_adapter:
2568 kfree(adapter);
2569
2570out_disable_device:
2571 pci_disable_device(pdev);
2572out_release_regions:
2573 pci_release_regions(pdev);
2574 pci_set_drvdata(pdev, NULL);
2575 return err;
2576}
2577
2578static void __devexit remove_one(struct pci_dev *pdev)
2579{
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002580 struct adapter *adapter = pci_get_drvdata(pdev);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002581
Divy Le Ray5fbf8162007-08-29 19:15:47 -07002582 if (adapter) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05002583 int i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002584
2585 t3_sge_stop(adapter);
Divy Le Ray0ee8d332007-02-08 16:55:59 -08002586 sysfs_remove_group(&adapter->port[0]->dev.kobj,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002587 &cxgb3_attr_group);
2588
2589 for_each_port(adapter, i)
2590 if (test_bit(i, &adapter->registered_device_map))
2591 unregister_netdev(adapter->port[i]);
2592
2593 if (is_offload(adapter)) {
2594 cxgb3_adapter_unofld(adapter);
2595 if (test_bit(OFFLOAD_DEVMAP_BIT,
2596 &adapter->open_device_map))
2597 offload_close(&adapter->tdev);
2598 }
2599
2600 t3_free_sge_resources(adapter);
2601 cxgb_disable_msi(adapter);
2602
Divy Le Ray4d22de32007-01-18 22:04:14 -05002603 for_each_port(adapter, i)
2604 if (adapter->port[i])
2605 free_netdev(adapter->port[i]);
2606
2607 iounmap(adapter->regs);
2608 kfree(adapter);
2609 pci_release_regions(pdev);
2610 pci_disable_device(pdev);
2611 pci_set_drvdata(pdev, NULL);
2612 }
2613}
2614
2615static struct pci_driver driver = {
2616 .name = DRV_NAME,
2617 .id_table = cxgb3_pci_tbl,
2618 .probe = init_one,
2619 .remove = __devexit_p(remove_one),
2620};
2621
2622static int __init cxgb3_init_module(void)
2623{
2624 int ret;
2625
2626 cxgb3_offload_init();
2627
2628 ret = pci_register_driver(&driver);
2629 return ret;
2630}
2631
2632static void __exit cxgb3_cleanup_module(void)
2633{
2634 pci_unregister_driver(&driver);
2635 if (cxgb3_wq)
2636 destroy_workqueue(cxgb3_wq);
2637}
2638
2639module_init(cxgb3_init_module);
2640module_exit(cxgb3_cleanup_module);