From 4845b93ff2c9247f5fed88182ea71dba370e76bb Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:42 +0200 Subject: s390/qeth: remove support for IPA_IP_FRAGMENTATION This Assist was never actually implemented in any hardware, so just remove the leftovers. Signed-off-by: Julian Wiedmann Reviewed-by: Hans Wippel Reviewed-by: Thomas Richter Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 3 +-- drivers/s390/net/qeth_core_mpc.h | 2 +- drivers/s390/net/qeth_l3_main.c | 26 -------------------------- 3 files changed, 2 insertions(+), 29 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index fc6d85f2b38d..dba7d00715e3 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4199,8 +4199,7 @@ int qeth_change_mtu(struct net_device *dev, int new_mtu) sprintf(dbf_text, "%8x", new_mtu); QETH_CARD_TEXT(card, 4, dbf_text); - if ((!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) && - (!qeth_mtu_is_valid(card, new_mtu))) + if (!qeth_mtu_is_valid(card, new_mtu)) return -EINVAL; dev->mtu = new_mtu; return 0; diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 4accb0a61ce0..45bbea2843bf 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -192,7 +192,7 @@ enum qeth_ipa_funcs { IPA_ARP_PROCESSING = 0x00000001L, IPA_INBOUND_CHECKSUM = 0x00000002L, IPA_OUTBOUND_CHECKSUM = 0x00000004L, - IPA_IP_FRAGMENTATION = 0x00000008L, + /* RESERVED = 0x00000008L,*/ IPA_FILTERING = 0x00000010L, IPA_IPV6 = 0x00000020L, IPA_MULTICASTING = 0x00000040L, diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index d8df1e635163..ac8310fe2fb0 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -956,31 +956,6 @@ static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card) return rc; } -static int qeth_l3_start_ipa_ip_fragmentation(struct qeth_card *card) -{ - int rc; - - QETH_CARD_TEXT(card, 3, "ipaipfrg"); - - if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) { - dev_info(&card->gdev->dev, - "Hardware IP fragmentation not supported on %s\n", - QETH_CARD_IFNAME(card)); - return -EOPNOTSUPP; - } - - rc = qeth_send_simple_setassparms(card, IPA_IP_FRAGMENTATION, - IPA_CMD_ASS_START, 0); - if (rc) { - dev_warn(&card->gdev->dev, - "Starting IP fragmentation support for %s failed\n", - QETH_CARD_IFNAME(card)); - } else - dev_info(&card->gdev->dev, - "Hardware IP fragmentation enabled \n"); - return rc; -} - static int qeth_l3_start_ipa_source_mac(struct qeth_card *card) { int rc; @@ -1171,7 +1146,6 @@ static int qeth_l3_start_ipassists(struct qeth_card *card) if (qeth_set_access_ctrl_online(card, 0)) return -EIO; qeth_l3_start_ipa_arp_processing(card); /* go on*/ - qeth_l3_start_ipa_ip_fragmentation(card); /* go on*/ qeth_l3_start_ipa_source_mac(card); /* go on*/ qeth_l3_start_ipa_vlan(card); /* go on*/ qeth_l3_start_ipa_multicast(card); /* go on*/ -- cgit v1.2.3 From 94a9c981f7bdfdb6d092d1f92546bf61552c95d7 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:43 +0200 Subject: s390/qeth: remove skb_is_nonlinear() check on IQD qeth doesn't advertise NETIF_F_SG for L3 IQDs. So trust the stack to not hand us any nonlinear skbs, and remove an always-true condition. With the fact that data_offset < 0 is no longer possible on IQDs, apply a small cleanup to subsequent code. Signed-off-by: Julian Wiedmann Acked-by: Ursula Braun Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index ac8310fe2fb0..56e813972d77 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2676,8 +2676,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, use_tso = skb_is_gso(skb) && (qeth_get_ip_protocol(skb) == IPPROTO_TCP) && (ipv == 4); - if ((card->info.type == QETH_CARD_TYPE_IQD) && - !skb_is_nonlinear(skb)) { + if (card->info.type == QETH_CARD_TYPE_IQD) { new_skb = skb; data_offset = ETH_HLEN; hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); @@ -2690,12 +2689,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, + VLAN_HLEN); if (!new_skb) goto tx_drop; - } - if (card->info.type == QETH_CARD_TYPE_IQD) { - if (data_offset < 0) - skb_pull(new_skb, ETH_HLEN); - } else { if (ipv == 4) { skb_pull(new_skb, ETH_HLEN); } -- cgit v1.2.3 From 23274596b565f8fba3d07e6cbed1de07947e365d Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:44 +0200 Subject: s390/qeth: query IPv6 IPA support on HiperSockets HiperSocket devices don't need the full IPv6 initialization, but we should still query the supported assists for logging purposes. Signed-off-by: Julian Wiedmann Acked-by: Ursula Braun Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 56e813972d77..fb4eee2a46ee 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1035,9 +1035,6 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card) QETH_CARD_TEXT(card, 3, "softipv6"); - if (card->info.type == QETH_CARD_TYPE_IQD) - goto out; - rc = qeth_query_ipassists(card, QETH_PROT_IPV6); if (rc) { dev_err(&card->gdev->dev, @@ -1045,6 +1042,10 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card) QETH_CARD_IFNAME(card)); return rc; } + + if (card->info.type == QETH_CARD_TYPE_IQD) + goto out; + rc = qeth_send_simple_setassparms(card, IPA_IPV6, IPA_CMD_ASS_START, 3); if (rc) { -- cgit v1.2.3 From 521c10ea2315366192a0641d5a063320685c0db1 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:45 +0200 Subject: s390/qeth: log bridgeport capabilities Bridgeport is a l2-specific feature, and we should write its capabilities to a debug entry. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l2_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index bd2df62a5cdf..70b633f951ea 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -1017,6 +1017,13 @@ static int qeth_l2_start_ipassists(struct qeth_card *card) return 0; } +static void qeth_l2_trace_features(struct qeth_card *card) +{ + QETH_CARD_TEXT(card, 2, "l2featur"); + QETH_CARD_HEX(card, 2, &card->options.sbp.supported_funcs, + sizeof(card->options.sbp.supported_funcs)); +} + static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); @@ -1040,6 +1047,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) dev_info(&card->gdev->dev, "The device represents a Bridge Capable Port\n"); qeth_trace_features(card); + qeth_l2_trace_features(card); if (!card->dev && qeth_l2_setup_netdev(card)) { rc = -ENODEV; -- cgit v1.2.3 From 84616e86f830490c4bbf93ddc1e374cd61865060 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:46 +0200 Subject: s390/qeth: add missing strings for IPA return codes commit 76b11f8e270f ("qeth: HiperSockets Network Traffic Analyzer") missed adding the human-readable translations when adding new RCs. Signed-off-by: Julian Wiedmann Acked-by: Ursula Braun Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_mpc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c index beb4bdc26de5..ab9b1376467f 100644 --- a/drivers/s390/net/qeth_core_mpc.c +++ b/drivers/s390/net/qeth_core_mpc.c @@ -167,6 +167,8 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = { {IPA_RC_IP_TABLE_FULL, "Add Addr IP Table Full - ipv6"}, {IPA_RC_UNKNOWN_ERROR, "IPA command failed - reason unknown"}, {IPA_RC_UNSUPPORTED_COMMAND, "Command not supported"}, + {IPA_RC_TRACE_ALREADY_ACTIVE, "trace already active"}, + {IPA_RC_INVALID_FORMAT, "invalid format or length"}, {IPA_RC_DUP_IPV6_REMOTE, "ipv6 address already registered remote"}, {IPA_RC_DUP_IPV6_HOME, "ipv6 address already registered"}, {IPA_RC_UNREGISTERED_ADDR, "Address not registered"}, -- cgit v1.2.3 From 664e42ac8b1bc39540ac9d657efa45c3e213e6c2 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:47 +0200 Subject: s390/qeth: consolidate pack buffer flushing qeth_switch_to_nonpacking_if_needed() contains an open-coded version of qeth_flush_buffers_on_no_pci(). Extract a single helper instead. Signed-off-by: Julian Wiedmann Acked-by: Ursula Braun Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 65 +++++++++++++++------------------------ 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index dba7d00715e3..a159eb900d03 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3347,6 +3347,28 @@ static void qeth_handle_send_error(struct qeth_card *card, (u16)qdio_err, (u8)sbalf15); } +/** + * qeth_prep_flush_pack_buffer - Prepares flushing of a packing buffer. + * @queue: queue to check for packing buffer + * + * Returns number of buffers that were prepared for flush. + */ +static int qeth_prep_flush_pack_buffer(struct qeth_qdio_out_q *queue) +{ + struct qeth_qdio_out_buffer *buffer; + + buffer = queue->bufs[queue->next_buf_to_fill]; + if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) && + (buffer->next_element_to_fill > 0)) { + /* it's a packing buffer */ + atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); + queue->next_buf_to_fill = + (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; + return 1; + } + return 0; +} + /* * Switched to packing state if the number of used buffers on a queue * reaches a certain limit. @@ -3373,9 +3395,6 @@ static void qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue) */ static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue) { - struct qeth_qdio_out_buffer *buffer; - int flush_count = 0; - if (queue->do_pack) { if (atomic_read(&queue->used_buffers) <= QETH_LOW_WATERMARK_PACK) { @@ -3384,42 +3403,9 @@ static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue) if (queue->card->options.performance_stats) queue->card->perf_stats.sc_p_dp++; queue->do_pack = 0; - /* flush packing buffers */ - buffer = queue->bufs[queue->next_buf_to_fill]; - if ((atomic_read(&buffer->state) == - QETH_QDIO_BUF_EMPTY) && - (buffer->next_element_to_fill > 0)) { - atomic_set(&buffer->state, - QETH_QDIO_BUF_PRIMED); - flush_count++; - queue->next_buf_to_fill = - (queue->next_buf_to_fill + 1) % - QDIO_MAX_BUFFERS_PER_Q; - } + return qeth_prep_flush_pack_buffer(queue); } } - return flush_count; -} - - -/* - * Called to flush a packing buffer if no more pci flags are on the queue. - * Checks if there is a packing buffer and prepares it to be flushed. - * In that case returns 1, otherwise zero. - */ -static int qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue) -{ - struct qeth_qdio_out_buffer *buffer; - - buffer = queue->bufs[queue->next_buf_to_fill]; - if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) && - (buffer->next_element_to_fill > 0)) { - /* it's a packing buffer */ - atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); - queue->next_buf_to_fill = - (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; - return 1; - } return 0; } @@ -3532,8 +3518,7 @@ static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) flush_cnt += qeth_switch_to_nonpacking_if_needed(queue); if (!flush_cnt && !atomic_read(&queue->set_pci_flags_count)) - flush_cnt += - qeth_flush_buffers_on_no_pci(queue); + flush_cnt += qeth_prep_flush_pack_buffer(queue); if (queue->card->options.performance_stats && q_was_packing) queue->card->perf_stats.bufs_sent_pack += @@ -4127,7 +4112,7 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, * flag out on the queue */ if (!flush_count && !atomic_read(&queue->set_pci_flags_count)) - flush_count += qeth_flush_buffers_on_no_pci(queue); + flush_count += qeth_prep_flush_pack_buffer(queue); if (flush_count) qeth_flush_buffers(queue, start_index, flush_count); } -- cgit v1.2.3 From cf536ffea99472e043929749508d6656163138a1 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:48 +0200 Subject: s390/qeth: silence qeth_fix_features() Noting the lack of TSO support on every feature change is just silly, in particular since the requested features might not even affect NETIF_F_TSO. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index a159eb900d03..3cc802cff9d1 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -6390,11 +6390,8 @@ netdev_features_t qeth_fix_features(struct net_device *dev, features &= ~NETIF_F_IP_CSUM; if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) features &= ~NETIF_F_RXCSUM; - if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) { + if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) features &= ~NETIF_F_TSO; - dev_info(&card->gdev->dev, "Outbound TSO not supported on %s\n", - QETH_CARD_IFNAME(card)); - } /* if the card isn't up, remove features that require hw changes */ if (card->state == CARD_STATE_DOWN || card->state == CARD_STATE_RECOVER) -- cgit v1.2.3 From 79a04e40f7f0e968b485a0d0cb12dcffc7f509c6 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Tue, 6 Jun 2017 14:33:49 +0200 Subject: s390/qeth: add support for early L3 device setup Similar to how qeth currently does early L2 setup of OSM and OSN devices, add support for early setup of L3-only devices. This adds a qeth_l3_devtype that contains all core and l3-specific sysfs attributes, so that they can be created in one go while probing. This just adds the infrastructure, exploitation of the support happens in a subsequent patch. Signed-off-by: Ursula Braun Reviewed-by: Julian Wiedmann Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3.h | 1 + drivers/s390/net/qeth_l3_main.c | 18 +++++++++++++----- drivers/s390/net/qeth_l3_sys.c | 11 +++++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index 26f79533e62e..9b5e439f18cf 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h @@ -65,6 +65,7 @@ struct qeth_ipato_entry { int mask_bits; }; +extern const struct attribute_group *qeth_l3_attr_groups[]; void qeth_l3_ipaddr_to_string(enum qeth_prot_versions, const __u8 *, char *); int qeth_l3_string_to_ipaddr(const char *, enum qeth_prot_versions, __u8 *); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index fb4eee2a46ee..37b594231b76 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3005,14 +3005,21 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) return register_netdev(card->dev); } +static const struct device_type qeth_l3_devtype = { + .name = "qeth_layer3", + .groups = qeth_l3_attr_groups, +}; + static int qeth_l3_probe_device(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); int rc; - rc = qeth_l3_create_device_attributes(&gdev->dev); - if (rc) - return rc; + if (gdev->dev.type == &qeth_generic_devtype) { + rc = qeth_l3_create_device_attributes(&gdev->dev); + if (rc) + return rc; + } hash_init(card->ip_htable); hash_init(card->ip_mc_htable); card->options.layer2 = 0; @@ -3024,7 +3031,8 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) { struct qeth_card *card = dev_get_drvdata(&cgdev->dev); - qeth_l3_remove_device_attributes(&cgdev->dev); + if (cgdev->dev.type == &qeth_generic_devtype) + qeth_l3_remove_device_attributes(&cgdev->dev); qeth_set_allowed_threads(card, 0, 1); wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); @@ -3280,7 +3288,7 @@ static int qeth_l3_control_event(struct qeth_card *card, } struct qeth_discipline qeth_l3_discipline = { - .devtype = &qeth_generic_devtype, + .devtype = &qeth_l3_devtype, .start_poll = qeth_qdio_start_poll, .input_handler = (qdio_handler_t *) qeth_qdio_input_handler, .output_handler = (qdio_handler_t *) qeth_qdio_output_handler, diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index ff29a4b416b4..f2f94f59e0fa 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -1049,3 +1049,14 @@ void qeth_l3_remove_device_attributes(struct device *dev) sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group); sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group); } + +const struct attribute_group *qeth_l3_attr_groups[] = { + &qeth_device_attr_group, + &qeth_device_blkt_group, + /* l3 specific, see l3_{create,remove}_device_attributes(): */ + &qeth_l3_device_attr_group, + &qeth_device_ipato_group, + &qeth_device_vipa_group, + &qeth_device_rxip_group, +NULL, +}; -- cgit v1.2.3 From c70eb09dc210b8d6fdd4a93d5bc25d85133fb9d2 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:50 +0200 Subject: s390/qeth: do early device setup for z/VM IQD NICs qeth currently supports early setup for OSM and OSN devices. This patch adds early setup support for z/VM HiperSockets, since they can only be coupled to L3 networks. Based on an initial version by Dmitriy Lakhvich. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 2 ++ drivers/s390/net/qeth_core_main.c | 44 ++++++++++++++++++++++++++++++--------- drivers/s390/net/qeth_core_sys.c | 2 +- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 30bc6105aac3..0efc54a4d82f 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -659,6 +659,7 @@ struct qeth_card_info { int max_mtu; int broadcast_capable; int unique_id; + bool layer_enforced; struct qeth_card_blkt blkt; enum qeth_ipa_promisc_modes promisc_mode; __u32 diagass_support; @@ -696,6 +697,7 @@ struct qeth_osn_info { }; enum qeth_discipline_id { + QETH_DISCIPLINE_UNDETERMINED = -1, QETH_DISCIPLINE_LAYER3 = 0, QETH_DISCIPLINE_LAYER2 = 1, }; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 3cc802cff9d1..1fb92e870040 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1723,6 +1723,25 @@ static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd) (prcd[0x11] == _ascebc['M'])); } +/* Determine whether the device requires a specific layer discipline */ +static enum qeth_discipline_id qeth_enforce_discipline(struct qeth_card *card) +{ + if (card->info.type == QETH_CARD_TYPE_OSM || + card->info.type == QETH_CARD_TYPE_OSN) { + QETH_DBF_TEXT(SETUP, 3, "force l2"); + return QETH_DISCIPLINE_LAYER2; + } + + /* virtual HiperSocket is L3 only: */ + if (card->info.guestlan && card->info.type == QETH_CARD_TYPE_IQD) { + QETH_DBF_TEXT(SETUP, 3, "force l3"); + return QETH_DISCIPLINE_LAYER3; + } + + QETH_DBF_TEXT(SETUP, 3, "force no"); + return QETH_DISCIPLINE_UNDETERMINED; +} + static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd) { QETH_DBF_TEXT(SETUP, 2, "cfgblkt"); @@ -5485,6 +5504,7 @@ int qeth_core_load_discipline(struct qeth_card *card, enum qeth_discipline_id discipline) { int rc = 0; + mutex_lock(&qeth_mod_mutex); switch (discipline) { case QETH_DISCIPLINE_LAYER3: @@ -5495,7 +5515,10 @@ int qeth_core_load_discipline(struct qeth_card *card, card->discipline = try_then_request_module( symbol_get(qeth_l2_discipline), "qeth_l2"); break; + default: + break; } + if (!card->discipline) { dev_err(&card->gdev->dev, "There is no kernel module to " "support discipline %d\n", discipline); @@ -5598,6 +5621,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) struct qeth_card *card; struct device *dev; int rc; + enum qeth_discipline_id enforced_disc; unsigned long flags; char dbf_name[DBF_NAME_LEN]; @@ -5645,10 +5669,15 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) goto err_card; } - switch (card->info.type) { - case QETH_CARD_TYPE_OSN: - case QETH_CARD_TYPE_OSM: - rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2); + qeth_determine_capabilities(card); + enforced_disc = qeth_enforce_discipline(card); + switch (enforced_disc) { + case QETH_DISCIPLINE_UNDETERMINED: + gdev->dev.type = &qeth_generic_devtype; + break; + default: + card->info.layer_enforced = true; + rc = qeth_core_load_discipline(card, enforced_disc); if (rc) goto err_card; @@ -5659,16 +5688,11 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) if (rc) goto err_disc; break; - default: - gdev->dev.type = &qeth_generic_devtype; - break; } write_lock_irqsave(&qeth_core_card_list.rwlock, flags); list_add_tail(&card->list, &qeth_core_card_list.list); write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); - - qeth_determine_capabilities(card); return 0; err_disc: @@ -5705,7 +5729,7 @@ static int qeth_core_set_online(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); int rc = 0; - int def_discipline; + enum qeth_discipline_id def_discipline; if (!card->discipline) { if (card->info.type == QETH_CARD_TYPE_IQD) diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index db6a285d41e0..6d255c22656d 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -413,7 +413,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, if (card->options.layer2 == newdis) goto out; - if (card->info.type == QETH_CARD_TYPE_OSM) { + if (card->info.layer_enforced) { /* fixed layer, can't switch */ rc = -EOPNOTSUPP; goto out; -- cgit v1.2.3