Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a264d830 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'qeth-next'



Ursula Braun says:

====================
s390: qeth patches

here are patches for the s390 qeth driver for net-next:

Patch 01 is a minor improvement for the bridgeport code in qeth.

Patches 02-07 take care about scatter/gather handling in qeth.

Patch 08 improves handling of multicast IP addresses in the qeth layer3
discipline.

Patches 09-11 improve netdev features related functions in qeth.

Patch 12 implements an outbound queue restriction for HiperSockets.

Patch 13 fixes a wrong indentation in qeth_l3_main.c causing a warning
with gcc-6.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 318d3cc0 77a83ed1
Loading
Loading
Loading
Loading
+29 −16
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/seq_file.h>
#include <linux/ethtool.h>
#include <linux/hashtable.h>
#include <linux/ip.h>

#include <net/ipv6.h>
#include <net/if_inet6.h>
@@ -144,6 +145,7 @@ struct qeth_perf_stats {
	unsigned int sg_alloc_page_rx;
	unsigned int tx_csum;
	unsigned int tx_lin;
	unsigned int tx_linfail;
};

/* Routing stuff */
@@ -559,7 +561,6 @@ enum qeth_ip_types {
	QETH_IP_TYPE_NORMAL,
	QETH_IP_TYPE_VIPA,
	QETH_IP_TYPE_RXIP,
	QETH_IP_TYPE_DEL_ALL_MC,
};

