18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 338c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 348c2ecf20Sopenharmony_ci#include <linux/if.h> 358c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 368c2ecf20Sopenharmony_ci#include <linux/jhash.h> 378c2ecf20Sopenharmony_ci#include <linux/slab.h> 388c2ecf20Sopenharmony_ci#include <linux/export.h> 398c2ecf20Sopenharmony_ci#include <net/neighbour.h> 408c2ecf20Sopenharmony_ci#include "common.h" 418c2ecf20Sopenharmony_ci#include "t3cdev.h" 428c2ecf20Sopenharmony_ci#include "cxgb3_defs.h" 438c2ecf20Sopenharmony_ci#include "l2t.h" 448c2ecf20Sopenharmony_ci#include "t3_cpl.h" 458c2ecf20Sopenharmony_ci#include "firmware_exports.h" 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define VLAN_NONE 0xfff 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* 508c2ecf20Sopenharmony_ci * Module locking notes: There is a RW lock protecting the L2 table as a 518c2ecf20Sopenharmony_ci * whole plus a spinlock per L2T entry. Entry lookups and allocations happen 528c2ecf20Sopenharmony_ci * under the protection of the table lock, individual entry changes happen 538c2ecf20Sopenharmony_ci * while holding that entry's spinlock. The table lock nests outside the 548c2ecf20Sopenharmony_ci * entry locks. Allocations of new entries take the table lock as writers so 558c2ecf20Sopenharmony_ci * no other lookups can happen while allocating new entries. Entry updates 568c2ecf20Sopenharmony_ci * take the table lock as readers so multiple entries can be updated in 578c2ecf20Sopenharmony_ci * parallel. An L2T entry can be dropped by decrementing its reference count 588c2ecf20Sopenharmony_ci * and therefore can happen in parallel with entry allocation but no entry 598c2ecf20Sopenharmony_ci * can change state or increment its ref count during allocation as both of 608c2ecf20Sopenharmony_ci * these perform lookups. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic inline unsigned int vlan_prio(const struct l2t_entry *e) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci return e->vlan >> 13; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic inline unsigned int arp_hash(u32 key, int ifindex, 698c2ecf20Sopenharmony_ci const struct l2t_data *d) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci return jhash_2words(key, ifindex, 0) & (d->nentries - 1); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic inline void neigh_replace(struct l2t_entry *e, struct neighbour *n) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci neigh_hold(n); 778c2ecf20Sopenharmony_ci if (e->neigh) 788c2ecf20Sopenharmony_ci neigh_release(e->neigh); 798c2ecf20Sopenharmony_ci e->neigh = n; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* 838c2ecf20Sopenharmony_ci * Set up an L2T entry and send any packets waiting in the arp queue. The 848c2ecf20Sopenharmony_ci * supplied skb is used for the CPL_L2T_WRITE_REQ. Must be called with the 858c2ecf20Sopenharmony_ci * entry locked. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistatic int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb, 888c2ecf20Sopenharmony_ci struct l2t_entry *e) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct cpl_l2t_write_req *req; 918c2ecf20Sopenharmony_ci struct sk_buff *tmp; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (!skb) { 948c2ecf20Sopenharmony_ci skb = alloc_skb(sizeof(*req), GFP_ATOMIC); 958c2ecf20Sopenharmony_ci if (!skb) 968c2ecf20Sopenharmony_ci return -ENOMEM; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci req = __skb_put(skb, sizeof(*req)); 1008c2ecf20Sopenharmony_ci req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1018c2ecf20Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx)); 1028c2ecf20Sopenharmony_ci req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) | 1038c2ecf20Sopenharmony_ci V_L2T_W_VLAN(e->vlan & VLAN_VID_MASK) | 1048c2ecf20Sopenharmony_ci V_L2T_W_PRIO(vlan_prio(e))); 1058c2ecf20Sopenharmony_ci memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac)); 1068c2ecf20Sopenharmony_ci memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); 1078c2ecf20Sopenharmony_ci skb->priority = CPL_PRIORITY_CONTROL; 1088c2ecf20Sopenharmony_ci cxgb3_ofld_send(dev, skb); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci skb_queue_walk_safe(&e->arpq, skb, tmp) { 1118c2ecf20Sopenharmony_ci __skb_unlink(skb, &e->arpq); 1128c2ecf20Sopenharmony_ci cxgb3_ofld_send(dev, skb); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci e->state = L2T_STATE_VALID; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * Add a packet to the an L2T entry's queue of packets awaiting resolution. 1218c2ecf20Sopenharmony_ci * Must be called with the entry's lock held. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_cistatic inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci __skb_queue_tail(&e->arpq, skb); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ciint t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb, 1298c2ecf20Sopenharmony_ci struct l2t_entry *e) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ciagain: 1328c2ecf20Sopenharmony_ci switch (e->state) { 1338c2ecf20Sopenharmony_ci case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ 1348c2ecf20Sopenharmony_ci neigh_event_send(e->neigh, NULL); 1358c2ecf20Sopenharmony_ci spin_lock_bh(&e->lock); 1368c2ecf20Sopenharmony_ci if (e->state == L2T_STATE_STALE) 1378c2ecf20Sopenharmony_ci e->state = L2T_STATE_VALID; 1388c2ecf20Sopenharmony_ci spin_unlock_bh(&e->lock); 1398c2ecf20Sopenharmony_ci fallthrough; 1408c2ecf20Sopenharmony_ci case L2T_STATE_VALID: /* fast-path, send the packet on */ 1418c2ecf20Sopenharmony_ci return cxgb3_ofld_send(dev, skb); 1428c2ecf20Sopenharmony_ci case L2T_STATE_RESOLVING: 1438c2ecf20Sopenharmony_ci spin_lock_bh(&e->lock); 1448c2ecf20Sopenharmony_ci if (e->state != L2T_STATE_RESOLVING) { 1458c2ecf20Sopenharmony_ci /* ARP already completed */ 1468c2ecf20Sopenharmony_ci spin_unlock_bh(&e->lock); 1478c2ecf20Sopenharmony_ci goto again; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci arpq_enqueue(e, skb); 1508c2ecf20Sopenharmony_ci spin_unlock_bh(&e->lock); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* 1538c2ecf20Sopenharmony_ci * Only the first packet added to the arpq should kick off 1548c2ecf20Sopenharmony_ci * resolution. However, because the alloc_skb below can fail, 1558c2ecf20Sopenharmony_ci * we allow each packet added to the arpq to retry resolution 1568c2ecf20Sopenharmony_ci * as a way of recovering from transient memory exhaustion. 1578c2ecf20Sopenharmony_ci * A better way would be to use a work request to retry L2T 1588c2ecf20Sopenharmony_ci * entries when there's no memory. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ci if (!neigh_event_send(e->neigh, NULL)) { 1618c2ecf20Sopenharmony_ci skb = alloc_skb(sizeof(struct cpl_l2t_write_req), 1628c2ecf20Sopenharmony_ci GFP_ATOMIC); 1638c2ecf20Sopenharmony_ci if (!skb) 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci spin_lock_bh(&e->lock); 1678c2ecf20Sopenharmony_ci if (!skb_queue_empty(&e->arpq)) 1688c2ecf20Sopenharmony_ci setup_l2e_send_pending(dev, skb, e); 1698c2ecf20Sopenharmony_ci else /* we lost the race */ 1708c2ecf20Sopenharmony_ci __kfree_skb(skb); 1718c2ecf20Sopenharmony_ci spin_unlock_bh(&e->lock); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(t3_l2t_send_slow); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_civoid t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ciagain: 1828c2ecf20Sopenharmony_ci switch (e->state) { 1838c2ecf20Sopenharmony_ci case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ 1848c2ecf20Sopenharmony_ci neigh_event_send(e->neigh, NULL); 1858c2ecf20Sopenharmony_ci spin_lock_bh(&e->lock); 1868c2ecf20Sopenharmony_ci if (e->state == L2T_STATE_STALE) { 1878c2ecf20Sopenharmony_ci e->state = L2T_STATE_VALID; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci spin_unlock_bh(&e->lock); 1908c2ecf20Sopenharmony_ci return; 1918c2ecf20Sopenharmony_ci case L2T_STATE_VALID: /* fast-path, send the packet on */ 1928c2ecf20Sopenharmony_ci return; 1938c2ecf20Sopenharmony_ci case L2T_STATE_RESOLVING: 1948c2ecf20Sopenharmony_ci spin_lock_bh(&e->lock); 1958c2ecf20Sopenharmony_ci if (e->state != L2T_STATE_RESOLVING) { 1968c2ecf20Sopenharmony_ci /* ARP already completed */ 1978c2ecf20Sopenharmony_ci spin_unlock_bh(&e->lock); 1988c2ecf20Sopenharmony_ci goto again; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci spin_unlock_bh(&e->lock); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* 2038c2ecf20Sopenharmony_ci * Only the first packet added to the arpq should kick off 2048c2ecf20Sopenharmony_ci * resolution. However, because the alloc_skb below can fail, 2058c2ecf20Sopenharmony_ci * we allow each packet added to the arpq to retry resolution 2068c2ecf20Sopenharmony_ci * as a way of recovering from transient memory exhaustion. 2078c2ecf20Sopenharmony_ci * A better way would be to use a work request to retry L2T 2088c2ecf20Sopenharmony_ci * entries when there's no memory. 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_ci neigh_event_send(e->neigh, NULL); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(t3_l2t_send_event); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* 2178c2ecf20Sopenharmony_ci * Allocate a free L2T entry. Must be called with l2t_data.lock held. 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_cistatic struct l2t_entry *alloc_l2e(struct l2t_data *d) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct l2t_entry *end, *e, **p; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (!atomic_read(&d->nfree)) 2248c2ecf20Sopenharmony_ci return NULL; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* there's definitely a free entry */ 2278c2ecf20Sopenharmony_ci for (e = d->rover, end = &d->l2tab[d->nentries]; e != end; ++e) 2288c2ecf20Sopenharmony_ci if (atomic_read(&e->refcnt) == 0) 2298c2ecf20Sopenharmony_ci goto found; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci for (e = &d->l2tab[1]; atomic_read(&e->refcnt); ++e) ; 2328c2ecf20Sopenharmony_cifound: 2338c2ecf20Sopenharmony_ci d->rover = e + 1; 2348c2ecf20Sopenharmony_ci atomic_dec(&d->nfree); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* 2378c2ecf20Sopenharmony_ci * The entry we found may be an inactive entry that is 2388c2ecf20Sopenharmony_ci * presently in the hash table. We need to remove it. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ci if (e->state != L2T_STATE_UNUSED) { 2418c2ecf20Sopenharmony_ci int hash = arp_hash(e->addr, e->ifindex, d); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci for (p = &d->l2tab[hash].first; *p; p = &(*p)->next) 2448c2ecf20Sopenharmony_ci if (*p == e) { 2458c2ecf20Sopenharmony_ci *p = e->next; 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci e->state = L2T_STATE_UNUSED; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci return e; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* 2548c2ecf20Sopenharmony_ci * Called when an L2T entry has no more users. The entry is left in the hash 2558c2ecf20Sopenharmony_ci * table since it is likely to be reused but we also bump nfree to indicate 2568c2ecf20Sopenharmony_ci * that the entry can be reallocated for a different neighbor. We also drop 2578c2ecf20Sopenharmony_ci * the existing neighbor reference in case the neighbor is going away and is 2588c2ecf20Sopenharmony_ci * waiting on our reference. 2598c2ecf20Sopenharmony_ci * 2608c2ecf20Sopenharmony_ci * Because entries can be reallocated to other neighbors once their ref count 2618c2ecf20Sopenharmony_ci * drops to 0 we need to take the entry's lock to avoid races with a new 2628c2ecf20Sopenharmony_ci * incarnation. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_civoid t3_l2e_free(struct l2t_data *d, struct l2t_entry *e) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci spin_lock_bh(&e->lock); 2678c2ecf20Sopenharmony_ci if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ 2688c2ecf20Sopenharmony_ci if (e->neigh) { 2698c2ecf20Sopenharmony_ci neigh_release(e->neigh); 2708c2ecf20Sopenharmony_ci e->neigh = NULL; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci spin_unlock_bh(&e->lock); 2748c2ecf20Sopenharmony_ci atomic_inc(&d->nfree); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(t3_l2e_free); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/* 2808c2ecf20Sopenharmony_ci * Update an L2T entry that was previously used for the same next hop as neigh. 2818c2ecf20Sopenharmony_ci * Must be called with softirqs disabled. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_cistatic inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci unsigned int nud_state; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci spin_lock(&e->lock); /* avoid race with t3_l2t_free */ 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (neigh != e->neigh) 2908c2ecf20Sopenharmony_ci neigh_replace(e, neigh); 2918c2ecf20Sopenharmony_ci nud_state = neigh->nud_state; 2928c2ecf20Sopenharmony_ci if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) || 2938c2ecf20Sopenharmony_ci !(nud_state & NUD_VALID)) 2948c2ecf20Sopenharmony_ci e->state = L2T_STATE_RESOLVING; 2958c2ecf20Sopenharmony_ci else if (nud_state & NUD_CONNECTED) 2968c2ecf20Sopenharmony_ci e->state = L2T_STATE_VALID; 2978c2ecf20Sopenharmony_ci else 2988c2ecf20Sopenharmony_ci e->state = L2T_STATE_STALE; 2998c2ecf20Sopenharmony_ci spin_unlock(&e->lock); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistruct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct dst_entry *dst, 3038c2ecf20Sopenharmony_ci struct net_device *dev, const void *daddr) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct l2t_entry *e = NULL; 3068c2ecf20Sopenharmony_ci struct neighbour *neigh; 3078c2ecf20Sopenharmony_ci struct port_info *p; 3088c2ecf20Sopenharmony_ci struct l2t_data *d; 3098c2ecf20Sopenharmony_ci int hash; 3108c2ecf20Sopenharmony_ci u32 addr; 3118c2ecf20Sopenharmony_ci int ifidx; 3128c2ecf20Sopenharmony_ci int smt_idx; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci rcu_read_lock(); 3158c2ecf20Sopenharmony_ci neigh = dst_neigh_lookup(dst, daddr); 3168c2ecf20Sopenharmony_ci if (!neigh) 3178c2ecf20Sopenharmony_ci goto done_rcu; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci addr = *(u32 *) neigh->primary_key; 3208c2ecf20Sopenharmony_ci ifidx = neigh->dev->ifindex; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (!dev) 3238c2ecf20Sopenharmony_ci dev = neigh->dev; 3248c2ecf20Sopenharmony_ci p = netdev_priv(dev); 3258c2ecf20Sopenharmony_ci smt_idx = p->port_id; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci d = L2DATA(cdev); 3288c2ecf20Sopenharmony_ci if (!d) 3298c2ecf20Sopenharmony_ci goto done_rcu; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci hash = arp_hash(addr, ifidx, d); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci write_lock_bh(&d->lock); 3348c2ecf20Sopenharmony_ci for (e = d->l2tab[hash].first; e; e = e->next) 3358c2ecf20Sopenharmony_ci if (e->addr == addr && e->ifindex == ifidx && 3368c2ecf20Sopenharmony_ci e->smt_idx == smt_idx) { 3378c2ecf20Sopenharmony_ci l2t_hold(d, e); 3388c2ecf20Sopenharmony_ci if (atomic_read(&e->refcnt) == 1) 3398c2ecf20Sopenharmony_ci reuse_entry(e, neigh); 3408c2ecf20Sopenharmony_ci goto done_unlock; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Need to allocate a new entry */ 3448c2ecf20Sopenharmony_ci e = alloc_l2e(d); 3458c2ecf20Sopenharmony_ci if (e) { 3468c2ecf20Sopenharmony_ci spin_lock(&e->lock); /* avoid race with t3_l2t_free */ 3478c2ecf20Sopenharmony_ci e->next = d->l2tab[hash].first; 3488c2ecf20Sopenharmony_ci d->l2tab[hash].first = e; 3498c2ecf20Sopenharmony_ci e->state = L2T_STATE_RESOLVING; 3508c2ecf20Sopenharmony_ci e->addr = addr; 3518c2ecf20Sopenharmony_ci e->ifindex = ifidx; 3528c2ecf20Sopenharmony_ci e->smt_idx = smt_idx; 3538c2ecf20Sopenharmony_ci atomic_set(&e->refcnt, 1); 3548c2ecf20Sopenharmony_ci neigh_replace(e, neigh); 3558c2ecf20Sopenharmony_ci if (is_vlan_dev(neigh->dev)) 3568c2ecf20Sopenharmony_ci e->vlan = vlan_dev_vlan_id(neigh->dev); 3578c2ecf20Sopenharmony_ci else 3588c2ecf20Sopenharmony_ci e->vlan = VLAN_NONE; 3598c2ecf20Sopenharmony_ci spin_unlock(&e->lock); 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_cidone_unlock: 3628c2ecf20Sopenharmony_ci write_unlock_bh(&d->lock); 3638c2ecf20Sopenharmony_cidone_rcu: 3648c2ecf20Sopenharmony_ci if (neigh) 3658c2ecf20Sopenharmony_ci neigh_release(neigh); 3668c2ecf20Sopenharmony_ci rcu_read_unlock(); 3678c2ecf20Sopenharmony_ci return e; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(t3_l2t_get); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* 3738c2ecf20Sopenharmony_ci * Called when address resolution fails for an L2T entry to handle packets 3748c2ecf20Sopenharmony_ci * on the arpq head. If a packet specifies a failure handler it is invoked, 3758c2ecf20Sopenharmony_ci * otherwise the packets is sent to the offload device. 3768c2ecf20Sopenharmony_ci * 3778c2ecf20Sopenharmony_ci * XXX: maybe we should abandon the latter behavior and just require a failure 3788c2ecf20Sopenharmony_ci * handler. 3798c2ecf20Sopenharmony_ci */ 3808c2ecf20Sopenharmony_cistatic void handle_failed_resolution(struct t3cdev *dev, struct sk_buff_head *arpq) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci struct sk_buff *skb, *tmp; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci skb_queue_walk_safe(arpq, skb, tmp) { 3858c2ecf20Sopenharmony_ci struct l2t_skb_cb *cb = L2T_SKB_CB(skb); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci __skb_unlink(skb, arpq); 3888c2ecf20Sopenharmony_ci if (cb->arp_failure_handler) 3898c2ecf20Sopenharmony_ci cb->arp_failure_handler(dev, skb); 3908c2ecf20Sopenharmony_ci else 3918c2ecf20Sopenharmony_ci cxgb3_ofld_send(dev, skb); 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci/* 3968c2ecf20Sopenharmony_ci * Called when the host's ARP layer makes a change to some entry that is 3978c2ecf20Sopenharmony_ci * loaded into the HW L2 table. 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_civoid t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct sk_buff_head arpq; 4028c2ecf20Sopenharmony_ci struct l2t_entry *e; 4038c2ecf20Sopenharmony_ci struct l2t_data *d = L2DATA(dev); 4048c2ecf20Sopenharmony_ci u32 addr = *(u32 *) neigh->primary_key; 4058c2ecf20Sopenharmony_ci int ifidx = neigh->dev->ifindex; 4068c2ecf20Sopenharmony_ci int hash = arp_hash(addr, ifidx, d); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci read_lock_bh(&d->lock); 4098c2ecf20Sopenharmony_ci for (e = d->l2tab[hash].first; e; e = e->next) 4108c2ecf20Sopenharmony_ci if (e->addr == addr && e->ifindex == ifidx) { 4118c2ecf20Sopenharmony_ci spin_lock(&e->lock); 4128c2ecf20Sopenharmony_ci goto found; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci read_unlock_bh(&d->lock); 4158c2ecf20Sopenharmony_ci return; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cifound: 4188c2ecf20Sopenharmony_ci __skb_queue_head_init(&arpq); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci read_unlock(&d->lock); 4218c2ecf20Sopenharmony_ci if (atomic_read(&e->refcnt)) { 4228c2ecf20Sopenharmony_ci if (neigh != e->neigh) 4238c2ecf20Sopenharmony_ci neigh_replace(e, neigh); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (e->state == L2T_STATE_RESOLVING) { 4268c2ecf20Sopenharmony_ci if (neigh->nud_state & NUD_FAILED) { 4278c2ecf20Sopenharmony_ci skb_queue_splice_init(&e->arpq, &arpq); 4288c2ecf20Sopenharmony_ci } else if (neigh->nud_state & (NUD_CONNECTED|NUD_STALE)) 4298c2ecf20Sopenharmony_ci setup_l2e_send_pending(dev, NULL, e); 4308c2ecf20Sopenharmony_ci } else { 4318c2ecf20Sopenharmony_ci e->state = neigh->nud_state & NUD_CONNECTED ? 4328c2ecf20Sopenharmony_ci L2T_STATE_VALID : L2T_STATE_STALE; 4338c2ecf20Sopenharmony_ci if (!ether_addr_equal(e->dmac, neigh->ha)) 4348c2ecf20Sopenharmony_ci setup_l2e_send_pending(dev, NULL, e); 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci spin_unlock_bh(&e->lock); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (!skb_queue_empty(&arpq)) 4408c2ecf20Sopenharmony_ci handle_failed_resolution(dev, &arpq); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistruct l2t_data *t3_init_l2t(unsigned int l2t_capacity) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct l2t_data *d; 4468c2ecf20Sopenharmony_ci int i; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci d = kvzalloc(struct_size(d, l2tab, l2t_capacity), GFP_KERNEL); 4498c2ecf20Sopenharmony_ci if (!d) 4508c2ecf20Sopenharmony_ci return NULL; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci d->nentries = l2t_capacity; 4538c2ecf20Sopenharmony_ci d->rover = &d->l2tab[1]; /* entry 0 is not used */ 4548c2ecf20Sopenharmony_ci atomic_set(&d->nfree, l2t_capacity - 1); 4558c2ecf20Sopenharmony_ci rwlock_init(&d->lock); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci for (i = 0; i < l2t_capacity; ++i) { 4588c2ecf20Sopenharmony_ci d->l2tab[i].idx = i; 4598c2ecf20Sopenharmony_ci d->l2tab[i].state = L2T_STATE_UNUSED; 4608c2ecf20Sopenharmony_ci __skb_queue_head_init(&d->l2tab[i].arpq); 4618c2ecf20Sopenharmony_ci spin_lock_init(&d->l2tab[i].lock); 4628c2ecf20Sopenharmony_ci atomic_set(&d->l2tab[i].refcnt, 0); 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci return d; 4658c2ecf20Sopenharmony_ci} 466