Marvel 88W8686 SDIO WiFi Integration

From RidgeRun Developer Connection
Jump to: navigation, search

Add chip code files to target file system

Marvell should have supplied the 88W8686 chip code files with the hardware. These files need to be copied to target file system, with a minor file rename. The driver expects to find these files in /lib/firmware on the target file system.

mkdir -p $DEVDIR/fs/overlay/lib/firmware 
cp /tmp/helper_sd.bin $DEVDIR/fs/overlay/lib/firmware/sd8686_helper.bin
cp /tmp/sd8686.bin $DEVDIR/fs/overlay/lib/firmware

files="$DEVDIR/fs/overlay/lib $DEVDIR/fs/overlay/lib/firmware $DEVDIR/fs/overlay/lib/firmware/sd8686_helper.bin $DEVDIR/fs/overlay/lib/firmware/sd8686.bin"
svn add $files
svn ci -m "Added code images for 88W8686 chipset" $files

Enable kernel drivers

Configure the kernel so there variable are set as follows:


Enable helper applications

Configure the Wifi tools so they get built.


SD8686 as a WiFi client

Runtime driver module loading

Boot target hardware without wifi module installed. Install module. You should see:

mmc0: new SDIO card at address 0001


mmc1: new SDIO card at address 0001

depending on which SD slot is used.

Verifying 88W8686 chip properly detected

On a DM365, the following entries should exist in sysfs.

For SD slot 0:

cd /sys/devices/platform/davinci_mmc.0/mmc_host/mmc0/mmc0:0001/mmc0:0001:1
echo class: `cat class`, vendor: `cat vendor`, device: `cat device`

For SD slot 1:

cd /sys/devices/platform/davinci_mmc.1/mmc_host/mmc1/mmc1:0001/mmc1:0001:1
echo class: `cat class`, vendor: `cat vendor`, device: `cat device`

The output should be:

class: 0x07, vendor: 0x02df, device: 0x9103

Verifying SDIO hardware interface configuration

The debugfs file system contains entries that contain the current settings for the MMC/SD/SDIO interface of interest.

mount -t debugfs none /sys/kernel/debug
cat /sys/kernel/debug/mmc0/ios
cat /sys/kernel/debug/mmc1/ios

Installing Libertas WiFi module

modprobe libertas

Output will only be generated if there is an error.

Installing Libertas SDIO module

modprobe libertas_sdio helper_name=/lib/firmware/sd8686_helper.bin fw_name=/lib/firmware/sd8686.bin

You should see:

Libertas SDIO driver
libertas_sdio: Copyright Pierre Ossman
libertas_sdio mmc0:0001:1: firmware: requesting /lib/firmware/sd8686_helper.bin
libertas_sdio mmc0:0001:1: firmware: requesting /lib/firmware/sd8686.bin
libertas: 00:19:88:3d:d3:77, fw 9.70.3p36, cap 0x00000303
libertas: wlan0: Marvell WLAN 802.11 adapter

If you don't see any output, you may need to increase the printk debug level:

echo 8 > /proc/sys/kernel/printk

or you can look in the kernel message buffer

dmesg | tail -n 6

Verifying wlan0 exists

Make sure Linux network interface and wireless LAN interface are both found

ifconfig wlan0
iwconfig wlan0

You should get output like:

wlan0     Link encap:Ethernet  HWaddr 00:19:88:3D:D3:77  
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

and for iwconfig, the output will be similar to:

wlan0     IEEE 802.11b/g  ESSID:""  
          Mode:Managed  Frequency:2.412 GHz  Access Point: Not-Associated   
          Bit Rate:0 kb/s   Tx-Power=15 dBm   
          Retry short limit:8   RTS thr=2347 B   Fragment thr=2346 B   
          Encryption key:off
          Power Management:off
          Link Quality:0  Signal level:0  Noise level:0
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0

Power on WiFi sub-system

ifconfig wlan0 up

No output will be generated if successful.

Scan for access points

iwlist wlan0 scan

which lists access points that are in range, like:

wlan0     Scan completed :
          Cell 01 - Address: 00:12:25:57:61:B5
                    Frequency:2.462 GHz (Channel 11)
                    Quality=97/100  Signal level=-28 dBm  Noise level=-96 dBm
                    Encryption key:off
                    Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 18 Mb/s
                              24 Mb/s; 36 Mb/s; 54 Mb/s; 6 Mb/s; 9 Mb/s
                              12 Mb/s; 48 Mb/s

Attaching WiFi to access point

Security disabled

iwconfig wlan0 essid "Hawley"

WEP security

iwconfig wlan0 essid "Hawley"
iwconfig wlan0 key 0001020304

WPA security

mkdir -p /etc/wpa_supplicant
cat <<EOF >/etc/wpa_supplicant/wpa_supplicant.conf
# Example wpa_supplicant 
	psk="very secret passphrase"

wpa_supplicant -d -iwlan0 -c/etc/wpa_supplicant/wpa_supplicant.conf -Dwext &

With debug output enabled, you will have lots of information on what is not working if you run into a problem.

Verifying access point association

You can check you are associated with an access point using

iwconfig wlan0

With example output being:

wlan0     IEEE 802.11b/g  ESSID:"Baily"  
          Mode:Managed  Frequency:2.437 GHz  Access Point: 00:13:10:EA:BD:66   
          Bit Rate:1 Mb/s   Tx-Power=13 dBm   
          Retry short limit:8   RTS thr=2347 B   Fragment thr=2346 B   
          Encryption key:<too big>   Security mode:open
          Power Management:off
          Link Quality=95/100  Signal level=-44 dBm  Noise level=-89 dBm
          Rx invalid nwid:0  Rx invalid crypt:121  Rx invalid frag:0
          Tx excessive retries:6  Invalid misc:13   Missed beacon:0