enum qeth_cmd_buffer_state {
@@ -740,17 +741,10 @@ struct qeth_vlan_vid {
	unsigned short vid;
};

enum qeth_mac_disposition {
	QETH_DISP_MAC_DELETE = 0,
	QETH_DISP_MAC_DO_NOTHING = 1,
	QETH_DISP_MAC_ADD = 2,
};

struct qeth_mac {
	u8 mac_addr[OSA_ADDR_LEN];
	u8 is_uc:1;
	u8 disp_flag:2;
	struct hlist_node hnode;
enum qeth_addr_disposition {
	QETH_DISP_ADDR_DELETE = 0,
	QETH_DISP_ADDR_DO_NOTHING = 1,
	QETH_DISP_ADDR_ADD = 2,
};

struct qeth_rx {
@@ -798,6 +792,8 @@ struct qeth_card {
	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
	struct list_head vid_list;
	DECLARE_HASHTABLE(mac_htable, 4);
	DECLARE_HASHTABLE(ip_htable, 4);
	DECLARE_HASHTABLE(ip_mc_htable, 4);
	struct work_struct kernel_thread_starter;
	spinlock_t thread_mask_lock;
	unsigned long thread_start_mask;
@@ -805,8 +801,6 @@ struct qeth_card {
	unsigned long thread_running_mask;
	struct task_struct *recovery_task;
	spinlock_t ip_lock;
	struct list_head ip_list;
	struct list_head *ip_tbd_list;
	struct qeth_ipato ipato;
	struct list_head cmd_waiter_list;
	/* QDIO buffer handling */
@@ -844,6 +838,19 @@ struct qeth_trap_id {
/*some helper functions*/
#define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "")

/**
 * qeth_get_elements_for_range() -	find number of SBALEs to cover range.
 * @start:				Start of the address range.
 * @end:				Address after the end of the range.
 *
 * Returns the number of pages, and thus QDIO buffer elements, needed to cover
 * the specified address range.
 */
static inline int qeth_get_elements_for_range(addr_t start, addr_t end)
{
	return PFN_UP(end - 1) - PFN_DOWN(start);
}

static inline int qeth_get_micros(void)
{
	return (int) (get_tod_clock() >> 12);
@@ -865,6 +872,11 @@ static inline int qeth_get_ip_version(struct sk_buff *skb)
	}
}

static inline int qeth_get_ip_protocol(struct sk_buff *skb)
{
	return ip_hdr(skb)->protocol;
}

static inline void qeth_put_buffer_pool_entry(struct qeth_card *card,
		struct qeth_buffer_pool_entry *entry)
{
@@ -981,12 +993,13 @@ int qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *, __u16,
			  int (*reply_cb)(struct qeth_card *,
					  struct qeth_reply *, unsigned long),
			  void *);
int qeth_setassparms_cb(struct qeth_card *, struct qeth_reply *, unsigned long);
struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *,
						 enum qeth_ipa_funcs,
						 __u16, __u16,
						 enum qeth_prot_versions);
int qeth_start_ipa_tx_checksum(struct qeth_card *);
int qeth_set_rx_csum(struct qeth_card *, int);
int qeth_set_features(struct net_device *, netdev_features_t);
netdev_features_t qeth_fix_features(struct net_device *, netdev_features_t);

/* exports for OSN */
int qeth_osn_assist(struct net_device *, void *, int);
+154 −77
Original line number Diff line number Diff line
@@ -1464,8 +1464,6 @@ static int qeth_setup_card(struct qeth_card *card)
	card->thread_allowed_mask = 0;
	card->thread_running_mask = 0;
	INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread);
	INIT_LIST_HEAD(&card->ip_list);
	INIT_LIST_HEAD(card->ip_tbd_list);
	INIT_LIST_HEAD(&card->cmd_waiter_list);
	init_waitqueue_head(&card->wait_q);
	/* initial options */
@@ -1500,11 +1498,6 @@ static struct qeth_card *qeth_alloc_card(void)
	if (!card)
		goto out;
	QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
	card->ip_tbd_list = kzalloc(sizeof(struct list_head), GFP_KERNEL);
	if (!card->ip_tbd_list) {
		QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
		goto out_card;
	}
	if (qeth_setup_channel(&card->read))
		goto out_ip;
	if (qeth_setup_channel(&card->write))
@@ -1517,8 +1510,6 @@ static struct qeth_card *qeth_alloc_card(void)
out_channel:
	qeth_clean_channel(&card->read);
out_ip:
	kfree(card->ip_tbd_list);
out_card:
	kfree(card);
out:
	return NULL;
@@ -3757,6 +3748,14 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
}
EXPORT_SYMBOL_GPL(qeth_qdio_output_handler);

/* We cannot use outbound queue 3 for unicast packets on HiperSockets */
static inline int qeth_cut_iqd_prio(struct qeth_card *card, int queue_num)
{
	if ((card->info.type == QETH_CARD_TYPE_IQD) && (queue_num == 3))
		return 2;
	return queue_num;
}

/**
 * Note: Function assumes that we have 4 outbound queues.
 */
@@ -3784,9 +3783,9 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
			return card->qdio.default_out_queue;
		}
		if (card->qdio.do_prio_queueing == QETH_PRIO_Q_ING_PREC)
			return ~tos >> 6 & 3;
			return qeth_cut_iqd_prio(card, ~tos >> 6 & 3);
		if (tos & IPTOS_MINCOST)
			return 3;
			return qeth_cut_iqd_prio(card, 3);
		if (tos & IPTOS_RELIABILITY)
			return 2;
		if (tos & IPTOS_THROUGHPUT)
@@ -3797,11 +3796,12 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
	case QETH_PRIO_Q_ING_SKB:
		if (skb->priority > 5)
			return 0;
		return ~skb->priority >> 1 & 3;
		return qeth_cut_iqd_prio(card, ~skb->priority >> 1 & 3);
	case QETH_PRIO_Q_ING_VLAN:
		tci = &((struct ethhdr *)skb->data)->h_proto;
		if (*tci == ETH_P_8021Q)
			return ~*(tci + 1) >> (VLAN_PRIO_SHIFT + 1) & 3;
			return qeth_cut_iqd_prio(card, ~*(tci + 1) >>
			(VLAN_PRIO_SHIFT + 1) & 3);
		break;
	default:
		break;
@@ -3810,41 +3810,54 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(qeth_get_priority_queue);

/**
 * qeth_get_elements_for_frags() -	find number of SBALEs for skb frags.
 * @skb:				SKB address
 *
 * Returns the number of pages, and thus QDIO buffer elements, needed to cover
 * fragmented part of the SKB. Returns zero for linear SKB.
 */
int qeth_get_elements_for_frags(struct sk_buff *skb)
{
	int cnt, length, e, elements = 0;
	struct skb_frag_struct *frag;
	char *data;
	int cnt, elements = 0;

	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;
		struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[cnt];

		elements += qeth_get_elements_for_range(
			(addr_t)skb_frag_address(frag),
			(addr_t)skb_frag_address(frag) + skb_frag_size(frag));
	}
	return elements;
}
EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags);

