diff options
author | Sandeep Gopalpet <Sandeep.Kumar@freescale.com> | 2009-11-02 02:03:40 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-03 02:40:59 -0500 |
commit | 7a8b3372e29ff58ebdf94def26703afabd287f11 (patch) | |
tree | 7d4ae47bb2ddc7de481fb4da4a4f9f31e808e1bf /drivers/net | |
parent | 46ceb60ca80fa07703bc6eb8f4651f900dff5a82 (diff) |
gianfar: Basic Support for programming hash rules
This patch provides basic hash rules programming via the ethtool
interface.
Signed-off-by: Sandeep Gopalpet <Sandeep.Kumar@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/gianfar.c | 73 | ||||
-rw-r--r-- | drivers/net/gianfar.h | 93 | ||||
-rw-r--r-- | drivers/net/gianfar_ethtool.c | 236 |
3 files changed, 402 insertions, 0 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index dc9fba09b17c..086d40dd526d 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -431,6 +431,9 @@ static const struct net_device_ops gfar_netdev_ops = { | |||
431 | #endif | 431 | #endif |
432 | }; | 432 | }; |
433 | 433 | ||
434 | unsigned int ftp_rqfpr[MAX_FILER_IDX + 1]; | ||
435 | unsigned int ftp_rqfcr[MAX_FILER_IDX + 1]; | ||
436 | |||
434 | void lock_rx_qs(struct gfar_private *priv) | 437 | void lock_rx_qs(struct gfar_private *priv) |
435 | { | 438 | { |
436 | int i = 0x0; | 439 | int i = 0x0; |
@@ -766,6 +769,73 @@ static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs) | |||
766 | } | 769 | } |
767 | return new_bit_map; | 770 | return new_bit_map; |
768 | } | 771 | } |
772 | |||
773 | u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar, u32 class) | ||
774 | { | ||
775 | u32 rqfpr = FPR_FILER_MASK; | ||
776 | u32 rqfcr = 0x0; | ||
777 | |||
778 | rqfar--; | ||
779 | rqfcr = RQFCR_CLE | RQFCR_PID_MASK | RQFCR_CMP_EXACT; | ||
780 | ftp_rqfpr[rqfar] = rqfpr; | ||
781 | ftp_rqfcr[rqfar] = rqfcr; | ||
782 | gfar_write_filer(priv, rqfar, rqfcr, rqfpr); | ||
783 | |||
784 | rqfar--; | ||
785 | rqfcr = RQFCR_CMP_NOMATCH; | ||
786 | ftp_rqfpr[rqfar] = rqfpr; | ||
787 | ftp_rqfcr[rqfar] = rqfcr; | ||
788 | gfar_write_filer(priv, rqfar, rqfcr, rqfpr); | ||
789 | |||
790 | rqfar--; | ||
791 | rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_PARSE | RQFCR_CLE | RQFCR_AND; | ||
792 | rqfpr = class; | ||
793 | ftp_rqfcr[rqfar] = rqfcr; | ||
794 | ftp_rqfpr[rqfar] = rqfpr; | ||
795 | gfar_write_filer(priv, rqfar, rqfcr, rqfpr); | ||
796 | |||
797 | rqfar--; | ||
798 | rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_MASK | RQFCR_AND; | ||
799 | rqfpr = class; | ||
800 | ftp_rqfcr[rqfar] = rqfcr; | ||
801 | ftp_rqfpr[rqfar] = rqfpr; | ||
802 | gfar_write_filer(priv, rqfar, rqfcr, rqfpr); | ||
803 | |||
804 | return rqfar; | ||
805 | } | ||
806 | |||
807 | static void gfar_init_filer_table(struct gfar_private *priv) | ||
808 | { | ||
809 | int i = 0x0; | ||
810 | u32 rqfar = MAX_FILER_IDX; | ||
811 | u32 rqfcr = 0x0; | ||
812 | u32 rqfpr = FPR_FILER_MASK; | ||
813 | |||
814 | /* Default rule */ | ||
815 | rqfcr = RQFCR_CMP_MATCH; | ||
816 | ftp_rqfcr[rqfar] = rqfcr; | ||
817 | ftp_rqfpr[rqfar] = rqfpr; | ||
818 | gfar_write_filer(priv, rqfar, rqfcr, rqfpr); | ||
819 | |||
820 | rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6); | ||
821 | rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6 | RQFPR_UDP); | ||
822 | rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6 | RQFPR_TCP); | ||
823 | rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4); | ||
824 | rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_UDP); | ||
825 | rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_TCP); | ||
826 | |||
827 | /* cur_filer_idx indicated the fisrt non-masked rule */ | ||
828 | priv->cur_filer_idx = rqfar; | ||
829 | |||
830 | /* Rest are masked rules */ | ||
831 | rqfcr = RQFCR_CMP_NOMATCH; | ||
832 | for (i = 0; i < rqfar; i++) { | ||
833 | ftp_rqfcr[i] = rqfcr; | ||
834 | ftp_rqfpr[i] = rqfpr; | ||
835 | gfar_write_filer(priv, i, rqfcr, rqfpr); | ||
836 | } | ||
837 | } | ||
838 | |||
769 | /* Set up the ethernet device structure, private data, | 839 | /* Set up the ethernet device structure, private data, |
770 | * and anything else we need before we start */ | 840 | * and anything else we need before we start */ |
771 | static int gfar_probe(struct of_device *ofdev, | 841 | static int gfar_probe(struct of_device *ofdev, |
@@ -1005,6 +1075,9 @@ static int gfar_probe(struct of_device *ofdev, | |||
1005 | priv->gfargrp[i].int_name_tx[len_devname] = '\0'; | 1075 | priv->gfargrp[i].int_name_tx[len_devname] = '\0'; |
1006 | } | 1076 | } |
1007 | 1077 | ||
1078 | /* Initialize the filer table */ | ||
1079 | gfar_init_filer_table(priv); | ||
1080 | |||
1008 | /* Create all the sysfs files */ | 1081 | /* Create all the sysfs files */ |
1009 | gfar_init_sysfs(dev); | 1082 | gfar_init_sysfs(dev); |
1010 | 1083 | ||
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index a2c1f963cdd6..44b63daa7ff3 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h | |||
@@ -381,6 +381,84 @@ extern const char gfar_driver_version[]; | |||
381 | #define BD_LFLAG(flags) ((flags) << 16) | 381 | #define BD_LFLAG(flags) ((flags) << 16) |
382 | #define BD_LENGTH_MASK 0x0000ffff | 382 | #define BD_LENGTH_MASK 0x0000ffff |
383 | 383 | ||
384 | #define CLASS_CODE_UNRECOG 0x00 | ||
385 | #define CLASS_CODE_DUMMY1 0x01 | ||
386 | #define CLASS_CODE_ETHERTYPE1 0x02 | ||
387 | #define CLASS_CODE_ETHERTYPE2 0x03 | ||
388 | #define CLASS_CODE_USER_PROG1 0x04 | ||
389 | #define CLASS_CODE_USER_PROG2 0x05 | ||
390 | #define CLASS_CODE_USER_PROG3 0x06 | ||
391 | #define CLASS_CODE_USER_PROG4 0x07 | ||
392 | #define CLASS_CODE_TCP_IPV4 0x08 | ||
393 | #define CLASS_CODE_UDP_IPV4 0x09 | ||
394 | #define CLASS_CODE_AH_ESP_IPV4 0x0a | ||
395 | #define CLASS_CODE_SCTP_IPV4 0x0b | ||
396 | #define CLASS_CODE_TCP_IPV6 0x0c | ||
397 | #define CLASS_CODE_UDP_IPV6 0x0d | ||
398 | #define CLASS_CODE_AH_ESP_IPV6 0x0e | ||
399 | #define CLASS_CODE_SCTP_IPV6 0x0f | ||
400 | |||
401 | #define FPR_FILER_MASK 0xFFFFFFFF | ||
402 | #define MAX_FILER_IDX 0xFF | ||
403 | |||
404 | /* RQFCR register bits */ | ||
405 | #define RQFCR_GPI 0x80000000 | ||
406 | #define RQFCR_HASHTBL_Q 0x00000000 | ||
407 | #define RQFCR_HASHTBL_0 0x00020000 | ||
408 | #define RQFCR_HASHTBL_1 0x00040000 | ||
409 | #define RQFCR_HASHTBL_2 0x00060000 | ||
410 | #define RQFCR_HASHTBL_3 0x00080000 | ||
411 | #define RQFCR_HASH 0x00010000 | ||
412 | #define RQFCR_CLE 0x00000200 | ||
413 | #define RQFCR_RJE 0x00000100 | ||
414 | #define RQFCR_AND 0x00000080 | ||
415 | #define RQFCR_CMP_EXACT 0x00000000 | ||
416 | #define RQFCR_CMP_MATCH 0x00000020 | ||
417 | #define RQFCR_CMP_NOEXACT 0x00000040 | ||
418 | #define RQFCR_CMP_NOMATCH 0x00000060 | ||
419 | |||
420 | /* RQFCR PID values */ | ||
421 | #define RQFCR_PID_MASK 0x00000000 | ||
422 | #define RQFCR_PID_PARSE 0x00000001 | ||
423 | #define RQFCR_PID_ARB 0x00000002 | ||
424 | #define RQFCR_PID_DAH 0x00000003 | ||
425 | #define RQFCR_PID_DAL 0x00000004 | ||
426 | #define RQFCR_PID_SAH 0x00000005 | ||
427 | #define RQFCR_PID_SAL 0x00000006 | ||
428 | #define RQFCR_PID_ETY 0x00000007 | ||
429 | #define RQFCR_PID_VID 0x00000008 | ||
430 | #define RQFCR_PID_PRI 0x00000009 | ||
431 | #define RQFCR_PID_TOS 0x0000000A | ||
432 | #define RQFCR_PID_L4P 0x0000000B | ||
433 | #define RQFCR_PID_DIA 0x0000000C | ||
434 | #define RQFCR_PID_SIA 0x0000000D | ||
435 | #define RQFCR_PID_DPT 0x0000000E | ||
436 | #define RQFCR_PID_SPT 0x0000000F | ||
437 | |||
438 | /* RQFPR when PID is 0x0001 */ | ||
439 | #define RQFPR_HDR_GE_512 0x00200000 | ||
440 | #define RQFPR_LERR 0x00100000 | ||
441 | #define RQFPR_RAR 0x00080000 | ||
442 | #define RQFPR_RARQ 0x00040000 | ||
443 | #define RQFPR_AR 0x00020000 | ||
444 | #define RQFPR_ARQ 0x00010000 | ||
445 | #define RQFPR_EBC 0x00008000 | ||
446 | #define RQFPR_VLN 0x00004000 | ||
447 | #define RQFPR_CFI 0x00002000 | ||
448 | #define RQFPR_JUM 0x00001000 | ||
449 | #define RQFPR_IPF 0x00000800 | ||
450 | #define RQFPR_FIF 0x00000400 | ||
451 | #define RQFPR_IPV4 0x00000200 | ||
452 | #define RQFPR_IPV6 0x00000100 | ||
453 | #define RQFPR_ICC 0x00000080 | ||
454 | #define RQFPR_ICV 0x00000040 | ||
455 | #define RQFPR_TCP 0x00000020 | ||
456 | #define RQFPR_UDP 0x00000010 | ||
457 | #define RQFPR_TUC 0x00000008 | ||
458 | #define RQFPR_TUV 0x00000004 | ||
459 | #define RQFPR_PER 0x00000002 | ||
460 | #define RQFPR_EER 0x00000001 | ||
461 | |||
384 | /* TxBD status field bits */ | 462 | /* TxBD status field bits */ |
385 | #define TXBD_READY 0x8000 | 463 | #define TXBD_READY 0x8000 |
386 | #define TXBD_PADCRC 0x4000 | 464 | #define TXBD_PADCRC 0x4000 |
@@ -959,6 +1037,8 @@ struct gfar_private { | |||
959 | unsigned int rx_stash_size; | 1037 | unsigned int rx_stash_size; |
960 | unsigned int rx_stash_index; | 1038 | unsigned int rx_stash_index; |
961 | 1039 | ||
1040 | u32 cur_filer_idx; | ||
1041 | |||
962 | struct sk_buff_head rx_recycle; | 1042 | struct sk_buff_head rx_recycle; |
963 | 1043 | ||
964 | struct vlan_group *vlgrp; | 1044 | struct vlan_group *vlgrp; |
@@ -1002,6 +1082,9 @@ struct gfar_private { | |||
1002 | struct gfar_extra_stats extra_stats; | 1082 | struct gfar_extra_stats extra_stats; |
1003 | }; | 1083 | }; |
1004 | 1084 | ||
1085 | extern unsigned int ftp_rqfpr[MAX_FILER_IDX + 1]; | ||
1086 | extern unsigned int ftp_rqfcr[MAX_FILER_IDX + 1]; | ||
1087 | |||
1005 | static inline u32 gfar_read(volatile unsigned __iomem *addr) | 1088 | static inline u32 gfar_read(volatile unsigned __iomem *addr) |
1006 | { | 1089 | { |
1007 | u32 val; | 1090 | u32 val; |
@@ -1014,6 +1097,16 @@ static inline void gfar_write(volatile unsigned __iomem *addr, u32 val) | |||
1014 | out_be32(addr, val); | 1097 | out_be32(addr, val); |
1015 | } | 1098 | } |
1016 | 1099 | ||
1100 | static inline void gfar_write_filer(struct gfar_private *priv, | ||
1101 | unsigned int far, unsigned int fcr, unsigned int fpr) | ||
1102 | { | ||
1103 | struct gfar __iomem *regs = priv->gfargrp[0].regs; | ||
1104 | |||
1105 | gfar_write(®s->rqfar, far); | ||
1106 | gfar_write(®s->rqfcr, fcr); | ||
1107 | gfar_write(®s->rqfpr, fpr); | ||
1108 | } | ||
1109 | |||
1017 | extern void lock_rx_qs(struct gfar_private *priv); | 1110 | extern void lock_rx_qs(struct gfar_private *priv); |
1018 | extern void lock_tx_qs(struct gfar_private *priv); | 1111 | extern void lock_tx_qs(struct gfar_private *priv); |
1019 | extern void unlock_rx_qs(struct gfar_private *priv); | 1112 | extern void unlock_rx_qs(struct gfar_private *priv); |
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 562f6c20f591..1010367695e4 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c | |||
@@ -645,6 +645,241 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | |||
645 | } | 645 | } |
646 | #endif | 646 | #endif |
647 | 647 | ||
648 | static int gfar_ethflow_to_class(int flow_type, u64 *class) | ||
649 | { | ||
650 | switch (flow_type) { | ||
651 | case TCP_V4_FLOW: | ||
652 | *class = CLASS_CODE_TCP_IPV4; | ||
653 | break; | ||
654 | case UDP_V4_FLOW: | ||
655 | *class = CLASS_CODE_UDP_IPV4; | ||
656 | break; | ||
657 | case AH_V4_FLOW: | ||
658 | case ESP_V4_FLOW: | ||
659 | *class = CLASS_CODE_AH_ESP_IPV4; | ||
660 | break; | ||
661 | case SCTP_V4_FLOW: | ||
662 | *class = CLASS_CODE_SCTP_IPV4; | ||
663 | break; | ||
664 | case TCP_V6_FLOW: | ||
665 | *class = CLASS_CODE_TCP_IPV6; | ||
666 | break; | ||
667 | case UDP_V6_FLOW: | ||
668 | *class = CLASS_CODE_UDP_IPV6; | ||
669 | break; | ||
670 | case AH_V6_FLOW: | ||
671 | case ESP_V6_FLOW: | ||
672 | *class = CLASS_CODE_AH_ESP_IPV6; | ||
673 | break; | ||
674 | case SCTP_V6_FLOW: | ||
675 | *class = CLASS_CODE_SCTP_IPV6; | ||
676 | break; | ||
677 | default: | ||
678 | return 0; | ||
679 | } | ||
680 | |||
681 | return 1; | ||
682 | } | ||
683 | |||
684 | static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow) | ||
685 | { | ||
686 | u32 fcr = 0x0, fpr = FPR_FILER_MASK; | ||
687 | |||
688 | if (ethflow & RXH_L2DA) { | ||
689 | fcr = RQFCR_PID_DAH |RQFCR_CMP_NOMATCH | | ||
690 | RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0; | ||
691 | ftp_rqfpr[priv->cur_filer_idx] = fpr; | ||
692 | ftp_rqfcr[priv->cur_filer_idx] = fcr; | ||
693 | gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); | ||
694 | priv->cur_filer_idx = priv->cur_filer_idx - 1; | ||
695 | |||
696 | fcr = RQFCR_PID_DAL | RQFCR_AND | RQFCR_CMP_NOMATCH | | ||
697 | RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0; | ||
698 | ftp_rqfpr[priv->cur_filer_idx] = fpr; | ||
699 | ftp_rqfcr[priv->cur_filer_idx] = fcr; | ||
700 | gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); | ||
701 | priv->cur_filer_idx = priv->cur_filer_idx - 1; | ||
702 | } | ||
703 | |||
704 | if (ethflow & RXH_VLAN) { | ||
705 | fcr = RQFCR_PID_VID | RQFCR_CMP_NOMATCH | RQFCR_HASH | | ||
706 | RQFCR_AND | RQFCR_HASHTBL_0; | ||
707 | gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); | ||
708 | ftp_rqfpr[priv->cur_filer_idx] = fpr; | ||
709 | ftp_rqfcr[priv->cur_filer_idx] = fcr; | ||
710 | priv->cur_filer_idx = priv->cur_filer_idx - 1; | ||
711 | } | ||
712 | |||
713 | if (ethflow & RXH_IP_SRC) { | ||
714 | fcr = RQFCR_PID_SIA | RQFCR_CMP_NOMATCH | RQFCR_HASH | | ||
715 | RQFCR_AND | RQFCR_HASHTBL_0; | ||
716 | ftp_rqfpr[priv->cur_filer_idx] = fpr; | ||
717 | ftp_rqfcr[priv->cur_filer_idx] = fcr; | ||
718 | gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); | ||
719 | priv->cur_filer_idx = priv->cur_filer_idx - 1; | ||
720 | } | ||
721 | |||
722 | if (ethflow & (RXH_IP_DST)) { | ||
723 | fcr = RQFCR_PID_DIA | RQFCR_CMP_NOMATCH | RQFCR_HASH | | ||
724 | RQFCR_AND | RQFCR_HASHTBL_0; | ||
725 | ftp_rqfpr[priv->cur_filer_idx] = fpr; | ||
726 | ftp_rqfcr[priv->cur_filer_idx] = fcr; | ||
727 | gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); | ||
728 | priv->cur_filer_idx = priv->cur_filer_idx - 1; | ||
729 | } | ||
730 | |||
731 | if (ethflow & RXH_L3_PROTO) { | ||
732 | fcr = RQFCR_PID_L4P | RQFCR_CMP_NOMATCH | RQFCR_HASH | | ||
733 | RQFCR_AND | RQFCR_HASHTBL_0; | ||
734 | ftp_rqfpr[priv->cur_filer_idx] = fpr; | ||
735 | ftp_rqfcr[priv->cur_filer_idx] = fcr; | ||
736 | gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); | ||
737 | priv->cur_filer_idx = priv->cur_filer_idx - 1; | ||
738 | } | ||
739 | |||
740 | if (ethflow & RXH_L4_B_0_1) { | ||
741 | fcr = RQFCR_PID_SPT | RQFCR_CMP_NOMATCH | RQFCR_HASH | | ||
742 | RQFCR_AND | RQFCR_HASHTBL_0; | ||
743 | ftp_rqfpr[priv->cur_filer_idx] = fpr; | ||
744 | ftp_rqfcr[priv->cur_filer_idx] = fcr; | ||
745 | gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); | ||
746 | priv->cur_filer_idx = priv->cur_filer_idx - 1; | ||
747 | } | ||
748 | |||
749 | if (ethflow & RXH_L4_B_2_3) { | ||
750 | fcr = RQFCR_PID_DPT | RQFCR_CMP_NOMATCH | RQFCR_HASH | | ||
751 | RQFCR_AND | RQFCR_HASHTBL_0; | ||
752 | ftp_rqfpr[priv->cur_filer_idx] = fpr; | ||
753 | ftp_rqfcr[priv->cur_filer_idx] = fcr; | ||
754 | gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); | ||
755 | priv->cur_filer_idx = priv->cur_filer_idx - 1; | ||
756 | } | ||
757 | } | ||
758 | |||
759 | static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u64 class) | ||
760 | { | ||
761 | unsigned int last_rule_idx = priv->cur_filer_idx; | ||
762 | unsigned int cmp_rqfpr; | ||
763 | unsigned int local_rqfpr[MAX_FILER_IDX + 1]; | ||
764 | unsigned int local_rqfcr[MAX_FILER_IDX + 1]; | ||
765 | int i = 0x0, k = 0x0; | ||
766 | int j = MAX_FILER_IDX, l = 0x0; | ||
767 | |||
768 | switch (class) { | ||
769 | case TCP_V4_FLOW: | ||
770 | cmp_rqfpr = RQFPR_IPV4 |RQFPR_TCP; | ||
771 | break; | ||
772 | case UDP_V4_FLOW: | ||
773 | cmp_rqfpr = RQFPR_IPV4 |RQFPR_UDP; | ||
774 | break; | ||
775 | case TCP_V6_FLOW: | ||
776 | cmp_rqfpr = RQFPR_IPV6 |RQFPR_TCP; | ||
777 | break; | ||
778 | case UDP_V6_FLOW: | ||
779 | cmp_rqfpr = RQFPR_IPV6 |RQFPR_UDP; | ||
780 | break; | ||
781 | case IPV4_FLOW: | ||
782 | cmp_rqfpr = RQFPR_IPV4; | ||
783 | case IPV6_FLOW: | ||
784 | cmp_rqfpr = RQFPR_IPV6; | ||
785 | break; | ||
786 | default: | ||
787 | printk(KERN_ERR "Right now this class is not supported\n"); | ||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | for (i = 0; i < MAX_FILER_IDX + 1; i++) { | ||
792 | local_rqfpr[j] = ftp_rqfpr[i]; | ||
793 | local_rqfcr[j] = ftp_rqfcr[i]; | ||
794 | j--; | ||
795 | if ((ftp_rqfcr[i] == (RQFCR_PID_PARSE | | ||
796 | RQFCR_CLE |RQFCR_AND)) && | ||
797 | (ftp_rqfpr[i] == cmp_rqfpr)) | ||
798 | break; | ||
799 | } | ||
800 | |||
801 | if (i == MAX_FILER_IDX + 1) { | ||
802 | printk(KERN_ERR "No parse rule found, "); | ||
803 | printk(KERN_ERR "can't create hash rules\n"); | ||
804 | return 0; | ||
805 | } | ||
806 | |||
807 | /* If a match was found, then it begins the starting of a cluster rule | ||
808 | * if it was already programmed, we need to overwrite these rules | ||
809 | */ | ||
810 | for (l = i+1; l < MAX_FILER_IDX; l++) { | ||
811 | if ((ftp_rqfcr[l] & RQFCR_CLE) && | ||
812 | !(ftp_rqfcr[l] & RQFCR_AND)) { | ||
813 | ftp_rqfcr[l] = RQFCR_CLE | RQFCR_CMP_EXACT | | ||
814 | RQFCR_HASHTBL_0 | RQFCR_PID_MASK; | ||
815 | ftp_rqfpr[l] = FPR_FILER_MASK; | ||
816 | gfar_write_filer(priv, l, ftp_rqfcr[l], ftp_rqfpr[l]); | ||
817 | break; | ||
818 | } | ||
819 | |||
820 | if (!(ftp_rqfcr[l] & RQFCR_CLE) && (ftp_rqfcr[l] & RQFCR_AND)) | ||
821 | continue; | ||
822 | else { | ||
823 | local_rqfpr[j] = ftp_rqfpr[l]; | ||
824 | local_rqfcr[j] = ftp_rqfcr[l]; | ||
825 | j--; | ||
826 | } | ||
827 | } | ||
828 | |||
829 | priv->cur_filer_idx = l - 1; | ||
830 | last_rule_idx = l; | ||
831 | |||
832 | /* hash rules */ | ||
833 | ethflow_to_filer_rules(priv, ethflow); | ||
834 | |||
835 | /* Write back the popped out rules again */ | ||
836 | for (k = j+1; k < MAX_FILER_IDX; k++) { | ||
837 | ftp_rqfpr[priv->cur_filer_idx] = local_rqfpr[k]; | ||
838 | ftp_rqfcr[priv->cur_filer_idx] = local_rqfcr[k]; | ||
839 | gfar_write_filer(priv, priv->cur_filer_idx, | ||
840 | local_rqfcr[k], local_rqfpr[k]); | ||
841 | if (!priv->cur_filer_idx) | ||
842 | break; | ||
843 | priv->cur_filer_idx = priv->cur_filer_idx - 1; | ||
844 | } | ||
845 | |||
846 | return 1; | ||
847 | } | ||
848 | |||
849 | static int gfar_set_hash_opts(struct gfar_private *priv, struct ethtool_rxnfc *cmd) | ||
850 | { | ||
851 | u64 class; | ||
852 | |||
853 | if (!gfar_ethflow_to_class(cmd->flow_type, &class)) | ||
854 | return -EINVAL; | ||
855 | |||
856 | if (class < CLASS_CODE_USER_PROG1 || | ||
857 | class > CLASS_CODE_SCTP_IPV6) | ||
858 | return -EINVAL; | ||
859 | |||
860 | /* write the filer rules here */ | ||
861 | if (!gfar_ethflow_to_filer_table(priv, cmd->data, cmd->flow_type)) | ||
862 | return -1; | ||
863 | |||
864 | return 0; | ||
865 | } | ||
866 | |||
867 | static int gfar_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd) | ||
868 | { | ||
869 | struct gfar_private *priv = netdev_priv(dev); | ||
870 | int ret = 0; | ||
871 | |||
872 | switch(cmd->cmd) { | ||
873 | case ETHTOOL_SRXFH: | ||
874 | ret = gfar_set_hash_opts(priv, cmd); | ||
875 | break; | ||
876 | default: | ||
877 | ret = -EINVAL; | ||
878 | } | ||
879 | |||
880 | return ret; | ||
881 | } | ||
882 | |||
648 | const struct ethtool_ops gfar_ethtool_ops = { | 883 | const struct ethtool_ops gfar_ethtool_ops = { |
649 | .get_settings = gfar_gsettings, | 884 | .get_settings = gfar_gsettings, |
650 | .set_settings = gfar_ssettings, | 885 | .set_settings = gfar_ssettings, |
@@ -670,4 +905,5 @@ const struct ethtool_ops gfar_ethtool_ops = { | |||
670 | .get_wol = gfar_get_wol, | 905 | .get_wol = gfar_get_wol, |
671 | .set_wol = gfar_set_wol, | 906 | .set_wol = gfar_set_wol, |
672 | #endif | 907 | #endif |
908 | .set_rxnfc = gfar_set_nfc, | ||
673 | }; | 909 | }; |