Skip to contentSkip to conversation

Add Qualcomm Gobi 2000/3000 driver.

PATCH In review Elly Jones 2 participants 2 messages Apr 13, 2011

Subsystems (3)
lore
Share & tools
lore

Elly Jones

author
#0 lore raw

PATCH 1/1 Add Qualcomm Gobi 2000/3000 driver.

From: Elizabeth Jones <[email protected]>

This is a rewrite and unification of the Qualcomm Gobi 2000 and Gobi 3000 drivers, available at:
https://www.codeaurora.org/patches/quic/gobi/VT773.Gobi2000Drivers_03022011.tar.gz
https://www.codeaurora.org/patches/quic/gobi/Gobi3000Drivers1040_03022011.tar.gz

Both devices need firmware loaded in order to be useful.

BUG=chromium-os:5521
TEST=suite_Cellular

Review URL: http://codereview.chromium.org/6539018

---
 drivers/net/usb/Kconfig          |    6 +
 drivers/net/usb/Makefile         |    1 +
 drivers/net/usb/gobi/Makefile    |    2 +
 drivers/net/usb/gobi/README      |   30 +
 drivers/net/usb/gobi/qcusbnet.c  |  717 +++++++++++++++++
 drivers/net/usb/gobi/qcusbnet.h  |   28 +
 drivers/net/usb/gobi/qmi.c       |  358 +++++++++
 drivers/net/usb/gobi/qmi.h       |   67 ++
 drivers/net/usb/gobi/qmidevice.c | 1562 ++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/gobi/qmidevice.h |   35 +
 drivers/net/usb/gobi/structs.h   |   96 +++
 11 files changed, 2902 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/usb/gobi/Makefile
 create mode 100644 drivers/net/usb/gobi/README
 create mode 100644 drivers/net/usb/gobi/qcusbnet.c
 create mode 100644 drivers/net/usb/gobi/qcusbnet.h
 create mode 100644 drivers/net/usb/gobi/qmi.c
 create mode 100644 drivers/net/usb/gobi/qmi.h
 create mode 100644 drivers/net/usb/gobi/qmidevice.c
 create mode 100644 drivers/net/usb/gobi/qmidevice.h
 create mode 100644 drivers/net/usb/gobi/structs.h
drivers/net/usb/Kconfig +6 -0
index 3ec22c3..3f43266 100644
@@ -448,4 +448,10 @@ config USB_VL600
 
 	  http://ubuntuforums.org/showpost.php?p=10589647&postcount=17
 
+config USB_NET_GOBI
+	tristate "Qualcomm Gobi"
+	depends on USB_USBNET
+	help
+	  Qualcomm Gobi 2k/3k support.
+
 endmenu
drivers/net/usb/Makefile +1 -0
index c7ec8a5..dd1f24c 100644
@@ -28,4 +28,5 @@ obj-$(CONFIG_USB_SIERRA_NET)	+= sierra_net.o
 obj-$(CONFIG_USB_NET_CX82310_ETH)	+= cx82310_eth.o
 obj-$(CONFIG_USB_NET_CDC_NCM)	+= cdc_ncm.o
 obj-$(CONFIG_USB_VL600)		+= lg-vl600.o
+obj-$(CONFIG_USB_NET_GOBI) += gobi/
 
drivers/net/usb/gobi/Makefile new file +2 -0
new file mode 100644
index 0000000..a6635f6
@@ -0,0 +1,2 @@
+obj-$(CONFIG_USB_NET_GOBI) += gobi.o
+gobi-objs += qcusbnet.o qmidevice.o qmi.o
drivers/net/usb/gobi/README new file +30 -0
new file mode 100644
index 0000000..113c523
@@ -0,0 +1,30 @@
+Qualcomm Gobi 2000 driver
+-------------------------
+
+This directory contains a driver for the Qualcomm Gobi 2000 CDMA/GSM modem. The
+device speaks a protocol called QMI with its host; this driver's responsibility
+is to multiplex transactions over QMI connections. Note that the relatively
+simple encoding defined in qmi.h and qmi.c is only the encapsulating protocol;
+the device speaks a more complex set of protocols embodied in the closed-source
+Gobi SDK which are necessary to use advanced features of the device.
+Furthermore, firmware (also proprietary) is needed to make the device useful. An
+open-source firmware loader exists: http://www.codon.org.uk/~mjg59/gobi_loader/.
+
+Interfaces:
+This driver presents two separate interfaces to userspace:
+- usbN, an ordinary usb network interface
+- /dev/qcqmiN, a channel to speak to the device using QMI messages
+The latter is for use by the Gobi SDK.
+
+History:
+This driver's original incarnation (of which this is a rewrite) was released
+under GPLv2 by Qualcomm on their Code Aurora site:
+https://www.codeaurora.org/gitweb/quic/la/?p=kernel/msm.git;a=commit;h=b5135a880f8942f990e8c2e383f7f876beacc55b
+
+Issues:
+Help and commentary on any of the issues below would be appreciated.
+- The locking in devqmi_close() is not threadsafe: we're walking a list of tasks
+  without holding a lock on the list. The original driver did this and I have
+  left it intact because I do not fully understand what's going on here.
+- The driver seems to deadlock very occasionally (one in ~6000 reboots during
+  stress testing). I've had no luck tracking this problem down.
drivers/net/usb/gobi/qcusbnet.c new file +717 -0