/**
 * qeth_get_elements_no() -	find number of SBALEs for skb data, inc. frags.
 * @card:			qeth card structure, to check max. elems.
 * @skb:			SKB address
 * @extra_elems:		extra elems needed, to check against max.
 *
 * Returns the number of pages, and thus QDIO buffer elements, needed to cover
 * skb data, including linear part and fragments. Checks if the result plus
 * extra_elems fits under the limit for the card. Returns 0 if it does not.
 * Note: extra_elems is not included in the returned result.
 */
int qeth_get_elements_no(struct qeth_card *card,
		     struct sk_buff *skb, int elems)
		     struct sk_buff *skb, int extra_elems)
{
	int dlen = skb->len - skb->data_len;
	int elements_needed = PFN_UP((unsigned long)skb->data + dlen - 1) -
		PFN_DOWN((unsigned long)skb->data);
	int elements = qeth_get_elements_for_range(
				(addr_t)skb->data,
				(addr_t)skb->data + skb_headlen(skb)) +
			qeth_get_elements_for_frags(skb);

	elements_needed += qeth_get_elements_for_frags(skb);

	if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
	if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
		QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
			"(Number=%d / Length=%d). Discarded.\n",
			(elements_needed+elems), skb->len);
			elements + extra_elems, skb->len);
		return 0;
	}
	return elements_needed;
	return elements;
}
EXPORT_SYMBOL_GPL(qeth_get_elements_no);

@@ -3859,7 +3872,7 @@ int qeth_hdr_chk_and_bounce(struct sk_buff *skb, struct qeth_hdr **hdr, int len)
		rest = len - inpage;
		if (rest > hroom)
			return 1;
		memmove(skb->data - rest, skb->data, skb->len - skb->data_len);
		memmove(skb->data - rest, skb->data, skb_headlen(skb));
		skb->data -= rest;
		skb->tail -= rest;
		*hdr = (struct qeth_hdr *)skb->data;
@@ -3873,7 +3886,7 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb,
	struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill,
	int offset)
{
	int length = skb->len - skb->data_len;
	int length = skb_headlen(skb);
	int length_here;
	int element;
	char *data;
@@ -4967,7 +4980,6 @@ static void qeth_core_free_card(struct qeth_card *card)
	qeth_clean_channel(&card->write);
	if (card->dev)
		free_netdev(card->dev);
	kfree(card->ip_tbd_list);
	qeth_free_qdio_buffers(card);
	unregister_service_level(&card->qeth_service_level);
	kfree(card);
@@ -5265,7 +5277,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
}
EXPORT_SYMBOL_GPL(qeth_core_get_next_skb);

