diff options
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_eeprom.c | 68 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_iba6110.c | 3 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_iba6120.c | 3 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_init_chip.c | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_kernel.h | 7 |
5 files changed, 53 insertions, 30 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c index 030185f90ee2..26daac9d8b63 100644 --- a/drivers/infiniband/hw/ipath/ipath_eeprom.c +++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c | |||
@@ -95,39 +95,37 @@ static int i2c_gpio_set(struct ipath_devdata *dd, | |||
95 | enum i2c_type line, | 95 | enum i2c_type line, |
96 | enum i2c_state new_line_state) | 96 | enum i2c_state new_line_state) |
97 | { | 97 | { |
98 | u64 read_val, write_val, mask, *gpioval; | 98 | u64 out_mask, dir_mask, *gpioval; |
99 | unsigned long flags = 0; | ||
99 | 100 | ||
100 | gpioval = &dd->ipath_gpio_out; | 101 | gpioval = &dd->ipath_gpio_out; |
101 | read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl); | ||
102 | if (line == i2c_line_scl) | ||
103 | mask = dd->ipath_gpio_scl; | ||
104 | else | ||
105 | mask = dd->ipath_gpio_sda; | ||
106 | 102 | ||
107 | if (new_line_state == i2c_line_high) | 103 | if (line == i2c_line_scl) { |
104 | dir_mask = dd->ipath_gpio_scl; | ||
105 | out_mask = (1UL << dd->ipath_gpio_scl_num); | ||
106 | } else { | ||
107 | dir_mask = dd->ipath_gpio_sda; | ||
108 | out_mask = (1UL << dd->ipath_gpio_sda_num); | ||
109 | } | ||
110 | |||
111 | spin_lock_irqsave(&dd->ipath_gpio_lock, flags); | ||
112 | if (new_line_state == i2c_line_high) { | ||
108 | /* tri-state the output rather than force high */ | 113 | /* tri-state the output rather than force high */ |
109 | write_val = read_val & ~mask; | 114 | dd->ipath_extctrl &= ~dir_mask; |
110 | else | 115 | } else { |
111 | /* config line to be an output */ | 116 | /* config line to be an output */ |
112 | write_val = read_val | mask; | 117 | dd->ipath_extctrl |= dir_mask; |
113 | ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, write_val); | 118 | } |
119 | ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, dd->ipath_extctrl); | ||
114 | 120 | ||
115 | /* set high and verify */ | 121 | /* set output as well (no real verify) */ |
116 | if (new_line_state == i2c_line_high) | 122 | if (new_line_state == i2c_line_high) |
117 | write_val = 0x1UL; | 123 | *gpioval |= out_mask; |
118 | else | 124 | else |
119 | write_val = 0x0UL; | 125 | *gpioval &= ~out_mask; |
120 | 126 | ||
121 | if (line == i2c_line_scl) { | ||
122 | write_val <<= dd->ipath_gpio_scl_num; | ||
123 | *gpioval = *gpioval & ~(1UL << dd->ipath_gpio_scl_num); | ||
124 | *gpioval |= write_val; | ||
125 | } else { | ||
126 | write_val <<= dd->ipath_gpio_sda_num; | ||
127 | *gpioval = *gpioval & ~(1UL << dd->ipath_gpio_sda_num); | ||
128 | *gpioval |= write_val; | ||
129 | } | ||
130 | ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_out, *gpioval); | 127 | ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_out, *gpioval); |
128 | spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags); | ||
131 | 129 | ||
132 | return 0; | 130 | return 0; |
133 | } | 131 | } |
@@ -145,8 +143,9 @@ static int i2c_gpio_get(struct ipath_devdata *dd, | |||
145 | enum i2c_type line, | 143 | enum i2c_type line, |
146 | enum i2c_state *curr_statep) | 144 | enum i2c_state *curr_statep) |
147 | { | 145 | { |
148 | u64 read_val, write_val, mask; | 146 | u64 read_val, mask; |
149 | int ret; | 147 | int ret; |
148 | unsigned long flags = 0; | ||
150 | 149 | ||
151 | /* check args */ | 150 | /* check args */ |
152 | if (curr_statep == NULL) { | 151 | if (curr_statep == NULL) { |
@@ -154,15 +153,21 @@ static int i2c_gpio_get(struct ipath_devdata *dd, | |||
154 | goto bail; | 153 | goto bail; |
155 | } | 154 | } |
156 | 155 | ||
157 | read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl); | ||
158 | /* config line to be an input */ | 156 | /* config line to be an input */ |
159 | if (line == i2c_line_scl) | 157 | if (line == i2c_line_scl) |
160 | mask = dd->ipath_gpio_scl; | 158 | mask = dd->ipath_gpio_scl; |
161 | else | 159 | else |
162 | mask = dd->ipath_gpio_sda; | 160 | mask = dd->ipath_gpio_sda; |
163 | write_val = read_val & ~mask; | 161 | |
164 | ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, write_val); | 162 | spin_lock_irqsave(&dd->ipath_gpio_lock, flags); |
163 | dd->ipath_extctrl &= ~mask; | ||
164 | ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, dd->ipath_extctrl); | ||
165 | /* | ||
166 | * Below is very unlikely to reflect true input state if Output | ||
167 | * Enable actually changed. | ||
168 | */ | ||
165 | read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus); | 169 | read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus); |
170 | spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags); | ||
166 | 171 | ||
167 | if (read_val & mask) | 172 | if (read_val & mask) |
168 | *curr_statep = i2c_line_high; | 173 | *curr_statep = i2c_line_high; |
@@ -192,6 +197,7 @@ static void i2c_wait_for_writes(struct ipath_devdata *dd) | |||
192 | 197 | ||
193 | static void scl_out(struct ipath_devdata *dd, u8 bit) | 198 | static void scl_out(struct ipath_devdata *dd, u8 bit) |
194 | { | 199 | { |
200 | udelay(1); | ||
195 | i2c_gpio_set(dd, i2c_line_scl, bit ? i2c_line_high : i2c_line_low); | 201 | i2c_gpio_set(dd, i2c_line_scl, bit ? i2c_line_high : i2c_line_low); |
196 | 202 | ||
197 | i2c_wait_for_writes(dd); | 203 | i2c_wait_for_writes(dd); |
@@ -314,12 +320,18 @@ static int eeprom_reset(struct ipath_devdata *dd) | |||
314 | int clock_cycles_left = 9; | 320 | int clock_cycles_left = 9; |
315 | u64 *gpioval = &dd->ipath_gpio_out; | 321 | u64 *gpioval = &dd->ipath_gpio_out; |
316 | int ret; | 322 | int ret; |
323 | unsigned long flags; | ||
317 | 324 | ||
318 | eeprom_init = 1; | 325 | spin_lock_irqsave(&dd->ipath_gpio_lock, flags); |
326 | /* Make sure shadows are consistent */ | ||
327 | dd->ipath_extctrl = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl); | ||
319 | *gpioval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_out); | 328 | *gpioval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_out); |
329 | spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags); | ||
330 | |||
320 | ipath_cdbg(VERBOSE, "Resetting i2c eeprom; initial gpioout reg " | 331 | ipath_cdbg(VERBOSE, "Resetting i2c eeprom; initial gpioout reg " |
321 | "is %llx\n", (unsigned long long) *gpioval); | 332 | "is %llx\n", (unsigned long long) *gpioval); |
322 | 333 | ||
334 | eeprom_init = 1; | ||
323 | /* | 335 | /* |
324 | * This is to get the i2c into a known state, by first going low, | 336 | * This is to get the i2c into a known state, by first going low, |
325 | * then tristate sda (and then tristate scl as first thing | 337 | * then tristate sda (and then tristate scl as first thing |
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index 4372c6c50ff6..8482ea366fb1 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c | |||
@@ -1059,6 +1059,7 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd, | |||
1059 | u64 lst, u64 ltst) | 1059 | u64 lst, u64 ltst) |
1060 | { | 1060 | { |
1061 | u64 extctl; | 1061 | u64 extctl; |
1062 | unsigned long flags = 0; | ||
1062 | 1063 | ||
1063 | /* the diags use the LED to indicate diag info, so we leave | 1064 | /* the diags use the LED to indicate diag info, so we leave |
1064 | * the external LED alone when the diags are running */ | 1065 | * the external LED alone when the diags are running */ |
@@ -1075,6 +1076,7 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd, | |||
1075 | : INFINIPATH_IBCS_L_STATE_DOWN; | 1076 | : INFINIPATH_IBCS_L_STATE_DOWN; |
1076 | } | 1077 | } |
1077 | 1078 | ||
1079 | spin_lock_irqsave(&dd->ipath_gpio_lock, flags); | ||
1078 | /* | 1080 | /* |
1079 | * start by setting both LED control bits to off, then turn | 1081 | * start by setting both LED control bits to off, then turn |
1080 | * on the appropriate bit(s). | 1082 | * on the appropriate bit(s). |
@@ -1103,6 +1105,7 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd, | |||
1103 | } | 1105 | } |
1104 | dd->ipath_extctrl = extctl; | 1106 | dd->ipath_extctrl = extctl; |
1105 | ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl); | 1107 | ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl); |
1108 | spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags); | ||
1106 | } | 1109 | } |
1107 | 1110 | ||
1108 | static void ipath_init_ht_variables(struct ipath_devdata *dd) | 1111 | static void ipath_init_ht_variables(struct ipath_devdata *dd) |
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index bcb70d67dbb9..2345bb011acd 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c | |||
@@ -791,6 +791,7 @@ static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst, | |||
791 | u64 ltst) | 791 | u64 ltst) |
792 | { | 792 | { |
793 | u64 extctl; | 793 | u64 extctl; |
794 | unsigned long flags = 0; | ||
794 | 795 | ||
795 | /* the diags use the LED to indicate diag info, so we leave | 796 | /* the diags use the LED to indicate diag info, so we leave |
796 | * the external LED alone when the diags are running */ | 797 | * the external LED alone when the diags are running */ |
@@ -807,6 +808,7 @@ static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst, | |||
807 | : INFINIPATH_IBCS_L_STATE_DOWN; | 808 | : INFINIPATH_IBCS_L_STATE_DOWN; |
808 | } | 809 | } |
809 | 810 | ||
811 | spin_lock_irqsave(&dd->ipath_gpio_lock, flags); | ||
810 | extctl = dd->ipath_extctrl & ~(INFINIPATH_EXTC_LED1PRIPORT_ON | | 812 | extctl = dd->ipath_extctrl & ~(INFINIPATH_EXTC_LED1PRIPORT_ON | |
811 | INFINIPATH_EXTC_LED2PRIPORT_ON); | 813 | INFINIPATH_EXTC_LED2PRIPORT_ON); |
812 | 814 | ||
@@ -816,6 +818,7 @@ static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst, | |||
816 | extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON; | 818 | extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON; |
817 | dd->ipath_extctrl = extctl; | 819 | dd->ipath_extctrl = extctl; |
818 | ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl); | 820 | ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl); |
821 | spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags); | ||
819 | } | 822 | } |
820 | 823 | ||
821 | /** | 824 | /** |
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c index 7045ba689494..f6ee7a83595a 100644 --- a/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c | |||
@@ -340,6 +340,8 @@ static int init_chip_first(struct ipath_devdata *dd, | |||
340 | 340 | ||
341 | spin_lock_init(&dd->ipath_tid_lock); | 341 | spin_lock_init(&dd->ipath_tid_lock); |
342 | 342 | ||
343 | spin_lock_init(&dd->ipath_gpio_lock); | ||
344 | |||
343 | done: | 345 | done: |
344 | *pdp = pd; | 346 | *pdp = pd; |
345 | return ret; | 347 | return ret; |
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 2f39db7df31c..bd1088a99891 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h | |||
@@ -399,6 +399,8 @@ struct ipath_devdata { | |||
399 | u64 ipath_gpio_out; | 399 | u64 ipath_gpio_out; |
400 | /* shadow the gpio mask register */ | 400 | /* shadow the gpio mask register */ |
401 | u64 ipath_gpio_mask; | 401 | u64 ipath_gpio_mask; |
402 | /* shadow the gpio output enable, etc... */ | ||
403 | u64 ipath_extctrl; | ||
402 | /* kr_revision shadow */ | 404 | /* kr_revision shadow */ |
403 | u64 ipath_revision; | 405 | u64 ipath_revision; |
404 | /* | 406 | /* |
@@ -473,8 +475,6 @@ struct ipath_devdata { | |||
473 | u32 ipath_cregbase; | 475 | u32 ipath_cregbase; |
474 | /* shadow the control register contents */ | 476 | /* shadow the control register contents */ |
475 | u32 ipath_control; | 477 | u32 ipath_control; |
476 | /* shadow the gpio output contents */ | ||
477 | u32 ipath_extctrl; | ||
478 | /* PCI revision register (HTC rev on FPGA) */ | 478 | /* PCI revision register (HTC rev on FPGA) */ |
479 | u32 ipath_pcirev; | 479 | u32 ipath_pcirev; |
480 | 480 | ||
@@ -576,6 +576,9 @@ struct ipath_devdata { | |||
576 | u64 ipath_gpio_sda; | 576 | u64 ipath_gpio_sda; |
577 | u64 ipath_gpio_scl; | 577 | u64 ipath_gpio_scl; |
578 | 578 | ||
579 | /* lock for doing RMW of shadows/regs for ExtCtrl and GPIO */ | ||
580 | spinlock_t ipath_gpio_lock; | ||
581 | |||
579 | /* used to override LED behavior */ | 582 | /* used to override LED behavior */ |
580 | u8 ipath_led_override; /* Substituted for normal value, if non-zero */ | 583 | u8 ipath_led_override; /* Substituted for normal value, if non-zero */ |
581 | u16 ipath_led_override_timeoff; /* delta to next timer event */ | 584 | u16 ipath_led_override_timeoff; /* delta to next timer event */ |