aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornikolay@redhat.com <nikolay@redhat.com>2013-03-11 22:49:01 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-15 08:22:20 -0400
commit8a7fbfab4be39b8690543f3d29b26860d2f6c576 (patch)
tree6618fe6878b31f43d094be20643df7e7186083f1
parent1e32b0c65c9e3f1a09cb5d1bcc0c5becf849d85f (diff)
netxen: write IP address to firmware when using bonding
This patch allows LRO aggregation on bonded devices that contain an NX3031 device. It also adds a for_each_netdev_in_bond_rcu(bond, slave) macro which executes for each slave that has bond as master. V3: After testing and discussing this with Rajesh, I decided to keep the vlan ip cache and just rename it to ip_cache since it will store bond ip addresses too. A new master flag has been added to the ip cache to denote that the address has been added because of a master device. I've taken care of the enslave/release cases by checking for various combinations of events and flags (e.g. netxen has a master, it's a bond master and it's not marked as a slave means it is being enslaved and is dev_open()ed in bond_enslave). I've changed netxen_free_ip_list() to have a "master" parameter which causes all IP addresses marked as master to be deleted (used when a netxen is being released). I've made the patch use the new upper device API as well. The following cases were tested: - bond -> netxen - vlan -> netxen - vlan -> bond -> netxen V2: Remove local ip caching, retrieve addresses dynamically and restore them if necessary. Note: Tested with NX3031 adapter. Tested-by: Rajesh Borundia <rajesh.borundia@qlogic.com> Signed-off-by: Andy Gospodarek <agospoda@redhat.com> Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic.h5
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c220
-rw-r--r--include/linux/netdevice.h8
3 files changed, 155 insertions, 78 deletions
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
index eb3dfdbb642b..322a36b76727 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
@@ -955,9 +955,10 @@ typedef struct nx_mac_list_s {
955 uint8_t mac_addr[ETH_ALEN+2]; 955 uint8_t mac_addr[ETH_ALEN+2];
956} nx_mac_list_t; 956} nx_mac_list_t;
957 957
958struct nx_vlan_ip_list { 958struct nx_ip_list {
959 struct list_head list; 959 struct list_head list;
960 __be32 ip_addr; 960 __be32 ip_addr;
961 bool master;
961}; 962};
962 963
963/* 964/*
@@ -1605,7 +1606,7 @@ struct netxen_adapter {
1605 struct net_device *netdev; 1606 struct net_device *netdev;
1606 struct pci_dev *pdev; 1607 struct pci_dev *pdev;
1607 struct list_head mac_list; 1608 struct list_head mac_list;
1608 struct list_head vlan_ip_list; 1609 struct list_head ip_list;
1609 1610
1610 spinlock_t tx_clean_lock; 1611 spinlock_t tx_clean_lock;
1611 1612
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index 501f49207da5..7867aebc05f2 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -90,7 +90,7 @@ static irqreturn_t netxen_intr(int irq, void *data);
90static irqreturn_t netxen_msi_intr(int irq, void *data); 90static irqreturn_t netxen_msi_intr(int irq, void *data);
91static irqreturn_t netxen_msix_intr(int irq, void *data); 91static irqreturn_t netxen_msix_intr(int irq, void *data);
92 92
93static void netxen_free_vlan_ip_list(struct netxen_adapter *); 93static void netxen_free_ip_list(struct netxen_adapter *, bool);
94static void netxen_restore_indev_addr(struct net_device *dev, unsigned long); 94static void netxen_restore_indev_addr(struct net_device *dev, unsigned long);
95static struct rtnl_link_stats64 *netxen_nic_get_stats(struct net_device *dev, 95static struct rtnl_link_stats64 *netxen_nic_get_stats(struct net_device *dev,
96 struct rtnl_link_stats64 *stats); 96 struct rtnl_link_stats64 *stats);
@@ -1450,7 +1450,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1450 1450
1451 spin_lock_init(&adapter->tx_clean_lock); 1451 spin_lock_init(&adapter->tx_clean_lock);
1452 INIT_LIST_HEAD(&adapter->mac_list); 1452 INIT_LIST_HEAD(&adapter->mac_list);
1453 INIT_LIST_HEAD(&adapter->vlan_ip_list); 1453 INIT_LIST_HEAD(&adapter->ip_list);
1454 1454
1455 err = netxen_setup_pci_map(adapter); 1455 err = netxen_setup_pci_map(adapter);
1456 if (err) 1456 if (err)
@@ -1585,7 +1585,7 @@ static void netxen_nic_remove(struct pci_dev *pdev)
1585 1585
1586 cancel_work_sync(&adapter->tx_timeout_task); 1586 cancel_work_sync(&adapter->tx_timeout_task);
1587 1587
1588 netxen_free_vlan_ip_list(adapter); 1588 netxen_free_ip_list(adapter, false);
1589 netxen_nic_detach(adapter); 1589 netxen_nic_detach(adapter);
1590 1590
1591 nx_decr_dev_ref_cnt(adapter); 1591 nx_decr_dev_ref_cnt(adapter);
@@ -3137,62 +3137,77 @@ netxen_destip_supported(struct netxen_adapter *adapter)
3137} 3137}
3138 3138
3139static void 3139static void
3140netxen_free_vlan_ip_list(struct netxen_adapter *adapter) 3140netxen_free_ip_list(struct netxen_adapter *adapter, bool master)
3141{ 3141{
3142 struct nx_vlan_ip_list *cur; 3142 struct nx_ip_list *cur, *tmp_cur;
3143 struct list_head *head = &adapter->vlan_ip_list;
3144 3143
3145 while (!list_empty(head)) { 3144 list_for_each_entry_safe(cur, tmp_cur, &adapter->ip_list, list) {
3146 cur = list_entry(head->next, struct nx_vlan_ip_list, list); 3145 if (master) {
3147 netxen_config_ipaddr(adapter, cur->ip_addr, NX_IP_DOWN); 3146 if (cur->master) {
3148 list_del(&cur->list); 3147 netxen_config_ipaddr(adapter, cur->ip_addr,
3149 kfree(cur); 3148 NX_IP_DOWN);
3149 list_del(&cur->list);
3150 kfree(cur);
3151 }
3152 } else {
3153 netxen_config_ipaddr(adapter, cur->ip_addr, NX_IP_DOWN);
3154 list_del(&cur->list);
3155 kfree(cur);
3156 }
3150 } 3157 }
3151
3152} 3158}
3153static void 3159
3154netxen_list_config_vlan_ip(struct netxen_adapter *adapter, 3160static bool
3161netxen_list_config_ip(struct netxen_adapter *adapter,
3155 struct in_ifaddr *ifa, unsigned long event) 3162 struct in_ifaddr *ifa, unsigned long event)
3156{ 3163{
3157 struct net_device *dev; 3164 struct net_device *dev;
3158 struct nx_vlan_ip_list *cur, *tmp_cur; 3165 struct nx_ip_list *cur, *tmp_cur;
3159 struct list_head *head; 3166 struct list_head *head;
3167 bool ret = false;
3160 3168
3161 dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL; 3169 dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
3162 3170
3163 if (dev == NULL) 3171 if (dev == NULL)
3164 return; 3172 goto out;
3165
3166 if (!is_vlan_dev(dev))
3167 return;
3168 3173
3169 switch (event) { 3174 switch (event) {
3170 case NX_IP_UP: 3175 case NX_IP_UP:
3171 list_for_each(head, &adapter->vlan_ip_list) { 3176 list_for_each(head, &adapter->ip_list) {
3172 cur = list_entry(head, struct nx_vlan_ip_list, list); 3177 cur = list_entry(head, struct nx_ip_list, list);
3173 3178
3174 if (cur->ip_addr == ifa->ifa_address) 3179 if (cur->ip_addr == ifa->ifa_address)
3175 return; 3180 goto out;
3176 } 3181 }
3177 3182
3178 cur = kzalloc(sizeof(struct nx_vlan_ip_list), GFP_ATOMIC); 3183 cur = kzalloc(sizeof(struct nx_ip_list), GFP_ATOMIC);
3179 if (cur == NULL) 3184 if (cur == NULL)
3180 return; 3185 goto out;
3181 3186 if (dev->priv_flags & IFF_802_1Q_VLAN)
3187 dev = vlan_dev_real_dev(dev);
3188 cur->master = !!netif_is_bond_master(dev);
3182 cur->ip_addr = ifa->ifa_address; 3189 cur->ip_addr = ifa->ifa_address;
3183 list_add_tail(&cur->list, &adapter->vlan_ip_list); 3190 list_add_tail(&cur->list, &adapter->ip_list);
3191 netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_UP);
3192 ret = true;
3184 break; 3193 break;
3185 case NX_IP_DOWN: 3194 case NX_IP_DOWN:
3186 list_for_each_entry_safe(cur, tmp_cur, 3195 list_for_each_entry_safe(cur, tmp_cur,
3187 &adapter->vlan_ip_list, list) { 3196 &adapter->ip_list, list) {
3188 if (cur->ip_addr == ifa->ifa_address) { 3197 if (cur->ip_addr == ifa->ifa_address) {
3189 list_del(&cur->list); 3198 list_del(&cur->list);
3190 kfree(cur); 3199 kfree(cur);
3200 netxen_config_ipaddr(adapter, ifa->ifa_address,
3201 NX_IP_DOWN);
3202 ret = true;
3191 break; 3203 break;
3192 } 3204 }
3193 } 3205 }
3194 } 3206 }
3207out:
3208 return ret;
3195} 3209}
3210
3196static void 3211static void
3197netxen_config_indev_addr(struct netxen_adapter *adapter, 3212netxen_config_indev_addr(struct netxen_adapter *adapter,
3198 struct net_device *dev, unsigned long event) 3213 struct net_device *dev, unsigned long event)
@@ -3209,14 +3224,10 @@ netxen_config_indev_addr(struct netxen_adapter *adapter,
3209 for_ifa(indev) { 3224 for_ifa(indev) {
3210 switch (event) { 3225 switch (event) {
3211 case NETDEV_UP: 3226 case NETDEV_UP:
3212 netxen_config_ipaddr(adapter, 3227 netxen_list_config_ip(adapter, ifa, NX_IP_UP);
3213 ifa->ifa_address, NX_IP_UP);
3214 netxen_list_config_vlan_ip(adapter, ifa, NX_IP_UP);
3215 break; 3228 break;
3216 case NETDEV_DOWN: 3229 case NETDEV_DOWN:
3217 netxen_config_ipaddr(adapter, 3230 netxen_list_config_ip(adapter, ifa, NX_IP_DOWN);
3218 ifa->ifa_address, NX_IP_DOWN);
3219 netxen_list_config_vlan_ip(adapter, ifa, NX_IP_DOWN);
3220 break; 3231 break;
3221 default: 3232 default:
3222 break; 3233 break;
@@ -3231,23 +3242,78 @@ netxen_restore_indev_addr(struct net_device *netdev, unsigned long event)
3231 3242
3232{ 3243{
3233 struct netxen_adapter *adapter = netdev_priv(netdev); 3244 struct netxen_adapter *adapter = netdev_priv(netdev);
3234 struct nx_vlan_ip_list *pos, *tmp_pos; 3245 struct nx_ip_list *pos, *tmp_pos;
3235 unsigned long ip_event; 3246 unsigned long ip_event;
3236 3247
3237 ip_event = (event == NETDEV_UP) ? NX_IP_UP : NX_IP_DOWN; 3248 ip_event = (event == NETDEV_UP) ? NX_IP_UP : NX_IP_DOWN;
3238 netxen_config_indev_addr(adapter, netdev, event); 3249 netxen_config_indev_addr(adapter, netdev, event);
3239 3250
3240 list_for_each_entry_safe(pos, tmp_pos, &adapter->vlan_ip_list, list) { 3251 list_for_each_entry_safe(pos, tmp_pos, &adapter->ip_list, list) {
3241 netxen_config_ipaddr(adapter, pos->ip_addr, ip_event); 3252 netxen_config_ipaddr(adapter, pos->ip_addr, ip_event);
3242 } 3253 }
3243} 3254}
3244 3255
3256static inline bool
3257netxen_config_checkdev(struct net_device *dev)
3258{
3259 struct netxen_adapter *adapter;
3260
3261 if (!is_netxen_netdev(dev))
3262 return false;
3263 adapter = netdev_priv(dev);
3264 if (!adapter)
3265 return false;
3266 if (!netxen_destip_supported(adapter))
3267 return false;
3268 if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
3269 return false;
3270
3271 return true;
3272}
3273
3274/**
3275 * netxen_config_master - configure addresses based on master
3276 * @dev: netxen device
3277 * @event: netdev event
3278 */
3279static void netxen_config_master(struct net_device *dev, unsigned long event)
3280{
3281 struct net_device *master, *slave;
3282 struct netxen_adapter *adapter = netdev_priv(dev);
3283
3284 rcu_read_lock();
3285 master = netdev_master_upper_dev_get_rcu(dev);
3286 /*
3287 * This is the case where the netxen nic is being
3288 * enslaved and is dev_open()ed in bond_enslave()
3289 * Now we should program the bond's (and its vlans')
3290 * addresses in the netxen NIC.
3291 */
3292 if (master && netif_is_bond_master(master) &&
3293 !netif_is_bond_slave(dev)) {
3294 netxen_config_indev_addr(adapter, master, event);
3295 for_each_netdev_rcu(&init_net, slave)
3296 if (slave->priv_flags & IFF_802_1Q_VLAN &&
3297 vlan_dev_real_dev(slave) == master)
3298 netxen_config_indev_addr(adapter, slave, event);
3299 }
3300 rcu_read_unlock();
3301 /*
3302 * This is the case where the netxen nic is being
3303 * released and is dev_close()ed in bond_release()
3304 * just before IFF_BONDING is stripped.
3305 */
3306 if (!master && dev->priv_flags & IFF_BONDING)
3307 netxen_free_ip_list(adapter, true);
3308}
3309
3245static int netxen_netdev_event(struct notifier_block *this, 3310static int netxen_netdev_event(struct notifier_block *this,
3246 unsigned long event, void *ptr) 3311 unsigned long event, void *ptr)
3247{ 3312{
3248 struct netxen_adapter *adapter; 3313 struct netxen_adapter *adapter;
3249 struct net_device *dev = (struct net_device *)ptr; 3314 struct net_device *dev = (struct net_device *)ptr;
3250 struct net_device *orig_dev = dev; 3315 struct net_device *orig_dev = dev;
3316 struct net_device *slave;
3251 3317
3252recheck: 3318recheck:
3253 if (dev == NULL) 3319 if (dev == NULL)
@@ -3257,19 +3323,28 @@ recheck:
3257 dev = vlan_dev_real_dev(dev); 3323 dev = vlan_dev_real_dev(dev);
3258 goto recheck; 3324 goto recheck;
3259 } 3325 }
3260 3326 if (event == NETDEV_UP || event == NETDEV_DOWN) {
3261 if (!is_netxen_netdev(dev)) 3327 /* If this is a bonding device, look for netxen-based slaves*/
3262 goto done; 3328 if (netif_is_bond_master(dev)) {
3263 3329 rcu_read_lock();
3264 adapter = netdev_priv(dev); 3330 for_each_netdev_in_bond_rcu(dev, slave) {
3265 3331 if (!netxen_config_checkdev(slave))
3266 if (!adapter) 3332 continue;
3267 goto done; 3333 adapter = netdev_priv(slave);
3268 3334 netxen_config_indev_addr(adapter,
3269 if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) 3335 orig_dev, event);
3270 goto done; 3336 }
3271 3337 rcu_read_unlock();
3272 netxen_config_indev_addr(adapter, orig_dev, event); 3338 } else {
3339 if (!netxen_config_checkdev(dev))
3340 goto done;
3341 adapter = netdev_priv(dev);
3342 /* Act only if the actual netxen is the target */
3343 if (orig_dev == dev)
3344 netxen_config_master(dev, event);
3345 netxen_config_indev_addr(adapter, orig_dev, event);
3346 }
3347 }
3273done: 3348done:
3274 return NOTIFY_DONE; 3349 return NOTIFY_DONE;
3275} 3350}
@@ -3279,12 +3354,12 @@ netxen_inetaddr_event(struct notifier_block *this,
3279 unsigned long event, void *ptr) 3354 unsigned long event, void *ptr)
3280{ 3355{
3281 struct netxen_adapter *adapter; 3356 struct netxen_adapter *adapter;
3282 struct net_device *dev; 3357 struct net_device *dev, *slave;
3283
3284 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; 3358 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
3359 unsigned long ip_event;
3285 3360
3286 dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL; 3361 dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
3287 3362 ip_event = (event == NETDEV_UP) ? NX_IP_UP : NX_IP_DOWN;
3288recheck: 3363recheck:
3289 if (dev == NULL) 3364 if (dev == NULL)
3290 goto done; 3365 goto done;
@@ -3293,31 +3368,24 @@ recheck:
3293 dev = vlan_dev_real_dev(dev); 3368 dev = vlan_dev_real_dev(dev);
3294 goto recheck; 3369 goto recheck;
3295 } 3370 }
3296 3371 if (event == NETDEV_UP || event == NETDEV_DOWN) {
3297 if (!is_netxen_netdev(dev)) 3372 /* If this is a bonding device, look for netxen-based slaves*/
3298 goto done; 3373 if (netif_is_bond_master(dev)) {
3299 3374 rcu_read_lock();
3300 adapter = netdev_priv(dev); 3375 for_each_netdev_in_bond_rcu(dev, slave) {
3301 3376 if (!netxen_config_checkdev(slave))
3302 if (!adapter || !netxen_destip_supported(adapter)) 3377 continue;
3303 goto done; 3378 adapter = netdev_priv(slave);
3304 3379 netxen_list_config_ip(adapter, ifa, ip_event);
3305 if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) 3380 }
3306 goto done; 3381 rcu_read_unlock();
3307 3382 } else {
3308 switch (event) { 3383 if (!netxen_config_checkdev(dev))
3309 case NETDEV_UP: 3384 goto done;
3310 netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_UP); 3385 adapter = netdev_priv(dev);
3311 netxen_list_config_vlan_ip(adapter, ifa, NX_IP_UP); 3386 netxen_list_config_ip(adapter, ifa, ip_event);
3312 break; 3387 }
3313 case NETDEV_DOWN:
3314 netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_DOWN);
3315 netxen_list_config_vlan_ip(adapter, ifa, NX_IP_DOWN);
3316 break;
3317 default:
3318 break;
3319 } 3388 }
3320
3321done: 3389done:
3322 return NOTIFY_DONE; 3390 return NOTIFY_DONE;
3323} 3391}
@@ -3334,7 +3402,7 @@ static void
3334netxen_restore_indev_addr(struct net_device *dev, unsigned long event) 3402netxen_restore_indev_addr(struct net_device *dev, unsigned long event)
3335{ } 3403{ }
3336static void 3404static void
3337netxen_free_vlan_ip_list(struct netxen_adapter *adapter) 3405netxen_free_ip_list(struct netxen_adapter *adapter, bool master)
3338{ } 3406{ }
3339#endif 3407#endif
3340 3408
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index e1ebeffa6b35..9fc1ab0c8914 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1617,6 +1617,9 @@ extern seqcount_t devnet_rename_seq; /* Device rename seq */
1617 list_for_each_entry_continue(d, &(net)->dev_base_head, dev_list) 1617 list_for_each_entry_continue(d, &(net)->dev_base_head, dev_list)
1618#define for_each_netdev_continue_rcu(net, d) \ 1618#define for_each_netdev_continue_rcu(net, d) \
1619 list_for_each_entry_continue_rcu(d, &(net)->dev_base_head, dev_list) 1619 list_for_each_entry_continue_rcu(d, &(net)->dev_base_head, dev_list)
1620#define for_each_netdev_in_bond_rcu(bond, slave) \
1621 for_each_netdev_rcu(&init_net, slave) \
1622 if (netdev_master_upper_dev_get_rcu(slave) == bond)
1620#define net_device_entry(lh) list_entry(lh, struct net_device, dev_list) 1623#define net_device_entry(lh) list_entry(lh, struct net_device, dev_list)
1621 1624
1622static inline struct net_device *next_net_device(struct net_device *dev) 1625static inline struct net_device *next_net_device(struct net_device *dev)
@@ -2774,6 +2777,11 @@ static inline void netif_set_gso_max_size(struct net_device *dev,
2774 dev->gso_max_size = size; 2777 dev->gso_max_size = size;
2775} 2778}
2776 2779
2780static inline bool netif_is_bond_master(struct net_device *dev)
2781{
2782 return dev->flags & IFF_MASTER && dev->priv_flags & IFF_BONDING;
2783}
2784
2777static inline bool netif_is_bond_slave(struct net_device *dev) 2785static inline bool netif_is_bond_slave(struct net_device *dev)
2778{ 2786{
2779 return dev->flags & IFF_SLAVE && dev->priv_flags & IFF_BONDING; 2787 return dev->flags & IFF_SLAVE && dev->priv_flags & IFF_BONDING;