l2t.c revision 4d22de3e6cc4a09c369b504cd8bcde3385a974cd
14d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray/* 24d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Copyright (c) 2006 Chelsio, Inc. All rights reserved. 34d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. 44d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * 54d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * This software is available to you under a choice of one of two 64d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * licenses. You may choose to be licensed under the terms of the GNU 74d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * General Public License (GPL) Version 2, available from the file 84d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * COPYING in the main directory of this source tree, or the 94d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * OpenIB.org BSD license below: 104d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * 114d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Redistribution and use in source and binary forms, with or 124d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * without modification, are permitted provided that the following 134d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * conditions are met: 144d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * 154d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * - Redistributions of source code must retain the above 164d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * copyright notice, this list of conditions and the following 174d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * disclaimer. 184d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * 194d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * - Redistributions in binary form must reproduce the above 204d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * copyright notice, this list of conditions and the following 214d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * disclaimer in the documentation and/or other materials 224d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * provided with the distribution. 234d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * 244d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 254d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 264d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 274d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 284d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 294d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 304d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 314d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * SOFTWARE. 324d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray */ 334d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray#include <linux/skbuff.h> 344d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray#include <linux/netdevice.h> 354d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray#include <linux/if.h> 364d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray#include <linux/if_vlan.h> 374d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray#include <linux/jhash.h> 384d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray#include <net/neighbour.h> 394d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray#include "common.h" 404d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray#include "t3cdev.h" 414d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray#include "cxgb3_defs.h" 424d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray#include "l2t.h" 434d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray#include "t3_cpl.h" 444d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray#include "firmware_exports.h" 454d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 464d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray#define VLAN_NONE 0xfff 474d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 484d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray/* 494d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Module locking notes: There is a RW lock protecting the L2 table as a 504d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * whole plus a spinlock per L2T entry. Entry lookups and allocations happen 514d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * under the protection of the table lock, individual entry changes happen 524d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * while holding that entry's spinlock. The table lock nests outside the 534d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * entry locks. Allocations of new entries take the table lock as writers so 544d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * no other lookups can happen while allocating new entries. Entry updates 554d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * take the table lock as readers so multiple entries can be updated in 564d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * parallel. An L2T entry can be dropped by decrementing its reference count 574d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * and therefore can happen in parallel with entry allocation but no entry 584d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * can change state or increment its ref count during allocation as both of 594d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * these perform lookups. 604d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray */ 614d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 624d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Raystatic inline unsigned int vlan_prio(const struct l2t_entry *e) 634d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 644d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return e->vlan >> 13; 654d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 664d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 674d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Raystatic inline unsigned int arp_hash(u32 key, int ifindex, 684d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray const struct l2t_data *d) 694d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 704d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return jhash_2words(key, ifindex, 0) & (d->nentries - 1); 714d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 724d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 734d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Raystatic inline void neigh_replace(struct l2t_entry *e, struct neighbour *n) 744d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 754d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray neigh_hold(n); 764d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (e->neigh) 774d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray neigh_release(e->neigh); 784d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->neigh = n; 794d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 804d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 814d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray/* 824d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Set up an L2T entry and send any packets waiting in the arp queue. The 834d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * supplied skb is used for the CPL_L2T_WRITE_REQ. Must be called with the 844d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * entry locked. 854d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray */ 864d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Raystatic int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb, 874d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct l2t_entry *e) 884d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 894d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct cpl_l2t_write_req *req; 904d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 914d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (!skb) { 924d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray skb = alloc_skb(sizeof(*req), GFP_ATOMIC); 934d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (!skb) 944d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return -ENOMEM; 954d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 964d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 974d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); 984d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 994d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx)); 1004d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) | 1014d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray V_L2T_W_VLAN(e->vlan & VLAN_VID_MASK) | 1024d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray V_L2T_W_PRIO(vlan_prio(e))); 1034d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac)); 1044d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); 1054d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray skb->priority = CPL_PRIORITY_CONTROL; 1064d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray cxgb3_ofld_send(dev, skb); 1074d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray while (e->arpq_head) { 1084d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray skb = e->arpq_head; 1094d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->arpq_head = skb->next; 1104d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray skb->next = NULL; 1114d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray cxgb3_ofld_send(dev, skb); 1124d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 1134d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->arpq_tail = NULL; 1144d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->state = L2T_STATE_VALID; 1154d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 1164d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return 0; 1174d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 1184d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 1194d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray/* 1204d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Add a packet to the an L2T entry's queue of packets awaiting resolution. 1214d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Must be called with the entry's lock held. 1224d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray */ 1234d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Raystatic inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb) 1244d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 1254d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray skb->next = NULL; 1264d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (e->arpq_head) 1274d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->arpq_tail->next = skb; 1284d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray else 1294d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->arpq_head = skb; 1304d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->arpq_tail = skb; 1314d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 1324d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 1334d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Rayint t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb, 1344d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct l2t_entry *e) 1354d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 1364d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Rayagain: 1374d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray switch (e->state) { 1384d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ 1394d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray neigh_event_send(e->neigh, NULL); 1404d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_lock_bh(&e->lock); 1414d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (e->state == L2T_STATE_STALE) 1424d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->state = L2T_STATE_VALID; 1434d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_unlock_bh(&e->lock); 1444d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray case L2T_STATE_VALID: /* fast-path, send the packet on */ 1454d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return cxgb3_ofld_send(dev, skb); 1464d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray case L2T_STATE_RESOLVING: 1474d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_lock_bh(&e->lock); 1484d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (e->state != L2T_STATE_RESOLVING) { 1494d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray /* ARP already completed */ 1504d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_unlock_bh(&e->lock); 1514d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray goto again; 1524d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 1534d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray arpq_enqueue(e, skb); 1544d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_unlock_bh(&e->lock); 1554d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 1564d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray /* 1574d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Only the first packet added to the arpq should kick off 1584d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * resolution. However, because the alloc_skb below can fail, 1594d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * we allow each packet added to the arpq to retry resolution 1604d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * as a way of recovering from transient memory exhaustion. 1614d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * A better way would be to use a work request to retry L2T 1624d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * entries when there's no memory. 1634d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray */ 1644d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (!neigh_event_send(e->neigh, NULL)) { 1654d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray skb = alloc_skb(sizeof(struct cpl_l2t_write_req), 1664d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray GFP_ATOMIC); 1674d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (!skb) 1684d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray break; 1694d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 1704d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_lock_bh(&e->lock); 1714d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (e->arpq_head) 1724d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray setup_l2e_send_pending(dev, skb, e); 1734d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray else /* we lost the race */ 1744d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray __kfree_skb(skb); 1754d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_unlock_bh(&e->lock); 1764d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 1774d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 1784d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return 0; 1794d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 1804d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 1814d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le RayEXPORT_SYMBOL(t3_l2t_send_slow); 1824d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 1834d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Rayvoid t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e) 1844d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 1854d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Rayagain: 1864d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray switch (e->state) { 1874d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ 1884d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray neigh_event_send(e->neigh, NULL); 1894d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_lock_bh(&e->lock); 1904d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (e->state == L2T_STATE_STALE) { 1914d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->state = L2T_STATE_VALID; 1924d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 1934d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_unlock_bh(&e->lock); 1944d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return; 1954d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray case L2T_STATE_VALID: /* fast-path, send the packet on */ 1964d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return; 1974d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray case L2T_STATE_RESOLVING: 1984d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_lock_bh(&e->lock); 1994d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (e->state != L2T_STATE_RESOLVING) { 2004d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray /* ARP already completed */ 2014d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_unlock_bh(&e->lock); 2024d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray goto again; 2034d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 2044d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_unlock_bh(&e->lock); 2054d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 2064d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray /* 2074d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Only the first packet added to the arpq should kick off 2084d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * resolution. However, because the alloc_skb below can fail, 2094d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * we allow each packet added to the arpq to retry resolution 2104d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * as a way of recovering from transient memory exhaustion. 2114d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * A better way would be to use a work request to retry L2T 2124d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * entries when there's no memory. 2134d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray */ 2144d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray neigh_event_send(e->neigh, NULL); 2154d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 2164d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return; 2174d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 2184d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 2194d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le RayEXPORT_SYMBOL(t3_l2t_send_event); 2204d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 2214d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray/* 2224d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Allocate a free L2T entry. Must be called with l2t_data.lock held. 2234d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray */ 2244d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Raystatic struct l2t_entry *alloc_l2e(struct l2t_data *d) 2254d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 2264d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct l2t_entry *end, *e, **p; 2274d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 2284d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (!atomic_read(&d->nfree)) 2294d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return NULL; 2304d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 2314d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray /* there's definitely a free entry */ 2324d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray for (e = d->rover, end = &d->l2tab[d->nentries]; e != end; ++e) 2334d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (atomic_read(&e->refcnt) == 0) 2344d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray goto found; 2354d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 2364d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray for (e = &d->l2tab[1]; atomic_read(&e->refcnt); ++e) ; 2374d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Rayfound: 2384d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray d->rover = e + 1; 2394d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray atomic_dec(&d->nfree); 2404d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 2414d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray /* 2424d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * The entry we found may be an inactive entry that is 2434d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * presently in the hash table. We need to remove it. 2444d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray */ 2454d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (e->state != L2T_STATE_UNUSED) { 2464d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray int hash = arp_hash(e->addr, e->ifindex, d); 2474d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 2484d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray for (p = &d->l2tab[hash].first; *p; p = &(*p)->next) 2494d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (*p == e) { 2504d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray *p = e->next; 2514d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray break; 2524d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 2534d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->state = L2T_STATE_UNUSED; 2544d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 2554d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return e; 2564d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 2574d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 2584d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray/* 2594d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Called when an L2T entry has no more users. The entry is left in the hash 2604d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * table since it is likely to be reused but we also bump nfree to indicate 2614d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * that the entry can be reallocated for a different neighbor. We also drop 2624d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * the existing neighbor reference in case the neighbor is going away and is 2634d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * waiting on our reference. 2644d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * 2654d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Because entries can be reallocated to other neighbors once their ref count 2664d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * drops to 0 we need to take the entry's lock to avoid races with a new 2674d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * incarnation. 2684d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray */ 2694d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Rayvoid t3_l2e_free(struct l2t_data *d, struct l2t_entry *e) 2704d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 2714d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_lock_bh(&e->lock); 2724d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ 2734d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (e->neigh) { 2744d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray neigh_release(e->neigh); 2754d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->neigh = NULL; 2764d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 2774d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 2784d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_unlock_bh(&e->lock); 2794d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray atomic_inc(&d->nfree); 2804d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 2814d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 2824d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le RayEXPORT_SYMBOL(t3_l2e_free); 2834d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 2844d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray/* 2854d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Update an L2T entry that was previously used for the same next hop as neigh. 2864d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Must be called with softirqs disabled. 2874d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray */ 2884d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Raystatic inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh) 2894d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 2904d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray unsigned int nud_state; 2914d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 2924d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_lock(&e->lock); /* avoid race with t3_l2t_free */ 2934d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 2944d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (neigh != e->neigh) 2954d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray neigh_replace(e, neigh); 2964d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray nud_state = neigh->nud_state; 2974d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) || 2984d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray !(nud_state & NUD_VALID)) 2994d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->state = L2T_STATE_RESOLVING; 3004d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray else if (nud_state & NUD_CONNECTED) 3014d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->state = L2T_STATE_VALID; 3024d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray else 3034d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->state = L2T_STATE_STALE; 3044d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_unlock(&e->lock); 3054d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 3064d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 3074d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Raystruct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, 3084d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct net_device *dev) 3094d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 3104d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct l2t_entry *e; 3114d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct l2t_data *d = L2DATA(cdev); 3124d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray u32 addr = *(u32 *) neigh->primary_key; 3134d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray int ifidx = neigh->dev->ifindex; 3144d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray int hash = arp_hash(addr, ifidx, d); 3154d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct port_info *p = netdev_priv(dev); 3164d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray int smt_idx = p->port_id; 3174d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 3184d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray write_lock_bh(&d->lock); 3194d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray for (e = d->l2tab[hash].first; e; e = e->next) 3204d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (e->addr == addr && e->ifindex == ifidx && 3214d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->smt_idx == smt_idx) { 3224d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray l2t_hold(d, e); 3234d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (atomic_read(&e->refcnt) == 1) 3244d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray reuse_entry(e, neigh); 3254d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray goto done; 3264d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 3274d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 3284d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray /* Need to allocate a new entry */ 3294d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e = alloc_l2e(d); 3304d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (e) { 3314d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_lock(&e->lock); /* avoid race with t3_l2t_free */ 3324d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->next = d->l2tab[hash].first; 3334d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray d->l2tab[hash].first = e; 3344d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->state = L2T_STATE_RESOLVING; 3354d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->addr = addr; 3364d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->ifindex = ifidx; 3374d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->smt_idx = smt_idx; 3384d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray atomic_set(&e->refcnt, 1); 3394d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray neigh_replace(e, neigh); 3404d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (neigh->dev->priv_flags & IFF_802_1Q_VLAN) 3414d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->vlan = VLAN_DEV_INFO(neigh->dev)->vlan_id; 3424d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray else 3434d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->vlan = VLAN_NONE; 3444d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_unlock(&e->lock); 3454d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 3464d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Raydone: 3474d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray write_unlock_bh(&d->lock); 3484d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return e; 3494d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 3504d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 3514d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le RayEXPORT_SYMBOL(t3_l2t_get); 3524d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 3534d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray/* 3544d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Called when address resolution fails for an L2T entry to handle packets 3554d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * on the arpq head. If a packet specifies a failure handler it is invoked, 3564d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * otherwise the packets is sent to the offload device. 3574d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * 3584d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * XXX: maybe we should abandon the latter behavior and just require a failure 3594d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * handler. 3604d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray */ 3614d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Raystatic void handle_failed_resolution(struct t3cdev *dev, struct sk_buff *arpq) 3624d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 3634d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray while (arpq) { 3644d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct sk_buff *skb = arpq; 3654d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct l2t_skb_cb *cb = L2T_SKB_CB(skb); 3664d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 3674d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray arpq = skb->next; 3684d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray skb->next = NULL; 3694d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (cb->arp_failure_handler) 3704d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray cb->arp_failure_handler(dev, skb); 3714d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray else 3724d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray cxgb3_ofld_send(dev, skb); 3734d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 3744d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 3754d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 3764d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray/* 3774d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * Called when the host's ARP layer makes a change to some entry that is 3784d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray * loaded into the HW L2 table. 3794d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray */ 3804d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Rayvoid t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh) 3814d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 3824d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct l2t_entry *e; 3834d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct sk_buff *arpq = NULL; 3844d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct l2t_data *d = L2DATA(dev); 3854d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray u32 addr = *(u32 *) neigh->primary_key; 3864d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray int ifidx = neigh->dev->ifindex; 3874d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray int hash = arp_hash(addr, ifidx, d); 3884d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 3894d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray read_lock_bh(&d->lock); 3904d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray for (e = d->l2tab[hash].first; e; e = e->next) 3914d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (e->addr == addr && e->ifindex == ifidx) { 3924d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_lock(&e->lock); 3934d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray goto found; 3944d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 3954d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray read_unlock_bh(&d->lock); 3964d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return; 3974d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 3984d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Rayfound: 3994d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray read_unlock(&d->lock); 4004d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (atomic_read(&e->refcnt)) { 4014d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (neigh != e->neigh) 4024d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray neigh_replace(e, neigh); 4034d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 4044d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (e->state == L2T_STATE_RESOLVING) { 4054d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (neigh->nud_state & NUD_FAILED) { 4064d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray arpq = e->arpq_head; 4074d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->arpq_head = e->arpq_tail = NULL; 4084d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } else if (neigh_is_connected(neigh)) 4094d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray setup_l2e_send_pending(dev, NULL, e); 4104d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } else { 4114d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray e->state = neigh_is_connected(neigh) ? 4124d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray L2T_STATE_VALID : L2T_STATE_STALE; 4134d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (memcmp(e->dmac, neigh->ha, 6)) 4144d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray setup_l2e_send_pending(dev, NULL, e); 4154d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 4164d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 4174d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_unlock_bh(&e->lock); 4184d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 4194d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (arpq) 4204d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray handle_failed_resolution(dev, arpq); 4214d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 4224d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 4234d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Raystruct l2t_data *t3_init_l2t(unsigned int l2t_capacity) 4244d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 4254d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray struct l2t_data *d; 4264d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray int i, size = sizeof(*d) + l2t_capacity * sizeof(struct l2t_entry); 4274d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 4284d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray d = cxgb_alloc_mem(size); 4294d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray if (!d) 4304d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return NULL; 4314d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 4324d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray d->nentries = l2t_capacity; 4334d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray d->rover = &d->l2tab[1]; /* entry 0 is not used */ 4344d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray atomic_set(&d->nfree, l2t_capacity - 1); 4354d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray rwlock_init(&d->lock); 4364d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 4374d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray for (i = 0; i < l2t_capacity; ++i) { 4384d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray d->l2tab[i].idx = i; 4394d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray d->l2tab[i].state = L2T_STATE_UNUSED; 4404d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray spin_lock_init(&d->l2tab[i].lock); 4414d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray atomic_set(&d->l2tab[i].refcnt, 0); 4424d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray } 4434d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray return d; 4444d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 4454d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 4464d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Rayvoid t3_free_l2t(struct l2t_data *d) 4474d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray{ 4484d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray cxgb_free_mem(d); 4494d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray} 4504d22de3e6cc4a09c369b504cd8bcde3385a974cdDivy Le Ray 451