1625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis/* 2625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * This file is part of the Chelsio T4 Ethernet driver for Linux. 3625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * 4625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. 5625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * 6625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * This software is available to you under a choice of one of two 7625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * licenses. You may choose to be licensed under the terms of the GNU 8625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * General Public License (GPL) Version 2, available from the file 9625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * COPYING in the main directory of this source tree, or the 10625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * OpenIB.org BSD license below: 11625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * 12625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Redistribution and use in source and binary forms, with or 13625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * without modification, are permitted provided that the following 14625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * conditions are met: 15625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * 16625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * - Redistributions of source code must retain the above 17625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * copyright notice, this list of conditions and the following 18625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * disclaimer. 19625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * 20625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * - Redistributions in binary form must reproduce the above 21625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * copyright notice, this list of conditions and the following 22625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * disclaimer in the documentation and/or other materials 23625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * provided with the distribution. 24625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * 25625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * SOFTWARE. 33625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis */ 34625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 35625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis#include <linux/skbuff.h> 36625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis#include <linux/netdevice.h> 37625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis#include <linux/if.h> 38625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis#include <linux/if_vlan.h> 39625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis#include <linux/jhash.h> 40310587c320e906c59ef4152c41d81b00adf1b259Paul Gortmaker#include <linux/module.h> 41310587c320e906c59ef4152c41d81b00adf1b259Paul Gortmaker#include <linux/debugfs.h> 42310587c320e906c59ef4152c41d81b00adf1b259Paul Gortmaker#include <linux/seq_file.h> 43625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis#include <net/neighbour.h> 44625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis#include "cxgb4.h" 45625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis#include "l2t.h" 46625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis#include "t4_msg.h" 47625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis#include "t4fw_api.h" 48625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 49625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis#define VLAN_NONE 0xfff 50625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 51625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis/* identifies sync vs async L2T_WRITE_REQs */ 52625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis#define F_SYNC_WR (1 << 12) 53625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 54625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisenum { 55625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis L2T_STATE_VALID, /* entry is up to date */ 56625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis L2T_STATE_STALE, /* entry may be used but needs revalidation */ 57625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis L2T_STATE_RESOLVING, /* entry needs address resolution */ 58625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis L2T_STATE_SYNC_WRITE, /* synchronous write of entry underway */ 59625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 60625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis /* when state is one of the below the entry is not hashed */ 61625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis L2T_STATE_SWITCHING, /* entry is being used by a switching filter */ 62625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis L2T_STATE_UNUSED /* entry not in use */ 63625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis}; 64625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 65625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstruct l2t_data { 66625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis rwlock_t lock; 67625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis atomic_t nfree; /* number of free entries */ 68625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct l2t_entry *rover; /* starting point for next allocation */ 69625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct l2t_entry l2tab[L2T_SIZE]; 70625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis}; 71625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 72625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic inline unsigned int vlan_prio(const struct l2t_entry *e) 73625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 74625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return e->vlan >> 13; 75625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 76625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 77625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e) 78625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 79625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */ 80625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis atomic_dec(&d->nfree); 81625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 82625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 83625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis/* 84625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * To avoid having to check address families we do not allow v4 and v6 85625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * neighbors to be on the same hash chain. We keep v4 entries in the first 86625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * half of available hash buckets and v6 in the second. 87625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis */ 88625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisenum { 89625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis L2T_SZ_HALF = L2T_SIZE / 2, 90625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis L2T_HASH_MASK = L2T_SZ_HALF - 1 91625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis}; 92625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 93625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic inline unsigned int arp_hash(const u32 *key, int ifindex) 94625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 95625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return jhash_2words(*key, ifindex, 0) & L2T_HASH_MASK; 96625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 97625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 98625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic inline unsigned int ipv6_hash(const u32 *key, int ifindex) 99625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 100625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis u32 xor = key[0] ^ key[1] ^ key[2] ^ key[3]; 101625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 102625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return L2T_SZ_HALF + (jhash_2words(xor, ifindex, 0) & L2T_HASH_MASK); 103625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 104625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 105625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic unsigned int addr_hash(const u32 *addr, int addr_len, int ifindex) 106625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 107625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return addr_len == 4 ? arp_hash(addr, ifindex) : 108625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis ipv6_hash(addr, ifindex); 109625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 110625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 111625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis/* 112625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Checks if an L2T entry is for the given IP/IPv6 address. It does not check 113625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * whether the L2T entry and the address are of the same address family. 114625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Callers ensure an address is only checked against L2T entries of the same 115625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * family, something made trivial by the separation of IP and IPv6 hash chains 116625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * mentioned above. Returns 0 if there's a match, 117625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis */ 118625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic int addreq(const struct l2t_entry *e, const u32 *addr) 119625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 120625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e->v6) 121625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return (e->addr[0] ^ addr[0]) | (e->addr[1] ^ addr[1]) | 122625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis (e->addr[2] ^ addr[2]) | (e->addr[3] ^ addr[3]); 123625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return e->addr[0] ^ addr[0]; 124625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 125625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 126625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic void neigh_replace(struct l2t_entry *e, struct neighbour *n) 127625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 128625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis neigh_hold(n); 129625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e->neigh) 130625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis neigh_release(e->neigh); 131625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->neigh = n; 132625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 133625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 134625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis/* 135625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Write an L2T entry. Must be called with the entry locked. 136625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * The write may be synchronous or asynchronous. 137625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis */ 138625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync) 139625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 140625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct sk_buff *skb; 141625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct cpl_l2t_write_req *req; 142625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 143625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis skb = alloc_skb(sizeof(*req), GFP_ATOMIC); 144625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (!skb) 145625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return -ENOMEM; 146625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 147625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); 148625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis INIT_TP_WR(req, 0); 149625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 150625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, 151625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->idx | (sync ? F_SYNC_WR : 0) | 152625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis TID_QID(adap->sge.fw_evtq.abs_id))); 153625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis req->params = htons(L2T_W_PORT(e->lport) | L2T_W_NOREPLY(!sync)); 154625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis req->l2t_idx = htons(e->idx); 155625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis req->vlan = htons(e->vlan); 156625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e->neigh) 157625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac)); 158625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); 159625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 160625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); 161625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis t4_ofld_send(adap, skb); 162625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 163625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (sync && e->state != L2T_STATE_SWITCHING) 164625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->state = L2T_STATE_SYNC_WRITE; 165625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return 0; 166625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 167625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 168625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis/* 169625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Send packets waiting in an L2T entry's ARP queue. Must be called with the 170625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * entry locked. 171625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis */ 172625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic void send_pending(struct adapter *adap, struct l2t_entry *e) 173625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 174625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis while (e->arpq_head) { 175625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct sk_buff *skb = e->arpq_head; 176625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 177625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->arpq_head = skb->next; 178625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis skb->next = NULL; 179625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis t4_ofld_send(adap, skb); 180625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 181625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->arpq_tail = NULL; 182625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 183625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 184625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis/* 185625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Process a CPL_L2T_WRITE_RPL. Wake up the ARP queue if it completes a 186625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * synchronous L2T_WRITE. Note that the TID in the reply is really the L2T 187625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * index it refers to. 188625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis */ 189625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisvoid do_l2t_write_rpl(struct adapter *adap, const struct cpl_l2t_write_rpl *rpl) 190625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 191625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis unsigned int tid = GET_TID(rpl); 192625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis unsigned int idx = tid & (L2T_SIZE - 1); 193625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 194625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (unlikely(rpl->status != CPL_ERR_NONE)) { 195625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis dev_err(adap->pdev_dev, 196625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis "Unexpected L2T_WRITE_RPL status %u for entry %u\n", 197625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis rpl->status, idx); 198625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return; 199625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 200625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 201625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (tid & F_SYNC_WR) { 202625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct l2t_entry *e = &adap->l2t->l2tab[idx]; 203625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 204625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_lock(&e->lock); 205625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e->state != L2T_STATE_SWITCHING) { 206625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis send_pending(adap, e); 207625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->state = (e->neigh->nud_state & NUD_STALE) ? 208625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis L2T_STATE_STALE : L2T_STATE_VALID; 209625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 210625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_unlock(&e->lock); 211625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 212625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 213625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 214625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis/* 215625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Add a packet to an L2T entry's queue of packets awaiting resolution. 216625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Must be called with the entry's lock held. 217625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis */ 218625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb) 219625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 220625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis skb->next = NULL; 221625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e->arpq_head) 222625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->arpq_tail->next = skb; 223625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis else 224625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->arpq_head = skb; 225625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->arpq_tail = skb; 226625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 227625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 228625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisint cxgb4_l2t_send(struct net_device *dev, struct sk_buff *skb, 229625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct l2t_entry *e) 230625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 231625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct adapter *adap = netdev2adap(dev); 232625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 233625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisagain: 234625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis switch (e->state) { 235625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ 236625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis neigh_event_send(e->neigh, NULL); 237625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_lock_bh(&e->lock); 238625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e->state == L2T_STATE_STALE) 239625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->state = L2T_STATE_VALID; 240625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_unlock_bh(&e->lock); 241625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis case L2T_STATE_VALID: /* fast-path, send the packet on */ 242625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return t4_ofld_send(adap, skb); 243625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis case L2T_STATE_RESOLVING: 244625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis case L2T_STATE_SYNC_WRITE: 245625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_lock_bh(&e->lock); 246625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e->state != L2T_STATE_SYNC_WRITE && 247625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->state != L2T_STATE_RESOLVING) { 248625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_unlock_bh(&e->lock); 249625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis goto again; 250625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 251625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis arpq_enqueue(e, skb); 252625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_unlock_bh(&e->lock); 253625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 254625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e->state == L2T_STATE_RESOLVING && 255625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis !neigh_event_send(e->neigh, NULL)) { 256625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_lock_bh(&e->lock); 257625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e->state == L2T_STATE_RESOLVING && e->arpq_head) 258625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis write_l2e(adap, e, 1); 259625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_unlock_bh(&e->lock); 260625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 261625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 262625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return 0; 263625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 264625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris MichailidisEXPORT_SYMBOL(cxgb4_l2t_send); 265625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 266625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis/* 267625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Allocate a free L2T entry. Must be called with l2t_data.lock held. 268625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis */ 269625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic struct l2t_entry *alloc_l2e(struct l2t_data *d) 270625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 271625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct l2t_entry *end, *e, **p; 272625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 273625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (!atomic_read(&d->nfree)) 274625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return NULL; 275625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 276625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis /* there's definitely a free entry */ 277625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis for (e = d->rover, end = &d->l2tab[L2T_SIZE]; e != end; ++e) 278625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (atomic_read(&e->refcnt) == 0) 279625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis goto found; 280625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 281625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis for (e = d->l2tab; atomic_read(&e->refcnt); ++e) 282625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis ; 283625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisfound: 284625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis d->rover = e + 1; 285625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis atomic_dec(&d->nfree); 286625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 287625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis /* 288625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * The entry we found may be an inactive entry that is 289625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * presently in the hash table. We need to remove it. 290625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis */ 291625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e->state < L2T_STATE_SWITCHING) 292625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis for (p = &d->l2tab[e->hash].first; *p; p = &(*p)->next) 293625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (*p == e) { 294625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis *p = e->next; 295625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->next = NULL; 296625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis break; 297625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 298625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 299625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->state = L2T_STATE_UNUSED; 300625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return e; 301625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 302625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 303625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis/* 304625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Called when an L2T entry has no more users. 305625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis */ 306625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic void t4_l2e_free(struct l2t_entry *e) 307625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 308625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct l2t_data *d; 309625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 310625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_lock_bh(&e->lock); 311625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ 312625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e->neigh) { 313625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis neigh_release(e->neigh); 314625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->neigh = NULL; 315625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 316204dc3c0b1bea10a7d811970fd41ceabaef31267Dimitris Michailidis while (e->arpq_head) { 317204dc3c0b1bea10a7d811970fd41ceabaef31267Dimitris Michailidis struct sk_buff *skb = e->arpq_head; 318204dc3c0b1bea10a7d811970fd41ceabaef31267Dimitris Michailidis 319204dc3c0b1bea10a7d811970fd41ceabaef31267Dimitris Michailidis e->arpq_head = skb->next; 32005eda04ba0b56b1bff3e5c9dbf58213ffc2e2a0bDenis Kirjanov kfree_skb(skb); 321204dc3c0b1bea10a7d811970fd41ceabaef31267Dimitris Michailidis } 322204dc3c0b1bea10a7d811970fd41ceabaef31267Dimitris Michailidis e->arpq_tail = NULL; 323625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 324625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_unlock_bh(&e->lock); 325625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 326625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis d = container_of(e, struct l2t_data, l2tab[e->idx]); 327625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis atomic_inc(&d->nfree); 328625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 329625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 330625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisvoid cxgb4_l2t_release(struct l2t_entry *e) 331625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 332625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (atomic_dec_and_test(&e->refcnt)) 333625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis t4_l2e_free(e); 334625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 335625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris MichailidisEXPORT_SYMBOL(cxgb4_l2t_release); 336625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 337625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis/* 338625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Update an L2T entry that was previously used for the same next hop as neigh. 339625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Must be called with softirqs disabled. 340625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis */ 341625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic void reuse_entry(struct l2t_entry *e, struct neighbour *neigh) 342625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 343625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis unsigned int nud_state; 344625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 345625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_lock(&e->lock); /* avoid race with t4_l2t_free */ 346625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (neigh != e->neigh) 347625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis neigh_replace(e, neigh); 348625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis nud_state = neigh->nud_state; 349625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) || 350625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis !(nud_state & NUD_VALID)) 351625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->state = L2T_STATE_RESOLVING; 352625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis else if (nud_state & NUD_CONNECTED) 353625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->state = L2T_STATE_VALID; 354625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis else 355625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->state = L2T_STATE_STALE; 356625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_unlock(&e->lock); 357625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 358625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 359625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstruct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh, 360625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis const struct net_device *physdev, 361625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis unsigned int priority) 362625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 363625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis u8 lport; 364625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis u16 vlan; 365625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct l2t_entry *e; 366625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis int addr_len = neigh->tbl->key_len; 367625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis u32 *addr = (u32 *)neigh->primary_key; 368625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis int ifidx = neigh->dev->ifindex; 369625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis int hash = addr_hash(addr, addr_len, ifidx); 370625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 371625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (neigh->dev->flags & IFF_LOOPBACK) 372625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis lport = netdev2pinfo(physdev)->tx_chan + 4; 373625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis else 374625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis lport = netdev2pinfo(physdev)->lport; 375625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 376625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (neigh->dev->priv_flags & IFF_802_1Q_VLAN) 377625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis vlan = vlan_dev_vlan_id(neigh->dev); 378625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis else 379625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis vlan = VLAN_NONE; 380625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 381625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis write_lock_bh(&d->lock); 382625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis for (e = d->l2tab[hash].first; e; e = e->next) 383625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (!addreq(e, addr) && e->ifindex == ifidx && 384625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->vlan == vlan && e->lport == lport) { 385625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis l2t_hold(d, e); 386625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (atomic_read(&e->refcnt) == 1) 387625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis reuse_entry(e, neigh); 388625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis goto done; 389625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 390625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 391625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis /* Need to allocate a new entry */ 392625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e = alloc_l2e(d); 393625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e) { 394625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_lock(&e->lock); /* avoid race with t4_l2t_free */ 395625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->state = L2T_STATE_RESOLVING; 396625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis memcpy(e->addr, addr, addr_len); 397625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->ifindex = ifidx; 398625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->hash = hash; 399625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->lport = lport; 400625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->v6 = addr_len == 16; 401625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis atomic_set(&e->refcnt, 1); 402625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis neigh_replace(e, neigh); 403625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->vlan = vlan; 404625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->next = d->l2tab[hash].first; 405625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis d->l2tab[hash].first = e; 406625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_unlock(&e->lock); 407625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 408625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisdone: 409625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis write_unlock_bh(&d->lock); 410625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return e; 411625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 412625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris MichailidisEXPORT_SYMBOL(cxgb4_l2t_get); 413625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 414625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis/* 415625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Called when address resolution fails for an L2T entry to handle packets 416625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * on the arpq head. If a packet specifies a failure handler it is invoked, 417625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * otherwise the packet is sent to the device. 418625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis */ 419625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic void handle_failed_resolution(struct adapter *adap, struct sk_buff *arpq) 420625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 421625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis while (arpq) { 422625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct sk_buff *skb = arpq; 423625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis const struct l2t_skb_cb *cb = L2T_SKB_CB(skb); 424625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 425625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis arpq = skb->next; 426625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis skb->next = NULL; 427625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (cb->arp_err_handler) 428625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis cb->arp_err_handler(cb->handle, skb); 429625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis else 430625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis t4_ofld_send(adap, skb); 431625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 432625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 433625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 434625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis/* 435625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * Called when the host's neighbor layer makes a change to some entry that is 436625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis * loaded into the HW L2 table. 437625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis */ 438625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisvoid t4_l2t_update(struct adapter *adap, struct neighbour *neigh) 439625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 440625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct l2t_entry *e; 441625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct sk_buff *arpq = NULL; 442625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct l2t_data *d = adap->l2t; 443625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis int addr_len = neigh->tbl->key_len; 444625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis u32 *addr = (u32 *) neigh->primary_key; 445625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis int ifidx = neigh->dev->ifindex; 446625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis int hash = addr_hash(addr, addr_len, ifidx); 447625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 448625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis read_lock_bh(&d->lock); 449625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis for (e = d->l2tab[hash].first; e; e = e->next) 450625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (!addreq(e, addr) && e->ifindex == ifidx) { 451625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_lock(&e->lock); 452625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (atomic_read(&e->refcnt)) 453625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis goto found; 454625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_unlock(&e->lock); 455625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis break; 456625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 457625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis read_unlock_bh(&d->lock); 458625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return; 459625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 460625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis found: 461625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis read_unlock(&d->lock); 462625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 463625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (neigh != e->neigh) 464625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis neigh_replace(e, neigh); 465625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 466625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e->state == L2T_STATE_RESOLVING) { 467625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (neigh->nud_state & NUD_FAILED) { 468625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis arpq = e->arpq_head; 469625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->arpq_head = e->arpq_tail = NULL; 470625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } else if ((neigh->nud_state & (NUD_CONNECTED | NUD_STALE)) && 471625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->arpq_head) { 472625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis write_l2e(adap, e, 1); 473625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 474625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } else { 475625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->state = neigh->nud_state & NUD_CONNECTED ? 476625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis L2T_STATE_VALID : L2T_STATE_STALE; 477625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac))) 478625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis write_l2e(adap, e, 0); 479625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 480625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 481625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_unlock_bh(&e->lock); 482625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 483625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (arpq) 484625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis handle_failed_resolution(adap, arpq); 485625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 486625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 487625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstruct l2t_data *t4_init_l2t(void) 488625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 489625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis int i; 490625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct l2t_data *d; 491625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 492625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis d = t4_alloc_mem(sizeof(*d)); 493625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (!d) 494625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return NULL; 495625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 496625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis d->rover = d->l2tab; 497625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis atomic_set(&d->nfree, L2T_SIZE); 498625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis rwlock_init(&d->lock); 499625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 500625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis for (i = 0; i < L2T_SIZE; ++i) { 501625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis d->l2tab[i].idx = i; 502625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis d->l2tab[i].state = L2T_STATE_UNUSED; 503625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_lock_init(&d->l2tab[i].lock); 504625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis atomic_set(&d->l2tab[i].refcnt, 0); 505625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 506625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return d; 507625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 508625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 509625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic inline void *l2t_get_idx(struct seq_file *seq, loff_t pos) 510625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 511625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct l2t_entry *l2tab = seq->private; 512625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 513625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return pos >= L2T_SIZE ? NULL : &l2tab[pos]; 514625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 515625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 516625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic void *l2t_seq_start(struct seq_file *seq, loff_t *pos) 517625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 518625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return *pos ? l2t_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; 519625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 520625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 521625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic void *l2t_seq_next(struct seq_file *seq, void *v, loff_t *pos) 522625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 523625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis v = l2t_get_idx(seq, *pos); 524625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (v) 525625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis ++*pos; 526625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return v; 527625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 528625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 529625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic void l2t_seq_stop(struct seq_file *seq, void *v) 530625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 531625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 532625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 533625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic char l2e_state(const struct l2t_entry *e) 534625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 535625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis switch (e->state) { 536625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis case L2T_STATE_VALID: return 'V'; 537625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis case L2T_STATE_STALE: return 'S'; 538625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis case L2T_STATE_SYNC_WRITE: return 'W'; 539625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis case L2T_STATE_RESOLVING: return e->arpq_head ? 'A' : 'R'; 540625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis case L2T_STATE_SWITCHING: return 'X'; 541625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis default: 542625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return 'U'; 543625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 544625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 545625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 546625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic int l2t_seq_show(struct seq_file *seq, void *v) 547625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 548625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (v == SEQ_START_TOKEN) 549625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis seq_puts(seq, " Idx IP address " 550625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis "Ethernet address VLAN/P LP State Users Port\n"); 551625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis else { 552625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis char ip[60]; 553625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct l2t_entry *e = v; 554625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 555625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_lock_bh(&e->lock); 556625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (e->state == L2T_STATE_SWITCHING) 557625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis ip[0] = '\0'; 558625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis else 559625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis sprintf(ip, e->v6 ? "%pI6c" : "%pI4", e->addr); 560625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis seq_printf(seq, "%4u %-25s %17pM %4d %u %2u %c %5u %s\n", 561625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->idx, ip, e->dmac, 562625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->vlan & VLAN_VID_MASK, vlan_prio(e), e->lport, 563625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis l2e_state(e), atomic_read(&e->refcnt), 564625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis e->neigh ? e->neigh->dev->name : ""); 565625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis spin_unlock_bh(&e->lock); 566625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 567625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return 0; 568625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 569625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 570625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic const struct seq_operations l2t_seq_ops = { 571625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis .start = l2t_seq_start, 572625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis .next = l2t_seq_next, 573625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis .stop = l2t_seq_stop, 574625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis .show = l2t_seq_show 575625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis}; 576625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 577625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisstatic int l2t_seq_open(struct inode *inode, struct file *file) 578625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis{ 579625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis int rc = seq_open(file, &l2t_seq_ops); 580625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 581625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis if (!rc) { 582625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct adapter *adap = inode->i_private; 583625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis struct seq_file *seq = file->private_data; 584625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 585625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis seq->private = adap->l2t->l2tab; 586625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis } 587625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis return rc; 588625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis} 589625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis 590625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidisconst struct file_operations t4_l2t_fops = { 591625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis .owner = THIS_MODULE, 592625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis .open = l2t_seq_open, 593625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis .read = seq_read, 594625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis .llseek = seq_lseek, 595625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis .release = seq_release, 596625ba2c2eed763fad9c3f51318cbe8e1917b9fc8Dimitris Michailidis}; 597