From b144b99fff69a5bc0d34c8e168bedb88c68ca23d Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 8 Nov 2018 15:06:15 +0100 Subject: [PATCH 1/8] s390/qeth: utilize virtual MAC for Layer2 OSD devices By default, READ MAC on a Layer2 OSD device returns the adapter's burnt-in MAC address. Given the default scenario of many virtual devices on the same adapter, qeth can't make any use of this address and therefore skips the READ MAC call for this device type. But in some configurations, the READ MAC command for a Layer2 OSD device actually returns a pre-provisioned, virtual MAC address. So enable the READ MAC code to detect this situation, and let the L2 subdriver call READ MAC for OSD devices. This also removes the QETH_LAYER2_MAC_READ flag, which protects L2 devices against calling READ MAC multiple times. Instead protect the whole call to qeth_l2_request_initial_mac(). Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 1 - drivers/s390/net/qeth_core_main.c | 12 +++++++----- drivers/s390/net/qeth_core_mpc.h | 25 +++++++++++++++---------- drivers/s390/net/qeth_l2_main.c | 10 ++++------ 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 04e294d1d16d..99af1a0a3314 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -665,7 +665,6 @@ struct qeth_card_blkt { #define QETH_BROADCAST_WITH_ECHO 0x01 #define QETH_BROADCAST_WITHOUT_ECHO 0x02 -#define QETH_LAYER2_MAC_READ 0x01 #define QETH_LAYER2_MAC_REGISTERED 0x02 struct qeth_card_info { unsigned short unit_addr2; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 4bce5ae65a55..abeecffb6d2e 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4235,16 +4235,18 @@ static int qeth_setadpparms_change_macaddr_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_setadpparms *adp_cmd; QETH_CARD_TEXT(card, 4, "chgmaccb"); if (qeth_setadpparms_inspect_rc(cmd)) return 0; - if (IS_LAYER3(card) || !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) { - ether_addr_copy(card->dev->dev_addr, - cmd->data.setadapterparms.data.change_addr.addr); - card->info.mac_bits |= QETH_LAYER2_MAC_READ; - } + adp_cmd = &cmd->data.setadapterparms; + if (IS_LAYER2(card) && IS_OSD(card) && !IS_VM_NIC(card) && + !(adp_cmd->hdr.flags & QETH_SETADP_FLAGS_VIRTUAL_MAC)) + return 0; + + ether_addr_copy(card->dev->dev_addr, adp_cmd->data.change_addr.addr); return 0; } diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 3e54be201b27..10cc487c16d6 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -80,7 +80,9 @@ enum qeth_card_types { }; #define IS_IQD(card) ((card)->info.type == QETH_CARD_TYPE_IQD) +#define IS_OSD(card) ((card)->info.type == QETH_CARD_TYPE_OSD) #define IS_OSN(card) ((card)->info.type == QETH_CARD_TYPE_OSN) +#define IS_VM_NIC(card) ((card)->info.guestlan) #define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18 /* only the first two bytes are looked at in qeth_get_cardname_short */ @@ -529,17 +531,20 @@ struct qeth_query_switch_attributes { __u8 reserved3[8]; }; +#define QETH_SETADP_FLAGS_VIRTUAL_MAC 0x80 /* for CHANGE_ADDR_READ_MAC */ + struct qeth_ipacmd_setadpparms_hdr { - __u32 supp_hw_cmds; - __u32 reserved1; - __u16 cmdlength; - __u16 reserved2; - __u32 command_code; - __u16 return_code; - __u8 used_total; - __u8 seq_no; - __u32 reserved3; -} __attribute__ ((packed)); + u32 supp_hw_cmds; + u32 reserved1; + u16 cmdlength; + u16 reserved2; + u32 command_code; + u16 return_code; + u8 used_total; + u8 seq_no; + u8 flags; + u8 reserved3[3]; +}; struct qeth_ipacmd_setadpparms { struct qeth_ipacmd_setadpparms_hdr hdr; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 2914a1a69f83..8d3601891c62 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -461,12 +461,9 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card) /* fall back to alternative mechanism: */ } - if (card->info.type == QETH_CARD_TYPE_IQD || - card->info.type == QETH_CARD_TYPE_OSM || - card->info.type == QETH_CARD_TYPE_OSX || - card->info.guestlan) { + if (!IS_OSN(card)) { rc = qeth_setadpparms_change_macaddr(card); - if (!rc) + if (!rc && is_valid_ether_addr(card->dev->dev_addr)) goto out; QETH_DBF_MESSAGE(2, "READ_MAC Assist failed on device %x: %#x\n", CARD_DEVID(card), rc); @@ -917,7 +914,8 @@ static int qeth_l2_setup_netdev(struct qeth_card *card, bool carrier_ok) PAGE_SIZE * (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)); } - qeth_l2_request_initial_mac(card); + if (!is_valid_ether_addr(card->dev->dev_addr)) + qeth_l2_request_initial_mac(card); netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT); rc = register_netdev(card->dev); if (!rc && carrier_ok) From 5a541f6d00c6d8aace789dfaa468443bd0edf564 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 8 Nov 2018 15:06:16 +0100 Subject: [PATCH 2/8] s390/qeth: handle af_iucv skbs in qeth_l3_fill_header() Filling the HW header from one single function will make it easier to rip out all the duplicated transmit code in qeth_l3_xmit(). On top, this saves one conditional branch in the TSO path. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 2 +- drivers/s390/net/qeth_l3_main.c | 45 ++++++++++++--------------------- 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 99af1a0a3314..d50d91219cf3 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -314,7 +314,7 @@ struct qeth_hdr_layer3 { __u16 frame_offset; union { /* TX: */ - u8 ipv6_addr[16]; + struct in6_addr ipv6_addr; struct ipv4 { u8 res[12]; u32 addr; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index f08b745c2007..004085344e85 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1929,22 +1929,6 @@ static int qeth_l3_get_cast_type(struct sk_buff *skb) } } -static void qeth_l3_fill_af_iucv_hdr(struct qeth_hdr *hdr, struct sk_buff *skb, - unsigned int data_len) -{ - char daddr[16]; - - hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; - hdr->hdr.l3.length = data_len; - hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST; - - memset(daddr, 0, sizeof(daddr)); - daddr[0] = 0xfe; - daddr[1] = 0x80; - memcpy(&daddr[8], iucv_trans_hdr(skb)->destUserID, 8); - memcpy(hdr->hdr.l3.next_hop.ipv6_addr, daddr, 16); -} - static u8 qeth_l3_cast_type_to_flag(int cast_type) { if (cast_type == RTN_MULTICAST) @@ -1960,6 +1944,7 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb, int ipv, int cast_type, unsigned int data_len) { + struct qeth_hdr_layer3 *l3_hdr = &hdr->hdr.l3; struct vlan_ethhdr *veth = vlan_eth_hdr(skb); hdr->hdr.l3.length = data_len; @@ -1968,6 +1953,15 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, hdr->hdr.l3.id = QETH_HEADER_TYPE_L3_TSO; } else { hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; + + if (skb->protocol == htons(ETH_P_AF_IUCV)) { + l3_hdr->flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST; + l3_hdr->next_hop.ipv6_addr.s6_addr16[0] = htons(0xfe80); + memcpy(&l3_hdr->next_hop.ipv6_addr.s6_addr32[2], + iucv_trans_hdr(skb)->destUserID, 8); + return; + } + if (skb->ip_summed == CHECKSUM_PARTIAL) { qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, ipv); /* some HW requires combined L3+L4 csum offload: */ @@ -2012,13 +2006,11 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, } else { /* IPv6 */ const struct rt6_info *rt = skb_rt6_info(skb); - const struct in6_addr *next_hop; if (rt && !ipv6_addr_any(&rt->rt6i_gateway)) - next_hop = &rt->rt6i_gateway; + l3_hdr->next_hop.ipv6_addr = rt->rt6i_gateway; else - next_hop = &ipv6_hdr(skb)->daddr; - memcpy(hdr->hdr.l3.next_hop.ipv6_addr, next_hop, 16); + l3_hdr->next_hop.ipv6_addr = ipv6_hdr(skb)->daddr; hdr->hdr.l3.flags |= QETH_HDR_IPV6; if (card->info.type != QETH_CARD_TYPE_IQD) @@ -2082,15 +2074,10 @@ static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, } memset(hdr, 0, hw_hdr_len); - if (skb->protocol == htons(ETH_P_AF_IUCV)) { - qeth_l3_fill_af_iucv_hdr(hdr, skb, frame_len); - } else { - qeth_l3_fill_header(card, hdr, skb, ipv, cast_type, frame_len); - if (is_tso) - qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr, - frame_len - proto_len, skb, - proto_len); - } + qeth_l3_fill_header(card, hdr, skb, ipv, cast_type, frame_len); + if (is_tso) + qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr, + frame_len - proto_len, skb, proto_len); is_sg = skb_is_nonlinear(skb); if (IS_IQD(card)) { From 81ec54393944fc0303127e1357dbbd615a6abb63 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 8 Nov 2018 15:06:17 +0100 Subject: [PATCH 3/8] s390/qeth: unify transmit code Since commit 82bf5c0867f6 ("s390/qeth: add support for IPv6 TSO"), qeth_xmit() also knows how to build TSO packets and is practically identical to qeth_l3_xmit(). Convert qeth_l3_xmit() into a thin wrapper that merely strips the L2 header off a packet, and calls qeth_xmit() for the actual TX processing. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 8 ---- drivers/s390/net/qeth_core_main.c | 22 +++++----- drivers/s390/net/qeth_l3_main.c | 72 ++++--------------------------- 3 files changed, 19 insertions(+), 83 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index d50d91219cf3..afe3662a4ad5 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -1024,9 +1024,6 @@ int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *, int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long), void *reply_param); unsigned int qeth_count_elements(struct sk_buff *skb, unsigned int data_offset); -int qeth_do_send_packet_fast(struct qeth_qdio_out_q *queue, struct sk_buff *skb, - struct qeth_hdr *hdr, unsigned int offset, - unsigned int hd_len); int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_hdr *hdr, unsigned int offset, unsigned int hd_len, @@ -1057,11 +1054,6 @@ netdev_features_t qeth_features_check(struct sk_buff *skb, struct net_device *dev, netdev_features_t features); int qeth_vm_request_mac(struct qeth_card *card); -int qeth_add_hw_header(struct qeth_card *card, struct sk_buff *skb, - struct qeth_hdr **hdr, unsigned int hdr_len, - unsigned int proto_len, unsigned int *elements); -void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr, unsigned int payload_len, - struct sk_buff *skb, unsigned int proto_len); int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, struct qeth_qdio_out_q *queue, int ipv, int cast_type, void (*fill_header)(struct qeth_card *card, struct qeth_hdr *hdr, diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index abeecffb6d2e..2568ddc1bbc3 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3777,9 +3777,9 @@ EXPORT_SYMBOL_GPL(qeth_count_elements); * The number of needed buffer elements is returned in @elements. * Error to create the hdr is indicated by returning with < 0. */ -int qeth_add_hw_header(struct qeth_card *card, struct sk_buff *skb, - struct qeth_hdr **hdr, unsigned int hdr_len, - unsigned int proto_len, unsigned int *elements) +static int qeth_add_hw_header(struct qeth_card *card, struct sk_buff *skb, + struct qeth_hdr **hdr, unsigned int hdr_len, + unsigned int proto_len, unsigned int *elements) { const unsigned int max_elements = QETH_MAX_BUFFER_ELEMENTS(card); const unsigned int contiguous = proto_len ? proto_len : 1; @@ -3849,7 +3849,6 @@ int qeth_add_hw_header(struct qeth_card *card, struct sk_buff *skb, skb_copy_from_linear_data(skb, ((char *)*hdr) + hdr_len, proto_len); return 0; } -EXPORT_SYMBOL_GPL(qeth_add_hw_header); static void __qeth_fill_buffer(struct sk_buff *skb, struct qeth_qdio_out_buffer *buf, @@ -3972,9 +3971,9 @@ static int qeth_fill_buffer(struct qeth_qdio_out_q *queue, return flush_cnt; } -int qeth_do_send_packet_fast(struct qeth_qdio_out_q *queue, struct sk_buff *skb, - struct qeth_hdr *hdr, unsigned int offset, - unsigned int hd_len) +static int qeth_do_send_packet_fast(struct qeth_qdio_out_q *queue, + struct sk_buff *skb, struct qeth_hdr *hdr, + unsigned int offset, unsigned int hd_len) { int index = queue->next_buf_to_fill; struct qeth_qdio_out_buffer *buffer = queue->bufs[index]; @@ -3990,7 +3989,6 @@ int qeth_do_send_packet_fast(struct qeth_qdio_out_q *queue, struct sk_buff *skb, qeth_flush_buffers(queue, index, 1); return 0; } -EXPORT_SYMBOL_GPL(qeth_do_send_packet_fast); int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_hdr *hdr, @@ -4082,8 +4080,9 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, } EXPORT_SYMBOL_GPL(qeth_do_send_packet); -void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr, unsigned int payload_len, - struct sk_buff *skb, unsigned int proto_len) +static void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr, + unsigned int payload_len, struct sk_buff *skb, + unsigned int proto_len) { struct qeth_hdr_ext_tso *ext = &hdr->ext; @@ -4096,7 +4095,6 @@ void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr, unsigned int payload_len, ext->mss = skb_shinfo(skb)->gso_size; ext->dg_hdr_len = proto_len; } -EXPORT_SYMBOL_GPL(qeth_fill_tso_ext); int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, struct qeth_qdio_out_q *queue, int ipv, int cast_type, @@ -4119,7 +4117,7 @@ int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, proto_len = skb_transport_offset(skb) + tcp_hdrlen(skb); } else { hw_hdr_len = sizeof(struct qeth_hdr); - proto_len = IS_IQD(card) ? ETH_HLEN : 0; + proto_len = (IS_IQD(card) && IS_LAYER2(card)) ? ETH_HLEN : 0; } rc = skb_cow_head(skb, hw_hdr_len); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 004085344e85..61d847d41cab 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2036,79 +2036,25 @@ static void qeth_l3_fixup_headers(struct sk_buff *skb) static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, struct qeth_qdio_out_q *queue, int ipv, int cast_type) { - unsigned int hw_hdr_len, proto_len, frame_len, elements; unsigned char eth_hdr[ETH_HLEN]; - bool is_tso = skb_is_gso(skb); - unsigned int data_offset = 0; - struct qeth_hdr *hdr = NULL; - unsigned int hd_len = 0; - int push_len, rc; - bool is_sg; - - if (is_tso) { - hw_hdr_len = sizeof(struct qeth_hdr_tso); - proto_len = skb_transport_offset(skb) + tcp_hdrlen(skb) - - ETH_HLEN; - } else { - hw_hdr_len = sizeof(struct qeth_hdr); - proto_len = 0; - } + unsigned int hw_hdr_len; + int rc; /* re-use the L2 header area for the HW header: */ + hw_hdr_len = skb_is_gso(skb) ? sizeof(struct qeth_hdr_tso) : + sizeof(struct qeth_hdr); rc = skb_cow_head(skb, hw_hdr_len - ETH_HLEN); if (rc) return rc; skb_copy_from_linear_data(skb, eth_hdr, ETH_HLEN); skb_pull(skb, ETH_HLEN); - frame_len = skb->len; qeth_l3_fixup_headers(skb); - push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, proto_len, - &elements); - if (push_len < 0) - return push_len; - if (is_tso || !push_len) { - /* HW header needs its own buffer element. */ - hd_len = hw_hdr_len + proto_len; - data_offset = push_len + proto_len; - } - memset(hdr, 0, hw_hdr_len); - - qeth_l3_fill_header(card, hdr, skb, ipv, cast_type, frame_len); - if (is_tso) - qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr, - frame_len - proto_len, skb, proto_len); - - is_sg = skb_is_nonlinear(skb); - if (IS_IQD(card)) { - rc = qeth_do_send_packet_fast(queue, skb, hdr, data_offset, - hd_len); - } else { - /* TODO: drop skb_orphan() once TX completion is fast enough */ - skb_orphan(skb); - rc = qeth_do_send_packet(card, queue, skb, hdr, data_offset, - hd_len, elements); - } - - if (!rc) { - if (card->options.performance_stats) { - card->perf_stats.buf_elements_sent += elements; - if (is_sg) - card->perf_stats.sg_skbs_sent++; - if (is_tso) { - card->perf_stats.large_send_bytes += frame_len; - card->perf_stats.large_send_cnt++; - } - } - } else { - if (!push_len) - kmem_cache_free(qeth_core_header_cache, hdr); - if (rc == -EBUSY) { - /* roll back to ETH header */ - skb_pull(skb, push_len); - skb_push(skb, ETH_HLEN); - skb_copy_to_linear_data(skb, eth_hdr, ETH_HLEN); - } + rc = qeth_xmit(card, skb, queue, ipv, cast_type, qeth_l3_fill_header); + if (rc == -EBUSY) { + /* roll back to ETH header */ + skb_push(skb, ETH_HLEN); + skb_copy_to_linear_data(skb, eth_hdr, ETH_HLEN); } return rc; } From d7d18da1f7033439f5359f4a95303a496cd16feb Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 8 Nov 2018 15:06:18 +0100 Subject: [PATCH 4/8] s390/qeth: remove card list Re-implement the card-by-RDEV lookup by using device model concepts, and remove the now redundant list of all qeth card instances in the system. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 8 +------ drivers/s390/net/qeth_core_main.c | 25 +++++++++++++--------- drivers/s390/net/qeth_l2_main.c | 35 +++++++------------------------ 3 files changed, 24 insertions(+), 44 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index afe3662a4ad5..0ee026947f20 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -774,7 +774,6 @@ struct qeth_switch_info { #define QETH_NAPI_WEIGHT NAPI_POLL_WEIGHT struct qeth_card { - struct list_head list; enum qeth_card_states state; spinlock_t lock; struct ccwgroup_device *gdev; @@ -826,11 +825,6 @@ struct qeth_card { struct work_struct close_dev_work; }; -struct qeth_card_list_struct { - struct list_head list; - rwlock_t rwlock; -}; - struct qeth_trap_id { __u16 lparnr; char vmname[8]; @@ -977,11 +971,11 @@ int qeth_core_load_discipline(struct qeth_card *, enum qeth_discipline_id); void qeth_core_free_discipline(struct qeth_card *); /* exports for qeth discipline device drivers */ -extern struct qeth_card_list_struct qeth_core_card_list; extern struct kmem_cache *qeth_core_header_cache; extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS]; struct net_device *qeth_clone_netdev(struct net_device *orig); +struct qeth_card *qeth_get_card_by_busid(char *bus_id); void qeth_set_recovery_task(struct qeth_card *); void qeth_clear_recovery_task(struct qeth_card *); void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 2568ddc1bbc3..508bad2dbd0b 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -54,8 +54,6 @@ struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS] = { }; EXPORT_SYMBOL_GPL(qeth_dbf); -struct qeth_card_list_struct qeth_core_card_list; -EXPORT_SYMBOL_GPL(qeth_core_card_list); struct kmem_cache *qeth_core_header_cache; EXPORT_SYMBOL_GPL(qeth_core_header_cache); static struct kmem_cache *qeth_qdio_outbuf_cache; @@ -5806,9 +5804,6 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) break; } - write_lock_irq(&qeth_core_card_list.rwlock); - list_add_tail(&card->list, &qeth_core_card_list.list); - write_unlock_irq(&qeth_core_card_list.rwlock); return 0; err_disc: @@ -5833,9 +5828,6 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev) qeth_core_free_discipline(card); } - write_lock_irq(&qeth_core_card_list.rwlock); - list_del(&card->list); - write_unlock_irq(&qeth_core_card_list.rwlock); free_netdev(card->dev); qeth_core_free_card(card); put_device(&gdev->dev); @@ -5950,6 +5942,21 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = { .restore = qeth_core_restore, }; +struct qeth_card *qeth_get_card_by_busid(char *bus_id) +{ + struct ccwgroup_device *gdev; + struct qeth_card *card; + + gdev = get_ccwgroupdev_by_busid(&qeth_core_ccwgroup_driver, bus_id); + if (!gdev) + return NULL; + + card = dev_get_drvdata(&gdev->dev); + put_device(&gdev->dev); + return card; +} +EXPORT_SYMBOL_GPL(qeth_get_card_by_busid); + int qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct qeth_card *card = dev->ml_priv; @@ -6688,8 +6695,6 @@ static int __init qeth_core_init(void) int rc; pr_info("loading core functions\n"); - INIT_LIST_HEAD(&qeth_core_card_list.list); - rwlock_init(&qeth_core_card_list.rwlock); qeth_wq = create_singlethread_workqueue("qeth_wq"); if (!qeth_wq) { diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 8d3601891c62..2836231c1c5d 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -36,28 +36,6 @@ static void qeth_l2_vnicc_init(struct qeth_card *card); static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc, u32 *timeout); -static struct net_device *qeth_l2_netdev_by_devno(unsigned char *read_dev_no) -{ - struct qeth_card *card; - struct net_device *ndev; - __u16 temp_dev_no; - unsigned long flags; - struct ccw_dev_id read_devid; - - ndev = NULL; - memcpy(&temp_dev_no, read_dev_no, 2); - read_lock_irqsave(&qeth_core_card_list.rwlock, flags); - list_for_each_entry(card, &qeth_core_card_list.list, list) { - ccw_device_get_id(CARD_RDEV(card), &read_devid); - if (read_devid.devno == temp_dev_no) { - ndev = card->dev; - break; - } - } - read_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); - return ndev; -} - static int qeth_setdelmac_makerc(struct qeth_card *card, int retcode) { int rc; @@ -1286,13 +1264,16 @@ int qeth_osn_register(unsigned char *read_dev_no, struct net_device **dev, int (*data_cb)(struct sk_buff *)) { struct qeth_card *card; + char bus_id[16]; + u16 devno; - *dev = qeth_l2_netdev_by_devno(read_dev_no); - if (*dev == NULL) - return -ENODEV; - card = (*dev)->ml_priv; - if (!card) + 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; From 605c9d5f58cc8a58882cf39375c39fcab8066dd4 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 8 Nov 2018 15:06:19 +0100 Subject: [PATCH 5/8] s390/qeth: replace open-coded cmd setup Call qeth_prepare_ipa_cmd() during setup of a new IPA cmd buffer, so that it is used for all commands. Thus ARP and SNMP requests don't have to do their own initialization. This will now also set the proper MPC protocol version for SNMP requests on L2 devices. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 27 ++++++++++++--------------- drivers/s390/net/qeth_core_mpc.c | 1 - drivers/s390/net/qeth_l3_main.c | 3 --- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 508bad2dbd0b..c1315ac63041 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2835,6 +2835,17 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card, cmd->hdr.prot_version = prot; } +void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob) +{ + u8 prot_type = qeth_mpc_select_prot_type(card); + + memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); + memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data), &prot_type, 1); + memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), + &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); +} +EXPORT_SYMBOL_GPL(qeth_prepare_ipa_cmd); + struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card, enum qeth_ipa_cmds ipacmd, enum qeth_prot_versions prot) { @@ -2842,6 +2853,7 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card, iob = qeth_get_buffer(&card->write); if (iob) { + qeth_prepare_ipa_cmd(card, iob); qeth_fill_ipacmd_header(card, __ipa_cmd(iob), ipacmd, prot); } else { dev_warn(&card->gdev->dev, @@ -2854,17 +2866,6 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card, } EXPORT_SYMBOL_GPL(qeth_get_ipacmd_buffer); -void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob) -{ - u8 prot_type = qeth_mpc_select_prot_type(card); - - memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); - memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data), &prot_type, 1); - memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), - &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); -} -EXPORT_SYMBOL_GPL(qeth_prepare_ipa_cmd); - /** * qeth_send_ipa_cmd() - send an IPA command * @@ -2879,7 +2880,6 @@ int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, int rc; QETH_CARD_TEXT(card, 4, "sendipa"); - qeth_prepare_ipa_cmd(card, iob); rc = qeth_send_control_data(card, IPA_CMD_LENGTH, iob, reply_cb, reply_param); if (rc == -ETIME) { @@ -4497,9 +4497,6 @@ static int qeth_send_ipa_snmp_cmd(struct qeth_card *card, QETH_CARD_TEXT(card, 4, "sendsnmp"); - memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); - memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), - &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); /* adjust PDU length fields in IPA_PDU_HEADER */ s1 = (u32) IPA_PDU_HEADER_SIZE + len; s2 = (u32) len; diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c index e891c0b52f4c..16fc51ad0514 100644 --- a/drivers/s390/net/qeth_core_mpc.c +++ b/drivers/s390/net/qeth_core_mpc.c @@ -144,7 +144,6 @@ unsigned char IPA_PDU_HEADER[] = { sizeof(struct qeth_ipa_cmd) % 256, 0x00, 0x00, 0x00, 0x40, }; -EXPORT_SYMBOL_GPL(IPA_PDU_HEADER); struct ipa_rc_msg { enum qeth_ipa_return_codes rc; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 61d847d41cab..ce5ef6aca891 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1693,9 +1693,6 @@ static int qeth_l3_send_ipa_arp_cmd(struct qeth_card *card, { QETH_CARD_TEXT(card, 4, "sendarp"); - memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); - memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), - &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); return qeth_send_control_data(card, IPA_PDU_HEADER_SIZE + len, iob, reply_cb, reply_param); } From 4fa55fa94f55f5bc31472e8b96b9846bc191eaf8 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 8 Nov 2018 15:06:20 +0100 Subject: [PATCH 6/8] s390/qeth: remove two IPA command helpers qeth_l3_send_ipa_arp_cmd() is merely a wrapper around qeth_send_control_data() now. So push the length adjustment into QETH_SETASS_BASE_LEN, and remove the wrapper. While at it, also remove some redundant 0-initializations. qeth_send_setassparms() requires that callers prepare their command parameters, so that they can be copied into the parameter area in one go. Skip the indirection, and just let callers set up the command themselves. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 51 ++++++++----------------------- drivers/s390/net/qeth_core_mpc.h | 7 ++--- drivers/s390/net/qeth_l3_main.c | 20 ++---------- 3 files changed, 19 insertions(+), 59 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index c1315ac63041..ae972461860e 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -5475,34 +5475,11 @@ struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card, } EXPORT_SYMBOL_GPL(qeth_get_setassparms_cmd); -static int qeth_send_setassparms(struct qeth_card *card, - struct qeth_cmd_buffer *iob, u16 len, - long data, int (*reply_cb)(struct qeth_card *, - struct qeth_reply *, - unsigned long), - void *reply_param) -{ - int rc; - struct qeth_ipa_cmd *cmd; - - QETH_CARD_TEXT(card, 4, "sendassp"); - - cmd = __ipa_cmd(iob); - if (len <= sizeof(__u32)) - cmd->data.setassparms.data.flags_32bit = (__u32) data; - else /* (len > sizeof(__u32)) */ - memcpy(&cmd->data.setassparms.data, (void *) data, len); - - rc = qeth_send_ipa_cmd(card, iob, reply_cb, reply_param); - return rc; -} - int qeth_send_simple_setassparms_prot(struct qeth_card *card, enum qeth_ipa_funcs ipa_func, u16 cmd_code, long data, enum qeth_prot_versions prot) { - int rc; int length = 0; struct qeth_cmd_buffer *iob; @@ -5512,9 +5489,9 @@ int qeth_send_simple_setassparms_prot(struct qeth_card *card, iob = qeth_get_setassparms_cmd(card, ipa_func, cmd_code, length, prot); if (!iob) return -ENOMEM; - rc = qeth_send_setassparms(card, iob, length, data, - qeth_setassparms_cb, NULL); - return rc; + + __ipa_cmd(iob)->data.setassparms.data.flags_32bit = (__u32) data; + return qeth_send_ipa_cmd(card, iob, qeth_setassparms_cb, NULL); } EXPORT_SYMBOL_GPL(qeth_send_simple_setassparms_prot); @@ -6385,16 +6362,16 @@ static int qeth_ipa_checksum_run_cmd(struct qeth_card *card, enum qeth_prot_versions prot) { struct qeth_cmd_buffer *iob; - int rc = -ENOMEM; QETH_CARD_TEXT(card, 4, "chkdocmd"); iob = qeth_get_setassparms_cmd(card, ipa_func, cmd_code, sizeof(__u32), prot); - if (iob) - rc = qeth_send_setassparms(card, iob, sizeof(__u32), data, - qeth_ipa_checksum_run_cmd_cb, - chksum_cb); - return rc; + if (!iob) + return -ENOMEM; + + __ipa_cmd(iob)->data.setassparms.data.flags_32bit = (__u32) data; + return qeth_send_ipa_cmd(card, iob, qeth_ipa_checksum_run_cmd_cb, + chksum_cb); } static int qeth_send_checksum_on(struct qeth_card *card, int cstype, @@ -6492,8 +6469,7 @@ static int qeth_set_tso_on(struct qeth_card *card, if (!iob) return -ENOMEM; - rc = qeth_send_setassparms(card, iob, 0, 0 /* unused */, - qeth_start_tso_cb, &tso_data); + rc = qeth_send_ipa_cmd(card, iob, qeth_start_tso_cb, &tso_data); if (rc) return rc; @@ -6510,10 +6486,9 @@ static int qeth_set_tso_on(struct qeth_card *card, } /* enable TSO capability */ - caps.supported = 0; - caps.enabled = QETH_IPA_LARGE_SEND_TCP; - rc = qeth_send_setassparms(card, iob, sizeof(caps), (long) &caps, - qeth_setassparms_get_caps_cb, &caps); + __ipa_cmd(iob)->data.setassparms.data.caps.enabled = + QETH_IPA_LARGE_SEND_TCP; + rc = qeth_send_ipa_cmd(card, iob, qeth_setassparms_get_caps_cb, &caps); if (rc) { qeth_set_tso_off(card, prot); return rc; diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 10cc487c16d6..1ab321926f64 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -833,10 +833,9 @@ enum qeth_ipa_arp_return_codes { extern const char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc); extern const char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd); -#define QETH_SETASS_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \ - sizeof(struct qeth_ipacmd_setassparms_hdr)) -#define QETH_IPA_ARP_DATA_POS(buffer) (buffer + IPA_PDU_HEADER_SIZE + \ - QETH_SETASS_BASE_LEN) +#define QETH_SETASS_BASE_LEN (IPA_PDU_HEADER_SIZE + \ + sizeof(struct qeth_ipacmd_hdr) + \ + sizeof(struct qeth_ipacmd_setassparms_hdr)) #define QETH_SETADP_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \ sizeof(struct qeth_ipacmd_setadpparms_hdr)) #define QETH_SNMP_SETADP_CMDLENGTH 16 diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index ce5ef6aca891..89d5e6fb21ac 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1685,18 +1685,6 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card, return 0; } -static int qeth_l3_send_ipa_arp_cmd(struct qeth_card *card, - struct qeth_cmd_buffer *iob, int len, - int (*reply_cb)(struct qeth_card *, struct qeth_reply *, - unsigned long), - void *reply_param) -{ - QETH_CARD_TEXT(card, 4, "sendarp"); - - return qeth_send_control_data(card, IPA_PDU_HEADER_SIZE + len, iob, - reply_cb, reply_param); -} - static int qeth_l3_query_arp_cache_info(struct qeth_card *card, enum qeth_prot_versions prot, struct qeth_arp_query_info *qinfo) @@ -1716,11 +1704,9 @@ static int qeth_l3_query_arp_cache_info(struct qeth_card *card, return -ENOMEM; cmd = __ipa_cmd(iob); cmd->data.setassparms.data.query_arp.request_bits = 0x000F; - cmd->data.setassparms.data.query_arp.reply_bits = 0; - cmd->data.setassparms.data.query_arp.no_entries = 0; - rc = qeth_l3_send_ipa_arp_cmd(card, iob, - QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN, - qeth_l3_arp_query_cb, (void *)qinfo); + rc = qeth_send_control_data(card, + QETH_SETASS_BASE_LEN + QETH_ARP_CMD_LEN, + iob, qeth_l3_arp_query_cb, qinfo); if (rc) QETH_DBF_MESSAGE(2, "Error while querying ARP cache on device %x: %#x\n", CARD_DEVID(card), rc); From 9168f5ae3837dd98cb201d16f813c6f1d96670ca Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 8 Nov 2018 15:06:21 +0100 Subject: [PATCH 7/8] s390/qeth: remove unused fallback in Layer3's MAC code If the CREATE ADDR sent by qeth_l3_iqd_read_initial_mac() fails, its callback sets a random MAC address on the net_device. The error then propagates back, and qeth_l3_setup_netdev() bails out without registering the net_device. Any subsequent call to qeth_l3_setup_netdev() will then attempt a fresh CREATE ADDR which either 1) also fails, or 2) sets a proper MAC address on the net_device. Consequently, the net_device will never be registered with a random MAC and we can drop the fallback code. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 89d5e6fb21ac..674ff3344ff3 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -949,9 +949,6 @@ static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card, if (cmd->hdr.return_code == 0) ether_addr_copy(card->dev->dev_addr, cmd->data.create_destroy_addr.unique_id); - else - eth_random_addr(card->dev->dev_addr); - return 0; } From ded9da1fc2d9509c1fd18ecdaae5f6185fb81dbc Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 8 Nov 2018 15:06:22 +0100 Subject: [PATCH 8/8] s390/qeth: don't process hsuid in qeth_l3_setup_netdev() qeth_l3_setup_netdev() checks if the hsuid attribute is set on the qeth device, and propagates it to the net_device. In the past this was needed to pick up any hsuid that was set before allocation of the net_device. With commit d3d1b205e89f ("s390/qeth: allocate netdevice early") this is no longer necessary, qeth_l3_dev_hsuid_store() always stores the hsuid straight into dev->perm_addr. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 674ff3344ff3..eca68da39d05 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2279,9 +2279,6 @@ static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok) rc = qeth_l3_iqd_read_initial_mac(card); if (rc) goto out; - - if (card->options.hsuid[0]) - memcpy(card->dev->perm_addr, card->options.hsuid, 9); } else return -ENODEV;