Fixing UMTS upload performance on Linux

UMTS, or better said, 3G, is a convenient way to connect to the Internet while you are travelling. However, the upload speed in Linux is only half as large as in Windows – but this can be fixed by a Kernel patch.

The background

3G is the so called third generation mobile technology, best known for it’s well known standard UMTS. Using that technology users are able to get quite fast Internet connections via mobile phone technology. In fact, in Germany the UMTS upload is currently faster than most of the ADSL connections you can get.

However, recently my company (credativ GmbH) was contacted by a customer who reported that the UMTS upload speed with Linux is rather slow compared with the upload speed on Windows. We did some tests and the result was disturbing: the factor is roughly two. While we had upload speeds of 1200 kbit/s on Windows XP, Linux only did less than 600 kbit/s (both using HSUPA). Hardware problems where out of question because we tested with a rather large set of UMTS hardware. We also tried different Linux distributions, different computers and so on. Additionally, the problem was at least verified by three (!) labs around the world: one lab of a major German mobile pone company and one lab each of two international hardware vendors. (And yes, it was me who tried to keep track of all the tests and people who are spread on several continents in different time zones 😀 ).

The fix

In the end, however, we were able to produce a rather simple patch to fix this problem. The upload speed in our test is now almost as large in Linux as in Windows, and this result was verified by the mentioned labs. The patch is:

--- drivers/usb/serial/option.c.old        2008-11-27 12:45:50.173275119 +0100
+++ drivers/usb/serial/option.c    2008-11-27 12:46:06.089274050 +0100
@@ -487,9 +487,9 @@
 /* per port private data */

 #define N_IN_URB 4
-#define N_OUT_URB 1
+#define N_OUT_URB 4
 #define IN_BUFLEN 4096
-#define OUT_BUFLEN 128
+#define OUT_BUFLEN 4096

 struct option_port_private {
        /* Input endpoints and buffer for this port */

This is around line 490 in drivers/usb/serial/option.c in the current linux tree.

At this point I’d like to plastinka who pointed me to that part of the kernel to fix the problem. I owe you something! 🙂

The problem: getting the fix upstream

The problem is now: how to get this fix upstream? I’m certainly not a kernel developer, and I could not even explain why this patch fixes the problem – I “just” have the test results. Joining the kernel list might also not be the best idea when I am not even a programmer.

So I decided to send the patch to the Red Hat guys – they have lots of developers, good connections to upstream, and I know how to talk to them. It’s bug #473252, let’s see what happens. In case you experience similar problems, send this patch upstream via your distribution, maybe that helps as well.


6 thoughts on “Fixing UMTS upload performance on Linux”

  1. Hum, you should correct some sentences in the text which are really confusing…
    In the abstract you have:
    “However, the upload speed in Linux is only half as large as in Linux”. 🙂
    But more importantly, you say:
    “a customer who reported that the UMTS upload speed with Windows is rather slow compared with the upload speed on Linux.” It seems you said the opposite of what you intended… Quite confusing 🙂

    I think you did well to report that to RedHat. Joining a mailing list just to report something is not the best solution and can be a pain.

  2. Explaining this is easy even without understanding anything more. In fact I can think of two explanations. I don’t know which is correct, but I think you can narrow down on which (or a combonation)

    -#define N_OUT_URB 1
    +#define N_OUT_URB 4

    This looks like transmit buffers. Your system sends data, and cannot send more until the previous set of data is sent. After the change your system can prepare 3 transmit buffers while sending one. More importantly you can start sending the second buffer while the first is still being received. (The speed of light is slow compared to how fast you can send data, it is common to have more than one byte in a wire at a time, so long as you can separate the bits on the other end this is fine)

    -#define OUT_BUFLEN 128
    +#define OUT_BUFLEN 4096

    Changes the buffers so you send more at a time. I’m not sure what protocols you are testing, but 128 bytes means that much of your data is lost to header, for each transmission. If you are talking TCP/IP (version 4), and no other fragmentation, almost half of each transmission is header! With the 4096 buffer most of the transmission is data.

    I hope this makes sense.

  3. What if you use option.ko instead of usbserial.ko? I recall reading that option.ko is a serial usb drive made for GSM devices. It’s design includes a large buffer.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s