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 31c044dc21SEugene Crosser static void qeth_bridgeport_query_support(struct qeth_card *card); 32c044dc21SEugene Crosser static void qeth_bridge_state_change(struct qeth_card *card, 33c044dc21SEugene Crosser struct qeth_ipa_cmd *cmd); 34a0138f59SAlexandra Winter static void qeth_addr_change_event(struct qeth_card *card, 35c044dc21SEugene Crosser struct qeth_ipa_cmd *cmd); 36caa1f0b1SHans Wippel static void qeth_l2_vnicc_set_defaults(struct qeth_card *card); 37a45b3fafSHans Wippel static void qeth_l2_vnicc_init(struct qeth_card *card); 38349d13d5SHans Wippel static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc, 39349d13d5SHans Wippel u32 *timeout); 404a71df50SFrank Blaschka 41742d4d40SJulian Wiedmann static int qeth_l2_setdelmac_makerc(struct qeth_card *card, u16 retcode) 424a71df50SFrank Blaschka { 43efbbc1d5SEugene Crosser int rc; 444a71df50SFrank Blaschka 45efbbc1d5SEugene Crosser if (retcode) 461aec42bcSThomas Richter QETH_CARD_TEXT_(card, 2, "err%04x", retcode); 47efbbc1d5SEugene Crosser switch (retcode) { 48efbbc1d5SEugene Crosser case IPA_RC_SUCCESS: 49efbbc1d5SEugene Crosser rc = 0; 50efbbc1d5SEugene Crosser break; 51efbbc1d5SEugene Crosser case IPA_RC_L2_UNSUPPORTED_CMD: 52ffb95251SEugene Crosser rc = -EOPNOTSUPP; 53efbbc1d5SEugene Crosser break; 54efbbc1d5SEugene Crosser case IPA_RC_L2_ADDR_TABLE_FULL: 55efbbc1d5SEugene Crosser rc = -ENOSPC; 56efbbc1d5SEugene Crosser break; 57efbbc1d5SEugene Crosser case IPA_RC_L2_DUP_MAC: 58efbbc1d5SEugene Crosser case IPA_RC_L2_DUP_LAYER3_MAC: 59bdb0cc12SJulian Wiedmann rc = -EADDRINUSE; 60efbbc1d5SEugene Crosser break; 61efbbc1d5SEugene Crosser case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: 62efbbc1d5SEugene Crosser case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: 63bdb0cc12SJulian Wiedmann rc = -EADDRNOTAVAIL; 64efbbc1d5SEugene Crosser break; 65efbbc1d5SEugene Crosser case IPA_RC_L2_MAC_NOT_FOUND: 66efbbc1d5SEugene Crosser rc = -ENOENT; 67efbbc1d5SEugene Crosser break; 68efbbc1d5SEugene Crosser default: 69efbbc1d5SEugene Crosser rc = -EIO; 70efbbc1d5SEugene Crosser break; 714a71df50SFrank Blaschka } 72efbbc1d5SEugene Crosser return rc; 734a71df50SFrank Blaschka } 744a71df50SFrank Blaschka 75742d4d40SJulian Wiedmann static int qeth_l2_send_setdelmac_cb(struct qeth_card *card, 76742d4d40SJulian Wiedmann struct qeth_reply *reply, 77742d4d40SJulian Wiedmann unsigned long data) 78742d4d40SJulian Wiedmann { 79742d4d40SJulian Wiedmann struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; 80742d4d40SJulian Wiedmann 81742d4d40SJulian Wiedmann return qeth_l2_setdelmac_makerc(card, cmd->hdr.return_code); 82742d4d40SJulian Wiedmann } 83742d4d40SJulian Wiedmann 84ac988d78SJulian Wiedmann static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac, 85ac988d78SJulian Wiedmann enum qeth_ipa_cmds ipacmd) 86ac988d78SJulian Wiedmann { 87ac988d78SJulian Wiedmann struct qeth_ipa_cmd *cmd; 88ac988d78SJulian Wiedmann struct qeth_cmd_buffer *iob; 89ac988d78SJulian Wiedmann 90ac988d78SJulian Wiedmann QETH_CARD_TEXT(card, 2, "L2sdmac"); 91a59d121dSJulian Wiedmann iob = qeth_ipa_alloc_cmd(card, ipacmd, QETH_PROT_IPV4, 92a59d121dSJulian Wiedmann IPA_DATA_SIZEOF(setdelmac)); 93ac988d78SJulian Wiedmann if (!iob) 94ac988d78SJulian Wiedmann return -ENOMEM; 95ff5caa7aSJulian Wiedmann cmd = __ipa_cmd(iob); 9699f0b85dSJulian Wiedmann cmd->data.setdelmac.mac_length = ETH_ALEN; 9799f0b85dSJulian Wiedmann ether_addr_copy(cmd->data.setdelmac.mac, mac); 98742d4d40SJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_l2_send_setdelmac_cb, NULL); 99ac988d78SJulian Wiedmann } 100ac988d78SJulian Wiedmann 101ac988d78SJulian Wiedmann static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac) 102ac988d78SJulian Wiedmann { 103ac988d78SJulian Wiedmann int rc; 104ac988d78SJulian Wiedmann 105ac988d78SJulian Wiedmann QETH_CARD_TEXT(card, 2, "L2Setmac"); 106ac988d78SJulian Wiedmann rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC); 107ac988d78SJulian Wiedmann if (rc == 0) { 108ac988d78SJulian Wiedmann dev_info(&card->gdev->dev, 109654e3d48SJulian Wiedmann "MAC address %pM successfully registered\n", mac); 110ac988d78SJulian Wiedmann } else { 111ac988d78SJulian Wiedmann switch (rc) { 112bdb0cc12SJulian Wiedmann case -EADDRINUSE: 113ac988d78SJulian Wiedmann dev_warn(&card->gdev->dev, 114ac988d78SJulian Wiedmann "MAC address %pM already exists\n", mac); 115ac988d78SJulian Wiedmann break; 116bdb0cc12SJulian Wiedmann case -EADDRNOTAVAIL: 117ac988d78SJulian Wiedmann dev_warn(&card->gdev->dev, 118ac988d78SJulian Wiedmann "MAC address %pM is not authorized\n", mac); 119ac988d78SJulian Wiedmann break; 120ac988d78SJulian Wiedmann } 121ac988d78SJulian Wiedmann } 122ac988d78SJulian Wiedmann return rc; 123ac988d78SJulian Wiedmann } 124ac988d78SJulian Wiedmann 1258174aa8aSJulian Wiedmann static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac) 1264a71df50SFrank Blaschka { 1279d0a58fbSVasily Gorbik enum qeth_ipa_cmds cmd = is_multicast_ether_addr(mac) ? 1288174aa8aSJulian Wiedmann IPA_CMD_SETGMAC : IPA_CMD_SETVMAC; 129efbbc1d5SEugene Crosser int rc; 130efbbc1d5SEugene Crosser 1318174aa8aSJulian Wiedmann QETH_CARD_TEXT(card, 2, "L2Wmac"); 1328174aa8aSJulian Wiedmann rc = qeth_l2_send_setdelmac(card, mac, cmd); 133bdb0cc12SJulian Wiedmann if (rc == -EADDRINUSE) 134e19e5be8SJulian Wiedmann QETH_DBF_MESSAGE(2, "MAC already registered on device %x\n", 135e19e5be8SJulian Wiedmann CARD_DEVID(card)); 136efbbc1d5SEugene Crosser else if (rc) 137e19e5be8SJulian Wiedmann QETH_DBF_MESSAGE(2, "Failed to register MAC on device %x: %d\n", 138e19e5be8SJulian Wiedmann CARD_DEVID(card), rc); 139efbbc1d5SEugene Crosser return rc; 1404a71df50SFrank Blaschka } 1414a71df50SFrank Blaschka 1428174aa8aSJulian Wiedmann static int qeth_l2_remove_mac(struct qeth_card *card, u8 *mac) 1434a71df50SFrank Blaschka { 1449d0a58fbSVasily Gorbik enum qeth_ipa_cmds cmd = is_multicast_ether_addr(mac) ? 1458174aa8aSJulian Wiedmann IPA_CMD_DELGMAC : IPA_CMD_DELVMAC; 146efbbc1d5SEugene Crosser int rc; 147efbbc1d5SEugene Crosser 1488174aa8aSJulian Wiedmann QETH_CARD_TEXT(card, 2, "L2Rmac"); 1498174aa8aSJulian Wiedmann rc = qeth_l2_send_setdelmac(card, mac, cmd); 150efbbc1d5SEugene Crosser if (rc) 151e19e5be8SJulian Wiedmann QETH_DBF_MESSAGE(2, "Failed to delete MAC on device %u: %d\n", 152e19e5be8SJulian Wiedmann CARD_DEVID(card), rc); 153efbbc1d5SEugene Crosser return rc; 1544a71df50SFrank Blaschka } 1554a71df50SFrank Blaschka 156d0c74825SJulian Wiedmann static void qeth_l2_drain_rx_mode_cache(struct qeth_card *card) 1574a71df50SFrank Blaschka { 158fe5c8028SLakhvich Dmitriy struct qeth_mac *mac; 159fe5c8028SLakhvich Dmitriy struct hlist_node *tmp; 160fe5c8028SLakhvich Dmitriy int i; 1614a71df50SFrank Blaschka 1620973292fSJulian Wiedmann hash_for_each_safe(card->rx_mode_addrs, i, tmp, mac, hnode) { 163fe5c8028SLakhvich Dmitriy hash_del(&mac->hnode); 164fe5c8028SLakhvich Dmitriy kfree(mac); 1654a71df50SFrank Blaschka } 1664a71df50SFrank Blaschka } 1674a71df50SFrank Blaschka 168b0abc4f5SJulian Wiedmann static void qeth_l2_fill_header(struct qeth_qdio_out_q *queue, 169b0abc4f5SJulian Wiedmann struct qeth_hdr *hdr, struct sk_buff *skb, 170eca1d5c2SJulian Wiedmann int ipv, unsigned int data_len) 1714a71df50SFrank Blaschka { 172eca1d5c2SJulian Wiedmann int cast_type = qeth_get_ether_cast_type(skb); 1730aef8392SJulian Wiedmann struct vlan_ethhdr *veth = vlan_eth_hdr(skb); 1744a71df50SFrank Blaschka 175ae79fe03SJulian Wiedmann hdr->hdr.l2.pkt_length = data_len; 1764a71df50SFrank Blaschka 1770aef8392SJulian Wiedmann if (skb_is_gso(skb)) { 1780aef8392SJulian Wiedmann hdr->hdr.l2.id = QETH_HEADER_TYPE_L2_TSO; 1790aef8392SJulian Wiedmann } else { 1800aef8392SJulian Wiedmann hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; 181eeac0e20SJulian Wiedmann if (skb->ip_summed == CHECKSUM_PARTIAL) 182fc69660bSJulian Wiedmann qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], ipv); 1830aef8392SJulian Wiedmann } 184fc69660bSJulian Wiedmann 1854a71df50SFrank Blaschka /* set byte byte 3 to casting flags */ 1864a71df50SFrank Blaschka if (cast_type == RTN_MULTICAST) 1874a71df50SFrank Blaschka hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_MULTICAST; 1884a71df50SFrank Blaschka else if (cast_type == RTN_BROADCAST) 1894a71df50SFrank Blaschka hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_BROADCAST; 1904a71df50SFrank Blaschka else 191ce73e10eSKlaus-Dieter Wacker hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_UNICAST; 1924a71df50SFrank Blaschka 1934a71df50SFrank Blaschka /* VSWITCH relies on the VLAN 1944a71df50SFrank Blaschka * information to be present in 1954a71df50SFrank Blaschka * the QDIO header */ 1964a71df50SFrank Blaschka if (veth->h_vlan_proto == __constant_htons(ETH_P_8021Q)) { 1974a71df50SFrank Blaschka hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_VLAN; 1984a71df50SFrank Blaschka hdr->hdr.l2.vlan_id = ntohs(veth->h_vlan_TCI); 1994a71df50SFrank Blaschka } 2004a71df50SFrank Blaschka } 2014a71df50SFrank Blaschka 202742d4d40SJulian Wiedmann static int qeth_l2_setdelvlan_makerc(struct qeth_card *card, u16 retcode) 2034a71df50SFrank Blaschka { 2042aa48671SJulian Wiedmann if (retcode) 2052aa48671SJulian Wiedmann QETH_CARD_TEXT_(card, 2, "err%04x", retcode); 2062aa48671SJulian Wiedmann 2072aa48671SJulian Wiedmann switch (retcode) { 2082aa48671SJulian Wiedmann case IPA_RC_SUCCESS: 2092aa48671SJulian Wiedmann return 0; 2102aa48671SJulian Wiedmann case IPA_RC_L2_INVALID_VLAN_ID: 2112aa48671SJulian Wiedmann return -EINVAL; 2122aa48671SJulian Wiedmann case IPA_RC_L2_DUP_VLAN_ID: 2132aa48671SJulian Wiedmann return -EEXIST; 2142aa48671SJulian Wiedmann case IPA_RC_L2_VLAN_ID_NOT_FOUND: 2152aa48671SJulian Wiedmann return -ENOENT; 2162aa48671SJulian Wiedmann case IPA_RC_L2_VLAN_ID_NOT_ALLOWED: 2172aa48671SJulian Wiedmann return -EPERM; 2182aa48671SJulian Wiedmann default: 2192aa48671SJulian Wiedmann return -EIO; 2202aa48671SJulian Wiedmann } 2212aa48671SJulian Wiedmann } 2222aa48671SJulian Wiedmann 2232aa48671SJulian Wiedmann static int qeth_l2_send_setdelvlan_cb(struct qeth_card *card, 2242aa48671SJulian Wiedmann struct qeth_reply *reply, 2252aa48671SJulian Wiedmann unsigned long data) 2262aa48671SJulian Wiedmann { 2272aa48671SJulian Wiedmann struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; 2284a71df50SFrank Blaschka 229847a50fdSCarsten Otte QETH_CARD_TEXT(card, 2, "L2sdvcb"); 2304a71df50SFrank Blaschka if (cmd->hdr.return_code) { 231e19e5be8SJulian Wiedmann QETH_DBF_MESSAGE(2, "Error in processing VLAN %u on device %x: %#x.\n", 2322aa48671SJulian Wiedmann cmd->data.setdelvlan.vlan_id, 233e19e5be8SJulian Wiedmann CARD_DEVID(card), cmd->hdr.return_code); 234847a50fdSCarsten Otte QETH_CARD_TEXT_(card, 2, "L2VL%4x", cmd->hdr.command); 2354a71df50SFrank Blaschka } 236742d4d40SJulian Wiedmann return qeth_l2_setdelvlan_makerc(card, cmd->hdr.return_code); 2374a71df50SFrank Blaschka } 2384a71df50SFrank Blaschka 2394a71df50SFrank Blaschka static int qeth_l2_send_setdelvlan(struct qeth_card *card, __u16 i, 2404a71df50SFrank Blaschka enum qeth_ipa_cmds ipacmd) 2414a71df50SFrank Blaschka { 2424a71df50SFrank Blaschka struct qeth_ipa_cmd *cmd; 2434a71df50SFrank Blaschka struct qeth_cmd_buffer *iob; 2444a71df50SFrank Blaschka 245847a50fdSCarsten Otte QETH_CARD_TEXT_(card, 4, "L2sdv%x", ipacmd); 246a59d121dSJulian Wiedmann iob = qeth_ipa_alloc_cmd(card, ipacmd, QETH_PROT_IPV4, 247a59d121dSJulian Wiedmann IPA_DATA_SIZEOF(setdelvlan)); 2481aec42bcSThomas Richter if (!iob) 2491aec42bcSThomas Richter return -ENOMEM; 250ff5caa7aSJulian Wiedmann cmd = __ipa_cmd(iob); 2514a71df50SFrank Blaschka cmd->data.setdelvlan.vlan_id = i; 252742d4d40SJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_l2_send_setdelvlan_cb, NULL); 2534a71df50SFrank Blaschka } 2544a71df50SFrank Blaschka 25580d5c368SPatrick McHardy static int qeth_l2_vlan_rx_add_vid(struct net_device *dev, 25680d5c368SPatrick McHardy __be16 proto, u16 vid) 2574a71df50SFrank Blaschka { 258509e2562SHeiko Carstens struct qeth_card *card = dev->ml_priv; 2594a71df50SFrank Blaschka 260847a50fdSCarsten Otte QETH_CARD_TEXT_(card, 4, "aid:%d", vid); 26110651db7SUrsula Braun if (!vid) 2628e586137SJiri Pirko return 0; 263e6e771b3SJulian Wiedmann 2645fc692a7SJulian Wiedmann return qeth_l2_send_setdelvlan(card, vid, IPA_CMD_SETVLAN); 2654a71df50SFrank Blaschka } 2664a71df50SFrank Blaschka 26780d5c368SPatrick McHardy static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev, 26880d5c368SPatrick McHardy __be16 proto, u16 vid) 2694a71df50SFrank Blaschka { 270509e2562SHeiko Carstens struct qeth_card *card = dev->ml_priv; 2714a71df50SFrank Blaschka 272847a50fdSCarsten Otte QETH_CARD_TEXT_(card, 4, "kid:%d", vid); 2735fc692a7SJulian Wiedmann if (!vid) 2745fc692a7SJulian Wiedmann return 0; 275e6e771b3SJulian Wiedmann 2765fc692a7SJulian Wiedmann return qeth_l2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN); 2774a71df50SFrank Blaschka } 2784a71df50SFrank Blaschka 2799d6a569aSJulian Wiedmann static void qeth_l2_set_pnso_mode(struct qeth_card *card, 2809d6a569aSJulian Wiedmann enum qeth_pnso_mode mode) 2819d6a569aSJulian Wiedmann { 2829d6a569aSJulian Wiedmann spin_lock_irq(get_ccwdev_lock(CARD_RDEV(card))); 2839d6a569aSJulian Wiedmann WRITE_ONCE(card->info.pnso_mode, mode); 2849d6a569aSJulian Wiedmann spin_unlock_irq(get_ccwdev_lock(CARD_RDEV(card))); 2859d6a569aSJulian Wiedmann 2869d6a569aSJulian Wiedmann if (mode == QETH_PNSO_NONE) 2879d6a569aSJulian Wiedmann drain_workqueue(card->event_wq); 2889d6a569aSJulian Wiedmann } 2899d6a569aSJulian Wiedmann 290817741a8SAlexandra Winter static void qeth_l2_dev2br_fdb_flush(struct qeth_card *card) 291817741a8SAlexandra Winter { 292817741a8SAlexandra Winter struct switchdev_notifier_fdb_info info; 293817741a8SAlexandra Winter 294817741a8SAlexandra Winter QETH_CARD_TEXT(card, 2, "fdbflush"); 295817741a8SAlexandra Winter 296817741a8SAlexandra Winter info.addr = NULL; 297817741a8SAlexandra Winter /* flush all VLANs: */ 298817741a8SAlexandra Winter info.vid = 0; 299817741a8SAlexandra Winter info.added_by_user = false; 300817741a8SAlexandra Winter info.offloaded = true; 301817741a8SAlexandra Winter 302817741a8SAlexandra Winter call_switchdev_notifiers(SWITCHDEV_FDB_FLUSH_TO_BRIDGE, 303817741a8SAlexandra Winter card->dev, &info.info, NULL); 304817741a8SAlexandra Winter } 305817741a8SAlexandra Winter 306d4560150SJulian Wiedmann static void qeth_l2_stop_card(struct qeth_card *card) 3074a71df50SFrank Blaschka { 30857a688aaSJulian Wiedmann QETH_CARD_TEXT(card, 2, "stopcard"); 3094a71df50SFrank Blaschka 3104a71df50SFrank Blaschka qeth_set_allowed_threads(card, 0, 1); 3110f7aedbdSJulian Wiedmann 312d0c74825SJulian Wiedmann cancel_work_sync(&card->rx_mode_work); 313d0c74825SJulian Wiedmann qeth_l2_drain_rx_mode_cache(card); 314d0c74825SJulian Wiedmann 3154a71df50SFrank Blaschka if (card->state == CARD_STATE_SOFTSETUP) { 3164a71df50SFrank Blaschka qeth_clear_ipacmd_list(card); 31741c47da3SJulian Wiedmann qeth_drain_output_queues(card); 3184a71df50SFrank Blaschka card->state = CARD_STATE_DOWN; 3194a71df50SFrank Blaschka } 320ad160872SJulian Wiedmann 3218b5026bcSJulian Wiedmann qeth_qdio_clear_card(card, 0); 322aa3ad392SJulian Wiedmann qeth_clear_working_pool_list(card); 3239d6a569aSJulian Wiedmann qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE); 3240d49c06bSJulian Wiedmann qeth_flush_local_addrs(card); 3250f399305SJulian Wiedmann card->info.promisc_mode = 0; 3264a71df50SFrank Blaschka } 3274a71df50SFrank Blaschka 3284a71df50SFrank Blaschka static int qeth_l2_request_initial_mac(struct qeth_card *card) 3294a71df50SFrank Blaschka { 3304a71df50SFrank Blaschka int rc = 0; 3314a71df50SFrank Blaschka 33257a688aaSJulian Wiedmann QETH_CARD_TEXT(card, 2, "l2reqmac"); 3334a71df50SFrank Blaschka 334ec61bd2fSJulian Wiedmann if (MACHINE_IS_VM) { 335ec61bd2fSJulian Wiedmann rc = qeth_vm_request_mac(card); 336ec61bd2fSJulian Wiedmann if (!rc) 337ec61bd2fSJulian Wiedmann goto out; 338e19e5be8SJulian Wiedmann QETH_DBF_MESSAGE(2, "z/VM MAC Service failed on device %x: %#x\n", 339e19e5be8SJulian Wiedmann CARD_DEVID(card), rc); 34057a688aaSJulian Wiedmann QETH_CARD_TEXT_(card, 2, "err%04x", rc); 341ec61bd2fSJulian Wiedmann /* fall back to alternative mechanism: */ 342ec61bd2fSJulian Wiedmann } 343ec61bd2fSJulian Wiedmann 344b144b99fSJulian Wiedmann if (!IS_OSN(card)) { 3454a71df50SFrank Blaschka rc = qeth_setadpparms_change_macaddr(card); 3464b7ae122SJulian Wiedmann if (!rc) 34721b1702aSJulian Wiedmann goto out; 348e19e5be8SJulian Wiedmann QETH_DBF_MESSAGE(2, "READ_MAC Assist failed on device %x: %#x\n", 349e19e5be8SJulian Wiedmann CARD_DEVID(card), rc); 35057a688aaSJulian Wiedmann QETH_CARD_TEXT_(card, 2, "1err%04x", rc); 35121b1702aSJulian Wiedmann /* fall back once more: */ 3524a71df50SFrank Blaschka } 35321b1702aSJulian Wiedmann 35421b1702aSJulian Wiedmann /* some devices don't support a custom MAC address: */ 355379ac99eSJulian Wiedmann if (IS_OSM(card) || IS_OSX(card)) 35621b1702aSJulian Wiedmann return (rc) ? rc : -EADDRNOTAVAIL; 35721b1702aSJulian Wiedmann eth_hw_addr_random(card->dev); 35821b1702aSJulian Wiedmann 359ec61bd2fSJulian Wiedmann out: 36057a688aaSJulian Wiedmann QETH_CARD_HEX(card, 2, card->dev->dev_addr, card->dev->addr_len); 3614a71df50SFrank Blaschka return 0; 3624a71df50SFrank Blaschka } 3634a71df50SFrank Blaschka 364654e3d48SJulian Wiedmann static void qeth_l2_register_dev_addr(struct qeth_card *card) 365654e3d48SJulian Wiedmann { 366654e3d48SJulian Wiedmann if (!is_valid_ether_addr(card->dev->dev_addr)) 367654e3d48SJulian Wiedmann qeth_l2_request_initial_mac(card); 368654e3d48SJulian Wiedmann 369654e3d48SJulian Wiedmann if (!IS_OSN(card) && !qeth_l2_send_setmac(card, card->dev->dev_addr)) 3709de15117SJulian Wiedmann card->info.dev_addr_is_registered = 1; 3719de15117SJulian Wiedmann else 3729de15117SJulian Wiedmann card->info.dev_addr_is_registered = 0; 373654e3d48SJulian Wiedmann } 374654e3d48SJulian Wiedmann 375e22355eaSJulian Wiedmann static int qeth_l2_validate_addr(struct net_device *dev) 376e22355eaSJulian Wiedmann { 377e22355eaSJulian Wiedmann struct qeth_card *card = dev->ml_priv; 378e22355eaSJulian Wiedmann 3799de15117SJulian Wiedmann if (card->info.dev_addr_is_registered) 380e22355eaSJulian Wiedmann return eth_validate_addr(dev); 381e22355eaSJulian Wiedmann 382e22355eaSJulian Wiedmann QETH_CARD_TEXT(card, 4, "nomacadr"); 383e22355eaSJulian Wiedmann return -EPERM; 384e22355eaSJulian Wiedmann } 385e22355eaSJulian Wiedmann 3864a71df50SFrank Blaschka static int qeth_l2_set_mac_address(struct net_device *dev, void *p) 3874a71df50SFrank Blaschka { 3884a71df50SFrank Blaschka struct sockaddr *addr = p; 389509e2562SHeiko Carstens struct qeth_card *card = dev->ml_priv; 390bcacfcbcSJulian Wiedmann u8 old_addr[ETH_ALEN]; 3914a71df50SFrank Blaschka int rc = 0; 3924a71df50SFrank Blaschka 393847a50fdSCarsten Otte QETH_CARD_TEXT(card, 3, "setmac"); 3944a71df50SFrank Blaschka 3958024cc9eSJulian Wiedmann if (IS_OSM(card) || IS_OSX(card)) { 396847a50fdSCarsten Otte QETH_CARD_TEXT(card, 3, "setmcTYP"); 3974a71df50SFrank Blaschka return -EOPNOTSUPP; 3984a71df50SFrank Blaschka } 39999f0b85dSJulian Wiedmann QETH_CARD_HEX(card, 3, addr->sa_data, ETH_ALEN); 400bcacfcbcSJulian Wiedmann if (!is_valid_ether_addr(addr->sa_data)) 401bcacfcbcSJulian Wiedmann return -EADDRNOTAVAIL; 402bcacfcbcSJulian Wiedmann 403bcacfcbcSJulian Wiedmann /* don't register the same address twice */ 404bcacfcbcSJulian Wiedmann if (ether_addr_equal_64bits(dev->dev_addr, addr->sa_data) && 4059de15117SJulian Wiedmann card->info.dev_addr_is_registered) 406e6e771b3SJulian Wiedmann return 0; 407bcacfcbcSJulian Wiedmann 408bcacfcbcSJulian Wiedmann /* add the new address, switch over, drop the old */ 4094a71df50SFrank Blaschka rc = qeth_l2_send_setmac(card, addr->sa_data); 410bcacfcbcSJulian Wiedmann if (rc) 411e6e771b3SJulian Wiedmann return rc; 412bcacfcbcSJulian Wiedmann ether_addr_copy(old_addr, dev->dev_addr); 413bcacfcbcSJulian Wiedmann ether_addr_copy(dev->dev_addr, addr->sa_data); 414bcacfcbcSJulian Wiedmann 4159de15117SJulian Wiedmann if (card->info.dev_addr_is_registered) 416bcacfcbcSJulian Wiedmann qeth_l2_remove_mac(card, old_addr); 4179de15117SJulian Wiedmann card->info.dev_addr_is_registered = 1; 418e6e771b3SJulian Wiedmann return 0; 4194a71df50SFrank Blaschka } 4204a71df50SFrank Blaschka 42159b757a9SJulian Wiedmann static void qeth_l2_promisc_to_bridge(struct qeth_card *card, bool enable) 4220db587b0SEugene Crosser { 4230db587b0SEugene Crosser int role; 4240db587b0SEugene Crosser int rc; 4250db587b0SEugene Crosser 4260db587b0SEugene Crosser QETH_CARD_TEXT(card, 3, "pmisc2br"); 4270db587b0SEugene Crosser 42859b757a9SJulian Wiedmann if (enable) { 4290db587b0SEugene Crosser if (card->options.sbp.reflect_promisc_primary) 4300db587b0SEugene Crosser role = QETH_SBP_ROLE_PRIMARY; 4310db587b0SEugene Crosser else 4320db587b0SEugene Crosser role = QETH_SBP_ROLE_SECONDARY; 4330db587b0SEugene Crosser } else 4340db587b0SEugene Crosser role = QETH_SBP_ROLE_NONE; 4350db587b0SEugene Crosser 4360db587b0SEugene Crosser rc = qeth_bridgeport_setrole(card, role); 43759b757a9SJulian Wiedmann QETH_CARD_TEXT_(card, 2, "bpm%c%04x", enable ? '+' : '-', rc); 4380db587b0SEugene Crosser if (!rc) { 4390db587b0SEugene Crosser card->options.sbp.role = role; 44059b757a9SJulian Wiedmann card->info.promisc_mode = enable; 44159b757a9SJulian Wiedmann } 4420db587b0SEugene Crosser } 443fe5c8028SLakhvich Dmitriy 44459b757a9SJulian Wiedmann static void qeth_l2_set_promisc_mode(struct qeth_card *card) 44559b757a9SJulian Wiedmann { 44659b757a9SJulian Wiedmann bool enable = card->dev->flags & IFF_PROMISC; 44759b757a9SJulian Wiedmann 44859b757a9SJulian Wiedmann if (card->info.promisc_mode == enable) 44959b757a9SJulian Wiedmann return; 45059b757a9SJulian Wiedmann 451c8183f54SJulian Wiedmann if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) { 45259b757a9SJulian Wiedmann qeth_setadp_promisc_mode(card, enable); 453c8183f54SJulian Wiedmann } else { 454c8183f54SJulian Wiedmann mutex_lock(&card->sbp_lock); 455c8183f54SJulian Wiedmann if (card->options.sbp.reflect_promisc) 45659b757a9SJulian Wiedmann qeth_l2_promisc_to_bridge(card, enable); 457c8183f54SJulian Wiedmann mutex_unlock(&card->sbp_lock); 458c8183f54SJulian Wiedmann } 459fe5c8028SLakhvich Dmitriy } 46059b757a9SJulian Wiedmann 461fe5c8028SLakhvich Dmitriy /* New MAC address is added to the hash table and marked to be written on card 462fe5c8028SLakhvich Dmitriy * only if there is not in the hash table storage already 463fe5c8028SLakhvich Dmitriy * 464fe5c8028SLakhvich Dmitriy */ 4654641b027SJulian Wiedmann static void qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha) 466fe5c8028SLakhvich Dmitriy { 467cef6ff22SJulian Wiedmann u32 mac_hash = get_unaligned((u32 *)(&ha->addr[2])); 468fe5c8028SLakhvich Dmitriy struct qeth_mac *mac; 469fe5c8028SLakhvich Dmitriy 4700973292fSJulian Wiedmann hash_for_each_possible(card->rx_mode_addrs, mac, hnode, mac_hash) { 47199f0b85dSJulian Wiedmann if (ether_addr_equal_64bits(ha->addr, mac->mac_addr)) { 4725f78e29cSLakhvich Dmitriy mac->disp_flag = QETH_DISP_ADDR_DO_NOTHING; 473fe5c8028SLakhvich Dmitriy return; 474fe5c8028SLakhvich Dmitriy } 4750db587b0SEugene Crosser } 4760db587b0SEugene Crosser 477fe5c8028SLakhvich Dmitriy mac = kzalloc(sizeof(struct qeth_mac), GFP_ATOMIC); 478fe5c8028SLakhvich Dmitriy if (!mac) 479fe5c8028SLakhvich Dmitriy return; 480fe5c8028SLakhvich Dmitriy 48199f0b85dSJulian Wiedmann ether_addr_copy(mac->mac_addr, ha->addr); 4825f78e29cSLakhvich Dmitriy mac->disp_flag = QETH_DISP_ADDR_ADD; 483fe5c8028SLakhvich Dmitriy 4840973292fSJulian Wiedmann hash_add(card->rx_mode_addrs, &mac->hnode, mac_hash); 485fe5c8028SLakhvich Dmitriy } 486fe5c8028SLakhvich Dmitriy 487d0c74825SJulian Wiedmann static void qeth_l2_rx_mode_work(struct work_struct *work) 4884a71df50SFrank Blaschka { 489d0c74825SJulian Wiedmann struct qeth_card *card = container_of(work, struct qeth_card, 490d0c74825SJulian Wiedmann rx_mode_work); 491d0c74825SJulian Wiedmann struct net_device *dev = card->dev; 492ccffad25SJiri Pirko struct netdev_hw_addr *ha; 493fe5c8028SLakhvich Dmitriy struct qeth_mac *mac; 494fe5c8028SLakhvich Dmitriy struct hlist_node *tmp; 495fe5c8028SLakhvich Dmitriy int i; 496fe5c8028SLakhvich Dmitriy int rc; 4974a71df50SFrank Blaschka 498847a50fdSCarsten Otte QETH_CARD_TEXT(card, 3, "setmulti"); 499fe5c8028SLakhvich Dmitriy 500d0c74825SJulian Wiedmann netif_addr_lock_bh(dev); 50122bedad3SJiri Pirko netdev_for_each_mc_addr(ha, dev) 5024641b027SJulian Wiedmann qeth_l2_add_mac(card, ha); 50332e7bfc4SJiri Pirko netdev_for_each_uc_addr(ha, dev) 5044641b027SJulian Wiedmann qeth_l2_add_mac(card, ha); 505d0c74825SJulian Wiedmann netif_addr_unlock_bh(dev); 506fe5c8028SLakhvich Dmitriy 5070973292fSJulian Wiedmann hash_for_each_safe(card->rx_mode_addrs, i, tmp, mac, hnode) { 50800c163f1SJulian Wiedmann switch (mac->disp_flag) { 50900c163f1SJulian Wiedmann case QETH_DISP_ADDR_DELETE: 5108174aa8aSJulian Wiedmann qeth_l2_remove_mac(card, mac->mac_addr); 511fe5c8028SLakhvich Dmitriy hash_del(&mac->hnode); 512fe5c8028SLakhvich Dmitriy kfree(mac); 51300c163f1SJulian Wiedmann break; 51400c163f1SJulian Wiedmann case QETH_DISP_ADDR_ADD: 5158174aa8aSJulian Wiedmann rc = qeth_l2_write_mac(card, mac->mac_addr); 516fe5c8028SLakhvich Dmitriy if (rc) { 517fe5c8028SLakhvich Dmitriy hash_del(&mac->hnode); 518fe5c8028SLakhvich Dmitriy kfree(mac); 51900c163f1SJulian Wiedmann break; 52000c163f1SJulian Wiedmann } 521df561f66SGustavo A. R. Silva fallthrough; 52200c163f1SJulian Wiedmann default: 52300c163f1SJulian Wiedmann /* for next call to set_rx_mode(): */ 5245f78e29cSLakhvich Dmitriy mac->disp_flag = QETH_DISP_ADDR_DELETE; 52500c163f1SJulian Wiedmann } 526fe5c8028SLakhvich Dmitriy } 5277db2266aSFrank Blaschka 52859b757a9SJulian Wiedmann qeth_l2_set_promisc_mode(card); 5294a71df50SFrank Blaschka } 5304a71df50SFrank Blaschka 5317286384bSJulian Wiedmann static int qeth_l2_xmit_osn(struct qeth_card *card, struct sk_buff *skb, 5327286384bSJulian Wiedmann struct qeth_qdio_out_q *queue) 5337286384bSJulian Wiedmann { 534b413ff8aSJulian Wiedmann gfp_t gfp = GFP_ATOMIC | (skb_pfmemalloc(skb) ? __GFP_MEMALLOC : 0); 53569d7ce80SJulian Wiedmann struct qeth_hdr *hdr = (struct qeth_hdr *)skb->data; 53669d7ce80SJulian Wiedmann addr_t end = (addr_t)(skb->data + sizeof(*hdr)); 53769d7ce80SJulian Wiedmann addr_t start = (addr_t)skb->data; 53869d7ce80SJulian Wiedmann unsigned int elements = 0; 53969d7ce80SJulian Wiedmann unsigned int hd_len = 0; 54069d7ce80SJulian Wiedmann int rc; 5417286384bSJulian Wiedmann 5427286384bSJulian Wiedmann if (skb->protocol == htons(ETH_P_IPV6)) 5437286384bSJulian Wiedmann return -EPROTONOSUPPORT; 5447286384bSJulian Wiedmann 54569d7ce80SJulian Wiedmann if (qeth_get_elements_for_range(start, end) > 1) { 54669d7ce80SJulian Wiedmann /* Misaligned HW header, move it to its own buffer element. */ 547b413ff8aSJulian Wiedmann hdr = kmem_cache_alloc(qeth_core_header_cache, gfp); 54869d7ce80SJulian Wiedmann if (!hdr) 54969d7ce80SJulian Wiedmann return -ENOMEM; 55069d7ce80SJulian Wiedmann hd_len = sizeof(*hdr); 55169d7ce80SJulian Wiedmann skb_copy_from_linear_data(skb, (char *)hdr, hd_len); 55269d7ce80SJulian Wiedmann elements++; 55369d7ce80SJulian Wiedmann } 55469d7ce80SJulian Wiedmann 55569d7ce80SJulian Wiedmann elements += qeth_count_elements(skb, hd_len); 5564e26c5feSJulian Wiedmann if (elements > queue->max_elements) { 55769d7ce80SJulian Wiedmann rc = -E2BIG; 55869d7ce80SJulian Wiedmann goto out; 55969d7ce80SJulian Wiedmann } 56069d7ce80SJulian Wiedmann 56169d7ce80SJulian Wiedmann rc = qeth_do_send_packet(card, queue, skb, hdr, hd_len, hd_len, 56269d7ce80SJulian Wiedmann elements); 56369d7ce80SJulian Wiedmann out: 56469d7ce80SJulian Wiedmann if (rc && hd_len) 56569d7ce80SJulian Wiedmann kmem_cache_free(qeth_core_header_cache, hdr); 56669d7ce80SJulian Wiedmann return rc; 5677286384bSJulian Wiedmann } 5687286384bSJulian Wiedmann 569e38db6beSJulian Wiedmann static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, 570e38db6beSJulian Wiedmann struct net_device *dev) 5714a71df50SFrank Blaschka { 572509e2562SHeiko Carstens struct qeth_card *card = dev->ml_priv; 5733a18d754SJulian Wiedmann u16 txq = skb_get_queue_mapping(skb); 574290b8348SStefan Raspl struct qeth_qdio_out_q *queue; 5757286384bSJulian Wiedmann int rc; 5764a71df50SFrank Blaschka 577eeac0e20SJulian Wiedmann if (!skb_is_gso(skb)) 578eeac0e20SJulian Wiedmann qdisc_skb_cb(skb)->pkt_len = skb->len; 5793a18d754SJulian Wiedmann if (IS_IQD(card)) 58054a50941SJulian Wiedmann txq = qeth_iqd_translate_txq(dev, txq); 58173dc2dafSJulian Wiedmann queue = card->qdio.out_qs[txq]; 582b0abc4f5SJulian Wiedmann 5835f89eca5SJulian Wiedmann if (IS_OSN(card)) 5847286384bSJulian Wiedmann rc = qeth_l2_xmit_osn(card, skb, queue); 5855f89eca5SJulian Wiedmann else 58673dc2dafSJulian Wiedmann rc = qeth_xmit(card, skb, queue, qeth_get_ip_version(skb), 58758aa2491SJulian Wiedmann qeth_l2_fill_header); 5884a71df50SFrank Blaschka 589eeac0e20SJulian Wiedmann if (!rc) 5907286384bSJulian Wiedmann return NETDEV_TX_OK; 5914a71df50SFrank Blaschka 592b0abc4f5SJulian Wiedmann QETH_TXQ_STAT_INC(queue, tx_dropped); 593104b4859SJulian Wiedmann kfree_skb(skb); 5944a71df50SFrank Blaschka return NETDEV_TX_OK; 5954a71df50SFrank Blaschka } 5964a71df50SFrank Blaschka 5973a18d754SJulian Wiedmann static u16 qeth_l2_select_queue(struct net_device *dev, struct sk_buff *skb, 5983a18d754SJulian Wiedmann struct net_device *sb_dev) 5993a18d754SJulian Wiedmann { 60073dc2dafSJulian Wiedmann struct qeth_card *card = dev->ml_priv; 60173dc2dafSJulian Wiedmann 60273dc2dafSJulian Wiedmann if (IS_IQD(card)) 60373dc2dafSJulian Wiedmann return qeth_iqd_select_queue(dev, skb, 60458aa2491SJulian Wiedmann qeth_get_ether_cast_type(skb), 6053a18d754SJulian Wiedmann sb_dev); 6061c103cf8SJulian Wiedmann 6071c103cf8SJulian Wiedmann return IS_VM_NIC(card) ? netdev_pick_tx(dev, skb, sb_dev) : 6081c103cf8SJulian Wiedmann qeth_get_priority_queue(card, skb); 6093a18d754SJulian Wiedmann } 6103a18d754SJulian Wiedmann 6112d2ebb3eSJulian Wiedmann static const struct device_type qeth_l2_devtype = { 6122d2ebb3eSJulian Wiedmann .name = "qeth_layer2", 6132d2ebb3eSJulian Wiedmann .groups = qeth_l2_attr_groups, 6142d2ebb3eSJulian Wiedmann }; 6152d2ebb3eSJulian Wiedmann 6164a71df50SFrank Blaschka static int qeth_l2_probe_device(struct ccwgroup_device *gdev) 6174a71df50SFrank Blaschka { 6184a71df50SFrank Blaschka struct qeth_card *card = dev_get_drvdata(&gdev->dev); 6199111e788SUrsula Braun int rc; 6204a71df50SFrank Blaschka 621fb64de1bSJulian Wiedmann if (IS_OSN(card)) 622fb64de1bSJulian Wiedmann dev_notice(&gdev->dev, "OSN support will be dropped in 2021\n"); 623fb64de1bSJulian Wiedmann 62412b409ddSJulian Wiedmann qeth_l2_vnicc_set_defaults(card); 625c8183f54SJulian Wiedmann mutex_init(&card->sbp_lock); 62612b409ddSJulian Wiedmann 6272d2ebb3eSJulian Wiedmann if (gdev->dev.type == &qeth_generic_devtype) { 6289111e788SUrsula Braun rc = qeth_l2_create_device_attributes(&gdev->dev); 6299111e788SUrsula Braun if (rc) 6309111e788SUrsula Braun return rc; 6312d2ebb3eSJulian Wiedmann } 6325fc692a7SJulian Wiedmann 633d0c74825SJulian Wiedmann INIT_WORK(&card->rx_mode_work, qeth_l2_rx_mode_work); 6344a71df50SFrank Blaschka return 0; 6354a71df50SFrank Blaschka } 6364a71df50SFrank Blaschka 6374a71df50SFrank Blaschka static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) 6384a71df50SFrank Blaschka { 6394a71df50SFrank Blaschka struct qeth_card *card = dev_get_drvdata(&cgdev->dev); 6404a71df50SFrank Blaschka 6412d2ebb3eSJulian Wiedmann if (cgdev->dev.type == &qeth_generic_devtype) 642b4d72c08SEugene Crosser qeth_l2_remove_device_attributes(&cgdev->dev); 643f2148565SUrsula Braun qeth_set_allowed_threads(card, 0, 1); 6444a71df50SFrank Blaschka wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); 6454a71df50SFrank Blaschka 64670919e23SUrsula Braun if (cgdev->state == CCWGROUP_ONLINE) 64791003f35SJulian Wiedmann qeth_set_offline(card, false); 648c2780c1aSJulian Wiedmann 649c2780c1aSJulian Wiedmann cancel_work_sync(&card->close_dev_work); 650cd652be5SJulian Wiedmann if (card->dev->reg_state == NETREG_REGISTERED) 6514a71df50SFrank Blaschka unregister_netdev(card->dev); 6524a71df50SFrank Blaschka } 6534a71df50SFrank Blaschka 654d0c74825SJulian Wiedmann static void qeth_l2_set_rx_mode(struct net_device *dev) 655d0c74825SJulian Wiedmann { 656d0c74825SJulian Wiedmann struct qeth_card *card = dev->ml_priv; 657d0c74825SJulian Wiedmann 658d0c74825SJulian Wiedmann schedule_work(&card->rx_mode_work); 659d0c74825SJulian Wiedmann } 660d0c74825SJulian Wiedmann 661a0138f59SAlexandra Winter /** 662a0138f59SAlexandra Winter * qeth_l2_pnso() - perform network subchannel operation 663a0138f59SAlexandra Winter * @card: qeth_card structure pointer 6644fea49a7SAlexandra Winter * @oc: Operation Code 665a0138f59SAlexandra Winter * @cnc: Boolean Change-Notification Control 666a0138f59SAlexandra Winter * @cb: Callback function will be executed for each element 667a0138f59SAlexandra Winter * of the address list 668a0138f59SAlexandra Winter * @priv: Pointer to pass to the callback function. 669a0138f59SAlexandra Winter * 670a0138f59SAlexandra Winter * Collects network information in a network address list and calls the 671a0138f59SAlexandra Winter * callback function for every entry in the list. If "change-notification- 672a0138f59SAlexandra Winter * control" is set, further changes in the address list will be reported 673a0138f59SAlexandra Winter * via the IPA command. 674a0138f59SAlexandra Winter */ 6754fea49a7SAlexandra Winter static int qeth_l2_pnso(struct qeth_card *card, u8 oc, int cnc, 676a0138f59SAlexandra Winter void (*cb)(void *priv, struct chsc_pnso_naid_l2 *entry), 677a0138f59SAlexandra Winter void *priv) 678a0138f59SAlexandra Winter { 679a0138f59SAlexandra Winter struct ccw_device *ddev = CARD_DDEV(card); 680a0138f59SAlexandra Winter struct chsc_pnso_area *rr; 681a0138f59SAlexandra Winter u32 prev_instance = 0; 682a0138f59SAlexandra Winter int isfirstblock = 1; 683a0138f59SAlexandra Winter int i, size, elems; 684a0138f59SAlexandra Winter int rc; 685a0138f59SAlexandra Winter 686a0138f59SAlexandra Winter rr = (struct chsc_pnso_area *)get_zeroed_page(GFP_KERNEL); 687a0138f59SAlexandra Winter if (rr == NULL) 688a0138f59SAlexandra Winter return -ENOMEM; 689a0138f59SAlexandra Winter do { 6904fea49a7SAlexandra Winter QETH_CARD_TEXT(card, 2, "PNSO"); 691a0138f59SAlexandra Winter /* on the first iteration, naihdr.resume_token will be zero */ 6924fea49a7SAlexandra Winter rc = ccw_device_pnso(ddev, rr, oc, rr->naihdr.resume_token, 6934fea49a7SAlexandra Winter cnc); 694a0138f59SAlexandra Winter if (rc) 695a0138f59SAlexandra Winter continue; 696a0138f59SAlexandra Winter if (cb == NULL) 697a0138f59SAlexandra Winter continue; 698a0138f59SAlexandra Winter 699a0138f59SAlexandra Winter size = rr->naihdr.naids; 700a0138f59SAlexandra Winter if (size != sizeof(struct chsc_pnso_naid_l2)) { 701a0138f59SAlexandra Winter WARN_ON_ONCE(1); 702a0138f59SAlexandra Winter continue; 703a0138f59SAlexandra Winter } 704a0138f59SAlexandra Winter 705a0138f59SAlexandra Winter elems = (rr->response.length - sizeof(struct chsc_header) - 706a0138f59SAlexandra Winter sizeof(struct chsc_pnso_naihdr)) / size; 707a0138f59SAlexandra Winter 708a0138f59SAlexandra Winter if (!isfirstblock && (rr->naihdr.instance != prev_instance)) { 709a0138f59SAlexandra Winter /* Inform the caller that they need to scrap */ 710a0138f59SAlexandra Winter /* the data that was already reported via cb */ 711a0138f59SAlexandra Winter rc = -EAGAIN; 712a0138f59SAlexandra Winter break; 713a0138f59SAlexandra Winter } 714a0138f59SAlexandra Winter isfirstblock = 0; 715a0138f59SAlexandra Winter prev_instance = rr->naihdr.instance; 716a0138f59SAlexandra Winter for (i = 0; i < elems; i++) 717a0138f59SAlexandra Winter (*cb)(priv, &rr->entries[i]); 718a0138f59SAlexandra Winter } while ((rc == -EBUSY) || (!rc && /* list stored */ 719a0138f59SAlexandra Winter /* resume token is non-zero => list incomplete */ 720a0138f59SAlexandra Winter (rr->naihdr.resume_token.t1 || rr->naihdr.resume_token.t2))); 721a0138f59SAlexandra Winter 722a0138f59SAlexandra Winter if (rc) 723a0138f59SAlexandra Winter QETH_CARD_TEXT_(card, 2, "PNrp%04x", rr->response.code); 724a0138f59SAlexandra Winter 725a0138f59SAlexandra Winter free_page((unsigned long)rr); 726a0138f59SAlexandra Winter return rc; 727a0138f59SAlexandra Winter } 728a0138f59SAlexandra Winter 72910a6cfc0SAlexandra Winter static bool qeth_is_my_net_if_token(struct qeth_card *card, 73010a6cfc0SAlexandra Winter struct net_if_token *token) 73110a6cfc0SAlexandra Winter { 73210a6cfc0SAlexandra Winter return ((card->info.ddev_devno == token->devnum) && 73310a6cfc0SAlexandra Winter (card->info.cssid == token->cssid) && 73410a6cfc0SAlexandra Winter (card->info.iid == token->iid) && 73510a6cfc0SAlexandra Winter (card->info.ssid == token->ssid) && 73610a6cfc0SAlexandra Winter (card->info.chpid == token->chpid) && 73710a6cfc0SAlexandra Winter (card->info.chid == token->chid)); 73810a6cfc0SAlexandra Winter } 73910a6cfc0SAlexandra Winter 74010a6cfc0SAlexandra Winter /** 74110a6cfc0SAlexandra Winter * qeth_l2_dev2br_fdb_notify() - update fdb of master bridge 74210a6cfc0SAlexandra Winter * @card: qeth_card structure pointer 74310a6cfc0SAlexandra Winter * @code: event bitmask: high order bit 0x80 set to 74410a6cfc0SAlexandra Winter * 1 - removal of an object 74510a6cfc0SAlexandra Winter * 0 - addition of an object 74610a6cfc0SAlexandra Winter * Object type(s): 74710a6cfc0SAlexandra Winter * 0x01 - VLAN, 0x02 - MAC, 0x03 - VLAN and MAC 74810a6cfc0SAlexandra Winter * @token: "network token" structure identifying 'physical' location 74910a6cfc0SAlexandra Winter * of the target 75010a6cfc0SAlexandra Winter * @addr_lnid: structure with MAC address and VLAN ID of the target 75110a6cfc0SAlexandra Winter */ 75210a6cfc0SAlexandra Winter static void qeth_l2_dev2br_fdb_notify(struct qeth_card *card, u8 code, 75310a6cfc0SAlexandra Winter struct net_if_token *token, 75410a6cfc0SAlexandra Winter struct mac_addr_lnid *addr_lnid) 75510a6cfc0SAlexandra Winter { 75610a6cfc0SAlexandra Winter struct switchdev_notifier_fdb_info info; 75710a6cfc0SAlexandra Winter u8 ntfy_mac[ETH_ALEN]; 75810a6cfc0SAlexandra Winter 75910a6cfc0SAlexandra Winter ether_addr_copy(ntfy_mac, addr_lnid->mac); 76010a6cfc0SAlexandra Winter /* Ignore VLAN only changes */ 76110a6cfc0SAlexandra Winter if (!(code & IPA_ADDR_CHANGE_CODE_MACADDR)) 76210a6cfc0SAlexandra Winter return; 76310a6cfc0SAlexandra Winter /* Ignore mcast entries */ 76410a6cfc0SAlexandra Winter if (is_multicast_ether_addr(ntfy_mac)) 76510a6cfc0SAlexandra Winter return; 76610a6cfc0SAlexandra Winter /* Ignore my own addresses */ 76710a6cfc0SAlexandra Winter if (qeth_is_my_net_if_token(card, token)) 76810a6cfc0SAlexandra Winter return; 76910a6cfc0SAlexandra Winter 77010a6cfc0SAlexandra Winter info.addr = ntfy_mac; 77110a6cfc0SAlexandra Winter /* don't report VLAN IDs */ 77210a6cfc0SAlexandra Winter info.vid = 0; 77310a6cfc0SAlexandra Winter info.added_by_user = false; 77410a6cfc0SAlexandra Winter info.offloaded = true; 77510a6cfc0SAlexandra Winter 77610a6cfc0SAlexandra Winter if (code & IPA_ADDR_CHANGE_CODE_REMOVAL) { 77710a6cfc0SAlexandra Winter call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, 77810a6cfc0SAlexandra Winter card->dev, &info.info, NULL); 77910a6cfc0SAlexandra Winter QETH_CARD_TEXT(card, 4, "andelmac"); 78010a6cfc0SAlexandra Winter QETH_CARD_TEXT_(card, 4, 78110a6cfc0SAlexandra Winter "mc%012lx", ether_addr_to_u64(ntfy_mac)); 78210a6cfc0SAlexandra Winter } else { 78310a6cfc0SAlexandra Winter call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, 78410a6cfc0SAlexandra Winter card->dev, &info.info, NULL); 78510a6cfc0SAlexandra Winter QETH_CARD_TEXT(card, 4, "anaddmac"); 78610a6cfc0SAlexandra Winter QETH_CARD_TEXT_(card, 4, 78710a6cfc0SAlexandra Winter "mc%012lx", ether_addr_to_u64(ntfy_mac)); 78810a6cfc0SAlexandra Winter } 78910a6cfc0SAlexandra Winter } 79010a6cfc0SAlexandra Winter 791817741a8SAlexandra Winter static void qeth_l2_dev2br_an_set_cb(void *priv, 792817741a8SAlexandra Winter struct chsc_pnso_naid_l2 *entry) 793817741a8SAlexandra Winter { 794817741a8SAlexandra Winter u8 code = IPA_ADDR_CHANGE_CODE_MACADDR; 795817741a8SAlexandra Winter struct qeth_card *card = priv; 796817741a8SAlexandra Winter 797817741a8SAlexandra Winter if (entry->addr_lnid.lnid < VLAN_N_VID) 798817741a8SAlexandra Winter code |= IPA_ADDR_CHANGE_CODE_VLANID; 799817741a8SAlexandra Winter qeth_l2_dev2br_fdb_notify(card, code, 800817741a8SAlexandra Winter (struct net_if_token *)&entry->nit, 801817741a8SAlexandra Winter (struct mac_addr_lnid *)&entry->addr_lnid); 802817741a8SAlexandra Winter } 803817741a8SAlexandra Winter 804817741a8SAlexandra Winter /** 805817741a8SAlexandra Winter * qeth_l2_dev2br_an_set() - 806817741a8SAlexandra Winter * Enable or disable 'dev to bridge network address notification' 807817741a8SAlexandra Winter * @card: qeth_card structure pointer 808817741a8SAlexandra Winter * @enable: Enable or disable 'dev to bridge network address notification' 809817741a8SAlexandra Winter * 810817741a8SAlexandra Winter * Returns negative errno-compatible error indication or 0 on success. 811817741a8SAlexandra Winter * 812817741a8SAlexandra Winter * On enable, emits a series of address notifications for all 813817741a8SAlexandra Winter * currently registered hosts. 814817741a8SAlexandra Winter * 815817741a8SAlexandra Winter * Must be called under rtnl_lock 816817741a8SAlexandra Winter */ 817817741a8SAlexandra Winter static int qeth_l2_dev2br_an_set(struct qeth_card *card, bool enable) 818817741a8SAlexandra Winter { 819817741a8SAlexandra Winter int rc; 820817741a8SAlexandra Winter 821817741a8SAlexandra Winter if (enable) { 822817741a8SAlexandra Winter QETH_CARD_TEXT(card, 2, "anseton"); 823817741a8SAlexandra Winter rc = qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 1, 824817741a8SAlexandra Winter qeth_l2_dev2br_an_set_cb, card); 825817741a8SAlexandra Winter if (rc == -EAGAIN) 826817741a8SAlexandra Winter /* address notification enabled, but inconsistent 827817741a8SAlexandra Winter * addresses reported -> disable address notification 828817741a8SAlexandra Winter */ 829817741a8SAlexandra Winter qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 0, 830817741a8SAlexandra Winter NULL, NULL); 831817741a8SAlexandra Winter } else { 832817741a8SAlexandra Winter QETH_CARD_TEXT(card, 2, "ansetoff"); 833817741a8SAlexandra Winter rc = qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 0, NULL, NULL); 834817741a8SAlexandra Winter } 835817741a8SAlexandra Winter 836817741a8SAlexandra Winter return rc; 837817741a8SAlexandra Winter } 838817741a8SAlexandra Winter 8393d58cefdSFrank Blaschka static const struct net_device_ops qeth_l2_netdev_ops = { 840e22355eaSJulian Wiedmann .ndo_open = qeth_open, 841e22355eaSJulian Wiedmann .ndo_stop = qeth_stop, 842b0abc4f5SJulian Wiedmann .ndo_get_stats64 = qeth_get_stats64, 8438403b13cSFrank Blaschka .ndo_start_xmit = qeth_l2_hard_start_xmit, 8446d69b1f1SJulian Wiedmann .ndo_features_check = qeth_features_check, 8453a18d754SJulian Wiedmann .ndo_select_queue = qeth_l2_select_queue, 846e22355eaSJulian Wiedmann .ndo_validate_addr = qeth_l2_validate_addr, 847fe5c8028SLakhvich Dmitriy .ndo_set_rx_mode = qeth_l2_set_rx_mode, 848942d6984SJulian Wiedmann .ndo_do_ioctl = qeth_do_ioctl, 8498403b13cSFrank Blaschka .ndo_set_mac_address = qeth_l2_set_mac_address, 8508403b13cSFrank Blaschka .ndo_vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid, 8518403b13cSFrank Blaschka .ndo_vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid, 8528403b13cSFrank Blaschka .ndo_tx_timeout = qeth_tx_timeout, 8538f43fb00SThomas Richter .ndo_fix_features = qeth_fix_features, 8548f43fb00SThomas Richter .ndo_set_features = qeth_set_features 8558403b13cSFrank Blaschka }; 8568403b13cSFrank Blaschka 8578024cc9eSJulian Wiedmann static const struct net_device_ops qeth_osn_netdev_ops = { 8588024cc9eSJulian Wiedmann .ndo_open = qeth_open, 8598024cc9eSJulian Wiedmann .ndo_stop = qeth_stop, 8608024cc9eSJulian Wiedmann .ndo_get_stats64 = qeth_get_stats64, 8618024cc9eSJulian Wiedmann .ndo_start_xmit = qeth_l2_hard_start_xmit, 8628024cc9eSJulian Wiedmann .ndo_validate_addr = eth_validate_addr, 8638024cc9eSJulian Wiedmann .ndo_tx_timeout = qeth_tx_timeout, 8648024cc9eSJulian Wiedmann }; 8658024cc9eSJulian Wiedmann 866cd652be5SJulian Wiedmann static int qeth_l2_setup_netdev(struct qeth_card *card) 8674a71df50SFrank Blaschka { 868d3d1b205SJulian Wiedmann int rc; 8694a71df50SFrank Blaschka 8708024cc9eSJulian Wiedmann if (IS_OSN(card)) { 8718024cc9eSJulian Wiedmann card->dev->netdev_ops = &qeth_osn_netdev_ops; 87225e2c341SJulian Wiedmann card->dev->flags |= IFF_NOARP; 8738024cc9eSJulian Wiedmann goto add_napi; 8748024cc9eSJulian Wiedmann } 8758024cc9eSJulian Wiedmann 8761c103cf8SJulian Wiedmann rc = qeth_setup_netdev(card); 8771c103cf8SJulian Wiedmann if (rc) 8781c103cf8SJulian Wiedmann return rc; 8791c103cf8SJulian Wiedmann 8805f89eca5SJulian Wiedmann card->dev->needed_headroom = sizeof(struct qeth_hdr); 8818024cc9eSJulian Wiedmann card->dev->netdev_ops = &qeth_l2_netdev_ops; 8828024cc9eSJulian Wiedmann card->dev->priv_flags |= IFF_UNICAST_FLT; 8839400c53fSJulian Wiedmann 8845fc692a7SJulian Wiedmann if (IS_OSM(card)) { 8859400c53fSJulian Wiedmann card->dev->features |= NETIF_F_VLAN_CHALLENGED; 8865fc692a7SJulian Wiedmann } else { 8875fc692a7SJulian Wiedmann if (!IS_VM_NIC(card)) 8885fc692a7SJulian Wiedmann card->dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; 889f646968fSPatrick McHardy card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; 8905fc692a7SJulian Wiedmann } 8910f342945SJulian Wiedmann 892379ac99eSJulian Wiedmann if (IS_OSD(card) && !IS_VM_NIC(card)) { 8936d69b1f1SJulian Wiedmann card->dev->features |= NETIF_F_SG; 8948f43fb00SThomas Richter /* OSA 3S and earlier has no RX/TX support */ 8959bdc4411SHans Wippel if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) { 8968f43fb00SThomas Richter card->dev->hw_features |= NETIF_F_IP_CSUM; 8979bdc4411SHans Wippel card->dev->vlan_features |= NETIF_F_IP_CSUM; 8989bdc4411SHans Wippel } 8994d7def2aSThomas Richter } 900571f9dd8SKittipon Meesompop if (qeth_is_supported6(card, IPA_OUTBOUND_CHECKSUM_V6)) { 901571f9dd8SKittipon Meesompop card->dev->hw_features |= NETIF_F_IPV6_CSUM; 902571f9dd8SKittipon Meesompop card->dev->vlan_features |= NETIF_F_IPV6_CSUM; 903571f9dd8SKittipon Meesompop } 904d7e6ed97SKittipon Meesompop if (qeth_is_supported(card, IPA_INBOUND_CHECKSUM) || 905d7e6ed97SKittipon Meesompop qeth_is_supported6(card, IPA_INBOUND_CHECKSUM_V6)) { 906d7e6ed97SKittipon Meesompop card->dev->hw_features |= NETIF_F_RXCSUM; 907d7e6ed97SKittipon Meesompop card->dev->vlan_features |= NETIF_F_RXCSUM; 908d7e6ed97SKittipon Meesompop } 9090aef8392SJulian Wiedmann if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { 9100aef8392SJulian Wiedmann card->dev->hw_features |= NETIF_F_TSO; 9110aef8392SJulian Wiedmann card->dev->vlan_features |= NETIF_F_TSO; 9120aef8392SJulian Wiedmann } 9130aef8392SJulian Wiedmann if (qeth_is_supported6(card, IPA_OUTBOUND_TSO)) { 9140aef8392SJulian Wiedmann card->dev->hw_features |= NETIF_F_TSO6; 9150aef8392SJulian Wiedmann card->dev->vlan_features |= NETIF_F_TSO6; 9160aef8392SJulian Wiedmann } 9170aef8392SJulian Wiedmann 9180aef8392SJulian Wiedmann if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6)) { 9190aef8392SJulian Wiedmann card->dev->needed_headroom = sizeof(struct qeth_hdr_tso); 920c619e9a6SJulian Wiedmann netif_keep_dst(card->dev); 9210aef8392SJulian Wiedmann netif_set_gso_max_size(card->dev, 9220aef8392SJulian Wiedmann PAGE_SIZE * (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)); 9230aef8392SJulian Wiedmann } 9240d6f02d3SJulian Wiedmann 9258024cc9eSJulian Wiedmann add_napi: 926d73ef324SJulian Wiedmann netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT); 927cd652be5SJulian Wiedmann return register_netdev(card->dev); 9284a71df50SFrank Blaschka } 9294a71df50SFrank Blaschka 930521c10eaSJulian Wiedmann static void qeth_l2_trace_features(struct qeth_card *card) 931521c10eaSJulian Wiedmann { 932a45b3fafSHans Wippel /* Set BridgePort features */ 933a45b3fafSHans Wippel QETH_CARD_TEXT(card, 2, "featuSBP"); 934521c10eaSJulian Wiedmann QETH_CARD_HEX(card, 2, &card->options.sbp.supported_funcs, 935521c10eaSJulian Wiedmann sizeof(card->options.sbp.supported_funcs)); 936a45b3fafSHans Wippel /* VNIC Characteristics features */ 937a45b3fafSHans Wippel QETH_CARD_TEXT(card, 2, "feaVNICC"); 938a45b3fafSHans Wippel QETH_CARD_HEX(card, 2, &card->options.vnicc.sup_chars, 939a45b3fafSHans Wippel sizeof(card->options.vnicc.sup_chars)); 940521c10eaSJulian Wiedmann } 941521c10eaSJulian Wiedmann 9428ca769e2SJulian Wiedmann static void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card) 9438ca769e2SJulian Wiedmann { 9448ca769e2SJulian Wiedmann if (!card->options.sbp.reflect_promisc && 9458ca769e2SJulian Wiedmann card->options.sbp.role != QETH_SBP_ROLE_NONE) { 9468ca769e2SJulian Wiedmann /* Conditional to avoid spurious error messages */ 9478ca769e2SJulian Wiedmann qeth_bridgeport_setrole(card, card->options.sbp.role); 9488ca769e2SJulian Wiedmann /* Let the callback function refresh the stored role value. */ 9498ca769e2SJulian Wiedmann qeth_bridgeport_query_ports(card, &card->options.sbp.role, 9508ca769e2SJulian Wiedmann NULL); 9518ca769e2SJulian Wiedmann } 9528ca769e2SJulian Wiedmann if (card->options.sbp.hostnotification) { 9538ca769e2SJulian Wiedmann if (qeth_bridgeport_an_set(card, 1)) 9548ca769e2SJulian Wiedmann card->options.sbp.hostnotification = 0; 9558ca769e2SJulian Wiedmann } 9568ca769e2SJulian Wiedmann } 9578ca769e2SJulian Wiedmann 958fa115adfSAlexandra Winter /** 959fa115adfSAlexandra Winter * qeth_l2_detect_dev2br_support() - 960fa115adfSAlexandra Winter * Detect whether this card supports 'dev to bridge fdb network address 961fa115adfSAlexandra Winter * change notification' and thus can support the learning_sync bridgeport 962fa115adfSAlexandra Winter * attribute 963fa115adfSAlexandra Winter * @card: qeth_card structure pointer 964fa115adfSAlexandra Winter * 965fa115adfSAlexandra Winter * This is a destructive test and must be called before dev2br or 966fa115adfSAlexandra Winter * bridgeport address notification is enabled! 967fa115adfSAlexandra Winter */ 968fa115adfSAlexandra Winter static void qeth_l2_detect_dev2br_support(struct qeth_card *card) 969fa115adfSAlexandra Winter { 970fa115adfSAlexandra Winter struct qeth_priv *priv = netdev_priv(card->dev); 971fa115adfSAlexandra Winter bool dev2br_supported; 972fa115adfSAlexandra Winter int rc; 973fa115adfSAlexandra Winter 974fa115adfSAlexandra Winter QETH_CARD_TEXT(card, 2, "d2brsup"); 975fa115adfSAlexandra Winter if (!IS_IQD(card)) 976fa115adfSAlexandra Winter return; 977fa115adfSAlexandra Winter 978fa115adfSAlexandra Winter /* dev2br requires valid cssid,iid,chid */ 979fa115adfSAlexandra Winter if (!card->info.ids_valid) { 980fa115adfSAlexandra Winter dev2br_supported = false; 981fa115adfSAlexandra Winter } else if (css_general_characteristics.enarf) { 982fa115adfSAlexandra Winter dev2br_supported = true; 983fa115adfSAlexandra Winter } else { 984fa115adfSAlexandra Winter /* Old machines don't have the feature bit: 985fa115adfSAlexandra Winter * Probe by testing whether a disable succeeds 986fa115adfSAlexandra Winter */ 987fa115adfSAlexandra Winter rc = qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 0, NULL, NULL); 988fa115adfSAlexandra Winter dev2br_supported = !rc; 989fa115adfSAlexandra Winter } 990fa115adfSAlexandra Winter QETH_CARD_TEXT_(card, 2, "D2Bsup%02x", dev2br_supported); 991fa115adfSAlexandra Winter 992fa115adfSAlexandra Winter if (dev2br_supported) 993fa115adfSAlexandra Winter priv->brport_hw_features |= BR_LEARNING_SYNC; 994fa115adfSAlexandra Winter else 995fa115adfSAlexandra Winter priv->brport_hw_features &= ~BR_LEARNING_SYNC; 996fa115adfSAlexandra Winter } 997fa115adfSAlexandra Winter 99891003f35SJulian Wiedmann static int qeth_l2_set_online(struct qeth_card *card) 9994a71df50SFrank Blaschka { 100091003f35SJulian Wiedmann struct ccwgroup_device *gdev = card->gdev; 1001fa3d2e60SJulian Wiedmann struct net_device *dev = card->dev; 10024a71df50SFrank Blaschka int rc = 0; 10039fae5c3bSJulian Wiedmann bool carrier_ok; 10044a71df50SFrank Blaschka 10059fae5c3bSJulian Wiedmann rc = qeth_core_hardsetup_card(card, &carrier_ok); 10064a71df50SFrank Blaschka if (rc) { 100757a688aaSJulian Wiedmann QETH_CARD_TEXT_(card, 2, "2err%04x", rc); 1008aa909224SUrsula Braun rc = -ENODEV; 10094a71df50SFrank Blaschka goto out_remove; 10104a71df50SFrank Blaschka } 1011654e3d48SJulian Wiedmann 1012fa115adfSAlexandra Winter /* query before bridgeport_notification may be enabled */ 1013fa115adfSAlexandra Winter qeth_l2_detect_dev2br_support(card); 1014fa115adfSAlexandra Winter 1015c8183f54SJulian Wiedmann mutex_lock(&card->sbp_lock); 1016d7ef489fSJulian Wiedmann qeth_bridgeport_query_support(card); 10178ca769e2SJulian Wiedmann if (card->options.sbp.supported_funcs) { 10188ca769e2SJulian Wiedmann qeth_l2_setup_bridgeport_attrs(card); 1019d7ef489fSJulian Wiedmann dev_info(&card->gdev->dev, 1020d7ef489fSJulian Wiedmann "The device represents a Bridge Capable Port\n"); 10218ca769e2SJulian Wiedmann } 1022c8183f54SJulian Wiedmann mutex_unlock(&card->sbp_lock); 1023d7ef489fSJulian Wiedmann 1024d7ef489fSJulian Wiedmann qeth_l2_register_dev_addr(card); 1025d7ef489fSJulian Wiedmann 1026a45b3fafSHans Wippel /* for the rx_bcast characteristic, init VNICC after setmac */ 1027a45b3fafSHans Wippel qeth_l2_vnicc_init(card); 1028a45b3fafSHans Wippel 1029a45b3fafSHans Wippel qeth_trace_features(card); 1030a45b3fafSHans Wippel qeth_l2_trace_features(card); 1031a45b3fafSHans Wippel 10324a71df50SFrank Blaschka qeth_print_status_message(card); 10334a71df50SFrank Blaschka 10344a71df50SFrank Blaschka /* softsetup */ 103557a688aaSJulian Wiedmann QETH_CARD_TEXT(card, 2, "softsetp"); 10364a71df50SFrank Blaschka 10374a71df50SFrank Blaschka card->state = CARD_STATE_SOFTSETUP; 10384a71df50SFrank Blaschka 10394a71df50SFrank Blaschka qeth_set_allowed_threads(card, 0xffffffff, 0); 1040d025da9eSJulian Wiedmann 1041cd652be5SJulian Wiedmann if (dev->reg_state != NETREG_REGISTERED) { 1042cd652be5SJulian Wiedmann rc = qeth_l2_setup_netdev(card); 1043fa3d2e60SJulian Wiedmann if (rc) 1044fa3d2e60SJulian Wiedmann goto out_remove; 1045cd652be5SJulian Wiedmann 1046cd652be5SJulian Wiedmann if (carrier_ok) 1047cd652be5SJulian Wiedmann netif_carrier_on(dev); 10484a71df50SFrank Blaschka } else { 10494a71df50SFrank Blaschka rtnl_lock(); 1050fa3d2e60SJulian Wiedmann if (carrier_ok) 1051fa3d2e60SJulian Wiedmann netif_carrier_on(dev); 1052fa3d2e60SJulian Wiedmann else 1053fa3d2e60SJulian Wiedmann netif_carrier_off(dev); 1054fa3d2e60SJulian Wiedmann 1055e6e771b3SJulian Wiedmann netif_device_attach(dev); 1056fa3d2e60SJulian Wiedmann qeth_enable_hw_features(dev); 1057fa3d2e60SJulian Wiedmann 1058d7d543f2SJulian Wiedmann if (card->info.open_when_online) { 1059d7d543f2SJulian Wiedmann card->info.open_when_online = 0; 1060fa3d2e60SJulian Wiedmann dev_open(dev, NULL); 1061fa3d2e60SJulian Wiedmann } 1062fa3d2e60SJulian Wiedmann rtnl_unlock(); 10634a71df50SFrank Blaschka } 10644a71df50SFrank Blaschka /* let user_space know that device is online */ 10654a71df50SFrank Blaschka kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE); 10664a71df50SFrank Blaschka return 0; 1067aa909224SUrsula Braun 10684a71df50SFrank Blaschka out_remove: 1069d4560150SJulian Wiedmann qeth_l2_stop_card(card); 1070f9e50b02SJulian Wiedmann qeth_stop_channel(&card->data); 1071f9e50b02SJulian Wiedmann qeth_stop_channel(&card->write); 1072f9e50b02SJulian Wiedmann qeth_stop_channel(&card->read); 107322ae2790SUrsula Braun qdio_free(CARD_DDEV(card)); 1074aa909224SUrsula Braun return rc; 10754a71df50SFrank Blaschka } 10764a71df50SFrank Blaschka 107791003f35SJulian Wiedmann static void qeth_l2_set_offline(struct qeth_card *card) 10784a71df50SFrank Blaschka { 1079d4560150SJulian Wiedmann qeth_l2_stop_card(card); 10804a71df50SFrank Blaschka } 10814a71df50SFrank Blaschka 10824a71df50SFrank Blaschka static int __init qeth_l2_init(void) 10834a71df50SFrank Blaschka { 108474eacdb9SFrank Blaschka pr_info("register layer 2 discipline\n"); 10854a71df50SFrank Blaschka return 0; 10864a71df50SFrank Blaschka } 10874a71df50SFrank Blaschka 10884a71df50SFrank Blaschka static void __exit qeth_l2_exit(void) 10894a71df50SFrank Blaschka { 109074eacdb9SFrank Blaschka pr_info("unregister layer 2 discipline\n"); 10914a71df50SFrank Blaschka } 10924a71df50SFrank Blaschka 1093c044dc21SEugene Crosser /* Returns zero if the command is successfully "consumed" */ 1094c044dc21SEugene Crosser static int qeth_l2_control_event(struct qeth_card *card, 1095c044dc21SEugene Crosser struct qeth_ipa_cmd *cmd) 1096c044dc21SEugene Crosser { 1097c044dc21SEugene Crosser switch (cmd->hdr.command) { 10989c23f4daSEugene Crosser case IPA_CMD_SETBRIDGEPORT_OSA: 10999c23f4daSEugene Crosser case IPA_CMD_SETBRIDGEPORT_IQD: 1100c044dc21SEugene Crosser if (cmd->data.sbp.hdr.command_code == 1101c044dc21SEugene Crosser IPA_SBP_BRIDGE_PORT_STATE_CHANGE) { 1102c044dc21SEugene Crosser qeth_bridge_state_change(card, cmd); 1103c044dc21SEugene Crosser return 0; 1104c044dc21SEugene Crosser } else 1105c044dc21SEugene Crosser return 1; 1106c044dc21SEugene Crosser case IPA_CMD_ADDRESS_CHANGE_NOTIF: 1107a0138f59SAlexandra Winter qeth_addr_change_event(card, cmd); 1108c044dc21SEugene Crosser return 0; 1109c044dc21SEugene Crosser default: 1110c044dc21SEugene Crosser return 1; 1111c044dc21SEugene Crosser } 1112c044dc21SEugene Crosser } 1113c044dc21SEugene Crosser 1114c041f2d4SSebastian Ott struct qeth_discipline qeth_l2_discipline = { 11152d2ebb3eSJulian Wiedmann .devtype = &qeth_l2_devtype, 1116c041f2d4SSebastian Ott .setup = qeth_l2_probe_device, 11174a71df50SFrank Blaschka .remove = qeth_l2_remove_device, 11184a71df50SFrank Blaschka .set_online = qeth_l2_set_online, 11194a71df50SFrank Blaschka .set_offline = qeth_l2_set_offline, 1120942d6984SJulian Wiedmann .do_ioctl = NULL, 1121c044dc21SEugene Crosser .control_event_handler = qeth_l2_control_event, 11224a71df50SFrank Blaschka }; 1123c041f2d4SSebastian Ott EXPORT_SYMBOL_GPL(qeth_l2_discipline); 11244a71df50SFrank Blaschka 11254e2b5aa5SJulian Wiedmann #ifdef CONFIG_QETH_OSN 11260ce37ec2SJulian Wiedmann static void qeth_osn_assist_cb(struct qeth_card *card, 112712fc286fSJulian Wiedmann struct qeth_cmd_buffer *iob, 112812fc286fSJulian Wiedmann unsigned int data_length) 11294a71df50SFrank Blaschka { 1130308946b0SJulian Wiedmann qeth_notify_cmd(iob, 0); 1131c3b2218dSJulian Wiedmann qeth_put_cmd(iob); 11324a71df50SFrank Blaschka } 11334a71df50SFrank Blaschka 11344a71df50SFrank Blaschka int qeth_osn_assist(struct net_device *dev, void *data, int data_len) 11354a71df50SFrank Blaschka { 11364a71df50SFrank Blaschka struct qeth_cmd_buffer *iob; 11374a71df50SFrank Blaschka struct qeth_card *card; 11384a71df50SFrank Blaschka 1139a59d121dSJulian Wiedmann if (data_len < 0) 1140a59d121dSJulian Wiedmann return -EINVAL; 11414a71df50SFrank Blaschka if (!dev) 11424a71df50SFrank Blaschka return -ENODEV; 1143509e2562SHeiko Carstens card = dev->ml_priv; 11444a71df50SFrank Blaschka if (!card) 11454a71df50SFrank Blaschka return -ENODEV; 1146847a50fdSCarsten Otte QETH_CARD_TEXT(card, 2, "osnsdmc"); 1147c3521254SEugene Crosser if (!qeth_card_hw_is_reachable(card)) 11484a71df50SFrank Blaschka return -ENODEV; 1149a59d121dSJulian Wiedmann 1150a59d121dSJulian Wiedmann iob = qeth_alloc_cmd(&card->write, IPA_PDU_HEADER_SIZE + data_len, 1, 1151a59d121dSJulian Wiedmann QETH_IPA_TIMEOUT); 11521273a800SJulian Wiedmann if (!iob) 11531273a800SJulian Wiedmann return -ENOMEM; 11541273a800SJulian Wiedmann 11557f92316cSJulian Wiedmann qeth_prepare_ipa_cmd(card, iob, (u16) data_len, NULL); 11567f92316cSJulian Wiedmann 1157ff5caa7aSJulian Wiedmann memcpy(__ipa_cmd(iob), data, data_len); 11580ce37ec2SJulian Wiedmann iob->callback = qeth_osn_assist_cb; 11590ce37ec2SJulian Wiedmann return qeth_send_ipa_cmd(card, iob, NULL, NULL); 11604a71df50SFrank Blaschka } 11614a71df50SFrank Blaschka EXPORT_SYMBOL(qeth_osn_assist); 11624a71df50SFrank Blaschka 11634a71df50SFrank Blaschka int qeth_osn_register(unsigned char *read_dev_no, struct net_device **dev, 11644a71df50SFrank Blaschka int (*assist_cb)(struct net_device *, void *), 11654a71df50SFrank Blaschka int (*data_cb)(struct sk_buff *)) 11664a71df50SFrank Blaschka { 11674a71df50SFrank Blaschka struct qeth_card *card; 1168d7d18da1SJulian Wiedmann char bus_id[16]; 1169d7d18da1SJulian Wiedmann u16 devno; 11704a71df50SFrank Blaschka 1171d7d18da1SJulian Wiedmann memcpy(&devno, read_dev_no, 2); 1172d7d18da1SJulian Wiedmann sprintf(bus_id, "0.0.%04x", devno); 1173d7d18da1SJulian Wiedmann card = qeth_get_card_by_busid(bus_id); 1174d7d18da1SJulian Wiedmann if (!card || !IS_OSN(card)) 11754a71df50SFrank Blaschka return -ENODEV; 1176d7d18da1SJulian Wiedmann *dev = card->dev; 1177d7d18da1SJulian Wiedmann 1178847a50fdSCarsten Otte QETH_CARD_TEXT(card, 2, "osnreg"); 11794a71df50SFrank Blaschka if ((assist_cb == NULL) || (data_cb == NULL)) 11804a71df50SFrank Blaschka return -EINVAL; 11814a71df50SFrank Blaschka card->osn_info.assist_cb = assist_cb; 11824a71df50SFrank Blaschka card->osn_info.data_cb = data_cb; 11834a71df50SFrank Blaschka return 0; 11844a71df50SFrank Blaschka } 11854a71df50SFrank Blaschka EXPORT_SYMBOL(qeth_osn_register); 11864a71df50SFrank Blaschka 11874a71df50SFrank Blaschka void qeth_osn_deregister(struct net_device *dev) 11884a71df50SFrank Blaschka { 11894a71df50SFrank Blaschka struct qeth_card *card; 11904a71df50SFrank Blaschka 11914a71df50SFrank Blaschka if (!dev) 11924a71df50SFrank Blaschka return; 1193509e2562SHeiko Carstens card = dev->ml_priv; 11944a71df50SFrank Blaschka if (!card) 11954a71df50SFrank Blaschka return; 1196847a50fdSCarsten Otte QETH_CARD_TEXT(card, 2, "osndereg"); 11974a71df50SFrank Blaschka card->osn_info.assist_cb = NULL; 11984a71df50SFrank Blaschka card->osn_info.data_cb = NULL; 11994a71df50SFrank Blaschka return; 12004a71df50SFrank Blaschka } 12014a71df50SFrank Blaschka EXPORT_SYMBOL(qeth_osn_deregister); 12024e2b5aa5SJulian Wiedmann #endif 12034a71df50SFrank Blaschka 1204b4d72c08SEugene Crosser /* SETBRIDGEPORT support, async notifications */ 1205b4d72c08SEugene Crosser 12069f48b9dbSEugene Crosser enum qeth_an_event_type {anev_reg_unreg, anev_abort, anev_reset}; 12079f48b9dbSEugene Crosser 12089f48b9dbSEugene Crosser /** 12099f48b9dbSEugene Crosser * qeth_bridge_emit_host_event() - bridgeport address change notification 12109f48b9dbSEugene Crosser * @card: qeth_card structure pointer, for udev events. 12119f48b9dbSEugene Crosser * @evtype: "normal" register/unregister, or abort, or reset. For abort 12129f48b9dbSEugene Crosser * and reset token and addr_lnid are unused and may be NULL. 12139f48b9dbSEugene Crosser * @code: event bitmask: high order bit 0x80 value 1 means removal of an 12149f48b9dbSEugene Crosser * object, 0 - addition of an object. 12159f48b9dbSEugene Crosser * 0x01 - VLAN, 0x02 - MAC, 0x03 - VLAN and MAC. 12169f48b9dbSEugene Crosser * @token: "network token" structure identifying physical address of the port. 12179f48b9dbSEugene Crosser * @addr_lnid: pointer to structure with MAC address and VLAN ID. 12189f48b9dbSEugene Crosser * 12199f48b9dbSEugene Crosser * This function is called when registrations and deregistrations are 12209f48b9dbSEugene Crosser * reported by the hardware, and also when notifications are enabled - 12219f48b9dbSEugene Crosser * for all currently registered addresses. 12229f48b9dbSEugene Crosser */ 12239f48b9dbSEugene Crosser static void qeth_bridge_emit_host_event(struct qeth_card *card, 12249f48b9dbSEugene Crosser enum qeth_an_event_type evtype, 1225a0138f59SAlexandra Winter u8 code, 1226a0138f59SAlexandra Winter struct net_if_token *token, 1227a0138f59SAlexandra Winter struct mac_addr_lnid *addr_lnid) 12289f48b9dbSEugene Crosser { 12299f48b9dbSEugene Crosser char str[7][32]; 12309f48b9dbSEugene Crosser char *env[8]; 12319f48b9dbSEugene Crosser int i = 0; 12329f48b9dbSEugene Crosser 12339f48b9dbSEugene Crosser switch (evtype) { 12349f48b9dbSEugene Crosser case anev_reg_unreg: 12359f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=%s", 12369f48b9dbSEugene Crosser (code & IPA_ADDR_CHANGE_CODE_REMOVAL) 12379f48b9dbSEugene Crosser ? "deregister" : "register"); 12389f48b9dbSEugene Crosser env[i] = str[i]; i++; 12399f48b9dbSEugene Crosser if (code & IPA_ADDR_CHANGE_CODE_VLANID) { 12409f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "VLAN=%d", 12419f48b9dbSEugene Crosser addr_lnid->lnid); 12429f48b9dbSEugene Crosser env[i] = str[i]; i++; 12439f48b9dbSEugene Crosser } 12449f48b9dbSEugene Crosser if (code & IPA_ADDR_CHANGE_CODE_MACADDR) { 12459846e70bSEugene Crosser snprintf(str[i], sizeof(str[i]), "MAC=%pM", 12469846e70bSEugene Crosser addr_lnid->mac); 12479f48b9dbSEugene Crosser env[i] = str[i]; i++; 12489f48b9dbSEugene Crosser } 12499f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "NTOK_BUSID=%x.%x.%04x", 12509f48b9dbSEugene Crosser token->cssid, token->ssid, token->devnum); 12519f48b9dbSEugene Crosser env[i] = str[i]; i++; 12529f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "NTOK_IID=%02x", token->iid); 12539f48b9dbSEugene Crosser env[i] = str[i]; i++; 12549f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "NTOK_CHPID=%02x", 12559f48b9dbSEugene Crosser token->chpid); 12569f48b9dbSEugene Crosser env[i] = str[i]; i++; 12579f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "NTOK_CHID=%04x", token->chid); 12589f48b9dbSEugene Crosser env[i] = str[i]; i++; 12599f48b9dbSEugene Crosser break; 12609f48b9dbSEugene Crosser case anev_abort: 12619f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=abort"); 12629f48b9dbSEugene Crosser env[i] = str[i]; i++; 12639f48b9dbSEugene Crosser break; 12649f48b9dbSEugene Crosser case anev_reset: 12659f48b9dbSEugene Crosser snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=reset"); 12669f48b9dbSEugene Crosser env[i] = str[i]; i++; 12679f48b9dbSEugene Crosser break; 12689f48b9dbSEugene Crosser } 12699f48b9dbSEugene Crosser env[i] = NULL; 12709f48b9dbSEugene Crosser kobject_uevent_env(&card->gdev->dev.kobj, KOBJ_CHANGE, env); 12719f48b9dbSEugene Crosser } 12729f48b9dbSEugene Crosser 1273b4d72c08SEugene Crosser struct qeth_bridge_state_data { 1274b4d72c08SEugene Crosser struct work_struct worker; 1275b4d72c08SEugene Crosser struct qeth_card *card; 127661c6f217SJulian Wiedmann u8 role; 127761c6f217SJulian Wiedmann u8 state; 1278b4d72c08SEugene Crosser }; 1279b4d72c08SEugene Crosser 1280b4d72c08SEugene Crosser static void qeth_bridge_state_change_worker(struct work_struct *work) 1281b4d72c08SEugene Crosser { 1282b4d72c08SEugene Crosser struct qeth_bridge_state_data *data = 1283b4d72c08SEugene Crosser container_of(work, struct qeth_bridge_state_data, worker); 1284b4d72c08SEugene Crosser char env_locrem[32]; 1285b4d72c08SEugene Crosser char env_role[32]; 1286b4d72c08SEugene Crosser char env_state[32]; 1287b4d72c08SEugene Crosser char *env[] = { 1288b4d72c08SEugene Crosser env_locrem, 1289b4d72c08SEugene Crosser env_role, 1290b4d72c08SEugene Crosser env_state, 1291b4d72c08SEugene Crosser NULL 1292b4d72c08SEugene Crosser }; 1293b4d72c08SEugene Crosser 1294b4d72c08SEugene Crosser snprintf(env_locrem, sizeof(env_locrem), "BRIDGEPORT=statechange"); 1295b4d72c08SEugene Crosser snprintf(env_role, sizeof(env_role), "ROLE=%s", 129661c6f217SJulian Wiedmann (data->role == QETH_SBP_ROLE_NONE) ? "none" : 129761c6f217SJulian Wiedmann (data->role == QETH_SBP_ROLE_PRIMARY) ? "primary" : 129861c6f217SJulian Wiedmann (data->role == QETH_SBP_ROLE_SECONDARY) ? "secondary" : 1299b4d72c08SEugene Crosser "<INVALID>"); 1300b4d72c08SEugene Crosser snprintf(env_state, sizeof(env_state), "STATE=%s", 130161c6f217SJulian Wiedmann (data->state == QETH_SBP_STATE_INACTIVE) ? "inactive" : 130261c6f217SJulian Wiedmann (data->state == QETH_SBP_STATE_STANDBY) ? "standby" : 130361c6f217SJulian Wiedmann (data->state == QETH_SBP_STATE_ACTIVE) ? "active" : 1304b4d72c08SEugene Crosser "<INVALID>"); 1305b4d72c08SEugene Crosser kobject_uevent_env(&data->card->gdev->dev.kobj, 1306b4d72c08SEugene Crosser KOBJ_CHANGE, env); 1307b4d72c08SEugene Crosser kfree(data); 1308b4d72c08SEugene Crosser } 1309b4d72c08SEugene Crosser 1310c044dc21SEugene Crosser static void qeth_bridge_state_change(struct qeth_card *card, 1311c044dc21SEugene Crosser struct qeth_ipa_cmd *cmd) 1312b4d72c08SEugene Crosser { 131365b0494eSJulian Wiedmann struct qeth_sbp_port_data *qports = &cmd->data.sbp.data.port_data; 1314b4d72c08SEugene Crosser struct qeth_bridge_state_data *data; 1315b4d72c08SEugene Crosser 1316b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brstchng"); 131702472e28SJulian Wiedmann if (qports->num_entries == 0) { 131802472e28SJulian Wiedmann QETH_CARD_TEXT(card, 2, "BPempty"); 131902472e28SJulian Wiedmann return; 132002472e28SJulian Wiedmann } 1321b4d72c08SEugene Crosser if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) { 13228a593148SThomas Richter QETH_CARD_TEXT_(card, 2, "BPsz%04x", qports->entry_length); 1323b4d72c08SEugene Crosser return; 1324b4d72c08SEugene Crosser } 132561c6f217SJulian Wiedmann 132661c6f217SJulian Wiedmann data = kzalloc(sizeof(*data), GFP_ATOMIC); 1327b4d72c08SEugene Crosser if (!data) { 1328b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "BPSalloc"); 1329b4d72c08SEugene Crosser return; 1330b4d72c08SEugene Crosser } 1331b4d72c08SEugene Crosser INIT_WORK(&data->worker, qeth_bridge_state_change_worker); 1332b4d72c08SEugene Crosser data->card = card; 133361c6f217SJulian Wiedmann /* Information for the local port: */ 133461c6f217SJulian Wiedmann data->role = qports->entry[0].role; 133561c6f217SJulian Wiedmann data->state = qports->entry[0].state; 133661c6f217SJulian Wiedmann 1337c0a2e4d1SJulian Wiedmann queue_work(card->event_wq, &data->worker); 1338b4d72c08SEugene Crosser } 1339b4d72c08SEugene Crosser 1340a0138f59SAlexandra Winter struct qeth_addr_change_data { 13419d6a569aSJulian Wiedmann struct delayed_work dwork; 13429f48b9dbSEugene Crosser struct qeth_card *card; 1343a0138f59SAlexandra Winter struct qeth_ipacmd_addr_change ac_event; 13449f48b9dbSEugene Crosser }; 13459f48b9dbSEugene Crosser 134610a6cfc0SAlexandra Winter static void qeth_l2_dev2br_worker(struct work_struct *work) 134710a6cfc0SAlexandra Winter { 134810a6cfc0SAlexandra Winter struct delayed_work *dwork = to_delayed_work(work); 134910a6cfc0SAlexandra Winter struct qeth_addr_change_data *data; 135010a6cfc0SAlexandra Winter struct qeth_card *card; 1351817741a8SAlexandra Winter struct qeth_priv *priv; 135210a6cfc0SAlexandra Winter unsigned int i; 1353817741a8SAlexandra Winter int rc; 135410a6cfc0SAlexandra Winter 135510a6cfc0SAlexandra Winter data = container_of(dwork, struct qeth_addr_change_data, dwork); 135610a6cfc0SAlexandra Winter card = data->card; 1357817741a8SAlexandra Winter priv = netdev_priv(card->dev); 135810a6cfc0SAlexandra Winter 135910a6cfc0SAlexandra Winter QETH_CARD_TEXT(card, 4, "dev2brew"); 136010a6cfc0SAlexandra Winter 136110a6cfc0SAlexandra Winter if (READ_ONCE(card->info.pnso_mode) == QETH_PNSO_NONE) 136210a6cfc0SAlexandra Winter goto free; 136310a6cfc0SAlexandra Winter 136410a6cfc0SAlexandra Winter /* Potential re-config in progress, try again later: */ 136510a6cfc0SAlexandra Winter if (!rtnl_trylock()) { 136610a6cfc0SAlexandra Winter queue_delayed_work(card->event_wq, dwork, 136710a6cfc0SAlexandra Winter msecs_to_jiffies(100)); 136810a6cfc0SAlexandra Winter return; 136910a6cfc0SAlexandra Winter } 1370817741a8SAlexandra Winter if (!netif_device_present(card->dev)) 1371817741a8SAlexandra Winter goto out_unlock; 137210a6cfc0SAlexandra Winter 137310a6cfc0SAlexandra Winter if (data->ac_event.lost_event_mask) { 137410a6cfc0SAlexandra Winter QETH_DBF_MESSAGE(3, 137510a6cfc0SAlexandra Winter "Address change notification overflow on device %x\n", 137610a6cfc0SAlexandra Winter CARD_DEVID(card)); 1377817741a8SAlexandra Winter /* Card fdb and bridge fdb are out of sync, card has stopped 1378817741a8SAlexandra Winter * notifications (no need to drain_workqueue). Purge all 1379817741a8SAlexandra Winter * 'extern_learn' entries from the parent bridge and restart 1380817741a8SAlexandra Winter * the notifications. 1381817741a8SAlexandra Winter */ 1382817741a8SAlexandra Winter qeth_l2_dev2br_fdb_flush(card); 1383817741a8SAlexandra Winter rc = qeth_l2_dev2br_an_set(card, true); 1384817741a8SAlexandra Winter if (rc) { 1385817741a8SAlexandra Winter /* TODO: if we want to retry after -EAGAIN, be 1386817741a8SAlexandra Winter * aware there could be stale entries in the 1387817741a8SAlexandra Winter * workqueue now, that need to be drained. 1388817741a8SAlexandra Winter * For now we give up: 1389817741a8SAlexandra Winter */ 1390817741a8SAlexandra Winter netdev_err(card->dev, 1391817741a8SAlexandra Winter "bridge learning_sync failed to recover: %d\n", 1392817741a8SAlexandra Winter rc); 1393817741a8SAlexandra Winter WRITE_ONCE(card->info.pnso_mode, 1394817741a8SAlexandra Winter QETH_PNSO_NONE); 1395817741a8SAlexandra Winter /* To remove fdb entries reported by an_set: */ 1396817741a8SAlexandra Winter qeth_l2_dev2br_fdb_flush(card); 1397817741a8SAlexandra Winter priv->brport_features ^= BR_LEARNING_SYNC; 1398817741a8SAlexandra Winter } else { 1399817741a8SAlexandra Winter QETH_DBF_MESSAGE(3, 1400817741a8SAlexandra Winter "Address Notification resynced on device %x\n", 1401817741a8SAlexandra Winter CARD_DEVID(card)); 1402817741a8SAlexandra Winter } 140310a6cfc0SAlexandra Winter } else { 140410a6cfc0SAlexandra Winter for (i = 0; i < data->ac_event.num_entries; i++) { 140510a6cfc0SAlexandra Winter struct qeth_ipacmd_addr_change_entry *entry = 140610a6cfc0SAlexandra Winter &data->ac_event.entry[i]; 140710a6cfc0SAlexandra Winter qeth_l2_dev2br_fdb_notify(card, 140810a6cfc0SAlexandra Winter entry->change_code, 140910a6cfc0SAlexandra Winter &entry->token, 141010a6cfc0SAlexandra Winter &entry->addr_lnid); 141110a6cfc0SAlexandra Winter } 141210a6cfc0SAlexandra Winter } 1413817741a8SAlexandra Winter 1414817741a8SAlexandra Winter out_unlock: 141510a6cfc0SAlexandra Winter rtnl_unlock(); 141610a6cfc0SAlexandra Winter 141710a6cfc0SAlexandra Winter free: 141810a6cfc0SAlexandra Winter kfree(data); 141910a6cfc0SAlexandra Winter } 142010a6cfc0SAlexandra Winter 1421a0138f59SAlexandra Winter static void qeth_addr_change_event_worker(struct work_struct *work) 14229f48b9dbSEugene Crosser { 14239d6a569aSJulian Wiedmann struct delayed_work *dwork = to_delayed_work(work); 14249d6a569aSJulian Wiedmann struct qeth_addr_change_data *data; 14259d6a569aSJulian Wiedmann struct qeth_card *card; 14269f48b9dbSEugene Crosser int i; 14279f48b9dbSEugene Crosser 14289d6a569aSJulian Wiedmann data = container_of(dwork, struct qeth_addr_change_data, dwork); 14299d6a569aSJulian Wiedmann card = data->card; 14309d6a569aSJulian Wiedmann 1431a0138f59SAlexandra Winter QETH_CARD_TEXT(data->card, 4, "adrchgew"); 14329d6a569aSJulian Wiedmann 14339d6a569aSJulian Wiedmann if (READ_ONCE(card->info.pnso_mode) == QETH_PNSO_NONE) 14349d6a569aSJulian Wiedmann goto free; 14359d6a569aSJulian Wiedmann 1436a0138f59SAlexandra Winter if (data->ac_event.lost_event_mask) { 14379d6a569aSJulian Wiedmann /* Potential re-config in progress, try again later: */ 14389d6a569aSJulian Wiedmann if (!mutex_trylock(&card->sbp_lock)) { 14399d6a569aSJulian Wiedmann queue_delayed_work(card->event_wq, dwork, 14409d6a569aSJulian Wiedmann msecs_to_jiffies(100)); 14419d6a569aSJulian Wiedmann return; 14429d6a569aSJulian Wiedmann } 14439d6a569aSJulian Wiedmann 14449f48b9dbSEugene Crosser dev_info(&data->card->gdev->dev, 1445a0138f59SAlexandra Winter "Address change notification stopped on %s (%s)\n", 14469f48b9dbSEugene Crosser data->card->dev->name, 1447a0138f59SAlexandra Winter (data->ac_event.lost_event_mask == 0x01) 14489f48b9dbSEugene Crosser ? "Overflow" 1449a0138f59SAlexandra Winter : (data->ac_event.lost_event_mask == 0x02) 14509f48b9dbSEugene Crosser ? "Bridge port state change" 14519f48b9dbSEugene Crosser : "Unknown reason"); 14529d6a569aSJulian Wiedmann 14539f48b9dbSEugene Crosser data->card->options.sbp.hostnotification = 0; 14549d6a569aSJulian Wiedmann card->info.pnso_mode = QETH_PNSO_NONE; 1455c8183f54SJulian Wiedmann mutex_unlock(&data->card->sbp_lock); 14569f48b9dbSEugene Crosser qeth_bridge_emit_host_event(data->card, anev_abort, 14579f48b9dbSEugene Crosser 0, NULL, NULL); 14589f48b9dbSEugene Crosser } else 1459a0138f59SAlexandra Winter for (i = 0; i < data->ac_event.num_entries; i++) { 14609f48b9dbSEugene Crosser struct qeth_ipacmd_addr_change_entry *entry = 1461a0138f59SAlexandra Winter &data->ac_event.entry[i]; 14629f48b9dbSEugene Crosser qeth_bridge_emit_host_event(data->card, 14639f48b9dbSEugene Crosser anev_reg_unreg, 14649f48b9dbSEugene Crosser entry->change_code, 1465a0138f59SAlexandra Winter &entry->token, 1466a0138f59SAlexandra Winter &entry->addr_lnid); 14679f48b9dbSEugene Crosser } 14689d6a569aSJulian Wiedmann 14699d6a569aSJulian Wiedmann free: 14709f48b9dbSEugene Crosser kfree(data); 14719f48b9dbSEugene Crosser } 14729f48b9dbSEugene Crosser 1473a0138f59SAlexandra Winter static void qeth_addr_change_event(struct qeth_card *card, 1474c044dc21SEugene Crosser struct qeth_ipa_cmd *cmd) 14759f48b9dbSEugene Crosser { 14769f48b9dbSEugene Crosser struct qeth_ipacmd_addr_change *hostevs = 14779f48b9dbSEugene Crosser &cmd->data.addrchange; 1478a0138f59SAlexandra Winter struct qeth_addr_change_data *data; 14799f48b9dbSEugene Crosser int extrasize; 14809f48b9dbSEugene Crosser 14819d6a569aSJulian Wiedmann if (card->info.pnso_mode == QETH_PNSO_NONE) 14829d6a569aSJulian Wiedmann return; 14839d6a569aSJulian Wiedmann 1484a0138f59SAlexandra Winter QETH_CARD_TEXT(card, 4, "adrchgev"); 14859f48b9dbSEugene Crosser if (cmd->hdr.return_code != 0x0000) { 14869f48b9dbSEugene Crosser if (cmd->hdr.return_code == 0x0010) { 14879f48b9dbSEugene Crosser if (hostevs->lost_event_mask == 0x00) 14889f48b9dbSEugene Crosser hostevs->lost_event_mask = 0xff; 14899f48b9dbSEugene Crosser } else { 1490a0138f59SAlexandra Winter QETH_CARD_TEXT_(card, 2, "ACHN%04x", 14919f48b9dbSEugene Crosser cmd->hdr.return_code); 14929f48b9dbSEugene Crosser return; 14939f48b9dbSEugene Crosser } 14949f48b9dbSEugene Crosser } 14959f48b9dbSEugene Crosser extrasize = sizeof(struct qeth_ipacmd_addr_change_entry) * 14969f48b9dbSEugene Crosser hostevs->num_entries; 1497a0138f59SAlexandra Winter data = kzalloc(sizeof(struct qeth_addr_change_data) + extrasize, 14989f48b9dbSEugene Crosser GFP_ATOMIC); 14999f48b9dbSEugene Crosser if (!data) { 1500a0138f59SAlexandra Winter QETH_CARD_TEXT(card, 2, "ACNalloc"); 15019f48b9dbSEugene Crosser return; 15029f48b9dbSEugene Crosser } 150310a6cfc0SAlexandra Winter if (card->info.pnso_mode == QETH_PNSO_BRIDGEPORT) 15049d6a569aSJulian Wiedmann INIT_DELAYED_WORK(&data->dwork, qeth_addr_change_event_worker); 150510a6cfc0SAlexandra Winter else 150610a6cfc0SAlexandra Winter INIT_DELAYED_WORK(&data->dwork, qeth_l2_dev2br_worker); 15079f48b9dbSEugene Crosser data->card = card; 1508a0138f59SAlexandra Winter memcpy(&data->ac_event, hostevs, 15099f48b9dbSEugene Crosser sizeof(struct qeth_ipacmd_addr_change) + extrasize); 15109d6a569aSJulian Wiedmann queue_delayed_work(card->event_wq, &data->dwork, 0); 15119f48b9dbSEugene Crosser } 15129f48b9dbSEugene Crosser 1513b4d72c08SEugene Crosser /* SETBRIDGEPORT support; sending commands */ 1514b4d72c08SEugene Crosser 1515b4d72c08SEugene Crosser struct _qeth_sbp_cbctl { 1516b4d72c08SEugene Crosser union { 1517b4d72c08SEugene Crosser u32 supported; 1518b4d72c08SEugene Crosser struct { 1519b4d72c08SEugene Crosser enum qeth_sbp_roles *role; 1520b4d72c08SEugene Crosser enum qeth_sbp_states *state; 1521b4d72c08SEugene Crosser } qports; 1522b4d72c08SEugene Crosser } data; 1523b4d72c08SEugene Crosser }; 1524b4d72c08SEugene Crosser 1525b4d72c08SEugene Crosser static int qeth_bridgeport_makerc(struct qeth_card *card, 15261709ff8dSJulian Wiedmann struct qeth_ipa_cmd *cmd) 1527b4d72c08SEugene Crosser { 15281709ff8dSJulian Wiedmann struct qeth_ipacmd_setbridgeport *sbp = &cmd->data.sbp; 15291709ff8dSJulian Wiedmann enum qeth_ipa_sbp_cmd setcmd = sbp->hdr.command_code; 15301709ff8dSJulian Wiedmann u16 ipa_rc = cmd->hdr.return_code; 15311709ff8dSJulian Wiedmann u16 sbp_rc = sbp->hdr.return_code; 1532b4d72c08SEugene Crosser int rc; 1533b4d72c08SEugene Crosser 15341709ff8dSJulian Wiedmann if (ipa_rc == IPA_RC_SUCCESS && sbp_rc == IPA_RC_SUCCESS) 15351709ff8dSJulian Wiedmann return 0; 15361709ff8dSJulian Wiedmann 15371709ff8dSJulian Wiedmann if ((IS_IQD(card) && ipa_rc == IPA_RC_SUCCESS) || 15381709ff8dSJulian Wiedmann (!IS_IQD(card) && ipa_rc == sbp_rc)) { 15391709ff8dSJulian Wiedmann switch (sbp_rc) { 15402063a5f5SKittipon Meesompop case IPA_RC_SUCCESS: 1541b4d72c08SEugene Crosser rc = 0; 1542b4d72c08SEugene Crosser break; 15432063a5f5SKittipon Meesompop case IPA_RC_L2_UNSUPPORTED_CMD: 15442063a5f5SKittipon Meesompop case IPA_RC_UNSUPPORTED_COMMAND: 1545ffb95251SEugene Crosser rc = -EOPNOTSUPP; 1546b4d72c08SEugene Crosser break; 15472063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_NOT_CONFIGURED: 15482063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_NOT_CONFIGURED: 1549b4d72c08SEugene Crosser rc = -ENODEV; /* maybe not the best code here? */ 1550b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 15519c23f4daSEugene Crosser "The device is not configured as a Bridge Port\n"); 1552b4d72c08SEugene Crosser break; 15532063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_OS_MISMATCH: 15542063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_OS_MISMATCH: 15551b05cf62SEugene Crosser rc = -EPERM; 15561b05cf62SEugene Crosser dev_err(&card->gdev->dev, 15571b05cf62SEugene Crosser "A Bridge Port is already configured by a different operating system\n"); 15581b05cf62SEugene Crosser break; 15592063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_ANO_DEV_PRIMARY: 15602063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_ANO_DEV_PRIMARY: 1561b4d72c08SEugene Crosser switch (setcmd) { 1562b4d72c08SEugene Crosser case IPA_SBP_SET_PRIMARY_BRIDGE_PORT: 1563b4d72c08SEugene Crosser rc = -EEXIST; 1564b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 15659c23f4daSEugene Crosser "The LAN already has a primary Bridge Port\n"); 1566b4d72c08SEugene Crosser break; 1567b4d72c08SEugene Crosser case IPA_SBP_SET_SECONDARY_BRIDGE_PORT: 1568b4d72c08SEugene Crosser rc = -EBUSY; 1569b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 15709c23f4daSEugene Crosser "The device is already a primary Bridge Port\n"); 1571b4d72c08SEugene Crosser break; 1572b4d72c08SEugene Crosser default: 1573b4d72c08SEugene Crosser rc = -EIO; 1574b4d72c08SEugene Crosser } 1575b4d72c08SEugene Crosser break; 15762063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_CURRENT_SECOND: 15772063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_CURRENT_SECOND: 1578b4d72c08SEugene Crosser rc = -EBUSY; 1579b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 15809c23f4daSEugene Crosser "The device is already a secondary Bridge Port\n"); 1581b4d72c08SEugene Crosser break; 15822063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_LIMIT_SECOND: 15832063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_LIMIT_SECOND: 1584b4d72c08SEugene Crosser rc = -EEXIST; 1585b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 15869c23f4daSEugene Crosser "The LAN cannot have more secondary Bridge Ports\n"); 1587b4d72c08SEugene Crosser break; 15882063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_CURRENT_PRIMARY: 15892063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_CURRENT_PRIMARY: 1590b4d72c08SEugene Crosser rc = -EBUSY; 1591b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 15929c23f4daSEugene Crosser "The device is already a primary Bridge Port\n"); 1593b4d72c08SEugene Crosser break; 15942063a5f5SKittipon Meesompop case IPA_RC_SBP_OSA_NOT_AUTHD_BY_ZMAN: 15952063a5f5SKittipon Meesompop case IPA_RC_SBP_IQD_NOT_AUTHD_BY_ZMAN: 1596b4d72c08SEugene Crosser rc = -EACCES; 1597b4d72c08SEugene Crosser dev_err(&card->gdev->dev, 15989c23f4daSEugene Crosser "The device is not authorized to be a Bridge Port\n"); 1599b4d72c08SEugene Crosser break; 1600b4d72c08SEugene Crosser default: 1601b4d72c08SEugene Crosser rc = -EIO; 1602b4d72c08SEugene Crosser } 16031709ff8dSJulian Wiedmann } else { 16041709ff8dSJulian Wiedmann switch (ipa_rc) { 1605b4d72c08SEugene Crosser case IPA_RC_NOTSUPP: 1606ffb95251SEugene Crosser rc = -EOPNOTSUPP; 1607b4d72c08SEugene Crosser break; 1608b4d72c08SEugene Crosser case IPA_RC_UNSUPPORTED_COMMAND: 1609ffb95251SEugene Crosser rc = -EOPNOTSUPP; 1610b4d72c08SEugene Crosser break; 1611b4d72c08SEugene Crosser default: 1612b4d72c08SEugene Crosser rc = -EIO; 1613b4d72c08SEugene Crosser } 16141709ff8dSJulian Wiedmann } 16159c23f4daSEugene Crosser 1616b4d72c08SEugene Crosser if (rc) { 16171709ff8dSJulian Wiedmann QETH_CARD_TEXT_(card, 2, "SBPi%04x", ipa_rc); 16181709ff8dSJulian Wiedmann QETH_CARD_TEXT_(card, 2, "SBPc%04x", sbp_rc); 1619b4d72c08SEugene Crosser } 1620b4d72c08SEugene Crosser return rc; 1621b4d72c08SEugene Crosser } 1622b4d72c08SEugene Crosser 1623d65626adSJulian Wiedmann static struct qeth_cmd_buffer *qeth_sbp_build_cmd(struct qeth_card *card, 1624d65626adSJulian Wiedmann enum qeth_ipa_sbp_cmd sbp_cmd, 1625b9150461SJulian Wiedmann unsigned int data_length) 16269c23f4daSEugene Crosser { 1627379ac99eSJulian Wiedmann enum qeth_ipa_cmds ipa_cmd = IS_IQD(card) ? IPA_CMD_SETBRIDGEPORT_IQD : 16289c23f4daSEugene Crosser IPA_CMD_SETBRIDGEPORT_OSA; 1629b9150461SJulian Wiedmann struct qeth_ipacmd_sbp_hdr *hdr; 1630d65626adSJulian Wiedmann struct qeth_cmd_buffer *iob; 1631d65626adSJulian Wiedmann 1632b9150461SJulian Wiedmann iob = qeth_ipa_alloc_cmd(card, ipa_cmd, QETH_PROT_NONE, 1633b9150461SJulian Wiedmann data_length + 1634b9150461SJulian Wiedmann offsetof(struct qeth_ipacmd_setbridgeport, 1635b9150461SJulian Wiedmann data)); 1636d65626adSJulian Wiedmann if (!iob) 1637d65626adSJulian Wiedmann return iob; 1638b9150461SJulian Wiedmann 1639b9150461SJulian Wiedmann hdr = &__ipa_cmd(iob)->data.sbp.hdr; 1640b9150461SJulian Wiedmann hdr->cmdlength = sizeof(*hdr) + data_length; 1641b9150461SJulian Wiedmann hdr->command_code = sbp_cmd; 1642b9150461SJulian Wiedmann hdr->used_total = 1; 1643b9150461SJulian Wiedmann hdr->seq_no = 1; 1644d65626adSJulian Wiedmann return iob; 16459c23f4daSEugene Crosser } 16469c23f4daSEugene Crosser 1647b4d72c08SEugene Crosser static int qeth_bridgeport_query_support_cb(struct qeth_card *card, 1648b4d72c08SEugene Crosser struct qeth_reply *reply, unsigned long data) 1649b4d72c08SEugene Crosser { 1650b4d72c08SEugene Crosser struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; 1651b4d72c08SEugene Crosser struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param; 16521709ff8dSJulian Wiedmann int rc; 16531709ff8dSJulian Wiedmann 1654b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brqsupcb"); 16551709ff8dSJulian Wiedmann rc = qeth_bridgeport_makerc(card, cmd); 16561709ff8dSJulian Wiedmann if (rc) 16571709ff8dSJulian Wiedmann return rc; 16581709ff8dSJulian Wiedmann 1659b4d72c08SEugene Crosser cbctl->data.supported = 1660b4d72c08SEugene Crosser cmd->data.sbp.data.query_cmds_supp.supported_cmds; 1661b4d72c08SEugene Crosser return 0; 1662b4d72c08SEugene Crosser } 1663b4d72c08SEugene Crosser 1664b4d72c08SEugene Crosser /** 1665b4d72c08SEugene Crosser * qeth_bridgeport_query_support() - store bitmask of supported subfunctions. 1666b4d72c08SEugene Crosser * @card: qeth_card structure pointer. 1667b4d72c08SEugene Crosser * 1668b4d72c08SEugene Crosser * Sets bitmask of supported setbridgeport subfunctions in the qeth_card 1669b4d72c08SEugene Crosser * strucutre: card->options.sbp.supported_funcs. 1670b4d72c08SEugene Crosser */ 1671c044dc21SEugene Crosser static void qeth_bridgeport_query_support(struct qeth_card *card) 1672b4d72c08SEugene Crosser { 1673b4d72c08SEugene Crosser struct qeth_cmd_buffer *iob; 1674b4d72c08SEugene Crosser struct _qeth_sbp_cbctl cbctl; 1675b4d72c08SEugene Crosser 1676b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brqsuppo"); 1677d65626adSJulian Wiedmann iob = qeth_sbp_build_cmd(card, IPA_SBP_QUERY_COMMANDS_SUPPORTED, 1678b9150461SJulian Wiedmann SBP_DATA_SIZEOF(query_cmds_supp)); 16791aec42bcSThomas Richter if (!iob) 16801aec42bcSThomas Richter return; 16811709ff8dSJulian Wiedmann 1682b4d72c08SEugene Crosser if (qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_support_cb, 16831709ff8dSJulian Wiedmann &cbctl)) { 1684b4d72c08SEugene Crosser card->options.sbp.role = QETH_SBP_ROLE_NONE; 16851709ff8dSJulian Wiedmann card->options.sbp.supported_funcs = 0; 1686b4d72c08SEugene Crosser return; 1687b4d72c08SEugene Crosser } 1688b4d72c08SEugene Crosser card->options.sbp.supported_funcs = cbctl.data.supported; 1689b4d72c08SEugene Crosser } 1690b4d72c08SEugene Crosser 1691b4d72c08SEugene Crosser static int qeth_bridgeport_query_ports_cb(struct qeth_card *card, 1692b4d72c08SEugene Crosser struct qeth_reply *reply, unsigned long data) 1693b4d72c08SEugene Crosser { 1694b4d72c08SEugene Crosser struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; 1695b4d72c08SEugene Crosser struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param; 169665b0494eSJulian Wiedmann struct qeth_sbp_port_data *qports; 16971709ff8dSJulian Wiedmann int rc; 1698b4d72c08SEugene Crosser 1699b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brqprtcb"); 17001709ff8dSJulian Wiedmann rc = qeth_bridgeport_makerc(card, cmd); 17011709ff8dSJulian Wiedmann if (rc) 17021709ff8dSJulian Wiedmann return rc; 17031709ff8dSJulian Wiedmann 170465b0494eSJulian Wiedmann qports = &cmd->data.sbp.data.port_data; 1705b4d72c08SEugene Crosser if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) { 1706b4d72c08SEugene Crosser QETH_CARD_TEXT_(card, 2, "SBPs%04x", qports->entry_length); 17071709ff8dSJulian Wiedmann return -EINVAL; 1708b4d72c08SEugene Crosser } 1709b4d72c08SEugene Crosser /* first entry contains the state of the local port */ 1710b4d72c08SEugene Crosser if (qports->num_entries > 0) { 1711b4d72c08SEugene Crosser if (cbctl->data.qports.role) 1712b4d72c08SEugene Crosser *cbctl->data.qports.role = qports->entry[0].role; 1713b4d72c08SEugene Crosser if (cbctl->data.qports.state) 1714b4d72c08SEugene Crosser *cbctl->data.qports.state = qports->entry[0].state; 1715b4d72c08SEugene Crosser } 1716b4d72c08SEugene Crosser return 0; 1717b4d72c08SEugene Crosser } 1718b4d72c08SEugene Crosser 1719b4d72c08SEugene Crosser /** 1720b4d72c08SEugene Crosser * qeth_bridgeport_query_ports() - query local bridgeport status. 1721b4d72c08SEugene Crosser * @card: qeth_card structure pointer. 1722b4d72c08SEugene Crosser * @role: Role of the port: 0-none, 1-primary, 2-secondary. 1723b4d72c08SEugene Crosser * @state: State of the port: 0-inactive, 1-standby, 2-active. 1724b4d72c08SEugene Crosser * 1725b4d72c08SEugene Crosser * Returns negative errno-compatible error indication or 0 on success. 1726b4d72c08SEugene Crosser * 1727b4d72c08SEugene Crosser * 'role' and 'state' are not updated in case of hardware operation failure. 1728b4d72c08SEugene Crosser */ 1729b4d72c08SEugene Crosser int qeth_bridgeport_query_ports(struct qeth_card *card, 1730b4d72c08SEugene Crosser enum qeth_sbp_roles *role, enum qeth_sbp_states *state) 1731b4d72c08SEugene Crosser { 1732b4d72c08SEugene Crosser struct qeth_cmd_buffer *iob; 1733b4d72c08SEugene Crosser struct _qeth_sbp_cbctl cbctl = { 1734b4d72c08SEugene Crosser .data = { 1735b4d72c08SEugene Crosser .qports = { 1736b4d72c08SEugene Crosser .role = role, 1737b4d72c08SEugene Crosser .state = state, 1738b4d72c08SEugene Crosser }, 1739b4d72c08SEugene Crosser }, 1740b4d72c08SEugene Crosser }; 1741b4d72c08SEugene Crosser 1742b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brqports"); 1743b4d72c08SEugene Crosser if (!(card->options.sbp.supported_funcs & IPA_SBP_QUERY_BRIDGE_PORTS)) 1744b4d72c08SEugene Crosser return -EOPNOTSUPP; 1745d65626adSJulian Wiedmann iob = qeth_sbp_build_cmd(card, IPA_SBP_QUERY_BRIDGE_PORTS, 0); 17461aec42bcSThomas Richter if (!iob) 17471aec42bcSThomas Richter return -ENOMEM; 17481709ff8dSJulian Wiedmann 17491709ff8dSJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_ports_cb, 17501709ff8dSJulian Wiedmann &cbctl); 1751b4d72c08SEugene Crosser } 1752b4d72c08SEugene Crosser 1753b4d72c08SEugene Crosser static int qeth_bridgeport_set_cb(struct qeth_card *card, 1754b4d72c08SEugene Crosser struct qeth_reply *reply, unsigned long data) 1755b4d72c08SEugene Crosser { 1756b4d72c08SEugene Crosser struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data; 17571709ff8dSJulian Wiedmann 1758b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brsetrcb"); 17591709ff8dSJulian Wiedmann return qeth_bridgeport_makerc(card, cmd); 1760b4d72c08SEugene Crosser } 1761b4d72c08SEugene Crosser 1762b4d72c08SEugene Crosser /** 1763b4d72c08SEugene Crosser * qeth_bridgeport_setrole() - Assign primary role to the port. 1764b4d72c08SEugene Crosser * @card: qeth_card structure pointer. 1765b4d72c08SEugene Crosser * @role: Role to assign. 1766b4d72c08SEugene Crosser * 1767b4d72c08SEugene Crosser * Returns negative errno-compatible error indication or 0 on success. 1768b4d72c08SEugene Crosser */ 1769b4d72c08SEugene Crosser int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role) 1770b4d72c08SEugene Crosser { 1771b4d72c08SEugene Crosser struct qeth_cmd_buffer *iob; 1772b4d72c08SEugene Crosser enum qeth_ipa_sbp_cmd setcmd; 1773b9150461SJulian Wiedmann unsigned int cmdlength = 0; 1774b4d72c08SEugene Crosser 1775b4d72c08SEugene Crosser QETH_CARD_TEXT(card, 2, "brsetrol"); 1776b4d72c08SEugene Crosser switch (role) { 1777b4d72c08SEugene Crosser case QETH_SBP_ROLE_NONE: 1778b4d72c08SEugene Crosser setcmd = IPA_SBP_RESET_BRIDGE_PORT_ROLE; 1779b4d72c08SEugene Crosser break; 1780b4d72c08SEugene Crosser case QETH_SBP_ROLE_PRIMARY: 1781b4d72c08SEugene Crosser setcmd = IPA_SBP_SET_PRIMARY_BRIDGE_PORT; 1782b9150461SJulian Wiedmann cmdlength = SBP_DATA_SIZEOF(set_primary); 1783b4d72c08SEugene Crosser break; 1784b4d72c08SEugene Crosser case QETH_SBP_ROLE_SECONDARY: 1785b4d72c08SEugene Crosser setcmd = IPA_SBP_SET_SECONDARY_BRIDGE_PORT; 1786b4d72c08SEugene Crosser break; 1787b4d72c08SEugene Crosser default: 1788b4d72c08SEugene Crosser return -EINVAL; 1789b4d72c08SEugene Crosser } 1790b4d72c08SEugene Crosser if (!(card->options.sbp.supported_funcs & setcmd)) 1791b4d72c08SEugene Crosser return -EOPNOTSUPP; 1792d65626adSJulian Wiedmann iob = qeth_sbp_build_cmd(card, setcmd, cmdlength); 17931aec42bcSThomas Richter if (!iob) 17941aec42bcSThomas Richter return -ENOMEM; 17951709ff8dSJulian Wiedmann 17961709ff8dSJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_bridgeport_set_cb, NULL); 1797b4d72c08SEugene Crosser } 1798b4d72c08SEugene Crosser 17999f48b9dbSEugene Crosser static void qeth_bridgeport_an_set_cb(void *priv, 1800a0138f59SAlexandra Winter struct chsc_pnso_naid_l2 *entry) 18019f48b9dbSEugene Crosser { 18029f48b9dbSEugene Crosser struct qeth_card *card = (struct qeth_card *)priv; 18039f48b9dbSEugene Crosser u8 code; 18049f48b9dbSEugene Crosser 18059f48b9dbSEugene Crosser code = IPA_ADDR_CHANGE_CODE_MACADDR; 1806a0138f59SAlexandra Winter if (entry->addr_lnid.lnid < VLAN_N_VID) 18079f48b9dbSEugene Crosser code |= IPA_ADDR_CHANGE_CODE_VLANID; 18089f48b9dbSEugene Crosser qeth_bridge_emit_host_event(card, anev_reg_unreg, code, 1809a0138f59SAlexandra Winter (struct net_if_token *)&entry->nit, 1810a0138f59SAlexandra Winter (struct mac_addr_lnid *)&entry->addr_lnid); 18119f48b9dbSEugene Crosser } 18129f48b9dbSEugene Crosser 18139f48b9dbSEugene Crosser /** 18149f48b9dbSEugene Crosser * qeth_bridgeport_an_set() - Enable or disable bridgeport address notification 18159f48b9dbSEugene Crosser * @card: qeth_card structure pointer. 18169f48b9dbSEugene Crosser * @enable: 0 - disable, non-zero - enable notifications 18179f48b9dbSEugene Crosser * 18189f48b9dbSEugene Crosser * Returns negative errno-compatible error indication or 0 on success. 18199f48b9dbSEugene Crosser * 18209f48b9dbSEugene Crosser * On enable, emits a series of address notifications udev events for all 18219f48b9dbSEugene Crosser * currently registered hosts. 18229f48b9dbSEugene Crosser */ 18239f48b9dbSEugene Crosser int qeth_bridgeport_an_set(struct qeth_card *card, int enable) 18249f48b9dbSEugene Crosser { 18259f48b9dbSEugene Crosser int rc; 18269f48b9dbSEugene Crosser 18279f48b9dbSEugene Crosser if (!card->options.sbp.supported_funcs) 18289f48b9dbSEugene Crosser return -EOPNOTSUPP; 18299f48b9dbSEugene Crosser 18309f48b9dbSEugene Crosser if (enable) { 18319f48b9dbSEugene Crosser qeth_bridge_emit_host_event(card, anev_reset, 0, NULL, NULL); 18329d6a569aSJulian Wiedmann qeth_l2_set_pnso_mode(card, QETH_PNSO_BRIDGEPORT); 18334fea49a7SAlexandra Winter rc = qeth_l2_pnso(card, PNSO_OC_NET_BRIDGE_INFO, 1, 18344fea49a7SAlexandra Winter qeth_bridgeport_an_set_cb, card); 18359d6a569aSJulian Wiedmann if (rc) 18369d6a569aSJulian Wiedmann qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE); 18379d6a569aSJulian Wiedmann } else { 18384fea49a7SAlexandra Winter rc = qeth_l2_pnso(card, PNSO_OC_NET_BRIDGE_INFO, 0, NULL, NULL); 18399d6a569aSJulian Wiedmann qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE); 18409d6a569aSJulian Wiedmann } 1841a0138f59SAlexandra Winter return rc; 18429f48b9dbSEugene Crosser } 18439f48b9dbSEugene Crosser 1844caa1f0b1SHans Wippel static bool qeth_bridgeport_is_in_use(struct qeth_card *card) 1845caa1f0b1SHans Wippel { 1846caa1f0b1SHans Wippel return (card->options.sbp.role || card->options.sbp.reflect_promisc || 1847caa1f0b1SHans Wippel card->options.sbp.hostnotification); 1848caa1f0b1SHans Wippel } 1849caa1f0b1SHans Wippel 1850a45b3fafSHans Wippel /* VNIC Characteristics support */ 1851a45b3fafSHans Wippel 1852a45b3fafSHans Wippel /* handle VNICC IPA command return codes; convert to error codes */ 1853742d4d40SJulian Wiedmann static int qeth_l2_vnicc_makerc(struct qeth_card *card, u16 ipa_rc) 1854a45b3fafSHans Wippel { 1855a45b3fafSHans Wippel int rc; 1856a45b3fafSHans Wippel 1857a45b3fafSHans Wippel switch (ipa_rc) { 1858a45b3fafSHans Wippel case IPA_RC_SUCCESS: 1859a45b3fafSHans Wippel return ipa_rc; 1860a45b3fafSHans Wippel case IPA_RC_L2_UNSUPPORTED_CMD: 1861a45b3fafSHans Wippel case IPA_RC_NOTSUPP: 1862a45b3fafSHans Wippel rc = -EOPNOTSUPP; 1863a45b3fafSHans Wippel break; 1864a45b3fafSHans Wippel case IPA_RC_VNICC_OOSEQ: 1865a45b3fafSHans Wippel rc = -EALREADY; 1866a45b3fafSHans Wippel break; 1867a45b3fafSHans Wippel case IPA_RC_VNICC_VNICBP: 1868a45b3fafSHans Wippel rc = -EBUSY; 1869a45b3fafSHans Wippel break; 1870a45b3fafSHans Wippel case IPA_RC_L2_ADDR_TABLE_FULL: 1871a45b3fafSHans Wippel rc = -ENOSPC; 1872a45b3fafSHans Wippel break; 1873a45b3fafSHans Wippel case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: 1874a45b3fafSHans Wippel rc = -EACCES; 1875a45b3fafSHans Wippel break; 1876a45b3fafSHans Wippel default: 1877a45b3fafSHans Wippel rc = -EIO; 1878a45b3fafSHans Wippel } 1879a45b3fafSHans Wippel 1880a45b3fafSHans Wippel QETH_CARD_TEXT_(card, 2, "err%04x", ipa_rc); 1881a45b3fafSHans Wippel return rc; 1882a45b3fafSHans Wippel } 1883a45b3fafSHans Wippel 1884a45b3fafSHans Wippel /* generic VNICC request call back */ 1885a45b3fafSHans Wippel static int qeth_l2_vnicc_request_cb(struct qeth_card *card, 1886a45b3fafSHans Wippel struct qeth_reply *reply, 1887a45b3fafSHans Wippel unsigned long data) 1888a45b3fafSHans Wippel { 1889a45b3fafSHans Wippel struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; 1890a45b3fafSHans Wippel struct qeth_ipacmd_vnicc *rep = &cmd->data.vnicc; 18912744d811SJulian Wiedmann u32 sub_cmd = cmd->data.vnicc.hdr.sub_command; 1892a45b3fafSHans Wippel 1893a45b3fafSHans Wippel QETH_CARD_TEXT(card, 2, "vniccrcb"); 1894a45b3fafSHans Wippel if (cmd->hdr.return_code) 1895742d4d40SJulian Wiedmann return qeth_l2_vnicc_makerc(card, cmd->hdr.return_code); 1896a45b3fafSHans Wippel /* return results to caller */ 18972cfb4810SJulian Wiedmann card->options.vnicc.sup_chars = rep->vnicc_cmds.supported; 18982cfb4810SJulian Wiedmann card->options.vnicc.cur_chars = rep->vnicc_cmds.enabled; 1899a45b3fafSHans Wippel 19002744d811SJulian Wiedmann if (sub_cmd == IPA_VNICC_QUERY_CMDS) 190149f42f5dSJulian Wiedmann *(u32 *)reply->param = rep->data.query_cmds.sup_cmds; 19022744d811SJulian Wiedmann else if (sub_cmd == IPA_VNICC_GET_TIMEOUT) 190349f42f5dSJulian Wiedmann *(u32 *)reply->param = rep->data.getset_timeout.timeout; 1904349d13d5SHans Wippel 1905a45b3fafSHans Wippel return 0; 1906a45b3fafSHans Wippel } 1907a45b3fafSHans Wippel 19082cfb4810SJulian Wiedmann static struct qeth_cmd_buffer *qeth_l2_vnicc_build_cmd(struct qeth_card *card, 19092cfb4810SJulian Wiedmann u32 vnicc_cmd, 19102cfb4810SJulian Wiedmann unsigned int data_length) 1911a45b3fafSHans Wippel { 19122cfb4810SJulian Wiedmann struct qeth_ipacmd_vnicc_hdr *hdr; 1913a45b3fafSHans Wippel struct qeth_cmd_buffer *iob; 1914a45b3fafSHans Wippel 19152cfb4810SJulian Wiedmann iob = qeth_ipa_alloc_cmd(card, IPA_CMD_VNICC, QETH_PROT_NONE, 19162cfb4810SJulian Wiedmann data_length + 19172cfb4810SJulian Wiedmann offsetof(struct qeth_ipacmd_vnicc, data)); 1918a45b3fafSHans Wippel if (!iob) 19192cfb4810SJulian Wiedmann return NULL; 1920a45b3fafSHans Wippel 19212cfb4810SJulian Wiedmann hdr = &__ipa_cmd(iob)->data.vnicc.hdr; 19222cfb4810SJulian Wiedmann hdr->data_length = sizeof(*hdr) + data_length; 19232cfb4810SJulian Wiedmann hdr->sub_command = vnicc_cmd; 19242cfb4810SJulian Wiedmann return iob; 1925a45b3fafSHans Wippel } 1926a45b3fafSHans Wippel 1927a45b3fafSHans Wippel /* VNICC query VNIC characteristics request */ 1928a45b3fafSHans Wippel static int qeth_l2_vnicc_query_chars(struct qeth_card *card) 1929a45b3fafSHans Wippel { 19302cfb4810SJulian Wiedmann struct qeth_cmd_buffer *iob; 19312cfb4810SJulian Wiedmann 19322cfb4810SJulian Wiedmann QETH_CARD_TEXT(card, 2, "vniccqch"); 19332cfb4810SJulian Wiedmann iob = qeth_l2_vnicc_build_cmd(card, IPA_VNICC_QUERY_CHARS, 0); 19342cfb4810SJulian Wiedmann if (!iob) 19352cfb4810SJulian Wiedmann return -ENOMEM; 1936a45b3fafSHans Wippel 19372744d811SJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, NULL); 1938a45b3fafSHans Wippel } 1939a45b3fafSHans Wippel 1940caa1f0b1SHans Wippel /* VNICC query sub commands request */ 1941caa1f0b1SHans Wippel static int qeth_l2_vnicc_query_cmds(struct qeth_card *card, u32 vnic_char, 1942caa1f0b1SHans Wippel u32 *sup_cmds) 1943caa1f0b1SHans Wippel { 19442cfb4810SJulian Wiedmann struct qeth_cmd_buffer *iob; 19452cfb4810SJulian Wiedmann 19462cfb4810SJulian Wiedmann QETH_CARD_TEXT(card, 2, "vniccqcm"); 19472cfb4810SJulian Wiedmann iob = qeth_l2_vnicc_build_cmd(card, IPA_VNICC_QUERY_CMDS, 19482cfb4810SJulian Wiedmann VNICC_DATA_SIZEOF(query_cmds)); 19492cfb4810SJulian Wiedmann if (!iob) 19502cfb4810SJulian Wiedmann return -ENOMEM; 19512cfb4810SJulian Wiedmann 19522cfb4810SJulian Wiedmann __ipa_cmd(iob)->data.vnicc.data.query_cmds.vnic_char = vnic_char; 1953caa1f0b1SHans Wippel 195449f42f5dSJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, sup_cmds); 1955caa1f0b1SHans Wippel } 1956caa1f0b1SHans Wippel 1957caa1f0b1SHans Wippel /* VNICC enable/disable characteristic request */ 1958caa1f0b1SHans Wippel static int qeth_l2_vnicc_set_char(struct qeth_card *card, u32 vnic_char, 1959caa1f0b1SHans Wippel u32 cmd) 1960caa1f0b1SHans Wippel { 19612cfb4810SJulian Wiedmann struct qeth_cmd_buffer *iob; 19622cfb4810SJulian Wiedmann 19632cfb4810SJulian Wiedmann QETH_CARD_TEXT(card, 2, "vniccedc"); 19642cfb4810SJulian Wiedmann iob = qeth_l2_vnicc_build_cmd(card, cmd, VNICC_DATA_SIZEOF(set_char)); 19652cfb4810SJulian Wiedmann if (!iob) 19662cfb4810SJulian Wiedmann return -ENOMEM; 19672cfb4810SJulian Wiedmann 19682cfb4810SJulian Wiedmann __ipa_cmd(iob)->data.vnicc.data.set_char.vnic_char = vnic_char; 1969caa1f0b1SHans Wippel 19702744d811SJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, NULL); 1971caa1f0b1SHans Wippel } 1972caa1f0b1SHans Wippel 1973349d13d5SHans Wippel /* VNICC get/set timeout for characteristic request */ 1974349d13d5SHans Wippel static int qeth_l2_vnicc_getset_timeout(struct qeth_card *card, u32 vnicc, 1975349d13d5SHans Wippel u32 cmd, u32 *timeout) 1976349d13d5SHans Wippel { 19772cfb4810SJulian Wiedmann struct qeth_vnicc_getset_timeout *getset_timeout; 19782cfb4810SJulian Wiedmann struct qeth_cmd_buffer *iob; 19792cfb4810SJulian Wiedmann 19802cfb4810SJulian Wiedmann QETH_CARD_TEXT(card, 2, "vniccgst"); 19812cfb4810SJulian Wiedmann iob = qeth_l2_vnicc_build_cmd(card, cmd, 19822cfb4810SJulian Wiedmann VNICC_DATA_SIZEOF(getset_timeout)); 19832cfb4810SJulian Wiedmann if (!iob) 19842cfb4810SJulian Wiedmann return -ENOMEM; 19852cfb4810SJulian Wiedmann 19862cfb4810SJulian Wiedmann getset_timeout = &__ipa_cmd(iob)->data.vnicc.data.getset_timeout; 19872cfb4810SJulian Wiedmann getset_timeout->vnic_char = vnicc; 19882cfb4810SJulian Wiedmann 19892cfb4810SJulian Wiedmann if (cmd == IPA_VNICC_SET_TIMEOUT) 19902cfb4810SJulian Wiedmann getset_timeout->timeout = *timeout; 1991349d13d5SHans Wippel 199249f42f5dSJulian Wiedmann return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, timeout); 1993349d13d5SHans Wippel } 1994349d13d5SHans Wippel 1995caa1f0b1SHans Wippel /* set current VNICC flag state; called from sysfs store function */ 1996caa1f0b1SHans Wippel int qeth_l2_vnicc_set_state(struct qeth_card *card, u32 vnicc, bool state) 1997caa1f0b1SHans Wippel { 1998caa1f0b1SHans Wippel int rc = 0; 1999caa1f0b1SHans Wippel u32 cmd; 2000caa1f0b1SHans Wippel 2001caa1f0b1SHans Wippel QETH_CARD_TEXT(card, 2, "vniccsch"); 2002caa1f0b1SHans Wippel 2003caa1f0b1SHans Wippel /* check if characteristic and enable/disable are supported */ 2004caa1f0b1SHans Wippel if (!(card->options.vnicc.sup_chars & vnicc) || 2005caa1f0b1SHans Wippel !(card->options.vnicc.set_char_sup & vnicc)) 2006caa1f0b1SHans Wippel return -EOPNOTSUPP; 2007caa1f0b1SHans Wippel 20086f3846f0SAlexandra Winter if (qeth_bridgeport_is_in_use(card)) 20096f3846f0SAlexandra Winter return -EBUSY; 20106f3846f0SAlexandra Winter 2011caa1f0b1SHans Wippel /* set enable/disable command and store wanted characteristic */ 2012caa1f0b1SHans Wippel if (state) { 2013caa1f0b1SHans Wippel cmd = IPA_VNICC_ENABLE; 2014caa1f0b1SHans Wippel card->options.vnicc.wanted_chars |= vnicc; 2015caa1f0b1SHans Wippel } else { 2016caa1f0b1SHans Wippel cmd = IPA_VNICC_DISABLE; 2017caa1f0b1SHans Wippel card->options.vnicc.wanted_chars &= ~vnicc; 2018caa1f0b1SHans Wippel } 2019caa1f0b1SHans Wippel 2020caa1f0b1SHans Wippel /* do we need to do anything? */ 2021caa1f0b1SHans Wippel if (card->options.vnicc.cur_chars == card->options.vnicc.wanted_chars) 2022caa1f0b1SHans Wippel return rc; 2023caa1f0b1SHans Wippel 2024caa1f0b1SHans Wippel /* if card is not ready, simply stop here */ 2025caa1f0b1SHans Wippel if (!qeth_card_hw_is_reachable(card)) { 2026caa1f0b1SHans Wippel if (state) 2027caa1f0b1SHans Wippel card->options.vnicc.cur_chars |= vnicc; 2028caa1f0b1SHans Wippel else 2029caa1f0b1SHans Wippel card->options.vnicc.cur_chars &= ~vnicc; 2030caa1f0b1SHans Wippel return rc; 2031caa1f0b1SHans Wippel } 2032caa1f0b1SHans Wippel 2033caa1f0b1SHans Wippel rc = qeth_l2_vnicc_set_char(card, vnicc, cmd); 2034caa1f0b1SHans Wippel if (rc) 2035caa1f0b1SHans Wippel card->options.vnicc.wanted_chars = 2036caa1f0b1SHans Wippel card->options.vnicc.cur_chars; 2037349d13d5SHans Wippel else { 2038349d13d5SHans Wippel /* successful online VNICC change; handle special cases */ 2039349d13d5SHans Wippel if (state && vnicc == QETH_VNICC_RX_BCAST) 2040caa1f0b1SHans Wippel card->options.vnicc.rx_bcast_enabled = true; 2041349d13d5SHans Wippel if (!state && vnicc == QETH_VNICC_LEARNING) 2042349d13d5SHans Wippel qeth_l2_vnicc_recover_timeout(card, vnicc, 2043349d13d5SHans Wippel &card->options.vnicc.learning_timeout); 2044349d13d5SHans Wippel } 2045caa1f0b1SHans Wippel 2046caa1f0b1SHans Wippel return rc; 2047caa1f0b1SHans Wippel } 2048caa1f0b1SHans Wippel 2049caa1f0b1SHans Wippel /* get current VNICC flag state; called from sysfs show function */ 2050caa1f0b1SHans Wippel int qeth_l2_vnicc_get_state(struct qeth_card *card, u32 vnicc, bool *state) 2051caa1f0b1SHans Wippel { 2052caa1f0b1SHans Wippel int rc = 0; 2053caa1f0b1SHans Wippel 2054caa1f0b1SHans Wippel QETH_CARD_TEXT(card, 2, "vniccgch"); 2055caa1f0b1SHans Wippel 2056caa1f0b1SHans Wippel /* check if characteristic is supported */ 2057caa1f0b1SHans Wippel if (!(card->options.vnicc.sup_chars & vnicc)) 2058caa1f0b1SHans Wippel return -EOPNOTSUPP; 2059caa1f0b1SHans Wippel 20606f3846f0SAlexandra Winter if (qeth_bridgeport_is_in_use(card)) 20616f3846f0SAlexandra Winter return -EBUSY; 20626f3846f0SAlexandra Winter 2063caa1f0b1SHans Wippel /* if card is ready, query current VNICC state */ 2064caa1f0b1SHans Wippel if (qeth_card_hw_is_reachable(card)) 2065caa1f0b1SHans Wippel rc = qeth_l2_vnicc_query_chars(card); 2066caa1f0b1SHans Wippel 2067caa1f0b1SHans Wippel *state = (card->options.vnicc.cur_chars & vnicc) ? true : false; 2068caa1f0b1SHans Wippel return rc; 2069caa1f0b1SHans Wippel } 2070caa1f0b1SHans Wippel 2071349d13d5SHans Wippel /* set VNICC timeout; called from sysfs store function. Currently, only learning 2072349d13d5SHans Wippel * supports timeout 2073349d13d5SHans Wippel */ 2074349d13d5SHans Wippel int qeth_l2_vnicc_set_timeout(struct qeth_card *card, u32 timeout) 2075349d13d5SHans Wippel { 2076349d13d5SHans Wippel int rc = 0; 2077349d13d5SHans Wippel 2078349d13d5SHans Wippel QETH_CARD_TEXT(card, 2, "vniccsto"); 2079349d13d5SHans Wippel 2080349d13d5SHans Wippel /* check if characteristic and set_timeout are supported */ 2081349d13d5SHans Wippel if (!(card->options.vnicc.sup_chars & QETH_VNICC_LEARNING) || 2082349d13d5SHans Wippel !(card->options.vnicc.getset_timeout_sup & QETH_VNICC_LEARNING)) 2083349d13d5SHans Wippel return -EOPNOTSUPP; 2084349d13d5SHans Wippel 20856f3846f0SAlexandra Winter if (qeth_bridgeport_is_in_use(card)) 20866f3846f0SAlexandra Winter return -EBUSY; 20876f3846f0SAlexandra Winter 2088349d13d5SHans Wippel /* do we need to do anything? */ 2089349d13d5SHans Wippel if (card->options.vnicc.learning_timeout == timeout) 2090349d13d5SHans Wippel return rc; 2091349d13d5SHans Wippel 2092349d13d5SHans Wippel /* if card is not ready, simply store the value internally and return */ 2093349d13d5SHans Wippel if (!qeth_card_hw_is_reachable(card)) { 2094349d13d5SHans Wippel card->options.vnicc.learning_timeout = timeout; 2095349d13d5SHans Wippel return rc; 2096349d13d5SHans Wippel } 2097349d13d5SHans Wippel 2098349d13d5SHans Wippel /* send timeout value to card; if successful, store value internally */ 2099349d13d5SHans Wippel rc = qeth_l2_vnicc_getset_timeout(card, QETH_VNICC_LEARNING, 2100349d13d5SHans Wippel IPA_VNICC_SET_TIMEOUT, &timeout); 2101349d13d5SHans Wippel if (!rc) 2102349d13d5SHans Wippel card->options.vnicc.learning_timeout = timeout; 2103349d13d5SHans Wippel 2104349d13d5SHans Wippel return rc; 2105349d13d5SHans Wippel } 2106349d13d5SHans Wippel 2107349d13d5SHans Wippel /* get current VNICC timeout; called from sysfs show function. Currently, only 2108349d13d5SHans Wippel * learning supports timeout 2109349d13d5SHans Wippel */ 2110349d13d5SHans Wippel int qeth_l2_vnicc_get_timeout(struct qeth_card *card, u32 *timeout) 2111349d13d5SHans Wippel { 2112349d13d5SHans Wippel int rc = 0; 2113349d13d5SHans Wippel 2114349d13d5SHans Wippel QETH_CARD_TEXT(card, 2, "vniccgto"); 2115349d13d5SHans Wippel 2116349d13d5SHans Wippel /* check if characteristic and get_timeout are supported */ 2117349d13d5SHans Wippel if (!(card->options.vnicc.sup_chars & QETH_VNICC_LEARNING) || 2118349d13d5SHans Wippel !(card->options.vnicc.getset_timeout_sup & QETH_VNICC_LEARNING)) 2119349d13d5SHans Wippel return -EOPNOTSUPP; 21206f3846f0SAlexandra Winter 21216f3846f0SAlexandra Winter if (qeth_bridgeport_is_in_use(card)) 21226f3846f0SAlexandra Winter return -EBUSY; 21236f3846f0SAlexandra Winter 2124349d13d5SHans Wippel /* if card is ready, get timeout. Otherwise, just return stored value */ 2125349d13d5SHans Wippel *timeout = card->options.vnicc.learning_timeout; 2126349d13d5SHans Wippel if (qeth_card_hw_is_reachable(card)) 2127349d13d5SHans Wippel rc = qeth_l2_vnicc_getset_timeout(card, QETH_VNICC_LEARNING, 2128349d13d5SHans Wippel IPA_VNICC_GET_TIMEOUT, 2129349d13d5SHans Wippel timeout); 2130349d13d5SHans Wippel 2131349d13d5SHans Wippel return rc; 2132349d13d5SHans Wippel } 2133349d13d5SHans Wippel 2134caa1f0b1SHans Wippel /* check if VNICC is currently enabled */ 2135817741a8SAlexandra Winter static bool _qeth_l2_vnicc_is_in_use(struct qeth_card *card) 2136caa1f0b1SHans Wippel { 2137e8a66d80SAlexandra Winter if (!card->options.vnicc.sup_chars) 2138caa1f0b1SHans Wippel return false; 2139caa1f0b1SHans Wippel /* default values are only OK if rx_bcast was not enabled by user 2140caa1f0b1SHans Wippel * or the card is offline. 2141caa1f0b1SHans Wippel */ 2142caa1f0b1SHans Wippel if (card->options.vnicc.cur_chars == QETH_VNICC_DEFAULT) { 2143caa1f0b1SHans Wippel if (!card->options.vnicc.rx_bcast_enabled || 2144caa1f0b1SHans Wippel !qeth_card_hw_is_reachable(card)) 2145caa1f0b1SHans Wippel return false; 2146caa1f0b1SHans Wippel } 2147caa1f0b1SHans Wippel return true; 2148caa1f0b1SHans Wippel } 2149caa1f0b1SHans Wippel 2150817741a8SAlexandra Winter /** 2151817741a8SAlexandra Winter * qeth_bridgeport_allowed - are any qeth_bridgeport functions allowed? 2152817741a8SAlexandra Winter * @card: qeth_card structure pointer 2153817741a8SAlexandra Winter * 2154817741a8SAlexandra Winter * qeth_bridgeport functionality is mutually exclusive with usage of the 2155817741a8SAlexandra Winter * VNIC Characteristics and dev2br address notifications 2156817741a8SAlexandra Winter */ 2157817741a8SAlexandra Winter bool qeth_bridgeport_allowed(struct qeth_card *card) 2158817741a8SAlexandra Winter { 2159817741a8SAlexandra Winter struct qeth_priv *priv = netdev_priv(card->dev); 2160817741a8SAlexandra Winter 2161817741a8SAlexandra Winter return (!_qeth_l2_vnicc_is_in_use(card) && 2162817741a8SAlexandra Winter !(priv->brport_features & BR_LEARNING_SYNC)); 2163817741a8SAlexandra Winter } 2164817741a8SAlexandra Winter 2165349d13d5SHans Wippel /* recover user timeout setting */ 2166349d13d5SHans Wippel static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc, 2167349d13d5SHans Wippel u32 *timeout) 2168349d13d5SHans Wippel { 2169349d13d5SHans Wippel if (card->options.vnicc.sup_chars & vnicc && 2170349d13d5SHans Wippel card->options.vnicc.getset_timeout_sup & vnicc && 2171349d13d5SHans Wippel !qeth_l2_vnicc_getset_timeout(card, vnicc, IPA_VNICC_SET_TIMEOUT, 2172349d13d5SHans Wippel timeout)) 2173349d13d5SHans Wippel return false; 2174349d13d5SHans Wippel *timeout = QETH_VNICC_DEFAULT_TIMEOUT; 2175349d13d5SHans Wippel return true; 2176349d13d5SHans Wippel } 2177349d13d5SHans Wippel 2178caa1f0b1SHans Wippel /* recover user characteristic setting */ 2179caa1f0b1SHans Wippel static bool qeth_l2_vnicc_recover_char(struct qeth_card *card, u32 vnicc, 2180caa1f0b1SHans Wippel bool enable) 2181caa1f0b1SHans Wippel { 2182caa1f0b1SHans Wippel u32 cmd = enable ? IPA_VNICC_ENABLE : IPA_VNICC_DISABLE; 2183caa1f0b1SHans Wippel 2184caa1f0b1SHans Wippel if (card->options.vnicc.sup_chars & vnicc && 2185caa1f0b1SHans Wippel card->options.vnicc.set_char_sup & vnicc && 2186caa1f0b1SHans Wippel !qeth_l2_vnicc_set_char(card, vnicc, cmd)) 2187caa1f0b1SHans Wippel return false; 2188caa1f0b1SHans Wippel card->options.vnicc.wanted_chars &= ~vnicc; 2189caa1f0b1SHans Wippel card->options.vnicc.wanted_chars |= QETH_VNICC_DEFAULT & vnicc; 2190caa1f0b1SHans Wippel return true; 2191caa1f0b1SHans Wippel } 2192caa1f0b1SHans Wippel 2193a45b3fafSHans Wippel /* (re-)initialize VNICC */ 2194a45b3fafSHans Wippel static void qeth_l2_vnicc_init(struct qeth_card *card) 2195a45b3fafSHans Wippel { 2196349d13d5SHans Wippel u32 *timeout = &card->options.vnicc.learning_timeout; 2197b528965bSAlexandra Winter bool enable, error = false; 2198caa1f0b1SHans Wippel unsigned int chars_len, i; 2199caa1f0b1SHans Wippel unsigned long chars_tmp; 2200caa1f0b1SHans Wippel u32 sup_cmds, vnicc; 2201caa1f0b1SHans Wippel 2202a45b3fafSHans Wippel QETH_CARD_TEXT(card, 2, "vniccini"); 2203caa1f0b1SHans Wippel /* reset rx_bcast */ 2204caa1f0b1SHans Wippel card->options.vnicc.rx_bcast_enabled = 0; 2205a45b3fafSHans Wippel /* initial query and storage of VNIC characteristics */ 2206a45b3fafSHans Wippel if (qeth_l2_vnicc_query_chars(card)) { 2207349d13d5SHans Wippel if (card->options.vnicc.wanted_chars != QETH_VNICC_DEFAULT || 2208349d13d5SHans Wippel *timeout != QETH_VNICC_DEFAULT_TIMEOUT) 2209caa1f0b1SHans Wippel dev_err(&card->gdev->dev, "Configuring the VNIC characteristics failed\n"); 2210caa1f0b1SHans Wippel /* fail quietly if user didn't change the default config */ 2211a45b3fafSHans Wippel card->options.vnicc.sup_chars = 0; 2212a45b3fafSHans Wippel card->options.vnicc.cur_chars = 0; 2213caa1f0b1SHans Wippel card->options.vnicc.wanted_chars = QETH_VNICC_DEFAULT; 2214caa1f0b1SHans Wippel return; 2215a45b3fafSHans Wippel } 2216caa1f0b1SHans Wippel /* get supported commands for each supported characteristic */ 2217caa1f0b1SHans Wippel chars_tmp = card->options.vnicc.sup_chars; 2218caa1f0b1SHans Wippel chars_len = sizeof(card->options.vnicc.sup_chars) * BITS_PER_BYTE; 2219caa1f0b1SHans Wippel for_each_set_bit(i, &chars_tmp, chars_len) { 2220caa1f0b1SHans Wippel vnicc = BIT(i); 2221b528965bSAlexandra Winter if (qeth_l2_vnicc_query_cmds(card, vnicc, &sup_cmds)) { 2222b528965bSAlexandra Winter sup_cmds = 0; 2223b528965bSAlexandra Winter error = true; 2224b528965bSAlexandra Winter } 2225be40a86cSAlexandra Winter if ((sup_cmds & IPA_VNICC_SET_TIMEOUT) && 2226be40a86cSAlexandra Winter (sup_cmds & IPA_VNICC_GET_TIMEOUT)) 2227be40a86cSAlexandra Winter card->options.vnicc.getset_timeout_sup |= vnicc; 2228be40a86cSAlexandra Winter else 2229349d13d5SHans Wippel card->options.vnicc.getset_timeout_sup &= ~vnicc; 2230be40a86cSAlexandra Winter if ((sup_cmds & IPA_VNICC_ENABLE) && 2231be40a86cSAlexandra Winter (sup_cmds & IPA_VNICC_DISABLE)) 2232be40a86cSAlexandra Winter card->options.vnicc.set_char_sup |= vnicc; 2233be40a86cSAlexandra Winter else 2234caa1f0b1SHans Wippel card->options.vnicc.set_char_sup &= ~vnicc; 2235caa1f0b1SHans Wippel } 2236caa1f0b1SHans Wippel /* enforce assumed default values and recover settings, if changed */ 2237b528965bSAlexandra Winter error |= qeth_l2_vnicc_recover_timeout(card, QETH_VNICC_LEARNING, 2238349d13d5SHans Wippel timeout); 2239d1b9ae18SAlexandra Winter /* Change chars, if necessary */ 2240d1b9ae18SAlexandra Winter chars_tmp = card->options.vnicc.wanted_chars ^ 2241d1b9ae18SAlexandra Winter card->options.vnicc.cur_chars; 2242caa1f0b1SHans Wippel chars_len = sizeof(card->options.vnicc.wanted_chars) * BITS_PER_BYTE; 2243caa1f0b1SHans Wippel for_each_set_bit(i, &chars_tmp, chars_len) { 2244caa1f0b1SHans Wippel vnicc = BIT(i); 2245caa1f0b1SHans Wippel enable = card->options.vnicc.wanted_chars & vnicc; 2246caa1f0b1SHans Wippel error |= qeth_l2_vnicc_recover_char(card, vnicc, enable); 2247caa1f0b1SHans Wippel } 2248caa1f0b1SHans Wippel if (error) 2249caa1f0b1SHans Wippel dev_err(&card->gdev->dev, "Configuring the VNIC characteristics failed\n"); 2250caa1f0b1SHans Wippel } 2251caa1f0b1SHans Wippel 2252caa1f0b1SHans Wippel /* configure default values of VNIC characteristics */ 2253caa1f0b1SHans Wippel static void qeth_l2_vnicc_set_defaults(struct qeth_card *card) 2254caa1f0b1SHans Wippel { 2255caa1f0b1SHans Wippel /* characteristics values */ 2256caa1f0b1SHans Wippel card->options.vnicc.sup_chars = QETH_VNICC_ALL; 2257caa1f0b1SHans Wippel card->options.vnicc.cur_chars = QETH_VNICC_DEFAULT; 2258349d13d5SHans Wippel card->options.vnicc.learning_timeout = QETH_VNICC_DEFAULT_TIMEOUT; 2259caa1f0b1SHans Wippel /* supported commands */ 2260caa1f0b1SHans Wippel card->options.vnicc.set_char_sup = QETH_VNICC_ALL; 2261349d13d5SHans Wippel card->options.vnicc.getset_timeout_sup = QETH_VNICC_LEARNING; 2262caa1f0b1SHans Wippel /* settings wanted by users */ 2263caa1f0b1SHans Wippel card->options.vnicc.wanted_chars = QETH_VNICC_DEFAULT; 2264a45b3fafSHans Wippel } 2265a45b3fafSHans Wippel 22664a71df50SFrank Blaschka module_init(qeth_l2_init); 22674a71df50SFrank Blaschka module_exit(qeth_l2_exit); 22684a71df50SFrank Blaschka MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>"); 22694a71df50SFrank Blaschka MODULE_DESCRIPTION("qeth layer 2 discipline"); 22704a71df50SFrank Blaschka MODULE_LICENSE("GPL"); 2271