Skip to content

Commit

Permalink
qeth: optimize IP handling in rx_mode callback
Browse files Browse the repository at this point in the history
In layer3 mode of the qeth driver, multicast IP addresses
from struct net_device and other type of IP addresses
from other sources require mapping to the OSA-card.
This patch simplifies the IP address mapping logic, and changes imple-
mentation of ndo_set_rx_mode callback and ip notifier events.
Addresses are stored in private hashtables instead of lists now.
It allows hardware registration/removal for new/deleted multicast
addresses only.

Signed-off-by: Lakhvich Dmitriy <[email protected]>
Signed-off-by: Ursula Braun <[email protected]>
Reviewed-by: Evgeny Cherkashin <[email protected]>
Reviewed-by: Thomas Richter <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
ReiReiRei authored and davem330 committed Jun 17, 2016
1 parent 6059c90 commit 5f78e29
Show file tree
Hide file tree
Showing 7 changed files with 482 additions and 458 deletions.
20 changes: 6 additions & 14 deletions drivers/s390/net/qeth_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,6 @@ enum qeth_ip_types {
QETH_IP_TYPE_NORMAL,
QETH_IP_TYPE_VIPA,
QETH_IP_TYPE_RXIP,
QETH_IP_TYPE_DEL_ALL_MC,
};

enum qeth_cmd_buffer_state {
Expand Down Expand Up @@ -742,17 +741,10 @@ struct qeth_vlan_vid {
unsigned short vid;
};

enum qeth_mac_disposition {
QETH_DISP_MAC_DELETE = 0,
QETH_DISP_MAC_DO_NOTHING = 1,
QETH_DISP_MAC_ADD = 2,
};

struct qeth_mac {
u8 mac_addr[OSA_ADDR_LEN];
u8 is_uc:1;
u8 disp_flag:2;
struct hlist_node hnode;
enum qeth_addr_disposition {
QETH_DISP_ADDR_DELETE = 0,
QETH_DISP_ADDR_DO_NOTHING = 1,
QETH_DISP_ADDR_ADD = 2,
};

struct qeth_rx {
Expand Down Expand Up @@ -800,15 +792,15 @@ struct qeth_card {
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
struct list_head vid_list;
DECLARE_HASHTABLE(mac_htable, 4);
DECLARE_HASHTABLE(ip_htable, 4);
DECLARE_HASHTABLE(ip_mc_htable, 4);
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;
struct task_struct *recovery_task;
spinlock_t ip_lock;
struct list_head ip_list;
struct list_head *ip_tbd_list;
struct qeth_ipato ipato;
struct list_head cmd_waiter_list;
/* QDIO buffer handling */
Expand Down
10 changes: 0 additions & 10 deletions drivers/s390/net/qeth_core_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1464,8 +1464,6 @@ static int qeth_setup_card(struct qeth_card *card)
card->thread_allowed_mask = 0;
card->thread_running_mask = 0;
INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread);
INIT_LIST_HEAD(&card->ip_list);
INIT_LIST_HEAD(card->ip_tbd_list);
INIT_LIST_HEAD(&card->cmd_waiter_list);
init_waitqueue_head(&card->wait_q);
/* initial options */
Expand Down Expand Up @@ -1500,11 +1498,6 @@ static struct qeth_card *qeth_alloc_card(void)
if (!card)
goto out;
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
card->ip_tbd_list = kzalloc(sizeof(struct list_head), GFP_KERNEL);
if (!card->ip_tbd_list) {
QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
goto out_card;
}
if (qeth_setup_channel(&card->read))
goto out_ip;
if (qeth_setup_channel(&card->write))
Expand All @@ -1517,8 +1510,6 @@ static struct qeth_card *qeth_alloc_card(void)
out_channel:
qeth_clean_channel(&card->read);
out_ip:
kfree(card->ip_tbd_list);
out_card:
kfree(card);
out:
return NULL;
Expand Down Expand Up @@ -4980,7 +4971,6 @@ static void qeth_core_free_card(struct qeth_card *card)
qeth_clean_channel(&card->write);
if (card->dev)
free_netdev(card->dev);
kfree(card->ip_tbd_list);
qeth_free_qdio_buffers(card);
unregister_service_level(&card->qeth_service_level);
kfree(card);
Expand Down
7 changes: 7 additions & 0 deletions drivers/s390/net/qeth_l2.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,11 @@ int qeth_l2_create_device_attributes(struct device *);
void qeth_l2_remove_device_attributes(struct device *);
void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card);

struct qeth_mac {
u8 mac_addr[OSA_ADDR_LEN];
u8 is_uc:1;
u8 disp_flag:2;
struct hlist_node hnode;
};

#endif /* __QETH_L2_H__ */
12 changes: 6 additions & 6 deletions drivers/s390/net/qeth_l2_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha, u8 is_uc)
qeth_l2_mac_hash(ha->addr)) {
if (is_uc == mac->is_uc &&
!memcmp(ha->addr, mac->mac_addr, OSA_ADDR_LEN)) {
mac->disp_flag = QETH_DISP_MAC_DO_NOTHING;
mac->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
return;
}
}
Expand All @@ -792,7 +792,7 @@ qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha, u8 is_uc)

