aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 20:48:54 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 20:48:54 -0400
commit1f1c2881f673671539b25686df463518d69c4649 (patch)
tree45f4a79f2371ae4525fd621d4b5820732efa161e /drivers/s390
parent7608a864e5211df1e3c1948e2719aec7c27b9333 (diff)
parentc5e3ae8823693b260ce1f217adca8add1bc0b3de (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')
-rw-r--r--drivers/s390/net/qeth.h9
-rw-r--r--drivers/s390/net/qeth_main.c183
-rw-r--r--drivers/s390/net/qeth_proc.c6
3 files changed, 166 insertions, 32 deletions
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index b34eb82edd9..ec18bae05df 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -211,6 +211,10 @@ struct qeth_perf_stats {
211 /* initial values when measuring starts */ 211 /* initial values when measuring starts */
212 unsigned long initial_rx_packets; 212 unsigned long initial_rx_packets;
213 unsigned long initial_tx_packets; 213 unsigned long initial_tx_packets;
214 /* inbound scatter gather data */
215 unsigned int sg_skbs_rx;
216 unsigned int sg_frags_rx;
217 unsigned int sg_alloc_page_rx;
214}; 218};
215 219
216/* Routing stuff */ 220/* Routing stuff */
@@ -341,6 +345,9 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
341 345
342#define QETH_IP_HEADER_SIZE 40 346#define QETH_IP_HEADER_SIZE 40
343 347
348/* large receive scatter gather copy break */
349#define QETH_RX_SG_CB (PAGE_SIZE >> 1)
350
344struct qeth_hdr_layer3 { 351struct qeth_hdr_layer3 {
345 __u8 id; 352 __u8 id;
346 __u8 flags; 353 __u8 flags;
@@ -771,6 +778,7 @@ struct qeth_card_options {
771 int layer2; 778 int layer2;
772 enum qeth_large_send_types large_send; 779 enum qeth_large_send_types large_send;
773 int performance_stats; 780 int performance_stats;
781 int rx_sg_cb;
774}; 782};
775 783
776/* 784/*
@@ -828,6 +836,7 @@ struct qeth_card {
828 int (*orig_hard_header)(struct sk_buff *,struct net_device *, 836 int (*orig_hard_header)(struct sk_buff *,struct net_device *,
829 unsigned short,void *,void *,unsigned); 837 unsigned short,void *,void *,unsigned);
830 struct qeth_osn_info osn_info; 838 struct qeth_osn_info osn_info;
839 atomic_t force_alloc_skb;
831}; 840};
832 841
833struct qeth_card_list_struct { 842struct qeth_card_list_struct {
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 86b0c44165c..57f69434fbf 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
2263static inline int
2264qeth_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
2300static inline struct qeth_buffer_pool_entry *
2301qeth_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
2261static struct sk_buff * 2346static struct sk_buff *
2262qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, 2347qeth_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;
2335no_mem: 2446no_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
2611static struct qeth_buffer_pool_entry * 2722static int
2612qeth_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
2626static void
2627qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) 2723qeth_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
2653static void 2752static 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);
6497retry: 6616retry:
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");
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
index 89d56c8ecdd..f1ff165a5e0 100644
--- a/drivers/s390/net/qeth_proc.c
+++ b/drivers/s390/net/qeth_proc.c
@@ -212,6 +212,12 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
212 " Skb fragments sent in SG mode : %u\n\n", 212 " Skb fragments sent in SG mode : %u\n\n",
213 card->perf_stats.sg_skbs_sent, 213 card->perf_stats.sg_skbs_sent,
214 card->perf_stats.sg_frags_sent); 214 card->perf_stats.sg_frags_sent);
215 seq_printf(s, " Skbs received in SG mode : %u\n"
216 " Skb fragments received in SG mode : %u\n"
217 " Page allocations for rx SG mode : %u\n\n",
218 card->perf_stats.sg_skbs_rx,
219 card->perf_stats.sg_frags_rx,
220 card->perf_stats.sg_alloc_page_rx);
215 seq_printf(s, " large_send tx (in Kbytes) : %u\n" 221 seq_printf(s, " large_send tx (in Kbytes) : %u\n"
216 " large_send count : %u\n\n", 222 " large_send count : %u\n\n",
217 card->perf_stats.large_send_bytes >> 10, 223 card->perf_stats.large_send_bytes >> 10,