Skip to content

Commit aa617aa

Browse files
Frank BlaschkaJeff Garzik
authored andcommitted
s390: scatter-gather for inbound traffic in qeth driver
For large incoming packets > PAGE_SIZE/2 qeth creates a fragmented skb by adding pointers to qdio pages to the fragment list of the skb. This avoids allocating big chunks of consecutive memory. Also copying data from the qdio buffer to the skb is economized. Signed-off-by: Frank Blaschka <[email protected]> Signed-off-by: Ursula Braun <[email protected]> Signed-off-by: Frank Pavlic <[email protected]> Signed-off-by: Jeff Garzik <[email protected]>
1 parent 44c8215 commit aa617aa

File tree

3 files changed

+165
-32
lines changed

3 files changed

+165
-32
lines changed

drivers/s390/net/qeth.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ struct qeth_perf_stats {
211211
/* initial values when measuring starts */
212212
unsigned long initial_rx_packets;
213213
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;
214218
};
215219

216220
/* Routing stuff */
@@ -341,6 +345,9 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
341345

342346
#define QETH_IP_HEADER_SIZE 40
343347

348+
/* large receive scatter gather copy break */
349+
#define QETH_RX_SG_CB (PAGE_SIZE >> 1)
350+
344351
struct qeth_hdr_layer3 {
345352
__u8 id;
346353
__u8 flags;
@@ -771,6 +778,7 @@ struct qeth_card_options {
771778
int layer2;
772779
enum qeth_large_send_types large_send;
773780
int performance_stats;
781+
int rx_sg_cb;
774782
};
775783

776784
/*
@@ -828,6 +836,7 @@ struct qeth_card {
828836
int (*orig_hard_header)(struct sk_buff *,struct net_device *,
829837
unsigned short,void *,void *,unsigned);
830838
struct qeth_osn_info osn_info;
839+
atomic_t force_alloc_skb;
831840
};
832841

833842
struct qeth_card_list_struct {

drivers/s390/net/qeth_main.c

Lines changed: 150 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,7 @@ qeth_set_intial_options(struct qeth_card *card)
10541054
else
10551055
card->options.layer2 = 0;
10561056
card->options.performance_stats = 0;
1057+
card->options.rx_sg_cb = QETH_RX_SG_CB;
10571058
}
10581059

10591060
/**
@@ -2258,6 +2259,89 @@ qeth_get_skb(unsigned int length, struct qeth_hdr *hdr)
22582259
return skb;
22592260
}
22602261

2262+
static inline int
2263+
qeth_create_skb_frag(struct qdio_buffer_element *element,
2264+
struct sk_buff **pskb,
2265+
int offset, int *pfrag, int data_len)
2266+
{
2267+
struct page *page = virt_to_page(element->addr);
2268+
if (*pfrag == 0) {
2269+
/* the upper protocol layers assume that there is data in the
2270+
* skb itself. Copy a small amount (64 bytes) to make them
2271+
* happy. */
2272+
*pskb = dev_alloc_skb(64 + QETH_FAKE_LL_LEN_ETH);
2273+
if (!(*pskb))
2274+
return -ENOMEM;
2275+
skb_reserve(*pskb, QETH_FAKE_LL_LEN_ETH);
2276+
if (data_len <= 64) {
2277+
memcpy(skb_put(*pskb, data_len), element->addr + offset,
2278+
data_len);
2279+
} else {
2280+
get_page(page);
2281+
memcpy(skb_put(*pskb, 64), element->addr + offset, 64);
2282+
skb_fill_page_desc(*pskb, *pfrag, page, offset + 64,
2283+
data_len - 64);
2284+
(*pskb)->data_len += data_len - 64;
2285+
(*pskb)->len += data_len - 64;
2286+
(*pskb)->truesize += data_len - 64;
2287+
}
2288+
} else {
2289+
get_page(page);
2290+
skb_fill_page_desc(*pskb, *pfrag, page, offset, data_len);
2291+
(*pskb)->data_len += data_len;
2292+
(*pskb)->len += data_len;
2293+
(*pskb)->truesize += data_len;
2294+
}
2295+
(*pfrag)++;
2296+
return 0;
2297+
}
2298+
2299+
static inline struct qeth_buffer_pool_entry *
2300+
qeth_find_free_buffer_pool_entry(struct qeth_card *card)
2301+
{
2302+
struct list_head *plh;
2303+
struct qeth_buffer_pool_entry *entry;
2304+
int i, free;
2305+
struct page *page;
2306+
2307+
if (list_empty(&card->qdio.in_buf_pool.entry_list))
2308+
return NULL;
2309+
2310+
list_for_each(plh, &card->qdio.in_buf_pool.entry_list) {
2311+
entry = list_entry(plh, struct qeth_buffer_pool_entry, list);
2312+
free = 1;
2313+
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
2314+
if (page_count(virt_to_page(entry->elements[i])) > 1) {
2315+
free = 0;
2316+
break;
2317+
}
2318+
}
2319+
if (free) {
2320+
list_del_init(&entry->list);
2321+
return entry;
2322+
}
2323+
}
2324+
2325+
/* no free buffer in pool so take first one and swap pages */
2326+
entry = list_entry(card->qdio.in_buf_pool.entry_list.next,
2327+
struct qeth_buffer_pool_entry, list);
2328+
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
2329+
if (page_count(virt_to_page(entry->elements[i])) > 1) {
2330+
page = alloc_page(GFP_ATOMIC|GFP_DMA);
2331+
if (!page) {
2332+
return NULL;
2333+
} else {
2334+
free_page((unsigned long)entry->elements[i]);
2335+
entry->elements[i] = page_address(page);
2336+
if (card->options.performance_stats)
2337+
card->perf_stats.sg_alloc_page_rx++;
2338+
}
2339+
}
2340+
}
2341+
list_del_init(&entry->list);
2342+
return entry;
2343+
}
2344+
22612345
static struct sk_buff *
22622346
qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
22632347
struct qdio_buffer_element **__element, int *__offset,
@@ -2269,6 +2353,8 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
22692353
int skb_len;
22702354
void *data_ptr;
22712355
int data_len;
2356+
int use_rx_sg = 0;
2357+
int frag = 0;
22722358

