Hi,
Attached below is a patch to several receive packet classification
and steering mechanisms for Xframe NIC hw channels. Current Xframe ASIC
supports one hardware channel per CPU, up to 8 channels. This number
will increase in the next ASIC release. A channel could be attached to a
specific MSI-X vector (with an independent interrupt moderation scheme),
which in turn can be bound to a CPU.

Follow-up patches will provide some enhancements for the default tcp
workload balancing across hw channels, as well as an optional hw channel
interface. The interface is intended to be very generic (not specific to
Xframe hardware).

The following mechanisms are supported in this patch:
Note: The steering type can be specified at load time with
parameter rx_steering_type. Values supported are 1(port based),
2(RTH), 4(SPDM), 8(MAC addr based). 
 
1. RTH(Receive traffic hashing):
Steering is based on socket tuple (or a subset) and the popular Jenkins
hash is used for RTH. This lets the receive processing to be spanned out
to multiple CPUs, thus reducing single CPU bottleneck on Rx path.
Hash-based steering can be used when it is desired to balance an
unlimited number or TCP sessions across multiple CPUs but the exact
mapping between a particular session and a particular cpu is not
important.

configuration: A mask(specified using loadable parameter rth_fn_and_mask)
can be used to select a subset of TCP/UDP tuple for hash calculation.
eg. To mask source port for TCP/IPv4 configuration,
# insmod s2io.ko rx_steering_type=2 rth_fn_and_mask=0x0101
LSB specifies RTH function type and MSB the mask. A full description
is provided at the beginning of s2io.c 

2. port based:
Steering is done based on source/destination TCP/UDP port number. 

configuration: Interface used is netlink sockets. Can specify port
number(s), TCP/UDP type, source/destination port.

3. MAC address-based:
Done based on destination MAC address of packet. Xframe can be
configured with multiple unicast MAC addresses.

configuration: Load-time parameters multi_mac_cnt and multi_macs
can be used to specify no. of MAC addresses and list of unicast
addresses.
eg. insmod s2io.ko rx_steering_type=8 multi_mac_cnt=3 
        multi_macs=00:0c:fc:00:00:22, 00:0c:fc:00:01:22, 00:0c:fc:00:02:22 
Packets received with default destination MAC address will be steered to 
ring0. Packets with destination MAC addresses specified by multi_macs are 
steered to ring1, ring2... respectively.

4. SPDM (Socket Pair Direct Match).
Steering is based on exact socket tuple (or a subset) match.
SPDM steering can be used when the exact mapping between a particular
session and a particular cpu is desired.

configuration: Interface used is netlink sockets. Can specify 
socket tuple values. If any of the values(say source port) needs
to be "don't care", specify 0xFFFF.

Signed-off-by: Raghavendra Koushik <[EMAIL PROTECTED]>
Signed-off-by: Sivakumar Subramani <[EMAIL PROTECTED]>
Signed-off-by: Ravinandan Arakali <[EMAIL PROTECTED]>
---

