diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_debug.h | 15 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_diag.c | 3 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_driver.c | 18 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_init_chip.c | 36 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_intr.c | 21 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_kernel.h | 10 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_layer.c | 6 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_pe800.c | 4 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_registers.h | 31 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_ruc.c | 15 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_sysfs.c | 14 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_ud.c | 6 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_verbs.c | 39 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_verbs.h | 3 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ips_common.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_provider.c | 2 |
16 files changed, 131 insertions, 94 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/infiniband/hw/ipath/ipath_debug.h index 593e28969c69..46762387f5f8 100644 --- a/drivers/infiniband/hw/ipath/ipath_debug.h +++ b/drivers/infiniband/hw/ipath/ipath_debug.h | |||
@@ -60,11 +60,11 @@ | |||
60 | #define __IPATH_KERNEL_SEND 0x2000 /* use kernel mode send */ | 60 | #define __IPATH_KERNEL_SEND 0x2000 /* use kernel mode send */ |
61 | #define __IPATH_EPKTDBG 0x4000 /* print ethernet packet data */ | 61 | #define __IPATH_EPKTDBG 0x4000 /* print ethernet packet data */ |
62 | #define __IPATH_SMADBG 0x8000 /* sma packet debug */ | 62 | #define __IPATH_SMADBG 0x8000 /* sma packet debug */ |
63 | #define __IPATH_IPATHDBG 0x10000 /* Ethernet (IPATH) general debug on */ | 63 | #define __IPATH_IPATHDBG 0x10000 /* Ethernet (IPATH) gen debug */ |
64 | #define __IPATH_IPATHWARN 0x20000 /* Ethernet (IPATH) warnings on */ | 64 | #define __IPATH_IPATHWARN 0x20000 /* Ethernet (IPATH) warnings */ |
65 | #define __IPATH_IPATHERR 0x40000 /* Ethernet (IPATH) errors on */ | 65 | #define __IPATH_IPATHERR 0x40000 /* Ethernet (IPATH) errors */ |
66 | #define __IPATH_IPATHPD 0x80000 /* Ethernet (IPATH) packet dump on */ | 66 | #define __IPATH_IPATHPD 0x80000 /* Ethernet (IPATH) packet dump */ |
67 | #define __IPATH_IPATHTABLE 0x100000 /* Ethernet (IPATH) table dump on */ | 67 | #define __IPATH_IPATHTABLE 0x100000 /* Ethernet (IPATH) table dump */ |
68 | 68 | ||
69 | #else /* _IPATH_DEBUGGING */ | 69 | #else /* _IPATH_DEBUGGING */ |
70 | 70 | ||
@@ -79,11 +79,12 @@ | |||
79 | #define __IPATH_TRSAMPLE 0x0 /* generate trace buffer sample entries */ | 79 | #define __IPATH_TRSAMPLE 0x0 /* generate trace buffer sample entries */ |
80 | #define __IPATH_VERBDBG 0x0 /* very verbose debug */ | 80 | #define __IPATH_VERBDBG 0x0 /* very verbose debug */ |
81 | #define __IPATH_PKTDBG 0x0 /* print packet data */ | 81 | #define __IPATH_PKTDBG 0x0 /* print packet data */ |
82 | #define __IPATH_PROCDBG 0x0 /* print process startup (init)/exit messages */ | 82 | #define __IPATH_PROCDBG 0x0 /* process startup (init)/exit messages */ |
83 | /* print mmap/nopage stuff, not using VDBG any more */ | 83 | /* print mmap/nopage stuff, not using VDBG any more */ |
84 | #define __IPATH_MMDBG 0x0 | 84 | #define __IPATH_MMDBG 0x0 |
85 | #define __IPATH_EPKTDBG 0x0 /* print ethernet packet data */ | 85 | #define __IPATH_EPKTDBG 0x0 /* print ethernet packet data */ |
86 | #define __IPATH_SMADBG 0x0 /* print process startup (init)/exit messages */#define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */ | 86 | #define __IPATH_SMADBG 0x0 /* process startup (init)/exit messages */ |
87 | #define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */ | ||
87 | #define __IPATH_IPATHWARN 0x0 /* Ethernet (IPATH) warnings on */ | 88 | #define __IPATH_IPATHWARN 0x0 /* Ethernet (IPATH) warnings on */ |
88 | #define __IPATH_IPATHERR 0x0 /* Ethernet (IPATH) errors on */ | 89 | #define __IPATH_IPATHERR 0x0 /* Ethernet (IPATH) errors on */ |
89 | #define __IPATH_IPATHPD 0x0 /* Ethernet (IPATH) packet dump on */ | 90 | #define __IPATH_IPATHPD 0x0 /* Ethernet (IPATH) packet dump on */ |
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c index 7d3fb6996b41..28ddceb260e8 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c | |||
@@ -277,13 +277,14 @@ static int ipath_diag_open(struct inode *in, struct file *fp) | |||
277 | 277 | ||
278 | bail: | 278 | bail: |
279 | spin_unlock_irqrestore(&ipath_devs_lock, flags); | 279 | spin_unlock_irqrestore(&ipath_devs_lock, flags); |
280 | mutex_unlock(&ipath_mutex); | ||
281 | 280 | ||
282 | /* Only expose a way to reset the device if we | 281 | /* Only expose a way to reset the device if we |
283 | make it into diag mode. */ | 282 | make it into diag mode. */ |
284 | if (ret == 0) | 283 | if (ret == 0) |
285 | ipath_expose_reset(&dd->pcidev->dev); | 284 | ipath_expose_reset(&dd->pcidev->dev); |
286 | 285 | ||
286 | mutex_unlock(&ipath_mutex); | ||
287 | |||
287 | return ret; | 288 | return ret; |
288 | } | 289 | } |
289 | 290 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index e7617c3982ea..398add4d4cb1 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c | |||
@@ -418,9 +418,19 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, | |||
418 | 418 | ||
419 | ret = pci_set_dma_mask(pdev, DMA_64BIT_MASK); | 419 | ret = pci_set_dma_mask(pdev, DMA_64BIT_MASK); |
420 | if (ret) { | 420 | if (ret) { |
421 | dev_info(&pdev->dev, "pci_set_dma_mask unit %u " | 421 | /* |
422 | "fails: %d\n", dd->ipath_unit, ret); | 422 | * if the 64 bit setup fails, try 32 bit. Some systems |
423 | goto bail_regions; | 423 | * do not setup 64 bit maps on systems with 2GB or less |
424 | * memory installed. | ||
425 | */ | ||
426 | ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | ||
427 | if (ret) { | ||
428 | dev_info(&pdev->dev, "pci_set_dma_mask unit %u " | ||
429 | "fails: %d\n", dd->ipath_unit, ret); | ||
430 | goto bail_regions; | ||
431 | } | ||
432 | else | ||
433 | ipath_dbg("No 64bit DMA mask, used 32 bit mask\n"); | ||
424 | } | 434 | } |
425 | 435 | ||
426 | pci_set_master(pdev); | 436 | pci_set_master(pdev); |
@@ -1949,7 +1959,7 @@ int ipath_reset_device(int unit) | |||
1949 | } | 1959 | } |
1950 | 1960 | ||
1951 | if (dd->ipath_pd) | 1961 | if (dd->ipath_pd) |
1952 | for (i = 1; i < dd->ipath_portcnt; i++) { | 1962 | for (i = 1; i < dd->ipath_cfgports; i++) { |
1953 | if (dd->ipath_pd[i] && dd->ipath_pd[i]->port_cnt) { | 1963 | if (dd->ipath_pd[i] && dd->ipath_pd[i]->port_cnt) { |
1954 | ipath_dbg("unit %u port %d is in use " | 1964 | ipath_dbg("unit %u port %d is in use " |
1955 | "(PID %u cmd %s), can't reset\n", | 1965 | "(PID %u cmd %s), can't reset\n", |
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c index 2823ff9c0c62..16f640e1c16e 100644 --- a/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c | |||
@@ -53,13 +53,19 @@ MODULE_PARM_DESC(cfgports, "Set max number of ports to use"); | |||
53 | 53 | ||
54 | /* | 54 | /* |
55 | * Number of buffers reserved for driver (layered drivers and SMA | 55 | * Number of buffers reserved for driver (layered drivers and SMA |
56 | * send). Reserved at end of buffer list. | 56 | * send). Reserved at end of buffer list. Initialized based on |
57 | * number of PIO buffers if not set via module interface. | ||
58 | * The problem with this is that it's global, but we'll use different | ||
59 | * numbers for different chip types. So the default value is not | ||
60 | * very useful. I've redefined it for the 1.3 release so that it's | ||
61 | * zero unless set by the user to something else, in which case we | ||
62 | * try to respect it. | ||
57 | */ | 63 | */ |
58 | static ushort ipath_kpiobufs = 32; | 64 | static ushort ipath_kpiobufs; |
59 | 65 | ||
60 | static int ipath_set_kpiobufs(const char *val, struct kernel_param *kp); | 66 | static int ipath_set_kpiobufs(const char *val, struct kernel_param *kp); |
61 | 67 | ||
62 | module_param_call(kpiobufs, ipath_set_kpiobufs, param_get_uint, | 68 | module_param_call(kpiobufs, ipath_set_kpiobufs, param_get_ushort, |
63 | &ipath_kpiobufs, S_IWUSR | S_IRUGO); | 69 | &ipath_kpiobufs, S_IWUSR | S_IRUGO); |
64 | MODULE_PARM_DESC(kpiobufs, "Set number of PIO buffers for driver"); | 70 | MODULE_PARM_DESC(kpiobufs, "Set number of PIO buffers for driver"); |
65 | 71 | ||
@@ -531,8 +537,11 @@ static int init_housekeeping(struct ipath_devdata *dd, | |||
531 | * Don't clear ipath_flags as 8bit mode was set before | 537 | * Don't clear ipath_flags as 8bit mode was set before |
532 | * entering this func. However, we do set the linkstate to | 538 | * entering this func. However, we do set the linkstate to |
533 | * unknown, so we can watch for a transition. | 539 | * unknown, so we can watch for a transition. |
540 | * PRESENT is set because we want register reads to work, | ||
541 | * and the kernel infrastructure saw it in config space; | ||
542 | * We clear it if we have failures. | ||
534 | */ | 543 | */ |
535 | dd->ipath_flags |= IPATH_LINKUNK; | 544 | dd->ipath_flags |= IPATH_LINKUNK | IPATH_PRESENT; |
536 | dd->ipath_flags &= ~(IPATH_LINKACTIVE | IPATH_LINKARMED | | 545 | dd->ipath_flags &= ~(IPATH_LINKACTIVE | IPATH_LINKARMED | |
537 | IPATH_LINKDOWN | IPATH_LINKINIT); | 546 | IPATH_LINKDOWN | IPATH_LINKINIT); |
538 | 547 | ||
@@ -560,6 +569,7 @@ static int init_housekeeping(struct ipath_devdata *dd, | |||
560 | || (dd->ipath_uregbase & 0xffffffff) == 0xffffffff) { | 569 | || (dd->ipath_uregbase & 0xffffffff) == 0xffffffff) { |
561 | ipath_dev_err(dd, "Register read failures from chip, " | 570 | ipath_dev_err(dd, "Register read failures from chip, " |
562 | "giving up initialization\n"); | 571 | "giving up initialization\n"); |
572 | dd->ipath_flags &= ~IPATH_PRESENT; | ||
563 | ret = -ENODEV; | 573 | ret = -ENODEV; |
564 | goto done; | 574 | goto done; |
565 | } | 575 | } |
@@ -682,16 +692,14 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) | |||
682 | */ | 692 | */ |
683 | dd->ipath_pioavregs = ALIGN(val, sizeof(u64) * BITS_PER_BYTE / 2) | 693 | dd->ipath_pioavregs = ALIGN(val, sizeof(u64) * BITS_PER_BYTE / 2) |
684 | / (sizeof(u64) * BITS_PER_BYTE / 2); | 694 | / (sizeof(u64) * BITS_PER_BYTE / 2); |
685 | if (!ipath_kpiobufs) /* have to have at least 1, for SMA */ | 695 | if (ipath_kpiobufs == 0) { |
686 | kpiobufs = ipath_kpiobufs = 1; | 696 | /* not set by user, or set explictly to default */ |
687 | else if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) < | 697 | if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) > 128) |
688 | (dd->ipath_cfgports * IPATH_MIN_USER_PORT_BUFCNT)) { | 698 | kpiobufs = 32; |
689 | dev_info(&dd->pcidev->dev, "Too few PIO buffers (%u) " | 699 | else |
690 | "for %u ports to have %u each!\n", | 700 | kpiobufs = 16; |
691 | dd->ipath_piobcnt2k + dd->ipath_piobcnt4k, | 701 | } |
692 | dd->ipath_cfgports, IPATH_MIN_USER_PORT_BUFCNT); | 702 | else |
693 | kpiobufs = 1; /* reserve just the minimum for SMA/ether */ | ||
694 | } else | ||
695 | kpiobufs = ipath_kpiobufs; | 703 | kpiobufs = ipath_kpiobufs; |
696 | 704 | ||
697 | if (kpiobufs > | 705 | if (kpiobufs > |
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 0bcb428041f3..3e72a1fe3d73 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c | |||
@@ -665,14 +665,14 @@ static void handle_layer_pioavail(struct ipath_devdata *dd) | |||
665 | 665 | ||
666 | ret = __ipath_layer_intr(dd, IPATH_LAYER_INT_SEND_CONTINUE); | 666 | ret = __ipath_layer_intr(dd, IPATH_LAYER_INT_SEND_CONTINUE); |
667 | if (ret > 0) | 667 | if (ret > 0) |
668 | goto clear; | 668 | goto set; |
669 | 669 | ||
670 | ret = __ipath_verbs_piobufavail(dd); | 670 | ret = __ipath_verbs_piobufavail(dd); |
671 | if (ret > 0) | 671 | if (ret > 0) |
672 | goto clear; | 672 | goto set; |
673 | 673 | ||
674 | return; | 674 | return; |
675 | clear: | 675 | set: |
676 | set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); | 676 | set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); |
677 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | 677 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, |
678 | dd->ipath_sendctrl); | 678 | dd->ipath_sendctrl); |
@@ -719,11 +719,24 @@ static void handle_rcv(struct ipath_devdata *dd, u32 istat) | |||
719 | irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs) | 719 | irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs) |
720 | { | 720 | { |
721 | struct ipath_devdata *dd = data; | 721 | struct ipath_devdata *dd = data; |
722 | u32 istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus); | 722 | u32 istat; |
723 | ipath_err_t estat = 0; | 723 | ipath_err_t estat = 0; |
724 | static unsigned unexpected = 0; | 724 | static unsigned unexpected = 0; |
725 | irqreturn_t ret; | 725 | irqreturn_t ret; |
726 | 726 | ||
727 | if(!(dd->ipath_flags & IPATH_PRESENT)) { | ||
728 | /* this is mostly so we don't try to touch the chip while | ||
729 | * it is being reset */ | ||
730 | /* | ||
731 | * This return value is perhaps odd, but we do not want the | ||
732 | * interrupt core code to remove our interrupt handler | ||
733 | * because we don't appear to be handling an interrupt | ||
734 | * during a chip reset. | ||
735 | */ | ||
736 | return IRQ_HANDLED; | ||
737 | } | ||
738 | |||
739 | istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus); | ||
727 | if (unlikely(!istat)) { | 740 | if (unlikely(!istat)) { |
728 | ipath_stats.sps_nullintr++; | 741 | ipath_stats.sps_nullintr++; |
729 | ret = IRQ_NONE; /* not our interrupt, or already handled */ | 742 | ret = IRQ_NONE; /* not our interrupt, or already handled */ |
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 0ce5f19c9d62..e6507f8115bc 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h | |||
@@ -731,7 +731,7 @@ u64 ipath_read_kreg64_port(const struct ipath_devdata *, ipath_kreg, | |||
731 | static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd, | 731 | static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd, |
732 | ipath_ureg regno, int port) | 732 | ipath_ureg regno, int port) |
733 | { | 733 | { |
734 | if (!dd->ipath_kregbase) | 734 | if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) |
735 | return 0; | 735 | return 0; |
736 | 736 | ||
737 | return readl(regno + (u64 __iomem *) | 737 | return readl(regno + (u64 __iomem *) |
@@ -762,7 +762,7 @@ static inline void ipath_write_ureg(const struct ipath_devdata *dd, | |||
762 | static inline u32 ipath_read_kreg32(const struct ipath_devdata *dd, | 762 | static inline u32 ipath_read_kreg32(const struct ipath_devdata *dd, |
763 | ipath_kreg regno) | 763 | ipath_kreg regno) |
764 | { | 764 | { |
765 | if (!dd->ipath_kregbase) | 765 | if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) |
766 | return -1; | 766 | return -1; |
767 | return readl((u32 __iomem *) & dd->ipath_kregbase[regno]); | 767 | return readl((u32 __iomem *) & dd->ipath_kregbase[regno]); |
768 | } | 768 | } |
@@ -770,7 +770,7 @@ static inline u32 ipath_read_kreg32(const struct ipath_devdata *dd, | |||
770 | static inline u64 ipath_read_kreg64(const struct ipath_devdata *dd, | 770 | static inline u64 ipath_read_kreg64(const struct ipath_devdata *dd, |
771 | ipath_kreg regno) | 771 | ipath_kreg regno) |
772 | { | 772 | { |
773 | if (!dd->ipath_kregbase) | 773 | if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) |
774 | return -1; | 774 | return -1; |
775 | 775 | ||
776 | return readq(&dd->ipath_kregbase[regno]); | 776 | return readq(&dd->ipath_kregbase[regno]); |
@@ -786,7 +786,7 @@ static inline void ipath_write_kreg(const struct ipath_devdata *dd, | |||
786 | static inline u64 ipath_read_creg(const struct ipath_devdata *dd, | 786 | static inline u64 ipath_read_creg(const struct ipath_devdata *dd, |
787 | ipath_sreg regno) | 787 | ipath_sreg regno) |
788 | { | 788 | { |
789 | if (!dd->ipath_kregbase) | 789 | if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) |
790 | return 0; | 790 | return 0; |
791 | 791 | ||
792 | return readq(regno + (u64 __iomem *) | 792 | return readq(regno + (u64 __iomem *) |
@@ -797,7 +797,7 @@ static inline u64 ipath_read_creg(const struct ipath_devdata *dd, | |||
797 | static inline u32 ipath_read_creg32(const struct ipath_devdata *dd, | 797 | static inline u32 ipath_read_creg32(const struct ipath_devdata *dd, |
798 | ipath_sreg regno) | 798 | ipath_sreg regno) |
799 | { | 799 | { |
800 | if (!dd->ipath_kregbase) | 800 | if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) |
801 | return 0; | 801 | return 0; |
802 | return readl(regno + (u64 __iomem *) | 802 | return readl(regno + (u64 __iomem *) |
803 | (dd->ipath_cregbase + | 803 | (dd->ipath_cregbase + |
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c index 69ed1100701a..9cb5258ffed9 100644 --- a/drivers/infiniband/hw/ipath/ipath_layer.c +++ b/drivers/infiniband/hw/ipath/ipath_layer.c | |||
@@ -46,13 +46,15 @@ | |||
46 | /* Acquire before ipath_devs_lock. */ | 46 | /* Acquire before ipath_devs_lock. */ |
47 | static DEFINE_MUTEX(ipath_layer_mutex); | 47 | static DEFINE_MUTEX(ipath_layer_mutex); |
48 | 48 | ||
49 | static int ipath_verbs_registered; | ||
50 | |||
49 | u16 ipath_layer_rcv_opcode; | 51 | u16 ipath_layer_rcv_opcode; |
52 | |||
50 | static int (*layer_intr)(void *, u32); | 53 | static int (*layer_intr)(void *, u32); |
51 | static int (*layer_rcv)(void *, void *, struct sk_buff *); | 54 | static int (*layer_rcv)(void *, void *, struct sk_buff *); |
52 | static int (*layer_rcv_lid)(void *, void *); | 55 | static int (*layer_rcv_lid)(void *, void *); |
53 | static int (*verbs_piobufavail)(void *); | 56 | static int (*verbs_piobufavail)(void *); |
54 | static void (*verbs_rcv)(void *, void *, void *, u32); | 57 | static void (*verbs_rcv)(void *, void *, void *, u32); |
55 | static int ipath_verbs_registered; | ||
56 | 58 | ||
57 | static void *(*layer_add_one)(int, struct ipath_devdata *); | 59 | static void *(*layer_add_one)(int, struct ipath_devdata *); |
58 | static void (*layer_remove_one)(void *); | 60 | static void (*layer_remove_one)(void *); |
@@ -586,6 +588,8 @@ void ipath_verbs_unregister(void) | |||
586 | verbs_rcv = NULL; | 588 | verbs_rcv = NULL; |
587 | verbs_timer_cb = NULL; | 589 | verbs_timer_cb = NULL; |
588 | 590 | ||
591 | ipath_verbs_registered = 0; | ||
592 | |||
589 | mutex_unlock(&ipath_layer_mutex); | 593 | mutex_unlock(&ipath_layer_mutex); |
590 | } | 594 | } |
591 | 595 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_pe800.c b/drivers/infiniband/hw/ipath/ipath_pe800.c index e1dc4f757062..6318067ab5ec 100644 --- a/drivers/infiniband/hw/ipath/ipath_pe800.c +++ b/drivers/infiniband/hw/ipath/ipath_pe800.c | |||
@@ -972,6 +972,8 @@ static int ipath_setup_pe_reset(struct ipath_devdata *dd) | |||
972 | /* Use ERROR so it shows up in logs, etc. */ | 972 | /* Use ERROR so it shows up in logs, etc. */ |
973 | ipath_dev_err(dd, "Resetting PE-800 unit %u\n", | 973 | ipath_dev_err(dd, "Resetting PE-800 unit %u\n", |
974 | dd->ipath_unit); | 974 | dd->ipath_unit); |
975 | /* keep chip from being accessed in a few places */ | ||
976 | dd->ipath_flags &= ~(IPATH_INITTED|IPATH_PRESENT); | ||
975 | val = dd->ipath_control | INFINIPATH_C_RESET; | 977 | val = dd->ipath_control | INFINIPATH_C_RESET; |
976 | ipath_write_kreg(dd, dd->ipath_kregs->kr_control, val); | 978 | ipath_write_kreg(dd, dd->ipath_kregs->kr_control, val); |
977 | mb(); | 979 | mb(); |
@@ -997,6 +999,8 @@ static int ipath_setup_pe_reset(struct ipath_devdata *dd) | |||
997 | if ((r = pci_enable_device(dd->pcidev))) | 999 | if ((r = pci_enable_device(dd->pcidev))) |
998 | ipath_dev_err(dd, "pci_enable_device failed after " | 1000 | ipath_dev_err(dd, "pci_enable_device failed after " |
999 | "reset: %d\n", r); | 1001 | "reset: %d\n", r); |
1002 | /* whether it worked or not, mark as present, again */ | ||
1003 | dd->ipath_flags |= IPATH_PRESENT; | ||
1000 | val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision); | 1004 | val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision); |
1001 | if (val == dd->ipath_revision) { | 1005 | if (val == dd->ipath_revision) { |
1002 | ipath_cdbg(VERBOSE, "Got matching revision " | 1006 | ipath_cdbg(VERBOSE, "Got matching revision " |
diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h index 1e59750c5f63..402126eb79c9 100644 --- a/drivers/infiniband/hw/ipath/ipath_registers.h +++ b/drivers/infiniband/hw/ipath/ipath_registers.h | |||
@@ -34,8 +34,9 @@ | |||
34 | #define _IPATH_REGISTERS_H | 34 | #define _IPATH_REGISTERS_H |
35 | 35 | ||
36 | /* | 36 | /* |
37 | * This file should only be included by kernel source, and by the diags. | 37 | * This file should only be included by kernel source, and by the diags. It |
38 | * It defines the registers, and their contents, for the InfiniPath HT-400 chip | 38 | * defines the registers, and their contents, for the InfiniPath HT-400 |
39 | * chip. | ||
39 | */ | 40 | */ |
40 | 41 | ||
41 | /* | 42 | /* |
@@ -156,8 +157,10 @@ | |||
156 | #define INFINIPATH_IBCC_FLOWCTRLWATERMARK_SHIFT 8 | 157 | #define INFINIPATH_IBCC_FLOWCTRLWATERMARK_SHIFT 8 |
157 | #define INFINIPATH_IBCC_LINKINITCMD_MASK 0x3ULL | 158 | #define INFINIPATH_IBCC_LINKINITCMD_MASK 0x3ULL |
158 | #define INFINIPATH_IBCC_LINKINITCMD_DISABLE 1 | 159 | #define INFINIPATH_IBCC_LINKINITCMD_DISABLE 1 |
159 | #define INFINIPATH_IBCC_LINKINITCMD_POLL 2 /* cycle through TS1/TS2 till OK */ | 160 | /* cycle through TS1/TS2 till OK */ |
160 | #define INFINIPATH_IBCC_LINKINITCMD_SLEEP 3 /* wait for TS1, then go on */ | 161 | #define INFINIPATH_IBCC_LINKINITCMD_POLL 2 |
162 | /* wait for TS1, then go on */ | ||
163 | #define INFINIPATH_IBCC_LINKINITCMD_SLEEP 3 | ||
161 | #define INFINIPATH_IBCC_LINKINITCMD_SHIFT 16 | 164 | #define INFINIPATH_IBCC_LINKINITCMD_SHIFT 16 |
162 | #define INFINIPATH_IBCC_LINKCMD_MASK 0x3ULL | 165 | #define INFINIPATH_IBCC_LINKCMD_MASK 0x3ULL |
163 | #define INFINIPATH_IBCC_LINKCMD_INIT 1 /* move to 0x11 */ | 166 | #define INFINIPATH_IBCC_LINKCMD_INIT 1 /* move to 0x11 */ |
@@ -182,7 +185,8 @@ | |||
182 | #define INFINIPATH_IBCS_LINKSTATE_SHIFT 4 | 185 | #define INFINIPATH_IBCS_LINKSTATE_SHIFT 4 |
183 | #define INFINIPATH_IBCS_TXREADY 0x40000000 | 186 | #define INFINIPATH_IBCS_TXREADY 0x40000000 |
184 | #define INFINIPATH_IBCS_TXCREDITOK 0x80000000 | 187 | #define INFINIPATH_IBCS_TXCREDITOK 0x80000000 |
185 | /* link training states (shift by INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) */ | 188 | /* link training states (shift by |
189 | INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) */ | ||
186 | #define INFINIPATH_IBCS_LT_STATE_DISABLED 0x00 | 190 | #define INFINIPATH_IBCS_LT_STATE_DISABLED 0x00 |
187 | #define INFINIPATH_IBCS_LT_STATE_LINKUP 0x01 | 191 | #define INFINIPATH_IBCS_LT_STATE_LINKUP 0x01 |
188 | #define INFINIPATH_IBCS_LT_STATE_POLLACTIVE 0x02 | 192 | #define INFINIPATH_IBCS_LT_STATE_POLLACTIVE 0x02 |
@@ -267,10 +271,12 @@ | |||
267 | /* kr_serdesconfig0 bits */ | 271 | /* kr_serdesconfig0 bits */ |
268 | #define INFINIPATH_SERDC0_RESET_MASK 0xfULL /* overal reset bits */ | 272 | #define INFINIPATH_SERDC0_RESET_MASK 0xfULL /* overal reset bits */ |
269 | #define INFINIPATH_SERDC0_RESET_PLL 0x10000000ULL /* pll reset */ | 273 | #define INFINIPATH_SERDC0_RESET_PLL 0x10000000ULL /* pll reset */ |
270 | #define INFINIPATH_SERDC0_TXIDLE 0xF000ULL /* tx idle enables (per lane) */ | 274 | /* tx idle enables (per lane) */ |
271 | #define INFINIPATH_SERDC0_RXDETECT_EN 0xF0000ULL /* rx detect enables (per lane) */ | 275 | #define INFINIPATH_SERDC0_TXIDLE 0xF000ULL |
272 | #define INFINIPATH_SERDC0_L1PWR_DN 0xF0ULL /* L1 Power down; use with RXDETECT, | 276 | /* rx detect enables (per lane) */ |
273 | Otherwise not used on IB side */ | 277 | #define INFINIPATH_SERDC0_RXDETECT_EN 0xF0000ULL |
278 | /* L1 Power down; use with RXDETECT, Otherwise not used on IB side */ | ||
279 | #define INFINIPATH_SERDC0_L1PWR_DN 0xF0ULL | ||
274 | 280 | ||
275 | /* kr_xgxsconfig bits */ | 281 | /* kr_xgxsconfig bits */ |
276 | #define INFINIPATH_XGXS_RESET 0x7ULL | 282 | #define INFINIPATH_XGXS_RESET 0x7ULL |
@@ -390,12 +396,13 @@ struct ipath_kregs { | |||
390 | ipath_kreg kr_txintmemsize; | 396 | ipath_kreg kr_txintmemsize; |
391 | ipath_kreg kr_xgxsconfig; | 397 | ipath_kreg kr_xgxsconfig; |
392 | ipath_kreg kr_ibpllcfg; | 398 | ipath_kreg kr_ibpllcfg; |
393 | /* use these two (and the following N ports) only with ipath_k*_kreg64_port(); | 399 | /* use these two (and the following N ports) only with |
394 | * not *kreg64() */ | 400 | * ipath_k*_kreg64_port(); not *kreg64() */ |
395 | ipath_kreg kr_rcvhdraddr; | 401 | ipath_kreg kr_rcvhdraddr; |
396 | ipath_kreg kr_rcvhdrtailaddr; | 402 | ipath_kreg kr_rcvhdrtailaddr; |
397 | 403 | ||
398 | /* remaining registers are not present on all types of infinipath chips */ | 404 | /* remaining registers are not present on all types of infinipath |
405 | chips */ | ||
399 | ipath_kreg kr_rcvpktledcnt; | 406 | ipath_kreg kr_rcvpktledcnt; |
400 | ipath_kreg kr_pcierbuftestreg0; | 407 | ipath_kreg kr_pcierbuftestreg0; |
401 | ipath_kreg kr_pcierbuftestreg1; | 408 | ipath_kreg kr_pcierbuftestreg1; |
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c index f232e77b78ee..eb81424b3c5b 100644 --- a/drivers/infiniband/hw/ipath/ipath_ruc.c +++ b/drivers/infiniband/hw/ipath/ipath_ruc.c | |||
@@ -531,19 +531,12 @@ int ipath_post_rc_send(struct ipath_qp *qp, struct ib_send_wr *wr) | |||
531 | } | 531 | } |
532 | wqe->wr.num_sge = j; | 532 | wqe->wr.num_sge = j; |
533 | qp->s_head = next; | 533 | qp->s_head = next; |
534 | /* | ||
535 | * Wake up the send tasklet if the QP is not waiting | ||
536 | * for an RNR timeout. | ||
537 | */ | ||
538 | next = qp->s_rnr_timeout; | ||
539 | spin_unlock_irqrestore(&qp->s_lock, flags); | 534 | spin_unlock_irqrestore(&qp->s_lock, flags); |
540 | 535 | ||
541 | if (next == 0) { | 536 | if (qp->ibqp.qp_type == IB_QPT_UC) |
542 | if (qp->ibqp.qp_type == IB_QPT_UC) | 537 | ipath_do_uc_send((unsigned long) qp); |
543 | ipath_do_uc_send((unsigned long) qp); | 538 | else |
544 | else | 539 | ipath_do_rc_send((unsigned long) qp); |
545 | ipath_do_rc_send((unsigned long) qp); | ||
546 | } | ||
547 | 540 | ||
548 | ret = 0; | 541 | ret = 0; |
549 | 542 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c index 32acd8048b49..f323791cc495 100644 --- a/drivers/infiniband/hw/ipath/ipath_sysfs.c +++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c | |||
@@ -711,10 +711,22 @@ static struct attribute_group dev_attr_group = { | |||
711 | * enters diag mode. A device reset is quite likely to crash the | 711 | * enters diag mode. A device reset is quite likely to crash the |
712 | * machine entirely, so we don't want to normally make it | 712 | * machine entirely, so we don't want to normally make it |
713 | * available. | 713 | * available. |
714 | * | ||
715 | * Called with ipath_mutex held. | ||
714 | */ | 716 | */ |
715 | int ipath_expose_reset(struct device *dev) | 717 | int ipath_expose_reset(struct device *dev) |
716 | { | 718 | { |
717 | return device_create_file(dev, &dev_attr_reset); | 719 | static int exposed; |
720 | int ret; | ||
721 | |||
722 | if (!exposed) { | ||
723 | ret = device_create_file(dev, &dev_attr_reset); | ||
724 | exposed = 1; | ||
725 | } | ||
726 | else | ||
727 | ret = 0; | ||
728 | |||
729 | return ret; | ||
718 | } | 730 | } |
719 | 731 | ||
720 | int ipath_driver_create_group(struct device_driver *drv) | 732 | int ipath_driver_create_group(struct device_driver *drv) |
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c index 01cfb30ee160..e606daf83210 100644 --- a/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/drivers/infiniband/hw/ipath/ipath_ud.c | |||
@@ -46,8 +46,10 @@ | |||
46 | * This is called from ipath_post_ud_send() to forward a WQE addressed | 46 | * This is called from ipath_post_ud_send() to forward a WQE addressed |
47 | * to the same HCA. | 47 | * to the same HCA. |
48 | */ | 48 | */ |
49 | static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_sge_state *ss, | 49 | static void ipath_ud_loopback(struct ipath_qp *sqp, |
50 | u32 length, struct ib_send_wr *wr, struct ib_wc *wc) | 50 | struct ipath_sge_state *ss, |
51 | u32 length, struct ib_send_wr *wr, | ||
52 | struct ib_wc *wc) | ||
51 | { | 53 | { |
52 | struct ipath_ibdev *dev = to_idev(sqp->ibqp.device); | 54 | struct ipath_ibdev *dev = to_idev(sqp->ibqp.device); |
53 | struct ipath_qp *qp; | 55 | struct ipath_qp *qp; |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 8d2558a01f35..cb9e387c301f 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c | |||
@@ -449,7 +449,6 @@ static void ipath_ib_timer(void *arg) | |||
449 | { | 449 | { |
450 | struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; | 450 | struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; |
451 | struct ipath_qp *resend = NULL; | 451 | struct ipath_qp *resend = NULL; |
452 | struct ipath_qp *rnr = NULL; | ||
453 | struct list_head *last; | 452 | struct list_head *last; |
454 | struct ipath_qp *qp; | 453 | struct ipath_qp *qp; |
455 | unsigned long flags; | 454 | unsigned long flags; |
@@ -465,32 +464,18 @@ static void ipath_ib_timer(void *arg) | |||
465 | last = &dev->pending[dev->pending_index]; | 464 | last = &dev->pending[dev->pending_index]; |
466 | while (!list_empty(last)) { | 465 | while (!list_empty(last)) { |
467 | qp = list_entry(last->next, struct ipath_qp, timerwait); | 466 | qp = list_entry(last->next, struct ipath_qp, timerwait); |
468 | if (last->next == LIST_POISON1 || | 467 | list_del(&qp->timerwait); |
469 | last->next != &qp->timerwait || | 468 | qp->timer_next = resend; |
470 | qp->timerwait.prev != last) { | 469 | resend = qp; |
471 | INIT_LIST_HEAD(last); | 470 | atomic_inc(&qp->refcount); |
472 | } else { | ||
473 | list_del(&qp->timerwait); | ||
474 | qp->timerwait.prev = (struct list_head *) resend; | ||
475 | resend = qp; | ||
476 | atomic_inc(&qp->refcount); | ||
477 | } | ||
478 | } | 471 | } |
479 | last = &dev->rnrwait; | 472 | last = &dev->rnrwait; |
480 | if (!list_empty(last)) { | 473 | if (!list_empty(last)) { |
481 | qp = list_entry(last->next, struct ipath_qp, timerwait); | 474 | qp = list_entry(last->next, struct ipath_qp, timerwait); |
482 | if (--qp->s_rnr_timeout == 0) { | 475 | if (--qp->s_rnr_timeout == 0) { |
483 | do { | 476 | do { |
484 | if (last->next == LIST_POISON1 || | ||
485 | last->next != &qp->timerwait || | ||
486 | qp->timerwait.prev != last) { | ||
487 | INIT_LIST_HEAD(last); | ||
488 | break; | ||
489 | } | ||
490 | list_del(&qp->timerwait); | 477 | list_del(&qp->timerwait); |
491 | qp->timerwait.prev = | 478 | tasklet_hi_schedule(&qp->s_task); |
492 | (struct list_head *) rnr; | ||
493 | rnr = qp; | ||
494 | if (list_empty(last)) | 479 | if (list_empty(last)) |
495 | break; | 480 | break; |
496 | qp = list_entry(last->next, struct ipath_qp, | 481 | qp = list_entry(last->next, struct ipath_qp, |
@@ -530,8 +515,7 @@ static void ipath_ib_timer(void *arg) | |||
530 | spin_unlock_irqrestore(&dev->pending_lock, flags); | 515 | spin_unlock_irqrestore(&dev->pending_lock, flags); |
531 | 516 | ||
532 | /* XXX What if timer fires again while this is running? */ | 517 | /* XXX What if timer fires again while this is running? */ |
533 | for (qp = resend; qp != NULL; | 518 | for (qp = resend; qp != NULL; qp = qp->timer_next) { |
534 | qp = (struct ipath_qp *) qp->timerwait.prev) { | ||
535 | struct ib_wc wc; | 519 | struct ib_wc wc; |
536 | 520 | ||
537 | spin_lock_irqsave(&qp->s_lock, flags); | 521 | spin_lock_irqsave(&qp->s_lock, flags); |
@@ -545,9 +529,6 @@ static void ipath_ib_timer(void *arg) | |||
545 | if (atomic_dec_and_test(&qp->refcount)) | 529 | if (atomic_dec_and_test(&qp->refcount)) |
546 | wake_up(&qp->wait); | 530 | wake_up(&qp->wait); |
547 | } | 531 | } |
548 | for (qp = rnr; qp != NULL; | ||
549 | qp = (struct ipath_qp *) qp->timerwait.prev) | ||
550 | tasklet_hi_schedule(&qp->s_task); | ||
551 | } | 532 | } |
552 | 533 | ||
553 | /** | 534 | /** |
@@ -556,9 +537,9 @@ static void ipath_ib_timer(void *arg) | |||
556 | * | 537 | * |
557 | * This is called from ipath_intr() at interrupt level when a PIO buffer is | 538 | * This is called from ipath_intr() at interrupt level when a PIO buffer is |
558 | * available after ipath_verbs_send() returned an error that no buffers were | 539 | * available after ipath_verbs_send() returned an error that no buffers were |
559 | * available. Return 0 if we consumed all the PIO buffers and we still have | 540 | * available. Return 1 if we consumed all the PIO buffers and we still have |
560 | * QPs waiting for buffers (for now, just do a tasklet_hi_schedule and | 541 | * QPs waiting for buffers (for now, just do a tasklet_hi_schedule and |
561 | * return one). | 542 | * return zero). |
562 | */ | 543 | */ |
563 | static int ipath_ib_piobufavail(void *arg) | 544 | static int ipath_ib_piobufavail(void *arg) |
564 | { | 545 | { |
@@ -579,7 +560,7 @@ static int ipath_ib_piobufavail(void *arg) | |||
579 | spin_unlock_irqrestore(&dev->pending_lock, flags); | 560 | spin_unlock_irqrestore(&dev->pending_lock, flags); |
580 | 561 | ||
581 | bail: | 562 | bail: |
582 | return 1; | 563 | return 0; |
583 | } | 564 | } |
584 | 565 | ||
585 | static int ipath_query_device(struct ib_device *ibdev, | 566 | static int ipath_query_device(struct ib_device *ibdev, |
@@ -1159,7 +1140,7 @@ static ssize_t show_stats(struct class_device *cdev, char *buf) | |||
1159 | 1140 | ||
1160 | len = sprintf(buf, | 1141 | len = sprintf(buf, |
1161 | "RC resends %d\n" | 1142 | "RC resends %d\n" |
1162 | "RC QACKs %d\n" | 1143 | "RC no QACK %d\n" |
1163 | "RC ACKs %d\n" | 1144 | "RC ACKs %d\n" |
1164 | "RC SEQ NAKs %d\n" | 1145 | "RC SEQ NAKs %d\n" |
1165 | "RC RDMA seq %d\n" | 1146 | "RC RDMA seq %d\n" |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index fcafbc7c9e71..4f8d59300e9b 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h | |||
@@ -282,7 +282,8 @@ struct ipath_srq { | |||
282 | */ | 282 | */ |
283 | struct ipath_qp { | 283 | struct ipath_qp { |
284 | struct ib_qp ibqp; | 284 | struct ib_qp ibqp; |
285 | struct ipath_qp *next; /* link list for QPN hash table */ | 285 | struct ipath_qp *next; /* link list for QPN hash table */ |
286 | struct ipath_qp *timer_next; /* link list for ipath_ib_timer() */ | ||
286 | struct list_head piowait; /* link for wait PIO buf */ | 287 | struct list_head piowait; /* link for wait PIO buf */ |
287 | struct list_head timerwait; /* link for waiting for timeouts */ | 288 | struct list_head timerwait; /* link for waiting for timeouts */ |
288 | struct ib_ah_attr remote_ah_attr; | 289 | struct ib_ah_attr remote_ah_attr; |
diff --git a/drivers/infiniband/hw/ipath/ips_common.h b/drivers/infiniband/hw/ipath/ips_common.h index 410a764dfcef..ab7cbbbfd03a 100644 --- a/drivers/infiniband/hw/ipath/ips_common.h +++ b/drivers/infiniband/hw/ipath/ips_common.h | |||
@@ -95,7 +95,7 @@ struct ether_header { | |||
95 | __u8 seq_num; | 95 | __u8 seq_num; |
96 | __le32 len; | 96 | __le32 len; |
97 | /* MUST be of word size due to PIO write requirements */ | 97 | /* MUST be of word size due to PIO write requirements */ |
98 | __u32 csum; | 98 | __le32 csum; |
99 | __le16 csum_offset; | 99 | __le16 csum_offset; |
100 | __le16 flags; | 100 | __le16 flags; |
101 | __u16 first_2_bytes; | 101 | __u16 first_2_bytes; |
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 565a24b1756f..a2eae8a30167 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c | |||
@@ -306,7 +306,7 @@ static int mthca_query_gid(struct ib_device *ibdev, u8 port, | |||
306 | goto out; | 306 | goto out; |
307 | } | 307 | } |
308 | 308 | ||
309 | memcpy(gid->raw + 8, out_mad->data + (index % 8) * 16, 8); | 309 | memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8); |
310 | 310 | ||
311 | out: | 311 | out: |
312 | kfree(in_mad); | 312 | kfree(in_mad); |