static int qeth_setassparms_cb(struct qeth_card *card,
int qeth_setassparms_cb(struct qeth_card *card,
			struct qeth_reply *reply, unsigned long data)
{
	struct qeth_ipa_cmd *cmd;
@@ -5294,6 +5306,7 @@ static int qeth_setassparms_cb(struct qeth_card *card,

	return 0;
}
EXPORT_SYMBOL_GPL(qeth_setassparms_cb);

struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card,
						 enum qeth_ipa_funcs ipa_func,
@@ -5788,6 +5801,7 @@ static struct {
	{"tx do_QDIO count"},
	{"tx csum"},
	{"tx lin"},
	{"tx linfail"},
	{"cq handler count"},
	{"cq handler time"}
};
@@ -5848,8 +5862,9 @@ void qeth_core_get_ethtool_stats(struct net_device *dev,
	data[32] = card->perf_stats.outbound_do_qdio_cnt;
	data[33] = card->perf_stats.tx_csum;
	data[34] = card->perf_stats.tx_lin;
	data[35] = card->perf_stats.cq_cnt;
	data[36] = card->perf_stats.cq_time;
	data[35] = card->perf_stats.tx_linfail;
	data[36] = card->perf_stats.cq_cnt;
	data[37] = card->perf_stats.cq_time;
}
EXPORT_SYMBOL_GPL(qeth_core_get_ethtool_stats);

@@ -6048,74 +6063,136 @@ int qeth_core_ethtool_get_settings(struct net_device *netdev,
}
EXPORT_SYMBOL_GPL(qeth_core_ethtool_get_settings);

static int qeth_send_checksum_command(struct qeth_card *card)
static int qeth_send_checksum_on(struct qeth_card *card, int cstype)
{
	long rxtx_arg;
	int rc;

	rc = qeth_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM,
					  IPA_CMD_ASS_START, 0);
	rc = qeth_send_simple_setassparms(card, cstype, IPA_CMD_ASS_START, 0);
	if (rc) {
		dev_warn(&card->gdev->dev, "Starting HW checksumming for %s "
			"failed, using SW checksumming\n",
		dev_warn(&card->gdev->dev,
			 "Starting HW checksumming for %s failed, using SW checksumming\n",
			 QETH_CARD_IFNAME(card));
		return rc;
	}
	rc = qeth_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM,
					  IPA_CMD_ASS_ENABLE,
					  card->info.csum_mask);
	rxtx_arg = (cstype == IPA_OUTBOUND_CHECKSUM) ? card->info.tx_csum_mask
						     : card->info.csum_mask;
	rc = qeth_send_simple_setassparms(card, cstype, IPA_CMD_ASS_ENABLE,
					  rxtx_arg);
	if (rc) {
		dev_warn(&card->gdev->dev, "Enabling HW checksumming for %s "
			"failed, using SW checksumming\n",
		dev_warn(&card->gdev->dev,
			 "Enabling HW checksumming for %s failed, using SW checksumming\n",
			 QETH_CARD_IFNAME(card));
		return rc;
	}

	dev_info(&card->gdev->dev, "HW Checksumming (%sbound) enabled\n",
		 cstype == IPA_INBOUND_CHECKSUM ? "in" : "out");
	return 0;
}

int qeth_set_rx_csum(struct qeth_card *card, int on)
static int qeth_set_ipa_csum(struct qeth_card *card, int on, int cstype)
{
	int rc;

	if (on) {
		rc = qeth_send_checksum_command(card);
		rc = qeth_send_checksum_on(card, cstype);
		if (rc)
			return -EIO;
		dev_info(&card->gdev->dev,
			"HW Checksumming (inbound) enabled\n");
	} else {
		rc = qeth_send_simple_setassparms(card,
			IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0);
		rc = qeth_send_simple_setassparms(card, cstype,
						  IPA_CMD_ASS_STOP, 0);
		if (rc)
			return -EIO;
	}
	return 0;
}
EXPORT_SYMBOL_GPL(qeth_set_rx_csum);

int qeth_start_ipa_tx_checksum(struct qeth_card *card)
static int qeth_set_ipa_tso(struct qeth_card *card, int on)
{
	int rc = 0;
	int rc;

	if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
		return rc;
	rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM,
	QETH_CARD_TEXT(card, 3, "sttso");

	if (on) {
		rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_TSO,
						  IPA_CMD_ASS_START, 0);
		if (rc) {
			dev_warn(&card->gdev->dev,
				 "Starting outbound TCP segmentation offload for %s failed\n",
				 QETH_CARD_IFNAME(card));
			return -EIO;
		}
		dev_info(&card->gdev->dev, "Outbound TSO enabled\n");
	} else {
		rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_TSO,
						  IPA_CMD_ASS_STOP, 0);
	}
	return rc;
}