22732359
QETH_DBF_TEXT(trace,6,"nextskb");
22742360
/* qeth_hdr must not cross element boundaries */
@@ -2293,23 +2379,43 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
22932379

22942380
if (!skb_len)
22952381
return NULL;
2296-
if (card->options.fake_ll){
2297-
if(card->dev->type == ARPHRD_IEEE802_TR){
2298-
if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR, *hdr)))
2299-
goto no_mem;
2300-
skb_reserve(skb,QETH_FAKE_LL_LEN_TR);
2382+
if ((skb_len >= card->options.rx_sg_cb) &&
2383+
(!(card->info.type == QETH_CARD_TYPE_OSN)) &&
2384+
(!atomic_read(&card->force_alloc_skb))) {
2385+
use_rx_sg = 1;
2386+
} else {
2387+
if (card->options.fake_ll) {
2388+
if (card->dev->type == ARPHRD_IEEE802_TR) {
2389+
if (!(skb = qeth_get_skb(skb_len +
2390+
QETH_FAKE_LL_LEN_TR, *hdr)))
2391+
goto no_mem;
2392+
skb_reserve(skb, QETH_FAKE_LL_LEN_TR);
2393+
} else {
2394+
if (!(skb = qeth_get_skb(skb_len +
2395+
QETH_FAKE_LL_LEN_ETH, *hdr)))
2396+
goto no_mem;
2397+
skb_reserve(skb, QETH_FAKE_LL_LEN_ETH);
2398+
}
23012399
} else {
2302-
if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH, *hdr)))
2400+
skb = qeth_get_skb(skb_len, *hdr);
2401+
if (!skb)
23032402
goto no_mem;
2304-
skb_reserve(skb,QETH_FAKE_LL_LEN_ETH);
23052403
}
2306-
} else if (!(skb = qeth_get_skb(skb_len, *hdr)))
2307-
goto no_mem;
2404+
}
2405+
23082406
data_ptr = element->addr + offset;
23092407
while (skb_len) {
23102408
data_len = min(skb_len, (int)(element->length - offset));
2311-
if (data_len)
2312-
memcpy(skb_put(skb, data_len), data_ptr, data_len);
2409+
if (data_len) {
2410+
if (use_rx_sg) {
2411+
if (qeth_create_skb_frag(element, &skb, offset,
2412+
&frag, data_len))
2413+
goto no_mem;
2414+
} else {
2415+
memcpy(skb_put(skb, data_len), data_ptr,
2416+
data_len);
2417+
}
2418+
}
23132419
skb_len -= data_len;
23142420
if (skb_len){
23152421
if (qeth_is_last_sbale(element)){
@@ -2331,6 +2437,10 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
23312437
}
23322438
*__element = element;
23332439
*__offset = offset;
2440+
if (use_rx_sg && card->options.performance_stats) {
2441+
card->perf_stats.sg_skbs_rx++;
2442+
card->perf_stats.sg_frags_rx += skb_shinfo(skb)->nr_frags;
2443+
}
23342444
return skb;
23352445
no_mem:
23362446
if (net_ratelimit()){
@@ -2608,28 +2718,15 @@ qeth_process_inbound_buffer(struct qeth_card *card,
26082718
}
26092719
}
26102720

2611-
static struct qeth_buffer_pool_entry *
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
2721+
static int
26272722
qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
26282723
{
26292724
struct qeth_buffer_pool_entry *pool_entry;
26302725
int i;
2631-
2632-
pool_entry = qeth_get_buffer_pool_entry(card);
2726+
2727+
pool_entry = qeth_find_free_buffer_pool_entry(card);
2728+
if (!pool_entry)
2729+
return 1;
26332730
/*
26342731
* since the buffer is accessed only from the input_tasklet
26352732
* there shouldn't be a need to synchronize; also, since we use
@@ -2648,6 +2745,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
26482745
buf->buffer->element[i].flags = 0;
26492746
}
26502747
buf->state = QETH_QDIO_BUF_EMPTY;
2748+
return 0;
26512749
}
26522750

26532751
static void
@@ -2682,6 +2780,7 @@ qeth_queue_input_buffer(struct qeth_card *card, int index)
26822780
int count;
26832781
int i;
26842782
int rc;
2783+
int newcount = 0;
26852784

26862785
QETH_DBF_TEXT(trace,6,"queinbuf");
26872786
count = (index < queue->next_buf_to_init)?
@@ -2692,9 +2791,27 @@ qeth_queue_input_buffer(struct qeth_card *card, int index)
26922791
/* only requeue at a certain threshold to avoid SIGAs */
26932792
if (count >= QETH_IN_BUF_REQUEUE_THRESHOLD(card)){
26942793
for (i = queue->next_buf_to_init;
2695-
i < queue->next_buf_to_init + count; ++i)
2696-
qeth_init_input_buffer(card,
2697-
&queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]);
2794+
i < queue->next_buf_to_init + count; ++i) {
2795+
if (qeth_init_input_buffer(card,
2796+
&queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q])) {
2797+
break;
2798+
} else {
2799+
newcount++;
2800+
}
2801+
}
2802+
2803+
if (newcount < count) {
2804+
/* we are in memory shortage so we switch back to
2805+
traditional skb allocation and drop packages */
2806+
if (atomic_cmpxchg(&card->force_alloc_skb, 0, 1))
2807+
printk(KERN_WARNING
2808+
"qeth: switch to alloc skb\n");
2809+
count = newcount;
2810+
} else {
2811+
if (atomic_cmpxchg(&card->force_alloc_skb, 1, 0))
2812+
printk(KERN_WARNING "qeth: switch to sg\n");
2813+
}
2814+
26982815
/*
26992816
* according to old code it should be avoided to requeue all
27002817
* 128 buffers in order to benefit from PCI avoidance.
@@ -6494,6 +6611,7 @@ qeth_hardsetup_card(struct qeth_card *card)
64946611

64956612
QETH_DBF_TEXT(setup, 2, "hrdsetup");
64966613

6614+
atomic_set(&card->force_alloc_skb, 0);
64976615
retry:
64986616
if (retries < 3){
64996617
PRINT_WARN("Retrying to do IDX activates.\n");

drivers/s390/net/qeth_proc.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,12 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
212212
" Skb fragments sent in SG mode : %u\n\n",
213213
card->perf_stats.sg_skbs_sent,
214214
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);
215221
seq_printf(s, " large_send tx (in Kbytes) : %u\n"
216222
" large_send count : %u\n\n",
217223
card->perf_stats.large_send_bytes >> 10,

0 commit comments

Comments
 (0)