Skip to content

Commit 4aa3b75

Browse files
author
William Breathitt Gray
committed
counter: 104-quad-8: Fix race condition between FLAG and CNTR reads
The Counter (CNTR) register is 24 bits wide, but we can have an effective 25-bit count value by setting bit 24 to the XOR of the Borrow flag and Carry flag. The flags can be read from the FLAG register, but a race condition exists: the Borrow flag and Carry flag are instantaneous and could change by the time the count value is read from the CNTR register. Since the race condition could result in an incorrect 25-bit count value, remove support for 25-bit count values from this driver; hard-coded maximum count values are replaced by a LS7267_CNTR_MAX define for consistency and clarity. Fixes: 28e5d3b ("iio: 104-quad-8: Add IIO support for the ACCES 104-QUAD-8") Cc: <stable@vger.kernel.org> # 6.1.x Cc: <stable@vger.kernel.org> # 6.2.x Link: https://lore.kernel.org/r/20230312231554.134858-1-william.gray@linaro.org/ Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
1 parent fe15c26 commit 4aa3b75

File tree

1 file changed

+8
-21
lines changed

1 file changed

+8
-21
lines changed

drivers/counter/104-quad-8.c

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,6 @@ struct quad8 {
9797
struct quad8_reg __iomem *reg;
9898
};
9999

100-
/* Borrow Toggle flip-flop */
101-
#define QUAD8_FLAG_BT BIT(0)
102-
/* Carry Toggle flip-flop */
103-
#define QUAD8_FLAG_CT BIT(1)
104100
/* Error flag */
105101
#define QUAD8_FLAG_E BIT(4)
106102
/* Up/Down flag */
@@ -133,6 +129,9 @@ struct quad8 {
133129
#define QUAD8_CMR_QUADRATURE_X2 0x10
134130
#define QUAD8_CMR_QUADRATURE_X4 0x18
135131

132+
/* Each Counter is 24 bits wide */
133+
#define LS7267_CNTR_MAX GENMASK(23, 0)
134+
136135
static int quad8_signal_read(struct counter_device *counter,
137136
struct counter_signal *signal,
138137
enum counter_signal_level *level)
@@ -156,18 +155,10 @@ static int quad8_count_read(struct counter_device *counter,
156155
{
157156
struct quad8 *const priv = counter_priv(counter);
158157
struct channel_reg __iomem *const chan = priv->reg->channel + count->id;
159-
unsigned int flags;
160-
unsigned int borrow;
161-
unsigned int carry;
162158
unsigned long irqflags;
163159
int i;
164160

165-
flags = ioread8(&chan->control);
166-
borrow = flags & QUAD8_FLAG_BT;
167-
carry = !!(flags & QUAD8_FLAG_CT);
168-
169-
/* Borrow XOR Carry effectively doubles count range */
170-
*val = (unsigned long)(borrow ^ carry) << 24;
161+
*val = 0;
171162

172163
spin_lock_irqsave(&priv->lock, irqflags);
173164

@@ -191,8 +182,7 @@ static int quad8_count_write(struct counter_device *counter,
191182
unsigned long irqflags;
192183
int i;
193184

194-
/* Only 24-bit values are supported */
195-
if (val > 0xFFFFFF)
185+
if (val > LS7267_CNTR_MAX)
196186
return -ERANGE;
197187

198188
spin_lock_irqsave(&priv->lock, irqflags);
@@ -806,8 +796,7 @@ static int quad8_count_preset_write(struct counter_device *counter,
806796
struct quad8 *const priv = counter_priv(counter);
807797
unsigned long irqflags;
808798

809-
/* Only 24-bit values are supported */
810-
if (preset > 0xFFFFFF)
799+
if (preset > LS7267_CNTR_MAX)
811800
return -ERANGE;
812801

813802
spin_lock_irqsave(&priv->lock, irqflags);
@@ -834,8 +823,7 @@ static int quad8_count_ceiling_read(struct counter_device *counter,
834823
*ceiling = priv->preset[count->id];
835824
break;
836825
default:
837-
/* By default 0x1FFFFFF (25 bits unsigned) is maximum count */
838-
*ceiling = 0x1FFFFFF;
826+
*ceiling = LS7267_CNTR_MAX;
839827
break;
840828
}
841829

@@ -850,8 +838,7 @@ static int quad8_count_ceiling_write(struct counter_device *counter,
850838
struct quad8 *const priv = counter_priv(counter);
851839
unsigned long irqflags;
852840

853-
/* Only 24-bit values are supported */
854-
if (ceiling > 0xFFFFFF)
841+
if (ceiling > LS7267_CNTR_MAX)
855842
return -ERANGE;
856843

857844
spin_lock_irqsave(&priv->lock, irqflags);

0 commit comments

Comments
 (0)