diff options
author | Bryan O'Sullivan <bos@pathscale.com> | 2006-09-28 12:00:00 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-09-28 14:16:27 -0400 |
commit | 2c9446a1d63f1ca570e92f89422595732efedf44 (patch) | |
tree | 9b401358de12f9f88e79ac471c5950b61aba45a3 /drivers/infiniband/hw | |
parent | 9929b0fb0f35f54371e9364bab809bcd753f9d3a (diff) |
IB/ipath: Support revision 2 InfiniPath PCIE devices
This also entailed a little GPIO-interrupt general cleanup.
Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_common.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_iba6120.c | 116 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_intr.c | 88 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_kernel.h | 18 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_verbs.c | 28 |
5 files changed, 215 insertions, 37 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h index 46b7b20d8a91..382956d2ea4b 100644 --- a/drivers/infiniband/hw/ipath/ipath_common.h +++ b/drivers/infiniband/hw/ipath/ipath_common.h | |||
@@ -186,6 +186,8 @@ typedef enum _ipath_ureg { | |||
186 | #define IPATH_RUNTIME_FORCE_WC_ORDER 0x4 | 186 | #define IPATH_RUNTIME_FORCE_WC_ORDER 0x4 |
187 | #define IPATH_RUNTIME_RCVHDR_COPY 0x8 | 187 | #define IPATH_RUNTIME_RCVHDR_COPY 0x8 |
188 | #define IPATH_RUNTIME_MASTER 0x10 | 188 | #define IPATH_RUNTIME_MASTER 0x10 |
189 | #define IPATH_RUNTIME_PBC_REWRITE 0x20 | ||
190 | #define IPATH_RUNTIME_LOOSE_DMA_ALIGN 0x40 | ||
189 | 191 | ||
190 | /* | 192 | /* |
191 | * This structure is returned by ipath_userinit() immediately after | 193 | * This structure is returned by ipath_userinit() immediately after |
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index d86516d23df6..d64b87bf1f97 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c | |||
@@ -294,6 +294,13 @@ static const struct ipath_cregs ipath_pe_cregs = { | |||
294 | #define IPATH_GPIO_SCL (1ULL << \ | 294 | #define IPATH_GPIO_SCL (1ULL << \ |
295 | (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT)) | 295 | (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT)) |
296 | 296 | ||
297 | /* | ||
298 | * Rev2 silicon allows suppressing check for ArmLaunch errors. | ||
299 | * this can speed up short packet sends on systems that do | ||
300 | * not guaranteee write-order. | ||
301 | */ | ||
302 | #define INFINIPATH_XGXS_SUPPRESS_ARMLAUNCH_ERR (1ULL<<63) | ||
303 | |||
297 | /** | 304 | /** |
298 | * ipath_pe_handle_hwerrors - display hardware errors. | 305 | * ipath_pe_handle_hwerrors - display hardware errors. |
299 | * @dd: the infinipath device | 306 | * @dd: the infinipath device |
@@ -571,9 +578,12 @@ static void ipath_pe_init_hwerrors(struct ipath_devdata *dd) | |||
571 | if (!dd->ipath_boardrev) // no PLL for Emulator | 578 | if (!dd->ipath_boardrev) // no PLL for Emulator |
572 | val &= ~INFINIPATH_HWE_SERDESPLLFAILED; | 579 | val &= ~INFINIPATH_HWE_SERDESPLLFAILED; |
573 | 580 | ||
574 | /* workaround bug 9460 in internal interface bus parity checking */ | 581 | if (dd->ipath_minrev < 2) { |
575 | val &= ~INFINIPATH_HWE_PCIEBUSPARITYRADM; | 582 | /* workaround bug 9460 in internal interface bus parity |
576 | 583 | * checking. Fixed (HW bug 9490) in Rev2. | |
584 | */ | ||
585 | val &= ~INFINIPATH_HWE_PCIEBUSPARITYRADM; | ||
586 | } | ||
577 | dd->ipath_hwerrmask = val; | 587 | dd->ipath_hwerrmask = val; |
578 | } | 588 | } |
579 | 589 | ||
@@ -583,8 +593,8 @@ static void ipath_pe_init_hwerrors(struct ipath_devdata *dd) | |||
583 | */ | 593 | */ |
584 | static int ipath_pe_bringup_serdes(struct ipath_devdata *dd) | 594 | static int ipath_pe_bringup_serdes(struct ipath_devdata *dd) |
585 | { | 595 | { |
586 | u64 val, tmp, config1; | 596 | u64 val, tmp, config1, prev_val; |
587 | int ret = 0, change = 0; | 597 | int ret = 0; |
588 | 598 | ||
589 | ipath_dbg("Trying to bringup serdes\n"); | 599 | ipath_dbg("Trying to bringup serdes\n"); |
590 | 600 | ||
@@ -641,6 +651,7 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd) | |||
641 | val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); | 651 | val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); |
642 | 652 | ||
643 | val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); | 653 | val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); |
654 | prev_val = val; | ||
644 | if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) & | 655 | if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) & |
645 | INFINIPATH_XGXS_MDIOADDR_MASK) != 3) { | 656 | INFINIPATH_XGXS_MDIOADDR_MASK) != 3) { |
646 | val &= | 657 | val &= |
@@ -648,11 +659,9 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd) | |||
648 | INFINIPATH_XGXS_MDIOADDR_SHIFT); | 659 | INFINIPATH_XGXS_MDIOADDR_SHIFT); |
649 | /* MDIO address 3 */ | 660 | /* MDIO address 3 */ |
650 | val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT; | 661 | val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT; |
651 | change = 1; | ||
652 | } | 662 | } |
653 | if (val & INFINIPATH_XGXS_RESET) { | 663 | if (val & INFINIPATH_XGXS_RESET) { |
654 | val &= ~INFINIPATH_XGXS_RESET; | 664 | val &= ~INFINIPATH_XGXS_RESET; |
655 | change = 1; | ||
656 | } | 665 | } |
657 | if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) & | 666 | if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) & |
658 | INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) { | 667 | INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) { |
@@ -661,9 +670,19 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd) | |||
661 | INFINIPATH_XGXS_RX_POL_SHIFT); | 670 | INFINIPATH_XGXS_RX_POL_SHIFT); |
662 | val |= dd->ipath_rx_pol_inv << | 671 | val |= dd->ipath_rx_pol_inv << |
663 | INFINIPATH_XGXS_RX_POL_SHIFT; | 672 | INFINIPATH_XGXS_RX_POL_SHIFT; |
664 | change = 1; | ||
665 | } | 673 | } |
666 | if (change) | 674 | if (dd->ipath_minrev >= 2) { |
675 | /* Rev 2. can tolerate multiple writes to PBC, and | ||
676 | * allowing them can provide lower latency on some | ||
677 | * CPUs, but this feature is off by default, only | ||
678 | * turned on by setting D63 of XGXSconfig reg. | ||
679 | * May want to make this conditional more | ||
680 | * fine-grained in future. This is not exactly | ||
681 | * related to XGXS, but where the bit ended up. | ||
682 | */ | ||
683 | val |= INFINIPATH_XGXS_SUPPRESS_ARMLAUNCH_ERR; | ||
684 | } | ||
685 | if (val != prev_val) | ||
667 | ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); | 686 | ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); |
668 | 687 | ||
669 | val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); | 688 | val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); |
@@ -717,9 +736,25 @@ static void ipath_pe_quiet_serdes(struct ipath_devdata *dd) | |||
717 | ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); | 736 | ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); |
718 | } | 737 | } |
719 | 738 | ||
720 | /* this is not yet needed on this chip, so just return 0. */ | ||
721 | static int ipath_pe_intconfig(struct ipath_devdata *dd) | 739 | static int ipath_pe_intconfig(struct ipath_devdata *dd) |
722 | { | 740 | { |
741 | u64 val; | ||
742 | u32 chiprev; | ||
743 | |||
744 | /* | ||
745 | * If the chip supports added error indication via GPIO pins, | ||
746 | * enable interrupts on those bits so the interrupt routine | ||
747 | * can count the events. Also set flag so interrupt routine | ||
748 | * can know they are expected. | ||
749 | */ | ||
750 | chiprev = dd->ipath_revision >> INFINIPATH_R_CHIPREVMINOR_SHIFT; | ||
751 | if ((chiprev & INFINIPATH_R_CHIPREVMINOR_MASK) > 1) { | ||
752 | /* Rev2+ reports extra errors via internal GPIO pins */ | ||
753 | dd->ipath_flags |= IPATH_GPIO_ERRINTRS; | ||
754 | val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask); | ||
755 | val |= IPATH_GPIO_ERRINTR_MASK; | ||
756 | ipath_write_kreg( dd, dd->ipath_kregs->kr_gpio_mask, val); | ||
757 | } | ||
723 | return 0; | 758 | return 0; |
724 | } | 759 | } |
725 | 760 | ||
@@ -1082,6 +1117,45 @@ static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr, | |||
1082 | mmiowb(); | 1117 | mmiowb(); |
1083 | spin_unlock_irqrestore(&dd->ipath_tid_lock, flags); | 1118 | spin_unlock_irqrestore(&dd->ipath_tid_lock, flags); |
1084 | } | 1119 | } |
1120 | /** | ||
1121 | * ipath_pe_put_tid_2 - write a TID in chip, Revision 2 or higher | ||
1122 | * @dd: the infinipath device | ||
1123 | * @tidptr: pointer to the expected TID (in chip) to udpate | ||
1124 | * @tidtype: 0 for eager, 1 for expected | ||
1125 | * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing | ||
1126 | * | ||
1127 | * This exists as a separate routine to allow for selection of the | ||
1128 | * appropriate "flavor". The static calls in cleanup just use the | ||
1129 | * revision-agnostic form, as they are not performance critical. | ||
1130 | */ | ||
1131 | static void ipath_pe_put_tid_2(struct ipath_devdata *dd, u64 __iomem *tidptr, | ||
1132 | u32 type, unsigned long pa) | ||
1133 | { | ||
1134 | u32 __iomem *tidp32 = (u32 __iomem *)tidptr; | ||
1135 | |||
1136 | if (pa != dd->ipath_tidinvalid) { | ||
1137 | if (pa & ((1U << 11) - 1)) { | ||
1138 | dev_info(&dd->pcidev->dev, "BUG: physaddr %lx " | ||
1139 | "not 4KB aligned!\n", pa); | ||
1140 | return; | ||
1141 | } | ||
1142 | pa >>= 11; | ||
1143 | /* paranoia check */ | ||
1144 | if (pa & (7<<29)) | ||
1145 | ipath_dev_err(dd, | ||
1146 | "BUG: Physical page address 0x%lx " | ||
1147 | "has bits set in 31-29\n", pa); | ||
1148 | |||
1149 | if (type == 0) | ||
1150 | pa |= dd->ipath_tidtemplate; | ||
1151 | else /* for now, always full 4KB page */ | ||
1152 | pa |= 2 << 29; | ||
1153 | } | ||
1154 | if (dd->ipath_kregbase) | ||
1155 | writel(pa, tidp32); | ||
1156 | mmiowb(); | ||
1157 | } | ||
1158 | |||
1085 | 1159 | ||
1086 | /** | 1160 | /** |
1087 | * ipath_pe_clear_tid - clear all TID entries for a port, expected and eager | 1161 | * ipath_pe_clear_tid - clear all TID entries for a port, expected and eager |
@@ -1203,7 +1277,7 @@ int __attribute__((weak)) ipath_unordered_wc(void) | |||
1203 | 1277 | ||
1204 | /** | 1278 | /** |
1205 | * ipath_init_pe_get_base_info - set chip-specific flags for user code | 1279 | * ipath_init_pe_get_base_info - set chip-specific flags for user code |
1206 | * @dd: the infinipath device | 1280 | * @pd: the infinipath port |
1207 | * @kbase: ipath_base_info pointer | 1281 | * @kbase: ipath_base_info pointer |
1208 | * | 1282 | * |
1209 | * We set the PCIE flag because the lower bandwidth on PCIe vs | 1283 | * We set the PCIE flag because the lower bandwidth on PCIe vs |
@@ -1212,6 +1286,7 @@ int __attribute__((weak)) ipath_unordered_wc(void) | |||
1212 | static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase) | 1286 | static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase) |
1213 | { | 1287 | { |
1214 | struct ipath_base_info *kinfo = kbase; | 1288 | struct ipath_base_info *kinfo = kbase; |
1289 | struct ipath_devdata *dd; | ||
1215 | 1290 | ||
1216 | if (ipath_unordered_wc()) { | 1291 | if (ipath_unordered_wc()) { |
1217 | kinfo->spi_runtime_flags |= IPATH_RUNTIME_FORCE_WC_ORDER; | 1292 | kinfo->spi_runtime_flags |= IPATH_RUNTIME_FORCE_WC_ORDER; |
@@ -1220,8 +1295,20 @@ static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase) | |||
1220 | else | 1295 | else |
1221 | ipath_cdbg(PROC, "Not Intel processor, WC ordered\n"); | 1296 | ipath_cdbg(PROC, "Not Intel processor, WC ordered\n"); |
1222 | 1297 | ||
1223 | kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE; | 1298 | if (pd == NULL) |
1299 | goto done; | ||
1300 | |||
1301 | dd = pd->port_dd; | ||
1302 | |||
1303 | if (dd != NULL && dd->ipath_minrev >= 2) { | ||
1304 | ipath_cdbg(PROC, "IBA6120 Rev2, allow multiple PBC write\n"); | ||
1305 | kinfo->spi_runtime_flags |= IPATH_RUNTIME_PBC_REWRITE; | ||
1306 | ipath_cdbg(PROC, "IBA6120 Rev2, allow loose DMA alignment\n"); | ||
1307 | kinfo->spi_runtime_flags |= IPATH_RUNTIME_LOOSE_DMA_ALIGN; | ||
1308 | } | ||
1224 | 1309 | ||
1310 | done: | ||
1311 | kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE; | ||
1225 | return 0; | 1312 | return 0; |
1226 | } | 1313 | } |
1227 | 1314 | ||
@@ -1244,7 +1331,10 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd) | |||
1244 | dd->ipath_f_quiet_serdes = ipath_pe_quiet_serdes; | 1331 | dd->ipath_f_quiet_serdes = ipath_pe_quiet_serdes; |
1245 | dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes; | 1332 | dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes; |
1246 | dd->ipath_f_clear_tids = ipath_pe_clear_tids; | 1333 | dd->ipath_f_clear_tids = ipath_pe_clear_tids; |
1247 | dd->ipath_f_put_tid = ipath_pe_put_tid; | 1334 | if (dd->ipath_minrev >= 2) |
1335 | dd->ipath_f_put_tid = ipath_pe_put_tid_2; | ||
1336 | else | ||
1337 | dd->ipath_f_put_tid = ipath_pe_put_tid; | ||
1248 | dd->ipath_f_cleanup = ipath_setup_pe_cleanup; | 1338 | dd->ipath_f_cleanup = ipath_setup_pe_cleanup; |
1249 | dd->ipath_f_setextled = ipath_setup_pe_setextled; | 1339 | dd->ipath_f_setextled = ipath_setup_pe_setextled; |
1250 | dd->ipath_f_get_base_info = ipath_pe_get_base_info; | 1340 | dd->ipath_f_get_base_info = ipath_pe_get_base_info; |
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 49bf7bb15b04..5762b87d12ec 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c | |||
@@ -808,7 +808,7 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs) | |||
808 | if (oldhead != curtail) { | 808 | if (oldhead != curtail) { |
809 | if (dd->ipath_flags & IPATH_GPIO_INTR) { | 809 | if (dd->ipath_flags & IPATH_GPIO_INTR) { |
810 | ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear, | 810 | ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear, |
811 | (u64) (1 << 2)); | 811 | (u64) (1 << IPATH_GPIO_PORT0_BIT)); |
812 | istat = port0rbits | INFINIPATH_I_GPIO; | 812 | istat = port0rbits | INFINIPATH_I_GPIO; |
813 | } | 813 | } |
814 | else | 814 | else |
@@ -867,26 +867,80 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs) | |||
867 | 867 | ||
868 | if (istat & INFINIPATH_I_GPIO) { | 868 | if (istat & INFINIPATH_I_GPIO) { |
869 | /* | 869 | /* |
870 | * Packets are available in the port 0 rcv queue. | 870 | * GPIO interrupts fall in two broad classes: |
871 | * Eventually this needs to be generalized to check | 871 | * GPIO_2 indicates (on some HT4xx boards) that a packet |
872 | * IPATH_GPIO_INTR, and the specific GPIO bit, if | 872 | * has arrived for Port 0. Checking for this |
873 | * GPIO interrupts are used for anything else. | 873 | * is controlled by flag IPATH_GPIO_INTR. |
874 | * GPIO_3..5 on IBA6120 Rev2 chips indicate errors | ||
875 | * that we need to count. Checking for this | ||
876 | * is controlled by flag IPATH_GPIO_ERRINTRS. | ||
874 | */ | 877 | */ |
875 | if (unlikely(!(dd->ipath_flags & IPATH_GPIO_INTR))) { | 878 | u32 gpiostatus; |
876 | u32 gpiostatus; | 879 | u32 to_clear = 0; |
877 | gpiostatus = ipath_read_kreg32( | 880 | |
878 | dd, dd->ipath_kregs->kr_gpio_status); | 881 | gpiostatus = ipath_read_kreg32( |
879 | ipath_dbg("Unexpected GPIO interrupt bits %x\n", | 882 | dd, dd->ipath_kregs->kr_gpio_status); |
880 | gpiostatus); | 883 | /* First the error-counter case. |
881 | ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear, | 884 | */ |
882 | gpiostatus); | 885 | if ((gpiostatus & IPATH_GPIO_ERRINTR_MASK) && |
886 | (dd->ipath_flags & IPATH_GPIO_ERRINTRS)) { | ||
887 | /* want to clear the bits we see asserted. */ | ||
888 | to_clear |= (gpiostatus & IPATH_GPIO_ERRINTR_MASK); | ||
889 | |||
890 | /* | ||
891 | * Count appropriately, clear bits out of our copy, | ||
892 | * as they have been "handled". | ||
893 | */ | ||
894 | if (gpiostatus & (1 << IPATH_GPIO_RXUVL_BIT)) { | ||
895 | ipath_dbg("FlowCtl on UnsupVL\n"); | ||
896 | dd->ipath_rxfc_unsupvl_errs++; | ||
897 | } | ||
898 | if (gpiostatus & (1 << IPATH_GPIO_OVRUN_BIT)) { | ||
899 | ipath_dbg("Overrun Threshold exceeded\n"); | ||
900 | dd->ipath_overrun_thresh_errs++; | ||
901 | } | ||
902 | if (gpiostatus & (1 << IPATH_GPIO_LLI_BIT)) { | ||
903 | ipath_dbg("Local Link Integrity error\n"); | ||
904 | dd->ipath_lli_errs++; | ||
905 | } | ||
906 | gpiostatus &= ~IPATH_GPIO_ERRINTR_MASK; | ||
883 | } | 907 | } |
884 | else { | 908 | /* Now the Port0 Receive case */ |
885 | /* Clear GPIO status bit 2 */ | 909 | if ((gpiostatus & (1 << IPATH_GPIO_PORT0_BIT)) && |
886 | ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear, | 910 | (dd->ipath_flags & IPATH_GPIO_INTR)) { |
887 | (u64) (1 << 2)); | 911 | /* |
912 | * GPIO status bit 2 is set, and we expected it. | ||
913 | * clear it and indicate in p0bits. | ||
914 | * This probably only happens if a Port0 pkt | ||
915 | * arrives at _just_ the wrong time, and we | ||
916 | * handle that by seting chk0rcv; | ||
917 | */ | ||
918 | to_clear |= (1 << IPATH_GPIO_PORT0_BIT); | ||
919 | gpiostatus &= ~(1 << IPATH_GPIO_PORT0_BIT); | ||
888 | chk0rcv = 1; | 920 | chk0rcv = 1; |
889 | } | 921 | } |
922 | if (unlikely(gpiostatus)) { | ||
923 | /* | ||
924 | * Some unexpected bits remain. If they could have | ||
925 | * caused the interrupt, complain and clear. | ||
926 | * MEA: this is almost certainly non-ideal. | ||
927 | * we should look into auto-disable of unexpected | ||
928 | * GPIO interrupts, possibly on a "three strikes" | ||
929 | * basis. | ||
930 | */ | ||
931 | u32 mask; | ||
932 | mask = ipath_read_kreg32( | ||
933 | dd, dd->ipath_kregs->kr_gpio_mask); | ||
934 | if (mask & gpiostatus) { | ||
935 | ipath_dbg("Unexpected GPIO IRQ bits %x\n", | ||
936 | gpiostatus & mask); | ||
937 | to_clear |= (gpiostatus & mask); | ||
938 | } | ||
939 | } | ||
940 | if (to_clear) { | ||
941 | ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear, | ||
942 | (u64) to_clear); | ||
943 | } | ||
890 | } | 944 | } |
891 | chk0rcv |= istat & port0rbits; | 945 | chk0rcv |= istat & port0rbits; |
892 | 946 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 0cabd4f16234..e9cd95f3c2e1 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h | |||
@@ -524,6 +524,15 @@ struct ipath_devdata { | |||
524 | u32 ipath_lli_counter; | 524 | u32 ipath_lli_counter; |
525 | /* local link integrity errors */ | 525 | /* local link integrity errors */ |
526 | u32 ipath_lli_errors; | 526 | u32 ipath_lli_errors; |
527 | /* | ||
528 | * Above counts only cases where _successive_ LocalLinkIntegrity | ||
529 | * errors were seen in the receive headers of kern-packets. | ||
530 | * Below are the three (monotonically increasing) counters | ||
531 | * maintained via GPIO interrupts on iba6120-rev2. | ||
532 | */ | ||
533 | u32 ipath_rxfc_unsupvl_errs; | ||
534 | u32 ipath_overrun_thresh_errs; | ||
535 | u32 ipath_lli_errs; | ||
527 | }; | 536 | }; |
528 | 537 | ||
529 | /* Private data for file operations */ | 538 | /* Private data for file operations */ |
@@ -636,6 +645,15 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv); | |||
636 | /* can miss port0 rx interrupts */ | 645 | /* can miss port0 rx interrupts */ |
637 | #define IPATH_POLL_RX_INTR 0x40000 | 646 | #define IPATH_POLL_RX_INTR 0x40000 |
638 | #define IPATH_DISABLED 0x80000 /* administratively disabled */ | 647 | #define IPATH_DISABLED 0x80000 /* administratively disabled */ |
648 | /* Use GPIO interrupts for new counters */ | ||
649 | #define IPATH_GPIO_ERRINTRS 0x100000 | ||
650 | |||
651 | /* Bits in GPIO for the added interrupts */ | ||
652 | #define IPATH_GPIO_PORT0_BIT 2 | ||
653 | #define IPATH_GPIO_RXUVL_BIT 3 | ||
654 | #define IPATH_GPIO_OVRUN_BIT 4 | ||
655 | #define IPATH_GPIO_LLI_BIT 5 | ||
656 | #define IPATH_GPIO_ERRINTR_MASK 0x38 | ||
639 | 657 | ||
640 | /* portdata flag bit offsets */ | 658 | /* portdata flag bit offsets */ |
641 | /* waiting for a packet to arrive */ | 659 | /* waiting for a packet to arrive */ |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index a4bf870c5e31..56c01938f714 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c | |||
@@ -898,7 +898,8 @@ int ipath_get_counters(struct ipath_devdata *dd, | |||
898 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) + | 898 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) + |
899 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) + | 899 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) + |
900 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) + | 900 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) + |
901 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt); | 901 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt) + |
902 | dd->ipath_rxfc_unsupvl_errs; | ||
902 | cntrs->port_rcv_remphys_errors = | 903 | cntrs->port_rcv_remphys_errors = |
903 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt); | 904 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt); |
904 | cntrs->port_xmit_discards = | 905 | cntrs->port_xmit_discards = |
@@ -911,8 +912,10 @@ int ipath_get_counters(struct ipath_devdata *dd, | |||
911 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt); | 912 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt); |
912 | cntrs->port_rcv_packets = | 913 | cntrs->port_rcv_packets = |
913 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt); | 914 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt); |
914 | cntrs->local_link_integrity_errors = dd->ipath_lli_errors; | 915 | cntrs->local_link_integrity_errors = |
915 | cntrs->excessive_buffer_overrun_errors = 0; /* XXX */ | 916 | (dd->ipath_flags & IPATH_GPIO_ERRINTRS) ? |
917 | dd->ipath_lli_errs : dd->ipath_lli_errors; | ||
918 | cntrs->excessive_buffer_overrun_errors = dd->ipath_overrun_thresh_errs; | ||
916 | 919 | ||
917 | ret = 0; | 920 | ret = 0; |
918 | 921 | ||
@@ -1380,11 +1383,13 @@ static int enable_timer(struct ipath_devdata *dd) | |||
1380 | * processing. | 1383 | * processing. |
1381 | */ | 1384 | */ |
1382 | if (dd->ipath_flags & IPATH_GPIO_INTR) { | 1385 | if (dd->ipath_flags & IPATH_GPIO_INTR) { |
1386 | u64 val; | ||
1383 | ipath_write_kreg(dd, dd->ipath_kregs->kr_debugportselect, | 1387 | ipath_write_kreg(dd, dd->ipath_kregs->kr_debugportselect, |
1384 | 0x2074076542310ULL); | 1388 | 0x2074076542310ULL); |
1385 | /* Enable GPIO bit 2 interrupt */ | 1389 | /* Enable GPIO bit 2 interrupt */ |
1386 | ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, | 1390 | val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask); |
1387 | (u64) (1 << 2)); | 1391 | val |= (u64) (1 << IPATH_GPIO_PORT0_BIT); |
1392 | ipath_write_kreg( dd, dd->ipath_kregs->kr_gpio_mask, val); | ||
1388 | } | 1393 | } |
1389 | 1394 | ||
1390 | init_timer(&dd->verbs_timer); | 1395 | init_timer(&dd->verbs_timer); |
@@ -1399,8 +1404,17 @@ static int enable_timer(struct ipath_devdata *dd) | |||
1399 | static int disable_timer(struct ipath_devdata *dd) | 1404 | static int disable_timer(struct ipath_devdata *dd) |
1400 | { | 1405 | { |
1401 | /* Disable GPIO bit 2 interrupt */ | 1406 | /* Disable GPIO bit 2 interrupt */ |
1402 | if (dd->ipath_flags & IPATH_GPIO_INTR) | 1407 | if (dd->ipath_flags & IPATH_GPIO_INTR) { |
1403 | ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, 0); | 1408 | u64 val; |
1409 | /* Disable GPIO bit 2 interrupt */ | ||
1410 | val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask); | ||
1411 | val &= ~((u64) (1 << IPATH_GPIO_PORT0_BIT)); | ||
1412 | ipath_write_kreg( dd, dd->ipath_kregs->kr_gpio_mask, val); | ||
1413 | /* | ||
1414 | * We might want to undo changes to debugportselect, | ||
1415 | * but how? | ||
1416 | */ | ||
1417 | } | ||
1404 | 1418 | ||
1405 | del_timer_sync(&dd->verbs_timer); | 1419 | del_timer_sync(&dd->verbs_timer); |
1406 | 1420 | ||