linux-tegra.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [tegrarcm PATCH 1/3] Move all USB device matching logic into usb_match()
@ 2015-10-08 18:38 Stephen Warren
       [not found] ` <1444329510-23848-1-git-send-email-swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Stephen Warren @ 2015-10-08 18:38 UTC (permalink / raw)
  To: Allen Martin; +Cc: Stephen Warren, linux-tegra-u79uwXL29TY76Z2rM5mHXA

From: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

This consolidates the matching logic into one place, which will make
future enhancements to the logic simpler.

Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 src/usb.c | 37 +++++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/src/usb.c b/src/usb.c
index b0a7a8822aa2..71234d77d7b1 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -45,16 +45,32 @@
 static int usb_match(libusb_device *dev, uint16_t venid, uint16_t *devid)
 {
 	struct libusb_device_descriptor desc;
+
 	if (libusb_get_device_descriptor(dev, &desc)) {
 		dprintf("libusb_get_device_descriptor\n");
 		return 0;
 	}
-	if (desc.idVendor == venid) {
-		*devid = desc.idProduct;
-		return 1;
+	if (desc.idVendor != venid) {
+		dprintf("non-NVIDIA USB device: 0x%x:0x%x\n",
+			desc.idVendor, desc.idProduct);
+		return 0;
+	}
+	switch (desc.idProduct & 0xff) {
+	case USB_DEVID_NVIDIA_TEGRA20:
+	case USB_DEVID_NVIDIA_TEGRA30:
+	case USB_DEVID_NVIDIA_TEGRA114:
+	case USB_DEVID_NVIDIA_TEGRA124:
+		break;
+	default:
+		dprintf("non-Tegra NVIDIA USB device: 0x%x:0x%x\n",
+			desc.idVendor, desc.idProduct);
+		return 0;
 	}
 
-	return 0;
+	dprintf("device matches\n");
+	*devid = desc.idProduct;
+
+	return 1;
 }
 
 static void usb_check_interface(const struct libusb_interface_descriptor *iface_desc,
@@ -155,17 +171,10 @@ usb_device_t *usb_open(uint16_t venid, uint16_t *devid)
 
 	for (i = 0; i < cnt; i++) {
 		libusb_device *device = list[i];
+
 		if (usb_match(device, venid, devid)) {
-			if ((*devid & 0xff) == USB_DEVID_NVIDIA_TEGRA20 ||
-			    (*devid & 0xff) == USB_DEVID_NVIDIA_TEGRA30 ||
-			    (*devid & 0xff) == USB_DEVID_NVIDIA_TEGRA114 ||
-			    (*devid & 0xff) == USB_DEVID_NVIDIA_TEGRA124) {
-				found = device;
-				break;
-			} else {
-				dprintf("non-tegra NVIDIA USB device: 0x%x\n",
-					*devid);
-			}
+			found = device;
+			break;
 		}
 	}
 
-- 
1.9.1

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

* [tegrarcm PATCH 2/3] Match USB port ID on re-enumeration
       [not found] ` <1444329510-23848-1-git-send-email-swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2015-10-08 18:38   ` Stephen Warren
  2015-10-08 18:38   ` [tegrarcm PATCH 3/3] Implement --usb-port-path cmdline option Stephen Warren
  2015-10-16 16:57   ` [tegrarcm PATCH 1/3] Move all USB device matching logic into usb_match() Stephen Warren
  2 siblings, 0 replies; 4+ messages in thread
From: Stephen Warren @ 2015-10-08 18:38 UTC (permalink / raw)
  To: Allen Martin; +Cc: Stephen Warren, linux-tegra-u79uwXL29TY76Z2rM5mHXA

From: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

When executing the RCM process, the Tegra device will be re-enumerated
on the USB bus once the miniloader is booted. This requires tegrarcm to
search for it again. In a system with multiple attached Tegra boards, all
being booted/shutdown in parallel, it is possible that the second call to
usb_open() will find a different Tegra device. Solve this issue by having
usb_open() record the exact physical USB port path of the device, and
match only that path on subsequent searches. This will be robust except in
the case where the device being operated on is physically unplugged and
replaced (not simply power-cycled) while tegrarcm is executing. This is
much less likely that the previous failure modes.

This feature also enables the next patch in this series.

Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 src/main.c | 18 +++++++++++++--
 src/usb.c  | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/usb.h  | 14 +++++++++++-
 3 files changed, 102 insertions(+), 6 deletions(-)

diff --git a/src/main.c b/src/main.c
index 50adc14f0b06..4936d02e0cd9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -136,6 +136,12 @@ int main(int argc, char **argv)
 	int do_read = 0;
 	char *mlfile = NULL;
 	uint32_t mlentry = 0;
+#ifdef HAVE_USB_PORT_MATCH
+	bool match_port = false;
+	uint8_t match_bus;
+	uint8_t match_ports[PORT_MATCH_MAX_PORTS];
+	int match_ports_len;
+#endif
 
 	static struct option long_options[] = {
 		[OPT_BCT]        = {"bct", 1, 0, 0},
@@ -232,7 +238,11 @@ int main(int argc, char **argv)
 		printf("entry addr 0x%x\n", entryaddr);
 	}
 
-	usb = usb_open(USB_VENID_NVIDIA, &devid);
+	usb = usb_open(USB_VENID_NVIDIA, &devid
+#ifdef HAVE_USB_PORT_MATCH
+		, &match_port, &match_bus, match_ports, &match_ports_len
+#endif
+	);
 	if (!usb)
 		error(1, errno, "could not open USB device");
 	printf("device id: 0x%x\n", devid);
@@ -259,7 +269,11 @@ int main(int argc, char **argv)
 
 		// device may have re-enumerated, so reopen USB
 		usb_close(usb);
-		usb = usb_open(USB_VENID_NVIDIA, &devid);
+		usb = usb_open(USB_VENID_NVIDIA, &devid
+#ifdef HAVE_USB_PORT_MATCH
+		, &match_port, &match_bus, match_ports, &match_ports_len
+#endif
+		);
 		if (!usb)
 			error(1, errno, "could not open USB device");
 	}
diff --git a/src/usb.c b/src/usb.c
index 71234d77d7b1..8a367426b29c 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -42,9 +42,27 @@
 //
 // returns 1 if the specified usb device matches the vendor id
 //
-static int usb_match(libusb_device *dev, uint16_t venid, uint16_t *devid)
+static int usb_match(libusb_device *dev, uint16_t venid, uint16_t *devid
+#ifdef HAVE_USB_PORT_MATCH
+	,
+	bool *match_port, uint8_t *match_bus, uint8_t *match_ports,
+	int *match_ports_len
+#endif
+)
 {
 	struct libusb_device_descriptor desc;
+#ifdef HAVE_USB_PORT_MATCH
+	uint8_t dev_bus;
+	uint8_t dev_ports[PORT_MATCH_MAX_PORTS];
+	int dev_ports_len;
+#ifdef DEBUG
+	int i;
+	char portstr[(PORT_MATCH_MAX_PORTS * 4)];
+	char *portstrp;
+	size_t portstr_lenleft;
+	int printed;
+#endif
+#endif
 
 	if (libusb_get_device_descriptor(dev, &desc)) {
 		dprintf("libusb_get_device_descriptor\n");
@@ -66,6 +84,47 @@ static int usb_match(libusb_device *dev, uint16_t venid, uint16_t *devid)
 			desc.idVendor, desc.idProduct);
 		return 0;
 	}
+#ifdef HAVE_USB_PORT_MATCH
+	dev_bus = libusb_get_bus_number(dev);
+	dev_ports_len = libusb_get_port_numbers(dev, dev_ports,
+			PORT_MATCH_MAX_PORTS);
+	if (dev_ports_len < 0) {
+		dprintf("libusb_get_port_numbers failed: %d\n", dev_ports_len);
+		return 0;
+	}
+	if (*match_port) {
+		if (dev_bus != *match_bus) {
+			dprintf("bus mismatch dev:%d match:%d\n", dev_bus,
+				*match_bus);
+			return 0;
+		}
+		if (memcmp(dev_ports, match_ports, dev_ports_len)) {
+			dprintf("ports mismatch\n");
+			return 0;
+		}
+	}
+	if (!*match_port) {
+		*match_port = true;
+		*match_bus = dev_bus;
+		memcpy(match_ports, dev_ports, dev_ports_len);
+		*match_ports_len = dev_ports_len;
+#ifdef DEBUG
+		portstrp = portstr;
+		portstr_lenleft = sizeof(portstr);
+		printed = snprintf(portstrp, portstr_lenleft, "%d-%d",
+			dev_bus, dev_ports[0]);
+		portstrp += printed;
+		portstr_lenleft -= printed;
+		for (i = 1; i < dev_ports_len; i++) {
+			printed = snprintf(portstrp, portstr_lenleft, ".%d",
+				(int)dev_ports[i]);
+			portstrp += printed;
+			portstr_lenleft -= printed;
+		}
+		dprintf("Enabling future match %s\n", portstr);
+#endif
+	}
+#endif
 
 	dprintf("device matches\n");
 	*devid = desc.idProduct;
@@ -151,7 +210,13 @@ static int usb_get_interface(libusb_device_handle *handle,
 	return 0;
 }
 
-usb_device_t *usb_open(uint16_t venid, uint16_t *devid)
+usb_device_t *usb_open(uint16_t venid, uint16_t *devid
+#ifdef HAVE_USB_PORT_MATCH
+	,
+	bool *match_port, uint8_t *match_bus, uint8_t *match_ports,
+	int *match_ports_len
+#endif
+)
 {
 	libusb_device **list = NULL;
 	libusb_device *found = NULL;
@@ -172,7 +237,12 @@ usb_device_t *usb_open(uint16_t venid, uint16_t *devid)
 	for (i = 0; i < cnt; i++) {
 		libusb_device *device = list[i];
 
-		if (usb_match(device, venid, devid)) {
+		if (usb_match(device, venid, devid
+#ifdef HAVE_USB_PORT_MATCH
+				, match_port, match_bus, match_ports,
+				match_ports_len
+#endif
+		)) {
 			found = device;
 			break;
 		}
diff --git a/src/usb.h b/src/usb.h
index a7b36af020d7..e8fcd67cf6cc 100644
--- a/src/usb.h
+++ b/src/usb.h
@@ -29,8 +29,14 @@
 #ifndef USB_H
 #define USB_H
 
+#include <stdbool.h>
 #include <libusb.h>
 
+#if defined(LIBUSBX_API_VERSION) && (LIBUSBX_API_VERSION >= 0x01000102)
+#define HAVE_USB_PORT_MATCH
+#define PORT_MATCH_MAX_PORTS 7
+#endif
+
 #define USB_VENID_NVIDIA 0x955
 #define USB_DEVID_NVIDIA_TEGRA20 0x20
 #define USB_DEVID_NVIDIA_TEGRA30 0x30
@@ -45,7 +51,13 @@ typedef struct {
 	int initialized;
 } usb_device_t;
 
-usb_device_t *usb_open(uint16_t venid, uint16_t *devid);
+usb_device_t *usb_open(uint16_t venid, uint16_t *devid
+#ifdef HAVE_USB_PORT_MATCH
+	,
+	bool *match_port, uint8_t *match_bus, uint8_t *match_ports,
+	int *match_ports_len
+#endif
+);
 void usb_close(usb_device_t *usb);
 int usb_write(usb_device_t *usb, uint8_t *buf, int len);
 int usb_read(usb_device_t *usb, uint8_t *buf, int len, int *actual_len);
-- 
1.9.1

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

* [tegrarcm PATCH 3/3] Implement --usb-port-path cmdline option
       [not found] ` <1444329510-23848-1-git-send-email-swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
  2015-10-08 18:38   ` [tegrarcm PATCH 2/3] Match USB port ID on re-enumeration Stephen Warren
@ 2015-10-08 18:38   ` Stephen Warren
  2015-10-16 16:57   ` [tegrarcm PATCH 1/3] Move all USB device matching logic into usb_match() Stephen Warren
  2 siblings, 0 replies; 4+ messages in thread
From: Stephen Warren @ 2015-10-08 18:38 UTC (permalink / raw)
  To: Allen Martin; +Cc: Stephen Warren, linux-tegra-u79uwXL29TY76Z2rM5mHXA

From: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

This allows the user to specify which USB device to control, and in a
manner that is most immune to the set of attached USB devices varying.
See the manpage edit in this commit for a full description of how to
use this option.

Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 src/main.c        | 50 +++++++++++++++++++++++++++++++++++++
 src/tegrarcm.1.in | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+)

diff --git a/src/main.c b/src/main.c
index 4936d02e0cd9..3db0ed8be506 100644
--- a/src/main.c
+++ b/src/main.c
@@ -81,6 +81,9 @@ enum cmdline_opts {
 	OPT_VERSION,
 	OPT_MINILOADER,
 	OPT_MINIENTRY,
+#ifdef HAVE_USB_PORT_MATCH
+	OPT_USBPORTPATH,
+#endif
 	OPT_END,
 };
 
@@ -102,6 +105,12 @@ static void usage(char *progname)
 	fprintf(stderr, "\tbootloader to device and start execution of bootloader\n");
 	fprintf(stderr, "\n");
 	fprintf(stderr, "Options:\n");
+#ifdef HAVE_USB_PORT_MATCH
+	fprintf(stderr, "\t--usb-port-path=<path>\n");
+	fprintf(stderr, "\t\tSpecify the USB device to program, e.g. 3-10.4\n");
+	fprintf(stderr, "\t\tSee `udevadm info /dev/bus/usb/003/042` DEVPATH\n");
+	fprintf(stderr, "\t\tSee /sys/bus/usb/devices/* with matching busnum/devnum files\n");
+#endif
 	fprintf(stderr, "\t--entryaddr=<entryaddr>\n");
 	fprintf(stderr, "\t\tSpecify the entry point for the bootloader, if this option is\n");
 	fprintf(stderr, "\t\tnot provided, it is assumed to be loadaddr\n");
@@ -117,6 +126,36 @@ static void usage(char *progname)
 	fprintf(stderr, "\n");
 }
 
+#ifdef HAVE_USB_PORT_MATCH
+static void parse_usb_port_path(char *argv0, char *path, uint8_t *match_bus,
+	uint8_t *match_ports, int *match_ports_len)
+{
+	*match_bus = strtoul(path, &path, 10);
+	if (*path != '-') {
+		usage(argv0);
+		exit(EXIT_FAILURE);
+	}
+	path++;
+
+	*match_ports_len = 0;
+	for (;;) {
+		match_ports[*match_ports_len] = strtoul(path, &path, 10);
+		(*match_ports_len)++;
+		if (!*path)
+			break;
+		if (*match_ports_len >= PORT_MATCH_MAX_PORTS) {
+			usage(argv0);
+			exit(EXIT_FAILURE);
+		}
+		if (*path != '.') {
+			usage(argv0);
+			exit(EXIT_FAILURE);
+		}
+		path++;
+	}
+}
+#endif
+
 int main(int argc, char **argv)
 {
 	// discover devices
@@ -152,6 +191,9 @@ int main(int argc, char **argv)
 		[OPT_VERSION]    = {"version", 0, 0, 0},
 		[OPT_MINILOADER] = {"miniloader", 1, 0, 0},
 		[OPT_MINIENTRY]  = {"miniloader_entry", 1, 0, 0},
+#ifdef HAVE_USB_PORT_MATCH
+		[OPT_USBPORTPATH]  = {"usb-port-path", 1, 0, 0},
+#endif
 		[OPT_END]        = {0, 0, 0, 0}
 	};
 
@@ -187,6 +229,14 @@ int main(int argc, char **argv)
 			case OPT_MINIENTRY:
 				mlentry = strtoul(optarg, NULL, 0);
 				break;
+#ifdef HAVE_USB_PORT_MATCH
+			case OPT_USBPORTPATH:
+				parse_usb_port_path(argv[0], optarg,
+					&match_bus, match_ports,
+					&match_ports_len);
+				match_port = true;
+				break;
+#endif
 			case OPT_HELP:
 			default:
 				usage(argv[0]);
diff --git a/src/tegrarcm.1.in b/src/tegrarcm.1.in
index f747fd8557f7..f8009b952176 100644
--- a/src/tegrarcm.1.in
+++ b/src/tegrarcm.1.in
@@ -79,6 +79,80 @@ built-in one.
 .TP
 .B \-\-miniloader_entry \fImlentry\fP
 Specify the entry address of the miniloader.
+.TP
+.B \-\-usb\-port\-path \fIpath\fP
+Specify the physical USB port path of the Tegra device to control.
+
+.SH USB PORT PATH
+
+By default, tegrarcm operates on the first USB applicable device it finds.
+In a system that contains multiple Tegra devices, the user may wish to
+specify which device tegrarcm should operate upon. The \-\-usb\-port\-path
+option allows this, and in a manner that is most immune to the set of attached
+USB devices varying.
+
+Note that the USB port path is associated with a physical USB port on a
+particular hub. This value will vary if you physically re-organize your USB
+connections. This feature is still useful even if your USB topology changes,
+providing you have some other mechanism to differentiate attached devices. For
+example, you could use a wrapper script around tegrarcm that identifies the
+appropriate device by other means, then automatically calculates the USB port
+path using the procedures below, and passes the value to tegrarcm.
+
+To determine the USB port path of a device, you must plug it in and find the
+current USB bus and USB device number of the device, then map that to the USB
+port path. Simply run lsusb to find the current USB bus and device number. If
+you have multiple NVIDIA devices attached, you may need to unplug and replug
+the Tegra device to ensure you know which is which (all while not changing the
+state of any other USB devices so you don't confuse yourself).
+
+.nf
+$ lsusb
+...
+Bus 003 Device 039: ID 0955:7721 NVidia Corp.
+Bus 003 Device 045: ID 0955:7140 NVidia Corp.
+...
+fi
+
+Then, to determine the USB port path, do one of:
+
+.IP 1.
+
+Execute udevmadm on the USB device, and look for the DEVPATH entry. The
+final component in the path is the USB port path:
+
+.nf
+$ udevadm info /dev/bus/usb/003/045
+P: /devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10.4
+N: bus/usb/003/045
+E: BUSNUM=003
+E: DEVNUM=045
+E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10.4
+.fi
+
+.IP 2.
+
+Look at all the sub-directories of /sys/bus/usb/devices/* that do not
+contain either ":" or "usb". Each of these will contain a busnum and
+devnum file. Find the directory which matches the lsusb output, and use
+its name:
+
+.nf
+$ cat /sys/bus/usb/devices/3-10.4/busnum
+3
+$ cat /sys/bus/usb/devices/3-10.4/devnum
+45
+.fi
+
+Alternatively, you may already have udev rules that create a device node
+symlink for the device (after some specific identification algorithm). In
+that case, you can search the udev output for MAJOR/MINOR values, or
+/sys/bus/usb/devices/* directories for "dev" files, that match the device
+node the symlink points to.
+
+Once the port path is known, this value will not vary unless your USB
+connections are physically changed, so you can use it over and over
+without repeating the steps above.
 
 .SH EXAMPLES
 To download u-boot firmware to a Tegra20 seaboard:
-- 
1.9.1

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

* Re: [tegrarcm PATCH 1/3] Move all USB device matching logic into usb_match()
       [not found] ` <1444329510-23848-1-git-send-email-swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
  2015-10-08 18:38   ` [tegrarcm PATCH 2/3] Match USB port ID on re-enumeration Stephen Warren
  2015-10-08 18:38   ` [tegrarcm PATCH 3/3] Implement --usb-port-path cmdline option Stephen Warren
@ 2015-10-16 16:57   ` Stephen Warren
  2 siblings, 0 replies; 4+ messages in thread
From: Stephen Warren @ 2015-10-16 16:57 UTC (permalink / raw)
  To: Allen Martin; +Cc: Stephen Warren, linux-tegra-u79uwXL29TY76Z2rM5mHXA

On 10/08/2015 12:38 PM, Stephen Warren wrote:
> This consolidates the matching logic into one place, which will make
> future enhancements to the logic simpler.

I've applied this series.

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

end of thread, other threads:[~2015-10-16 16:57 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-08 18:38 [tegrarcm PATCH 1/3] Move all USB device matching logic into usb_match() Stephen Warren
     [not found] ` <1444329510-23848-1-git-send-email-swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2015-10-08 18:38   ` [tegrarcm PATCH 2/3] Match USB port ID on re-enumeration Stephen Warren
2015-10-08 18:38   ` [tegrarcm PATCH 3/3] Implement --usb-port-path cmdline option Stephen Warren
2015-10-16 16:57   ` [tegrarcm PATCH 1/3] Move all USB device matching logic into usb_match() Stephen Warren

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).