memcpy(mac->mac_addr, ha->addr, OSA_ADDR_LEN);
mac->is_uc = is_uc;
mac->disp_flag = QETH_DISP_MAC_ADD;
mac->disp_flag = QETH_DISP_ADDR_ADD;

hash_add(card->mac_htable, &mac->hnode,
qeth_l2_mac_hash(mac->mac_addr));
Expand Down Expand Up @@ -825,7 +825,7 @@ static void qeth_l2_set_rx_mode(struct net_device *dev)
qeth_l2_add_mac(card, ha, 1);

hash_for_each_safe(card->mac_htable, i, tmp, mac, hnode) {
if (mac->disp_flag == QETH_DISP_MAC_DELETE) {
if (mac->disp_flag == QETH_DISP_ADDR_DELETE) {
if (!mac->is_uc)
rc = qeth_l2_send_delgroupmac(card,
mac->mac_addr);
Expand All @@ -837,15 +837,15 @@ static void qeth_l2_set_rx_mode(struct net_device *dev)
hash_del(&mac->hnode);
kfree(mac);

} else if (mac->disp_flag == QETH_DISP_MAC_ADD) {
} else if (mac->disp_flag == QETH_DISP_ADDR_ADD) {
rc = qeth_l2_write_mac(card, mac);
if (rc) {
hash_del(&mac->hnode);
kfree(mac);
} else
mac->disp_flag = QETH_DISP_MAC_DELETE;
mac->disp_flag = QETH_DISP_ADDR_DELETE;
} else
mac->disp_flag = QETH_DISP_MAC_DELETE;
mac->disp_flag = QETH_DISP_ADDR_DELETE;
}

spin_unlock_bh(&card->mclock);
Expand Down
31 changes: 27 additions & 4 deletions drivers/s390/net/qeth_l3.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,23 @@
#define __QETH_L3_H__

#include "qeth_core.h"
#include <linux/hashtable.h>

#define QETH_SNIFF_AVAIL 0x0008

struct qeth_ipaddr {
struct list_head entry;
struct hlist_node hnode;
enum qeth_ip_types type;
enum qeth_ipa_setdelip_flags set_flags;
enum qeth_ipa_setdelip_flags del_flags;
int is_multicast;
int users;
u8 is_multicast:1;
u8 in_progress:1;
u8 disp_flag:2;

/* is changed only for normal ip addresses
* for non-normal addresses it always is 1
*/
int ref_counter;
enum qeth_prot_versions proto;
unsigned char mac[OSA_ADDR_LEN];
union {
Expand All @@ -32,7 +39,24 @@ struct qeth_ipaddr {
unsigned int pfxlen;
} a6;
} u;

};
static inline u64 qeth_l3_ipaddr_hash(struct qeth_ipaddr *addr)
{
u64 ret = 0;
u8 *point;

if (addr->proto == QETH_PROT_IPV6) {
point = (u8 *) &addr->u.a6.addr;
ret = get_unaligned((u64 *)point) ^
get_unaligned((u64 *) (point + 8));
}
if (addr->proto == QETH_PROT_IPV4) {
point = (u8 *) &addr->u.a4.addr;
ret = get_unaligned((u32 *) point);
}
return ret;
}

struct qeth_ipato_entry {
struct list_head entry;
Expand Down Expand Up @@ -60,6 +84,5 @@ int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *, struct qeth_ipaddr *);
struct qeth_ipaddr *qeth_l3_get_addr_buffer(enum qeth_prot_versions);
int qeth_l3_add_ip(struct qeth_card *, struct qeth_ipaddr *);
int qeth_l3_delete_ip(struct qeth_card *, struct qeth_ipaddr *);
void qeth_l3_set_ip_addr_list(struct qeth_card *);

#endif /* __QETH_L3_H__ */
Loading

0 comments on commit 5f78e29

Please sign in to comment.