All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 2/9] w1_therm: fix reset_select_slave at beginning of search process
@ 2020-04-29 22:59 Akira Shimahara
  2020-05-05 14:49 ` Greg KH
  0 siblings, 1 reply; 3+ messages in thread
From: Akira Shimahara @ 2020-04-29 22:59 UTC (permalink / raw)
  To: greg; +Cc: zbr, linux-kernel, Akira Shimahara

Fix reset_select_slave issue during devices discovery by the master on
bus. The w1_reset_select_slave() from w1_io.c, which was previously used,
assume that if the slave count is 1 there is only one slave attached on
the bus. This is not always true. For example when discovering devices,
when the first device is discover by the bus master, its slave count is
1, but some other slaves may be on the bus.

In that case instead of adressing command to the attached slave the 
master throw a SKIP ROM command so that all slaves attached on the bus
will answer simultenaously causing data collision.

A dedicated reset_select_slave() function is implemented here,
it always perform an adressing to each slave using the MATCH ROM
command.

Signed-off-by: Akira Shimahara <akira215corp@gmail.com>
---
 drivers/w1/slaves/w1_therm.c | 29 ++++++++++++++++++++++-------
 drivers/w1/slaves/w1_therm.h | 13 +++++++++++++
 2 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index f027360..6245950 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -235,7 +235,7 @@ static inline int w1_DS18B20_precision(struct device *device, int val)
 	while (max_trying--) {
 		crc = 0;
 
-		if (!w1_reset_select_slave(sl)) {
+		if (!reset_select_slave(sl)) {
 			int count = 0;
 
 			/* read values to only alter precision bits */
@@ -248,7 +248,7 @@ static inline int w1_DS18B20_precision(struct device *device, int val)
 			if (rom[8] == crc) {
 				rom[4] = (rom[4] & ~mask) | (precision_bits & mask);
 
-				if (!w1_reset_select_slave(sl)) {
+				if (!reset_select_slave(sl)) {
 					w1_write_8(dev, W1_WRITE_SCRATCHPAD);
 					w1_write_8(dev, rom[2]);
 					w1_write_8(dev, rom[3]);
@@ -319,6 +319,21 @@ static void w1_therm_remove_slave(struct w1_slave *sl)
 
 /*------------------------Hardware Functions--------------------------*/
 
+/* Safe version of reser_select_slave - avoid using the one in w_io.c */
+static int reset_select_slave(struct w1_slave *sl)
+{
+	u8 match[9] = { W1_MATCH_ROM, };
+	u64 rn = le64_to_cpu(*((u64 *)&sl->reg_num));
+
+	if (w1_reset_bus(sl->master))
+		return -ENODEV;
+
+	memcpy(&match[1], &rn, 8);
+	w1_write_block(sl->master, match, 9);
+
+	return 0;
+}
+
 static inline int w1_convert_temp(u8 rom[9], u8 fid)
 {
 	int i;
@@ -357,7 +372,7 @@ static ssize_t read_therm(struct device *device,
 		info->verdict = 0;
 		info->crc = 0;
 
-		if (!w1_reset_select_slave(sl)) {
+		if (!reset_select_slave(sl)) {
 			int count = 0;
 			unsigned int tm = 750;
 			unsigned long sleep_rem;
@@ -365,7 +380,7 @@ static ssize_t read_therm(struct device *device,
 			w1_write_8(dev, W1_READ_PSUPPLY);
 			external_power = w1_read_8(dev);
 
-			if (w1_reset_select_slave(sl))
+			if (reset_select_slave(sl))
 				continue;
 
 			/* 750ms strong pullup (or delay) after the convert */
@@ -395,7 +410,7 @@ static ssize_t read_therm(struct device *device,
 				}
 			}
 
-			if (!w1_reset_select_slave(sl)) {
+			if (!reset_select_slave(sl)) {
 
 				w1_write_8(dev, W1_READ_SCRATCHPAD);
 				count = w1_read_block(dev, info->rom, 9);
@@ -447,7 +462,7 @@ static inline int w1_therm_eeprom(struct device *device)
 	memset(rom, 0, sizeof(rom));
 
 	while (max_trying--) {
-		if (!w1_reset_select_slave(sl)) {
+		if (!reset_select_slave(sl)) {
 			unsigned int tm = 10;
 			unsigned long sleep_rem;
 
@@ -455,7 +470,7 @@ static inline int w1_therm_eeprom(struct device *device)
 			w1_write_8(dev, W1_READ_PSUPPLY);
 			external_power = w1_read_8(dev);
 
-			if (w1_reset_select_slave(sl))
+			if (reset_select_slave(sl))
 				continue;
 
 			/* 10ms strong pullup/delay after the copy command */
diff --git a/drivers/w1/slaves/w1_therm.h b/drivers/w1/slaves/w1_therm.h
index 8aa69cc..ba11c96 100644
--- a/drivers/w1/slaves/w1_therm.h
+++ b/drivers/w1/slaves/w1_therm.h
@@ -87,6 +87,19 @@ static inline int w1_DS18S20_convert_temp(u8 rom[9]);
 
 /*---------------------------Hardware Functions-----------------------------*/
 
+/**
+ * reset_select_slave() - reset and select a slave
+ * @brief Resets the bus and select the slave by sending either a ROM MATCH
+ * w1_reset_select_slave() from w1_io.c could not be used
+ * here because a SKIP ROM command is sent if only one device is on the line.
+ * At the beginning of the such process, sl->master->slave_count is 1 even if
+ * more devices are on the line, causing collision on the line.
+ * The w1 master lock must be held.
+ * @param sl the slave to select
+ * @return 0 if success, negative kernel error code otherwise
+ */
+static int reset_select_slave(struct w1_slave *sl);
+
 /** read_therm()
  * @param sl pointer to the slave to read
  * @param info pointer to a structure to store the read results
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v4 2/9] w1_therm: fix reset_select_slave at beginning of search process
  2020-04-29 22:59 [PATCH v4 2/9] w1_therm: fix reset_select_slave at beginning of search process Akira Shimahara
@ 2020-05-05 14:49 ` Greg KH
  2020-05-05 21:06   ` Akira shimahara
  0 siblings, 1 reply; 3+ messages in thread
From: Greg KH @ 2020-05-05 14:49 UTC (permalink / raw)
  To: Akira Shimahara; +Cc: zbr, linux-kernel

On Thu, Apr 30, 2020 at 12:59:43AM +0200, Akira Shimahara wrote:
> Fix reset_select_slave issue during devices discovery by the master on
> bus. The w1_reset_select_slave() from w1_io.c, which was previously used,
> assume that if the slave count is 1 there is only one slave attached on
> the bus. This is not always true. For example when discovering devices,
> when the first device is discover by the bus master, its slave count is
> 1, but some other slaves may be on the bus.
> 
> In that case instead of adressing command to the attached slave the 
> master throw a SKIP ROM command so that all slaves attached on the bus
> will answer simultenaously causing data collision.
> 
> A dedicated reset_select_slave() function is implemented here,
> it always perform an adressing to each slave using the MATCH ROM
> command.
> 
> Signed-off-by: Akira Shimahara <akira215corp@gmail.com>
> ---
>  drivers/w1/slaves/w1_therm.c | 29 ++++++++++++++++++++++-------
>  drivers/w1/slaves/w1_therm.h | 13 +++++++++++++
>  2 files changed, 35 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
> index f027360..6245950 100644
> --- a/drivers/w1/slaves/w1_therm.c
> +++ b/drivers/w1/slaves/w1_therm.c
> @@ -235,7 +235,7 @@ static inline int w1_DS18B20_precision(struct device *device, int val)
>  	while (max_trying--) {
>  		crc = 0;
>  
> -		if (!w1_reset_select_slave(sl)) {
> +		if (!reset_select_slave(sl)) {
>  			int count = 0;
>  
>  			/* read values to only alter precision bits */
> @@ -248,7 +248,7 @@ static inline int w1_DS18B20_precision(struct device *device, int val)
>  			if (rom[8] == crc) {
>  				rom[4] = (rom[4] & ~mask) | (precision_bits & mask);
>  
> -				if (!w1_reset_select_slave(sl)) {
> +				if (!reset_select_slave(sl)) {
>  					w1_write_8(dev, W1_WRITE_SCRATCHPAD);
>  					w1_write_8(dev, rom[2]);
>  					w1_write_8(dev, rom[3]);
> @@ -319,6 +319,21 @@ static void w1_therm_remove_slave(struct w1_slave *sl)
>  
>  /*------------------------Hardware Functions--------------------------*/
>  
> +/* Safe version of reser_select_slave - avoid using the one in w_io.c */
> +static int reset_select_slave(struct w1_slave *sl)
> +{
> +	u8 match[9] = { W1_MATCH_ROM, };
> +	u64 rn = le64_to_cpu(*((u64 *)&sl->reg_num));
> +
> +	if (w1_reset_bus(sl->master))
> +		return -ENODEV;
> +
> +	memcpy(&match[1], &rn, 8);
> +	w1_write_block(sl->master, match, 9);
> +
> +	return 0;
> +}

If you put this higher up in the .c file, no function definition is
needed in the .h file at all, right?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v4 2/9] w1_therm: fix reset_select_slave at beginning of search process
  2020-05-05 14:49 ` Greg KH