diff -urpN old/drivers/net/rx_cfg.h new/drivers/net/rx_cfg.h
--- old/drivers/net/rx_cfg.h    1969-12-31 16:00:00.000000000 -0800
+++ new/drivers/net/rx_cfg.h    2006-03-10 02:54:56.000000000 -0800
@@ -0,0 +1,44 @@
+#ifndef _RX_CFG_H_
+#define        _RX_CFG_H_
+
+typedef struct {
+       unsigned short  port;
+       unsigned short  prot_n_type; /* TCP/UDP & Dst/Src port type */
+#define        SRC_PRT         0x0
+#define        DST_PRT         0x1
+#define        TCP_PROT        0x0
+#define        UDP_PROT        0x1
+       unsigned short  dst_ring;
+}port_info_t;
+
+/* A Rx steering config structure to pass info the driver by user */
+typedef struct {
+       //SPDM
+       unsigned int    sip; /* Src IP addr */
+       unsigned int    dip; /* Dst IP addr */
+       unsigned short  sprt; /* Src TCP port */
+       unsigned short  dprt; /* Dst TCP port */
+       unsigned int    t_queue; /*Target Rx Queue for the packet */
+       unsigned int    hash; /* the hash as per jenkin's hash algorithm. */
+#define SPDM_NO_DATA                   0x1
+#define SPDM_XENA_IF                   0x2
+#define SPDM_HW_UNINITIALIZED          0x3
+#define SPDM_INCOMPLETE_SOCKET         0x4
+#define SPDM_TABLE_ACCESS_FAILED       0x5
+#define SPDM_TABLE_FULL                        0x6
+#define SPDM_TABLE_UNKNOWN_BAR         0x7
+#define SPDM_TABLE_MALLOC_FAIL         0x8
+#define        SPDM_INVALID_DEVICE             0x9
+#define SPDM_CONF_SUCCESS              0x0
+#define        SPDM_GET_CFG_DATA               0xAA55
+       int             ret;
+#define MAX_SPDM_ENTRIES_SIZE  (0x100 * 0x40)
+       unsigned char   data[MAX_SPDM_ENTRIES_SIZE];
+       int             data_len; /* Number of entries retrieved */
+       char            dev_name[20];   /* Device name, e.g. eth0, eth1... */
+
+       // Port steering
+       port_info_t     l4_ports;
+} rx_steering_cfg_t;
+
+#endif /*_RX_CFG_H_*/
diff -urpN old/drivers/net/s2io-regs.h new/drivers/net/s2io-regs.h
--- old/drivers/net/s2io-regs.h 2006-03-01 08:45:58.000000000 -0800
+++ new/drivers/net/s2io-regs.h 2006-03-10 02:54:56.000000000 -0800
@@ -291,7 +291,13 @@ typedef struct _XENA_dev_config {
        u64 wreq_split_mask;
 #define        WREQ_SPLIT_MASK_SET_MASK(val)   vBIT(val, 52, 12)
 
-       u8 unused7_2[0x800 - 0x248];
+       u8 unused7_2[0x318 - 0x248];
+       u64 spdm_bir_offset;
+       u64 spdm_overwrite;
+
+       u8 unused7_3[0x368 - 0x328];
+       u64 spdm_structure;
+       u8 unused7_4[0x800 - 0x370];
 
 /* TxDMA registers */
        u64 txdma_int_status;
@@ -678,6 +684,7 @@ typedef struct _XENA_dev_config {
        u64 rts_ctrl;
 #define RTS_CTRL_IGNORE_SNAP_OUI           BIT(2)
 #define RTS_CTRL_IGNORE_LLC_CTRL           BIT(3)
+#define  RTS_CTRL_ENHANCED                BIT(7)
 
        u64 rts_pn_cam_ctrl;
 #define RTS_PN_CAM_CTRL_WE                 BIT(7)
@@ -697,7 +704,55 @@ typedef struct _XENA_dev_config {
        u64 rts_ds_mem_data;
 #define RTS_DS_MEM_DATA(n)                 vBIT(n,0,8)
 
-       u8 unused16[0x700 - 0x220];
+       u8 unused15_1[0x338 - 0x220];
+
+       u64 rts_da_cfg;
+#define        RTS_DA_EN_SEC(n)                BIT(n)
+
+       u8 unused15_2[0x380 - 0x340];
+
+       u64 rts_rth_cfg;
+       #define RTS_RTH_EN                     BIT(3)
+       #define RTS_RTH_BUCKET_SIZE(n)         vBIT(n,4,4)
+       #define RTS_RTH_TCP_IPV4_EN            BIT(15)
+       #define RTS_RTH_UDP_IPV4_EN            BIT(19)
+       #define RTS_RTH_IPV4_EN                BIT(23)
+       #define RTS_RTH_TCP_IPV6_EN            BIT(27)
+       #define RTS_RTH_UDP_IPV6_EN            BIT(31)
+       #define RTS_RTH_IPV6_EN                BIT(35)
+       #define RTS_RTH_TCP_IPV6_EX_EN         BIT(39)
+       #define RTS_RTH_UDP_IPV6_EX_EN         BIT(43)
+       #define RTS_RTH_IPV6_EX_EN             BIT(47)
+
+       u64 rts_rth_map_mem_ctrl;
+       #define RTS_RTH_MAP_MEM_CTRL_WE                BIT(7)
+       #define RTS_RTH_MAP_MEM_CTRL_STROBE    BIT(15)
+       #define RTS_RTH_MAP_MEM_CTRL_OFFSET(n) vBIT(n,24,8)
+
+       u64 rts_rth_map_mem_data;
+       #define RTS_RTH_MAP_MEM_DATA_ENTRY_EN  BIT(3)
+       #define RTS_RTH_MAP_MEM_DATA_(n)       vBIT(n,5,3)
+
+       u64 rts_rth_spdm_mem_ctrl;
+       #define RTS_RTH_SPDM_MEM_CTRL_STROBE           BIT(15)
+       #define RTS_RTH_SPDM_MEM_CTRL_LINE_SEL(n)      vBIT(n,21,3)
+       #define RTS_RTH_SPDM_MEM_CTRL_OFFSET(n)        vBIT(n,24,8)
+
+       u64 rts_rth_spdm_mem_data;
+
+       u64 rts_rth_jhash_cfg;
+       #define RTS_RTH_JHASH_GOLDEN(n)        vBIT(n,0,32)
+       #define RTS_RTH_JHASH_INIT_VAL(n)      vBIT(n,32,32)
+
+       u64 rts_rth_hash_mask_n[5];
+       #define RTS_RTH_HASH_MASK_IPV4_SA(mask)   vBIT(mask,0,32)
+       #define RTS_RTH_HASH_MASK_IPV4_DA(mask)   vBIT(mask,32,32)
+
+       u64 rts_rth_hash_mask_5;
+       #define RTS_RTH_HASH_MASK_L4_SP(mask)  vBIT(mask,0,16)
+       #define RTS_RTH_HASH_MASK_L4_DP(mask)  vBIT(mask,16,16)
+
+       u8 unused16[0x700 - 0x3E0];
 
        u64 mac_debug_ctrl;
 #define MAC_DBG_ACTIVITY_VALUE            0x411040400000000ULL
diff -urpN old/drivers/net/s2io.c new/drivers/net/s2io.c
--- old/drivers/net/s2io.c      2006-03-01 08:47:42.000000000 -0800
+++ new/drivers/net/s2io.c      2006-03-10 02:55:25.000000000 -0800
@@ -27,14 +27,38 @@
  * The module loadable parameters that are supported by the driver and a brief
  * explaination of all the variables.
  * rx_ring_num : This can be used to program the number of receive rings used
- * in the driver.
+ *  in the driver.
  * rx_ring_sz: This defines the number of descriptors each ring can have. This
  * is also an array of size 8.
  * rx_ring_mode: This defines the operation mode of all 8 rings. The valid
- *             values are 1, 2 and 3.
+ *  values are 1, 2 and 3.
  * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver.
  * tx_fifo_len: This too is an array of 8. Each element defines the number of
  * Tx descriptors that can be associated with each corresponding FIFO.
+ * rx_steering_type: Currently 4 ways are supported to steer Rx'ed frames to
+ *  the correct rings on the host. They are either SPDM or RTH or TCP port 
based
+ *  or Destination MAC address based steering. This parameter can be used to
+ *  choose any one scheme. The value of the module and it's corresponding 
steering
+ *  scheme are as mentioned below, TCP port steering - 1, RTH - 2 SPDM - 4 and
+ *  MAC Addr - 8
+ * rth_fn_and_mask: This parameter is used when RTH/SPDM steering is 
employed.It
+ * can be used to define
+ *     i. Input to the hash function (Least significant byte).
+ *              1 is IPV4 Src and dst address and TCP src abd Dst ports
+ *              2 is IPV4 Src and dst address and UDP src abd Dst ports
+ *              3 is IPV4 Src and dst address
+ *              4 is IPV6 Src and dst address and TCP src abd Dst ports
+ *              5 is IPV6 Src and dst address and UDP src abd Dst ports
+ *              6 is IPV6 Src and dst address
+ *              7 is extended IPV6 Src and dst address and TCP src abd Dst
+ *              ports
+ *              8 is extended IPV6 Src and dst address and UDP src abd Dst
+ *              ports
+ *              9 is extended IPV6 Src and dst address
+ *      ii. Mask any of the six parameters used for RTH calculation mentioned
+ *              above(bit 9 to bit 14). The bits 9 to 14 represent IPV4 SA,
+ *              IPV4 DA, IPV6 SA, IPV6 DA, L4 SP, L4 DP in that order.
+ *              Masking any field will make it all '1's.
  ************************************************************************/
 
 #include <linux/config.h>
@@ -67,10 +91,11 @@
 #include <asm/div64.h>
 
 /* local include */
+#include "rx_cfg.h"
 #include "s2io.h"
 #include "s2io-regs.h"
 
-#define DRV_VERSION "2.0.11.2"
+#define DRV_VERSION "2.0.12.2"
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
@@ -79,6 +104,12 @@ static char s2io_driver_version[] = DRV_
 int rxd_size[4] = {32,48,48,64};
 int rxd_count[4] = {127,85,85,63};
 
+#ifndef NETLINK_S2IO
+#define NETLINK_S2IO    17
+#endif
+static struct sock *nl_sk = NULL; /* Socket to interact with user layer */
+static int kill_thread = 0; /* indicates if the kernel thread needs to be 
killed */
+
 static inline int RXD_IS_UP2DT(RxD_t *rxdp)
 {
        int ret;
@@ -332,6 +363,13 @@ static unsigned int lro = 0;
  * aggregation happens until we hit max IP pkt size(64K)
  */
 static unsigned int lro_max_pkts = 0xFFFF;
+/* rx side steering parameter. Default is no steering */
+static unsigned int rx_steering_type = NO_STEERING;
+static unsigned int rth_fn_and_mask = 0x1;
+/* Params to program multiple Unicast MACs on the NIC */
+static int multi_mac_cnt = 0;
+static char *multi_macs[MAX_MACS] =
+{[0 ...(MAX_MACS-1)] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAA"};
 
 /*
  * S2IO device table.
@@ -361,6 +399,143 @@ static struct pci_driver s2io_driver = {
 /* A simplifier macro used both by init and free shared_mem Fns(). */
 #define TXD_MEM_PAGE_CNT(len, per_each) ((len+per_each - 1) / per_each)
 
+//NETLINK
+static int spdm_data_processor(rx_steering_cfg_t *usr_info, nic_t *sp)
+{
+       struct config_param *config;
+        int ret = FAILURE;
+
+       config = &sp->config;
+
+        if ((sp->device_type == XFRAME_I_DEVICE) && (config->rx_steering_type
+                                                    ==SPDM_STEERING)){
+                usr_info->ret = SPDM_XENA_IF;
+                return FAILURE;
+        }
+
+       if (atomic_read(&sp->card_state) == CARD_DOWN) {
+                usr_info->ret = SPDM_HW_UNINITIALIZED;
+                return FAILURE;
+        }
+
+        if (usr_info->ret == SPDM_GET_CFG_DATA) {/* Retrieve info */
+                u8 *data = kmalloc(MAX_SPDM_ENTRIES_SIZE, GFP_KERNEL);
+                if (!data) {
+                        usr_info->ret = SPDM_TABLE_MALLOC_FAIL;
+                        return FAILURE;
+                }
+
+                ret = spdm_extract_table(data, sp);
+                if (ret != FAILURE) {
+                        memcpy(usr_info->data, data,
+                                     (sp->spdm_entry * 0x40));
+                        usr_info->data_len= ret;
+                        usr_info->ret = SPDM_CONF_SUCCESS;
+                        ret = SUCCESS;
+                } else {
+                        usr_info->ret = SPDM_TABLE_ACCESS_FAILED;
+                        ret = FAILURE;
+                }
+
+                kfree(data);
+                return ret;
+        }
+
+        if (!usr_info->dip || !usr_info->sip || !usr_info->sprt ||
+           !usr_info->dprt) {
+                usr_info->ret = SPDM_INCOMPLETE_SOCKET;
+                return FAILURE;
+        }
+
+       if (config->rx_steering_type == PORT_STEERING) {
+               ret = s2io_set_steering_ports(sp, usr_info);
+       } else if (config->rx_steering_type == SPDM_STEERING) {
+               if (!usr_info->dip || !usr_info->sip || !usr_info->sprt ||
+                   !usr_info->dprt) {
+                       usr_info->ret = SPDM_INCOMPLETE_SOCKET;
+                       return FAILURE;
+               }
+               ret = spdm_configure(sp, usr_info);
+        }
+
+       if (ret == SUCCESS)
+               usr_info->ret = SPDM_CONF_SUCCESS;
+        return SUCCESS;
+}
+
+void nl_data_ready (struct sock *sk, int len)
+{
+        wake_up_interruptible(sk->sk_sleep);
+}
+
+static int read_and_write_nl(void)
+{
+        struct sk_buff *skb = NULL;
+        struct nlmsghdr *nlh = NULL;
+        int err, pid;
+        rx_steering_cfg_t *up;
+        struct net_device *dev;
+        nic_t *sp;
+
+        /* wait for message coming down from user-space */
+        skb = skb_recv_datagram(nl_sk, 0, 1, &err);
+        if (skb == NULL) {
+                DBG_PRINT(INFO_DBG, "%s: SKB is NULL\n", __FUNCTION__);
+                return -EAGAIN;
+        }
+
+        if (kill_thread) {
+                DBG_PRINT(ERR_DBG,"%s: Killing thread\n", __FUNCTION__);
+                kfree_skb(skb);
+                return -1;
+        }
+
+        nlh = (struct nlmsghdr *)skb->data;
+        up = NLMSG_DATA(nlh);
+        dev = dev_get_by_name(up->dev_name);
+        if (dev == NULL) {
+                up->ret = SPDM_INVALID_DEVICE;
+                goto return_pkt;
+        }
+        sp = (nic_t *)dev->priv;
+        dev_put(dev);
+        if (sp->pdev->vendor != PCI_VENDOR_ID_S2IO) {
+                up->ret = SPDM_INVALID_DEVICE;
+                goto return_pkt;
+        }
+
+        if(spdm_data_processor(up, sp)) {
+                DBG_PRINT(ERR_DBG,"%s: returned %d\n", __FUNCTION__, up->ret);
+        }
+
+return_pkt:
+        pid = nlh->nlmsg_pid; /*pid of sending process */
+       NETLINK_CB(skb).pid = 0;
+       NETLINK_CB(skb).dst_pid = pid;
+       NETLINK_CB(skb).dst_group = 0;
+        netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT);
+
+        return 0;
+}
+
+static int nl_reader(void *dummy)
+{
+        int err;
+
+        while(1) {
+                err = read_and_write_nl();
+                if ((err) && (err != -EAGAIN)) {
+                        kill_thread = 0;
+                        break;
+                }
+               msleep(500); /* Chk for usr input, every 0.5 sec */
+        }
+        sock_release(nl_sk->sk_socket);
+        nl_sk = NULL;
+
+        return 0;
+}
+
 /**
  * init_shared_mem - Allocation and Initialization of Memory
  * @nic: Device private variable.
@@ -835,6 +1010,362 @@ static int s2io_print_pci_mode(nic_t *ni
        return mode;
 }
 
+/* RTH */
+/*
+ * s2io_set_rth_fn -
+ */
+static void s2io_set_rth_fn(u8 fn_type, nic_t *nic)
+{
+        XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+        register u64 val64 = 0;
+        struct config_param *config = &nic->config;
+       int rth_sz = ((config->rx_ring_num + 1)/2);
+
+       switch(fn_type) {
+               case 1:
+                       val64 = RTS_RTH_TCP_IPV4_EN;
+                       break;
+               case 2:
+                       val64 = RTS_RTH_UDP_IPV4_EN;
+                       break;
+               case 3:
+                       val64 = RTS_RTH_IPV4_EN;
+                       break;
+               case 4:
+                       val64 = RTS_RTH_TCP_IPV6_EN;
+                       break;
+               case 5:
+                       val64 = RTS_RTH_UDP_IPV6_EN;
+                       break;
+               case 6:
+                       val64 = RTS_RTH_IPV6_EN;
+                       break;
+               case 7:
+                       val64 = RTS_RTH_TCP_IPV6_EX_EN;
+                       break;
+               case 8:
+                       val64 = RTS_RTH_UDP_IPV6_EX_EN;
+                       break;
+               case 9:
+                       val64 = RTS_RTH_IPV6_EX_EN;
+                       break;
+               default:
+                       val64 = RTS_RTH_TCP_IPV4_EN;
+                       break;
+       }
+       val64 |= RTS_RTH_EN | RTS_RTH_BUCKET_SIZE(rth_sz);
+       writeq(val64, &bar0->rts_rth_cfg);
+}
+
+/*
+ * s2io_set_rth_mask -
+ */
+static void s2io_set_rth_mask(u8 mask, nic_t *nic)
+{
+        XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+        register u64 val64 = 0;
+       int i;
+
+       for (i=0; i<6; i++) {
+               if (!((mask >> i) & 0x1))
+                       continue;
+               switch(i) {
+                       case 0:
+                               val64 = readq(&bar0->rts_rth_hash_mask_n[4]);
+                               val64 |= RTS_RTH_HASH_MASK_IPV4_SA(0xFFFFFFFF);
+                               writeq(val64, &bar0->rts_rth_hash_mask_n[4]);
+                               break;
+                       case 1:
+                               val64 = readq(&bar0->rts_rth_hash_mask_n[4]);
+                               val64 |= RTS_RTH_HASH_MASK_IPV4_DA(0xFFFFFFFF);
+                               writeq(val64, &bar0->rts_rth_hash_mask_n[4]);
+                               break;
+                       case 2:
+                               val64 = 0xFFFFFFFFFFFFFFFFULL;
+                               writeq(val64, &bar0->rts_rth_hash_mask_n[0]);
+                               val64 = 0xFFFFFFFFFFFFFFFFULL;
+                               writeq(val64, &bar0->rts_rth_hash_mask_n[1]);
+                               break;
+                       case 3:
+                               val64 = 0xFFFFFFFFFFFFFFFFULL;
+                               writeq(val64, &bar0->rts_rth_hash_mask_n[2]);
+                               val64 = 0xFFFFFFFFFFFFFFFFULL;
+                               writeq(val64, &bar0->rts_rth_hash_mask_n[3]);
+                               break;
+                       case 4:
+                               val64 = readq(&bar0->rts_rth_hash_mask_5);
+                               val64 |= RTS_RTH_HASH_MASK_L4_SP(0xFFFF);
+                               writeq(val64, &bar0->rts_rth_hash_mask_5);
+                               break;
+                       case 5:
+                               val64 = readq(&bar0->rts_rth_hash_mask_5);
+                               val64 |= RTS_RTH_HASH_MASK_L4_DP(0xFFFF);
+                               writeq(val64, &bar0->rts_rth_hash_mask_5);
+                               break;
+               }
+       }
+}
+
+/**
+ * s2io_set_steering_ports -
+ */
+
+static int s2io_set_steering_ports(nic_t *nic, rx_steering_cfg_t *info)
+{
+        XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+        register u64 val64 = 0;
+        int i, ring = 0, port, port_type, prot_type;
+        struct config_param *config;
+
+        config = &nic->config;
+       for (i=0, ring = 0; i<(MAX_STEER_PORTS-1); i++)
+               if (!config->steer_ports[i])
+                       break;
+       if (i == (MAX_STEER_PORTS-1)) {
+               DBG_PRINT(ERR_DBG,"%s: Max(32) ports already configured\n",
+                         __FUNCTION__);
+               return FAILURE;
+       }
+
+       /* Disable Qos type and DS field Steering */
+       writeq(0, &bar0->rts_qos_steering);
+       writeq(0, &bar0->rts_ds_mem_data);
+       for (i = 0; i < 64; i++) {
+               val64 = BIT(7) | BIT(15) | vBIT(i,26,6);
+               writeq(val64, &bar0->rts_ds_mem_ctrl);
+               if (wait_for_cmd_complete(&bar0->rts_ds_mem_ctrl,
+                       RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED) == FAILURE)
+                       return FAILURE;
+       }
+
+       port = config->steer_ports[i] = info->l4_ports.port;
+       ring = info->l4_ports.dst_ring;
+       port_type = info->l4_ports.prot_n_type & 0x1;
+       prot_type = (info->l4_ports.prot_n_type >> 1) & 0x1;
+       if (nic->device_type == XFRAME_II_DEVICE) {
+               val64 = vBIT(port,8,16) | vBIT(ring,37,3) | BIT(63);
+               if (port_type == SRC_PRT)
+                       val64 |= BIT(47);
+               if (prot_type == TCP_PROT)
+                       val64 |= BIT(7);
+               writeq(val64, &bar0->rts_pn_cam_data);
+       } else {
+               /* XFRAME_I_DEVICE */
+               ring = 0x80 >> ring;
+               val64 = vBIT(port,8,16) | vBIT(ring,24,8);
+               if (prot_type == TCP_PROT)
+                       val64 |= BIT(7);
+               writeq(val64, &bar0->rts_pn_cam_data);
+       }
+       val64 = BIT(7) | BIT(15) | vBIT(i+1,24,8);
+       writeq(val64, &bar0->rts_pn_cam_ctrl);
+
+       if (wait_for_cmd_complete(&bar0->rts_pn_cam_ctrl,\
+                                 RTS_PN_CAM_CTRL_STROBE_BEING_EXECUTED)\
+           == FAILURE)
+               return FAILURE;
+       return 0;
+}
+
+/**
+ * s2io_rth_configure -
+ */
+static int s2io_rth_configure(nic_t *nic)
+{
+        XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+        register u64 val64 = 0;
+        struct config_param *config;
+        int buckets, i, ring = 0, cnt = 0;
+        u8 mask, fn_type;
+
+        config = &nic->config;
+       buckets = config->rx_ring_num;
+
+       for (i=0; i<buckets; i++) {
+               val64 = RTS_RTH_MAP_MEM_DATA_ENTRY_EN |
+                       RTS_RTH_MAP_MEM_DATA_(ring);
+               writeq(val64, &bar0->rts_rth_map_mem_data);
+
+               val64 = RTS_RTH_MAP_MEM_CTRL_WE |
+                       RTS_RTH_MAP_MEM_CTRL_STROBE |
+                       RTS_RTH_MAP_MEM_CTRL_OFFSET(i);
+               writeq(val64, &bar0->rts_rth_map_mem_ctrl);
+
+               do {
+                       val64 = readq(&bar0->rts_rth_map_mem_ctrl);
+                       if (val64 & RTS_RTH_MAP_MEM_CTRL_STROBE) {
+                               cnt++;
+                               msleep(10);
+                               continue;
+                       }
+                       break;
+               } while(cnt < 5);
+               if (cnt == 5)
+                       return FAILURE;
+               ring ++;
+               ring %= config->rx_ring_num;
+       }
+
+       /* Mask all parameters as per user's input. */
+       mask = (u8)((config->rth_fn_and_mask >> 8) & 0xFF);
+       s2io_set_rth_mask(mask, nic);
+
+       /* Set the requested RTH function type */
+       fn_type = (u8)(config->rth_fn_and_mask & 0xFF);
+       s2io_set_rth_fn(fn_type, nic);
+
+        return 0;
+}
+
+/* SPDM */
+/**
+ * spdm_extract_table -
+ * @data: Space to store the contents of SPDM table.
+ * @nic:  Device private variable.
+ * Description: This function is to extract the contents of the
+ * SPDM table and return this info back to the user to inform
+ * about the socket pairs configured into the NIC.
+ */
+static int spdm_extract_table(void *data, nic_t *nic)
+{
+        XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+        u64 val64, table_content;
+        int line, entry = 0;
+
+        while (entry < nic->spdm_entry) {
+                u64 *tmp = (u64 *)((u8 *)data + (0x40 * entry));
+                for (line = 0; line < 8; line++, tmp++) {
+                        val64 = RTS_RTH_SPDM_MEM_CTRL_OFFSET(entry) |
+                                RTS_RTH_SPDM_MEM_CTRL_LINE_SEL(line) |
+                                RTS_RTH_SPDM_MEM_CTRL_STROBE;
+                        writeq(val64, &bar0->rts_rth_spdm_mem_ctrl);
+                        if (wait_for_cmd_complete(&bar0->rts_rth_spdm_mem_ctrl,
+                              RTS_RTH_SPDM_MEM_CTRL_STROBE) == FAILURE)
+                                return FAILURE;
+                        table_content = readq(&bar0->rts_rth_spdm_mem_data);
+                        if (!line && !table_content)
+                                goto end;
+                        *tmp = table_content;
+                }
+                entry++;
+        }
+end:
+        return entry;
+}
+
+/**
+ * s2io_program_spdm_table -
+ * @info: Data structure to exchange data between Kernel and user layers.
+ * @nic:  Device private variable.
+ * Description: This function is to program a new socket pair 
+ * (IP Src & Dst addrs, TCP Src and Dst ports) into SPDM table.
+ * 
+ * It's the driver's responsibilty to keep track of the number of
+ * socket pairs currently programmed in the SPDM table of the NIC.
+ * Currently only IPV4 based socket pairs can be programmed. The device 
+ * itself supports both IPV4 and IPV6 based socket pair matching. 
+ */
+static int s2io_program_spdm_table(rx_steering_cfg_t *info, int entry, nic_t 
*nic)
+{
+        XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+        u64 val64;
+        unsigned long tmp;
+        int ring;
+        u32 start_tbl, entry_offset;
+        spdm_entry_t element;
+        void *element_addr;
+        u16 sprt, dprt;
+        u32 sip, dip, hash;
+
+        ring = info->t_queue;
+        entry = nic->spdm_entry;
+
+        val64 = readq(&bar0->spdm_bir_offset);
+        start_tbl = (u32)(val64 >> 32);
+        start_tbl = (u32)(val64 >> 32);
+        start_tbl *= 8;
+        entry_offset = entry * sizeof(spdm_entry_t);
+
+        element_addr = (void *)((u8 *)bar0 + start_tbl + entry_offset);
+        tmp = (unsigned long)element_addr;
+
+        sprt = info->sprt;
+        dprt = info->dprt;
+        sip = info->sip;
+        dip = info->dip;
+        element.port_n_entry_control_0 = SPDM_PGM_L4_SRC_PORT(sprt) |
+                        SPDM_PGM_L4_DST_PORT(dprt) |
+                        SPDM_PGM_TARGET_QUEUE(ring);
+        if (info->sprt)
+                element.port_n_entry_control_0 |= SPDM_PGM_IS_TCP |
+                        SPDM_PGM_IS_IPV4;
+        writeq(element.port_n_entry_control_0, element_addr);
+        tmp += 8;
+        element_addr = (void *)tmp;
+
+        element.ip.ipv4_sa_da = sip;
+        element.ip.ipv4_sa_da <<= 32;
+        element.ip.ipv4_sa_da |= dip;
+        writeq(element.ip.ipv4_sa_da, element_addr);
+
+        tmp += 8;
+        element_addr = (void *)tmp;
+        writeq(0, element_addr);
+        tmp += 8;
+        element_addr = (void *)tmp;
+        writeq(0, element_addr);
+        tmp += 8;
+        element_addr = (void *)tmp;
+        writeq(0, element_addr);
+        tmp += 8;
+        element_addr = (void *)tmp;
+        writeq(0, element_addr);
+        tmp += 8;
+        element_addr = (void *)tmp;
+        writeq(0, element_addr);
+        tmp += 8;
+        element_addr = (void *)tmp;
+
+        hash = info->hash;
+        element.hash_n_entry_control_1 = SPDM_PGM_HASH(hash) |
+                                        SPDM_PGM_ENABLE_ENTRY;
+        writeq(element.hash_n_entry_control_1, element_addr);
+        msleep(20);
+
+        return 0;
+}
+
+/**
+ * spdm_configure -
+ * @info: Data structure to exchange data between Kernel and user layers.
+ * @nic:  Device private variable.
+ * Description: This function called by the netlink recv handler decides
+ * whether the user is requesting SPDM table information or intends to
+ * program a new value into it and calls an appropriate function to do it.
+ */
+static int spdm_configure(nic_t *nic, rx_steering_cfg_t *info)
+{
+        XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+        struct net_device *dev = nic->dev;
+        u64 val64;
+        int ret;
+
+        val64 = readq(&bar0->spdm_bir_offset);
+        if (!(val64 & (vBIT(3, 0, 2)))) {
+                s2io_program_spdm_table(info, nic->spdm_entry, nic);
+                nic->spdm_entry++;
+                if (nic->spdm_entry == MAX_SUPPORTED_SPDM_ENTRIES)
+                        nic->spdm_entry = 0;
+                ret = SUCCESS;
+        } else {
+                DBG_PRINT(ERR_DBG,"SPDM table of %s is not in BAR0!!\n", 
dev->name);
+                info->ret = SPDM_TABLE_UNKNOWN_BAR;
+                ret = FAILURE;
+        }
+
+        return ret;
+}
+
 /**
  *  init_nic - Initialization of hardware
  *  @nic: device peivate variable
@@ -1182,8 +1713,6 @@ static int init_nic(struct s2io_nic *nic
          */
        switch (config->rx_ring_num) {
        case 1:
-               val64 = 0x8080808080808080ULL;
-               writeq(val64, &bar0->rts_qos_steering);
                break;
        case 2:
                val64 = 0x0000010000010000ULL;
@@ -1196,9 +1725,6 @@ static int init_nic(struct s2io_nic *nic
                writeq(val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0100000000000000ULL;
                writeq(val64, &bar0->rx_w_round_robin_4);
-
-               val64 = 0x8080808040404040ULL;
-               writeq(val64, &bar0->rts_qos_steering);
                break;
        case 3:
                val64 = 0x0001000102000001ULL;
@@ -1211,9 +1737,6 @@ static int init_nic(struct s2io_nic *nic
                writeq(val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0001020000000000ULL;
                writeq(val64, &bar0->rx_w_round_robin_4);
-
-               val64 = 0x8080804040402020ULL;
-               writeq(val64, &bar0->rts_qos_steering);
                break;
        case 4:
                val64 = 0x0001020300010200ULL;
@@ -1226,9 +1749,6 @@ static int init_nic(struct s2io_nic *nic
                writeq(val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0203000100000000ULL;
                writeq(val64, &bar0->rx_w_round_robin_4);
-
-               val64 = 0x8080404020201010ULL;
-               writeq(val64, &bar0->rts_qos_steering);
                break;
        case 5:
                val64 = 0x0001000203000102ULL;
@@ -1241,9 +1761,6 @@ static int init_nic(struct s2io_nic *nic
                writeq(val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0001000000000000ULL;
                writeq(val64, &bar0->rx_w_round_robin_4);
-
-               val64 = 0x8080404020201008ULL;
-               writeq(val64, &bar0->rts_qos_steering);
                break;
        case 6:
                val64 = 0x0001020304000102ULL;
@@ -1256,9 +1773,6 @@ static int init_nic(struct s2io_nic *nic
                writeq(val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0001000200000000ULL;
                writeq(val64, &bar0->rx_w_round_robin_4);
-
-               val64 = 0x8080404020100804ULL;
-               writeq(val64, &bar0->rts_qos_steering);
                break;
        case 7:
                val64 = 0x0001020001020300ULL;
@@ -1271,9 +1785,6 @@ static int init_nic(struct s2io_nic *nic
                writeq(val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0102030000000000ULL;
                writeq(val64, &bar0->rx_w_round_robin_4);
-
-               val64 = 0x8080402010080402ULL;
-               writeq(val64, &bar0->rts_qos_steering);
                break;
        case 8:
                val64 = 0x0001020300040105ULL;
@@ -1286,9 +1797,6 @@ static int init_nic(struct s2io_nic *nic
                writeq(val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0103020400000000ULL;
                writeq(val64, &bar0->rx_w_round_robin_4);
-
-               val64 = 0x8040201008040201ULL;
-               writeq(val64, &bar0->rts_qos_steering);
                break;
        }
 
@@ -1474,6 +1982,30 @@ static int init_nic(struct s2io_nic *nic
                }
        }
 
+        /* Enable enhanced steering mode if device is Herc*/
+        if ((config->rx_steering_type & RX_STEERING_SUPPORT)
+           &&(nic->device_type == XFRAME_II_DEVICE)) {
+
+               val64 = readq(&bar0->rts_ctrl);
+               val64 |= RTS_CTRL_ENHANCED;
+               writeq(val64, &bar0->rts_ctrl);
+
+               /* Configure RTH */
+               if (config->rx_steering_type & ENHANCED_STEERING_SUPPORT) {
+                       s2io_rth_configure(nic);
+               } else if (config->rx_steering_type & DS_MAC_STEERING) {
+                       if (config->num_mac_cfg > 1) {
+                               u64 val64;
+                               /*
+                                * Enable MAC based Rx steering for Section 0-31
+                                * on Herc
+                                */
+                               val64 = RTS_DA_EN_SEC(0);
+                               writeq(val64, &bar0->rts_da_cfg);
+                       }
+               }
+        }
+
        /*
         * Initializing proper values as Pause threshold into all
         * the 8 Queues on Rx side.
@@ -2864,19 +3396,21 @@ static void alarm_intr_handler(struct s2
  *   SUCCESS on success and FAILURE on failure.
  */
 
-static int wait_for_cmd_complete(nic_t * sp)
+static int wait_for_cmd_complete(void *addr, u64 busy_bit)
 {
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
        int ret = FAILURE, cnt = 0;
        u64 val64;
 
        while (TRUE) {
-               val64 = readq(&bar0->rmac_addr_cmd_mem);
-               if (!(val64 & RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
+               val64 = readq(addr);
+               if (!(val64 & busy_bit)) {
                        ret = SUCCESS;
                        break;
                }
-               msleep(50);
+               if (in_interrupt())
+                       mdelay(50);
+               else
+                       msleep(50);
                if (cnt++ > 10)
                        break;
        }
@@ -2986,7 +3520,7 @@ int s2io_set_swapper(nic_t * sp)
 {
        struct net_device *dev = sp->dev;
        XENA_dev_config_t __iomem *bar0 = sp->bar0;
-       u64 val64, valt, valr;
+       u64 val64, valt, valr, sw_wr, rth_wr;
 
        /*
         * Set proper endian settings and verify the same by reading
@@ -3048,6 +3582,9 @@ int s2io_set_swapper(nic_t * sp)
        }
        val64 = readq(&bar0->swapper_ctrl);
        val64 &= 0xFFFF000000000000ULL;
+       sw_wr = (val64 & vBIT(3, 8, 2));
+       rth_wr = (sw_wr >> 2);
+       val64 |= rth_wr;
 
 #ifdef  __BIG_ENDIAN
        /*
@@ -3327,6 +3864,7 @@ static int s2io_open(struct net_device *
        int err = 0;
        int i;
        u16 msi_control; /* Temp variable */
+       struct config_param *config;
 
        /*
         * Make sure you have link off by default every time
@@ -3394,10 +3932,19 @@ failed\n", dev->name, i);
                }
        }
 
-       if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
-               DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
-               err = -ENODEV;
-               goto setting_mac_address_failed;
+       config = &sp->config;
+       for (i=0; i<config->num_mac_cfg; i++) {
+               u8 *addr;
+
+               if (i)
+                       addr = (u8 *)config->mac_addrs[i-1].mac_addr;
+               else
+                       addr = (u8 *)dev->dev_addr;
+               if (s2io_set_mac_addr(dev, addr, i) == FAILURE) {
+                       DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
+                       err = -ENODEV;
+                       goto setting_mac_address_failed;
+               }
        }
 
        netif_start_queue(dev);
@@ -3482,7 +4029,7 @@ static int s2io_close(struct net_device 
                free_irq(sp->pdev->irq, dev);
                if (sp->intr_type == MSI)
                        pci_disable_msi(sp->pdev);
-       }       
+       }
        sp->device_close_flag = TRUE;   /* Device is shut down. */
        return 0;
 }
@@ -4067,7 +4614,8 @@ static void s2io_set_multicast(struct ne
                    RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
                writeq(val64, &bar0->rmac_addr_cmd_mem);
                /* Wait till command completes */
-               wait_for_cmd_complete(sp);
+               wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+                                     RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
 
                sp->m_cast_flg = 1;
                sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
@@ -4082,7 +4630,8 @@ static void s2io_set_multicast(struct ne
                    RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos);
                writeq(val64, &bar0->rmac_addr_cmd_mem);
                /* Wait till command completes */
-               wait_for_cmd_complete(sp);
+               wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+                                     RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
 
                sp->m_cast_flg = 0;
                sp->all_multi_pos = 0;
@@ -4147,7 +4696,8 @@ static void s2io_set_multicast(struct ne
                        writeq(val64, &bar0->rmac_addr_cmd_mem);
 
                        /* Wait for command completes */
-                       if (wait_for_cmd_complete(sp)) {
+                       if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+                               RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
                                DBG_PRINT(ERR_DBG, "%s: Adding ",
                                          dev->name);
                                DBG_PRINT(ERR_DBG, "Multicasts failed\n");
@@ -4176,7 +4726,8 @@ static void s2io_set_multicast(struct ne
                        writeq(val64, &bar0->rmac_addr_cmd_mem);
 
                        /* Wait for command completes */
-                       if (wait_for_cmd_complete(sp)) {
+                       if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+                               RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
                                DBG_PRINT(ERR_DBG, "%s: Adding ",
                                          dev->name);
                                DBG_PRINT(ERR_DBG, "Multicasts failed\n");
@@ -4196,7 +4747,7 @@ static void s2io_set_multicast(struct ne
  *  as defined in errno.h file on failure.
  */
 
-int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
+int s2io_set_mac_addr(struct net_device *dev, u8 * addr, int off)
 {
        nic_t *sp = dev->priv;
        XENA_dev_config_t __iomem *bar0 = sp->bar0;
@@ -4218,10 +4769,11 @@ int s2io_set_mac_addr(struct net_device 
 
        val64 =
            RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
-           RMAC_ADDR_CMD_MEM_OFFSET(0);
+           RMAC_ADDR_CMD_MEM_OFFSET(off);
        writeq(val64, &bar0->rmac_addr_cmd_mem);
        /* Wait till command completes */
-       if (wait_for_cmd_complete(sp)) {
+       if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+               RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
                DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
                return FAILURE;
        }
@@ -5670,6 +6222,72 @@ static void s2io_tx_watchdog(struct net_
 }
 
 /**
+ * s2io_eth_type_trans -
+ * @skb - rx'ed buffer.
+ * @dev - Device structure of the Rx'ing NIC
+ * Description - This is an almost replica of the Kernel's eth_type_trans
+ * func, but since the kernel variety treats any packet whose destination
+ * MAC addr does match with the programmed MAC as PACKET_OTHERHOST
+ * irrespective of whether IF_PROMISC flag is set, had to define this local
+ * function. XFrame (I & II) Nics are capable of rx'ing 64/256 unicast MACs
+ * which can be programmed by the user. -KSK
+ */
+
+__be16 s2io_eth_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ethhdr *eth;
+       unsigned char *rawp;
+
+       skb->mac.raw=skb->data;
+       skb_pull(skb,ETH_HLEN);
+       eth = eth_hdr(skb);
+       skb->input_dev = dev;
+
+       if(*eth->h_dest&1) {
+               if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
+                       skb->pkt_type=PACKET_BROADCAST;
+               else
+                       skb->pkt_type=PACKET_MULTICAST;
+       } else if(dev->flags&IFF_PROMISC) {/* This is where we differ.. */
+               nic_t *sp = dev->priv;
+               struct config_param *config = &sp->config;
+               int i;
+
+               for (i=0; i<config->num_mac_cfg; i++) {
+                       if (i) {
+                               if(!memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
+                                       break;
+                       } else {
+                               if(!memcmp(eth->h_dest,config->mac_addrs[i].
+                                         mac_addr, ETH_ALEN))
+                                       break;
+                       }
+               }
+               if (i == config->num_mac_cfg)
+                       skb->pkt_type = PACKET_OTHERHOST;
+       }
+
+       if (ntohs(eth->h_proto) >= 1536)
+               return eth->h_proto;
+
+       rawp = skb->data;
+
+       /*
+        * This is a magic hack to spot IPX packets. Older Novell breaks
+        * the protocol design and runs IPX over 802.3 without an 802.2 LLC
+        * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
+        * won't work for fault tolerant netware but does for the rest.
+        */
+       if (*(unsigned short *)rawp == 0xFFFF)
+               return htons(ETH_P_802_3);
+
+       /*
+        * Real 802.2 LLC
+        */
+       return htons(ETH_P_802_2);
+}
+
+/**
  *   rx_osm_handler - To perform some OS related operations on SKB.
  *   @sp: private member of the device structure,pointer to s2io_nic structure.
  *   @skb : the socket buffer pointer.
@@ -5815,7 +6433,7 @@ static int rx_osm_handler(ring_info_t *r
        }
 
        if (!sp->lro) {
-               skb->protocol = eth_type_trans(skb, dev);
+               skb->protocol = s2io_eth_type_trans(skb, dev);
 #ifdef CONFIG_S2IO_NAPI
                if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
                        /* Queueing the vlan frame to the upper layer */
@@ -5836,7 +6454,7 @@ static int rx_osm_handler(ring_info_t *r
        } else {
 send_up:
                queue_rx_frame(skb);
-       }               
+       }
        dev->last_rx = jiffies;
 aggregate:
        atomic_dec(&sp->rx_bufs_left[ring_no]);
@@ -5952,6 +6570,35 @@ module_param(rxsync_frequency, int, 0);
 module_param(intr_type, int, 0);
 module_param(lro, int, 0);
 module_param(lro_max_pkts, int, 0);
+/* Rx steering */
+module_param(rx_steering_type, int, 0);
+module_param(rth_fn_and_mask, int, 0);
+module_param(multi_mac_cnt, int, 0);
+module_param_array(multi_macs, charp, NULL, 0);
+
+/**
+ * mac_str_to_val -
+ */
+void mac_str_to_val(const char *str, u8 *mac_addr)
+{
+       int i = 0;
+       char src[10];
+
+       do {
+               if (*str == ':') {
+                       *mac_addr = (u8)simple_strtol(src, NULL, 16);
+                       mac_addr++;
+                       i = 0;
+                       str++;
+               } else {
+                       src[i] = *str;
+                       i++;
+                       str++;
+               }
+       } while(*str);
+
+       *mac_addr = (u8)simple_strtol(src, NULL, 16);
+}
 
 /**
  *  s2io_init_nic - Initialization of the adapter .
@@ -6084,7 +6731,8 @@ Defaulting to INTA\n");
                sp->device_type = XFRAME_I_DEVICE;
 
        sp->lro = lro;
-               
+       sp->spdm_entry = 0;
+
        /* Initialize some PCI/PCI-X fields of the NIC. */
        s2io_init_pci(sp);
 
@@ -6139,6 +6787,24 @@ Defaulting to INTA\n");
                    (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER);
        }
 
+       /* Support for Rx steering */
+       if (rx_steering_type > 8) {
+               rx_steering_type = 0; /* No Rx steering */
+       }
+       config->rx_steering_type = rx_steering_type;
+       config->rth_fn_and_mask = rth_fn_and_mask;
+
+       if (multi_mac_cnt > MAX_MACS)
+               multi_mac_cnt = MAX_MACS;
+       config->num_mac_cfg = (multi_mac_cnt+1); /* '1' is default MAC */
+       if (sp->device_type == XFRAME_I_DEVICE) {
+               DBG_PRINT(ERR_DBG,"S2IO: Warning.. XFRAME I does not support ");
+                DBG_PRINT(ERR_DBG,"MAC based steering!!\n");
+        }
+
+       for (i=0; i<multi_mac_cnt; i++)
+               mac_str_to_val(multi_macs[i], config->mac_addrs[i].mac_addr);
+
        /*  Setting Mac Control parameters */
        mac_control->rmac_pause_time = rmac_pause_time;
        mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3;
@@ -6219,7 +6885,6 @@ Defaulting to INTA\n");
                dev->features |= NETIF_F_UFO;
                dev->features |= NETIF_F_HW_CSUM;
        }
-
        dev->tx_timeout = &s2io_tx_watchdog;
        dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
        INIT_WORK(&sp->rst_timer_task,
@@ -6266,7 +6931,8 @@ Defaulting to INTA\n");
        val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
            RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
        writeq(val64, &bar0->rmac_addr_cmd_mem);
-       wait_for_cmd_complete(sp);
+       wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+                             RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
 
        tmp64 = readq(&bar0->rmac_addr_data0_mem);
        mac_down = (u32) tmp64;
@@ -6413,6 +7079,26 @@ Defaulting to INTA\n");
         */
        netif_carrier_off(dev);
 
+        //NETLINK
+        if ((sp->device_type == XFRAME_II_DEVICE) && (nl_sk == NULL)) {
+                int pid;
+
+                nl_sk = netlink_kernel_create(NETLINK_S2IO, 0, nl_data_ready,
+                                               THIS_MODULE);
+                if (nl_sk == NULL) {
+                        printk("%s: Ctearing Kernel Sock failed\n",
+                                __FUNCTION__);
+                        ret = -1;
+                        goto register_failed;
+                }
+
+                pid = kernel_thread(nl_reader, ((void*)NULL), 0);
+                if (pid < 0) {
+                        ret = -1;
+                        goto register_failed;
+                }
+        }
+
        return 0;
 
       register_failed:
@@ -6438,6 +7124,23 @@ Defaulting to INTA\n");
        return ret;
 }
 
+//NETLINK
+void netlink_kill(void)
+{
+        struct sk_buff *skb;
+
+        if (!nl_sk)
+                return;
+        skb = alloc_skb(10, GFP_KERNEL);
+        kill_thread = 1;
+        netlink_unicast(nl_sk, skb, 0, MSG_DONTWAIT);
+
+        do {
+                set_current_state(TASK_INTERRUPTIBLE);
+                schedule_timeout(10);
+        }while(nl_sk);
+}
+
 /**
  * s2io_rem_nic - Free the PCI device
  * @pdev: structure containing the PCI related information of the device.
@@ -6459,6 +7162,10 @@ static void __devexit s2io_rem_nic(struc
        }
 
        sp = dev->priv;
+       //NETLINK
+       if ((sp->device_type == XFRAME_II_DEVICE) && nl_sk)
+               netlink_kill();
+
        unregister_netdev(dev);
 
        free_shared_mem(sp);
@@ -6790,7 +7497,7 @@ static void queue_rx_frame(struct sk_buf
 {
        struct net_device *dev = skb->dev;
 
-       skb->protocol = eth_type_trans(skb, dev);
+       skb->protocol = s2io_eth_type_trans(skb, dev);
 #ifdef CONFIG_S2IO_NAPI
        netif_receive_skb(skb);
 #else
diff -urpN old/drivers/net/s2io.h new/drivers/net/s2io.h
--- old/drivers/net/s2io.h      2006-03-01 08:47:42.000000000 -0800
+++ new/drivers/net/s2io.h      2006-03-10 02:54:56.000000000 -0800
@@ -331,7 +331,14 @@ typedef struct rx_ring_config {
 #define NO_SNOOP_RXD_BUFFER         0x02
 } rx_ring_config_t;
 
-/* This structure provides contains values of the tunable parameters
+
+/* Structure representing MAC Addrs */
+typedef struct mac_addr {
+       u8 mac_addr[ETH_ALEN];
+} macaddr_t;
+
+/*
+ * This structure provides contains values of the tunable parameters
  * of the H/W
  */
 struct config_param {
@@ -364,12 +371,25 @@ struct config_param {
 #define MAX_MTU_JUMBO               (MAX_PYLD_JUMBO+18)
 #define MAX_MTU_JUMBO_VLAN          (MAX_PYLD_JUMBO+22)
        u16 bus_speed;
-};
 
-/* Structure representing MAC Addrs */
-typedef struct mac_addr {
-       u8 mac_addr[ETH_ALEN];
-} macaddr_t;
+/* rx steering parameters */
+#define NO_STEERING                    0x0
+#define PORT_STEERING                  0x1
+#define RTH_STEERING                   0x2
+#define SPDM_STEERING                  0x4
+#define DS_MAC_STEERING                        0x8
+#define ENHANCED_STEERING_SUPPORT      0x6
+#define RX_STEERING_SUPPORT            0xF
+       u32 rx_steering_type;
+
+       int rth_fn_and_mask;
+#define MAX_STEER_PORTS        32
+       u16 steer_ports[MAX_STEER_PORTS];
+
+#define MAX_MACS        15
+       macaddr_t mac_addrs[MAX_MACS];
+        int num_mac_cfg;
+};
 
 /* Structure that represent every FIFO element in the BAR1
  * Address location.
@@ -824,6 +844,7 @@ struct s2io_nic {
        spinlock_t      rx_lock;
        atomic_t        isr_cnt;
        u64 *ufo_in_band_v;
+       int spdm_entry;
 };
 
 #define RESET_ERROR 1;
@@ -954,7 +975,7 @@ void s2io_reset(nic_t * sp);
 static int s2io_poll(struct net_device *dev, int *budget);
 #endif
 static void s2io_init_pci(nic_t * sp);
-int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
+int s2io_set_mac_addr(struct net_device *dev, u8 * addr, int off);
 static void s2io_alarm_handle(unsigned long data);
 static int s2io_enable_msi(nic_t *nic);
 static irqreturn_t s2io_msi_handle(int irq, void *dev_id, struct pt_regs 
*regs);
@@ -978,4 +999,36 @@ static void clear_lro_session(lro_t *lro
 static void queue_rx_frame(struct sk_buff *skb);
 static void update_L3L4_header(nic_t *sp, lro_t *lro);
 static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 
tcp_len);
+static int wait_for_cmd_complete(void *addr, u64 busy_bit);
+
+/* Rx port steering */
+static int s2io_set_steering_ports(nic_t *nic, rx_steering_cfg_t *info);
+//SPDM
+static int spdm_configure(nic_t *nic, rx_steering_cfg_t *info);
+static int spdm_extract_table(void *data, nic_t *nic);
+
+#define MAX_SUPPORTED_SPDM_ENTRIES 256
+typedef struct {
+               u64 port_n_entry_control_0;
+#define SPDM_PGM_L4_SRC_PORT(port)      vBIT(port, 0, 16)
+#define SPDM_PGM_L4_DST_PORT(port)      vBIT(port, 16, 16)
+#define SPDM_PGM_TARGET_QUEUE(queue)    vBIT(queue, 53, 3)
+#define SPDM_PGM_IS_TCP                 BIT(59)
+#define SPDM_PGM_IS_IPV4                BIT(63)
+
+               union {
+                       u64 ipv4_sa_da;
+                       u64 ipv6_sa_p0;
+               }ip;
+               u64 ipv6_sa_p1;
+               u64 ipv6_da_p0;
+               u64 ipv6_da_p1;
+               u64 rsvd_3;
+               u64 rsvd_4;
+
+               u64 hash_n_entry_control_1;
+#define SPDM_PGM_HASH(hash)             vBIT(hash, 0, 32)
+#define SPDM_PGM_ENABLE_ENTRY           BIT(63)
+}spdm_entry_t;
+
 #endif                         /* _S2IO_H */

-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to