OpenWrt Forum Archive

Topic: Optimized version of mmc.c

The content of this topic has been archived between 5 Jun 2014 and 7 Mar 2018. Unfortunately there are posts – most likely complete pages – missing.

Hi

Here is an optimized version of mmc.c.

Summury :
* Transfer bandwidth is now 850KB/s for WRITE and 450KB/s for READ on my WRT54GSv4@200Mhz + Sandisk 1GB SD.
* Best of all, it let the router usable while doing transfers from/to the card.
* More SD cards are now working, especially >=2GB cards.
* real MMCs should work now.

v1.3.2 binary (old) :
mmc driver v1.3.2 compiled for whiterussian GPIO2 (md5sum: 44dff17b051cae27eafdcb13dce53092)
mmc driver v1.3.2 compiled for whiterussian GPIO5 (md5sum: 854f0743e8fa4f455ede89a2bc1fd0be)
mmc driver v1.3.2 compiled for whiterussian buffalos (md5sum: fb6fbd378951d45c72a0a856ef097316)

v1.3.3 binary (stable) :
mmc driver v1.3.3 compiled for whiterussian GPIO2 (md5sum: fdf5ea0b3baf172e51ec8a7fc7c7be32)
mmc driver v1.3.3 compiled for whiterussian GPIO5 (md5sum: 195d8de0bb8797ff5b59fa04b558f001)
mmc driver v1.3.3 compiled for whiterussian buffalos (md5sum: 5bb6da4b650e5bb68d5d18747239326e)

v1.3.4 binary (current) :
mmc driver v1.3.4 compiled for whiterussian GPIO2 (md5sum: 4fe21d26f688315d5cfe01a94c019a2a)
mmc driver v1.3.4 compiled for whiterussian GPIO5 (md5sum: 0a17362d802ddf8d4d67815847836023)
mmc driver v1.3.4 compiled for whiterussian buffalos (md5sum: 74bffc93d999d8a502dce9589a270432)

