aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/infiniband/hw/ipath/ipath_eeprom.c68
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6120.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_init_chip.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h7
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
193static void scl_out(struct ipath_devdata *dd, u8 bit) 198static 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
1108static void ipath_init_ht_variables(struct ipath_devdata *dd) 1111static 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
343done: 345done:
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 */