717 lines not on this page · raw message

drivers/net/usb/gobi/qcusbnet.h new file +28 -0
new file mode 100644
index 0000000..00c3a7e
@@ -0,0 +1,28 @@
+/* qcusbnet.h - gobi network device header
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef QCUSBNET_QCUSBNET_H
+#define QCUSBNET_QCUSBNET_H
+
+#include "structs.h"
+
+extern int qc_suspend(struct usb_interface *iface, pm_message_t event);
+extern void qcusbnet_put(struct qcusbnet *dev);
+extern struct qcusbnet *qcusbnet_get(struct qcusbnet *dev);
+
+#endif /* !QCUSBNET_QCUSBNET_H */
drivers/net/usb/gobi/qmi.c new file +358 -0

358 lines not on this page · raw message

drivers/net/usb/gobi/qmi.h new file +67 -0

67 lines not on this page · raw message

drivers/net/usb/gobi/qmidevice.c new file +1562 -0

1,562 lines not on this page · raw message

drivers/net/usb/gobi/qmidevice.h new file +35 -0
new file mode 100644
index 0000000..5274a0d
@@ -0,0 +1,35 @@
+/* qmidevice.h - gobi QMI device header
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef QCUSBNET_QMIDEVICE_H
+#define QCUSBNET_QMIDEVICE_H
+
+#include "structs.h"
+#include "qmi.h"
+
+void qc_setdown(struct qcusbnet *dev, u8 reason);
+void qc_cleardown(struct qcusbnet *dev, u8 reason);
+bool qc_isdown(struct qcusbnet *dev, u8 reason);
+
+int qc_startread(struct qcusbnet *dev);
+void qc_stopread(struct qcusbnet *dev);
+
+int qc_register(struct qcusbnet *dev);
+void qc_deregister(struct qcusbnet *dev);
+
+#endif /* !QCUSBNET_QMIDEVICE_H */
drivers/net/usb/gobi/structs.h new file +96 -0

96 lines not on this page · raw message

Signature · 1 line
1.7.3.1
maintainer
#1 lore raw

From: Elly Jones <[email protected]>
Date: Wed, 13 Apr 2011 15:00:24 -0400

drivers/net/usb/gobi/qcusbnet.c line 48

Quoted 6 lines
drivers/net/usb/gobi/qcusbnet.c new file +6 -0
+void qcusbnet_put(struct qcusbnet *dev)
+{
+	mutex_lock(&qcusbnet_lock);
+	kref_put(&dev->refcount, free_dev);
+	mutex_unlock(&qcusbnet_lock);
+}

This locking looks excessive, and shouldn't be needed simply to release a reference to an object.

drivers/net/usb/gobi/qcusbnet.c line 77

