[RFC PATCH 1/1] USB: myriad-ma24xx-vsc: Firmware loader driver for USB Myriad ma24xx

Rhys Kidd rhyskidd at gmail.com
Mon Sep 16 21:03:41 AEST 2019


The Myriad ma24xx in USB Intel Neural Compute Stick and Intel Neural
Compute Stick 2 provides an API to accelerate AI inference calculations
on the dedicated SHAVE VLIW vector co-processors, which are orchestrated
by one or more LEON SPARC v8 real time cores.

However, they need firmware to be loaded beforehand. An uninitialised
Myriad ma24xx presents with a distinctive USB ID. After firmware
loading, the device detaches from the USB bus and reattaches with a new
device ID. It can then be claimed by the usermode driver.

Signed-off-by: Rhys Kidd <rhyskidd at gmail.com>
---
 MAINTAINERS                          |   6 +
 drivers/usb/misc/Kconfig             |   8 ++
 drivers/usb/misc/Makefile            |   1 +
 drivers/usb/misc/myriad-ma24xx-vsc.c | 171 +++++++++++++++++++++++++++
 4 files changed, 186 insertions(+)
 create mode 100644 drivers/usb/misc/myriad-ma24xx-vsc.c

diff --git a/MAINTAINERS b/MAINTAINERS
index a50e97a63bc8..2c3ab39ac26a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16682,6 +16682,12 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:	Maintained
 F:	sound/usb/midi.*
 
+USB MYRIAD MA24XX FIRMWARE DRIVER
+M:	Rhys Kidd <rhyskidd at gmail.com>
+L:	linux-usb at vger.kernel.org
+S:	Maintained
+F:	drivers/usb/misc/myriad-ma24xx-vsc.c
+
 USB NETWORKING DRIVERS
 L:	linux-usb at vger.kernel.org
 S:	Odd Fixes
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index bdae62b2ffe0..5d600fb8ac50 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -275,3 +275,11 @@ config USB_CHAOSKEY
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called chaoskey.
+
+config USB_MYRIAD_MA24XX_VSC
+	tristate "USB Intel Myriad MA24xx firmware loading support"
+	select FW_LOADER
+	help
+	  This driver loads firmware for Myriad ma24xx AI inference accelerators, as
+	  found in the USB Intel Neural Compute Stick (ma2450) and Intel Neural
+	  Compute Stick 2 (ma2485).
\ No newline at end of file
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 109f54f5b9aa..e19d1348c5b6 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_USB_ISIGHTFW)		+= isight_firmware.o
 obj-$(CONFIG_USB_LCD)			+= usblcd.o
 obj-$(CONFIG_USB_LD)			+= ldusb.o
 obj-$(CONFIG_USB_LEGOTOWER)		+= legousbtower.o
+obj-$(CONFIG_USB_MYRIAD_MA24XX_VSC)    += myriad-ma24xx-vsc.o
 obj-$(CONFIG_USB_RIO500)		+= rio500.o
 obj-$(CONFIG_USB_TEST)			+= usbtest.o
 obj-$(CONFIG_USB_EHSET_TEST_FIXTURE)    += ehset.o