v1.3.4 source code. All GPIOs (#defines are working again)

Versions:
* version v1.1: can write at 700KB/s. The trick is to use SPI's multi-block write.
* version v1.1.1: correcting a write bug introduced in v1.1. Sorry. Write speed now 800KB/s !
* version v1.2: introduces read speed at 450KB/s and write speed at 850KB/s.
* version v1.3:
  - now uses byte access to gpio control addresses (it was a long word access). Don't know if it can speedup things.
  - log functions to support log level/log to a file in the future
  - the module param: mp_max_init_tries can now be used to handle cards with long init time (bigger cards tends to have slower init time). Default value: 10000
* version v1.3.1:
  - corrections to support 4GB cards. Don't know if it works now cause I dont have such a card. Please test and PM me.
  - more SD cards now work : example : my Sandisk Ultra II 512MB didn't work and now is ok.
* version v1.3.2:
  - changed all printk to better messages in dmesg
  - new parameter that controls the number of clocks being sent to the card to power it on : mp_max_pwr_on_clocks
Default value: 80. You can try to raise it if your card does not init correctly and the message 'card not inited after xxxx tries' is not shown in dmesg.
  - default value for parameter mp_max_init_tries is now 20000
  - Card ID register is shown in dmesg (code from rcichielo. Thanks)
* version v1.3.3:
  - mp_max_init_tries increased to 30000 as users stated that some cards needs such a high number.
  - GPIO #defines works again. It is now possible to compile this version to other GPIOs just by changing values in config.h . Generated code is as fast as 1_3_2.
  - Contributions (hardware and software) by Marc Denty :
       + his kingston 2GB card now works (maybe others and 4GB - please report)
       + code comments / CID parsing to show card name in dmesg.
* version v1.3.4:
  - MMC init backward compatibility (frequency limited to 380KHz). A lot of SD/MMC previously not working will now certainly work.
  - MMC CID register parsing. It now shows product serial number, product manufacturer, product name, product version, and product release date in the dmesg.


Cyril

(Last edited by Cyril on 24 Mar 2007, 22:21)

You would be an angel if you can make a mmc module for kernel 2.6 big_smile

Sorry but i won't.

I don't have a 2.6 kernel on my WRT.

Maybe when kamikaze is released.

Cyril

- I am currently looking for other optimizations on mmc.c

I really wish someone would update this driver for 2.6, or write a new one using the mmc framework. i've been working on it, but I know almost nothing about kernel development

Can someone post the compiled file? My VMware keeps crashing when trying to setup the environement for openwrt.

I just need the mmc.o file. I got an old one which is limited to around 120KB/s tongue

Do you want a GPIO2 version ? Or GPIO5 ?

GPIO2
In other words, the one for WRT54G v4 (same as you)

Here it is.

[s]mmc.o GPIO2 compiled for whiterussian[/s] [link deleted - use links on the heading post of this topic]

(Last edited by Cyril on 6 Mar 2007, 14:28)

Thanks man! but.... this new mmc.o file causes my router to reboot the moment it loads this module (LED lights up and wam! reboot!).

I had to revert back to my old mmc.o.

I cant think of anything causing my router to constantly reboot.

I got a script always writing "0x9c" in my gpiomask to prevent my router from crashing with the old mmc.o module.

Other than that, nothing else affects the mmc.o module.

Any suggestion?

can you comment out the script that now loads the module ?
especially the part that loops and writes into /proc/diag/gpiomask ?


Then try to load mmc.o manually and do a 'dmesg'.



Here is my bootup script (/etc/init.d/S20mmc) :

#!/bin/sh
echo "0x9c" > /proc/diag/gpiomask
insmod mmc
e2fsck /dev/mmc/disc0/part1
mount /opt

In my case, i don't have to send gpiomask in a loop. It works.

I've found the problem.

I transfered the file to my ftp in ASCII mode ... sorry.

Here is a new link [s]mmc driver v1.2 compiled for whiterussian GPIO2[/s] [link deleted - use links on the heading post of this topic]

(Last edited by Cyril on 6 Mar 2007, 14:28)

Thanks man! Now it works and the new driver is super FAST! wink

ANYONE can port this to kernel 2.6?

Cyril wrote:

Do you want a GPIO2 version ? Or GPIO5 ?

Any chance of getting the GPIO5 version, too? smile

Here is a GPIO5 version.

[s]mmc driver v1.2 compiled for whiterussian GPIO5[/s] [link deleted - use links on the heading post of this topic]

I will try to make the code more user friendly (switching beetween different GPIO more easily).

(Last edited by Cyril on 6 Mar 2007, 14:27)

Suggestion:


module_param(sd_di, int, 0)
module_param(sd_do, int, 0)
module_param(sd_clk, int, 0)
module_param(sd_cs, int, 0)

#define SD_DI (1<<sd_di)
#define SD_DO (1<<sd_do)
#define SD_CLK (1<<sd_clk)
#define SD_CS (1<<sd_cs)

Hello Cyril

Not sure why, but this new mmc.o is not working in my WRT54GS v4 (GPIO2)
I am getting error
mmc Hardware init
mmc Card init
mmc Card init *1*
mmc Card init
mmc Card init *1*
mmc: error in mmc_card_init (2)
mmc: error in mmc_init (-1)

My current mmc.o size is 12528 and your's new one is 23548 bytes.


mbm wrote:

Suggestion:


module_param(sd_di, int, 0)
module_param(sd_do, int, 0)
module_param(sd_clk, int, 0)
module_param(sd_cs, int, 0)

#define SD_DI (1<<sd_di)
#define SD_DO (1<<sd_do)
#define SD_CLK (1<<sd_clk)
#define SD_CS (1<<sd_cs)

Thanks for this mbm.
I will integrate it soon.
But the problem is not here ... But that i coded in hard some shifts in read/write functions to speed things up.
The shifts i coded are based on the fact that SD_DI is 0x08 ...
I have to rewrite some parts without loosing any bit of performance.

mbm ? or someone ? I think there's maybe another way to improve the driver, but i don't have too much time to do it :
- function mmc_request receives file io events from the kernel and calls mmc_write_block/mmc_read_block with a pointer to the data to read/write and the number of sectors to read/write.
- the problem is that nr_sectors is always 2 (because block_size is 1024 and hardware block size of the mmc is 512)
- if someone can find a way to bufferize some requests (because blocks requested are near for example) and do read/write requests
  with nr_sectors > 2, then it will be faster !

Hope someone here will do it !

hello baba2s.
Because this version is a little faster then it seems that your card needs more init cycles to work.

You can try v1.3 (link on the heading post), passing mp_max_init_tries when loading the module.

Example :
insmod mmc.o mp_max_init_tries=30000

Default value is 10000 (used in v1.2).

You can try 20000, 30000, 40000, ...

I don't know how great can this number be for your card.

MMC specification states that some cards needs several hundreds of millis to init.

I got one that needs 6500 cycles (noname SD 128MB) and another one 600 cycles (sandisk SD 512MB).

6500 cycles seems to last 439 usec !

Cyril

baba2s wrote:

Hello Cyril

Not sure why, but this new mmc.o is not working in my WRT54GS v4 (GPIO2)
I am getting error
mmc Hardware init
mmc Card init
mmc Card init *1*
mmc Card init
mmc Card init *1*
mmc: error in mmc_card_init (2)
mmc: error in mmc_init (-1)

My current mmc.o size is 12528 and your's new one is 23548 bytes.

(Last edited by Cyril on 6 Mar 2007, 21:18)

- if someone can find a way to bufferize some requests (because blocks requested are near for example) and do read/write requests
  with nr_sectors > 2, then it will be faster !

you could.. buffer requests (in the driver), and do them asynchronously to the current request. possibly trading response time for throughput, and definitely adding a lot of complexity smile

a question:

   *l_gpioaddr_output = l_ps_di; *l_gpioaddr_output = l_ps_di_clk;
    *l_gpioaddr_output = l_ps_di; *l_gpioaddr_output = l_ps_di_clk;
    *l_gpioaddr_output = l_ps_di; *l_gpioaddr_output = l_ps_di_clk;

what's the purpose of doing the same thing a specific multiple of times in your code? it smells of a hack to work around something or other

Hello Kevin.

These are not hacks.

The var l_ps_di_clk is written to *l_gpioaddr_output to send the clock to the SD.
It must be done one time per bit. For a transfer rate of 850KB it has been sent 7 million of times per second !


Kevin wrote:

- if someone can find a way to bufferize some requests (because blocks requested are near for example) and do read/write requests
  with nr_sectors > 2, then it will be faster !

you could.. buffer requests (in the driver), and do them asynchronously to the current request. possibly trading response time for throughput, and definitely adding a lot of complexity smile

a question:

   *l_gpioaddr_output = l_ps_di; *l_gpioaddr_output = l_ps_di_clk;
    *l_gpioaddr_output = l_ps_di; *l_gpioaddr_output = l_ps_di_clk;
    *l_gpioaddr_output = l_ps_di; *l_gpioaddr_output = l_ps_di_clk;

what's the purpose of doing the same thing a specific multiple of times in your code? it smells of a hack to work around something or other

yes.. but why are you cycling the clock without effectively doing anything during that time?

Look twice.

SD_DI is sent. That means data input bit is 1.
8 times => data is 0xFF.

If you're interested in MMC protocol : http://elm-chan.org/docs/mmc/mmc_e.html .

And to answer differently : there are many cases in the MMC protocol where you just have to cycle the clock :
- to read data
- when the MMC is in busy state
- when your are waiting for it to respond to a command.
- while initing it.
- ...

Kevin wrote:

yes.. but why are you cycling the clock without effectively doing anything during that time?

version 1.2 GPIO5 is working fast and stable on my WRT54GS1.1 whiterussian 0.9 ,but i have 2 questions

1.How to measure transfer bandwidth?

2.Is there any chance to 4Gb support ? price for it is good these days

rgds

(Last edited by nicefile on 7 Mar 2007, 20:05)

nicefile wrote:

1.How to measure transfer bandwidth?

Here is the way i use :

* make a directory in your mmc called bw_test
* cd to this directory
* create a file called bw_test with this content :

#!/bin/sh
rm bw_test_tmp
sync
echo "write test :"
time ./bw_test_w
echo "read test :"
time ./bw_test_r

* create another file that will be your write test, call it bw_test_w :

#!/bin/sh
# this will create a file of 32MB
dd if=/dev/zero of=bw_test_tmp count=65536
sync

* create another file that will be your read test, call it bw_test_r :

#!/bin/sh
# this will read the file bw_test_tmp
dd if=bw_test_tmp of=/dev/null
sync

* chmod +x *
* ./bw_test

It will output the time to create a 32MB file then the time to read it.
Then it is simple to calculate bandwith : 32768/<time in sec> => bandwith in KB/s

nicefile wrote:

2.Is there any chance to 4Gb support ? price for it is good these days

I will look further but I think that the SPI protocol used by this driver to communicate with the card is limited to 2GB.
This limitation is due to the fact that the address passed by parameter to the card is coded in a signed integer (32bit - 1bit => 31bit => 2GB).
In other words : I doubt that it is possible.

(Last edited by Cyril on 9 Mar 2007, 23:28)