Merge branch 'cxgb4-t6'

Hariprasad Shenai says:

====================
Cleanup, T6 changes and register range update

This patch series adds the following:
Don't use entire L2T table, update register ranges for T6 adapter,
read stats for only available channels for T6 and enable cim_la dump for
T6 adapter also.

This patch series has been created against net-next tree and includes
patches on cxgb4 driver.

We have included all the maintainers of respective drivers. Kindly review
the change and let us know in case of any review comments.
====================

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2015-07-08 16:13:55 -07:00
commit ca661a2888
6 changed files with 157 additions and 101 deletions

View File

@ -151,6 +151,45 @@ static int cim_la_show_3in1(struct seq_file *seq, void *v, int idx)
return 0;
}
static int cim_la_show_t6(struct seq_file *seq, void *v, int idx)
{
if (v == SEQ_START_TOKEN) {
seq_puts(seq, "Status Inst Data PC LS0Stat "
"LS0Addr LS0Data LS1Stat LS1Addr LS1Data\n");
} else {
const u32 *p = v;
seq_printf(seq, " %02x %04x%04x %04x%04x %04x%04x %08x %08x %08x %08x %08x %08x\n",
(p[9] >> 16) & 0xff, /* Status */
p[9] & 0xffff, p[8] >> 16, /* Inst */
p[8] & 0xffff, p[7] >> 16, /* Data */
p[7] & 0xffff, p[6] >> 16, /* PC */
p[2], p[1], p[0], /* LS0 Stat, Addr and Data */
p[5], p[4], p[3]); /* LS1 Stat, Addr and Data */
}
return 0;
}
static int cim_la_show_pc_t6(struct seq_file *seq, void *v, int idx)
{
if (v == SEQ_START_TOKEN) {
seq_puts(seq, "Status Inst Data PC\n");
} else {
const u32 *p = v;
seq_printf(seq, " %02x %08x %08x %08x\n",
p[3] & 0xff, p[2], p[1], p[0]);
seq_printf(seq, " %02x %02x%06x %02x%06x %02x%06x\n",
(p[6] >> 8) & 0xff, p[6] & 0xff, p[5] >> 8,
p[5] & 0xff, p[4] >> 8, p[4] & 0xff, p[3] >> 8);
seq_printf(seq, " %02x %04x%04x %04x%04x %04x%04x\n",
(p[9] >> 16) & 0xff, p[9] & 0xffff, p[8] >> 16,
p[8] & 0xffff, p[7] >> 16, p[7] & 0xffff,
p[6] >> 16);
}
return 0;
}
static int cim_la_open(struct inode *inode, struct file *file)
{
int ret;
@ -162,9 +201,18 @@ static int cim_la_open(struct inode *inode, struct file *file)
if (ret)
return ret;
p = seq_open_tab(file, adap->params.cim_la_size / 8, 8 * sizeof(u32), 1,
cfg & UPDBGLACAPTPCONLY_F ?
cim_la_show_3in1 : cim_la_show);
if (is_t6(adap->params.chip)) {
/* +1 to account for integer division of CIMLA_SIZE/10 */
p = seq_open_tab(file, (adap->params.cim_la_size / 10) + 1,
10 * sizeof(u32), 1,
cfg & UPDBGLACAPTPCONLY_F ?
cim_la_show_pc_t6 : cim_la_show_t6);
} else {
p = seq_open_tab(file, adap->params.cim_la_size / 8,
8 * sizeof(u32), 1,
cfg & UPDBGLACAPTPCONLY_F ? cim_la_show_3in1 :
cim_la_show);
}
if (!p)
return -ENOMEM;

View File

@ -4757,7 +4757,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
cfg_queues(adapter);
adapter->l2t = t4_init_l2t();
adapter->l2t = t4_init_l2t(adapter->l2t_start, adapter->l2t_end);
if (!adapter->l2t) {
/* We tolerate a lack of L2T, giving up some functionality */
dev_warn(&pdev->dev, "could not allocate L2T, continuing\n");

View File

@ -51,24 +51,17 @@
#define VLAN_NONE 0xfff
/* identifies sync vs async L2T_WRITE_REQs */
#define F_SYNC_WR (1 << 12)
enum {
L2T_STATE_VALID, /* entry is up to date */
L2T_STATE_STALE, /* entry may be used but needs revalidation */
L2T_STATE_RESOLVING, /* entry needs address resolution */
L2T_STATE_SYNC_WRITE, /* synchronous write of entry underway */
/* when state is one of the below the entry is not hashed */
L2T_STATE_SWITCHING, /* entry is being used by a switching filter */
L2T_STATE_UNUSED /* entry not in use */
};
#define SYNC_WR_S 12
#define SYNC_WR_V(x) ((x) << SYNC_WR_S)
#define SYNC_WR_F SYNC_WR_V(1)
struct l2t_data {
unsigned int l2t_start; /* start index of our piece of the L2T */
unsigned int l2t_size; /* number of entries in l2tab */
rwlock_t lock;
atomic_t nfree; /* number of free entries */
struct l2t_entry *rover; /* starting point for next allocation */
struct l2t_entry l2tab[L2T_SIZE];
struct l2t_entry l2tab[0]; /* MUST BE LAST */
};
static inline unsigned int vlan_prio(const struct l2t_entry *e)
@ -85,29 +78,36 @@ static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e)
/*
* To avoid having to check address families we do not allow v4 and v6
* neighbors to be on the same hash chain. We keep v4 entries in the first
* half of available hash buckets and v6 in the second.
* half of available hash buckets and v6 in the second. We need at least two
* entries in our L2T for this scheme to work.
*/
enum {
L2T_SZ_HALF = L2T_SIZE / 2,
L2T_HASH_MASK = L2T_SZ_HALF - 1
L2T_MIN_HASH_BUCKETS = 2,
};
static inline unsigned int arp_hash(const u32 *key, int ifindex)
static inline unsigned int arp_hash(struct l2t_data *d, const u32 *key,
int ifindex)
{
return jhash_2words(*key, ifindex, 0) & L2T_HASH_MASK;
unsigned int l2t_size_half = d->l2t_size / 2;
return jhash_2words(*key, ifindex, 0) % l2t_size_half;
}
static inline unsigned int ipv6_hash(const u32 *key, int ifindex)
static inline unsigned int ipv6_hash(struct l2t_data *d, const u32 *key,
int ifindex)
{
unsigned int l2t_size_half = d->l2t_size / 2;
u32 xor = key[0] ^ key[1] ^ key[2] ^ key[3];
return L2T_SZ_HALF + (jhash_2words(xor, ifindex, 0) & L2T_HASH_MASK);
return (l2t_size_half +
(jhash_2words(xor, ifindex, 0) % l2t_size_half));
}
static unsigned int addr_hash(const u32 *addr, int addr_len, int ifindex)
static unsigned int addr_hash(struct l2t_data *d, const u32 *addr,
int addr_len, int ifindex)
{
return addr_len == 4 ? arp_hash(addr, ifindex) :
ipv6_hash(addr, ifindex);
return addr_len == 4 ? arp_hash(d, addr, ifindex) :
ipv6_hash(d, addr, ifindex);
}
/*
@ -139,6 +139,8 @@ static void neigh_replace(struct l2t_entry *e, struct neighbour *n)
*/
static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync)
{
struct l2t_data *d = adap->l2t;
unsigned int l2t_idx = e->idx + d->l2t_start;
struct sk_buff *skb;
struct cpl_l2t_write_req *req;
@ -150,10 +152,10 @@ static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync)
INIT_TP_WR(req, 0);
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ,
e->idx | (sync ? F_SYNC_WR : 0) |
l2t_idx | (sync ? SYNC_WR_F : 0) |
TID_QID_V(adap->sge.fw_evtq.abs_id)));
req->params = htons(L2T_W_PORT_V(e->lport) | L2T_W_NOREPLY_V(!sync));
req->l2t_idx = htons(e->idx);
req->l2t_idx = htons(l2t_idx);
req->vlan = htons(e->vlan);
if (e->neigh && !(e->neigh->dev->flags & IFF_LOOPBACK))
memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac));
@ -190,18 +192,19 @@ static void send_pending(struct adapter *adap, struct l2t_entry *e)
*/
void do_l2t_write_rpl(struct adapter *adap, const struct cpl_l2t_write_rpl *rpl)
{
struct l2t_data *d = adap->l2t;
unsigned int tid = GET_TID(rpl);
unsigned int idx = tid & (L2T_SIZE - 1);
unsigned int l2t_idx = tid % L2T_SIZE;
if (unlikely(rpl->status != CPL_ERR_NONE)) {
dev_err(adap->pdev_dev,
"Unexpected L2T_WRITE_RPL status %u for entry %u\n",
rpl->status, idx);
rpl->status, l2t_idx);
return;
}
if (tid & F_SYNC_WR) {
struct l2t_entry *e = &adap->l2t->l2tab[idx];
if (tid & SYNC_WR_F) {
struct l2t_entry *e = &d->l2tab[l2t_idx - d->l2t_start];
spin_lock(&e->lock);
if (e->state != L2T_STATE_SWITCHING) {
@ -276,7 +279,7 @@ static struct l2t_entry *alloc_l2e(struct l2t_data *d)
return NULL;
/* there's definitely a free entry */
for (e = d->rover, end = &d->l2tab[L2T_SIZE]; e != end; ++e)
for (e = d->rover, end = &d->l2tab[d->l2t_size]; e != end; ++e)
if (atomic_read(&e->refcnt) == 0)
goto found;
@ -368,7 +371,7 @@ struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh,
int addr_len = neigh->tbl->key_len;
u32 *addr = (u32 *)neigh->primary_key;
int ifidx = neigh->dev->ifindex;
int hash = addr_hash(addr, addr_len, ifidx);
int hash = addr_hash(d, addr, addr_len, ifidx);
if (neigh->dev->flags & IFF_LOOPBACK)
lport = netdev2pinfo(physdev)->tx_chan + 4;
@ -481,7 +484,7 @@ void t4_l2t_update(struct adapter *adap, struct neighbour *neigh)
int addr_len = neigh->tbl->key_len;
u32 *addr = (u32 *) neigh->primary_key;
int ifidx = neigh->dev->ifindex;
int hash = addr_hash(addr, addr_len, ifidx);
int hash = addr_hash(d, addr, addr_len, ifidx);
read_lock_bh(&d->lock);
for (e = d->l2tab[hash].first; e; e = e->next)
@ -554,20 +557,30 @@ int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan,
return write_l2e(adap, e, 0);
}
struct l2t_data *t4_init_l2t(void)
struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end)
{
unsigned int l2t_size;
int i;
struct l2t_data *d;
d = t4_alloc_mem(sizeof(*d));
if (l2t_start >= l2t_end || l2t_end >= L2T_SIZE)
return NULL;
l2t_size = l2t_end - l2t_start + 1;
if (l2t_size < L2T_MIN_HASH_BUCKETS)
return NULL;
d = t4_alloc_mem(sizeof(*d) + l2t_size * sizeof(struct l2t_entry));
if (!d)
return NULL;
d->l2t_start = l2t_start;
d->l2t_size = l2t_size;
d->rover = d->l2tab;
atomic_set(&d->nfree, L2T_SIZE);
atomic_set(&d->nfree, l2t_size);
rwlock_init(&d->lock);
for (i = 0; i < L2T_SIZE; ++i) {
for (i = 0; i < d->l2t_size; ++i) {
d->l2tab[i].idx = i;
d->l2tab[i].state = L2T_STATE_UNUSED;
spin_lock_init(&d->l2tab[i].lock);
@ -578,9 +591,9 @@ struct l2t_data *t4_init_l2t(void)
static inline void *l2t_get_idx(struct seq_file *seq, loff_t pos)
{
struct l2t_entry *l2tab = seq->private;
struct l2t_data *d = seq->private;
return pos >= L2T_SIZE ? NULL : &l2tab[pos];
return pos >= d->l2t_size ? NULL : &d->l2tab[pos];
}
static void *l2t_seq_start(struct seq_file *seq, loff_t *pos)
@ -620,6 +633,7 @@ static int l2t_seq_show(struct seq_file *seq, void *v)
"Ethernet address VLAN/P LP State Users Port\n");
else {
char ip[60];
struct l2t_data *d = seq->private;
struct l2t_entry *e = v;
spin_lock_bh(&e->lock);
@ -628,7 +642,7 @@ static int l2t_seq_show(struct seq_file *seq, void *v)
else
sprintf(ip, e->v6 ? "%pI6c" : "%pI4", e->addr);
seq_printf(seq, "%4u %-25s %17pM %4d %u %2u %c %5u %s\n",
e->idx, ip, e->dmac,
e->idx + d->l2t_start, ip, e->dmac,
e->vlan & VLAN_VID_MASK, vlan_prio(e), e->lport,
l2e_state(e), atomic_read(&e->refcnt),
e->neigh ? e->neigh->dev->name : "");
@ -652,7 +666,7 @@ static int l2t_seq_open(struct inode *inode, struct file *file)
struct adapter *adap = inode->i_private;
struct seq_file *seq = file->private_data;
seq->private = adap->l2t->l2tab;
seq->private = adap->l2t;
}
return rc;
}

View File

@ -39,6 +39,20 @@
#include <linux/if_ether.h>
#include <linux/atomic.h>
enum { L2T_SIZE = 4096 }; /* # of L2T entries */
enum {
L2T_STATE_VALID, /* entry is up to date */
L2T_STATE_STALE, /* entry may be used but needs revalidation */
L2T_STATE_RESOLVING, /* entry needs address resolution */
L2T_STATE_SYNC_WRITE, /* synchronous write of entry underway */
L2T_STATE_NOARP, /* Netdev down or removed*/
/* when state is one of the below the entry is not hashed */
L2T_STATE_SWITCHING, /* entry is being used by a switching filter */
L2T_STATE_UNUSED /* entry not in use */
};
struct adapter;
struct l2t_data;
struct neighbour;
@ -56,7 +70,7 @@ struct cpl_l2t_write_rpl;
*/
struct l2t_entry {
u16 state; /* entry state */
u16 idx; /* entry index */
u16 idx; /* entry index within in-memory table */
u32 addr[4]; /* next hop IP or IPv6 address */
int ifindex; /* neighbor's net_device's ifindex */
struct neighbour *neigh; /* associated neighbour */
@ -104,7 +118,7 @@ void t4_l2t_update(struct adapter *adap, struct neighbour *neigh);
struct l2t_entry *t4_l2t_alloc_switching(struct l2t_data *d);
int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan,
u8 port, u8 *eth_addr);
struct l2t_data *t4_init_l2t(void);
struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end);
void do_l2t_write_rpl(struct adapter *p, const struct cpl_l2t_write_rpl *rpl);
extern const struct file_operations t4_l2t_fops;

View File

@ -1345,9 +1345,9 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x5a80, 0x5a9c,
0x5b94, 0x5bfc,
0x5c10, 0x5ec0,
0x5ec8, 0x5ec8,
0x5ec8, 0x5ecc,
0x6000, 0x6040,
0x6058, 0x6154,
0x6058, 0x615c,
0x7700, 0x7798,
0x77c0, 0x7880,
0x78cc, 0x78fc,
@ -1371,20 +1371,22 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x9f00, 0x9f6c,
0x9f80, 0xa020,
0xd004, 0xd03c,
0xd100, 0xd118,
0xd200, 0xd31c,
0xdfc0, 0xdfe0,
0xe000, 0xf008,
0x11000, 0x11014,
0x11048, 0x11110,
0x11118, 0x1117c,
0x11190, 0x11260,
0x11190, 0x11264,
0x11300, 0x1130c,
0x12000, 0x1205c,
0x12000, 0x1206c,
0x19040, 0x1906c,
0x19078, 0x19080,
0x1908c, 0x19124,
0x19150, 0x191b0,
0x191d0, 0x191e8,
0x19238, 0x192b8,
0x19238, 0x192bc,
0x193f8, 0x19474,
0x19490, 0x194cc,
0x194f0, 0x194f8,
@ -1466,7 +1468,7 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x30200, 0x30318,
0x30400, 0x3052c,
0x30540, 0x3061c,
0x30800, 0x3088c,
0x30800, 0x30890,
0x308c0, 0x30908,
0x30910, 0x309b8,
0x30a00, 0x30a04,
@ -1544,7 +1546,7 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x34200, 0x34318,
0x34400, 0x3452c,
0x34540, 0x3461c,
0x34800, 0x3488c,
0x34800, 0x34890,
0x348c0, 0x34908,
0x34910, 0x349b8,
0x34a00, 0x34a04,
@ -3924,43 +3926,25 @@ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
*/
void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st)
{
/* T6 and later has 2 channels */
if (adap->params.arch.nchan == NCHAN) {
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->mac_in_errs, 12, TP_MIB_MAC_IN_ERR_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->tnl_cong_drops, 8,
TP_MIB_TNL_CNG_DROP_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->tnl_tx_drops, 4,
TP_MIB_TNL_DROP_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->ofld_vlan_drops, 4,
TP_MIB_OFD_VLN_DROP_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->tcp6_in_errs, 4,
TP_MIB_TCP_V6IN_ERR_0_A);
} else {
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->mac_in_errs, 2, TP_MIB_MAC_IN_ERR_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->hdr_in_errs, 2, TP_MIB_HDR_IN_ERR_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->tcp_in_errs, 2, TP_MIB_TCP_IN_ERR_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->tnl_cong_drops, 2,
TP_MIB_TNL_CNG_DROP_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->ofld_chan_drops, 2,
TP_MIB_OFD_CHN_DROP_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->tnl_tx_drops, 2, TP_MIB_TNL_DROP_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->ofld_vlan_drops, 2,
TP_MIB_OFD_VLN_DROP_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->tcp6_in_errs, 2, TP_MIB_TCP_V6IN_ERR_0_A);
}
int nchan = adap->params.arch.nchan;
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->mac_in_errs, nchan, TP_MIB_MAC_IN_ERR_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->hdr_in_errs, nchan, TP_MIB_HDR_IN_ERR_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->tcp_in_errs, nchan, TP_MIB_TCP_IN_ERR_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->tnl_cong_drops, nchan, TP_MIB_TNL_CNG_DROP_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->ofld_chan_drops, nchan, TP_MIB_OFD_CHN_DROP_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->tnl_tx_drops, nchan, TP_MIB_TNL_DROP_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->ofld_vlan_drops, nchan, TP_MIB_OFD_VLN_DROP_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
st->tcp6_in_errs, nchan, TP_MIB_TCP_V6IN_ERR_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
&st->ofld_no_neigh, 2, TP_MIB_OFD_ARP_DROP_A);
}
@ -3974,16 +3958,13 @@ void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st)
*/
void t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st)
{
/* T6 and later has 2 channels */
if (adap->params.arch.nchan == NCHAN) {
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req,
8, TP_MIB_CPL_IN_REQ_0_A);
} else {
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req,
2, TP_MIB_CPL_IN_REQ_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->rsp,
2, TP_MIB_CPL_OUT_RSP_0_A);
}
int nchan = adap->params.arch.nchan;
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req,
nchan, TP_MIB_CPL_IN_REQ_0_A);
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->rsp,
nchan, TP_MIB_CPL_OUT_RSP_0_A);
}
/**

View File

@ -47,7 +47,6 @@ enum {
TCB_SIZE = 128, /* TCB size */
NMTUS = 16, /* size of MTU table */
NCCTRL_WIN = 32, /* # of congestion control windows */
L2T_SIZE = 4096, /* # of L2T entries */
PM_NSTATS = 5, /* # of PM stats */
MBOX_LEN = 64, /* mailbox size in bytes */
TRACE_LEN = 112, /* length of trace data and mask */