diff options
Diffstat (limited to 'drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c')
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 247 |
1 files changed, 243 insertions, 4 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index d833a2d418ea..9233117ea506 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | |||
@@ -518,6 +518,16 @@ static void bnx2x_vf_set_bars(struct bnx2x *bp, struct bnx2x_virtf *vf) | |||
518 | } | 518 | } |
519 | } | 519 | } |
520 | 520 | ||
521 | void bnx2x_iov_remove_one(struct bnx2x *bp) | ||
522 | { | ||
523 | /* if SRIOV is not enabled there's nothing to do */ | ||
524 | if (!IS_SRIOV(bp)) | ||
525 | return; | ||
526 | |||
527 | /* free vf database */ | ||
528 | __bnx2x_iov_free_vfdb(bp); | ||
529 | } | ||
530 | |||
521 | void bnx2x_iov_free_mem(struct bnx2x *bp) | 531 | void bnx2x_iov_free_mem(struct bnx2x *bp) |
522 | { | 532 | { |
523 | int i; | 533 | int i; |
@@ -692,12 +702,241 @@ int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line) | |||
692 | return line + i; | 702 | return line + i; |
693 | } | 703 | } |
694 | 704 | ||
695 | void bnx2x_iov_remove_one(struct bnx2x *bp) | 705 | static u8 bnx2x_iov_is_vf_cid(struct bnx2x *bp, u16 cid) |
696 | { | 706 | { |
697 | /* if SRIOV is not enabled there's nothing to do */ | 707 | return ((cid >= BNX2X_FIRST_VF_CID) && |
708 | ((cid - BNX2X_FIRST_VF_CID) < BNX2X_VF_CIDS)); | ||
709 | } | ||
710 | |||
711 | static | ||
712 | void bnx2x_vf_handle_classification_eqe(struct bnx2x *bp, | ||
713 | struct bnx2x_vf_queue *vfq, | ||
714 | union event_ring_elem *elem) | ||
715 | { | ||
716 | unsigned long ramrod_flags = 0; | ||
717 | int rc = 0; | ||
718 | |||
719 | /* Always push next commands out, don't wait here */ | ||
720 | set_bit(RAMROD_CONT, &ramrod_flags); | ||
721 | |||
722 | switch (elem->message.data.eth_event.echo >> BNX2X_SWCID_SHIFT) { | ||
723 | case BNX2X_FILTER_MAC_PENDING: | ||
724 | rc = vfq->mac_obj.complete(bp, &vfq->mac_obj, elem, | ||
725 | &ramrod_flags); | ||
726 | break; | ||
727 | case BNX2X_FILTER_VLAN_PENDING: | ||
728 | rc = vfq->vlan_obj.complete(bp, &vfq->vlan_obj, elem, | ||
729 | &ramrod_flags); | ||
730 | break; | ||
731 | default: | ||
732 | BNX2X_ERR("Unsupported classification command: %d\n", | ||
733 | elem->message.data.eth_event.echo); | ||
734 | return; | ||
735 | } | ||
736 | if (rc < 0) | ||
737 | BNX2X_ERR("Failed to schedule new commands: %d\n", rc); | ||
738 | else if (rc > 0) | ||
739 | DP(BNX2X_MSG_IOV, "Scheduled next pending commands...\n"); | ||
740 | } | ||
741 | |||
742 | static | ||
743 | void bnx2x_vf_handle_mcast_eqe(struct bnx2x *bp, | ||
744 | struct bnx2x_virtf *vf) | ||
745 | { | ||
746 | struct bnx2x_mcast_ramrod_params rparam = {NULL}; | ||
747 | int rc; | ||
748 | |||
749 | rparam.mcast_obj = &vf->mcast_obj; | ||
750 | vf->mcast_obj.raw.clear_pending(&vf->mcast_obj.raw); | ||
751 | |||
752 | /* If there are pending mcast commands - send them */ | ||
753 | if (vf->mcast_obj.check_pending(&vf->mcast_obj)) { | ||
754 | rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT); | ||
755 | if (rc < 0) | ||
756 | BNX2X_ERR("Failed to send pending mcast commands: %d\n", | ||
757 | rc); | ||
758 | } | ||
759 | } | ||
760 | |||
761 | static | ||
762 | void bnx2x_vf_handle_filters_eqe(struct bnx2x *bp, | ||
763 | struct bnx2x_virtf *vf) | ||
764 | { | ||
765 | smp_mb__before_clear_bit(); | ||
766 | clear_bit(BNX2X_FILTER_RX_MODE_PENDING, &vf->filter_state); | ||
767 | smp_mb__after_clear_bit(); | ||
768 | } | ||
769 | |||
770 | int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem) | ||
771 | { | ||
772 | struct bnx2x_virtf *vf; | ||
773 | int qidx = 0, abs_vfid; | ||
774 | u8 opcode; | ||
775 | u16 cid = 0xffff; | ||
776 | |||
777 | if (!IS_SRIOV(bp)) | ||
778 | return 1; | ||
779 | |||
780 | /* first get the cid - the only events we handle here are cfc-delete | ||
781 | * and set-mac completion | ||
782 | */ | ||
783 | opcode = elem->message.opcode; | ||
784 | |||
785 | switch (opcode) { | ||
786 | case EVENT_RING_OPCODE_CFC_DEL: | ||
787 | cid = SW_CID((__force __le32) | ||
788 | elem->message.data.cfc_del_event.cid); | ||
789 | DP(BNX2X_MSG_IOV, "checking cfc-del comp cid=%d\n", cid); | ||
790 | break; | ||
791 | case EVENT_RING_OPCODE_CLASSIFICATION_RULES: | ||
792 | case EVENT_RING_OPCODE_MULTICAST_RULES: | ||
793 | case EVENT_RING_OPCODE_FILTERS_RULES: | ||
794 | cid = (elem->message.data.eth_event.echo & | ||
795 | BNX2X_SWCID_MASK); | ||
796 | DP(BNX2X_MSG_IOV, "checking filtering comp cid=%d\n", cid); | ||
797 | break; | ||
798 | case EVENT_RING_OPCODE_VF_FLR: | ||
799 | abs_vfid = elem->message.data.vf_flr_event.vf_id; | ||
800 | DP(BNX2X_MSG_IOV, "Got VF FLR notification abs_vfid=%d\n", | ||
801 | abs_vfid); | ||
802 | goto get_vf; | ||
803 | case EVENT_RING_OPCODE_MALICIOUS_VF: | ||
804 | abs_vfid = elem->message.data.malicious_vf_event.vf_id; | ||
805 | DP(BNX2X_MSG_IOV, "Got VF MALICIOUS notification abs_vfid=%d\n", | ||
806 | abs_vfid); | ||
807 | goto get_vf; | ||
808 | default: | ||
809 | return 1; | ||
810 | } | ||
811 | |||
812 | /* check if the cid is the VF range */ | ||
813 | if (!bnx2x_iov_is_vf_cid(bp, cid)) { | ||
814 | DP(BNX2X_MSG_IOV, "cid is outside vf range: %d\n", cid); | ||
815 | return 1; | ||
816 | } | ||
817 | |||
818 | /* extract vf and rxq index from vf_cid - relies on the following: | ||
819 | * 1. vfid on cid reflects the true abs_vfid | ||
820 | * 2. the max number of VFs (per path) is 64 | ||
821 | */ | ||
822 | qidx = cid & ((1 << BNX2X_VF_CID_WND)-1); | ||
823 | abs_vfid = (cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1); | ||
824 | get_vf: | ||
825 | vf = bnx2x_vf_by_abs_fid(bp, abs_vfid); | ||
826 | |||
827 | if (!vf) { | ||
828 | BNX2X_ERR("EQ completion for unknown VF, cid %d, abs_vfid %d\n", | ||
829 | cid, abs_vfid); | ||
830 | return 0; | ||
831 | } | ||
832 | |||
833 | switch (opcode) { | ||
834 | case EVENT_RING_OPCODE_CFC_DEL: | ||
835 | DP(BNX2X_MSG_IOV, "got VF [%d:%d] cfc delete ramrod\n", | ||
836 | vf->abs_vfid, qidx); | ||
837 | vfq_get(vf, qidx)->sp_obj.complete_cmd(bp, | ||
838 | &vfq_get(vf, | ||
839 | qidx)->sp_obj, | ||
840 | BNX2X_Q_CMD_CFC_DEL); | ||
841 | break; | ||
842 | case EVENT_RING_OPCODE_CLASSIFICATION_RULES: | ||
843 | DP(BNX2X_MSG_IOV, "got VF [%d:%d] set mac/vlan ramrod\n", | ||
844 | vf->abs_vfid, qidx); | ||
845 | bnx2x_vf_handle_classification_eqe(bp, vfq_get(vf, qidx), elem); | ||
846 | break; | ||
847 | case EVENT_RING_OPCODE_MULTICAST_RULES: | ||
848 | DP(BNX2X_MSG_IOV, "got VF [%d:%d] set mcast ramrod\n", | ||
849 | vf->abs_vfid, qidx); | ||
850 | bnx2x_vf_handle_mcast_eqe(bp, vf); | ||
851 | break; | ||
852 | case EVENT_RING_OPCODE_FILTERS_RULES: | ||
853 | DP(BNX2X_MSG_IOV, "got VF [%d:%d] set rx-mode ramrod\n", | ||
854 | vf->abs_vfid, qidx); | ||
855 | bnx2x_vf_handle_filters_eqe(bp, vf); | ||
856 | break; | ||
857 | case EVENT_RING_OPCODE_VF_FLR: | ||
858 | DP(BNX2X_MSG_IOV, "got VF [%d] FLR notification\n", | ||
859 | vf->abs_vfid); | ||
860 | /* Do nothing for now */ | ||
861 | break; | ||
862 | case EVENT_RING_OPCODE_MALICIOUS_VF: | ||
863 | DP(BNX2X_MSG_IOV, "got VF [%d] MALICIOUS notification\n", | ||
864 | vf->abs_vfid); | ||
865 | /* Do nothing for now */ | ||
866 | break; | ||
867 | } | ||
868 | /* SRIOV: reschedule any 'in_progress' operations */ | ||
869 | bnx2x_iov_sp_event(bp, cid, false); | ||
870 | |||
871 | return 0; | ||
872 | } | ||
873 | |||
874 | static struct bnx2x_virtf *bnx2x_vf_by_cid(struct bnx2x *bp, int vf_cid) | ||
875 | { | ||
876 | /* extract the vf from vf_cid - relies on the following: | ||
877 | * 1. vfid on cid reflects the true abs_vfid | ||
878 | * 2. the max number of VFs (per path) is 64 | ||
879 | */ | ||
880 | int abs_vfid = (vf_cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1); | ||
881 | return bnx2x_vf_by_abs_fid(bp, abs_vfid); | ||
882 | } | ||
883 | |||
884 | void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid, | ||
885 | struct bnx2x_queue_sp_obj **q_obj) | ||
886 | { | ||
887 | struct bnx2x_virtf *vf; | ||
888 | |||
698 | if (!IS_SRIOV(bp)) | 889 | if (!IS_SRIOV(bp)) |
699 | return; | 890 | return; |
700 | 891 | ||
701 | /* free vf database */ | 892 | vf = bnx2x_vf_by_cid(bp, vf_cid); |
702 | __bnx2x_iov_free_vfdb(bp); | 893 | |
894 | if (vf) { | ||
895 | /* extract queue index from vf_cid - relies on the following: | ||
896 | * 1. vfid on cid reflects the true abs_vfid | ||
897 | * 2. the max number of VFs (per path) is 64 | ||
898 | */ | ||
899 | int q_index = vf_cid & ((1 << BNX2X_VF_CID_WND)-1); | ||
900 | *q_obj = &bnx2x_vfq(vf, q_index, sp_obj); | ||
901 | } else { | ||
902 | BNX2X_ERR("No vf matching cid %d\n", vf_cid); | ||
903 | } | ||
904 | } | ||
905 | |||
906 | void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work) | ||
907 | { | ||
908 | struct bnx2x_virtf *vf; | ||
909 | |||
910 | /* check if the cid is the VF range */ | ||
911 | if (!IS_SRIOV(bp) || !bnx2x_iov_is_vf_cid(bp, vf_cid)) | ||
912 | return; | ||
913 | |||
914 | vf = bnx2x_vf_by_cid(bp, vf_cid); | ||
915 | if (vf) { | ||
916 | /* set in_progress flag */ | ||
917 | atomic_set(&vf->op_in_progress, 1); | ||
918 | if (queue_work) | ||
919 | queue_delayed_work(bnx2x_wq, &bp->sp_task, 0); | ||
920 | } | ||
921 | } | ||
922 | |||
923 | void bnx2x_iov_sp_task(struct bnx2x *bp) | ||
924 | { | ||
925 | int i; | ||
926 | |||
927 | if (!IS_SRIOV(bp)) | ||
928 | return; | ||
929 | /* Iterate over all VFs and invoke state transition for VFs with | ||
930 | * 'in-progress' slow-path operations | ||
931 | */ | ||
932 | DP(BNX2X_MSG_IOV, "searching for pending vf operations\n"); | ||
933 | for_each_vf(bp, i) { | ||
934 | struct bnx2x_virtf *vf = BP_VF(bp, i); | ||
935 | |||
936 | if (!list_empty(&vf->op_list_head) && | ||
937 | atomic_read(&vf->op_in_progress)) { | ||
938 | DP(BNX2X_MSG_IOV, "running pending op for vf %d\n", i); | ||
939 | bnx2x_vfop_cur(bp, vf)->transition(bp, vf); | ||
940 | } | ||
941 | } | ||
703 | } | 942 | } |