aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Albaugh <michael.albaugh@qlogic.com>2007-05-16 18:45:09 -0400
committerRoland Dreier <rolandd@cisco.com>2007-07-09 23:12:25 -0400
commit82466f00ec6ef0a5ca7ea8991c731af2ec561c7d (patch)
tree48fcc8f78e6df67130e8c70b160fea42aeff79ca
parenta024291b367f98188f4da4a66a9f2f40a2163efb (diff)
IB/ipath: Support blinking LEDs with an led_override file
When we want to find an InfiniPath HCA in a rack of nodes, it is often expeditious to blink the status LEDs via a userspace /sys file. A write-only led_override "file" is published per device. Writes to this file are interpreted as (string form) numbers, and the resulting value sent to ipath_set_led_override(). The upper eight bits are interpretted as a 4.4 fixed-point "frequency in Hertz", and the bottom two 4-bit values are alternately (D0..3, then D4..7) used by the board-specific LED-setting function to override the normal state. Signed-off-by: Michael Albaugh <michael.albaugh@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c92
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c10
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6120.c10
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h19
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sysfs.c19
5 files changed, 149 insertions, 1 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index e3a223209710..097593286582 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -1846,6 +1846,87 @@ void ipath_write_kreg_port(const struct ipath_devdata *dd, ipath_kreg regno,
1846 ipath_write_kreg(dd, where, value); 1846 ipath_write_kreg(dd, where, value);
1847} 1847}
1848 1848
1849/*
1850 * Following deal with the "obviously simple" task of overriding the state
1851 * of the LEDS, which normally indicate link physical and logical status.
1852 * The complications arise in dealing with different hardware mappings
1853 * and the board-dependent routine being called from interrupts.
1854 * and then there's the requirement to _flash_ them.
1855 */
1856#define LED_OVER_FREQ_SHIFT 8
1857#define LED_OVER_FREQ_MASK (0xFF<<LED_OVER_FREQ_SHIFT)
1858/* Below is "non-zero" to force override, but both actual LEDs are off */
1859#define LED_OVER_BOTH_OFF (8)
1860
1861void ipath_run_led_override(unsigned long opaque)
1862{
1863 struct ipath_devdata *dd = (struct ipath_devdata *)opaque;
1864 int timeoff;
1865 int pidx;
1866 u64 lstate, ltstate, val;
1867
1868 if (!(dd->ipath_flags & IPATH_INITTED))
1869 return;
1870
1871 pidx = dd->ipath_led_override_phase++ & 1;
1872 dd->ipath_led_override = dd->ipath_led_override_vals[pidx];
1873 timeoff = dd->ipath_led_override_timeoff;
1874
1875 /*
1876 * below potentially restores the LED values per current status,
1877 * should also possibly setup the traffic-blink register,
1878 * but leave that to per-chip functions.
1879 */
1880 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
1881 ltstate = (val >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
1882 INFINIPATH_IBCS_LINKTRAININGSTATE_MASK;
1883 lstate = (val >> INFINIPATH_IBCS_LINKSTATE_SHIFT) &
1884 INFINIPATH_IBCS_LINKSTATE_MASK;
1885
1886 dd->ipath_f_setextled(dd, lstate, ltstate);
1887 mod_timer(&dd->ipath_led_override_timer, jiffies + timeoff);
1888}
1889
1890void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val)
1891{
1892 int timeoff, freq;
1893
1894 if (!(dd->ipath_flags & IPATH_INITTED))
1895 return;
1896
1897 /* First check if we are blinking. If not, use 1HZ polling */
1898 timeoff = HZ;
1899 freq = (val & LED_OVER_FREQ_MASK) >> LED_OVER_FREQ_SHIFT;
1900
1901 if (freq) {
1902 /* For blink, set each phase from one nybble of val */
1903 dd->ipath_led_override_vals[0] = val & 0xF;
1904 dd->ipath_led_override_vals[1] = (val >> 4) & 0xF;
1905 timeoff = (HZ << 4)/freq;
1906 } else {
1907 /* Non-blink set both phases the same. */
1908 dd->ipath_led_override_vals[0] = val & 0xF;
1909 dd->ipath_led_override_vals[1] = val & 0xF;
1910 }
1911 dd->ipath_led_override_timeoff = timeoff;
1912
1913 /*
1914 * If the timer has not already been started, do so. Use a "quick"
1915 * timeout so the function will be called soon, to look at our request.
1916 */
1917 if (atomic_inc_return(&dd->ipath_led_override_timer_active) == 1) {
1918 /* Need to start timer */
1919 init_timer(&dd->ipath_led_override_timer);
1920 dd->ipath_led_override_timer.function =
1921 ipath_run_led_override;
1922 dd->ipath_led_override_timer.data = (unsigned long) dd;
1923 dd->ipath_led_override_timer.expires = jiffies + 1;
1924 add_timer(&dd->ipath_led_override_timer);
1925 } else {
1926 atomic_dec(&dd->ipath_led_override_timer_active);
1927 }
1928}
1929
1849/** 1930/**
1850 * ipath_shutdown_device - shut down a device 1931 * ipath_shutdown_device - shut down a device
1851 * @dd: the infinipath device 1932 * @dd: the infinipath device
@@ -1909,7 +1990,6 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
1909 * Turn the LEDs off explictly for the same reason. 1990 * Turn the LEDs off explictly for the same reason.
1910 */ 1991 */
1911 dd->ipath_f_quiet_serdes(dd); 1992 dd->ipath_f_quiet_serdes(dd);
1912 dd->ipath_f_setextled(dd, 0, 0);
1913 1993
1914 if (dd->ipath_stats_timer_active) { 1994 if (dd->ipath_stats_timer_active) {
1915 del_timer_sync(&dd->ipath_stats_timer); 1995 del_timer_sync(&dd->ipath_stats_timer);
@@ -2085,6 +2165,16 @@ int ipath_reset_device(int unit)
2085 goto bail; 2165 goto bail;
2086 } 2166 }
2087 2167
2168 if (atomic_read(&dd->ipath_led_override_timer_active)) {
2169 /* Need to stop LED timer, _then_ shut off LEDs */
2170 del_timer_sync(&dd->ipath_led_override_timer);
2171 atomic_set(&dd->ipath_led_override_timer_active, 0);
2172 }
2173
2174 /* Shut off LEDs after we are sure timer is not running */
2175 dd->ipath_led_override = LED_OVER_BOTH_OFF;
2176 dd->ipath_f_setextled(dd, 0, 0);
2177
2088 dev_info(&dd->pcidev->dev, "Reset on unit %u requested\n", unit); 2178 dev_info(&dd->pcidev->dev, "Reset on unit %u requested\n", unit);
2089 2179
2090 if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) { 2180 if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) {
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index ba73dd0a06cd..4372c6c50ff6 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -1065,6 +1065,16 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
1065 if (ipath_diag_inuse) 1065 if (ipath_diag_inuse)
1066 return; 1066 return;
1067 1067
1068 /* Allow override of LED display for, e.g. Locating system in rack */
1069 if (dd->ipath_led_override) {
1070 ltst = (dd->ipath_led_override & IPATH_LED_PHYS)
1071 ? INFINIPATH_IBCS_LT_STATE_LINKUP
1072 : INFINIPATH_IBCS_LT_STATE_DISABLED;
1073 lst = (dd->ipath_led_override & IPATH_LED_LOG)
1074 ? INFINIPATH_IBCS_L_STATE_ACTIVE
1075 : INFINIPATH_IBCS_L_STATE_DOWN;
1076 }
1077
1068 /* 1078 /*
1069 * start by setting both LED control bits to off, then turn 1079 * start by setting both LED control bits to off, then turn
1070 * on the appropriate bit(s). 1080 * on the appropriate bit(s).
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
index 4e2e3dfeb2c8..bcb70d67dbb9 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6120.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
@@ -797,6 +797,16 @@ static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst,
797 if (ipath_diag_inuse) 797 if (ipath_diag_inuse)
798 return; 798 return;
799 799
800 /* Allow override of LED display for, e.g. Locating system in rack */
801 if (dd->ipath_led_override) {
802 ltst = (dd->ipath_led_override & IPATH_LED_PHYS)
803 ? INFINIPATH_IBCS_LT_STATE_LINKUP
804 : INFINIPATH_IBCS_LT_STATE_DISABLED;
805 lst = (dd->ipath_led_override & IPATH_LED_LOG)
806 ? INFINIPATH_IBCS_L_STATE_ACTIVE
807 : INFINIPATH_IBCS_L_STATE_DOWN;
808 }
809
800 extctl = dd->ipath_extctrl & ~(INFINIPATH_EXTC_LED1PRIPORT_ON | 810 extctl = dd->ipath_extctrl & ~(INFINIPATH_EXTC_LED1PRIPORT_ON |
801 INFINIPATH_EXTC_LED2PRIPORT_ON); 811 INFINIPATH_EXTC_LED2PRIPORT_ON);
802 812
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 12194f3dd8cc..2f39db7df31c 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -575,6 +575,16 @@ struct ipath_devdata {
575 u16 ipath_gpio_scl_num; 575 u16 ipath_gpio_scl_num;
576 u64 ipath_gpio_sda; 576 u64 ipath_gpio_sda;
577 u64 ipath_gpio_scl; 577 u64 ipath_gpio_scl;
578
579 /* used to override LED behavior */
580 u8 ipath_led_override; /* Substituted for normal value, if non-zero */
581 u16 ipath_led_override_timeoff; /* delta to next timer event */
582 u8 ipath_led_override_vals[2]; /* Alternates per blink-frame */
583 u8 ipath_led_override_phase; /* Just counts, LSB picks from vals[] */
584 atomic_t ipath_led_override_timer_active;
585 /* Used to flash LEDs in override mode */
586 struct timer_list ipath_led_override_timer;
587
578}; 588};
579 589
580/* Private data for file operations */ 590/* Private data for file operations */
@@ -717,6 +727,15 @@ u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg);
717void ipath_disarm_senderrbufs(struct ipath_devdata *, int); 727void ipath_disarm_senderrbufs(struct ipath_devdata *, int);
718 728
719/* 729/*
730 * Set LED override, only the two LSBs have "public" meaning, but
731 * any non-zero value substitutes them for the Link and LinkTrain
732 * LED states.
733 */
734#define IPATH_LED_PHYS 1 /* Physical (linktraining) GREEN LED */
735#define IPATH_LED_LOG 2 /* Logical (link) YELLOW LED */
736void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val);
737
738/*
720 * number of words used for protocol header if not set by ipath_userinit(); 739 * number of words used for protocol header if not set by ipath_userinit();
721 */ 740 */
722#define IPATH_DFLT_RCVHDRSIZE 9 741#define IPATH_DFLT_RCVHDRSIZE 9
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
index 4dc398d5e011..17ec14571722 100644
--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
@@ -596,6 +596,23 @@ bail:
596 return ret; 596 return ret;
597} 597}
598 598
599static ssize_t store_led_override(struct device *dev,
600 struct device_attribute *attr,
601 const char *buf,
602 size_t count)
603{
604 struct ipath_devdata *dd = dev_get_drvdata(dev);
605 int ret;
606 u16 val;
607
608 ret = ipath_parse_ushort(buf, &val);
609 if (ret > 0)
610 ipath_set_led_override(dd, val);
611 else
612 ipath_dev_err(dd, "attempt to set invalid LED override\n");
613 return ret;
614}
615
599 616
600static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL); 617static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL);
601static DRIVER_ATTR(version, S_IRUGO, show_version, NULL); 618static DRIVER_ATTR(version, S_IRUGO, show_version, NULL);
@@ -625,6 +642,7 @@ static DEVICE_ATTR(status_str, S_IRUGO, show_status_str, NULL);
625static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL); 642static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
626static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL); 643static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL);
627static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv); 644static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv);
645static DEVICE_ATTR(led_override, S_IWUSR, NULL, store_led_override);
628 646
629static struct attribute *dev_attributes[] = { 647static struct attribute *dev_attributes[] = {
630 &dev_attr_guid.attr, 648 &dev_attr_guid.attr,
@@ -641,6 +659,7 @@ static struct attribute *dev_attributes[] = {
641 &dev_attr_unit.attr, 659 &dev_attr_unit.attr,
642 &dev_attr_enabled.attr, 660 &dev_attr_enabled.attr,
643 &dev_attr_rx_pol_inv.attr, 661 &dev_attr_rx_pol_inv.attr,
662 &dev_attr_led_override.attr,
644 NULL 663 NULL
645}; 664};
646 665