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 74978bb0aeSJakub Kicinski static int qeth_l2_send_setdelmac(struct qeth_card *card, const __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 91978bb0aeSJakub Kicinski static int qeth_l2_send_setmac(struct qeth_card *card, const __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) 1240969becbSJulian Wiedmann QETH_DBF_MESSAGE(2, "MAC address %012llx is already registered on device %x\n", 1250969becbSJulian Wiedmann ether_addr_to_u64(mac), CARD_DEVID(card)); 126efbbc1d5SEugene Crosser else if (rc) 1270969becbSJulian Wiedmann QETH_DBF_MESSAGE(2, "Failed to register MAC address %012llx on device %x: %d\n", 1280969becbSJulian Wiedmann ether_addr_to_u64(mac), 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) 1410969becbSJulian Wiedmann QETH_DBF_MESSAGE(2, "Failed to delete MAC address %012llx on device %x: %d\n", 1420969becbSJulian Wiedmann ether_addr_to_u64(mac), 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, 16017f3a8b5SJulian Wiedmann __be16 proto, 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) 17217f3a8b5SJulian Wiedmann qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], proto); 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 */ 186378ac80dSJulian Wiedmann if (veth->h_vlan_proto == 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 { 282c35b57ceSVladimir Oltean 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 3124a71df50SFrank Blaschka rc = qeth_setadpparms_change_macaddr(card); 3134b7ae122SJulian Wiedmann if (!rc) 31421b1702aSJulian Wiedmann goto out; 315e19e5be8SJulian Wiedmann QETH_DBF_MESSAGE(2, "READ_MAC Assist failed on device %x: %#x\n", 316e19e5be8SJulian Wiedmann CARD_DEVID(card), rc); 31757a688aaSJulian Wiedmann QETH_CARD_TEXT_(card, 2, "1err%04x", rc); 31821b1702aSJulian Wiedmann 319a8c7629cSJulian Wiedmann /* Fall back once more, but some devices don't support a custom MAC 320a8c7629cSJulian Wiedmann * address: 321a8c7629cSJulian Wiedmann */ 322379ac99eSJulian Wiedmann if (IS_OSM(card) || IS_OSX(card)) 32321b1702aSJulian Wiedmann return (rc) ? rc : -EADDRNOTAVAIL; 32421b1702aSJulian Wiedmann eth_hw_addr_random(card->dev); 32521b1702aSJulian Wiedmann 326ec61bd2fSJulian Wiedmann out: 32757a688aaSJulian Wiedmann QETH_CARD_HEX(card, 2, card->dev->dev_addr, card->dev->addr_len); 3284a71df50SFrank Blaschka return 0; 3294a71df50SFrank Blaschka } 3304a71df50SFrank Blaschka 331654e3d48SJulian Wiedmann static void qeth_l2_register_dev_addr(struct qeth_card *card) 332654e3d48SJulian Wiedmann { 333654e3d48SJulian Wiedmann if (!is_valid_ether_addr(card->dev->dev_addr)) 334654e3d48SJulian Wiedmann qeth_l2_request_initial_mac(card); 335654e3d48SJulian Wiedmann 336a8c7629cSJulian Wiedmann if (!qeth_l2_send_setmac(card, card->dev->dev_addr)) 3379de15117SJulian Wiedmann card->info.dev_addr_is_registered = 1; 3389de15117SJulian Wiedmann else 3399de15117SJulian Wiedmann card->info.dev_addr_is_registered = 0; 340654e3d48SJulian Wiedmann } 341654e3d48SJulian Wiedmann 342e22355eaSJulian Wiedmann static int qeth_l2_validate_addr(struct net_device *dev) 343e22355eaSJulian Wiedmann { 344e22355eaSJulian Wiedmann struct qeth_card *card = dev->ml_priv; 345e22355eaSJulian Wiedmann 3469de15117SJulian Wiedmann if (card->info.dev_addr_is_registered) 347e22355eaSJulian Wiedmann return eth_validate_addr(dev); 348e22355eaSJulian Wiedmann 349e22355eaSJulian Wiedmann QETH_CARD_TEXT(card, 4, "nomacadr"); 350e22355eaSJulian Wiedmann return -EPERM; 351e22355eaSJulian Wiedmann } 352e22355eaSJulian Wiedmann 3534a71df50SFrank Blaschka static int qeth_l2_set_mac_address(struct net_device *dev, void *p) 3544a71df50SFrank Blaschka { 3554a71df50SFrank Blaschka struct sockaddr *addr = p; 356509e2562SHeiko Carstens struct qeth_card *card = dev->ml_priv; 357bcacfcbcSJulian Wiedmann u8 old_addr[ETH_ALEN]; 3584a71df50SFrank Blaschka int rc = 0; 3594a71df50SFrank Blaschka 360847a50fdSCarsten Otte QETH_CARD_TEXT(card, 3, "setmac"); 3614a71df50SFrank Blaschka 3628024cc9eSJulian Wiedmann if (IS_OSM(card) || IS_OSX(card)) { 363847a50fdSCarsten Otte QETH_CARD_TEXT(card, 3, "setmcTYP"); 3644a71df50SFrank Blaschka return -EOPNOTSUPP; 3654a71df50SFrank Blaschka } 36699f0b85dSJulian Wiedmann QETH_CARD_HEX(card, 3, addr->sa_data, ETH_ALEN); 367bcacfcbcSJulian Wiedmann if (!is_valid_ether_addr(addr->sa_data)) 368bcacfcbcSJulian Wiedmann return -EADDRNOTAVAIL; 369bcacfcbcSJulian Wiedmann 370bcacfcbcSJulian Wiedmann /* don't register the same address twice */ 371bcacfcbcSJulian Wiedmann if (ether_addr_equal_64bits(dev->dev_addr, addr->sa_data) && 3729de15117SJulian Wiedmann card->info.dev_addr_is_registered) 373e6e771b3SJulian Wiedmann return 0; 374bcacfcbcSJulian Wiedmann 375bcacfcbcSJulian Wiedmann /* add the new address, switch over, drop the old */ 3764a71df50SFrank Blaschka rc = qeth_l2_send_setmac(card, addr->sa_data); 377bcacfcbcSJulian Wiedmann if (rc) 378e6e771b3SJulian Wiedmann return rc; 379bcacfcbcSJulian Wiedmann ether_addr_copy(old_addr, dev->dev_addr); 380978bb0aeSJakub Kicinski eth_hw_addr_set(dev, addr->sa_data); 381bcacfcbcSJulian Wiedmann 3829de15117SJulian Wiedmann if (card->info.dev_addr_is_registered) 383bcacfcbcSJulian Wiedmann qeth_l2_remove_mac(card, old_addr); 3849de15117SJulian Wiedmann card->info.dev_addr_is_registered = 1; 385e6e771b3SJulian Wiedmann return 0; 3864a71df50SFrank Blaschka } 3874a71df50SFrank Blaschka 38859b757a9SJulian Wiedmann static void qeth_l2_promisc_to_bridge(struct qeth_card *card, bool enable) 3890db587b0SEugene Crosser { 3900db587b0SEugene Crosser int role; 3910db587b0SEugene Crosser int rc; 3920db587b0SEugene Crosser 3930db587b0SEugene Crosser QETH_CARD_TEXT(card, 3, "pmisc2br"); 3940db587b0SEugene Crosser 39559b757a9SJulian Wiedmann if (enable) { 3960db587b0SEugene Crosser if (card->options.sbp.reflect_promisc_primary) 3970db587b0SEugene Crosser role = QETH_SBP_ROLE_PRIMARY; 3980db587b0SEugene Crosser else 3990db587b0SEugene Crosser role = QETH_SBP_ROLE_SECONDARY; 4000db587b0SEugene Crosser } else 4010db587b0SEugene Crosser role = QETH_SBP_ROLE_NONE; 4020db587b0SEugene Crosser 4030db587b0SEugene Crosser rc = qeth_bridgeport_setrole(card, role); 40459b757a9SJulian Wiedmann QETH_CARD_TEXT_(card, 2, "bpm%c%04x", enable ? '+' : '-', rc); 4050db587b0SEugene Crosser if (!rc) { 4060db587b0SEugene Crosser card->options.sbp.role = role; 40759b757a9SJulian Wiedmann card->info.promisc_mode = enable; 40859b757a9SJulian Wiedmann } 4090db587b0SEugene Crosser } 410fe5c8028SLakhvich Dmitriy 41159b757a9SJulian Wiedmann static void qeth_l2_set_promisc_mode(struct qeth_card *card) 41259b757a9SJulian Wiedmann { 41359b757a9SJulian Wiedmann bool enable = card->dev->flags & IFF_PROMISC; 41459b757a9SJulian Wiedmann 41559b757a9SJulian Wiedmann if (card->info.promisc_mode == enable) 41659b757a9SJulian Wiedmann return; 41759b757a9SJulian Wiedmann 418c8183f54SJulian Wiedmann if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) { 41959b757a9SJulian Wiedmann qeth_setadp_promisc_mode(card, enable); 420c8183f54SJulian Wiedmann } else { 421c8183f54SJulian Wiedmann mutex_lock(&card->sbp_lock); 422c8183f54SJulian Wiedmann if (card->options.sbp.reflect_promisc) 42359b757a9SJulian Wiedmann qeth_l2_promisc_to_bridge(card, enable); 424c8183f54SJulian Wiedmann mutex_unlock(&card->sbp_lock); 425c8183f54SJulian Wiedmann } 426fe5c8028SLakhvich Dmitriy } 42759b757a9SJulian Wiedmann 428fe5c8028SLakhvich Dmitriy /* New MAC address is added to the hash table and marked to be written on card 429fe5c8028SLakhvich Dmitriy * only if there is not in the hash table storage already 430fe5c8028SLakhvich Dmitriy * 431fe5c8028SLakhvich Dmitriy */ 4324641b027SJulian Wiedmann static void qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha) 433fe5c8028SLakhvich Dmitriy { 434cef6ff22SJulian Wiedmann u32 mac_hash = get_unaligned((u32 *)(&ha->addr[2])); 435fe5c8028SLakhvich Dmitriy struct qeth_mac *mac; 436fe5c8028SLakhvich Dmitriy 4370973292fSJulian Wiedmann hash_for_each_possible(card->rx_mode_addrs, mac, hnode, mac_hash) { 43899f0b85dSJulian Wiedmann if (ether_addr_equal_64bits(ha->addr, mac->mac_addr)) { 4395f78e29cSLakhvich Dmitriy mac->disp_flag = QETH_DISP_ADDR_DO_NOTHING; 440fe5c8028SLakhvich Dmitriy return; 441fe5c8028SLakhvich Dmitriy } 4420db587b0SEugene Crosser } 4430db587b0SEugene Crosser 444fe5c8028SLakhvich Dmitriy mac = kzalloc(sizeof(struct qeth_mac), GFP_ATOMIC); 445fe5c8028SLakhvich Dmitriy if (!mac) 446fe5c8028SLakhvich Dmitriy return; 447fe5c8028SLakhvich Dmitriy 44899f0b85dSJulian Wiedmann ether_addr_copy(mac->mac_addr, ha->addr); 4495f78e29cSLakhvich Dmitriy mac->disp_flag = QETH_DISP_ADDR_ADD; 450fe5c8028SLakhvich Dmitriy 4510973292fSJulian Wiedmann hash_add(card->rx_mode_addrs, &mac->hnode, mac_hash); 452fe5c8028SLakhvich Dmitriy } 453fe5c8028SLakhvich Dmitriy 454d0c74825SJulian Wiedmann static void qeth_l2_rx_mode_work(struct work_struct *work) 4554a71df50SFrank Blaschka { 456d0c74825SJulian Wiedmann struct qeth_card *card = container_of(work, struct qeth_card, 457d0c74825SJulian Wiedmann rx_mode_work); 458d0c74825SJulian Wiedmann struct net_device *dev = card->dev; 459ccffad25SJiri Pirko struct netdev_hw_addr *ha; 460fe5c8028SLakhvich Dmitriy struct qeth_mac *mac; 461fe5c8028SLakhvich Dmitriy struct hlist_node *tmp; 462fe5c8028SLakhvich Dmitriy int i; 463fe5c8028SLakhvich Dmitriy int rc; 4644a71df50SFrank Blaschka 465847a50fdSCarsten Otte QETH_CARD_TEXT(card, 3, "setmulti"); 466fe5c8028SLakhvich Dmitriy 467d0c74825SJulian Wiedmann netif_addr_lock_bh(dev); 46822bedad3SJiri Pirko netdev_for_each_mc_addr(ha, dev) 4694641b027SJulian Wiedmann qeth_l2_add_mac(card, ha); 47032e7bfc4SJiri Pirko netdev_for_each_uc_addr(ha, dev) 4714641b027SJulian Wiedmann qeth_l2_add_mac(card, ha); 472d0c74825SJulian Wiedmann netif_addr_unlock_bh(dev); 473fe5c8028SLakhvich Dmitriy 4740973292fSJulian Wiedmann hash_for_each_safe(card->rx_mode_addrs, i, tmp, mac, hnode) { 47500c163f1SJulian Wiedmann switch (mac->disp_flag) { 47600c163f1SJulian Wiedmann case QETH_DISP_ADDR_DELETE: 4778174aa8aSJulian Wiedmann qeth_l2_remove_mac(card, mac->mac_addr); 478fe5c8028SLakhvich Dmitriy hash_del(&mac->hnode); 479fe5c8028SLakhvich Dmitriy kfree(mac); 48000c163f1SJulian Wiedmann break; 48100c163f1SJulian Wiedmann case QETH_DISP_ADDR_ADD: 4828174aa8aSJulian Wiedmann rc = qeth_l2_write_mac(card, mac->mac_addr); 483fe5c8028SLakhvich Dmitriy if (rc) { 484fe5c8028SLakhvich Dmitriy hash_del(&mac->hnode); 485fe5c8028SLakhvich Dmitriy kfree(mac); 48600c163f1SJulian Wiedmann break; 48700c163f1SJulian Wiedmann } 488df561f66SGustavo A. R. Silva fallthrough; 48900c163f1SJulian Wiedmann default: 49000c163f1SJulian Wiedmann /* for next call to set_rx_mode(): */ 4915f78e29cSLakhvich Dmitriy mac->disp_flag = QETH_DISP_ADDR_DELETE; 49200c163f1SJulian Wiedmann } 493fe5c8028SLakhvich Dmitriy } 4947db2266aSFrank Blaschka 49559b757a9SJulian Wiedmann qeth_l2_set_promisc_mode(card); 4964a71df50SFrank Blaschka } 4974a71df50SFrank Blaschka 498e38db6beSJulian Wiedmann static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, 499e38db6beSJulian Wiedmann struct net_device *dev) 5004a71df50SFrank Blaschka { 501509e2562SHeiko Carstens struct qeth_card *card = dev->ml_priv; 5023a18d754SJulian Wiedmann u16 txq = skb_get_queue_mapping(skb); 503290b8348SStefan Raspl struct qeth_qdio_out_q *queue; 5047286384bSJulian Wiedmann int rc; 5054a71df50SFrank Blaschka 506eeac0e20SJulian Wiedmann if (!skb_is_gso(skb)) 507eeac0e20SJulian Wiedmann qdisc_skb_cb(skb)->pkt_len = skb->len; 5083a18d754SJulian Wiedmann if (IS_IQD(card)) 50954a50941SJulian Wiedmann txq = qeth_iqd_translate_txq(dev, txq); 51073dc2dafSJulian Wiedmann queue = card->qdio.out_qs[txq]; 511b0abc4f5SJulian Wiedmann 51217f3a8b5SJulian Wiedmann rc = qeth_xmit(card, skb, queue, vlan_get_protocol(skb), 51358aa2491SJulian Wiedmann qeth_l2_fill_header); 514eeac0e20SJulian Wiedmann if (!rc) 5157286384bSJulian Wiedmann return NETDEV_TX_OK; 5164a71df50SFrank Blaschka 517b0abc4f5SJulian Wiedmann QETH_TXQ_STAT_INC(queue, tx_dropped); 518104b4859SJulian Wiedmann kfree_skb(skb); 5194a71df50SFrank Blaschka return NETDEV_TX_OK; 5204a71df50SFrank Blaschka } 5214a71df50SFrank Blaschka 522*1b9e410fSJulian Wiedmann static u16 qeth_l2_iqd_select_queue(struct net_device *dev, struct sk_buff *skb, 5233a18d754SJulian Wiedmann struct net_device *sb_dev) 5243a18d754SJulian Wiedmann { 525*1b9e410fSJulian Wiedmann return qeth_iqd_select_queue(dev, skb, qeth_get_ether_cast_type(skb), 5263a18d754SJulian Wiedmann sb_dev); 5273a18d754SJulian Wiedmann } 5283a18d754SJulian Wiedmann 529d0c74825SJulian Wiedmann static void qeth_l2_set_rx_mode(struct net_device *dev) 530d0c74825SJulian Wiedmann { 531d0c74825SJulian Wiedmann struct qeth_card *card = dev->ml_priv; 532d0c74825SJulian Wiedmann 533d0c74825SJulian Wiedmann schedule_work(&card->rx_mode_work); 534d0c74825SJulian Wiedmann } 535d0c74825SJulian Wiedmann 536a0138f59SAlexandra Winter /** 537a0138f59SAlexandra Winter * qeth_l2_pnso() - perform network subchannel operation 538a0138f59SAlexandra Winter * @card: qeth_card structure pointer 5394fea49a7SAlexandra Winter * @oc: Operation Code 540a0138f59SAlexandra Winter * @cnc: Boolean Change-Notification Control 541a0138f59SAlexandra Winter * @cb: Callback function will be executed for each element 542a0138f59SAlexandra Winter * of the address list 543a0138f59SAlexandra Winter * @priv: Pointer to pass to the callback function. 544a0138f59SAlexandra Winter * 545a0138f59SAlexandra Winter * Collects network information in a network address list and calls the 546a0138f59SAlexandra Winter * callback function for every entry in the list. If "change-notification- 547a0138f59SAlexandra Winter * control" is set, further changes in the address list will be reported 548a0138f59SAlexandra Winter * via the IPA command. 549a0138f59SAlexandra Winter */ 5504fea49a7SAlexandra Winter static int qeth_l2_pnso(struct qeth_card *card, u8 oc, int cnc, 551a0138f59SAlexandra Winter void (*cb)(void *priv, struct chsc_pnso_naid_l2 *entry), 552a0138f59SAlexandra Winter void *priv) 553a0138f59SAlexandra Winter { 554a0138f59SAlexandra Winter struct ccw_device *ddev = CARD_DDEV(card); 555a0138f59SAlexandra Winter struct chsc_pnso_area *rr; 556a0138f59SAlexandra Winter u32 prev_instance = 0; 557a0138f59SAlexandra Winter int isfirstblock = 1; 558a0138f59SAlexandra Winter int i, size, elems; 559a0138f59SAlexandra Winter int rc; 560a0138f59SAlexandra Winter 561a0138f59SAlexandra Winter rr = (struct chsc_pnso_area *)get_zeroed_page(GFP_KERNEL); 562a0138f59SAlexandra Winter if (rr == NULL) 563a0138f59SAlexandra Winter return -ENOMEM; 564a0138f59SAlexandra Winter do { 5654fea49a7SAlexandra Winter QETH_CARD_TEXT(card, 2, "PNSO"); 566a0138f59SAlexandra Winter /* on the first iteration, naihdr.resume_token will be zero */ 5674fea49a7SAlexandra Winter rc = ccw_device_pnso(ddev, rr, oc, rr->naihdr.resume_token, 5684fea49a7SAlexandra Winter cnc); 569a0138f59SAlexandra Winter if (rc) 570a0138f59SAlexandra Winter continue; 571a0138f59SAlexandra Winter if (cb == NULL) 572a0138f59SAlexandra Winter continue; 573a0138f59SAlexandra Winter 574a0138f59SAlexandra Winter size = rr->naihdr.naids; 575a0138f59SAlexandra Winter if (size != sizeof(struct chsc_pnso_naid_l2)) { 576a0138f59SAlexandra Winter WARN_ON_ONCE(1); 577a0138f59SAlexandra Winter continue; 578a0138f59SAlexandra Winter } 579a0138f59SAlexandra Winter 580a0138f59SAlexandra Winter elems = (rr->response.length - sizeof(struct chsc_header) - 581a0138f59SAlexandra Winter sizeof(struct chsc_pnso_naihdr)) / size; 582a0138f59SAlexandra Winter 583a0138f59SAlexandra Winter if (!isfirstblock && (rr->naihdr.instance != prev_instance)) { 584a0138f59SAlexandra Winter /* Inform the caller that they need to scrap */ 585a0138f59SAlexandra Winter /* the data that was already reported via cb */ 586a0138f59SAlexandra Winter rc = -EAGAIN; 587a0138f59SAlexandra Winter break; 588a0138f59SAlexandra Winter } 589a0138f59SAlexandra Winter isfirstblock = 0; 590a0138f59SAlexandra Winter prev_instance = rr->naihdr.instance; 591a0138f59SAlexandra Winter for (i = 0; i < elems; i++) 592a0138f59SAlexandra Winter (*cb)(priv, &rr->entries[i]); 593a0138f59SAlexandra Winter } while ((rc == -EBUSY) || (!rc && /* list stored */ 594a0138f59SAlexandra Winter /* resume token is non-zero => list incomplete */ 595a0138f59SAlexandra Winter (rr->naihdr.resume_token.t1 || rr->naihdr.resume_token.t2))); 596a0138f59SAlexandra Winter 597a0138f59SAlexandra Winter if (rc) 598a0138f59SAlexandra Winter QETH_CARD_TEXT_(card, 2, "PNrp%04x", rr->response.code); 599a0138f59SAlexandra Winter 600a0138f59SAlexandra Winter free_page((unsigned long)rr); 601a0138f59SAlexandra Winter return rc; 602a0138f59SAlexandra Winter } 603a0138f59SAlexandra Winter 60410a6cfc0SAlexandra Winter static bool qeth_is_my_net_if_token(struct qeth_card *card, 60510a6cfc0SAlexandra Winter struct net_if_token *token) 60610a6cfc0SAlexandra Winter { 60710a6cfc0SAlexandra Winter return ((card->info.ddev_devno == token->devnum) && 60810a6cfc0SAlexandra Winter (card->info.cssid == token->cssid) && 60910a6cfc0SAlexandra Winter (card->info.iid == token->iid) && 61010a6cfc0SAlexandra Winter (card->info.ssid == token->ssid) && 61110a6cfc0SAlexandra Winter (card->info.chpid == token->chpid) && 61210a6cfc0SAlexandra Winter (card->info.chid == token->chid)); 61310a6cfc0SAlexandra Winter } 61410a6cfc0SAlexandra Winter 61510a6cfc0SAlexandra Winter /** 61610a6cfc0SAlexandra Winter * qeth_l2_dev2br_fdb_notify() - update fdb of master bridge 61710a6cfc0SAlexandra Winter * @card: qeth_card structure pointer 61810a6cfc0SAlexandra Winter * @code: event bitmask: high order bit 0x80 set to 61910a6cfc0SAlexandra Winter * 1 - removal of an object 62010a6cfc0SAlexandra Winter * 0 - addition of an object 62110a6cfc0SAlexandra Winter * Object type(s): 62210a6cfc0SAlexandra Winter * 0x01 - VLAN, 0x02 - MAC, 0x03 - VLAN and MAC 62310a6cfc0SAlexandra Winter * @token: "network token" structure identifying 'physical' location 62410a6cfc0SAlexandra Winter * of the target 62510a6cfc0SAlexandra Winter * @addr_lnid: structure with MAC address and VLAN ID of the target 62610a6cfc0SAlexandra Winter */ 62710a6cfc0SAlexandra Winter static void qeth_l2_dev2br_fdb_notify(struct qeth_card *card, u8 code, 62810a6cfc0SAlexandra Winter struct net_if_token *token, 62910a6cfc0SAlexandra Winter struct mac_addr_lnid *addr_lnid) 63010a6cfc0SAlexandra Winter { 631c35b57ceSVladimir Oltean struct switchdev_notifier_fdb_info info = {}; 63210a6cfc0SAlexandra Winter u8 ntfy_mac[ETH_ALEN]; 63310a6cfc0SAlexandra Winter 63410a6cfc0SAlexandra Winter ether_addr_copy(ntfy_mac, addr_lnid->mac); 63510a6cfc0SAlexandra Winter /* Ignore VLAN only changes */ 63610a6cfc0SAlexandra Winter if (!(code & IPA_ADDR_CHANGE_CODE_MACADDR)) 63710a6cfc0SAlexandra Winter return; 63810a6cfc0SAlexandra Winter /* Ignore mcast entries */ 63910a6cfc0SAlexandra Winter if (is_multicast_ether_addr(ntfy_mac)) 64010a6cfc0SAlexandra Winter return; 64110a6cfc0SAlexandra Winter /* Ignore my own addresses */ 64210a6cfc0SAlexandra Winter if (qeth_is_my_net_if_token(card, token)) 64310a6cfc0SAlexandra Winter return; 64410a6cfc0SAlexandra Winter 64510a6cfc0SAlexandra Winter info.addr = ntfy_mac; 64610a6cfc0SAlexandra Winter /* don't report VLAN IDs */ 64710a6cfc0SAlexandra Winter info.vid = 0; 64810a6cfc0SAlexandra Winter info.added_by_user = false; 64910a6cfc0SAlexandra Winter info.offloaded = true; 65010a6cfc0SAlexandra Winter 65110a6cfc0SAlexandra Winter if (code & IPA_ADDR_CHANGE_CODE_REMOVAL) { 65210a6cfc0SAlexandra Winter call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, 65310a6cfc0SAlexandra Winter card->dev, &info.info, NULL); 65410a6cfc0SAlexandra Winter QETH_CARD_TEXT(card, 4, "andelmac"); 65510a6cfc0SAlexandra Winter QETH_CARD_TEXT_(card, 4, 65622e2b5cdSHeiko Carstens "mc%012llx", ether_addr_to_u64(ntfy_mac)); 65710a6cfc0SAlexandra Winter } else { 65810a6cfc0SAlexandra Winter call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, 65910a6cfc0SAlexandra Winter card->dev, &info.info, NULL); 66010a6cfc0SAlexandra Winter QETH_CARD_TEXT(card, 4, "anaddmac"); 66110a6cfc0SAlexandra Winter QETH_CARD_TEXT_(card, 4, 66222e2b5cdSHeiko Carstens "mc%012llx", ether_addr_to_u64(ntfy_mac)); 66310a6cfc0SAlexandra Winter } 66410a6cfc0SAlexandra Winter } 66510a6cfc0SAlexandra Winter 666817741a8SAlexandra Winter static void qeth_l2_dev2br_an_set_cb(void *priv, 667817741a8SAlexandra Winter struct chsc_pnso_naid_l2 *entry) 668817741a8SAlexandra Winter { 669817741a8SAlexandra Winter u8 code = IPA_ADDR_CHANGE_CODE_MACADDR; 670817741a8SAlexandra Winter struct qeth_card *card = priv; 671817741a8SAlexandra Winter 672817741a8SAlexandra Winter if (entry->addr_lnid.lnid < VLAN_N_VID) 673817741a8SAlexandra Winter code |= IPA_ADDR_CHANGE_CODE_VLANID; 674817741a8SAlexandra Winter qeth_l2_dev2br_fdb_notify(card, code, 675817741a8SAlexandra Winter (struct net_if_token *)&entry->nit, 676817741a8SAlexandra Winter (struct mac_addr_lnid *)&entry->addr_lnid); 677817741a8SAlexandra Winter } 678817741a8SAlexandra Winter 679817741a8SAlexandra Winter /** 680817741a8SAlexandra Winter * qeth_l2_dev2br_an_set() - 681817741a8SAlexandra Winter * Enable or disable 'dev to bridge network address notification' 682817741a8SAlexandra Winter * @card: qeth_card structure pointer 683817741a8SAlexandra Winter * @enable: Enable or disable 'dev to bridge network address notification' 684817741a8SAlexandra Winter * 685817741a8SAlexandra Winter * Returns negative errno-compatible error indication or 0 on success. 686817741a8SAlexandra Winter * 687817741a8SAlexandra Winter * On enable, emits a series of address notifications for all 688817741a8SAlexandra Winter * currently registered hosts. 689817741a8SAlexandra Winter */ 690817741a8SAlexandra Winter static int qeth_l2_dev2br_an_set(struct qeth_card *card, bool enable) 691817741a8SAlexandra Winter { 692817741a8SAlexandra Winter int rc; 693817741a8SAlexandra Winter 694817741a8SAlexandra Winter if (enable) { 695817741a8SAlexandra Winter QETH_CARD_TEXT(card, 2, "anseton"); 696817741a8SAlexandra Winter rc = qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 1, 697817741a8SAlexandra Winter qeth_l2_dev2br_an_set_cb, card); 698817741a8SAlexandra Winter if (rc == -EAGAIN) 699817741a8SAlexandra Winter /* address notification enabled, but inconsistent 700817741a8SAlexandra Winter * addresses reported -> disable address notification 701817741a8SAlexandra Winter */ 702817741a8SAlexandra Winter qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 0, 703817741a8SAlexandra Winter NULL, NULL); 704817741a8SAlexandra Winter } else { 705817741a8SAlexandra Winter QETH_CARD_TEXT(card, 2, "ansetoff"); 706817741a8SAlexandra Winter rc = qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 0, NULL, NULL); 707817741a8SAlexandra Winter } 708817741a8SAlexandra Winter 709817741a8SAlexandra Winter return rc; 710817741a8SAlexandra Winter } 711817741a8SAlexandra Winter 712f7936b7bSAlexandra Winter struct qeth_l2_br2dev_event_work { 713f7936b7bSAlexandra Winter struct work_struct work; 714f7936b7bSAlexandra Winter struct net_device *br_dev; 715f7936b7bSAlexandra Winter struct net_device *lsync_dev; 716f7936b7bSAlexandra Winter struct net_device *dst_dev; 717f7936b7bSAlexandra Winter unsigned long event; 718f7936b7bSAlexandra Winter unsigned char addr[ETH_ALEN]; 719f7936b7bSAlexandra Winter }; 720f7936b7bSAlexandra Winter 7212dbc7a1dSJulian Wiedmann static const struct net_device_ops qeth_l2_iqd_netdev_ops; 7222dbc7a1dSJulian Wiedmann static const struct net_device_ops qeth_l2_osa_netdev_ops; 7234e20e73eSAlexandra Winter 7244e20e73eSAlexandra Winter static bool qeth_l2_must_learn(struct net_device *netdev, 7254e20e73eSAlexandra Winter struct net_device *dstdev) 7264e20e73eSAlexandra Winter { 7274e20e73eSAlexandra Winter struct qeth_priv *priv; 7284e20e73eSAlexandra Winter 7294e20e73eSAlexandra Winter priv = netdev_priv(netdev); 7304e20e73eSAlexandra Winter return (netdev != dstdev && 7314e20e73eSAlexandra Winter (priv->brport_features & BR_LEARNING_SYNC) && 7324e20e73eSAlexandra Winter !(br_port_flag_is_set(netdev, BR_ISOLATED) && 7334e20e73eSAlexandra Winter br_port_flag_is_set(dstdev, BR_ISOLATED)) && 7342dbc7a1dSJulian Wiedmann (netdev->netdev_ops == &qeth_l2_iqd_netdev_ops || 7352dbc7a1dSJulian Wiedmann netdev->netdev_ops == &qeth_l2_osa_netdev_ops)); 7364e20e73eSAlexandra Winter } 7374e20e73eSAlexandra Winter 738f7936b7bSAlexandra Winter /** 739f7936b7bSAlexandra Winter * qeth_l2_br2dev_worker() - update local MACs 740f7936b7bSAlexandra Winter * @work: bridge to device FDB update 741f7936b7bSAlexandra Winter * 742f7936b7bSAlexandra Winter * Update local MACs of a learning_sync bridgeport so it can receive 743f7936b7bSAlexandra Winter * messages for a destination port. 744f7936b7bSAlexandra Winter * In case of an isolated learning_sync port, also update its isolated 745f7936b7bSAlexandra Winter * siblings. 746f7936b7bSAlexandra Winter */ 747f7936b7bSAlexandra Winter static void qeth_l2_br2dev_worker(struct work_struct *work) 748f7936b7bSAlexandra Winter { 749f7936b7bSAlexandra Winter struct qeth_l2_br2dev_event_work *br2dev_event_work = 750f7936b7bSAlexandra Winter container_of(work, struct qeth_l2_br2dev_event_work, work); 751f7936b7bSAlexandra Winter struct net_device *lsyncdev = br2dev_event_work->lsync_dev; 752f7936b7bSAlexandra Winter struct net_device *dstdev = br2dev_event_work->dst_dev; 753f7936b7bSAlexandra Winter struct net_device *brdev = br2dev_event_work->br_dev; 754f7936b7bSAlexandra Winter unsigned long event = br2dev_event_work->event; 755f7936b7bSAlexandra Winter unsigned char *addr = br2dev_event_work->addr; 756f7936b7bSAlexandra Winter struct qeth_card *card = lsyncdev->ml_priv; 757f7936b7bSAlexandra Winter struct net_device *lowerdev; 758f7936b7bSAlexandra Winter struct list_head *iter; 759f7936b7bSAlexandra Winter int err = 0; 760f7936b7bSAlexandra Winter 761f7936b7bSAlexandra Winter kfree(br2dev_event_work); 76222e2b5cdSHeiko Carstens QETH_CARD_TEXT_(card, 4, "b2dw%04lx", event); 76322e2b5cdSHeiko Carstens QETH_CARD_TEXT_(card, 4, "ma%012llx", ether_addr_to_u64(addr)); 764f7936b7bSAlexandra Winter 765f7936b7bSAlexandra Winter rcu_read_lock(); 766f7936b7bSAlexandra Winter /* Verify preconditions are still valid: */ 767f7936b7bSAlexandra Winter if (!netif_is_bridge_port(lsyncdev) || 768f7936b7bSAlexandra Winter brdev != netdev_master_upper_dev_get_rcu(lsyncdev)) 769f7936b7bSAlexandra Winter goto unlock; 770f7936b7bSAlexandra Winter if (!qeth_l2_must_learn(lsyncdev, dstdev)) 771f7936b7bSAlexandra Winter goto unlock; 772f7936b7bSAlexandra Winter 773f7936b7bSAlexandra Winter if (br_port_flag_is_set(lsyncdev, BR_ISOLATED)) { 774f7936b7bSAlexandra Winter /* Update lsyncdev and its isolated sibling(s): */ 775f7936b7bSAlexandra Winter iter = &brdev->adj_list.lower; 776f7936b7bSAlexandra Winter lowerdev = netdev_next_lower_dev_rcu(brdev, &iter); 777f7936b7bSAlexandra Winter while (lowerdev) { 778f7936b7bSAlexandra Winter if (br_port_flag_is_set(lowerdev, BR_ISOLATED)) { 779f7936b7bSAlexandra Winter switch (event) { 780f7936b7bSAlexandra Winter case SWITCHDEV_FDB_ADD_TO_DEVICE: 781f7936b7bSAlexandra Winter err = dev_uc_add(lowerdev, addr); 782f7936b7bSAlexandra Winter break; 783f7936b7bSAlexandra Winter case SWITCHDEV_FDB_DEL_TO_DEVICE: 784f7936b7bSAlexandra Winter err = dev_uc_del(lowerdev, addr); 785f7936b7bSAlexandra Winter break; 786f7936b7bSAlexandra Winter default: 787f7936b7bSAlexandra Winter break; 788f7936b7bSAlexandra Winter } 789f7936b7bSAlexandra Winter if (err) { 790f7936b7bSAlexandra Winter QETH_CARD_TEXT(card, 2, "b2derris"); 791f7936b7bSAlexandra Winter QETH_CARD_TEXT_(card, 2, 79222e2b5cdSHeiko Carstens "err%02lx%03d", event, 793f7936b7bSAlexandra Winter lowerdev->ifindex); 794f7936b7bSAlexandra Winter } 795f7936b7bSAlexandra Winter } 796f7936b7bSAlexandra Winter lowerdev = netdev_next_lower_dev_rcu(brdev, &iter); 797f7936b7bSAlexandra Winter } 798f7936b7bSAlexandra Winter } else { 799f7936b7bSAlexandra Winter switch (event) { 800f7936b7bSAlexandra Winter case SWITCHDEV_FDB_ADD_TO_DEVICE: 801f7936b7bSAlexandra Winter err = dev_uc_add(lsyncdev, addr); 802f7936b7bSAlexandra Winter break; 803f7936b7bSAlexandra Winter case SWITCHDEV_FDB_DEL_TO_DEVICE: 804f7936b7bSAlexandra Winter err = dev_uc_del(lsyncdev, addr); 805f7936b7bSAlexandra Winter break; 806f7936b7bSAlexandra Winter default: 807f7936b7bSAlexandra Winter break; 808f7936b7bSAlexandra Winter } 809f7936b7bSAlexandra Winter if (err) 81022e2b5cdSHeiko Carstens QETH_CARD_TEXT_(card, 2, "b2derr%02lx", event); 811f7936b7bSAlexandra Winter } 812f7936b7bSAlexandra Winter 813f7936b7bSAlexandra Winter unlock: 814f7936b7bSAlexandra Winter rcu_read_unlock(); 815f7936b7bSAlexandra Winter dev_put(brdev); 816f7936b7bSAlexandra Winter dev_put(lsyncdev); 817f7936b7bSAlexandra Winter dev_put(dstdev); 818f7936b7bSAlexandra Winter } 819f7936b7bSAlexandra Winter 820f7936b7bSAlexandra Winter static int qeth_l2_br2dev_queue_work(struct net_device *brdev, 821f7936b7bSAlexandra Winter struct net_device *lsyncdev, 822f7936b7bSAlexandra Winter struct net_device *dstdev, 823f7936b7bSAlexandra Winter unsigned long event, 824f7936b7bSAlexandra Winter const unsigned char *addr) 825f7936b7bSAlexandra Winter { 826f7936b7bSAlexandra Winter struct qeth_l2_br2dev_event_work *worker_data; 827f7936b7bSAlexandra Winter struct qeth_card *card; 828f7936b7bSAlexandra Winter 829f7936b7bSAlexandra Winter worker_data = kzalloc(sizeof(*worker_data), GFP_ATOMIC); 830f7936b7bSAlexandra Winter if (!worker_data) 831f7936b7bSAlexandra Winter return -ENOMEM; 832f7936b7bSAlexandra Winter INIT_WORK(&worker_data->work, qeth_l2_br2dev_worker); 833f7936b7bSAlexandra Winter worker_data->br_dev = brdev; 834f7936b7bSAlexandra Winter worker_data->lsync_dev = lsyncdev; 835f7936b7bSAlexandra Winter worker_data->dst_dev = dstdev; 836f7936b7bSAlexandra Winter worker_data->event = event; 837f7936b7bSAlexandra Winter ether_addr_copy(worker_data->addr, addr); 838f7936b7bSAlexandra Winter 839f7936b7bSAlexandra Winter card = lsyncdev->ml_priv; 840f7936b7bSAlexandra Winter /* Take a reference on the sw port devices and the bridge */ 841f7936b7bSAlexandra Winter dev_hold(brdev); 842f7936b7bSAlexandra Winter dev_hold(lsyncdev); 843f7936b7bSAlexandra Winter dev_hold(dstdev); 844f7936b7bSAlexandra Winter queue_work(card->event_wq, &worker_data->work); 845f7936b7bSAlexandra Winter return 0; 846f7936b7bSAlexandra Winter } 847f7936b7bSAlexandra Winter 8484e20e73eSAlexandra Winter /* Called under rtnl_lock */ 8494e20e73eSAlexandra Winter static int qeth_l2_switchdev_event(struct notifier_block *unused, 8504e20e73eSAlexandra Winter unsigned long event, void *ptr) 8514e20e73eSAlexandra Winter { 8524e20e73eSAlexandra Winter struct net_device *dstdev, *brdev, *lowerdev; 8534e20e73eSAlexandra Winter struct switchdev_notifier_fdb_info *fdb_info; 8544e20e73eSAlexandra Winter struct switchdev_notifier_info *info = ptr; 8554e20e73eSAlexandra Winter struct list_head *iter; 8564e20e73eSAlexandra Winter struct qeth_card *card; 857f7936b7bSAlexandra Winter int rc; 8584e20e73eSAlexandra Winter 8594e20e73eSAlexandra Winter if (!(event == SWITCHDEV_FDB_ADD_TO_DEVICE || 8604e20e73eSAlexandra Winter event == SWITCHDEV_FDB_DEL_TO_DEVICE)) 8614e20e73eSAlexandra Winter return NOTIFY_DONE; 8624e20e73eSAlexandra Winter 8634e20e73eSAlexandra Winter dstdev = switchdev_notifier_info_to_dev(info); 8644e20e73eSAlexandra Winter brdev = netdev_master_upper_dev_get_rcu(dstdev); 8654e20e73eSAlexandra Winter if (!brdev || !netif_is_bridge_master(brdev)) 8664e20e73eSAlexandra Winter return NOTIFY_DONE; 8674e20e73eSAlexandra Winter fdb_info = container_of(info, 8684e20e73eSAlexandra Winter struct switchdev_notifier_fdb_info, 8694e20e73eSAlexandra Winter info); 8704e20e73eSAlexandra Winter iter = &brdev->adj_list.lower; 8714e20e73eSAlexandra Winter lowerdev = netdev_next_lower_dev_rcu(brdev, &iter); 8724e20e73eSAlexandra Winter while (lowerdev) { 8734e20e73eSAlexandra Winter if (qeth_l2_must_learn(lowerdev, dstdev)) { 8744e20e73eSAlexandra Winter card = lowerdev->ml_priv; 87522e2b5cdSHeiko Carstens QETH_CARD_TEXT_(card, 4, "b2dqw%03lx", event); 876f7936b7bSAlexandra Winter rc = qeth_l2_br2dev_queue_work(brdev, lowerdev, 877f7936b7bSAlexandra Winter dstdev, event, 878f7936b7bSAlexandra Winter fdb_info->addr); 879f7936b7bSAlexandra Winter if (rc) { 880f7936b7bSAlexandra Winter QETH_CARD_TEXT(card, 2, "b2dqwerr"); 881f7936b7bSAlexandra Winter return NOTIFY_BAD; 882f7936b7bSAlexandra Winter } 8834e20e73eSAlexandra Winter } 8844e20e73eSAlexandra Winter lowerdev = netdev_next_lower_dev_rcu(brdev, &iter); 8854e20e73eSAlexandra Winter } 8864e20e73eSAlexandra Winter return NOTIFY_DONE; 8874e20e73eSAlexandra Winter } 8884e20e73eSAlexandra Winter 8894e20e73eSAlexandra Winter static struct notifier_block qeth_l2_sw_notifier = { 8904e20e73eSAlexandra Winter .notifier_call = qeth_l2_switchdev_event, 8914e20e73eSAlexandra Winter }; 8924e20e73eSAlexandra Winter 89360bb1089SAlexandra Winter static refcount_t qeth_l2_switchdev_notify_refcnt; 89460bb1089SAlexandra Winter 89560bb1089SAlexandra Winter /* Called under rtnl_lock */ 89660bb1089SAlexandra Winter static void qeth_l2_br2dev_get(void) 89760bb1089SAlexandra Winter { 8984e20e73eSAlexandra Winter int rc; 8994e20e73eSAlexandra Winter 90060bb1089SAlexandra Winter if (!refcount_inc_not_zero(&qeth_l2_switchdev_notify_refcnt)) { 9014e20e73eSAlexandra Winter rc = register_switchdev_notifier(&qeth_l2_sw_notifier); 9024e20e73eSAlexandra Winter if (rc) { 9034e20e73eSAlexandra Winter QETH_DBF_MESSAGE(2, 9044e20e73eSAlexandra Winter "failed to register qeth_l2_sw_notifier: %d\n", 9054e20e73eSAlexandra Winter rc); 9064e20e73eSAlexandra Winter } else { 90760bb1089SAlexandra Winter refcount_set(&qeth_l2_switchdev_notify_refcnt, 1); 90860bb1089SAlexandra Winter QETH_DBF_MESSAGE(2, "qeth_l2_sw_notifier registered\n"); 90960bb1089SAlexandra Winter } 9104e20e73eSAlexandra Winter } 91160bb1089SAlexandra Winter QETH_DBF_TEXT_(SETUP, 2, "b2d+%04d", 91260bb1089SAlexandra Winter qeth_l2_switchdev_notify_refcnt.refs.counter); 91360bb1089SAlexandra Winter } 91460bb1089SAlexandra Winter 91560bb1089SAlexandra Winter /* Called under rtnl_lock */ 91660bb1089SAlexandra Winter static void qeth_l2_br2dev_put(void) 91760bb1089SAlexandra Winter { 9184e20e73eSAlexandra Winter int rc; 9194e20e73eSAlexandra Winter 92060bb1089SAlexandra Winter if (refcount_dec_and_test(&qeth_l2_switchdev_notify_refcnt)) { 9214e20e73eSAlexandra Winter rc = unregister_switchdev_notifier(&qeth_l2_sw_notifier); 9224e20e73eSAlexandra Winter if (rc) { 9234e20e73eSAlexandra Winter QETH_DBF_MESSAGE(2, 9244e20e73eSAlexandra Winter "failed to unregister qeth_l2_sw_notifier: %d\n", 9254e20e73eSAlexandra Winter rc); 9264e20e73eSAlexandra Winter } else { 9274e20e73eSAlexandra Winter QETH_DBF_MESSAGE(2, 9284e20e73eSAlexandra Winter "qeth_l2_sw_notifier unregistered\n"); 9294e20e73eSAlexandra Winter } 93060bb1089SAlexandra Winter } 93160bb1089SAlexandra Winter QETH_DBF_TEXT_(SETUP, 2, "b2d-%04d", 93260bb1089SAlexandra Winter qeth_l2_switchdev_notify_refcnt.refs.counter); 93360bb1089SAlexandra Winter } 93460bb1089SAlexandra Winter 935780b6e7dSAlexandra Winter static int qeth_l2_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, 936780b6e7dSAlexandra Winter struct net_device *dev, u32 filter_mask, 937780b6e7dSAlexandra Winter int nlflags) 938780b6e7dSAlexandra Winter { 939780b6e7dSAlexandra Winter struct qeth_priv *priv = netdev_priv(dev); 940780b6e7dSAlexandra Winter struct qeth_card *card = dev->ml_priv; 941780b6e7dSAlexandra Winter u16 mode = BRIDGE_MODE_UNDEF; 942780b6e7dSAlexandra Winter 943780b6e7dSAlexandra Winter /* Do not even show qeth devs that cannot do bridge_setlink */ 944780b6e7dSAlexandra Winter if (!priv->brport_hw_features || !netif_device_present(dev) || 945780b6e7dSAlexandra Winter qeth_bridgeport_is_in_use(card)) 946780b6e7dSAlexandra Winter return -EOPNOTSUPP; 947780b6e7dSAlexandra Winter 948780b6e7dSAlexandra Winter return ndo_dflt_bridge_getlink(skb, pid, seq, dev, 949780b6e7dSAlexandra Winter mode, priv->brport_features, 950780b6e7dSAlexandra Winter priv->brport_hw_features, 951780b6e7dSAlexandra Winter nlflags, filter_mask, NULL); 952780b6e7dSAlexandra Winter } 953780b6e7dSAlexandra Winter 954521c65b6SAlexandra Winter static const struct nla_policy qeth_brport_policy[IFLA_BRPORT_MAX + 1] = { 955521c65b6SAlexandra Winter [IFLA_BRPORT_LEARNING_SYNC] = { .type = NLA_U8 }, 956521c65b6SAlexandra Winter }; 957521c65b6SAlexandra Winter 958521c65b6SAlexandra Winter /** 959521c65b6SAlexandra Winter * qeth_l2_bridge_setlink() - set bridgeport attributes 960521c65b6SAlexandra Winter * @dev: netdevice 961521c65b6SAlexandra Winter * @nlh: netlink message header 962521c65b6SAlexandra Winter * @flags: bridge flags (here: BRIDGE_FLAGS_SELF) 963521c65b6SAlexandra Winter * @extack: extended ACK report struct 964521c65b6SAlexandra Winter * 965521c65b6SAlexandra Winter * Called under rtnl_lock 966521c65b6SAlexandra Winter */ 967521c65b6SAlexandra Winter static int qeth_l2_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, 968521c65b6SAlexandra Winter u16 flags, struct netlink_ext_ack *extack) 969521c65b6SAlexandra Winter { 970521c65b6SAlexandra Winter struct qeth_priv *priv = netdev_priv(dev); 971521c65b6SAlexandra Winter struct nlattr *bp_tb[IFLA_BRPORT_MAX + 1]; 972521c65b6SAlexandra Winter struct qeth_card *card = dev->ml_priv; 973521c65b6SAlexandra Winter struct nlattr *attr, *nested_attr; 974521c65b6SAlexandra Winter bool enable, has_protinfo = false; 975521c65b6SAlexandra Winter int rem1, rem2; 976521c65b6SAlexandra Winter int rc; 977521c65b6SAlexandra Winter 978521c65b6SAlexandra Winter if (!netif_device_present(dev)) 979521c65b6SAlexandra Winter return -ENODEV; 980521c65b6SAlexandra Winter 981521c65b6SAlexandra Winter nlmsg_for_each_attr(attr, nlh, sizeof(struct ifinfomsg), rem1) { 982521c65b6SAlexandra Winter if (nla_type(attr) == IFLA_PROTINFO) { 983521c65b6SAlexandra Winter rc = nla_parse_nested(bp_tb, IFLA_BRPORT_MAX, attr, 984521c65b6SAlexandra Winter qeth_brport_policy, extack); 985521c65b6SAlexandra Winter if (rc) 986521c65b6SAlexandra Winter return rc; 987521c65b6SAlexandra Winter has_protinfo = true; 988521c65b6SAlexandra Winter } else if (nla_type(attr) == IFLA_AF_SPEC) { 989521c65b6SAlexandra Winter nla_for_each_nested(nested_attr, attr, rem2) { 990521c65b6SAlexandra Winter if (nla_type(nested_attr) == IFLA_BRIDGE_FLAGS) 991521c65b6SAlexandra Winter continue; 992521c65b6SAlexandra Winter NL_SET_ERR_MSG_ATTR(extack, nested_attr, 993521c65b6SAlexandra Winter "Unsupported attribute"); 994521c65b6SAlexandra Winter return -EINVAL; 995521c65b6SAlexandra Winter } 996521c65b6SAlexandra Winter } else { 997521c65b6SAlexandra Winter NL_SET_ERR_MSG_ATTR(extack, attr, "Unsupported attribute"); 998521c65b6SAlexandra Winter return -EINVAL; 999521c65b6SAlexandra Winter } 1000521c65b6SAlexandra Winter } 1001521c65b6SAlexandra Winter if (!has_protinfo) 1002521c65b6SAlexandra Winter return 0; 1003521c65b6SAlexandra Winter if (!bp_tb[IFLA_BRPORT_LEARNING_SYNC]) 1004521c65b6SAlexandra Winter return -EINVAL; 1005953fb4dcSAlexandra Winter if (!(priv->brport_hw_features & BR_LEARNING_SYNC)) { 1006953fb4dcSAlexandra Winter NL_SET_ERR_MSG_ATTR(extack, bp_tb[IFLA_BRPORT_LEARNING_SYNC], 1007953fb4dcSAlexandra Winter "Operation not supported by HW"); 1008953fb4dcSAlexandra Winter return -EOPNOTSUPP; 1009953fb4dcSAlexandra Winter } 1010953fb4dcSAlexandra Winter if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) { 1011953fb4dcSAlexandra Winter NL_SET_ERR_MSG_ATTR(extack, bp_tb[IFLA_BRPORT_LEARNING_SYNC], 1012953fb4dcSAlexandra Winter "Requires NET_SWITCHDEV"); 1013953fb4dcSAlexandra Winter return -EOPNOTSUPP; 1014953fb4dcSAlexandra Winter } 1015521c65b6SAlexandra Winter enable = !!nla_get_u8(bp_tb[IFLA_BRPORT_LEARNING_SYNC]); 1016521c65b6SAlexandra Winter 1017521c65b6SAlexandra Winter if (enable == !!(priv->brport_features & BR_LEARNING_SYNC)) 1018521c65b6SAlexandra Winter return 0; 1019521c65b6SAlexandra Winter 1020521c65b6SAlexandra Winter mutex_lock(&card->sbp_lock); 1021521c65b6SAlexandra Winter /* do not change anything if BridgePort is enabled */ 1022521c65b6SAlexandra Winter if (qeth_bridgeport_is_in_use(card)) { 1023521c65b6SAlexandra Winter NL_SET_ERR_MSG(extack, "n/a (BridgePort)"); 1024521c65b6SAlexandra Winter rc = -EBUSY; 1025521c65b6SAlexandra Winter } else if (enable) { 1026521c65b6SAlexandra Winter qeth_l2_set_pnso_mode(card, QETH_PNSO_ADDR_INFO); 1027521c65b6SAlexandra Winter rc = qeth_l2_dev2br_an_set(card, true); 102860bb1089SAlexandra Winter if (rc) { 1029521c65b6SAlexandra Winter qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE); 103060bb1089SAlexandra Winter } else { 1031521c65b6SAlexandra Winter priv->brport_features |= BR_LEARNING_SYNC; 103260bb1089SAlexandra Winter qeth_l2_br2dev_get(); 103360bb1089SAlexandra Winter } 1034521c65b6SAlexandra Winter } else { 1035521c65b6SAlexandra Winter rc = qeth_l2_dev2br_an_set(card, false); 1036521c65b6SAlexandra Winter if (!rc) { 1037521c65b6SAlexandra Winter qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE); 1038521c65b6SAlexandra Winter priv->brport_features ^= BR_LEARNING_SYNC; 1039521c65b6SAlexandra Winter qeth_l2_dev2br_fdb_flush(card); 104060bb1089SAlexandra Winter qeth_l2_br2dev_put(); 1041521c65b6SAlexandra Winter } 1042521c65b6SAlexandra Winter } 1043521c65b6SAlexandra Winter mutex_unlock(&card->sbp_lock); 1044521c65b6SAlexandra Winter 1045521c65b6SAlexandra Winter return rc; 1046521c65b6SAlexandra Winter } 1047521c65b6SAlexandra Winter 10482dbc7a1dSJulian Wiedmann static const struct net_device_ops qeth_l2_iqd_netdev_ops = { 10492dbc7a1dSJulian Wiedmann .ndo_open = qeth_open, 10502dbc7a1dSJulian Wiedmann .ndo_stop = qeth_stop, 10512dbc7a1dSJulian Wiedmann .ndo_get_stats64 = qeth_get_stats64, 10522dbc7a1dSJulian Wiedmann .ndo_start_xmit = qeth_l2_hard_start_xmit, 10532dbc7a1dSJulian Wiedmann .ndo_features_check = qeth_features_check, 1054*1b9e410fSJulian Wiedmann .ndo_select_queue = qeth_l2_iqd_select_queue, 10552dbc7a1dSJulian Wiedmann .ndo_validate_addr = qeth_l2_validate_addr, 10562dbc7a1dSJulian Wiedmann .ndo_set_rx_mode = qeth_l2_set_rx_mode, 10572dbc7a1dSJulian Wiedmann .ndo_eth_ioctl = qeth_do_ioctl, 10582dbc7a1dSJulian Wiedmann .ndo_siocdevprivate = qeth_siocdevprivate, 10592dbc7a1dSJulian Wiedmann .ndo_set_mac_address = qeth_l2_set_mac_address, 10602dbc7a1dSJulian Wiedmann .ndo_vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid, 10612dbc7a1dSJulian Wiedmann .ndo_vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid, 10622dbc7a1dSJulian Wiedmann .ndo_tx_timeout = qeth_tx_timeout, 10632dbc7a1dSJulian Wiedmann .ndo_fix_features = qeth_fix_features, 10642dbc7a1dSJulian Wiedmann .ndo_set_features = qeth_set_features, 10652dbc7a1dSJulian Wiedmann .ndo_bridge_getlink = qeth_l2_bridge_getlink, 10662dbc7a1dSJulian Wiedmann .ndo_bridge_setlink = qeth_l2_bridge_setlink, 10672dbc7a1dSJulian Wiedmann }; 10682dbc7a1dSJulian Wiedmann 10692dbc7a1dSJulian Wiedmann static const struct net_device_ops qeth_l2_osa_netdev_ops = { 1070e22355eaSJulian Wiedmann .ndo_open = qeth_open, 1071e22355eaSJulian Wiedmann .ndo_stop = qeth_stop, 1072b0abc4f5SJulian Wiedmann .ndo_get_stats64 = qeth_get_stats64, 10738403b13cSFrank Blaschka .ndo_start_xmit = qeth_l2_hard_start_xmit, 10746d69b1f1SJulian Wiedmann .ndo_features_check = qeth_features_check, 1075*1b9e410fSJulian Wiedmann .ndo_select_queue = qeth_osa_select_queue, 1076e22355eaSJulian Wiedmann .ndo_validate_addr = qeth_l2_validate_addr, 1077fe5c8028SLakhvich Dmitriy .ndo_set_rx_mode = qeth_l2_set_rx_mode, 1078a7605370SArnd Bergmann .ndo_eth_ioctl = qeth_do_ioctl, 107918787eeeSArnd Bergmann .ndo_siocdevprivate = qeth_siocdevprivate, 10808403b13cSFrank Blaschka .ndo_set_mac_address = qeth_l2_set_mac_address, 10818403b13cSFrank Blaschka .ndo_vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid, 10828403b13cSFrank Blaschka .ndo_vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid, 10838403b13cSFrank Blaschka .ndo_tx_timeout = qeth_tx_timeout, 10848f43fb00SThomas Richter .ndo_fix_features = qeth_fix_features, 1085780b6e7dSAlexandra Winter .ndo_set_features = qeth_set_features, 10868403b13cSFrank Blaschka }; 10878403b13cSFrank Blaschka 1088cd652be5SJulian Wiedmann static int qeth_l2_setup_netdev(struct qeth_card *card) 10894a71df50SFrank Blaschka { 10902dbc7a1dSJulian Wiedmann card->dev->netdev_ops = IS_IQD(card) ? &qeth_l2_iqd_netdev_ops : 10912dbc7a1dSJulian Wiedmann &qeth_l2_osa_netdev_ops; 10925f89eca5SJulian Wiedmann card->dev->needed_headroom = sizeof(struct qeth_hdr); 10938024cc9eSJulian Wiedmann card->dev->priv_flags |= IFF_UNICAST_FLT; 10949400c53fSJulian Wiedmann 10955fc692a7SJulian Wiedmann if (IS_OSM(card)) { 10969400c53fSJulian Wiedmann card->dev->features |= NETIF_F_VLAN_CHALLENGED; 10975fc692a7SJulian Wiedmann } else { 10985fc692a7SJulian Wiedmann if (!IS_VM_NIC(card)) 10995fc692a7SJulian Wiedmann card->dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; 1100f646968fSPatrick McHardy card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; 11015fc692a7SJulian Wiedmann } 11020f342945SJulian Wiedmann 1103379ac99eSJulian Wiedmann if (IS_OSD(card) && !IS_VM_NIC(card)) { 11046d69b1f1SJulian Wiedmann card->dev->features |= NETIF_F_SG; 11058f43fb00SThomas Richter /* OSA 3S and earlier has no RX/TX support */ 11069bdc4411SHans Wippel if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) { 11078f43fb00SThomas Richter card->dev->hw_features |= NETIF_F_IP_CSUM; 11089bdc4411SHans Wippel card->dev->vlan_features |= NETIF_F_IP_CSUM; 11099bdc4411SHans Wippel } 11104d7def2aSThomas Richter } 1111571f9dd8SKittipon Meesompop if (qeth_is_supported6(card, IPA_OUTBOUND_CHECKSUM_V6)) { 1112571f9dd8SKittipon Meesompop card->dev->hw_features |= NETIF_F_IPV6_CSUM; 1113571f9dd8SKittipon Meesompop card->dev->vlan_features |= NETIF_F_IPV6_CSUM; 1114571f9dd8SKittipon Meesompop } 1115d7e6ed97SKittipon Meesompop if (qeth_is_supported(card, IPA_INBOUND_CHECKSUM) || 1116d7e6ed97SKittipon Meesompop qeth_is_supported6(card, IPA_INBOUND_CHECKSUM_V6)) { 1117d7e6ed97SKittipon Meesompop card->dev->hw_features |= NETIF_F_RXCSUM; 1118d7e6ed97SKittipon Meesompop card->dev->vlan_features |= NETIF_F_RXCSUM; 1119d7e6ed97SKittipon Meesompop } 11200aef8392SJulian Wiedmann if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { 11210aef8392SJulian Wiedmann card->dev->hw_features |= NETIF_F_TSO; 11220aef8392SJulian Wiedmann card->dev->vlan_features |= NETIF_F_TSO; 11230aef8392SJulian Wiedmann } 11240aef8392SJulian Wiedmann if (qeth_is_supported6(card, IPA_OUTBOUND_TSO)) { 11250aef8392SJulian Wiedmann card->dev->hw_features |= NETIF_F_TSO6; 11260aef8392SJulian Wiedmann card->dev->vlan_features |= NETIF_F_TSO6; 11270aef8392SJulian Wiedmann } 11280aef8392SJulian Wiedmann 11290aef8392SJulian Wiedmann if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6)) { 11300aef8392SJulian Wiedmann card->dev->needed_headroom = sizeof(struct qeth_hdr_tso); 1131c619e9a6SJulian Wiedmann netif_keep_dst(card->dev); 11320aef8392SJulian Wiedmann netif_set_gso_max_size(card->dev, 11330aef8392SJulian Wiedmann PAGE_SIZE * (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)); 11340aef8392SJulian Wiedmann } 11350d6f02d3SJulian Wiedmann 1136d73ef324SJulian Wiedmann netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT); 1137cd652be5SJulian Wiedmann return register_netdev(card->dev); 11384a71df50SFrank Blaschka } 11394a71df50SFrank Blaschka 1140521c10eaSJulian Wiedmann static void qeth_l2_trace_features(struct qeth_card *card) 1141521c10eaSJulian Wiedmann { 1142a45b3fafSHans Wippel /* Set BridgePort features */ 1143a45b3fafSHans Wippel QETH_CARD_TEXT(card, 2, "featuSBP"); 1144521c10eaSJulian Wiedmann QETH_CARD_HEX(card, 2, &card->options.sbp.supported_funcs, 1145521c10eaSJulian Wiedmann sizeof(card->options.sbp.supported_funcs)); 1146a45b3fafSHans Wippel /* VNIC Characteristics features */ 1147a45b3fafSHans Wippel QETH_CARD_TEXT(card, 2, "feaVNICC"); 1148a45b3fafSHans Wippel QETH_CARD_HEX(card, 2, &card->options.vnicc.sup_chars, 1149a45b3fafSHans Wippel sizeof(card->options.vnicc.sup_chars)); 1150521c10eaSJulian Wiedmann } 1151521c10eaSJulian Wiedmann 11528ca769e2SJulian Wiedmann static void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card) 11538ca769e2SJulian Wiedmann { 11548ca769e2SJulian Wiedmann if (!card->options.sbp.reflect_promisc && 11558ca769e2SJulian Wiedmann card->options.sbp.role != QETH_SBP_ROLE_NONE) { 11568ca769e2SJulian Wiedmann /* Conditional to avoid spurious error messages */ 11578ca769e2SJulian Wiedmann qeth_bridgeport_setrole(card, card->options.sbp.role); 11588ca769e2SJulian Wiedmann /* Let the callback function refresh the stored role value. */ 11598ca769e2SJulian Wiedmann qeth_bridgeport_query_ports(card, &card->options.sbp.role, 11608ca769e2SJulian Wiedmann NULL); 11618ca769e2SJulian Wiedmann } 11628ca769e2SJulian Wiedmann if (card->options.sbp.hostnotification) { 11638ca769e2SJulian Wiedmann if (qeth_bridgeport_an_set(card, 1)) 11648ca769e2SJulian Wiedmann card->options.sbp.hostnotification = 0; 11658ca769e2SJulian Wiedmann } 11668ca769e2SJulian Wiedmann } 11678ca769e2SJulian Wiedmann 1168fa115adfSAlexandra Winter /** 1169fa115adfSAlexandra Winter * qeth_l2_detect_dev2br_support() - 1170fa115adfSAlexandra Winter * Detect whether this card supports 'dev to bridge fdb network address 1171fa115adfSAlexandra Winter * change notification' and thus can support the learning_sync bridgeport 1172fa115adfSAlexandra Winter * attribute 1173fa115adfSAlexandra Winter * @card: qeth_card structure pointer 1174fa115adfSAlexandra Winter */ 1175fa115adfSAlexandra Winter static void qeth_l2_detect_dev2br_support(struct qeth_card *card) 1176fa115adfSAlexandra Winter { 1177fa115adfSAlexandra Winter struct qeth_priv *priv = netdev_priv(card->dev); 1178fa115adfSAlexandra Winter bool dev2br_supported; 1179fa115adfSAlexandra Winter 1180fa115adfSAlexandra Winter QETH_CARD_TEXT(card, 2, "d2brsup"); 1181fa115adfSAlexandra Winter if (!IS_IQD(card)) 1182fa115adfSAlexandra Winter return; 1183fa115adfSAlexandra Winter 1184fa115adfSAlexandra Winter /* dev2br requires valid cssid,iid,chid */ 11850d0e2b53SAlexandra Winter dev2br_supported = card->info.ids_valid && 11860d0e2b53SAlexandra Winter css_general_characteristics.enarf; 1187fa115adfSAlexandra Winter QETH_CARD_TEXT_(card, 2, "D2Bsup%02x", dev2br_supported); 1188fa115adfSAlexandra Winter 1189fa115adfSAlexandra Winter if (dev2br_supported) 1190fa115adfSAlexandra Winter priv->brport_hw_features |= BR_LEARNING_SYNC; 1191fa115adfSAlexandra Winter else 1192fa115adfSAlexandra Winter priv->brport_hw_features &= ~BR_LEARNING_SYNC; 1193fa115adfSAlexandra Winter } 1194fa115adfSAlexandra Winter 1195521c65b6SAlexandra Winter static void qeth_l2_enable_brport_features(struct qeth_card *card) 1196521c65b6SAlexandra Winter { 1197521c65b6SAlexandra Winter struct qeth_priv *priv = netdev_priv(card->dev); 1198521c65b6SAlexandra Winter int rc; 1199521c65b6SAlexandra Winter 1200521c65b6SAlexandra Winter if (priv->brport_features & BR_LEARNING_SYNC) { 1201521c65b6SAlexandra Winter if (priv->brport_hw_features & BR_LEARNING_SYNC) { 1202521c65b6SAlexandra Winter qeth_l2_set_pnso_mode(card, QETH_PNSO_ADDR_INFO); 1203521c65b6SAlexandra Winter rc = qeth_l2_dev2br_an_set(card, true); 1204521c65b6SAlexandra Winter if (rc == -EAGAIN) { 1205521c65b6SAlexandra Winter /* Recoverable error, retry once */ 1206521c65b6SAlexandra Winter qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE); 1207521c65b6SAlexandra Winter qeth_l2_dev2br_fdb_flush(card); 1208521c65b6SAlexandra Winter qeth_l2_set_pnso_mode(card, QETH_PNSO_ADDR_INFO); 1209521c65b6SAlexandra Winter rc = qeth_l2_dev2br_an_set(card, true); 1210521c65b6SAlexandra Winter } 1211521c65b6SAlexandra Winter if (rc) { 1212521c65b6SAlexandra Winter netdev_err(card->dev, 1213521c65b6SAlexandra Winter "failed to enable bridge learning_sync: %d\n", 1214521c65b6SAlexandra Winter rc); 1215521c65b6SAlexandra Winter qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE); 1216521c65b6SAlexandra Winter qeth_l2_dev2br_fdb_flush(card); 1217521c65b6SAlexandra Winter priv->brport_features ^= BR_LEARNING_SYNC; 1218521c65b6SAlexandra Winter } 1219521c65b6SAlexandra Winter } else { 1220521c65b6SAlexandra Winter dev_warn(&card->gdev->dev, 1221521c65b6SAlexandra Winter "bridge learning_sync not supported\n"); 1222521c65b6SAlexandra Winter priv->brport_features ^= BR_LEARNING_SYNC; 1223521c65b6SAlexandra Winter } 1224521c65b6SAlexandra Winter } 1225521c65b6SAlexandra Winter } 1226521c65b6SAlexandra Winter 1227b4d72c08SEugene Crosser /* SETBRIDGEPORT support, async notifications */ 1228b4d72c08SEugene Crosser 12299f48b9dbSEugene Crosser enum qeth_an_event_type {anev_reg_unreg, anev_abort, anev_reset}; 12309f48b9dbSEugene Crosser 12319f48b9dbSEugene Crosser /** 12329f48b9dbSEugene Crosser * qeth_bridge_emit_host_event() - bridgeport address change notification 12339f48b9dbSEugene Crosser * @card: qeth_card structure pointer, for udev events. 12349f48b9dbSEugene Crosser * @evtype: "normal" register/unregister, or abort, or reset. For abort 12359f48b9dbSEugene Crosser * and reset token and addr_lnid are unused and may be NULL. 12369f48b9dbSEugene Crosser * @code: event bitmask: high order bit 0x80 value 1 means removal of an 12379f48b9dbSEugene Crosser * object, 0 - addition of an object. 12389f48b9dbSEugene Crosser * 0x01 - VLAN, 0x02 - MAC, 0x03 - VLAN and MAC. 12399f48b9dbSEugene Crosser * @token: "network token" structure identifying physical address of the port. 12409f48b9dbSEugene Crosser * @addr_lnid: pointer to structure with MAC address and VLAN ID. 12419f48b9dbSEugene Crosser * 12429f48b9dbSEugene Crosser * This function is called when registrations and deregistrations are 12439f48b9dbSEugene Crosser * reported by the hardware, and also when notifications are enabled - 12449f48b9dbSEugene Crosser * for all currently registered addresses. 12459f48b9dbSEugene Crosser */ 12469f48b9dbSEugene Crosser static void qeth_bridge_emit_host_event(struct qeth_card *card, 12479f48b9dbSEugene Crosser enum qeth_an_event_type evtype, 1248a0138f59SAlexandra Winter u8 code, 1249a0138f59SAlexandra Winter struct net_if_token *token, 1250a0138f59SAlexandra Winter struct mac_addr_lnid *addr_lnid) 12519f48b9dbSEugene Crosser { 12529f48b9dbSEugene Crosser char str[7][32]; 12539f48b9dbSEugene Crosser char *env[8]; 12549f48b9dbSEugene Crosser int i = 0; 12559f48b9dbSEugene Crosser 12569f48b9dbSEugene Crosser switch (evtype) { 12579f48b9dbSEugene Crosser case anev_reg_unreg: 12589f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=%s", 12599f48b9dbSEugene Crosser (code & IPA_ADDR_CHANGE_CODE_REMOVAL) 12609f48b9dbSEugene Crosser ? "deregister" : "register"); 12619f48b9dbSEugene Crosser env[i] = str[i]; i++; 12629f48b9dbSEugene Crosser if (code & IPA_ADDR_CHANGE_CODE_VLANID) { 12639f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "VLAN=%d", 12649f48b9dbSEugene Crosser addr_lnid->lnid); 12659f48b9dbSEugene Crosser env[i] = str[i]; i++; 12669f48b9dbSEugene Crosser } 12679f48b9dbSEugene Crosser if (code & IPA_ADDR_CHANGE_CODE_MACADDR) { 12689846e70bSEugene Crosser snprintf(str[i], sizeof(str[i]), "MAC=%pM", 12699846e70bSEugene Crosser addr_lnid->mac); 12709f48b9dbSEugene Crosser env[i] = str[i]; i++; 12719f48b9dbSEugene Crosser } 12729f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "NTOK_BUSID=%x.%x.%04x", 12739f48b9dbSEugene Crosser token->cssid, token->ssid, token->devnum); 12749f48b9dbSEugene Crosser env[i] = str[i]; i++; 12759f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "NTOK_IID=%02x", token->iid); 12769f48b9dbSEugene Crosser env[i] = str[i]; i++; 12779f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "NTOK_CHPID=%02x", 12789f48b9dbSEugene Crosser token->chpid); 12799f48b9dbSEugene Crosser env[i] = str[i]; i++; 12809f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "NTOK_CHID=%04x", token->chid); 12819f48b9dbSEugene Crosser env[i] = str[i]; i++; 12829f48b9dbSEugene Crosser break; 12839f48b9dbSEugene Crosser case anev_abort: 12849f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=abort"); 12859f48b9dbSEugene Crosser env[i] = str[i]; i++; 12869f48b9dbSEugene Crosser break; 12879f48b9dbSEugene Crosser case anev_reset: 12889f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=reset"); 12899f48b9dbSEugene Crosser env[i] = str[i]; i++; 12909f48b9dbSEugene Crosser break; 12919f48b9dbSEugene Crosser } 12929f48b9dbSEugene Crosser env[i] = NULL; 12939f48b9dbSEugene Crosser kobject_uevent_env(&card->gdev->dev.kobj, KOBJ_CHANGE, env); 12949f48b9dbSEugene Crosser } 12959f48b9dbSEugene Crosser 1296b4d72c08SEugene Crosser struct qeth_bridge_state_data { 1297b4d72c08SEugene Crosser struct work_struct worker; 1298b4d72c08SEugene Crosser struct qeth_card *card; 129961c6f217SJulian Wiedmann u8 role; 130061c6f217SJulian Wiedmann u8 state; 1301b4d72c08SEugene Crosser }; 1302b4d72c08SEugene Crosser 1303b4d72c08SEugene Crosser static void qeth_bridge_state_change_worker(struct work_struct *work) 1304b4d72c08SEugene Crosser { 1305b4d72c08SEugene Crosser struct qeth_bridge_state_data *data = 1306b4d72c08SEugene Crosser container_of(work, struct qeth_bridge_state_data, worker); 1307b4d72c08SEugene Crosser char env_locrem[32]; 1308b4d72c08SEugene Crosser char env_role[32]; 1309b4d72c08SEugene Crosser char env_state[32]; 1310b4d72c08SEugene Crosser char *env[] = { 1311b4d72c08SEugene Crosser env_locrem, 1312b4d72c08SEugene Crosser env_role, 1313b4d72c08SEugene Crosser env_state, 1314b4d72c08SEugene Crosser NULL 1315b4d72c08SEugene Crosser }; 1316b4d72c08SEugene Crosser 1317b4d72c08SEugene Crosser snprintf(env_locrem, sizeof(env_locrem), "BRIDGEPORT=statechange"); 1318b4d72c08SEugene Crosser snprintf(env_role, sizeof(env_role), "ROLE=%s", 131961c6f217SJulian Wiedmann (data->role == QETH_SBP_ROLE_NONE) ? "none" : 132061c6f217SJulian Wiedmann (data->role == QETH_SBP_ROLE_PRIMARY) ? "primary" : 132161c6f217SJulian Wiedmann (data->role == QETH_SBP_ROLE_SECONDARY) ? "secondary" : 1322b4d72c08SEugene Crosser "<INVALID>"); 1323b4d72c08SEugene Crosser snprintf(env_state, sizeof(env_state), "STATE=%s", 132461c6f217SJulian Wiedmann (data->state == QETH_SBP_STATE_INACTIVE) ? "inactive" : 132561c6f217SJulian Wiedmann (data->state == QETH_SBP_STATE_STANDBY) ? "standby" : 132661c6f217SJulian Wiedmann (data->state == QETH_SBP_STATE_ACTIVE) ? "active" : 1327b4d72c08SEugene Crosser "<INVALID>"); 1328b4d72c08SEugene Crosser kobject_uevent_env(&data->card->gdev->dev.kobj, 1329b4d72c08SEugene Crosser KOBJ_CHANGE, env); 1330b4d72c08SEugene Crosser kfree(data); 1331b4d72c08SEugene Crosser } 1332b4d72c08SEugene Crosser 1333c044dc21SEugene Crosser static void qeth_bridge_state_change(struct qeth_card *card, 1334c044dc21SEugene Crosser struct qeth_ipa_cmd *cmd) 1335b4d72c08SEugene Crosser { 133665b0494eSJulian Wiedmann struct qeth_sbp_port_data *qports = &cmd->data.sbp.data.port_data; 1337b4d72c08SEugene Crosser struct qeth_bridge_state_data *data; 1338b4d72c08SEugene Crosser 1339b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brstchng"); 134002472e28SJulian Wiedmann if (qports->num_entries == 0) { 134102472e28SJulian Wiedmann QETH_CARD_TEXT(card, 2, "BPempty"); 134202472e28SJulian Wiedmann return; 134302472e28SJulian Wiedmann } 1344b4d72c08SEugene Crosser if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) { 13458a593148SThomas Richter QETH_CARD_TEXT_(card, 2, "BPsz%04x", qports->entry_length); 1346b4d72c08SEugene Crosser return; 1347b4d72c08SEugene Crosser } 134861c6f217SJulian Wiedmann 134961c6f217SJulian Wiedmann data = kzalloc(sizeof(*data), GFP_ATOMIC); 1350b4d72c08SEugene Crosser if (!data) { 1351b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "BPSalloc"); 1352b4d72c08SEugene Crosser return; 1353b4d72c08SEugene Crosser } 1354b4d72c08SEugene Crosser INIT_WORK(&data->worker, qeth_bridge_state_change_worker); 1355b4d72c08SEugene Crosser data->card = card; 135661c6f217SJulian Wiedmann /* Information for the local port: */ 135761c6f217SJulian Wiedmann data->role = qports->entry[0].role; 135861c6f217SJulian Wiedmann data->state = qports->entry[0].state; 135961c6f217SJulian Wiedmann 1360c0a2e4d1SJulian Wiedmann queue_work(card->event_wq, &data->worker); 1361b4d72c08SEugene Crosser } 1362b4d72c08SEugene Crosser 1363a0138f59SAlexandra Winter struct qeth_addr_change_data { 13649d6a569aSJulian Wiedmann struct delayed_work dwork; 13659f48b9dbSEugene Crosser struct qeth_card *card; 1366a0138f59SAlexandra Winter struct qeth_ipacmd_addr_change ac_event; 13679f48b9dbSEugene Crosser }; 13689f48b9dbSEugene Crosser 136910a6cfc0SAlexandra Winter static void qeth_l2_dev2br_worker(struct work_struct *work) 137010a6cfc0SAlexandra Winter { 137110a6cfc0SAlexandra Winter struct delayed_work *dwork = to_delayed_work(work); 137210a6cfc0SAlexandra Winter struct qeth_addr_change_data *data; 137310a6cfc0SAlexandra Winter struct qeth_card *card; 1374817741a8SAlexandra Winter struct qeth_priv *priv; 137510a6cfc0SAlexandra Winter unsigned int i; 1376817741a8SAlexandra Winter int rc; 137710a6cfc0SAlexandra Winter 137810a6cfc0SAlexandra Winter data = container_of(dwork, struct qeth_addr_change_data, dwork); 137910a6cfc0SAlexandra Winter card = data->card; 1380817741a8SAlexandra Winter priv = netdev_priv(card->dev); 138110a6cfc0SAlexandra Winter 138210a6cfc0SAlexandra Winter QETH_CARD_TEXT(card, 4, "dev2brew"); 138310a6cfc0SAlexandra Winter 138410a6cfc0SAlexandra Winter if (READ_ONCE(card->info.pnso_mode) == QETH_PNSO_NONE) 138510a6cfc0SAlexandra Winter goto free; 138610a6cfc0SAlexandra Winter 138709840f70SJulian Wiedmann if (data->ac_event.lost_event_mask) { 138810a6cfc0SAlexandra Winter /* Potential re-config in progress, try again later: */ 138910a6cfc0SAlexandra Winter if (!rtnl_trylock()) { 139010a6cfc0SAlexandra Winter queue_delayed_work(card->event_wq, dwork, 139110a6cfc0SAlexandra Winter msecs_to_jiffies(100)); 139210a6cfc0SAlexandra Winter return; 139310a6cfc0SAlexandra Winter } 139410a6cfc0SAlexandra Winter 139509840f70SJulian Wiedmann if (!netif_device_present(card->dev)) { 139609840f70SJulian Wiedmann rtnl_unlock(); 139709840f70SJulian Wiedmann goto free; 139809840f70SJulian Wiedmann } 139909840f70SJulian Wiedmann 140010a6cfc0SAlexandra Winter QETH_DBF_MESSAGE(3, 140110a6cfc0SAlexandra Winter "Address change notification overflow on device %x\n", 140210a6cfc0SAlexandra Winter CARD_DEVID(card)); 1403817741a8SAlexandra Winter /* Card fdb and bridge fdb are out of sync, card has stopped 1404817741a8SAlexandra Winter * notifications (no need to drain_workqueue). Purge all 1405817741a8SAlexandra Winter * 'extern_learn' entries from the parent bridge and restart 1406817741a8SAlexandra Winter * the notifications. 1407817741a8SAlexandra Winter */ 1408817741a8SAlexandra Winter qeth_l2_dev2br_fdb_flush(card); 1409817741a8SAlexandra Winter rc = qeth_l2_dev2br_an_set(card, true); 1410817741a8SAlexandra Winter if (rc) { 1411817741a8SAlexandra Winter /* TODO: if we want to retry after -EAGAIN, be 1412817741a8SAlexandra Winter * aware there could be stale entries in the 1413817741a8SAlexandra Winter * workqueue now, that need to be drained. 1414817741a8SAlexandra Winter * For now we give up: 1415817741a8SAlexandra Winter */ 1416817741a8SAlexandra Winter netdev_err(card->dev, 1417817741a8SAlexandra Winter "bridge learning_sync failed to recover: %d\n", 1418817741a8SAlexandra Winter rc); 1419817741a8SAlexandra Winter WRITE_ONCE(card->info.pnso_mode, 1420817741a8SAlexandra Winter QETH_PNSO_NONE); 1421817741a8SAlexandra Winter /* To remove fdb entries reported by an_set: */ 1422817741a8SAlexandra Winter qeth_l2_dev2br_fdb_flush(card); 1423817741a8SAlexandra Winter priv->brport_features ^= BR_LEARNING_SYNC; 1424817741a8SAlexandra Winter } else { 1425817741a8SAlexandra Winter QETH_DBF_MESSAGE(3, 1426817741a8SAlexandra Winter "Address Notification resynced on device %x\n", 1427817741a8SAlexandra Winter CARD_DEVID(card)); 1428817741a8SAlexandra Winter } 142909840f70SJulian Wiedmann 143009840f70SJulian Wiedmann rtnl_unlock(); 143110a6cfc0SAlexandra Winter } else { 143210a6cfc0SAlexandra Winter for (i = 0; i < data->ac_event.num_entries; i++) { 143310a6cfc0SAlexandra Winter struct qeth_ipacmd_addr_change_entry *entry = 143410a6cfc0SAlexandra Winter &data->ac_event.entry[i]; 143510a6cfc0SAlexandra Winter qeth_l2_dev2br_fdb_notify(card, 143610a6cfc0SAlexandra Winter entry->change_code, 143710a6cfc0SAlexandra Winter &entry->token, 143810a6cfc0SAlexandra Winter &entry->addr_lnid); 143910a6cfc0SAlexandra Winter } 144010a6cfc0SAlexandra Winter } 1441817741a8SAlexandra Winter 144210a6cfc0SAlexandra Winter free: 144310a6cfc0SAlexandra Winter kfree(data); 144410a6cfc0SAlexandra Winter } 144510a6cfc0SAlexandra Winter 1446a0138f59SAlexandra Winter static void qeth_addr_change_event_worker(struct work_struct *work) 14479f48b9dbSEugene Crosser { 14489d6a569aSJulian Wiedmann struct delayed_work *dwork = to_delayed_work(work); 14499d6a569aSJulian Wiedmann struct qeth_addr_change_data *data; 14509d6a569aSJulian Wiedmann struct qeth_card *card; 14519f48b9dbSEugene Crosser int i; 14529f48b9dbSEugene Crosser 14539d6a569aSJulian Wiedmann data = container_of(dwork, struct qeth_addr_change_data, dwork); 14549d6a569aSJulian Wiedmann card = data->card; 14559d6a569aSJulian Wiedmann 1456a0138f59SAlexandra Winter QETH_CARD_TEXT(data->card, 4, "adrchgew"); 14579d6a569aSJulian Wiedmann 14589d6a569aSJulian Wiedmann if (READ_ONCE(card->info.pnso_mode) == QETH_PNSO_NONE) 14599d6a569aSJulian Wiedmann goto free; 14609d6a569aSJulian Wiedmann 1461a0138f59SAlexandra Winter if (data->ac_event.lost_event_mask) { 14629d6a569aSJulian Wiedmann /* Potential re-config in progress, try again later: */ 14639d6a569aSJulian Wiedmann if (!mutex_trylock(&card->sbp_lock)) { 14649d6a569aSJulian Wiedmann queue_delayed_work(card->event_wq, dwork, 14659d6a569aSJulian Wiedmann msecs_to_jiffies(100)); 14669d6a569aSJulian Wiedmann return; 14679d6a569aSJulian Wiedmann } 14689d6a569aSJulian Wiedmann 14699f48b9dbSEugene Crosser dev_info(&data->card->gdev->dev, 1470a0138f59SAlexandra Winter "Address change notification stopped on %s (%s)\n", 147184c91482SJulian Wiedmann netdev_name(card->dev), 1472a0138f59SAlexandra Winter (data->ac_event.lost_event_mask == 0x01) 14739f48b9dbSEugene Crosser ? "Overflow" 1474a0138f59SAlexandra Winter : (data->ac_event.lost_event_mask == 0x02) 14759f48b9dbSEugene Crosser ? "Bridge port state change" 14769f48b9dbSEugene Crosser : "Unknown reason"); 14779d6a569aSJulian Wiedmann 14789f48b9dbSEugene Crosser data->card->options.sbp.hostnotification = 0; 14799d6a569aSJulian Wiedmann card->info.pnso_mode = QETH_PNSO_NONE; 1480c8183f54SJulian Wiedmann mutex_unlock(&data->card->sbp_lock); 14819f48b9dbSEugene Crosser qeth_bridge_emit_host_event(data->card, anev_abort, 14829f48b9dbSEugene Crosser 0, NULL, NULL); 14839f48b9dbSEugene Crosser } else 1484a0138f59SAlexandra Winter for (i = 0; i < data->ac_event.num_entries; i++) { 14859f48b9dbSEugene Crosser struct qeth_ipacmd_addr_change_entry *entry = 1486a0138f59SAlexandra Winter &data->ac_event.entry[i]; 14879f48b9dbSEugene Crosser qeth_bridge_emit_host_event(data->card, 14889f48b9dbSEugene Crosser anev_reg_unreg, 14899f48b9dbSEugene Crosser entry->change_code, 1490a0138f59SAlexandra Winter &entry->token, 1491a0138f59SAlexandra Winter &entry->addr_lnid); 14929f48b9dbSEugene Crosser } 14939d6a569aSJulian Wiedmann 14949d6a569aSJulian Wiedmann free: 14959f48b9dbSEugene Crosser kfree(data); 14969f48b9dbSEugene Crosser } 14979f48b9dbSEugene Crosser 1498a0138f59SAlexandra Winter static void qeth_addr_change_event(struct qeth_card *card, 1499c044dc21SEugene Crosser struct qeth_ipa_cmd *cmd) 15009f48b9dbSEugene Crosser { 15019f48b9dbSEugene Crosser struct qeth_ipacmd_addr_change *hostevs = 15029f48b9dbSEugene Crosser &cmd->data.addrchange; 1503a0138f59SAlexandra Winter struct qeth_addr_change_data *data; 15049f48b9dbSEugene Crosser int extrasize; 15059f48b9dbSEugene Crosser 15069d6a569aSJulian Wiedmann if (card->info.pnso_mode == QETH_PNSO_NONE) 15079d6a569aSJulian Wiedmann return; 15089d6a569aSJulian Wiedmann 1509a0138f59SAlexandra Winter QETH_CARD_TEXT(card, 4, "adrchgev"); 15109f48b9dbSEugene Crosser if (cmd->hdr.return_code != 0x0000) { 15119f48b9dbSEugene Crosser if (cmd->hdr.return_code == 0x0010) { 15129f48b9dbSEugene Crosser if (hostevs->lost_event_mask == 0x00) 15139f48b9dbSEugene Crosser hostevs->lost_event_mask = 0xff; 15149f48b9dbSEugene Crosser } else { 1515a0138f59SAlexandra Winter QETH_CARD_TEXT_(card, 2, "ACHN%04x", 15169f48b9dbSEugene Crosser cmd->hdr.return_code); 15179f48b9dbSEugene Crosser return; 15189f48b9dbSEugene Crosser } 15199f48b9dbSEugene Crosser } 15209f48b9dbSEugene Crosser extrasize = sizeof(struct qeth_ipacmd_addr_change_entry) * 15219f48b9dbSEugene Crosser hostevs->num_entries; 1522a0138f59SAlexandra Winter data = kzalloc(sizeof(struct qeth_addr_change_data) + extrasize, 15239f48b9dbSEugene Crosser GFP_ATOMIC); 15249f48b9dbSEugene Crosser if (!data) { 1525a0138f59SAlexandra Winter QETH_CARD_TEXT(card, 2, "ACNalloc"); 15269f48b9dbSEugene Crosser return; 15279f48b9dbSEugene Crosser } 152810a6cfc0SAlexandra Winter if (card->info.pnso_mode == QETH_PNSO_BRIDGEPORT) 15299d6a569aSJulian Wiedmann INIT_DELAYED_WORK(&data->dwork, qeth_addr_change_event_worker); 153010a6cfc0SAlexandra Winter else 153110a6cfc0SAlexandra Winter INIT_DELAYED_WORK(&data->dwork, qeth_l2_dev2br_worker); 15329f48b9dbSEugene Crosser data->card = card; 1533a0138f59SAlexandra Winter memcpy(&data->ac_event, hostevs, 15349f48b9dbSEugene Crosser sizeof(struct qeth_ipacmd_addr_change) + extrasize); 15359d6a569aSJulian Wiedmann queue_delayed_work(card->event_wq, &data->dwork, 0); 15369f48b9dbSEugene Crosser } 15379f48b9dbSEugene Crosser 1538b4d72c08SEugene Crosser /* SETBRIDGEPORT support; sending commands */ 1539b4d72c08SEugene Crosser 1540b4d72c08SEugene Crosser struct _qeth_sbp_cbctl { 1541b4d72c08SEugene Crosser union { 1542b4d72c08SEugene Crosser u32 supported; 1543b4d72c08SEugene Crosser struct { 1544b4d72c08SEugene Crosser enum qeth_sbp_roles *role; 1545b4d72c08SEugene Crosser enum qeth_sbp_states *state; 1546b4d72c08SEugene Crosser } qports; 1547b4d72c08SEugene Crosser } data; 1548b4d72c08SEugene Crosser }; 1549b4d72c08SEugene Crosser 1550b4d72c08SEugene Crosser static int qeth_bridgeport_makerc(struct qeth_card *card, 15511709ff8dSJulian Wiedmann struct qeth_ipa_cmd *cmd) 1552b4d72c08SEugene Crosser { 15531709ff8dSJulian Wiedmann struct qeth_ipacmd_setbridgeport *sbp = &cmd->data.sbp; 15541709ff8dSJulian Wiedmann enum qeth_ipa_sbp_cmd setcmd = sbp->hdr.command_code; 15551709ff8dSJulian Wiedmann u16 ipa_rc = cmd->hdr.return_code; 15561709ff8dSJulian Wiedmann u16 sbp_rc = sbp->hdr.return_code; 1557b4d72c08SEugene Crosser int rc; 1558b4d72c08SEugene Crosser 15591709ff8dSJulian Wiedmann if (ipa_rc == IPA_RC_SUCCESS && sbp_rc == IPA_RC_SUCCESS) 15601709ff8dSJulian Wiedmann return 0; 15611709ff8dSJulian Wiedmann 15621709ff8dSJulian Wiedmann if ((IS_IQD(card) && ipa_rc == IPA_RC_SUCCESS) || 15631709ff8dSJulian Wiedmann (!IS_IQD(card) && ipa_rc == sbp_rc)) { 15641709ff8dSJulian Wiedmann switch (sbp_rc) { 15652063a5f5SKittipon Meesompop case IPA_RC_SUCCESS: 1566b4d72c08SEugene Crosser rc = 0; 1567b4d72c08SEugene Crosser break; 15682063a5f5SKittipon Meesompop case IPA_RC_L2_UNSUPPORTED_CMD: 15692063a5f5SKittipon Meesompop case IPA_RC_UNSUPPORTED_COMMAND: 1570ffb95251SEugene Crosser rc = -EOPNOTSUPP; 1571b4d72c08SEugene Crosser break; 15722063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_NOT_CONFIGURED: 15732063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_NOT_CONFIGURED: 1574b4d72c08SEugene Crosser rc = -ENODEV; /* maybe not the best code here? */ 1575b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 15769c23f4daSEugene Crosser "The device is not configured as a Bridge Port\n"); 1577b4d72c08SEugene Crosser break; 15782063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_OS_MISMATCH: 15792063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_OS_MISMATCH: 15801b05cf62SEugene Crosser rc = -EPERM; 15811b05cf62SEugene Crosser dev_err(&card->gdev->dev, 15821b05cf62SEugene Crosser "A Bridge Port is already configured by a different operating system\n"); 15831b05cf62SEugene Crosser break; 15842063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_ANO_DEV_PRIMARY: 15852063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_ANO_DEV_PRIMARY: 1586b4d72c08SEugene Crosser switch (setcmd) { 1587b4d72c08SEugene Crosser case IPA_SBP_SET_PRIMARY_BRIDGE_PORT: 1588b4d72c08SEugene Crosser rc = -EEXIST; 1589b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 15909c23f4daSEugene Crosser "The LAN already has a primary Bridge Port\n"); 1591b4d72c08SEugene Crosser break; 1592b4d72c08SEugene Crosser case IPA_SBP_SET_SECONDARY_BRIDGE_PORT: 1593b4d72c08SEugene Crosser rc = -EBUSY; 1594b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 15959c23f4daSEugene Crosser "The device is already a primary Bridge Port\n"); 1596b4d72c08SEugene Crosser break; 1597b4d72c08SEugene Crosser default: 1598b4d72c08SEugene Crosser rc = -EIO; 1599b4d72c08SEugene Crosser } 1600b4d72c08SEugene Crosser break; 16012063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_CURRENT_SECOND: 16022063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_CURRENT_SECOND: 1603b4d72c08SEugene Crosser rc = -EBUSY; 1604b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 16059c23f4daSEugene Crosser "The device is already a secondary Bridge Port\n"); 1606b4d72c08SEugene Crosser break; 16072063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_LIMIT_SECOND: 16082063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_LIMIT_SECOND: 1609b4d72c08SEugene Crosser rc = -EEXIST; 1610b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 16119c23f4daSEugene Crosser "The LAN cannot have more secondary Bridge Ports\n"); 1612b4d72c08SEugene Crosser break; 16132063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_CURRENT_PRIMARY: 16142063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_CURRENT_PRIMARY: 1615b4d72c08SEugene Crosser rc = -EBUSY; 1616b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 16179c23f4daSEugene Crosser "The device is already a primary Bridge Port\n"); 1618b4d72c08SEugene Crosser break; 16192063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_NOT_AUTHD_BY_ZMAN: 16202063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_NOT_AUTHD_BY_ZMAN: 1621b4d72c08SEugene Crosser rc = -EACCES; 1622b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 16239c23f4daSEugene Crosser "The device is not authorized to be a Bridge Port\n"); 1624b4d72c08SEugene Crosser break; 1625b4d72c08SEugene Crosser default: 1626b4d72c08SEugene Crosser rc = -EIO; 1627b4d72c08SEugene Crosser } 16281709ff8dSJulian Wiedmann } else { 16291709ff8dSJulian Wiedmann switch (ipa_rc) { 1630b4d72c08SEugene Crosser case IPA_RC_NOTSUPP: 1631ffb95251SEugene Crosser rc = -EOPNOTSUPP; 1632b4d72c08SEugene Crosser break; 1633b4d72c08SEugene Crosser case IPA_RC_UNSUPPORTED_COMMAND: 1634ffb95251SEugene Crosser rc = -EOPNOTSUPP; 1635b4d72c08SEugene Crosser break; 1636b4d72c08SEugene Crosser default: 1637b4d72c08SEugene Crosser rc = -EIO; 1638b4d72c08SEugene Crosser } 16391709ff8dSJulian Wiedmann } 16409c23f4daSEugene Crosser 1641b4d72c08SEugene Crosser if (rc) { 16421709ff8dSJulian Wiedmann QETH_CARD_TEXT_(card, 2, "SBPi%04x", ipa_rc); 16431709ff8dSJulian Wiedmann QETH_CARD_TEXT_(card, 2, "SBPc%04x", sbp_rc); 1644b4d72c08SEugene Crosser } 1645b4d72c08SEugene Crosser return rc; 1646b4d72c08SEugene Crosser } 1647b4d72c08SEugene Crosser 1648d65626adSJulian Wiedmann static struct qeth_cmd_buffer *qeth_sbp_build_cmd(struct qeth_card *card, 1649d65626adSJulian Wiedmann enum qeth_ipa_sbp_cmd sbp_cmd, 1650b9150461SJulian Wiedmann unsigned int data_length) 16519c23f4daSEugene Crosser { 1652379ac99eSJulian Wiedmann enum qeth_ipa_cmds ipa_cmd = IS_IQD(card) ? IPA_CMD_SETBRIDGEPORT_IQD : 16539c23f4daSEugene Crosser IPA_CMD_SETBRIDGEPORT_OSA; 1654b9150461SJulian Wiedmann struct qeth_ipacmd_sbp_hdr *hdr; 1655d65626adSJulian Wiedmann struct qeth_cmd_buffer *iob; 1656d65626adSJulian Wiedmann 1657b9150461SJulian Wiedmann iob = qeth_ipa_alloc_cmd(card, ipa_cmd, QETH_PROT_NONE, 1658b9150461SJulian Wiedmann data_length + 1659b9150461SJulian Wiedmann offsetof(struct qeth_ipacmd_setbridgeport, 1660b9150461SJulian Wiedmann data)); 1661d65626adSJulian Wiedmann if (!iob) 1662d65626adSJulian Wiedmann return iob; 1663b9150461SJulian Wiedmann 1664b9150461SJulian Wiedmann hdr = &__ipa_cmd(iob)->data.sbp.hdr; 1665b9150461SJulian Wiedmann hdr->cmdlength = sizeof(*hdr) + data_length; 1666b9150461SJulian Wiedmann hdr->command_code = sbp_cmd; 1667b9150461SJulian Wiedmann hdr->used_total = 1; 1668b9150461SJulian Wiedmann hdr->seq_no = 1; 1669d65626adSJulian Wiedmann return iob; 16709c23f4daSEugene Crosser } 16719c23f4daSEugene Crosser 1672b4d72c08SEugene Crosser static int qeth_bridgeport_query_support_cb(struct qeth_card *card, 1673b4d72c08SEugene Crosser struct qeth_reply *reply, unsigned long data) 1674b4d72c08SEugene Crosser { 1675b4d72c08SEugene Crosser struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; 1676b4d72c08SEugene Crosser struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param; 16771709ff8dSJulian Wiedmann int rc; 16781709ff8dSJulian Wiedmann 1679b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brqsupcb"); 16801709ff8dSJulian Wiedmann rc = qeth_bridgeport_makerc(card, cmd); 16811709ff8dSJulian Wiedmann if (rc) 16821709ff8dSJulian Wiedmann return rc; 16831709ff8dSJulian Wiedmann 1684b4d72c08SEugene Crosser cbctl->data.supported = 1685b4d72c08SEugene Crosser cmd->data.sbp.data.query_cmds_supp.supported_cmds; 1686b4d72c08SEugene Crosser return 0; 1687b4d72c08SEugene Crosser } 1688b4d72c08SEugene Crosser 1689b4d72c08SEugene Crosser /** 1690b4d72c08SEugene Crosser * qeth_bridgeport_query_support() - store bitmask of supported subfunctions. 1691b4d72c08SEugene Crosser * @card: qeth_card structure pointer. 1692b4d72c08SEugene Crosser * 1693b4d72c08SEugene Crosser * Sets bitmask of supported setbridgeport subfunctions in the qeth_card 1694b4d72c08SEugene Crosser * strucutre: card->options.sbp.supported_funcs. 1695b4d72c08SEugene Crosser */ 1696c044dc21SEugene Crosser static void qeth_bridgeport_query_support(struct qeth_card *card) 1697b4d72c08SEugene Crosser { 1698b4d72c08SEugene Crosser struct qeth_cmd_buffer *iob; 1699b4d72c08SEugene Crosser struct _qeth_sbp_cbctl cbctl; 1700b4d72c08SEugene Crosser 1701b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brqsuppo"); 1702d65626adSJulian Wiedmann iob = qeth_sbp_build_cmd(card, IPA_SBP_QUERY_COMMANDS_SUPPORTED, 1703b9150461SJulian Wiedmann SBP_DATA_SIZEOF(query_cmds_supp)); 17041aec42bcSThomas Richter if (!iob) 17051aec42bcSThomas Richter return; 17061709ff8dSJulian Wiedmann 1707b4d72c08SEugene Crosser if (qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_support_cb, 17081709ff8dSJulian Wiedmann &cbctl)) { 1709b4d72c08SEugene Crosser card->options.sbp.role = QETH_SBP_ROLE_NONE; 17101709ff8dSJulian Wiedmann card->options.sbp.supported_funcs = 0; 1711b4d72c08SEugene Crosser return; 1712b4d72c08SEugene Crosser } 1713b4d72c08SEugene Crosser card->options.sbp.supported_funcs = cbctl.data.supported; 1714b4d72c08SEugene Crosser } 1715b4d72c08SEugene Crosser 1716b4d72c08SEugene Crosser static int qeth_bridgeport_query_ports_cb(struct qeth_card *card, 1717b4d72c08SEugene Crosser struct qeth_reply *reply, unsigned long data) 1718b4d72c08SEugene Crosser { 1719b4d72c08SEugene Crosser struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; 1720b4d72c08SEugene Crosser struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param; 172165b0494eSJulian Wiedmann struct qeth_sbp_port_data *qports; 17221709ff8dSJulian Wiedmann int rc; 1723b4d72c08SEugene Crosser 1724b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brqprtcb"); 17251709ff8dSJulian Wiedmann rc = qeth_bridgeport_makerc(card, cmd); 17261709ff8dSJulian Wiedmann if (rc) 17271709ff8dSJulian Wiedmann return rc; 17281709ff8dSJulian Wiedmann 172965b0494eSJulian Wiedmann qports = &cmd->data.sbp.data.port_data; 1730b4d72c08SEugene Crosser if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) { 1731b4d72c08SEugene Crosser QETH_CARD_TEXT_(card, 2, "SBPs%04x", qports->entry_length); 17321709ff8dSJulian Wiedmann return -EINVAL; 1733b4d72c08SEugene Crosser } 1734b4d72c08SEugene Crosser /* first entry contains the state of the local port */ 1735b4d72c08SEugene Crosser if (qports->num_entries > 0) { 1736b4d72c08SEugene Crosser if (cbctl->data.qports.role) 1737b4d72c08SEugene Crosser *cbctl->data.qports.role = qports->entry[0].role; 1738b4d72c08SEugene Crosser if (cbctl->data.qports.state) 1739b4d72c08SEugene Crosser *cbctl->data.qports.state = qports->entry[0].state; 1740b4d72c08SEugene Crosser } 1741b4d72c08SEugene Crosser return 0; 1742b4d72c08SEugene Crosser } 1743b4d72c08SEugene Crosser 1744b4d72c08SEugene Crosser /** 1745b4d72c08SEugene Crosser * qeth_bridgeport_query_ports() - query local bridgeport status. 1746b4d72c08SEugene Crosser * @card: qeth_card structure pointer. 1747b4d72c08SEugene Crosser * @role: Role of the port: 0-none, 1-primary, 2-secondary. 1748b4d72c08SEugene Crosser * @state: State of the port: 0-inactive, 1-standby, 2-active. 1749b4d72c08SEugene Crosser * 1750b4d72c08SEugene Crosser * Returns negative errno-compatible error indication or 0 on success. 1751b4d72c08SEugene Crosser * 1752b4d72c08SEugene Crosser * 'role' and 'state' are not updated in case of hardware operation failure. 1753b4d72c08SEugene Crosser */ 1754b4d72c08SEugene Crosser int qeth_bridgeport_query_ports(struct qeth_card *card, 1755b4d72c08SEugene Crosser enum qeth_sbp_roles *role, enum qeth_sbp_states *state) 1756b4d72c08SEugene Crosser { 1757b4d72c08SEugene Crosser struct qeth_cmd_buffer *iob; 1758b4d72c08SEugene Crosser struct _qeth_sbp_cbctl cbctl = { 1759b4d72c08SEugene Crosser .data = { 1760b4d72c08SEugene Crosser .qports = { 1761b4d72c08SEugene Crosser .role = role, 1762b4d72c08SEugene Crosser .state = state, 1763b4d72c08SEugene Crosser }, 1764b4d72c08SEugene Crosser }, 1765b4d72c08SEugene Crosser }; 1766b4d72c08SEugene Crosser 1767b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brqports"); 1768b4d72c08SEugene Crosser if (!(card->options.sbp.supported_funcs & IPA_SBP_QUERY_BRIDGE_PORTS)) 1769b4d72c08SEugene Crosser return -EOPNOTSUPP; 1770d65626adSJulian Wiedmann iob = qeth_sbp_build_cmd(card, IPA_SBP_QUERY_BRIDGE_PORTS, 0); 17711aec42bcSThomas Richter if (!iob) 17721aec42bcSThomas Richter return -ENOMEM; 17731709ff8dSJulian Wiedmann 17741709ff8dSJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_ports_cb, 17751709ff8dSJulian Wiedmann &cbctl); 1776b4d72c08SEugene Crosser } 1777b4d72c08SEugene Crosser 1778b4d72c08SEugene Crosser static int qeth_bridgeport_set_cb(struct qeth_card *card, 1779b4d72c08SEugene Crosser struct qeth_reply *reply, unsigned long data) 1780b4d72c08SEugene Crosser { 1781b4d72c08SEugene Crosser struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data; 17821709ff8dSJulian Wiedmann 1783b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brsetrcb"); 17841709ff8dSJulian Wiedmann return qeth_bridgeport_makerc(card, cmd); 1785b4d72c08SEugene Crosser } 1786b4d72c08SEugene Crosser 1787b4d72c08SEugene Crosser /** 1788b4d72c08SEugene Crosser * qeth_bridgeport_setrole() - Assign primary role to the port. 1789b4d72c08SEugene Crosser * @card: qeth_card structure pointer. 1790b4d72c08SEugene Crosser * @role: Role to assign. 1791b4d72c08SEugene Crosser * 1792b4d72c08SEugene Crosser * Returns negative errno-compatible error indication or 0 on success. 1793b4d72c08SEugene Crosser */ 1794b4d72c08SEugene Crosser int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role) 1795b4d72c08SEugene Crosser { 1796b4d72c08SEugene Crosser struct qeth_cmd_buffer *iob; 1797b4d72c08SEugene Crosser enum qeth_ipa_sbp_cmd setcmd; 1798b9150461SJulian Wiedmann unsigned int cmdlength = 0; 1799b4d72c08SEugene Crosser 1800b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brsetrol"); 1801b4d72c08SEugene Crosser switch (role) { 1802b4d72c08SEugene Crosser case QETH_SBP_ROLE_NONE: 1803b4d72c08SEugene Crosser setcmd = IPA_SBP_RESET_BRIDGE_PORT_ROLE; 1804b4d72c08SEugene Crosser break; 1805b4d72c08SEugene Crosser case QETH_SBP_ROLE_PRIMARY: 1806b4d72c08SEugene Crosser setcmd = IPA_SBP_SET_PRIMARY_BRIDGE_PORT; 1807b9150461SJulian Wiedmann cmdlength = SBP_DATA_SIZEOF(set_primary); 1808b4d72c08SEugene Crosser break; 1809b4d72c08SEugene Crosser case QETH_SBP_ROLE_SECONDARY: 1810b4d72c08SEugene Crosser setcmd = IPA_SBP_SET_SECONDARY_BRIDGE_PORT; 1811b4d72c08SEugene Crosser break; 1812b4d72c08SEugene Crosser default: 1813b4d72c08SEugene Crosser return -EINVAL; 1814b4d72c08SEugene Crosser } 1815b4d72c08SEugene Crosser if (!(card->options.sbp.supported_funcs & setcmd)) 1816b4d72c08SEugene Crosser return -EOPNOTSUPP; 1817d65626adSJulian Wiedmann iob = qeth_sbp_build_cmd(card, setcmd, cmdlength); 18181aec42bcSThomas Richter if (!iob) 18191aec42bcSThomas Richter return -ENOMEM; 18201709ff8dSJulian Wiedmann 18211709ff8dSJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_bridgeport_set_cb, NULL); 1822b4d72c08SEugene Crosser } 1823b4d72c08SEugene Crosser 18249f48b9dbSEugene Crosser static void qeth_bridgeport_an_set_cb(void *priv, 1825a0138f59SAlexandra Winter struct chsc_pnso_naid_l2 *entry) 18269f48b9dbSEugene Crosser { 18279f48b9dbSEugene Crosser struct qeth_card *card = (struct qeth_card *)priv; 18289f48b9dbSEugene Crosser u8 code; 18299f48b9dbSEugene Crosser 18309f48b9dbSEugene Crosser code = IPA_ADDR_CHANGE_CODE_MACADDR; 1831a0138f59SAlexandra Winter if (entry->addr_lnid.lnid < VLAN_N_VID) 18329f48b9dbSEugene Crosser code |= IPA_ADDR_CHANGE_CODE_VLANID; 18339f48b9dbSEugene Crosser qeth_bridge_emit_host_event(card, anev_reg_unreg, code, 1834a0138f59SAlexandra Winter (struct net_if_token *)&entry->nit, 1835a0138f59SAlexandra Winter (struct mac_addr_lnid *)&entry->addr_lnid); 18369f48b9dbSEugene Crosser } 18379f48b9dbSEugene Crosser 18389f48b9dbSEugene Crosser /** 18399f48b9dbSEugene Crosser * qeth_bridgeport_an_set() - Enable or disable bridgeport address notification 18409f48b9dbSEugene Crosser * @card: qeth_card structure pointer. 18419f48b9dbSEugene Crosser * @enable: 0 - disable, non-zero - enable notifications 18429f48b9dbSEugene Crosser * 18439f48b9dbSEugene Crosser * Returns negative errno-compatible error indication or 0 on success. 18449f48b9dbSEugene Crosser * 18459f48b9dbSEugene Crosser * On enable, emits a series of address notifications udev events for all 18469f48b9dbSEugene Crosser * currently registered hosts. 18479f48b9dbSEugene Crosser */ 18489f48b9dbSEugene Crosser int qeth_bridgeport_an_set(struct qeth_card *card, int enable) 18499f48b9dbSEugene Crosser { 18509f48b9dbSEugene Crosser int rc; 18519f48b9dbSEugene Crosser 18529f48b9dbSEugene Crosser if (!card->options.sbp.supported_funcs) 18539f48b9dbSEugene Crosser return -EOPNOTSUPP; 18549f48b9dbSEugene Crosser 18559f48b9dbSEugene Crosser if (enable) { 18569f48b9dbSEugene Crosser qeth_bridge_emit_host_event(card, anev_reset, 0, NULL, NULL); 18579d6a569aSJulian Wiedmann qeth_l2_set_pnso_mode(card, QETH_PNSO_BRIDGEPORT); 18584fea49a7SAlexandra Winter rc = qeth_l2_pnso(card, PNSO_OC_NET_BRIDGE_INFO, 1, 18594fea49a7SAlexandra Winter qeth_bridgeport_an_set_cb, card); 18609d6a569aSJulian Wiedmann if (rc) 18619d6a569aSJulian Wiedmann qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE); 18629d6a569aSJulian Wiedmann } else { 18634fea49a7SAlexandra Winter rc = qeth_l2_pnso(card, PNSO_OC_NET_BRIDGE_INFO, 0, NULL, NULL); 18649d6a569aSJulian Wiedmann qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE); 18659d6a569aSJulian Wiedmann } 1866a0138f59SAlexandra Winter return rc; 18679f48b9dbSEugene Crosser } 18689f48b9dbSEugene Crosser 1869a45b3fafSHans Wippel /* VNIC Characteristics support */ 1870a45b3fafSHans Wippel 1871a45b3fafSHans Wippel /* handle VNICC IPA command return codes; convert to error codes */ 1872742d4d40SJulian Wiedmann static int qeth_l2_vnicc_makerc(struct qeth_card *card, u16 ipa_rc) 1873a45b3fafSHans Wippel { 1874a45b3fafSHans Wippel int rc; 1875a45b3fafSHans Wippel 1876a45b3fafSHans Wippel switch (ipa_rc) { 1877a45b3fafSHans Wippel case IPA_RC_SUCCESS: 1878a45b3fafSHans Wippel return ipa_rc; 1879a45b3fafSHans Wippel case IPA_RC_L2_UNSUPPORTED_CMD: 1880a45b3fafSHans Wippel case IPA_RC_NOTSUPP: 1881a45b3fafSHans Wippel rc = -EOPNOTSUPP; 1882a45b3fafSHans Wippel break; 1883a45b3fafSHans Wippel case IPA_RC_VNICC_OOSEQ: 1884a45b3fafSHans Wippel rc = -EALREADY; 1885a45b3fafSHans Wippel break; 1886a45b3fafSHans Wippel case IPA_RC_VNICC_VNICBP: 1887a45b3fafSHans Wippel rc = -EBUSY; 1888a45b3fafSHans Wippel break; 1889a45b3fafSHans Wippel case IPA_RC_L2_ADDR_TABLE_FULL: 1890a45b3fafSHans Wippel rc = -ENOSPC; 1891a45b3fafSHans Wippel break; 1892a45b3fafSHans Wippel case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: 1893a45b3fafSHans Wippel rc = -EACCES; 1894a45b3fafSHans Wippel break; 1895a45b3fafSHans Wippel default: 1896a45b3fafSHans Wippel rc = -EIO; 1897a45b3fafSHans Wippel } 1898a45b3fafSHans Wippel 1899a45b3fafSHans Wippel QETH_CARD_TEXT_(card, 2, "err%04x", ipa_rc); 1900a45b3fafSHans Wippel return rc; 1901a45b3fafSHans Wippel } 1902a45b3fafSHans Wippel 1903a45b3fafSHans Wippel /* generic VNICC request call back */ 1904a45b3fafSHans Wippel static int qeth_l2_vnicc_request_cb(struct qeth_card *card, 1905a45b3fafSHans Wippel struct qeth_reply *reply, 1906a45b3fafSHans Wippel unsigned long data) 1907a45b3fafSHans Wippel { 1908a45b3fafSHans Wippel struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; 1909a45b3fafSHans Wippel struct qeth_ipacmd_vnicc *rep = &cmd->data.vnicc; 19102744d811SJulian Wiedmann u32 sub_cmd = cmd->data.vnicc.hdr.sub_command; 1911a45b3fafSHans Wippel 1912a45b3fafSHans Wippel QETH_CARD_TEXT(card, 2, "vniccrcb"); 1913a45b3fafSHans Wippel if (cmd->hdr.return_code) 1914742d4d40SJulian Wiedmann return qeth_l2_vnicc_makerc(card, cmd->hdr.return_code); 1915a45b3fafSHans Wippel /* return results to caller */ 19162cfb4810SJulian Wiedmann card->options.vnicc.sup_chars = rep->vnicc_cmds.supported; 19172cfb4810SJulian Wiedmann card->options.vnicc.cur_chars = rep->vnicc_cmds.enabled; 1918a45b3fafSHans Wippel 19192744d811SJulian Wiedmann if (sub_cmd == IPA_VNICC_QUERY_CMDS) 192049f42f5dSJulian Wiedmann *(u32 *)reply->param = rep->data.query_cmds.sup_cmds; 19212744d811SJulian Wiedmann else if (sub_cmd == IPA_VNICC_GET_TIMEOUT) 192249f42f5dSJulian Wiedmann *(u32 *)reply->param = rep->data.getset_timeout.timeout; 1923349d13d5SHans Wippel 1924a45b3fafSHans Wippel return 0; 1925a45b3fafSHans Wippel } 1926a45b3fafSHans Wippel 19272cfb4810SJulian Wiedmann static struct qeth_cmd_buffer *qeth_l2_vnicc_build_cmd(struct qeth_card *card, 19282cfb4810SJulian Wiedmann u32 vnicc_cmd, 19292cfb4810SJulian Wiedmann unsigned int data_length) 1930a45b3fafSHans Wippel { 19312cfb4810SJulian Wiedmann struct qeth_ipacmd_vnicc_hdr *hdr; 1932a45b3fafSHans Wippel struct qeth_cmd_buffer *iob; 1933a45b3fafSHans Wippel 19342cfb4810SJulian Wiedmann iob = qeth_ipa_alloc_cmd(card, IPA_CMD_VNICC, QETH_PROT_NONE, 19352cfb4810SJulian Wiedmann data_length + 19362cfb4810SJulian Wiedmann offsetof(struct qeth_ipacmd_vnicc, data)); 1937a45b3fafSHans Wippel if (!iob) 19382cfb4810SJulian Wiedmann return NULL; 1939a45b3fafSHans Wippel 19402cfb4810SJulian Wiedmann hdr = &__ipa_cmd(iob)->data.vnicc.hdr; 19412cfb4810SJulian Wiedmann hdr->data_length = sizeof(*hdr) + data_length; 19422cfb4810SJulian Wiedmann hdr->sub_command = vnicc_cmd; 19432cfb4810SJulian Wiedmann return iob; 1944a45b3fafSHans Wippel } 1945a45b3fafSHans Wippel 1946a45b3fafSHans Wippel /* VNICC query VNIC characteristics request */ 1947a45b3fafSHans Wippel static int qeth_l2_vnicc_query_chars(struct qeth_card *card) 1948a45b3fafSHans Wippel { 19492cfb4810SJulian Wiedmann struct qeth_cmd_buffer *iob; 19502cfb4810SJulian Wiedmann 19512cfb4810SJulian Wiedmann QETH_CARD_TEXT(card, 2, "vniccqch"); 19522cfb4810SJulian Wiedmann iob = qeth_l2_vnicc_build_cmd(card, IPA_VNICC_QUERY_CHARS, 0); 19532cfb4810SJulian Wiedmann if (!iob) 19542cfb4810SJulian Wiedmann return -ENOMEM; 1955a45b3fafSHans Wippel 19562744d811SJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, NULL); 1957a45b3fafSHans Wippel } 1958a45b3fafSHans Wippel 1959caa1f0b1SHans Wippel /* VNICC query sub commands request */ 1960caa1f0b1SHans Wippel static int qeth_l2_vnicc_query_cmds(struct qeth_card *card, u32 vnic_char, 1961caa1f0b1SHans Wippel u32 *sup_cmds) 1962caa1f0b1SHans Wippel { 19632cfb4810SJulian Wiedmann struct qeth_cmd_buffer *iob; 19642cfb4810SJulian Wiedmann 19652cfb4810SJulian Wiedmann QETH_CARD_TEXT(card, 2, "vniccqcm"); 19662cfb4810SJulian Wiedmann iob = qeth_l2_vnicc_build_cmd(card, IPA_VNICC_QUERY_CMDS, 19672cfb4810SJulian Wiedmann VNICC_DATA_SIZEOF(query_cmds)); 19682cfb4810SJulian Wiedmann if (!iob) 19692cfb4810SJulian Wiedmann return -ENOMEM; 19702cfb4810SJulian Wiedmann 19712cfb4810SJulian Wiedmann __ipa_cmd(iob)->data.vnicc.data.query_cmds.vnic_char = vnic_char; 1972caa1f0b1SHans Wippel 197349f42f5dSJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, sup_cmds); 1974caa1f0b1SHans Wippel } 1975caa1f0b1SHans Wippel 1976caa1f0b1SHans Wippel /* VNICC enable/disable characteristic request */ 1977caa1f0b1SHans Wippel static int qeth_l2_vnicc_set_char(struct qeth_card *card, u32 vnic_char, 1978caa1f0b1SHans Wippel u32 cmd) 1979caa1f0b1SHans Wippel { 19802cfb4810SJulian Wiedmann struct qeth_cmd_buffer *iob; 19812cfb4810SJulian Wiedmann 19822cfb4810SJulian Wiedmann QETH_CARD_TEXT(card, 2, "vniccedc"); 19832cfb4810SJulian Wiedmann iob = qeth_l2_vnicc_build_cmd(card, cmd, VNICC_DATA_SIZEOF(set_char)); 19842cfb4810SJulian Wiedmann if (!iob) 19852cfb4810SJulian Wiedmann return -ENOMEM; 19862cfb4810SJulian Wiedmann 19872cfb4810SJulian Wiedmann __ipa_cmd(iob)->data.vnicc.data.set_char.vnic_char = vnic_char; 1988caa1f0b1SHans Wippel 19892744d811SJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, NULL); 1990caa1f0b1SHans Wippel } 1991caa1f0b1SHans Wippel 1992349d13d5SHans Wippel /* VNICC get/set timeout for characteristic request */ 1993349d13d5SHans Wippel static int qeth_l2_vnicc_getset_timeout(struct qeth_card *card, u32 vnicc, 1994349d13d5SHans Wippel u32 cmd, u32 *timeout) 1995349d13d5SHans Wippel { 19962cfb4810SJulian Wiedmann struct qeth_vnicc_getset_timeout *getset_timeout; 19972cfb4810SJulian Wiedmann struct qeth_cmd_buffer *iob; 19982cfb4810SJulian Wiedmann 19992cfb4810SJulian Wiedmann QETH_CARD_TEXT(card, 2, "vniccgst"); 20002cfb4810SJulian Wiedmann iob = qeth_l2_vnicc_build_cmd(card, cmd, 20012cfb4810SJulian Wiedmann VNICC_DATA_SIZEOF(getset_timeout)); 20022cfb4810SJulian Wiedmann if (!iob) 20032cfb4810SJulian Wiedmann return -ENOMEM; 20042cfb4810SJulian Wiedmann 20052cfb4810SJulian Wiedmann getset_timeout = &__ipa_cmd(iob)->data.vnicc.data.getset_timeout; 20062cfb4810SJulian Wiedmann getset_timeout->vnic_char = vnicc; 20072cfb4810SJulian Wiedmann 20082cfb4810SJulian Wiedmann if (cmd == IPA_VNICC_SET_TIMEOUT) 20092cfb4810SJulian Wiedmann getset_timeout->timeout = *timeout; 2010349d13d5SHans Wippel 201149f42f5dSJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, timeout); 2012349d13d5SHans Wippel } 2013349d13d5SHans Wippel 201458fa3575SJulian Wiedmann /* recover user timeout setting */ 201558fa3575SJulian Wiedmann static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc, 201658fa3575SJulian Wiedmann u32 *timeout) 201758fa3575SJulian Wiedmann { 201858fa3575SJulian Wiedmann if (card->options.vnicc.sup_chars & vnicc && 201958fa3575SJulian Wiedmann card->options.vnicc.getset_timeout_sup & vnicc && 202058fa3575SJulian Wiedmann !qeth_l2_vnicc_getset_timeout(card, vnicc, IPA_VNICC_SET_TIMEOUT, 202158fa3575SJulian Wiedmann timeout)) 202258fa3575SJulian Wiedmann return false; 202358fa3575SJulian Wiedmann *timeout = QETH_VNICC_DEFAULT_TIMEOUT; 202458fa3575SJulian Wiedmann return true; 202558fa3575SJulian Wiedmann } 202658fa3575SJulian Wiedmann 2027caa1f0b1SHans Wippel /* set current VNICC flag state; called from sysfs store function */ 2028caa1f0b1SHans Wippel int qeth_l2_vnicc_set_state(struct qeth_card *card, u32 vnicc, bool state) 2029caa1f0b1SHans Wippel { 2030caa1f0b1SHans Wippel int rc = 0; 2031caa1f0b1SHans Wippel u32 cmd; 2032caa1f0b1SHans Wippel 2033caa1f0b1SHans Wippel QETH_CARD_TEXT(card, 2, "vniccsch"); 2034caa1f0b1SHans Wippel 2035caa1f0b1SHans Wippel /* check if characteristic and enable/disable are supported */ 2036caa1f0b1SHans Wippel if (!(card->options.vnicc.sup_chars & vnicc) || 2037caa1f0b1SHans Wippel !(card->options.vnicc.set_char_sup & vnicc)) 2038caa1f0b1SHans Wippel return -EOPNOTSUPP; 2039caa1f0b1SHans Wippel 20406f3846f0SAlexandra Winter if (qeth_bridgeport_is_in_use(card)) 20416f3846f0SAlexandra Winter return -EBUSY; 20426f3846f0SAlexandra Winter 2043caa1f0b1SHans Wippel /* set enable/disable command and store wanted characteristic */ 2044caa1f0b1SHans Wippel if (state) { 2045caa1f0b1SHans Wippel cmd = IPA_VNICC_ENABLE; 2046caa1f0b1SHans Wippel card->options.vnicc.wanted_chars |= vnicc; 2047caa1f0b1SHans Wippel } else { 2048caa1f0b1SHans Wippel cmd = IPA_VNICC_DISABLE; 2049caa1f0b1SHans Wippel card->options.vnicc.wanted_chars &= ~vnicc; 2050caa1f0b1SHans Wippel } 2051caa1f0b1SHans Wippel 2052caa1f0b1SHans Wippel /* do we need to do anything? */ 2053caa1f0b1SHans Wippel if (card->options.vnicc.cur_chars == card->options.vnicc.wanted_chars) 2054caa1f0b1SHans Wippel return rc; 2055caa1f0b1SHans Wippel 2056caa1f0b1SHans Wippel /* if card is not ready, simply stop here */ 2057caa1f0b1SHans Wippel if (!qeth_card_hw_is_reachable(card)) { 2058caa1f0b1SHans Wippel if (state) 2059caa1f0b1SHans Wippel card->options.vnicc.cur_chars |= vnicc; 2060caa1f0b1SHans Wippel else 2061caa1f0b1SHans Wippel card->options.vnicc.cur_chars &= ~vnicc; 2062caa1f0b1SHans Wippel return rc; 2063caa1f0b1SHans Wippel } 2064caa1f0b1SHans Wippel 2065caa1f0b1SHans Wippel rc = qeth_l2_vnicc_set_char(card, vnicc, cmd); 2066caa1f0b1SHans Wippel if (rc) 2067caa1f0b1SHans Wippel card->options.vnicc.wanted_chars = 2068caa1f0b1SHans Wippel card->options.vnicc.cur_chars; 2069349d13d5SHans Wippel else { 2070349d13d5SHans Wippel /* successful online VNICC change; handle special cases */ 2071349d13d5SHans Wippel if (state && vnicc == QETH_VNICC_RX_BCAST) 2072caa1f0b1SHans Wippel card->options.vnicc.rx_bcast_enabled = true; 2073349d13d5SHans Wippel if (!state && vnicc == QETH_VNICC_LEARNING) 2074349d13d5SHans Wippel qeth_l2_vnicc_recover_timeout(card, vnicc, 2075349d13d5SHans Wippel &card->options.vnicc.learning_timeout); 2076349d13d5SHans Wippel } 2077caa1f0b1SHans Wippel 2078caa1f0b1SHans Wippel return rc; 2079caa1f0b1SHans Wippel } 2080caa1f0b1SHans Wippel 2081caa1f0b1SHans Wippel /* get current VNICC flag state; called from sysfs show function */ 2082caa1f0b1SHans Wippel int qeth_l2_vnicc_get_state(struct qeth_card *card, u32 vnicc, bool *state) 2083caa1f0b1SHans Wippel { 2084caa1f0b1SHans Wippel int rc = 0; 2085caa1f0b1SHans Wippel 2086caa1f0b1SHans Wippel QETH_CARD_TEXT(card, 2, "vniccgch"); 2087caa1f0b1SHans Wippel 2088caa1f0b1SHans Wippel /* check if characteristic is supported */ 2089caa1f0b1SHans Wippel if (!(card->options.vnicc.sup_chars & vnicc)) 2090caa1f0b1SHans Wippel return -EOPNOTSUPP; 2091caa1f0b1SHans Wippel 20926f3846f0SAlexandra Winter if (qeth_bridgeport_is_in_use(card)) 20936f3846f0SAlexandra Winter return -EBUSY; 20946f3846f0SAlexandra Winter 2095caa1f0b1SHans Wippel /* if card is ready, query current VNICC state */ 2096caa1f0b1SHans Wippel if (qeth_card_hw_is_reachable(card)) 2097caa1f0b1SHans Wippel rc = qeth_l2_vnicc_query_chars(card); 2098caa1f0b1SHans Wippel 2099caa1f0b1SHans Wippel *state = (card->options.vnicc.cur_chars & vnicc) ? true : false; 2100caa1f0b1SHans Wippel return rc; 2101caa1f0b1SHans Wippel } 2102caa1f0b1SHans Wippel 2103349d13d5SHans Wippel /* set VNICC timeout; called from sysfs store function. Currently, only learning 2104349d13d5SHans Wippel * supports timeout 2105349d13d5SHans Wippel */ 2106349d13d5SHans Wippel int qeth_l2_vnicc_set_timeout(struct qeth_card *card, u32 timeout) 2107349d13d5SHans Wippel { 2108349d13d5SHans Wippel int rc = 0; 2109349d13d5SHans Wippel 2110349d13d5SHans Wippel QETH_CARD_TEXT(card, 2, "vniccsto"); 2111349d13d5SHans Wippel 2112349d13d5SHans Wippel /* check if characteristic and set_timeout are supported */ 2113349d13d5SHans Wippel if (!(card->options.vnicc.sup_chars & QETH_VNICC_LEARNING) || 2114349d13d5SHans Wippel !(card->options.vnicc.getset_timeout_sup & QETH_VNICC_LEARNING)) 2115349d13d5SHans Wippel return -EOPNOTSUPP; 2116349d13d5SHans Wippel 21176f3846f0SAlexandra Winter if (qeth_bridgeport_is_in_use(card)) 21186f3846f0SAlexandra Winter return -EBUSY; 21196f3846f0SAlexandra Winter 2120349d13d5SHans Wippel /* do we need to do anything? */ 2121349d13d5SHans Wippel if (card->options.vnicc.learning_timeout == timeout) 2122349d13d5SHans Wippel return rc; 2123349d13d5SHans Wippel 2124349d13d5SHans Wippel /* if card is not ready, simply store the value internally and return */ 2125349d13d5SHans Wippel if (!qeth_card_hw_is_reachable(card)) { 2126349d13d5SHans Wippel card->options.vnicc.learning_timeout = timeout; 2127349d13d5SHans Wippel return rc; 2128349d13d5SHans Wippel } 2129349d13d5SHans Wippel 2130349d13d5SHans Wippel /* send timeout value to card; if successful, store value internally */ 2131349d13d5SHans Wippel rc = qeth_l2_vnicc_getset_timeout(card, QETH_VNICC_LEARNING, 2132349d13d5SHans Wippel IPA_VNICC_SET_TIMEOUT, &timeout); 2133349d13d5SHans Wippel if (!rc) 2134349d13d5SHans Wippel card->options.vnicc.learning_timeout = timeout; 2135349d13d5SHans Wippel 2136349d13d5SHans Wippel return rc; 2137349d13d5SHans Wippel } 2138349d13d5SHans Wippel 2139349d13d5SHans Wippel /* get current VNICC timeout; called from sysfs show function. Currently, only 2140349d13d5SHans Wippel * learning supports timeout 2141349d13d5SHans Wippel */ 2142349d13d5SHans Wippel int qeth_l2_vnicc_get_timeout(struct qeth_card *card, u32 *timeout) 2143349d13d5SHans Wippel { 2144349d13d5SHans Wippel int rc = 0; 2145349d13d5SHans Wippel 2146349d13d5SHans Wippel QETH_CARD_TEXT(card, 2, "vniccgto"); 2147349d13d5SHans Wippel 2148349d13d5SHans Wippel /* check if characteristic and get_timeout are supported */ 2149349d13d5SHans Wippel if (!(card->options.vnicc.sup_chars & QETH_VNICC_LEARNING) || 2150349d13d5SHans Wippel !(card->options.vnicc.getset_timeout_sup & QETH_VNICC_LEARNING)) 2151349d13d5SHans Wippel return -EOPNOTSUPP; 21526f3846f0SAlexandra Winter 21536f3846f0SAlexandra Winter if (qeth_bridgeport_is_in_use(card)) 21546f3846f0SAlexandra Winter return -EBUSY; 21556f3846f0SAlexandra Winter 2156349d13d5SHans Wippel /* if card is ready, get timeout. Otherwise, just return stored value */ 2157349d13d5SHans Wippel *timeout = card->options.vnicc.learning_timeout; 2158349d13d5SHans Wippel if (qeth_card_hw_is_reachable(card)) 2159349d13d5SHans Wippel rc = qeth_l2_vnicc_getset_timeout(card, QETH_VNICC_LEARNING, 2160349d13d5SHans Wippel IPA_VNICC_GET_TIMEOUT, 2161349d13d5SHans Wippel timeout); 2162349d13d5SHans Wippel 2163349d13d5SHans Wippel return rc; 2164349d13d5SHans Wippel } 2165349d13d5SHans Wippel 2166caa1f0b1SHans Wippel /* check if VNICC is currently enabled */ 2167817741a8SAlexandra Winter static bool _qeth_l2_vnicc_is_in_use(struct qeth_card *card) 2168caa1f0b1SHans Wippel { 2169e8a66d80SAlexandra Winter if (!card->options.vnicc.sup_chars) 2170caa1f0b1SHans Wippel return false; 2171caa1f0b1SHans Wippel /* default values are only OK if rx_bcast was not enabled by user 2172caa1f0b1SHans Wippel * or the card is offline. 2173caa1f0b1SHans Wippel */ 2174caa1f0b1SHans Wippel if (card->options.vnicc.cur_chars == QETH_VNICC_DEFAULT) { 2175caa1f0b1SHans Wippel if (!card->options.vnicc.rx_bcast_enabled || 2176caa1f0b1SHans Wippel !qeth_card_hw_is_reachable(card)) 2177caa1f0b1SHans Wippel return false; 2178caa1f0b1SHans Wippel } 2179caa1f0b1SHans Wippel return true; 2180caa1f0b1SHans Wippel } 2181caa1f0b1SHans Wippel 2182817741a8SAlexandra Winter /** 2183817741a8SAlexandra Winter * qeth_bridgeport_allowed - are any qeth_bridgeport functions allowed? 2184817741a8SAlexandra Winter * @card: qeth_card structure pointer 2185817741a8SAlexandra Winter * 2186817741a8SAlexandra Winter * qeth_bridgeport functionality is mutually exclusive with usage of the 2187817741a8SAlexandra Winter * VNIC Characteristics and dev2br address notifications 2188817741a8SAlexandra Winter */ 2189817741a8SAlexandra Winter bool qeth_bridgeport_allowed(struct qeth_card *card) 2190817741a8SAlexandra Winter { 2191817741a8SAlexandra Winter struct qeth_priv *priv = netdev_priv(card->dev); 2192817741a8SAlexandra Winter 2193817741a8SAlexandra Winter return (!_qeth_l2_vnicc_is_in_use(card) && 2194817741a8SAlexandra Winter !(priv->brport_features & BR_LEARNING_SYNC)); 2195817741a8SAlexandra Winter } 2196817741a8SAlexandra Winter 2197caa1f0b1SHans Wippel /* recover user characteristic setting */ 2198caa1f0b1SHans Wippel static bool qeth_l2_vnicc_recover_char(struct qeth_card *card, u32 vnicc, 2199caa1f0b1SHans Wippel bool enable) 2200caa1f0b1SHans Wippel { 2201caa1f0b1SHans Wippel u32 cmd = enable ? IPA_VNICC_ENABLE : IPA_VNICC_DISABLE; 2202caa1f0b1SHans Wippel 2203caa1f0b1SHans Wippel if (card->options.vnicc.sup_chars & vnicc && 2204caa1f0b1SHans Wippel card->options.vnicc.set_char_sup & vnicc && 2205caa1f0b1SHans Wippel !qeth_l2_vnicc_set_char(card, vnicc, cmd)) 2206caa1f0b1SHans Wippel return false; 2207caa1f0b1SHans Wippel card->options.vnicc.wanted_chars &= ~vnicc; 2208caa1f0b1SHans Wippel card->options.vnicc.wanted_chars |= QETH_VNICC_DEFAULT & vnicc; 2209caa1f0b1SHans Wippel return true; 2210caa1f0b1SHans Wippel } 2211caa1f0b1SHans Wippel 2212a45b3fafSHans Wippel /* (re-)initialize VNICC */ 2213a45b3fafSHans Wippel static void qeth_l2_vnicc_init(struct qeth_card *card) 2214a45b3fafSHans Wippel { 2215349d13d5SHans Wippel u32 *timeout = &card->options.vnicc.learning_timeout; 2216b528965bSAlexandra Winter bool enable, error = false; 2217caa1f0b1SHans Wippel unsigned int chars_len, i; 2218caa1f0b1SHans Wippel unsigned long chars_tmp; 2219caa1f0b1SHans Wippel u32 sup_cmds, vnicc; 2220caa1f0b1SHans Wippel 2221a45b3fafSHans Wippel QETH_CARD_TEXT(card, 2, "vniccini"); 2222caa1f0b1SHans Wippel /* reset rx_bcast */ 2223caa1f0b1SHans Wippel card->options.vnicc.rx_bcast_enabled = 0; 2224a45b3fafSHans Wippel /* initial query and storage of VNIC characteristics */ 2225a45b3fafSHans Wippel if (qeth_l2_vnicc_query_chars(card)) { 2226349d13d5SHans Wippel if (card->options.vnicc.wanted_chars != QETH_VNICC_DEFAULT || 2227349d13d5SHans Wippel *timeout != QETH_VNICC_DEFAULT_TIMEOUT) 2228caa1f0b1SHans Wippel dev_err(&card->gdev->dev, "Configuring the VNIC characteristics failed\n"); 2229caa1f0b1SHans Wippel /* fail quietly if user didn't change the default config */ 2230a45b3fafSHans Wippel card->options.vnicc.sup_chars = 0; 2231a45b3fafSHans Wippel card->options.vnicc.cur_chars = 0; 2232caa1f0b1SHans Wippel card->options.vnicc.wanted_chars = QETH_VNICC_DEFAULT; 2233caa1f0b1SHans Wippel return; 2234a45b3fafSHans Wippel } 2235caa1f0b1SHans Wippel /* get supported commands for each supported characteristic */ 2236caa1f0b1SHans Wippel chars_tmp = card->options.vnicc.sup_chars; 2237caa1f0b1SHans Wippel chars_len = sizeof(card->options.vnicc.sup_chars) * BITS_PER_BYTE; 2238caa1f0b1SHans Wippel for_each_set_bit(i, &chars_tmp, chars_len) { 2239caa1f0b1SHans Wippel vnicc = BIT(i); 2240b528965bSAlexandra Winter if (qeth_l2_vnicc_query_cmds(card, vnicc, &sup_cmds)) { 2241b528965bSAlexandra Winter sup_cmds = 0; 2242b528965bSAlexandra Winter error = true; 2243b528965bSAlexandra Winter } 2244be40a86cSAlexandra Winter if ((sup_cmds & IPA_VNICC_SET_TIMEOUT) && 2245be40a86cSAlexandra Winter (sup_cmds & IPA_VNICC_GET_TIMEOUT)) 2246be40a86cSAlexandra Winter card->options.vnicc.getset_timeout_sup |= vnicc; 2247be40a86cSAlexandra Winter else 2248349d13d5SHans Wippel card->options.vnicc.getset_timeout_sup &= ~vnicc; 2249be40a86cSAlexandra Winter if ((sup_cmds & IPA_VNICC_ENABLE) && 2250be40a86cSAlexandra Winter (sup_cmds & IPA_VNICC_DISABLE)) 2251be40a86cSAlexandra Winter card->options.vnicc.set_char_sup |= vnicc; 2252be40a86cSAlexandra Winter else 2253caa1f0b1SHans Wippel card->options.vnicc.set_char_sup &= ~vnicc; 2254caa1f0b1SHans Wippel } 2255caa1f0b1SHans Wippel /* enforce assumed default values and recover settings, if changed */ 2256b528965bSAlexandra Winter error |= qeth_l2_vnicc_recover_timeout(card, QETH_VNICC_LEARNING, 2257349d13d5SHans Wippel timeout); 2258d1b9ae18SAlexandra Winter /* Change chars, if necessary */ 2259d1b9ae18SAlexandra Winter chars_tmp = card->options.vnicc.wanted_chars ^ 2260d1b9ae18SAlexandra Winter card->options.vnicc.cur_chars; 2261caa1f0b1SHans Wippel chars_len = sizeof(card->options.vnicc.wanted_chars) * BITS_PER_BYTE; 2262caa1f0b1SHans Wippel for_each_set_bit(i, &chars_tmp, chars_len) { 2263caa1f0b1SHans Wippel vnicc = BIT(i); 2264caa1f0b1SHans Wippel enable = card->options.vnicc.wanted_chars & vnicc; 2265caa1f0b1SHans Wippel error |= qeth_l2_vnicc_recover_char(card, vnicc, enable); 2266caa1f0b1SHans Wippel } 2267caa1f0b1SHans Wippel if (error) 2268caa1f0b1SHans Wippel dev_err(&card->gdev->dev, "Configuring the VNIC characteristics failed\n"); 2269caa1f0b1SHans Wippel } 2270caa1f0b1SHans Wippel 2271caa1f0b1SHans Wippel /* configure default values of VNIC characteristics */ 2272caa1f0b1SHans Wippel static void qeth_l2_vnicc_set_defaults(struct qeth_card *card) 2273caa1f0b1SHans Wippel { 2274caa1f0b1SHans Wippel /* characteristics values */ 2275caa1f0b1SHans Wippel card->options.vnicc.sup_chars = QETH_VNICC_ALL; 2276caa1f0b1SHans Wippel card->options.vnicc.cur_chars = QETH_VNICC_DEFAULT; 2277349d13d5SHans Wippel card->options.vnicc.learning_timeout = QETH_VNICC_DEFAULT_TIMEOUT; 2278caa1f0b1SHans Wippel /* supported commands */ 2279caa1f0b1SHans Wippel card->options.vnicc.set_char_sup = QETH_VNICC_ALL; 2280349d13d5SHans Wippel card->options.vnicc.getset_timeout_sup = QETH_VNICC_LEARNING; 2281caa1f0b1SHans Wippel /* settings wanted by users */ 2282caa1f0b1SHans Wippel card->options.vnicc.wanted_chars = QETH_VNICC_DEFAULT; 2283a45b3fafSHans Wippel } 2284a45b3fafSHans Wippel 228558fa3575SJulian Wiedmann static const struct device_type qeth_l2_devtype = { 228658fa3575SJulian Wiedmann .name = "qeth_layer2", 228758fa3575SJulian Wiedmann .groups = qeth_l2_attr_groups, 228858fa3575SJulian Wiedmann }; 228958fa3575SJulian Wiedmann 229058fa3575SJulian Wiedmann static int qeth_l2_probe_device(struct ccwgroup_device *gdev) 229158fa3575SJulian Wiedmann { 229258fa3575SJulian Wiedmann struct qeth_card *card = dev_get_drvdata(&gdev->dev); 229358fa3575SJulian Wiedmann int rc; 229458fa3575SJulian Wiedmann 229558fa3575SJulian Wiedmann qeth_l2_vnicc_set_defaults(card); 229658fa3575SJulian Wiedmann mutex_init(&card->sbp_lock); 229758fa3575SJulian Wiedmann 2298ae57ea7aSJulian Wiedmann if (gdev->dev.type) { 22990b8da811SJulian Wiedmann rc = device_add_groups(&gdev->dev, qeth_l2_attr_groups); 230058fa3575SJulian Wiedmann if (rc) 230158fa3575SJulian Wiedmann return rc; 2302ae57ea7aSJulian Wiedmann } else { 2303ae57ea7aSJulian Wiedmann gdev->dev.type = &qeth_l2_devtype; 230458fa3575SJulian Wiedmann } 230558fa3575SJulian Wiedmann 230658fa3575SJulian Wiedmann INIT_WORK(&card->rx_mode_work, qeth_l2_rx_mode_work); 230758fa3575SJulian Wiedmann return 0; 230858fa3575SJulian Wiedmann } 230958fa3575SJulian Wiedmann 231058fa3575SJulian Wiedmann static void qeth_l2_remove_device(struct ccwgroup_device *gdev) 231158fa3575SJulian Wiedmann { 231258fa3575SJulian Wiedmann struct qeth_card *card = dev_get_drvdata(&gdev->dev); 231360bb1089SAlexandra Winter struct qeth_priv *priv; 231458fa3575SJulian Wiedmann 2315ae57ea7aSJulian Wiedmann if (gdev->dev.type != &qeth_l2_devtype) 23160b8da811SJulian Wiedmann device_remove_groups(&gdev->dev, qeth_l2_attr_groups); 2317ae57ea7aSJulian Wiedmann 231858fa3575SJulian Wiedmann qeth_set_allowed_threads(card, 0, 1); 231958fa3575SJulian Wiedmann wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); 232058fa3575SJulian Wiedmann 2321b41b554cSJulian Wiedmann if (gdev->state == CCWGROUP_ONLINE) 23220b9902c1SJulian Wiedmann qeth_set_offline(card, card->discipline, false); 232358fa3575SJulian Wiedmann 232460bb1089SAlexandra Winter if (card->dev->reg_state == NETREG_REGISTERED) { 232560bb1089SAlexandra Winter priv = netdev_priv(card->dev); 232660bb1089SAlexandra Winter if (priv->brport_features & BR_LEARNING_SYNC) { 232760bb1089SAlexandra Winter rtnl_lock(); 232860bb1089SAlexandra Winter qeth_l2_br2dev_put(); 232960bb1089SAlexandra Winter rtnl_unlock(); 233060bb1089SAlexandra Winter } 233158fa3575SJulian Wiedmann unregister_netdev(card->dev); 233258fa3575SJulian Wiedmann } 233360bb1089SAlexandra Winter } 233458fa3575SJulian Wiedmann 233558fa3575SJulian Wiedmann static int qeth_l2_set_online(struct qeth_card *card, bool carrier_ok) 233658fa3575SJulian Wiedmann { 233758fa3575SJulian Wiedmann struct net_device *dev = card->dev; 233858fa3575SJulian Wiedmann int rc = 0; 233958fa3575SJulian Wiedmann 234058fa3575SJulian Wiedmann qeth_l2_detect_dev2br_support(card); 234158fa3575SJulian Wiedmann 234258fa3575SJulian Wiedmann mutex_lock(&card->sbp_lock); 234358fa3575SJulian Wiedmann qeth_bridgeport_query_support(card); 234458fa3575SJulian Wiedmann if (card->options.sbp.supported_funcs) { 234558fa3575SJulian Wiedmann qeth_l2_setup_bridgeport_attrs(card); 234658fa3575SJulian Wiedmann dev_info(&card->gdev->dev, 234758fa3575SJulian Wiedmann "The device represents a Bridge Capable Port\n"); 234858fa3575SJulian Wiedmann } 234958fa3575SJulian Wiedmann mutex_unlock(&card->sbp_lock); 235058fa3575SJulian Wiedmann 235158fa3575SJulian Wiedmann qeth_l2_register_dev_addr(card); 235258fa3575SJulian Wiedmann 235358fa3575SJulian Wiedmann /* for the rx_bcast characteristic, init VNICC after setmac */ 235458fa3575SJulian Wiedmann qeth_l2_vnicc_init(card); 235558fa3575SJulian Wiedmann 235658fa3575SJulian Wiedmann qeth_l2_trace_features(card); 235758fa3575SJulian Wiedmann 235858fa3575SJulian Wiedmann /* softsetup */ 235958fa3575SJulian Wiedmann QETH_CARD_TEXT(card, 2, "softsetp"); 236058fa3575SJulian Wiedmann 236158fa3575SJulian Wiedmann card->state = CARD_STATE_SOFTSETUP; 236258fa3575SJulian Wiedmann 236358fa3575SJulian Wiedmann qeth_set_allowed_threads(card, 0xffffffff, 0); 236458fa3575SJulian Wiedmann 236558fa3575SJulian Wiedmann if (dev->reg_state != NETREG_REGISTERED) { 236658fa3575SJulian Wiedmann rc = qeth_l2_setup_netdev(card); 236758fa3575SJulian Wiedmann if (rc) 236858fa3575SJulian Wiedmann goto err_setup; 236958fa3575SJulian Wiedmann 237058fa3575SJulian Wiedmann if (carrier_ok) 237158fa3575SJulian Wiedmann netif_carrier_on(dev); 237258fa3575SJulian Wiedmann } else { 237358fa3575SJulian Wiedmann rtnl_lock(); 2374bb5ab541SJulian Wiedmann rc = qeth_set_real_num_tx_queues(card, 2375bb5ab541SJulian Wiedmann qeth_tx_actual_queues(card)); 2376bb5ab541SJulian Wiedmann if (rc) { 2377bb5ab541SJulian Wiedmann rtnl_unlock(); 2378bb5ab541SJulian Wiedmann goto err_set_queues; 2379bb5ab541SJulian Wiedmann } 2380bb5ab541SJulian Wiedmann 238158fa3575SJulian Wiedmann if (carrier_ok) 238258fa3575SJulian Wiedmann netif_carrier_on(dev); 238358fa3575SJulian Wiedmann else 238458fa3575SJulian Wiedmann netif_carrier_off(dev); 238558fa3575SJulian Wiedmann 238658fa3575SJulian Wiedmann netif_device_attach(dev); 238758fa3575SJulian Wiedmann qeth_enable_hw_features(dev); 238858fa3575SJulian Wiedmann qeth_l2_enable_brport_features(card); 238958fa3575SJulian Wiedmann 239058fa3575SJulian Wiedmann if (card->info.open_when_online) { 239158fa3575SJulian Wiedmann card->info.open_when_online = 0; 239258fa3575SJulian Wiedmann dev_open(dev, NULL); 239358fa3575SJulian Wiedmann } 239458fa3575SJulian Wiedmann rtnl_unlock(); 239558fa3575SJulian Wiedmann } 239658fa3575SJulian Wiedmann return 0; 239758fa3575SJulian Wiedmann 2398bb5ab541SJulian Wiedmann err_set_queues: 239958fa3575SJulian Wiedmann err_setup: 240058fa3575SJulian Wiedmann qeth_set_allowed_threads(card, 0, 1); 240158fa3575SJulian Wiedmann card->state = CARD_STATE_DOWN; 240258fa3575SJulian Wiedmann return rc; 240358fa3575SJulian Wiedmann } 240458fa3575SJulian Wiedmann 240558fa3575SJulian Wiedmann static void qeth_l2_set_offline(struct qeth_card *card) 240658fa3575SJulian Wiedmann { 240758fa3575SJulian Wiedmann struct qeth_priv *priv = netdev_priv(card->dev); 240858fa3575SJulian Wiedmann 240958fa3575SJulian Wiedmann qeth_set_allowed_threads(card, 0, 1); 241058fa3575SJulian Wiedmann qeth_l2_drain_rx_mode_cache(card); 241158fa3575SJulian Wiedmann 241258fa3575SJulian Wiedmann if (card->state == CARD_STATE_SOFTSETUP) 241358fa3575SJulian Wiedmann card->state = CARD_STATE_DOWN; 241458fa3575SJulian Wiedmann 241558fa3575SJulian Wiedmann qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE); 241609840f70SJulian Wiedmann if (priv->brport_features & BR_LEARNING_SYNC) 241758fa3575SJulian Wiedmann qeth_l2_dev2br_fdb_flush(card); 241858fa3575SJulian Wiedmann } 241958fa3575SJulian Wiedmann 242058fa3575SJulian Wiedmann /* Returns zero if the command is successfully "consumed" */ 242158fa3575SJulian Wiedmann static int qeth_l2_control_event(struct qeth_card *card, 242258fa3575SJulian Wiedmann struct qeth_ipa_cmd *cmd) 242358fa3575SJulian Wiedmann { 242458fa3575SJulian Wiedmann switch (cmd->hdr.command) { 242558fa3575SJulian Wiedmann case IPA_CMD_SETBRIDGEPORT_OSA: 242658fa3575SJulian Wiedmann case IPA_CMD_SETBRIDGEPORT_IQD: 242758fa3575SJulian Wiedmann if (cmd->data.sbp.hdr.command_code == 242858fa3575SJulian Wiedmann IPA_SBP_BRIDGE_PORT_STATE_CHANGE) { 242958fa3575SJulian Wiedmann qeth_bridge_state_change(card, cmd); 243058fa3575SJulian Wiedmann return 0; 243158fa3575SJulian Wiedmann } 243258fa3575SJulian Wiedmann 243358fa3575SJulian Wiedmann return 1; 243458fa3575SJulian Wiedmann case IPA_CMD_ADDRESS_CHANGE_NOTIF: 243558fa3575SJulian Wiedmann qeth_addr_change_event(card, cmd); 243658fa3575SJulian Wiedmann return 0; 243758fa3575SJulian Wiedmann default: 243858fa3575SJulian Wiedmann return 1; 243958fa3575SJulian Wiedmann } 244058fa3575SJulian Wiedmann } 244158fa3575SJulian Wiedmann 244250144f67SJulian Wiedmann const struct qeth_discipline qeth_l2_discipline = { 244358fa3575SJulian Wiedmann .setup = qeth_l2_probe_device, 244458fa3575SJulian Wiedmann .remove = qeth_l2_remove_device, 244558fa3575SJulian Wiedmann .set_online = qeth_l2_set_online, 244658fa3575SJulian Wiedmann .set_offline = qeth_l2_set_offline, 244758fa3575SJulian Wiedmann .control_event_handler = qeth_l2_control_event, 244858fa3575SJulian Wiedmann }; 244958fa3575SJulian Wiedmann EXPORT_SYMBOL_GPL(qeth_l2_discipline); 245058fa3575SJulian Wiedmann 245158fa3575SJulian Wiedmann static int __init qeth_l2_init(void) 245258fa3575SJulian Wiedmann { 245358fa3575SJulian Wiedmann pr_info("register layer 2 discipline\n"); 245460bb1089SAlexandra Winter refcount_set(&qeth_l2_switchdev_notify_refcnt, 0); 245558fa3575SJulian Wiedmann return 0; 245658fa3575SJulian Wiedmann } 245758fa3575SJulian Wiedmann 245858fa3575SJulian Wiedmann static void __exit qeth_l2_exit(void) 245958fa3575SJulian Wiedmann { 246058fa3575SJulian Wiedmann pr_info("unregister layer 2 discipline\n"); 246158fa3575SJulian Wiedmann } 246258fa3575SJulian Wiedmann 24634a71df50SFrank Blaschka module_init(qeth_l2_init); 24644a71df50SFrank Blaschka module_exit(qeth_l2_exit); 24654a71df50SFrank Blaschka MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>"); 24664a71df50SFrank Blaschka MODULE_DESCRIPTION("qeth layer 2 discipline"); 24674a71df50SFrank Blaschka MODULE_LICENSE("GPL"); 2468