xref: /openbmc/linux/drivers/s390/net/qeth_l2_main.c (revision 50144f67)
1ab9953ffSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
24a71df50SFrank Blaschka /*
3bbcfcdc8SFrank Blaschka  *    Copyright IBM Corp. 2007, 2009
44a71df50SFrank Blaschka  *    Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
54a71df50SFrank Blaschka  *		 Frank Pavlic <fpavlic@de.ibm.com>,
64a71df50SFrank Blaschka  *		 Thomas Spatzier <tspat@de.ibm.com>,
74a71df50SFrank Blaschka  *		 Frank Blaschka <frank.blaschka@de.ibm.com>
84a71df50SFrank Blaschka  */
94a71df50SFrank Blaschka 
1074eacdb9SFrank Blaschka #define KMSG_COMPONENT "qeth"
1174eacdb9SFrank Blaschka #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1274eacdb9SFrank Blaschka 
134a71df50SFrank Blaschka #include <linux/module.h>
144a71df50SFrank Blaschka #include <linux/moduleparam.h>
154a71df50SFrank Blaschka #include <linux/string.h>
164a71df50SFrank Blaschka #include <linux/errno.h>
174a71df50SFrank Blaschka #include <linux/kernel.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
194a71df50SFrank Blaschka #include <linux/etherdevice.h>
20fa115adfSAlexandra Winter #include <linux/if_bridge.h>
21ccffad25SJiri Pirko #include <linux/list.h>
22fe5c8028SLakhvich Dmitriy #include <linux/hash.h>
23fe5c8028SLakhvich Dmitriy #include <linux/hashtable.h>
2410a6cfc0SAlexandra Winter #include <net/switchdev.h>
25a0138f59SAlexandra Winter #include <asm/chsc.h>
26fa115adfSAlexandra Winter #include <asm/css_chars.h>
27ec61bd2fSJulian Wiedmann #include <asm/setup.h>
284a71df50SFrank Blaschka #include "qeth_core.h"
29b4d72c08SEugene Crosser #include "qeth_l2.h"
304a71df50SFrank Blaschka 
31742d4d40SJulian Wiedmann static int qeth_l2_setdelmac_makerc(struct qeth_card *card, u16 retcode)
324a71df50SFrank Blaschka {
33efbbc1d5SEugene Crosser 	int rc;
344a71df50SFrank Blaschka 
35efbbc1d5SEugene Crosser 	if (retcode)
361aec42bcSThomas Richter 		QETH_CARD_TEXT_(card, 2, "err%04x", retcode);
37efbbc1d5SEugene Crosser 	switch (retcode) {
38efbbc1d5SEugene Crosser 	case IPA_RC_SUCCESS:
39efbbc1d5SEugene Crosser 		rc = 0;
40efbbc1d5SEugene Crosser 		break;
41efbbc1d5SEugene Crosser 	case IPA_RC_L2_UNSUPPORTED_CMD:
42ffb95251SEugene Crosser 		rc = -EOPNOTSUPP;
43efbbc1d5SEugene Crosser 		break;
44efbbc1d5SEugene Crosser 	case IPA_RC_L2_ADDR_TABLE_FULL:
45efbbc1d5SEugene Crosser 		rc = -ENOSPC;
46efbbc1d5SEugene Crosser 		break;
47efbbc1d5SEugene Crosser 	case IPA_RC_L2_DUP_MAC:
48efbbc1d5SEugene Crosser 	case IPA_RC_L2_DUP_LAYER3_MAC:
49bdb0cc12SJulian Wiedmann 		rc = -EADDRINUSE;
50efbbc1d5SEugene Crosser 		break;
51efbbc1d5SEugene Crosser 	case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP:
52efbbc1d5SEugene Crosser 	case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP:
53bdb0cc12SJulian Wiedmann 		rc = -EADDRNOTAVAIL;
54efbbc1d5SEugene Crosser 		break;
55efbbc1d5SEugene Crosser 	case IPA_RC_L2_MAC_NOT_FOUND:
56efbbc1d5SEugene Crosser 		rc = -ENOENT;
57efbbc1d5SEugene Crosser 		break;
58efbbc1d5SEugene Crosser 	default:
59efbbc1d5SEugene Crosser 		rc = -EIO;
60efbbc1d5SEugene Crosser 		break;
614a71df50SFrank Blaschka 	}
62efbbc1d5SEugene Crosser 	return rc;
634a71df50SFrank Blaschka }
644a71df50SFrank Blaschka 
65742d4d40SJulian Wiedmann static int qeth_l2_send_setdelmac_cb(struct qeth_card *card,
66742d4d40SJulian Wiedmann 				     struct qeth_reply *reply,
67742d4d40SJulian Wiedmann 				     unsigned long data)
68742d4d40SJulian Wiedmann {
69742d4d40SJulian Wiedmann 	struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
70742d4d40SJulian Wiedmann 
71742d4d40SJulian Wiedmann 	return qeth_l2_setdelmac_makerc(card, cmd->hdr.return_code);
72742d4d40SJulian Wiedmann }
73742d4d40SJulian Wiedmann 
74ac988d78SJulian Wiedmann static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac,
75ac988d78SJulian Wiedmann 			   enum qeth_ipa_cmds ipacmd)
76ac988d78SJulian Wiedmann {
77ac988d78SJulian Wiedmann 	struct qeth_ipa_cmd *cmd;
78ac988d78SJulian Wiedmann 	struct qeth_cmd_buffer *iob;
79ac988d78SJulian Wiedmann 
80ac988d78SJulian Wiedmann 	QETH_CARD_TEXT(card, 2, "L2sdmac");
81a59d121dSJulian Wiedmann 	iob = qeth_ipa_alloc_cmd(card, ipacmd, QETH_PROT_IPV4,
82a59d121dSJulian Wiedmann 				 IPA_DATA_SIZEOF(setdelmac));
83ac988d78SJulian Wiedmann 	if (!iob)
84ac988d78SJulian Wiedmann 		return -ENOMEM;
85ff5caa7aSJulian Wiedmann 	cmd = __ipa_cmd(iob);
8699f0b85dSJulian Wiedmann 	cmd->data.setdelmac.mac_length = ETH_ALEN;
8799f0b85dSJulian Wiedmann 	ether_addr_copy(cmd->data.setdelmac.mac, mac);
88742d4d40SJulian Wiedmann 	return qeth_send_ipa_cmd(card, iob, qeth_l2_send_setdelmac_cb, NULL);
89ac988d78SJulian Wiedmann }
90ac988d78SJulian Wiedmann 
91ac988d78SJulian Wiedmann static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
92ac988d78SJulian Wiedmann {
93ac988d78SJulian Wiedmann 	int rc;
94ac988d78SJulian Wiedmann 
95ac988d78SJulian Wiedmann 	QETH_CARD_TEXT(card, 2, "L2Setmac");
96ac988d78SJulian Wiedmann 	rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC);
97ac988d78SJulian Wiedmann 	if (rc == 0) {
98ac988d78SJulian Wiedmann 		dev_info(&card->gdev->dev,
99654e3d48SJulian Wiedmann 			 "MAC address %pM successfully registered\n", mac);
100ac988d78SJulian Wiedmann 	} else {
101ac988d78SJulian Wiedmann 		switch (rc) {
102bdb0cc12SJulian Wiedmann 		case -EADDRINUSE:
103ac988d78SJulian Wiedmann 			dev_warn(&card->gdev->dev,
104ac988d78SJulian Wiedmann 				"MAC address %pM already exists\n", mac);
105ac988d78SJulian Wiedmann 			break;
106bdb0cc12SJulian Wiedmann 		case -EADDRNOTAVAIL:
107ac988d78SJulian Wiedmann 			dev_warn(&card->gdev->dev,
108ac988d78SJulian Wiedmann 				"MAC address %pM is not authorized\n", mac);
109ac988d78SJulian Wiedmann 			break;
110ac988d78SJulian Wiedmann 		}
111ac988d78SJulian Wiedmann 	}
112ac988d78SJulian Wiedmann 	return rc;
113ac988d78SJulian Wiedmann }
114ac988d78SJulian Wiedmann 
1158174aa8aSJulian Wiedmann static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac)
1164a71df50SFrank Blaschka {
1179d0a58fbSVasily Gorbik 	enum qeth_ipa_cmds cmd = is_multicast_ether_addr(mac) ?
1188174aa8aSJulian Wiedmann 					IPA_CMD_SETGMAC : IPA_CMD_SETVMAC;
119efbbc1d5SEugene Crosser 	int rc;
120efbbc1d5SEugene Crosser 
1218174aa8aSJulian Wiedmann 	QETH_CARD_TEXT(card, 2, "L2Wmac");
1228174aa8aSJulian Wiedmann 	rc = qeth_l2_send_setdelmac(card, mac, cmd);
123bdb0cc12SJulian Wiedmann 	if (rc == -EADDRINUSE)
124e19e5be8SJulian Wiedmann 		QETH_DBF_MESSAGE(2, "MAC already registered on device %x\n",
125e19e5be8SJulian Wiedmann 				 CARD_DEVID(card));
126efbbc1d5SEugene Crosser 	else if (rc)
127e19e5be8SJulian Wiedmann 		QETH_DBF_MESSAGE(2, "Failed to register MAC on device %x: %d\n",
128e19e5be8SJulian Wiedmann 				 CARD_DEVID(card), rc);
129efbbc1d5SEugene Crosser 	return rc;
1304a71df50SFrank Blaschka }
1314a71df50SFrank Blaschka 
1328174aa8aSJulian Wiedmann static int qeth_l2_remove_mac(struct qeth_card *card, u8 *mac)
1334a71df50SFrank Blaschka {
1349d0a58fbSVasily Gorbik 	enum qeth_ipa_cmds cmd = is_multicast_ether_addr(mac) ?
1358174aa8aSJulian Wiedmann 					IPA_CMD_DELGMAC : IPA_CMD_DELVMAC;
136efbbc1d5SEugene Crosser 	int rc;
137efbbc1d5SEugene Crosser 
1388174aa8aSJulian Wiedmann 	QETH_CARD_TEXT(card, 2, "L2Rmac");
1398174aa8aSJulian Wiedmann 	rc = qeth_l2_send_setdelmac(card, mac, cmd);
140efbbc1d5SEugene Crosser 	if (rc)
141e19e5be8SJulian Wiedmann 		QETH_DBF_MESSAGE(2, "Failed to delete MAC on device %u: %d\n",
142e19e5be8SJulian Wiedmann 				 CARD_DEVID(card), rc);
143efbbc1d5SEugene Crosser 	return rc;
1444a71df50SFrank Blaschka }
1454a71df50SFrank Blaschka 
146d0c74825SJulian Wiedmann static void qeth_l2_drain_rx_mode_cache(struct qeth_card *card)
1474a71df50SFrank Blaschka {
148fe5c8028SLakhvich Dmitriy 	struct qeth_mac *mac;
149fe5c8028SLakhvich Dmitriy 	struct hlist_node *tmp;
150fe5c8028SLakhvich Dmitriy 	int i;
1514a71df50SFrank Blaschka 
1520973292fSJulian Wiedmann 	hash_for_each_safe(card->rx_mode_addrs, i, tmp, mac, hnode) {
153fe5c8028SLakhvich Dmitriy 		hash_del(&mac->hnode);
154fe5c8028SLakhvich Dmitriy 		kfree(mac);
1554a71df50SFrank Blaschka 	}
1564a71df50SFrank Blaschka }
1574a71df50SFrank Blaschka 
158b0abc4f5SJulian Wiedmann static void qeth_l2_fill_header(struct qeth_qdio_out_q *queue,
159b0abc4f5SJulian Wiedmann 				struct qeth_hdr *hdr, struct sk_buff *skb,
160eca1d5c2SJulian Wiedmann 				int ipv, unsigned int data_len)
1614a71df50SFrank Blaschka {
162eca1d5c2SJulian Wiedmann 	int cast_type = qeth_get_ether_cast_type(skb);
1630aef8392SJulian Wiedmann 	struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
1644a71df50SFrank Blaschka 
165ae79fe03SJulian Wiedmann 	hdr->hdr.l2.pkt_length = data_len;
1664a71df50SFrank Blaschka 
1670aef8392SJulian Wiedmann 	if (skb_is_gso(skb)) {
1680aef8392SJulian Wiedmann 		hdr->hdr.l2.id = QETH_HEADER_TYPE_L2_TSO;
1690aef8392SJulian Wiedmann 	} else {
1700aef8392SJulian Wiedmann 		hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2;
171eeac0e20SJulian Wiedmann 		if (skb->ip_summed == CHECKSUM_PARTIAL)
172fc69660bSJulian Wiedmann 			qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], ipv);
1730aef8392SJulian Wiedmann 	}
174fc69660bSJulian Wiedmann 
1754a71df50SFrank Blaschka 	/* set byte byte 3 to casting flags */
1764a71df50SFrank Blaschka 	if (cast_type == RTN_MULTICAST)
1774a71df50SFrank Blaschka 		hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_MULTICAST;
1784a71df50SFrank Blaschka 	else if (cast_type == RTN_BROADCAST)
1794a71df50SFrank Blaschka 		hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_BROADCAST;
1804a71df50SFrank Blaschka 	else
181ce73e10eSKlaus-Dieter Wacker 		hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_UNICAST;
1824a71df50SFrank Blaschka 
1834a71df50SFrank Blaschka 	/* VSWITCH relies on the VLAN
1844a71df50SFrank Blaschka 	 * information to be present in
1854a71df50SFrank Blaschka 	 * the QDIO header */
1864a71df50SFrank Blaschka 	if (veth->h_vlan_proto == __constant_htons(ETH_P_8021Q)) {
1874a71df50SFrank Blaschka 		hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_VLAN;
1884a71df50SFrank Blaschka 		hdr->hdr.l2.vlan_id = ntohs(veth->h_vlan_TCI);
1894a71df50SFrank Blaschka 	}
1904a71df50SFrank Blaschka }
1914a71df50SFrank Blaschka 
192742d4d40SJulian Wiedmann static int qeth_l2_setdelvlan_makerc(struct qeth_card *card, u16 retcode)
1934a71df50SFrank Blaschka {
1942aa48671SJulian Wiedmann 	if (retcode)
1952aa48671SJulian Wiedmann 		QETH_CARD_TEXT_(card, 2, "err%04x", retcode);
1962aa48671SJulian Wiedmann 
1972aa48671SJulian Wiedmann 	switch (retcode) {
1982aa48671SJulian Wiedmann 	case IPA_RC_SUCCESS:
1992aa48671SJulian Wiedmann 		return 0;
2002aa48671SJulian Wiedmann 	case IPA_RC_L2_INVALID_VLAN_ID:
2012aa48671SJulian Wiedmann 		return -EINVAL;
2022aa48671SJulian Wiedmann 	case IPA_RC_L2_DUP_VLAN_ID:
2032aa48671SJulian Wiedmann 		return -EEXIST;
2042aa48671SJulian Wiedmann 	case IPA_RC_L2_VLAN_ID_NOT_FOUND:
2052aa48671SJulian Wiedmann 		return -ENOENT;
2062aa48671SJulian Wiedmann 	case IPA_RC_L2_VLAN_ID_NOT_ALLOWED:
2072aa48671SJulian Wiedmann 		return -EPERM;
2082aa48671SJulian Wiedmann 	default:
2092aa48671SJulian Wiedmann 		return -EIO;
2102aa48671SJulian Wiedmann 	}
2112aa48671SJulian Wiedmann }
2122aa48671SJulian Wiedmann 
2132aa48671SJulian Wiedmann static int qeth_l2_send_setdelvlan_cb(struct qeth_card *card,
2142aa48671SJulian Wiedmann 				      struct qeth_reply *reply,
2152aa48671SJulian Wiedmann 				      unsigned long data)
2162aa48671SJulian Wiedmann {
2172aa48671SJulian Wiedmann 	struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
2184a71df50SFrank Blaschka 
219847a50fdSCarsten Otte 	QETH_CARD_TEXT(card, 2, "L2sdvcb");
2204a71df50SFrank Blaschka 	if (cmd->hdr.return_code) {
221e19e5be8SJulian Wiedmann 		QETH_DBF_MESSAGE(2, "Error in processing VLAN %u on device %x: %#x.\n",
2222aa48671SJulian Wiedmann 				 cmd->data.setdelvlan.vlan_id,
223e19e5be8SJulian Wiedmann 				 CARD_DEVID(card), cmd->hdr.return_code);
224847a50fdSCarsten Otte 		QETH_CARD_TEXT_(card, 2, "L2VL%4x", cmd->hdr.command);
2254a71df50SFrank Blaschka 	}
226742d4d40SJulian Wiedmann 	return qeth_l2_setdelvlan_makerc(card, cmd->hdr.return_code);
2274a71df50SFrank Blaschka }
2284a71df50SFrank Blaschka 
2294a71df50SFrank Blaschka static int qeth_l2_send_setdelvlan(struct qeth_card *card, __u16 i,
2304a71df50SFrank Blaschka 				   enum qeth_ipa_cmds ipacmd)
2314a71df50SFrank Blaschka {
2324a71df50SFrank Blaschka 	struct qeth_ipa_cmd *cmd;
2334a71df50SFrank Blaschka 	struct qeth_cmd_buffer *iob;
2344a71df50SFrank Blaschka 
235847a50fdSCarsten Otte 	QETH_CARD_TEXT_(card, 4, "L2sdv%x", ipacmd);
236a59d121dSJulian Wiedmann 	iob = qeth_ipa_alloc_cmd(card, ipacmd, QETH_PROT_IPV4,
237a59d121dSJulian Wiedmann 				 IPA_DATA_SIZEOF(setdelvlan));
2381aec42bcSThomas Richter 	if (!iob)
2391aec42bcSThomas Richter 		return -ENOMEM;
240ff5caa7aSJulian Wiedmann 	cmd = __ipa_cmd(iob);
2414a71df50SFrank Blaschka 	cmd->data.setdelvlan.vlan_id = i;
242742d4d40SJulian Wiedmann 	return qeth_send_ipa_cmd(card, iob, qeth_l2_send_setdelvlan_cb, NULL);
2434a71df50SFrank Blaschka }
2444a71df50SFrank Blaschka 
24580d5c368SPatrick McHardy static int qeth_l2_vlan_rx_add_vid(struct net_device *dev,
24680d5c368SPatrick McHardy 				   __be16 proto, u16 vid)
2474a71df50SFrank Blaschka {
248509e2562SHeiko Carstens 	struct qeth_card *card = dev->ml_priv;
2494a71df50SFrank Blaschka 
250847a50fdSCarsten Otte 	QETH_CARD_TEXT_(card, 4, "aid:%d", vid);
25110651db7SUrsula Braun 	if (!vid)
2528e586137SJiri Pirko 		return 0;
253e6e771b3SJulian Wiedmann 
2545fc692a7SJulian Wiedmann 	return qeth_l2_send_setdelvlan(card, vid, IPA_CMD_SETVLAN);
2554a71df50SFrank Blaschka }
2564a71df50SFrank Blaschka 
25780d5c368SPatrick McHardy static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev,
25880d5c368SPatrick McHardy 				    __be16 proto, u16 vid)
2594a71df50SFrank Blaschka {
260509e2562SHeiko Carstens 	struct qeth_card *card = dev->ml_priv;
2614a71df50SFrank Blaschka 
262847a50fdSCarsten Otte 	QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
2635fc692a7SJulian Wiedmann 	if (!vid)
2645fc692a7SJulian Wiedmann 		return 0;
265e6e771b3SJulian Wiedmann 
2665fc692a7SJulian Wiedmann 	return qeth_l2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN);
2674a71df50SFrank Blaschka }
2684a71df50SFrank Blaschka 
2699d6a569aSJulian Wiedmann static void qeth_l2_set_pnso_mode(struct qeth_card *card,
2709d6a569aSJulian Wiedmann 				  enum qeth_pnso_mode mode)
2719d6a569aSJulian Wiedmann {
2729d6a569aSJulian Wiedmann 	spin_lock_irq(get_ccwdev_lock(CARD_RDEV(card)));
2739d6a569aSJulian Wiedmann 	WRITE_ONCE(card->info.pnso_mode, mode);
2749d6a569aSJulian Wiedmann 	spin_unlock_irq(get_ccwdev_lock(CARD_RDEV(card)));
2759d6a569aSJulian Wiedmann 
2769d6a569aSJulian Wiedmann 	if (mode == QETH_PNSO_NONE)
2779d6a569aSJulian Wiedmann 		drain_workqueue(card->event_wq);
2789d6a569aSJulian Wiedmann }
2799d6a569aSJulian Wiedmann 
280817741a8SAlexandra Winter static void qeth_l2_dev2br_fdb_flush(struct qeth_card *card)
281817741a8SAlexandra Winter {
282817741a8SAlexandra Winter 	struct switchdev_notifier_fdb_info info;
283817741a8SAlexandra Winter 
284817741a8SAlexandra Winter 	QETH_CARD_TEXT(card, 2, "fdbflush");
285817741a8SAlexandra Winter 
286817741a8SAlexandra Winter 	info.addr = NULL;
287817741a8SAlexandra Winter 	/* flush all VLANs: */
288817741a8SAlexandra Winter 	info.vid = 0;
289817741a8SAlexandra Winter 	info.added_by_user = false;
290817741a8SAlexandra Winter 	info.offloaded = true;
291817741a8SAlexandra Winter 
292817741a8SAlexandra Winter 	call_switchdev_notifiers(SWITCHDEV_FDB_FLUSH_TO_BRIDGE,
293817741a8SAlexandra Winter 				 card->dev, &info.info, NULL);
294817741a8SAlexandra Winter }
295817741a8SAlexandra Winter 
2964a71df50SFrank Blaschka static int qeth_l2_request_initial_mac(struct qeth_card *card)
2974a71df50SFrank Blaschka {
2984a71df50SFrank Blaschka 	int rc = 0;
2994a71df50SFrank Blaschka 
30057a688aaSJulian Wiedmann 	QETH_CARD_TEXT(card, 2, "l2reqmac");
3014a71df50SFrank Blaschka 
302ec61bd2fSJulian Wiedmann 	if (MACHINE_IS_VM) {
303ec61bd2fSJulian Wiedmann 		rc = qeth_vm_request_mac(card);
304ec61bd2fSJulian Wiedmann 		if (!rc)
305ec61bd2fSJulian Wiedmann 			goto out;
306e19e5be8SJulian Wiedmann 		QETH_DBF_MESSAGE(2, "z/VM MAC Service failed on device %x: %#x\n",
307e19e5be8SJulian Wiedmann 				 CARD_DEVID(card), rc);
30857a688aaSJulian Wiedmann 		QETH_CARD_TEXT_(card, 2, "err%04x", rc);
309ec61bd2fSJulian Wiedmann 		/* fall back to alternative mechanism: */
310ec61bd2fSJulian Wiedmann 	}
311ec61bd2fSJulian Wiedmann 
312b144b99fSJulian Wiedmann 	if (!IS_OSN(card)) {
3134a71df50SFrank Blaschka 		rc = qeth_setadpparms_change_macaddr(card);
3144b7ae122SJulian Wiedmann 		if (!rc)
31521b1702aSJulian Wiedmann 			goto out;
316e19e5be8SJulian Wiedmann 		QETH_DBF_MESSAGE(2, "READ_MAC Assist failed on device %x: %#x\n",
317e19e5be8SJulian Wiedmann 				 CARD_DEVID(card), rc);
31857a688aaSJulian Wiedmann 		QETH_CARD_TEXT_(card, 2, "1err%04x", rc);
31921b1702aSJulian Wiedmann 		/* fall back once more: */
3204a71df50SFrank Blaschka 	}
32121b1702aSJulian Wiedmann 
32221b1702aSJulian Wiedmann 	/* some devices don't support a custom MAC address: */
323379ac99eSJulian Wiedmann 	if (IS_OSM(card) || IS_OSX(card))
32421b1702aSJulian Wiedmann 		return (rc) ? rc : -EADDRNOTAVAIL;
32521b1702aSJulian Wiedmann 	eth_hw_addr_random(card->dev);
32621b1702aSJulian Wiedmann 
327ec61bd2fSJulian Wiedmann out:
32857a688aaSJulian Wiedmann 	QETH_CARD_HEX(card, 2, card->dev->dev_addr, card->dev->addr_len);
3294a71df50SFrank Blaschka 	return 0;
3304a71df50SFrank Blaschka }
3314a71df50SFrank Blaschka 
332654e3d48SJulian Wiedmann static void qeth_l2_register_dev_addr(struct qeth_card *card)
333654e3d48SJulian Wiedmann {
334654e3d48SJulian Wiedmann 	if (!is_valid_ether_addr(card->dev->dev_addr))
335654e3d48SJulian Wiedmann 		qeth_l2_request_initial_mac(card);
336654e3d48SJulian Wiedmann 
337654e3d48SJulian Wiedmann 	if (!IS_OSN(card) && !qeth_l2_send_setmac(card, card->dev->dev_addr))
3389de15117SJulian Wiedmann 		card->info.dev_addr_is_registered = 1;
3399de15117SJulian Wiedmann 	else
3409de15117SJulian Wiedmann 		card->info.dev_addr_is_registered = 0;
341654e3d48SJulian Wiedmann }
342654e3d48SJulian Wiedmann 
343e22355eaSJulian Wiedmann static int qeth_l2_validate_addr(struct net_device *dev)
344e22355eaSJulian Wiedmann {
345e22355eaSJulian Wiedmann 	struct qeth_card *card = dev->ml_priv;
346e22355eaSJulian Wiedmann 
3479de15117SJulian Wiedmann 	if (card->info.dev_addr_is_registered)
348e22355eaSJulian Wiedmann 		return eth_validate_addr(dev);
349e22355eaSJulian Wiedmann 
350e22355eaSJulian Wiedmann 	QETH_CARD_TEXT(card, 4, "nomacadr");
351e22355eaSJulian Wiedmann 	return -EPERM;
352e22355eaSJulian Wiedmann }
353e22355eaSJulian Wiedmann 
3544a71df50SFrank Blaschka static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
3554a71df50SFrank Blaschka {
3564a71df50SFrank Blaschka 	struct sockaddr *addr = p;
357509e2562SHeiko Carstens 	struct qeth_card *card = dev->ml_priv;
358bcacfcbcSJulian Wiedmann 	u8 old_addr[ETH_ALEN];
3594a71df50SFrank Blaschka 	int rc = 0;
3604a71df50SFrank Blaschka 
361847a50fdSCarsten Otte 	QETH_CARD_TEXT(card, 3, "setmac");
3624a71df50SFrank Blaschka 
3638024cc9eSJulian Wiedmann 	if (IS_OSM(card) || IS_OSX(card)) {
364847a50fdSCarsten Otte 		QETH_CARD_TEXT(card, 3, "setmcTYP");
3654a71df50SFrank Blaschka 		return -EOPNOTSUPP;
3664a71df50SFrank Blaschka 	}
36799f0b85dSJulian Wiedmann 	QETH_CARD_HEX(card, 3, addr->sa_data, ETH_ALEN);
368bcacfcbcSJulian Wiedmann 	if (!is_valid_ether_addr(addr->sa_data))
369bcacfcbcSJulian Wiedmann 		return -EADDRNOTAVAIL;
370bcacfcbcSJulian Wiedmann 
371bcacfcbcSJulian Wiedmann 	/* don't register the same address twice */
372bcacfcbcSJulian Wiedmann 	if (ether_addr_equal_64bits(dev->dev_addr, addr->sa_data) &&
3739de15117SJulian Wiedmann 	    card->info.dev_addr_is_registered)
374e6e771b3SJulian Wiedmann 		return 0;
375bcacfcbcSJulian Wiedmann 
376bcacfcbcSJulian Wiedmann 	/* add the new address, switch over, drop the old */
3774a71df50SFrank Blaschka 	rc = qeth_l2_send_setmac(card, addr->sa_data);
378bcacfcbcSJulian Wiedmann 	if (rc)
379e6e771b3SJulian Wiedmann 		return rc;
380bcacfcbcSJulian Wiedmann 	ether_addr_copy(old_addr, dev->dev_addr);
381bcacfcbcSJulian Wiedmann 	ether_addr_copy(dev->dev_addr, addr->sa_data);
382bcacfcbcSJulian Wiedmann 
3839de15117SJulian Wiedmann 	if (card->info.dev_addr_is_registered)
384bcacfcbcSJulian Wiedmann 		qeth_l2_remove_mac(card, old_addr);
3859de15117SJulian Wiedmann 	card->info.dev_addr_is_registered = 1;
386e6e771b3SJulian Wiedmann 	return 0;
3874a71df50SFrank Blaschka }
3884a71df50SFrank Blaschka 
38959b757a9SJulian Wiedmann static void qeth_l2_promisc_to_bridge(struct qeth_card *card, bool enable)
3900db587b0SEugene Crosser {
3910db587b0SEugene Crosser 	int role;
3920db587b0SEugene Crosser 	int rc;
3930db587b0SEugene Crosser 
3940db587b0SEugene Crosser 	QETH_CARD_TEXT(card, 3, "pmisc2br");
3950db587b0SEugene Crosser 
39659b757a9SJulian Wiedmann 	if (enable) {
3970db587b0SEugene Crosser 		if (card->options.sbp.reflect_promisc_primary)
3980db587b0SEugene Crosser 			role = QETH_SBP_ROLE_PRIMARY;
3990db587b0SEugene Crosser 		else
4000db587b0SEugene Crosser 			role = QETH_SBP_ROLE_SECONDARY;
4010db587b0SEugene Crosser 	} else
4020db587b0SEugene Crosser 		role = QETH_SBP_ROLE_NONE;
4030db587b0SEugene Crosser 
4040db587b0SEugene Crosser 	rc = qeth_bridgeport_setrole(card, role);
40559b757a9SJulian Wiedmann 	QETH_CARD_TEXT_(card, 2, "bpm%c%04x", enable ? '+' : '-', rc);
4060db587b0SEugene Crosser 	if (!rc) {
4070db587b0SEugene Crosser 		card->options.sbp.role = role;
40859b757a9SJulian Wiedmann 		card->info.promisc_mode = enable;
40959b757a9SJulian Wiedmann 	}
4100db587b0SEugene Crosser }
411fe5c8028SLakhvich Dmitriy 
41259b757a9SJulian Wiedmann static void qeth_l2_set_promisc_mode(struct qeth_card *card)
41359b757a9SJulian Wiedmann {
41459b757a9SJulian Wiedmann 	bool enable = card->dev->flags & IFF_PROMISC;
41559b757a9SJulian Wiedmann 
41659b757a9SJulian Wiedmann 	if (card->info.promisc_mode == enable)
41759b757a9SJulian Wiedmann 		return;
41859b757a9SJulian Wiedmann 
419c8183f54SJulian Wiedmann 	if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) {
42059b757a9SJulian Wiedmann 		qeth_setadp_promisc_mode(card, enable);
421c8183f54SJulian Wiedmann 	} else {
422c8183f54SJulian Wiedmann 		mutex_lock(&card->sbp_lock);
423c8183f54SJulian Wiedmann 		if (card->options.sbp.reflect_promisc)
42459b757a9SJulian Wiedmann 			qeth_l2_promisc_to_bridge(card, enable);
425c8183f54SJulian Wiedmann 		mutex_unlock(&card->sbp_lock);
426c8183f54SJulian Wiedmann 	}
427fe5c8028SLakhvich Dmitriy }
42859b757a9SJulian Wiedmann 
429fe5c8028SLakhvich Dmitriy /* New MAC address is added to the hash table and marked to be written on card
430fe5c8028SLakhvich Dmitriy  * only if there is not in the hash table storage already
431fe5c8028SLakhvich Dmitriy  *
432fe5c8028SLakhvich Dmitriy */
4334641b027SJulian Wiedmann static void qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha)
434fe5c8028SLakhvich Dmitriy {
435cef6ff22SJulian Wiedmann 	u32 mac_hash = get_unaligned((u32 *)(&ha->addr[2]));
436fe5c8028SLakhvich Dmitriy 	struct qeth_mac *mac;
437fe5c8028SLakhvich Dmitriy 
4380973292fSJulian Wiedmann 	hash_for_each_possible(card->rx_mode_addrs, mac, hnode, mac_hash) {
43999f0b85dSJulian Wiedmann 		if (ether_addr_equal_64bits(ha->addr, mac->mac_addr)) {
4405f78e29cSLakhvich Dmitriy 			mac->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
441fe5c8028SLakhvich Dmitriy 			return;
442fe5c8028SLakhvich Dmitriy 		}
4430db587b0SEugene Crosser 	}
4440db587b0SEugene Crosser 
445fe5c8028SLakhvich Dmitriy 	mac = kzalloc(sizeof(struct qeth_mac), GFP_ATOMIC);
446fe5c8028SLakhvich Dmitriy 	if (!mac)
447fe5c8028SLakhvich Dmitriy 		return;
448fe5c8028SLakhvich Dmitriy 
44999f0b85dSJulian Wiedmann 	ether_addr_copy(mac->mac_addr, ha->addr);
4505f78e29cSLakhvich Dmitriy 	mac->disp_flag = QETH_DISP_ADDR_ADD;
451fe5c8028SLakhvich Dmitriy 
4520973292fSJulian Wiedmann 	hash_add(card->rx_mode_addrs, &mac->hnode, mac_hash);
453fe5c8028SLakhvich Dmitriy }
454fe5c8028SLakhvich Dmitriy 
455d0c74825SJulian Wiedmann static void qeth_l2_rx_mode_work(struct work_struct *work)
4564a71df50SFrank Blaschka {
457d0c74825SJulian Wiedmann 	struct qeth_card *card = container_of(work, struct qeth_card,
458d0c74825SJulian Wiedmann 					      rx_mode_work);
459d0c74825SJulian Wiedmann 	struct net_device *dev = card->dev;
460ccffad25SJiri Pirko 	struct netdev_hw_addr *ha;
461fe5c8028SLakhvich Dmitriy 	struct qeth_mac *mac;
462fe5c8028SLakhvich Dmitriy 	struct hlist_node *tmp;
463fe5c8028SLakhvich Dmitriy 	int i;
464fe5c8028SLakhvich Dmitriy 	int rc;
4654a71df50SFrank Blaschka 
466847a50fdSCarsten Otte 	QETH_CARD_TEXT(card, 3, "setmulti");
467fe5c8028SLakhvich Dmitriy 
468d0c74825SJulian Wiedmann 	netif_addr_lock_bh(dev);
46922bedad3SJiri Pirko 	netdev_for_each_mc_addr(ha, dev)
4704641b027SJulian Wiedmann 		qeth_l2_add_mac(card, ha);
47132e7bfc4SJiri Pirko 	netdev_for_each_uc_addr(ha, dev)
4724641b027SJulian Wiedmann 		qeth_l2_add_mac(card, ha);
473d0c74825SJulian Wiedmann 	netif_addr_unlock_bh(dev);
474fe5c8028SLakhvich Dmitriy 
4750973292fSJulian Wiedmann 	hash_for_each_safe(card->rx_mode_addrs, i, tmp, mac, hnode) {
47600c163f1SJulian Wiedmann 		switch (mac->disp_flag) {
47700c163f1SJulian Wiedmann 		case QETH_DISP_ADDR_DELETE:
4788174aa8aSJulian Wiedmann 			qeth_l2_remove_mac(card, mac->mac_addr);
479fe5c8028SLakhvich Dmitriy 			hash_del(&mac->hnode);
480fe5c8028SLakhvich Dmitriy 			kfree(mac);
48100c163f1SJulian Wiedmann 			break;
48200c163f1SJulian Wiedmann 		case QETH_DISP_ADDR_ADD:
4838174aa8aSJulian Wiedmann 			rc = qeth_l2_write_mac(card, mac->mac_addr);
484fe5c8028SLakhvich Dmitriy 			if (rc) {
485fe5c8028SLakhvich Dmitriy 				hash_del(&mac->hnode);
486fe5c8028SLakhvich Dmitriy 				kfree(mac);
48700c163f1SJulian Wiedmann 				break;
48800c163f1SJulian Wiedmann 			}
489df561f66SGustavo A. R. Silva 			fallthrough;
49000c163f1SJulian Wiedmann 		default:
49100c163f1SJulian Wiedmann 			/* for next call to set_rx_mode(): */
4925f78e29cSLakhvich Dmitriy 			mac->disp_flag = QETH_DISP_ADDR_DELETE;
49300c163f1SJulian Wiedmann 		}
494fe5c8028SLakhvich Dmitriy 	}
4957db2266aSFrank Blaschka 
49659b757a9SJulian Wiedmann 	qeth_l2_set_promisc_mode(card);
4974a71df50SFrank Blaschka }
4984a71df50SFrank Blaschka 
4997286384bSJulian Wiedmann static int qeth_l2_xmit_osn(struct qeth_card *card, struct sk_buff *skb,
5007286384bSJulian Wiedmann 			    struct qeth_qdio_out_q *queue)
5017286384bSJulian Wiedmann {
502b413ff8aSJulian Wiedmann 	gfp_t gfp = GFP_ATOMIC | (skb_pfmemalloc(skb) ? __GFP_MEMALLOC : 0);
50369d7ce80SJulian Wiedmann 	struct qeth_hdr *hdr = (struct qeth_hdr *)skb->data;
50469d7ce80SJulian Wiedmann 	addr_t end = (addr_t)(skb->data + sizeof(*hdr));
50569d7ce80SJulian Wiedmann 	addr_t start = (addr_t)skb->data;
50669d7ce80SJulian Wiedmann 	unsigned int elements = 0;
50769d7ce80SJulian Wiedmann 	unsigned int hd_len = 0;
50869d7ce80SJulian Wiedmann 	int rc;
5097286384bSJulian Wiedmann 
5107286384bSJulian Wiedmann 	if (skb->protocol == htons(ETH_P_IPV6))
5117286384bSJulian Wiedmann 		return -EPROTONOSUPPORT;
5127286384bSJulian Wiedmann 
51369d7ce80SJulian Wiedmann 	if (qeth_get_elements_for_range(start, end) > 1) {
51469d7ce80SJulian Wiedmann 		/* Misaligned HW header, move it to its own buffer element. */
515b413ff8aSJulian Wiedmann 		hdr = kmem_cache_alloc(qeth_core_header_cache, gfp);
51669d7ce80SJulian Wiedmann 		if (!hdr)
51769d7ce80SJulian Wiedmann 			return -ENOMEM;
51869d7ce80SJulian Wiedmann 		hd_len = sizeof(*hdr);
51969d7ce80SJulian Wiedmann 		skb_copy_from_linear_data(skb, (char *)hdr, hd_len);
52069d7ce80SJulian Wiedmann 		elements++;
52169d7ce80SJulian Wiedmann 	}
52269d7ce80SJulian Wiedmann 
52369d7ce80SJulian Wiedmann 	elements += qeth_count_elements(skb, hd_len);
5244e26c5feSJulian Wiedmann 	if (elements > queue->max_elements) {
52569d7ce80SJulian Wiedmann 		rc = -E2BIG;
52669d7ce80SJulian Wiedmann 		goto out;
52769d7ce80SJulian Wiedmann 	}
52869d7ce80SJulian Wiedmann 
52969d7ce80SJulian Wiedmann 	rc = qeth_do_send_packet(card, queue, skb, hdr, hd_len, hd_len,
53069d7ce80SJulian Wiedmann 				 elements);
53169d7ce80SJulian Wiedmann out:
53269d7ce80SJulian Wiedmann 	if (rc && hd_len)
53369d7ce80SJulian Wiedmann 		kmem_cache_free(qeth_core_header_cache, hdr);
53469d7ce80SJulian Wiedmann 	return rc;
5357286384bSJulian Wiedmann }
5367286384bSJulian Wiedmann 
537e38db6beSJulian Wiedmann static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb,
538e38db6beSJulian Wiedmann 					   struct net_device *dev)
5394a71df50SFrank Blaschka {
540509e2562SHeiko Carstens 	struct qeth_card *card = dev->ml_priv;
5413a18d754SJulian Wiedmann 	u16 txq = skb_get_queue_mapping(skb);
542290b8348SStefan Raspl 	struct qeth_qdio_out_q *queue;
5437286384bSJulian Wiedmann 	int rc;
5444a71df50SFrank Blaschka 
545eeac0e20SJulian Wiedmann 	if (!skb_is_gso(skb))
546eeac0e20SJulian Wiedmann 		qdisc_skb_cb(skb)->pkt_len = skb->len;
5473a18d754SJulian Wiedmann 	if (IS_IQD(card))
54854a50941SJulian Wiedmann 		txq = qeth_iqd_translate_txq(dev, txq);
54973dc2dafSJulian Wiedmann 	queue = card->qdio.out_qs[txq];
550b0abc4f5SJulian Wiedmann 
5515f89eca5SJulian Wiedmann 	if (IS_OSN(card))
5527286384bSJulian Wiedmann 		rc = qeth_l2_xmit_osn(card, skb, queue);
5535f89eca5SJulian Wiedmann 	else
55473dc2dafSJulian Wiedmann 		rc = qeth_xmit(card, skb, queue, qeth_get_ip_version(skb),
55558aa2491SJulian Wiedmann 			       qeth_l2_fill_header);
5564a71df50SFrank Blaschka 
557eeac0e20SJulian Wiedmann 	if (!rc)
5587286384bSJulian Wiedmann 		return NETDEV_TX_OK;
5594a71df50SFrank Blaschka 
560b0abc4f5SJulian Wiedmann 	QETH_TXQ_STAT_INC(queue, tx_dropped);
561104b4859SJulian Wiedmann 	kfree_skb(skb);
5624a71df50SFrank Blaschka 	return NETDEV_TX_OK;
5634a71df50SFrank Blaschka }
5644a71df50SFrank Blaschka 
5653a18d754SJulian Wiedmann static u16 qeth_l2_select_queue(struct net_device *dev, struct sk_buff *skb,
5663a18d754SJulian Wiedmann 				struct net_device *sb_dev)
5673a18d754SJulian Wiedmann {
56873dc2dafSJulian Wiedmann 	struct qeth_card *card = dev->ml_priv;
56973dc2dafSJulian Wiedmann 
57073dc2dafSJulian Wiedmann 	if (IS_IQD(card))
57173dc2dafSJulian Wiedmann 		return qeth_iqd_select_queue(dev, skb,
57258aa2491SJulian Wiedmann 					     qeth_get_ether_cast_type(skb),
5733a18d754SJulian Wiedmann 					     sb_dev);
574949bbf4dSJulian Wiedmann 	if (qeth_uses_tx_prio_queueing(card))
575949bbf4dSJulian Wiedmann 		return qeth_get_priority_queue(card, skb);
5761c103cf8SJulian Wiedmann 
577949bbf4dSJulian Wiedmann 	return netdev_pick_tx(dev, skb, sb_dev);
5783a18d754SJulian Wiedmann }
5793a18d754SJulian Wiedmann 
580d0c74825SJulian Wiedmann static void qeth_l2_set_rx_mode(struct net_device *dev)
581d0c74825SJulian Wiedmann {
582d0c74825SJulian Wiedmann 	struct qeth_card *card = dev->ml_priv;
583d0c74825SJulian Wiedmann 
584d0c74825SJulian Wiedmann 	schedule_work(&card->rx_mode_work);
585d0c74825SJulian Wiedmann }
586d0c74825SJulian Wiedmann 
587a0138f59SAlexandra Winter /**
588a0138f59SAlexandra Winter  *	qeth_l2_pnso() - perform network subchannel operation
589a0138f59SAlexandra Winter  *	@card: qeth_card structure pointer
5904fea49a7SAlexandra Winter  *	@oc: Operation Code
591a0138f59SAlexandra Winter  *	@cnc: Boolean Change-Notification Control
592a0138f59SAlexandra Winter  *	@cb: Callback function will be executed for each element
593a0138f59SAlexandra Winter  *		of the address list
594a0138f59SAlexandra Winter  *	@priv: Pointer to pass to the callback function.
595a0138f59SAlexandra Winter  *
596a0138f59SAlexandra Winter  *	Collects network information in a network address list and calls the
597a0138f59SAlexandra Winter  *	callback function for every entry in the list. If "change-notification-
598a0138f59SAlexandra Winter  *	control" is set, further changes in the address list will be reported
599a0138f59SAlexandra Winter  *	via the IPA command.
600a0138f59SAlexandra Winter  */
6014fea49a7SAlexandra Winter static int qeth_l2_pnso(struct qeth_card *card, u8 oc, int cnc,
602a0138f59SAlexandra Winter 			void (*cb)(void *priv, struct chsc_pnso_naid_l2 *entry),
603a0138f59SAlexandra Winter 			void *priv)
604a0138f59SAlexandra Winter {
605a0138f59SAlexandra Winter 	struct ccw_device *ddev = CARD_DDEV(card);
606a0138f59SAlexandra Winter 	struct chsc_pnso_area *rr;
607a0138f59SAlexandra Winter 	u32 prev_instance = 0;
608a0138f59SAlexandra Winter 	int isfirstblock = 1;
609a0138f59SAlexandra Winter 	int i, size, elems;
610a0138f59SAlexandra Winter 	int rc;
611a0138f59SAlexandra Winter 
612a0138f59SAlexandra Winter 	rr = (struct chsc_pnso_area *)get_zeroed_page(GFP_KERNEL);
613a0138f59SAlexandra Winter 	if (rr == NULL)
614a0138f59SAlexandra Winter 		return -ENOMEM;
615a0138f59SAlexandra Winter 	do {
6164fea49a7SAlexandra Winter 		QETH_CARD_TEXT(card, 2, "PNSO");
617a0138f59SAlexandra Winter 		/* on the first iteration, naihdr.resume_token will be zero */
6184fea49a7SAlexandra Winter 		rc = ccw_device_pnso(ddev, rr, oc, rr->naihdr.resume_token,
6194fea49a7SAlexandra Winter 				     cnc);
620a0138f59SAlexandra Winter 		if (rc)
621a0138f59SAlexandra Winter 			continue;
622a0138f59SAlexandra Winter 		if (cb == NULL)
623a0138f59SAlexandra Winter 			continue;
624a0138f59SAlexandra Winter 
625a0138f59SAlexandra Winter 		size = rr->naihdr.naids;
626a0138f59SAlexandra Winter 		if (size != sizeof(struct chsc_pnso_naid_l2)) {
627a0138f59SAlexandra Winter 			WARN_ON_ONCE(1);
628a0138f59SAlexandra Winter 			continue;
629a0138f59SAlexandra Winter 		}
630a0138f59SAlexandra Winter 
631a0138f59SAlexandra Winter 		elems = (rr->response.length - sizeof(struct chsc_header) -
632a0138f59SAlexandra Winter 			 sizeof(struct chsc_pnso_naihdr)) / size;
633a0138f59SAlexandra Winter 
634a0138f59SAlexandra Winter 		if (!isfirstblock && (rr->naihdr.instance != prev_instance)) {
635a0138f59SAlexandra Winter 			/* Inform the caller that they need to scrap */
636a0138f59SAlexandra Winter 			/* the data that was already reported via cb */
637a0138f59SAlexandra Winter 			rc = -EAGAIN;
638a0138f59SAlexandra Winter 			break;
639a0138f59SAlexandra Winter 		}
640a0138f59SAlexandra Winter 		isfirstblock = 0;
641a0138f59SAlexandra Winter 		prev_instance = rr->naihdr.instance;
642a0138f59SAlexandra Winter 		for (i = 0; i < elems; i++)
643a0138f59SAlexandra Winter 			(*cb)(priv, &rr->entries[i]);
644a0138f59SAlexandra Winter 	} while ((rc == -EBUSY) || (!rc && /* list stored */
645a0138f59SAlexandra Winter 		   /* resume token is non-zero => list incomplete */
646a0138f59SAlexandra Winter 		   (rr->naihdr.resume_token.t1 || rr->naihdr.resume_token.t2)));
647a0138f59SAlexandra Winter 
648a0138f59SAlexandra Winter 	if (rc)
649a0138f59SAlexandra Winter 		QETH_CARD_TEXT_(card, 2, "PNrp%04x", rr->response.code);
650a0138f59SAlexandra Winter 
651a0138f59SAlexandra Winter 	free_page((unsigned long)rr);
652a0138f59SAlexandra Winter 	return rc;
653a0138f59SAlexandra Winter }
654a0138f59SAlexandra Winter 
65510a6cfc0SAlexandra Winter static bool qeth_is_my_net_if_token(struct qeth_card *card,
65610a6cfc0SAlexandra Winter 				    struct net_if_token *token)
65710a6cfc0SAlexandra Winter {
65810a6cfc0SAlexandra Winter 	return ((card->info.ddev_devno == token->devnum) &&
65910a6cfc0SAlexandra Winter 		(card->info.cssid == token->cssid) &&
66010a6cfc0SAlexandra Winter 		(card->info.iid == token->iid) &&
66110a6cfc0SAlexandra Winter 		(card->info.ssid == token->ssid) &&
66210a6cfc0SAlexandra Winter 		(card->info.chpid == token->chpid) &&
66310a6cfc0SAlexandra Winter 		(card->info.chid == token->chid));
66410a6cfc0SAlexandra Winter }
66510a6cfc0SAlexandra Winter 
66610a6cfc0SAlexandra Winter /**
66710a6cfc0SAlexandra Winter  *	qeth_l2_dev2br_fdb_notify() - update fdb of master bridge
66810a6cfc0SAlexandra Winter  *	@card:	qeth_card structure pointer
66910a6cfc0SAlexandra Winter  *	@code:	event bitmask: high order bit 0x80 set to
67010a6cfc0SAlexandra Winter  *				1 - removal of an object
67110a6cfc0SAlexandra Winter  *				0 - addition of an object
67210a6cfc0SAlexandra Winter  *			       Object type(s):
67310a6cfc0SAlexandra Winter  *				0x01 - VLAN, 0x02 - MAC, 0x03 - VLAN and MAC
67410a6cfc0SAlexandra Winter  *	@token: "network token" structure identifying 'physical' location
67510a6cfc0SAlexandra Winter  *		of the target
67610a6cfc0SAlexandra Winter  *	@addr_lnid: structure with MAC address and VLAN ID of the target
67710a6cfc0SAlexandra Winter  */
67810a6cfc0SAlexandra Winter static void qeth_l2_dev2br_fdb_notify(struct qeth_card *card, u8 code,
67910a6cfc0SAlexandra Winter 				      struct net_if_token *token,
68010a6cfc0SAlexandra Winter 				      struct mac_addr_lnid *addr_lnid)
68110a6cfc0SAlexandra Winter {
68210a6cfc0SAlexandra Winter 	struct switchdev_notifier_fdb_info info;
68310a6cfc0SAlexandra Winter 	u8 ntfy_mac[ETH_ALEN];
68410a6cfc0SAlexandra Winter 
68510a6cfc0SAlexandra Winter 	ether_addr_copy(ntfy_mac, addr_lnid->mac);
68610a6cfc0SAlexandra Winter 	/* Ignore VLAN only changes */
68710a6cfc0SAlexandra Winter 	if (!(code & IPA_ADDR_CHANGE_CODE_MACADDR))
68810a6cfc0SAlexandra Winter 		return;
68910a6cfc0SAlexandra Winter 	/* Ignore mcast entries */
69010a6cfc0SAlexandra Winter 	if (is_multicast_ether_addr(ntfy_mac))
69110a6cfc0SAlexandra Winter 		return;
69210a6cfc0SAlexandra Winter 	/* Ignore my own addresses */
69310a6cfc0SAlexandra Winter 	if (qeth_is_my_net_if_token(card, token))
69410a6cfc0SAlexandra Winter 		return;
69510a6cfc0SAlexandra Winter 
69610a6cfc0SAlexandra Winter 	info.addr = ntfy_mac;
69710a6cfc0SAlexandra Winter 	/* don't report VLAN IDs */
69810a6cfc0SAlexandra Winter 	info.vid = 0;
69910a6cfc0SAlexandra Winter 	info.added_by_user = false;
70010a6cfc0SAlexandra Winter 	info.offloaded = true;
70110a6cfc0SAlexandra Winter 
70210a6cfc0SAlexandra Winter 	if (code & IPA_ADDR_CHANGE_CODE_REMOVAL) {
70310a6cfc0SAlexandra Winter 		call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
70410a6cfc0SAlexandra Winter 					 card->dev, &info.info, NULL);
70510a6cfc0SAlexandra Winter 		QETH_CARD_TEXT(card, 4, "andelmac");
70610a6cfc0SAlexandra Winter 		QETH_CARD_TEXT_(card, 4,
70710a6cfc0SAlexandra Winter 				"mc%012lx", ether_addr_to_u64(ntfy_mac));
70810a6cfc0SAlexandra Winter 	} else {
70910a6cfc0SAlexandra Winter 		call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE,
71010a6cfc0SAlexandra Winter 					 card->dev, &info.info, NULL);
71110a6cfc0SAlexandra Winter 		QETH_CARD_TEXT(card, 4, "anaddmac");
71210a6cfc0SAlexandra Winter 		QETH_CARD_TEXT_(card, 4,
71310a6cfc0SAlexandra Winter 				"mc%012lx", ether_addr_to_u64(ntfy_mac));
71410a6cfc0SAlexandra Winter 	}
71510a6cfc0SAlexandra Winter }
71610a6cfc0SAlexandra Winter 
717817741a8SAlexandra Winter static void qeth_l2_dev2br_an_set_cb(void *priv,
718817741a8SAlexandra Winter 				     struct chsc_pnso_naid_l2 *entry)
719817741a8SAlexandra Winter {
720817741a8SAlexandra Winter 	u8 code = IPA_ADDR_CHANGE_CODE_MACADDR;
721817741a8SAlexandra Winter 	struct qeth_card *card = priv;
722817741a8SAlexandra Winter 
723817741a8SAlexandra Winter 	if (entry->addr_lnid.lnid < VLAN_N_VID)
724817741a8SAlexandra Winter 		code |= IPA_ADDR_CHANGE_CODE_VLANID;
725817741a8SAlexandra Winter 	qeth_l2_dev2br_fdb_notify(card, code,
726817741a8SAlexandra Winter 				  (struct net_if_token *)&entry->nit,
727817741a8SAlexandra Winter 				  (struct mac_addr_lnid *)&entry->addr_lnid);
728817741a8SAlexandra Winter }
729817741a8SAlexandra Winter 
730817741a8SAlexandra Winter /**
731817741a8SAlexandra Winter  *	qeth_l2_dev2br_an_set() -
732817741a8SAlexandra Winter  *	Enable or disable 'dev to bridge network address notification'
733817741a8SAlexandra Winter  *	@card: qeth_card structure pointer
734817741a8SAlexandra Winter  *	@enable: Enable or disable 'dev to bridge network address notification'
735817741a8SAlexandra Winter  *
736817741a8SAlexandra Winter  *	Returns negative errno-compatible error indication or 0 on success.
737817741a8SAlexandra Winter  *
738817741a8SAlexandra Winter  *	On enable, emits a series of address notifications for all
739817741a8SAlexandra Winter  *	currently registered hosts.
740817741a8SAlexandra Winter  *
741817741a8SAlexandra Winter  *	Must be called under rtnl_lock
742817741a8SAlexandra Winter  */
743817741a8SAlexandra Winter static int qeth_l2_dev2br_an_set(struct qeth_card *card, bool enable)
744817741a8SAlexandra Winter {
745817741a8SAlexandra Winter 	int rc;
746817741a8SAlexandra Winter 
747817741a8SAlexandra Winter 	if (enable) {
748817741a8SAlexandra Winter 		QETH_CARD_TEXT(card, 2, "anseton");
749817741a8SAlexandra Winter 		rc = qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 1,
750817741a8SAlexandra Winter 				  qeth_l2_dev2br_an_set_cb, card);
751817741a8SAlexandra Winter 		if (rc == -EAGAIN)
752817741a8SAlexandra Winter 			/* address notification enabled, but inconsistent
753817741a8SAlexandra Winter 			 * addresses reported -> disable address notification
754817741a8SAlexandra Winter 			 */
755817741a8SAlexandra Winter 			qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 0,
756817741a8SAlexandra Winter 				     NULL, NULL);
757817741a8SAlexandra Winter 	} else {
758817741a8SAlexandra Winter 		QETH_CARD_TEXT(card, 2, "ansetoff");
759817741a8SAlexandra Winter 		rc = qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 0, NULL, NULL);
760817741a8SAlexandra Winter 	}
761817741a8SAlexandra Winter 
762817741a8SAlexandra Winter 	return rc;
763817741a8SAlexandra Winter }
764817741a8SAlexandra Winter 
765780b6e7dSAlexandra Winter static int qeth_l2_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
766780b6e7dSAlexandra Winter 				  struct net_device *dev, u32 filter_mask,
767780b6e7dSAlexandra Winter 				  int nlflags)
768780b6e7dSAlexandra Winter {
769780b6e7dSAlexandra Winter 	struct qeth_priv *priv = netdev_priv(dev);
770780b6e7dSAlexandra Winter 	struct qeth_card *card = dev->ml_priv;
771780b6e7dSAlexandra Winter 	u16 mode = BRIDGE_MODE_UNDEF;
772780b6e7dSAlexandra Winter 
773780b6e7dSAlexandra Winter 	/* Do not even show qeth devs that cannot do bridge_setlink */
774780b6e7dSAlexandra Winter 	if (!priv->brport_hw_features || !netif_device_present(dev) ||
775780b6e7dSAlexandra Winter 	    qeth_bridgeport_is_in_use(card))
776780b6e7dSAlexandra Winter 		return -EOPNOTSUPP;
777780b6e7dSAlexandra Winter 
778780b6e7dSAlexandra Winter 	return ndo_dflt_bridge_getlink(skb, pid, seq, dev,
779780b6e7dSAlexandra Winter 				       mode, priv->brport_features,
780780b6e7dSAlexandra Winter 				       priv->brport_hw_features,
781780b6e7dSAlexandra Winter 				       nlflags, filter_mask, NULL);
782780b6e7dSAlexandra Winter }
783780b6e7dSAlexandra Winter 
784521c65b6SAlexandra Winter static const struct nla_policy qeth_brport_policy[IFLA_BRPORT_MAX + 1] = {
785521c65b6SAlexandra Winter 	[IFLA_BRPORT_LEARNING_SYNC]	= { .type = NLA_U8 },
786521c65b6SAlexandra Winter };
787521c65b6SAlexandra Winter 
788521c65b6SAlexandra Winter /**
789521c65b6SAlexandra Winter  *	qeth_l2_bridge_setlink() - set bridgeport attributes
790521c65b6SAlexandra Winter  *	@dev: netdevice
791521c65b6SAlexandra Winter  *	@nlh: netlink message header
792521c65b6SAlexandra Winter  *	@flags: bridge flags (here: BRIDGE_FLAGS_SELF)
793521c65b6SAlexandra Winter  *	@extack: extended ACK report struct
794521c65b6SAlexandra Winter  *
795521c65b6SAlexandra Winter  *	Called under rtnl_lock
796521c65b6SAlexandra Winter  */
797521c65b6SAlexandra Winter static int qeth_l2_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
798521c65b6SAlexandra Winter 				  u16 flags, struct netlink_ext_ack *extack)
799521c65b6SAlexandra Winter {
800521c65b6SAlexandra Winter 	struct qeth_priv *priv = netdev_priv(dev);
801521c65b6SAlexandra Winter 	struct nlattr *bp_tb[IFLA_BRPORT_MAX + 1];
802521c65b6SAlexandra Winter 	struct qeth_card *card = dev->ml_priv;
803521c65b6SAlexandra Winter 	struct nlattr *attr, *nested_attr;
804521c65b6SAlexandra Winter 	bool enable, has_protinfo = false;
805521c65b6SAlexandra Winter 	int rem1, rem2;
806521c65b6SAlexandra Winter 	int rc;
807521c65b6SAlexandra Winter 
808521c65b6SAlexandra Winter 	if (!netif_device_present(dev))
809521c65b6SAlexandra Winter 		return -ENODEV;
810521c65b6SAlexandra Winter 	if (!(priv->brport_hw_features))
811521c65b6SAlexandra Winter 		return -EOPNOTSUPP;
812521c65b6SAlexandra Winter 
813521c65b6SAlexandra Winter 	nlmsg_for_each_attr(attr, nlh, sizeof(struct ifinfomsg), rem1) {
814521c65b6SAlexandra Winter 		if (nla_type(attr) == IFLA_PROTINFO) {
815521c65b6SAlexandra Winter 			rc = nla_parse_nested(bp_tb, IFLA_BRPORT_MAX, attr,
816521c65b6SAlexandra Winter 					      qeth_brport_policy, extack);
817521c65b6SAlexandra Winter 			if (rc)
818521c65b6SAlexandra Winter 				return rc;
819521c65b6SAlexandra Winter 			has_protinfo = true;
820521c65b6SAlexandra Winter 		} else if (nla_type(attr) == IFLA_AF_SPEC) {
821521c65b6SAlexandra Winter 			nla_for_each_nested(nested_attr, attr, rem2) {
822521c65b6SAlexandra Winter 				if (nla_type(nested_attr) == IFLA_BRIDGE_FLAGS)
823521c65b6SAlexandra Winter 					continue;
824521c65b6SAlexandra Winter 				NL_SET_ERR_MSG_ATTR(extack, nested_attr,
825521c65b6SAlexandra Winter 						    "Unsupported attribute");
826521c65b6SAlexandra Winter 				return -EINVAL;
827521c65b6SAlexandra Winter 			}
828521c65b6SAlexandra Winter 		} else {
829521c65b6SAlexandra Winter 			NL_SET_ERR_MSG_ATTR(extack, attr, "Unsupported attribute");
830521c65b6SAlexandra Winter 			return -EINVAL;
831521c65b6SAlexandra Winter 		}
832521c65b6SAlexandra Winter 	}
833521c65b6SAlexandra Winter 	if (!has_protinfo)
834521c65b6SAlexandra Winter 		return 0;
835521c65b6SAlexandra Winter 	if (!bp_tb[IFLA_BRPORT_LEARNING_SYNC])
836521c65b6SAlexandra Winter 		return -EINVAL;
837521c65b6SAlexandra Winter 	enable = !!nla_get_u8(bp_tb[IFLA_BRPORT_LEARNING_SYNC]);
838521c65b6SAlexandra Winter 
839521c65b6SAlexandra Winter 	if (enable == !!(priv->brport_features & BR_LEARNING_SYNC))
840521c65b6SAlexandra Winter 		return 0;
841521c65b6SAlexandra Winter 
842521c65b6SAlexandra Winter 	mutex_lock(&card->sbp_lock);
843521c65b6SAlexandra Winter 	/* do not change anything if BridgePort is enabled */
844521c65b6SAlexandra Winter 	if (qeth_bridgeport_is_in_use(card)) {
845521c65b6SAlexandra Winter 		NL_SET_ERR_MSG(extack, "n/a (BridgePort)");
846521c65b6SAlexandra Winter 		rc = -EBUSY;
847521c65b6SAlexandra Winter 	} else if (enable) {
848521c65b6SAlexandra Winter 		qeth_l2_set_pnso_mode(card, QETH_PNSO_ADDR_INFO);
849521c65b6SAlexandra Winter 		rc = qeth_l2_dev2br_an_set(card, true);
850521c65b6SAlexandra Winter 		if (rc)
851521c65b6SAlexandra Winter 			qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
852521c65b6SAlexandra Winter 		else
853521c65b6SAlexandra Winter 			priv->brport_features |= BR_LEARNING_SYNC;
854521c65b6SAlexandra Winter 	} else {
855521c65b6SAlexandra Winter 		rc = qeth_l2_dev2br_an_set(card, false);
856521c65b6SAlexandra Winter 		if (!rc) {
857521c65b6SAlexandra Winter 			qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
858521c65b6SAlexandra Winter 			priv->brport_features ^= BR_LEARNING_SYNC;
859521c65b6SAlexandra Winter 			qeth_l2_dev2br_fdb_flush(card);
860521c65b6SAlexandra Winter 		}
861521c65b6SAlexandra Winter 	}
862521c65b6SAlexandra Winter 	mutex_unlock(&card->sbp_lock);
863521c65b6SAlexandra Winter 
864521c65b6SAlexandra Winter 	return rc;
865521c65b6SAlexandra Winter }
866521c65b6SAlexandra Winter 
8673d58cefdSFrank Blaschka static const struct net_device_ops qeth_l2_netdev_ops = {
868e22355eaSJulian Wiedmann 	.ndo_open		= qeth_open,
869e22355eaSJulian Wiedmann 	.ndo_stop		= qeth_stop,
870b0abc4f5SJulian Wiedmann 	.ndo_get_stats64	= qeth_get_stats64,
8718403b13cSFrank Blaschka 	.ndo_start_xmit		= qeth_l2_hard_start_xmit,
8726d69b1f1SJulian Wiedmann 	.ndo_features_check	= qeth_features_check,
8733a18d754SJulian Wiedmann 	.ndo_select_queue	= qeth_l2_select_queue,
874e22355eaSJulian Wiedmann 	.ndo_validate_addr	= qeth_l2_validate_addr,
875fe5c8028SLakhvich Dmitriy 	.ndo_set_rx_mode	= qeth_l2_set_rx_mode,
876942d6984SJulian Wiedmann 	.ndo_do_ioctl		= qeth_do_ioctl,
8778403b13cSFrank Blaschka 	.ndo_set_mac_address    = qeth_l2_set_mac_address,
8788403b13cSFrank Blaschka 	.ndo_vlan_rx_add_vid	= qeth_l2_vlan_rx_add_vid,
8798403b13cSFrank Blaschka 	.ndo_vlan_rx_kill_vid   = qeth_l2_vlan_rx_kill_vid,
8808403b13cSFrank Blaschka 	.ndo_tx_timeout	   	= qeth_tx_timeout,
8818f43fb00SThomas Richter 	.ndo_fix_features	= qeth_fix_features,
882780b6e7dSAlexandra Winter 	.ndo_set_features	= qeth_set_features,
883780b6e7dSAlexandra Winter 	.ndo_bridge_getlink	= qeth_l2_bridge_getlink,
884521c65b6SAlexandra Winter 	.ndo_bridge_setlink	= qeth_l2_bridge_setlink,
8858403b13cSFrank Blaschka };
8868403b13cSFrank Blaschka 
8878024cc9eSJulian Wiedmann static const struct net_device_ops qeth_osn_netdev_ops = {
8888024cc9eSJulian Wiedmann 	.ndo_open		= qeth_open,
8898024cc9eSJulian Wiedmann 	.ndo_stop		= qeth_stop,
8908024cc9eSJulian Wiedmann 	.ndo_get_stats64	= qeth_get_stats64,
8918024cc9eSJulian Wiedmann 	.ndo_start_xmit		= qeth_l2_hard_start_xmit,
8928024cc9eSJulian Wiedmann 	.ndo_validate_addr	= eth_validate_addr,
8938024cc9eSJulian Wiedmann 	.ndo_tx_timeout		= qeth_tx_timeout,
8948024cc9eSJulian Wiedmann };
8958024cc9eSJulian Wiedmann 
896cd652be5SJulian Wiedmann static int qeth_l2_setup_netdev(struct qeth_card *card)
8974a71df50SFrank Blaschka {
8988024cc9eSJulian Wiedmann 	if (IS_OSN(card)) {
8998024cc9eSJulian Wiedmann 		card->dev->netdev_ops = &qeth_osn_netdev_ops;
90025e2c341SJulian Wiedmann 		card->dev->flags |= IFF_NOARP;
9018024cc9eSJulian Wiedmann 		goto add_napi;
9028024cc9eSJulian Wiedmann 	}
9038024cc9eSJulian Wiedmann 
9045f89eca5SJulian Wiedmann 	card->dev->needed_headroom = sizeof(struct qeth_hdr);
9058024cc9eSJulian Wiedmann 	card->dev->netdev_ops = &qeth_l2_netdev_ops;
9068024cc9eSJulian Wiedmann 	card->dev->priv_flags |= IFF_UNICAST_FLT;
9079400c53fSJulian Wiedmann 
9085fc692a7SJulian Wiedmann 	if (IS_OSM(card)) {
9099400c53fSJulian Wiedmann 		card->dev->features |= NETIF_F_VLAN_CHALLENGED;
9105fc692a7SJulian Wiedmann 	} else {
9115fc692a7SJulian Wiedmann 		if (!IS_VM_NIC(card))
9125fc692a7SJulian Wiedmann 			card->dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
913f646968fSPatrick McHardy 		card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
9145fc692a7SJulian Wiedmann 	}
9150f342945SJulian Wiedmann 
916379ac99eSJulian Wiedmann 	if (IS_OSD(card) && !IS_VM_NIC(card)) {
9176d69b1f1SJulian Wiedmann 		card->dev->features |= NETIF_F_SG;
9188f43fb00SThomas Richter 		/* OSA 3S and earlier has no RX/TX support */
9199bdc4411SHans Wippel 		if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) {
9208f43fb00SThomas Richter 			card->dev->hw_features |= NETIF_F_IP_CSUM;
9219bdc4411SHans Wippel 			card->dev->vlan_features |= NETIF_F_IP_CSUM;
9229bdc4411SHans Wippel 		}
9234d7def2aSThomas Richter 	}
924571f9dd8SKittipon Meesompop 	if (qeth_is_supported6(card, IPA_OUTBOUND_CHECKSUM_V6)) {
925571f9dd8SKittipon Meesompop 		card->dev->hw_features |= NETIF_F_IPV6_CSUM;
926571f9dd8SKittipon Meesompop 		card->dev->vlan_features |= NETIF_F_IPV6_CSUM;
927571f9dd8SKittipon Meesompop 	}
928d7e6ed97SKittipon Meesompop 	if (qeth_is_supported(card, IPA_INBOUND_CHECKSUM) ||
929d7e6ed97SKittipon Meesompop 	    qeth_is_supported6(card, IPA_INBOUND_CHECKSUM_V6)) {
930d7e6ed97SKittipon Meesompop 		card->dev->hw_features |= NETIF_F_RXCSUM;
931d7e6ed97SKittipon Meesompop 		card->dev->vlan_features |= NETIF_F_RXCSUM;
932d7e6ed97SKittipon Meesompop 	}
9330aef8392SJulian Wiedmann 	if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
9340aef8392SJulian Wiedmann 		card->dev->hw_features |= NETIF_F_TSO;
9350aef8392SJulian Wiedmann 		card->dev->vlan_features |= NETIF_F_TSO;
9360aef8392SJulian Wiedmann 	}
9370aef8392SJulian Wiedmann 	if (qeth_is_supported6(card, IPA_OUTBOUND_TSO)) {
9380aef8392SJulian Wiedmann 		card->dev->hw_features |= NETIF_F_TSO6;
9390aef8392SJulian Wiedmann 		card->dev->vlan_features |= NETIF_F_TSO6;
9400aef8392SJulian Wiedmann 	}
9410aef8392SJulian Wiedmann 
9420aef8392SJulian Wiedmann 	if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6)) {
9430aef8392SJulian Wiedmann 		card->dev->needed_headroom = sizeof(struct qeth_hdr_tso);
944c619e9a6SJulian Wiedmann 		netif_keep_dst(card->dev);
9450aef8392SJulian Wiedmann 		netif_set_gso_max_size(card->dev,
9460aef8392SJulian Wiedmann 				       PAGE_SIZE * (QDIO_MAX_ELEMENTS_PER_BUFFER - 1));
9470aef8392SJulian Wiedmann 	}
9480d6f02d3SJulian Wiedmann 
9498024cc9eSJulian Wiedmann add_napi:
950d73ef324SJulian Wiedmann 	netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT);
951cd652be5SJulian Wiedmann 	return register_netdev(card->dev);
9524a71df50SFrank Blaschka }
9534a71df50SFrank Blaschka 
954521c10eaSJulian Wiedmann static void qeth_l2_trace_features(struct qeth_card *card)
955521c10eaSJulian Wiedmann {
956a45b3fafSHans Wippel 	/* Set BridgePort features */
957a45b3fafSHans Wippel 	QETH_CARD_TEXT(card, 2, "featuSBP");
958521c10eaSJulian Wiedmann 	QETH_CARD_HEX(card, 2, &card->options.sbp.supported_funcs,
959521c10eaSJulian Wiedmann 		      sizeof(card->options.sbp.supported_funcs));
960a45b3fafSHans Wippel 	/* VNIC Characteristics features */
961a45b3fafSHans Wippel 	QETH_CARD_TEXT(card, 2, "feaVNICC");
962a45b3fafSHans Wippel 	QETH_CARD_HEX(card, 2, &card->options.vnicc.sup_chars,
963a45b3fafSHans Wippel 		      sizeof(card->options.vnicc.sup_chars));
964521c10eaSJulian Wiedmann }
965521c10eaSJulian Wiedmann 
9668ca769e2SJulian Wiedmann static void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card)
9678ca769e2SJulian Wiedmann {
9688ca769e2SJulian Wiedmann 	if (!card->options.sbp.reflect_promisc &&
9698ca769e2SJulian Wiedmann 	    card->options.sbp.role != QETH_SBP_ROLE_NONE) {
9708ca769e2SJulian Wiedmann 		/* Conditional to avoid spurious error messages */
9718ca769e2SJulian Wiedmann 		qeth_bridgeport_setrole(card, card->options.sbp.role);
9728ca769e2SJulian Wiedmann 		/* Let the callback function refresh the stored role value. */
9738ca769e2SJulian Wiedmann 		qeth_bridgeport_query_ports(card, &card->options.sbp.role,
9748ca769e2SJulian Wiedmann 					    NULL);
9758ca769e2SJulian Wiedmann 	}
9768ca769e2SJulian Wiedmann 	if (card->options.sbp.hostnotification) {
9778ca769e2SJulian Wiedmann 		if (qeth_bridgeport_an_set(card, 1))
9788ca769e2SJulian Wiedmann 			card->options.sbp.hostnotification = 0;
9798ca769e2SJulian Wiedmann 	}
9808ca769e2SJulian Wiedmann }
9818ca769e2SJulian Wiedmann 
982fa115adfSAlexandra Winter /**
983fa115adfSAlexandra Winter  *	qeth_l2_detect_dev2br_support() -
984fa115adfSAlexandra Winter  *	Detect whether this card supports 'dev to bridge fdb network address
985fa115adfSAlexandra Winter  *	change notification' and thus can support the learning_sync bridgeport
986fa115adfSAlexandra Winter  *	attribute
987fa115adfSAlexandra Winter  *	@card: qeth_card structure pointer
988fa115adfSAlexandra Winter  *
989fa115adfSAlexandra Winter  *	This is a destructive test and must be called before dev2br or
990fa115adfSAlexandra Winter  *	bridgeport address notification is enabled!
991fa115adfSAlexandra Winter  */
992fa115adfSAlexandra Winter static void qeth_l2_detect_dev2br_support(struct qeth_card *card)
993fa115adfSAlexandra Winter {
994fa115adfSAlexandra Winter 	struct qeth_priv *priv = netdev_priv(card->dev);
995fa115adfSAlexandra Winter 	bool dev2br_supported;
996fa115adfSAlexandra Winter 	int rc;
997fa115adfSAlexandra Winter 
998fa115adfSAlexandra Winter 	QETH_CARD_TEXT(card, 2, "d2brsup");
999fa115adfSAlexandra Winter 	if (!IS_IQD(card))
1000fa115adfSAlexandra Winter 		return;
1001fa115adfSAlexandra Winter 
1002fa115adfSAlexandra Winter 	/* dev2br requires valid cssid,iid,chid */
1003fa115adfSAlexandra Winter 	if (!card->info.ids_valid) {
1004fa115adfSAlexandra Winter 		dev2br_supported = false;
1005fa115adfSAlexandra Winter 	} else if (css_general_characteristics.enarf) {
1006fa115adfSAlexandra Winter 		dev2br_supported = true;
1007fa115adfSAlexandra Winter 	} else {
1008fa115adfSAlexandra Winter 		/* Old machines don't have the feature bit:
1009fa115adfSAlexandra Winter 		 * Probe by testing whether a disable succeeds
1010fa115adfSAlexandra Winter 		 */
1011fa115adfSAlexandra Winter 		rc = qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 0, NULL, NULL);
1012fa115adfSAlexandra Winter 		dev2br_supported = !rc;
1013fa115adfSAlexandra Winter 	}
1014fa115adfSAlexandra Winter 	QETH_CARD_TEXT_(card, 2, "D2Bsup%02x", dev2br_supported);
1015fa115adfSAlexandra Winter 
1016fa115adfSAlexandra Winter 	if (dev2br_supported)
1017fa115adfSAlexandra Winter 		priv->brport_hw_features |= BR_LEARNING_SYNC;
1018fa115adfSAlexandra Winter 	else
1019fa115adfSAlexandra Winter 		priv->brport_hw_features &= ~BR_LEARNING_SYNC;
1020fa115adfSAlexandra Winter }
1021fa115adfSAlexandra Winter 
1022521c65b6SAlexandra Winter static void qeth_l2_enable_brport_features(struct qeth_card *card)
1023521c65b6SAlexandra Winter {
1024521c65b6SAlexandra Winter 	struct qeth_priv *priv = netdev_priv(card->dev);
1025521c65b6SAlexandra Winter 	int rc;
1026521c65b6SAlexandra Winter 
1027521c65b6SAlexandra Winter 	if (priv->brport_features & BR_LEARNING_SYNC) {
1028521c65b6SAlexandra Winter 		if (priv->brport_hw_features & BR_LEARNING_SYNC) {
1029521c65b6SAlexandra Winter 			qeth_l2_set_pnso_mode(card, QETH_PNSO_ADDR_INFO);
1030521c65b6SAlexandra Winter 			rc = qeth_l2_dev2br_an_set(card, true);
1031521c65b6SAlexandra Winter 			if (rc == -EAGAIN) {
1032521c65b6SAlexandra Winter 				/* Recoverable error, retry once */
1033521c65b6SAlexandra Winter 				qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
1034521c65b6SAlexandra Winter 				qeth_l2_dev2br_fdb_flush(card);
1035521c65b6SAlexandra Winter 				qeth_l2_set_pnso_mode(card, QETH_PNSO_ADDR_INFO);
1036521c65b6SAlexandra Winter 				rc = qeth_l2_dev2br_an_set(card, true);
1037521c65b6SAlexandra Winter 			}
1038521c65b6SAlexandra Winter 			if (rc) {
1039521c65b6SAlexandra Winter 				netdev_err(card->dev,
1040521c65b6SAlexandra Winter 					   "failed to enable bridge learning_sync: %d\n",
1041521c65b6SAlexandra Winter 					   rc);
1042521c65b6SAlexandra Winter 				qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
1043521c65b6SAlexandra Winter 				qeth_l2_dev2br_fdb_flush(card);
1044521c65b6SAlexandra Winter 				priv->brport_features ^= BR_LEARNING_SYNC;
1045521c65b6SAlexandra Winter 			}
1046521c65b6SAlexandra Winter 		} else {
1047521c65b6SAlexandra Winter 			dev_warn(&card->gdev->dev,
1048521c65b6SAlexandra Winter 				"bridge learning_sync not supported\n");
1049521c65b6SAlexandra Winter 			priv->brport_features ^= BR_LEARNING_SYNC;
1050521c65b6SAlexandra Winter 		}
1051521c65b6SAlexandra Winter 	}
1052521c65b6SAlexandra Winter }
1053521c65b6SAlexandra Winter 
10544e2b5aa5SJulian Wiedmann #ifdef CONFIG_QETH_OSN
10550ce37ec2SJulian Wiedmann static void qeth_osn_assist_cb(struct qeth_card *card,
105612fc286fSJulian Wiedmann 			       struct qeth_cmd_buffer *iob,
105712fc286fSJulian Wiedmann 			       unsigned int data_length)
10584a71df50SFrank Blaschka {
1059308946b0SJulian Wiedmann 	qeth_notify_cmd(iob, 0);
1060c3b2218dSJulian Wiedmann 	qeth_put_cmd(iob);
10614a71df50SFrank Blaschka }
10624a71df50SFrank Blaschka 
10634a71df50SFrank Blaschka int qeth_osn_assist(struct net_device *dev, void *data, int data_len)
10644a71df50SFrank Blaschka {
10654a71df50SFrank Blaschka 	struct qeth_cmd_buffer *iob;
10664a71df50SFrank Blaschka 	struct qeth_card *card;
10674a71df50SFrank Blaschka 
1068a59d121dSJulian Wiedmann 	if (data_len < 0)
1069a59d121dSJulian Wiedmann 		return -EINVAL;
10704a71df50SFrank Blaschka 	if (!dev)
10714a71df50SFrank Blaschka 		return -ENODEV;
1072509e2562SHeiko Carstens 	card = dev->ml_priv;
10734a71df50SFrank Blaschka 	if (!card)
10744a71df50SFrank Blaschka 		return -ENODEV;
1075847a50fdSCarsten Otte 	QETH_CARD_TEXT(card, 2, "osnsdmc");
1076c3521254SEugene Crosser 	if (!qeth_card_hw_is_reachable(card))
10774a71df50SFrank Blaschka 		return -ENODEV;
1078a59d121dSJulian Wiedmann 
1079a59d121dSJulian Wiedmann 	iob = qeth_alloc_cmd(&card->write, IPA_PDU_HEADER_SIZE + data_len, 1,
1080a59d121dSJulian Wiedmann 			     QETH_IPA_TIMEOUT);
10811273a800SJulian Wiedmann 	if (!iob)
10821273a800SJulian Wiedmann 		return -ENOMEM;
10831273a800SJulian Wiedmann 
10847f92316cSJulian Wiedmann 	qeth_prepare_ipa_cmd(card, iob, (u16) data_len, NULL);
10857f92316cSJulian Wiedmann 
1086ff5caa7aSJulian Wiedmann 	memcpy(__ipa_cmd(iob), data, data_len);
10870ce37ec2SJulian Wiedmann 	iob->callback = qeth_osn_assist_cb;
10880ce37ec2SJulian Wiedmann 	return qeth_send_ipa_cmd(card, iob, NULL, NULL);
10894a71df50SFrank Blaschka }
10904a71df50SFrank Blaschka EXPORT_SYMBOL(qeth_osn_assist);
10914a71df50SFrank Blaschka 
10924a71df50SFrank Blaschka int qeth_osn_register(unsigned char *read_dev_no, struct net_device **dev,
10934a71df50SFrank Blaschka 		  int (*assist_cb)(struct net_device *, void *),
10944a71df50SFrank Blaschka 		  int (*data_cb)(struct sk_buff *))
10954a71df50SFrank Blaschka {
10964a71df50SFrank Blaschka 	struct qeth_card *card;
1097d7d18da1SJulian Wiedmann 	char bus_id[16];
1098d7d18da1SJulian Wiedmann 	u16 devno;
10994a71df50SFrank Blaschka 
1100d7d18da1SJulian Wiedmann 	memcpy(&devno, read_dev_no, 2);
1101d7d18da1SJulian Wiedmann 	sprintf(bus_id, "0.0.%04x", devno);
1102d7d18da1SJulian Wiedmann 	card = qeth_get_card_by_busid(bus_id);
1103d7d18da1SJulian Wiedmann 	if (!card || !IS_OSN(card))
11044a71df50SFrank Blaschka 		return -ENODEV;
1105d7d18da1SJulian Wiedmann 	*dev = card->dev;
1106d7d18da1SJulian Wiedmann 
1107847a50fdSCarsten Otte 	QETH_CARD_TEXT(card, 2, "osnreg");
11084a71df50SFrank Blaschka 	if ((assist_cb == NULL) || (data_cb == NULL))
11094a71df50SFrank Blaschka 		return -EINVAL;
11104a71df50SFrank Blaschka 	card->osn_info.assist_cb = assist_cb;
11114a71df50SFrank Blaschka 	card->osn_info.data_cb = data_cb;
11124a71df50SFrank Blaschka 	return 0;
11134a71df50SFrank Blaschka }
11144a71df50SFrank Blaschka EXPORT_SYMBOL(qeth_osn_register);
11154a71df50SFrank Blaschka 
11164a71df50SFrank Blaschka void qeth_osn_deregister(struct net_device *dev)
11174a71df50SFrank Blaschka {
11184a71df50SFrank Blaschka 	struct qeth_card *card;
11194a71df50SFrank Blaschka 
11204a71df50SFrank Blaschka 	if (!dev)
11214a71df50SFrank Blaschka 		return;
1122509e2562SHeiko Carstens 	card = dev->ml_priv;
11234a71df50SFrank Blaschka 	if (!card)
11244a71df50SFrank Blaschka 		return;
1125847a50fdSCarsten Otte 	QETH_CARD_TEXT(card, 2, "osndereg");
11264a71df50SFrank Blaschka 	card->osn_info.assist_cb = NULL;
11274a71df50SFrank Blaschka 	card->osn_info.data_cb = NULL;
11284a71df50SFrank Blaschka 	return;
11294a71df50SFrank Blaschka }
11304a71df50SFrank Blaschka EXPORT_SYMBOL(qeth_osn_deregister);
11314e2b5aa5SJulian Wiedmann #endif
11324a71df50SFrank Blaschka 
1133b4d72c08SEugene Crosser /* SETBRIDGEPORT support, async notifications */
1134b4d72c08SEugene Crosser 
11359f48b9dbSEugene Crosser enum qeth_an_event_type {anev_reg_unreg, anev_abort, anev_reset};
11369f48b9dbSEugene Crosser 
11379f48b9dbSEugene Crosser /**
11389f48b9dbSEugene Crosser  * qeth_bridge_emit_host_event() - bridgeport address change notification
11399f48b9dbSEugene Crosser  * @card:  qeth_card structure pointer, for udev events.
11409f48b9dbSEugene Crosser  * @evtype:  "normal" register/unregister, or abort, or reset. For abort
11419f48b9dbSEugene Crosser  *	      and reset token and addr_lnid are unused and may be NULL.
11429f48b9dbSEugene Crosser  * @code:  event bitmask: high order bit 0x80 value 1 means removal of an
11439f48b9dbSEugene Crosser  *			  object, 0 - addition of an object.
11449f48b9dbSEugene Crosser  *			  0x01 - VLAN, 0x02 - MAC, 0x03 - VLAN and MAC.
11459f48b9dbSEugene Crosser  * @token: "network token" structure identifying physical address of the port.
11469f48b9dbSEugene Crosser  * @addr_lnid: pointer to structure with MAC address and VLAN ID.
11479f48b9dbSEugene Crosser  *
11489f48b9dbSEugene Crosser  * This function is called when registrations and deregistrations are
11499f48b9dbSEugene Crosser  * reported by the hardware, and also when notifications are enabled -
11509f48b9dbSEugene Crosser  * for all currently registered addresses.
11519f48b9dbSEugene Crosser  */
11529f48b9dbSEugene Crosser static void qeth_bridge_emit_host_event(struct qeth_card *card,
11539f48b9dbSEugene Crosser 					enum qeth_an_event_type evtype,
1154a0138f59SAlexandra Winter 					u8 code,
1155a0138f59SAlexandra Winter 					struct net_if_token *token,
1156a0138f59SAlexandra Winter 					struct mac_addr_lnid *addr_lnid)
11579f48b9dbSEugene Crosser {
11589f48b9dbSEugene Crosser 	char str[7][32];
11599f48b9dbSEugene Crosser 	char *env[8];
11609f48b9dbSEugene Crosser 	int i = 0;
11619f48b9dbSEugene Crosser 
11629f48b9dbSEugene Crosser 	switch (evtype) {
11639f48b9dbSEugene Crosser 	case anev_reg_unreg:
11649f48b9dbSEugene Crosser 		snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=%s",
11659f48b9dbSEugene Crosser 				(code & IPA_ADDR_CHANGE_CODE_REMOVAL)
11669f48b9dbSEugene Crosser 				? "deregister" : "register");
11679f48b9dbSEugene Crosser 		env[i] = str[i]; i++;
11689f48b9dbSEugene Crosser 		if (code & IPA_ADDR_CHANGE_CODE_VLANID) {
11699f48b9dbSEugene Crosser 			snprintf(str[i], sizeof(str[i]), "VLAN=%d",
11709f48b9dbSEugene Crosser 				addr_lnid->lnid);
11719f48b9dbSEugene Crosser 			env[i] = str[i]; i++;
11729f48b9dbSEugene Crosser 		}
11739f48b9dbSEugene Crosser 		if (code & IPA_ADDR_CHANGE_CODE_MACADDR) {
11749846e70bSEugene Crosser 			snprintf(str[i], sizeof(str[i]), "MAC=%pM",
11759846e70bSEugene Crosser 				addr_lnid->mac);
11769f48b9dbSEugene Crosser 			env[i] = str[i]; i++;
11779f48b9dbSEugene Crosser 		}
11789f48b9dbSEugene Crosser 		snprintf(str[i], sizeof(str[i]), "NTOK_BUSID=%x.%x.%04x",
11799f48b9dbSEugene Crosser 			token->cssid, token->ssid, token->devnum);
11809f48b9dbSEugene Crosser 		env[i] = str[i]; i++;
11819f48b9dbSEugene Crosser 		snprintf(str[i], sizeof(str[i]), "NTOK_IID=%02x", token->iid);
11829f48b9dbSEugene Crosser 		env[i] = str[i]; i++;
11839f48b9dbSEugene Crosser 		snprintf(str[i], sizeof(str[i]), "NTOK_CHPID=%02x",
11849f48b9dbSEugene Crosser 				token->chpid);
11859f48b9dbSEugene Crosser 		env[i] = str[i]; i++;
11869f48b9dbSEugene Crosser 		snprintf(str[i], sizeof(str[i]), "NTOK_CHID=%04x", token->chid);
11879f48b9dbSEugene Crosser 		env[i] = str[i]; i++;
11889f48b9dbSEugene Crosser 		break;
11899f48b9dbSEugene Crosser 	case anev_abort:
11909f48b9dbSEugene Crosser 		snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=abort");
11919f48b9dbSEugene Crosser 		env[i] = str[i]; i++;
11929f48b9dbSEugene Crosser 		break;
11939f48b9dbSEugene Crosser 	case anev_reset:
11949f48b9dbSEugene Crosser 		snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=reset");
11959f48b9dbSEugene Crosser 		env[i] = str[i]; i++;
11969f48b9dbSEugene Crosser 		break;
11979f48b9dbSEugene Crosser 	}
11989f48b9dbSEugene Crosser 	env[i] = NULL;
11999f48b9dbSEugene Crosser 	kobject_uevent_env(&card->gdev->dev.kobj, KOBJ_CHANGE, env);
12009f48b9dbSEugene Crosser }
12019f48b9dbSEugene Crosser 
1202b4d72c08SEugene Crosser struct qeth_bridge_state_data {
1203b4d72c08SEugene Crosser 	struct work_struct worker;
1204b4d72c08SEugene Crosser 	struct qeth_card *card;
120561c6f217SJulian Wiedmann 	u8 role;
120661c6f217SJulian Wiedmann 	u8 state;
1207b4d72c08SEugene Crosser };
1208b4d72c08SEugene Crosser 
1209b4d72c08SEugene Crosser static void qeth_bridge_state_change_worker(struct work_struct *work)
1210b4d72c08SEugene Crosser {
1211b4d72c08SEugene Crosser 	struct qeth_bridge_state_data *data =
1212b4d72c08SEugene Crosser 		container_of(work, struct qeth_bridge_state_data, worker);
1213b4d72c08SEugene Crosser 	char env_locrem[32];
1214b4d72c08SEugene Crosser 	char env_role[32];
1215b4d72c08SEugene Crosser 	char env_state[32];
1216b4d72c08SEugene Crosser 	char *env[] = {
1217b4d72c08SEugene Crosser 		env_locrem,
1218b4d72c08SEugene Crosser 		env_role,
1219b4d72c08SEugene Crosser 		env_state,
1220b4d72c08SEugene Crosser 		NULL
1221b4d72c08SEugene Crosser 	};
1222b4d72c08SEugene Crosser 
1223b4d72c08SEugene Crosser 	snprintf(env_locrem, sizeof(env_locrem), "BRIDGEPORT=statechange");
1224b4d72c08SEugene Crosser 	snprintf(env_role, sizeof(env_role), "ROLE=%s",
122561c6f217SJulian Wiedmann 		(data->role == QETH_SBP_ROLE_NONE) ? "none" :
122661c6f217SJulian Wiedmann 		(data->role == QETH_SBP_ROLE_PRIMARY) ? "primary" :
122761c6f217SJulian Wiedmann 		(data->role == QETH_SBP_ROLE_SECONDARY) ? "secondary" :
1228b4d72c08SEugene Crosser 		"<INVALID>");
1229b4d72c08SEugene Crosser 	snprintf(env_state, sizeof(env_state), "STATE=%s",
123061c6f217SJulian Wiedmann 		(data->state == QETH_SBP_STATE_INACTIVE) ? "inactive" :
123161c6f217SJulian Wiedmann 		(data->state == QETH_SBP_STATE_STANDBY) ? "standby" :
123261c6f217SJulian Wiedmann 		(data->state == QETH_SBP_STATE_ACTIVE) ? "active" :
1233b4d72c08SEugene Crosser 		"<INVALID>");
1234b4d72c08SEugene Crosser 	kobject_uevent_env(&data->card->gdev->dev.kobj,
1235b4d72c08SEugene Crosser 				KOBJ_CHANGE, env);
1236b4d72c08SEugene Crosser 	kfree(data);
1237b4d72c08SEugene Crosser }
1238b4d72c08SEugene Crosser 
1239c044dc21SEugene Crosser static void qeth_bridge_state_change(struct qeth_card *card,
1240c044dc21SEugene Crosser 					struct qeth_ipa_cmd *cmd)
1241b4d72c08SEugene Crosser {
124265b0494eSJulian Wiedmann 	struct qeth_sbp_port_data *qports = &cmd->data.sbp.data.port_data;
1243b4d72c08SEugene Crosser 	struct qeth_bridge_state_data *data;
1244b4d72c08SEugene Crosser 
1245b4d72c08SEugene Crosser 	QETH_CARD_TEXT(card, 2, "brstchng");
124602472e28SJulian Wiedmann 	if (qports->num_entries == 0) {
124702472e28SJulian Wiedmann 		QETH_CARD_TEXT(card, 2, "BPempty");
124802472e28SJulian Wiedmann 		return;
124902472e28SJulian Wiedmann 	}
1250b4d72c08SEugene Crosser 	if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) {
12518a593148SThomas Richter 		QETH_CARD_TEXT_(card, 2, "BPsz%04x", qports->entry_length);
1252b4d72c08SEugene Crosser 		return;
1253b4d72c08SEugene Crosser 	}
125461c6f217SJulian Wiedmann 
125561c6f217SJulian Wiedmann 	data = kzalloc(sizeof(*data), GFP_ATOMIC);
1256b4d72c08SEugene Crosser 	if (!data) {
1257b4d72c08SEugene Crosser 		QETH_CARD_TEXT(card, 2, "BPSalloc");
1258b4d72c08SEugene Crosser 		return;
1259b4d72c08SEugene Crosser 	}
1260b4d72c08SEugene Crosser 	INIT_WORK(&data->worker, qeth_bridge_state_change_worker);
1261b4d72c08SEugene Crosser 	data->card = card;
126261c6f217SJulian Wiedmann 	/* Information for the local port: */
126361c6f217SJulian Wiedmann 	data->role = qports->entry[0].role;
126461c6f217SJulian Wiedmann 	data->state = qports->entry[0].state;
126561c6f217SJulian Wiedmann 
1266c0a2e4d1SJulian Wiedmann 	queue_work(card->event_wq, &data->worker);
1267b4d72c08SEugene Crosser }
1268b4d72c08SEugene Crosser 
1269a0138f59SAlexandra Winter struct qeth_addr_change_data {
12709d6a569aSJulian Wiedmann 	struct delayed_work dwork;
12719f48b9dbSEugene Crosser 	struct qeth_card *card;
1272a0138f59SAlexandra Winter 	struct qeth_ipacmd_addr_change ac_event;
12739f48b9dbSEugene Crosser };
12749f48b9dbSEugene Crosser 
127510a6cfc0SAlexandra Winter static void qeth_l2_dev2br_worker(struct work_struct *work)
127610a6cfc0SAlexandra Winter {
127710a6cfc0SAlexandra Winter 	struct delayed_work *dwork = to_delayed_work(work);
127810a6cfc0SAlexandra Winter 	struct qeth_addr_change_data *data;
127910a6cfc0SAlexandra Winter 	struct qeth_card *card;
1280817741a8SAlexandra Winter 	struct qeth_priv *priv;
128110a6cfc0SAlexandra Winter 	unsigned int i;
1282817741a8SAlexandra Winter 	int rc;
128310a6cfc0SAlexandra Winter 
128410a6cfc0SAlexandra Winter 	data = container_of(dwork, struct qeth_addr_change_data, dwork);
128510a6cfc0SAlexandra Winter 	card = data->card;
1286817741a8SAlexandra Winter 	priv = netdev_priv(card->dev);
128710a6cfc0SAlexandra Winter 
128810a6cfc0SAlexandra Winter 	QETH_CARD_TEXT(card, 4, "dev2brew");
128910a6cfc0SAlexandra Winter 
129010a6cfc0SAlexandra Winter 	if (READ_ONCE(card->info.pnso_mode) == QETH_PNSO_NONE)
129110a6cfc0SAlexandra Winter 		goto free;
129210a6cfc0SAlexandra Winter 
129310a6cfc0SAlexandra Winter 	/* Potential re-config in progress, try again later: */
129410a6cfc0SAlexandra Winter 	if (!rtnl_trylock()) {
129510a6cfc0SAlexandra Winter 		queue_delayed_work(card->event_wq, dwork,
129610a6cfc0SAlexandra Winter 				   msecs_to_jiffies(100));
129710a6cfc0SAlexandra Winter 		return;
129810a6cfc0SAlexandra Winter 	}
1299817741a8SAlexandra Winter 	if (!netif_device_present(card->dev))
1300817741a8SAlexandra Winter 		goto out_unlock;
130110a6cfc0SAlexandra Winter 
130210a6cfc0SAlexandra Winter 	if (data->ac_event.lost_event_mask) {
130310a6cfc0SAlexandra Winter 		QETH_DBF_MESSAGE(3,
130410a6cfc0SAlexandra Winter 				 "Address change notification overflow on device %x\n",
130510a6cfc0SAlexandra Winter 				 CARD_DEVID(card));
1306817741a8SAlexandra Winter 		/* Card fdb and bridge fdb are out of sync, card has stopped
1307817741a8SAlexandra Winter 		 * notifications (no need to drain_workqueue). Purge all
1308817741a8SAlexandra Winter 		 * 'extern_learn' entries from the parent bridge and restart
1309817741a8SAlexandra Winter 		 * the notifications.
1310817741a8SAlexandra Winter 		 */
1311817741a8SAlexandra Winter 		qeth_l2_dev2br_fdb_flush(card);
1312817741a8SAlexandra Winter 		rc = qeth_l2_dev2br_an_set(card, true);
1313817741a8SAlexandra Winter 		if (rc) {
1314817741a8SAlexandra Winter 			/* TODO: if we want to retry after -EAGAIN, be
1315817741a8SAlexandra Winter 			 * aware there could be stale entries in the
1316817741a8SAlexandra Winter 			 * workqueue now, that need to be drained.
1317817741a8SAlexandra Winter 			 * For now we give up:
1318817741a8SAlexandra Winter 			 */
1319817741a8SAlexandra Winter 			netdev_err(card->dev,
1320817741a8SAlexandra Winter 				   "bridge learning_sync failed to recover: %d\n",
1321817741a8SAlexandra Winter 				   rc);
1322817741a8SAlexandra Winter 			WRITE_ONCE(card->info.pnso_mode,
1323817741a8SAlexandra Winter 				   QETH_PNSO_NONE);
1324817741a8SAlexandra Winter 			/* To remove fdb entries reported by an_set: */
1325817741a8SAlexandra Winter 			qeth_l2_dev2br_fdb_flush(card);
1326817741a8SAlexandra Winter 			priv->brport_features ^= BR_LEARNING_SYNC;
1327817741a8SAlexandra Winter 		} else {
1328817741a8SAlexandra Winter 			QETH_DBF_MESSAGE(3,
1329817741a8SAlexandra Winter 					 "Address Notification resynced on device %x\n",
1330817741a8SAlexandra Winter 					 CARD_DEVID(card));
1331817741a8SAlexandra Winter 		}
133210a6cfc0SAlexandra Winter 	} else {
133310a6cfc0SAlexandra Winter 		for (i = 0; i < data->ac_event.num_entries; i++) {
133410a6cfc0SAlexandra Winter 			struct qeth_ipacmd_addr_change_entry *entry =
133510a6cfc0SAlexandra Winter 					&data->ac_event.entry[i];
133610a6cfc0SAlexandra Winter 			qeth_l2_dev2br_fdb_notify(card,
133710a6cfc0SAlexandra Winter 						  entry->change_code,
133810a6cfc0SAlexandra Winter 						  &entry->token,
133910a6cfc0SAlexandra Winter 						  &entry->addr_lnid);
134010a6cfc0SAlexandra Winter 		}
134110a6cfc0SAlexandra Winter 	}
1342817741a8SAlexandra Winter 
1343817741a8SAlexandra Winter out_unlock:
134410a6cfc0SAlexandra Winter 	rtnl_unlock();
134510a6cfc0SAlexandra Winter 
134610a6cfc0SAlexandra Winter free:
134710a6cfc0SAlexandra Winter 	kfree(data);
134810a6cfc0SAlexandra Winter }
134910a6cfc0SAlexandra Winter 
1350a0138f59SAlexandra Winter static void qeth_addr_change_event_worker(struct work_struct *work)
13519f48b9dbSEugene Crosser {
13529d6a569aSJulian Wiedmann 	struct delayed_work *dwork = to_delayed_work(work);
13539d6a569aSJulian Wiedmann 	struct qeth_addr_change_data *data;
13549d6a569aSJulian Wiedmann 	struct qeth_card *card;
13559f48b9dbSEugene Crosser 	int i;
13569f48b9dbSEugene Crosser 
13579d6a569aSJulian Wiedmann 	data = container_of(dwork, struct qeth_addr_change_data, dwork);
13589d6a569aSJulian Wiedmann 	card = data->card;
13599d6a569aSJulian Wiedmann 
1360a0138f59SAlexandra Winter 	QETH_CARD_TEXT(data->card, 4, "adrchgew");
13619d6a569aSJulian Wiedmann 
13629d6a569aSJulian Wiedmann 	if (READ_ONCE(card->info.pnso_mode) == QETH_PNSO_NONE)
13639d6a569aSJulian Wiedmann 		goto free;
13649d6a569aSJulian Wiedmann 
1365a0138f59SAlexandra Winter 	if (data->ac_event.lost_event_mask) {
13669d6a569aSJulian Wiedmann 		/* Potential re-config in progress, try again later: */
13679d6a569aSJulian Wiedmann 		if (!mutex_trylock(&card->sbp_lock)) {
13689d6a569aSJulian Wiedmann 			queue_delayed_work(card->event_wq, dwork,
13699d6a569aSJulian Wiedmann 					   msecs_to_jiffies(100));
13709d6a569aSJulian Wiedmann 			return;
13719d6a569aSJulian Wiedmann 		}
13729d6a569aSJulian Wiedmann 
13739f48b9dbSEugene Crosser 		dev_info(&data->card->gdev->dev,
1374a0138f59SAlexandra Winter 			 "Address change notification stopped on %s (%s)\n",
13759f48b9dbSEugene Crosser 			 data->card->dev->name,
1376a0138f59SAlexandra Winter 			(data->ac_event.lost_event_mask == 0x01)
13779f48b9dbSEugene Crosser 			? "Overflow"
1378a0138f59SAlexandra Winter 			: (data->ac_event.lost_event_mask == 0x02)
13799f48b9dbSEugene Crosser 			? "Bridge port state change"
13809f48b9dbSEugene Crosser 			: "Unknown reason");
13819d6a569aSJulian Wiedmann 
13829f48b9dbSEugene Crosser 		data->card->options.sbp.hostnotification = 0;
13839d6a569aSJulian Wiedmann 		card->info.pnso_mode = QETH_PNSO_NONE;
1384c8183f54SJulian Wiedmann 		mutex_unlock(&data->card->sbp_lock);
13859f48b9dbSEugene Crosser 		qeth_bridge_emit_host_event(data->card, anev_abort,
13869f48b9dbSEugene Crosser 					    0, NULL, NULL);
13879f48b9dbSEugene Crosser 	} else
1388a0138f59SAlexandra Winter 		for (i = 0; i < data->ac_event.num_entries; i++) {
13899f48b9dbSEugene Crosser 			struct qeth_ipacmd_addr_change_entry *entry =
1390a0138f59SAlexandra Winter 					&data->ac_event.entry[i];
13919f48b9dbSEugene Crosser 			qeth_bridge_emit_host_event(data->card,
13929f48b9dbSEugene Crosser 						    anev_reg_unreg,
13939f48b9dbSEugene Crosser 						    entry->change_code,
1394a0138f59SAlexandra Winter 						    &entry->token,
1395a0138f59SAlexandra Winter 						    &entry->addr_lnid);
13969f48b9dbSEugene Crosser 		}
13979d6a569aSJulian Wiedmann 
13989d6a569aSJulian Wiedmann free:
13999f48b9dbSEugene Crosser 	kfree(data);
14009f48b9dbSEugene Crosser }
14019f48b9dbSEugene Crosser 
1402a0138f59SAlexandra Winter static void qeth_addr_change_event(struct qeth_card *card,
1403c044dc21SEugene Crosser 				   struct qeth_ipa_cmd *cmd)
14049f48b9dbSEugene Crosser {
14059f48b9dbSEugene Crosser 	struct qeth_ipacmd_addr_change *hostevs =
14069f48b9dbSEugene Crosser 		 &cmd->data.addrchange;
1407a0138f59SAlexandra Winter 	struct qeth_addr_change_data *data;
14089f48b9dbSEugene Crosser 	int extrasize;
14099f48b9dbSEugene Crosser 
14109d6a569aSJulian Wiedmann 	if (card->info.pnso_mode == QETH_PNSO_NONE)
14119d6a569aSJulian Wiedmann 		return;
14129d6a569aSJulian Wiedmann 
1413a0138f59SAlexandra Winter 	QETH_CARD_TEXT(card, 4, "adrchgev");
14149f48b9dbSEugene Crosser 	if (cmd->hdr.return_code != 0x0000) {
14159f48b9dbSEugene Crosser 		if (cmd->hdr.return_code == 0x0010) {
14169f48b9dbSEugene Crosser 			if (hostevs->lost_event_mask == 0x00)
14179f48b9dbSEugene Crosser 				hostevs->lost_event_mask = 0xff;
14189f48b9dbSEugene Crosser 		} else {
1419a0138f59SAlexandra Winter 			QETH_CARD_TEXT_(card, 2, "ACHN%04x",
14209f48b9dbSEugene Crosser 				cmd->hdr.return_code);
14219f48b9dbSEugene Crosser 			return;
14229f48b9dbSEugene Crosser 		}
14239f48b9dbSEugene Crosser 	}
14249f48b9dbSEugene Crosser 	extrasize = sizeof(struct qeth_ipacmd_addr_change_entry) *
14259f48b9dbSEugene Crosser 						hostevs->num_entries;
1426a0138f59SAlexandra Winter 	data = kzalloc(sizeof(struct qeth_addr_change_data) + extrasize,
14279f48b9dbSEugene Crosser 		       GFP_ATOMIC);
14289f48b9dbSEugene Crosser 	if (!data) {
1429a0138f59SAlexandra Winter 		QETH_CARD_TEXT(card, 2, "ACNalloc");
14309f48b9dbSEugene Crosser 		return;
14319f48b9dbSEugene Crosser 	}
143210a6cfc0SAlexandra Winter 	if (card->info.pnso_mode == QETH_PNSO_BRIDGEPORT)
14339d6a569aSJulian Wiedmann 		INIT_DELAYED_WORK(&data->dwork, qeth_addr_change_event_worker);
143410a6cfc0SAlexandra Winter 	else
143510a6cfc0SAlexandra Winter 		INIT_DELAYED_WORK(&data->dwork, qeth_l2_dev2br_worker);
14369f48b9dbSEugene Crosser 	data->card = card;
1437a0138f59SAlexandra Winter 	memcpy(&data->ac_event, hostevs,
14389f48b9dbSEugene Crosser 			sizeof(struct qeth_ipacmd_addr_change) + extrasize);
14399d6a569aSJulian Wiedmann 	queue_delayed_work(card->event_wq, &data->dwork, 0);
14409f48b9dbSEugene Crosser }
14419f48b9dbSEugene Crosser 
1442b4d72c08SEugene Crosser /* SETBRIDGEPORT support; sending commands */
1443b4d72c08SEugene Crosser 
1444b4d72c08SEugene Crosser struct _qeth_sbp_cbctl {
1445b4d72c08SEugene Crosser 	union {
1446b4d72c08SEugene Crosser 		u32 supported;
1447b4d72c08SEugene Crosser 		struct {
1448b4d72c08SEugene Crosser 			enum qeth_sbp_roles *role;
1449b4d72c08SEugene Crosser 			enum qeth_sbp_states *state;
1450b4d72c08SEugene Crosser 		} qports;
1451b4d72c08SEugene Crosser 	} data;
1452b4d72c08SEugene Crosser };
1453b4d72c08SEugene Crosser 
1454b4d72c08SEugene Crosser static int qeth_bridgeport_makerc(struct qeth_card *card,
14551709ff8dSJulian Wiedmann 				  struct qeth_ipa_cmd *cmd)
1456b4d72c08SEugene Crosser {
14571709ff8dSJulian Wiedmann 	struct qeth_ipacmd_setbridgeport *sbp = &cmd->data.sbp;
14581709ff8dSJulian Wiedmann 	enum qeth_ipa_sbp_cmd setcmd = sbp->hdr.command_code;
14591709ff8dSJulian Wiedmann 	u16 ipa_rc = cmd->hdr.return_code;
14601709ff8dSJulian Wiedmann 	u16 sbp_rc = sbp->hdr.return_code;
1461b4d72c08SEugene Crosser 	int rc;
1462b4d72c08SEugene Crosser 
14631709ff8dSJulian Wiedmann 	if (ipa_rc == IPA_RC_SUCCESS && sbp_rc == IPA_RC_SUCCESS)
14641709ff8dSJulian Wiedmann 		return 0;
14651709ff8dSJulian Wiedmann 
14661709ff8dSJulian Wiedmann 	if ((IS_IQD(card) && ipa_rc == IPA_RC_SUCCESS) ||
14671709ff8dSJulian Wiedmann 	    (!IS_IQD(card) && ipa_rc == sbp_rc)) {
14681709ff8dSJulian Wiedmann 		switch (sbp_rc) {
14692063a5f5SKittipon Meesompop 		case IPA_RC_SUCCESS:
1470b4d72c08SEugene Crosser 			rc = 0;
1471b4d72c08SEugene Crosser 			break;
14722063a5f5SKittipon Meesompop 		case IPA_RC_L2_UNSUPPORTED_CMD:
14732063a5f5SKittipon Meesompop 		case IPA_RC_UNSUPPORTED_COMMAND:
1474ffb95251SEugene Crosser 			rc = -EOPNOTSUPP;
1475b4d72c08SEugene Crosser 			break;
14762063a5f5SKittipon Meesompop 		case IPA_RC_SBP_OSA_NOT_CONFIGURED:
14772063a5f5SKittipon Meesompop 		case IPA_RC_SBP_IQD_NOT_CONFIGURED:
1478b4d72c08SEugene Crosser 			rc = -ENODEV; /* maybe not the best code here? */
1479b4d72c08SEugene Crosser 			dev_err(&card->gdev->dev,
14809c23f4daSEugene Crosser 	"The device is not configured as a Bridge Port\n");
1481b4d72c08SEugene Crosser 			break;
14822063a5f5SKittipon Meesompop 		case IPA_RC_SBP_OSA_OS_MISMATCH:
14832063a5f5SKittipon Meesompop 		case IPA_RC_SBP_IQD_OS_MISMATCH:
14841b05cf62SEugene Crosser 			rc = -EPERM;
14851b05cf62SEugene Crosser 			dev_err(&card->gdev->dev,
14861b05cf62SEugene Crosser 	"A Bridge Port is already configured by a different operating system\n");
14871b05cf62SEugene Crosser 			break;
14882063a5f5SKittipon Meesompop 		case IPA_RC_SBP_OSA_ANO_DEV_PRIMARY:
14892063a5f5SKittipon Meesompop 		case IPA_RC_SBP_IQD_ANO_DEV_PRIMARY:
1490b4d72c08SEugene Crosser 			switch (setcmd) {
1491b4d72c08SEugene Crosser 			case IPA_SBP_SET_PRIMARY_BRIDGE_PORT:
1492b4d72c08SEugene Crosser 				rc = -EEXIST;
1493b4d72c08SEugene Crosser 				dev_err(&card->gdev->dev,
14949c23f4daSEugene Crosser 	"The LAN already has a primary Bridge Port\n");
1495b4d72c08SEugene Crosser 				break;
1496b4d72c08SEugene Crosser 			case IPA_SBP_SET_SECONDARY_BRIDGE_PORT:
1497b4d72c08SEugene Crosser 				rc = -EBUSY;
1498b4d72c08SEugene Crosser 				dev_err(&card->gdev->dev,
14999c23f4daSEugene Crosser 	"The device is already a primary Bridge Port\n");
1500b4d72c08SEugene Crosser 				break;
1501b4d72c08SEugene Crosser 			default:
1502b4d72c08SEugene Crosser 				rc = -EIO;
1503b4d72c08SEugene Crosser 			}
1504b4d72c08SEugene Crosser 			break;
15052063a5f5SKittipon Meesompop 		case IPA_RC_SBP_OSA_CURRENT_SECOND:
15062063a5f5SKittipon Meesompop 		case IPA_RC_SBP_IQD_CURRENT_SECOND:
1507b4d72c08SEugene Crosser 			rc = -EBUSY;
1508b4d72c08SEugene Crosser 			dev_err(&card->gdev->dev,
15099c23f4daSEugene Crosser 	"The device is already a secondary Bridge Port\n");
1510b4d72c08SEugene Crosser 			break;
15112063a5f5SKittipon Meesompop 		case IPA_RC_SBP_OSA_LIMIT_SECOND:
15122063a5f5SKittipon Meesompop 		case IPA_RC_SBP_IQD_LIMIT_SECOND:
1513b4d72c08SEugene Crosser 			rc = -EEXIST;
1514b4d72c08SEugene Crosser 			dev_err(&card->gdev->dev,
15159c23f4daSEugene Crosser 	"The LAN cannot have more secondary Bridge Ports\n");
1516b4d72c08SEugene Crosser 			break;
15172063a5f5SKittipon Meesompop 		case IPA_RC_SBP_OSA_CURRENT_PRIMARY:
15182063a5f5SKittipon Meesompop 		case IPA_RC_SBP_IQD_CURRENT_PRIMARY:
1519b4d72c08SEugene Crosser 			rc = -EBUSY;
1520b4d72c08SEugene Crosser 			dev_err(&card->gdev->dev,
15219c23f4daSEugene Crosser 	"The device is already a primary Bridge Port\n");
1522b4d72c08SEugene Crosser 			break;
15232063a5f5SKittipon Meesompop 		case IPA_RC_SBP_OSA_NOT_AUTHD_BY_ZMAN:
15242063a5f5SKittipon Meesompop 		case IPA_RC_SBP_IQD_NOT_AUTHD_BY_ZMAN:
1525b4d72c08SEugene Crosser 			rc = -EACCES;
1526b4d72c08SEugene Crosser 			dev_err(&card->gdev->dev,
15279c23f4daSEugene Crosser 	"The device is not authorized to be a Bridge Port\n");
1528b4d72c08SEugene Crosser 			break;
1529b4d72c08SEugene Crosser 		default:
1530b4d72c08SEugene Crosser 			rc = -EIO;
1531b4d72c08SEugene Crosser 		}
15321709ff8dSJulian Wiedmann 	} else {
15331709ff8dSJulian Wiedmann 		switch (ipa_rc) {
1534b4d72c08SEugene Crosser 		case IPA_RC_NOTSUPP:
1535ffb95251SEugene Crosser 			rc = -EOPNOTSUPP;
1536b4d72c08SEugene Crosser 			break;
1537b4d72c08SEugene Crosser 		case IPA_RC_UNSUPPORTED_COMMAND:
1538ffb95251SEugene Crosser 			rc = -EOPNOTSUPP;
1539b4d72c08SEugene Crosser 			break;
1540b4d72c08SEugene Crosser 		default:
1541b4d72c08SEugene Crosser 			rc = -EIO;
1542b4d72c08SEugene Crosser 		}
15431709ff8dSJulian Wiedmann 	}
15449c23f4daSEugene Crosser 
1545b4d72c08SEugene Crosser 	if (rc) {
15461709ff8dSJulian Wiedmann 		QETH_CARD_TEXT_(card, 2, "SBPi%04x", ipa_rc);
15471709ff8dSJulian Wiedmann 		QETH_CARD_TEXT_(card, 2, "SBPc%04x", sbp_rc);
1548b4d72c08SEugene Crosser 	}
1549b4d72c08SEugene Crosser 	return rc;
1550b4d72c08SEugene Crosser }
1551b4d72c08SEugene Crosser 
1552d65626adSJulian Wiedmann static struct qeth_cmd_buffer *qeth_sbp_build_cmd(struct qeth_card *card,
1553d65626adSJulian Wiedmann 						  enum qeth_ipa_sbp_cmd sbp_cmd,
1554b9150461SJulian Wiedmann 						  unsigned int data_length)
15559c23f4daSEugene Crosser {
1556379ac99eSJulian Wiedmann 	enum qeth_ipa_cmds ipa_cmd = IS_IQD(card) ? IPA_CMD_SETBRIDGEPORT_IQD :
15579c23f4daSEugene Crosser 						    IPA_CMD_SETBRIDGEPORT_OSA;
1558b9150461SJulian Wiedmann 	struct qeth_ipacmd_sbp_hdr *hdr;
1559d65626adSJulian Wiedmann 	struct qeth_cmd_buffer *iob;
1560d65626adSJulian Wiedmann 
1561b9150461SJulian Wiedmann 	iob = qeth_ipa_alloc_cmd(card, ipa_cmd, QETH_PROT_NONE,
1562b9150461SJulian Wiedmann 				 data_length +
1563b9150461SJulian Wiedmann 				 offsetof(struct qeth_ipacmd_setbridgeport,
1564b9150461SJulian Wiedmann 					  data));
1565d65626adSJulian Wiedmann 	if (!iob)
1566d65626adSJulian Wiedmann 		return iob;
1567b9150461SJulian Wiedmann 
1568b9150461SJulian Wiedmann 	hdr = &__ipa_cmd(iob)->data.sbp.hdr;
1569b9150461SJulian Wiedmann 	hdr->cmdlength = sizeof(*hdr) + data_length;
1570b9150461SJulian Wiedmann 	hdr->command_code = sbp_cmd;
1571b9150461SJulian Wiedmann 	hdr->used_total = 1;
1572b9150461SJulian Wiedmann 	hdr->seq_no = 1;
1573d65626adSJulian Wiedmann 	return iob;
15749c23f4daSEugene Crosser }
15759c23f4daSEugene Crosser 
1576b4d72c08SEugene Crosser static int qeth_bridgeport_query_support_cb(struct qeth_card *card,
1577b4d72c08SEugene Crosser 	struct qeth_reply *reply, unsigned long data)
1578b4d72c08SEugene Crosser {
1579b4d72c08SEugene Crosser 	struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
1580b4d72c08SEugene Crosser 	struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
15811709ff8dSJulian Wiedmann 	int rc;
15821709ff8dSJulian Wiedmann 
1583b4d72c08SEugene Crosser 	QETH_CARD_TEXT(card, 2, "brqsupcb");
15841709ff8dSJulian Wiedmann 	rc = qeth_bridgeport_makerc(card, cmd);
15851709ff8dSJulian Wiedmann 	if (rc)
15861709ff8dSJulian Wiedmann 		return rc;
15871709ff8dSJulian Wiedmann 
1588b4d72c08SEugene Crosser 	cbctl->data.supported =
1589b4d72c08SEugene Crosser 		cmd->data.sbp.data.query_cmds_supp.supported_cmds;
1590b4d72c08SEugene Crosser 	return 0;
1591b4d72c08SEugene Crosser }
1592b4d72c08SEugene Crosser 
1593b4d72c08SEugene Crosser /**
1594b4d72c08SEugene Crosser  * qeth_bridgeport_query_support() - store bitmask of supported subfunctions.
1595b4d72c08SEugene Crosser  * @card:			     qeth_card structure pointer.
1596b4d72c08SEugene Crosser  *
1597b4d72c08SEugene Crosser  * Sets bitmask of supported setbridgeport subfunctions in the qeth_card
1598b4d72c08SEugene Crosser  * strucutre: card->options.sbp.supported_funcs.
1599b4d72c08SEugene Crosser  */
1600c044dc21SEugene Crosser static void qeth_bridgeport_query_support(struct qeth_card *card)
1601b4d72c08SEugene Crosser {
1602b4d72c08SEugene Crosser 	struct qeth_cmd_buffer *iob;
1603b4d72c08SEugene Crosser 	struct _qeth_sbp_cbctl cbctl;
1604b4d72c08SEugene Crosser 
1605b4d72c08SEugene Crosser 	QETH_CARD_TEXT(card, 2, "brqsuppo");
1606d65626adSJulian Wiedmann 	iob = qeth_sbp_build_cmd(card, IPA_SBP_QUERY_COMMANDS_SUPPORTED,
1607b9150461SJulian Wiedmann 				 SBP_DATA_SIZEOF(query_cmds_supp));
16081aec42bcSThomas Richter 	if (!iob)
16091aec42bcSThomas Richter 		return;
16101709ff8dSJulian Wiedmann 
1611b4d72c08SEugene Crosser 	if (qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_support_cb,
16121709ff8dSJulian Wiedmann 			      &cbctl)) {
1613b4d72c08SEugene Crosser 		card->options.sbp.role = QETH_SBP_ROLE_NONE;
16141709ff8dSJulian Wiedmann 		card->options.sbp.supported_funcs = 0;
1615b4d72c08SEugene Crosser 		return;
1616b4d72c08SEugene Crosser 	}
1617b4d72c08SEugene Crosser 	card->options.sbp.supported_funcs = cbctl.data.supported;
1618b4d72c08SEugene Crosser }
1619b4d72c08SEugene Crosser 
1620b4d72c08SEugene Crosser static int qeth_bridgeport_query_ports_cb(struct qeth_card *card,
1621b4d72c08SEugene Crosser 	struct qeth_reply *reply, unsigned long data)
1622b4d72c08SEugene Crosser {
1623b4d72c08SEugene Crosser 	struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
1624b4d72c08SEugene Crosser 	struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
162565b0494eSJulian Wiedmann 	struct qeth_sbp_port_data *qports;
16261709ff8dSJulian Wiedmann 	int rc;
1627b4d72c08SEugene Crosser 
1628b4d72c08SEugene Crosser 	QETH_CARD_TEXT(card, 2, "brqprtcb");
16291709ff8dSJulian Wiedmann 	rc = qeth_bridgeport_makerc(card, cmd);
16301709ff8dSJulian Wiedmann 	if (rc)
16311709ff8dSJulian Wiedmann 		return rc;
16321709ff8dSJulian Wiedmann 
163365b0494eSJulian Wiedmann 	qports = &cmd->data.sbp.data.port_data;
1634b4d72c08SEugene Crosser 	if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) {
1635b4d72c08SEugene Crosser 		QETH_CARD_TEXT_(card, 2, "SBPs%04x", qports->entry_length);
16361709ff8dSJulian Wiedmann 		return -EINVAL;
1637b4d72c08SEugene Crosser 	}
1638b4d72c08SEugene Crosser 	/* first entry contains the state of the local port */
1639b4d72c08SEugene Crosser 	if (qports->num_entries > 0) {
1640b4d72c08SEugene Crosser 		if (cbctl->data.qports.role)
1641b4d72c08SEugene Crosser 			*cbctl->data.qports.role = qports->entry[0].role;
1642b4d72c08SEugene Crosser 		if (cbctl->data.qports.state)
1643b4d72c08SEugene Crosser 			*cbctl->data.qports.state = qports->entry[0].state;
1644b4d72c08SEugene Crosser 	}
1645b4d72c08SEugene Crosser 	return 0;
1646b4d72c08SEugene Crosser }
1647b4d72c08SEugene Crosser 
1648b4d72c08SEugene Crosser /**
1649b4d72c08SEugene Crosser  * qeth_bridgeport_query_ports() - query local bridgeport status.
1650b4d72c08SEugene Crosser  * @card:			   qeth_card structure pointer.
1651b4d72c08SEugene Crosser  * @role:   Role of the port: 0-none, 1-primary, 2-secondary.
1652b4d72c08SEugene Crosser  * @state:  State of the port: 0-inactive, 1-standby, 2-active.
1653b4d72c08SEugene Crosser  *
1654b4d72c08SEugene Crosser  * Returns negative errno-compatible error indication or 0 on success.
1655b4d72c08SEugene Crosser  *
1656b4d72c08SEugene Crosser  * 'role' and 'state' are not updated in case of hardware operation failure.
1657b4d72c08SEugene Crosser  */
1658b4d72c08SEugene Crosser int qeth_bridgeport_query_ports(struct qeth_card *card,
1659b4d72c08SEugene Crosser 	enum qeth_sbp_roles *role, enum qeth_sbp_states *state)
1660b4d72c08SEugene Crosser {
1661b4d72c08SEugene Crosser 	struct qeth_cmd_buffer *iob;
1662b4d72c08SEugene Crosser 	struct _qeth_sbp_cbctl cbctl = {
1663b4d72c08SEugene Crosser 		.data = {
1664b4d72c08SEugene Crosser 			.qports = {
1665b4d72c08SEugene Crosser 				.role = role,
1666b4d72c08SEugene Crosser 				.state = state,
1667b4d72c08SEugene Crosser 			},
1668b4d72c08SEugene Crosser 		},
1669b4d72c08SEugene Crosser 	};
1670b4d72c08SEugene Crosser 
1671b4d72c08SEugene Crosser 	QETH_CARD_TEXT(card, 2, "brqports");
1672b4d72c08SEugene Crosser 	if (!(card->options.sbp.supported_funcs & IPA_SBP_QUERY_BRIDGE_PORTS))
1673b4d72c08SEugene Crosser 		return -EOPNOTSUPP;
1674d65626adSJulian Wiedmann 	iob = qeth_sbp_build_cmd(card, IPA_SBP_QUERY_BRIDGE_PORTS, 0);
16751aec42bcSThomas Richter 	if (!iob)
16761aec42bcSThomas Richter 		return -ENOMEM;
16771709ff8dSJulian Wiedmann 
16781709ff8dSJulian Wiedmann 	return qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_ports_cb,
16791709ff8dSJulian Wiedmann 				 &cbctl);
1680b4d72c08SEugene Crosser }
1681b4d72c08SEugene Crosser 
1682b4d72c08SEugene Crosser static int qeth_bridgeport_set_cb(struct qeth_card *card,
1683b4d72c08SEugene Crosser 	struct qeth_reply *reply, unsigned long data)
1684b4d72c08SEugene Crosser {
1685b4d72c08SEugene Crosser 	struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data;
16861709ff8dSJulian Wiedmann 
1687b4d72c08SEugene Crosser 	QETH_CARD_TEXT(card, 2, "brsetrcb");
16881709ff8dSJulian Wiedmann 	return qeth_bridgeport_makerc(card, cmd);
1689b4d72c08SEugene Crosser }
1690b4d72c08SEugene Crosser 
1691b4d72c08SEugene Crosser /**
1692b4d72c08SEugene Crosser  * qeth_bridgeport_setrole() - Assign primary role to the port.
1693b4d72c08SEugene Crosser  * @card:		       qeth_card structure pointer.
1694b4d72c08SEugene Crosser  * @role:		       Role to assign.
1695b4d72c08SEugene Crosser  *
1696b4d72c08SEugene Crosser  * Returns negative errno-compatible error indication or 0 on success.
1697b4d72c08SEugene Crosser  */
1698b4d72c08SEugene Crosser int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role)
1699b4d72c08SEugene Crosser {
1700b4d72c08SEugene Crosser 	struct qeth_cmd_buffer *iob;
1701b4d72c08SEugene Crosser 	enum qeth_ipa_sbp_cmd setcmd;
1702b9150461SJulian Wiedmann 	unsigned int cmdlength = 0;
1703b4d72c08SEugene Crosser 
1704b4d72c08SEugene Crosser 	QETH_CARD_TEXT(card, 2, "brsetrol");
1705b4d72c08SEugene Crosser 	switch (role) {
1706b4d72c08SEugene Crosser 	case QETH_SBP_ROLE_NONE:
1707b4d72c08SEugene Crosser 		setcmd = IPA_SBP_RESET_BRIDGE_PORT_ROLE;
1708b4d72c08SEugene Crosser 		break;
1709b4d72c08SEugene Crosser 	case QETH_SBP_ROLE_PRIMARY:
1710b4d72c08SEugene Crosser 		setcmd = IPA_SBP_SET_PRIMARY_BRIDGE_PORT;
1711b9150461SJulian Wiedmann 		cmdlength = SBP_DATA_SIZEOF(set_primary);
1712b4d72c08SEugene Crosser 		break;
1713b4d72c08SEugene Crosser 	case QETH_SBP_ROLE_SECONDARY:
1714b4d72c08SEugene Crosser 		setcmd = IPA_SBP_SET_SECONDARY_BRIDGE_PORT;
1715b4d72c08SEugene Crosser 		break;
1716b4d72c08SEugene Crosser 	default:
1717b4d72c08SEugene Crosser 		return -EINVAL;
1718b4d72c08SEugene Crosser 	}
1719b4d72c08SEugene Crosser 	if (!(card->options.sbp.supported_funcs & setcmd))
1720b4d72c08SEugene Crosser 		return -EOPNOTSUPP;
1721d65626adSJulian Wiedmann 	iob = qeth_sbp_build_cmd(card, setcmd, cmdlength);
17221aec42bcSThomas Richter 	if (!iob)
17231aec42bcSThomas Richter 		return -ENOMEM;
17241709ff8dSJulian Wiedmann 
17251709ff8dSJulian Wiedmann 	return qeth_send_ipa_cmd(card, iob, qeth_bridgeport_set_cb, NULL);
1726b4d72c08SEugene Crosser }
1727b4d72c08SEugene Crosser 
17289f48b9dbSEugene Crosser static void qeth_bridgeport_an_set_cb(void *priv,
1729a0138f59SAlexandra Winter 				      struct chsc_pnso_naid_l2 *entry)
17309f48b9dbSEugene Crosser {
17319f48b9dbSEugene Crosser 	struct qeth_card *card = (struct qeth_card *)priv;
17329f48b9dbSEugene Crosser 	u8 code;
17339f48b9dbSEugene Crosser 
17349f48b9dbSEugene Crosser 	code = IPA_ADDR_CHANGE_CODE_MACADDR;
1735a0138f59SAlexandra Winter 	if (entry->addr_lnid.lnid < VLAN_N_VID)
17369f48b9dbSEugene Crosser 		code |= IPA_ADDR_CHANGE_CODE_VLANID;
17379f48b9dbSEugene Crosser 	qeth_bridge_emit_host_event(card, anev_reg_unreg, code,
1738a0138f59SAlexandra Winter 				    (struct net_if_token *)&entry->nit,
1739a0138f59SAlexandra Winter 				    (struct mac_addr_lnid *)&entry->addr_lnid);
17409f48b9dbSEugene Crosser }
17419f48b9dbSEugene Crosser 
17429f48b9dbSEugene Crosser /**
17439f48b9dbSEugene Crosser  * qeth_bridgeport_an_set() - Enable or disable bridgeport address notification
17449f48b9dbSEugene Crosser  * @card:		      qeth_card structure pointer.
17459f48b9dbSEugene Crosser  * @enable:		      0 - disable, non-zero - enable notifications
17469f48b9dbSEugene Crosser  *
17479f48b9dbSEugene Crosser  * Returns negative errno-compatible error indication or 0 on success.
17489f48b9dbSEugene Crosser  *
17499f48b9dbSEugene Crosser  * On enable, emits a series of address notifications udev events for all
17509f48b9dbSEugene Crosser  * currently registered hosts.
17519f48b9dbSEugene Crosser  */
17529f48b9dbSEugene Crosser int qeth_bridgeport_an_set(struct qeth_card *card, int enable)
17539f48b9dbSEugene Crosser {
17549f48b9dbSEugene Crosser 	int rc;
17559f48b9dbSEugene Crosser 
17569f48b9dbSEugene Crosser 	if (!card->options.sbp.supported_funcs)
17579f48b9dbSEugene Crosser 		return -EOPNOTSUPP;
17589f48b9dbSEugene Crosser 
17599f48b9dbSEugene Crosser 	if (enable) {
17609f48b9dbSEugene Crosser 		qeth_bridge_emit_host_event(card, anev_reset, 0, NULL, NULL);
17619d6a569aSJulian Wiedmann 		qeth_l2_set_pnso_mode(card, QETH_PNSO_BRIDGEPORT);
17624fea49a7SAlexandra Winter 		rc = qeth_l2_pnso(card, PNSO_OC_NET_BRIDGE_INFO, 1,
17634fea49a7SAlexandra Winter 				  qeth_bridgeport_an_set_cb, card);
17649d6a569aSJulian Wiedmann 		if (rc)
17659d6a569aSJulian Wiedmann 			qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
17669d6a569aSJulian Wiedmann 	} else {
17674fea49a7SAlexandra Winter 		rc = qeth_l2_pnso(card, PNSO_OC_NET_BRIDGE_INFO, 0, NULL, NULL);
17689d6a569aSJulian Wiedmann 		qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
17699d6a569aSJulian Wiedmann 	}
1770a0138f59SAlexandra Winter 	return rc;
17719f48b9dbSEugene Crosser }
17729f48b9dbSEugene Crosser 
1773a45b3fafSHans Wippel /* VNIC Characteristics support */
1774a45b3fafSHans Wippel 
1775a45b3fafSHans Wippel /* handle VNICC IPA command return codes; convert to error codes */
1776742d4d40SJulian Wiedmann static int qeth_l2_vnicc_makerc(struct qeth_card *card, u16 ipa_rc)
1777a45b3fafSHans Wippel {
1778a45b3fafSHans Wippel 	int rc;
1779a45b3fafSHans Wippel 
1780a45b3fafSHans Wippel 	switch (ipa_rc) {
1781a45b3fafSHans Wippel 	case IPA_RC_SUCCESS:
1782a45b3fafSHans Wippel 		return ipa_rc;
1783a45b3fafSHans Wippel 	case IPA_RC_L2_UNSUPPORTED_CMD:
1784a45b3fafSHans Wippel 	case IPA_RC_NOTSUPP:
1785a45b3fafSHans Wippel 		rc = -EOPNOTSUPP;
1786a45b3fafSHans Wippel 		break;
1787a45b3fafSHans Wippel 	case IPA_RC_VNICC_OOSEQ:
1788a45b3fafSHans Wippel 		rc = -EALREADY;
1789a45b3fafSHans Wippel 		break;
1790a45b3fafSHans Wippel 	case IPA_RC_VNICC_VNICBP:
1791a45b3fafSHans Wippel 		rc = -EBUSY;
1792a45b3fafSHans Wippel 		break;
1793a45b3fafSHans Wippel 	case IPA_RC_L2_ADDR_TABLE_FULL:
1794a45b3fafSHans Wippel 		rc = -ENOSPC;
1795a45b3fafSHans Wippel 		break;
1796a45b3fafSHans Wippel 	case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP:
1797a45b3fafSHans Wippel 		rc = -EACCES;
1798a45b3fafSHans Wippel 		break;
1799a45b3fafSHans Wippel 	default:
1800a45b3fafSHans Wippel 		rc = -EIO;
1801a45b3fafSHans Wippel 	}
1802a45b3fafSHans Wippel 
1803a45b3fafSHans Wippel 	QETH_CARD_TEXT_(card, 2, "err%04x", ipa_rc);
1804a45b3fafSHans Wippel 	return rc;
1805a45b3fafSHans Wippel }
1806a45b3fafSHans Wippel 
1807a45b3fafSHans Wippel /* generic VNICC request call back */
1808a45b3fafSHans Wippel static int qeth_l2_vnicc_request_cb(struct qeth_card *card,
1809a45b3fafSHans Wippel 				    struct qeth_reply *reply,
1810a45b3fafSHans Wippel 				    unsigned long data)
1811a45b3fafSHans Wippel {
1812a45b3fafSHans Wippel 	struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
1813a45b3fafSHans Wippel 	struct qeth_ipacmd_vnicc *rep = &cmd->data.vnicc;
18142744d811SJulian Wiedmann 	u32 sub_cmd = cmd->data.vnicc.hdr.sub_command;
1815a45b3fafSHans Wippel 
1816a45b3fafSHans Wippel 	QETH_CARD_TEXT(card, 2, "vniccrcb");
1817a45b3fafSHans Wippel 	if (cmd->hdr.return_code)
1818742d4d40SJulian Wiedmann 		return qeth_l2_vnicc_makerc(card, cmd->hdr.return_code);
1819a45b3fafSHans Wippel 	/* return results to caller */
18202cfb4810SJulian Wiedmann 	card->options.vnicc.sup_chars = rep->vnicc_cmds.supported;
18212cfb4810SJulian Wiedmann 	card->options.vnicc.cur_chars = rep->vnicc_cmds.enabled;
1822a45b3fafSHans Wippel 
18232744d811SJulian Wiedmann 	if (sub_cmd == IPA_VNICC_QUERY_CMDS)
182449f42f5dSJulian Wiedmann 		*(u32 *)reply->param = rep->data.query_cmds.sup_cmds;
18252744d811SJulian Wiedmann 	else if (sub_cmd == IPA_VNICC_GET_TIMEOUT)
182649f42f5dSJulian Wiedmann 		*(u32 *)reply->param = rep->data.getset_timeout.timeout;
1827349d13d5SHans Wippel 
1828a45b3fafSHans Wippel 	return 0;
1829a45b3fafSHans Wippel }
1830a45b3fafSHans Wippel 
18312cfb4810SJulian Wiedmann static struct qeth_cmd_buffer *qeth_l2_vnicc_build_cmd(struct qeth_card *card,
18322cfb4810SJulian Wiedmann 						       u32 vnicc_cmd,
18332cfb4810SJulian Wiedmann 						       unsigned int data_length)
1834a45b3fafSHans Wippel {
18352cfb4810SJulian Wiedmann 	struct qeth_ipacmd_vnicc_hdr *hdr;
1836a45b3fafSHans Wippel 	struct qeth_cmd_buffer *iob;
1837a45b3fafSHans Wippel 
18382cfb4810SJulian Wiedmann 	iob = qeth_ipa_alloc_cmd(card, IPA_CMD_VNICC, QETH_PROT_NONE,
18392cfb4810SJulian Wiedmann 				 data_length +
18402cfb4810SJulian Wiedmann 				 offsetof(struct qeth_ipacmd_vnicc, data));
1841a45b3fafSHans Wippel 	if (!iob)
18422cfb4810SJulian Wiedmann 		return NULL;
1843a45b3fafSHans Wippel 
18442cfb4810SJulian Wiedmann 	hdr = &__ipa_cmd(iob)->data.vnicc.hdr;
18452cfb4810SJulian Wiedmann 	hdr->data_length = sizeof(*hdr) + data_length;
18462cfb4810SJulian Wiedmann 	hdr->sub_command = vnicc_cmd;
18472cfb4810SJulian Wiedmann 	return iob;
1848a45b3fafSHans Wippel }
1849a45b3fafSHans Wippel 
1850a45b3fafSHans Wippel /* VNICC query VNIC characteristics request */
1851a45b3fafSHans Wippel static int qeth_l2_vnicc_query_chars(struct qeth_card *card)
1852a45b3fafSHans Wippel {
18532cfb4810SJulian Wiedmann 	struct qeth_cmd_buffer *iob;
18542cfb4810SJulian Wiedmann 
18552cfb4810SJulian Wiedmann 	QETH_CARD_TEXT(card, 2, "vniccqch");
18562cfb4810SJulian Wiedmann 	iob = qeth_l2_vnicc_build_cmd(card, IPA_VNICC_QUERY_CHARS, 0);
18572cfb4810SJulian Wiedmann 	if (!iob)
18582cfb4810SJulian Wiedmann 		return -ENOMEM;
1859a45b3fafSHans Wippel 
18602744d811SJulian Wiedmann 	return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, NULL);
1861a45b3fafSHans Wippel }
1862a45b3fafSHans Wippel 
1863caa1f0b1SHans Wippel /* VNICC query sub commands request */
1864caa1f0b1SHans Wippel static int qeth_l2_vnicc_query_cmds(struct qeth_card *card, u32 vnic_char,
1865caa1f0b1SHans Wippel 				    u32 *sup_cmds)
1866caa1f0b1SHans Wippel {
18672cfb4810SJulian Wiedmann 	struct qeth_cmd_buffer *iob;
18682cfb4810SJulian Wiedmann 
18692cfb4810SJulian Wiedmann 	QETH_CARD_TEXT(card, 2, "vniccqcm");
18702cfb4810SJulian Wiedmann 	iob = qeth_l2_vnicc_build_cmd(card, IPA_VNICC_QUERY_CMDS,
18712cfb4810SJulian Wiedmann 				      VNICC_DATA_SIZEOF(query_cmds));
18722cfb4810SJulian Wiedmann 	if (!iob)
18732cfb4810SJulian Wiedmann 		return -ENOMEM;
18742cfb4810SJulian Wiedmann 
18752cfb4810SJulian Wiedmann 	__ipa_cmd(iob)->data.vnicc.data.query_cmds.vnic_char = vnic_char;
1876caa1f0b1SHans Wippel 
187749f42f5dSJulian Wiedmann 	return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, sup_cmds);
1878caa1f0b1SHans Wippel }
1879caa1f0b1SHans Wippel 
1880caa1f0b1SHans Wippel /* VNICC enable/disable characteristic request */
1881caa1f0b1SHans Wippel static int qeth_l2_vnicc_set_char(struct qeth_card *card, u32 vnic_char,
1882caa1f0b1SHans Wippel 				      u32 cmd)
1883caa1f0b1SHans Wippel {
18842cfb4810SJulian Wiedmann 	struct qeth_cmd_buffer *iob;
18852cfb4810SJulian Wiedmann 
18862cfb4810SJulian Wiedmann 	QETH_CARD_TEXT(card, 2, "vniccedc");
18872cfb4810SJulian Wiedmann 	iob = qeth_l2_vnicc_build_cmd(card, cmd, VNICC_DATA_SIZEOF(set_char));
18882cfb4810SJulian Wiedmann 	if (!iob)
18892cfb4810SJulian Wiedmann 		return -ENOMEM;
18902cfb4810SJulian Wiedmann 
18912cfb4810SJulian Wiedmann 	__ipa_cmd(iob)->data.vnicc.data.set_char.vnic_char = vnic_char;
1892caa1f0b1SHans Wippel 
18932744d811SJulian Wiedmann 	return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, NULL);
1894caa1f0b1SHans Wippel }
1895caa1f0b1SHans Wippel 
1896349d13d5SHans Wippel /* VNICC get/set timeout for characteristic request */
1897349d13d5SHans Wippel static int qeth_l2_vnicc_getset_timeout(struct qeth_card *card, u32 vnicc,
1898349d13d5SHans Wippel 					u32 cmd, u32 *timeout)
1899349d13d5SHans Wippel {
19002cfb4810SJulian Wiedmann 	struct qeth_vnicc_getset_timeout *getset_timeout;
19012cfb4810SJulian Wiedmann 	struct qeth_cmd_buffer *iob;
19022cfb4810SJulian Wiedmann 
19032cfb4810SJulian Wiedmann 	QETH_CARD_TEXT(card, 2, "vniccgst");
19042cfb4810SJulian Wiedmann 	iob = qeth_l2_vnicc_build_cmd(card, cmd,
19052cfb4810SJulian Wiedmann 				      VNICC_DATA_SIZEOF(getset_timeout));
19062cfb4810SJulian Wiedmann 	if (!iob)
19072cfb4810SJulian Wiedmann 		return -ENOMEM;
19082cfb4810SJulian Wiedmann 
19092cfb4810SJulian Wiedmann 	getset_timeout = &__ipa_cmd(iob)->data.vnicc.data.getset_timeout;
19102cfb4810SJulian Wiedmann 	getset_timeout->vnic_char = vnicc;
19112cfb4810SJulian Wiedmann 
19122cfb4810SJulian Wiedmann 	if (cmd == IPA_VNICC_SET_TIMEOUT)
19132cfb4810SJulian Wiedmann 		getset_timeout->timeout = *timeout;
1914349d13d5SHans Wippel 
191549f42f5dSJulian Wiedmann 	return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, timeout);
1916349d13d5SHans Wippel }
1917349d13d5SHans Wippel 
191858fa3575SJulian Wiedmann /* recover user timeout setting */
191958fa3575SJulian Wiedmann static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc,
192058fa3575SJulian Wiedmann 					  u32 *timeout)
192158fa3575SJulian Wiedmann {
192258fa3575SJulian Wiedmann 	if (card->options.vnicc.sup_chars & vnicc &&
192358fa3575SJulian Wiedmann 	    card->options.vnicc.getset_timeout_sup & vnicc &&
192458fa3575SJulian Wiedmann 	    !qeth_l2_vnicc_getset_timeout(card, vnicc, IPA_VNICC_SET_TIMEOUT,
192558fa3575SJulian Wiedmann 					  timeout))
192658fa3575SJulian Wiedmann 		return false;
192758fa3575SJulian Wiedmann 	*timeout = QETH_VNICC_DEFAULT_TIMEOUT;
192858fa3575SJulian Wiedmann 	return true;
192958fa3575SJulian Wiedmann }
193058fa3575SJulian Wiedmann 
1931caa1f0b1SHans Wippel /* set current VNICC flag state; called from sysfs store function */
1932caa1f0b1SHans Wippel int qeth_l2_vnicc_set_state(struct qeth_card *card, u32 vnicc, bool state)
1933caa1f0b1SHans Wippel {
1934caa1f0b1SHans Wippel 	int rc = 0;
1935caa1f0b1SHans Wippel 	u32 cmd;
1936caa1f0b1SHans Wippel 
1937caa1f0b1SHans Wippel 	QETH_CARD_TEXT(card, 2, "vniccsch");
1938caa1f0b1SHans Wippel 
1939caa1f0b1SHans Wippel 	/* check if characteristic and enable/disable are supported */
1940caa1f0b1SHans Wippel 	if (!(card->options.vnicc.sup_chars & vnicc) ||
1941caa1f0b1SHans Wippel 	    !(card->options.vnicc.set_char_sup & vnicc))
1942caa1f0b1SHans Wippel 		return -EOPNOTSUPP;
1943caa1f0b1SHans Wippel 
19446f3846f0SAlexandra Winter 	if (qeth_bridgeport_is_in_use(card))
19456f3846f0SAlexandra Winter 		return -EBUSY;
19466f3846f0SAlexandra Winter 
1947caa1f0b1SHans Wippel 	/* set enable/disable command and store wanted characteristic */
1948caa1f0b1SHans Wippel 	if (state) {
1949caa1f0b1SHans Wippel 		cmd = IPA_VNICC_ENABLE;
1950caa1f0b1SHans Wippel 		card->options.vnicc.wanted_chars |= vnicc;
1951caa1f0b1SHans Wippel 	} else {
1952caa1f0b1SHans Wippel 		cmd = IPA_VNICC_DISABLE;
1953caa1f0b1SHans Wippel 		card->options.vnicc.wanted_chars &= ~vnicc;
1954caa1f0b1SHans Wippel 	}
1955caa1f0b1SHans Wippel 
1956caa1f0b1SHans Wippel 	/* do we need to do anything? */
1957caa1f0b1SHans Wippel 	if (card->options.vnicc.cur_chars == card->options.vnicc.wanted_chars)
1958caa1f0b1SHans Wippel 		return rc;
1959caa1f0b1SHans Wippel 
1960caa1f0b1SHans Wippel 	/* if card is not ready, simply stop here */
1961caa1f0b1SHans Wippel 	if (!qeth_card_hw_is_reachable(card)) {
1962caa1f0b1SHans Wippel 		if (state)
1963caa1f0b1SHans Wippel 			card->options.vnicc.cur_chars |= vnicc;
1964caa1f0b1SHans Wippel 		else
1965caa1f0b1SHans Wippel 			card->options.vnicc.cur_chars &= ~vnicc;
1966caa1f0b1SHans Wippel 		return rc;
1967caa1f0b1SHans Wippel 	}
1968caa1f0b1SHans Wippel 
1969caa1f0b1SHans Wippel 	rc = qeth_l2_vnicc_set_char(card, vnicc, cmd);
1970caa1f0b1SHans Wippel 	if (rc)
1971caa1f0b1SHans Wippel 		card->options.vnicc.wanted_chars =
1972caa1f0b1SHans Wippel 			card->options.vnicc.cur_chars;
1973349d13d5SHans Wippel 	else {
1974349d13d5SHans Wippel 		/* successful online VNICC change; handle special cases */
1975349d13d5SHans Wippel 		if (state && vnicc == QETH_VNICC_RX_BCAST)
1976caa1f0b1SHans Wippel 			card->options.vnicc.rx_bcast_enabled = true;
1977349d13d5SHans Wippel 		if (!state && vnicc == QETH_VNICC_LEARNING)
1978349d13d5SHans Wippel 			qeth_l2_vnicc_recover_timeout(card, vnicc,
1979349d13d5SHans Wippel 					&card->options.vnicc.learning_timeout);
1980349d13d5SHans Wippel 	}
1981caa1f0b1SHans Wippel 
1982caa1f0b1SHans Wippel 	return rc;
1983caa1f0b1SHans Wippel }
1984caa1f0b1SHans Wippel 
1985caa1f0b1SHans Wippel /* get current VNICC flag state; called from sysfs show function */
1986caa1f0b1SHans Wippel int qeth_l2_vnicc_get_state(struct qeth_card *card, u32 vnicc, bool *state)
1987caa1f0b1SHans Wippel {
1988caa1f0b1SHans Wippel 	int rc = 0;
1989caa1f0b1SHans Wippel 
1990caa1f0b1SHans Wippel 	QETH_CARD_TEXT(card, 2, "vniccgch");
1991caa1f0b1SHans Wippel 
1992caa1f0b1SHans Wippel 	/* check if characteristic is supported */
1993caa1f0b1SHans Wippel 	if (!(card->options.vnicc.sup_chars & vnicc))
1994caa1f0b1SHans Wippel 		return -EOPNOTSUPP;
1995caa1f0b1SHans Wippel 
19966f3846f0SAlexandra Winter 	if (qeth_bridgeport_is_in_use(card))
19976f3846f0SAlexandra Winter 		return -EBUSY;
19986f3846f0SAlexandra Winter 
1999caa1f0b1SHans Wippel 	/* if card is ready, query current VNICC state */
2000caa1f0b1SHans Wippel 	if (qeth_card_hw_is_reachable(card))
2001caa1f0b1SHans Wippel 		rc = qeth_l2_vnicc_query_chars(card);
2002caa1f0b1SHans Wippel 
2003caa1f0b1SHans Wippel 	*state = (card->options.vnicc.cur_chars & vnicc) ? true : false;
2004caa1f0b1SHans Wippel 	return rc;
2005caa1f0b1SHans Wippel }
2006caa1f0b1SHans Wippel 
2007349d13d5SHans Wippel /* set VNICC timeout; called from sysfs store function. Currently, only learning
2008349d13d5SHans Wippel  * supports timeout
2009349d13d5SHans Wippel  */
2010349d13d5SHans Wippel int qeth_l2_vnicc_set_timeout(struct qeth_card *card, u32 timeout)
2011349d13d5SHans Wippel {
2012349d13d5SHans Wippel 	int rc = 0;
2013349d13d5SHans Wippel 
2014349d13d5SHans Wippel 	QETH_CARD_TEXT(card, 2, "vniccsto");
2015349d13d5SHans Wippel 
2016349d13d5SHans Wippel 	/* check if characteristic and set_timeout are supported */
2017349d13d5SHans Wippel 	if (!(card->options.vnicc.sup_chars & QETH_VNICC_LEARNING) ||
2018349d13d5SHans Wippel 	    !(card->options.vnicc.getset_timeout_sup & QETH_VNICC_LEARNING))
2019349d13d5SHans Wippel 		return -EOPNOTSUPP;
2020349d13d5SHans Wippel 
20216f3846f0SAlexandra Winter 	if (qeth_bridgeport_is_in_use(card))
20226f3846f0SAlexandra Winter 		return -EBUSY;
20236f3846f0SAlexandra Winter 
2024349d13d5SHans Wippel 	/* do we need to do anything? */
2025349d13d5SHans Wippel 	if (card->options.vnicc.learning_timeout == timeout)
2026349d13d5SHans Wippel 		return rc;
2027349d13d5SHans Wippel 
2028349d13d5SHans Wippel 	/* if card is not ready, simply store the value internally and return */
2029349d13d5SHans Wippel 	if (!qeth_card_hw_is_reachable(card)) {
2030349d13d5SHans Wippel 		card->options.vnicc.learning_timeout = timeout;
2031349d13d5SHans Wippel 		return rc;
2032349d13d5SHans Wippel 	}
2033349d13d5SHans Wippel 
2034349d13d5SHans Wippel 	/* send timeout value to card; if successful, store value internally */
2035349d13d5SHans Wippel 	rc = qeth_l2_vnicc_getset_timeout(card, QETH_VNICC_LEARNING,
2036349d13d5SHans Wippel 					  IPA_VNICC_SET_TIMEOUT, &timeout);
2037349d13d5SHans Wippel 	if (!rc)
2038349d13d5SHans Wippel 		card->options.vnicc.learning_timeout = timeout;
2039349d13d5SHans Wippel 
2040349d13d5SHans Wippel 	return rc;
2041349d13d5SHans Wippel }
2042349d13d5SHans Wippel 
2043349d13d5SHans Wippel /* get current VNICC timeout; called from sysfs show function. Currently, only
2044349d13d5SHans Wippel  * learning supports timeout
2045349d13d5SHans Wippel  */
2046349d13d5SHans Wippel int qeth_l2_vnicc_get_timeout(struct qeth_card *card, u32 *timeout)
2047349d13d5SHans Wippel {
2048349d13d5SHans Wippel 	int rc = 0;
2049349d13d5SHans Wippel 
2050349d13d5SHans Wippel 	QETH_CARD_TEXT(card, 2, "vniccgto");
2051349d13d5SHans Wippel 
2052349d13d5SHans Wippel 	/* check if characteristic and get_timeout are supported */
2053349d13d5SHans Wippel 	if (!(card->options.vnicc.sup_chars & QETH_VNICC_LEARNING) ||
2054349d13d5SHans Wippel 	    !(card->options.vnicc.getset_timeout_sup & QETH_VNICC_LEARNING))
2055349d13d5SHans Wippel 		return -EOPNOTSUPP;
20566f3846f0SAlexandra Winter 
20576f3846f0SAlexandra Winter 	if (qeth_bridgeport_is_in_use(card))
20586f3846f0SAlexandra Winter 		return -EBUSY;
20596f3846f0SAlexandra Winter 
2060349d13d5SHans Wippel 	/* if card is ready, get timeout. Otherwise, just return stored value */
2061349d13d5SHans Wippel 	*timeout = card->options.vnicc.learning_timeout;
2062349d13d5SHans Wippel 	if (qeth_card_hw_is_reachable(card))
2063349d13d5SHans Wippel 		rc = qeth_l2_vnicc_getset_timeout(card, QETH_VNICC_LEARNING,
2064349d13d5SHans Wippel 						  IPA_VNICC_GET_TIMEOUT,
2065349d13d5SHans Wippel 						  timeout);
2066349d13d5SHans Wippel 
2067349d13d5SHans Wippel 	return rc;
2068349d13d5SHans Wippel }
2069349d13d5SHans Wippel 
2070caa1f0b1SHans Wippel /* check if VNICC is currently enabled */
2071817741a8SAlexandra Winter static bool _qeth_l2_vnicc_is_in_use(struct qeth_card *card)
2072caa1f0b1SHans Wippel {
2073e8a66d80SAlexandra Winter 	if (!card->options.vnicc.sup_chars)
2074caa1f0b1SHans Wippel 		return false;
2075caa1f0b1SHans Wippel 	/* default values are only OK if rx_bcast was not enabled by user
2076caa1f0b1SHans Wippel 	 * or the card is offline.
2077caa1f0b1SHans Wippel 	 */
2078caa1f0b1SHans Wippel 	if (card->options.vnicc.cur_chars == QETH_VNICC_DEFAULT) {
2079caa1f0b1SHans Wippel 		if (!card->options.vnicc.rx_bcast_enabled ||
2080caa1f0b1SHans Wippel 		    !qeth_card_hw_is_reachable(card))
2081caa1f0b1SHans Wippel 			return false;
2082caa1f0b1SHans Wippel 	}
2083caa1f0b1SHans Wippel 	return true;
2084caa1f0b1SHans Wippel }
2085caa1f0b1SHans Wippel 
2086817741a8SAlexandra Winter /**
2087817741a8SAlexandra Winter  *	qeth_bridgeport_allowed - are any qeth_bridgeport functions allowed?
2088817741a8SAlexandra Winter  *	@card: qeth_card structure pointer
2089817741a8SAlexandra Winter  *
2090817741a8SAlexandra Winter  *	qeth_bridgeport functionality is mutually exclusive with usage of the
2091817741a8SAlexandra Winter  *	VNIC Characteristics and dev2br address notifications
2092817741a8SAlexandra Winter  */
2093817741a8SAlexandra Winter bool qeth_bridgeport_allowed(struct qeth_card *card)
2094817741a8SAlexandra Winter {
2095817741a8SAlexandra Winter 	struct qeth_priv *priv = netdev_priv(card->dev);
2096817741a8SAlexandra Winter 
2097817741a8SAlexandra Winter 	return (!_qeth_l2_vnicc_is_in_use(card) &&
2098817741a8SAlexandra Winter 		!(priv->brport_features & BR_LEARNING_SYNC));
2099817741a8SAlexandra Winter }
2100817741a8SAlexandra Winter 
2101caa1f0b1SHans Wippel /* recover user characteristic setting */
2102caa1f0b1SHans Wippel static bool qeth_l2_vnicc_recover_char(struct qeth_card *card, u32 vnicc,
2103caa1f0b1SHans Wippel 				       bool enable)
2104caa1f0b1SHans Wippel {
2105caa1f0b1SHans Wippel 	u32 cmd = enable ? IPA_VNICC_ENABLE : IPA_VNICC_DISABLE;
2106caa1f0b1SHans Wippel 
2107caa1f0b1SHans Wippel 	if (card->options.vnicc.sup_chars & vnicc &&
2108caa1f0b1SHans Wippel 	    card->options.vnicc.set_char_sup & vnicc &&
2109caa1f0b1SHans Wippel 	    !qeth_l2_vnicc_set_char(card, vnicc, cmd))
2110caa1f0b1SHans Wippel 		return false;
2111caa1f0b1SHans Wippel 	card->options.vnicc.wanted_chars &= ~vnicc;
2112caa1f0b1SHans Wippel 	card->options.vnicc.wanted_chars |= QETH_VNICC_DEFAULT & vnicc;
2113caa1f0b1SHans Wippel 	return true;
2114caa1f0b1SHans Wippel }
2115caa1f0b1SHans Wippel 
2116a45b3fafSHans Wippel /* (re-)initialize VNICC */
2117a45b3fafSHans Wippel static void qeth_l2_vnicc_init(struct qeth_card *card)
2118a45b3fafSHans Wippel {
2119349d13d5SHans Wippel 	u32 *timeout = &card->options.vnicc.learning_timeout;
2120b528965bSAlexandra Winter 	bool enable, error = false;
2121caa1f0b1SHans Wippel 	unsigned int chars_len, i;
2122caa1f0b1SHans Wippel 	unsigned long chars_tmp;
2123caa1f0b1SHans Wippel 	u32 sup_cmds, vnicc;
2124caa1f0b1SHans Wippel 
2125a45b3fafSHans Wippel 	QETH_CARD_TEXT(card, 2, "vniccini");
2126caa1f0b1SHans Wippel 	/* reset rx_bcast */
2127caa1f0b1SHans Wippel 	card->options.vnicc.rx_bcast_enabled = 0;
2128a45b3fafSHans Wippel 	/* initial query and storage of VNIC characteristics */
2129a45b3fafSHans Wippel 	if (qeth_l2_vnicc_query_chars(card)) {
2130349d13d5SHans Wippel 		if (card->options.vnicc.wanted_chars != QETH_VNICC_DEFAULT ||
2131349d13d5SHans Wippel 		    *timeout != QETH_VNICC_DEFAULT_TIMEOUT)
2132caa1f0b1SHans Wippel 			dev_err(&card->gdev->dev, "Configuring the VNIC characteristics failed\n");
2133caa1f0b1SHans Wippel 		/* fail quietly if user didn't change the default config */
2134a45b3fafSHans Wippel 		card->options.vnicc.sup_chars = 0;
2135a45b3fafSHans Wippel 		card->options.vnicc.cur_chars = 0;
2136caa1f0b1SHans Wippel 		card->options.vnicc.wanted_chars = QETH_VNICC_DEFAULT;
2137caa1f0b1SHans Wippel 		return;
2138a45b3fafSHans Wippel 	}
2139caa1f0b1SHans Wippel 	/* get supported commands for each supported characteristic */
2140caa1f0b1SHans Wippel 	chars_tmp = card->options.vnicc.sup_chars;
2141caa1f0b1SHans Wippel 	chars_len = sizeof(card->options.vnicc.sup_chars) * BITS_PER_BYTE;
2142caa1f0b1SHans Wippel 	for_each_set_bit(i, &chars_tmp, chars_len) {
2143caa1f0b1SHans Wippel 		vnicc = BIT(i);
2144b528965bSAlexandra Winter 		if (qeth_l2_vnicc_query_cmds(card, vnicc, &sup_cmds)) {
2145b528965bSAlexandra Winter 			sup_cmds = 0;
2146b528965bSAlexandra Winter 			error = true;
2147b528965bSAlexandra Winter 		}
2148be40a86cSAlexandra Winter 		if ((sup_cmds & IPA_VNICC_SET_TIMEOUT) &&
2149be40a86cSAlexandra Winter 		    (sup_cmds & IPA_VNICC_GET_TIMEOUT))
2150be40a86cSAlexandra Winter 			card->options.vnicc.getset_timeout_sup |= vnicc;
2151be40a86cSAlexandra Winter 		else
2152349d13d5SHans Wippel 			card->options.vnicc.getset_timeout_sup &= ~vnicc;
2153be40a86cSAlexandra Winter 		if ((sup_cmds & IPA_VNICC_ENABLE) &&
2154be40a86cSAlexandra Winter 		    (sup_cmds & IPA_VNICC_DISABLE))
2155be40a86cSAlexandra Winter 			card->options.vnicc.set_char_sup |= vnicc;
2156be40a86cSAlexandra Winter 		else
2157caa1f0b1SHans Wippel 			card->options.vnicc.set_char_sup &= ~vnicc;
2158caa1f0b1SHans Wippel 	}
2159caa1f0b1SHans Wippel 	/* enforce assumed default values and recover settings, if changed  */
2160b528965bSAlexandra Winter 	error |= qeth_l2_vnicc_recover_timeout(card, QETH_VNICC_LEARNING,
2161349d13d5SHans Wippel 					       timeout);
2162d1b9ae18SAlexandra Winter 	/* Change chars, if necessary  */
2163d1b9ae18SAlexandra Winter 	chars_tmp = card->options.vnicc.wanted_chars ^
2164d1b9ae18SAlexandra Winter 		    card->options.vnicc.cur_chars;
2165caa1f0b1SHans Wippel 	chars_len = sizeof(card->options.vnicc.wanted_chars) * BITS_PER_BYTE;
2166caa1f0b1SHans Wippel 	for_each_set_bit(i, &chars_tmp, chars_len) {
2167caa1f0b1SHans Wippel 		vnicc = BIT(i);
2168caa1f0b1SHans Wippel 		enable = card->options.vnicc.wanted_chars & vnicc;
2169caa1f0b1SHans Wippel 		error |= qeth_l2_vnicc_recover_char(card, vnicc, enable);
2170caa1f0b1SHans Wippel 	}
2171caa1f0b1SHans Wippel 	if (error)
2172caa1f0b1SHans Wippel 		dev_err(&card->gdev->dev, "Configuring the VNIC characteristics failed\n");
2173caa1f0b1SHans Wippel }
2174caa1f0b1SHans Wippel 
2175caa1f0b1SHans Wippel /* configure default values of VNIC characteristics */
2176caa1f0b1SHans Wippel static void qeth_l2_vnicc_set_defaults(struct qeth_card *card)
2177caa1f0b1SHans Wippel {
2178caa1f0b1SHans Wippel 	/* characteristics values */
2179caa1f0b1SHans Wippel 	card->options.vnicc.sup_chars = QETH_VNICC_ALL;
2180caa1f0b1SHans Wippel 	card->options.vnicc.cur_chars = QETH_VNICC_DEFAULT;
2181349d13d5SHans Wippel 	card->options.vnicc.learning_timeout = QETH_VNICC_DEFAULT_TIMEOUT;
2182caa1f0b1SHans Wippel 	/* supported commands */
2183caa1f0b1SHans Wippel 	card->options.vnicc.set_char_sup = QETH_VNICC_ALL;
2184349d13d5SHans Wippel 	card->options.vnicc.getset_timeout_sup = QETH_VNICC_LEARNING;
2185caa1f0b1SHans Wippel 	/* settings wanted by users */
2186caa1f0b1SHans Wippel 	card->options.vnicc.wanted_chars = QETH_VNICC_DEFAULT;
2187a45b3fafSHans Wippel }
2188a45b3fafSHans Wippel 
218958fa3575SJulian Wiedmann static const struct device_type qeth_l2_devtype = {
219058fa3575SJulian Wiedmann 	.name = "qeth_layer2",
219158fa3575SJulian Wiedmann 	.groups = qeth_l2_attr_groups,
219258fa3575SJulian Wiedmann };
219358fa3575SJulian Wiedmann 
219458fa3575SJulian Wiedmann static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
219558fa3575SJulian Wiedmann {
219658fa3575SJulian Wiedmann 	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
219758fa3575SJulian Wiedmann 	int rc;
219858fa3575SJulian Wiedmann 
219958fa3575SJulian Wiedmann 	if (IS_OSN(card))
220058fa3575SJulian Wiedmann 		dev_notice(&gdev->dev, "OSN support will be dropped in 2021\n");
220158fa3575SJulian Wiedmann 
220258fa3575SJulian Wiedmann 	qeth_l2_vnicc_set_defaults(card);
220358fa3575SJulian Wiedmann 	mutex_init(&card->sbp_lock);
220458fa3575SJulian Wiedmann 
220558fa3575SJulian Wiedmann 	if (gdev->dev.type == &qeth_generic_devtype) {
220658fa3575SJulian Wiedmann 		rc = qeth_l2_create_device_attributes(&gdev->dev);
220758fa3575SJulian Wiedmann 		if (rc)
220858fa3575SJulian Wiedmann 			return rc;
220958fa3575SJulian Wiedmann 	}
221058fa3575SJulian Wiedmann 
221158fa3575SJulian Wiedmann 	INIT_WORK(&card->rx_mode_work, qeth_l2_rx_mode_work);
221258fa3575SJulian Wiedmann 	return 0;
221358fa3575SJulian Wiedmann }
221458fa3575SJulian Wiedmann 
221558fa3575SJulian Wiedmann static void qeth_l2_remove_device(struct ccwgroup_device *gdev)
221658fa3575SJulian Wiedmann {
221758fa3575SJulian Wiedmann 	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
221858fa3575SJulian Wiedmann 
221958fa3575SJulian Wiedmann 	if (gdev->dev.type == &qeth_generic_devtype)
222058fa3575SJulian Wiedmann 		qeth_l2_remove_device_attributes(&gdev->dev);
222158fa3575SJulian Wiedmann 	qeth_set_allowed_threads(card, 0, 1);
222258fa3575SJulian Wiedmann 	wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
222358fa3575SJulian Wiedmann 
222458fa3575SJulian Wiedmann 	if (gdev->state == CCWGROUP_ONLINE)
222558fa3575SJulian Wiedmann 		qeth_set_offline(card, false);
222658fa3575SJulian Wiedmann 
222758fa3575SJulian Wiedmann 	cancel_work_sync(&card->close_dev_work);
222858fa3575SJulian Wiedmann 	if (card->dev->reg_state == NETREG_REGISTERED)
222958fa3575SJulian Wiedmann 		unregister_netdev(card->dev);
223058fa3575SJulian Wiedmann }
223158fa3575SJulian Wiedmann 
223258fa3575SJulian Wiedmann static int qeth_l2_set_online(struct qeth_card *card, bool carrier_ok)
223358fa3575SJulian Wiedmann {
223458fa3575SJulian Wiedmann 	struct net_device *dev = card->dev;
223558fa3575SJulian Wiedmann 	int rc = 0;
223658fa3575SJulian Wiedmann 
223758fa3575SJulian Wiedmann 	/* query before bridgeport_notification may be enabled */
223858fa3575SJulian Wiedmann 	qeth_l2_detect_dev2br_support(card);
223958fa3575SJulian Wiedmann 
224058fa3575SJulian Wiedmann 	mutex_lock(&card->sbp_lock);
224158fa3575SJulian Wiedmann 	qeth_bridgeport_query_support(card);
224258fa3575SJulian Wiedmann 	if (card->options.sbp.supported_funcs) {
224358fa3575SJulian Wiedmann 		qeth_l2_setup_bridgeport_attrs(card);
224458fa3575SJulian Wiedmann 		dev_info(&card->gdev->dev,
224558fa3575SJulian Wiedmann 			 "The device represents a Bridge Capable Port\n");
224658fa3575SJulian Wiedmann 	}
224758fa3575SJulian Wiedmann 	mutex_unlock(&card->sbp_lock);
224858fa3575SJulian Wiedmann 
224958fa3575SJulian Wiedmann 	qeth_l2_register_dev_addr(card);
225058fa3575SJulian Wiedmann 
225158fa3575SJulian Wiedmann 	/* for the rx_bcast characteristic, init VNICC after setmac */
225258fa3575SJulian Wiedmann 	qeth_l2_vnicc_init(card);
225358fa3575SJulian Wiedmann 
225458fa3575SJulian Wiedmann 	qeth_l2_trace_features(card);
225558fa3575SJulian Wiedmann 
225658fa3575SJulian Wiedmann 	/* softsetup */
225758fa3575SJulian Wiedmann 	QETH_CARD_TEXT(card, 2, "softsetp");
225858fa3575SJulian Wiedmann 
225958fa3575SJulian Wiedmann 	card->state = CARD_STATE_SOFTSETUP;
226058fa3575SJulian Wiedmann 
226158fa3575SJulian Wiedmann 	qeth_set_allowed_threads(card, 0xffffffff, 0);
226258fa3575SJulian Wiedmann 
226358fa3575SJulian Wiedmann 	if (dev->reg_state != NETREG_REGISTERED) {
226458fa3575SJulian Wiedmann 		rc = qeth_l2_setup_netdev(card);
226558fa3575SJulian Wiedmann 		if (rc)
226658fa3575SJulian Wiedmann 			goto err_setup;
226758fa3575SJulian Wiedmann 
226858fa3575SJulian Wiedmann 		if (carrier_ok)
226958fa3575SJulian Wiedmann 			netif_carrier_on(dev);
227058fa3575SJulian Wiedmann 	} else {
227158fa3575SJulian Wiedmann 		rtnl_lock();
2272bb5ab541SJulian Wiedmann 		rc = qeth_set_real_num_tx_queues(card,
2273bb5ab541SJulian Wiedmann 						 qeth_tx_actual_queues(card));
2274bb5ab541SJulian Wiedmann 		if (rc) {
2275bb5ab541SJulian Wiedmann 			rtnl_unlock();
2276bb5ab541SJulian Wiedmann 			goto err_set_queues;
2277bb5ab541SJulian Wiedmann 		}
2278bb5ab541SJulian Wiedmann 
227958fa3575SJulian Wiedmann 		if (carrier_ok)
228058fa3575SJulian Wiedmann 			netif_carrier_on(dev);
228158fa3575SJulian Wiedmann 		else
228258fa3575SJulian Wiedmann 			netif_carrier_off(dev);
228358fa3575SJulian Wiedmann 
228458fa3575SJulian Wiedmann 		netif_device_attach(dev);
228558fa3575SJulian Wiedmann 		qeth_enable_hw_features(dev);
228658fa3575SJulian Wiedmann 		qeth_l2_enable_brport_features(card);
228758fa3575SJulian Wiedmann 
228858fa3575SJulian Wiedmann 		if (card->info.open_when_online) {
228958fa3575SJulian Wiedmann 			card->info.open_when_online = 0;
229058fa3575SJulian Wiedmann 			dev_open(dev, NULL);
229158fa3575SJulian Wiedmann 		}
229258fa3575SJulian Wiedmann 		rtnl_unlock();
229358fa3575SJulian Wiedmann 	}
229458fa3575SJulian Wiedmann 	return 0;
229558fa3575SJulian Wiedmann 
2296bb5ab541SJulian Wiedmann err_set_queues:
229758fa3575SJulian Wiedmann err_setup:
229858fa3575SJulian Wiedmann 	qeth_set_allowed_threads(card, 0, 1);
229958fa3575SJulian Wiedmann 	card->state = CARD_STATE_DOWN;
230058fa3575SJulian Wiedmann 	return rc;
230158fa3575SJulian Wiedmann }
230258fa3575SJulian Wiedmann 
230358fa3575SJulian Wiedmann static void qeth_l2_set_offline(struct qeth_card *card)
230458fa3575SJulian Wiedmann {
230558fa3575SJulian Wiedmann 	struct qeth_priv *priv = netdev_priv(card->dev);
230658fa3575SJulian Wiedmann 
230758fa3575SJulian Wiedmann 	qeth_set_allowed_threads(card, 0, 1);
230858fa3575SJulian Wiedmann 	qeth_l2_drain_rx_mode_cache(card);
230958fa3575SJulian Wiedmann 
231058fa3575SJulian Wiedmann 	if (card->state == CARD_STATE_SOFTSETUP)
231158fa3575SJulian Wiedmann 		card->state = CARD_STATE_DOWN;
231258fa3575SJulian Wiedmann 
231358fa3575SJulian Wiedmann 	qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
231458fa3575SJulian Wiedmann 	if (priv->brport_features & BR_LEARNING_SYNC) {
231558fa3575SJulian Wiedmann 		rtnl_lock();
231658fa3575SJulian Wiedmann 		qeth_l2_dev2br_fdb_flush(card);
231758fa3575SJulian Wiedmann 		rtnl_unlock();
231858fa3575SJulian Wiedmann 	}
231958fa3575SJulian Wiedmann }
232058fa3575SJulian Wiedmann 
232158fa3575SJulian Wiedmann /* Returns zero if the command is successfully "consumed" */
232258fa3575SJulian Wiedmann static int qeth_l2_control_event(struct qeth_card *card,
232358fa3575SJulian Wiedmann 				 struct qeth_ipa_cmd *cmd)
232458fa3575SJulian Wiedmann {
232558fa3575SJulian Wiedmann 	switch (cmd->hdr.command) {
232658fa3575SJulian Wiedmann 	case IPA_CMD_SETBRIDGEPORT_OSA:
232758fa3575SJulian Wiedmann 	case IPA_CMD_SETBRIDGEPORT_IQD:
232858fa3575SJulian Wiedmann 		if (cmd->data.sbp.hdr.command_code ==
232958fa3575SJulian Wiedmann 		    IPA_SBP_BRIDGE_PORT_STATE_CHANGE) {
233058fa3575SJulian Wiedmann 			qeth_bridge_state_change(card, cmd);
233158fa3575SJulian Wiedmann 			return 0;
233258fa3575SJulian Wiedmann 		}
233358fa3575SJulian Wiedmann 
233458fa3575SJulian Wiedmann 		return 1;
233558fa3575SJulian Wiedmann 	case IPA_CMD_ADDRESS_CHANGE_NOTIF:
233658fa3575SJulian Wiedmann 		qeth_addr_change_event(card, cmd);
233758fa3575SJulian Wiedmann 		return 0;
233858fa3575SJulian Wiedmann 	default:
233958fa3575SJulian Wiedmann 		return 1;
234058fa3575SJulian Wiedmann 	}
234158fa3575SJulian Wiedmann }
234258fa3575SJulian Wiedmann 
234350144f67SJulian Wiedmann const struct qeth_discipline qeth_l2_discipline = {
234458fa3575SJulian Wiedmann 	.devtype = &qeth_l2_devtype,
234558fa3575SJulian Wiedmann 	.setup = qeth_l2_probe_device,
234658fa3575SJulian Wiedmann 	.remove = qeth_l2_remove_device,
234758fa3575SJulian Wiedmann 	.set_online = qeth_l2_set_online,
234858fa3575SJulian Wiedmann 	.set_offline = qeth_l2_set_offline,
234958fa3575SJulian Wiedmann 	.do_ioctl = NULL,
235058fa3575SJulian Wiedmann 	.control_event_handler = qeth_l2_control_event,
235158fa3575SJulian Wiedmann };
235258fa3575SJulian Wiedmann EXPORT_SYMBOL_GPL(qeth_l2_discipline);
235358fa3575SJulian Wiedmann 
235458fa3575SJulian Wiedmann static int __init qeth_l2_init(void)
235558fa3575SJulian Wiedmann {
235658fa3575SJulian Wiedmann 	pr_info("register layer 2 discipline\n");
235758fa3575SJulian Wiedmann 	return 0;
235858fa3575SJulian Wiedmann }
235958fa3575SJulian Wiedmann 
236058fa3575SJulian Wiedmann static void __exit qeth_l2_exit(void)
236158fa3575SJulian Wiedmann {
236258fa3575SJulian Wiedmann 	pr_info("unregister layer 2 discipline\n");
236358fa3575SJulian Wiedmann }
236458fa3575SJulian Wiedmann 
23654a71df50SFrank Blaschka module_init(qeth_l2_init);
23664a71df50SFrank Blaschka module_exit(qeth_l2_exit);
23674a71df50SFrank Blaschka MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>");
23684a71df50SFrank Blaschka MODULE_DESCRIPTION("qeth layer 2 discipline");
23694a71df50SFrank Blaschka MODULE_LICENSE("GPL");
2370