diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/net/qeth_core.h | 131 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 919 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_mpc.h | 2 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_sys.c | 10 | ||||
-rw-r--r-- | drivers/s390/net/qeth_ethtool.c | 17 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 99 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 263 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_sys.c | 26 |
8 files changed, 782 insertions, 685 deletions
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index c851cf6e01c4..784a2e76a1b0 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -10,6 +10,7 @@ #ifndef __QETH_CORE_H__ #define __QETH_CORE_H__ +#include <linux/completion.h> #include <linux/if.h> #include <linux/if_arp.h> #include <linux/etherdevice.h> @@ -21,6 +22,7 @@ #include <linux/hashtable.h> #include <linux/ip.h> #include <linux/refcount.h> +#include <linux/wait.h> #include <linux/workqueue.h> #include <net/ipv6.h> @@ -163,6 +165,12 @@ struct qeth_vnicc_info { bool rx_bcast_enabled; }; +static inline int qeth_is_adp_supported(struct qeth_ipa_info *ipa, + enum qeth_ipa_setadp_cmd func) +{ + return (ipa->supported_funcs & func); +} + static inline int qeth_is_ipa_supported(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func) { @@ -176,9 +184,7 @@ static inline int qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, } #define qeth_adp_supported(c, f) \ - qeth_is_ipa_supported(&c->options.adp, f) -#define qeth_adp_enabled(c, f) \ - qeth_is_ipa_enabled(&c->options.adp, f) + qeth_is_adp_supported(&c->options.adp, f) #define qeth_is_supported(c, f) \ qeth_is_ipa_supported(&c->options.ipa4, f) #define qeth_is_enabled(c, f) \ @@ -217,6 +223,9 @@ static inline int qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, /* QDIO queue and buffer handling */ /*****************************************************************************/ #define QETH_MAX_QUEUES 4 +#define QETH_IQD_MIN_TXQ 2 /* One for ucast, one for mcast. */ +#define QETH_IQD_MCAST_TXQ 0 +#define QETH_IQD_MIN_UCAST_TXQ 1 #define QETH_IN_BUF_SIZE_DEFAULT 65536 #define QETH_IN_BUF_COUNT_DEFAULT 64 #define QETH_IN_BUF_COUNT_HSDEFAULT 128 @@ -365,34 +374,6 @@ enum qeth_header_ids { #define QETH_HDR_EXT_CSUM_TRANSP_REQ 0x20 #define QETH_HDR_EXT_UDP 0x40 /*bit off for TCP*/ -enum qeth_qdio_buffer_states { - /* - * inbound: read out by driver; owned by hardware in order to be filled - * outbound: owned by driver in order to be filled - */ - QETH_QDIO_BUF_EMPTY, - /* - * inbound: filled by hardware; owned by driver in order to be read out - * outbound: filled by driver; owned by hardware in order to be sent - */ - QETH_QDIO_BUF_PRIMED, - /* - * inbound: not applicable - * outbound: identified to be pending in TPQ - */ - QETH_QDIO_BUF_PENDING, - /* - * inbound: not applicable - * outbound: found in completion queue - */ - QETH_QDIO_BUF_IN_CQ, - /* - * inbound: not applicable - * outbound: handled via transfer pending / completion queue - */ - QETH_QDIO_BUF_HANDLED_DELAYED, -}; - enum qeth_qdio_info_states { QETH_QDIO_UNINITIALIZED, QETH_QDIO_ALLOCATED, @@ -424,6 +405,19 @@ struct qeth_qdio_q { int next_buf_to_init; }; +enum qeth_qdio_out_buffer_state { + /* Owned by driver, in order to be filled. */ + QETH_QDIO_BUF_EMPTY, + /* Filled by driver; owned by hardware in order to be sent. */ + QETH_QDIO_BUF_PRIMED, + /* Identified to be pending in TPQ. */ + QETH_QDIO_BUF_PENDING, + /* Found in completion queue. */ + QETH_QDIO_BUF_IN_CQ, + /* Handled via transfer pending / completion queue. */ + QETH_QDIO_BUF_HANDLED_DELAYED, +}; + struct qeth_qdio_out_buffer { struct qdio_buffer *buffer; atomic_t state; @@ -462,7 +456,6 @@ struct qeth_card_stats { u64 rx_errors; u64 rx_dropped; u64 rx_multicast; - u64 tx_errors; }; struct qeth_out_q_stats { @@ -477,6 +470,7 @@ struct qeth_out_q_stats { u64 skbs_linearized_fail; u64 tso_bytes; u64 packing_mode_switch; + u64 stopped; /* rtnl_link_stats64 */ u64 tx_packets; @@ -490,14 +484,12 @@ struct qeth_qdio_out_q { struct qeth_qdio_out_buffer *bufs[QDIO_MAX_BUFFERS_PER_Q]; struct qdio_outbuf_state *bufstates; /* convenience pointer */ struct qeth_out_q_stats stats; - int queue_no; + u8 next_buf_to_fill; + u8 max_elements; + u8 queue_no; + u8 do_pack; struct qeth_card *card; atomic_t state; - int do_pack; - /* - * index of buffer to be filled by driver; state EMPTY or PACKING - */ - int next_buf_to_fill; /* * number of buffers that are currently filled (PRIMED) * -> these buffers are hardware-owned @@ -507,6 +499,11 @@ struct qeth_qdio_out_q { atomic_t set_pci_flags_count; }; +static inline bool qeth_out_queue_is_full(struct qeth_qdio_out_q *queue) +{ + return atomic_read(&queue->used_buffers) >= QDIO_MAX_BUFFERS_PER_Q; +} + struct qeth_qdio_info { atomic_t state; /* input */ @@ -538,7 +535,6 @@ struct qeth_qdio_info { enum qeth_channel_states { CH_STATE_UP, CH_STATE_DOWN, - CH_STATE_ACTIVATING, CH_STATE_HALTED, CH_STATE_STOPPED, CH_STATE_RCD, @@ -585,7 +581,10 @@ struct qeth_cmd_buffer { enum qeth_cmd_buffer_state state; struct qeth_channel *channel; struct qeth_reply *reply; + long timeout; unsigned char *data; + void (*finalize)(struct qeth_card *card, struct qeth_cmd_buffer *iob, + unsigned int length); void (*callback)(struct qeth_card *card, struct qeth_channel *channel, struct qeth_cmd_buffer *iob); }; @@ -610,6 +609,11 @@ struct qeth_channel { int io_buf_no; }; +static inline bool qeth_trylock_channel(struct qeth_channel *channel) +{ + return atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0; +} + /** * OSA card related definitions */ @@ -631,17 +635,15 @@ struct qeth_seqno { __u32 pdu_hdr; __u32 pdu_hdr_ack; __u16 ipa; - __u32 pkt_seqno; }; struct qeth_reply { struct list_head list; - wait_queue_head_t wait_q; + struct completion received; int (*callback)(struct qeth_card *, struct qeth_reply *, unsigned long); u32 seqno; unsigned long offset; - atomic_t received; int rc; void *param; refcount_t refcnt; @@ -663,7 +665,7 @@ struct qeth_card_info { __u16 func_level; char mcl_level[QETH_MCL_LENGTH + 1]; u8 open_when_online:1; - int guestlan; + u8 is_vm_nic:1; int mac_bits; enum qeth_card_types type; enum qeth_link_types link_type; @@ -774,18 +776,19 @@ struct qeth_card { struct qeth_card_options options; struct workqueue_struct *event_wq; + struct workqueue_struct *cmd_wq; wait_queue_head_t wait_q; - spinlock_t mclock; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; DECLARE_HASHTABLE(mac_htable, 4); DECLARE_HASHTABLE(ip_htable, 4); + struct mutex ip_lock; DECLARE_HASHTABLE(ip_mc_htable, 4); + struct work_struct rx_mode_work; struct work_struct kernel_thread_starter; spinlock_t thread_mask_lock; unsigned long thread_start_mask; unsigned long thread_allowed_mask; unsigned long thread_running_mask; - spinlock_t ip_lock; struct qeth_ipato ipato; struct list_head cmd_waiter_list; /* QDIO buffer handling */ @@ -827,6 +830,15 @@ static inline bool qeth_netdev_is_registered(struct net_device *dev) return dev->netdev_ops != NULL; } +static inline u16 qeth_iqd_translate_txq(struct net_device *dev, u16 txq) +{ + if (txq == QETH_IQD_MCAST_TXQ) + return dev->num_tx_queues - 1; + if (txq == dev->num_tx_queues - 1) + return QETH_IQD_MCAST_TXQ; + return txq; +} + static inline void qeth_scrub_qdio_buffer(struct qdio_buffer *buf, unsigned int elements) { @@ -869,6 +881,16 @@ static inline int qeth_get_ip_version(struct sk_buff *skb) } } +static inline int qeth_get_ether_cast_type(struct sk_buff *skb) +{ + u8 *addr = eth_hdr(skb)->h_dest; + + if (is_multicast_ether_addr(addr)) + return is_broadcast_ether_addr(addr) ? RTN_BROADCAST : + RTN_MULTICAST; + return RTN_UNICAST; +} + static inline void qeth_rx_csum(struct qeth_card *card, struct sk_buff *skb, u8 flags) { @@ -922,18 +944,7 @@ static inline int qeth_send_simple_setassparms_v6(struct qeth_card *card, data, QETH_PROT_IPV6); } -int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb, - int ipv); -static inline struct qeth_qdio_out_q *qeth_get_tx_queue(struct qeth_card *card, - struct sk_buff *skb, - int ipv, int cast_type) -{ - if (IS_IQD(card) && cast_type != RTN_UNICAST) - return card->qdio.out_qs[card->qdio.no_out_queues - 1]; - if (!card->qdio.do_prio_queueing) - return card->qdio.out_qs[card->qdio.default_out_queue]; - return card->qdio.out_qs[qeth_get_priority_queue(card, skb, ipv)]; -} +int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb); extern struct qeth_discipline qeth_l2_discipline; extern struct qeth_discipline qeth_l3_discipline; @@ -979,12 +990,10 @@ void qeth_clear_ipacmd_list(struct qeth_card *); int qeth_qdio_clear_card(struct qeth_card *, int); void qeth_clear_working_pool_list(struct qeth_card *); void qeth_clear_cmd_buffers(struct qeth_channel *); -void qeth_clear_qdio_buffers(struct qeth_card *); +void qeth_drain_output_queues(struct qeth_card *card); void qeth_setadp_promisc_mode(struct qeth_card *); int qeth_setadpparms_change_macaddr(struct qeth_card *); void qeth_tx_timeout(struct net_device *); -void qeth_prepare_control_data(struct qeth_card *, int, - struct qeth_cmd_buffer *); void qeth_release_buffer(struct qeth_channel *, struct qeth_cmd_buffer *); void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, u16 cmd_length); @@ -1016,6 +1025,8 @@ netdev_features_t qeth_features_check(struct sk_buff *skb, struct net_device *dev, netdev_features_t features); void qeth_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats); +u16 qeth_iqd_select_queue(struct net_device *dev, struct sk_buff *skb, + u8 cast_type, struct net_device *sb_dev); int qeth_open(struct net_device *dev); int qeth_stop(struct net_device *dev); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 44bd6f04c145..009f2c0ec504 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -61,13 +61,13 @@ static struct kmem_cache *qeth_qdio_outbuf_cache; static struct device *qeth_core_root_dev; static struct lock_class_key qdio_out_skb_queue_key; -static void qeth_send_control_data_cb(struct qeth_card *card, - struct qeth_channel *channel, - struct qeth_cmd_buffer *iob); +static void qeth_issue_next_read_cb(struct qeth_card *card, + struct qeth_channel *channel, + struct qeth_cmd_buffer *iob); static struct qeth_cmd_buffer *qeth_get_buffer(struct qeth_channel *); static void qeth_free_buffer_pool(struct qeth_card *); static int qeth_qdio_establish(struct qeth_card *); -static void qeth_free_qdio_buffers(struct qeth_card *); +static void qeth_free_qdio_queues(struct qeth_card *card); static void qeth_notify_skbs(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf, enum iucv_tx_notify notification); @@ -85,7 +85,7 @@ static void qeth_close_dev_handler(struct work_struct *work) static const char *qeth_get_cardname(struct qeth_card *card) { - if (card->info.guestlan) { + if (IS_VM_NIC(card)) { switch (card->info.type) { case QETH_CARD_TYPE_OSD: return " Virtual NIC QDIO"; @@ -120,7 +120,7 @@ static const char *qeth_get_cardname(struct qeth_card *card) /* max length to be returned: 14 */ const char *qeth_get_cardname_short(struct qeth_card *card) { - if (card->info.guestlan) { + if (IS_VM_NIC(card)) { switch (card->info.type) { case QETH_CARD_TYPE_OSD: return "Virt.NIC QDIO"; @@ -511,7 +511,9 @@ static int __qeth_issue_next_read(struct qeth_card *card) CARD_DEVID(card)); return -ENOMEM; } + qeth_setup_ccw(channel->ccw, CCW_CMD_READ, QETH_BUFSIZE, iob->data); + iob->callback = qeth_issue_next_read_cb; QETH_CARD_TEXT(card, 6, "noirqpnd"); rc = ccw_device_start(channel->ccwdev, channel->ccw, (addr_t) iob, 0, 0); @@ -542,11 +544,10 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) { struct qeth_reply *reply; - reply = kzalloc(sizeof(struct qeth_reply), GFP_ATOMIC); + reply = kzalloc(sizeof(*reply), GFP_KERNEL); if (reply) { refcount_set(&reply->refcnt, 1); - atomic_set(&reply->received, 0); - init_waitqueue_head(&reply->wait_q); + init_completion(&reply->received); } return reply; } @@ -576,10 +577,10 @@ static void qeth_dequeue_reply(struct qeth_card *card, struct qeth_reply *reply) spin_unlock_irq(&card->lock); } -static void qeth_notify_reply(struct qeth_reply *reply) +static void qeth_notify_reply(struct qeth_reply *reply, int reason) { - atomic_inc(&reply->received); - wake_up(&reply->wait_q); + reply->rc = reason; + complete(&reply->received); } static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc, @@ -664,10 +665,8 @@ void qeth_clear_ipacmd_list(struct qeth_card *card) QETH_CARD_TEXT(card, 4, "clipalst"); spin_lock_irqsave(&card->lock, flags); - list_for_each_entry(reply, &card->cmd_waiter_list, list) { - reply->rc = -EIO; - qeth_notify_reply(reply); - } + list_for_each_entry(reply, &card->cmd_waiter_list, list) + qeth_notify_reply(reply, -EIO); spin_unlock_irqrestore(&card->lock, flags); } EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list); @@ -675,9 +674,6 @@ EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list); static int qeth_check_idx_response(struct qeth_card *card, unsigned char *buffer) { - if (!buffer) - return 0; - QETH_DBF_HEX(CTRL, 2, buffer, QETH_DBF_CTRL_LEN); if ((buffer[2] & 0xc0) == 0xc0) { QETH_DBF_MESSAGE(2, "received an IDX TERMINATE with cause code %#04x\n", @@ -704,6 +700,7 @@ static struct qeth_cmd_buffer *__qeth_get_buffer(struct qeth_channel *channel) do { if (channel->iob[index].state == BUF_STATE_FREE) { channel->iob[index].state = BUF_STATE_LOCKED; + channel->iob[index].timeout = QETH_TIMEOUT; channel->io_buf_no = (channel->io_buf_no + 1) % QETH_CMD_BUFFER_NO; memset(channel->iob[index].data, 0, QETH_BUFSIZE); @@ -722,7 +719,7 @@ void qeth_release_buffer(struct qeth_channel *channel, spin_lock_irqsave(&channel->iob_lock, flags); iob->state = BUF_STATE_FREE; - iob->callback = qeth_send_control_data_cb; + iob->callback = NULL; if (iob->reply) { qeth_put_reply(iob->reply); iob->reply = NULL; @@ -743,10 +740,8 @@ static void qeth_cancel_cmd(struct qeth_cmd_buffer *iob, int rc) { struct qeth_reply *reply = iob->reply; - if (reply) { - reply->rc = rc; - qeth_notify_reply(reply); - } + if (reply) + qeth_notify_reply(reply, rc); qeth_release_buffer(iob->channel, iob); } @@ -780,9 +775,9 @@ void qeth_clear_cmd_buffers(struct qeth_channel *channel) } EXPORT_SYMBOL_GPL(qeth_clear_cmd_buffers); -static void qeth_send_control_data_cb(struct qeth_card *card, - struct qeth_channel *channel, - struct qeth_cmd_buffer *iob) +static void qeth_issue_next_read_cb(struct qeth_card *card, + struct qeth_channel *channel, + struct qeth_cmd_buffer *iob) { struct qeth_ipa_cmd *cmd = NULL; struct qeth_reply *reply = NULL; @@ -846,11 +841,8 @@ static void qeth_send_control_data_cb(struct qeth_card *card, } } - if (rc <= 0) { - reply->rc = rc; - qeth_notify_reply(reply); - } - + if (rc <= 0) + qeth_notify_reply(reply, rc); qeth_put_reply(reply); out: @@ -1173,20 +1165,19 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, qeth_release_skbs(buf); - for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) { + for (i = 0; i < queue->max_elements; ++i) { if (buf->buffer->element[i].addr && buf->is_header[i]) kmem_cache_free(qeth_core_header_cache, buf->buffer->element[i].addr); buf->is_header[i] = 0; } - qeth_scrub_qdio_buffer(buf->buffer, - QETH_MAX_BUFFER_ELEMENTS(queue->card)); + qeth_scrub_qdio_buffer(buf->buffer, queue->max_elements); buf->next_element_to_fill = 0; atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); } -static void qeth_clear_outq_buffers(struct qeth_qdio_out_q *q, int free) +static void qeth_drain_output_queue(struct qeth_qdio_out_q *q, bool free) { int j; @@ -1202,19 +1193,18 @@ static void qeth_clear_outq_buffers(struct qeth_qdio_out_q *q, int free) } } -void qeth_clear_qdio_buffers(struct qeth_card *card) +void qeth_drain_output_queues(struct qeth_card *card) { int i; QETH_CARD_TEXT(card, 2, "clearqdbf"); /* clear outbound buffers to free skbs */ for (i = 0; i < card->qdio.no_out_queues; ++i) { - if (card->qdio.out_qs[i]) { - qeth_clear_outq_buffers(card->qdio.out_qs[i], 0); - } + if (card->qdio.out_qs[i]) + qeth_drain_output_queue(card->qdio.out_qs[i], false); } } -EXPORT_SYMBOL_GPL(qeth_clear_qdio_buffers); +EXPORT_SYMBOL_GPL(qeth_drain_output_queues); static void qeth_free_buffer_pool(struct qeth_card *card) { @@ -1273,7 +1263,6 @@ static int qeth_setup_channel(struct qeth_channel *channel, bool alloc_buffers) break; channel->iob[cnt].state = BUF_STATE_FREE; channel->iob[cnt].channel = channel; - channel->iob[cnt].callback = qeth_send_control_data_cb; } if (cnt < QETH_CMD_BUFFER_NO) { qeth_clean_channel(channel); @@ -1285,30 +1274,28 @@ static int qeth_setup_channel(struct qeth_channel *channel, bool alloc_buffers) return 0; } -static void qeth_set_single_write_queues(struct qeth_card *card) +static void qeth_osa_set_output_queues(struct qeth_card *card, bool single) { - if ((atomic_read(&card->qdio.state) != QETH_QDIO_UNINITIALIZED) && - (card->qdio.no_out_queues == 4)) - qeth_free_qdio_buffers(card); + unsigned int count = single ? 1 : card->dev->num_tx_queues; - card->qdio.no_out_queues = 1; - if (card->qdio.default_out_queue != 0) - dev_info(&card->gdev->dev, "Priority Queueing not supported\n"); + rtnl_lock(); + netif_set_real_num_tx_queues(card->dev, count); + rtnl_unlock(); - card->qdio.default_out_queue = 0; -} + if (card->qdio.no_out_queues == count) + return; -static void qeth_set_multiple_write_queues(struct qeth_card *card) -{ - if ((atomic_read(&card->qdio.state) != QETH_QDIO_UNINITIALIZED) && - (card->qdio.no_out_queues == 1)) { - qeth_free_qdio_buffers(card); - card->qdio.default_out_queue = 2; - } - card->qdio.no_out_queues = 4; + if (atomic_read(&card->qdio.state) != QETH_QDIO_UNINITIALIZED) + qeth_free_qdio_queues(card); + + if (count == 1) + dev_info(&card->gdev->dev, "Priority Queueing not supported\n"); + + card->qdio.default_out_queue = single ? 0 : QETH_DEFAULT_QUEUE; + card->qdio.no_out_queues = count; } -static void qeth_update_from_chp_desc(struct qeth_card *card) +static int qeth_update_from_chp_desc(struct qeth_card *card) { struct ccw_device *ccwdev; struct channel_path_desc_fmt0 *chp_dsc; @@ -1318,21 +1305,18 @@ static void qeth_update_from_chp_desc(struct qeth_card *card) ccwdev = card->data.ccwdev; chp_dsc = ccw_device_get_chp_desc(ccwdev, 0); if (!chp_dsc) - goto out; + return -ENOMEM; card->info.func_level = 0x4100 + chp_dsc->desc; - if (card->info.type == QETH_CARD_TYPE_IQD) - goto out; - /* CHPP field bit 6 == 1 -> single queue */ - if ((chp_dsc->chpp & 0x02) == 0x02) - qeth_set_single_write_queues(card); - else - qeth_set_multiple_write_queues(card); -out: + if (IS_OSD(card) || IS_OSX(card)) + /* CHPP field bit 6 == 1 -> single queue */ + qeth_osa_set_output_queues(card, chp_dsc->chpp & 0x02); + kfree(chp_dsc); QETH_DBF_TEXT_(SETUP, 2, "nr:%x", card->qdio.no_out_queues); QETH_DBF_TEXT_(SETUP, 2, "lvl:%02x", card->info.func_level); + return 0; } static void qeth_init_qdio_info(struct qeth_card *card) @@ -1341,12 +1325,11 @@ static void qeth_init_qdio_info(struct qeth_card *card) atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED); card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; - card->qdio.no_out_queues = QETH_MAX_QUEUES; /* inbound */ card->qdio.no_in_queues = 1; card->qdio.in_buf_size = QETH_IN_BUF_SIZE_DEFAULT; - if (card->info.type == QETH_CARD_TYPE_IQD) + if (IS_IQD(card)) card->qdio.init_pool.buf_count = QETH_IN_BUF_COUNT_HSDEFAULT; else card->qdio.init_pool.buf_count = QETH_IN_BUF_COUNT_DEFAULT; @@ -1409,9 +1392,7 @@ static void qeth_setup_card(struct qeth_card *card) card->info.type = CARD_RDEV(card)->id.driver_info; card->state = CARD_STATE_DOWN; - spin_lock_init(&card->mclock); spin_lock_init(&card->lock); - spin_lock_init(&card->ip_lock); spin_lock_init(&card->thread_mask_lock); mutex_init(&card->conf_mutex); mutex_init(&card->discipline_mutex); @@ -1451,7 +1432,8 @@ static struct qeth_card *qeth_alloc_card(struct ccwgroup_device *gdev) CARD_WDEV(card) = gdev->cdev[1]; CARD_DDEV(card) = gdev->cdev[2]; - card->event_wq = alloc_ordered_workqueue("%s", 0, dev_name(&gdev->dev)); + card->event_wq = alloc_ordered_workqueue("%s_event", 0, + dev_name(&gdev->dev)); if (!card->event_wq) goto out_wq; if (qeth_setup_channel(&card->read, true)) @@ -1571,7 +1553,7 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt) switch (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ESTABLISHED, QETH_QDIO_CLEANING)) { case QETH_QDIO_ESTABLISHED: - if (card->info.type == QETH_CARD_TYPE_IQD) + if (IS_IQD(card)) rc = qdio_shutdown(CARD_DDEV(card), QDIO_FLAG_CLEANUP_USING_HALT); else @@ -1644,8 +1626,8 @@ static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd) card->info.chpid = prcd[30]; card->info.unit_addr2 = prcd[31]; card->info.cula = prcd[63]; - card->info.guestlan = ((prcd[0x10] == _ascebc['V']) && - (prcd[0x11] == _ascebc['M'])); + card->info.is_vm_nic = ((prcd[0x10] == _ascebc['V']) && + (prcd[0x11] == _ascebc['M'])); } static enum qeth_discipline_id qeth_vm_detect_layer(struct qeth_card *card) @@ -1709,13 +1691,11 @@ static enum qeth_discipline_id qeth_enforce_discipline(struct qeth_card *card) { enum qeth_discipline_id disc = QETH_DISCIPLINE_UNDETERMINED; - if (card->info.type == QETH_CARD_TYPE_OSM || - card->info.type == QETH_CARD_TYPE_OSN) + if (IS_OSM(card) || IS_OSN(card)) disc = QETH_DISCIPLINE_LAYER2; - else if (card->info.guestlan) - disc = (card->info.type == QETH_CARD_TYPE_IQD) ? - QETH_DISCIPLINE_LAYER3 : - qeth_vm_detect_layer(card); + else if (IS_VM_NIC(card)) + disc = IS_IQD(card) ? QETH_DISCIPLINE_LAYER3 : + qeth_vm_detect_layer(card); switch (disc) { case QETH_DISCIPLINE_LAYER2: @@ -1771,121 +1751,16 @@ static void qeth_init_func_level(struct qeth_card *card) } } -static int qeth_idx_activate_get_answer(struct qeth_card *card, - struct qeth_channel *channel, - void (*reply_cb)(struct qeth_card *, - struct qeth_channel *, - struct qeth_cmd_buffer *)) -{ - struct qeth_cmd_buffer *iob; - int rc; - - QETH_DBF_TEXT(SETUP, 2, "idxanswr"); - iob = qeth_get_buffer(channel); - if (!iob) - return -ENOMEM; - iob->callback = reply_cb; - qeth_setup_ccw(channel->ccw, CCW_CMD_READ, QETH_BUFSIZE, iob->data); - - wait_event(card->wait_q, - atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0); - QETH_DBF_TEXT(SETUP, 6, "noirqpnd"); - spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); - rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw, - (addr_t) iob, 0, 0, QETH_TIMEOUT); - spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); - - if (rc) { - QETH_DBF_MESSAGE(2, "Error2 in activating channel rc=%d\n", rc); - QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); - atomic_set(&channel->irq_pending, 0); - qeth_release_buffer(channel, iob); - wake_up(&card->wait_q); - return rc; - } - rc = wait_event_interruptible_timeout(card->wait_q, - channel->state == CH_STATE_UP, QETH_TIMEOUT); - if (rc == -ERESTARTSYS) - return rc; - if (channel->state != CH_STATE_UP) { - rc = -ETIME; - QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); - } else - rc = 0; - return rc; -} - -static int qeth_idx_activate_channel(struct qeth_card *card, - struct qeth_channel *channel, - void (*reply_cb)(struct qeth_card *, - struct qeth_channel *, - struct qeth_cmd_buffer *)) +static void qeth_idx_finalize_cmd(struct qeth_card *card, + struct qeth_cmd_buffer *iob, + unsigned int length) { - struct qeth_cmd_buffer *iob; - __u16 temp; - __u8 tmp; - int rc; - struct ccw_dev_id temp_devid; - - QETH_DBF_TEXT(SETUP, 2, "idxactch"); + qeth_setup_ccw(iob->channel->ccw, CCW_CMD_WRITE, length, iob->data); - iob = qeth_get_buffer(channel); - if (!iob) - return -ENOMEM; - iob->callback = reply_cb; - qeth_setup_ccw(channel->ccw, CCW_CMD_WRITE, IDX_ACTIVATE_SIZE, - iob->data); - if (channel == &card->write) { - memcpy(iob->data, IDX_ACTIVATE_WRITE, IDX_ACTIVATE_SIZE); - memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), - &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH); + memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), &card->seqno.trans_hdr, + QETH_SEQ_NO_LENGTH); + if (iob->channel == &card->write) card->seqno.trans_hdr++; - } else { - memcpy(iob->data, IDX_ACTIVATE_READ, IDX_ACTIVATE_SIZE); - memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), - &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH); - } - tmp = ((u8)card->dev->dev_port) | 0x80; - memcpy(QETH_IDX_ACT_PNO(iob->data), &tmp, 1); - memcpy(QETH_IDX_ACT_ISSUER_RM_TOKEN(iob->data), - &card->token.issuer_rm_w, QETH_MPC_TOKEN_LENGTH); - memcpy(QETH_IDX_ACT_FUNC_LEVEL(iob->data), - &card->info.func_level, sizeof(__u16)); - ccw_device_get_id(CARD_DDEV(card), &temp_devid); - memcpy(QETH_IDX_ACT_QDIO_DEV_CUA(iob->data), &temp_devid.devno, 2); - temp = (card->info.cula << 8) + card->info.unit_addr2; - memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(iob->data), &temp, 2); - - wait_event(card->wait_q, - atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0); - QETH_DBF_TEXT(SETUP, 6, "noirqpnd"); - spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); - rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw, - (addr_t) iob, 0, 0, QETH_TIMEOUT); - spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); - - if (rc) { - QETH_DBF_MESSAGE(2, "Error1 in activating channel. rc=%d\n", - rc); - QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); - atomic_set(&channel->irq_pending, 0); - qeth_release_buffer(channel, iob); - wake_up(&card->wait_q); - return rc; - } - rc = wait_event_interruptible_timeout(card->wait_q, - channel->state == CH_STATE_ACTIVATING, QETH_TIMEOUT); - if (rc == -ERESTARTSYS) - return rc; - if (channel->state != CH_STATE_ACTIVATING) { - dev_warn(&channel->ccwdev->dev, "The qeth device driver" - " failed to recover an error on the device\n"); - QETH_DBF_MESSAGE(2, "IDX activate timed out on channel %x\n", - CCW_DEVID(channel->ccwdev)); - QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME); - return -ETIME; - } - return qeth_idx_activate_get_answer(card, channel, reply_cb); } static int qeth_peer_func_level(int level) @@ -1897,112 +1772,21 @@ static int qeth_peer_func_level(int level) return level; } -static void qeth_idx_write_cb(struct qeth_card *card, - struct qeth_channel *channel, - struct qeth_cmd_buffer *iob) -{ - __u16 temp; - - QETH_DBF_TEXT(SETUP , 2, "idxwrcb"); - - if (channel->state == CH_STATE_DOWN) { - channel->state = CH_STATE_ACTIVATING; - goto out; - } - - if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) { - if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == QETH_IDX_ACT_ERR_EXCL) - dev_err(&channel->ccwdev->dev, - "The adapter is used exclusively by another " - "host\n"); - else - QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: negative reply\n", - CCW_DEVID(channel->ccwdev)); - goto out; - } - memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2); - if ((temp & ~0x0100) != qeth_peer_func_level(card->info.func_level)) { - QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: function level mismatch (sent: %#x, received: %#x)\n", - CCW_DEVID(channel->ccwdev), - card->info.func_level, temp); - goto out; - } - channel->state = CH_STATE_UP; -out: - qeth_release_buffer(channel, iob); -} - -static void qeth_idx_read_cb(struct qeth_card *card, - struct qeth_channel *channel, - struct qeth_cmd_buffer *iob) -{ - __u16 temp; - - QETH_DBF_TEXT(SETUP , 2, "idxrdcb"); - if (channel->state == CH_STATE_DOWN) { - channel->state = CH_STATE_ACTIVATING; - goto out; - } - - if (qeth_check_idx_response(card, iob->data)) - goto out; - - if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) { - switch (QETH_IDX_ACT_CAUSE_CODE(iob->data)) { - case QETH_IDX_ACT_ERR_EXCL: - dev_err(&channel->ccwdev->dev, - "The adapter is used exclusively by another " - "host\n"); - break; - case QETH_IDX_ACT_ERR_AUTH: - case QETH_IDX_ACT_ERR_AUTH_USER: - dev_err(&channel->ccwdev->dev, - "Setting the device online failed because of " - "insufficient authorization\n"); - break; - default: - QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: negative reply\n", - CCW_DEVID(channel->ccwdev)); - } - QETH_CARD_TEXT_(card, 2, "idxread%c", - QETH_IDX_ACT_CAUSE_CODE(iob->data)); - goto out; - } - - memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2); - if (temp != qeth_peer_func_level(card->info.func_level)) { - QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: function level mismatch (sent: %#x, received: %#x)\n", - CCW_DEVID(channel->ccwdev), - card->info.func_level, temp); - goto out; - } - memcpy(&card->token.issuer_rm_r, - QETH_IDX_ACT_ISSUER_RM_TOKEN(iob->data), - QETH_MPC_TOKEN_LENGTH); - memcpy(&card->info.mcl_level[0], - QETH_IDX_REPLY_LEVEL(iob->data), QETH_MCL_LENGTH); - channel->state = CH_STATE_UP; -out: - qeth_release_buffer(channel, iob); -} - -void qeth_prepare_control_data(struct qeth_card *card, int len, - struct qeth_cmd_buffer *iob) +static void qeth_mpc_finalize_cmd(struct qeth_card *card, + struct qeth_cmd_buffer *iob, + unsigned int length) { - qeth_setup_ccw(iob->channel->ccw, CCW_CMD_WRITE, len, iob->data); - iob->callback = qeth_release_buffer_cb; + qeth_idx_finalize_cmd(card, iob, length); - memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), - &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH); - card->seqno.trans_hdr++; memcpy(QETH_PDU_HEADER_SEQ_NO(iob->data), &card->seqno.pdu_hdr, QETH_SEQ_NO_LENGTH); card->seqno.pdu_hdr++; memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data), &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH); - QETH_DBF_HEX(CTRL, 2, iob->data, min(len, QETH_DBF_CTRL_LEN)); + + iob->reply->seqno = QETH_IDX_COMMAND_SEQNO; + iob->callback = qeth_release_buffer_cb; } -EXPORT_SYMBOL_GPL(qeth_prepare_control_data); /** * qeth_send_control_data() - send control command to the card @@ -2035,17 +1819,12 @@ static int qeth_send_control_data(struct qeth_card *card, int len, void *reply_param) { struct qeth_channel *channel = iob->channel; + long timeout = iob->timeout; int rc; struct qeth_reply *reply = NULL; - unsigned long timeout, event_timeout; - struct qeth_ipa_cmd *cmd = NULL; QETH_CARD_TEXT(card, 2, "sendctl"); - if (card->read_or_write_problem) { - qeth_release_buffer(channel, iob); - return -EIO; - } reply = qeth_alloc_reply(card); if (!reply) { qeth_release_buffer(channel, iob); @@ -2058,27 +1837,24 @@ static int qeth_send_control_data(struct qeth_card *card, int len, qeth_get_reply(reply); iob->reply = reply; - while (atomic_cmpxchg(&channel->irq_pending, 0, 1)) ; - - if (IS_IPA(iob->data)) { - cmd = __ipa_cmd(iob); - cmd->hdr.seqno = card->seqno.ipa++; - reply->seqno = cmd->hdr.seqno; - event_timeout = QETH_IPA_TIMEOUT; - } else { - reply->seqno = QETH_IDX_COMMAND_SEQNO; - event_timeout = QETH_TIMEOUT; + timeout = wait_event_interruptible_timeout(card->wait_q, + qeth_trylock_channel(channel), + timeout); + if (timeout <= 0) { + qeth_put_reply(reply); + qeth_release_buffer(channel, iob); + return (timeout == -ERESTARTSYS) ? -EINTR : -ETIME; } - qeth_prepare_control_data(card, len, iob); - qeth_enqueue_reply(card, reply); + iob->finalize(card, iob, len); + QETH_DBF_HEX(CTRL, 2, iob->data, min(len, QETH_DBF_CTRL_LEN)); - timeout = jiffies + event_timeout; + qeth_enqueue_reply(card, reply); QETH_CARD_TEXT(card, 6, "noirqpnd"); spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw, - (addr_t) iob, 0, 0, event_timeout); + (addr_t) iob, 0, 0, timeout); spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); if (rc) { QETH_DBF_MESSAGE(2, "qeth_send_control_data on device %x: ccw_device_start rc = %i\n", @@ -2092,30 +1868,211 @@ static int qeth_send_control_data(struct qeth_card *card, int len, return rc; } - /* we have only one long running ipassist, since we can ensure - process context of this command we can sleep */ - if (cmd && cmd->hdr.command == IPA_CMD_SETIP && - cmd->hdr.prot_version == QETH_PROT_IPV4) { - if (!wait_event_timeout(reply->wait_q, - atomic_read(&reply->received), event_timeout)) - goto time_err; - } else { - while (!atomic_read(&reply->received)) { - if (time_after(jiffies, timeout)) - goto time_err; - cpu_relax(); - } - } + timeout = wait_for_completion_interruptible_timeout(&reply->received, + timeout); + if (timeout <= 0) + rc = (timeout == -ERESTARTSYS) ? -EINTR : -ETIME; qeth_dequeue_reply(card, reply); - rc = reply->rc; + if (!rc) + rc = reply->rc; qeth_put_reply(reply); return rc; +} -time_err: - qeth_dequeue_reply(card, reply); - qeth_put_reply(reply); - return -ETIME; +static int qeth_idx_check_activate_response(struct qeth_card *card, + struct qeth_channel *channel, + struct qeth_cmd_buffer *iob) +{ + int rc; + + rc = qeth_check_idx_response(card, iob->data); + if (rc) + return rc; + + if (QETH_IS_IDX_ACT_POS_REPLY(iob->data)) + return 0; + + /* negative reply: */ + QETH_DBF_TEXT_(SETUP, 2, "idxneg%c", + QETH_IDX_ACT_CAUSE_CODE(iob->data)); + + switch (QETH_IDX_ACT_CAUSE_CODE(iob->data)) { + case QETH_IDX_ACT_ERR_EXCL: + dev_err(&channel->ccwdev->dev, + "The adapter is used exclusively by another host\n"); + return -EBUSY; + case QETH_IDX_ACT_ERR_AUTH: + case QETH_IDX_ACT_ERR_AUTH_USER: + dev_err(&channel->ccwdev->dev, + "Setting the device online failed because of insufficient authorization\n"); + return -EPERM; + default: + QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: negative reply\n", + CCW_DEVID(channel->ccwdev)); + return -EIO; + } +} + +static void qeth_idx_query_read_cb(struct qeth_card *card, + struct qeth_channel *channel, + struct qeth_cmd_buffer *iob) +{ + u16 peer_level; + int rc; + + QETH_DBF_TEXT(SETUP, 2, "idxrdcb"); + + rc = qeth_idx_check_activate_response(card, channel, iob); + if (rc) + goto out; + + memcpy(&peer_level, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2); + if (peer_level != qeth_peer_func_level(card->info.func_level)) { + QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: function level mismatch (sent: %#x, received: %#x)\n", + CCW_DEVID(channel->ccwdev), + card->info.func_level, peer_level); + rc = -EINVAL; + goto out; + } + + memcpy(&card->token.issuer_rm_r, + QETH_IDX_ACT_ISSUER_RM_TOKEN(iob->data), + QETH_MPC_TOKEN_LENGTH); + memcpy(&card->info.mcl_level[0], + QETH_IDX_REPLY_LEVEL(iob->data), QETH_MCL_LENGTH); + +out: + qeth_notify_reply(iob->reply, rc); + qeth_release_buffer(channel, iob); +} + +static void qeth_idx_query_write_cb(struct qeth_card *card, + struct qeth_channel *channel, + struct qeth_cmd_buffer *iob) +{ + u16 peer_level; + int rc; + + QETH_DBF_TEXT(SETUP, 2, "idxwrcb"); + + rc = qeth_idx_check_activate_response(card, channel, iob); + if (rc) + goto out; + + memcpy(&peer_level, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2); + if ((peer_level & ~0x0100) != + qeth_peer_func_level(card->info.func_level)) { + QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: function level mismatch (sent: %#x, received: %#x)\n", + CCW_DEVID(channel->ccwdev), + card->info.func_level, peer_level); + rc = -EINVAL; + } + +out: + qeth_notify_reply(iob->reply, rc); + qeth_release_buffer(channel, iob); +} + +static void qeth_idx_finalize_query_cmd(struct qeth_card *card, + struct qeth_cmd_buffer *iob, + unsigned int length) +{ + qeth_setup_ccw(iob->channel->ccw, CCW_CMD_READ, length, iob->data); +} + +static void qeth_idx_activate_cb(struct qeth_card *card, + struct qeth_channel *channel, + struct qeth_cmd_buffer *iob) +{ + qeth_notify_reply(iob->reply, 0); + qeth_release_buffer(channel, iob); +} + +static void qeth_idx_setup_activate_cmd(struct qeth_card *card, + struct qeth_cmd_buffer *iob) +{ + u16 addr = (card->info.cula << 8) + card->info.unit_addr2; + u8 port = ((u8)card->dev->dev_port) | 0x80; + struct ccw_dev_id dev_id; + + ccw_device_get_id(CARD_DDEV(card), &dev_id); + iob->finalize = qeth_idx_finalize_cmd; + iob->callback = qeth_idx_activate_cb; + + memcpy(QETH_IDX_ACT_PNO(iob->data), &port, 1); + memcpy(QETH_IDX_ACT_ISSUER_RM_TOKEN(iob->data), + &card->token.issuer_rm_w, QETH_MPC_TOKEN_LENGTH); + memcpy(QETH_IDX_ACT_FUNC_LEVEL(iob->data), + &card->info.func_level, 2); + memcpy(QETH_IDX_ACT_QDIO_DEV_CUA(iob->data), &dev_id.devno, 2); + memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(iob->data), &addr, 2); +} + +static int qeth_idx_activate_read_channel(struct qeth_card *card) +{ + struct qeth_channel *channel = &card->read; + struct qeth_cmd_buffer *iob; + int rc; + + QETH_DBF_TEXT(SETUP, 2, "idxread"); + + iob = qeth_get_buffer(channel); + if (!iob) + return -ENOMEM; + + memcpy(iob->data, IDX_ACTIVATE_READ, IDX_ACTIVATE_SIZE); + qeth_idx_setup_activate_cmd(card, iob); + + rc = qeth_send_control_data(card, IDX_ACTIVATE_SIZE, iob, NULL, NULL); + if (rc) + return rc; + + iob = qeth_get_buffer(channel); + if (!iob) + return -ENOMEM; + + iob->finalize = qeth_idx_finalize_query_cmd; + iob->callback = qeth_idx_query_read_cb; + rc = qeth_send_control_data(card, QETH_BUFSIZE, iob, NULL, NULL); + if (rc) + return rc; + + channel->state = CH_STATE_UP; + return 0; +} + +static int qeth_idx_activate_write_channel(struct qeth_card *card) +{ + struct qeth_channel *channel = &card->write; + struct qeth_cmd_buffer *iob; + int rc; + + QETH_DBF_TEXT(SETUP, 2, "idxwrite"); + + iob = qeth_get_buffer(channel); + if (!iob) + return -ENOMEM; + + memcpy(iob->data, IDX_ACTIVATE_WRITE, IDX_ACTIVATE_SIZE); + qeth_idx_setup_activate_cmd(card, iob); + + rc = qeth_send_control_data(card, IDX_ACTIVATE_SIZE, iob, NULL, NULL); + if (rc) + return rc; + + iob = qeth_get_buffer(channel); + if (!iob) + return -ENOMEM; + + iob->finalize = qeth_idx_finalize_query_cmd; + iob->callback = qeth_idx_query_write_cb; + rc = qeth_send_control_data(card, QETH_BUFSIZE, iob, NULL, NULL); + if (rc) + return rc; + + channel->state = CH_STATE_UP; + return 0; } static int qeth_cm_enable_cb(struct qeth_card *card, struct qeth_reply *reply, @@ -2140,7 +2097,9 @@ static int qeth_cm_enable(struct qeth_card *card) QETH_DBF_TEXT(SETUP, 2, "cmenable"); iob = qeth_wait_for_buffer(&card->write); + iob->finalize = qeth_mpc_finalize_cmd; memcpy(iob->data, CM_ENABLE, CM_ENABLE_SIZE); + memcpy(QETH_CM_ENABLE_ISSUER_RM_TOKEN(iob->data), &card->token.issuer_rm_r, QETH_MPC_TOKEN_LENGTH); memcpy(QETH_CM_ENABLE_FILTER_TOKEN(iob->data), @@ -2173,7 +2132,9 @@ static int qeth_cm_setup(struct qeth_card *card) QETH_DBF_TEXT(SETUP, 2, "cmsetup"); iob = qeth_wait_for_buffer(&card->write); + iob->finalize = qeth_mpc_finalize_cmd; memcpy(iob->data, CM_SETUP, CM_SETUP_SIZE); + memcpy(QETH_CM_SETUP_DEST_ADDR(iob->data), &card->token.issuer_rm_r, QETH_MPC_TOKEN_LENGTH); memcpy(QETH_CM_SETUP_CONNECTION_TOKEN(iob->data), @@ -2206,7 +2167,7 @@ static int qeth_update_max_mtu(struct qeth_card *card, unsigned int max_mtu) /* adjust RX buffer size to new max MTU: */ card->qdio.in_buf_size = max_mtu + 2 * PAGE_SIZE; if (dev->max_mtu && dev->max_mtu != max_mtu) - qeth_free_qdio_buffers(card); + qeth_free_qdio_queues(card); } else { if (dev->mtu) new_mtu = dev->mtu; @@ -2253,7 +2214,7 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply, memcpy(&card->token.ulp_filter_r, QETH_ULP_ENABLE_RESP_FILTER_TOKEN(iob->data), QETH_MPC_TOKEN_LENGTH); - if (card->info.type == QETH_CARD_TYPE_IQD) { + if (IS_IQD(card)) { memcpy(&framesize, QETH_ULP_ENABLE_RESP_MAX_MTU(iob->data), 2); mtu = qeth_get_mtu_outof_framesize(framesize); } else { @@ -2290,6 +2251,7 @@ static int qeth_ulp_enable(struct qeth_card *card) QETH_DBF_TEXT(SETUP, 2, "ulpenabl"); iob = qeth_wait_for_buffer(&card->write); + iob->finalize = qeth_mpc_finalize_cmd; memcpy(iob->data, ULP_ENABLE, ULP_ENABLE_SIZE); *(QETH_ULP_ENABLE_LINKNUM(iob->data)) = (u8) card->dev->dev_port; @@ -2336,6 +2298,7 @@ static int qeth_ulp_setup(struct qeth_card *card) QETH_DBF_TEXT(SETUP, 2, "ulpsetup"); iob = qeth_wait_for_buffer(&card->write); + iob->finalize = qeth_mpc_finalize_cmd; memcpy(iob->data, ULP_SETUP, ULP_SETUP_SIZE); memcpy(QETH_ULP_SETUP_DEST_ADDR(iob->data), @@ -2377,12 +2340,12 @@ static void qeth_free_output_queue(struct qeth_qdio_out_q *q) if (!q) return; - qeth_clear_outq_buffers(q, 1); + qeth_drain_output_queue(q, true); qdio_free_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q); kfree(q); } -static struct qeth_qdio_out_q *qeth_alloc_qdio_out_buf(void) +static struct qeth_qdio_out_q *qeth_alloc_output_queue(void) { struct qeth_qdio_out_q *q = kzalloc(sizeof(*q), GFP_KERNEL); @@ -2396,7 +2359,7 @@ static struct qeth_qdio_out_q *qeth_alloc_qdio_out_buf(void) return q; } -static int qeth_alloc_qdio_buffers(struct qeth_card *card) +static int qeth_alloc_qdio_queues(struct qeth_card *card) { int i, j; @@ -2417,11 +2380,12 @@ static int qeth_alloc_qdio_buffers(struct qeth_card *card) /* outbound */ for (i = 0; i < card->qdio.no_out_queues; ++i) { - card->qdio.out_qs[i] = qeth_alloc_qdio_out_buf(); + card->qdio.out_qs[i] = qeth_alloc_output_queue(); if (!card->qdio.out_qs[i]) goto out_freeoutq; QETH_DBF_TEXT_(SETUP, 2, "outq %i", i); QETH_DBF_HEX(SETUP, 2, &card->qdio.out_qs[i], sizeof(void *)); + card->qdio.out_qs[i]->card = card; card->qdio.out_qs[i]->queue_no = i; /* give outbound qeth_qdio_buffers their qdio_buffers */ for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { @@ -2458,7 +2422,7 @@ out_nomem: return -ENOMEM; } -static void qeth_free_qdio_buffers(struct qeth_card *card) +static void qeth_free_qdio_queues(struct qeth_card *card) { int i, j; @@ -2523,6 +2487,7 @@ static int qeth_dm_act(struct qeth_card *card) QETH_DBF_TEXT(SETUP, 2, "dmact"); iob = qeth_wait_for_buffer(&card->write); + iob->finalize = qeth_mpc_finalize_cmd; memcpy(iob->data, DM_ACT, DM_ACT_SIZE); memcpy(QETH_DM_ACT_DEST_ADDR(iob->data), @@ -2564,7 +2529,7 @@ static int qeth_mpc_initialize(struct qeth_card *card) QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); goto out_qdio; } - rc = qeth_alloc_qdio_buffers(card); + rc = qeth_alloc_qdio_queues(card); if (rc) { QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); goto out_qdio; @@ -2572,7 +2537,7 @@ static int qeth_mpc_initialize(struct qeth_card *card) rc = qeth_qdio_establish(card); if (rc) { QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); - qeth_free_qdio_buffers(card); + qeth_free_qdio_queues(card); goto out_qdio; } rc = qeth_qdio_activate(card); @@ -2588,7 +2553,7 @@ static int qeth_mpc_initialize(struct qeth_card *card) return 0; out_qdio: - qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD); + qeth_qdio_clear_card(card, !IS_IQD(card)); qdio_free(CARD_DDEV(card)); return rc; } @@ -2611,8 +2576,7 @@ void qeth_print_status_message(struct qeth_card *card) } /* fallthrough */ case QETH_CARD_TYPE_IQD: - if ((card->info.guestlan) || - (card->info.mcl_level[0] & 0x80)) { + if (IS_VM_NIC(card) || (card->info.mcl_level[0] & 0x80)) { card->info.mcl_level[0] = (char) _ebcasc[(__u8) card->info.mcl_level[0]]; card->info.mcl_level[1] = (char) _ebcasc[(__u8) @@ -2733,7 +2697,7 @@ static int qeth_init_input_buffer(struct qeth_card *card, int qeth_init_qdio_queues(struct qeth_card *card) { - int i, j; + unsigned int i; int rc; QETH_DBF_TEXT(SETUP, 2, "initqdqs"); @@ -2762,19 +2726,15 @@ int qeth_init_qdio_queues(struct qeth_card *card) /* outbound queue */ for (i = 0; i < card->qdio.no_out_queues; ++i) { - qdio_reset_buffers(card->qdio.out_qs[i]->qdio_bufs, - QDIO_MAX_BUFFERS_PER_Q); - for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { - qeth_clear_output_buffer(card->qdio.out_qs[i], - card->qdio.out_qs[i]->bufs[j]); - } - card->qdio.out_qs[i]->card = card; - card->qdio.out_qs[i]->next_buf_to_fill = 0; - card->qdio.out_qs[i]->do_pack = 0; - atomic_set(&card->qdio.out_qs[i]->used_buffers, 0); - atomic_set(&card->qdio.out_qs[i]->set_pci_flags_count, 0); - atomic_set(&card->qdio.out_qs[i]->state, - QETH_OUT_Q_UNLOCKED); + struct qeth_qdio_out_q *queue = card->qdio.out_qs[i]; + + qdio_reset_buffers(queue->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q); + queue->max_elements = QETH_MAX_BUFFER_ELEMENTS(card); + queue->next_buf_to_fill = 0; + queue->do_pack = 0; + atomic_set(&queue->used_buffers, 0); + atomic_set(&queue->set_pci_flags_count, 0); + atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); } return 0; } @@ -2805,12 +2765,26 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card, cmd->hdr.prot_version = prot; } +static void qeth_ipa_finalize_cmd(struct qeth_card *card, + struct qeth_cmd_buffer *iob, + unsigned int length) +{ + qeth_mpc_finalize_cmd(card, iob, length); + + /* override with IPA-specific values: */ + __ipa_cmd(iob)->hdr.seqno = card->seqno.ipa; + iob->reply->seqno = card->seqno.ipa++; +} + void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, u16 cmd_length) { u16 total_length = IPA_PDU_HEADER_SIZE + cmd_length; u8 prot_type = qeth_mpc_select_prot_type(card); + iob->finalize = qeth_ipa_finalize_cmd; + iob->timeout = QETH_IPA_TIMEOUT; + memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &total_length, 2); memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data), &prot_type, 1); @@ -2866,6 +2840,11 @@ int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, QETH_CARD_TEXT(card, 4, "sendipa"); + if (card->read_or_write_problem) { + qeth_release_buffer(iob->channel, iob); + return -EIO; + } + if (reply_cb == NULL) reply_cb = qeth_send_ipa_cmd_cb; memcpy(&length, QETH_IPA_PDU_LEN_TOTAL(iob->data), 2); @@ -3251,7 +3230,7 @@ static void qeth_handle_send_error(struct qeth_card *card, int sbalf15 = buffer->buffer->element[15].sflags; QETH_CARD_TEXT(card, 6, "hdsnderr"); - if (card->info.type == QETH_CARD_TYPE_IQD) { + if (IS_IQD(card)) { if (sbalf15 == 0) { qdio_err = 0; } else { @@ -3348,7 +3327,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, if (queue->bufstates) queue->bufstates[bidx].user = buf; - if (queue->card->info.type == QETH_CARD_TYPE_IQD) + if (IS_IQD(queue->card)) continue; if (!queue->do_pack) { @@ -3378,11 +3357,9 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, } QETH_TXQ_STAT_ADD(queue, bufs, count); - netif_trans_update(queue->card->dev); qdio_flags = QDIO_FLAG_SYNC_OUTPUT; if (atomic_read(&queue->set_pci_flags_count)) qdio_flags |= QDIO_FLAG_PCI_OUT; - atomic_add(count, &queue->used_buffers); rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags, queue->queue_no, index, count); if (rc) { @@ -3422,7 +3399,6 @@ static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) * do_send_packet. So, we check if there is a * packing buffer to be flushed here. */ - netif_stop_queue(queue->card->dev); index = queue->next_buf_to_fill; q_was_packing = queue->do_pack; /* queue->do_pack may change */ @@ -3467,7 +3443,7 @@ int qeth_configure_cq(struct qeth_card *card, enum qeth_cq cq) goto out; } - qeth_free_qdio_buffers(card); + qeth_free_qdio_queues(card); card->options.cq = cq; rc = 0; } @@ -3493,7 +3469,7 @@ static void qeth_qdio_cq_handler(struct qeth_card *card, unsigned int qdio_err, QETH_CARD_TEXT_(card, 5, "qcqherr%d", qdio_err); if (qdio_err) { - netif_stop_queue(card->dev); + netif_tx_stop_all_queues(card->dev); qeth_schedule_recovery(card); return; } @@ -3549,12 +3525,14 @@ static void qeth_qdio_output_handler(struct ccw_device *ccwdev, struct qeth_card *card = (struct qeth_card *) card_ptr; struct qeth_qdio_out_q *queue = card->qdio.out_qs[__queue]; struct qeth_qdio_out_buffer *buffer; + struct net_device *dev = card->dev; + struct netdev_queue *txq; int i; QETH_CARD_TEXT(card, 6, "qdouhdl"); if (qdio_error & QDIO_ERROR_FATAL) { QETH_CARD_TEXT(card, 2, "achkcond"); - netif_stop_queue(card->dev); + netif_tx_stop_all_queues(dev); qeth_schedule_recovery(card); return; } @@ -3580,7 +3558,7 @@ static void qeth_qdio_output_handler(struct ccw_device *ccwdev, /* prepare the queue slot for re-use: */ qeth_scrub_qdio_buffer(buffer->buffer, - QETH_MAX_BUFFER_ELEMENTS(card)); + queue->max_elements); if (qeth_init_qdio_out_buf(queue, bidx)) { QETH_CARD_TEXT(card, 2, "outofbuf"); qeth_schedule_recovery(card); @@ -3600,33 +3578,32 @@ static void qeth_qdio_output_handler(struct ccw_device *ccwdev, } atomic_sub(count, &queue->used_buffers); /* check if we need to do something on this outbound queue */ - if (card->info.type != QETH_CARD_TYPE_IQD) + if (!IS_IQD(card)) qeth_check_outbound_queue(queue); - netif_wake_queue(queue->card->dev); -} - -/* We cannot use outbound queue 3 for unicast packets on HiperSockets */ -static inline int qeth_cut_iqd_prio(struct qeth_card *card, int queue_num) -{ - if ((card->info.type == QETH_CARD_TYPE_IQD) && (queue_num == 3)) - return 2; - return queue_num; + if (IS_IQD(card)) + __queue = qeth_iqd_translate_txq(dev, __queue); + txq = netdev_get_tx_queue(dev, __queue); + /* xmit may have observed the full-condition, but not yet stopped the + * txq. In which case the code below won't trigger. So before returning, + * xmit will re-check the txq's fill level and wake it up if needed. + */ + if (netif_tx_queue_stopped(txq) && !qeth_out_queue_is_full(queue)) + netif_tx_wake_queue(txq); } /** * Note: Function assumes that we have 4 outbound queues. */ -int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb, - int ipv) +int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb) { - __be16 *tci; + struct vlan_ethhdr *veth = vlan_eth_hdr(skb); u8 tos; switch (card->qdio.do_prio_queueing) { case QETH_PRIO_Q_ING_TOS: case QETH_PRIO_Q_ING_PREC: - switch (ipv) { + switch (qeth_get_ip_version(skb)) { case 4: tos = ipv4_get_dsfield(ip_hdr(skb)); break; @@ -3637,9 +3614,9 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb, return card->qdio.default_out_queue; } if (card->qdio.do_prio_queueing == QETH_PRIO_Q_ING_PREC) - return qeth_cut_iqd_prio(card, ~tos >> 6 & 3); + return ~tos >> 6 & 3; if (tos & IPTOS_MINCOST) - return qeth_cut_iqd_prio(card, 3); + return 3; if (tos & IPTOS_RELIABILITY) return 2; if (tos & IPTOS_THROUGHPUT) @@ -3650,12 +3627,11 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb, case QETH_PRIO_Q_ING_SKB: if (skb->priority > 5) return 0; - return qeth_cut_iqd_prio(card, ~skb->priority >> 1 & 3); + return ~skb->priority >> 1 & 3; case QETH_PRIO_Q_ING_VLAN: - tci = &((struct ethhdr *)skb->data)->h_proto; - if (be16_to_cpu(*tci) == ETH_P_8021Q) - return qeth_cut_iqd_prio(card, - ~be16_to_cpu(*(tci + 1)) >> (VLAN_PRIO_SHIFT + 1) & 3); + if (veth->h_vlan_proto == htons(ETH_P_8021Q)) + return ~ntohs(veth->h_vlan_TCI) >> + (VLAN_PRIO_SHIFT + 1) & 3; break; default: break; @@ -3729,8 +3705,8 @@ static int qeth_add_hw_header(struct qeth_qdio_out_q *queue, unsigned int hdr_len, unsigned int proto_len, unsigned int *elements) { - const unsigned int max_elements = QETH_MAX_BUFFER_ELEMENTS(queue->card); const unsigned int contiguous = proto_len ? proto_len : 1; + const unsigned int max_elements = queue->max_elements; unsigned int __elements; addr_t start, end; bool push_ok; @@ -3867,11 +3843,13 @@ static void __qeth_fill_buffer(struct sk_buff *skb, * from qeth_core_header_cache. * @offset: when mapping the skb, start at skb->data + offset * @hd_len: if > 0, build a dedicated header element of this size + * flush: Prepare the buffer to be flushed, regardless of its fill level. */ static int qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf, struct sk_buff *skb, struct qeth_hdr *hdr, - unsigned int offset, unsigned int hd_len) + unsigned int offset, unsigned int hd_len, + bool flush) { struct qdio_buffer *buffer = buf->buffer; bool is_first_elem = true; @@ -3900,8 +3878,8 @@ static int qeth_fill_buffer(struct qeth_qdio_out_q *queue, QETH_TXQ_STAT_INC(queue, skbs_pack); /* If the buffer still has free elements, keep using it. */ - if (buf->next_element_to_fill < - QETH_MAX_BUFFER_ELEMENTS(queue->card)) + if (!flush && + buf->next_element_to_fill < queue->max_elements) return 0; } @@ -3918,15 +3896,31 @@ static int qeth_do_send_packet_fast(struct qeth_qdio_out_q *queue, { int index = queue->next_buf_to_fill; struct qeth_qdio_out_buffer *buffer = queue->bufs[index]; + struct netdev_queue *txq; + bool stopped = false; - /* - * check if buffer is empty to make sure that we do not 'overtake' - * ourselves and try to fill a buffer that is already primed + /* Just a sanity check, the wake/stop logic should ensure that we always + * get a free buffer. */ if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) return -EBUSY; - qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len); + + txq = netdev_get_tx_queue(queue->card->dev, skb_get_queue_mapping(skb)); + + if (atomic_inc_return(&queue->used_buffers) >= QDIO_MAX_BUFFERS_PER_Q) { + /* If a TX completion happens right _here_ and misses to wake + * the txq, then our re-check below will catch the race. + */ + QETH_TXQ_STAT_INC(queue, stopped); + netif_tx_stop_queue(txq); + stopped = true; + } + + qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len, stopped); qeth_flush_buffers(queue, index, 1); + + if (stopped && !qeth_out_queue_is_full(queue)) + netif_tx_start_queue(txq); return 0; } @@ -3936,6 +3930,8 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, int elements_needed) { struct qeth_qdio_out_buffer *buffer; + struct netdev_queue *txq; + bool stopped = false; int start_index; int flush_count = 0; int do_pack = 0; @@ -3947,21 +3943,24 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED); start_index = queue->next_buf_to_fill; buffer = queue->bufs[queue->next_buf_to_fill]; - /* - * check if buffer is empty to make sure that we do not 'overtake' - * ourselves and try to fill a buffer that is already primed + + /* Just a sanity check, the wake/stop logic should ensure that we always + * get a free buffer. */ if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) { atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); return -EBUSY; } + + txq = netdev_get_tx_queue(card->dev, skb_get_queue_mapping(skb)); + /* check if we need to switch packing state of this queue */ qeth_switch_to_packing_if_needed(queue); if (queue->do_pack) { do_pack = 1; /* does packet fit in current buffer? */ - if ((QETH_MAX_BUFFER_ELEMENTS(card) - - buffer->next_element_to_fill) < elements_needed) { + if (buffer->next_element_to_fill + elements_needed > + queue->max_elements) { /* ... no -> set state PRIMED */ atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); flush_count++; @@ -3969,8 +3968,8 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; buffer = queue->bufs[queue->next_buf_to_fill]; - /* we did a step forward, so check buffer state - * again */ + + /* We stepped forward, so sanity-check again: */ if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) { qeth_flush_buffers(queue, start_index, @@ -3983,8 +3982,18 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, } } - flush_count += qeth_fill_buffer(queue, buffer, skb, hdr, offset, - hd_len); + if (buffer->next_element_to_fill == 0 && + atomic_inc_return(&queue->used_buffers) >= QDIO_MAX_BUFFERS_PER_Q) { + /* If a TX completion happens right _here_ and misses to wake + * the txq, then our re-check below will catch the race. + */ + QETH_TXQ_STAT_INC(queue, stopped); + netif_tx_stop_queue(txq); + stopped = true; + } + + flush_count += qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len, + stopped); if (flush_count) qeth_flush_buffers(queue, start_index, flush_count); else if (!atomic_read(&queue->set_pci_flags_count)) @@ -4015,6 +4024,8 @@ out: if (do_pack) QETH_TXQ_STAT_ADD(queue, bufs_pack, flush_count); + if (stopped && !qeth_out_queue_is_full(queue)) + netif_tx_start_queue(txq); return rc; } EXPORT_SYMBOL_GPL(qeth_do_send_packet); @@ -4101,9 +4112,6 @@ int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, } 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); } return rc; } @@ -4321,9 +4329,8 @@ int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback) QETH_CARD_TEXT(card, 4, "setactlo"); - if ((card->info.type == QETH_CARD_TYPE_OSD || - card->info.type == QETH_CARD_TYPE_OSX) && - qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) { + if ((IS_OSD(card) || IS_OSX(card)) && + qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) { rc = qeth_setadpparms_set_access_ctrl(card, card->options.isolation, fallback); if (rc) { @@ -4348,7 +4355,6 @@ void qeth_tx_timeout(struct net_device *dev) card = dev->ml_priv; QETH_CARD_TEXT(card, 4, "txtimeo"); - QETH_CARD_STAT_INC(card, tx_errors); qeth_schedule_recovery(card); } EXPORT_SYMBOL_GPL(qeth_tx_timeout); @@ -4489,7 +4495,7 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata) QETH_CARD_TEXT(card, 3, "snmpcmd"); - if (card->info.guestlan) + if (IS_VM_NIC(card)) return -EOPNOTSUPP; if ((!qeth_adp_supported(card, IPA_SETADP_SET_SNMP_CONTROL)) && @@ -4732,14 +4738,6 @@ out: } EXPORT_SYMBOL_GPL(qeth_vm_request_mac); -static int qeth_get_qdio_q_format(struct qeth_card *card) -{ - if (card->info.type == QETH_CARD_TYPE_IQD) - return QDIO_IQDIO_QFMT; - else - return QDIO_QETH_QFMT; -} - static void qeth_determine_capabilities(struct qeth_card *card) { int rc; @@ -4878,7 +4876,8 @@ static int qeth_qdio_establish(struct qeth_card *card) memset(&init_data, 0, sizeof(struct qdio_initialize)); init_data.cdev = CARD_DDEV(card); - init_data.q_format = qeth_get_qdio_q_format(card); + init_data.q_format = IS_IQD(card) ? QDIO_IQDIO_QFMT : + QDIO_QETH_QFMT; init_data.qib_param_field_format = 0; init_data.qib_param_field = qib_param_field; init_data.no_input_qs = card->qdio.no_in_queues; @@ -4890,8 +4889,7 @@ static int qeth_qdio_establish(struct qeth_card *card) init_data.input_sbal_addr_array = in_sbal_ptrs; init_data.output_sbal_addr_array = out_sbal_ptrs; init_data.output_sbal_state_array = card->qdio.out_bufstates; - init_data.scan_threshold = - (card->info.type == QETH_CARD_TYPE_IQD) ? 1 : 32; + init_data.scan_threshold = IS_IQD(card) ? 1 : 32; if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED, QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) { @@ -4937,7 +4935,7 @@ static void qeth_core_free_card(struct qeth_card *card) qeth_clean_channel(&card->write); qeth_clean_channel(&card->data); destroy_workqueue(card->event_wq); - qeth_free_qdio_buffers(card); + qeth_free_qdio_queues(card); unregister_service_level(&card->qeth_service_level); dev_set_drvdata(&card->gdev->dev, NULL); kfree(card); @@ -4986,12 +4984,14 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok) QETH_DBF_TEXT(SETUP, 2, "hrdsetup"); atomic_set(&card->force_alloc_skb, 0); - qeth_update_from_chp_desc(card); + rc = qeth_update_from_chp_desc(card); + if (rc) + return rc; retry: if (retries < 3) QETH_DBF_MESSAGE(2, "Retrying to do IDX activates on device %x.\n", CARD_DEVID(card)); - rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD); + rc = qeth_qdio_clear_card(card, !IS_IQD(card)); ccw_device_set_offline(CARD_DDEV(card)); ccw_device_set_offline(CARD_WDEV(card)); ccw_device_set_offline(CARD_RDEV(card)); @@ -5019,8 +5019,9 @@ retriable: qeth_determine_capabilities(card); qeth_init_tokens(card); qeth_init_func_level(card); - rc = qeth_idx_activate_channel(card, &card->read, qeth_idx_read_cb); - if (rc == -ERESTARTSYS) { + + rc = qeth_idx_activate_read_channel(card); + if (rc == -EINTR) { QETH_DBF_TEXT(SETUP, 2, "break2"); return rc; } else if (rc) { @@ -5030,8 +5031,9 @@ retriable: else goto retry; } - rc = qeth_idx_activate_channel(card, &card->write, qeth_idx_write_cb); - if (rc == -ERESTARTSYS) { + + rc = qeth_idx_activate_write_channel(card); + if (rc == -EINTR) { QETH_DBF_TEXT(SETUP, 2, "break3"); return rc; } else if (rc) { @@ -5171,7 +5173,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, return NULL; if (((skb_len >= card->options.rx_sg_cb) && - (!(card->info.type == QETH_CARD_TYPE_OSN)) && + !IS_OSN(card) && (!atomic_read(&card->force_alloc_skb))) || (card->options.cq == QETH_CQ_ENABLED)) use_rx_sg = 1; @@ -5562,13 +5564,17 @@ static struct net_device *qeth_alloc_netdev(struct qeth_card *card) switch (card->info.type) { case QETH_CARD_TYPE_IQD: - dev = alloc_netdev(0, "hsi%d", NET_NAME_UNKNOWN, ether_setup); + dev = alloc_netdev_mqs(0, "hsi%d", NET_NAME_UNKNOWN, + ether_setup, QETH_MAX_QUEUES, 1); + break; + case QETH_CARD_TYPE_OSM: + dev = alloc_etherdev(0); break; case QETH_CARD_TYPE_OSN: dev = alloc_netdev(0, "osn%d", NET_NAME_UNKNOWN, ether_setup); break; default: - dev = alloc_etherdev(0); + dev = alloc_etherdev_mqs(0, QETH_MAX_QUEUES, 1); } if (!dev) @@ -5590,8 +5596,10 @@ static struct net_device *qeth_alloc_netdev(struct qeth_card *card) dev->priv_flags &= ~IFF_TX_SKB_SHARING; dev->hw_features |= NETIF_F_SG; dev->vlan_features |= NETIF_F_SG; - if (IS_IQD(card)) + if (IS_IQD(card)) { + netif_set_real_num_tx_queues(dev, QETH_IQD_MIN_TXQ); dev->features |= NETIF_F_SG; + } } return dev; @@ -5641,14 +5649,16 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) } qeth_setup_card(card); - qeth_update_from_chp_desc(card); - card->dev = qeth_alloc_netdev(card); if (!card->dev) { rc = -ENOMEM; goto err_card; } + card->qdio.no_out_queues = card->dev->num_tx_queues; + rc = qeth_update_from_chp_desc(card); + if (rc) + goto err_chp_desc; qeth_determine_capabilities(card); enforced_disc = qeth_enforce_discipline(card); switch (enforced_disc) { @@ -5661,9 +5671,8 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) if (rc) goto err_load; - gdev->dev.type = (card->info.type != QETH_CARD_TYPE_OSN) - ? card->discipline->devtype - : &qeth_osn_devtype; + gdev->dev.type = IS_OSN(card) ? &qeth_osn_devtype : + card->discipline->devtype; rc = card->discipline->setup(card->gdev); if (rc) goto err_disc; @@ -5675,6 +5684,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) err_disc: qeth_core_free_discipline(card); err_load: +err_chp_desc: free_netdev(card->dev); err_card: qeth_core_free_card(card); @@ -5706,10 +5716,8 @@ static int qeth_core_set_online(struct ccwgroup_device *gdev) enum qeth_discipline_id def_discipline; if (!card->discipline) { - if (card->info.type == QETH_CARD_TYPE_IQD) - def_discipline = QETH_DISCIPLINE_LAYER3; - else - def_discipline = QETH_DISCIPLINE_LAYER2; + def_discipline = IS_IQD(card) ? QETH_DISCIPLINE_LAYER3 : + QETH_DISCIPLINE_LAYER2; rc = qeth_core_load_discipline(card, def_discipline); if (rc) goto err; @@ -5737,7 +5745,7 @@ static void qeth_core_shutdown(struct ccwgroup_device *gdev) if ((gdev->state == CCWGROUP_ONLINE) && card->info.hwtrap) qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); qeth_qdio_clear_card(card, 0); - qeth_clear_qdio_buffers(card); + qeth_drain_output_queues(card); qdio_free(CARD_DDEV(card)); } @@ -5837,13 +5845,10 @@ int qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) rc = qeth_snmp_command(card, rq->ifr_ifru.ifru_data); break; case SIOC_QETH_GET_CARD_TYPE: - if ((card->info.type == QETH_CARD_TYPE_OSD || - card->info.type == QETH_CARD_TYPE_OSM || - card->info.type == QETH_CARD_TYPE_OSX) && - !card->info.guestlan) + if ((IS_OSD(card) || IS_OSM(card) || IS_OSX(card)) && + !IS_VM_NIC(card)) return 1; - else - return 0; + return 0; case SIOCGMIIPHY: mii_data = if_mii(rq); mii_data->phy_id = 0; @@ -6193,7 +6198,6 @@ void qeth_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) stats->rx_errors = card->stats.rx_errors; stats->rx_dropped = card->stats.rx_dropped; stats->multicast = card->stats.rx_multicast; - stats->tx_errors = card->stats.tx_errors; for (i = 0; i < card->qdio.no_out_queues; i++) { queue = card->qdio.out_qs[i]; @@ -6206,6 +6210,15 @@ void qeth_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) } EXPORT_SYMBOL_GPL(qeth_get_stats64); +u16 qeth_iqd_select_queue(struct net_device *dev, struct sk_buff *skb, + u8 cast_type, struct net_device *sb_dev) +{ + if (cast_type != RTN_UNICAST) + return QETH_IQD_MCAST_TXQ; + return QETH_IQD_MIN_UCAST_TXQ; +} +EXPORT_SYMBOL_GPL(qeth_iqd_select_queue); + int qeth_open(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; @@ -6216,7 +6229,7 @@ int qeth_open(struct net_device *dev) return -EIO; card->data.state = CH_STATE_UP; - netif_start_queue(dev); + netif_tx_start_all_queues(dev); napi_enable(&card->napi); local_bh_disable(); diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index f8c5d4a9be13..f5237b7c14c4 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -82,7 +82,7 @@ enum qeth_card_types { #define IS_OSM(card) ((card)->info.type == QETH_CARD_TYPE_OSM) #define IS_OSN(card) ((card)->info.type == QETH_CARD_TYPE_OSN) #define IS_OSX(card) ((card)->info.type == QETH_CARD_TYPE_OSX) -#define IS_VM_NIC(card) ((card)->info.guestlan) +#define IS_VM_NIC(card) ((card)->info.is_vm_nic) #define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18 /* only the first two bytes are looked at in qeth_get_cardname_short */ diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 56deeb6f7bc0..9f392497d570 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -198,6 +198,9 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev, if (!card) return -EINVAL; + if (IS_IQD(card)) + return -EOPNOTSUPP; + mutex_lock(&card->conf_mutex); if (card->state != CARD_STATE_DOWN) { rc = -EPERM; @@ -239,10 +242,6 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev, card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; card->qdio.default_out_queue = 2; } else if (sysfs_streq(buf, "no_prio_queueing:3")) { - if (card->info.type == QETH_CARD_TYPE_IQD) { - rc = -EPERM; - goto out; - } card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; card->qdio.default_out_queue = 3; } else if (sysfs_streq(buf, "no_prio_queueing")) { @@ -480,8 +479,7 @@ static ssize_t qeth_dev_isolation_store(struct device *dev, return -EINVAL; mutex_lock(&card->conf_mutex); - if (card->info.type != QETH_CARD_TYPE_OSD && - card->info.type != QETH_CARD_TYPE_OSX) { + if (!IS_OSD(card) && !IS_OSX(card)) { rc = -EOPNOTSUPP; dev_err(&card->gdev->dev, "Adapter does not " "support QDIO data connection isolation\n"); diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index 93a53fed4cf8..4166eb29f0bd 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -38,6 +38,7 @@ static const struct qeth_stats txq_stats[] = { QETH_TXQ_STAT("linearized+error skbs", skbs_linearized_fail), QETH_TXQ_STAT("TSO bytes", tso_bytes), QETH_TXQ_STAT("Packing mode switches", packing_mode_switch), + QETH_TXQ_STAT("Queue stopped", stopped), }; static const struct qeth_stats card_stats[] = { @@ -154,6 +155,21 @@ static void qeth_get_drvinfo(struct net_device *dev, CARD_RDEV_ID(card), CARD_WDEV_ID(card), CARD_DDEV_ID(card)); } +static void qeth_get_channels(struct net_device *dev, + struct ethtool_channels *channels) +{ + struct qeth_card *card = dev->ml_priv; + + channels->max_rx = dev->num_rx_queues; + channels->max_tx = card->qdio.no_out_queues; + channels->max_other = 0; + channels->max_combined = 0; + channels->rx_count = dev->real_num_rx_queues; + channels->tx_count = dev->real_num_tx_queues; + channels->other_count = 0; + channels->combined_count = 0; +} + /* Helper function to fill 'advertising' and 'supported' which are the same. */ /* Autoneg and full-duplex are supported and advertised unconditionally. */ /* Always advertise and support all speeds up to specified, and only one */ @@ -359,6 +375,7 @@ const struct ethtool_ops qeth_ethtool_ops = { .get_ethtool_stats = qeth_get_ethtool_stats, .get_sset_count = qeth_get_sset_count, .get_drvinfo = qeth_get_drvinfo, + .get_channels = qeth_get_channels, .get_link_ksettings = qeth_get_link_ksettings, }; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index c3067fd3bd9e..218801232ca2 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -149,29 +149,16 @@ static int qeth_l2_remove_mac(struct qeth_card *card, u8 *mac) return rc; } -static void qeth_l2_del_all_macs(struct qeth_card *card) +static void qeth_l2_drain_rx_mode_cache(struct qeth_card *card) { struct qeth_mac *mac; struct hlist_node *tmp; int i; - spin_lock_bh(&card->mclock); hash_for_each_safe(card->mac_htable, i, tmp, mac, hnode) { hash_del(&mac->hnode); kfree(mac); } - spin_unlock_bh(&card->mclock); -} - -static int qeth_l2_get_cast_type(struct qeth_card *card, struct sk_buff *skb) -{ - if (card->info.type == QETH_CARD_TYPE_OSN) - return RTN_UNICAST; - if (is_broadcast_ether_addr(skb->data)) - return RTN_BROADCAST; - if (is_multicast_ether_addr(skb->data)) - return RTN_MULTICAST; - return RTN_UNICAST; } static void qeth_l2_fill_header(struct qeth_qdio_out_q *queue, @@ -292,14 +279,16 @@ static void qeth_l2_stop_card(struct qeth_card *card) qeth_set_allowed_threads(card, 0, 1); + cancel_work_sync(&card->rx_mode_work); + qeth_l2_drain_rx_mode_cache(card); + if (card->state == CARD_STATE_SOFTSETUP) { - qeth_l2_del_all_macs(card); qeth_clear_ipacmd_list(card); card->state = CARD_STATE_HARDSETUP; } if (card->state == CARD_STATE_HARDSETUP) { qeth_qdio_clear_card(card, 0); - qeth_clear_qdio_buffers(card); + qeth_drain_output_queues(card); qeth_clear_working_pool_list(card); card->state = CARD_STATE_DOWN; } @@ -334,13 +323,11 @@ static int qeth_l2_process_inbound_buffer(struct qeth_card *card, case QETH_HEADER_TYPE_LAYER2: skb->protocol = eth_type_trans(skb, skb->dev); qeth_rx_csum(card, skb, hdr->hdr.l2.flags[1]); - if (skb->protocol == htons(ETH_P_802_2)) - *((__u32 *)skb->cb) = ++card->seqno.pkt_seqno; len = skb->len; napi_gro_receive(&card->napi, skb); break; case QETH_HEADER_TYPE_OSN: - if (card->info.type == QETH_CARD_TYPE_OSN) { + if (IS_OSN(card)) { skb_push(skb, sizeof(struct qeth_hdr)); skb_copy_to_linear_data(skb, hdr, sizeof(struct qeth_hdr)); @@ -391,8 +378,7 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card) } /* some devices don't support a custom MAC address: */ - if (card->info.type == QETH_CARD_TYPE_OSM || - card->info.type == QETH_CARD_TYPE_OSX) + if (IS_OSM(card) || IS_OSX(card)) return (rc) ? rc : -EADDRNOTAVAIL; eth_hw_addr_random(card->dev); @@ -515,9 +501,11 @@ static void qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha) hash_add(card->mac_htable, &mac->hnode, mac_hash); } -static void qeth_l2_set_rx_mode(struct net_device *dev) +static void qeth_l2_rx_mode_work(struct work_struct *work) { - struct qeth_card *card = dev->ml_priv; + 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; @@ -526,12 +514,12 @@ static void qeth_l2_set_rx_mode(struct net_device *dev) QETH_CARD_TEXT(card, 3, "setmulti"); - spin_lock_bh(&card->mclock); - + 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->mac_htable, i, tmp, mac, hnode) { switch (mac->disp_flag) { @@ -554,8 +542,6 @@ static void qeth_l2_set_rx_mode(struct net_device *dev) } } - spin_unlock_bh(&card->mclock); - if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) qeth_setadp_promisc_mode(card); else @@ -586,7 +572,7 @@ static int qeth_l2_xmit_osn(struct qeth_card *card, struct sk_buff *skb, } elements += qeth_count_elements(skb, hd_len); - if (elements > QETH_MAX_BUFFER_ELEMENTS(card)) { + if (elements > queue->max_elements) { rc = -E2BIG; goto out; } @@ -603,37 +589,45 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct qeth_card *card = dev->ml_priv; - int cast_type = qeth_l2_get_cast_type(card, skb); - int ipv = qeth_get_ip_version(skb); + u16 txq = skb_get_queue_mapping(skb); struct qeth_qdio_out_q *queue; int tx_bytes = skb->len; int rc; - queue = qeth_get_tx_queue(card, skb, ipv, cast_type); - - netif_stop_queue(dev); + 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, ipv, cast_type, + rc = qeth_xmit(card, skb, queue, qeth_get_ip_version(skb), + qeth_get_ether_cast_type(skb), qeth_l2_fill_header); if (!rc) { QETH_TXQ_STAT_INC(queue, tx_packets); QETH_TXQ_STAT_ADD(queue, tx_bytes, tx_bytes); - netif_wake_queue(dev); return NETDEV_TX_OK; - } else if (rc == -EBUSY) { - return NETDEV_TX_BUSY; - } /* else fall through */ + } QETH_TXQ_STAT_INC(queue, tx_dropped); kfree_skb(skb); - netif_wake_queue(dev); 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); + return qeth_get_priority_queue(card, skb); +} + static const struct device_type qeth_l2_devtype = { .name = "qeth_layer2", .groups = qeth_l2_attr_groups, @@ -653,6 +647,7 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev) } hash_init(card->mac_htable); + INIT_WORK(&card->rx_mode_work, qeth_l2_rx_mode_work); return 0; } @@ -673,12 +668,20 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) unregister_netdev(card->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); +} + 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, @@ -721,7 +724,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card, bool carrier_ok) card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; } - if (card->info.type == QETH_CARD_TYPE_OSD && !card->info.guestlan) { + 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)) { @@ -831,8 +834,7 @@ static int qeth_l2_set_online(struct ccwgroup_device *gdev) /* softsetup */ QETH_DBF_TEXT(SETUP, 2, "softsetp"); - if ((card->info.type == QETH_CARD_TYPE_OSD) || - (card->info.type == QETH_CARD_TYPE_OSX)) { + if (IS_OSD(card) || IS_OSX(card)) { rc = qeth_l2_start_ipassists(card); if (rc) goto out_remove; @@ -1042,13 +1044,13 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len, QETH_CARD_TEXT(card, 5, "osndctrd"); - wait_event(card->wait_q, - atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0); - qeth_prepare_control_data(card, len, iob); + wait_event(card->wait_q, qeth_trylock_channel(channel)); + iob->finalize(card, iob, len); + QETH_DBF_HEX(CTRL, 2, iob->data, min(len, QETH_DBF_CTRL_LEN)); QETH_CARD_TEXT(card, 6, "osnoirqp"); spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw, - (addr_t) iob, 0, 0, QETH_IPA_TIMEOUT); + (addr_t) iob, 0, 0, iob->timeout); spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); if (rc) { QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: " @@ -1456,9 +1458,8 @@ static struct qeth_cmd_buffer *qeth_sbp_build_cmd(struct qeth_card *card, enum qeth_ipa_sbp_cmd sbp_cmd, unsigned int cmd_length) { - enum qeth_ipa_cmds ipa_cmd = (card->info.type == QETH_CARD_TYPE_IQD) ? - IPA_CMD_SETBRIDGEPORT_IQD : - IPA_CMD_SETBRIDGEPORT_OSA; + enum qeth_ipa_cmds ipa_cmd = IS_IQD(card) ? IPA_CMD_SETBRIDGEPORT_IQD : + IPA_CMD_SETBRIDGEPORT_OSA; struct qeth_cmd_buffer *iob; struct qeth_ipa_cmd *cmd; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 53712cf26406..0271833da6a2 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -246,9 +246,9 @@ static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) */ if (addr->proto == QETH_PROT_IPV4) { addr->in_progress = 1; - spin_unlock_bh(&card->ip_lock); + mutex_unlock(&card->ip_lock); rc = qeth_l3_register_addr_entry(card, addr); - spin_lock_bh(&card->ip_lock); + mutex_lock(&card->ip_lock); addr->in_progress = 0; } else rc = qeth_l3_register_addr_entry(card, addr); @@ -268,6 +268,30 @@ static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) return rc; } +static int qeth_l3_modify_ip(struct qeth_card *card, struct qeth_ipaddr *addr, + bool add) +{ + int rc; + + mutex_lock(&card->ip_lock); + rc = add ? qeth_l3_add_ip(card, addr) : qeth_l3_delete_ip(card, addr); + mutex_unlock(&card->ip_lock); + + return rc; +} + +static void qeth_l3_drain_rx_mode_cache(struct qeth_card *card) +{ + struct qeth_ipaddr *addr; + struct hlist_node *tmp; + int i; + + hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) { + hash_del(&addr->hnode); + kfree(addr); + } +} + static void qeth_l3_clear_ip_htable(struct qeth_card *card, int recover) { struct qeth_ipaddr *addr; @@ -276,7 +300,7 @@ static void qeth_l3_clear_ip_htable(struct qeth_card *card, int recover) QETH_CARD_TEXT(card, 4, "clearip"); - spin_lock_bh(&card->ip_lock); + mutex_lock(&card->ip_lock); hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) { if (!recover) { @@ -287,19 +311,9 @@ static void qeth_l3_clear_ip_htable(struct qeth_card *card, int recover) addr->disp_flag = QETH_DISP_ADDR_ADD; } - spin_unlock_bh(&card->ip_lock); - - spin_lock_bh(&card->mclock); - - hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) { - hash_del(&addr->hnode); - kfree(addr); - } - - spin_unlock_bh(&card->mclock); - - + mutex_unlock(&card->ip_lock); } + static void qeth_l3_recover_ip(struct qeth_card *card) { struct qeth_ipaddr *addr; @@ -309,15 +323,15 @@ static void qeth_l3_recover_ip(struct qeth_card *card) QETH_CARD_TEXT(card, 4, "recovrip"); - spin_lock_bh(&card->ip_lock); + mutex_lock(&card->ip_lock); hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) { if (addr->disp_flag == QETH_DISP_ADDR_ADD) { if (addr->proto == QETH_PROT_IPV4) { addr->in_progress = 1; - spin_unlock_bh(&card->ip_lock); + mutex_unlock(&card->ip_lock); rc = qeth_l3_register_addr_entry(card, addr); - spin_lock_bh(&card->ip_lock); + mutex_lock(&card->ip_lock); addr->in_progress = 0; } else rc = qeth_l3_register_addr_entry(card, addr); @@ -333,8 +347,7 @@ static void qeth_l3_recover_ip(struct qeth_card *card) } } - spin_unlock_bh(&card->ip_lock); - + mutex_unlock(&card->ip_lock); } static int qeth_l3_setdelip_cb(struct qeth_card *card, struct qeth_reply *reply, @@ -461,7 +474,7 @@ static int qeth_l3_send_setrouting(struct qeth_card *card, static int qeth_l3_correct_routing_type(struct qeth_card *card, enum qeth_routing_types *type, enum qeth_prot_versions prot) { - if (card->info.type == QETH_CARD_TYPE_IQD) { + if (IS_IQD(card)) { switch (*type) { case NO_ROUTER: case PRIMARY_CONNECTOR: @@ -559,7 +572,7 @@ static void qeth_l3_clear_ipato_list(struct qeth_card *card) { struct qeth_ipato_entry *ipatoe, *tmp; - spin_lock_bh(&card->ip_lock); + mutex_lock(&card->ip_lock); list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry) { list_del(&ipatoe->entry); @@ -567,7 +580,7 @@ static void qeth_l3_clear_ipato_list(struct qeth_card *card) } qeth_l3_update_ipato(card); - spin_unlock_bh(&card->ip_lock); + mutex_unlock(&card->ip_lock); } int qeth_l3_add_ipato_entry(struct qeth_card *card, @@ -578,7 +591,7 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card, QETH_CARD_TEXT(card, 2, "addipato"); - spin_lock_bh(&card->ip_lock); + mutex_lock(&card->ip_lock); list_for_each_entry(ipatoe, &card->ipato.entries, entry) { if (ipatoe->proto != new->proto) @@ -596,7 +609,7 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card, qeth_l3_update_ipato(card); } - spin_unlock_bh(&card->ip_lock); + mutex_unlock(&card->ip_lock); return rc; } @@ -610,7 +623,7 @@ int qeth_l3_del_ipato_entry(struct qeth_card *card, QETH_CARD_TEXT(card, 2, "delipato"); - spin_lock_bh(&card->ip_lock); + mutex_lock(&card->ip_lock); list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry) { if (ipatoe->proto != proto) @@ -625,7 +638,7 @@ int qeth_l3_del_ipato_entry(struct qeth_card *card, } } - spin_unlock_bh(&card->ip_lock); + mutex_unlock(&card->ip_lock); return rc; } @@ -634,7 +647,6 @@ int qeth_l3_modify_rxip_vipa(struct qeth_card *card, bool add, const u8 *ip, enum qeth_prot_versions proto) { struct qeth_ipaddr addr; - int rc; qeth_l3_init_ipaddr(&addr, type, proto); if (proto == QETH_PROT_IPV4) @@ -642,16 +654,13 @@ int qeth_l3_modify_rxip_vipa(struct qeth_card *card, bool add, const u8 *ip, else memcpy(&addr.u.a6.addr, ip, 16); - spin_lock_bh(&card->ip_lock); - rc = add ? qeth_l3_add_ip(card, &addr) : qeth_l3_delete_ip(card, &addr); - spin_unlock_bh(&card->ip_lock); - return rc; + return qeth_l3_modify_ip(card, &addr, add); } int qeth_l3_modify_hsuid(struct qeth_card *card, bool add) { struct qeth_ipaddr addr; - int rc, i; + unsigned int i; qeth_l3_init_ipaddr(&addr, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV6); addr.u.a6.addr.s6_addr[0] = 0xfe; @@ -659,10 +668,7 @@ int qeth_l3_modify_hsuid(struct qeth_card *card, bool add) for (i = 0; i < 8; i++) addr.u.a6.addr.s6_addr[8+i] = card->options.hsuid[i]; - spin_lock_bh(&card->ip_lock); - rc = add ? qeth_l3_add_ip(card, &addr) : qeth_l3_delete_ip(card, &addr); - spin_unlock_bh(&card->ip_lock); - return rc; + return qeth_l3_modify_ip(card, &addr, add); } static int qeth_l3_register_addr_entry(struct qeth_card *card, @@ -848,7 +854,7 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card) QETH_CARD_TEXT(card, 3, "softipv6"); - if (card->info.type == QETH_CARD_TYPE_IQD) + if (IS_IQD(card)) goto out; rc = qeth_send_simple_setassparms(card, IPA_IPV6, @@ -1374,8 +1380,7 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card, switch (hdr->hdr.l3.id) { case QETH_HEADER_TYPE_LAYER3: magic = *(__u16 *)skb->data; - if ((card->info.type == QETH_CARD_TYPE_IQD) && - (magic == ETH_P_AF_IUCV)) { + if (IS_IQD(card) && magic == ETH_P_AF_IUCV) { len = skb->len; dev_hard_header(skb, dev, ETH_P_AF_IUCV, dev->dev_addr, "FAKELL", len); @@ -1413,6 +1418,9 @@ static void qeth_l3_stop_card(struct qeth_card *card) qeth_set_allowed_threads(card, 0, 1); + cancel_work_sync(&card->rx_mode_work); + qeth_l3_drain_rx_mode_cache(card); + if (card->options.sniffer && (card->info.promisc_mode == SET_PROMISC_MODE_ON)) qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE); @@ -1424,7 +1432,7 @@ static void qeth_l3_stop_card(struct qeth_card *card) } if (card->state == CARD_STATE_HARDSETUP) { qeth_qdio_clear_card(card, 0); - qeth_clear_qdio_buffers(card); + qeth_drain_output_queues(card); qeth_clear_working_pool_list(card); card->state = CARD_STATE_DOWN; } @@ -1451,7 +1459,7 @@ qeth_l3_handle_promisc_mode(struct qeth_card *card) (card->info.promisc_mode == SET_PROMISC_MODE_OFF))) return; - if (card->info.guestlan) { /* Guestlan trace */ + if (IS_VM_NIC(card)) { /* Guestlan trace */ if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) qeth_setadp_promisc_mode(card); } else if (card->options.sniffer && /* HiperSockets trace */ @@ -1466,9 +1474,10 @@ qeth_l3_handle_promisc_mode(struct qeth_card *card) } } -static void qeth_l3_set_rx_mode(struct net_device *dev) +static void qeth_l3_rx_mode_work(struct work_struct *work) { - struct qeth_card *card = dev->ml_priv; + struct qeth_card *card = container_of(work, struct qeth_card, + rx_mode_work); struct qeth_ipaddr *addr; struct hlist_node *tmp; int i, rc; @@ -1476,8 +1485,6 @@ static void qeth_l3_set_rx_mode(struct net_device *dev) QETH_CARD_TEXT(card, 3, "setmulti"); if (!card->options.sniffer) { - spin_lock_bh(&card->mclock); - qeth_l3_add_multicast_ipv4(card); qeth_l3_add_multicast_ipv6(card); @@ -1505,8 +1512,6 @@ static void qeth_l3_set_rx_mode(struct net_device *dev) } } - spin_unlock_bh(&card->mclock); - if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) return; } @@ -1551,7 +1556,7 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries) * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_SET_NO_ENTRIES; * thus we say EOPNOTSUPP for this ARP function */ - if (card->info.guestlan) + if (IS_VM_NIC(card)) return -EOPNOTSUPP; if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) { return -EOPNOTSUPP; @@ -1783,7 +1788,7 @@ static int qeth_l3_arp_modify_entry(struct qeth_card *card, * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_ADD_ENTRY; * thus we say EOPNOTSUPP for this ARP function */ - if (card->info.guestlan) + if (IS_VM_NIC(card)) return -EOPNOTSUPP; if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) { return -EOPNOTSUPP; @@ -1816,7 +1821,7 @@ static int qeth_l3_arp_flush_cache(struct qeth_card *card) * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_FLUSH_CACHE; * thus we say EOPNOTSUPP for this ARP function */ - if (card->info.guestlan || (card->info.type == QETH_CARD_TYPE_IQD)) + if (IS_VM_NIC(card) || IS_IQD(card)) return -EOPNOTSUPP; if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) { return -EOPNOTSUPP; @@ -1913,13 +1918,7 @@ static int qeth_l3_get_cast_type(struct sk_buff *skb) RTN_MULTICAST : RTN_UNICAST; default: /* ... and MAC address */ - if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, - skb->dev->broadcast)) - return RTN_BROADCAST; - if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) - return RTN_MULTICAST; - /* default to unicast */ - return RTN_UNICAST; + return qeth_get_ether_cast_type(skb); } } @@ -1977,19 +1976,14 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue, hdr->hdr.l3.vlan_id = ntohs(veth->h_vlan_TCI); } + l3_hdr->flags = qeth_l3_cast_type_to_flag(cast_type); + /* OSA only: */ if (!ipv) { - hdr->hdr.l3.flags = QETH_HDR_PASSTHRU; - if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, - skb->dev->broadcast)) - hdr->hdr.l3.flags |= QETH_CAST_BROADCAST; - else - hdr->hdr.l3.flags |= (cast_type == RTN_MULTICAST) ? - QETH_CAST_MULTICAST : QETH_CAST_UNICAST; + l3_hdr->flags |= QETH_HDR_PASSTHRU; return; } - hdr->hdr.l3.flags = qeth_l3_cast_type_to_flag(cast_type); rcu_read_lock(); if (ipv == 4) { struct rtable *rt = skb_rtable(skb); @@ -2007,7 +2001,7 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue, 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) + if (!IS_IQD(card)) hdr->hdr.l3.flags |= QETH_HDR_PASSTHRU; } rcu_read_unlock(); @@ -2030,7 +2024,6 @@ 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 char eth_hdr[ETH_HLEN]; unsigned int hw_hdr_len; int rc; @@ -2040,45 +2033,44 @@ static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, 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); qeth_l3_fixup_headers(skb); - 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; + return qeth_xmit(card, skb, queue, ipv, cast_type, qeth_l3_fill_header); } static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - int cast_type = qeth_l3_get_cast_type(skb); struct qeth_card *card = dev->ml_priv; + u16 txq = skb_get_queue_mapping(skb); int ipv = qeth_get_ip_version(skb); struct qeth_qdio_out_q *queue; int tx_bytes = skb->len; - int rc; - - queue = qeth_get_tx_queue(card, skb, ipv, cast_type); + int cast_type, rc; if (IS_IQD(card)) { + queue = card->qdio.out_qs[qeth_iqd_translate_txq(dev, txq)]; + if (card->options.sniffer) goto tx_drop; if ((card->options.cq != QETH_CQ_ENABLED && !ipv) || (card->options.cq == QETH_CQ_ENABLED && skb->protocol != htons(ETH_P_AF_IUCV))) goto tx_drop; + + if (txq == QETH_IQD_MCAST_TXQ) + cast_type = qeth_l3_get_cast_type(skb); + else + cast_type = RTN_UNICAST; + } else { + queue = card->qdio.out_qs[txq]; + cast_type = qeth_l3_get_cast_type(skb); } if (cast_type == RTN_BROADCAST && !card->info.broadcast_capable) goto tx_drop; - netif_stop_queue(dev); - if (ipv == 4 || IS_IQD(card)) rc = qeth_l3_xmit(card, skb, queue, ipv, cast_type); else @@ -2088,19 +2080,22 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, if (!rc) { QETH_TXQ_STAT_INC(queue, tx_packets); QETH_TXQ_STAT_ADD(queue, tx_bytes, tx_bytes); - netif_wake_queue(dev); return NETDEV_TX_OK; - } else if (rc == -EBUSY) { - return NETDEV_TX_BUSY; - } /* else fall through */ + } tx_drop: QETH_TXQ_STAT_INC(queue, tx_dropped); kfree_skb(skb); - netif_wake_queue(dev); return NETDEV_TX_OK; } +static void qeth_l3_set_rx_mode(struct net_device *dev) +{ + struct qeth_card *card = dev->ml_priv; + + schedule_work(&card->rx_mode_work); +} + /* * we need NOARP for IPv4 but we want neighbor solicitation for IPv6. Setting * NOARP on the netdevice is no option because it also turns off neighbor @@ -2134,11 +2129,27 @@ static netdev_features_t qeth_l3_osa_features_check(struct sk_buff *skb, return qeth_features_check(skb, dev, features); } +static u16 qeth_l3_iqd_select_queue(struct net_device *dev, struct sk_buff *skb, + struct net_device *sb_dev) +{ + return qeth_iqd_select_queue(dev, skb, qeth_l3_get_cast_type(skb), + sb_dev); +} + +static u16 qeth_l3_osa_select_queue(struct net_device *dev, struct sk_buff *skb, + struct net_device *sb_dev) +{ + struct qeth_card *card = dev->ml_priv; + + return qeth_get_priority_queue(card, skb); +} + static const struct net_device_ops qeth_l3_netdev_ops = { .ndo_open = qeth_open, .ndo_stop = qeth_stop, .ndo_get_stats64 = qeth_get_stats64, .ndo_start_xmit = qeth_l3_hard_start_xmit, + .ndo_select_queue = qeth_l3_iqd_select_queue, .ndo_validate_addr = eth_validate_addr, .ndo_set_rx_mode = qeth_l3_set_rx_mode, .ndo_do_ioctl = qeth_do_ioctl, @@ -2155,6 +2166,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = { .ndo_get_stats64 = qeth_get_stats64, .ndo_start_xmit = qeth_l3_hard_start_xmit, .ndo_features_check = qeth_l3_osa_features_check, + .ndo_select_queue = qeth_l3_osa_select_queue, .ndo_validate_addr = eth_validate_addr, .ndo_set_rx_mode = qeth_l3_set_rx_mode, .ndo_do_ioctl = qeth_do_ioctl, @@ -2171,8 +2183,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok) unsigned int headroom; int rc; - if (card->info.type == QETH_CARD_TYPE_OSD || - card->info.type == QETH_CARD_TYPE_OSX) { + if (IS_OSD(card) || IS_OSX(card)) { if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) || (card->info.link_type == QETH_LINK_TYPE_HSTR)) { pr_info("qeth_l3: ignoring TR device\n"); @@ -2186,7 +2197,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok) if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD)) card->dev->dev_id = card->info.unique_id & 0xffff; - if (!card->info.guestlan) { + if (!IS_VM_NIC(card)) { card->dev->features |= NETIF_F_SG; card->dev->hw_features |= NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_IP_CSUM; @@ -2210,7 +2221,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok) headroom = sizeof(struct qeth_hdr_tso); else headroom = sizeof(struct qeth_hdr) + VLAN_HLEN; - } else if (card->info.type == QETH_CARD_TYPE_IQD) { + } else if (IS_IQD(card)) { card->dev->flags |= IFF_NOARP; card->dev->netdev_ops = &qeth_l3_netdev_ops; headroom = sizeof(struct qeth_hdr) - ETH_HLEN; @@ -2253,14 +2264,22 @@ static int qeth_l3_probe_device(struct ccwgroup_device *gdev) int rc; hash_init(card->ip_htable); + mutex_init(&card->ip_lock); + card->cmd_wq = alloc_ordered_workqueue("%s_cmd", 0, + dev_name(&gdev->dev)); + if (!card->cmd_wq) + return -ENOMEM; if (gdev->dev.type == &qeth_generic_devtype) { rc = qeth_l3_create_device_attributes(&gdev->dev); - if (rc) + if (rc) { + destroy_workqueue(card->cmd_wq); return rc; + } } hash_init(card->ip_mc_htable); + INIT_WORK(&card->rx_mode_work, qeth_l3_rx_mode_work); return 0; } @@ -2280,6 +2299,9 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) cancel_work_sync(&card->close_dev_work); if (qeth_netdev_is_registered(card->dev)) unregister_netdev(card->dev); + + flush_workqueue(card->cmd_wq); + destroy_workqueue(card->cmd_wq); qeth_l3_clear_ip_htable(card, 0); qeth_l3_clear_ipato_list(card); } @@ -2517,20 +2539,40 @@ static int qeth_l3_handle_ip_event(struct qeth_card *card, { switch (event) { case NETDEV_UP: - spin_lock_bh(&card->ip_lock); - qeth_l3_add_ip(card, addr); - spin_unlock_bh(&card->ip_lock); + qeth_l3_modify_ip(card, addr, true); return NOTIFY_OK; case NETDEV_DOWN: - spin_lock_bh(&card->ip_lock); - qeth_l3_delete_ip(card, addr); - spin_unlock_bh(&card->ip_lock); + qeth_l3_modify_ip(card, addr, false); return NOTIFY_OK; default: return NOTIFY_DONE; } } +struct qeth_l3_ip_event_work { + struct work_struct work; + struct qeth_card *card; + struct qeth_ipaddr addr; +}; + +#define to_ip_work(w) container_of((w), struct qeth_l3_ip_event_work, work) + +static void qeth_l3_add_ip_worker(struct work_struct *work) +{ + struct qeth_l3_ip_event_work *ip_work = to_ip_work(work); + + qeth_l3_modify_ip(ip_work->card, &ip_work->addr, true); + kfree(work); +} + +static void qeth_l3_delete_ip_worker(struct work_struct *work) +{ + struct qeth_l3_ip_event_work *ip_work = to_ip_work(work); + + qeth_l3_modify_ip(ip_work->card, &ip_work->addr, false); + kfree(work); +} + static struct qeth_card *qeth_l3_get_card_from_dev(struct net_device *dev) { if (is_vlan_dev(dev)) @@ -2575,9 +2617,12 @@ static int qeth_l3_ip6_event(struct notifier_block *this, { struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; struct net_device *dev = ifa->idev->dev; - struct qeth_ipaddr addr; + struct qeth_l3_ip_event_work *ip_work; struct qeth_card *card; + if (event != NETDEV_UP && event != NETDEV_DOWN) + return NOTIFY_DONE; + card = qeth_l3_get_card_from_dev(dev); if (!card) return NOTIFY_DONE; @@ -2585,11 +2630,23 @@ static int qeth_l3_ip6_event(struct notifier_block *this, if (!qeth_is_supported(card, IPA_IPV6)) return NOTIFY_DONE; - qeth_l3_init_ipaddr(&addr, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV6); - addr.u.a6.addr = ifa->addr; - addr.u.a6.pfxlen = ifa->prefix_len; + ip_work = kmalloc(sizeof(*ip_work), GFP_ATOMIC); + if (!ip_work) + return NOTIFY_DONE; - return qeth_l3_handle_ip_event(card, &addr, event); + if (event == NETDEV_UP) + INIT_WORK(&ip_work->work, qeth_l3_add_ip_worker); + else + INIT_WORK(&ip_work->work, qeth_l3_delete_ip_worker); + + ip_work->card = card; + qeth_l3_init_ipaddr(&ip_work->addr, QETH_IP_TYPE_NORMAL, + QETH_PROT_IPV6); + ip_work->addr.u.a6.addr = ifa->addr; + ip_work->addr.u.a6.pfxlen = ifa->prefix_len; + + queue_work(card->cmd_wq, &ip_work->work); + return NOTIFY_OK; } static struct notifier_block qeth_l3_ip6_notifier = { diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index cff518b0f904..2f73b33c9347 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -206,7 +206,7 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev, if (!card) return -EINVAL; - if (card->info.type != QETH_CARD_TYPE_IQD) + if (!IS_IQD(card)) return -EPERM; if (card->options.cq == QETH_CQ_ENABLED) return -EPERM; @@ -258,7 +258,7 @@ static ssize_t qeth_l3_dev_hsuid_show(struct device *dev, if (!card) return -EINVAL; - if (card->info.type != QETH_CARD_TYPE_IQD) + if (!IS_IQD(card)) return -EPERM; memcpy(tmp_hsuid, card->options.hsuid, sizeof(tmp_hsuid)); @@ -276,7 +276,7 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev, if (!card) return -EINVAL; - if (card->info.type != QETH_CARD_TYPE_IQD) + if (!IS_IQD(card)) return -EPERM; if (card->state != CARD_STATE_DOWN) return -EPERM; @@ -367,9 +367,9 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, if (card->ipato.enabled != enable) { card->ipato.enabled = enable; - spin_lock_bh(&card->ip_lock); + mutex_lock(&card->ip_lock); qeth_l3_update_ipato(card); - spin_unlock_bh(&card->ip_lock); + mutex_unlock(&card->ip_lock); } out: mutex_unlock(&card->conf_mutex); @@ -412,9 +412,9 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev, if (card->ipato.invert4 != invert) { card->ipato.invert4 = invert; - spin_lock_bh(&card->ip_lock); + mutex_lock(&card->ip_lock); qeth_l3_update_ipato(card); - spin_unlock_bh(&card->ip_lock); + mutex_unlock(&card->ip_lock); } out: mutex_unlock(&card->conf_mutex); @@ -436,7 +436,7 @@ static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card, entry_len = (proto == QETH_PROT_IPV4)? 12 : 40; /* add strlen for "/<mask>\n" */ entry_len += (proto == QETH_PROT_IPV4)? 5 : 6; - spin_lock_bh(&card->ip_lock); + mutex_lock(&card->ip_lock); list_for_each_entry(ipatoe, &card->ipato.entries, entry) { if (ipatoe->proto != proto) continue; @@ -449,7 +449,7 @@ static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card, i += snprintf(buf + i, PAGE_SIZE - i, "%s/%i\n", addr_str, ipatoe->mask_bits); } - spin_unlock_bh(&card->ip_lock); + mutex_unlock(&card->ip_lock); i += snprintf(buf + i, PAGE_SIZE - i, "\n"); return i; @@ -598,9 +598,9 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev, if (card->ipato.invert6 != invert) { card->ipato.invert6 = invert; - spin_lock_bh(&card->ip_lock); + mutex_lock(&card->ip_lock); qeth_l3_update_ipato(card); - spin_unlock_bh(&card->ip_lock); + mutex_unlock(&card->ip_lock); } out: mutex_unlock(&card->conf_mutex); @@ -684,7 +684,7 @@ static ssize_t qeth_l3_dev_ip_add_show(struct device *dev, char *buf, entry_len = (proto == QETH_PROT_IPV4)? 12 : 40; entry_len += 2; /* \n + terminator */ - spin_lock_bh(&card->ip_lock); + mutex_lock(&card->ip_lock); hash_for_each(card->ip_htable, i, ipaddr, hnode) { if (ipaddr->proto != proto || ipaddr->type != type) continue; @@ -698,7 +698,7 @@ static ssize_t qeth_l3_dev_ip_add_show(struct device *dev, char *buf, str_len += snprintf(buf + str_len, PAGE_SIZE - str_len, "%s\n", addr_str); } - spin_unlock_bh(&card->ip_lock); + mutex_unlock(&card->ip_lock); str_len += snprintf(buf + str_len, PAGE_SIZE - str_len, "\n"); return str_len; |