@ 2020-05-05 21:06   ` Akira shimahara
  0 siblings, 0 replies; 3+ messages in thread
From: Akira shimahara @ 2020-05-05 21:06 UTC (permalink / raw)
  To: Greg KH; +Cc: zbr, linux-kernel

Le mardi 05 mai 2020 à 16:49 +0200, Greg KH a écrit :
> >   /*------------------------Hardware Functions---------------------
> > -----*/
> >   
> > +/* Safe version of reser_select_slave - avoid using the one in
> > w_io.c */
> > +static int reset_select_slave(struct w1_slave *sl)
> > +{
> > +     u8 match[9] = { W1_MATCH_ROM, };
> > +     u64 rn = le64_to_cpu(*((u64 *)&sl->reg_num));
> > +
> > +     if (w1_reset_bus(sl->master))
> > +             return -ENODEV;
> > +
> > +     memcpy(&match[1], &rn, 8);
> > +     w1_write_block(sl->master, match, 9);
> > +
> > +     return 0;
> > +}
> 
> 
> If you put this higher up in the .c file, no function definition is
> 
> needed in the .h file at all, right?
> 
> 
> 
> thanks,
> 
> 
> 
> greg k-h

Yes, everything could be put in the .c file, but I think we will loose
clarity.
Please, let me know what you prefer.

Thanks

Akira Shimahara


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-05-05 21:06 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-29 22:59 [PATCH v4 2/9] w1_therm: fix reset_select_slave at beginning of search process Akira Shimahara
2020-05-05 14:49 ` Greg KH
2020-05-05 21:06   ` Akira shimahara

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.