Quoted 7 lines
drivers/net/usb/gobi/qcusbnet.c new file +7 -0
+int qc_suspend(struct usb_interface *iface, pm_message_t event)
+{
+	struct usbnet *usbnet;
+	struct qcusbnet *dev;
+
+	if (!iface)
+		return -ENOMEM;

When is qc_suspend() called with a NULL iface arguemnt?

drivers/net/usb/gobi/qcusbnet.c line 119

Quoted 9 lines
drivers/net/usb/gobi/qcusbnet.c new file +9 -0
+static int qc_resume(struct usb_interface *iface)
+{
+	struct usbnet *usbnet;
+	struct qcusbnet *dev;
+	int ret;
+	int oldstate;
+
+	if (iface == 0)
+		return -ENOMEM;

Likewise, and if it is needed use consistent tests for NULL. Testing against the integer "0" is definitely the wrong way.

drivers/net/usb/gobi/qcusbnet.c line 191

Quoted 2 lines
drivers/net/usb/gobi/qcusbnet.c new file +2 -0
+		if (usb_endpoint_dir_in(&endpoint->desc)
+		&&  !usb_endpoint_xfer_int(&endpoint->desc)) {

Please do it like this:

	if (A &&
	    B) {

Not like:

	if (A
	&&  B

the latter looks awful at best.

drivers/net/usb/gobi/qcusbnet.c line 271

Quoted 10 lines
drivers/net/usb/gobi/qcusbnet.c new file +10 -0
+	if (!usbnet || !usbnet->net) {
+		DBG("failed to get usbnet device\n");
+		return;
+	}
+
+	dev = (struct qcusbnet *)usbnet->data[0];
+	if (!dev) {
+		DBG("failed to get QMIDevice\n");
+		return;
+	}

These NULL checks are everywhere! Do we really _ever_ create a full registered netdev with any of these things being NULL? I severely doubt it.

drivers/net/usb/gobi/qcusbnet.c line 304

Quoted 12 lines
drivers/net/usb/gobi/qcusbnet.c new file +12 -0
+static int qcnet_worker(void *arg)
+{
+	struct list_head *node, *tmp;
+	unsigned long activeflags, listflags;
+	struct urbreq *req;
+	int status;
+	struct usb_device *usbdev;
+	struct worker *worker = arg;
+	if (!worker) {
+		DBG("passed null pointer\n");
+		return -EINVAL;
+	}

This NULL check is impossible, you register the worker function with an explicit &dev->worker argument, so seeing NULL here is impossible.

Quoted 8 lines
drivers/net/usb/gobi/qcusbnet.c new file +8 -0
+static int qcnet_startxmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	unsigned long listflags;
+	struct qcusbnet *dev;
+	struct worker *worker;
+	struct urbreq *req;
+	void *data;
+	struct usbnet *usbnet = netdev_priv(netdev);

drivers/net/usb/gobi/qcusbnet.c line 413

Quoted 10 lines
drivers/net/usb/gobi/qcusbnet.c new file +10 -0
+
+	DBG("\n");
+
+	if (!usbnet || !usbnet->net) {
+		DBG("failed to get usbnet device\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	dev = (struct qcusbnet *)usbnet->data[0];
+	if (!dev) {

Again, kill this NULL check noise, all of it can't be necessary.

drivers/net/usb/gobi/qcusbnet.c line 457

Quoted 1 line
drivers/net/usb/gobi/qcusbnet.c new file +1 -0
+	netdev->trans_start = jiffies;

Setting netdev->trans_start in drivers is expensive and deprecated, please set netdev_queue->trans_start instead.

Quoted 6 lines
drivers/net/usb/gobi/qcusbnet.c new file +6 -0
+static int qcnet_open(struct net_device *netdev)
+{
+	int status = 0;
+	struct qcusbnet *dev;
+	struct usbnet *usbnet = netdev_priv(netdev);
+

drivers/net/usb/gobi/qcusbnet.c line 478

Quoted 10 lines
drivers/net/usb/gobi/qcusbnet.c new file +10 -0
+	if (!usbnet) {
+		DBG("failed to get usbnet device\n");
+		return -ENXIO;
+	}
+
+	dev = (struct qcusbnet *)usbnet->data[0];
+	if (!dev) {
+		DBG("failed to get QMIDevice\n");
+		return -ENXIO;
+	}

Again, excessive NULL checks.

Quoted 5 lines
drivers/net/usb/gobi/qcusbnet.c new file +5 -0
+int qcnet_stop(struct net_device *netdev)
+{
+	struct qcusbnet *dev;
+	struct usbnet *usbnet = netdev_priv(netdev);
+

drivers/net/usb/gobi/qcusbnet.c line 522

Quoted 10 lines
drivers/net/usb/gobi/qcusbnet.c new file +10 -0
+	if (!usbnet || !usbnet->net) {
+		DBG("failed to get netdevice\n");
+		return -ENXIO;
+	}
+
+	dev = (struct qcusbnet *)usbnet->data[0];
+	if (!dev) {
+		DBG("failed to get QMIDevice\n");
+		return -ENXIO;
+	}

Here too.

drivers/net/usb/gobi/qcusbnet.c line 591

Quoted 9 lines
drivers/net/usb/gobi/qcusbnet.c new file +9 -0
+static u8 nibble(unsigned char c)
+{
+	if (likely(isdigit(c)))
+		return c - '0';
+	c = toupper(c);
+	if (likely(isxdigit(c)))
+		return 10 + c - 'A';
+	return 0;
+}

Remove this function and use hex_to_bin() instead.