]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/niu.c
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireles...
[linux-2.6-omap-h63xx.git] / drivers / net / niu.c
index 57cfd72ffdf7adaf7885efd1118c45ee09d7967a..de2a8a30199d8377fb73f006879d9aef04f93099 100644 (file)
@@ -865,7 +865,6 @@ static int link_status_1g_serdes(struct niu *np, int *link_up_p)
        return 0;
 }
 
-
 static int link_status_10g_serdes(struct niu *np, int *link_up_p)
 {
        unsigned long flags;
@@ -900,7 +899,6 @@ static int link_status_10g_serdes(struct niu *np, int *link_up_p)
        return 0;
 }
 
-
 static int link_status_1g_rgmii(struct niu *np, int *link_up_p)
 {
        struct niu_link_config *lp = &np->link_config;
@@ -957,7 +955,6 @@ out:
        return err;
 }
 
-
 static int bcm8704_reset(struct niu *np)
 {
        int err, limit;
@@ -1357,8 +1354,6 @@ static int mii_reset(struct niu *np)
        return 0;
 }
 
-
-
 static int xcvr_init_1g_rgmii(struct niu *np)
 {
        int err;
@@ -1419,7 +1414,6 @@ static int xcvr_init_1g_rgmii(struct niu *np)
        return 0;
 }
 
