afdc22e2d17f24a9a61c5832a8864da3f61459e2
[oweals/openwrt.git] /
1 From 714580d7c11f81afb5e08c71f79a03a1ed4ae44e Mon Sep 17 00:00:00 2001
2 From: Jean-Francois Dagenais <jeff.dagenais@gmail.com>
3 Date: Thu, 28 Mar 2019 12:41:11 -0400
4 Subject: [PATCH] w1: ds2408: reset on output_write retry with readback
5
6 commit 49695ac46861180baf2b2b92c62da8619b6bf28f upstream.
7
8 When we have success in 'Channel Access Write' but reading back latch
9 states fails, a write is retried without doing a proper slave reset.
10 This leads to protocol errors as the slave treats the next 'Channel
11 Access Write' as the continuation of previous command.
12
13 This commit is fixing this by making sure if the retry loop re-runs, a
14 reset is performed, whatever the failure (CONFIRM_BYTE or the read
15 back).
16
17 The loop was quite due for a cleanup and this change mandated it. By
18 isolating the CONFIG_W1_SLAVE_DS2408_READBACK case into it's own
19 function, we vastly reduce the visual and branching(runtime and
20 compile-time) noise.
21
22 Reported-by: Mariusz Bialonczyk <manio@skyboo.net>
23 Tested-by: Mariusz Bialonczyk <manio@skyboo.net>
24 Signed-off-by: Jean-Francois Dagenais <jeff.dagenais@gmail.com>
25 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
26 ---
27  drivers/w1/slaves/w1_ds2408.c | 76 ++++++++++++++++++-----------------
28  1 file changed, 39 insertions(+), 37 deletions(-)
29
30 --- a/drivers/w1/slaves/w1_ds2408.c
31 +++ b/drivers/w1/slaves/w1_ds2408.c
32 @@ -138,14 +138,37 @@ static ssize_t status_control_read(struc
33                 W1_F29_REG_CONTROL_AND_STATUS, buf);
34  }
35  
36 +#ifdef fCONFIG_W1_SLAVE_DS2408_READBACK
37 +static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)
38 +{
39 +       u8 w1_buf[3];
40 +
41 +       if (w1_reset_resume_command(sl->master))
42 +               return false;
43 +
44 +       w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
45 +       w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
46 +       w1_buf[2] = 0;
47 +
48 +       w1_write_block(sl->master, w1_buf, 3);
49 +
50 +       return (w1_read_8(sl->master) == expected);
51 +}
52 +#else
53 +static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)
54 +{
55 +       return true;
56 +}
57 +#endif
58 +
59  static ssize_t output_write(struct file *filp, struct kobject *kobj,
60                             struct bin_attribute *bin_attr, char *buf,
61                             loff_t off, size_t count)
62  {
63         struct w1_slave *sl = kobj_to_w1_slave(kobj);
64         u8 w1_buf[3];
65 -       u8 readBack;
66         unsigned int retries = W1_F29_RETRIES;
67 +       ssize_t bytes_written = -EIO;
68  
69         if (count != 1 || off != 0)
70                 return -EFAULT;
71 @@ -155,54 +178,33 @@ static ssize_t output_write(struct file
72         dev_dbg(&sl->dev, "mutex locked");
73  
74         if (w1_reset_select_slave(sl))
75 -               goto error;
76 +               goto out;
77  
78 -       while (retries--) {
79 +       do {
80                 w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE;
81                 w1_buf[1] = *buf;
82                 w1_buf[2] = ~(*buf);
83 -               w1_write_block(sl->master, w1_buf, 3);
84  
85 -               readBack = w1_read_8(sl->master);
86 +               w1_write_block(sl->master, w1_buf, 3);
87  
88 -               if (readBack != W1_F29_SUCCESS_CONFIRM_BYTE) {
89 -                       if (w1_reset_resume_command(sl->master))
90 -                               goto error;
91 -                       /* try again, the slave is ready for a command */
92 -                       continue;
93 +               if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE &&
94 +                   optional_read_back_valid(sl, *buf)) {
95 +                       bytes_written = 1;
96 +                       goto out;
97                 }
98  
99 -#ifdef CONFIG_W1_SLAVE_DS2408_READBACK
100 -               /* here the master could read another byte which
101 -                  would be the PIO reg (the actual pin logic state)
102 -                  since in this driver we don't know which pins are
103 -                  in and outs, there's no value to read the state and
104 -                  compare. with (*buf) so end this command abruptly: */
105                 if (w1_reset_resume_command(sl->master))
106 -                       goto error;
107 +                       goto out; /* unrecoverable error */
108 +               /* try again, the slave is ready for a command */
109 +       } while (--retries);
110  
111 -               /* go read back the output latches */
112 -               /* (the direct effect of the write above) */
113 -               w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
114 -               w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
115 -               w1_buf[2] = 0;
116 -               w1_write_block(sl->master, w1_buf, 3);
117 -               /* read the result of the READ_PIO_REGS command */
118 -               if (w1_read_8(sl->master) == *buf)
119 -#endif
120 -               {
121 -                       /* success! */
122 -                       mutex_unlock(&sl->master->bus_mutex);
123 -                       dev_dbg(&sl->dev,
124 -                               "mutex unlocked, retries:%d", retries);
125 -                       return 1;
126 -               }
127 -       }
128 -error:
129 +out:
130         mutex_unlock(&sl->master->bus_mutex);
131 -       dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
132  
133 -       return -EIO;
134 +       dev_dbg(&sl->dev, "%s, mutex unlocked retries:%d\n",
135 +               (bytes_written > 0) ? "succeeded" : "error", retries);
136 +
137 +       return bytes_written;
138  }
139  
140