How to learn the structure of Linux wireless drivers (mac80211)? - linux

There is so many structures in the Linux wireless driver mac80211. Things like struct net_device, struct ieee80211_hw, struct ieee80211_vif and struct ieee80211_local and so on. So many structures that I don't understand what information they contain and when them were initialized.
How can I learn about them and the whole architecture of wireless drivers?

You may want to check out Johannes Berg's (mac80211 maintainer) slides here.
They may be somewhat outdated but should give you a place to start.
A high level description of the Linux WiFi kernel stack:
It's important to understand there are 2 paths in which userspace communicates with the kernel when we're talking about WiFi:
Data path: the data being received is passed from the wireless driver to the netdev core (usually using netif_rx()). From there the net core will pass it through the TCP/IP stack code and will queue it on the relevant sockets from which the userspace process will read it. On the Tx path packets will be sent from the netdev core to the wireless driver using the ndo_start_xmit() callback. The driver registers (like other netdevices such as an ethernet driver) a set of operations callbacks by using the struct net_device_ops.
Control path: This path is how userspace controls the WiFi interface/device and performs operations like scan / authentication / association. The userspace interface is based on netlink and called nl80211 (see include/uapi/linux/nl80211.h). You can send commands and get events in response.
When you send an nl80211 command it gets initially handled by cfg80211 kernel module (it's code is under net/wireless and the handlers are in net/wireless/nl80211.c).
cfg80211 will usually call a lower level driver. In case of Full MAC hardware the specific HW driver is right below cfg80211. The driver below cfg80211 registers a set of ops with cfg80211 by using cfg80211_ops struct. For example see brcmfmac driver (drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c)
For Soft MAC hardware there's mac80211 which is a kernel module implementing the 802.11 MAC layer. In this case cfg80211 will talk to mac80211 which will in turn use the hardware specific lower level driver. An example of this is iwlwifi (For Intel chips).
mac80211 registers itself with cfg80211 by using the cfg80211_ops (see net/mac80211/cfg.c). The specific HW driver registers itself with mac80211 by using the ieee80211_ops struct (for example drivers/net/wireless/iwlwifi/mvm/mac80211.c).
Initialization of a new NIC you've connected occurs from the bottom up the stack. The HW specific driver will call mac80211's ieee80211_allow_hw() usually after probing the HW. ieee80211_alloc_hw() gets the size of private data struct used by the HW driver. It in turns calls cfg80211 wiphy_new() which does the actual allocation of space sufficient for the wiphy struct, the ieee80211_local struct (which is used by mac80211) and the HW driver private data (the layering is seen in ieee80211_alloc_hw code).
ieee80211_hw is an embedded struct within ieee80211_local which is "visible" to the the HW driver. All of these (wiphy, ieee80211_local, ieee80211_hw) represent a single physical device connected.
On top of a single physical device (also referred to as phy) you can set up multiple virtual interfaces. These are essentially what you know as wlan0 or wlan1 which you control with ifconfig. Each such virtual interface is represented by an ieee80211_vif. This struct also contains at the end private structs accessed by the HW driver. Multiple interfaces can be used to run something like a station on wlan0 and an AP on wlan1 (this is possible depending on the HW capabilities).

Related

why firmware is part of a driver. Is it important, Can I exclude it from a driver

First why firmware is important. For example in real drivers I see there is DMA or MMIO read/write is done, but normally driver code in Linux add firmware struct after requesting it from Kernel using request_firmware function.
why should I add firmware in PCI driver when i can read and write to device from driver using direct memory access. DMA is totally different and has nothing to do with firmware. DMA map device object to kernel virtual page and firmware struct object simple has read and write operations.which I don't know why they are needed. For example for typical driver this function is a struct of firmware write operations
typedef void (*my_driver_write_phy)(struct mydriver_private *o, int register, int val);
This function is registered as a callback and member of my driver's firmware struct. so I guess Kernel calls this function. But my question is, when does kernel call this function. is it used for additional features (please explain if it can be excluded) or is it called every time when data transfer happen from device to/from system including when DMA memory is accessed
So basically real question is: IS firmware required also for Direct Memory access? AND can it be excluded

What's the difference between streaming mappings and coherent mapping in DMA

According to Linux Device Drivers book author says something like: one have to make sure that DMA address mapping range between Operating system and The hardware should be equal
The first question that must be answered before attempting DMA is where the given device is
capable of such an operation on the current host
From Kernel.org it says
first step for The setup for streaming mappings is performed via a call to
int dma_set_mask(struct device *dev, u64 mask);
And first step for DMA coherent mapping/consistent allocations is performed via a call
to dma_set_coherent_mask()
In E1000E driver and also in RealTek drivers do both because they use this function call in probe function of pci driver
dma_set_mask_and_coherent
Which is for both streaming and coherent mapping informing kernel the bit mask supported by hardware 64
This is how RealTek Device driver enables both DMA mappings
dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
&tp->RxPhyAddr, GFP_KERNEL);
inside open function of net_device
And for streaming DMA mapping this used
alloc_pages_node // allocating Kernel page for DMA
dma_map_page(d, data, 0, R8169_RX_BUF_SIZE, DMA_FROM_DEVICE); //Enabling Streaming mappingg?
also in open function
My question is why two mappings for DMA, why real drivers use both Streaming and Coherent mappings?
Like in RealTek device it just use single page streaming mappings plus coherent mapping so basically its connecting Rx Descriptor Array represented by pointer with Coherent mapping and Page streaming mapping connected to an array which it calls Rx_databuff[256U] of type page *