-
 static int mii_init_common(struct niu *np)
 {
        struct niu_link_config *lp = &np->link_config;
@@ -6391,6 +6385,162 @@ static int niu_get_eeprom(struct net_device *dev,
        return 0;
 }
 
+static int niu_ethflow_to_class(int flow_type, u64 *class)
+{
+       switch (flow_type) {
+       case TCP_V4_FLOW:
+               *class = CLASS_CODE_TCP_IPV4;
+               break;
+       case UDP_V4_FLOW:
+               *class = CLASS_CODE_UDP_IPV4;
+               break;
+       case AH_ESP_V4_FLOW:
+               *class = CLASS_CODE_AH_ESP_IPV4;
+               break;
+       case SCTP_V4_FLOW:
+               *class = CLASS_CODE_SCTP_IPV4;
+               break;
+       case TCP_V6_FLOW:
+               *class = CLASS_CODE_TCP_IPV6;
+               break;
+       case UDP_V6_FLOW:
+               *class = CLASS_CODE_UDP_IPV6;
+               break;
+       case AH_ESP_V6_FLOW:
+               *class = CLASS_CODE_AH_ESP_IPV6;
+               break;
+       case SCTP_V6_FLOW:
+               *class = CLASS_CODE_SCTP_IPV6;
+               break;
+       default:
+               return -1;
+       }
+
+       return 1;
+}
+
+static u64 niu_flowkey_to_ethflow(u64 flow_key)
+{
+       u64 ethflow = 0;
+
+       if (flow_key & FLOW_KEY_PORT)
+               ethflow |= RXH_DEV_PORT;
+       if (flow_key & FLOW_KEY_L2DA)
+               ethflow |= RXH_L2DA;
+       if (flow_key & FLOW_KEY_VLAN)
+               ethflow |= RXH_VLAN;
+       if (flow_key & FLOW_KEY_IPSA)
+               ethflow |= RXH_IP_SRC;
+       if (flow_key & FLOW_KEY_IPDA)
+               ethflow |= RXH_IP_DST;
+       if (flow_key & FLOW_KEY_PROTO)
+               ethflow |= RXH_L3_PROTO;
+       if (flow_key & (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_0_SHIFT))
+               ethflow |= RXH_L4_B_0_1;
+       if (flow_key & (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_1_SHIFT))
+               ethflow |= RXH_L4_B_2_3;
+
+       return ethflow;
+
+}
+
+static int niu_ethflow_to_flowkey(u64 ethflow, u64 *flow_key)
+{
+       u64 key = 0;
+
+       if (ethflow & RXH_DEV_PORT)
+               key |= FLOW_KEY_PORT;
+       if (ethflow & RXH_L2DA)
+               key |= FLOW_KEY_L2DA;
+       if (ethflow & RXH_VLAN)
+               key |= FLOW_KEY_VLAN;
+       if (ethflow & RXH_IP_SRC)
+               key |= FLOW_KEY_IPSA;
+       if (ethflow & RXH_IP_DST)
+               key |= FLOW_KEY_IPDA;
+       if (ethflow & RXH_L3_PROTO)
+               key |= FLOW_KEY_PROTO;
+       if (ethflow & RXH_L4_B_0_1)
+               key |= (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_0_SHIFT);
+       if (ethflow & RXH_L4_B_2_3)
+               key |= (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_1_SHIFT);
+
+       *flow_key = key;
+
+       return 1;
+
+}
+
+static int niu_get_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+       struct niu *np = netdev_priv(dev);
+       u64 class;
+
+       cmd->data = 0;
+
+       if (!niu_ethflow_to_class(cmd->flow_type, &class))
+               return -EINVAL;
+
+       if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] &
+           TCAM_KEY_DISC)
+               cmd->data = RXH_DISCARD;
+       else
+
+               cmd->data = niu_flowkey_to_ethflow(np->parent->flow_key[class -
+                                                     CLASS_CODE_USER_PROG1]);
+       return 0;
+}
+
+static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+       struct niu *np = netdev_priv(dev);
+       u64 class;
+       u64 flow_key = 0;
+       unsigned long flags;
+
+       if (!niu_ethflow_to_class(cmd->flow_type, &class))
+               return -EINVAL;
+
+       if (class < CLASS_CODE_USER_PROG1 ||
+           class > CLASS_CODE_SCTP_IPV6)
+               return -EINVAL;
+
+       if (cmd->data & RXH_DISCARD) {
+               niu_lock_parent(np, flags);
+               flow_key = np->parent->tcam_key[class -
+                                              CLASS_CODE_USER_PROG1];
+               flow_key |= TCAM_KEY_DISC;
+               nw64(TCAM_KEY(class - CLASS_CODE_USER_PROG1), flow_key);
+               np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] = flow_key;
+               niu_unlock_parent(np, flags);
+               return 0;
+       } else {
+               /* Discard was set before, but is not set now */
+               if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] &
+                   TCAM_KEY_DISC) {
+                       niu_lock_parent(np, flags);
+                       flow_key = np->parent->tcam_key[class -
+                                              CLASS_CODE_USER_PROG1];
+                       flow_key &= ~TCAM_KEY_DISC;
+                       nw64(TCAM_KEY(class - CLASS_CODE_USER_PROG1),
+                            flow_key);
+                       np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] =
+                               flow_key;
+                       niu_unlock_parent(np, flags);
+               }
+       }
+
+       if (!niu_ethflow_to_flowkey(cmd->data, &flow_key))
+               return -EINVAL;
+
+       niu_lock_parent(np, flags);
+       nw64(FLOW_KEY(class - CLASS_CODE_USER_PROG1), flow_key);
+       np->parent->flow_key[class - CLASS_CODE_USER_PROG1] = flow_key;
+       niu_unlock_parent(np, flags);
+
+       return 0;
+}
+
 static const struct {
        const char string[ETH_GSTRING_LEN];
 } niu_xmac_stat_keys[] = {
@@ -6621,6 +6771,8 @@ static const struct ethtool_ops niu_ethtool_ops = {
        .get_stats_count        = niu_get_stats_count,
        .get_ethtool_stats      = niu_get_ethtool_stats,
        .phys_id                = niu_phys_id,
+       .get_rxhash             = niu_get_hash_opts,
+       .set_rxhash             = niu_set_hash_opts,
 };
 
 static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent,
@@ -7008,31 +7160,20 @@ static int __devinit niu_phy_type_prop_decode(struct niu *np,
        return 0;
 }
 
-/* niu board models have a trailing dash version incremented
- * with HW rev change. Need to ingnore the  dash version while
- * checking for match
- *
- * for example, for the 10G card the current vpd.board_model
- * is 501-5283-04, of which -04 is the  dash version and have
- * to be ignored
- */
-static int niu_board_model_match(struct niu *np, const char *model)
-{
-       return !strncmp(np->vpd.board_model, model, strlen(model));
-}
-
 static int niu_pci_vpd_get_nports(struct niu *np)
 {
        int ports = 0;
 
-       if ((niu_board_model_match(np, NIU_QGC_LP_BM_STR)) ||
-           (niu_board_model_match(np, NIU_QGC_PEM_BM_STR)) ||
-           (niu_board_model_match(np, NIU_ALONSO_BM_STR))) {
+       if ((!strcmp(np->vpd.model, NIU_QGC_LP_MDL_STR)) ||
+           (!strcmp(np->vpd.model, NIU_QGC_PEM_MDL_STR)) ||
+           (!strcmp(np->vpd.model, NIU_MARAMBA_MDL_STR)) ||
+           (!strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) ||
+           (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR))) {
                ports = 4;
-       } else if ((niu_board_model_match(np, NIU_2XGF_LP_BM_STR)) ||
-                  (niu_board_model_match(np, NIU_2XGF_PEM_BM_STR)) ||
-                  (niu_board_model_match(np, NIU_FOXXY_BM_STR)) ||
-                  (niu_board_model_match(np, NIU_2XGF_MRVL_BM_STR))) {
+       } else if ((!strcmp(np->vpd.model, NIU_2XGF_LP_MDL_STR)) ||
+                  (!strcmp(np->vpd.model, NIU_2XGF_PEM_MDL_STR)) ||
+                  (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) ||
+                  (!strcmp(np->vpd.model, NIU_2XGF_MRVL_MDL_STR))) {
                ports = 2;
        }
 
@@ -7053,8 +7194,8 @@ static void __devinit niu_pci_vpd_validate(struct niu *np)
                return;
        }
 
-       if (!strcmp(np->vpd.model, "SUNW,CP3220") ||
-           !strcmp(np->vpd.model, "SUNW,CP3260")) {
+       if (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR) ||
+           !strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) {
                np->flags |= NIU_FLAGS_10G;
                np->flags &= ~NIU_FLAGS_FIBER;
                np->flags |= NIU_FLAGS_XCVR_SERDES;
@@ -7065,7 +7206,7 @@ static void __devinit niu_pci_vpd_validate(struct niu *np)
                }
                if (np->flags & NIU_FLAGS_10G)
                         np->mac_xcvr = MAC_XCVR_XPCS;
-       } else if (niu_board_model_match(np, NIU_FOXXY_BM_STR)) {
+       } else if (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) {
                np->flags |= (NIU_FLAGS_10G | NIU_FLAGS_FIBER |
                              NIU_FLAGS_HOTPLUG_PHY);
        } else if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
