be2net: fix bug in rx page posting
authorSathya Perla <sathyap@serverengines.com>
Fri, 22 Jan 2010 06:52:08 +0000 (22:52 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 22 Jan 2010 06:52:08 +0000 (22:52 -0800)
Pages are posted to the rxq in such a way that more than one frag
can share the page. The last frag that uses the page unmaps the
page.  In the case when a page is not fully used (due to lack of space in rxq)
the last frag that uses the page is not being set as a "last_page_user";
instead, the next frag in the rxq is incorrectly being set.

The fix has also been tested on ppc64 with 64k pages...

Signed-off-by: Sathya Perla <sathyap@serverengines.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/benet/be_main.c

index 3a1f7902c16df0b51ad3be1803e92b3d2b23bb6c..33ab8c7f14feff67f68f0a8b88ebcae60ad2a4d4 100644 (file)
@@ -910,7 +910,7 @@ static inline struct page *be_alloc_pages(u32 size)
 static void be_post_rx_frags(struct be_adapter *adapter)
 {
        struct be_rx_page_info *page_info_tbl = adapter->rx_obj.page_info_tbl;
 static void be_post_rx_frags(struct be_adapter *adapter)
 {
        struct be_rx_page_info *page_info_tbl = adapter->rx_obj.page_info_tbl;
-       struct be_rx_page_info *page_info = NULL;
+       struct be_rx_page_info *page_info = NULL, *prev_page_info = NULL;
        struct be_queue_info *rxq = &adapter->rx_obj.q;
        struct page *pagep = NULL;
        struct be_eth_rx_d *rxd;
        struct be_queue_info *rxq = &adapter->rx_obj.q;
        struct page *pagep = NULL;
        struct be_eth_rx_d *rxd;
@@ -941,7 +941,6 @@ static void be_post_rx_frags(struct be_adapter *adapter)
                rxd = queue_head_node(rxq);
                rxd->fragpa_lo = cpu_to_le32(frag_dmaaddr & 0xFFFFFFFF);
                rxd->fragpa_hi = cpu_to_le32(upper_32_bits(frag_dmaaddr));
                rxd = queue_head_node(rxq);
                rxd->fragpa_lo = cpu_to_le32(frag_dmaaddr & 0xFFFFFFFF);
                rxd->fragpa_hi = cpu_to_le32(upper_32_bits(frag_dmaaddr));
-               queue_head_inc(rxq);
 
                /* Any space left in the current big page for another frag? */
                if ((page_offset + rx_frag_size + rx_frag_size) >
 
                /* Any space left in the current big page for another frag? */
                if ((page_offset + rx_frag_size + rx_frag_size) >
@@ -949,10 +948,13 @@ static void be_post_rx_frags(struct be_adapter *adapter)
                        pagep = NULL;
                        page_info->last_page_user = true;
                }
                        pagep = NULL;
                        page_info->last_page_user = true;
                }
+
+               prev_page_info = page_info;
+               queue_head_inc(rxq);
                page_info = &page_info_tbl[rxq->head];
        }
        if (pagep)
                page_info = &page_info_tbl[rxq->head];
        }
        if (pagep)
-               page_info->last_page_user = true;
+               prev_page_info->last_page_user = true;
 
        if (posted) {
                atomic_add(posted, &rxq->used);
 
        if (posted) {
                atomic_add(posted, &rxq->used);