Why all the pins on a chip are not GPIOs?

Documentation of GPIOs in Linux states:
A "General Purpose Input/Output" (GPIO) is a flexible software-controlled
digital signal. They are provided from many kinds of chip, and are familiar
to Linux developers working with embedded and custom hardware.
If we are capable of control the behavior of a pin, then why all the pins on a chip are not GPIOs?
OR
How can we provide functionality through software for a pin on chip?
Please explain.
When you design an integrated circuit (chip) you design with some component model in mind, those internal components may have specific needs that can not be reassigned among different pins, then those pins are fixed function.
For example pins related to memory controller have a very strict performance requirements set (in terms of signal integrity, toggle rate, output driver, capacitance), those pins are fixed function not reassignable, thus you can not use those pins for GPIO. If you do it you will end with a slower chip because the additional circuit change those values becoming unfeasible. Other example are power domain pins (those tipically called VCC, VDD, VEE, GND,).
Thats why GPIO pins are always shared with slow interfaces like SPI, I2C, SMBUS but never with fast interfaces like SATA, DDR, etc.
In other cases the only reason is because the chip doesnt make sense without a particular component, for example, given you must to have RAM memory, then RAM dedicated pins doesnt need to be reassignable because you never will implement the system without RAM memory and never will need reuse those pins for GPIO
All the pins in SOC are not GPIO. A specific group of pins mapped as GPIO. Other pins are configured for specific interfaces like DDR, SPI, I2C... etc, which includes clock, data and power supply pins. GPIO is generic pins can be used for any purpose based on user requirement. It can be used for handling IRQs, trigger Resets, Glow LEDs..etc.
for example, Consider a FPGA is connected to SOC via GPIOs. User need to program the FPGA via these GPIO pins. In SOC side user need to write a specific program with mentioned sequence to drive those GPIO to program the FPGA config file.

How does device mmap work in contrast to I/O address ports?

I was wondering if Linux sees a difference between mmap to a peripheral devices memory in comparision to reading/writing to the device via I/O Ports. From what I've learned in my Assembly class, we pretty much looked at I/O port addressing in the same light as memory addressing. So I suppose I was wondering if I were to rw to the I/O my port my device is connected to, is that the same thing mmaping to that devices memory?
Thanks
I/O ports are not memory. Some hardware (e.g. graphical cards) are interfaced thru the memory bus, not only thru the I/O port bus.
For hardware having a memory interface (that is, viewed as a range of memory to the CPU), you might use mmap.
The X11 server Xorg is very often mmap-ing the graphical cards.
I think the OP is confusing three things:
mmap() is a way for application programs to perform some operations on page registers and/or the MMU.
Memory mapped I/O is a hardware architecture concept: instead of having separate buses and operations for I/O, some area of the address space is dedicated to I/O operations. (the 68K processor family uses memory mapped I/O, and IBM's AIX too, IIRC).
DMA means that not only the CPU(s), but also the I/O devices can read and write to and from (parts of) physical memory.
The vm_area_struct contains vm_flags field. In case of the special mapping it contains VM_PFNMAP or VM_IO flags. See struct vm_area_struct, VM_PFNMAP and VM_IO definitions at LXR.

Mapping DMA interrupts in the linux kernel

I'm writing a kernel module for a powerpc SoC which contains a DMA controller. I want to map the DMA interrupts in the linux kernel. my DMA structure has two interrupts:
struct dma
{
u32 dma1;
u32 dma2;
}*dma;
I have memory mapped the DMA structure in the Kernel. I have used the function irq_of_parse_and_map() to get the virq number to the corresponding interrupts.
dma->dma1=irq_of_parse_and_map(ofdev->node,0);
dma->dma2=irq_of_parse_and_map(ofdev->node,1);
but i cant get the virq numbers for the above interrupts. What APIs might be available to access the VIRQ numbers?
PowerPC based system uses a Device Tree Blob (DTB), also referred as Device Tree Source (DTS), which is a database that represents the hardware components (Processor Configuration, Buses, Peripherals etc...) on a given board. Linux kernel during its bootup expects certain information on the hardware that it runs on. Hardware information is passed from DTB to kernel by the bootloader software (eg: u-boot) as per Open Firmware standard. Once kernel get the hardware information, it will do all the software setup as a part of the kernel initilization routine.
From here on if any kernel software component (eg: device driver) needs hardware detail, it should get it from the kernel by using a set of Open Firmware Standard Binary Interfaces. Some of them are listed below:
of_register_platform_driver() - Register driver for device
of_unregister_platform_driver() - Unregister driver for device
of_address_to_resource() - Obtain physical address of peripheral
of_get_property() - Find property with a given name for a given node
of_find_node_by_phandle() - Find a node given a phandle
irq_of_parse_and_map() - Parse and map an interrupt into linux virq space
of_irq_to_resourse() - Obtain virtual IRQ of peripheral
...
...
Now coming to the problem raised here. irq_of_parse_and_map() is used to parse and map an interrupt into linux virq space. Usually this will be done by the Interrupt Controller device driver of the system. Once the interrupt mapping is done, you can get the Interrupt Source virq by referring to of_irq_to_resource() call. This step will be required for registering interrupt handler to the interrupt source. So try using of_irq_to_resource() instead of irq_of_parse_and_map().
Ref:
Device Tree Blob: http://www.informit.com/articles/article.aspx?p=1647051&seqNum=5
Open Firmware: http://www.openfirmware.org/
OF IRQ Interface: linux-2.6/drivers/of/irq.c

Resources