* [PATCH 0/3] myri10ge updates for 2.6.28
@ 2008-09-29 1:30 Brice Goglin
2008-09-29 1:34 ` [PATCH 1/3] myri10ge: add multiqueue TX Brice Goglin
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Brice Goglin @ 2008-09-29 1:30 UTC (permalink / raw)
To: Jeff Garzik, David S. Miller; +Cc: netdev
Hello Jeff and Dave or whoever is not on a trip :)
Here's the multiqueue TX patch for myri10ge again. And it is followed by
2 patches splitting the huge myri10ge.c into pieces (no functional
changes at all there). It's my first time sending a "git rename" patch,
I hope I did well :)
Please apply for 2.6.28.
thanks,
Brice
PS: These patches are against Dave's net-next tree. So, if you get yet
another strange conflict, I'd like to see the actual conflict. I still
don't understand what could have conflicted in the previous submission,
it did apply fine as well here :/
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/3] myri10ge: add multiqueue TX
2008-09-29 1:30 [PATCH 0/3] myri10ge updates for 2.6.28 Brice Goglin
@ 2008-09-29 1:34 ` Brice Goglin
2008-09-29 1:34 ` [PATCH 2/3] myri10ge: rename main file into myri10ge_main.c Brice Goglin
2008-09-29 1:34 ` [PATCH 3/3] myri10ge: split main file into pieces Brice Goglin
2 siblings, 0 replies; 4+ messages in thread
From: Brice Goglin @ 2008-09-29 1:34 UTC (permalink / raw)
To: Jeff Garzik, David S. Miller; +Cc: netdev
Add multiqueue TX support to myri10ge.
Signed-off-by: Brice Goglin <brice@myri.com>
---
drivers/net/myri10ge/myri10ge.c | 155 ++++++++++++++++++++++++++++++---------
1 files changed, 121 insertions(+), 34 deletions(-)
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 005f2aa..d9fcd2c 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -102,6 +102,8 @@ MODULE_LICENSE("Dual BSD/GPL");
#define MYRI10GE_ALLOC_SIZE ((1 << MYRI10GE_ALLOC_ORDER) * PAGE_SIZE)
#define MYRI10GE_MAX_FRAGS_PER_FRAME (MYRI10GE_MAX_ETHER_MTU/MYRI10GE_ALLOC_SIZE + 1)
+#define MYRI10GE_MAX_SLICES 32
+
struct myri10ge_rx_buffer_state {
struct page *page;
int page_offset;
@@ -138,6 +140,8 @@ struct myri10ge_rx_buf {
struct myri10ge_tx_buf {
struct mcp_kreq_ether_send __iomem *lanai; /* lanai ptr for sendq */
+ __be32 __iomem *send_go; /* "go" doorbell ptr */
+ __be32 __iomem *send_stop; /* "stop" doorbell ptr */
struct mcp_kreq_ether_send *req_list; /* host shadow of sendq */
char *req_bytes;
struct myri10ge_tx_buffer_state *info;
@@ -149,6 +153,7 @@ struct myri10ge_tx_buf {
int done ____cacheline_aligned; /* transmit slots completed */
int pkt_done; /* packets completed */
int wake_queue;
+ int queue_active;
};
struct myri10ge_rx_done {
@@ -418,6 +423,12 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
return -ENOSYS;
} else if (result == MXGEFW_CMD_ERROR_UNALIGNED) {
return -E2BIG;
+ } else if (result == MXGEFW_CMD_ERROR_RANGE &&
+ cmd == MXGEFW_CMD_ENABLE_RSS_QUEUES &&
+ (data->
+ data1 & MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES) !=
+ 0) {
+ return -ERANGE;
} else {
dev_err(&mgp->pdev->dev,
"command %d failed, result = %d\n",
@@ -947,9 +958,24 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
*/
cmd.data0 = mgp->num_slices;
- cmd.data1 = 1; /* use MSI-X */
+ cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE;
+ if (mgp->dev->real_num_tx_queues > 1)
+ cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES;
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES,
&cmd, 0);
+
+ /* Firmware older than 1.4.32 only supports multiple
+ * RX queues, so if we get an error, first retry using a
+ * single TX queue before giving up */
+ if (status != 0 && mgp->dev->real_num_tx_queues > 1) {
+ mgp->dev->real_num_tx_queues = 1;
+ cmd.data0 = mgp->num_slices;
+ cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE;
+ status = myri10ge_send_cmd(mgp,
+ MXGEFW_CMD_ENABLE_RSS_QUEUES,
+ &cmd, 0);
+ }
+
if (status != 0) {
dev_err(&mgp->pdev->dev,
"failed to set number of slices\n");
@@ -1317,6 +1343,7 @@ myri10ge_tx_done(struct myri10ge_slice_state *ss, int mcp_index)
{
struct pci_dev *pdev = ss->mgp->pdev;
struct myri10ge_tx_buf *tx = &ss->tx;
+ struct netdev_queue *dev_queue;
struct sk_buff *skb;
int idx, len;
@@ -1350,11 +1377,31 @@ myri10ge_tx_done(struct myri10ge_slice_state *ss, int mcp_index)
PCI_DMA_TODEVICE);
}
}
+
+ dev_queue = netdev_get_tx_queue(ss->dev, ss - ss->mgp->ss);
+ /*
+ * Make a minimal effort to prevent the NIC from polling an
+ * idle tx queue. If we can't get the lock we leave the queue
+ * active. In this case, either a thread was about to start
+ * using the queue anyway, or we lost a race and the NIC will
+ * waste some of its resources polling an inactive queue for a
+ * while.
+ */
+
+ if ((ss->mgp->dev->real_num_tx_queues > 1) &&
+ __netif_tx_trylock(dev_queue)) {
+ if (tx->req == tx->done) {
+ tx->queue_active = 0;
+ put_be32(htonl(1), tx->send_stop);
+ }
+ __netif_tx_unlock(dev_queue);
+ }
+
/* start the queue if we've stopped it */
- if (netif_queue_stopped(ss->dev)
+ if (netif_tx_queue_stopped(dev_queue)
&& tx->req - tx->done < (tx->mask >> 1)) {
tx->wake_queue++;
- netif_wake_queue(ss->dev);
+ netif_tx_wake_queue(dev_queue);
}
}
@@ -1482,9 +1529,9 @@ static irqreturn_t myri10ge_intr(int irq, void *arg)
u32 send_done_count;
int i;
- /* an interrupt on a non-zero slice is implicitly valid
- * since MSI-X irqs are not shared */
- if (ss != mgp->ss) {
+ /* an interrupt on a non-zero receive-only slice is implicitly
+ * valid since MSI-X irqs are not shared */
+ if ((mgp->dev->real_num_tx_queues == 1) && (ss != mgp->ss)) {
netif_rx_schedule(ss->dev, &ss->napi);
return (IRQ_HANDLED);
}
@@ -1526,7 +1573,9 @@ static irqreturn_t myri10ge_intr(int irq, void *arg)
barrier();
}
- myri10ge_check_statblock(mgp);
+ /* Only slice 0 updates stats */
+ if (ss == mgp->ss)
+ myri10ge_check_statblock(mgp);
put_be32(htonl(3), ss->irq_claim + 1);
return (IRQ_HANDLED);
@@ -1884,6 +1933,7 @@ static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss)
/* ensure req_list entries are aligned to 8 bytes */
ss->tx.req_list = (struct mcp_kreq_ether_send *)
ALIGN((unsigned long)ss->tx.req_bytes, 8);
+ ss->tx.queue_active = 0;
bytes = rx_ring_entries * sizeof(*ss->rx_small.shadow);
ss->rx_small.shadow = kzalloc(bytes, GFP_KERNEL);
@@ -2201,11 +2251,14 @@ static int myri10ge_get_txrx(struct myri10ge_priv *mgp, int slice)
int status;
ss = &mgp->ss[slice];
- cmd.data0 = 0; /* single slice for now */
- status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0);
- ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *)
- (mgp->sram + cmd.data0);
-
+ status = 0;
+ if (slice == 0 || (mgp->dev->real_num_tx_queues > 1)) {
+ cmd.data0 = slice;
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET,
+ &cmd, 0);
+ ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *)
+ (mgp->sram + cmd.data0);
+ }
cmd.data0 = slice;
status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET,
&cmd, 0);
@@ -2217,6 +2270,10 @@ static int myri10ge_get_txrx(struct myri10ge_priv *mgp, int slice)
ss->rx_big.lanai = (struct mcp_kreq_ether_recv __iomem *)
(mgp->sram + cmd.data0);
+ ss->tx.send_go = (__iomem __be32 *)
+ (mgp->sram + MXGEFW_ETH_SEND_GO + 64 * slice);
+ ss->tx.send_stop = (__iomem __be32 *)
+ (mgp->sram + MXGEFW_ETH_SEND_STOP + 64 * slice);
return status;
}
@@ -2230,7 +2287,7 @@ static int myri10ge_set_stats(struct myri10ge_priv *mgp, int slice)
ss = &mgp->ss[slice];
cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->fw_stats_bus);
cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->fw_stats_bus);
- cmd.data2 = sizeof(struct mcp_irq_data);
+ cmd.data2 = sizeof(struct mcp_irq_data) | (slice << 16);
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0);
if (status == -ENOSYS) {
dma_addr_t bus = ss->fw_stats_bus;
@@ -2271,7 +2328,9 @@ static int myri10ge_open(struct net_device *dev)
if (mgp->num_slices > 1) {
cmd.data0 = mgp->num_slices;
- cmd.data1 = 1; /* use MSI-X */
+ cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE;
+ if (mgp->dev->real_num_tx_queues > 1)
+ cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES;
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES,
&cmd, 0);
if (status != 0) {
@@ -2292,6 +2351,7 @@ static int myri10ge_open(struct net_device *dev)
printk(KERN_ERR
"myri10ge: %s: failed to setup rss tables\n",
dev->name);
+ goto abort_with_nothing;
}
/* just enable an identity mapping */
@@ -2362,7 +2422,11 @@ static int myri10ge_open(struct net_device *dev)
status = myri10ge_allocate_rings(ss);
if (status != 0)
goto abort_with_rings;
- if (slice == 0)
+
+ /* only firmware which supports multiple TX queues
+ * supports setting up the tx stats on non-zero
+ * slices */
+ if (slice == 0 || mgp->dev->real_num_tx_queues > 1)
status = myri10ge_set_stats(mgp, slice);
if (status) {
printk(KERN_ERR
@@ -2428,7 +2492,8 @@ static int myri10ge_open(struct net_device *dev)
mgp->running = MYRI10GE_ETH_RUNNING;
mgp->watchdog_timer.expires = jiffies + myri10ge_watchdog_timeout * HZ;
add_timer(&mgp->watchdog_timer);
- netif_wake_queue(dev);
+ netif_tx_wake_all_queues(dev);
+
return 0;
abort_with_rings:
@@ -2461,7 +2526,8 @@ static int myri10ge_close(struct net_device *dev)
napi_disable(&mgp->ss[i].napi);
}
netif_carrier_off(dev);
- netif_stop_queue(dev);
+
+ netif_tx_stop_all_queues(dev);
old_down_cnt = mgp->down_cnt;
mb();
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_DOWN, &cmd, 0);
@@ -2566,18 +2632,23 @@ static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev)
struct mcp_kreq_ether_send *req;
struct myri10ge_tx_buf *tx;
struct skb_frag_struct *frag;
+ struct netdev_queue *netdev_queue;
dma_addr_t bus;
u32 low;
__be32 high_swapped;
unsigned int len;
int idx, last_idx, avail, frag_cnt, frag_idx, count, mss, max_segments;
- u16 pseudo_hdr_offset, cksum_offset;
+ u16 pseudo_hdr_offset, cksum_offset, queue;
int cum_len, seglen, boundary, rdma_count;
u8 flags, odd_flag;
- /* always transmit through slot 0 */
- ss = mgp->ss;
+ queue = skb_get_queue_mapping(skb);
+ queue &= (mgp->num_slices - 1);
+
+ ss = &mgp->ss[queue];
+ netdev_queue = netdev_get_tx_queue(mgp->dev, queue);
tx = &ss->tx;
+
again:
req = tx->req_list;
avail = tx->mask - 1 - (tx->req - tx->done);
@@ -2593,7 +2664,7 @@ again:
if ((unlikely(avail < max_segments))) {
/* we are out of transmit resources */
tx->stop_queue++;
- netif_stop_queue(dev);
+ netif_tx_stop_queue(netdev_queue);
return 1;
}
@@ -2786,10 +2857,16 @@ again:
idx = ((count - 1) + tx->req) & tx->mask;
tx->info[idx].last = 1;
myri10ge_submit_req(tx, tx->req_list, count);
+ /* if using multiple tx queues, make sure NIC polls the
+ * current slice */
+ if ((mgp->dev->real_num_tx_queues > 1) && tx->queue_active == 0) {
+ tx->queue_active = 1;
+ put_be32(htonl(1), tx->send_go);
+ }
tx->pkt_start++;
if ((avail - count) < MXGEFW_MAX_SEND_DESC) {
tx->stop_queue++;
- netif_stop_queue(dev);
+ netif_tx_stop_queue(netdev_queue);
}
dev->trans_start = jiffies;
return 0;
@@ -3367,20 +3444,21 @@ static void myri10ge_watchdog(struct work_struct *work)
for (i = 0; i < mgp->num_slices; i++) {
tx = &mgp->ss[i].tx;
printk(KERN_INFO
- "myri10ge: %s: (%d): %d %d %d %d %d\n",
- mgp->dev->name, i, tx->req, tx->done,
- tx->pkt_start, tx->pkt_done,
+ "myri10ge: %s: (%d): %d %d %d %d %d %d\n",
+ mgp->dev->name, i, tx->queue_active, tx->req,
+ tx->done, tx->pkt_start, tx->pkt_done,
(int)ntohl(mgp->ss[i].fw_stats->
send_done_count));
msleep(2000);
printk(KERN_INFO
- "myri10ge: %s: (%d): %d %d %d %d %d\n",
- mgp->dev->name, i, tx->req, tx->done,
- tx->pkt_start, tx->pkt_done,
+ "myri10ge: %s: (%d): %d %d %d %d %d %d\n",
+ mgp->dev->name, i, tx->queue_active, tx->req,
+ tx->done, tx->pkt_start, tx->pkt_done,
(int)ntohl(mgp->ss[i].fw_stats->
send_done_count));
}
}
+
rtnl_lock();
myri10ge_close(mgp->dev);
status = myri10ge_load_firmware(mgp, 1);
@@ -3435,10 +3513,14 @@ static void myri10ge_watchdog_timer(unsigned long arg)
/* nic seems like it might be stuck.. */
if (rx_pause_cnt != mgp->watchdog_pause) {
if (net_ratelimit())
- printk(KERN_WARNING "myri10ge %s:"
+ printk(KERN_WARNING
+ "myri10ge %s slice %d:"
"TX paused, check link partner\n",
- mgp->dev->name);
+ mgp->dev->name, i);
} else {
+ printk(KERN_WARNING
+ "myri10ge %s slice %d stuck:",
+ mgp->dev->name, i);
reset_needed = 1;
}
}
@@ -3624,6 +3706,9 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
mgp->num_slices);
if (status == 0) {
pci_disable_msix(pdev);
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ mgp->features |= NETIF_F_MULTI_QUEUE;
+#endif
return;
}
if (status > 0)
@@ -3653,7 +3738,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
int status = -ENXIO;
int dac_enabled;
- netdev = alloc_etherdev(sizeof(*mgp));
+ netdev = alloc_etherdev_mq(sizeof(*mgp), MYRI10GE_MAX_SLICES);
if (netdev == NULL) {
dev_err(dev, "Could not allocate ethernet device\n");
return -ENOMEM;
@@ -3758,7 +3843,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_err(&pdev->dev, "failed to alloc slice state\n");
goto abort_with_firmware;
}
-
+ netdev->real_num_tx_queues = mgp->num_slices;
status = myri10ge_reset(mgp);
if (status != 0) {
dev_err(&pdev->dev, "failed reset\n");
@@ -3782,6 +3867,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->set_multicast_list = myri10ge_set_multicast_list;
netdev->set_mac_address = myri10ge_set_mac_address;
netdev->features = mgp->features;
+
if (dac_enabled)
netdev->features |= NETIF_F_HIGHDMA;
@@ -3937,8 +4023,7 @@ static __init int myri10ge_init_module(void)
printk(KERN_INFO "%s: Version %s\n", myri10ge_driver.name,
MYRI10GE_VERSION_STR);
- if (myri10ge_rss_hash > MXGEFW_RSS_HASH_TYPE_SRC_PORT ||
- myri10ge_rss_hash < MXGEFW_RSS_HASH_TYPE_IPV4) {
+ if (myri10ge_rss_hash > MXGEFW_RSS_HASH_TYPE_MAX) {
printk(KERN_ERR
"%s: Illegal rssh hash type %d, defaulting to source port\n",
myri10ge_driver.name, myri10ge_rss_hash);
@@ -3947,6 +4032,8 @@ static __init int myri10ge_init_module(void)
#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
dca_register_notify(&myri10ge_dca_notifier);
#endif
+ if (myri10ge_max_slices > MYRI10GE_MAX_SLICES)
+ myri10ge_max_slices = MYRI10GE_MAX_SLICES;
return pci_register_driver(&myri10ge_driver);
}
--
1.5.6.5
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/3] myri10ge: rename main file into myri10ge_main.c
2008-09-29 1:30 [PATCH 0/3] myri10ge updates for 2.6.28 Brice Goglin
2008-09-29 1:34 ` [PATCH 1/3] myri10ge: add multiqueue TX Brice Goglin
@ 2008-09-29 1:34 ` Brice Goglin
2008-09-29 1:34 ` [PATCH 3/3] myri10ge: split main file into pieces Brice Goglin
2 siblings, 0 replies; 4+ messages in thread
From: Brice Goglin @ 2008-09-29 1:34 UTC (permalink / raw)
To: Jeff Garzik, David S. Miller; +Cc: netdev
To prepare myri10ge.c split into multiple files, rename
it to myri10ge_main.c first.
Signed-off-by: Brice Goglin <brice@myri.com>
---
drivers/net/myri10ge/Makefile | 2 ++
.../net/myri10ge/{myri10ge.c => myri10ge_main.c} | 0
2 files changed, 2 insertions(+), 0 deletions(-)
rename drivers/net/myri10ge/{myri10ge.c => myri10ge_main.c} (100%)
diff --git a/drivers/net/myri10ge/Makefile b/drivers/net/myri10ge/Makefile
index 5df8916..597440c 100644
--- a/drivers/net/myri10ge/Makefile
+++ b/drivers/net/myri10ge/Makefile
@@ -3,3 +3,5 @@
#
obj-$(CONFIG_MYRI10GE) += myri10ge.o
+
+myri10ge-objs := myri10ge_main.o
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge_main.c
similarity index 100%
rename from drivers/net/myri10ge/myri10ge.c
rename to drivers/net/myri10ge/myri10ge_main.c
--
1.5.6.5
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 3/3] myri10ge: split main file into pieces
2008-09-29 1:30 [PATCH 0/3] myri10ge updates for 2.6.28 Brice Goglin
2008-09-29 1:34 ` [PATCH 1/3] myri10ge: add multiqueue TX Brice Goglin
2008-09-29 1:34 ` [PATCH 2/3] myri10ge: rename main file into myri10ge_main.c Brice Goglin
@ 2008-09-29 1:34 ` Brice Goglin
2 siblings, 0 replies; 4+ messages in thread
From: Brice Goglin @ 2008-09-29 1:34 UTC (permalink / raw)
To: Jeff Garzik, David S. Miller; +Cc: netdev
Move ethtool-related functions to myri10ge_ethtool.c.
Move firmware-probing/selecting/loading routines to myri10ge_firmware.c.
Move types and defines to myri10ge.h, and add some prototypes.
Signed-off-by: Brice Goglin <brice@myri.com>
---
drivers/net/myri10ge/Makefile | 2 +-
drivers/net/myri10ge/myri10ge.h | 244 ++++++++++
drivers/net/myri10ge/myri10ge_ethtool.c | 362 ++++++++++++++
drivers/net/myri10ge/myri10ge_firmware.c | 309 ++++++++++++
drivers/net/myri10ge/myri10ge_main.c | 779 +-----------------------------
5 files changed, 926 insertions(+), 770 deletions(-)
create mode 100644 drivers/net/myri10ge/myri10ge.h
create mode 100644 drivers/net/myri10ge/myri10ge_ethtool.c
create mode 100644 drivers/net/myri10ge/myri10ge_firmware.c
diff --git a/drivers/net/myri10ge/Makefile b/drivers/net/myri10ge/Makefile
index 597440c..98bf3bf 100644
--- a/drivers/net/myri10ge/Makefile
+++ b/drivers/net/myri10ge/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_MYRI10GE) += myri10ge.o
-myri10ge-objs := myri10ge_main.o
+myri10ge-objs := myri10ge_main.o myri10ge_firmware.o myri10ge_ethtool.o
diff --git a/drivers/net/myri10ge/myri10ge.h b/drivers/net/myri10ge/myri10ge.h
new file mode 100644
index 0000000..a10e01a
--- /dev/null
+++ b/drivers/net/myri10ge/myri10ge.h
@@ -0,0 +1,244 @@
+/*************************************************************************
+ * myri10ge.c: Myricom Myri-10G Ethernet driver.
+ *
+ * Copyright (C) 2005 - 2007 Myricom, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Myricom, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * If the eeprom on your board is not recent enough, you will need to get a
+ * newer firmware image at:
+ * http://www.myri.com/scs/download-Myri10GE.html
+ *
+ * Contact Information:
+ * <help@myri.com>
+ * Myricom, Inc., 325N Santa Anita Avenue, Arcadia, CA 91006
+ *************************************************************************/
+
+#ifndef __MYRI10GE_H__
+#define __MYRI10GE_H__
+
+#define MYRI10GE_MAX_ETHER_MTU 9014
+
+#define MYRI10GE_ETH_STOPPED 0
+#define MYRI10GE_ETH_STOPPING 1
+#define MYRI10GE_ETH_STARTING 2
+#define MYRI10GE_ETH_RUNNING 3
+#define MYRI10GE_ETH_OPEN_FAILED 4
+
+#define MYRI10GE_EEPROM_STRINGS_SIZE 256
+#define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2)
+#define MYRI10GE_MAX_LRO_DESCRIPTORS 8
+#define MYRI10GE_LRO_MAX_PKTS 64
+
+#define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff)
+#define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff
+
+#define MYRI10GE_ALLOC_ORDER 0
+#define MYRI10GE_ALLOC_SIZE ((1 << MYRI10GE_ALLOC_ORDER) * PAGE_SIZE)
+#define MYRI10GE_MAX_FRAGS_PER_FRAME (MYRI10GE_MAX_ETHER_MTU/MYRI10GE_ALLOC_SIZE + 1)
+
+#define MYRI10GE_MAX_SLICES 32
+
+struct myri10ge_rx_buffer_state {
+ struct page *page;
+ int page_offset;
+ DECLARE_PCI_UNMAP_ADDR(bus)
+ DECLARE_PCI_UNMAP_LEN(len)
+};
+
+struct myri10ge_tx_buffer_state {
+ struct sk_buff *skb;
+ int last;
+ DECLARE_PCI_UNMAP_ADDR(bus)
+ DECLARE_PCI_UNMAP_LEN(len)
+};
+
+struct myri10ge_cmd {
+ u32 data0;
+ u32 data1;
+ u32 data2;
+};
+
+struct myri10ge_rx_buf {
+ struct mcp_kreq_ether_recv __iomem *lanai; /* lanai ptr for recv ring */
+ struct mcp_kreq_ether_recv *shadow; /* host shadow of recv ring */
+ struct myri10ge_rx_buffer_state *info;
+ struct page *page;
+ dma_addr_t bus;
+ int page_offset;
+ int cnt;
+ int fill_cnt;
+ int alloc_fail;
+ int mask; /* number of rx slots -1 */
+ int watchdog_needed;
+};
+
+struct myri10ge_tx_buf {
+ struct mcp_kreq_ether_send __iomem *lanai; /* lanai ptr for sendq */
+ __be32 __iomem *send_go; /* "go" doorbell ptr */
+ __be32 __iomem *send_stop; /* "stop" doorbell ptr */
+ struct mcp_kreq_ether_send *req_list; /* host shadow of sendq */
+ char *req_bytes;
+ struct myri10ge_tx_buffer_state *info;
+ int mask; /* number of transmit slots -1 */
+ int req ____cacheline_aligned; /* transmit slots submitted */
+ int pkt_start; /* packets started */
+ int stop_queue;
+ int linearized;
+ int done ____cacheline_aligned; /* transmit slots completed */
+ int pkt_done; /* packets completed */
+ int wake_queue;
+ int queue_active;
+};
+
+struct myri10ge_rx_done {
+ struct mcp_slot *entry;
+ dma_addr_t bus;
+ int cnt;
+ int idx;
+ struct net_lro_mgr lro_mgr;
+ struct net_lro_desc lro_desc[MYRI10GE_MAX_LRO_DESCRIPTORS];
+};
+
+struct myri10ge_slice_netstats {
+ unsigned long rx_packets;
+ unsigned long tx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_bytes;
+ unsigned long rx_dropped;
+ unsigned long tx_dropped;
+};
+
+struct myri10ge_slice_state {
+ struct myri10ge_tx_buf tx; /* transmit ring */
+ struct myri10ge_rx_buf rx_small;
+ struct myri10ge_rx_buf rx_big;
+ struct myri10ge_rx_done rx_done;
+ struct net_device *dev;
+ struct napi_struct napi;
+ struct myri10ge_priv *mgp;
+ struct myri10ge_slice_netstats stats;
+ __be32 __iomem *irq_claim;
+ struct mcp_irq_data *fw_stats;
+ dma_addr_t fw_stats_bus;
+ int watchdog_tx_done;
+ int watchdog_tx_req;
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
+ int cached_dca_tag;
+ int cpu;
+ __be32 __iomem *dca_tag;
+#endif
+ char irq_desc[32];
+};
+
+struct myri10ge_priv {
+ struct myri10ge_slice_state *ss;
+ int tx_boundary; /* boundary transmits cannot cross */
+ int num_slices;
+ int running; /* running? */
+ int csum_flag; /* rx_csums? */
+ int small_bytes;
+ int big_bytes;
+ int max_intr_slots;
+ struct net_device *dev;
+ struct net_device_stats stats;
+ spinlock_t stats_lock;
+ u8 __iomem *sram;
+ int sram_size;
+ unsigned long board_span;
+ unsigned long iomem_base;
+ __be32 __iomem *irq_deassert;
+ char *mac_addr_string;
+ struct mcp_cmd_response *cmd;
+ dma_addr_t cmd_bus;
+ struct pci_dev *pdev;
+ int msi_enabled;
+ int msix_enabled;
+ struct msix_entry *msix_vectors;
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
+ int dca_enabled;
+#endif
+ u32 link_state;
+ unsigned int rdma_tags_available;
+ int intr_coal_delay;
+ __be32 __iomem *intr_coal_delay_ptr;
+ int mtrr;
+ int wc_enabled;
+ int down_cnt;
+ wait_queue_head_t down_wq;
+ struct work_struct watchdog_work;
+ struct timer_list watchdog_timer;
+ int watchdog_resets;
+ int watchdog_pause;
+ int pause;
+ char *fw_name;
+ char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE];
+ char *product_code_string;
+ char fw_version[128];
+ int fw_ver_major;
+ int fw_ver_minor;
+ int fw_ver_tiny;
+ int adopted_rx_filter_bug;
+ u8 mac_addr[6]; /* eeprom mac address */
+ unsigned long serial_number;
+ int vendor_specific_offset;
+ int fw_multicast_support;
+ unsigned long features;
+ u32 max_tso6;
+ u32 read_dma;
+ u32 write_dma;
+ u32 read_write_dma;
+ u32 link_changes;
+ u32 msg_enable;
+};
+
+extern char *myri10ge_fw_unaligned;
+extern char *myri10ge_fw_aligned;
+extern char *myri10ge_fw_rss_unaligned;
+extern char *myri10ge_fw_rss_aligned;
+extern char *myri10ge_fw_name;
+extern const struct ethtool_ops myri10ge_ethtool_ops;
+extern int myri10ge_tso6;
+
+int myri10ge_load_firmware(struct myri10ge_priv *mgp, int adopt);
+int myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
+ struct myri10ge_cmd *data, int atomic);
+void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable);
+int myri10ge_change_pause(struct myri10ge_priv *mgp, int pause);
+
+#define MYRI10GE_FW_OFFSET 1024*1024
+#define MYRI10GE_HIGHPART_TO_U32(X) \
+(sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0)
+#define MYRI10GE_LOWPART_TO_U32(X) ((u32)(X))
+
+#define put_be32(val, p) __raw_writel((__force __u32)(val), (__force void __iomem *)(p))
+
+#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)
+
+#define MYRI10GE_VERSION_STR "1.4.3-1.366"
+
+#endif /* __MYRI10GE_H__ */
diff --git a/drivers/net/myri10ge/myri10ge_ethtool.c b/drivers/net/myri10ge/myri10ge_ethtool.c
new file mode 100644
index 0000000..d095a8c
--- /dev/null
+++ b/drivers/net/myri10ge/myri10ge_ethtool.c
@@ -0,0 +1,362 @@
+/*************************************************************************
+ * myri10ge.c: Myricom Myri-10G Ethernet driver.
+ *
+ * Copyright (C) 2005 - 2008 Myricom, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Myricom, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * If the eeprom on your board is not recent enough, you will need to get a
+ * newer firmware image at:
+ * http://www.myri.com/scs/download-Myri10GE.html
+ *
+ * Contact Information:
+ * <help@myri.com>
+ * Myricom, Inc., 325N Santa Anita Avenue, Arcadia, CA 91006
+ *************************************************************************/
+
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/inet_lro.h>
+#include <linux/dca.h>
+#include <linux/ethtool.h>
+#include <linux/firmware.h>
+#include "myri10ge_mcp.h"
+#include "myri10ge.h"
+
+static int
+myri10ge_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ char *ptr;
+ int i;
+
+ cmd->autoneg = AUTONEG_DISABLE;
+ cmd->speed = SPEED_10000;
+ cmd->duplex = DUPLEX_FULL;
+
+ /*
+ * parse the product code to deterimine the interface type
+ * (CX4, XFP, Quad Ribbon Fiber) by looking at the character
+ * after the 3rd dash in the driver's cached copy of the
+ * EEPROM's product code string.
+ */
+ ptr = mgp->product_code_string;
+ if (ptr == NULL) {
+ printk(KERN_ERR "myri10ge: %s: Missing product code\n",
+ netdev->name);
+ return 0;
+ }
+ for (i = 0; i < 3; i++, ptr++) {
+ ptr = strchr(ptr, '-');
+ if (ptr == NULL) {
+ printk(KERN_ERR "myri10ge: %s: Invalid product "
+ "code %s\n", netdev->name,
+ mgp->product_code_string);
+ return 0;
+ }
+ }
+ if (*ptr == 'R' || *ptr == 'Q') {
+ /* We've found either an XFP or quad ribbon fiber */
+ cmd->port = PORT_FIBRE;
+ }
+ return 0;
+}
+
+static void
+myri10ge_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ strlcpy(info->driver, "myri10ge", sizeof(info->driver));
+ strlcpy(info->version, MYRI10GE_VERSION_STR, sizeof(info->version));
+ strlcpy(info->fw_version, mgp->fw_version, sizeof(info->fw_version));
+ strlcpy(info->bus_info, pci_name(mgp->pdev), sizeof(info->bus_info));
+}
+
+static int
+myri10ge_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coal)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ coal->rx_coalesce_usecs = mgp->intr_coal_delay;
+ return 0;
+}
+
+static int
+myri10ge_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coal)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ mgp->intr_coal_delay = coal->rx_coalesce_usecs;
+ put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr);
+ return 0;
+}
+
+static void
+myri10ge_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ pause->autoneg = 0;
+ pause->rx_pause = mgp->pause;
+ pause->tx_pause = mgp->pause;
+}
+
+static int
+myri10ge_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ if (pause->tx_pause != mgp->pause)
+ return myri10ge_change_pause(mgp, pause->tx_pause);
+ if (pause->rx_pause != mgp->pause)
+ return myri10ge_change_pause(mgp, pause->tx_pause);
+ if (pause->autoneg != 0)
+ return -EINVAL;
+ return 0;
+}
+
+static void
+myri10ge_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ ring->rx_mini_max_pending = mgp->ss[0].rx_small.mask + 1;
+ ring->rx_max_pending = mgp->ss[0].rx_big.mask + 1;
+ ring->rx_jumbo_max_pending = 0;
+ ring->tx_max_pending = mgp->ss[0].rx_small.mask + 1;
+ ring->rx_mini_pending = ring->rx_mini_max_pending;
+ ring->rx_pending = ring->rx_max_pending;
+ ring->rx_jumbo_pending = ring->rx_jumbo_max_pending;
+ ring->tx_pending = ring->tx_max_pending;
+}
+
+static u32 myri10ge_get_rx_csum(struct net_device *netdev)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ if (mgp->csum_flag)
+ return 1;
+ else
+ return 0;
+}
+
+static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ if (csum_enabled)
+ mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
+ else
+ mgp->csum_flag = 0;
+ return 0;
+}
+
+static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ unsigned long flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO);
+
+ if (tso_enabled)
+ netdev->features |= flags;
+ else
+ netdev->features &= ~flags;
+ return 0;
+}
+
+static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = {
+ "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
+ "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
+ "rx_length_errors", "rx_over_errors", "rx_crc_errors",
+ "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
+ "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
+ "tx_heartbeat_errors", "tx_window_errors",
+ /* device-specific stats */
+ "tx_boundary", "WC", "irq", "MSI", "MSIX",
+ "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
+ "serial_number", "watchdog_resets",
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
+ "dca_capable_firmware", "dca_device_present",
+#endif
+ "link_changes", "link_up", "dropped_link_overflow",
+ "dropped_link_error_or_filtered",
+ "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32",
+ "dropped_unicast_filtered", "dropped_multicast_filtered",
+ "dropped_runt", "dropped_overrun", "dropped_no_small_buffer",
+ "dropped_no_big_buffer"
+};
+
+static const char myri10ge_gstrings_slice_stats[][ETH_GSTRING_LEN] = {
+ "----------- slice ---------",
+ "tx_pkt_start", "tx_pkt_done", "tx_req", "tx_done",
+ "rx_small_cnt", "rx_big_cnt",
+ "wake_queue", "stop_queue", "tx_linearized", "LRO aggregated",
+ "LRO flushed",
+ "LRO avg aggr", "LRO no_desc"
+};
+
+#define MYRI10GE_NET_STATS_LEN 21
+#define MYRI10GE_MAIN_STATS_LEN ARRAY_SIZE(myri10ge_gstrings_main_stats)
+#define MYRI10GE_SLICE_STATS_LEN ARRAY_SIZE(myri10ge_gstrings_slice_stats)
+
+static void
+myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ memcpy(data, *myri10ge_gstrings_main_stats,
+ sizeof(myri10ge_gstrings_main_stats));
+ data += sizeof(myri10ge_gstrings_main_stats);
+ for (i = 0; i < mgp->num_slices; i++) {
+ memcpy(data, *myri10ge_gstrings_slice_stats,
+ sizeof(myri10ge_gstrings_slice_stats));
+ data += sizeof(myri10ge_gstrings_slice_stats);
+ }
+ break;
+ }
+}
+
+static int myri10ge_get_sset_count(struct net_device *netdev, int sset)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ switch (sset) {
+ case ETH_SS_STATS:
+ return MYRI10GE_MAIN_STATS_LEN +
+ mgp->num_slices * MYRI10GE_SLICE_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void
+myri10ge_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 * data)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ struct myri10ge_slice_state *ss;
+ int slice;
+ int i;
+
+ for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
+ data[i] = ((unsigned long *)&mgp->stats)[i];
+
+ data[i++] = (unsigned int)mgp->tx_boundary;
+ data[i++] = (unsigned int)mgp->wc_enabled;
+ data[i++] = (unsigned int)mgp->pdev->irq;
+ data[i++] = (unsigned int)mgp->msi_enabled;
+ data[i++] = (unsigned int)mgp->msix_enabled;
+ data[i++] = (unsigned int)mgp->read_dma;
+ data[i++] = (unsigned int)mgp->write_dma;
+ data[i++] = (unsigned int)mgp->read_write_dma;
+ data[i++] = (unsigned int)mgp->serial_number;
+ data[i++] = (unsigned int)mgp->watchdog_resets;
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
+ data[i++] = (unsigned int)(mgp->ss[0].dca_tag != NULL);
+ data[i++] = (unsigned int)(mgp->dca_enabled);
+#endif
+ data[i++] = (unsigned int)mgp->link_changes;
+
+ /* firmware stats are useful only in the first slice */
+ ss = &mgp->ss[0];
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->link_up);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_link_overflow);
+ data[i++] =
+ (unsigned int)ntohl(ss->fw_stats->dropped_link_error_or_filtered);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_pause);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_bad_phy);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_bad_crc32);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_unicast_filtered);
+ data[i++] =
+ (unsigned int)ntohl(ss->fw_stats->dropped_multicast_filtered);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_runt);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_overrun);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_small_buffer);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_big_buffer);
+
+ for (slice = 0; slice < mgp->num_slices; slice++) {
+ ss = &mgp->ss[slice];
+ data[i++] = slice;
+ data[i++] = (unsigned int)ss->tx.pkt_start;
+ data[i++] = (unsigned int)ss->tx.pkt_done;
+ data[i++] = (unsigned int)ss->tx.req;
+ data[i++] = (unsigned int)ss->tx.done;
+ data[i++] = (unsigned int)ss->rx_small.cnt;
+ data[i++] = (unsigned int)ss->rx_big.cnt;
+ data[i++] = (unsigned int)ss->tx.wake_queue;
+ data[i++] = (unsigned int)ss->tx.stop_queue;
+ data[i++] = (unsigned int)ss->tx.linearized;
+ data[i++] = ss->rx_done.lro_mgr.stats.aggregated;
+ data[i++] = ss->rx_done.lro_mgr.stats.flushed;
+ if (ss->rx_done.lro_mgr.stats.flushed)
+ data[i++] = ss->rx_done.lro_mgr.stats.aggregated /
+ ss->rx_done.lro_mgr.stats.flushed;
+ else
+ data[i++] = 0;
+ data[i++] = ss->rx_done.lro_mgr.stats.no_desc;
+ }
+}
+
+static void myri10ge_set_msglevel(struct net_device *netdev, u32 value)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ mgp->msg_enable = value;
+}
+
+static u32 myri10ge_get_msglevel(struct net_device *netdev)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ return mgp->msg_enable;
+}
+
+const struct ethtool_ops myri10ge_ethtool_ops = {
+ .get_settings = myri10ge_get_settings,
+ .get_drvinfo = myri10ge_get_drvinfo,
+ .get_coalesce = myri10ge_get_coalesce,
+ .set_coalesce = myri10ge_set_coalesce,
+ .get_pauseparam = myri10ge_get_pauseparam,
+ .set_pauseparam = myri10ge_set_pauseparam,
+ .get_ringparam = myri10ge_get_ringparam,
+ .get_rx_csum = myri10ge_get_rx_csum,
+ .set_rx_csum = myri10ge_set_rx_csum,
+ .set_tx_csum = ethtool_op_set_tx_hw_csum,
+ .set_sg = ethtool_op_set_sg,
+ .set_tso = myri10ge_set_tso,
+ .get_link = ethtool_op_get_link,
+ .get_strings = myri10ge_get_strings,
+ .get_sset_count = myri10ge_get_sset_count,
+ .get_ethtool_stats = myri10ge_get_ethtool_stats,
+ .set_msglevel = myri10ge_set_msglevel,
+ .get_msglevel = myri10ge_get_msglevel
+};
diff --git a/drivers/net/myri10ge/myri10ge_firmware.c b/drivers/net/myri10ge/myri10ge_firmware.c
new file mode 100644
index 0000000..542fba0
--- /dev/null
+++ b/drivers/net/myri10ge/myri10ge_firmware.c
@@ -0,0 +1,309 @@
+/*************************************************************************
+ * myri10ge.c: Myricom Myri-10G Ethernet driver.
+ *
+ * Copyright (C) 2005 - 2008 Myricom, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Myricom, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * If the eeprom on your board is not recent enough, you will need to get a
+ * newer firmware image at:
+ * http://www.myri.com/scs/download-Myri10GE.html
+ *
+ * Contact Information:
+ * <help@myri.com>
+ * Myricom, Inc., 325N Santa Anita Avenue, Arcadia, CA 91006
+ *************************************************************************/
+
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/inet_lro.h>
+#include <linux/dca.h>
+#include <linux/io.h>
+#include <linux/ethtool.h>
+#include <linux/crc32.h>
+#include <linux/firmware.h>
+#include "myri10ge_mcp.h"
+#include "myri10ge_mcp_gen_header.h"
+#include "myri10ge.h"
+
+static int
+myri10ge_validate_firmware(struct myri10ge_priv *mgp,
+ struct mcp_gen_header *hdr)
+{
+ struct device *dev = &mgp->pdev->dev;
+
+ /* check firmware type */
+ if (ntohl(hdr->mcp_type) != MCP_TYPE_ETH) {
+ dev_err(dev, "Bad firmware type: 0x%x\n", ntohl(hdr->mcp_type));
+ return -EINVAL;
+ }
+
+ /* save firmware version for ethtool */
+ strncpy(mgp->fw_version, hdr->version, sizeof(mgp->fw_version));
+
+ sscanf(mgp->fw_version, "%d.%d.%d", &mgp->fw_ver_major,
+ &mgp->fw_ver_minor, &mgp->fw_ver_tiny);
+
+ if (!(mgp->fw_ver_major == MXGEFW_VERSION_MAJOR
+ && mgp->fw_ver_minor == MXGEFW_VERSION_MINOR)) {
+ dev_err(dev, "Found firmware version %s\n", mgp->fw_version);
+ dev_err(dev, "Driver needs %d.%d\n", MXGEFW_VERSION_MAJOR,
+ MXGEFW_VERSION_MINOR);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int myri10ge_load_hotplug_firmware(struct myri10ge_priv *mgp, u32 * size)
+{
+ unsigned crc, reread_crc;
+ const struct firmware *fw;
+ struct device *dev = &mgp->pdev->dev;
+ unsigned char *fw_readback;
+ struct mcp_gen_header *hdr;
+ size_t hdr_offset;
+ int status;
+ unsigned i;
+
+ if ((status = request_firmware(&fw, mgp->fw_name, dev)) < 0) {
+ dev_err(dev, "Unable to load %s firmware image via hotplug\n",
+ mgp->fw_name);
+ status = -EINVAL;
+ goto abort_with_nothing;
+ }
+
+ /* check size */
+
+ if (fw->size >= mgp->sram_size - MYRI10GE_FW_OFFSET ||
+ fw->size < MCP_HEADER_PTR_OFFSET + 4) {
+ dev_err(dev, "Firmware size invalid:%d\n", (int)fw->size);
+ status = -EINVAL;
+ goto abort_with_fw;
+ }
+
+ /* check id */
+ hdr_offset = ntohl(*(__be32 *) (fw->data + MCP_HEADER_PTR_OFFSET));
+ if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw->size) {
+ dev_err(dev, "Bad firmware file\n");
+ status = -EINVAL;
+ goto abort_with_fw;
+ }
+ hdr = (void *)(fw->data + hdr_offset);
+
+ status = myri10ge_validate_firmware(mgp, hdr);
+ if (status != 0)
+ goto abort_with_fw;
+
+ crc = crc32(~0, fw->data, fw->size);
+ for (i = 0; i < fw->size; i += 256) {
+ myri10ge_pio_copy(mgp->sram + MYRI10GE_FW_OFFSET + i,
+ (__force u8 *) fw->data + i,
+ min(256U, (unsigned)(fw->size - i)));
+ mb();
+ readb(mgp->sram);
+ }
+ fw_readback = vmalloc(fw->size);
+ if (!fw_readback) {
+ status = -ENOMEM;
+ goto abort_with_fw;
+ }
+ /* corruption checking is good for parity recovery and buggy chipset */
+ memcpy_fromio(fw_readback, mgp->sram + MYRI10GE_FW_OFFSET, fw->size);
+ reread_crc = crc32(~0, fw_readback, fw->size);
+ vfree(fw_readback);
+ if (crc != reread_crc) {
+ dev_err(dev, "CRC failed(fw-len=%u), got 0x%x (expect 0x%x)\n",
+ (unsigned)fw->size, reread_crc, crc);
+ status = -EIO;
+ goto abort_with_fw;
+ }
+ *size = (u32) fw->size;
+
+abort_with_fw:
+ release_firmware(fw);
+
+abort_with_nothing:
+ return status;
+}
+
+static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp)
+{
+ struct mcp_gen_header *hdr;
+ struct device *dev = &mgp->pdev->dev;
+ const size_t bytes = sizeof(struct mcp_gen_header);
+ size_t hdr_offset;
+ int status;
+
+ /* find running firmware header */
+ hdr_offset = swab32(readl(mgp->sram + MCP_HEADER_PTR_OFFSET));
+
+ if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > mgp->sram_size) {
+ dev_err(dev, "Running firmware has bad header offset (%d)\n",
+ (int)hdr_offset);
+ return -EIO;
+ }
+
+ /* copy header of running firmware from SRAM to host memory to
+ * validate firmware */
+ hdr = kmalloc(bytes, GFP_KERNEL);
+ if (hdr == NULL) {
+ dev_err(dev, "could not malloc firmware hdr\n");
+ return -ENOMEM;
+ }
+ memcpy_fromio(hdr, mgp->sram + hdr_offset, bytes);
+ status = myri10ge_validate_firmware(mgp, hdr);
+ kfree(hdr);
+
+ /* check to see if adopted firmware has bug where adopting
+ * it will cause broadcasts to be filtered unless the NIC
+ * is kept in ALLMULTI mode */
+ if (mgp->fw_ver_major == 1 && mgp->fw_ver_minor == 4 &&
+ mgp->fw_ver_tiny >= 4 && mgp->fw_ver_tiny <= 11) {
+ mgp->adopted_rx_filter_bug = 1;
+ dev_warn(dev, "Adopting fw %d.%d.%d: "
+ "working around rx filter bug\n",
+ mgp->fw_ver_major, mgp->fw_ver_minor,
+ mgp->fw_ver_tiny);
+ }
+ return status;
+}
+
+static int myri10ge_get_firmware_capabilities(struct myri10ge_priv *mgp)
+{
+ struct myri10ge_cmd cmd;
+ int status;
+
+ /* probe for IPv6 TSO support */
+ mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
+ &cmd, 0);
+ if (status == 0) {
+ mgp->max_tso6 = cmd.data0;
+ mgp->features |= NETIF_F_TSO6;
+ }
+
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0);
+ if (status != 0) {
+ dev_err(&mgp->pdev->dev,
+ "failed MXGEFW_CMD_GET_RX_RING_SIZE\n");
+ return -ENXIO;
+ }
+
+ mgp->max_intr_slots = 2 * (cmd.data0 / sizeof(struct mcp_dma_addr));
+
+ return 0;
+}
+
+int myri10ge_load_firmware(struct myri10ge_priv *mgp, int adopt)
+{
+ char __iomem *submit;
+ __be32 buf[16] __attribute__ ((__aligned__(8)));
+ u32 dma_low, dma_high, size;
+ int status, i;
+
+ size = 0;
+ status = myri10ge_load_hotplug_firmware(mgp, &size);
+ if (status) {
+ if (!adopt)
+ return status;
+ dev_warn(&mgp->pdev->dev, "hotplug firmware loading failed\n");
+
+ /* Do not attempt to adopt firmware if there
+ * was a bad crc */
+ if (status == -EIO)
+ return status;
+
+ status = myri10ge_adopt_running_firmware(mgp);
+ if (status != 0) {
+ dev_err(&mgp->pdev->dev,
+ "failed to adopt running firmware\n");
+ return status;
+ }
+ dev_info(&mgp->pdev->dev,
+ "Successfully adopted running firmware\n");
+ if (mgp->tx_boundary == 4096) {
+ dev_warn(&mgp->pdev->dev,
+ "Using firmware currently running on NIC"
+ ". For optimal\n");
+ dev_warn(&mgp->pdev->dev,
+ "performance consider loading optimized "
+ "firmware\n");
+ dev_warn(&mgp->pdev->dev, "via hotplug\n");
+ }
+
+ mgp->fw_name = "adopted";
+ mgp->tx_boundary = 2048;
+ myri10ge_dummy_rdma(mgp, 1);
+ status = myri10ge_get_firmware_capabilities(mgp);
+ return status;
+ }
+
+ /* clear confirmation addr */
+ mgp->cmd->data = 0;
+ mb();
+
+ /* send a reload command to the bootstrap MCP, and wait for the
+ * response in the confirmation address. The firmware should
+ * write a -1 there to indicate it is alive and well
+ */
+ dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus);
+ dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus);
+
+ buf[0] = htonl(dma_high); /* confirm addr MSW */
+ buf[1] = htonl(dma_low); /* confirm addr LSW */
+ buf[2] = MYRI10GE_NO_CONFIRM_DATA; /* confirm data */
+
+ /* FIX: All newest firmware should un-protect the bottom of
+ * the sram before handoff. However, the very first interfaces
+ * do not. Therefore the handoff copy must skip the first 8 bytes
+ */
+ buf[3] = htonl(MYRI10GE_FW_OFFSET + 8); /* where the code starts */
+ buf[4] = htonl(size - 8); /* length of code */
+ buf[5] = htonl(8); /* where to copy to */
+ buf[6] = htonl(0); /* where to jump to */
+
+ submit = mgp->sram + MXGEFW_BOOT_HANDOFF;
+
+ myri10ge_pio_copy(submit, &buf, sizeof(buf));
+ mb();
+ msleep(1);
+ mb();
+ i = 0;
+ while (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 9) {
+ msleep(1 << i);
+ i++;
+ }
+ if (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA) {
+ dev_err(&mgp->pdev->dev, "handoff failed\n");
+ return -ENXIO;
+ }
+ myri10ge_dummy_rdma(mgp, 1);
+ status = myri10ge_get_firmware_capabilities(mgp);
+
+ return status;
+}
diff --git a/drivers/net/myri10ge/myri10ge_main.c b/drivers/net/myri10ge/myri10ge_main.c
index d9fcd2c..2f72db2 100644
--- a/drivers/net/myri10ge/myri10ge_main.c
+++ b/drivers/net/myri10ge/myri10ge_main.c
@@ -1,7 +1,7 @@
/*************************************************************************
* myri10ge.c: Myricom Myri-10G Ethernet driver.
*
- * Copyright (C) 2005 - 2007 Myricom, Inc.
+ * Copyright (C) 2005 - 2008 Myricom, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,7 +54,6 @@
#include <linux/inet.h>
#include <linux/in.h>
#include <linux/ethtool.h>
-#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/vmalloc.h>
@@ -74,195 +73,19 @@
#include "myri10ge_mcp.h"
#include "myri10ge_mcp_gen_header.h"
-
-#define MYRI10GE_VERSION_STR "1.4.3-1.358"
+#include "myri10ge.h"
MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
MODULE_AUTHOR("Maintainer: help@myri.com");
MODULE_VERSION(MYRI10GE_VERSION_STR);
MODULE_LICENSE("Dual BSD/GPL");
-#define MYRI10GE_MAX_ETHER_MTU 9014
-
-#define MYRI10GE_ETH_STOPPED 0
-#define MYRI10GE_ETH_STOPPING 1
-#define MYRI10GE_ETH_STARTING 2
-#define MYRI10GE_ETH_RUNNING 3
-#define MYRI10GE_ETH_OPEN_FAILED 4
-
-#define MYRI10GE_EEPROM_STRINGS_SIZE 256
-#define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2)
-#define MYRI10GE_MAX_LRO_DESCRIPTORS 8
-#define MYRI10GE_LRO_MAX_PKTS 64
-
-#define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff)
-#define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff
-
-#define MYRI10GE_ALLOC_ORDER 0
-#define MYRI10GE_ALLOC_SIZE ((1 << MYRI10GE_ALLOC_ORDER) * PAGE_SIZE)
-#define MYRI10GE_MAX_FRAGS_PER_FRAME (MYRI10GE_MAX_ETHER_MTU/MYRI10GE_ALLOC_SIZE + 1)
-
-#define MYRI10GE_MAX_SLICES 32
-
-struct myri10ge_rx_buffer_state {
- struct page *page;
- int page_offset;
- DECLARE_PCI_UNMAP_ADDR(bus)
- DECLARE_PCI_UNMAP_LEN(len)
-};
-
-struct myri10ge_tx_buffer_state {
- struct sk_buff *skb;
- int last;
- DECLARE_PCI_UNMAP_ADDR(bus)
- DECLARE_PCI_UNMAP_LEN(len)
-};
-
-struct myri10ge_cmd {
- u32 data0;
- u32 data1;
- u32 data2;
-};
-
-struct myri10ge_rx_buf {
- struct mcp_kreq_ether_recv __iomem *lanai; /* lanai ptr for recv ring */
- struct mcp_kreq_ether_recv *shadow; /* host shadow of recv ring */
- struct myri10ge_rx_buffer_state *info;
- struct page *page;
- dma_addr_t bus;
- int page_offset;
- int cnt;
- int fill_cnt;
- int alloc_fail;
- int mask; /* number of rx slots -1 */
- int watchdog_needed;
-};
+char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat";
+char *myri10ge_fw_aligned = "myri10ge_eth_z8e.dat";
+char *myri10ge_fw_rss_unaligned = "myri10ge_rss_ethp_z8e.dat";
+char *myri10ge_fw_rss_aligned = "myri10ge_rss_eth_z8e.dat";
-struct myri10ge_tx_buf {
- struct mcp_kreq_ether_send __iomem *lanai; /* lanai ptr for sendq */
- __be32 __iomem *send_go; /* "go" doorbell ptr */
- __be32 __iomem *send_stop; /* "stop" doorbell ptr */
- struct mcp_kreq_ether_send *req_list; /* host shadow of sendq */
- char *req_bytes;
- struct myri10ge_tx_buffer_state *info;
- int mask; /* number of transmit slots -1 */
- int req ____cacheline_aligned; /* transmit slots submitted */
- int pkt_start; /* packets started */
- int stop_queue;
- int linearized;
- int done ____cacheline_aligned; /* transmit slots completed */
- int pkt_done; /* packets completed */
- int wake_queue;
- int queue_active;
-};
-
-struct myri10ge_rx_done {
- struct mcp_slot *entry;
- dma_addr_t bus;
- int cnt;
- int idx;
- struct net_lro_mgr lro_mgr;
- struct net_lro_desc lro_desc[MYRI10GE_MAX_LRO_DESCRIPTORS];
-};
-
-struct myri10ge_slice_netstats {
- unsigned long rx_packets;
- unsigned long tx_packets;
- unsigned long rx_bytes;
- unsigned long tx_bytes;
- unsigned long rx_dropped;
- unsigned long tx_dropped;
-};
-
-struct myri10ge_slice_state {
- struct myri10ge_tx_buf tx; /* transmit ring */
- struct myri10ge_rx_buf rx_small;
- struct myri10ge_rx_buf rx_big;
- struct myri10ge_rx_done rx_done;
- struct net_device *dev;
- struct napi_struct napi;
- struct myri10ge_priv *mgp;
- struct myri10ge_slice_netstats stats;
- __be32 __iomem *irq_claim;
- struct mcp_irq_data *fw_stats;
- dma_addr_t fw_stats_bus;
- int watchdog_tx_done;
- int watchdog_tx_req;
-#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
- int cached_dca_tag;
- int cpu;
- __be32 __iomem *dca_tag;
-#endif
- char irq_desc[32];
-};
-
-struct myri10ge_priv {
- struct myri10ge_slice_state *ss;
- int tx_boundary; /* boundary transmits cannot cross */
- int num_slices;
- int running; /* running? */
- int csum_flag; /* rx_csums? */
- int small_bytes;
- int big_bytes;
- int max_intr_slots;
- struct net_device *dev;
- struct net_device_stats stats;
- spinlock_t stats_lock;
- u8 __iomem *sram;
- int sram_size;
- unsigned long board_span;
- unsigned long iomem_base;
- __be32 __iomem *irq_deassert;
- char *mac_addr_string;
- struct mcp_cmd_response *cmd;
- dma_addr_t cmd_bus;
- struct pci_dev *pdev;
- int msi_enabled;
- int msix_enabled;
- struct msix_entry *msix_vectors;
-#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
- int dca_enabled;
-#endif
- u32 link_state;
- unsigned int rdma_tags_available;
- int intr_coal_delay;
- __be32 __iomem *intr_coal_delay_ptr;
- int mtrr;
- int wc_enabled;
- int down_cnt;
- wait_queue_head_t down_wq;
- struct work_struct watchdog_work;
- struct timer_list watchdog_timer;
- int watchdog_resets;
- int watchdog_pause;
- int pause;
- char *fw_name;
- char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE];
- char *product_code_string;
- char fw_version[128];
- int fw_ver_major;
- int fw_ver_minor;
- int fw_ver_tiny;
- int adopted_rx_filter_bug;
- u8 mac_addr[6]; /* eeprom mac address */
- unsigned long serial_number;
- int vendor_specific_offset;
- int fw_multicast_support;
- unsigned long features;
- u32 max_tso6;
- u32 read_dma;
- u32 write_dma;
- u32 read_write_dma;
- u32 link_changes;
- u32 msg_enable;
-};
-
-static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat";
-static char *myri10ge_fw_aligned = "myri10ge_eth_z8e.dat";
-static char *myri10ge_fw_rss_unaligned = "myri10ge_rss_ethp_z8e.dat";
-static char *myri10ge_fw_rss_aligned = "myri10ge_rss_eth_z8e.dat";
-
-static char *myri10ge_fw_name = NULL;
+char *myri10ge_fw_name = NULL;
module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name");
@@ -346,22 +169,10 @@ static int myri10ge_dca = 1;
module_param(myri10ge_dca, int, S_IRUGO);
MODULE_PARM_DESC(myri10ge_dca, "Enable DCA if possible");
-#define MYRI10GE_FW_OFFSET 1024*1024
-#define MYRI10GE_HIGHPART_TO_U32(X) \
-(sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0)
-#define MYRI10GE_LOWPART_TO_U32(X) ((u32)(X))
-
-#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)
-
static void myri10ge_set_multicast_list(struct net_device *dev);
static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev);
-static inline void put_be32(__be32 val, __be32 __iomem * p)
-{
- __raw_writel((__force __u32) val, (__force void __iomem *)p);
-}
-
-static int
+int
myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
struct myri10ge_cmd *data, int atomic)
{
@@ -492,7 +303,7 @@ abort:
* chipsets resend dropped PCIe messages
*/
-static void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable)
+void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable)
{
char __iomem *submit;
__be32 buf[16] __attribute__ ((__aligned__(8)));
@@ -527,263 +338,6 @@ static void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable)
(enable ? "enable" : "disable"));
}
-static int
-myri10ge_validate_firmware(struct myri10ge_priv *mgp,
- struct mcp_gen_header *hdr)
-{
- struct device *dev = &mgp->pdev->dev;
-
- /* check firmware type */
- if (ntohl(hdr->mcp_type) != MCP_TYPE_ETH) {
- dev_err(dev, "Bad firmware type: 0x%x\n", ntohl(hdr->mcp_type));
- return -EINVAL;
- }
-
- /* save firmware version for ethtool */
- strncpy(mgp->fw_version, hdr->version, sizeof(mgp->fw_version));
-
- sscanf(mgp->fw_version, "%d.%d.%d", &mgp->fw_ver_major,
- &mgp->fw_ver_minor, &mgp->fw_ver_tiny);
-
- if (!(mgp->fw_ver_major == MXGEFW_VERSION_MAJOR
- && mgp->fw_ver_minor == MXGEFW_VERSION_MINOR)) {
- dev_err(dev, "Found firmware version %s\n", mgp->fw_version);
- dev_err(dev, "Driver needs %d.%d\n", MXGEFW_VERSION_MAJOR,
- MXGEFW_VERSION_MINOR);
- return -EINVAL;
- }
- return 0;
-}
-
-static int myri10ge_load_hotplug_firmware(struct myri10ge_priv *mgp, u32 * size)
-{
- unsigned crc, reread_crc;
- const struct firmware *fw;
- struct device *dev = &mgp->pdev->dev;
- unsigned char *fw_readback;
- struct mcp_gen_header *hdr;
- size_t hdr_offset;
- int status;
- unsigned i;
-
- if ((status = request_firmware(&fw, mgp->fw_name, dev)) < 0) {
- dev_err(dev, "Unable to load %s firmware image via hotplug\n",
- mgp->fw_name);
- status = -EINVAL;
- goto abort_with_nothing;
- }
-
- /* check size */
-
- if (fw->size >= mgp->sram_size - MYRI10GE_FW_OFFSET ||
- fw->size < MCP_HEADER_PTR_OFFSET + 4) {
- dev_err(dev, "Firmware size invalid:%d\n", (int)fw->size);
- status = -EINVAL;
- goto abort_with_fw;
- }
-
- /* check id */
- hdr_offset = ntohl(*(__be32 *) (fw->data + MCP_HEADER_PTR_OFFSET));
- if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw->size) {
- dev_err(dev, "Bad firmware file\n");
- status = -EINVAL;
- goto abort_with_fw;
- }
- hdr = (void *)(fw->data + hdr_offset);
-
- status = myri10ge_validate_firmware(mgp, hdr);
- if (status != 0)
- goto abort_with_fw;
-
- crc = crc32(~0, fw->data, fw->size);
- for (i = 0; i < fw->size; i += 256) {
- myri10ge_pio_copy(mgp->sram + MYRI10GE_FW_OFFSET + i,
- fw->data + i,
- min(256U, (unsigned)(fw->size - i)));
- mb();
- readb(mgp->sram);
- }
- fw_readback = vmalloc(fw->size);
- if (!fw_readback) {
- status = -ENOMEM;
- goto abort_with_fw;
- }
- /* corruption checking is good for parity recovery and buggy chipset */
- memcpy_fromio(fw_readback, mgp->sram + MYRI10GE_FW_OFFSET, fw->size);
- reread_crc = crc32(~0, fw_readback, fw->size);
- vfree(fw_readback);
- if (crc != reread_crc) {
- dev_err(dev, "CRC failed(fw-len=%u), got 0x%x (expect 0x%x)\n",
- (unsigned)fw->size, reread_crc, crc);
- status = -EIO;
- goto abort_with_fw;
- }
- *size = (u32) fw->size;
-
-abort_with_fw:
- release_firmware(fw);
-
-abort_with_nothing:
- return status;
-}
-
-static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp)
-{
- struct mcp_gen_header *hdr;
- struct device *dev = &mgp->pdev->dev;
- const size_t bytes = sizeof(struct mcp_gen_header);
- size_t hdr_offset;
- int status;
-
- /* find running firmware header */
- hdr_offset = swab32(readl(mgp->sram + MCP_HEADER_PTR_OFFSET));
-
- if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > mgp->sram_size) {
- dev_err(dev, "Running firmware has bad header offset (%d)\n",
- (int)hdr_offset);
- return -EIO;
- }
-
- /* copy header of running firmware from SRAM to host memory to
- * validate firmware */
- hdr = kmalloc(bytes, GFP_KERNEL);
- if (hdr == NULL) {
- dev_err(dev, "could not malloc firmware hdr\n");
- return -ENOMEM;
- }
- memcpy_fromio(hdr, mgp->sram + hdr_offset, bytes);
- status = myri10ge_validate_firmware(mgp, hdr);
- kfree(hdr);
-
- /* check to see if adopted firmware has bug where adopting
- * it will cause broadcasts to be filtered unless the NIC
- * is kept in ALLMULTI mode */
- if (mgp->fw_ver_major == 1 && mgp->fw_ver_minor == 4 &&
- mgp->fw_ver_tiny >= 4 && mgp->fw_ver_tiny <= 11) {
- mgp->adopted_rx_filter_bug = 1;
- dev_warn(dev, "Adopting fw %d.%d.%d: "
- "working around rx filter bug\n",
- mgp->fw_ver_major, mgp->fw_ver_minor,
- mgp->fw_ver_tiny);
- }
- return status;
-}
-
-static int myri10ge_get_firmware_capabilities(struct myri10ge_priv *mgp)
-{
- struct myri10ge_cmd cmd;
- int status;
-
- /* probe for IPv6 TSO support */
- mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
- status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
- &cmd, 0);
- if (status == 0) {
- mgp->max_tso6 = cmd.data0;
- mgp->features |= NETIF_F_TSO6;
- }
-
- status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0);
- if (status != 0) {
- dev_err(&mgp->pdev->dev,
- "failed MXGEFW_CMD_GET_RX_RING_SIZE\n");
- return -ENXIO;
- }
-
- mgp->max_intr_slots = 2 * (cmd.data0 / sizeof(struct mcp_dma_addr));
-
- return 0;
-}
-
-static int myri10ge_load_firmware(struct myri10ge_priv *mgp, int adopt)
-{
- char __iomem *submit;
- __be32 buf[16] __attribute__ ((__aligned__(8)));
- u32 dma_low, dma_high, size;
- int status, i;
-
- size = 0;
- status = myri10ge_load_hotplug_firmware(mgp, &size);
- if (status) {
- if (!adopt)
- return status;
- dev_warn(&mgp->pdev->dev, "hotplug firmware loading failed\n");
-
- /* Do not attempt to adopt firmware if there
- * was a bad crc */
- if (status == -EIO)
- return status;
-
- status = myri10ge_adopt_running_firmware(mgp);
- if (status != 0) {
- dev_err(&mgp->pdev->dev,
- "failed to adopt running firmware\n");
- return status;
- }
- dev_info(&mgp->pdev->dev,
- "Successfully adopted running firmware\n");
- if (mgp->tx_boundary == 4096) {
- dev_warn(&mgp->pdev->dev,
- "Using firmware currently running on NIC"
- ". For optimal\n");
- dev_warn(&mgp->pdev->dev,
- "performance consider loading optimized "
- "firmware\n");
- dev_warn(&mgp->pdev->dev, "via hotplug\n");
- }
-
- mgp->fw_name = "adopted";
- mgp->tx_boundary = 2048;
- myri10ge_dummy_rdma(mgp, 1);
- status = myri10ge_get_firmware_capabilities(mgp);
- return status;
- }
-
- /* clear confirmation addr */
- mgp->cmd->data = 0;
- mb();
-
- /* send a reload command to the bootstrap MCP, and wait for the
- * response in the confirmation address. The firmware should
- * write a -1 there to indicate it is alive and well
- */
- dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus);
- dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus);
-
- buf[0] = htonl(dma_high); /* confirm addr MSW */
- buf[1] = htonl(dma_low); /* confirm addr LSW */
- buf[2] = MYRI10GE_NO_CONFIRM_DATA; /* confirm data */
-
- /* FIX: All newest firmware should un-protect the bottom of
- * the sram before handoff. However, the very first interfaces
- * do not. Therefore the handoff copy must skip the first 8 bytes
- */
- buf[3] = htonl(MYRI10GE_FW_OFFSET + 8); /* where the code starts */
- buf[4] = htonl(size - 8); /* length of code */
- buf[5] = htonl(8); /* where to copy to */
- buf[6] = htonl(0); /* where to jump to */
-
- submit = mgp->sram + MXGEFW_BOOT_HANDOFF;
-
- myri10ge_pio_copy(submit, &buf, sizeof(buf));
- mb();
- msleep(1);
- mb();
- i = 0;
- while (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 9) {
- msleep(1 << i);
- i++;
- }
- if (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA) {
- dev_err(&mgp->pdev->dev, "handoff failed\n");
- return -ENXIO;
- }
- myri10ge_dummy_rdma(mgp, 1);
- status = myri10ge_get_firmware_capabilities(mgp);
-
- return status;
-}
-
static int myri10ge_update_mac_address(struct myri10ge_priv *mgp, u8 * addr)
{
struct myri10ge_cmd cmd;
@@ -798,7 +352,7 @@ static int myri10ge_update_mac_address(struct myri10ge_priv *mgp, u8 * addr)
return status;
}
-static int myri10ge_change_pause(struct myri10ge_priv *mgp, int pause)
+int myri10ge_change_pause(struct myri10ge_priv *mgp, int pause)
{
struct myri10ge_cmd cmd;
int status, ctl;
@@ -1581,319 +1135,6 @@ static irqreturn_t myri10ge_intr(int irq, void *arg)
return (IRQ_HANDLED);
}
-static int
-myri10ge_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
- char *ptr;
- int i;
-
- cmd->autoneg = AUTONEG_DISABLE;
- cmd->speed = SPEED_10000;
- cmd->duplex = DUPLEX_FULL;
-
- /*
- * parse the product code to deterimine the interface type
- * (CX4, XFP, Quad Ribbon Fiber) by looking at the character
- * after the 3rd dash in the driver's cached copy of the
- * EEPROM's product code string.
- */
- ptr = mgp->product_code_string;
- if (ptr == NULL) {
- printk(KERN_ERR "myri10ge: %s: Missing product code\n",
- netdev->name);
- return 0;
- }
- for (i = 0; i < 3; i++, ptr++) {
- ptr = strchr(ptr, '-');
- if (ptr == NULL) {
- printk(KERN_ERR "myri10ge: %s: Invalid product "
- "code %s\n", netdev->name,
- mgp->product_code_string);
- return 0;
- }
- }
- if (*ptr == 'R' || *ptr == 'Q') {
- /* We've found either an XFP or quad ribbon fiber */
- cmd->port = PORT_FIBRE;
- }
- return 0;
-}
-
-static void
-myri10ge_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
-
- strlcpy(info->driver, "myri10ge", sizeof(info->driver));
- strlcpy(info->version, MYRI10GE_VERSION_STR, sizeof(info->version));
- strlcpy(info->fw_version, mgp->fw_version, sizeof(info->fw_version));
- strlcpy(info->bus_info, pci_name(mgp->pdev), sizeof(info->bus_info));
-}
-
-static int
-myri10ge_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coal)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
-
- coal->rx_coalesce_usecs = mgp->intr_coal_delay;
- return 0;
-}
-
-static int
-myri10ge_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coal)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
-
- mgp->intr_coal_delay = coal->rx_coalesce_usecs;
- put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr);
- return 0;
-}
-
-static void
-myri10ge_get_pauseparam(struct net_device *netdev,
- struct ethtool_pauseparam *pause)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
-
- pause->autoneg = 0;
- pause->rx_pause = mgp->pause;
- pause->tx_pause = mgp->pause;
-}
-
-static int
-myri10ge_set_pauseparam(struct net_device *netdev,
- struct ethtool_pauseparam *pause)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
-
- if (pause->tx_pause != mgp->pause)
- return myri10ge_change_pause(mgp, pause->tx_pause);
- if (pause->rx_pause != mgp->pause)
- return myri10ge_change_pause(mgp, pause->tx_pause);
- if (pause->autoneg != 0)
- return -EINVAL;
- return 0;
-}
-
-static void
-myri10ge_get_ringparam(struct net_device *netdev,
- struct ethtool_ringparam *ring)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
-
- ring->rx_mini_max_pending = mgp->ss[0].rx_small.mask + 1;
- ring->rx_max_pending = mgp->ss[0].rx_big.mask + 1;
- ring->rx_jumbo_max_pending = 0;
- ring->tx_max_pending = mgp->ss[0].rx_small.mask + 1;
- ring->rx_mini_pending = ring->rx_mini_max_pending;
- ring->rx_pending = ring->rx_max_pending;
- ring->rx_jumbo_pending = ring->rx_jumbo_max_pending;
- ring->tx_pending = ring->tx_max_pending;
-}
-
-static u32 myri10ge_get_rx_csum(struct net_device *netdev)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
-
- if (mgp->csum_flag)
- return 1;
- else
- return 0;
-}
-
-static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
-
- if (csum_enabled)
- mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
- else
- mgp->csum_flag = 0;
- return 0;
-}
-
-static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
- unsigned long flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO);
-
- if (tso_enabled)
- netdev->features |= flags;
- else
- netdev->features &= ~flags;
- return 0;
-}
-
-static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = {
- "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
- "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
- "rx_length_errors", "rx_over_errors", "rx_crc_errors",
- "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
- "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
- "tx_heartbeat_errors", "tx_window_errors",
- /* device-specific stats */
- "tx_boundary", "WC", "irq", "MSI", "MSIX",
- "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
- "serial_number", "watchdog_resets",
-#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
- "dca_capable_firmware", "dca_device_present",
-#endif
- "link_changes", "link_up", "dropped_link_overflow",
- "dropped_link_error_or_filtered",
- "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32",
- "dropped_unicast_filtered", "dropped_multicast_filtered",
- "dropped_runt", "dropped_overrun", "dropped_no_small_buffer",
- "dropped_no_big_buffer"
-};
-
-static const char myri10ge_gstrings_slice_stats[][ETH_GSTRING_LEN] = {
- "----------- slice ---------",
- "tx_pkt_start", "tx_pkt_done", "tx_req", "tx_done",
- "rx_small_cnt", "rx_big_cnt",
- "wake_queue", "stop_queue", "tx_linearized", "LRO aggregated",
- "LRO flushed",
- "LRO avg aggr", "LRO no_desc"
-};
-
-#define MYRI10GE_NET_STATS_LEN 21
-#define MYRI10GE_MAIN_STATS_LEN ARRAY_SIZE(myri10ge_gstrings_main_stats)
-#define MYRI10GE_SLICE_STATS_LEN ARRAY_SIZE(myri10ge_gstrings_slice_stats)
-
-static void
-myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
- int i;
-
- switch (stringset) {
- case ETH_SS_STATS:
- memcpy(data, *myri10ge_gstrings_main_stats,
- sizeof(myri10ge_gstrings_main_stats));
- data += sizeof(myri10ge_gstrings_main_stats);
- for (i = 0; i < mgp->num_slices; i++) {
- memcpy(data, *myri10ge_gstrings_slice_stats,
- sizeof(myri10ge_gstrings_slice_stats));
- data += sizeof(myri10ge_gstrings_slice_stats);
- }
- break;
- }
-}
-
-static int myri10ge_get_sset_count(struct net_device *netdev, int sset)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
-
- switch (sset) {
- case ETH_SS_STATS:
- return MYRI10GE_MAIN_STATS_LEN +
- mgp->num_slices * MYRI10GE_SLICE_STATS_LEN;
- default:
- return -EOPNOTSUPP;
- }
-}
-
-static void
-myri10ge_get_ethtool_stats(struct net_device *netdev,
- struct ethtool_stats *stats, u64 * data)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
- struct myri10ge_slice_state *ss;
- int slice;
- int i;
-
- for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
- data[i] = ((unsigned long *)&mgp->stats)[i];
-
- data[i++] = (unsigned int)mgp->tx_boundary;
- data[i++] = (unsigned int)mgp->wc_enabled;
- data[i++] = (unsigned int)mgp->pdev->irq;
- data[i++] = (unsigned int)mgp->msi_enabled;
- data[i++] = (unsigned int)mgp->msix_enabled;
- data[i++] = (unsigned int)mgp->read_dma;
- data[i++] = (unsigned int)mgp->write_dma;
- data[i++] = (unsigned int)mgp->read_write_dma;
- data[i++] = (unsigned int)mgp->serial_number;
- data[i++] = (unsigned int)mgp->watchdog_resets;
-#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
- data[i++] = (unsigned int)(mgp->ss[0].dca_tag != NULL);
- data[i++] = (unsigned int)(mgp->dca_enabled);
-#endif
- data[i++] = (unsigned int)mgp->link_changes;
-
- /* firmware stats are useful only in the first slice */
- ss = &mgp->ss[0];
- data[i++] = (unsigned int)ntohl(ss->fw_stats->link_up);
- data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_link_overflow);
- data[i++] =
- (unsigned int)ntohl(ss->fw_stats->dropped_link_error_or_filtered);
- data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_pause);
- data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_bad_phy);
- data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_bad_crc32);
- data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_unicast_filtered);
- data[i++] =
- (unsigned int)ntohl(ss->fw_stats->dropped_multicast_filtered);
- data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_runt);
- data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_overrun);
- data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_small_buffer);
- data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_big_buffer);
-
- for (slice = 0; slice < mgp->num_slices; slice++) {
- ss = &mgp->ss[slice];
- data[i++] = slice;
- data[i++] = (unsigned int)ss->tx.pkt_start;
- data[i++] = (unsigned int)ss->tx.pkt_done;
- data[i++] = (unsigned int)ss->tx.req;
- data[i++] = (unsigned int)ss->tx.done;
- data[i++] = (unsigned int)ss->rx_small.cnt;
- data[i++] = (unsigned int)ss->rx_big.cnt;
- data[i++] = (unsigned int)ss->tx.wake_queue;
- data[i++] = (unsigned int)ss->tx.stop_queue;
- data[i++] = (unsigned int)ss->tx.linearized;
- data[i++] = ss->rx_done.lro_mgr.stats.aggregated;
- data[i++] = ss->rx_done.lro_mgr.stats.flushed;
- if (ss->rx_done.lro_mgr.stats.flushed)
- data[i++] = ss->rx_done.lro_mgr.stats.aggregated /
- ss->rx_done.lro_mgr.stats.flushed;
- else
- data[i++] = 0;
- data[i++] = ss->rx_done.lro_mgr.stats.no_desc;
- }
-}
-
-static void myri10ge_set_msglevel(struct net_device *netdev, u32 value)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
- mgp->msg_enable = value;
-}
-
-static u32 myri10ge_get_msglevel(struct net_device *netdev)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
- return mgp->msg_enable;
-}
-
-static const struct ethtool_ops myri10ge_ethtool_ops = {
- .get_settings = myri10ge_get_settings,
- .get_drvinfo = myri10ge_get_drvinfo,
- .get_coalesce = myri10ge_get_coalesce,
- .set_coalesce = myri10ge_set_coalesce,
- .get_pauseparam = myri10ge_get_pauseparam,
- .set_pauseparam = myri10ge_set_pauseparam,
- .get_ringparam = myri10ge_get_ringparam,
- .get_rx_csum = myri10ge_get_rx_csum,
- .set_rx_csum = myri10ge_set_rx_csum,
- .set_tx_csum = ethtool_op_set_tx_hw_csum,
- .set_sg = ethtool_op_set_sg,
- .set_tso = myri10ge_set_tso,
- .get_link = ethtool_op_get_link,
- .get_strings = myri10ge_get_strings,
- .get_sset_count = myri10ge_get_sset_count,
- .get_ethtool_stats = myri10ge_get_ethtool_stats,
- .set_msglevel = myri10ge_set_msglevel,
- .get_msglevel = myri10ge_get_msglevel
-};
-
static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss)
{
struct myri10ge_priv *mgp = ss->mgp;
--
1.5.6.5
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2008-09-29 1:34 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-29 1:30 [PATCH 0/3] myri10ge updates for 2.6.28 Brice Goglin
2008-09-29 1:34 ` [PATCH 1/3] myri10ge: add multiqueue TX Brice Goglin
2008-09-29 1:34 ` [PATCH 2/3] myri10ge: rename main file into myri10ge_main.c Brice Goglin
2008-09-29 1:34 ` [PATCH 3/3] myri10ge: split main file into pieces Brice Goglin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.