Friday, March 25, 2016

67 Steps

<< Prev: Compiler Dysfunction       Next: Wait Queues >>

So there may have been some bumps in the road, but I felt like on the whole, I'd taken two steps forward. Obviously, then, I was due for a step back. (Have no fear, you won't have to wait long for this one...)

Anyway, I figured, what I'd really like to do next is turn on the hardware. You, know, do whatever needs to be done to light it up, even if it doesn't connect to anything. That would be a solid step.

I had the firmware file, identified, loaded, and parsed. But I wasn't exactly clear on how to send that to the hardware. I knew there had to be something in there to set up a block of DMA memory, and to set up an interrupt handler, and things like that. But at best I knew of a few little pieces, without much of a big picture. I wasn't even really sure where it all started in the Linux driver. I mean, I had seen PCI device registration code, module startup code, and so on, but what really kicked everything off?

So, it seemed like the thing to do was find that start point, and trace the code from there until it was "up." I began poking around, and here's what I found:

The iwl_drv_init module initializer registers various PCI device definitions. Then if there's any matching hardware, the kernel calls the registered PCI probe method iwl_pci_probe in a pretty similar manner to OS X, and that's what kicks the whole thing off.

That part was easy enough.

Now iwl_pci_probe calls iwl_trans_pcie_alloc, which if I'm going to be generous, has on the order of 20 things it does. Some of them are the things I expected: Sets up PCIe bus mastering and DMA, registers an interrupt handler, etc. That was going to be challenging enough to convert. Still, even with the extra stuff, I could be up to this challenge. So far so good.

Then iwl_pci_probe calls iwl_drv_start, which mainly kicks off the firmware loading and parsing. That I had mostly already converted. Yay!

But from there, it all sort of exploded.

Toward the end of the firmware loading, it calls the start function provided for the "op mode" (the firmware style, which for now would always be the MVM firmware for me). And that's where it gets ugly.

At that point, the process bounces back and forth between PCIe code, MVM firmware code, and generic driver code. Mostly there are layers upon layers, where the firmware code calls some generic code that resolves to PCIe code, which calls some generic code that resolves to MVM firmware code, and so on. I tried to count only calls that were non-trivial: not just performing some simple logic or calling just one other function or reducing to memory reads or writes. I also didn't count a call to any given function past the first time. I still got to nearly 50 major functions.

Worse were some of the convolutions. Interrupts were going up and down and up and down, there were command packets sent, calls to set various configuration bits spread out all over the place...

I get that there was an effort to make some of this stuff generic and reusable. It's not hardcoded to a specific firmware type, and it's not hardcoded to the PCIe bus (though, why not, since there's not another bus used?). Probably this would look sorta sensible if (when?) I convert it to C++ and you get a generic base class with a couple specific subclasses.

But to try to understand the startup process, it's a huge mess. What are the odds it's really all correct? And if anything goes wrong, how are you supposed to figure out where?

I don't know, I mean, obviously it works when you run this thing in Linux. But the complexity just rubs me the wrong way. Startup is the kind of thing I'd strive to make really simple, not really, er, "normalized."

In practical terms, it's going to be really hard to implement because it touches so many parts of so many files at one point or another. And yes, somewhere it in there it sends the firmware chunks I parsed out to the hardware -- but don't ask me to point to where in the list that happens. I just recall that it's in there somewhere.

So that's the step back. I'm not even talking about connecting to a wireless network yet, I'm just trying to turn the thing on. And all this progress I made on firmware loading, that's less than one step out of fifty. Yippee.

Reference


Here's my list of steps in the startup process. You can say a little prayer for me after you read it. (Even if it's only to the Flying Spaghetti Monster -- I'll take his help too.)

<< Prev: Compiler Dysfunction       Next: Wait Queues >>

1 comment:

  1. Hi Aaron! I just came here to give you a heads up! I think what you are doing is great and although it seems like ways to go I hope to have a somewhat functional wifi driver for these cards at some point in the future. It looks like rocket science to me! Love to read your posts anyway. Thanks for all your efforts on this!

    ReplyDelete