bcm27xx: import latest patches from the RPi foundation
[openwrt/openwrt.git] / target / linux / bcm27xx / patches-5.4 / 950-0767-w1_therm-fix-reset_select_slave-during-discovery.patch
1 From dfc9fd0060f9103ca1f9335d529401ee8a105737 Mon Sep 17 00:00:00 2001
2 From: Akira Shimahara <akira215corp@gmail.com>
3 Date: Mon, 11 May 2020 22:36:10 +0200
4 Subject: [PATCH] w1_therm: fix reset_select_slave during discovery
5
6 commit c8ad65f6fbfdcb9b620674ef456020eef2bfeb36 upstream.
7
8 Fix reset_select_slave issue during devices discovery by the master on
9 bus. The w1_reset_select_slave() from w1_io.c, which was previously used,
10 assume that if the slave count is 1 there is only one slave attached on
11 the bus. This is not always true. For example when discovering devices,
12 when the first device is discover by the bus master, its slave count is
13 1, but some other slaves may be on the bus.
14
15 In that case instead of adressing command to the attached slave the
16 master throw a SKIP ROM command so that all slaves attached on the bus
17 will answer simultenaously causing data collision.
18
19 A dedicated reset_select_slave() function is implemented here,
20 it always perform an adressing to each slave using the MATCH ROM
21 command.
22
23 Signed-off-by: Akira Shimahara <akira215corp@gmail.com>
24 Link: https://lore.kernel.org/r/20200511203610.409975-1-akira215corp@gmail.com
25 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
26 ---
27 drivers/w1/slaves/w1_therm.c | 48 ++++++++++++++++++++++++++++++------
28 1 file changed, 41 insertions(+), 7 deletions(-)
29
30 --- a/drivers/w1/slaves/w1_therm.c
31 +++ b/drivers/w1/slaves/w1_therm.c
32 @@ -16,6 +16,7 @@
33 #include <linux/slab.h>
34 #include <linux/delay.h>
35 #include <linux/hwmon.h>
36 +#include <linux/string.h>
37
38 #include <linux/w1.h>
39
40 @@ -90,6 +91,24 @@ struct therm_info {
41 u8 verdict;
42 };
43
44 +/* Hardware Functions declaration */
45 +
46 +/**
47 + * reset_select_slave() - reset and select a slave
48 + * @sl: the slave to select
49 + *
50 + * Resets the bus and select the slave by sending a ROM MATCH cmd
51 + * w1_reset_select_slave() from w1_io.c could not be used here because
52 + * it sent a SKIP ROM command if only one device is on the line.
53 + * At the beginning of the such process, sl->master->slave_count is 1 even if
54 + * more devices are on the line, causing collision on the line.
55 + *
56 + * Context: The w1 master lock must be held.
57 + *
58 + * Return: 0 if success, negative kernel error code otherwise.
59 + */
60 +static int reset_select_slave(struct w1_slave *sl);
61 +
62 /* Sysfs interface declaration */
63
64 static ssize_t w1_slave_show(struct device *device,
65 @@ -301,7 +320,7 @@ static inline int w1_DS18B20_precision(s
66 while (max_trying--) {
67 crc = 0;
68
69 - if (!w1_reset_select_slave(sl)) {
70 + if (!reset_select_slave(sl)) {
71 int count = 0;
72
73 /* read values to only alter precision bits */
74 @@ -314,7 +333,7 @@ static inline int w1_DS18B20_precision(s
75 if (rom[8] == crc) {
76 rom[4] = (rom[4] & ~mask) | (precision_bits & mask);
77
78 - if (!w1_reset_select_slave(sl)) {
79 + if (!reset_select_slave(sl)) {
80 w1_write_8(dev, W1_WRITE_SCRATCHPAD);
81 w1_write_8(dev, rom[2]);
82 w1_write_8(dev, rom[3]);
83 @@ -460,6 +479,21 @@ static void w1_therm_remove_slave(struct
84
85 /* Hardware Functions */
86
87 +/* Safe version of reset_select_slave - avoid using the one in w_io.c */
88 +static int reset_select_slave(struct w1_slave *sl)
89 +{
90 + u8 match[9] = { W1_MATCH_ROM, };
91 + u64 rn = le64_to_cpu(*((u64 *)&sl->reg_num));
92 +
93 + if (w1_reset_bus(sl->master))
94 + return -ENODEV;
95 +
96 + memcpy(&match[1], &rn, 8);
97 + w1_write_block(sl->master, match, 9);
98 +
99 + return 0;
100 +}
101 +
102 static ssize_t read_therm(struct device *device,
103 struct w1_slave *sl, struct therm_info *info)
104 {
105 @@ -487,7 +521,7 @@ static ssize_t read_therm(struct device
106 info->verdict = 0;
107 info->crc = 0;
108
109 - if (!w1_reset_select_slave(sl)) {
110 + if (!reset_select_slave(sl)) {
111 int count = 0;
112 unsigned int tm = 750;
113 unsigned long sleep_rem;
114 @@ -495,7 +529,7 @@ static ssize_t read_therm(struct device
115 w1_write_8(dev, W1_READ_PSUPPLY);
116 external_power = w1_read_8(dev);
117
118 - if (w1_reset_select_slave(sl))
119 + if (reset_select_slave(sl))
120 continue;
121
122 /* 750ms strong pullup (or delay) after the convert */
123 @@ -525,7 +559,7 @@ static ssize_t read_therm(struct device
124 }
125 }
126
127 - if (!w1_reset_select_slave(sl)) {
128 + if (!reset_select_slave(sl)) {
129
130 w1_write_8(dev, W1_READ_SCRATCHPAD);
131 count = w1_read_block(dev, info->rom, 9);
132 @@ -577,7 +611,7 @@ static inline int w1_therm_eeprom(struct
133 memset(rom, 0, sizeof(rom));
134
135 while (max_trying--) {
136 - if (!w1_reset_select_slave(sl)) {
137 + if (!reset_select_slave(sl)) {
138 unsigned int tm = 10;
139 unsigned long sleep_rem;
140
141 @@ -585,7 +619,7 @@ static inline int w1_therm_eeprom(struct
142 w1_write_8(dev, W1_READ_PSUPPLY);
143 external_power = w1_read_8(dev);
144
145 - if (w1_reset_select_slave(sl))
146 + if (reset_select_slave(sl))
147 continue;
148
149 /* 10ms strong pullup/delay after the copy command */