diff --git a/drivers/usb/misc/myriad-ma24xx-vsc.c b/drivers/usb/misc/myriad-ma24xx-vsc.c
new file mode 100644
index 000000000000..f516c236a8f5
--- /dev/null
+++ b/drivers/usb/misc/myriad-ma24xx-vsc.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for loading USB Myriad ma24xx firmware
+ *
+ * Copyright (C) 2018 Rhys Kidd <rhyskidd at gmail.com>
+ *
+ * The Myriad ma24xx in USB Intel Neural Compute Stick and Intel Neural
+ * Compute Stick 2 provides an API to accelerate AI inference calculations
+ * on the dedicated SHAVE VLIW vector co-processors, which are orchestrated
+ * by one or more LEON SPARC v8 real time cores.
+ *
+ * However, they need firmware to be loaded beforehand. An uninitialised
+ * Myriad ma24xx presents with a distinctive USB ID. After firmware
+ * loading, the device detaches from the USB bus and reattaches with a new
+ * device ID. It can then be claimed by the usermode driver.
+ *
+ * The firmware is non-free and must be extracted by the user.
+ */
+
+/* Standard include files */
+#include <linux/errno.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#define usb_dbg(usb_if, format, arg...) \
+	dev_dbg(&(usb_if)->dev, format, ## arg)
+
+#define usb_err(usb_if, format, arg...) \
+	dev_err(&(usb_if)->dev, format, ## arg)
+
+/* Version Information */
+#define DRIVER_AUTHOR "Rhys Kidd <rhyskidd at gmail.com>"
+#define DRIVER_DESC   "Driver for loading USB Myriad ma24xx firmware"
+#define DRIVER_SHORT  "myriad_ma24xx_vsc"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define FW_DIR "myriad/"
+#define MA2450_FIRMWARE FW_DIR "mvncapi-2450.mvcmd"
+#define MA2480_FIRMWARE FW_DIR "mvncapi-2480.mvcmd"
+
+MODULE_FIRMWARE(MA2450_FIRMWARE);
+MODULE_FIRMWARE(MA2480_FIRMWARE);
+
+enum {
+	MA2450FW = 0,
+	MA2480FW
+};
+
+/* macros for struct usb_device_id */
+#define MYRIAD_CHIP_VERSION(x) \
+	((x)->driver_info & 0xf)
+
+#define MYRIAD_VID  0x03e7   /* Movidius Ltd, an Intel company */
+#define MA2450_PID  0x2150   /* ma2450 VSC loopback device, without fw */
+#define MA2485_PID  0x2485   /* ma2485 VSC loopback device, without fw */
+
+#define MYRIAD_BUF_LEN 512   /* max size of USB_SPEED_HIGH packet */
+#define WRITE_TIMEOUT  2000  /* milliseconds */
+
+static const struct usb_device_id id_table[] = {
+	{ USB_DEVICE(MYRIAD_VID, MA2450_PID), .driver_info = MA2450FW },
+	{ USB_DEVICE(MYRIAD_VID, MA2485_PID), .driver_info = MA2480FW },
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static int myriad_ma24xx_vsc_probe(struct usb_interface *intf,
+				    const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_host_interface *altsetting = intf->cur_altsetting;
+	struct usb_endpoint_descriptor *epd;
+	int out_ep, res, size;
+	const struct firmware *firmware = NULL;
+	const u8 *ptr;
+	int offset, ret = 0;
+	char *buf;
+	char *fw_family_name;
+
+	usb_dbg(intf, "probe %s-%s", dev->product, dev->serial);
+
+	/* Find the first bulk OUT endpoint and its packet size */
+	res = usb_find_bulk_out_endpoint(altsetting, &epd);
+	if (res) {
+		usb_err(intf, "no OUT endpoint found");
+		return res;
+	}
+
+	out_ep = usb_endpoint_num(epd);
+	size = usb_endpoint_maxp(epd);
+
+	/* Validate endpoint and size */
+	if (size <= 0) {
+		usb_err(intf, "invalid size (%d)", size);
+		return -ENODEV;
+	}
+
+	if (size > MYRIAD_BUF_LEN) {
+		usb_dbg(intf, "size reduced %d -> %d\n", size, MYRIAD_BUF_LEN);
+		size = MYRIAD_BUF_LEN;
+	}
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	switch (MYRIAD_CHIP_VERSION(id)) {
+	case MA2450FW:
+		fw_family_name = MA2450_FIRMWARE;
+		break;
+	case MA2480FW:
+		fw_family_name = MA2480_FIRMWARE;
+		break;
+	default:
+		usb_err(intf, "unsupported myriad ma24xx firmware family\n");
+		return -ENODEV;
+	}
+
+	if (request_firmware(&firmware, fw_family_name, &dev->dev) != 0) {
+		usb_err(intf, "unable to load myriad ma24xx firmware\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	ptr = firmware->data;
+
+	/* Handle the sending of firmware */
+	usb_dbg(intf, "starting firmware load...\n");
+
+	for (offset = 0; offset < firmware->size; offset += size) {
+		int thislen = min_t(int, size, firmware->size - offset);
+
+		memcpy(buf, firmware->data + offset, thislen);
+
+		if (usb_bulk_msg(dev,
+				 usb_sndbulkpipe(dev, out_ep),
+				 buf,
+				 thislen,
+				 NULL,
+				 WRITE_TIMEOUT) != 0) {
+			usb_err(intf, "failed to initialise myriad ma24xx firmware\n");
+			ret = -ENODEV;
+			goto out;
+		}
+	}
+	usb_dbg(intf, "firmware uploaded (%zu bytes)\n", firmware->size);
+
+out:
+	kfree(buf);
+	release_firmware(firmware);
+	return ret;
+}
+
+static void myriad_ma24xx_vsc_disconnect(struct usb_interface *intf)
+{
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver myriad_ma24xx_vsc_driver = {
+	.name = DRIVER_SHORT,
+	.probe = myriad_ma24xx_vsc_probe,
+	.disconnect = myriad_ma24xx_vsc_disconnect,
+	.id_table = id_table,
+};
+
+module_usb_driver(myriad_ma24xx_vsc_driver);
-- 
2.20.1



More information about the Linux-accelerators mailing list