mirror of https://gitee.com/openkylin/linux.git
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: Lakhvich Dmitriy <ldmitriy@ru.ibm.com> Signed-off-by: Ursula Braun <ubraun@linux.vnet.ibm.com> Reviewed-by: Evgeny Cherkashin <Eugene.Crosser@ru.ibm.com> Reviewed-by: Thomas Richter <tmricht@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
6059c90537
commit
5f78e29cee
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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__ */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <linux/slab.h>
|
||||
#include <asm/ebcdic.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include "qeth_l3.h"
|
||||
|
||||
#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
|
||||
|
@ -285,19 +286,19 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
|
|||
if (card->options.hsuid[0]) {
|
||||
/* delete old ip address */
|
||||
addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
|
||||
if (addr != NULL) {
|
||||
addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
|
||||
addr->u.a6.addr.s6_addr32[1] = 0x00000000;
|
||||
for (i = 8; i < 16; i++)
|
||||
addr->u.a6.addr.s6_addr[i] =
|
||||
card->options.hsuid[i - 8];
|
||||
addr->u.a6.pfxlen = 0;
|
||||
addr->type = QETH_IP_TYPE_NORMAL;
|
||||
} else
|
||||
if (!addr)
|
||||
return -ENOMEM;
|
||||
if (!qeth_l3_delete_ip(card, addr))
|
||||
kfree(addr);
|
||||
qeth_l3_set_ip_addr_list(card);
|
||||
|
||||
addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
|
||||
addr->u.a6.addr.s6_addr32[1] = 0x00000000;
|
||||
for (i = 8; i < 16; i++)
|
||||
addr->u.a6.addr.s6_addr[i] =
|
||||
card->options.hsuid[i - 8];
|
||||
addr->u.a6.pfxlen = 0;
|
||||
addr->type = QETH_IP_TYPE_NORMAL;
|
||||
|
||||
qeth_l3_delete_ip(card, addr);
|
||||
kfree(addr);
|
||||
}
|
||||
|
||||
if (strlen(tmp) == 0) {
|
||||
|
@ -328,9 +329,8 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
|
|||
addr->type = QETH_IP_TYPE_NORMAL;
|
||||
} else
|
||||
return -ENOMEM;
|
||||
if (!qeth_l3_add_ip(card, addr))
|
||||
kfree(addr);
|
||||
qeth_l3_set_ip_addr_list(card);
|
||||
qeth_l3_add_ip(card, addr);
|
||||
kfree(addr);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -367,8 +367,8 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct qeth_card *card = dev_get_drvdata(dev);
|
||||
struct qeth_ipaddr *tmpipa, *t;
|
||||
int rc = 0;
|
||||
struct qeth_ipaddr *addr;
|
||||
int i, rc = 0;
|
||||
|
||||
if (!card)
|
||||
return -EINVAL;
|
||||
|
@ -384,21 +384,20 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
|
|||
card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
|
||||
} else if (sysfs_streq(buf, "1")) {
|
||||
card->ipato.enabled = 1;
|
||||
list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
|
||||
if ((tmpipa->type == QETH_IP_TYPE_NORMAL) &&
|
||||
qeth_l3_is_addr_covered_by_ipato(card, tmpipa))
|
||||
tmpipa->set_flags |=
|
||||
hash_for_each(card->ip_htable, i, addr, hnode) {
|
||||
if ((addr->type == QETH_IP_TYPE_NORMAL) &&
|
||||
qeth_l3_is_addr_covered_by_ipato(card, addr))
|
||||
addr->set_flags |=
|
||||
QETH_IPA_SETIP_TAKEOVER_FLAG;
|
||||
}
|
||||
|
||||
}
|
||||
} else if (sysfs_streq(buf, "0")) {
|
||||
card->ipato.enabled = 0;
|
||||
list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
|
||||
if (tmpipa->set_flags &
|
||||
QETH_IPA_SETIP_TAKEOVER_FLAG)
|
||||
tmpipa->set_flags &=
|
||||
~QETH_IPA_SETIP_TAKEOVER_FLAG;
|
||||
}
|
||||
hash_for_each(card->ip_htable, i, addr, hnode) {
|
||||
if (addr->set_flags &
|
||||
QETH_IPA_SETIP_TAKEOVER_FLAG)
|
||||
addr->set_flags &=
|
||||
~QETH_IPA_SETIP_TAKEOVER_FLAG;
|
||||
}
|
||||
} else
|
||||
rc = -EINVAL;
|
||||
out:
|
||||
|
@ -452,7 +451,6 @@ static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card,
|
|||
enum qeth_prot_versions proto)
|
||||
{
|
||||
struct qeth_ipato_entry *ipatoe;
|
||||
unsigned long flags;
|
||||
char addr_str[40];
|
||||
int entry_len; /* length of 1 entry string, differs between v4 and v6 */
|
||||
int i = 0;
|
||||
|
@ -460,7 +458,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_irqsave(&card->ip_lock, flags);
|
||||
spin_lock_bh(&card->ip_lock);
|
||||
list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
|
||||
if (ipatoe->proto != proto)
|
||||
continue;
|
||||
|
@ -473,7 +471,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_irqrestore(&card->ip_lock, flags);
|
||||
spin_unlock_bh(&card->ip_lock);
|
||||
i += snprintf(buf + i, PAGE_SIZE - i, "\n");
|
||||
|
||||
return i;
|
||||
|
@ -689,15 +687,15 @@ static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card,
|
|||
enum qeth_prot_versions proto)
|
||||
{
|
||||
struct qeth_ipaddr *ipaddr;
|
||||
struct hlist_node *tmp;
|
||||
char addr_str[40];
|
||||
int entry_len; /* length of 1 entry string, differs between v4 and v6 */
|
||||
unsigned long flags;
|
||||
int i = 0;
|
||||
|
||||
entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
|
||||
entry_len += 2; /* \n + terminator */
|
||||
spin_lock_irqsave(&card->ip_lock, flags);
|
||||
list_for_each_entry(ipaddr, &card->ip_list, entry) {
|
||||
spin_lock_bh(&card->ip_lock);
|
||||
hash_for_each_safe(card->ip_htable, i, tmp, ipaddr, hnode) {
|
||||
if (ipaddr->proto != proto)
|
||||
continue;
|
||||
if (ipaddr->type != QETH_IP_TYPE_VIPA)
|
||||
|
@ -711,7 +709,7 @@ static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card,
|
|||
addr_str);
|
||||
i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str);
|
||||
}
|
||||
spin_unlock_irqrestore(&card->ip_lock, flags);
|
||||
spin_unlock_bh(&card->ip_lock);
|
||||
i += snprintf(buf + i, PAGE_SIZE - i, "\n");
|
||||
|
||||
return i;
|
||||
|
@ -851,15 +849,15 @@ static ssize_t qeth_l3_dev_rxip_add_show(char *buf, struct qeth_card *card,
|
|||
enum qeth_prot_versions proto)
|
||||
{
|
||||
struct qeth_ipaddr *ipaddr;
|
||||
struct hlist_node *tmp;
|
||||
char addr_str[40];
|
||||
int entry_len; /* length of 1 entry string, differs between v4 and v6 */
|
||||
unsigned long flags;
|
||||
int i = 0;
|
||||
|
||||
entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
|
||||
entry_len += 2; /* \n + terminator */
|
||||
spin_lock_irqsave(&card->ip_lock, flags);
|
||||
list_for_each_entry(ipaddr, &card->ip_list, entry) {
|
||||
spin_lock_bh(&card->ip_lock);
|
||||
hash_for_each_safe(card->ip_htable, i, tmp, ipaddr, hnode) {
|
||||
if (ipaddr->proto != proto)
|
||||
continue;
|
||||
if (ipaddr->type != QETH_IP_TYPE_RXIP)
|
||||
|
@ -873,7 +871,7 @@ static ssize_t qeth_l3_dev_rxip_add_show(char *buf, struct qeth_card *card,
|
|||
addr_str);
|
||||
i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str);
|
||||
}
|
||||
spin_unlock_irqrestore(&card->ip_lock, flags);
|
||||
spin_unlock_bh(&card->ip_lock);
|
||||
i += snprintf(buf + i, PAGE_SIZE - i, "\n");
|
||||
|
||||
return i;
|
||||
|
|
Loading…
Reference in New Issue