int qeth_set_features(struct net_device *dev, netdev_features_t features)
{
	struct qeth_card *card = dev->ml_priv;
	netdev_features_t changed = dev->features ^ features;
	int rc = 0;

	QETH_DBF_TEXT(SETUP, 2, "setfeat");
	QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));

	if ((changed & NETIF_F_IP_CSUM)) {
		rc = qeth_set_ipa_csum(card,
				       features & NETIF_F_IP_CSUM ? 1 : 0,
				       IPA_OUTBOUND_CHECKSUM);
		if (rc)
		goto err_out;
	rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM,
					  IPA_CMD_ASS_ENABLE,
					  card->info.tx_csum_mask);
			changed ^= NETIF_F_IP_CSUM;
	}
	if ((changed & NETIF_F_RXCSUM)) {
		rc = qeth_set_ipa_csum(card,
					features & NETIF_F_RXCSUM ? 1 : 0,
					IPA_INBOUND_CHECKSUM);
		if (rc)
		goto err_out;
			changed ^= NETIF_F_RXCSUM;
	}
	if ((changed & NETIF_F_TSO)) {
		rc = qeth_set_ipa_tso(card, features & NETIF_F_TSO ? 1 : 0);
		if (rc)
			changed ^= NETIF_F_TSO;
	}

	dev_info(&card->gdev->dev, "HW TX Checksumming enabled\n");
	return rc;
err_out:
	dev_warn(&card->gdev->dev, "Enabling HW TX checksumming for %s "
		"failed, using SW TX checksumming\n", QETH_CARD_IFNAME(card));
	return rc;
	/* everything changed successfully? */
	if ((dev->features ^ features) == changed)
		return 0;
	/* something went wrong. save changed features and return error */
	dev->features ^= changed;
	return -EIO;
}
EXPORT_SYMBOL_GPL(qeth_set_features);

netdev_features_t qeth_fix_features(struct net_device *dev,
				    netdev_features_t features)
{
	struct qeth_card *card = dev->ml_priv;

	QETH_DBF_TEXT(SETUP, 2, "fixfeat");
	if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
		features &= ~NETIF_F_IP_CSUM;
	if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM))
		features &= ~NETIF_F_RXCSUM;
	if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
		features &= ~NETIF_F_TSO;
		dev_info(&card->gdev->dev, "Outbound TSO not supported on %s\n",
			 QETH_CARD_IFNAME(card));
	}
	/* if the card isn't up, remove features that require hw changes */
	if (card->state == CARD_STATE_DOWN ||
	    card->state == CARD_STATE_RECOVER)
		features = features & ~(NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
					NETIF_F_TSO);
	QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));
	return features;
}
EXPORT_SYMBOL_GPL(qeth_start_ipa_tx_checksum);
EXPORT_SYMBOL_GPL(qeth_fix_features);

static int __init qeth_core_init(void)
{
+4 −0
Original line number Diff line number Diff line
@@ -243,6 +243,10 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev,
		card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
		card->qdio.default_out_queue = 2;
	} else if (sysfs_streq(buf, "no_prio_queueing:3")) {
		if (card->info.type == QETH_CARD_TYPE_IQD) {
			rc = -EPERM;
			goto out;
		}
		card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
		card->qdio.default_out_queue = 3;
	} else if (sysfs_streq(buf, "no_prio_queueing")) {
+7 −0
Original line number Diff line number Diff line
@@ -12,4 +12,11 @@ int qeth_l2_create_device_attributes(struct device *);
void qeth_l2_remove_device_attributes(struct device *);
void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card);

struct qeth_mac {
	u8 mac_addr[OSA_ADDR_LEN];
	u8 is_uc:1;
	u8 disp_flag:2;
	struct hlist_node hnode;
};

#endif /* __QETH_L2_H__ */
+58 −47
Original line number Diff line number Diff line
@@ -404,38 +404,6 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev,
	return rc;
}

static netdev_features_t qeth_l2_fix_features(struct net_device *dev,
					      netdev_features_t features)
{
	struct qeth_card *card = dev->ml_priv;

	QETH_DBF_TEXT(SETUP, 2, "fixfeat");
	if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
		features &= ~NETIF_F_IP_CSUM;
	if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM))
		features &= ~NETIF_F_RXCSUM;
	QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));
	return features;
}

