/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2010 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#include <linux/in.h>
#include <net/ip.h>
#include "efx.h"
#include "filter.h"
#include "io.h"
#include "nic.h"
#include "farch_regs.h"
/* "Fudge factors" - difference between programmed value and actual depth.
* Due to pipelined implementation we need to program H/W with a value that
* is larger than the hop limit we want.
*/
#define EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD 3
#define EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL 1
/* Hard maximum hop limit. Hardware will time-out beyond 200-something.
* We also need to avoid infinite loops in efx_farch_filter_search() when the
* table is full.
*/
#define EFX_FARCH_FILTER_CTL_SRCH_MAX 200
/* Don't try very hard to find space for performance hints, as this is
* counter-productive. */
#define EFX_FARCH_FILTER_CTL_SRCH_HINT_MAX 5
enum efx_farch_filter_type {
EFX_FARCH_FILTER_TCP_FULL = 0,
EFX_FARCH_FILTER_TCP_WILD,
EFX_FARCH_FILTER_UDP_FULL,
EFX_FARCH_FILTER_UDP_WILD,
EFX_FARCH_FILTER_MAC_FULL = 4,
EFX_FARCH_FILTER_MAC_WILD,
EFX_FARCH_FILTER_UC_DEF = 8,
EFX_FARCH_FILTER_MC_DEF,
EFX_FARCH_FILTER_TYPE_COUNT, /* number of specific types */
};
enum efx_farch_filter_table_id {
EFX_FARCH_FILTER_TABLE_RX_IP = 0,
EFX_FARCH_FILTER_TABLE_RX_MAC,
EFX_FARCH_FILTER_TABLE_RX_DEF,
EFX_FARCH_FILTER_TABLE_TX_MAC,
EFX_FARCH_FILTER_TABLE_COUNT,
};
enum efx_farch_filter_index {
EFX_FARCH_FILTER_INDEX_UC_DEF,
EFX_FARCH_FILTER_INDEX_MC_DEF,
EFX_FARCH_FILTER_SIZE_RX_DEF,
};
struct efx_farch_filter_spec {
u8 type:4;
u8 priority:4;
u8 flags;
u16 dmaq_id;
u32 data[3];
};
struct efx_farch_filter_table {
enum efx_farch_filter_table_id id;
u32 offset; /* address of table relative to BAR */
unsigned size; /* number of entries */
unsigned step; /* step between entries */
unsigned used; /* number currently used */
unsigned long *used_bitmap;
struct efx_farch_filter_spec *spec;
unsigned search_depth[EFX_FARCH_FILTER_TYPE_COUNT];
};
struct efx_farch_filter_state {
struct efx_farch_filter_table table[EFX_FARCH_FILTER_TABLE_COUNT];
};
static void
efx_farch_filter_table_clear_entry(struct efx_nic *efx,
struct efx_farch_filter_table *table,
unsigned int filter_idx);
/* The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
* key derived from the n-tuple. The initial LFSR state is 0xffff. */
static u16 efx_farch_filter_hash(u32 key)
{
u16 tmp;
/* First 16 rounds */
tmp = 0x1fff ^ key >> 16;
tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
tmp = tmp ^ tmp >> 9;
/* Last 16 rounds */
tmp = tmp ^ tmp << 13 ^ key;
tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
return tmp ^ tmp >> 9;
}
/* To allow for hash collisions, filter search continues at these
* increments from the first possible entry selected by the hash. */
static u16 efx_farch_filter_increment(u32 key)
{
return key * 2 - 1;
}
static enum efx_farch_filter_table_id
efx_farch_filter_spec_table_id(const struct efx_farch_filter_spec