aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShahed Shaikh <shahed.shaikh@qlogic.com>2013-02-18 08:22:37 -0500
committerDavid S. Miller <davem@davemloft.net>2013-02-19 00:47:01 -0500
commit53643a75b147bfb30f3488a4eaf5a59bfeeb39bb (patch)
tree7235a9db539637feb24c09e34b6ea5b2ff12dc35
parent99e8587900a3d32b1eaa3a92da90b49e9d4ff765 (diff)
qlcnic: fix ping resumption to a VM after a live migration
Delete the MAC address of a VM, from the adapter's embedded switch, after the VM had been migrated out of this adapter/server. Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com> Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com> Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h5
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c18
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c145
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c21
4 files changed, 177 insertions, 12 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 61b594c6d9d7..01e9ea149da0 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1008,9 +1008,12 @@ struct qlcnic_adapter {
1008 struct delayed_work idc_aen_work; 1008 struct delayed_work idc_aen_work;
1009 1009
1010 struct qlcnic_filter_hash fhash; 1010 struct qlcnic_filter_hash fhash;
1011 struct qlcnic_filter_hash rx_fhash;
1011 1012
1012 spinlock_t tx_clean_lock; 1013 spinlock_t tx_clean_lock;
1013 spinlock_t mac_learn_lock; 1014 spinlock_t mac_learn_lock;
1015 /* spinlock for catching rcv filters for eswitch traffic */
1016 spinlock_t rx_mac_learn_lock;
1014 u32 file_prd_off; /*File fw product offset*/ 1017 u32 file_prd_off; /*File fw product offset*/
1015 u32 fw_version; 1018 u32 fw_version;
1016 const struct firmware *fw; 1019 const struct firmware *fw;
@@ -1506,6 +1509,8 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *);
1506int qlcnic_set_default_offload_settings(struct qlcnic_adapter *); 1509int qlcnic_set_default_offload_settings(struct qlcnic_adapter *);
1507int qlcnic_reset_npar_config(struct qlcnic_adapter *); 1510int qlcnic_reset_npar_config(struct qlcnic_adapter *);
1508int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *); 1511int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *);
1512void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int,
1513 __le16);
1509/* 1514/*
1510 * QLOGIC Board information 1515 * QLOGIC Board information
1511 */ 1516 */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 51716ab8739a..325e11e1ce0f 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -578,7 +578,8 @@ void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)
578 struct qlcnic_filter *tmp_fil; 578 struct qlcnic_filter *tmp_fil;
579 struct hlist_node *tmp_hnode, *n; 579 struct hlist_node *tmp_hnode, *n;
580 struct hlist_head *head; 580 struct hlist_head *head;
581 int i, time; 581 int i;
582 unsigned long time;
582 u8 cmd; 583 u8 cmd;
583 584
584 for (i = 0; i < adapter->fhash.fbucket_size; i++) { 585 for (i = 0; i < adapter->fhash.fbucket_size; i++) {
@@ -600,6 +601,21 @@ void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)
600 } 601 }
601 } 602 }
602 } 603 }
604 for (i = 0; i < adapter->rx_fhash.fbucket_size; i++) {
605 head = &(adapter->rx_fhash.fhead[i]);
606
607 hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode)
608 {
609 time = tmp_fil->ftime;
610 if (jiffies > (QLCNIC_FILTER_AGE * HZ + time)) {
611 spin_lock_bh(&adapter->rx_mac_learn_lock);
612 adapter->rx_fhash.fnum--;
613 hlist_del(&tmp_fil->fnode);
614 spin_unlock_bh(&adapter->rx_mac_learn_lock);
615 kfree(tmp_fil);
616 }
617 }
618 }
603} 619}
604 620
605void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter) 621void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index 2990f45df787..6387e0cc3ea9 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -152,6 +152,89 @@ static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter,
152 return handle; 152 return handle;
153} 153}
154 154
155static inline int qlcnic_82xx_is_lb_pkt(u64 sts_data)
156{
157 return (qlcnic_get_sts_status(sts_data) == STATUS_CKSUM_LOOP) ? 1 : 0;
158}
159
160void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
161 int loopback_pkt, __le16 vlan_id)
162{
163 struct ethhdr *phdr = (struct ethhdr *)(skb->data);
164 struct qlcnic_filter *fil, *tmp_fil;
165 struct hlist_node *tmp_hnode, *n;
166 struct hlist_head *head;
167 unsigned long time;
168 u64 src_addr = 0;
169 u8 hindex, found = 0, op;
170 int ret;
171
172 memcpy(&src_addr, phdr->h_source, ETH_ALEN);
173
174 if (loopback_pkt) {
175 if (adapter->rx_fhash.fnum >= adapter->rx_fhash.fmax)
176 return;
177
178 hindex = qlcnic_mac_hash(src_addr) &
179 (adapter->fhash.fbucket_size - 1);
180 head = &(adapter->rx_fhash.fhead[hindex]);
181
182 hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
183 if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
184 tmp_fil->vlan_id == vlan_id) {
185 time = tmp_fil->ftime;
186 if (jiffies > (QLCNIC_READD_AGE * HZ + time))
187 tmp_fil->ftime = jiffies;
188 return;
189 }
190 }
191
192 fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
193 if (!fil)
194 return;
195
196 fil->ftime = jiffies;
197 memcpy(fil->faddr, &src_addr, ETH_ALEN);
198 fil->vlan_id = vlan_id;
199 spin_lock(&adapter->rx_mac_learn_lock);
200 hlist_add_head(&(fil->fnode), head);
201 adapter->rx_fhash.fnum++;
202 spin_unlock(&adapter->rx_mac_learn_lock);
203 } else {
204 hindex = qlcnic_mac_hash(src_addr) &
205 (adapter->fhash.fbucket_size - 1);
206 head = &(adapter->rx_fhash.fhead[hindex]);
207 spin_lock(&adapter->rx_mac_learn_lock);
208 hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
209 if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
210 tmp_fil->vlan_id == vlan_id) {
211 found = 1;
212 break;
213 }
214 }
215
216 if (!found) {
217 spin_unlock(&adapter->rx_mac_learn_lock);
218 return;
219 }
220
221 op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
222 ret = qlcnic_sre_macaddr_change(adapter, (u8 *)&src_addr,
223 vlan_id, op);
224 if (!ret) {
225 op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL;
226 ret = qlcnic_sre_macaddr_change(adapter,
227 (u8 *)&src_addr,
228 vlan_id, op);
229 if (!ret) {
230 hlist_del(&(tmp_fil->fnode));
231 adapter->rx_fhash.fnum--;
232 }
233 }
234 spin_unlock(&adapter->rx_mac_learn_lock);
235 }
236}
237
155void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr, 238void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr,
156 __le16 vlan_id) 239 __le16 vlan_id)
157{ 240{
@@ -207,9 +290,6 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
207 return; 290 return;
208 } 291 }
209 292
210 /* Only NPAR capable devices support vlan based learning */
211 if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
212 vlan_id = first_desc->vlan_TCI;
213 memcpy(&src_addr, phdr->h_source, ETH_ALEN); 293 memcpy(&src_addr, phdr->h_source, ETH_ALEN);
214 hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1); 294 hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1);
215 head = &(adapter->fhash.fhead[hindex]); 295 head = &(adapter->fhash.fhead[hindex]);
@@ -920,8 +1000,8 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
920 struct qlcnic_rx_buffer *buffer; 1000 struct qlcnic_rx_buffer *buffer;
921 struct sk_buff *skb; 1001 struct sk_buff *skb;
922 struct qlcnic_host_rds_ring *rds_ring; 1002 struct qlcnic_host_rds_ring *rds_ring;
923 int index, length, cksum, pkt_offset; 1003 int index, length, cksum, pkt_offset, is_lb_pkt;
924 u16 vid = 0xffff; 1004 u16 vid = 0xffff, t_vid;
925 1005
926 if (unlikely(ring >= adapter->max_rds_rings)) 1006 if (unlikely(ring >= adapter->max_rds_rings))
927 return NULL; 1007 return NULL;
@@ -941,6 +1021,14 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
941 if (!skb) 1021 if (!skb)
942 return buffer; 1022 return buffer;
943 1023
1024 if (adapter->drv_mac_learn &&
1025 (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
1026 t_vid = 0;
1027 is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
1028 qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
1029 cpu_to_le16(t_vid));
1030 }
1031
944 if (length > rds_ring->skb_size) 1032 if (length > rds_ring->skb_size)
945 skb_put(skb, rds_ring->skb_size); 1033 skb_put(skb, rds_ring->skb_size);
946 else 1034 else
@@ -985,8 +1073,8 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
985 struct ipv6hdr *ipv6h; 1073 struct ipv6hdr *ipv6h;
986 struct tcphdr *th; 1074 struct tcphdr *th;
987 bool push, timestamp; 1075 bool push, timestamp;
988 int index, l2_hdr_offset, l4_hdr_offset; 1076 int index, l2_hdr_offset, l4_hdr_offset, is_lb_pkt;
989 u16 lro_length, length, data_offset, vid = 0xffff; 1077 u16 lro_length, length, data_offset, t_vid, vid = 0xffff;
990 u32 seq_number; 1078 u32 seq_number;
991 1079
992 if (unlikely(ring > adapter->max_rds_rings)) 1080 if (unlikely(ring > adapter->max_rds_rings))
@@ -1011,6 +1099,14 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
1011 if (!skb) 1099 if (!skb)
1012 return buffer; 1100 return buffer;
1013 1101
1102 if (adapter->drv_mac_learn &&
1103 (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
1104 t_vid = 0;
1105 is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
1106 qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
1107 cpu_to_le16(t_vid));
1108 }
1109
1014 if (timestamp) 1110 if (timestamp)
1015 data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE; 1111 data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE;
1016 else 1112 else
@@ -1357,6 +1453,17 @@ void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter)
1357 } 1453 }
1358} 1454}
1359 1455
1456#define QLC_83XX_NORMAL_LB_PKT (1ULL << 36)
1457#define QLC_83XX_LRO_LB_PKT (1ULL << 46)
1458
1459static inline int qlcnic_83xx_is_lb_pkt(u64 sts_data, int lro_pkt)
1460{
1461 if (lro_pkt)
1462 return (sts_data & QLC_83XX_LRO_LB_PKT) ? 1 : 0;
1463 else
1464 return (sts_data & QLC_83XX_NORMAL_LB_PKT) ? 1 : 0;
1465}
1466
1360static struct qlcnic_rx_buffer * 1467static struct qlcnic_rx_buffer *
1361qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter, 1468qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
1362 struct qlcnic_host_sds_ring *sds_ring, 1469 struct qlcnic_host_sds_ring *sds_ring,
@@ -1367,8 +1474,8 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
1367 struct qlcnic_rx_buffer *buffer; 1474 struct qlcnic_rx_buffer *buffer;
1368 struct sk_buff *skb; 1475 struct sk_buff *skb;
1369 struct qlcnic_host_rds_ring *rds_ring; 1476 struct qlcnic_host_rds_ring *rds_ring;
1370 int index, length, cksum; 1477 int index, length, cksum, is_lb_pkt;
1371 u16 vid = 0xffff; 1478 u16 vid = 0xffff, t_vid;
1372 1479
1373 if (unlikely(ring >= adapter->max_rds_rings)) 1480 if (unlikely(ring >= adapter->max_rds_rings))
1374 return NULL; 1481 return NULL;
@@ -1386,6 +1493,14 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
1386 if (!skb) 1493 if (!skb)
1387 return buffer; 1494 return buffer;
1388 1495
1496 if (adapter->drv_mac_learn &&
1497 (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
1498 t_vid = 0;
1499 is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0);
1500 qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
1501 cpu_to_le16(t_vid));
1502 }
1503
1389 if (length > rds_ring->skb_size) 1504 if (length > rds_ring->skb_size)
1390 skb_put(skb, rds_ring->skb_size); 1505 skb_put(skb, rds_ring->skb_size);
1391 else 1506 else
@@ -1424,9 +1539,9 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
1424 struct tcphdr *th; 1539 struct tcphdr *th;
1425 bool push; 1540 bool push;
1426 int l2_hdr_offset, l4_hdr_offset; 1541 int l2_hdr_offset, l4_hdr_offset;
1427 int index; 1542 int index, is_lb_pkt;
1428 u16 lro_length, length, data_offset, gso_size; 1543 u16 lro_length, length, data_offset, gso_size;
1429 u16 vid = 0xffff; 1544 u16 vid = 0xffff, t_vid;
1430 1545
1431 if (unlikely(ring > adapter->max_rds_rings)) 1546 if (unlikely(ring > adapter->max_rds_rings))
1432 return NULL; 1547 return NULL;
@@ -1447,6 +1562,14 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
1447 skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK); 1562 skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
1448 if (!skb) 1563 if (!skb)
1449 return buffer; 1564 return buffer;
1565
1566 if (adapter->drv_mac_learn &&
1567 (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
1568 t_vid = 0;
1569 is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1);
1570 qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
1571 cpu_to_le16(t_vid));
1572 }
1450 if (qlcnic_83xx_is_tstamp(sts_data[1])) 1573 if (qlcnic_83xx_is_tstamp(sts_data[1]))
1451 data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE; 1574 data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE;
1452 else 1575 else
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index e03017a999b4..5d5fd06c4b42 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -2208,6 +2208,7 @@ void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)
2208 2208
2209 act_pci_func = adapter->ahw->act_pci_func; 2209 act_pci_func = adapter->ahw->act_pci_func;
2210 spin_lock_init(&adapter->mac_learn_lock); 2210 spin_lock_init(&adapter->mac_learn_lock);
2211 spin_lock_init(&adapter->rx_mac_learn_lock);
2211 2212
2212 if (qlcnic_82xx_check(adapter)) { 2213 if (qlcnic_82xx_check(adapter)) {
2213 filter_size = QLCNIC_LB_MAX_FILTERS; 2214 filter_size = QLCNIC_LB_MAX_FILTERS;
@@ -2231,6 +2232,20 @@ void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)
2231 2232
2232 for (i = 0; i < adapter->fhash.fbucket_size; i++) 2233 for (i = 0; i < adapter->fhash.fbucket_size; i++)
2233 INIT_HLIST_HEAD(&adapter->fhash.fhead[i]); 2234 INIT_HLIST_HEAD(&adapter->fhash.fhead[i]);
2235
2236 adapter->rx_fhash.fbucket_size = adapter->fhash.fbucket_size;
2237
2238 head = kcalloc(adapter->rx_fhash.fbucket_size,
2239 sizeof(struct hlist_head), GFP_ATOMIC);
2240
2241 if (!head)
2242 return;
2243
2244 adapter->rx_fhash.fmax = (filter_size / act_pci_func);
2245 adapter->rx_fhash.fhead = head;
2246
2247 for (i = 0; i < adapter->rx_fhash.fbucket_size; i++)
2248 INIT_HLIST_HEAD(&adapter->rx_fhash.fhead[i]);
2234} 2249}
2235 2250
2236static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter) 2251static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
@@ -2240,6 +2255,12 @@ static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
2240 2255
2241 adapter->fhash.fhead = NULL; 2256 adapter->fhash.fhead = NULL;
2242 adapter->fhash.fmax = 0; 2257 adapter->fhash.fmax = 0;
2258
2259 if (adapter->rx_fhash.fmax && adapter->rx_fhash.fhead)
2260 kfree(adapter->rx_fhash.fhead);
2261
2262 adapter->rx_fhash.fmax = 0;
2263 adapter->rx_fhash.fhead = NULL;
2243} 2264}
2244 2265
2245int qlcnic_check_temp(struct qlcnic_adapter *adapter) 2266int qlcnic_check_temp(struct qlcnic_adapter *adapter)