static int qeth_l2_set_features(struct net_device *dev,
				netdev_features_t features)
{
	struct qeth_card *card = dev->ml_priv;
	netdev_features_t changed = dev->features ^ features;

	QETH_DBF_TEXT(SETUP, 2, "setfeat");
	QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));

	if (card->state == CARD_STATE_DOWN ||
	    card->state == CARD_STATE_RECOVER)
		return 0;

	if (!(changed & NETIF_F_RXCSUM))
		return 0;
	return qeth_set_rx_csum(card, features & NETIF_F_RXCSUM ? 1 : 0);
}

static void qeth_l2_stop_card(struct qeth_card *card, int recovery_mode)
{
	QETH_DBF_TEXT(SETUP , 2, "stopcard");
@@ -780,7 +748,7 @@ qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha, u8 is_uc)
			qeth_l2_mac_hash(ha->addr)) {
		if (is_uc == mac->is_uc &&
		    !memcmp(ha->addr, mac->mac_addr, OSA_ADDR_LEN)) {
			mac->disp_flag = QETH_DISP_MAC_DO_NOTHING;
			mac->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
			return;
		}
	}
@@ -792,7 +760,7 @@ qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha, u8 is_uc)

	memcpy(mac->mac_addr, ha->addr, OSA_ADDR_LEN);
	mac->is_uc = is_uc;
	mac->disp_flag = QETH_DISP_MAC_ADD;
	mac->disp_flag = QETH_DISP_ADDR_ADD;

	hash_add(card->mac_htable, &mac->hnode,
			qeth_l2_mac_hash(mac->mac_addr));
