* [PATCH 0/7] myri10ge updates
@ 2006-12-11 10:23 Brice Goglin
2006-12-11 10:24 ` [PATCH 1/7] myri10ge: indentation cleanups Brice Goglin
` (6 more replies)
0 siblings, 7 replies; 9+ messages in thread
From: Brice Goglin @ 2006-12-11 10:23 UTC (permalink / raw)
To: Jeff Garzik, netdev
Hi Jeff,
The following 7 patches update/fix myri10ge:
1. indentation cleanups
2. add page-based skb routines
3. switch to page-based skb
4. drop contiguous skb routines
5. full vlan frame in small_bytes
6. fix big_bytes in case of vlan frames
7. update driver version to 1.1.0
#1 is independent, while #2-#7 should be applied in order.
#2-#4 contains the physical page based skb conversion splitted in 3 patches
to make it very easy to review.
All these patches have been updated to match the annotations that got
committed last week.
Please apply.
Thanks,
Brice
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/7] myri10ge: indentation cleanups
2006-12-11 10:23 [PATCH 0/7] myri10ge updates Brice Goglin
@ 2006-12-11 10:24 ` Brice Goglin
2006-12-11 14:54 ` Jeff Garzik
2006-12-11 10:25 ` [PATCH 2/7] myri10ge: add page-based skb routines Brice Goglin
` (5 subsequent siblings)
6 siblings, 1 reply; 9+ messages in thread
From: Brice Goglin @ 2006-12-11 10:24 UTC (permalink / raw)
To: Jeff Garzik, netdev
Indentation cleanups to synchronize to our tree which is automatically
indent'ed.
Signed-off-by: Brice Goglin <brice@myri.com>
---
drivers/net/myri10ge/myri10ge.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
Index: linux-git/drivers/net/myri10ge/myri10ge.c
===================================================================
--- linux-git.orig/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:50:26.000000000 +0100
+++ linux-git/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:52:08.000000000 +0100
@@ -273,9 +273,9 @@
#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)
-static inline void put_be32(__be32 val, __be32 __iomem *p)
+static inline void put_be32(__be32 val, __be32 __iomem * p)
{
- __raw_writel((__force __u32)val, (__force void __iomem *)p);
+ __raw_writel((__force __u32) val, (__force void __iomem *)p);
}
static int
@@ -2206,7 +2206,7 @@
struct myri10ge_cmd cmd;
struct myri10ge_priv *mgp;
struct dev_mc_list *mc_list;
- __be32 data[2] = {0, 0};
+ __be32 data[2] = { 0, 0 };
int err;
mgp = netdev_priv(dev);
@@ -2625,7 +2625,7 @@
static void myri10ge_watchdog(struct work_struct *work)
{
struct myri10ge_priv *mgp =
- container_of(work, struct myri10ge_priv, watchdog_work);
+ container_of(work, struct myri10ge_priv, watchdog_work);
u32 reboot;
int status;
u16 cmd, vendor;
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/7] myri10ge: add page-based skb routines
2006-12-11 10:23 [PATCH 0/7] myri10ge updates Brice Goglin
2006-12-11 10:24 ` [PATCH 1/7] myri10ge: indentation cleanups Brice Goglin
@ 2006-12-11 10:25 ` Brice Goglin
2006-12-11 10:25 ` [PATCH 3/7] myri10ge: switch to page-based skb Brice Goglin
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Brice Goglin @ 2006-12-11 10:25 UTC (permalink / raw)
To: Jeff Garzik, netdev
Add physical page skb allocation routines and page based rx_done,
to be used by upcoming patches.
Signed-off-by: Brice Goglin <brice@myri.com>
---
drivers/net/myri10ge/myri10ge.c | 190 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 190 insertions(+)
Index: linux-git/drivers/net/myri10ge/myri10ge.c
===================================================================
--- linux-git.orig/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:52:08.000000000 +0100
+++ linux-git/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:52:26.000000000 +0100
@@ -92,8 +92,14 @@
#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)
+
struct myri10ge_rx_buffer_state {
struct sk_buff *skb;
+ struct page *page;
+ int page_offset;
DECLARE_PCI_UNMAP_ADDR(bus)
DECLARE_PCI_UNMAP_LEN(len)
};
@@ -116,9 +122,14 @@
u8 __iomem *wc_fifo; /* w/c rx dma addr fifo address */
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 {
@@ -150,6 +161,7 @@
struct myri10ge_rx_buf rx_big;
struct myri10ge_rx_done rx_done;
int small_bytes;
+ int big_bytes;
struct net_device *dev;
struct net_device_stats stats;
u8 __iomem *sram;
@@ -266,6 +278,10 @@
module_param(myri10ge_debug, int, 0);
MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)");
+static int myri10ge_fill_thresh = 256;
+module_param(myri10ge_fill_thresh, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed\n");
+
#define MYRI10GE_FW_OFFSET 1024*1024
#define MYRI10GE_HIGHPART_TO_U32(X) \
(sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0)
@@ -958,6 +974,180 @@
}
}
+static inline void
+myri10ge_rx_skb_build(struct sk_buff *skb, u8 * va,
+ struct skb_frag_struct *rx_frags, int len, int hlen)
+{
+ struct skb_frag_struct *skb_frags;
+
+ skb->len = skb->data_len = len;
+ skb->truesize = len + sizeof(struct sk_buff);
+ /* attach the page(s) */
+
+ skb_frags = skb_shinfo(skb)->frags;
+ while (len > 0) {
+ memcpy(skb_frags, rx_frags, sizeof(*skb_frags));
+ len -= rx_frags->size;
+ skb_frags++;
+ rx_frags++;
+ skb_shinfo(skb)->nr_frags++;
+ }
+
+ /* pskb_may_pull is not available in irq context, but
+ * skb_pull() (for ether_pad and eth_type_trans()) requires
+ * the beginning of the packet in skb_headlen(), move it
+ * manually */
+ memcpy(skb->data, va, hlen);
+ skb_shinfo(skb)->frags[0].page_offset += hlen;
+ skb_shinfo(skb)->frags[0].size -= hlen;
+ skb->data_len -= hlen;
+ skb->tail += hlen;
+ skb_pull(skb, MXGEFW_PAD);
+}
+
+static void
+myri10ge_alloc_rx_pages(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
+ int bytes, int watchdog)
+{
+ struct page *page;
+ int idx;
+
+ if (unlikely(rx->watchdog_needed && !watchdog))
+ return;
+
+ /* try to refill entire ring */
+ while (rx->fill_cnt != (rx->cnt + rx->mask + 1)) {
+ idx = rx->fill_cnt & rx->mask;
+
+ if ((bytes < MYRI10GE_ALLOC_SIZE / 2) &&
+ (rx->page_offset + bytes <= MYRI10GE_ALLOC_SIZE)) {
+ /* we can use part of previous page */
+ get_page(rx->page);
+ } else {
+ /* we need a new page */
+ page =
+ alloc_pages(GFP_ATOMIC | __GFP_COMP,
+ MYRI10GE_ALLOC_ORDER);
+ if (unlikely(page == NULL)) {
+ if (rx->fill_cnt - rx->cnt < 16)
+ rx->watchdog_needed = 1;
+ return;
+ }
+ rx->page = page;
+ rx->page_offset = 0;
+ rx->bus = pci_map_page(mgp->pdev, page, 0,
+ MYRI10GE_ALLOC_SIZE,
+ PCI_DMA_FROMDEVICE);
+ }
+ rx->info[idx].page = rx->page;
+ rx->info[idx].page_offset = rx->page_offset;
+ /* note that this is the address of the start of the
+ * page */
+ pci_unmap_addr_set(&rx->info[idx], bus, rx->bus);
+ rx->shadow[idx].addr_low =
+ htonl(MYRI10GE_LOWPART_TO_U32(rx->bus) + rx->page_offset);
+ rx->shadow[idx].addr_high =
+ htonl(MYRI10GE_HIGHPART_TO_U32(rx->bus));
+
+ /* start next packet on a cacheline boundary */
+ rx->page_offset += SKB_DATA_ALIGN(bytes);
+ rx->fill_cnt++;
+
+ /* copy 8 descriptors to the firmware at a time */
+ if ((idx & 7) == 7) {
+ if (rx->wc_fifo == NULL)
+ myri10ge_submit_8rx(&rx->lanai[idx - 7],
+ &rx->shadow[idx - 7]);
+ else {
+ mb();
+ myri10ge_pio_copy(rx->wc_fifo,
+ &rx->shadow[idx - 7], 64);
+ }
+ }
+ }
+}
+
+static inline void
+myri10ge_unmap_rx_page(struct pci_dev *pdev,
+ struct myri10ge_rx_buffer_state *info, int bytes)
+{
+ /* unmap the recvd page if we're the only or last user of it */
+ if (bytes >= MYRI10GE_ALLOC_SIZE / 2 ||
+ (info->page_offset + 2 * bytes) > MYRI10GE_ALLOC_SIZE) {
+ pci_unmap_page(pdev, (pci_unmap_addr(info, bus)
+ & ~(MYRI10GE_ALLOC_SIZE - 1)),
+ MYRI10GE_ALLOC_SIZE, PCI_DMA_FROMDEVICE);
+ }
+}
+
+#define MYRI10GE_HLEN 64 /* The number of bytes to copy from a
+ * page into an skb */
+
+static inline int
+myri10ge_page_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
+ int bytes, int len, __wsum csum)
+{
+ struct sk_buff *skb;
+ struct skb_frag_struct rx_frags[MYRI10GE_MAX_FRAGS_PER_FRAME];
+ int i, idx, hlen, remainder;
+ struct pci_dev *pdev = mgp->pdev;
+ struct net_device *dev = mgp->dev;
+ u8 *va;
+
+ len += MXGEFW_PAD;
+ idx = rx->cnt & rx->mask;
+ va = page_address(rx->info[idx].page) + rx->info[idx].page_offset;
+ prefetch(va);
+ /* Fill skb_frag_struct(s) with data from our receive */
+ for (i = 0, remainder = len; remainder > 0; i++) {
+ myri10ge_unmap_rx_page(pdev, &rx->info[idx], bytes);
+ rx_frags[i].page = rx->info[idx].page;
+ rx_frags[i].page_offset = rx->info[idx].page_offset;
+ if (remainder < MYRI10GE_ALLOC_SIZE)
+ rx_frags[i].size = remainder;
+ else
+ rx_frags[i].size = MYRI10GE_ALLOC_SIZE;
+ rx->cnt++;
+ idx = rx->cnt & rx->mask;
+ remainder -= MYRI10GE_ALLOC_SIZE;
+ }
+
+ hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN;
+
+ /* allocate an skb to attach the page(s) to. */
+
+ skb = netdev_alloc_skb(dev, MYRI10GE_HLEN + 16);
+ if (unlikely(skb == NULL)) {
+ mgp->stats.rx_dropped++;
+ do {
+ i--;
+ put_page(rx_frags[i].page);
+ } while (i != 0);
+ return 0;
+ }
+
+ /* Attach the pages to the skb, and trim off any padding */
+ myri10ge_rx_skb_build(skb, va, rx_frags, len, hlen);
+ if (skb_shinfo(skb)->frags[0].size <= 0) {
+ put_page(skb_shinfo(skb)->frags[0].page);
+ skb_shinfo(skb)->nr_frags = 0;
+ }
+ skb->protocol = eth_type_trans(skb, dev);
+ skb->dev = dev;
+
+ if (mgp->csum_flag) {
+ if ((skb->protocol == htons(ETH_P_IP)) ||
+ (skb->protocol == htons(ETH_P_IPV6))) {
+ skb->csum = csum;
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ } else
+ myri10ge_vlan_ip_csum(skb, csum);
+ }
+ netif_receive_skb(skb);
+ dev->last_rx = jiffies;
+ return 1;
+}
+
static inline unsigned long
myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
int bytes, int len, __wsum csum)
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/7] myri10ge: switch to page-based skb
2006-12-11 10:23 [PATCH 0/7] myri10ge updates Brice Goglin
2006-12-11 10:24 ` [PATCH 1/7] myri10ge: indentation cleanups Brice Goglin
2006-12-11 10:25 ` [PATCH 2/7] myri10ge: add page-based skb routines Brice Goglin
@ 2006-12-11 10:25 ` Brice Goglin
2006-12-11 10:26 ` [PATCH 4/7] myri10ge: drop contiguous skb routines Brice Goglin
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Brice Goglin @ 2006-12-11 10:25 UTC (permalink / raw)
To: Jeff Garzik, netdev
Switch to physical page skb, by calling the new page-based
allocation routines and using myri10ge_page_rx_done().
Signed-off-by: Brice Goglin <brice@myri.com>
---
drivers/net/myri10ge/myri10ge.c | 180 +++++++++++++++++++++-------------------
1 file changed, 97 insertions(+), 83 deletions(-)
Index: linux-git/drivers/net/myri10ge/myri10ge.c
===================================================================
--- linux-git.orig/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:52:26.000000000 +0100
+++ linux-git/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:52:35.000000000 +0100
@@ -1264,13 +1264,13 @@
rx_done->entry[idx].length = 0;
checksum = csum_unfold(rx_done->entry[idx].checksum);
if (length <= mgp->small_bytes)
- rx_ok = myri10ge_rx_done(mgp, &mgp->rx_small,
- mgp->small_bytes,
- length, checksum);
+ rx_ok = myri10ge_page_rx_done(mgp, &mgp->rx_small,
+ mgp->small_bytes,
+ length, checksum);
else
- rx_ok = myri10ge_rx_done(mgp, &mgp->rx_big,
- mgp->dev->mtu + ETH_HLEN,
- length, checksum);
+ rx_ok = myri10ge_page_rx_done(mgp, &mgp->rx_big,
+ mgp->big_bytes,
+ length, checksum);
rx_packets += rx_ok;
rx_bytes += rx_ok * (unsigned long)length;
cnt++;
@@ -1284,6 +1284,14 @@
rx_done->cnt = cnt;
mgp->stats.rx_packets += rx_packets;
mgp->stats.rx_bytes += rx_bytes;
+
+ /* restock receive rings if needed */
+ if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt < myri10ge_fill_thresh)
+ myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+ mgp->small_bytes + MXGEFW_PAD, 0);
+ if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt < myri10ge_fill_thresh)
+ myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0);
+
}
static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
@@ -1674,56 +1682,48 @@
goto abort_with_rx_small_info;
/* Fill the receive rings */
-
- for (i = 0; i <= mgp->rx_small.mask; i++) {
- status = myri10ge_getbuf(&mgp->rx_small, mgp,
- mgp->small_bytes, i);
- if (status) {
- printk(KERN_ERR
- "myri10ge: %s: alloced only %d small bufs\n",
- dev->name, i);
- goto abort_with_rx_small_ring;
- }
- }
-
- for (i = 0; i <= mgp->rx_big.mask; i++) {
- status =
- myri10ge_getbuf(&mgp->rx_big, mgp, dev->mtu + ETH_HLEN, i);
- if (status) {
- printk(KERN_ERR
- "myri10ge: %s: alloced only %d big bufs\n",
- dev->name, i);
- goto abort_with_rx_big_ring;
- }
+ mgp->rx_big.cnt = 0;
+ mgp->rx_small.cnt = 0;
+ mgp->rx_big.fill_cnt = 0;
+ mgp->rx_small.fill_cnt = 0;
+ mgp->rx_small.page_offset = MYRI10GE_ALLOC_SIZE;
+ mgp->rx_big.page_offset = MYRI10GE_ALLOC_SIZE;
+ mgp->rx_small.watchdog_needed = 0;
+ mgp->rx_big.watchdog_needed = 0;
+ myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+ mgp->small_bytes + MXGEFW_PAD, 0);
+
+ if (mgp->rx_small.fill_cnt < mgp->rx_small.mask + 1) {
+ printk(KERN_ERR "myri10ge: %s: alloced only %d small bufs\n",
+ dev->name, mgp->rx_small.fill_cnt);
+ goto abort_with_rx_small_ring;
+ }
+
+ myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0);
+ if (mgp->rx_big.fill_cnt < mgp->rx_big.mask + 1) {
+ printk(KERN_ERR "myri10ge: %s: alloced only %d big bufs\n",
+ dev->name, mgp->rx_big.fill_cnt);
+ goto abort_with_rx_big_ring;
}
return 0;
abort_with_rx_big_ring:
- for (i = 0; i <= mgp->rx_big.mask; i++) {
- if (mgp->rx_big.info[i].skb != NULL)
- dev_kfree_skb_any(mgp->rx_big.info[i].skb);
- if (pci_unmap_len(&mgp->rx_big.info[i], len))
- pci_unmap_single(mgp->pdev,
- pci_unmap_addr(&mgp->rx_big.info[i],
- bus),
- pci_unmap_len(&mgp->rx_big.info[i],
- len),
- PCI_DMA_FROMDEVICE);
+ for (i = mgp->rx_big.cnt; i < mgp->rx_big.fill_cnt; i++) {
+ int idx = i & mgp->rx_big.mask;
+ myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_big.info[idx],
+ mgp->big_bytes);
+ put_page(mgp->rx_big.info[idx].page);
}
abort_with_rx_small_ring:
- for (i = 0; i <= mgp->rx_small.mask; i++) {
- if (mgp->rx_small.info[i].skb != NULL)
- dev_kfree_skb_any(mgp->rx_small.info[i].skb);
- if (pci_unmap_len(&mgp->rx_small.info[i], len))
- pci_unmap_single(mgp->pdev,
- pci_unmap_addr(&mgp->rx_small.info[i],
- bus),
- pci_unmap_len(&mgp->rx_small.info[i],
- len),
- PCI_DMA_FROMDEVICE);
+ for (i = mgp->rx_small.cnt; i < mgp->rx_small.fill_cnt; i++) {
+ int idx = i & mgp->rx_small.mask;
+ myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_small.info[idx],
+ mgp->small_bytes + MXGEFW_PAD);
+ put_page(mgp->rx_small.info[idx].page);
}
+
kfree(mgp->rx_big.info);
abort_with_rx_small_info:
@@ -1756,30 +1756,24 @@
mgp = netdev_priv(dev);
- for (i = 0; i <= mgp->rx_big.mask; i++) {
- if (mgp->rx_big.info[i].skb != NULL)
- dev_kfree_skb_any(mgp->rx_big.info[i].skb);
- if (pci_unmap_len(&mgp->rx_big.info[i], len))
- pci_unmap_single(mgp->pdev,
- pci_unmap_addr(&mgp->rx_big.info[i],
- bus),
- pci_unmap_len(&mgp->rx_big.info[i],
- len),
- PCI_DMA_FROMDEVICE);
- }
-
- for (i = 0; i <= mgp->rx_small.mask; i++) {
- if (mgp->rx_small.info[i].skb != NULL)
- dev_kfree_skb_any(mgp->rx_small.info[i].skb);
- if (pci_unmap_len(&mgp->rx_small.info[i], len))
- pci_unmap_single(mgp->pdev,
- pci_unmap_addr(&mgp->rx_small.info[i],
- bus),
- pci_unmap_len(&mgp->rx_small.info[i],
- len),
- PCI_DMA_FROMDEVICE);
+ for (i = mgp->rx_big.cnt; i < mgp->rx_big.fill_cnt; i++) {
+ idx = i & mgp->rx_big.mask;
+ if (i == mgp->rx_big.fill_cnt - 1)
+ mgp->rx_big.info[idx].page_offset = MYRI10GE_ALLOC_SIZE;
+ myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_big.info[idx],
+ mgp->big_bytes);
+ put_page(mgp->rx_big.info[idx].page);
+ }
+
+ for (i = mgp->rx_small.cnt; i < mgp->rx_small.fill_cnt; i++) {
+ idx = i & mgp->rx_small.mask;
+ if (i == mgp->rx_small.fill_cnt - 1)
+ mgp->rx_small.info[idx].page_offset =
+ MYRI10GE_ALLOC_SIZE;
+ myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_small.info[idx],
+ mgp->small_bytes + MXGEFW_PAD);
+ put_page(mgp->rx_small.info[idx].page);
}
-
tx = &mgp->tx;
while (tx->done != tx->req) {
idx = tx->done & tx->mask;
@@ -1847,19 +1841,18 @@
*/
if (dev->mtu <= ETH_DATA_LEN)
- mgp->small_bytes = 128; /* enough for a TCP header */
+ /* enough for a TCP header */
+ mgp->small_bytes = (128 > SMP_CACHE_BYTES)
+ ? (128 - MXGEFW_PAD)
+ : (SMP_CACHE_BYTES - MXGEFW_PAD);
else
- mgp->small_bytes = ETH_FRAME_LEN; /* enough for an ETH_DATA_LEN frame */
+ /* enough for an ETH_DATA_LEN frame */
+ mgp->small_bytes = ETH_FRAME_LEN;
/* Override the small buffer size? */
if (myri10ge_small_bytes > 0)
mgp->small_bytes = myri10ge_small_bytes;
- /* If the user sets an obscenely small MTU, adjust the small
- * bytes down to nearly nothing */
- if (mgp->small_bytes >= (dev->mtu + ETH_HLEN))
- mgp->small_bytes = 64;
-
/* get the lanai pointers to the send and receive rings */
status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0);
@@ -1895,17 +1888,23 @@
mgp->rx_big.wc_fifo = NULL;
}
- status = myri10ge_allocate_rings(dev);
- if (status != 0)
- goto abort_with_nothing;
-
/* Firmware needs the big buff size as a power of 2. Lie and
* tell him the buffer is larger, because we only use 1
* buffer/pkt, and the mtu will prevent overruns.
*/
big_pow2 = dev->mtu + ETH_HLEN + MXGEFW_PAD;
- while ((big_pow2 & (big_pow2 - 1)) != 0)
- big_pow2++;
+ if (big_pow2 < MYRI10GE_ALLOC_SIZE / 2) {
+ while ((big_pow2 & (big_pow2 - 1)) != 0)
+ big_pow2++;
+ mgp->big_bytes = dev->mtu + ETH_HLEN + MXGEFW_PAD;
+ } else {
+ big_pow2 = MYRI10GE_ALLOC_SIZE;
+ mgp->big_bytes = big_pow2;
+ }
+
+ status = myri10ge_allocate_rings(dev);
+ if (status != 0)
+ goto abort_with_nothing;
/* now give firmware buffers sizes, and MTU */
cmd.data0 = dev->mtu + ETH_HLEN + VLAN_HLEN;
@@ -2888,6 +2887,21 @@
struct myri10ge_priv *mgp;
mgp = (struct myri10ge_priv *)arg;
+
+ if (mgp->rx_small.watchdog_needed) {
+ myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+ mgp->small_bytes + MXGEFW_PAD, 1);
+ if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt >=
+ myri10ge_fill_thresh)
+ mgp->rx_small.watchdog_needed = 0;
+ }
+ if (mgp->rx_big.watchdog_needed) {
+ myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 1);
+ if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt >=
+ myri10ge_fill_thresh)
+ mgp->rx_big.watchdog_needed = 0;
+ }
+
if (mgp->tx.req != mgp->tx.done &&
mgp->tx.done == mgp->watchdog_tx_done &&
mgp->watchdog_tx_req != mgp->watchdog_tx_done)
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/7] myri10ge: drop contiguous skb routines
2006-12-11 10:23 [PATCH 0/7] myri10ge updates Brice Goglin
` (2 preceding siblings ...)
2006-12-11 10:25 ` [PATCH 3/7] myri10ge: switch to page-based skb Brice Goglin
@ 2006-12-11 10:26 ` Brice Goglin
2006-12-11 10:26 ` [PATCH 5/7] myri10ge: Full vlan frame in small_bytes Brice Goglin
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Brice Goglin @ 2006-12-11 10:26 UTC (permalink / raw)
To: Jeff Garzik, netdev
Drop the old routines that used the physically contigous skb now
that we use the physical pages. And rename myri10ge_page_rx_done()
to myri10ge_rx_done() as it was previously.
Signed-off-by: Brice Goglin <brice@myri.com>
---
drivers/net/myri10ge/myri10ge.c | 212 +---------------------------------------
1 file changed, 8 insertions(+), 204 deletions(-)
Index: linux-git/drivers/net/myri10ge/myri10ge.c
===================================================================
--- linux-git.orig/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:52:35.000000000 +0100
+++ linux-git/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:52:44.000000000 +0100
@@ -97,7 +97,6 @@
#define MYRI10GE_MAX_FRAGS_PER_FRAME (MYRI10GE_MAX_ETHER_MTU/MYRI10GE_ALLOC_SIZE + 1)
struct myri10ge_rx_buffer_state {
- struct sk_buff *skb;
struct page *page;
int page_offset;
DECLARE_PCI_UNMAP_ADDR(bus)
@@ -250,11 +249,6 @@
MODULE_PARM_DESC(myri10ge_force_firmware,
"Force firmware to assume aligned completions\n");
-static int myri10ge_skb_cross_4k = 0;
-module_param(myri10ge_skb_cross_4k, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(myri10ge_skb_cross_4k,
- "Can a small skb cross a 4KB boundary?\n");
-
static int myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN;
module_param(myri10ge_initial_mtu, int, S_IRUGO);
MODULE_PARM_DESC(myri10ge_initial_mtu, "Initial MTU\n");
@@ -820,148 +814,6 @@
mb();
}
-/*
- * Set of routines to get a new receive buffer. Any buffer which
- * crosses a 4KB boundary must start on a 4KB boundary due to PCIe
- * wdma restrictions. We also try to align any smaller allocation to
- * at least a 16 byte boundary for efficiency. We assume the linux
- * memory allocator works by powers of 2, and will not return memory
- * smaller than 2KB which crosses a 4KB boundary. If it does, we fall
- * back to allocating 2x as much space as required.
- *
- * We intend to replace large (>4KB) skb allocations by using
- * pages directly and building a fraglist in the near future.
- */
-
-static inline struct sk_buff *myri10ge_alloc_big(struct net_device *dev,
- int bytes)
-{
- struct sk_buff *skb;
- unsigned long data, roundup;
-
- skb = netdev_alloc_skb(dev, bytes + 4096 + MXGEFW_PAD);
- if (skb == NULL)
- return NULL;
-
- /* Correct skb->truesize so that socket buffer
- * accounting is not confused the rounding we must
- * do to satisfy alignment constraints.
- */
- skb->truesize -= 4096;
-
- data = (unsigned long)(skb->data);
- roundup = (-data) & (4095);
- skb_reserve(skb, roundup);
- return skb;
-}
-
-/* Allocate 2x as much space as required and use whichever portion
- * does not cross a 4KB boundary */
-static inline struct sk_buff *myri10ge_alloc_small_safe(struct net_device *dev,
- unsigned int bytes)
-{
- struct sk_buff *skb;
- unsigned long data, boundary;
-
- skb = netdev_alloc_skb(dev, 2 * (bytes + MXGEFW_PAD) - 1);
- if (unlikely(skb == NULL))
- return NULL;
-
- /* Correct skb->truesize so that socket buffer
- * accounting is not confused the rounding we must
- * do to satisfy alignment constraints.
- */
- skb->truesize -= bytes + MXGEFW_PAD;
-
- data = (unsigned long)(skb->data);
- boundary = (data + 4095UL) & ~4095UL;
- if ((boundary - data) >= (bytes + MXGEFW_PAD))
- return skb;
-
- skb_reserve(skb, boundary - data);
- return skb;
-}
-
-/* Allocate just enough space, and verify that the allocated
- * space does not cross a 4KB boundary */
-static inline struct sk_buff *myri10ge_alloc_small(struct net_device *dev,
- int bytes)
-{
- struct sk_buff *skb;
- unsigned long roundup, data, end;
-
- skb = netdev_alloc_skb(dev, bytes + 16 + MXGEFW_PAD);
- if (unlikely(skb == NULL))
- return NULL;
-
- /* Round allocated buffer to 16 byte boundary */
- data = (unsigned long)(skb->data);
- roundup = (-data) & 15UL;
- skb_reserve(skb, roundup);
- /* Verify that the data buffer does not cross a page boundary */
- data = (unsigned long)(skb->data);
- end = data + bytes + MXGEFW_PAD - 1;
- if (unlikely(((end >> 12) != (data >> 12)) && (data & 4095UL))) {
- printk(KERN_NOTICE
- "myri10ge_alloc_small: small skb crossed 4KB boundary\n");
- myri10ge_skb_cross_4k = 1;
- dev_kfree_skb_any(skb);
- skb = myri10ge_alloc_small_safe(dev, bytes);
- }
- return skb;
-}
-
-static inline int
-myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct myri10ge_priv *mgp,
- int bytes, int idx)
-{
- struct net_device *dev = mgp->dev;
- struct pci_dev *pdev = mgp->pdev;
- struct sk_buff *skb;
- dma_addr_t bus;
- int len, retval = 0;
-
- bytes += VLAN_HLEN; /* account for 802.1q vlan tag */
-
- if ((bytes + MXGEFW_PAD) > (4096 - 16) /* linux overhead */ )
- skb = myri10ge_alloc_big(dev, bytes);
- else if (myri10ge_skb_cross_4k)
- skb = myri10ge_alloc_small_safe(dev, bytes);
- else
- skb = myri10ge_alloc_small(dev, bytes);
-
- if (unlikely(skb == NULL)) {
- rx->alloc_fail++;
- retval = -ENOBUFS;
- goto done;
- }
-
- /* set len so that it only covers the area we
- * need mapped for DMA */
- len = bytes + MXGEFW_PAD;
-
- bus = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE);
- rx->info[idx].skb = skb;
- pci_unmap_addr_set(&rx->info[idx], bus, bus);
- pci_unmap_len_set(&rx->info[idx], len, len);
- rx->shadow[idx].addr_low = htonl(MYRI10GE_LOWPART_TO_U32(bus));
- rx->shadow[idx].addr_high = htonl(MYRI10GE_HIGHPART_TO_U32(bus));
-
-done:
- /* copy 8 descriptors (64-bytes) to the mcp at a time */
- if ((idx & 7) == 7) {
- if (rx->wc_fifo == NULL)
- myri10ge_submit_8rx(&rx->lanai[idx - 7],
- &rx->shadow[idx - 7]);
- else {
- mb();
- myri10ge_pio_copy(rx->wc_fifo,
- &rx->shadow[idx - 7], 64);
- }
- }
- return retval;
-}
-
static inline void myri10ge_vlan_ip_csum(struct sk_buff *skb, __wsum hw_csum)
{
struct vlan_hdr *vh = (struct vlan_hdr *)(skb->data);
@@ -1084,8 +936,8 @@
* page into an skb */
static inline int
-myri10ge_page_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
- int bytes, int len, __wsum csum)
+myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
+ int bytes, int len, __wsum csum)
{
struct sk_buff *skb;
struct skb_frag_struct rx_frags[MYRI10GE_MAX_FRAGS_PER_FRAME];
@@ -1148,54 +1000,6 @@
return 1;
}
-static inline unsigned long
-myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
- int bytes, int len, __wsum csum)
-{
- dma_addr_t bus;
- struct sk_buff *skb;
- int idx, unmap_len;
-
- idx = rx->cnt & rx->mask;
- rx->cnt++;
-
- /* save a pointer to the received skb */
- skb = rx->info[idx].skb;
- bus = pci_unmap_addr(&rx->info[idx], bus);
- unmap_len = pci_unmap_len(&rx->info[idx], len);
-
- /* try to replace the received skb */
- if (myri10ge_getbuf(rx, mgp, bytes, idx)) {
- /* drop the frame -- the old skbuf is re-cycled */
- mgp->stats.rx_dropped += 1;
- return 0;
- }
-
- /* unmap the recvd skb */
- pci_unmap_single(mgp->pdev, bus, unmap_len, PCI_DMA_FROMDEVICE);
-
- /* mcp implicitly skips 1st bytes so that packet is properly
- * aligned */
- skb_reserve(skb, MXGEFW_PAD);
-
- /* set the length of the frame */
- skb_put(skb, len);
-
- skb->protocol = eth_type_trans(skb, mgp->dev);
- if (mgp->csum_flag) {
- if ((skb->protocol == htons(ETH_P_IP)) ||
- (skb->protocol == htons(ETH_P_IPV6))) {
- skb->csum = csum;
- skb->ip_summed = CHECKSUM_COMPLETE;
- } else
- myri10ge_vlan_ip_csum(skb, csum);
- }
-
- netif_receive_skb(skb);
- mgp->dev->last_rx = jiffies;
- return 1;
-}
-
static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index)
{
struct pci_dev *pdev = mgp->pdev;
@@ -1264,13 +1068,13 @@
rx_done->entry[idx].length = 0;
checksum = csum_unfold(rx_done->entry[idx].checksum);
if (length <= mgp->small_bytes)
- rx_ok = myri10ge_page_rx_done(mgp, &mgp->rx_small,
- mgp->small_bytes,
- length, checksum);
+ rx_ok = myri10ge_rx_done(mgp, &mgp->rx_small,
+ mgp->small_bytes,
+ length, checksum);
else
- rx_ok = myri10ge_page_rx_done(mgp, &mgp->rx_big,
- mgp->big_bytes,
- length, checksum);
+ rx_ok = myri10ge_rx_done(mgp, &mgp->rx_big,
+ mgp->big_bytes,
+ length, checksum);
rx_packets += rx_ok;
rx_bytes += rx_ok * (unsigned long)length;
cnt++;
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 5/7] myri10ge: Full vlan frame in small_bytes
2006-12-11 10:23 [PATCH 0/7] myri10ge updates Brice Goglin
` (3 preceding siblings ...)
2006-12-11 10:26 ` [PATCH 4/7] myri10ge: drop contiguous skb routines Brice Goglin
@ 2006-12-11 10:26 ` Brice Goglin
2006-12-11 10:27 ` [PATCH 6/7] myri10ge: fix big_bytes in case of vlan frames Brice Goglin
2006-12-11 10:27 ` [PATCH 7/7] myri10ge: update driver version to 1.1.0 Brice Goglin
6 siblings, 0 replies; 9+ messages in thread
From: Brice Goglin @ 2006-12-11 10:26 UTC (permalink / raw)
To: Jeff Garzik, netdev
Receive full vlan frames into smalls when running with a jumbo MTU.
Signed-off-by: Brice Goglin <brice@myri.com>
---
drivers/net/myri10ge/myri10ge.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
Index: linux-git/drivers/net/myri10ge/myri10ge.c
===================================================================
--- linux-git.orig/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:52:44.000000000 +0100
+++ linux-git/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:52:51.000000000 +0100
@@ -1650,8 +1650,8 @@
? (128 - MXGEFW_PAD)
: (SMP_CACHE_BYTES - MXGEFW_PAD);
else
- /* enough for an ETH_DATA_LEN frame */
- mgp->small_bytes = ETH_FRAME_LEN;
+ /* enough for a vlan encapsulated ETH_DATA_LEN frame */
+ mgp->small_bytes = VLAN_ETH_FRAME_LEN;
/* Override the small buffer size? */
if (myri10ge_small_bytes > 0)
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 6/7] myri10ge: fix big_bytes in case of vlan frames
2006-12-11 10:23 [PATCH 0/7] myri10ge updates Brice Goglin
` (4 preceding siblings ...)
2006-12-11 10:26 ` [PATCH 5/7] myri10ge: Full vlan frame in small_bytes Brice Goglin
@ 2006-12-11 10:27 ` Brice Goglin
2006-12-11 10:27 ` [PATCH 7/7] myri10ge: update driver version to 1.1.0 Brice Goglin
6 siblings, 0 replies; 9+ messages in thread
From: Brice Goglin @ 2006-12-11 10:27 UTC (permalink / raw)
To: Jeff Garzik, netdev
Fix sizing of big_bytes in the case of vlan frames. The 4
VLAN_HLEN bytes were omitted, leading to sizing the big buffer
4 bytes smaller than it should be. Due to how rx buffers are
carved from pages, this was harmless for the common (9000, 1500)
byte MTUs, but could lead to data corruption for some MTUs.
Signed-off-by: Brice Goglin <brice@myri.com>
---
drivers/net/myri10ge/myri10ge.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
Index: linux-git/drivers/net/myri10ge/myri10ge.c
===================================================================
--- linux-git.orig/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:52:51.000000000 +0100
+++ linux-git/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:53:06.000000000 +0100
@@ -1696,11 +1696,11 @@
* tell him the buffer is larger, because we only use 1
* buffer/pkt, and the mtu will prevent overruns.
*/
- big_pow2 = dev->mtu + ETH_HLEN + MXGEFW_PAD;
+ big_pow2 = dev->mtu + ETH_HLEN + VLAN_HLEN + MXGEFW_PAD;
if (big_pow2 < MYRI10GE_ALLOC_SIZE / 2) {
while ((big_pow2 & (big_pow2 - 1)) != 0)
big_pow2++;
- mgp->big_bytes = dev->mtu + ETH_HLEN + MXGEFW_PAD;
+ mgp->big_bytes = dev->mtu + ETH_HLEN + VLAN_HLEN + MXGEFW_PAD;
} else {
big_pow2 = MYRI10GE_ALLOC_SIZE;
mgp->big_bytes = big_pow2;
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 7/7] myri10ge: update driver version to 1.1.0
2006-12-11 10:23 [PATCH 0/7] myri10ge updates Brice Goglin
` (5 preceding siblings ...)
2006-12-11 10:27 ` [PATCH 6/7] myri10ge: fix big_bytes in case of vlan frames Brice Goglin
@ 2006-12-11 10:27 ` Brice Goglin
6 siblings, 0 replies; 9+ messages in thread
From: Brice Goglin @ 2006-12-11 10:27 UTC (permalink / raw)
To: Jeff Garzik, netdev
Update driver version to 1.1.0.
Signed-off-by: Brice Goglin <brice@myri.com>
---
drivers/net/myri10ge/myri10ge.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: linux-git/drivers/net/myri10ge/myri10ge.c
===================================================================
--- linux-git.orig/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:53:06.000000000 +0100
+++ linux-git/drivers/net/myri10ge/myri10ge.c 2006-12-11 10:53:14.000000000 +0100
@@ -71,7 +71,7 @@
#include "myri10ge_mcp.h"
#include "myri10ge_mcp_gen_header.h"
-#define MYRI10GE_VERSION_STR "1.0.0"
+#define MYRI10GE_VERSION_STR "1.1.0"
MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
MODULE_AUTHOR("Maintainer: help@myri.com");
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/7] myri10ge: indentation cleanups
2006-12-11 10:24 ` [PATCH 1/7] myri10ge: indentation cleanups Brice Goglin
@ 2006-12-11 14:54 ` Jeff Garzik
0 siblings, 0 replies; 9+ messages in thread
From: Jeff Garzik @ 2006-12-11 14:54 UTC (permalink / raw)
To: Brice Goglin; +Cc: netdev
Brice Goglin wrote:
> Indentation cleanups to synchronize to our tree which is automatically
> indent'ed.
>
> Signed-off-by: Brice Goglin <brice@myri.com>
applied 1-7
thanks for splitting the page alloc stuff, that helped
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2006-12-11 14:54 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-12-11 10:23 [PATCH 0/7] myri10ge updates Brice Goglin
2006-12-11 10:24 ` [PATCH 1/7] myri10ge: indentation cleanups Brice Goglin
2006-12-11 14:54 ` Jeff Garzik
2006-12-11 10:25 ` [PATCH 2/7] myri10ge: add page-based skb routines Brice Goglin
2006-12-11 10:25 ` [PATCH 3/7] myri10ge: switch to page-based skb Brice Goglin
2006-12-11 10:26 ` [PATCH 4/7] myri10ge: drop contiguous skb routines Brice Goglin
2006-12-11 10:26 ` [PATCH 5/7] myri10ge: Full vlan frame in small_bytes Brice Goglin
2006-12-11 10:27 ` [PATCH 6/7] myri10ge: fix big_bytes in case of vlan frames Brice Goglin
2006-12-11 10:27 ` [PATCH 7/7] myri10ge: update driver version to 1.1.0 Brice Goglin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).