diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-16 20:48:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-16 20:48:54 -0400 |
commit | 1f1c2881f673671539b25686df463518d69c4649 (patch) | |
tree | 45f4a79f2371ae4525fd621d4b5820732efa161e /drivers/s390/net/qeth_main.c | |
parent | 7608a864e5211df1e3c1948e2719aec7c27b9333 (diff) | |
parent | c5e3ae8823693b260ce1f217adca8add1bc0b3de (diff) |
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6: (37 commits)
forcedeth bug fix: realtek phy
forcedeth bug fix: vitesse phy
forcedeth bug fix: cicada phy
atl1: reorder atl1_main functions
atl1: fix excessively indented code
atl1: cleanup atl1_main
atl1: header file cleanup
atl1: remove irq_sem
cdc-subset to support new vendor/product ID
8139cp: implement the missing dev->tx_timeout
myri10ge: Remove nonsensical limit in the tx done routine
gianfar: kill unused header
EP93XX_ETH must select MII
macb: Add multicast capability
macb: Use generic PHY layer
s390: add barriers to qeth driver
s390: scatter-gather for inbound traffic in qeth driver
eHEA: Introducing support vor DLPAR memory add
Fix a potential NULL pointer dereference in free_shared_mem() in drivers/net/s2io.c
[PATCH] softmac: Fix ESSID problem
...
Diffstat (limited to 'drivers/s390/net/qeth_main.c')
-rw-r--r-- | drivers/s390/net/qeth_main.c | 183 |
1 files changed, 151 insertions, 32 deletions
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 86b0c44165c1..57f69434fbf9 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c | |||
@@ -1054,6 +1054,7 @@ qeth_set_intial_options(struct qeth_card *card) | |||
1054 | else | 1054 | else |
1055 | card->options.layer2 = 0; | 1055 | card->options.layer2 = 0; |
1056 | card->options.performance_stats = 0; | 1056 | card->options.performance_stats = 0; |
1057 | card->options.rx_sg_cb = QETH_RX_SG_CB; | ||
1057 | } | 1058 | } |
1058 | 1059 | ||
1059 | /** | 1060 | /** |
@@ -1934,6 +1935,7 @@ qeth_send_control_data(struct qeth_card *card, int len, | |||
1934 | atomic_inc(&reply->received); | 1935 | atomic_inc(&reply->received); |
1935 | wake_up(&reply->wait_q); | 1936 | wake_up(&reply->wait_q); |
1936 | } | 1937 | } |
1938 | cpu_relax(); | ||
1937 | }; | 1939 | }; |
1938 | rc = reply->rc; | 1940 | rc = reply->rc; |
1939 | qeth_put_reply(reply); | 1941 | qeth_put_reply(reply); |
@@ -2258,6 +2260,89 @@ qeth_get_skb(unsigned int length, struct qeth_hdr *hdr) | |||
2258 | return skb; | 2260 | return skb; |
2259 | } | 2261 | } |
2260 | 2262 | ||
2263 | static inline int | ||
2264 | qeth_create_skb_frag(struct qdio_buffer_element *element, | ||
2265 | struct sk_buff **pskb, | ||
2266 | int offset, int *pfrag, int data_len) | ||
2267 | { | ||
2268 | struct page *page = virt_to_page(element->addr); | ||
2269 | if (*pfrag == 0) { | ||
2270 | /* the upper protocol layers assume that there is data in the | ||
2271 | * skb itself. Copy a small amount (64 bytes) to make them | ||
2272 | * happy. */ | ||
2273 | *pskb = dev_alloc_skb(64 + QETH_FAKE_LL_LEN_ETH); | ||
2274 | if (!(*pskb)) | ||
2275 | return -ENOMEM; | ||
2276 | skb_reserve(*pskb, QETH_FAKE_LL_LEN_ETH); | ||
2277 | if (data_len <= 64) { | ||
2278 | memcpy(skb_put(*pskb, data_len), element->addr + offset, | ||
2279 | data_len); | ||
2280 | } else { | ||
2281 | get_page(page); | ||
2282 | memcpy(skb_put(*pskb, 64), element->addr + offset, 64); | ||
2283 | skb_fill_page_desc(*pskb, *pfrag, page, offset + 64, | ||
2284 | data_len - 64); | ||
2285 | (*pskb)->data_len += data_len - 64; | ||
2286 | (*pskb)->len += data_len - 64; | ||
2287 | (*pskb)->truesize += data_len - 64; | ||
2288 | } | ||
2289 | } else { | ||
2290 | get_page(page); | ||
2291 | skb_fill_page_desc(*pskb, *pfrag, page, offset, data_len); | ||
2292 | (*pskb)->data_len += data_len; | ||
2293 | (*pskb)->len += data_len; | ||
2294 | (*pskb)->truesize += data_len; | ||
2295 | } | ||
2296 | (*pfrag)++; | ||
2297 | return 0; | ||
2298 | } | ||
2299 | |||
2300 | static inline struct qeth_buffer_pool_entry * | ||
2301 | qeth_find_free_buffer_pool_entry(struct qeth_card *card) | ||
2302 | { | ||
2303 | struct list_head *plh; | ||
2304 | struct qeth_buffer_pool_entry *entry; | ||
2305 | int i, free; | ||
2306 | struct page *page; | ||
2307 | |||
2308 | if (list_empty(&card->qdio.in_buf_pool.entry_list)) | ||
2309 | return NULL; | ||
2310 | |||
2311 | list_for_each(plh, &card->qdio.in_buf_pool.entry_list) { | ||
2312 | entry = list_entry(plh, struct qeth_buffer_pool_entry, list); | ||
2313 | free = 1; | ||
2314 | for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { | ||
2315 | if (page_count(virt_to_page(entry->elements[i])) > 1) { | ||
2316 | free = 0; | ||
2317 | break; | ||
2318 | } | ||
2319 | } | ||
2320 | if (free) { | ||
2321 | list_del_init(&entry->list); | ||
2322 | return entry; | ||
2323 | } | ||
2324 | } | ||
2325 | |||
2326 | /* no free buffer in pool so take first one and swap pages */ | ||
2327 | entry = list_entry(card->qdio.in_buf_pool.entry_list.next, | ||
2328 | struct qeth_buffer_pool_entry, list); | ||
2329 | for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { | ||
2330 | if (page_count(virt_to_page(entry->elements[i])) > 1) { | ||
2331 | page = alloc_page(GFP_ATOMIC|GFP_DMA); | ||
2332 | if (!page) { | ||
2333 | return NULL; | ||
2334 | } else { | ||
2335 | free_page((unsigned long)entry->elements[i]); | ||
2336 | entry->elements[i] = page_address(page); | ||
2337 | if (card->options.performance_stats) | ||
2338 | card->perf_stats.sg_alloc_page_rx++; | ||
2339 | } | ||
2340 | } | ||
2341 | } | ||
2342 | list_del_init(&entry->list); | ||
2343 | return entry; | ||
2344 | } | ||
2345 | |||
2261 | static struct sk_buff * | 2346 | static struct sk_buff * |
2262 | qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, | 2347 | qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, |
2263 | struct qdio_buffer_element **__element, int *__offset, | 2348 | struct qdio_buffer_element **__element, int *__offset, |
@@ -2269,6 +2354,8 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, | |||
2269 | int skb_len; | 2354 | int skb_len; |
2270 | void *data_ptr; | 2355 | void *data_ptr; |
2271 | int data_len; | 2356 | int data_len; |
2357 | int use_rx_sg = 0; | ||
2358 | int frag = 0; | ||
2272 | 2359 | ||
2273 | QETH_DBF_TEXT(trace,6,"nextskb"); | 2360 | QETH_DBF_TEXT(trace,6,"nextskb"); |
2274 | /* qeth_hdr must not cross element boundaries */ | 2361 | /* qeth_hdr must not cross element boundaries */ |
@@ -2293,23 +2380,43 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, | |||
2293 | 2380 | ||
2294 | if (!skb_len) | 2381 | if (!skb_len) |
2295 | return NULL; | 2382 | return NULL; |
2296 | if (card->options.fake_ll){ | 2383 | if ((skb_len >= card->options.rx_sg_cb) && |
2297 | if(card->dev->type == ARPHRD_IEEE802_TR){ | 2384 | (!(card->info.type == QETH_CARD_TYPE_OSN)) && |
2298 | if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR, *hdr))) | 2385 | (!atomic_read(&card->force_alloc_skb))) { |
2299 | goto no_mem; | 2386 | use_rx_sg = 1; |
2300 | skb_reserve(skb,QETH_FAKE_LL_LEN_TR); | 2387 | } else { |
2388 | if (card->options.fake_ll) { | ||
2389 | if (card->dev->type == ARPHRD_IEEE802_TR) { | ||
2390 | if (!(skb = qeth_get_skb(skb_len + | ||
2391 | QETH_FAKE_LL_LEN_TR, *hdr))) | ||
2392 | goto no_mem; | ||
2393 | skb_reserve(skb, QETH_FAKE_LL_LEN_TR); | ||
2394 | } else { | ||
2395 | if (!(skb = qeth_get_skb(skb_len + | ||
2396 | QETH_FAKE_LL_LEN_ETH, *hdr))) | ||
2397 | goto no_mem; | ||
2398 | skb_reserve(skb, QETH_FAKE_LL_LEN_ETH); | ||
2399 | } | ||
2301 | } else { | 2400 | } else { |
2302 | if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH, *hdr))) | 2401 | skb = qeth_get_skb(skb_len, *hdr); |
2402 | if (!skb) | ||
2303 | goto no_mem; | 2403 | goto no_mem; |
2304 | skb_reserve(skb,QETH_FAKE_LL_LEN_ETH); | ||
2305 | } | 2404 | } |
2306 | } else if (!(skb = qeth_get_skb(skb_len, *hdr))) | 2405 | } |
2307 | goto no_mem; | 2406 | |
2308 | data_ptr = element->addr + offset; | 2407 | data_ptr = element->addr + offset; |
2309 | while (skb_len) { | 2408 | while (skb_len) { |
2310 | data_len = min(skb_len, (int)(element->length - offset)); | 2409 | data_len = min(skb_len, (int)(element->length - offset)); |
2311 | if (data_len) | 2410 | if (data_len) { |
2312 | memcpy(skb_put(skb, data_len), data_ptr, data_len); | 2411 | if (use_rx_sg) { |
2412 | if (qeth_create_skb_frag(element, &skb, offset, | ||
2413 | &frag, data_len)) | ||
2414 | goto no_mem; | ||
2415 | } else { | ||
2416 | memcpy(skb_put(skb, data_len), data_ptr, | ||
2417 | data_len); | ||
2418 | } | ||
2419 | } | ||
2313 | skb_len -= data_len; | 2420 | skb_len -= data_len; |
2314 | if (skb_len){ | 2421 | if (skb_len){ |
2315 | if (qeth_is_last_sbale(element)){ | 2422 | if (qeth_is_last_sbale(element)){ |
@@ -2331,6 +2438,10 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, | |||
2331 | } | 2438 | } |
2332 | *__element = element; | 2439 | *__element = element; |
2333 | *__offset = offset; | 2440 | *__offset = offset; |
2441 | if (use_rx_sg && card->options.performance_stats) { | ||
2442 | card->perf_stats.sg_skbs_rx++; | ||
2443 | card->perf_stats.sg_frags_rx += skb_shinfo(skb)->nr_frags; | ||
2444 | } | ||
2334 | return skb; | 2445 | return skb; |
2335 | no_mem: | 2446 | no_mem: |
2336 | if (net_ratelimit()){ | 2447 | if (net_ratelimit()){ |
@@ -2608,28 +2719,15 @@ qeth_process_inbound_buffer(struct qeth_card *card, | |||
2608 | } | 2719 | } |
2609 | } | 2720 | } |
2610 | 2721 | ||
2611 | static struct qeth_buffer_pool_entry * | 2722 | static int |
2612 | qeth_get_buffer_pool_entry(struct qeth_card *card) | ||
2613 | { | ||
2614 | struct qeth_buffer_pool_entry *entry; | ||
2615 | |||
2616 | QETH_DBF_TEXT(trace, 6, "gtbfplen"); | ||
2617 | if (!list_empty(&card->qdio.in_buf_pool.entry_list)) { | ||
2618 | entry = list_entry(card->qdio.in_buf_pool.entry_list.next, | ||
2619 | struct qeth_buffer_pool_entry, list); | ||
2620 | list_del_init(&entry->list); | ||
2621 | return entry; | ||
2622 | } | ||
2623 | return NULL; | ||
2624 | } | ||
2625 | |||
2626 | static void | ||
2627 | qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) | 2723 | qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) |
2628 | { | 2724 | { |
2629 | struct qeth_buffer_pool_entry *pool_entry; | 2725 | struct qeth_buffer_pool_entry *pool_entry; |
2630 | int i; | 2726 | int i; |
2631 | 2727 | ||
2632 | pool_entry = qeth_get_buffer_pool_entry(card); | 2728 | pool_entry = qeth_find_free_buffer_pool_entry(card); |
2729 | if (!pool_entry) | ||
2730 | return 1; | ||
2633 | /* | 2731 | /* |
2634 | * since the buffer is accessed only from the input_tasklet | 2732 | * since the buffer is accessed only from the input_tasklet |
2635 | * there shouldn't be a need to synchronize; also, since we use | 2733 | * there shouldn't be a need to synchronize; also, since we use |
@@ -2648,6 +2746,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) | |||
2648 | buf->buffer->element[i].flags = 0; | 2746 | buf->buffer->element[i].flags = 0; |
2649 | } | 2747 | } |
2650 | buf->state = QETH_QDIO_BUF_EMPTY; | 2748 | buf->state = QETH_QDIO_BUF_EMPTY; |
2749 | return 0; | ||
2651 | } | 2750 | } |
2652 | 2751 | ||
2653 | static void | 2752 | static void |
@@ -2682,6 +2781,7 @@ qeth_queue_input_buffer(struct qeth_card *card, int index) | |||
2682 | int count; | 2781 | int count; |
2683 | int i; | 2782 | int i; |
2684 | int rc; | 2783 | int rc; |
2784 | int newcount = 0; | ||
2685 | 2785 | ||
2686 | QETH_DBF_TEXT(trace,6,"queinbuf"); | 2786 | QETH_DBF_TEXT(trace,6,"queinbuf"); |
2687 | count = (index < queue->next_buf_to_init)? | 2787 | count = (index < queue->next_buf_to_init)? |
@@ -2692,9 +2792,27 @@ qeth_queue_input_buffer(struct qeth_card *card, int index) | |||
2692 | /* only requeue at a certain threshold to avoid SIGAs */ | 2792 | /* only requeue at a certain threshold to avoid SIGAs */ |
2693 | if (count >= QETH_IN_BUF_REQUEUE_THRESHOLD(card)){ | 2793 | if (count >= QETH_IN_BUF_REQUEUE_THRESHOLD(card)){ |
2694 | for (i = queue->next_buf_to_init; | 2794 | for (i = queue->next_buf_to_init; |
2695 | i < queue->next_buf_to_init + count; ++i) | 2795 | i < queue->next_buf_to_init + count; ++i) { |
2696 | qeth_init_input_buffer(card, | 2796 | if (qeth_init_input_buffer(card, |
2697 | &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]); | 2797 | &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q])) { |
2798 | break; | ||
2799 | } else { | ||
2800 | newcount++; | ||
2801 | } | ||
2802 | } | ||
2803 | |||
2804 | if (newcount < count) { | ||
2805 | /* we are in memory shortage so we switch back to | ||
2806 | traditional skb allocation and drop packages */ | ||
2807 | if (atomic_cmpxchg(&card->force_alloc_skb, 0, 1)) | ||
2808 | printk(KERN_WARNING | ||
2809 | "qeth: switch to alloc skb\n"); | ||
2810 | count = newcount; | ||
2811 | } else { | ||
2812 | if (atomic_cmpxchg(&card->force_alloc_skb, 1, 0)) | ||
2813 | printk(KERN_WARNING "qeth: switch to sg\n"); | ||
2814 | } | ||
2815 | |||
2698 | /* | 2816 | /* |
2699 | * according to old code it should be avoided to requeue all | 2817 | * according to old code it should be avoided to requeue all |
2700 | * 128 buffers in order to benefit from PCI avoidance. | 2818 | * 128 buffers in order to benefit from PCI avoidance. |
@@ -6494,6 +6612,7 @@ qeth_hardsetup_card(struct qeth_card *card) | |||
6494 | 6612 | ||
6495 | QETH_DBF_TEXT(setup, 2, "hrdsetup"); | 6613 | QETH_DBF_TEXT(setup, 2, "hrdsetup"); |
6496 | 6614 | ||
6615 | atomic_set(&card->force_alloc_skb, 0); | ||
6497 | retry: | 6616 | retry: |
6498 | if (retries < 3){ | 6617 | if (retries < 3){ |
6499 | PRINT_WARN("Retrying to do IDX activates.\n"); | 6618 | PRINT_WARN("Retrying to do IDX activates.\n"); |