linux/drivers/s390/net/qeth_l2_main.c

2352 lines
63 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright IBM Corp. 2007, 2009
* Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
* Frank Pavlic <fpavlic@de.ibm.com>,
* Thomas Spatzier <tspat@de.ibm.com>,
* Frank Blaschka <frank.blaschka@de.ibm.com>
*/
#define KMSG_COMPONENT "qeth"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/kernel.h>
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h percpu.h is included by sched.h and module.h and thus ends up being included when building most .c files. percpu.h includes slab.h which in turn includes gfp.h making everything defined by the two files universally available and complicating inclusion dependencies. percpu.h -> slab.h dependency is about to be removed. Prepare for this change by updating users of gfp and slab facilities include those headers directly instead of assuming availability. As this conversion needs to touch large number of source files, the following script is used as the basis of conversion. http://userweb.kernel.org/~tj/misc/slabh-sweep.py The script does the followings. * Scan files for gfp and slab usages and update includes such that only the necessary includes are there. ie. if only gfp is used, gfp.h, if slab is used, slab.h. * When the script inserts a new include, it looks at the include blocks and try to put the new include such that its order conforms to its surrounding. It's put in the include block which contains core kernel includes, in the same order that the rest are ordered - alphabetical, Christmas tree, rev-Xmas-tree or at the end if there doesn't seem to be any matching order. * If the script can't find a place to put a new include (mostly because the file doesn't have fitting include block), it prints out an error message indicating which .h file needs to be added to the file. The conversion was done in the following steps. 1. The initial automatic conversion of all .c files updated slightly over 4000 files, deleting around 700 includes and adding ~480 gfp.h and ~3000 slab.h inclusions. The script emitted errors for ~400 files. 2. Each error was manually checked. Some didn't need the inclusion, some needed manual addition while adding it to implementation .h or embedding .c file was more appropriate for others. This step added inclusions to around 150 files. 3. The script was run again and the output was compared to the edits from #2 to make sure no file was left behind. 4. Several build tests were done and a couple of problems were fixed. e.g. lib/decompress_*.c used malloc/free() wrappers around slab APIs requiring slab.h to be added manually. 5. The script was run on all .h files but without automatically editing them as sprinkling gfp.h and slab.h inclusions around .h files could easily lead to inclusion dependency hell. Most gfp.h inclusion directives were ignored as stuff from gfp.h was usually wildly available and often used in preprocessor macros. Each slab.h inclusion directive was examined and added manually as necessary. 6. percpu.h was updated not to include slab.h. 7. Build test were done on the following configurations and failures were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my distributed build env didn't work with gcov compiles) and a few more options had to be turned off depending on archs to make things build (like ipr on powerpc/64 which failed due to missing writeq). * x86 and x86_64 UP and SMP allmodconfig and a custom test config. * powerpc and powerpc64 SMP allmodconfig * sparc and sparc64 SMP allmodconfig * ia64 SMP allmodconfig * s390 SMP allmodconfig * alpha SMP allmodconfig * um on x86_64 SMP allmodconfig 8. percpu.h modifications were reverted so that it could be applied as a separate patch and serve as bisection point. Given the fact that I had only a couple of failures from tests on step 6, I'm fairly confident about the coverage of this conversion patch. If there is a breakage, it's likely to be something in one of the arch headers which should be easily discoverable easily on most builds of the specific arch. Signed-off-by: Tejun Heo <tj@kernel.org> Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
#include <linux/slab.h>
#include <linux/etherdevice.h>
#include <linux/if_bridge.h>
#include <linux/list.h>
#include <linux/hash.h>
#include <linux/hashtable.h>
s390/qeth: Translate address events into switchdev notifiers A qeth-l2 HiperSockets card can show switch-ish behaviour in the sense, that it can report all MACs that are reachable via this interface. Just like a switch device, it can notify the software bridge about changes to its fdb. This patch exploits this device-to-bridge-notification and extracts the relevant information from the hardware events to generate notifications to an attached software bridge. There are 2 sources for this information: 1) The reply message of Perform-Network-Subchannel-Operations (PNSO) (operation code ADDR_INFO) reports all addresses that are currently reachable (implemented in a later patch). 2) As long as device-to-bridge-notification is enabled, hardware will generate address change notification events, whenever the content of the hardware fdb changes (this patch). The bridge_hostnotify feature (PNSO operation code BRIDGE_INFO) uses the same address change notification events. We need to distinguish between qeth_pnso_mode QETH_PNSO_BRIDGEPORT and QETH_PNSO_ADDR_INFO and call a different handler. In both cases deadlocks must be prevented, if the workqueue is drained under lock and QETH_PNSO_NONE, when notification is disabled. bridge_hostnotify generates udev events, there is no intend to do the same for dev2br. Instead this patch will generate SWITCHDEV_FDB_ADD_TO_BRIDGE and SWITCHDEV_FDB_DEL_TO_BRIDGE notifications, that will cause the software bridge to add (or delete) entries to its fdb as 'extern_learn offload'. Documentation/networking/switchdev.txt proposes to add "depends NET_SWITCHDEV" to driver's Kconfig. This is not done here, so even in absence of the NET_SWITCHDEV module, the QETH_L2 module will still be built, but then the switchdev notifiers will have no effect. No VLAN filtering is done on the entries and VLAN information is not passed on to the bridge fdb entries. This could be added later. For now VLAN interfaces can be defined on the upper bridge interface. Multicast entries are not passed on to the bridge fdb. This could be added later. For now mcast flooding can be used in the bridge. The card reports all MACs that are in its FDB, but we must not pass on MACs that are registered for this interface. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:47 +08:00
#include <net/switchdev.h>
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
#include <asm/chsc.h>
#include <asm/css_chars.h>
#include <asm/setup.h>
#include "qeth_core.h"
#include "qeth_l2.h"
static int qeth_l2_setdelmac_makerc(struct qeth_card *card, u16 retcode)
{
int rc;
if (retcode)
390/qeth: Fix locking warning during qeth device setup Do not wait for channel command buffers in IPA commands. The potential wait could be done while holding a spin lock and causes in recent kernels such a bug if kernel lock debugging is enabled: kernel: BUG: sleeping function called from invalid context at drivers/s390/net/qeth_core_main.c: 794 kernel: in_atomic(): 1, irqs_disabled(): 0, pid: 2031, name: NetworkManager kernel: 2 locks held by NetworkManager/2031: kernel: #0: (rtnl_mutex){+.+.+.}, at: [<00000000006e0d7a>] rtnetlink_rcv+0x32/0x50 kernel: #1: (_xmit_ETHER){+.....}, at: [<00000000006cfe90>] dev_set_rx_mode+0x30/0x50 kernel: CPU: 0 PID: 2031 Comm: NetworkManager Not tainted 3.18.0-rc5-next-20141124 #1 kernel: 00000000275fb1f0 00000000275fb280 0000000000000002 0000000000000000 00000000275fb320 00000000275fb298 00000000275fb298 00000000007e326a 0000000000000000 000000000099ce2c 00000000009b4988 000000000000000b 00000000275fb2e0 00000000275fb280 0000000000000000 0000000000000000 0000000000000000 00000000001129c8 00000000275fb280 00000000275fb2e0 kernel: Call Trace: kernel: ([<00000000001128b0>] show_trace+0xf8/0x158) kernel: [<000000000011297a>] show_stack+0x6a/0xe8 kernel: [<00000000007e995a>] dump_stack+0x82/0xb0 kernel: [<000000000017d668>] ___might_sleep+0x170/0x228 kernel: [<000003ff80026f0e>] qeth_wait_for_buffer+0x36/0xd0 [qeth] kernel: [<000003ff80026fe2>] qeth_get_ipacmd_buffer+0x3a/0xc0 [qeth] kernel: [<000003ff80105078>] qeth_l3_send_setdelmc+0x58/0xf8 [qeth_l3] kernel: [<000003ff8010b1fe>] qeth_l3_set_ip_addr_list+0x2c6/0x848 [qeth_l3] kernel: [<000003ff8010bbb4>] qeth_l3_set_multicast_list+0x434/0xc48 [qeth_l3] kernel: [<00000000006cfe9a>] dev_set_rx_mode+0x3a/0x50 kernel: [<00000000006cff90>] __dev_open+0xe0/0x140 kernel: [<00000000006d02a0>] __dev_change_flags+0xa0/0x178 kernel: [<00000000006d03a8>] dev_change_flags+0x30/0x70 kernel: [<00000000006e14ee>] do_setlink+0x346/0x9a0 ... The device driver has plenty of command buffers available per channel for channel command communication. In the extremely rare case when there is no command buffer available, return a NULL pointer and issue a warning in the kernel log. The caller handles the case when a NULL pointer is encountered and returns an error. In the case the wait for command buffer is possible (because no lock is held as in the OSN case), still wait until a channel command buffer is available. Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com> Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Reviewed-by: Eugene Crosser <Eugene.Crosser@ru.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-01-21 20:39:10 +08:00
QETH_CARD_TEXT_(card, 2, "err%04x", retcode);
switch (retcode) {
case IPA_RC_SUCCESS:
rc = 0;
break;
case IPA_RC_L2_UNSUPPORTED_CMD:
rc = -EOPNOTSUPP;
break;
case IPA_RC_L2_ADDR_TABLE_FULL:
rc = -ENOSPC;
break;
case IPA_RC_L2_DUP_MAC:
case IPA_RC_L2_DUP_LAYER3_MAC:
rc = -EADDRINUSE;
break;
case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP:
case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP:
rc = -EADDRNOTAVAIL;
break;
case IPA_RC_L2_MAC_NOT_FOUND:
rc = -ENOENT;
break;
default:
rc = -EIO;
break;
}
return rc;
}
static int qeth_l2_send_setdelmac_cb(struct qeth_card *card,
struct qeth_reply *reply,
unsigned long data)
{
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
return qeth_l2_setdelmac_makerc(card, cmd->hdr.return_code);
}
static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac,
enum qeth_ipa_cmds ipacmd)
{
struct qeth_ipa_cmd *cmd;
struct qeth_cmd_buffer *iob;
QETH_CARD_TEXT(card, 2, "L2sdmac");
iob = qeth_ipa_alloc_cmd(card, ipacmd, QETH_PROT_IPV4,
IPA_DATA_SIZEOF(setdelmac));
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
cmd->data.setdelmac.mac_length = ETH_ALEN;
ether_addr_copy(cmd->data.setdelmac.mac, mac);
return qeth_send_ipa_cmd(card, iob, qeth_l2_send_setdelmac_cb, NULL);
}
static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
{
int rc;
QETH_CARD_TEXT(card, 2, "L2Setmac");
rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC);
if (rc == 0) {
dev_info(&card->gdev->dev,
"MAC address %pM successfully registered\n", mac);
} else {
switch (rc) {
case -EADDRINUSE:
dev_warn(&card->gdev->dev,
"MAC address %pM already exists\n", mac);
break;
case -EADDRNOTAVAIL:
dev_warn(&card->gdev->dev,
"MAC address %pM is not authorized\n", mac);
break;
}
}
return rc;
}
static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac)
{
enum qeth_ipa_cmds cmd = is_multicast_ether_addr(mac) ?
IPA_CMD_SETGMAC : IPA_CMD_SETVMAC;
int rc;
QETH_CARD_TEXT(card, 2, "L2Wmac");
rc = qeth_l2_send_setdelmac(card, mac, cmd);
if (rc == -EADDRINUSE)
QETH_DBF_MESSAGE(2, "MAC already registered on device %x\n",
CARD_DEVID(card));
else if (rc)
QETH_DBF_MESSAGE(2, "Failed to register MAC on device %x: %d\n",
CARD_DEVID(card), rc);
return rc;
}
static int qeth_l2_remove_mac(struct qeth_card *card, u8 *mac)
{
enum qeth_ipa_cmds cmd = is_multicast_ether_addr(mac) ?
IPA_CMD_DELGMAC : IPA_CMD_DELVMAC;
int rc;
QETH_CARD_TEXT(card, 2, "L2Rmac");
rc = qeth_l2_send_setdelmac(card, mac, cmd);
if (rc)
QETH_DBF_MESSAGE(2, "Failed to delete MAC on device %u: %d\n",
CARD_DEVID(card), rc);
return rc;
}
static void qeth_l2_drain_rx_mode_cache(struct qeth_card *card)
{
struct qeth_mac *mac;
struct hlist_node *tmp;
int i;
hash_for_each_safe(card->rx_mode_addrs, i, tmp, mac, hnode) {
hash_del(&mac->hnode);
kfree(mac);
}
}
static void qeth_l2_fill_header(struct qeth_qdio_out_q *queue,
struct qeth_hdr *hdr, struct sk_buff *skb,
__be16 proto, unsigned int data_len)
{
int cast_type = qeth_get_ether_cast_type(skb);
struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
hdr->hdr.l2.pkt_length = data_len;
if (skb_is_gso(skb)) {
hdr->hdr.l2.id = QETH_HEADER_TYPE_L2_TSO;
} else {
hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2;
if (skb->ip_summed == CHECKSUM_PARTIAL)
qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], proto);
}
/* set byte byte 3 to casting flags */
if (cast_type == RTN_MULTICAST)
hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_MULTICAST;
else if (cast_type == RTN_BROADCAST)
hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_BROADCAST;
else
hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_UNICAST;
/* VSWITCH relies on the VLAN
* information to be present in
* the QDIO header */
if (veth->h_vlan_proto == htons(ETH_P_8021Q)) {
hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_VLAN;
hdr->hdr.l2.vlan_id = ntohs(veth->h_vlan_TCI);
}
}
static int qeth_l2_setdelvlan_makerc(struct qeth_card *card, u16 retcode)
{
if (retcode)
QETH_CARD_TEXT_(card, 2, "err%04x", retcode);
switch (retcode) {
case IPA_RC_SUCCESS:
return 0;
case IPA_RC_L2_INVALID_VLAN_ID:
return -EINVAL;
case IPA_RC_L2_DUP_VLAN_ID:
return -EEXIST;
case IPA_RC_L2_VLAN_ID_NOT_FOUND:
return -ENOENT;
case IPA_RC_L2_VLAN_ID_NOT_ALLOWED:
return -EPERM;
default:
return -EIO;
}
}
static int qeth_l2_send_setdelvlan_cb(struct qeth_card *card,
struct qeth_reply *reply,
unsigned long data)
{
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
QETH_CARD_TEXT(card, 2, "L2sdvcb");
if (cmd->hdr.return_code) {
QETH_DBF_MESSAGE(2, "Error in processing VLAN %u on device %x: %#x.\n",
cmd->data.setdelvlan.vlan_id,
CARD_DEVID(card), cmd->hdr.return_code);
QETH_CARD_TEXT_(card, 2, "L2VL%4x", cmd->hdr.command);
}
return qeth_l2_setdelvlan_makerc(card, cmd->hdr.return_code);
}
static int qeth_l2_send_setdelvlan(struct qeth_card *card, __u16 i,
enum qeth_ipa_cmds ipacmd)
{
struct qeth_ipa_cmd *cmd;
struct qeth_cmd_buffer *iob;
QETH_CARD_TEXT_(card, 4, "L2sdv%x", ipacmd);
iob = qeth_ipa_alloc_cmd(card, ipacmd, QETH_PROT_IPV4,
IPA_DATA_SIZEOF(setdelvlan));
390/qeth: Fix locking warning during qeth device setup Do not wait for channel command buffers in IPA commands. The potential wait could be done while holding a spin lock and causes in recent kernels such a bug if kernel lock debugging is enabled: kernel: BUG: sleeping function called from invalid context at drivers/s390/net/qeth_core_main.c: 794 kernel: in_atomic(): 1, irqs_disabled(): 0, pid: 2031, name: NetworkManager kernel: 2 locks held by NetworkManager/2031: kernel: #0: (rtnl_mutex){+.+.+.}, at: [<00000000006e0d7a>] rtnetlink_rcv+0x32/0x50 kernel: #1: (_xmit_ETHER){+.....}, at: [<00000000006cfe90>] dev_set_rx_mode+0x30/0x50 kernel: CPU: 0 PID: 2031 Comm: NetworkManager Not tainted 3.18.0-rc5-next-20141124 #1 kernel: 00000000275fb1f0 00000000275fb280 0000000000000002 0000000000000000 00000000275fb320 00000000275fb298 00000000275fb298 00000000007e326a 0000000000000000 000000000099ce2c 00000000009b4988 000000000000000b 00000000275fb2e0 00000000275fb280 0000000000000000 0000000000000000 0000000000000000 00000000001129c8 00000000275fb280 00000000275fb2e0 kernel: Call Trace: kernel: ([<00000000001128b0>] show_trace+0xf8/0x158) kernel: [<000000000011297a>] show_stack+0x6a/0xe8 kernel: [<00000000007e995a>] dump_stack+0x82/0xb0 kernel: [<000000000017d668>] ___might_sleep+0x170/0x228 kernel: [<000003ff80026f0e>] qeth_wait_for_buffer+0x36/0xd0 [qeth] kernel: [<000003ff80026fe2>] qeth_get_ipacmd_buffer+0x3a/0xc0 [qeth] kernel: [<000003ff80105078>] qeth_l3_send_setdelmc+0x58/0xf8 [qeth_l3] kernel: [<000003ff8010b1fe>] qeth_l3_set_ip_addr_list+0x2c6/0x848 [qeth_l3] kernel: [<000003ff8010bbb4>] qeth_l3_set_multicast_list+0x434/0xc48 [qeth_l3] kernel: [<00000000006cfe9a>] dev_set_rx_mode+0x3a/0x50 kernel: [<00000000006cff90>] __dev_open+0xe0/0x140 kernel: [<00000000006d02a0>] __dev_change_flags+0xa0/0x178 kernel: [<00000000006d03a8>] dev_change_flags+0x30/0x70 kernel: [<00000000006e14ee>] do_setlink+0x346/0x9a0 ... The device driver has plenty of command buffers available per channel for channel command communication. In the extremely rare case when there is no command buffer available, return a NULL pointer and issue a warning in the kernel log. The caller handles the case when a NULL pointer is encountered and returns an error. In the case the wait for command buffer is possible (because no lock is held as in the OSN case), still wait until a channel command buffer is available. Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com> Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Reviewed-by: Eugene Crosser <Eugene.Crosser@ru.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-01-21 20:39:10 +08:00
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
cmd->data.setdelvlan.vlan_id = i;
return qeth_send_ipa_cmd(card, iob, qeth_l2_send_setdelvlan_cb, NULL);
}
static int qeth_l2_vlan_rx_add_vid(struct net_device *dev,
__be16 proto, u16 vid)
{
struct qeth_card *card = dev->ml_priv;
QETH_CARD_TEXT_(card, 4, "aid:%d", vid);
if (!vid)
return 0;
return qeth_l2_send_setdelvlan(card, vid, IPA_CMD_SETVLAN);
}
static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev,
__be16 proto, u16 vid)
{
struct qeth_card *card = dev->ml_priv;
QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
if (!vid)
return 0;
return qeth_l2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN);
}
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
static void qeth_l2_set_pnso_mode(struct qeth_card *card,
enum qeth_pnso_mode mode)
{
spin_lock_irq(get_ccwdev_lock(CARD_RDEV(card)));
WRITE_ONCE(card->info.pnso_mode, mode);
spin_unlock_irq(get_ccwdev_lock(CARD_RDEV(card)));
if (mode == QETH_PNSO_NONE)
drain_workqueue(card->event_wq);
}
s390/qeth: Reset address notification in case of buffer overflow In case hardware sends more device-to-bridge-address-change notfications than the qeth-l2 driver can handle, the hardware will send an overflow event and then stop sending any events. It expects software to flush its FDB and start over again. Re-enabling address-change-notification will report all current addresses. In order to re-enable address-change-notification this patch defines the functions qeth_l2_dev2br_an_set() and qeth_l2_dev2br_an_set_cb to enable or disable dev-to-bridge-address-notification. A following patch will use the learning_sync bridgeport flag to trigger enabling or disabling of address-change-notification, so we define priv->brport_features to store the current setting. BRIDGE_INFO and ADDR_INFO functionality are mutually exclusive, whereas ADDR_INFO and qeth_l2_vnicc* can be used together. Alternative implementations to handle buffer overflow: Just re-enabling notification and adding all newly reported addresses would cover any lost 'add' events, but not the lost 'delete' events. Then these invalid addresses would stay in the bridge FDB as long as the device exists. Setting the net device down and up, would be an alternative, but is a bit drastic. If the net device has many secondary addresses this will create many delete/add events at its peers which could de-stabilize the network segment. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:49 +08:00
static void qeth_l2_dev2br_fdb_flush(struct qeth_card *card)
{
struct switchdev_notifier_fdb_info info;
QETH_CARD_TEXT(card, 2, "fdbflush");
info.addr = NULL;
/* flush all VLANs: */
info.vid = 0;
info.added_by_user = false;
info.offloaded = true;
call_switchdev_notifiers(SWITCHDEV_FDB_FLUSH_TO_BRIDGE,
card->dev, &info.info, NULL);
}
static int qeth_l2_request_initial_mac(struct qeth_card *card)
{
int rc = 0;
QETH_CARD_TEXT(card, 2, "l2reqmac");
if (MACHINE_IS_VM) {
rc = qeth_vm_request_mac(card);
if (!rc)
goto out;
QETH_DBF_MESSAGE(2, "z/VM MAC Service failed on device %x: %#x\n",
CARD_DEVID(card), rc);
QETH_CARD_TEXT_(card, 2, "err%04x", rc);
/* fall back to alternative mechanism: */
}
if (!IS_OSN(card)) {
rc = qeth_setadpparms_change_macaddr(card);
s390/qeth: allow cmd callbacks to return errnos Error propagation from cmd callbacks currently works in a way where qeth_send_control_data_cb() picks the raw HW code from the response, and the cmd's originator later translates this into an errno. The callback itself only returns 0 ("done") or 1 ("expect more data"). This is 1. limiting, as the only means for the callback to report an internal error is to invent pseudo HW codes (such as IPA_RC_ENOMEM), that the originator then needs to understand. For non-IPA callbacks, we even provide a separate field in the IO buffer metadata (iob->rc) so the callback can pass back a return value. 2. fragile, as the originator must take care to not translate any errno that is returned by qeth's own IO code paths (eg -ENOMEM). Also, any originator that forgets to translate the HW codes potentially passes garbage back to its caller. For instance, see commit 2aa4867198c2 ("s390/qeth: translate SETVLAN/DELVLAN errors"). Introduce a new model where all HW error translation is done within the callback, and the callback returns > 0, if it expects more data (as before) == 0, on success < 0, with an errno Start off with converting all callbacks to the new model that either a) pass back pseudo HW codes, or b) have a dependency on a specific HW error code. Also convert c) the one callback that uses iob->rc, and d) qeth_setadpparms_change_macaddr_cb() so that it can pass back an error back to qeth_l2_request_initial_mac() even when the cmd itself was successful. The old model remains supported: if the callback returns 0, we still propagate the response's HW error code back to the originator. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-02-13 01:33:23 +08:00
if (!rc)
goto out;
QETH_DBF_MESSAGE(2, "READ_MAC Assist failed on device %x: %#x\n",
CARD_DEVID(card), rc);
QETH_CARD_TEXT_(card, 2, "1err%04x", rc);
/* fall back once more: */
}
/* some devices don't support a custom MAC address: */
if (IS_OSM(card) || IS_OSX(card))
return (rc) ? rc : -EADDRNOTAVAIL;
eth_hw_addr_random(card->dev);
out:
QETH_CARD_HEX(card, 2, card->dev->dev_addr, card->dev->addr_len);
return 0;
}
static void qeth_l2_register_dev_addr(struct qeth_card *card)
{
if (!is_valid_ether_addr(card->dev->dev_addr))
qeth_l2_request_initial_mac(card);
if (!IS_OSN(card) && !qeth_l2_send_setmac(card, card->dev->dev_addr))
card->info.dev_addr_is_registered = 1;
else
card->info.dev_addr_is_registered = 0;
}
static int qeth_l2_validate_addr(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
if (card->info.dev_addr_is_registered)
return eth_validate_addr(dev);
QETH_CARD_TEXT(card, 4, "nomacadr");
return -EPERM;
}
static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
struct qeth_card *card = dev->ml_priv;
u8 old_addr[ETH_ALEN];
int rc = 0;
QETH_CARD_TEXT(card, 3, "setmac");
if (IS_OSM(card) || IS_OSX(card)) {
QETH_CARD_TEXT(card, 3, "setmcTYP");
return -EOPNOTSUPP;
}
QETH_CARD_HEX(card, 3, addr->sa_data, ETH_ALEN);
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
/* don't register the same address twice */
if (ether_addr_equal_64bits(dev->dev_addr, addr->sa_data) &&
card->info.dev_addr_is_registered)
return 0;
/* add the new address, switch over, drop the old */
rc = qeth_l2_send_setmac(card, addr->sa_data);
if (rc)
return rc;
ether_addr_copy(old_addr, dev->dev_addr);
ether_addr_copy(dev->dev_addr, addr->sa_data);
if (card->info.dev_addr_is_registered)
qeth_l2_remove_mac(card, old_addr);
card->info.dev_addr_is_registered = 1;
return 0;
}
static void qeth_l2_promisc_to_bridge(struct qeth_card *card, bool enable)
{
int role;
int rc;
QETH_CARD_TEXT(card, 3, "pmisc2br");
if (enable) {
if (card->options.sbp.reflect_promisc_primary)
role = QETH_SBP_ROLE_PRIMARY;
else
role = QETH_SBP_ROLE_SECONDARY;
} else
role = QETH_SBP_ROLE_NONE;
rc = qeth_bridgeport_setrole(card, role);
QETH_CARD_TEXT_(card, 2, "bpm%c%04x", enable ? '+' : '-', rc);
if (!rc) {
card->options.sbp.role = role;
card->info.promisc_mode = enable;
}
}
static void qeth_l2_set_promisc_mode(struct qeth_card *card)
{
bool enable = card->dev->flags & IFF_PROMISC;
if (card->info.promisc_mode == enable)
return;
if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) {
qeth_setadp_promisc_mode(card, enable);
} else {
mutex_lock(&card->sbp_lock);
if (card->options.sbp.reflect_promisc)
qeth_l2_promisc_to_bridge(card, enable);
mutex_unlock(&card->sbp_lock);
}
}
/* New MAC address is added to the hash table and marked to be written on card
* only if there is not in the hash table storage already
*
*/
static void qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha)
{
u32 mac_hash = get_unaligned((u32 *)(&ha->addr[2]));
struct qeth_mac *mac;
hash_for_each_possible(card->rx_mode_addrs, mac, hnode, mac_hash) {
if (ether_addr_equal_64bits(ha->addr, mac->mac_addr)) {
mac->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
return;
}
}
mac = kzalloc(sizeof(struct qeth_mac), GFP_ATOMIC);
if (!mac)
return;
ether_addr_copy(mac->mac_addr, ha->addr);
mac->disp_flag = QETH_DISP_ADDR_ADD;
hash_add(card->rx_mode_addrs, &mac->hnode, mac_hash);
}
static void qeth_l2_rx_mode_work(struct work_struct *work)
{
struct qeth_card *card = container_of(work, struct qeth_card,
rx_mode_work);
struct net_device *dev = card->dev;
struct netdev_hw_addr *ha;
struct qeth_mac *mac;
struct hlist_node *tmp;
int i;
int rc;
QETH_CARD_TEXT(card, 3, "setmulti");
netif_addr_lock_bh(dev);
netdev_for_each_mc_addr(ha, dev)
qeth_l2_add_mac(card, ha);
netdev_for_each_uc_addr(ha, dev)
qeth_l2_add_mac(card, ha);
netif_addr_unlock_bh(dev);
hash_for_each_safe(card->rx_mode_addrs, i, tmp, mac, hnode) {
switch (mac->disp_flag) {
case QETH_DISP_ADDR_DELETE:
qeth_l2_remove_mac(card, mac->mac_addr);
hash_del(&mac->hnode);
kfree(mac);
break;
case QETH_DISP_ADDR_ADD:
rc = qeth_l2_write_mac(card, mac->mac_addr);
if (rc) {
hash_del(&mac->hnode);
kfree(mac);
break;
}
fallthrough;
default:
/* for next call to set_rx_mode(): */
mac->disp_flag = QETH_DISP_ADDR_DELETE;
}
}
qeth_l2_set_promisc_mode(card);
}
static int qeth_l2_xmit_osn(struct qeth_card *card, struct sk_buff *skb,
struct qeth_qdio_out_q *queue)
{
gfp_t gfp = GFP_ATOMIC | (skb_pfmemalloc(skb) ? __GFP_MEMALLOC : 0);
struct qeth_hdr *hdr = (struct qeth_hdr *)skb->data;
addr_t end = (addr_t)(skb->data + sizeof(*hdr));
addr_t start = (addr_t)skb->data;
unsigned int elements = 0;
unsigned int hd_len = 0;
int rc;
if (skb->protocol == htons(ETH_P_IPV6))
return -EPROTONOSUPPORT;
if (qeth_get_elements_for_range(start, end) > 1) {
/* Misaligned HW header, move it to its own buffer element. */
hdr = kmem_cache_alloc(qeth_core_header_cache, gfp);
if (!hdr)
return -ENOMEM;
hd_len = sizeof(*hdr);
skb_copy_from_linear_data(skb, (char *)hdr, hd_len);
elements++;
}
elements += qeth_count_elements(skb, hd_len);
if (elements > queue->max_elements) {
rc = -E2BIG;
goto out;
}
rc = qeth_do_send_packet(card, queue, skb, hdr, hd_len, hd_len,
elements);
out:
if (rc && hd_len)
kmem_cache_free(qeth_core_header_cache, hdr);
return rc;
}
static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
u16 txq = skb_get_queue_mapping(skb);
struct qeth_qdio_out_q *queue;
int rc;
if (!skb_is_gso(skb))
qdisc_skb_cb(skb)->pkt_len = skb->len;
if (IS_IQD(card))
txq = qeth_iqd_translate_txq(dev, txq);
queue = card->qdio.out_qs[txq];
if (IS_OSN(card))
rc = qeth_l2_xmit_osn(card, skb, queue);
else
rc = qeth_xmit(card, skb, queue, vlan_get_protocol(skb),
qeth_l2_fill_header);
if (!rc)
return NETDEV_TX_OK;
QETH_TXQ_STAT_INC(queue, tx_dropped);
kfree_skb(skb);
return NETDEV_TX_OK;
}
static u16 qeth_l2_select_queue(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev)
{
struct qeth_card *card = dev->ml_priv;
if (IS_IQD(card))
return qeth_iqd_select_queue(dev, skb,
qeth_get_ether_cast_type(skb),
sb_dev);
if (qeth_uses_tx_prio_queueing(card))
return qeth_get_priority_queue(card, skb);
return netdev_pick_tx(dev, skb, sb_dev);
}
static void qeth_l2_set_rx_mode(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
schedule_work(&card->rx_mode_work);
}
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
/**
* qeth_l2_pnso() - perform network subchannel operation
* @card: qeth_card structure pointer
* @oc: Operation Code
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
* @cnc: Boolean Change-Notification Control
* @cb: Callback function will be executed for each element
* of the address list
* @priv: Pointer to pass to the callback function.
*
* Collects network information in a network address list and calls the
* callback function for every entry in the list. If "change-notification-
* control" is set, further changes in the address list will be reported
* via the IPA command.
*/
static int qeth_l2_pnso(struct qeth_card *card, u8 oc, int cnc,
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
void (*cb)(void *priv, struct chsc_pnso_naid_l2 *entry),
void *priv)
{
struct ccw_device *ddev = CARD_DDEV(card);
struct chsc_pnso_area *rr;
u32 prev_instance = 0;
int isfirstblock = 1;
int i, size, elems;
int rc;
rr = (struct chsc_pnso_area *)get_zeroed_page(GFP_KERNEL);
if (rr == NULL)
return -ENOMEM;
do {
QETH_CARD_TEXT(card, 2, "PNSO");
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
/* on the first iteration, naihdr.resume_token will be zero */
rc = ccw_device_pnso(ddev, rr, oc, rr->naihdr.resume_token,
cnc);
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
if (rc)
continue;
if (cb == NULL)
continue;
size = rr->naihdr.naids;
if (size != sizeof(struct chsc_pnso_naid_l2)) {
WARN_ON_ONCE(1);
continue;
}
elems = (rr->response.length - sizeof(struct chsc_header) -
sizeof(struct chsc_pnso_naihdr)) / size;
if (!isfirstblock && (rr->naihdr.instance != prev_instance)) {
/* Inform the caller that they need to scrap */
/* the data that was already reported via cb */
rc = -EAGAIN;
break;
}
isfirstblock = 0;
prev_instance = rr->naihdr.instance;
for (i = 0; i < elems; i++)
(*cb)(priv, &rr->entries[i]);
} while ((rc == -EBUSY) || (!rc && /* list stored */
/* resume token is non-zero => list incomplete */
(rr->naihdr.resume_token.t1 || rr->naihdr.resume_token.t2)));
if (rc)
QETH_CARD_TEXT_(card, 2, "PNrp%04x", rr->response.code);
free_page((unsigned long)rr);
return rc;
}
s390/qeth: Translate address events into switchdev notifiers A qeth-l2 HiperSockets card can show switch-ish behaviour in the sense, that it can report all MACs that are reachable via this interface. Just like a switch device, it can notify the software bridge about changes to its fdb. This patch exploits this device-to-bridge-notification and extracts the relevant information from the hardware events to generate notifications to an attached software bridge. There are 2 sources for this information: 1) The reply message of Perform-Network-Subchannel-Operations (PNSO) (operation code ADDR_INFO) reports all addresses that are currently reachable (implemented in a later patch). 2) As long as device-to-bridge-notification is enabled, hardware will generate address change notification events, whenever the content of the hardware fdb changes (this patch). The bridge_hostnotify feature (PNSO operation code BRIDGE_INFO) uses the same address change notification events. We need to distinguish between qeth_pnso_mode QETH_PNSO_BRIDGEPORT and QETH_PNSO_ADDR_INFO and call a different handler. In both cases deadlocks must be prevented, if the workqueue is drained under lock and QETH_PNSO_NONE, when notification is disabled. bridge_hostnotify generates udev events, there is no intend to do the same for dev2br. Instead this patch will generate SWITCHDEV_FDB_ADD_TO_BRIDGE and SWITCHDEV_FDB_DEL_TO_BRIDGE notifications, that will cause the software bridge to add (or delete) entries to its fdb as 'extern_learn offload'. Documentation/networking/switchdev.txt proposes to add "depends NET_SWITCHDEV" to driver's Kconfig. This is not done here, so even in absence of the NET_SWITCHDEV module, the QETH_L2 module will still be built, but then the switchdev notifiers will have no effect. No VLAN filtering is done on the entries and VLAN information is not passed on to the bridge fdb entries. This could be added later. For now VLAN interfaces can be defined on the upper bridge interface. Multicast entries are not passed on to the bridge fdb. This could be added later. For now mcast flooding can be used in the bridge. The card reports all MACs that are in its FDB, but we must not pass on MACs that are registered for this interface. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:47 +08:00
static bool qeth_is_my_net_if_token(struct qeth_card *card,
struct net_if_token *token)
{
return ((card->info.ddev_devno == token->devnum) &&
(card->info.cssid == token->cssid) &&
(card->info.iid == token->iid) &&
(card->info.ssid == token->ssid) &&
(card->info.chpid == token->chpid) &&
(card->info.chid == token->chid));
}
/**
* qeth_l2_dev2br_fdb_notify() - update fdb of master bridge
* @card: qeth_card structure pointer
* @code: event bitmask: high order bit 0x80 set to
* 1 - removal of an object
* 0 - addition of an object
* Object type(s):
* 0x01 - VLAN, 0x02 - MAC, 0x03 - VLAN and MAC
* @token: "network token" structure identifying 'physical' location
* of the target
* @addr_lnid: structure with MAC address and VLAN ID of the target
*/
static void qeth_l2_dev2br_fdb_notify(struct qeth_card *card, u8 code,
struct net_if_token *token,
struct mac_addr_lnid *addr_lnid)
{
struct switchdev_notifier_fdb_info info;
u8 ntfy_mac[ETH_ALEN];
ether_addr_copy(ntfy_mac, addr_lnid->mac);
/* Ignore VLAN only changes */
if (!(code & IPA_ADDR_CHANGE_CODE_MACADDR))
return;
/* Ignore mcast entries */
if (is_multicast_ether_addr(ntfy_mac))
return;
/* Ignore my own addresses */
if (qeth_is_my_net_if_token(card, token))
return;
info.addr = ntfy_mac;
/* don't report VLAN IDs */
info.vid = 0;
info.added_by_user = false;
info.offloaded = true;
if (code & IPA_ADDR_CHANGE_CODE_REMOVAL) {
call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
card->dev, &info.info, NULL);
QETH_CARD_TEXT(card, 4, "andelmac");
QETH_CARD_TEXT_(card, 4,
"mc%012lx", ether_addr_to_u64(ntfy_mac));
} else {
call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE,
card->dev, &info.info, NULL);
QETH_CARD_TEXT(card, 4, "anaddmac");
QETH_CARD_TEXT_(card, 4,
"mc%012lx", ether_addr_to_u64(ntfy_mac));
}
}
s390/qeth: Reset address notification in case of buffer overflow In case hardware sends more device-to-bridge-address-change notfications than the qeth-l2 driver can handle, the hardware will send an overflow event and then stop sending any events. It expects software to flush its FDB and start over again. Re-enabling address-change-notification will report all current addresses. In order to re-enable address-change-notification this patch defines the functions qeth_l2_dev2br_an_set() and qeth_l2_dev2br_an_set_cb to enable or disable dev-to-bridge-address-notification. A following patch will use the learning_sync bridgeport flag to trigger enabling or disabling of address-change-notification, so we define priv->brport_features to store the current setting. BRIDGE_INFO and ADDR_INFO functionality are mutually exclusive, whereas ADDR_INFO and qeth_l2_vnicc* can be used together. Alternative implementations to handle buffer overflow: Just re-enabling notification and adding all newly reported addresses would cover any lost 'add' events, but not the lost 'delete' events. Then these invalid addresses would stay in the bridge FDB as long as the device exists. Setting the net device down and up, would be an alternative, but is a bit drastic. If the net device has many secondary addresses this will create many delete/add events at its peers which could de-stabilize the network segment. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:49 +08:00
static void qeth_l2_dev2br_an_set_cb(void *priv,
struct chsc_pnso_naid_l2 *entry)
{
u8 code = IPA_ADDR_CHANGE_CODE_MACADDR;
struct qeth_card *card = priv;
if (entry->addr_lnid.lnid < VLAN_N_VID)
code |= IPA_ADDR_CHANGE_CODE_VLANID;
qeth_l2_dev2br_fdb_notify(card, code,
(struct net_if_token *)&entry->nit,
(struct mac_addr_lnid *)&entry->addr_lnid);
}
/**
* qeth_l2_dev2br_an_set() -
* Enable or disable 'dev to bridge network address notification'
* @card: qeth_card structure pointer
* @enable: Enable or disable 'dev to bridge network address notification'
*
* Returns negative errno-compatible error indication or 0 on success.
*
* On enable, emits a series of address notifications for all
* currently registered hosts.
*/
static int qeth_l2_dev2br_an_set(struct qeth_card *card, bool enable)
{
int rc;
if (enable) {
QETH_CARD_TEXT(card, 2, "anseton");
rc = qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 1,
qeth_l2_dev2br_an_set_cb, card);
if (rc == -EAGAIN)
/* address notification enabled, but inconsistent
* addresses reported -> disable address notification
*/
qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 0,
NULL, NULL);
} else {
QETH_CARD_TEXT(card, 2, "ansetoff");
rc = qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 0, NULL, NULL);
}
return rc;
}
static int qeth_l2_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
struct net_device *dev, u32 filter_mask,
int nlflags)
{
struct qeth_priv *priv = netdev_priv(dev);
struct qeth_card *card = dev->ml_priv;
u16 mode = BRIDGE_MODE_UNDEF;
/* Do not even show qeth devs that cannot do bridge_setlink */
if (!priv->brport_hw_features || !netif_device_present(dev) ||
qeth_bridgeport_is_in_use(card))
return -EOPNOTSUPP;
return ndo_dflt_bridge_getlink(skb, pid, seq, dev,
mode, priv->brport_features,
priv->brport_hw_features,
nlflags, filter_mask, NULL);
}
s390/qeth: implement ndo_bridge_setlink for learning_sync Documentation/networking/switchdev.txt and 'man bridge' indicate that the learning_sync bridge attribute is used to control whether a given device will sync MAC addresses learned on its device port to a master bridge FDB, where they will show up as 'extern_learn offload'. So we map qeth_l2_dev2br_an_set() to the learning_sync bridge link attribute. Turning off learning_sync will flush all extern_learn entries from the bridge fdb and all pending events from the card's work queue. When the hardware interface goes offline with learning_sync on (e.g. for HW recovery), all extern_learn entries will be flushed from the bridge fdb and all pending events from the card's work queue. When the interface goes online again, it will send new notifications for all then valid MACs. learning_sync attribute can not be modified while interface is offline. See 'commit e6e771b3d897 ("s390/qeth: detach netdevice while card is offline")' An alternative implementation would be to always offload the 'learning' attribute of a software bridge to the hardware interface attached to it and thus implicitly enable fdb notification. This was not chosen for 2 reasons: 1) In our case the software bridge is NOT a representation of a hardware switch. It is just connected to a smart NIC that is able to inform about the addresses attached to it. It is not necessarily using source MAC learning for this and other bridgeports can be attached to other NICs with different properties. 2) We want a means to enable this notification explicitly. There may be cases where a bridgeport is set to 'learning', but we do not want to enable the notification. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:51 +08:00
static const struct nla_policy qeth_brport_policy[IFLA_BRPORT_MAX + 1] = {
[IFLA_BRPORT_LEARNING_SYNC] = { .type = NLA_U8 },
};
/**
* qeth_l2_bridge_setlink() - set bridgeport attributes
* @dev: netdevice
* @nlh: netlink message header
* @flags: bridge flags (here: BRIDGE_FLAGS_SELF)
* @extack: extended ACK report struct
*
* Called under rtnl_lock
*/
static int qeth_l2_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
u16 flags, struct netlink_ext_ack *extack)
{
struct qeth_priv *priv = netdev_priv(dev);
struct nlattr *bp_tb[IFLA_BRPORT_MAX + 1];
struct qeth_card *card = dev->ml_priv;
struct nlattr *attr, *nested_attr;
bool enable, has_protinfo = false;
int rem1, rem2;
int rc;
if (!netif_device_present(dev))
return -ENODEV;
if (!(priv->brport_hw_features))
return -EOPNOTSUPP;
nlmsg_for_each_attr(attr, nlh, sizeof(struct ifinfomsg), rem1) {
if (nla_type(attr) == IFLA_PROTINFO) {
rc = nla_parse_nested(bp_tb, IFLA_BRPORT_MAX, attr,
qeth_brport_policy, extack);
if (rc)
return rc;
has_protinfo = true;
} else if (nla_type(attr) == IFLA_AF_SPEC) {
nla_for_each_nested(nested_attr, attr, rem2) {
if (nla_type(nested_attr) == IFLA_BRIDGE_FLAGS)
continue;
NL_SET_ERR_MSG_ATTR(extack, nested_attr,
"Unsupported attribute");
return -EINVAL;
}
} else {
NL_SET_ERR_MSG_ATTR(extack, attr, "Unsupported attribute");
return -EINVAL;
}
}
if (!has_protinfo)
return 0;
if (!bp_tb[IFLA_BRPORT_LEARNING_SYNC])
return -EINVAL;
enable = !!nla_get_u8(bp_tb[IFLA_BRPORT_LEARNING_SYNC]);
if (enable == !!(priv->brport_features & BR_LEARNING_SYNC))
return 0;
mutex_lock(&card->sbp_lock);
/* do not change anything if BridgePort is enabled */
if (qeth_bridgeport_is_in_use(card)) {
NL_SET_ERR_MSG(extack, "n/a (BridgePort)");
rc = -EBUSY;
} else if (enable) {
qeth_l2_set_pnso_mode(card, QETH_PNSO_ADDR_INFO);
rc = qeth_l2_dev2br_an_set(card, true);
if (rc)
qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
else
priv->brport_features |= BR_LEARNING_SYNC;
} else {
rc = qeth_l2_dev2br_an_set(card, false);
if (!rc) {
qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
priv->brport_features ^= BR_LEARNING_SYNC;
qeth_l2_dev2br_fdb_flush(card);
}
}
mutex_unlock(&card->sbp_lock);
return rc;
}
static const struct net_device_ops qeth_l2_netdev_ops = {
.ndo_open = qeth_open,
.ndo_stop = qeth_stop,
.ndo_get_stats64 = qeth_get_stats64,
.ndo_start_xmit = qeth_l2_hard_start_xmit,
.ndo_features_check = qeth_features_check,
.ndo_select_queue = qeth_l2_select_queue,
.ndo_validate_addr = qeth_l2_validate_addr,
.ndo_set_rx_mode = qeth_l2_set_rx_mode,
.ndo_do_ioctl = qeth_do_ioctl,
.ndo_set_mac_address = qeth_l2_set_mac_address,
.ndo_vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid,
.ndo_tx_timeout = qeth_tx_timeout,
.ndo_fix_features = qeth_fix_features,
.ndo_set_features = qeth_set_features,
.ndo_bridge_getlink = qeth_l2_bridge_getlink,
s390/qeth: implement ndo_bridge_setlink for learning_sync Documentation/networking/switchdev.txt and 'man bridge' indicate that the learning_sync bridge attribute is used to control whether a given device will sync MAC addresses learned on its device port to a master bridge FDB, where they will show up as 'extern_learn offload'. So we map qeth_l2_dev2br_an_set() to the learning_sync bridge link attribute. Turning off learning_sync will flush all extern_learn entries from the bridge fdb and all pending events from the card's work queue. When the hardware interface goes offline with learning_sync on (e.g. for HW recovery), all extern_learn entries will be flushed from the bridge fdb and all pending events from the card's work queue. When the interface goes online again, it will send new notifications for all then valid MACs. learning_sync attribute can not be modified while interface is offline. See 'commit e6e771b3d897 ("s390/qeth: detach netdevice while card is offline")' An alternative implementation would be to always offload the 'learning' attribute of a software bridge to the hardware interface attached to it and thus implicitly enable fdb notification. This was not chosen for 2 reasons: 1) In our case the software bridge is NOT a representation of a hardware switch. It is just connected to a smart NIC that is able to inform about the addresses attached to it. It is not necessarily using source MAC learning for this and other bridgeports can be attached to other NICs with different properties. 2) We want a means to enable this notification explicitly. There may be cases where a bridgeport is set to 'learning', but we do not want to enable the notification. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:51 +08:00
.ndo_bridge_setlink = qeth_l2_bridge_setlink,
};
static const struct net_device_ops qeth_osn_netdev_ops = {
.ndo_open = qeth_open,
.ndo_stop = qeth_stop,
.ndo_get_stats64 = qeth_get_stats64,
.ndo_start_xmit = qeth_l2_hard_start_xmit,
.ndo_validate_addr = eth_validate_addr,
.ndo_tx_timeout = qeth_tx_timeout,
};
static int qeth_l2_setup_netdev(struct qeth_card *card)
{
if (IS_OSN(card)) {
card->dev->netdev_ops = &qeth_osn_netdev_ops;
card->dev->flags |= IFF_NOARP;
goto add_napi;
}
card->dev->needed_headroom = sizeof(struct qeth_hdr);
card->dev->netdev_ops = &qeth_l2_netdev_ops;
card->dev->priv_flags |= IFF_UNICAST_FLT;
if (IS_OSM(card)) {
card->dev->features |= NETIF_F_VLAN_CHALLENGED;
} else {
if (!IS_VM_NIC(card))
card->dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
}
if (IS_OSD(card) && !IS_VM_NIC(card)) {
card->dev->features |= NETIF_F_SG;
/* OSA 3S and earlier has no RX/TX support */
if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) {
card->dev->hw_features |= NETIF_F_IP_CSUM;
card->dev->vlan_features |= NETIF_F_IP_CSUM;
}
}
if (qeth_is_supported6(card, IPA_OUTBOUND_CHECKSUM_V6)) {
card->dev->hw_features |= NETIF_F_IPV6_CSUM;
card->dev->vlan_features |= NETIF_F_IPV6_CSUM;
}
if (qeth_is_supported(card, IPA_INBOUND_CHECKSUM) ||
qeth_is_supported6(card, IPA_INBOUND_CHECKSUM_V6)) {
card->dev->hw_features |= NETIF_F_RXCSUM;
card->dev->vlan_features |= NETIF_F_RXCSUM;
}
if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
card->dev->hw_features |= NETIF_F_TSO;
card->dev->vlan_features |= NETIF_F_TSO;
}
if (qeth_is_supported6(card, IPA_OUTBOUND_TSO)) {
card->dev->hw_features |= NETIF_F_TSO6;
card->dev->vlan_features |= NETIF_F_TSO6;
}
if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6)) {
card->dev->needed_headroom = sizeof(struct qeth_hdr_tso);
netif_keep_dst(card->dev);
netif_set_gso_max_size(card->dev,
PAGE_SIZE * (QDIO_MAX_ELEMENTS_PER_BUFFER - 1));
}
add_napi:
netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT);
return register_netdev(card->dev);
}
static void qeth_l2_trace_features(struct qeth_card *card)
{
/* Set BridgePort features */
QETH_CARD_TEXT(card, 2, "featuSBP");
QETH_CARD_HEX(card, 2, &card->options.sbp.supported_funcs,
sizeof(card->options.sbp.supported_funcs));
/* VNIC Characteristics features */
QETH_CARD_TEXT(card, 2, "feaVNICC");
QETH_CARD_HEX(card, 2, &card->options.vnicc.sup_chars,
sizeof(card->options.vnicc.sup_chars));
}
static void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card)
{
if (!card->options.sbp.reflect_promisc &&
card->options.sbp.role != QETH_SBP_ROLE_NONE) {
/* Conditional to avoid spurious error messages */
qeth_bridgeport_setrole(card, card->options.sbp.role);
/* Let the callback function refresh the stored role value. */
qeth_bridgeport_query_ports(card, &card->options.sbp.role,
NULL);
}
if (card->options.sbp.hostnotification) {
if (qeth_bridgeport_an_set(card, 1))
card->options.sbp.hostnotification = 0;
}
}
/**
* qeth_l2_detect_dev2br_support() -
* Detect whether this card supports 'dev to bridge fdb network address
* change notification' and thus can support the learning_sync bridgeport
* attribute
* @card: qeth_card structure pointer
*/
static void qeth_l2_detect_dev2br_support(struct qeth_card *card)
{
struct qeth_priv *priv = netdev_priv(card->dev);
bool dev2br_supported;
QETH_CARD_TEXT(card, 2, "d2brsup");
if (!IS_IQD(card))
return;
/* dev2br requires valid cssid,iid,chid */
dev2br_supported = card->info.ids_valid &&
css_general_characteristics.enarf;
QETH_CARD_TEXT_(card, 2, "D2Bsup%02x", dev2br_supported);
if (dev2br_supported)
priv->brport_hw_features |= BR_LEARNING_SYNC;
else
priv->brport_hw_features &= ~BR_LEARNING_SYNC;
}
s390/qeth: implement ndo_bridge_setlink for learning_sync Documentation/networking/switchdev.txt and 'man bridge' indicate that the learning_sync bridge attribute is used to control whether a given device will sync MAC addresses learned on its device port to a master bridge FDB, where they will show up as 'extern_learn offload'. So we map qeth_l2_dev2br_an_set() to the learning_sync bridge link attribute. Turning off learning_sync will flush all extern_learn entries from the bridge fdb and all pending events from the card's work queue. When the hardware interface goes offline with learning_sync on (e.g. for HW recovery), all extern_learn entries will be flushed from the bridge fdb and all pending events from the card's work queue. When the interface goes online again, it will send new notifications for all then valid MACs. learning_sync attribute can not be modified while interface is offline. See 'commit e6e771b3d897 ("s390/qeth: detach netdevice while card is offline")' An alternative implementation would be to always offload the 'learning' attribute of a software bridge to the hardware interface attached to it and thus implicitly enable fdb notification. This was not chosen for 2 reasons: 1) In our case the software bridge is NOT a representation of a hardware switch. It is just connected to a smart NIC that is able to inform about the addresses attached to it. It is not necessarily using source MAC learning for this and other bridgeports can be attached to other NICs with different properties. 2) We want a means to enable this notification explicitly. There may be cases where a bridgeport is set to 'learning', but we do not want to enable the notification. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:51 +08:00
static void qeth_l2_enable_brport_features(struct qeth_card *card)
{
struct qeth_priv *priv = netdev_priv(card->dev);
int rc;
if (priv->brport_features & BR_LEARNING_SYNC) {
if (priv->brport_hw_features & BR_LEARNING_SYNC) {
qeth_l2_set_pnso_mode(card, QETH_PNSO_ADDR_INFO);
rc = qeth_l2_dev2br_an_set(card, true);
if (rc == -EAGAIN) {
/* Recoverable error, retry once */
qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
qeth_l2_dev2br_fdb_flush(card);
qeth_l2_set_pnso_mode(card, QETH_PNSO_ADDR_INFO);
rc = qeth_l2_dev2br_an_set(card, true);
}
if (rc) {
netdev_err(card->dev,
"failed to enable bridge learning_sync: %d\n",
rc);
qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
qeth_l2_dev2br_fdb_flush(card);
priv->brport_features ^= BR_LEARNING_SYNC;
}
} else {
dev_warn(&card->gdev->dev,
"bridge learning_sync not supported\n");
priv->brport_features ^= BR_LEARNING_SYNC;
}
}
}
#ifdef CONFIG_QETH_OSN
static void qeth_osn_assist_cb(struct qeth_card *card,
struct qeth_cmd_buffer *iob,
unsigned int data_length)
{
qeth_notify_cmd(iob, 0);
qeth_put_cmd(iob);
}
int qeth_osn_assist(struct net_device *dev, void *data, int data_len)
{
struct qeth_cmd_buffer *iob;
struct qeth_card *card;
if (data_len < 0)
return -EINVAL;
if (!dev)
return -ENODEV;
card = dev->ml_priv;
if (!card)
return -ENODEV;
QETH_CARD_TEXT(card, 2, "osnsdmc");
if (!qeth_card_hw_is_reachable(card))
return -ENODEV;
iob = qeth_alloc_cmd(&card->write, IPA_PDU_HEADER_SIZE + data_len, 1,
QETH_IPA_TIMEOUT);
if (!iob)
return -ENOMEM;
qeth_prepare_ipa_cmd(card, iob, (u16) data_len, NULL);
memcpy(__ipa_cmd(iob), data, data_len);
iob->callback = qeth_osn_assist_cb;
return qeth_send_ipa_cmd(card, iob, NULL, NULL);
}
EXPORT_SYMBOL(qeth_osn_assist);
int qeth_osn_register(unsigned char *read_dev_no, struct net_device **dev,
int (*assist_cb)(struct net_device *, void *),
int (*data_cb)(struct sk_buff *))
{
struct qeth_card *card;
char bus_id[16];
u16 devno;
memcpy(&devno, read_dev_no, 2);
sprintf(bus_id, "0.0.%04x", devno);
card = qeth_get_card_by_busid(bus_id);
if (!card || !IS_OSN(card))
return -ENODEV;
*dev = card->dev;
QETH_CARD_TEXT(card, 2, "osnreg");
if ((assist_cb == NULL) || (data_cb == NULL))
return -EINVAL;
card->osn_info.assist_cb = assist_cb;
card->osn_info.data_cb = data_cb;
return 0;
}
EXPORT_SYMBOL(qeth_osn_register);
void qeth_osn_deregister(struct net_device *dev)
{
struct qeth_card *card;
if (!dev)
return;
card = dev->ml_priv;
if (!card)
return;
QETH_CARD_TEXT(card, 2, "osndereg");
card->osn_info.assist_cb = NULL;
card->osn_info.data_cb = NULL;
}
EXPORT_SYMBOL(qeth_osn_deregister);
#endif
/* SETBRIDGEPORT support, async notifications */
enum qeth_an_event_type {anev_reg_unreg, anev_abort, anev_reset};
/**
* qeth_bridge_emit_host_event() - bridgeport address change notification
* @card: qeth_card structure pointer, for udev events.
* @evtype: "normal" register/unregister, or abort, or reset. For abort
* and reset token and addr_lnid are unused and may be NULL.
* @code: event bitmask: high order bit 0x80 value 1 means removal of an
* object, 0 - addition of an object.
* 0x01 - VLAN, 0x02 - MAC, 0x03 - VLAN and MAC.
* @token: "network token" structure identifying physical address of the port.
* @addr_lnid: pointer to structure with MAC address and VLAN ID.
*
* This function is called when registrations and deregistrations are
* reported by the hardware, and also when notifications are enabled -
* for all currently registered addresses.
*/
static void qeth_bridge_emit_host_event(struct qeth_card *card,
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
enum qeth_an_event_type evtype,
u8 code,
struct net_if_token *token,
struct mac_addr_lnid *addr_lnid)
{
char str[7][32];
char *env[8];
int i = 0;
switch (evtype) {
case anev_reg_unreg:
snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=%s",
(code & IPA_ADDR_CHANGE_CODE_REMOVAL)
? "deregister" : "register");
env[i] = str[i]; i++;
if (code & IPA_ADDR_CHANGE_CODE_VLANID) {
snprintf(str[i], sizeof(str[i]), "VLAN=%d",
addr_lnid->lnid);
env[i] = str[i]; i++;
}
if (code & IPA_ADDR_CHANGE_CODE_MACADDR) {
snprintf(str[i], sizeof(str[i]), "MAC=%pM",
addr_lnid->mac);
env[i] = str[i]; i++;
}
snprintf(str[i], sizeof(str[i]), "NTOK_BUSID=%x.%x.%04x",
token->cssid, token->ssid, token->devnum);
env[i] = str[i]; i++;
snprintf(str[i], sizeof(str[i]), "NTOK_IID=%02x", token->iid);
env[i] = str[i]; i++;
snprintf(str[i], sizeof(str[i]), "NTOK_CHPID=%02x",
token->chpid);
env[i] = str[i]; i++;
snprintf(str[i], sizeof(str[i]), "NTOK_CHID=%04x", token->chid);
env[i] = str[i]; i++;
break;
case anev_abort:
snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=abort");
env[i] = str[i]; i++;
break;
case anev_reset:
snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=reset");
env[i] = str[i]; i++;
break;
}
env[i] = NULL;
kobject_uevent_env(&card->gdev->dev.kobj, KOBJ_CHANGE, env);
}
struct qeth_bridge_state_data {
struct work_struct worker;
struct qeth_card *card;
u8 role;
u8 state;
};
static void qeth_bridge_state_change_worker(struct work_struct *work)
{
struct qeth_bridge_state_data *data =
container_of(work, struct qeth_bridge_state_data, worker);
char env_locrem[32];
char env_role[32];
char env_state[32];
char *env[] = {
env_locrem,
env_role,
env_state,
NULL
};
snprintf(env_locrem, sizeof(env_locrem), "BRIDGEPORT=statechange");
snprintf(env_role, sizeof(env_role), "ROLE=%s",
(data->role == QETH_SBP_ROLE_NONE) ? "none" :
(data->role == QETH_SBP_ROLE_PRIMARY) ? "primary" :
(data->role == QETH_SBP_ROLE_SECONDARY) ? "secondary" :
"<INVALID>");
snprintf(env_state, sizeof(env_state), "STATE=%s",
(data->state == QETH_SBP_STATE_INACTIVE) ? "inactive" :
(data->state == QETH_SBP_STATE_STANDBY) ? "standby" :
(data->state == QETH_SBP_STATE_ACTIVE) ? "active" :
"<INVALID>");
kobject_uevent_env(&data->card->gdev->dev.kobj,
KOBJ_CHANGE, env);
kfree(data);
}
static void qeth_bridge_state_change(struct qeth_card *card,
struct qeth_ipa_cmd *cmd)
{
struct qeth_sbp_port_data *qports = &cmd->data.sbp.data.port_data;
struct qeth_bridge_state_data *data;
QETH_CARD_TEXT(card, 2, "brstchng");
if (qports->num_entries == 0) {
QETH_CARD_TEXT(card, 2, "BPempty");
return;
}
if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) {
QETH_CARD_TEXT_(card, 2, "BPsz%04x", qports->entry_length);
return;
}
data = kzalloc(sizeof(*data), GFP_ATOMIC);
if (!data) {
QETH_CARD_TEXT(card, 2, "BPSalloc");
return;
}
INIT_WORK(&data->worker, qeth_bridge_state_change_worker);
data->card = card;
/* Information for the local port: */
data->role = qports->entry[0].role;
data->state = qports->entry[0].state;
queue_work(card->event_wq, &data->worker);
}
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
struct qeth_addr_change_data {
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
struct delayed_work dwork;
struct qeth_card *card;
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
struct qeth_ipacmd_addr_change ac_event;
};
s390/qeth: Translate address events into switchdev notifiers A qeth-l2 HiperSockets card can show switch-ish behaviour in the sense, that it can report all MACs that are reachable via this interface. Just like a switch device, it can notify the software bridge about changes to its fdb. This patch exploits this device-to-bridge-notification and extracts the relevant information from the hardware events to generate notifications to an attached software bridge. There are 2 sources for this information: 1) The reply message of Perform-Network-Subchannel-Operations (PNSO) (operation code ADDR_INFO) reports all addresses that are currently reachable (implemented in a later patch). 2) As long as device-to-bridge-notification is enabled, hardware will generate address change notification events, whenever the content of the hardware fdb changes (this patch). The bridge_hostnotify feature (PNSO operation code BRIDGE_INFO) uses the same address change notification events. We need to distinguish between qeth_pnso_mode QETH_PNSO_BRIDGEPORT and QETH_PNSO_ADDR_INFO and call a different handler. In both cases deadlocks must be prevented, if the workqueue is drained under lock and QETH_PNSO_NONE, when notification is disabled. bridge_hostnotify generates udev events, there is no intend to do the same for dev2br. Instead this patch will generate SWITCHDEV_FDB_ADD_TO_BRIDGE and SWITCHDEV_FDB_DEL_TO_BRIDGE notifications, that will cause the software bridge to add (or delete) entries to its fdb as 'extern_learn offload'. Documentation/networking/switchdev.txt proposes to add "depends NET_SWITCHDEV" to driver's Kconfig. This is not done here, so even in absence of the NET_SWITCHDEV module, the QETH_L2 module will still be built, but then the switchdev notifiers will have no effect. No VLAN filtering is done on the entries and VLAN information is not passed on to the bridge fdb entries. This could be added later. For now VLAN interfaces can be defined on the upper bridge interface. Multicast entries are not passed on to the bridge fdb. This could be added later. For now mcast flooding can be used in the bridge. The card reports all MACs that are in its FDB, but we must not pass on MACs that are registered for this interface. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:47 +08:00
static void qeth_l2_dev2br_worker(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct qeth_addr_change_data *data;
struct qeth_card *card;
s390/qeth: Reset address notification in case of buffer overflow In case hardware sends more device-to-bridge-address-change notfications than the qeth-l2 driver can handle, the hardware will send an overflow event and then stop sending any events. It expects software to flush its FDB and start over again. Re-enabling address-change-notification will report all current addresses. In order to re-enable address-change-notification this patch defines the functions qeth_l2_dev2br_an_set() and qeth_l2_dev2br_an_set_cb to enable or disable dev-to-bridge-address-notification. A following patch will use the learning_sync bridgeport flag to trigger enabling or disabling of address-change-notification, so we define priv->brport_features to store the current setting. BRIDGE_INFO and ADDR_INFO functionality are mutually exclusive, whereas ADDR_INFO and qeth_l2_vnicc* can be used together. Alternative implementations to handle buffer overflow: Just re-enabling notification and adding all newly reported addresses would cover any lost 'add' events, but not the lost 'delete' events. Then these invalid addresses would stay in the bridge FDB as long as the device exists. Setting the net device down and up, would be an alternative, but is a bit drastic. If the net device has many secondary addresses this will create many delete/add events at its peers which could de-stabilize the network segment. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:49 +08:00
struct qeth_priv *priv;
s390/qeth: Translate address events into switchdev notifiers A qeth-l2 HiperSockets card can show switch-ish behaviour in the sense, that it can report all MACs that are reachable via this interface. Just like a switch device, it can notify the software bridge about changes to its fdb. This patch exploits this device-to-bridge-notification and extracts the relevant information from the hardware events to generate notifications to an attached software bridge. There are 2 sources for this information: 1) The reply message of Perform-Network-Subchannel-Operations (PNSO) (operation code ADDR_INFO) reports all addresses that are currently reachable (implemented in a later patch). 2) As long as device-to-bridge-notification is enabled, hardware will generate address change notification events, whenever the content of the hardware fdb changes (this patch). The bridge_hostnotify feature (PNSO operation code BRIDGE_INFO) uses the same address change notification events. We need to distinguish between qeth_pnso_mode QETH_PNSO_BRIDGEPORT and QETH_PNSO_ADDR_INFO and call a different handler. In both cases deadlocks must be prevented, if the workqueue is drained under lock and QETH_PNSO_NONE, when notification is disabled. bridge_hostnotify generates udev events, there is no intend to do the same for dev2br. Instead this patch will generate SWITCHDEV_FDB_ADD_TO_BRIDGE and SWITCHDEV_FDB_DEL_TO_BRIDGE notifications, that will cause the software bridge to add (or delete) entries to its fdb as 'extern_learn offload'. Documentation/networking/switchdev.txt proposes to add "depends NET_SWITCHDEV" to driver's Kconfig. This is not done here, so even in absence of the NET_SWITCHDEV module, the QETH_L2 module will still be built, but then the switchdev notifiers will have no effect. No VLAN filtering is done on the entries and VLAN information is not passed on to the bridge fdb entries. This could be added later. For now VLAN interfaces can be defined on the upper bridge interface. Multicast entries are not passed on to the bridge fdb. This could be added later. For now mcast flooding can be used in the bridge. The card reports all MACs that are in its FDB, but we must not pass on MACs that are registered for this interface. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:47 +08:00
unsigned int i;
s390/qeth: Reset address notification in case of buffer overflow In case hardware sends more device-to-bridge-address-change notfications than the qeth-l2 driver can handle, the hardware will send an overflow event and then stop sending any events. It expects software to flush its FDB and start over again. Re-enabling address-change-notification will report all current addresses. In order to re-enable address-change-notification this patch defines the functions qeth_l2_dev2br_an_set() and qeth_l2_dev2br_an_set_cb to enable or disable dev-to-bridge-address-notification. A following patch will use the learning_sync bridgeport flag to trigger enabling or disabling of address-change-notification, so we define priv->brport_features to store the current setting. BRIDGE_INFO and ADDR_INFO functionality are mutually exclusive, whereas ADDR_INFO and qeth_l2_vnicc* can be used together. Alternative implementations to handle buffer overflow: Just re-enabling notification and adding all newly reported addresses would cover any lost 'add' events, but not the lost 'delete' events. Then these invalid addresses would stay in the bridge FDB as long as the device exists. Setting the net device down and up, would be an alternative, but is a bit drastic. If the net device has many secondary addresses this will create many delete/add events at its peers which could de-stabilize the network segment. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:49 +08:00
int rc;
s390/qeth: Translate address events into switchdev notifiers A qeth-l2 HiperSockets card can show switch-ish behaviour in the sense, that it can report all MACs that are reachable via this interface. Just like a switch device, it can notify the software bridge about changes to its fdb. This patch exploits this device-to-bridge-notification and extracts the relevant information from the hardware events to generate notifications to an attached software bridge. There are 2 sources for this information: 1) The reply message of Perform-Network-Subchannel-Operations (PNSO) (operation code ADDR_INFO) reports all addresses that are currently reachable (implemented in a later patch). 2) As long as device-to-bridge-notification is enabled, hardware will generate address change notification events, whenever the content of the hardware fdb changes (this patch). The bridge_hostnotify feature (PNSO operation code BRIDGE_INFO) uses the same address change notification events. We need to distinguish between qeth_pnso_mode QETH_PNSO_BRIDGEPORT and QETH_PNSO_ADDR_INFO and call a different handler. In both cases deadlocks must be prevented, if the workqueue is drained under lock and QETH_PNSO_NONE, when notification is disabled. bridge_hostnotify generates udev events, there is no intend to do the same for dev2br. Instead this patch will generate SWITCHDEV_FDB_ADD_TO_BRIDGE and SWITCHDEV_FDB_DEL_TO_BRIDGE notifications, that will cause the software bridge to add (or delete) entries to its fdb as 'extern_learn offload'. Documentation/networking/switchdev.txt proposes to add "depends NET_SWITCHDEV" to driver's Kconfig. This is not done here, so even in absence of the NET_SWITCHDEV module, the QETH_L2 module will still be built, but then the switchdev notifiers will have no effect. No VLAN filtering is done on the entries and VLAN information is not passed on to the bridge fdb entries. This could be added later. For now VLAN interfaces can be defined on the upper bridge interface. Multicast entries are not passed on to the bridge fdb. This could be added later. For now mcast flooding can be used in the bridge. The card reports all MACs that are in its FDB, but we must not pass on MACs that are registered for this interface. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:47 +08:00
data = container_of(dwork, struct qeth_addr_change_data, dwork);
card = data->card;
s390/qeth: Reset address notification in case of buffer overflow In case hardware sends more device-to-bridge-address-change notfications than the qeth-l2 driver can handle, the hardware will send an overflow event and then stop sending any events. It expects software to flush its FDB and start over again. Re-enabling address-change-notification will report all current addresses. In order to re-enable address-change-notification this patch defines the functions qeth_l2_dev2br_an_set() and qeth_l2_dev2br_an_set_cb to enable or disable dev-to-bridge-address-notification. A following patch will use the learning_sync bridgeport flag to trigger enabling or disabling of address-change-notification, so we define priv->brport_features to store the current setting. BRIDGE_INFO and ADDR_INFO functionality are mutually exclusive, whereas ADDR_INFO and qeth_l2_vnicc* can be used together. Alternative implementations to handle buffer overflow: Just re-enabling notification and adding all newly reported addresses would cover any lost 'add' events, but not the lost 'delete' events. Then these invalid addresses would stay in the bridge FDB as long as the device exists. Setting the net device down and up, would be an alternative, but is a bit drastic. If the net device has many secondary addresses this will create many delete/add events at its peers which could de-stabilize the network segment. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:49 +08:00
priv = netdev_priv(card->dev);
s390/qeth: Translate address events into switchdev notifiers A qeth-l2 HiperSockets card can show switch-ish behaviour in the sense, that it can report all MACs that are reachable via this interface. Just like a switch device, it can notify the software bridge about changes to its fdb. This patch exploits this device-to-bridge-notification and extracts the relevant information from the hardware events to generate notifications to an attached software bridge. There are 2 sources for this information: 1) The reply message of Perform-Network-Subchannel-Operations (PNSO) (operation code ADDR_INFO) reports all addresses that are currently reachable (implemented in a later patch). 2) As long as device-to-bridge-notification is enabled, hardware will generate address change notification events, whenever the content of the hardware fdb changes (this patch). The bridge_hostnotify feature (PNSO operation code BRIDGE_INFO) uses the same address change notification events. We need to distinguish between qeth_pnso_mode QETH_PNSO_BRIDGEPORT and QETH_PNSO_ADDR_INFO and call a different handler. In both cases deadlocks must be prevented, if the workqueue is drained under lock and QETH_PNSO_NONE, when notification is disabled. bridge_hostnotify generates udev events, there is no intend to do the same for dev2br. Instead this patch will generate SWITCHDEV_FDB_ADD_TO_BRIDGE and SWITCHDEV_FDB_DEL_TO_BRIDGE notifications, that will cause the software bridge to add (or delete) entries to its fdb as 'extern_learn offload'. Documentation/networking/switchdev.txt proposes to add "depends NET_SWITCHDEV" to driver's Kconfig. This is not done here, so even in absence of the NET_SWITCHDEV module, the QETH_L2 module will still be built, but then the switchdev notifiers will have no effect. No VLAN filtering is done on the entries and VLAN information is not passed on to the bridge fdb entries. This could be added later. For now VLAN interfaces can be defined on the upper bridge interface. Multicast entries are not passed on to the bridge fdb. This could be added later. For now mcast flooding can be used in the bridge. The card reports all MACs that are in its FDB, but we must not pass on MACs that are registered for this interface. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:47 +08:00
QETH_CARD_TEXT(card, 4, "dev2brew");
if (READ_ONCE(card->info.pnso_mode) == QETH_PNSO_NONE)
goto free;
if (data->ac_event.lost_event_mask) {
/* Potential re-config in progress, try again later: */
if (!rtnl_trylock()) {
queue_delayed_work(card->event_wq, dwork,
msecs_to_jiffies(100));
return;
}
if (!netif_device_present(card->dev)) {
rtnl_unlock();
goto free;
}
s390/qeth: Translate address events into switchdev notifiers A qeth-l2 HiperSockets card can show switch-ish behaviour in the sense, that it can report all MACs that are reachable via this interface. Just like a switch device, it can notify the software bridge about changes to its fdb. This patch exploits this device-to-bridge-notification and extracts the relevant information from the hardware events to generate notifications to an attached software bridge. There are 2 sources for this information: 1) The reply message of Perform-Network-Subchannel-Operations (PNSO) (operation code ADDR_INFO) reports all addresses that are currently reachable (implemented in a later patch). 2) As long as device-to-bridge-notification is enabled, hardware will generate address change notification events, whenever the content of the hardware fdb changes (this patch). The bridge_hostnotify feature (PNSO operation code BRIDGE_INFO) uses the same address change notification events. We need to distinguish between qeth_pnso_mode QETH_PNSO_BRIDGEPORT and QETH_PNSO_ADDR_INFO and call a different handler. In both cases deadlocks must be prevented, if the workqueue is drained under lock and QETH_PNSO_NONE, when notification is disabled. bridge_hostnotify generates udev events, there is no intend to do the same for dev2br. Instead this patch will generate SWITCHDEV_FDB_ADD_TO_BRIDGE and SWITCHDEV_FDB_DEL_TO_BRIDGE notifications, that will cause the software bridge to add (or delete) entries to its fdb as 'extern_learn offload'. Documentation/networking/switchdev.txt proposes to add "depends NET_SWITCHDEV" to driver's Kconfig. This is not done here, so even in absence of the NET_SWITCHDEV module, the QETH_L2 module will still be built, but then the switchdev notifiers will have no effect. No VLAN filtering is done on the entries and VLAN information is not passed on to the bridge fdb entries. This could be added later. For now VLAN interfaces can be defined on the upper bridge interface. Multicast entries are not passed on to the bridge fdb. This could be added later. For now mcast flooding can be used in the bridge. The card reports all MACs that are in its FDB, but we must not pass on MACs that are registered for this interface. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:47 +08:00
QETH_DBF_MESSAGE(3,
"Address change notification overflow on device %x\n",
CARD_DEVID(card));
s390/qeth: Reset address notification in case of buffer overflow In case hardware sends more device-to-bridge-address-change notfications than the qeth-l2 driver can handle, the hardware will send an overflow event and then stop sending any events. It expects software to flush its FDB and start over again. Re-enabling address-change-notification will report all current addresses. In order to re-enable address-change-notification this patch defines the functions qeth_l2_dev2br_an_set() and qeth_l2_dev2br_an_set_cb to enable or disable dev-to-bridge-address-notification. A following patch will use the learning_sync bridgeport flag to trigger enabling or disabling of address-change-notification, so we define priv->brport_features to store the current setting. BRIDGE_INFO and ADDR_INFO functionality are mutually exclusive, whereas ADDR_INFO and qeth_l2_vnicc* can be used together. Alternative implementations to handle buffer overflow: Just re-enabling notification and adding all newly reported addresses would cover any lost 'add' events, but not the lost 'delete' events. Then these invalid addresses would stay in the bridge FDB as long as the device exists. Setting the net device down and up, would be an alternative, but is a bit drastic. If the net device has many secondary addresses this will create many delete/add events at its peers which could de-stabilize the network segment. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:49 +08:00
/* Card fdb and bridge fdb are out of sync, card has stopped
* notifications (no need to drain_workqueue). Purge all
* 'extern_learn' entries from the parent bridge and restart
* the notifications.
*/
qeth_l2_dev2br_fdb_flush(card);
rc = qeth_l2_dev2br_an_set(card, true);
if (rc) {
/* TODO: if we want to retry after -EAGAIN, be
* aware there could be stale entries in the
* workqueue now, that need to be drained.
* For now we give up:
*/
netdev_err(card->dev,
"bridge learning_sync failed to recover: %d\n",
rc);
WRITE_ONCE(card->info.pnso_mode,
QETH_PNSO_NONE);
/* To remove fdb entries reported by an_set: */
qeth_l2_dev2br_fdb_flush(card);
priv->brport_features ^= BR_LEARNING_SYNC;
} else {
QETH_DBF_MESSAGE(3,
"Address Notification resynced on device %x\n",
CARD_DEVID(card));
}
rtnl_unlock();
s390/qeth: Translate address events into switchdev notifiers A qeth-l2 HiperSockets card can show switch-ish behaviour in the sense, that it can report all MACs that are reachable via this interface. Just like a switch device, it can notify the software bridge about changes to its fdb. This patch exploits this device-to-bridge-notification and extracts the relevant information from the hardware events to generate notifications to an attached software bridge. There are 2 sources for this information: 1) The reply message of Perform-Network-Subchannel-Operations (PNSO) (operation code ADDR_INFO) reports all addresses that are currently reachable (implemented in a later patch). 2) As long as device-to-bridge-notification is enabled, hardware will generate address change notification events, whenever the content of the hardware fdb changes (this patch). The bridge_hostnotify feature (PNSO operation code BRIDGE_INFO) uses the same address change notification events. We need to distinguish between qeth_pnso_mode QETH_PNSO_BRIDGEPORT and QETH_PNSO_ADDR_INFO and call a different handler. In both cases deadlocks must be prevented, if the workqueue is drained under lock and QETH_PNSO_NONE, when notification is disabled. bridge_hostnotify generates udev events, there is no intend to do the same for dev2br. Instead this patch will generate SWITCHDEV_FDB_ADD_TO_BRIDGE and SWITCHDEV_FDB_DEL_TO_BRIDGE notifications, that will cause the software bridge to add (or delete) entries to its fdb as 'extern_learn offload'. Documentation/networking/switchdev.txt proposes to add "depends NET_SWITCHDEV" to driver's Kconfig. This is not done here, so even in absence of the NET_SWITCHDEV module, the QETH_L2 module will still be built, but then the switchdev notifiers will have no effect. No VLAN filtering is done on the entries and VLAN information is not passed on to the bridge fdb entries. This could be added later. For now VLAN interfaces can be defined on the upper bridge interface. Multicast entries are not passed on to the bridge fdb. This could be added later. For now mcast flooding can be used in the bridge. The card reports all MACs that are in its FDB, but we must not pass on MACs that are registered for this interface. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:47 +08:00
} else {
for (i = 0; i < data->ac_event.num_entries; i++) {
struct qeth_ipacmd_addr_change_entry *entry =
&data->ac_event.entry[i];
qeth_l2_dev2br_fdb_notify(card,
entry->change_code,
&entry->token,
&entry->addr_lnid);
}
}
s390/qeth: Reset address notification in case of buffer overflow In case hardware sends more device-to-bridge-address-change notfications than the qeth-l2 driver can handle, the hardware will send an overflow event and then stop sending any events. It expects software to flush its FDB and start over again. Re-enabling address-change-notification will report all current addresses. In order to re-enable address-change-notification this patch defines the functions qeth_l2_dev2br_an_set() and qeth_l2_dev2br_an_set_cb to enable or disable dev-to-bridge-address-notification. A following patch will use the learning_sync bridgeport flag to trigger enabling or disabling of address-change-notification, so we define priv->brport_features to store the current setting. BRIDGE_INFO and ADDR_INFO functionality are mutually exclusive, whereas ADDR_INFO and qeth_l2_vnicc* can be used together. Alternative implementations to handle buffer overflow: Just re-enabling notification and adding all newly reported addresses would cover any lost 'add' events, but not the lost 'delete' events. Then these invalid addresses would stay in the bridge FDB as long as the device exists. Setting the net device down and up, would be an alternative, but is a bit drastic. If the net device has many secondary addresses this will create many delete/add events at its peers which could de-stabilize the network segment. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:49 +08:00
s390/qeth: Translate address events into switchdev notifiers A qeth-l2 HiperSockets card can show switch-ish behaviour in the sense, that it can report all MACs that are reachable via this interface. Just like a switch device, it can notify the software bridge about changes to its fdb. This patch exploits this device-to-bridge-notification and extracts the relevant information from the hardware events to generate notifications to an attached software bridge. There are 2 sources for this information: 1) The reply message of Perform-Network-Subchannel-Operations (PNSO) (operation code ADDR_INFO) reports all addresses that are currently reachable (implemented in a later patch). 2) As long as device-to-bridge-notification is enabled, hardware will generate address change notification events, whenever the content of the hardware fdb changes (this patch). The bridge_hostnotify feature (PNSO operation code BRIDGE_INFO) uses the same address change notification events. We need to distinguish between qeth_pnso_mode QETH_PNSO_BRIDGEPORT and QETH_PNSO_ADDR_INFO and call a different handler. In both cases deadlocks must be prevented, if the workqueue is drained under lock and QETH_PNSO_NONE, when notification is disabled. bridge_hostnotify generates udev events, there is no intend to do the same for dev2br. Instead this patch will generate SWITCHDEV_FDB_ADD_TO_BRIDGE and SWITCHDEV_FDB_DEL_TO_BRIDGE notifications, that will cause the software bridge to add (or delete) entries to its fdb as 'extern_learn offload'. Documentation/networking/switchdev.txt proposes to add "depends NET_SWITCHDEV" to driver's Kconfig. This is not done here, so even in absence of the NET_SWITCHDEV module, the QETH_L2 module will still be built, but then the switchdev notifiers will have no effect. No VLAN filtering is done on the entries and VLAN information is not passed on to the bridge fdb entries. This could be added later. For now VLAN interfaces can be defined on the upper bridge interface. Multicast entries are not passed on to the bridge fdb. This could be added later. For now mcast flooding can be used in the bridge. The card reports all MACs that are in its FDB, but we must not pass on MACs that are registered for this interface. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:47 +08:00
free:
kfree(data);
}
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
static void qeth_addr_change_event_worker(struct work_struct *work)
{
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
struct delayed_work *dwork = to_delayed_work(work);
struct qeth_addr_change_data *data;
struct qeth_card *card;
int i;
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
data = container_of(dwork, struct qeth_addr_change_data, dwork);
card = data->card;
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
QETH_CARD_TEXT(data->card, 4, "adrchgew");
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
if (READ_ONCE(card->info.pnso_mode) == QETH_PNSO_NONE)
goto free;
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
if (data->ac_event.lost_event_mask) {
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
/* Potential re-config in progress, try again later: */
if (!mutex_trylock(&card->sbp_lock)) {
queue_delayed_work(card->event_wq, dwork,
msecs_to_jiffies(100));
return;
}
dev_info(&data->card->gdev->dev,
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
"Address change notification stopped on %s (%s)\n",
netdev_name(card->dev),
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
(data->ac_event.lost_event_mask == 0x01)
? "Overflow"
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
: (data->ac_event.lost_event_mask == 0x02)
? "Bridge port state change"
: "Unknown reason");
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
data->card->options.sbp.hostnotification = 0;
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
card->info.pnso_mode = QETH_PNSO_NONE;
mutex_unlock(&data->card->sbp_lock);
qeth_bridge_emit_host_event(data->card, anev_abort,
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
0, NULL, NULL);
} else
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
for (i = 0; i < data->ac_event.num_entries; i++) {
struct qeth_ipacmd_addr_change_entry *entry =
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
&data->ac_event.entry[i];
qeth_bridge_emit_host_event(data->card,
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
anev_reg_unreg,
entry->change_code,
&entry->token,
&entry->addr_lnid);
}
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
free:
kfree(data);
}
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
static void qeth_addr_change_event(struct qeth_card *card,
struct qeth_ipa_cmd *cmd)
{
struct qeth_ipacmd_addr_change *hostevs =
&cmd->data.addrchange;
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
struct qeth_addr_change_data *data;
int extrasize;
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
if (card->info.pnso_mode == QETH_PNSO_NONE)
return;
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
QETH_CARD_TEXT(card, 4, "adrchgev");
if (cmd->hdr.return_code != 0x0000) {
if (cmd->hdr.return_code == 0x0010) {
if (hostevs->lost_event_mask == 0x00)
hostevs->lost_event_mask = 0xff;
} else {
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
QETH_CARD_TEXT_(card, 2, "ACHN%04x",
cmd->hdr.return_code);
return;
}
}
extrasize = sizeof(struct qeth_ipacmd_addr_change_entry) *
hostevs->num_entries;
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
data = kzalloc(sizeof(struct qeth_addr_change_data) + extrasize,
GFP_ATOMIC);
if (!data) {
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
QETH_CARD_TEXT(card, 2, "ACNalloc");
return;
}
s390/qeth: Translate address events into switchdev notifiers A qeth-l2 HiperSockets card can show switch-ish behaviour in the sense, that it can report all MACs that are reachable via this interface. Just like a switch device, it can notify the software bridge about changes to its fdb. This patch exploits this device-to-bridge-notification and extracts the relevant information from the hardware events to generate notifications to an attached software bridge. There are 2 sources for this information: 1) The reply message of Perform-Network-Subchannel-Operations (PNSO) (operation code ADDR_INFO) reports all addresses that are currently reachable (implemented in a later patch). 2) As long as device-to-bridge-notification is enabled, hardware will generate address change notification events, whenever the content of the hardware fdb changes (this patch). The bridge_hostnotify feature (PNSO operation code BRIDGE_INFO) uses the same address change notification events. We need to distinguish between qeth_pnso_mode QETH_PNSO_BRIDGEPORT and QETH_PNSO_ADDR_INFO and call a different handler. In both cases deadlocks must be prevented, if the workqueue is drained under lock and QETH_PNSO_NONE, when notification is disabled. bridge_hostnotify generates udev events, there is no intend to do the same for dev2br. Instead this patch will generate SWITCHDEV_FDB_ADD_TO_BRIDGE and SWITCHDEV_FDB_DEL_TO_BRIDGE notifications, that will cause the software bridge to add (or delete) entries to its fdb as 'extern_learn offload'. Documentation/networking/switchdev.txt proposes to add "depends NET_SWITCHDEV" to driver's Kconfig. This is not done here, so even in absence of the NET_SWITCHDEV module, the QETH_L2 module will still be built, but then the switchdev notifiers will have no effect. No VLAN filtering is done on the entries and VLAN information is not passed on to the bridge fdb entries. This could be added later. For now VLAN interfaces can be defined on the upper bridge interface. Multicast entries are not passed on to the bridge fdb. This could be added later. For now mcast flooding can be used in the bridge. The card reports all MACs that are in its FDB, but we must not pass on MACs that are registered for this interface. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:47 +08:00
if (card->info.pnso_mode == QETH_PNSO_BRIDGEPORT)
INIT_DELAYED_WORK(&data->dwork, qeth_addr_change_event_worker);
else
INIT_DELAYED_WORK(&data->dwork, qeth_l2_dev2br_worker);
data->card = card;
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
memcpy(&data->ac_event, hostevs,
sizeof(struct qeth_ipacmd_addr_change) + extrasize);
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
queue_delayed_work(card->event_wq, &data->dwork, 0);
}
/* SETBRIDGEPORT support; sending commands */
struct _qeth_sbp_cbctl {
union {
u32 supported;
struct {
enum qeth_sbp_roles *role;
enum qeth_sbp_states *state;
} qports;
} data;
};
static int qeth_bridgeport_makerc(struct qeth_card *card,
struct qeth_ipa_cmd *cmd)
{
struct qeth_ipacmd_setbridgeport *sbp = &cmd->data.sbp;
enum qeth_ipa_sbp_cmd setcmd = sbp->hdr.command_code;
u16 ipa_rc = cmd->hdr.return_code;
u16 sbp_rc = sbp->hdr.return_code;
int rc;
if (ipa_rc == IPA_RC_SUCCESS && sbp_rc == IPA_RC_SUCCESS)
return 0;
if ((IS_IQD(card) && ipa_rc == IPA_RC_SUCCESS) ||
(!IS_IQD(card) && ipa_rc == sbp_rc)) {
switch (sbp_rc) {
case IPA_RC_SUCCESS:
rc = 0;
break;
case IPA_RC_L2_UNSUPPORTED_CMD:
case IPA_RC_UNSUPPORTED_COMMAND:
rc = -EOPNOTSUPP;
break;
case IPA_RC_SBP_OSA_NOT_CONFIGURED:
case IPA_RC_SBP_IQD_NOT_CONFIGURED:
rc = -ENODEV; /* maybe not the best code here? */
dev_err(&card->gdev->dev,
"The device is not configured as a Bridge Port\n");
break;
case IPA_RC_SBP_OSA_OS_MISMATCH:
case IPA_RC_SBP_IQD_OS_MISMATCH:
rc = -EPERM;
dev_err(&card->gdev->dev,
"A Bridge Port is already configured by a different operating system\n");
break;
case IPA_RC_SBP_OSA_ANO_DEV_PRIMARY:
case IPA_RC_SBP_IQD_ANO_DEV_PRIMARY:
switch (setcmd) {
case IPA_SBP_SET_PRIMARY_BRIDGE_PORT:
rc = -EEXIST;
dev_err(&card->gdev->dev,
"The LAN already has a primary Bridge Port\n");
break;
case IPA_SBP_SET_SECONDARY_BRIDGE_PORT:
rc = -EBUSY;
dev_err(&card->gdev->dev,
"The device is already a primary Bridge Port\n");
break;
default:
rc = -EIO;
}
break;
case IPA_RC_SBP_OSA_CURRENT_SECOND:
case IPA_RC_SBP_IQD_CURRENT_SECOND:
rc = -EBUSY;
dev_err(&card->gdev->dev,
"The device is already a secondary Bridge Port\n");
break;
case IPA_RC_SBP_OSA_LIMIT_SECOND:
case IPA_RC_SBP_IQD_LIMIT_SECOND:
rc = -EEXIST;
dev_err(&card->gdev->dev,
"The LAN cannot have more secondary Bridge Ports\n");
break;
case IPA_RC_SBP_OSA_CURRENT_PRIMARY:
case IPA_RC_SBP_IQD_CURRENT_PRIMARY:
rc = -EBUSY;
dev_err(&card->gdev->dev,
"The device is already a primary Bridge Port\n");
break;
case IPA_RC_SBP_OSA_NOT_AUTHD_BY_ZMAN:
case IPA_RC_SBP_IQD_NOT_AUTHD_BY_ZMAN:
rc = -EACCES;
dev_err(&card->gdev->dev,
"The device is not authorized to be a Bridge Port\n");
break;
default:
rc = -EIO;
}
} else {
switch (ipa_rc) {
case IPA_RC_NOTSUPP:
rc = -EOPNOTSUPP;
break;
case IPA_RC_UNSUPPORTED_COMMAND:
rc = -EOPNOTSUPP;
break;
default:
rc = -EIO;
}
}
if (rc) {
QETH_CARD_TEXT_(card, 2, "SBPi%04x", ipa_rc);
QETH_CARD_TEXT_(card, 2, "SBPc%04x", sbp_rc);
}
return rc;
}
static struct qeth_cmd_buffer *qeth_sbp_build_cmd(struct qeth_card *card,
enum qeth_ipa_sbp_cmd sbp_cmd,
unsigned int data_length)
{
enum qeth_ipa_cmds ipa_cmd = IS_IQD(card) ? IPA_CMD_SETBRIDGEPORT_IQD :
IPA_CMD_SETBRIDGEPORT_OSA;
struct qeth_ipacmd_sbp_hdr *hdr;
struct qeth_cmd_buffer *iob;
iob = qeth_ipa_alloc_cmd(card, ipa_cmd, QETH_PROT_NONE,
data_length +
offsetof(struct qeth_ipacmd_setbridgeport,
data));
if (!iob)
return iob;
hdr = &__ipa_cmd(iob)->data.sbp.hdr;
hdr->cmdlength = sizeof(*hdr) + data_length;
hdr->command_code = sbp_cmd;
hdr->used_total = 1;
hdr->seq_no = 1;
return iob;
}
static int qeth_bridgeport_query_support_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data)
{
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
int rc;
QETH_CARD_TEXT(card, 2, "brqsupcb");
rc = qeth_bridgeport_makerc(card, cmd);
if (rc)
return rc;
cbctl->data.supported =
cmd->data.sbp.data.query_cmds_supp.supported_cmds;
return 0;
}
/**
* qeth_bridgeport_query_support() - store bitmask of supported subfunctions.
* @card: qeth_card structure pointer.
*
* Sets bitmask of supported setbridgeport subfunctions in the qeth_card
* strucutre: card->options.sbp.supported_funcs.
*/
static void qeth_bridgeport_query_support(struct qeth_card *card)
{
struct qeth_cmd_buffer *iob;
struct _qeth_sbp_cbctl cbctl;
QETH_CARD_TEXT(card, 2, "brqsuppo");
iob = qeth_sbp_build_cmd(card, IPA_SBP_QUERY_COMMANDS_SUPPORTED,
SBP_DATA_SIZEOF(query_cmds_supp));
390/qeth: Fix locking warning during qeth device setup Do not wait for channel command buffers in IPA commands. The potential wait could be done while holding a spin lock and causes in recent kernels such a bug if kernel lock debugging is enabled: kernel: BUG: sleeping function called from invalid context at drivers/s390/net/qeth_core_main.c: 794 kernel: in_atomic(): 1, irqs_disabled(): 0, pid: 2031, name: NetworkManager kernel: 2 locks held by NetworkManager/2031: kernel: #0: (rtnl_mutex){+.+.+.}, at: [<00000000006e0d7a>] rtnetlink_rcv+0x32/0x50 kernel: #1: (_xmit_ETHER){+.....}, at: [<00000000006cfe90>] dev_set_rx_mode+0x30/0x50 kernel: CPU: 0 PID: 2031 Comm: NetworkManager Not tainted 3.18.0-rc5-next-20141124 #1 kernel: 00000000275fb1f0 00000000275fb280 0000000000000002 0000000000000000 00000000275fb320 00000000275fb298 00000000275fb298 00000000007e326a 0000000000000000 000000000099ce2c 00000000009b4988 000000000000000b 00000000275fb2e0 00000000275fb280 0000000000000000 0000000000000000 0000000000000000 00000000001129c8 00000000275fb280 00000000275fb2e0 kernel: Call Trace: kernel: ([<00000000001128b0>] show_trace+0xf8/0x158) kernel: [<000000000011297a>] show_stack+0x6a/0xe8 kernel: [<00000000007e995a>] dump_stack+0x82/0xb0 kernel: [<000000000017d668>] ___might_sleep+0x170/0x228 kernel: [<000003ff80026f0e>] qeth_wait_for_buffer+0x36/0xd0 [qeth] kernel: [<000003ff80026fe2>] qeth_get_ipacmd_buffer+0x3a/0xc0 [qeth] kernel: [<000003ff80105078>] qeth_l3_send_setdelmc+0x58/0xf8 [qeth_l3] kernel: [<000003ff8010b1fe>] qeth_l3_set_ip_addr_list+0x2c6/0x848 [qeth_l3] kernel: [<000003ff8010bbb4>] qeth_l3_set_multicast_list+0x434/0xc48 [qeth_l3] kernel: [<00000000006cfe9a>] dev_set_rx_mode+0x3a/0x50 kernel: [<00000000006cff90>] __dev_open+0xe0/0x140 kernel: [<00000000006d02a0>] __dev_change_flags+0xa0/0x178 kernel: [<00000000006d03a8>] dev_change_flags+0x30/0x70 kernel: [<00000000006e14ee>] do_setlink+0x346/0x9a0 ... The device driver has plenty of command buffers available per channel for channel command communication. In the extremely rare case when there is no command buffer available, return a NULL pointer and issue a warning in the kernel log. The caller handles the case when a NULL pointer is encountered and returns an error. In the case the wait for command buffer is possible (because no lock is held as in the OSN case), still wait until a channel command buffer is available. Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com> Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Reviewed-by: Eugene Crosser <Eugene.Crosser@ru.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-01-21 20:39:10 +08:00
if (!iob)
return;
if (qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_support_cb,
&cbctl)) {
card->options.sbp.role = QETH_SBP_ROLE_NONE;
card->options.sbp.supported_funcs = 0;
return;
}
card->options.sbp.supported_funcs = cbctl.data.supported;
}
static int qeth_bridgeport_query_ports_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data)
{
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
struct qeth_sbp_port_data *qports;
int rc;
QETH_CARD_TEXT(card, 2, "brqprtcb");
rc = qeth_bridgeport_makerc(card, cmd);
if (rc)
return rc;
qports = &cmd->data.sbp.data.port_data;
if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) {
QETH_CARD_TEXT_(card, 2, "SBPs%04x", qports->entry_length);
return -EINVAL;
}
/* first entry contains the state of the local port */
if (qports->num_entries > 0) {
if (cbctl->data.qports.role)
*cbctl->data.qports.role = qports->entry[0].role;
if (cbctl->data.qports.state)
*cbctl->data.qports.state = qports->entry[0].state;
}
return 0;
}
/**
* qeth_bridgeport_query_ports() - query local bridgeport status.
* @card: qeth_card structure pointer.
* @role: Role of the port: 0-none, 1-primary, 2-secondary.
* @state: State of the port: 0-inactive, 1-standby, 2-active.
*
* Returns negative errno-compatible error indication or 0 on success.
*
* 'role' and 'state' are not updated in case of hardware operation failure.
*/
int qeth_bridgeport_query_ports(struct qeth_card *card,
enum qeth_sbp_roles *role, enum qeth_sbp_states *state)
{
struct qeth_cmd_buffer *iob;
struct _qeth_sbp_cbctl cbctl = {
.data = {
.qports = {
.role = role,
.state = state,
},
},
};
QETH_CARD_TEXT(card, 2, "brqports");
if (!(card->options.sbp.supported_funcs & IPA_SBP_QUERY_BRIDGE_PORTS))
return -EOPNOTSUPP;
iob = qeth_sbp_build_cmd(card, IPA_SBP_QUERY_BRIDGE_PORTS, 0);
390/qeth: Fix locking warning during qeth device setup Do not wait for channel command buffers in IPA commands. The potential wait could be done while holding a spin lock and causes in recent kernels such a bug if kernel lock debugging is enabled: kernel: BUG: sleeping function called from invalid context at drivers/s390/net/qeth_core_main.c: 794 kernel: in_atomic(): 1, irqs_disabled(): 0, pid: 2031, name: NetworkManager kernel: 2 locks held by NetworkManager/2031: kernel: #0: (rtnl_mutex){+.+.+.}, at: [<00000000006e0d7a>] rtnetlink_rcv+0x32/0x50 kernel: #1: (_xmit_ETHER){+.....}, at: [<00000000006cfe90>] dev_set_rx_mode+0x30/0x50 kernel: CPU: 0 PID: 2031 Comm: NetworkManager Not tainted 3.18.0-rc5-next-20141124 #1 kernel: 00000000275fb1f0 00000000275fb280 0000000000000002 0000000000000000 00000000275fb320 00000000275fb298 00000000275fb298 00000000007e326a 0000000000000000 000000000099ce2c 00000000009b4988 000000000000000b 00000000275fb2e0 00000000275fb280 0000000000000000 0000000000000000 0000000000000000 00000000001129c8 00000000275fb280 00000000275fb2e0 kernel: Call Trace: kernel: ([<00000000001128b0>] show_trace+0xf8/0x158) kernel: [<000000000011297a>] show_stack+0x6a/0xe8 kernel: [<00000000007e995a>] dump_stack+0x82/0xb0 kernel: [<000000000017d668>] ___might_sleep+0x170/0x228 kernel: [<000003ff80026f0e>] qeth_wait_for_buffer+0x36/0xd0 [qeth] kernel: [<000003ff80026fe2>] qeth_get_ipacmd_buffer+0x3a/0xc0 [qeth] kernel: [<000003ff80105078>] qeth_l3_send_setdelmc+0x58/0xf8 [qeth_l3] kernel: [<000003ff8010b1fe>] qeth_l3_set_ip_addr_list+0x2c6/0x848 [qeth_l3] kernel: [<000003ff8010bbb4>] qeth_l3_set_multicast_list+0x434/0xc48 [qeth_l3] kernel: [<00000000006cfe9a>] dev_set_rx_mode+0x3a/0x50 kernel: [<00000000006cff90>] __dev_open+0xe0/0x140 kernel: [<00000000006d02a0>] __dev_change_flags+0xa0/0x178 kernel: [<00000000006d03a8>] dev_change_flags+0x30/0x70 kernel: [<00000000006e14ee>] do_setlink+0x346/0x9a0 ... The device driver has plenty of command buffers available per channel for channel command communication. In the extremely rare case when there is no command buffer available, return a NULL pointer and issue a warning in the kernel log. The caller handles the case when a NULL pointer is encountered and returns an error. In the case the wait for command buffer is possible (because no lock is held as in the OSN case), still wait until a channel command buffer is available. Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com> Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Reviewed-by: Eugene Crosser <Eugene.Crosser@ru.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-01-21 20:39:10 +08:00
if (!iob)
return -ENOMEM;
return qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_ports_cb,
&cbctl);
}
static int qeth_bridgeport_set_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data)
{
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data;
QETH_CARD_TEXT(card, 2, "brsetrcb");
return qeth_bridgeport_makerc(card, cmd);
}
/**
* qeth_bridgeport_setrole() - Assign primary role to the port.
* @card: qeth_card structure pointer.
* @role: Role to assign.
*
* Returns negative errno-compatible error indication or 0 on success.
*/
int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role)
{
struct qeth_cmd_buffer *iob;
enum qeth_ipa_sbp_cmd setcmd;
unsigned int cmdlength = 0;
QETH_CARD_TEXT(card, 2, "brsetrol");
switch (role) {
case QETH_SBP_ROLE_NONE:
setcmd = IPA_SBP_RESET_BRIDGE_PORT_ROLE;
break;
case QETH_SBP_ROLE_PRIMARY:
setcmd = IPA_SBP_SET_PRIMARY_BRIDGE_PORT;
cmdlength = SBP_DATA_SIZEOF(set_primary);
break;
case QETH_SBP_ROLE_SECONDARY:
setcmd = IPA_SBP_SET_SECONDARY_BRIDGE_PORT;
break;
default:
return -EINVAL;
}
if (!(card->options.sbp.supported_funcs & setcmd))
return -EOPNOTSUPP;
iob = qeth_sbp_build_cmd(card, setcmd, cmdlength);
390/qeth: Fix locking warning during qeth device setup Do not wait for channel command buffers in IPA commands. The potential wait could be done while holding a spin lock and causes in recent kernels such a bug if kernel lock debugging is enabled: kernel: BUG: sleeping function called from invalid context at drivers/s390/net/qeth_core_main.c: 794 kernel: in_atomic(): 1, irqs_disabled(): 0, pid: 2031, name: NetworkManager kernel: 2 locks held by NetworkManager/2031: kernel: #0: (rtnl_mutex){+.+.+.}, at: [<00000000006e0d7a>] rtnetlink_rcv+0x32/0x50 kernel: #1: (_xmit_ETHER){+.....}, at: [<00000000006cfe90>] dev_set_rx_mode+0x30/0x50 kernel: CPU: 0 PID: 2031 Comm: NetworkManager Not tainted 3.18.0-rc5-next-20141124 #1 kernel: 00000000275fb1f0 00000000275fb280 0000000000000002 0000000000000000 00000000275fb320 00000000275fb298 00000000275fb298 00000000007e326a 0000000000000000 000000000099ce2c 00000000009b4988 000000000000000b 00000000275fb2e0 00000000275fb280 0000000000000000 0000000000000000 0000000000000000 00000000001129c8 00000000275fb280 00000000275fb2e0 kernel: Call Trace: kernel: ([<00000000001128b0>] show_trace+0xf8/0x158) kernel: [<000000000011297a>] show_stack+0x6a/0xe8 kernel: [<00000000007e995a>] dump_stack+0x82/0xb0 kernel: [<000000000017d668>] ___might_sleep+0x170/0x228 kernel: [<000003ff80026f0e>] qeth_wait_for_buffer+0x36/0xd0 [qeth] kernel: [<000003ff80026fe2>] qeth_get_ipacmd_buffer+0x3a/0xc0 [qeth] kernel: [<000003ff80105078>] qeth_l3_send_setdelmc+0x58/0xf8 [qeth_l3] kernel: [<000003ff8010b1fe>] qeth_l3_set_ip_addr_list+0x2c6/0x848 [qeth_l3] kernel: [<000003ff8010bbb4>] qeth_l3_set_multicast_list+0x434/0xc48 [qeth_l3] kernel: [<00000000006cfe9a>] dev_set_rx_mode+0x3a/0x50 kernel: [<00000000006cff90>] __dev_open+0xe0/0x140 kernel: [<00000000006d02a0>] __dev_change_flags+0xa0/0x178 kernel: [<00000000006d03a8>] dev_change_flags+0x30/0x70 kernel: [<00000000006e14ee>] do_setlink+0x346/0x9a0 ... The device driver has plenty of command buffers available per channel for channel command communication. In the extremely rare case when there is no command buffer available, return a NULL pointer and issue a warning in the kernel log. The caller handles the case when a NULL pointer is encountered and returns an error. In the case the wait for command buffer is possible (because no lock is held as in the OSN case), still wait until a channel command buffer is available. Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com> Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Reviewed-by: Eugene Crosser <Eugene.Crosser@ru.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-01-21 20:39:10 +08:00
if (!iob)
return -ENOMEM;
return qeth_send_ipa_cmd(card, iob, qeth_bridgeport_set_cb, NULL);
}
static void qeth_bridgeport_an_set_cb(void *priv,
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
struct chsc_pnso_naid_l2 *entry)
{
struct qeth_card *card = (struct qeth_card *)priv;
u8 code;
code = IPA_ADDR_CHANGE_CODE_MACADDR;
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
if (entry->addr_lnid.lnid < VLAN_N_VID)
code |= IPA_ADDR_CHANGE_CODE_VLANID;
qeth_bridge_emit_host_event(card, anev_reg_unreg, code,
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
(struct net_if_token *)&entry->nit,
(struct mac_addr_lnid *)&entry->addr_lnid);
}
/**
* qeth_bridgeport_an_set() - Enable or disable bridgeport address notification
* @card: qeth_card structure pointer.
* @enable: 0 - disable, non-zero - enable notifications
*
* Returns negative errno-compatible error indication or 0 on success.
*
* On enable, emits a series of address notifications udev events for all
* currently registered hosts.
*/
int qeth_bridgeport_an_set(struct qeth_card *card, int enable)
{
int rc;
if (!card->options.sbp.supported_funcs)
return -EOPNOTSUPP;
if (enable) {
qeth_bridge_emit_host_event(card, anev_reset, 0, NULL, NULL);
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
qeth_l2_set_pnso_mode(card, QETH_PNSO_BRIDGEPORT);
rc = qeth_l2_pnso(card, PNSO_OC_NET_BRIDGE_INFO, 1,
qeth_bridgeport_an_set_cb, card);
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
if (rc)
qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
} else {
rc = qeth_l2_pnso(card, PNSO_OC_NET_BRIDGE_INFO, 0, NULL, NULL);
s390/qeth: strictly order bridge address events The current code for bridge address events has two shortcomings in its control sequence: 1. after disabling address events via PNSO, we don't flush the remaining events from the event_wq. So if the feature is re-enabled fast enough, stale events could leak over. 2. PNSO and the events' arrival via the READ ccw device are unordered. So even if we flushed the workqueue, it's difficult to say whether the READ device might produce more events onto the workqueue afterwards. Fix this by 1. explicitly fencing off the events when we no longer care, in the READ device's event handler. This ensures that once we flush the workqueue, it doesn't get additional address events. 2. Flush the workqueue after disabling the events & fencing them off. As the code that triggers the flush will typically hold the sbp_lock, we need to rework the worker code to avoid a deadlock here in case of a 'notifications-stopped' event. In case of lock contention, requeue such an event with a delay. We'll eventually aquire the lock, or spot that the feature has been disabled and the event can thus be discarded. This leaves the theoretical race that a stale event could arrive _after_ we re-enabled ourselves to receive events again. Such an event would be impossible to distinguish from a 'good' event, nothing we can do about it. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-27 16:17:05 +08:00
qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
}
s390/cio, s390/qeth: cleanup PNSO CHSC CHSC3D (PNSO - perform network subchannel operation) is used for OC0 (Store-network-bridging-information) as well as for OC3 (Store-network-address-information). So common fields are renamed from *brinfo* to *pnso*. Also *_bridge_host_* is changed into *_addr_change_*, e.g. qeth_bridge_host_event to qeth_addr_change_event, for the same reasons. The keywords in the card traces are changed accordingly. Remove unused L3 types, as PNSO will only return Layer2 entries. Make PNSO CHSC implementation more consistent with existing API usage: Add new function ccw_device_pnso() to drivers/s390/cio/device_ops.c and the function declaration to arch/s390/include/asm/ccwdev.h, which takes a struct ccw_device * as parameter instead of schid and calls chsc_pnso(). PNSO CHSC has no strict relationship to qdio. So move the calling function from qdio to qeth_l2 and move the necessary structures to a new file arch/s390/include/asm/chsc.h. Do response code evaluation only in chsc_error_from_response() and use return code in all other places. qeth_anset_makerc() was meant to evaluate the PNSO response code, but never did, because pnso_rc was already non-zero. Indentation was corrected in some places. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2020-04-16 21:08:41 +08:00
return rc;
}
/* VNIC Characteristics support */
/* handle VNICC IPA command return codes; convert to error codes */
static int qeth_l2_vnicc_makerc(struct qeth_card *card, u16 ipa_rc)
{
int rc;
switch (ipa_rc) {
case IPA_RC_SUCCESS:
return ipa_rc;
case IPA_RC_L2_UNSUPPORTED_CMD:
case IPA_RC_NOTSUPP:
rc = -EOPNOTSUPP;
break;
case IPA_RC_VNICC_OOSEQ:
rc = -EALREADY;
break;
case IPA_RC_VNICC_VNICBP:
rc = -EBUSY;
break;
case IPA_RC_L2_ADDR_TABLE_FULL:
rc = -ENOSPC;
break;
case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP:
rc = -EACCES;
break;
default:
rc = -EIO;
}
QETH_CARD_TEXT_(card, 2, "err%04x", ipa_rc);
return rc;
}
/* generic VNICC request call back */
static int qeth_l2_vnicc_request_cb(struct qeth_card *card,
struct qeth_reply *reply,
unsigned long data)
{
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
struct qeth_ipacmd_vnicc *rep = &cmd->data.vnicc;
u32 sub_cmd = cmd->data.vnicc.hdr.sub_command;
QETH_CARD_TEXT(card, 2, "vniccrcb");
if (cmd->hdr.return_code)
return qeth_l2_vnicc_makerc(card, cmd->hdr.return_code);
/* return results to caller */
card->options.vnicc.sup_chars = rep->vnicc_cmds.supported;
card->options.vnicc.cur_chars = rep->vnicc_cmds.enabled;
if (sub_cmd == IPA_VNICC_QUERY_CMDS)
*(u32 *)reply->param = rep->data.query_cmds.sup_cmds;
else if (sub_cmd == IPA_VNICC_GET_TIMEOUT)
*(u32 *)reply->param = rep->data.getset_timeout.timeout;
return 0;
}
static struct qeth_cmd_buffer *qeth_l2_vnicc_build_cmd(struct qeth_card *card,
u32 vnicc_cmd,
unsigned int data_length)
{
struct qeth_ipacmd_vnicc_hdr *hdr;
struct qeth_cmd_buffer *iob;
iob = qeth_ipa_alloc_cmd(card, IPA_CMD_VNICC, QETH_PROT_NONE,
data_length +
offsetof(struct qeth_ipacmd_vnicc, data));
if (!iob)
return NULL;
hdr = &__ipa_cmd(iob)->data.vnicc.hdr;
hdr->data_length = sizeof(*hdr) + data_length;
hdr->sub_command = vnicc_cmd;
return iob;
}
/* VNICC query VNIC characteristics request */
static int qeth_l2_vnicc_query_chars(struct qeth_card *card)
{
struct qeth_cmd_buffer *iob;
QETH_CARD_TEXT(card, 2, "vniccqch");
iob = qeth_l2_vnicc_build_cmd(card, IPA_VNICC_QUERY_CHARS, 0);
if (!iob)
return -ENOMEM;
return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, NULL);
}
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
/* VNICC query sub commands request */
static int qeth_l2_vnicc_query_cmds(struct qeth_card *card, u32 vnic_char,
u32 *sup_cmds)
{
struct qeth_cmd_buffer *iob;
QETH_CARD_TEXT(card, 2, "vniccqcm");
iob = qeth_l2_vnicc_build_cmd(card, IPA_VNICC_QUERY_CMDS,
VNICC_DATA_SIZEOF(query_cmds));
if (!iob)
return -ENOMEM;
__ipa_cmd(iob)->data.vnicc.data.query_cmds.vnic_char = vnic_char;
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, sup_cmds);
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
}
/* VNICC enable/disable characteristic request */
static int qeth_l2_vnicc_set_char(struct qeth_card *card, u32 vnic_char,
u32 cmd)
{
struct qeth_cmd_buffer *iob;
QETH_CARD_TEXT(card, 2, "vniccedc");
iob = qeth_l2_vnicc_build_cmd(card, cmd, VNICC_DATA_SIZEOF(set_char));
if (!iob)
return -ENOMEM;
__ipa_cmd(iob)->data.vnicc.data.set_char.vnic_char = vnic_char;
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, NULL);
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
}
/* VNICC get/set timeout for characteristic request */
static int qeth_l2_vnicc_getset_timeout(struct qeth_card *card, u32 vnicc,
u32 cmd, u32 *timeout)
{
struct qeth_vnicc_getset_timeout *getset_timeout;
struct qeth_cmd_buffer *iob;
QETH_CARD_TEXT(card, 2, "vniccgst");
iob = qeth_l2_vnicc_build_cmd(card, cmd,
VNICC_DATA_SIZEOF(getset_timeout));
if (!iob)
return -ENOMEM;
getset_timeout = &__ipa_cmd(iob)->data.vnicc.data.getset_timeout;
getset_timeout->vnic_char = vnicc;
if (cmd == IPA_VNICC_SET_TIMEOUT)
getset_timeout->timeout = *timeout;
return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, timeout);
}
/* recover user timeout setting */
static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc,
u32 *timeout)
{
if (card->options.vnicc.sup_chars & vnicc &&
card->options.vnicc.getset_timeout_sup & vnicc &&
!qeth_l2_vnicc_getset_timeout(card, vnicc, IPA_VNICC_SET_TIMEOUT,
timeout))
return false;
*timeout = QETH_VNICC_DEFAULT_TIMEOUT;
return true;
}
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
/* set current VNICC flag state; called from sysfs store function */
int qeth_l2_vnicc_set_state(struct qeth_card *card, u32 vnicc, bool state)
{
int rc = 0;
u32 cmd;
QETH_CARD_TEXT(card, 2, "vniccsch");
/* check if characteristic and enable/disable are supported */
if (!(card->options.vnicc.sup_chars & vnicc) ||
!(card->options.vnicc.set_char_sup & vnicc))
return -EOPNOTSUPP;
if (qeth_bridgeport_is_in_use(card))
return -EBUSY;
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
/* set enable/disable command and store wanted characteristic */
if (state) {
cmd = IPA_VNICC_ENABLE;
card->options.vnicc.wanted_chars |= vnicc;
} else {
cmd = IPA_VNICC_DISABLE;
card->options.vnicc.wanted_chars &= ~vnicc;
}
/* do we need to do anything? */
if (card->options.vnicc.cur_chars == card->options.vnicc.wanted_chars)
return rc;
/* if card is not ready, simply stop here */
if (!qeth_card_hw_is_reachable(card)) {
if (state)
card->options.vnicc.cur_chars |= vnicc;
else
card->options.vnicc.cur_chars &= ~vnicc;
return rc;
}
rc = qeth_l2_vnicc_set_char(card, vnicc, cmd);
if (rc)
card->options.vnicc.wanted_chars =
card->options.vnicc.cur_chars;
else {
/* successful online VNICC change; handle special cases */
if (state && vnicc == QETH_VNICC_RX_BCAST)
card->options.vnicc.rx_bcast_enabled = true;
if (!state && vnicc == QETH_VNICC_LEARNING)
qeth_l2_vnicc_recover_timeout(card, vnicc,
&card->options.vnicc.learning_timeout);
}
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
return rc;
}
/* get current VNICC flag state; called from sysfs show function */
int qeth_l2_vnicc_get_state(struct qeth_card *card, u32 vnicc, bool *state)
{
int rc = 0;
QETH_CARD_TEXT(card, 2, "vniccgch");
/* check if characteristic is supported */
if (!(card->options.vnicc.sup_chars & vnicc))
return -EOPNOTSUPP;
if (qeth_bridgeport_is_in_use(card))
return -EBUSY;
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
/* if card is ready, query current VNICC state */
if (qeth_card_hw_is_reachable(card))
rc = qeth_l2_vnicc_query_chars(card);
*state = (card->options.vnicc.cur_chars & vnicc) ? true : false;
return rc;
}
/* set VNICC timeout; called from sysfs store function. Currently, only learning
* supports timeout
*/
int qeth_l2_vnicc_set_timeout(struct qeth_card *card, u32 timeout)
{
int rc = 0;
QETH_CARD_TEXT(card, 2, "vniccsto");
/* check if characteristic and set_timeout are supported */
if (!(card->options.vnicc.sup_chars & QETH_VNICC_LEARNING) ||
!(card->options.vnicc.getset_timeout_sup & QETH_VNICC_LEARNING))
return -EOPNOTSUPP;
if (qeth_bridgeport_is_in_use(card))
return -EBUSY;
/* do we need to do anything? */
if (card->options.vnicc.learning_timeout == timeout)
return rc;
/* if card is not ready, simply store the value internally and return */
if (!qeth_card_hw_is_reachable(card)) {
card->options.vnicc.learning_timeout = timeout;
return rc;
}
/* send timeout value to card; if successful, store value internally */
rc = qeth_l2_vnicc_getset_timeout(card, QETH_VNICC_LEARNING,
IPA_VNICC_SET_TIMEOUT, &timeout);
if (!rc)
card->options.vnicc.learning_timeout = timeout;
return rc;
}
/* get current VNICC timeout; called from sysfs show function. Currently, only
* learning supports timeout
*/
int qeth_l2_vnicc_get_timeout(struct qeth_card *card, u32 *timeout)
{
int rc = 0;
QETH_CARD_TEXT(card, 2, "vniccgto");
/* check if characteristic and get_timeout are supported */
if (!(card->options.vnicc.sup_chars & QETH_VNICC_LEARNING) ||
!(card->options.vnicc.getset_timeout_sup & QETH_VNICC_LEARNING))
return -EOPNOTSUPP;
if (qeth_bridgeport_is_in_use(card))
return -EBUSY;
/* if card is ready, get timeout. Otherwise, just return stored value */
*timeout = card->options.vnicc.learning_timeout;
if (qeth_card_hw_is_reachable(card))
rc = qeth_l2_vnicc_getset_timeout(card, QETH_VNICC_LEARNING,
IPA_VNICC_GET_TIMEOUT,
timeout);
return rc;
}
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
/* check if VNICC is currently enabled */
s390/qeth: Reset address notification in case of buffer overflow In case hardware sends more device-to-bridge-address-change notfications than the qeth-l2 driver can handle, the hardware will send an overflow event and then stop sending any events. It expects software to flush its FDB and start over again. Re-enabling address-change-notification will report all current addresses. In order to re-enable address-change-notification this patch defines the functions qeth_l2_dev2br_an_set() and qeth_l2_dev2br_an_set_cb to enable or disable dev-to-bridge-address-notification. A following patch will use the learning_sync bridgeport flag to trigger enabling or disabling of address-change-notification, so we define priv->brport_features to store the current setting. BRIDGE_INFO and ADDR_INFO functionality are mutually exclusive, whereas ADDR_INFO and qeth_l2_vnicc* can be used together. Alternative implementations to handle buffer overflow: Just re-enabling notification and adding all newly reported addresses would cover any lost 'add' events, but not the lost 'delete' events. Then these invalid addresses would stay in the bridge FDB as long as the device exists. Setting the net device down and up, would be an alternative, but is a bit drastic. If the net device has many secondary addresses this will create many delete/add events at its peers which could de-stabilize the network segment. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:49 +08:00
static bool _qeth_l2_vnicc_is_in_use(struct qeth_card *card)
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
{
if (!card->options.vnicc.sup_chars)
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
return false;
/* default values are only OK if rx_bcast was not enabled by user
* or the card is offline.
*/
if (card->options.vnicc.cur_chars == QETH_VNICC_DEFAULT) {
if (!card->options.vnicc.rx_bcast_enabled ||
!qeth_card_hw_is_reachable(card))
return false;
}
return true;
}
s390/qeth: Reset address notification in case of buffer overflow In case hardware sends more device-to-bridge-address-change notfications than the qeth-l2 driver can handle, the hardware will send an overflow event and then stop sending any events. It expects software to flush its FDB and start over again. Re-enabling address-change-notification will report all current addresses. In order to re-enable address-change-notification this patch defines the functions qeth_l2_dev2br_an_set() and qeth_l2_dev2br_an_set_cb to enable or disable dev-to-bridge-address-notification. A following patch will use the learning_sync bridgeport flag to trigger enabling or disabling of address-change-notification, so we define priv->brport_features to store the current setting. BRIDGE_INFO and ADDR_INFO functionality are mutually exclusive, whereas ADDR_INFO and qeth_l2_vnicc* can be used together. Alternative implementations to handle buffer overflow: Just re-enabling notification and adding all newly reported addresses would cover any lost 'add' events, but not the lost 'delete' events. Then these invalid addresses would stay in the bridge FDB as long as the device exists. Setting the net device down and up, would be an alternative, but is a bit drastic. If the net device has many secondary addresses this will create many delete/add events at its peers which could de-stabilize the network segment. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-11 01:23:49 +08:00
/**
* qeth_bridgeport_allowed - are any qeth_bridgeport functions allowed?
* @card: qeth_card structure pointer
*
* qeth_bridgeport functionality is mutually exclusive with usage of the
* VNIC Characteristics and dev2br address notifications
*/
bool qeth_bridgeport_allowed(struct qeth_card *card)
{
struct qeth_priv *priv = netdev_priv(card->dev);
return (!_qeth_l2_vnicc_is_in_use(card) &&
!(priv->brport_features & BR_LEARNING_SYNC));
}
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
/* recover user characteristic setting */
static bool qeth_l2_vnicc_recover_char(struct qeth_card *card, u32 vnicc,
bool enable)
{
u32 cmd = enable ? IPA_VNICC_ENABLE : IPA_VNICC_DISABLE;
if (card->options.vnicc.sup_chars & vnicc &&
card->options.vnicc.set_char_sup & vnicc &&
!qeth_l2_vnicc_set_char(card, vnicc, cmd))
return false;
card->options.vnicc.wanted_chars &= ~vnicc;
card->options.vnicc.wanted_chars |= QETH_VNICC_DEFAULT & vnicc;
return true;
}
/* (re-)initialize VNICC */
static void qeth_l2_vnicc_init(struct qeth_card *card)
{
u32 *timeout = &card->options.vnicc.learning_timeout;
bool enable, error = false;
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
unsigned int chars_len, i;
unsigned long chars_tmp;
u32 sup_cmds, vnicc;
QETH_CARD_TEXT(card, 2, "vniccini");
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
/* reset rx_bcast */
card->options.vnicc.rx_bcast_enabled = 0;
/* initial query and storage of VNIC characteristics */
if (qeth_l2_vnicc_query_chars(card)) {
if (card->options.vnicc.wanted_chars != QETH_VNICC_DEFAULT ||
*timeout != QETH_VNICC_DEFAULT_TIMEOUT)
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
dev_err(&card->gdev->dev, "Configuring the VNIC characteristics failed\n");
/* fail quietly if user didn't change the default config */
card->options.vnicc.sup_chars = 0;
card->options.vnicc.cur_chars = 0;
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
card->options.vnicc.wanted_chars = QETH_VNICC_DEFAULT;
return;
}
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
/* get supported commands for each supported characteristic */
chars_tmp = card->options.vnicc.sup_chars;
chars_len = sizeof(card->options.vnicc.sup_chars) * BITS_PER_BYTE;
for_each_set_bit(i, &chars_tmp, chars_len) {
vnicc = BIT(i);
if (qeth_l2_vnicc_query_cmds(card, vnicc, &sup_cmds)) {
sup_cmds = 0;
error = true;
}
if ((sup_cmds & IPA_VNICC_SET_TIMEOUT) &&
(sup_cmds & IPA_VNICC_GET_TIMEOUT))
card->options.vnicc.getset_timeout_sup |= vnicc;
else
card->options.vnicc.getset_timeout_sup &= ~vnicc;
if ((sup_cmds & IPA_VNICC_ENABLE) &&
(sup_cmds & IPA_VNICC_DISABLE))
card->options.vnicc.set_char_sup |= vnicc;
else
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
card->options.vnicc.set_char_sup &= ~vnicc;
}
/* enforce assumed default values and recover settings, if changed */
error |= qeth_l2_vnicc_recover_timeout(card, QETH_VNICC_LEARNING,
timeout);
/* Change chars, if necessary */
chars_tmp = card->options.vnicc.wanted_chars ^
card->options.vnicc.cur_chars;
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
chars_len = sizeof(card->options.vnicc.wanted_chars) * BITS_PER_BYTE;
for_each_set_bit(i, &chars_tmp, chars_len) {
vnicc = BIT(i);
enable = card->options.vnicc.wanted_chars & vnicc;
error |= qeth_l2_vnicc_recover_char(card, vnicc, enable);
}
if (error)
dev_err(&card->gdev->dev, "Configuring the VNIC characteristics failed\n");
}
/* configure default values of VNIC characteristics */
static void qeth_l2_vnicc_set_defaults(struct qeth_card *card)
{
/* characteristics values */
card->options.vnicc.sup_chars = QETH_VNICC_ALL;
card->options.vnicc.cur_chars = QETH_VNICC_DEFAULT;
card->options.vnicc.learning_timeout = QETH_VNICC_DEFAULT_TIMEOUT;
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
/* supported commands */
card->options.vnicc.set_char_sup = QETH_VNICC_ALL;
card->options.vnicc.getset_timeout_sup = QETH_VNICC_LEARNING;
s390/qeth: add VNICC enable/disable support HiperSocket devices allow enabling and disabling so called VNIC Characteristics (VNICC) that influence how the underlying hardware handles packets. These VNICCs are: * Flooding VNICC: Flooding allows specifying if packets to unknown destination MAC addresses are received by the qeth device. * Multicast flooding VNICC: Multicast flooding allows specifying if packets to multicast MAC addresses are received by the qeth device. * Learning VNICC: If learning is enabled on a qeth device, the device learns the source MAC addresses of outgoing packets and incoming packets to those learned MAC addresses are received. * Takeover setvmac VNICC: If takeover setvmac is configured on a qeth device, the MAC address of this device can be configured on a different qeth device with the setvmac IPA command. * Takeover by learning VNICC: If takeover learning is enabled on a qeth device, the MAC address of this device can be learned (learning VNICC) on a different qeth device. * BridgePort invisible VNICC: If BridgePort invisible is enabled on a qeth device, (1) packets from this device are not sent to a BridgePort enabled qeth device and (2) packets coming from a BridgePort enabled qeth device are not received by this device. * Receive broadcast VNICC: Receive broadcast allows configuring if a qeth device receives packets with the broadcast destination MAC address. This patch adds support for the IPA commands that are required to enable and disable these VNIC characteristics on qeth devices. As a prerequisite, it also adds the query commands IPA command. The query commands IPA command allows requesting the supported commands for each characteristic from the underlying hardware. Additionally, this patch provides users with a sysfs user interface to enable/disable the VNICCs mentioned above. Signed-off-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Reviewed-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-19 03:18:15 +08:00
/* settings wanted by users */
card->options.vnicc.wanted_chars = QETH_VNICC_DEFAULT;
}
static const struct device_type qeth_l2_devtype = {
.name = "qeth_layer2",
.groups = qeth_l2_attr_groups,
};
static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
int rc;
if (IS_OSN(card))
dev_notice(&gdev->dev, "OSN support will be dropped in 2021\n");
qeth_l2_vnicc_set_defaults(card);
mutex_init(&card->sbp_lock);
if (gdev->dev.type == &qeth_generic_devtype) {
rc = device_add_groups(&gdev->dev, qeth_l2_attr_groups);
if (rc)
return rc;
}
INIT_WORK(&card->rx_mode_work, qeth_l2_rx_mode_work);
return 0;
}
static void qeth_l2_remove_device(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
if (gdev->dev.type == &qeth_generic_devtype)
device_remove_groups(&gdev->dev, qeth_l2_attr_groups);
qeth_set_allowed_threads(card, 0, 1);
wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
if (gdev->state == CCWGROUP_ONLINE)
qeth_set_offline(card, card->discipline, false);
cancel_work_sync(&card->close_dev_work);
if (card->dev->reg_state == NETREG_REGISTERED)
unregister_netdev(card->dev);
}
static int qeth_l2_set_online(struct qeth_card *card, bool carrier_ok)
{
struct net_device *dev = card->dev;
int rc = 0;
qeth_l2_detect_dev2br_support(card);
mutex_lock(&card->sbp_lock);
qeth_bridgeport_query_support(card);
if (card->options.sbp.supported_funcs) {
qeth_l2_setup_bridgeport_attrs(card);
dev_info(&card->gdev->dev,
"The device represents a Bridge Capable Port\n");
}
mutex_unlock(&card->sbp_lock);
qeth_l2_register_dev_addr(card);
/* for the rx_bcast characteristic, init VNICC after setmac */
qeth_l2_vnicc_init(card);
qeth_l2_trace_features(card);
/* softsetup */
QETH_CARD_TEXT(card, 2, "softsetp");
card->state = CARD_STATE_SOFTSETUP;
qeth_set_allowed_threads(card, 0xffffffff, 0);
if (dev->reg_state != NETREG_REGISTERED) {
rc = qeth_l2_setup_netdev(card);
if (rc)
goto err_setup;
if (carrier_ok)
netif_carrier_on(dev);
} else {
rtnl_lock();
rc = qeth_set_real_num_tx_queues(card,
qeth_tx_actual_queues(card));
if (rc) {
rtnl_unlock();
goto err_set_queues;
}
if (carrier_ok)
netif_carrier_on(dev);
else
netif_carrier_off(dev);
netif_device_attach(dev);
qeth_enable_hw_features(dev);
qeth_l2_enable_brport_features(card);
if (card->info.open_when_online) {
card->info.open_when_online = 0;
dev_open(dev, NULL);
}
rtnl_unlock();
}
return 0;
err_set_queues:
err_setup:
qeth_set_allowed_threads(card, 0, 1);
card->state = CARD_STATE_DOWN;
return rc;
}
static void qeth_l2_set_offline(struct qeth_card *card)
{
struct qeth_priv *priv = netdev_priv(card->dev);
qeth_set_allowed_threads(card, 0, 1);
qeth_l2_drain_rx_mode_cache(card);
if (card->state == CARD_STATE_SOFTSETUP)
card->state = CARD_STATE_DOWN;
qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
if (priv->brport_features & BR_LEARNING_SYNC)
qeth_l2_dev2br_fdb_flush(card);
}
/* Returns zero if the command is successfully "consumed" */
static int qeth_l2_control_event(struct qeth_card *card,
struct qeth_ipa_cmd *cmd)
{
switch (cmd->hdr.command) {
case IPA_CMD_SETBRIDGEPORT_OSA:
case IPA_CMD_SETBRIDGEPORT_IQD:
if (cmd->data.sbp.hdr.command_code ==
IPA_SBP_BRIDGE_PORT_STATE_CHANGE) {
qeth_bridge_state_change(card, cmd);
return 0;
}
return 1;
case IPA_CMD_ADDRESS_CHANGE_NOTIF:
qeth_addr_change_event(card, cmd);
return 0;
default:
return 1;
}
}
const struct qeth_discipline qeth_l2_discipline = {
.devtype = &qeth_l2_devtype,
.setup = qeth_l2_probe_device,
.remove = qeth_l2_remove_device,
.set_online = qeth_l2_set_online,
.set_offline = qeth_l2_set_offline,
.do_ioctl = NULL,
.control_event_handler = qeth_l2_control_event,
};
EXPORT_SYMBOL_GPL(qeth_l2_discipline);
static int __init qeth_l2_init(void)
{
pr_info("register layer 2 discipline\n");
return 0;
}
static void __exit qeth_l2_exit(void)
{
pr_info("unregister layer 2 discipline\n");
}
module_init(qeth_l2_init);
module_exit(qeth_l2_exit);
MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>");
MODULE_DESCRIPTION("qeth layer 2 discipline");
MODULE_LICENSE("GPL");