diff options
Diffstat (limited to 'drivers/s390/net/qeth_core_main.c')
| -rw-r--r-- | drivers/s390/net/qeth_core_main.c | 64 | 
1 files changed, 57 insertions, 7 deletions
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 0d8cdff8181..451f9202059 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -177,6 +177,23 @@ const char *qeth_get_cardname_short(struct qeth_card *card)  	return "n/a";  } +void qeth_set_recovery_task(struct qeth_card *card) +{ +	card->recovery_task = current; +} +EXPORT_SYMBOL_GPL(qeth_set_recovery_task); + +void qeth_clear_recovery_task(struct qeth_card *card) +{ +	card->recovery_task = NULL; +} +EXPORT_SYMBOL_GPL(qeth_clear_recovery_task); + +static bool qeth_is_recovery_task(const struct qeth_card *card) +{ +	return card->recovery_task == current; +} +  void qeth_set_allowed_threads(struct qeth_card *card, unsigned long threads,  			 int clear_start_mask)  { @@ -205,6 +222,8 @@ EXPORT_SYMBOL_GPL(qeth_threads_running);  int qeth_wait_for_threads(struct qeth_card *card, unsigned long threads)  { +	if (qeth_is_recovery_task(card)) +		return 0;  	return wait_event_interruptible(card->wait_q,  			qeth_threads_running(card, threads) == 0);  } @@ -3679,6 +3698,25 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,  }  EXPORT_SYMBOL_GPL(qeth_get_priority_queue); +int qeth_get_elements_for_frags(struct sk_buff *skb) +{ +	int cnt, length, e, elements = 0; +	struct skb_frag_struct *frag; +	char *data; + +	for (cnt = 0; cnt < skb_shinfo(skb)->nr_frags; cnt++) { +		frag = &skb_shinfo(skb)->frags[cnt]; +		data = (char *)page_to_phys(skb_frag_page(frag)) + +			frag->page_offset; +		length = frag->size; +		e = PFN_UP((unsigned long)data + length - 1) - +			PFN_DOWN((unsigned long)data); +		elements += e; +	} +	return elements; +} +EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags); +  int qeth_get_elements_no(struct qeth_card *card, void *hdr,  		     struct sk_buff *skb, int elems)  { @@ -3686,7 +3724,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr,  	int elements_needed = PFN_UP((unsigned long)skb->data + dlen - 1) -  		PFN_DOWN((unsigned long)skb->data); -	elements_needed += skb_shinfo(skb)->nr_frags; +	elements_needed += qeth_get_elements_for_frags(skb); +  	if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {  		QETH_DBF_MESSAGE(2, "Invalid size of IP packet "  			"(Number=%d / Length=%d). Discarded.\n", @@ -3771,12 +3810,23 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb,  	for (cnt = 0; cnt < skb_shinfo(skb)->nr_frags; cnt++) {  		frag = &skb_shinfo(skb)->frags[cnt]; -		buffer->element[element].addr = (char *) -			page_to_phys(skb_frag_page(frag)) -			+ frag->page_offset; -		buffer->element[element].length = frag->size; -		buffer->element[element].eflags = SBAL_EFLAGS_MIDDLE_FRAG; -		element++; +		data = (char *)page_to_phys(skb_frag_page(frag)) + +			frag->page_offset; +		length = frag->size; +		while (length > 0) { +			length_here = PAGE_SIZE - +				((unsigned long) data % PAGE_SIZE); +			if (length < length_here) +				length_here = length; + +			buffer->element[element].addr = data; +			buffer->element[element].length = length_here; +			buffer->element[element].eflags = +				SBAL_EFLAGS_MIDDLE_FRAG; +			length -= length_here; +			data += length_here; +			element++; +		}  	}  	if (buffer->element[element - 1].eflags)  |