If you are having trouble associating with an access point, I find connecting to the AP with my laptop is a good way to verify the AP is configured as expected.

Configuring IP networking

ifconfig wlan0
route add -net gw netmask dev wlan0
route -n

With example output:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface   U     0      0        0 eth0       U     0      0        0 wlan0         UG    0      0        0 wlan0         UG    0      0        0 eth0

Note that the routing table is traversed from top to bottom, so packets for the Internet will go out wlan0 since that entry is closer to the top.

Functional test

The Google nameserver, which supports ping, is at IP address

ping -c 5

Unconfiguring WiFi client mode of operation

ifconfig wlan0 down
rmmod libertas_sdio
rmmod libertas

SD8686 as a WiFi access point

Patch kernel

The following approach patches the SDIO IRQ handler is such a way that operation can switch between wifi client and micro access point by unloading and reloading drivers. The patch that came with the Marvell uap code broke wifi client mode of operation.

0) static struct sdio_driver sdio_uap points to uap_io_probe() and uap_io_remove() -- uap_io.c

1) uap_io_probe() get struct sdio_func *func -- uap_io.c

2) func-> card is struct mmc_card -- sdio_func.h

3) func -> card -> host is struct mmc_host -- include/linux/mmc/card.h

4) In struct mmc_host there is a back pointer to the card host -> card -- include/linux/mmc/host.h

5) card -> quirks in struct mmc_card allows unique aspects of a card to be recorded

6) The line that gets changed in drivers/mmc/core/sdio_irq.c

-	if (host->caps & MMC_CAP_SDIO_IRQ)
+	if ((host->caps & MMC_CAP_SDIO_IRQ) && (host->card->cis.vendor != MARVELL))

instead of testing card vendor against MARVELL, we can use quirks

+	if ((host->caps & MMC_CAP_SDIO_IRQ) && (!(host->card->quirks & MMC_QUIRK_SLOW_IRQS)))

7) Need to define MMC_QUIRK_SLOW_IRQ_PROCESSING in include/linux/mmc/card.h

#define MMC_QUIRK_SLOW_IRQS	(1<<1)		/* wait until all pending irqs processed before enabling irqs again */

8) in uap_io_probe() in uap_io.c, we can have really ugly code that mungs all the layers and records the quirk

+	if (func->card != NULL)
+		func->card->quirks |= MMC_QUIRK_SLOW_IRQ_PROCESSING;
+	else
+		printk(KERN_WARN " Unable to adjust SD8686 card handling properties\n");
	ret = sdio_claim_irq(func, uap_io_interrupt);

9) in uap_io_remove(), unrecord quirk

+	if (func->card != NULL)
+		func->card->quirks &= ~MMC_QUIRK_SLOW_IRQ_PROCESSING;

Load modules

cd /lib/modules/2.6.32-17-ridgerun/extra
insmod  uapio.ko
insmod uap8xxx.ko helper_name=/lib/firmware/sd8686_helper.bin fw_name=/lib/firmware/sd8686_ap.bin

Start station

Adjust the access point configuration by editing the /etc/uaputl.conf file. Instructions in $DEVDIR/proprietary/sd8686-uap/src/uap_src/README.

uaputl sys_config /etc/uaputl.conf
uaputl bss_start

Using another computer you should see Marvell Micro AP SSID as an available access point. You can monitor the access point using

uaputl sys_config
uaputl sta_list

Problems and how to fix them

uap_main.c error: struct net_device has no member named open

When building micro access point, you get a

sd8686-uap/src/uap_src/uap/uap_main.c:1460: error: 'struct net_device' has no member named 'open'

libertas: unable to identify card model

If installing the Libertas SDIO module produces

libertas_sdio: Libertas SDIO driver
libertas_sdio: Copyright Pierre Ossman
libertas: unable to identify card model

and the output of dmesg contains:

SDIO: ignoring broken CISTPL_VERS_1
mmc0: new SDIO card at address 0001
libertas enter: lbs_init_module()
libertas leave: lbs_init_module()
libertas enter: if_sdio_init_module()
libertas_sdio: Libertas SDIO driver
libertas_sdio: Copyright Pierre Ossman
libertas enter: if_sdio_probe()
libertas: unable to identify card model
libertas leave: if_sdio_init_module(), ret 0

You likely need a kernel patch.

davinci_mmc davinci_mmc.1: data write CRC error

When SD8686 SDIO card is inserted into the mmc1 slot on the TI DM365 EVM, the following error is reported

mmc1: new SDIO card at address 0001
libertas_sdio mmc1:0001:1: firmware: requesting /lib/firmware/sd8686_helper.bin
davinci_mmc davinci_mmc.1: data write CRC error
libertas: failed to load helper firmware
libertas_sdio: probe of mmc1:0001:1 failed with error -84

Solution to the problem unknown at this time.

Testing with hardware with one SD slot

If you can have u-boot active and remove the SD memory card, you can load and boot the kernel over the network, if that is available.

setenv bootargs2 console=ttyS0,115200n8  mem=99M root=/dev/nfs nfsroot= rw ip=dhcp

setenv setargs setenv bootargs \${bootargs2} ; setenv autostart no ; setenv autoload no ; dhcp ; setenv t 'setenv serverip ; tftp 0x82000000 kernel.uImage.tfischer.p.leo365 ; run setargs ; bootm 0x82000000' ; run t