@@ -825,7 +793,7 @@ static void qeth_l2_set_rx_mode(struct net_device *dev)
		qeth_l2_add_mac(card, ha, 1);

	hash_for_each_safe(card->mac_htable, i, tmp, mac, hnode) {
		if (mac->disp_flag == QETH_DISP_MAC_DELETE) {
		if (mac->disp_flag == QETH_DISP_ADDR_DELETE) {
			if (!mac->is_uc)
				rc = qeth_l2_send_delgroupmac(card,
						mac->mac_addr);
@@ -837,15 +805,15 @@ static void qeth_l2_set_rx_mode(struct net_device *dev)
			hash_del(&mac->hnode);
			kfree(mac);

		} else if (mac->disp_flag == QETH_DISP_MAC_ADD) {
		} else if (mac->disp_flag == QETH_DISP_ADDR_ADD) {
			rc = qeth_l2_write_mac(card, mac);
			if (rc) {
				hash_del(&mac->hnode);
				kfree(mac);
			} else
				mac->disp_flag = QETH_DISP_MAC_DELETE;
				mac->disp_flag = QETH_DISP_ADDR_DELETE;
		} else
			mac->disp_flag = QETH_DISP_MAC_DELETE;
			mac->disp_flag = QETH_DISP_ADDR_DELETE;
	}

	spin_unlock_bh(&card->mclock);
@@ -869,6 +837,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
	int data_offset = -1;
	int elements_needed = 0;
	int hd_len = 0;
	int nr_frags;

	if (card->qdio.do_prio_queueing || (cast_type &&
					card->info.is_multicast_different))
@@ -892,6 +861,23 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
	}
	netif_stop_queue(dev);

	/* fix hardware limitation: as long as we do not have sbal
	 * chaining we can not send long frag lists
	 */
	if ((card->info.type != QETH_CARD_TYPE_IQD) &&
	    !qeth_get_elements_no(card, new_skb, 0)) {
		int lin_rc = skb_linearize(new_skb);

		if (card->options.performance_stats) {
			if (lin_rc)
				card->perf_stats.tx_linfail++;
			else
				card->perf_stats.tx_lin++;
		}
		if (lin_rc)
			goto tx_drop;
	}

	if (card->info.type == QETH_CARD_TYPE_OSN)
		hdr = (struct qeth_hdr *)skb->data;
	else {
@@ -943,6 +929,14 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
	if (!rc) {
		card->stats.tx_packets++;
		card->stats.tx_bytes += tx_bytes;
		if (card->options.performance_stats) {
			nr_frags = skb_shinfo(new_skb)->nr_frags;
			if (nr_frags) {
				card->perf_stats.sg_skbs_sent++;
				/* nr_frags + skb->data */
				card->perf_stats.sg_frags_sent += nr_frags + 1;
			}
		}
		if (new_skb != skb)
			dev_kfree_skb_any(skb);
		rc = NETDEV_TX_OK;
@@ -1086,8 +1080,8 @@ static const struct net_device_ops qeth_l2_netdev_ops = {
	.ndo_vlan_rx_add_vid	= qeth_l2_vlan_rx_add_vid,
	.ndo_vlan_rx_kill_vid   = qeth_l2_vlan_rx_kill_vid,
	.ndo_tx_timeout	   	= qeth_tx_timeout,
	.ndo_fix_features	= qeth_l2_fix_features,
	.ndo_set_features	= qeth_l2_set_features
	.ndo_fix_features	= qeth_fix_features,
	.ndo_set_features	= qeth_set_features
};

static int qeth_l2_setup_netdev(struct qeth_card *card)
@@ -1118,12 +1112,25 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
		&qeth_l2_ethtool_ops : &qeth_l2_osn_ops;
	card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
	if (card->info.type == QETH_CARD_TYPE_OSD && !card->info.guestlan) {
		card->dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
		/* Turn on RX offloading per default */
		card->dev->features |= NETIF_F_RXCSUM;
		card->dev->hw_features = NETIF_F_SG;
		card->dev->vlan_features = NETIF_F_SG;
		/* OSA 3S and earlier has no RX/TX support */
		if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) {
			card->dev->hw_features |= NETIF_F_IP_CSUM;
			card->dev->vlan_features |= NETIF_F_IP_CSUM;
		}
		if (qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) {
			card->dev->hw_features |= NETIF_F_RXCSUM;
			card->dev->vlan_features |= NETIF_F_RXCSUM;
		}
		/* Turn on SG per default */
		card->dev->features |= NETIF_F_SG;
	}
	card->info.broadcast_capable = 1;
	qeth_l2_request_initial_mac(card);
	card->dev->gso_max_size = (QETH_MAX_BUFFER_ELEMENTS(card) - 1) *
				  PAGE_SIZE;
	card->dev->gso_max_segs = (QETH_MAX_BUFFER_ELEMENTS(card) - 1);
	SET_NETDEV_DEV(card->dev, &card->gdev->dev);
	netif_napi_add(card->dev, &card->napi, qeth_l2_poll, QETH_NAPI_WEIGHT);
	netif_carrier_off(card->dev);
@@ -1135,9 +1142,6 @@ static int qeth_l2_start_ipassists(struct qeth_card *card)
	/* configure isolation level */
	if (qeth_set_access_ctrl_online(card, 0))
		return -ENODEV;
	if (qeth_is_supported(card, IPA_INBOUND_CHECKSUM))
		qeth_set_rx_csum(card, 1);
	qeth_start_ipa_tx_checksum(card);
	return 0;
}

@@ -1206,7 +1210,8 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
contin:
	if ((card->info.type == QETH_CARD_TYPE_OSD) ||
	    (card->info.type == QETH_CARD_TYPE_OSX)) {
		if (qeth_l2_start_ipassists(card))
		rc = qeth_l2_start_ipassists(card);
		if (rc)
			goto out_remove;
	}

@@ -1800,6 +1805,12 @@ static int qeth_bridgeport_makerc(struct qeth_card *card,
			dev_err(&card->gdev->dev,
	"The device is not configured as a Bridge Port\n");
			break;
		case 0x2B10:
		case 0x0010: /* OS mismatch */
			rc = -EPERM;
			dev_err(&card->gdev->dev,
	"A Bridge Port is already configured by a different operating system\n");
			break;
		case 0x2B14:
		case 0x0014: /* Another device is Primary */
			switch (setcmd) {
Loading