aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLogan Gunthorpe <logang@deltatee.com>2017-03-02 18:24:34 -0500
committerBjorn Helgaas <bhelgaas@google.com>2017-04-12 13:23:37 -0400
commit52eabba5bcdb2853dec6ef007ba427b092034738 (patch)
tree959b69df05f188f33ae2d7e5ba53158fd50f2f83
parent5d8e1881f431cf470170813eb048e6a384340904 (diff)
switchtec: Add IOCTLs to the Switchtec driver
Add a couple of special IOCTLs to: * Inform userspace of firmware partition locations * Pass event counts and allow userspace to wait on events * Translate PFF numbers used by the switch to port numbers [Dan Carpenter <dan.carpenter@oracle.com>: fix off-by-one in ioctl_event_ctl()] Tested-by: Krishna Dhulipala <krishnad@fb.com> Signed-off-by: Logan Gunthorpe <logang@deltatee.com> Signed-off-by: Stephen Bates <stephen.bates@microsemi.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Wei Zhang <wzhang@fb.com> Reviewed-by: Jens Axboe <axboe@fb.com>
-rw-r--r--Documentation/ioctl/ioctl-number.txt1
-rw-r--r--Documentation/switchtec.txt27
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/pci/switch/switchtec.c481
-rw-r--r--include/uapi/linux/switchtec_ioctl.h132
5 files changed, 642 insertions, 0 deletions
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 08244bea5048..0682bd3eaa8a 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -191,6 +191,7 @@ Code Seq#(hex) Include File Comments
191'W' 00-1F linux/watchdog.h conflict! 191'W' 00-1F linux/watchdog.h conflict!
192'W' 00-1F linux/wanrouter.h conflict! (pre 3.9) 192'W' 00-1F linux/wanrouter.h conflict! (pre 3.9)
193'W' 00-3F sound/asound.h conflict! 193'W' 00-3F sound/asound.h conflict!
194'W' 40-5F drivers/pci/switch/switchtec.c
194'X' all fs/xfs/xfs_fs.h conflict! 195'X' all fs/xfs/xfs_fs.h conflict!
195 and fs/xfs/linux-2.6/xfs_ioctl32.h 196 and fs/xfs/linux-2.6/xfs_ioctl32.h
196 and include/linux/falloc.h 197 and include/linux/falloc.h
diff --git a/Documentation/switchtec.txt b/Documentation/switchtec.txt
index 4bced4c78446..a0a9c7b3d4d5 100644
--- a/Documentation/switchtec.txt
+++ b/Documentation/switchtec.txt
@@ -51,3 +51,30 @@ The char device has the following semantics:
51 51
52* The poll call will also be supported for userspace applications that 52* The poll call will also be supported for userspace applications that
53 need to do other things while waiting for the command to complete. 53 need to do other things while waiting for the command to complete.
54
55The following IOCTLs are also supported by the device:
56
57* SWITCHTEC_IOCTL_FLASH_INFO - Retrieve firmware length and number
58 of partitions in the device.
59
60* SWITCHTEC_IOCTL_FLASH_PART_INFO - Retrieve address and lengeth for
61 any specified partition in flash.
62
63* SWITCHTEC_IOCTL_EVENT_SUMMARY - Read a structure of bitmaps
64 indicating all uncleared events.
65
66* SWITCHTEC_IOCTL_EVENT_CTL - Get the current count, clear and set flags
67 for any event. This ioctl takes in a switchtec_ioctl_event_ctl struct
68 with the event_id, index and flags set (index being the partition or PFF
69 number for non-global events). It returns whether the event has
70 occurred, the number of times and any event specific data. The flags
71 can be used to clear the count or enable and disable actions to
72 happen when the event occurs.
73 By using the SWITCHTEC_IOCTL_EVENT_FLAG_EN_POLL flag,
74 you can set an event to trigger a poll command to return with
75 POLLPRI. In this way, userspace can wait for events to occur.
76
77* SWITCHTEC_IOCTL_PFF_TO_PORT and SWITCHTEC_IOCTL_PORT_TO_PFF convert
78 between PCI Function Framework number (used by the event system)
79 and Switchtec Logic Port ID and Partition number (which is more
80 user friendly).
diff --git a/MAINTAINERS b/MAINTAINERS
index 76ccc5a805dd..3744019a8853 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9664,6 +9664,7 @@ S: Maintained
9664F: Documentation/switchtec.txt 9664F: Documentation/switchtec.txt
9665F: Documentation/ABI/testing/sysfs-class-switchtec 9665F: Documentation/ABI/testing/sysfs-class-switchtec
9666F: drivers/pci/switch/switchtec* 9666F: drivers/pci/switch/switchtec*
9667F: include/uapi/linux/switchtec_ioctl.h
9667 9668
9668PCI DRIVER FOR NVIDIA TEGRA 9669PCI DRIVER FOR NVIDIA TEGRA
9669M: Thierry Reding <thierry.reding@gmail.com> 9670M: Thierry Reding <thierry.reding@gmail.com>
diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c
index 15ff61c7718b..cc6e085008fb 100644
--- a/drivers/pci/switch/switchtec.c
+++ b/drivers/pci/switch/switchtec.c
@@ -13,6 +13,8 @@
13 * 13 *
14 */ 14 */
15 15
16#include <linux/switchtec_ioctl.h>
17
16#include <linux/interrupt.h> 18#include <linux/interrupt.h>
17#include <linux/module.h> 19#include <linux/module.h>
18#include <linux/fs.h> 20#include <linux/fs.h>
@@ -778,6 +780,431 @@ static unsigned int switchtec_dev_poll(struct file *filp, poll_table *wait)
778 return ret; 780 return ret;
779} 781}
780 782
783static int ioctl_flash_info(struct switchtec_dev *stdev,
784 struct switchtec_ioctl_flash_info __user *uinfo)
785{
786 struct switchtec_ioctl_flash_info info = {0};
787 struct flash_info_regs __iomem *fi = stdev->mmio_flash_info;
788
789 info.flash_length = ioread32(&fi->flash_length);
790 info.num_partitions = SWITCHTEC_IOCTL_NUM_PARTITIONS;
791
792 if (copy_to_user(uinfo, &info, sizeof(info)))
793 return -EFAULT;
794
795 return 0;
796}
797
798static void set_fw_info_part(struct switchtec_ioctl_flash_part_info *info,
799 struct partition_info __iomem *pi)
800{
801 info->address = ioread32(&pi->address);
802 info->length = ioread32(&pi->length);
803}
804
805static int ioctl_flash_part_info(struct switchtec_dev *stdev,
806 struct switchtec_ioctl_flash_part_info __user *uinfo)
807{
808 struct switchtec_ioctl_flash_part_info info = {0};
809 struct flash_info_regs __iomem *fi = stdev->mmio_flash_info;
810 u32 active_addr = -1;
811
812 if (copy_from_user(&info, uinfo, sizeof(info)))
813 return -EFAULT;
814
815 switch (info.flash_partition) {
816 case SWITCHTEC_IOCTL_PART_CFG0:
817 active_addr = ioread32(&fi->active_cfg);
818 set_fw_info_part(&info, &fi->cfg0);
819 break;
820 case SWITCHTEC_IOCTL_PART_CFG1:
821 active_addr = ioread32(&fi->active_cfg);
822 set_fw_info_part(&info, &fi->cfg1);
823 break;
824 case SWITCHTEC_IOCTL_PART_IMG0:
825 active_addr = ioread32(&fi->active_img);
826 set_fw_info_part(&info, &fi->img0);
827 break;
828 case SWITCHTEC_IOCTL_PART_IMG1:
829 active_addr = ioread32(&fi->active_img);
830 set_fw_info_part(&info, &fi->img1);
831 break;
832 case SWITCHTEC_IOCTL_PART_NVLOG:
833 set_fw_info_part(&info, &fi->nvlog);
834 break;
835 case SWITCHTEC_IOCTL_PART_VENDOR0:
836 set_fw_info_part(&info, &fi->vendor[0]);
837 break;
838 case SWITCHTEC_IOCTL_PART_VENDOR1:
839 set_fw_info_part(&info, &fi->vendor[1]);
840 break;
841 case SWITCHTEC_IOCTL_PART_VENDOR2:
842 set_fw_info_part(&info, &fi->vendor[2]);
843 break;
844 case SWITCHTEC_IOCTL_PART_VENDOR3:
845 set_fw_info_part(&info, &fi->vendor[3]);
846 break;
847 case SWITCHTEC_IOCTL_PART_VENDOR4:
848 set_fw_info_part(&info, &fi->vendor[4]);
849 break;
850 case SWITCHTEC_IOCTL_PART_VENDOR5:
851 set_fw_info_part(&info, &fi->vendor[5]);
852 break;
853 case SWITCHTEC_IOCTL_PART_VENDOR6:
854 set_fw_info_part(&info, &fi->vendor[6]);
855 break;
856 case SWITCHTEC_IOCTL_PART_VENDOR7:
857 set_fw_info_part(&info, &fi->vendor[7]);
858 break;
859 default:
860 return -EINVAL;
861 }
862
863 if (info.address == active_addr)
864 info.active = 1;
865
866 if (copy_to_user(uinfo, &info, sizeof(info)))
867 return -EFAULT;
868
869 return 0;
870}
871
872static int ioctl_event_summary(struct switchtec_dev *stdev,
873 struct switchtec_user *stuser,
874 struct switchtec_ioctl_event_summary __user *usum)
875{
876 struct switchtec_ioctl_event_summary s = {0};
877 int i;
878 u32 reg;
879
880 s.global = ioread32(&stdev->mmio_sw_event->global_summary);
881 s.part_bitmap = ioread32(&stdev->mmio_sw_event->part_event_bitmap);
882 s.local_part = ioread32(&stdev->mmio_part_cfg->part_event_summary);
883
884 for (i = 0; i < stdev->partition_count; i++) {
885 reg = ioread32(&stdev->mmio_part_cfg_all[i].part_event_summary);
886 s.part[i] = reg;
887 }
888
889 for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) {
890 reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id);
891 if (reg != MICROSEMI_VENDOR_ID)
892 break;
893
894 reg = ioread32(&stdev->mmio_pff_csr[i].pff_event_summary);
895 s.pff[i] = reg;
896 }
897
898 if (copy_to_user(usum, &s, sizeof(s)))
899 return -EFAULT;
900
901 stuser->event_cnt = atomic_read(&stdev->event_cnt);
902
903 return 0;
904}
905
906static u32 __iomem *global_ev_reg(struct switchtec_dev *stdev,
907 size_t offset, int index)
908{
909 return (void __iomem *)stdev->mmio_sw_event + offset;
910}
911
912static u32 __iomem *part_ev_reg(struct switchtec_dev *stdev,
913 size_t offset, int index)
914{
915 return (void __iomem *)&stdev->mmio_part_cfg_all[index] + offset;
916}
917
918static u32 __iomem *pff_ev_reg(struct switchtec_dev *stdev,
919 size_t offset, int index)
920{
921 return (void __iomem *)&stdev->mmio_pff_csr[index] + offset;
922}
923
924#define EV_GLB(i, r)[i] = {offsetof(struct sw_event_regs, r), global_ev_reg}
925#define EV_PAR(i, r)[i] = {offsetof(struct part_cfg_regs, r), part_ev_reg}
926#define EV_PFF(i, r)[i] = {offsetof(struct pff_csr_regs, r), pff_ev_reg}
927
928const struct event_reg {
929 size_t offset;
930 u32 __iomem *(*map_reg)(struct switchtec_dev *stdev,
931 size_t offset, int index);
932} event_regs[] = {
933 EV_GLB(SWITCHTEC_IOCTL_EVENT_STACK_ERROR, stack_error_event_hdr),
934 EV_GLB(SWITCHTEC_IOCTL_EVENT_PPU_ERROR, ppu_error_event_hdr),
935 EV_GLB(SWITCHTEC_IOCTL_EVENT_ISP_ERROR, isp_error_event_hdr),
936 EV_GLB(SWITCHTEC_IOCTL_EVENT_SYS_RESET, sys_reset_event_hdr),
937 EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_EXC, fw_exception_hdr),
938 EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_NMI, fw_nmi_hdr),
939 EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_NON_FATAL, fw_non_fatal_hdr),
940 EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_FATAL, fw_fatal_hdr),
941 EV_GLB(SWITCHTEC_IOCTL_EVENT_TWI_MRPC_COMP, twi_mrpc_comp_hdr),
942 EV_GLB(SWITCHTEC_IOCTL_EVENT_TWI_MRPC_COMP_ASYNC,
943 twi_mrpc_comp_async_hdr),
944 EV_GLB(SWITCHTEC_IOCTL_EVENT_CLI_MRPC_COMP, cli_mrpc_comp_hdr),
945 EV_GLB(SWITCHTEC_IOCTL_EVENT_CLI_MRPC_COMP_ASYNC,
946 cli_mrpc_comp_async_hdr),
947 EV_GLB(SWITCHTEC_IOCTL_EVENT_GPIO_INT, gpio_interrupt_hdr),
948 EV_PAR(SWITCHTEC_IOCTL_EVENT_PART_RESET, part_reset_hdr),
949 EV_PAR(SWITCHTEC_IOCTL_EVENT_MRPC_COMP, mrpc_comp_hdr),
950 EV_PAR(SWITCHTEC_IOCTL_EVENT_MRPC_COMP_ASYNC, mrpc_comp_async_hdr),
951 EV_PAR(SWITCHTEC_IOCTL_EVENT_DYN_PART_BIND_COMP, dyn_binding_hdr),
952 EV_PFF(SWITCHTEC_IOCTL_EVENT_AER_IN_P2P, aer_in_p2p_hdr),
953 EV_PFF(SWITCHTEC_IOCTL_EVENT_AER_IN_VEP, aer_in_vep_hdr),
954 EV_PFF(SWITCHTEC_IOCTL_EVENT_DPC, dpc_hdr),
955 EV_PFF(SWITCHTEC_IOCTL_EVENT_CTS, cts_hdr),
956 EV_PFF(SWITCHTEC_IOCTL_EVENT_HOTPLUG, hotplug_hdr),
957 EV_PFF(SWITCHTEC_IOCTL_EVENT_IER, ier_hdr),
958 EV_PFF(SWITCHTEC_IOCTL_EVENT_THRESH, threshold_hdr),
959 EV_PFF(SWITCHTEC_IOCTL_EVENT_POWER_MGMT, power_mgmt_hdr),
960 EV_PFF(SWITCHTEC_IOCTL_EVENT_TLP_THROTTLING, tlp_throttling_hdr),
961 EV_PFF(SWITCHTEC_IOCTL_EVENT_FORCE_SPEED, force_speed_hdr),
962 EV_PFF(SWITCHTEC_IOCTL_EVENT_CREDIT_TIMEOUT, credit_timeout_hdr),
963 EV_PFF(SWITCHTEC_IOCTL_EVENT_LINK_STATE, link_state_hdr),
964};
965
966static u32 __iomem *event_hdr_addr(struct switchtec_dev *stdev,
967 int event_id, int index)
968{
969 size_t off;
970
971 if (event_id < 0 || event_id >= SWITCHTEC_IOCTL_MAX_EVENTS)
972 return ERR_PTR(-EINVAL);
973
974 off = event_regs[event_id].offset;
975
976 if (event_regs[event_id].map_reg == part_ev_reg) {
977 if (index == SWITCHTEC_IOCTL_EVENT_LOCAL_PART_IDX)
978 index = stdev->partition;
979 else if (index < 0 || index >= stdev->partition_count)
980 return ERR_PTR(-EINVAL);
981 } else if (event_regs[event_id].map_reg == pff_ev_reg) {
982 if (index < 0 || index >= stdev->pff_csr_count)
983 return ERR_PTR(-EINVAL);
984 }
985
986 return event_regs[event_id].map_reg(stdev, off, index);
987}
988
989static int event_ctl(struct switchtec_dev *stdev,
990 struct switchtec_ioctl_event_ctl *ctl)
991{
992 int i;
993 u32 __iomem *reg;
994 u32 hdr;
995
996 reg = event_hdr_addr(stdev, ctl->event_id, ctl->index);
997 if (IS_ERR(reg))
998 return PTR_ERR(reg);
999
1000 hdr = ioread32(reg);
1001 for (i = 0; i < ARRAY_SIZE(ctl->data); i++)
1002 ctl->data[i] = ioread32(&reg[i + 1]);
1003
1004 ctl->occurred = hdr & SWITCHTEC_EVENT_OCCURRED;
1005 ctl->count = (hdr >> 5) & 0xFF;
1006
1007 if (!(ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_CLEAR))
1008 hdr &= ~SWITCHTEC_EVENT_CLEAR;
1009 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_POLL)
1010 hdr |= SWITCHTEC_EVENT_EN_IRQ;
1011 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_POLL)
1012 hdr &= ~SWITCHTEC_EVENT_EN_IRQ;
1013 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_LOG)
1014 hdr |= SWITCHTEC_EVENT_EN_LOG;
1015 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_LOG)
1016 hdr &= ~SWITCHTEC_EVENT_EN_LOG;
1017 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_CLI)
1018 hdr |= SWITCHTEC_EVENT_EN_CLI;
1019 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_CLI)
1020 hdr &= ~SWITCHTEC_EVENT_EN_CLI;
1021 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_FATAL)
1022 hdr |= SWITCHTEC_EVENT_FATAL;
1023 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_FATAL)
1024 hdr &= ~SWITCHTEC_EVENT_FATAL;
1025
1026 if (ctl->flags)
1027 iowrite32(hdr, reg);
1028
1029 ctl->flags = 0;
1030 if (hdr & SWITCHTEC_EVENT_EN_IRQ)
1031 ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_POLL;
1032 if (hdr & SWITCHTEC_EVENT_EN_LOG)
1033 ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_LOG;
1034 if (hdr & SWITCHTEC_EVENT_EN_CLI)
1035 ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_CLI;
1036 if (hdr & SWITCHTEC_EVENT_FATAL)
1037 ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_FATAL;
1038
1039 return 0;
1040}
1041
1042static int ioctl_event_ctl(struct switchtec_dev *stdev,
1043 struct switchtec_ioctl_event_ctl __user *uctl)
1044{
1045 int ret;
1046 int nr_idxs;
1047 struct switchtec_ioctl_event_ctl ctl;
1048
1049 if (copy_from_user(&ctl, uctl, sizeof(ctl)))
1050 return -EFAULT;
1051
1052 if (ctl.event_id >= SWITCHTEC_IOCTL_MAX_EVENTS)
1053 return -EINVAL;
1054
1055 if (ctl.flags & SWITCHTEC_IOCTL_EVENT_FLAG_UNUSED)
1056 return -EINVAL;
1057
1058 if (ctl.index == SWITCHTEC_IOCTL_EVENT_IDX_ALL) {
1059 if (event_regs[ctl.event_id].map_reg == global_ev_reg)
1060 nr_idxs = 1;
1061 else if (event_regs[ctl.event_id].map_reg == part_ev_reg)
1062 nr_idxs = stdev->partition_count;
1063 else if (event_regs[ctl.event_id].map_reg == pff_ev_reg)
1064 nr_idxs = stdev->pff_csr_count;
1065 else
1066 return -EINVAL;
1067
1068 for (ctl.index = 0; ctl.index < nr_idxs; ctl.index++) {
1069 ret = event_ctl(stdev, &ctl);
1070 if (ret < 0)
1071 return ret;
1072 }
1073 } else {
1074 ret = event_ctl(stdev, &ctl);
1075 if (ret < 0)
1076 return ret;
1077 }
1078
1079 if (copy_to_user(uctl, &ctl, sizeof(ctl)))
1080 return -EFAULT;
1081
1082 return 0;
1083}
1084
1085static int ioctl_pff_to_port(struct switchtec_dev *stdev,
1086 struct switchtec_ioctl_pff_port *up)
1087{
1088 int i, part;
1089 u32 reg;
1090 struct part_cfg_regs *pcfg;
1091 struct switchtec_ioctl_pff_port p;
1092
1093 if (copy_from_user(&p, up, sizeof(p)))
1094 return -EFAULT;
1095
1096 p.port = -1;
1097 for (part = 0; part < stdev->partition_count; part++) {
1098 pcfg = &stdev->mmio_part_cfg_all[part];
1099 p.partition = part;
1100
1101 reg = ioread32(&pcfg->usp_pff_inst_id);
1102 if (reg == p.pff) {
1103 p.port = 0;
1104 break;
1105 }
1106
1107 reg = ioread32(&pcfg->vep_pff_inst_id);
1108 if (reg == p.pff) {
1109 p.port = SWITCHTEC_IOCTL_PFF_VEP;
1110 break;
1111 }
1112
1113 for (i = 0; i < ARRAY_SIZE(pcfg->dsp_pff_inst_id); i++) {
1114 reg = ioread32(&pcfg->dsp_pff_inst_id[i]);
1115 if (reg != p.pff)
1116 continue;
1117
1118 p.port = i + 1;
1119 break;
1120 }
1121
1122 if (p.port != -1)
1123 break;
1124 }
1125
1126 if (copy_to_user(up, &p, sizeof(p)))
1127 return -EFAULT;
1128
1129 return 0;
1130}
1131
1132static int ioctl_port_to_pff(struct switchtec_dev *stdev,
1133 struct switchtec_ioctl_pff_port *up)
1134{
1135 struct switchtec_ioctl_pff_port p;
1136 struct part_cfg_regs *pcfg;
1137
1138 if (copy_from_user(&p, up, sizeof(p)))
1139 return -EFAULT;
1140
1141 if (p.partition == SWITCHTEC_IOCTL_EVENT_LOCAL_PART_IDX)
1142 pcfg = stdev->mmio_part_cfg;
1143 else if (p.partition < stdev->partition_count)
1144 pcfg = &stdev->mmio_part_cfg_all[p.partition];
1145 else
1146 return -EINVAL;
1147
1148 switch (p.port) {
1149 case 0:
1150 p.pff = ioread32(&pcfg->usp_pff_inst_id);
1151 break;
1152 case SWITCHTEC_IOCTL_PFF_VEP:
1153 p.pff = ioread32(&pcfg->vep_pff_inst_id);
1154 break;
1155 default:
1156 if (p.port > ARRAY_SIZE(pcfg->dsp_pff_inst_id))
1157 return -EINVAL;
1158 p.pff = ioread32(&pcfg->dsp_pff_inst_id[p.port - 1]);
1159 break;
1160 }
1161
1162 if (copy_to_user(up, &p, sizeof(p)))
1163 return -EFAULT;
1164
1165 return 0;
1166}
1167
1168static long switchtec_dev_ioctl(struct file *filp, unsigned int cmd,
1169 unsigned long arg)
1170{
1171 struct switchtec_user *stuser = filp->private_data;
1172 struct switchtec_dev *stdev = stuser->stdev;
1173 int rc;
1174 void __user *argp = (void __user *)arg;
1175
1176 rc = lock_mutex_and_test_alive(stdev);
1177 if (rc)
1178 return rc;
1179
1180 switch (cmd) {
1181 case SWITCHTEC_IOCTL_FLASH_INFO:
1182 rc = ioctl_flash_info(stdev, argp);
1183 break;
1184 case SWITCHTEC_IOCTL_FLASH_PART_INFO:
1185 rc = ioctl_flash_part_info(stdev, argp);
1186 break;
1187 case SWITCHTEC_IOCTL_EVENT_SUMMARY:
1188 rc = ioctl_event_summary(stdev, stuser, argp);
1189 break;
1190 case SWITCHTEC_IOCTL_EVENT_CTL:
1191 rc = ioctl_event_ctl(stdev, argp);
1192 break;
1193 case SWITCHTEC_IOCTL_PFF_TO_PORT:
1194 rc = ioctl_pff_to_port(stdev, argp);
1195 break;
1196 case SWITCHTEC_IOCTL_PORT_TO_PFF:
1197 rc = ioctl_port_to_pff(stdev, argp);
1198 break;
1199 default:
1200 rc = -ENOTTY;
1201 break;
1202 }
1203
1204 mutex_unlock(&stdev->mrpc_mutex);
1205 return rc;
1206}
1207
781static const struct file_operations switchtec_fops = { 1208static const struct file_operations switchtec_fops = {
782 .owner = THIS_MODULE, 1209 .owner = THIS_MODULE,
783 .open = switchtec_dev_open, 1210 .open = switchtec_dev_open,
@@ -785,6 +1212,8 @@ static const struct file_operations switchtec_fops = {
785 .write = switchtec_dev_write, 1212 .write = switchtec_dev_write,
786 .read = switchtec_dev_read, 1213 .read = switchtec_dev_read,
787 .poll = switchtec_dev_poll, 1214 .poll = switchtec_dev_poll,
1215 .unlocked_ioctl = switchtec_dev_ioctl,
1216 .compat_ioctl = switchtec_dev_ioctl,
788}; 1217};
789 1218
790static void stdev_release(struct device *dev) 1219static void stdev_release(struct device *dev)
@@ -871,11 +1300,52 @@ err_put:
871 return ERR_PTR(rc); 1300 return ERR_PTR(rc);
872} 1301}
873 1302
1303static int mask_event(struct switchtec_dev *stdev, int eid, int idx)
1304{
1305 size_t off = event_regs[eid].offset;
1306 u32 __iomem *hdr_reg;
1307 u32 hdr;
1308
1309 hdr_reg = event_regs[eid].map_reg(stdev, off, idx);
1310 hdr = ioread32(hdr_reg);
1311
1312 if (!(hdr & SWITCHTEC_EVENT_OCCURRED && hdr & SWITCHTEC_EVENT_EN_IRQ))
1313 return 0;
1314
1315 dev_dbg(&stdev->dev, "%s: %d %d %x\n", __func__, eid, idx, hdr);
1316 hdr &= ~(SWITCHTEC_EVENT_EN_IRQ | SWITCHTEC_EVENT_OCCURRED);
1317 iowrite32(hdr, hdr_reg);
1318
1319 return 1;
1320}
1321
1322static int mask_all_events(struct switchtec_dev *stdev, int eid)
1323{
1324 int idx;
1325 int count = 0;
1326
1327 if (event_regs[eid].map_reg == part_ev_reg) {
1328 for (idx = 0; idx < stdev->partition_count; idx++)
1329 count += mask_event(stdev, eid, idx);
1330 } else if (event_regs[eid].map_reg == pff_ev_reg) {
1331 for (idx = 0; idx < stdev->pff_csr_count; idx++) {
1332 if (!stdev->pff_local[idx])
1333 continue;
1334 count += mask_event(stdev, eid, idx);
1335 }
1336 } else {
1337 count += mask_event(stdev, eid, 0);
1338 }
1339
1340 return count;
1341}
1342
874static irqreturn_t switchtec_event_isr(int irq, void *dev) 1343static irqreturn_t switchtec_event_isr(int irq, void *dev)
875{ 1344{
876 struct switchtec_dev *stdev = dev; 1345 struct switchtec_dev *stdev = dev;
877 u32 reg; 1346 u32 reg;
878 irqreturn_t ret = IRQ_NONE; 1347 irqreturn_t ret = IRQ_NONE;
1348 int eid, event_count = 0;
879 1349
880 reg = ioread32(&stdev->mmio_part_cfg->mrpc_comp_hdr); 1350 reg = ioread32(&stdev->mmio_part_cfg->mrpc_comp_hdr);
881 if (reg & SWITCHTEC_EVENT_OCCURRED) { 1351 if (reg & SWITCHTEC_EVENT_OCCURRED) {
@@ -885,6 +1355,17 @@ static irqreturn_t switchtec_event_isr(int irq, void *dev)
885 iowrite32(reg, &stdev->mmio_part_cfg->mrpc_comp_hdr); 1355 iowrite32(reg, &stdev->mmio_part_cfg->mrpc_comp_hdr);
886 } 1356 }
887 1357
1358 for (eid = 0; eid < SWITCHTEC_IOCTL_MAX_EVENTS; eid++)
1359 event_count += mask_all_events(stdev, eid);
1360
1361 if (event_count) {
1362 atomic_inc(&stdev->event_cnt);
1363 wake_up_interruptible(&stdev->event_wq);
1364 dev_dbg(&stdev->dev, "%s: %d events\n", __func__,
1365 event_count);
1366 return IRQ_HANDLED;
1367 }
1368
888 return ret; 1369 return ret;
889} 1370}
890 1371
diff --git a/include/uapi/linux/switchtec_ioctl.h b/include/uapi/linux/switchtec_ioctl.h
new file mode 100644
index 000000000000..3e824e1a6495
--- /dev/null
+++ b/include/uapi/linux/switchtec_ioctl.h
@@ -0,0 +1,132 @@
1/*
2 * Microsemi Switchtec PCIe Driver
3 * Copyright (c) 2017, Microsemi Corporation
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#ifndef _UAPI_LINUX_SWITCHTEC_IOCTL_H
17#define _UAPI_LINUX_SWITCHTEC_IOCTL_H
18
19#include <linux/types.h>
20
21#define SWITCHTEC_IOCTL_PART_CFG0 0
22#define SWITCHTEC_IOCTL_PART_CFG1 1
23#define SWITCHTEC_IOCTL_PART_IMG0 2
24#define SWITCHTEC_IOCTL_PART_IMG1 3
25#define SWITCHTEC_IOCTL_PART_NVLOG 4
26#define SWITCHTEC_IOCTL_PART_VENDOR0 5
27#define SWITCHTEC_IOCTL_PART_VENDOR1 6
28#define SWITCHTEC_IOCTL_PART_VENDOR2 7
29#define SWITCHTEC_IOCTL_PART_VENDOR3 8
30#define SWITCHTEC_IOCTL_PART_VENDOR4 9
31#define SWITCHTEC_IOCTL_PART_VENDOR5 10
32#define SWITCHTEC_IOCTL_PART_VENDOR6 11
33#define SWITCHTEC_IOCTL_PART_VENDOR7 12
34#define SWITCHTEC_IOCTL_NUM_PARTITIONS 13
35
36struct switchtec_ioctl_flash_info {
37 __u64 flash_length;
38 __u32 num_partitions;
39 __u32 padding;
40};
41
42struct switchtec_ioctl_flash_part_info {
43 __u32 flash_partition;
44 __u32 address;
45 __u32 length;
46 __u32 active;
47};
48
49struct switchtec_ioctl_event_summary {
50 __u64 global;
51 __u64 part_bitmap;
52 __u32 local_part;
53 __u32 padding;
54 __u32 part[48];
55 __u32 pff[48];
56};
57
58#define SWITCHTEC_IOCTL_EVENT_STACK_ERROR 0
59#define SWITCHTEC_IOCTL_EVENT_PPU_ERROR 1
60#define SWITCHTEC_IOCTL_EVENT_ISP_ERROR 2
61#define SWITCHTEC_IOCTL_EVENT_SYS_RESET 3
62#define SWITCHTEC_IOCTL_EVENT_FW_EXC 4
63#define SWITCHTEC_IOCTL_EVENT_FW_NMI 5
64#define SWITCHTEC_IOCTL_EVENT_FW_NON_FATAL 6
65#define SWITCHTEC_IOCTL_EVENT_FW_FATAL 7
66#define SWITCHTEC_IOCTL_EVENT_TWI_MRPC_COMP 8
67#define SWITCHTEC_IOCTL_EVENT_TWI_MRPC_COMP_ASYNC 9
68#define SWITCHTEC_IOCTL_EVENT_CLI_MRPC_COMP 10
69#define SWITCHTEC_IOCTL_EVENT_CLI_MRPC_COMP_ASYNC 11
70#define SWITCHTEC_IOCTL_EVENT_GPIO_INT 12
71#define SWITCHTEC_IOCTL_EVENT_PART_RESET 13
72#define SWITCHTEC_IOCTL_EVENT_MRPC_COMP 14
73#define SWITCHTEC_IOCTL_EVENT_MRPC_COMP_ASYNC 15
74#define SWITCHTEC_IOCTL_EVENT_DYN_PART_BIND_COMP 16
75#define SWITCHTEC_IOCTL_EVENT_AER_IN_P2P 17
76#define SWITCHTEC_IOCTL_EVENT_AER_IN_VEP 18
77#define SWITCHTEC_IOCTL_EVENT_DPC 19
78#define SWITCHTEC_IOCTL_EVENT_CTS 20
79#define SWITCHTEC_IOCTL_EVENT_HOTPLUG 21
80#define SWITCHTEC_IOCTL_EVENT_IER 22
81#define SWITCHTEC_IOCTL_EVENT_THRESH 23
82#define SWITCHTEC_IOCTL_EVENT_POWER_MGMT 24
83#define SWITCHTEC_IOCTL_EVENT_TLP_THROTTLING 25
84#define SWITCHTEC_IOCTL_EVENT_FORCE_SPEED 26
85#define SWITCHTEC_IOCTL_EVENT_CREDIT_TIMEOUT 27
86#define SWITCHTEC_IOCTL_EVENT_LINK_STATE 28
87#define SWITCHTEC_IOCTL_MAX_EVENTS 29
88
89#define SWITCHTEC_IOCTL_EVENT_LOCAL_PART_IDX -1
90#define SWITCHTEC_IOCTL_EVENT_IDX_ALL -2
91
92#define SWITCHTEC_IOCTL_EVENT_FLAG_CLEAR (1 << 0)
93#define SWITCHTEC_IOCTL_EVENT_FLAG_EN_POLL (1 << 1)
94#define SWITCHTEC_IOCTL_EVENT_FLAG_EN_LOG (1 << 2)
95#define SWITCHTEC_IOCTL_EVENT_FLAG_EN_CLI (1 << 3)
96#define SWITCHTEC_IOCTL_EVENT_FLAG_EN_FATAL (1 << 4)
97#define SWITCHTEC_IOCTL_EVENT_FLAG_DIS_POLL (1 << 5)
98#define SWITCHTEC_IOCTL_EVENT_FLAG_DIS_LOG (1 << 6)
99#define SWITCHTEC_IOCTL_EVENT_FLAG_DIS_CLI (1 << 7)
100#define SWITCHTEC_IOCTL_EVENT_FLAG_DIS_FATAL (1 << 8)
101#define SWITCHTEC_IOCTL_EVENT_FLAG_UNUSED (~0x1ff)
102
103struct switchtec_ioctl_event_ctl {
104 __u32 event_id;
105 __s32 index;
106 __u32 flags;
107 __u32 occurred;
108 __u32 count;
109 __u32 data[5];
110};
111
112#define SWITCHTEC_IOCTL_PFF_VEP 100
113struct switchtec_ioctl_pff_port {
114 __u32 pff;
115 __u32 partition;
116 __u32 port;
117};
118
119#define SWITCHTEC_IOCTL_FLASH_INFO \
120 _IOR('W', 0x40, struct switchtec_ioctl_flash_info)
121#define SWITCHTEC_IOCTL_FLASH_PART_INFO \
122 _IOWR('W', 0x41, struct switchtec_ioctl_flash_part_info)
123#define SWITCHTEC_IOCTL_EVENT_SUMMARY \
124 _IOR('W', 0x42, struct switchtec_ioctl_event_summary)
125#define SWITCHTEC_IOCTL_EVENT_CTL \
126 _IOWR('W', 0x43, struct switchtec_ioctl_event_ctl)
127#define SWITCHTEC_IOCTL_PFF_TO_PORT \
128 _IOWR('W', 0x44, struct switchtec_ioctl_pff_port)
129#define SWITCHTEC_IOCTL_PORT_TO_PFF \
130 _IOWR('W', 0x45, struct switchtec_ioctl_pff_port)
131
132#endif