@@ -7541,8 +7682,8 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
        u32 val;
        int err;
 
-       if (!strcmp(np->vpd.model, "SUNW,CP3220") ||
-           !strcmp(np->vpd.model, "SUNW,CP3260")) {
+       if (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR) ||
+           !strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) {
                num_10g = 0;
                num_1g = 2;
                parent->plat_type = PLAT_TYPE_ATCA_CP3220;
@@ -7551,7 +7692,7 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
                       phy_encode(PORT_TYPE_1G, 1) |
                       phy_encode(PORT_TYPE_1G, 2) |
                       phy_encode(PORT_TYPE_1G, 3));
-       } else if (niu_board_model_match(np, NIU_FOXXY_BM_STR)) {
+       } else if (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) {
                num_10g = 2;
                num_1g = 0;
                parent->num_ports = 2;
@@ -7946,6 +8087,7 @@ static int __devinit niu_get_of_props(struct niu *np)
        struct device_node *dp;
        const char *phy_type;
        const u8 *mac_addr;
+       const char *model;
        int prop_len;
 
        if (np->parent->plat_type == PLAT_TYPE_NIU)
@@ -8000,6 +8142,11 @@ static int __devinit niu_get_of_props(struct niu *np)
 
        memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
 
+       model = of_get_property(dp, "model", &prop_len);
+
+       if (model)
+               strcpy(np->vpd.model, model);
+
        return 0;
 #else
        return -EINVAL;