aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSantwona Behera <santwona.behera@sun.com>2009-02-20 03:58:45 -0500
committerDavid S. Miller <davem@davemloft.net>2009-02-20 03:58:45 -0500
commit2d96cf8cdfd625da51e5d237d564cd75d3147547 (patch)
tree2acc376af0acebc752f563051ace6a90571c7680
parent59089d8d162ddcb5c434672e915331964d38a754 (diff)
niu: Add TCAM classification configuration
Signed-off-by: Santwona Behera <santwona.behera@sun.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/niu.c699
-rw-r--r--drivers/net/niu.h14
2 files changed, 686 insertions, 27 deletions
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 75991eb761c..50c11126a3d 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -2981,7 +2981,6 @@ static int tcam_user_ip_class_enable(struct niu *np, unsigned long class,
2981 return 0; 2981 return 0;
2982} 2982}
2983 2983
2984#if 0
2985static int tcam_user_ip_class_set(struct niu *np, unsigned long class, 2984static int tcam_user_ip_class_set(struct niu *np, unsigned long class,
2986 int ipv6, u64 protocol_id, 2985 int ipv6, u64 protocol_id,
2987 u64 tos_mask, u64 tos_val) 2986 u64 tos_mask, u64 tos_val)
@@ -3009,7 +3008,6 @@ static int tcam_user_ip_class_set(struct niu *np, unsigned long class,
3009 3008
3010 return 0; 3009 return 0;
3011} 3010}
3012#endif
3013 3011
3014static int tcam_early_init(struct niu *np) 3012static int tcam_early_init(struct niu *np)
3015{ 3013{
@@ -3276,6 +3274,27 @@ static int niu_set_tcam_key(struct niu *np, unsigned long class_code, u64 key)
3276 return 0; 3274 return 0;
3277} 3275}
3278 3276
3277/* Entries for the ports are interleaved in the TCAM */
3278static u16 tcam_get_index(struct niu *np, u16 idx)
3279{
3280 /* One entry reserved for IP fragment rule */
3281 if (idx >= (np->clas.tcam_sz - 1))
3282 idx = 0;
3283 return (np->clas.tcam_top + ((idx+1) * np->parent->num_ports));
3284}
3285
3286static u16 tcam_get_size(struct niu *np)
3287{
3288 /* One entry reserved for IP fragment rule */
3289 return np->clas.tcam_sz - 1;
3290}
3291
3292static u16 tcam_get_valid_entry_cnt(struct niu *np)
3293{
3294 /* One entry reserved for IP fragment rule */
3295 return np->clas.tcam_valid_entries - 1;
3296}
3297
3279static void niu_rx_skb_append(struct sk_buff *skb, struct page *page, 3298static void niu_rx_skb_append(struct sk_buff *skb, struct page *page,
3280 u32 offset, u32 size) 3299 u32 offset, u32 size)
3281{ 3300{
@@ -4999,8 +5018,7 @@ static int niu_set_ip_frag_rule(struct niu *np)
4999 struct niu_tcam_entry *tp; 5018 struct niu_tcam_entry *tp;
5000 int index, err; 5019 int index, err;
5001 5020
5002 /* XXX fix this allocation scheme XXX */ 5021 index = cp->tcam_top;
5003 index = cp->tcam_index;
5004 tp = &parent->tcam[index]; 5022 tp = &parent->tcam[index];
5005 5023
5006 /* Note that the noport bit is the same in both ipv4 and 5024 /* Note that the noport bit is the same in both ipv4 and
@@ -5017,6 +5035,8 @@ static int niu_set_ip_frag_rule(struct niu *np)
5017 err = tcam_assoc_write(np, index, tp->assoc_data); 5035 err = tcam_assoc_write(np, index, tp->assoc_data);
5018 if (err) 5036 if (err)
5019 return err; 5037 return err;
5038 tp->valid = 1;
5039 cp->tcam_valid_entries++;
5020 5040
5021 return 0; 5041 return 0;
5022} 5042}
@@ -6907,6 +6927,75 @@ static int niu_get_eeprom(struct net_device *dev,
6907 return 0; 6927 return 0;
6908} 6928}
6909 6929
6930static void niu_ethflow_to_l3proto(int flow_type, u8 *pid)
6931{
6932 switch (flow_type) {
6933 case TCP_V4_FLOW:
6934 case TCP_V6_FLOW:
6935 *pid = IPPROTO_TCP;
6936 break;
6937 case UDP_V4_FLOW:
6938 case UDP_V6_FLOW:
6939 *pid = IPPROTO_UDP;
6940 break;
6941 case SCTP_V4_FLOW:
6942 case SCTP_V6_FLOW:
6943 *pid = IPPROTO_SCTP;
6944 break;
6945 case AH_V4_FLOW:
6946 case AH_V6_FLOW:
6947 *pid = IPPROTO_AH;
6948 break;
6949 case ESP_V4_FLOW:
6950 case ESP_V6_FLOW:
6951 *pid = IPPROTO_ESP;
6952 break;
6953 default:
6954 *pid = 0;
6955 break;
6956 }
6957}
6958
6959static int niu_class_to_ethflow(u64 class, int *flow_type)
6960{
6961 switch (class) {
6962 case CLASS_CODE_TCP_IPV4:
6963 *flow_type = TCP_V4_FLOW;
6964 break;
6965 case CLASS_CODE_UDP_IPV4:
6966 *flow_type = UDP_V4_FLOW;
6967 break;
6968 case CLASS_CODE_AH_ESP_IPV4:
6969 *flow_type = AH_V4_FLOW;
6970 break;
6971 case CLASS_CODE_SCTP_IPV4:
6972 *flow_type = SCTP_V4_FLOW;
6973 break;
6974 case CLASS_CODE_TCP_IPV6:
6975 *flow_type = TCP_V6_FLOW;
6976 break;
6977 case CLASS_CODE_UDP_IPV6:
6978 *flow_type = UDP_V6_FLOW;
6979 break;
6980 case CLASS_CODE_AH_ESP_IPV6:
6981 *flow_type = AH_V6_FLOW;
6982 break;
6983 case CLASS_CODE_SCTP_IPV6:
6984 *flow_type = SCTP_V6_FLOW;
6985 break;
6986 case CLASS_CODE_USER_PROG1:
6987 case CLASS_CODE_USER_PROG2:
6988 case CLASS_CODE_USER_PROG3:
6989 case CLASS_CODE_USER_PROG4:
6990 *flow_type = IP_USER_FLOW;
6991 break;
6992 default:
6993 return 0;
6994 }
6995
6996 return 1;
6997}
6998
6910static int niu_ethflow_to_class(int flow_type, u64 *class) 6999static int niu_ethflow_to_class(int flow_type, u64 *class)
6911{ 7000{
6912 switch (flow_type) { 7001 switch (flow_type) {
@@ -6916,7 +7005,8 @@ static int niu_ethflow_to_class(int flow_type, u64 *class)
6916 case UDP_V4_FLOW: 7005 case UDP_V4_FLOW:
6917 *class = CLASS_CODE_UDP_IPV4; 7006 *class = CLASS_CODE_UDP_IPV4;
6918 break; 7007 break;
6919 case AH_ESP_V4_FLOW: 7008 case AH_V4_FLOW:
7009 case ESP_V4_FLOW:
6920 *class = CLASS_CODE_AH_ESP_IPV4; 7010 *class = CLASS_CODE_AH_ESP_IPV4;
6921 break; 7011 break;
6922 case SCTP_V4_FLOW: 7012 case SCTP_V4_FLOW:
@@ -6928,7 +7018,8 @@ static int niu_ethflow_to_class(int flow_type, u64 *class)
6928 case UDP_V6_FLOW: 7018 case UDP_V6_FLOW:
6929 *class = CLASS_CODE_UDP_IPV6; 7019 *class = CLASS_CODE_UDP_IPV6;
6930 break; 7020 break;
6931 case AH_ESP_V6_FLOW: 7021 case AH_V6_FLOW:
7022 case ESP_V6_FLOW:
6932 *class = CLASS_CODE_AH_ESP_IPV6; 7023 *class = CLASS_CODE_AH_ESP_IPV6;
6933 break; 7024 break;
6934 case SCTP_V6_FLOW: 7025 case SCTP_V6_FLOW:
@@ -6945,8 +7036,6 @@ static u64 niu_flowkey_to_ethflow(u64 flow_key)
6945{ 7036{
6946 u64 ethflow = 0; 7037 u64 ethflow = 0;
6947 7038
6948 if (flow_key & FLOW_KEY_PORT)
6949 ethflow |= RXH_DEV_PORT;
6950 if (flow_key & FLOW_KEY_L2DA) 7039 if (flow_key & FLOW_KEY_L2DA)
6951 ethflow |= RXH_L2DA; 7040 ethflow |= RXH_L2DA;
6952 if (flow_key & FLOW_KEY_VLAN) 7041 if (flow_key & FLOW_KEY_VLAN)
@@ -6970,8 +7059,6 @@ static int niu_ethflow_to_flowkey(u64 ethflow, u64 *flow_key)
6970{ 7059{
6971 u64 key = 0; 7060 u64 key = 0;
6972 7061
6973 if (ethflow & RXH_DEV_PORT)
6974 key |= FLOW_KEY_PORT;
6975 if (ethflow & RXH_L2DA) 7062 if (ethflow & RXH_L2DA)
6976 key |= FLOW_KEY_L2DA; 7063 key |= FLOW_KEY_L2DA;
6977 if (ethflow & RXH_VLAN) 7064 if (ethflow & RXH_VLAN)
@@ -6993,41 +7080,279 @@ static int niu_ethflow_to_flowkey(u64 ethflow, u64 *flow_key)
6993 7080
6994} 7081}
6995 7082
6996static int niu_get_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd) 7083static int niu_get_hash_opts(struct niu *np, struct ethtool_rxnfc *nfc)
6997{ 7084{
6998 struct niu *np = netdev_priv(dev);
6999 u64 class; 7085 u64 class;
7000 7086
7001 cmd->data = 0; 7087 nfc->data = 0;
7002 7088
7003 if (!niu_ethflow_to_class(cmd->flow_type, &class)) 7089 if (!niu_ethflow_to_class(nfc->flow_type, &class))
7004 return -EINVAL; 7090 return -EINVAL;
7005 7091
7006 if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] & 7092 if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] &
7007 TCAM_KEY_DISC) 7093 TCAM_KEY_DISC)
7008 cmd->data = RXH_DISCARD; 7094 nfc->data = RXH_DISCARD;
7009 else 7095 else
7010 7096 nfc->data = niu_flowkey_to_ethflow(np->parent->flow_key[class -
7011 cmd->data = niu_flowkey_to_ethflow(np->parent->flow_key[class -
7012 CLASS_CODE_USER_PROG1]); 7097 CLASS_CODE_USER_PROG1]);
7013 return 0; 7098 return 0;
7014} 7099}
7015 7100
7016static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd) 7101static void niu_get_ip4fs_from_tcam_key(struct niu_tcam_entry *tp,
7102 struct ethtool_rx_flow_spec *fsp)
7103{
7104
7105 fsp->h_u.tcp_ip4_spec.ip4src = (tp->key[3] & TCAM_V4KEY3_SADDR) >>
7106 TCAM_V4KEY3_SADDR_SHIFT;
7107 fsp->h_u.tcp_ip4_spec.ip4dst = (tp->key[3] & TCAM_V4KEY3_DADDR) >>
7108 TCAM_V4KEY3_DADDR_SHIFT;
7109 fsp->m_u.tcp_ip4_spec.ip4src = (tp->key_mask[3] & TCAM_V4KEY3_SADDR) >>
7110 TCAM_V4KEY3_SADDR_SHIFT;
7111 fsp->m_u.tcp_ip4_spec.ip4dst = (tp->key_mask[3] & TCAM_V4KEY3_DADDR) >>
7112 TCAM_V4KEY3_DADDR_SHIFT;
7113
7114 fsp->h_u.tcp_ip4_spec.ip4src =
7115 cpu_to_be32(fsp->h_u.tcp_ip4_spec.ip4src);
7116 fsp->m_u.tcp_ip4_spec.ip4src =
7117 cpu_to_be32(fsp->m_u.tcp_ip4_spec.ip4src);
7118 fsp->h_u.tcp_ip4_spec.ip4dst =
7119 cpu_to_be32(fsp->h_u.tcp_ip4_spec.ip4dst);
7120 fsp->m_u.tcp_ip4_spec.ip4dst =
7121 cpu_to_be32(fsp->m_u.tcp_ip4_spec.ip4dst);
7122
7123 fsp->h_u.tcp_ip4_spec.tos = (tp->key[2] & TCAM_V4KEY2_TOS) >>
7124 TCAM_V4KEY2_TOS_SHIFT;
7125 fsp->m_u.tcp_ip4_spec.tos = (tp->key_mask[2] & TCAM_V4KEY2_TOS) >>
7126 TCAM_V4KEY2_TOS_SHIFT;
7127
7128 switch (fsp->flow_type) {
7129 case TCP_V4_FLOW:
7130 case UDP_V4_FLOW:
7131 case SCTP_V4_FLOW:
7132 fsp->h_u.tcp_ip4_spec.psrc =
7133 ((tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
7134 TCAM_V4KEY2_PORT_SPI_SHIFT) >> 16;
7135 fsp->h_u.tcp_ip4_spec.pdst =
7136 ((tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
7137 TCAM_V4KEY2_PORT_SPI_SHIFT) & 0xffff;
7138 fsp->m_u.tcp_ip4_spec.psrc =
7139 ((tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
7140 TCAM_V4KEY2_PORT_SPI_SHIFT) >> 16;
7141 fsp->m_u.tcp_ip4_spec.pdst =
7142 ((tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
7143 TCAM_V4KEY2_PORT_SPI_SHIFT) & 0xffff;
7144
7145 fsp->h_u.tcp_ip4_spec.psrc =
7146 cpu_to_be16(fsp->h_u.tcp_ip4_spec.psrc);
7147 fsp->h_u.tcp_ip4_spec.pdst =
7148 cpu_to_be16(fsp->h_u.tcp_ip4_spec.pdst);
7149 fsp->m_u.tcp_ip4_spec.psrc =
7150 cpu_to_be16(fsp->m_u.tcp_ip4_spec.psrc);
7151 fsp->m_u.tcp_ip4_spec.pdst =
7152 cpu_to_be16(fsp->m_u.tcp_ip4_spec.pdst);
7153 break;
7154 case AH_V4_FLOW:
7155 case ESP_V4_FLOW:
7156 fsp->h_u.ah_ip4_spec.spi =
7157 (tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
7158 TCAM_V4KEY2_PORT_SPI_SHIFT;
7159 fsp->m_u.ah_ip4_spec.spi =
7160 (tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
7161 TCAM_V4KEY2_PORT_SPI_SHIFT;
7162
7163 fsp->h_u.ah_ip4_spec.spi =
7164 cpu_to_be32(fsp->h_u.ah_ip4_spec.spi);
7165 fsp->m_u.ah_ip4_spec.spi =
7166 cpu_to_be32(fsp->m_u.ah_ip4_spec.spi);
7167 break;
7168 case IP_USER_FLOW:
7169 fsp->h_u.usr_ip4_spec.l4_4_bytes =
7170 (tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
7171 TCAM_V4KEY2_PORT_SPI_SHIFT;
7172 fsp->m_u.usr_ip4_spec.l4_4_bytes =
7173 (tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
7174 TCAM_V4KEY2_PORT_SPI_SHIFT;
7175
7176 fsp->h_u.usr_ip4_spec.l4_4_bytes =
7177 cpu_to_be32(fsp->h_u.usr_ip4_spec.l4_4_bytes);
7178 fsp->m_u.usr_ip4_spec.l4_4_bytes =
7179 cpu_to_be32(fsp->m_u.usr_ip4_spec.l4_4_bytes);
7180
7181 fsp->h_u.usr_ip4_spec.proto =
7182 (tp->key[2] & TCAM_V4KEY2_PROTO) >>
7183 TCAM_V4KEY2_PROTO_SHIFT;
7184 fsp->m_u.usr_ip4_spec.proto =
7185 (tp->key_mask[2] & TCAM_V4KEY2_PROTO) >>
7186 TCAM_V4KEY2_PROTO_SHIFT;
7187
7188 fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
7189 break;
7190 default:
7191 break;
7192 }
7193}
7194
7195static int niu_get_ethtool_tcam_entry(struct niu *np,
7196 struct ethtool_rxnfc *nfc)
7197{
7198 struct niu_parent *parent = np->parent;
7199 struct niu_tcam_entry *tp;
7200 struct ethtool_rx_flow_spec *fsp = &nfc->fs;
7201 u16 idx;
7202 u64 class;
7203 int ret = 0;
7204
7205 idx = tcam_get_index(np, (u16)nfc->fs.location);
7206
7207 tp = &parent->tcam[idx];
7208 if (!tp->valid) {
7209 pr_info(PFX "niu%d: %s entry [%d] invalid for idx[%d]\n",
7210 parent->index, np->dev->name, (u16)nfc->fs.location, idx);
7211 return -EINVAL;
7212 }
7213
7214 /* fill the flow spec entry */
7215 class = (tp->key[0] & TCAM_V4KEY0_CLASS_CODE) >>
7216 TCAM_V4KEY0_CLASS_CODE_SHIFT;
7217 ret = niu_class_to_ethflow(class, &fsp->flow_type);
7218
7219 if (ret < 0) {
7220 pr_info(PFX "niu%d: %s niu_class_to_ethflow failed\n",
7221 parent->index, np->dev->name);
7222 ret = -EINVAL;
7223 goto out;
7224 }
7225
7226 if (fsp->flow_type == AH_V4_FLOW || fsp->flow_type == AH_V6_FLOW) {
7227 u32 proto = (tp->key[2] & TCAM_V4KEY2_PROTO) >>
7228 TCAM_V4KEY2_PROTO_SHIFT;
7229 if (proto == IPPROTO_ESP) {
7230 if (fsp->flow_type == AH_V4_FLOW)
7231 fsp->flow_type = ESP_V4_FLOW;
7232 else
7233 fsp->flow_type = ESP_V6_FLOW;
7234 }
7235 }
7236
7237 switch (fsp->flow_type) {
7238 case TCP_V4_FLOW:
7239 case UDP_V4_FLOW:
7240 case SCTP_V4_FLOW:
7241 case AH_V4_FLOW:
7242 case ESP_V4_FLOW:
7243 niu_get_ip4fs_from_tcam_key(tp, fsp);
7244 break;
7245 case TCP_V6_FLOW:
7246 case UDP_V6_FLOW:
7247 case SCTP_V6_FLOW:
7248 case AH_V6_FLOW:
7249 case ESP_V6_FLOW:
7250 /* Not yet implemented */
7251 ret = -EINVAL;
7252 break;
7253 case IP_USER_FLOW:
7254 niu_get_ip4fs_from_tcam_key(tp, fsp);
7255 break;
7256 default:
7257 ret = -EINVAL;
7258 break;
7259 }
7260
7261 if (ret < 0)
7262 goto out;
7263
7264 if (tp->assoc_data & TCAM_ASSOCDATA_DISC)
7265 fsp->ring_cookie = RX_CLS_FLOW_DISC;
7266 else
7267 fsp->ring_cookie = (tp->assoc_data & TCAM_ASSOCDATA_OFFSET) >>
7268 TCAM_ASSOCDATA_OFFSET_SHIFT;
7269
7270 /* put the tcam size here */
7271 nfc->data = tcam_get_size(np);
7272out:
7273 return ret;
7274}
7275
7276static int niu_get_ethtool_tcam_all(struct niu *np,
7277 struct ethtool_rxnfc *nfc,
7278 u32 *rule_locs)
7279{
7280 struct niu_parent *parent = np->parent;
7281 struct niu_tcam_entry *tp;
7282 int i, idx, cnt;
7283 u16 n_entries;
7284 unsigned long flags;
7285
7286
7287 /* put the tcam size here */
7288 nfc->data = tcam_get_size(np);
7289
7290 niu_lock_parent(np, flags);
7291 n_entries = nfc->rule_cnt;
7292 for (cnt = 0, i = 0; i < nfc->data; i++) {
7293 idx = tcam_get_index(np, i);
7294 tp = &parent->tcam[idx];
7295 if (!tp->valid)
7296 continue;
7297 rule_locs[cnt] = i;
7298 cnt++;
7299 }
7300 niu_unlock_parent(np, flags);
7301
7302 if (n_entries != cnt) {
7303 /* print warning, this should not happen */
7304 pr_info(PFX "niu%d: %s In niu_get_ethtool_tcam_all, "
7305 "n_entries[%d] != cnt[%d]!!!\n\n",
7306 np->parent->index, np->dev->name, n_entries, cnt);
7307 }
7308
7309 return 0;
7310}
7311
7312static int niu_get_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
7313 void *rule_locs)
7017{ 7314{
7018 struct niu *np = netdev_priv(dev); 7315 struct niu *np = netdev_priv(dev);
7316 int ret = 0;
7317
7318 switch (cmd->cmd) {
7319 case ETHTOOL_GRXFH:
7320 ret = niu_get_hash_opts(np, cmd);
7321 break;
7322 case ETHTOOL_GRXRINGS:
7323 cmd->data = np->num_rx_rings;
7324 break;
7325 case ETHTOOL_GRXCLSRLCNT:
7326 cmd->rule_cnt = tcam_get_valid_entry_cnt(np);
7327 break;
7328 case ETHTOOL_GRXCLSRULE:
7329 ret = niu_get_ethtool_tcam_entry(np, cmd);
7330 break;
7331 case ETHTOOL_GRXCLSRLALL:
7332 ret = niu_get_ethtool_tcam_all(np, cmd, (u32 *)rule_locs);
7333 break;
7334 default:
7335 ret = -EINVAL;
7336 break;
7337 }
7338
7339 return ret;
7340}
7341
7342static int niu_set_hash_opts(struct niu *np, struct ethtool_rxnfc *nfc)
7343{
7019 u64 class; 7344 u64 class;
7020 u64 flow_key = 0; 7345 u64 flow_key = 0;
7021 unsigned long flags; 7346 unsigned long flags;
7022 7347
7023 if (!niu_ethflow_to_class(cmd->flow_type, &class)) 7348 if (!niu_ethflow_to_class(nfc->flow_type, &class))
7024 return -EINVAL; 7349 return -EINVAL;
7025 7350
7026 if (class < CLASS_CODE_USER_PROG1 || 7351 if (class < CLASS_CODE_USER_PROG1 ||
7027 class > CLASS_CODE_SCTP_IPV6) 7352 class > CLASS_CODE_SCTP_IPV6)
7028 return -EINVAL; 7353 return -EINVAL;
7029 7354
7030 if (cmd->data & RXH_DISCARD) { 7355 if (nfc->data & RXH_DISCARD) {
7031 niu_lock_parent(np, flags); 7356 niu_lock_parent(np, flags);
7032 flow_key = np->parent->tcam_key[class - 7357 flow_key = np->parent->tcam_key[class -
7033 CLASS_CODE_USER_PROG1]; 7358 CLASS_CODE_USER_PROG1];
@@ -7052,7 +7377,7 @@ static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd)
7052 } 7377 }
7053 } 7378 }
7054 7379
7055 if (!niu_ethflow_to_flowkey(cmd->data, &flow_key)) 7380 if (!niu_ethflow_to_flowkey(nfc->data, &flow_key))
7056 return -EINVAL; 7381 return -EINVAL;
7057 7382
7058 niu_lock_parent(np, flags); 7383 niu_lock_parent(np, flags);
@@ -7063,6 +7388,331 @@ static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd)
7063 return 0; 7388 return 0;
7064} 7389}
7065 7390
7391static void niu_get_tcamkey_from_ip4fs(struct ethtool_rx_flow_spec *fsp,
7392 struct niu_tcam_entry *tp,
7393 int l2_rdc_tab, u64 class)
7394{
7395 u8 pid = 0;
7396 u32 sip, dip, sipm, dipm, spi, spim;
7397 u16 sport, dport, spm, dpm;
7398
7399 sip = be32_to_cpu(fsp->h_u.tcp_ip4_spec.ip4src);
7400 sipm = be32_to_cpu(fsp->m_u.tcp_ip4_spec.ip4src);
7401 dip = be32_to_cpu(fsp->h_u.tcp_ip4_spec.ip4dst);
7402 dipm = be32_to_cpu(fsp->m_u.tcp_ip4_spec.ip4dst);
7403
7404 tp->key[0] = class << TCAM_V4KEY0_CLASS_CODE_SHIFT;
7405 tp->key_mask[0] = TCAM_V4KEY0_CLASS_CODE;
7406 tp->key[1] = (u64)l2_rdc_tab << TCAM_V4KEY1_L2RDCNUM_SHIFT;
7407 tp->key_mask[1] = TCAM_V4KEY1_L2RDCNUM;
7408
7409 tp->key[3] = (u64)sip << TCAM_V4KEY3_SADDR_SHIFT;
7410 tp->key[3] |= dip;
7411
7412 tp->key_mask[3] = (u64)sipm << TCAM_V4KEY3_SADDR_SHIFT;
7413 tp->key_mask[3] |= dipm;
7414
7415 tp->key[2] |= ((u64)fsp->h_u.tcp_ip4_spec.tos <<
7416 TCAM_V4KEY2_TOS_SHIFT);
7417 tp->key_mask[2] |= ((u64)fsp->m_u.tcp_ip4_spec.tos <<
7418 TCAM_V4KEY2_TOS_SHIFT);
7419 switch (fsp->flow_type) {
7420 case TCP_V4_FLOW:
7421 case UDP_V4_FLOW:
7422 case SCTP_V4_FLOW:
7423 sport = be16_to_cpu(fsp->h_u.tcp_ip4_spec.psrc);
7424 spm = be16_to_cpu(fsp->m_u.tcp_ip4_spec.psrc);
7425 dport = be16_to_cpu(fsp->h_u.tcp_ip4_spec.pdst);
7426 dpm = be16_to_cpu(fsp->m_u.tcp_ip4_spec.pdst);
7427
7428 tp->key[2] |= (((u64)sport << 16) | dport);
7429 tp->key_mask[2] |= (((u64)spm << 16) | dpm);
7430 niu_ethflow_to_l3proto(fsp->flow_type, &pid);
7431 break;
7432 case AH_V4_FLOW:
7433 case ESP_V4_FLOW:
7434 spi = be32_to_cpu(fsp->h_u.ah_ip4_spec.spi);
7435 spim = be32_to_cpu(fsp->m_u.ah_ip4_spec.spi);
7436
7437 tp->key[2] |= spi;
7438 tp->key_mask[2] |= spim;
7439 niu_ethflow_to_l3proto(fsp->flow_type, &pid);
7440 break;
7441 case IP_USER_FLOW:
7442 spi = be32_to_cpu(fsp->h_u.usr_ip4_spec.l4_4_bytes);
7443 spim = be32_to_cpu(fsp->m_u.usr_ip4_spec.l4_4_bytes);
7444
7445 tp->key[2] |= spi;
7446 tp->key_mask[2] |= spim;
7447 pid = fsp->h_u.usr_ip4_spec.proto;
7448 break;
7449 default:
7450 break;
7451 }
7452
7453 tp->key[2] |= ((u64)pid << TCAM_V4KEY2_PROTO_SHIFT);
7454 if (pid) {
7455 tp->key_mask[2] |= TCAM_V4KEY2_PROTO;
7456 }
7457}
7458
7459static int niu_add_ethtool_tcam_entry(struct niu *np,
7460 struct ethtool_rxnfc *nfc)
7461{
7462 struct niu_parent *parent = np->parent;
7463 struct niu_tcam_entry *tp;
7464 struct ethtool_rx_flow_spec *fsp = &nfc->fs;
7465 struct niu_rdc_tables *rdc_table = &parent->rdc_group_cfg[np->port];
7466 int l2_rdc_table = rdc_table->first_table_num;
7467 u16 idx;
7468 u64 class;
7469 unsigned long flags;
7470 int err, ret;
7471
7472 ret = 0;
7473
7474 idx = nfc->fs.location;
7475 if (idx >= tcam_get_size(np))
7476 return -EINVAL;
7477
7478 if (fsp->flow_type == IP_USER_FLOW) {
7479 int i;
7480 int add_usr_cls = 0;
7481 int ipv6 = 0;
7482 struct ethtool_usrip4_spec *uspec = &fsp->h_u.usr_ip4_spec;
7483 struct ethtool_usrip4_spec *umask = &fsp->m_u.usr_ip4_spec;
7484
7485 niu_lock_parent(np, flags);
7486
7487 for (i = 0; i < NIU_L3_PROG_CLS; i++) {
7488 if (parent->l3_cls[i]) {
7489 if (uspec->proto == parent->l3_cls_pid[i]) {
7490 class = parent->l3_cls[i];
7491 parent->l3_cls_refcnt[i]++;
7492 add_usr_cls = 1;
7493 break;
7494 }
7495 } else {
7496 /* Program new user IP class */
7497 switch (i) {
7498 case 0:
7499 class = CLASS_CODE_USER_PROG1;
7500 break;
7501 case 1:
7502 class = CLASS_CODE_USER_PROG2;
7503 break;
7504 case 2:
7505 class = CLASS_CODE_USER_PROG3;
7506 break;
7507 case 3:
7508 class = CLASS_CODE_USER_PROG4;
7509 break;
7510 default:
7511 break;
7512 }
7513 if (uspec->ip_ver == ETH_RX_NFC_IP6)
7514 ipv6 = 1;
7515 ret = tcam_user_ip_class_set(np, class, ipv6,
7516 uspec->proto,
7517 uspec->tos,
7518 umask->tos);
7519 if (ret)
7520 goto out;
7521
7522 ret = tcam_user_ip_class_enable(np, class, 1);
7523 if (ret)
7524 goto out;
7525 parent->l3_cls[i] = class;
7526 parent->l3_cls_pid[i] = uspec->proto;
7527 parent->l3_cls_refcnt[i]++;
7528 add_usr_cls = 1;
7529 break;
7530 }
7531 }
7532 if (!add_usr_cls) {
7533 pr_info(PFX "niu%d: %s niu_add_ethtool_tcam_entry: "
7534 "Could not find/insert class for pid %d\n",
7535 parent->index, np->dev->name, uspec->proto);
7536 ret = -EINVAL;
7537 goto out;
7538 }
7539 niu_unlock_parent(np, flags);
7540 } else {
7541 if (!niu_ethflow_to_class(fsp->flow_type, &class)) {
7542 return -EINVAL;
7543 }
7544 }
7545
7546 niu_lock_parent(np, flags);
7547
7548 idx = tcam_get_index(np, idx);
7549 tp = &parent->tcam[idx];
7550
7551 memset(tp, 0, sizeof(*tp));
7552
7553 /* fill in the tcam key and mask */
7554 switch (fsp->flow_type) {
7555 case TCP_V4_FLOW:
7556 case UDP_V4_FLOW:
7557 case SCTP_V4_FLOW:
7558 case AH_V4_FLOW:
7559 case ESP_V4_FLOW:
7560 niu_get_tcamkey_from_ip4fs(fsp, tp, l2_rdc_table, class);
7561 break;
7562 case TCP_V6_FLOW:
7563 case UDP_V6_FLOW:
7564 case SCTP_V6_FLOW:
7565 case AH_V6_FLOW:
7566 case ESP_V6_FLOW:
7567 /* Not yet implemented */
7568 pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: "
7569 "flow %d for IPv6 not implemented\n\n",
7570 parent->index, np->dev->name, fsp->flow_type);
7571 ret = -EINVAL;
7572 goto out;
7573 case IP_USER_FLOW:
7574 if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4) {
7575 niu_get_tcamkey_from_ip4fs(fsp, tp, l2_rdc_table,
7576 class);
7577 } else {
7578 /* Not yet implemented */
7579 pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: "
7580 "usr flow for IPv6 not implemented\n\n",
7581 parent->index, np->dev->name);
7582 ret = -EINVAL;
7583 goto out;
7584 }
7585 break;
7586 default:
7587 pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: "
7588 "Unknown flow type %d\n\n",
7589 parent->index, np->dev->name, fsp->flow_type);
7590 ret = -EINVAL;
7591 goto out;
7592 }
7593
7594 /* fill in the assoc data */
7595 if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
7596 tp->assoc_data = TCAM_ASSOCDATA_DISC;
7597 } else {
7598 if (fsp->ring_cookie >= np->num_rx_rings) {
7599 pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: "
7600 "Invalid RX ring %lld\n\n",
7601 parent->index, np->dev->name,
7602 (long long) fsp->ring_cookie);
7603 ret = -EINVAL;
7604 goto out;
7605 }
7606 tp->assoc_data = (TCAM_ASSOCDATA_TRES_USE_OFFSET |
7607 (fsp->ring_cookie <<
7608 TCAM_ASSOCDATA_OFFSET_SHIFT));
7609 }
7610
7611 err = tcam_write(np, idx, tp->key, tp->key_mask);
7612 if (err) {
7613 ret = -EINVAL;
7614 goto out;
7615 }
7616 err = tcam_assoc_write(np, idx, tp->assoc_data);
7617 if (err) {
7618 ret = -EINVAL;
7619 goto out;
7620 }
7621
7622 /* validate the entry */
7623 tp->valid = 1;
7624 np->clas.tcam_valid_entries++;
7625out:
7626 niu_unlock_parent(np, flags);
7627
7628 return ret;
7629}
7630
7631static int niu_del_ethtool_tcam_entry(struct niu *np, u32 loc)
7632{
7633 struct niu_parent *parent = np->parent;
7634 struct niu_tcam_entry *tp;
7635 u16 idx;
7636 unsigned long flags;
7637 u64 class;
7638 int ret = 0;
7639
7640 if (loc >= tcam_get_size(np))
7641 return -EINVAL;
7642
7643 niu_lock_parent(np, flags);
7644
7645 idx = tcam_get_index(np, loc);
7646 tp = &parent->tcam[idx];
7647
7648 /* if the entry is of a user defined class, then update*/
7649 class = (tp->key[0] & TCAM_V4KEY0_CLASS_CODE) >>
7650 TCAM_V4KEY0_CLASS_CODE_SHIFT;
7651
7652 if (class >= CLASS_CODE_USER_PROG1 && class <= CLASS_CODE_USER_PROG4) {
7653 int i;
7654 for (i = 0; i < NIU_L3_PROG_CLS; i++) {
7655 if (parent->l3_cls[i] == class) {
7656 parent->l3_cls_refcnt[i]--;
7657 if (!parent->l3_cls_refcnt[i]) {
7658 /* disable class */
7659 ret = tcam_user_ip_class_enable(np,
7660 class,
7661 0);
7662 if (ret)
7663 goto out;
7664 parent->l3_cls[i] = 0;
7665 parent->l3_cls_pid[i] = 0;
7666 }
7667 break;
7668 }
7669 }
7670 if (i == NIU_L3_PROG_CLS) {
7671 pr_info(PFX "niu%d: %s In niu_del_ethtool_tcam_entry,"
7672 "Usr class 0x%llx not found \n",
7673 parent->index, np->dev->name,
7674 (unsigned long long) class);
7675 ret = -EINVAL;
7676 goto out;
7677 }
7678 }
7679
7680 ret = tcam_flush(np, idx);
7681 if (ret)
7682 goto out;
7683
7684 /* invalidate the entry */
7685 tp->valid = 0;
7686 np->clas.tcam_valid_entries--;
7687out:
7688 niu_unlock_parent(np, flags);
7689
7690 return ret;
7691}
7692
7693static int niu_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
7694{
7695 struct niu *np = netdev_priv(dev);
7696 int ret = 0;
7697
7698 switch (cmd->cmd) {
7699 case ETHTOOL_SRXFH:
7700 ret = niu_set_hash_opts(np, cmd);
7701 break;
7702 case ETHTOOL_SRXCLSRLINS:
7703 ret = niu_add_ethtool_tcam_entry(np, cmd);
7704 break;
7705 case ETHTOOL_SRXCLSRLDEL:
7706 ret = niu_del_ethtool_tcam_entry(np, cmd->fs.location);
7707 break;
7708 default:
7709 ret = -EINVAL;
7710 break;
7711 }
7712
7713 return ret;
7714}
7715
7066static const struct { 7716static const struct {
7067 const char string[ETH_GSTRING_LEN]; 7717 const char string[ETH_GSTRING_LEN];
7068} niu_xmac_stat_keys[] = { 7718} niu_xmac_stat_keys[] = {
@@ -7296,8 +7946,8 @@ static const struct ethtool_ops niu_ethtool_ops = {
7296 .get_stats_count = niu_get_stats_count, 7946 .get_stats_count = niu_get_stats_count,
7297 .get_ethtool_stats = niu_get_ethtool_stats, 7947 .get_ethtool_stats = niu_get_ethtool_stats,
7298 .phys_id = niu_phys_id, 7948 .phys_id = niu_phys_id,
7299 .get_rxhash = niu_get_hash_opts, 7949 .get_rxnfc = niu_get_nfc,
7300 .set_rxhash = niu_set_hash_opts, 7950 .set_rxnfc = niu_set_nfc,
7301}; 7951};
7302 7952
7303static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent, 7953static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent,
@@ -8367,7 +9017,8 @@ static int __devinit niu_classifier_swstate_init(struct niu *np)
8367 niudbg(PROBE, "niu_classifier_swstate_init: num_tcam(%d)\n", 9017 niudbg(PROBE, "niu_classifier_swstate_init: num_tcam(%d)\n",
8368 np->parent->tcam_num_entries); 9018 np->parent->tcam_num_entries);
8369 9019
8370 cp->tcam_index = (u16) np->port; 9020 cp->tcam_top = (u16) np->port;
9021 cp->tcam_sz = np->parent->tcam_num_entries / np->parent->num_ports;
8371 cp->h1_init = 0xffffffff; 9022 cp->h1_init = 0xffffffff;
8372 cp->h2_init = 0xffff; 9023 cp->h2_init = 0xffff;
8373 9024
diff --git a/drivers/net/niu.h b/drivers/net/niu.h
index 5a002375b35..8754e44cada 100644
--- a/drivers/net/niu.h
+++ b/drivers/net/niu.h
@@ -3004,7 +3004,9 @@ struct niu_classifier {
3004 struct niu_altmac_rdc alt_mac_mappings[16]; 3004 struct niu_altmac_rdc alt_mac_mappings[16];
3005 struct niu_vlan_rdc vlan_mappings[ENET_VLAN_TBL_NUM_ENTRIES]; 3005 struct niu_vlan_rdc vlan_mappings[ENET_VLAN_TBL_NUM_ENTRIES];
3006 3006
3007 u16 tcam_index; 3007 u16 tcam_top;
3008 u16 tcam_sz;
3009 u16 tcam_valid_entries;
3008 u16 num_alt_mac_mappings; 3010 u16 num_alt_mac_mappings;
3009 3011
3010 u32 h1_init; 3012 u32 h1_init;
@@ -3040,6 +3042,7 @@ struct phy_probe_info {
3040}; 3042};
3041 3043
3042struct niu_tcam_entry { 3044struct niu_tcam_entry {
3045 u8 valid;
3043 u64 key[4]; 3046 u64 key[4];
3044 u64 key_mask[4]; 3047 u64 key_mask[4];
3045 u64 assoc_data; 3048 u64 assoc_data;
@@ -3107,10 +3110,15 @@ struct niu_parent {
3107 struct phy_probe_info phy_probe_info; 3110 struct phy_probe_info phy_probe_info;
3108 3111
3109 struct niu_tcam_entry tcam[NIU_TCAM_ENTRIES_MAX]; 3112 struct niu_tcam_entry tcam[NIU_TCAM_ENTRIES_MAX];
3110 u64 l2_cls[2]; 3113
3111 u64 l3_cls[4]; 3114#define NIU_L2_PROG_CLS 2
3115#define NIU_L3_PROG_CLS 4
3116 u64 l2_cls[NIU_L2_PROG_CLS];
3117 u64 l3_cls[NIU_L3_PROG_CLS];
3112 u64 tcam_key[12]; 3118 u64 tcam_key[12];
3113 u64 flow_key[12]; 3119 u64 flow_key[12];
3120 u16 l3_cls_refcnt[NIU_L3_PROG_CLS];
3121 u8 l3_cls_pid[NIU_L3_PROG_CLS];
3114}; 3122};
3115 3123
3116struct niu_ops { 3124struct niu_ops {