Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f78e29c authored by Lakhvich Dmitriy's avatar Lakhvich Dmitriy Committed by David S. Miller
Browse files

qeth: optimize IP handling in rx_mode callback



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: default avatarLakhvich Dmitriy <ldmitriy@ru.ibm.com>
Signed-off-by: default avatarUrsula Braun <ubraun@linux.vnet.ibm.com>
Reviewed-by: default avatarEvgeny Cherkashin <Eugene.Crosser@ru.ibm.com>
Reviewed-by: default avatarThomas Richter <tmricht@linux.vnet.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6059c905
Loading
Loading
Loading
Loading
+6 −14
Original line number Diff line number Diff line
@@ -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 {
@@ -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 {
@@ -800,6 +792,8 @@ 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;
@@ -807,8 +801,6 @@ struct qeth_card {
	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 */
+0 −10
Original line number Diff line number Diff line
@@ -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 */
@@ -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))
@@ -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;
@@ -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);
+7 −0
Original line number Diff line number Diff line
@@ -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__ */
+6 −6
Original line number Diff line number Diff line
@@ -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;
		}
	}
@@ -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));
@@ -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);
@@ -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);
+27 −4
Original line number Diff line number Diff line
@@ -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 {
@@ -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;
@@ -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