mmc_claim_host

来源:互联网 发布:js 唤醒支付宝app 编辑:程序博客网 时间:2024/06/03 21:35
http://www.cnblogs.com/autum/archive/2013/03/15/mmc_claim_host.html
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort){    DECLARE_WAITQUEUE(wait, current);    //初始化一个等待节点    unsigned long flags;    int stop;    might_sleep();    add_wait_queue(&host->wq, &wait);    //当前进程进入等待队列    spin_lock_irqsave(&host->lock, flags);    while (1) {        set_current_state(TASK_UNINTERRUPTIBLE);        //wake_up才能唤醒        stop = abort ? atomic_read(abort) : 0;        //stop=0        if (stop || !host->claimed || host->claimer == current)            //分别为终止,host可用,拥有host的是当前线程,然后就不需要睡眠了            break;        spin_unlock_irqrestore(&host->lock, flags);        schedule();        //调度,因为没有获得控制器使用权        //stop一直为0,因为只有一个卡,没有冲突        spin_lock_irqsave(&host->lock, flags);    }    set_current_state(TASK_RUNNING);    if (!stop) {        host->claimed = 1;        host->claimer = current;        host->claim_cnt += 1;    } else        wake_up(&host->wq);    //唤醒工作队列,这个放的位置是不是有点问题啊    spin_unlock_irqrestore(&host->lock, flags);    remove_wait_queue(&host->wq, &wait);    //从等待队列中释放    if (!stop)        mmc_host_enable(host);    //获取控制器使用权    return stop;}这是请求占用sd卡控制器的函数,如果sd卡正在被使用,此进程就切换出去,如果没有就获得sd卡使用权。那么为什么会出现这样的问题呢?按常理,sd卡作为临界资源,不会有两个进程同时访问的,在linux内核进程调度的时候已经考虑了,怎么还有这样的问题呢?原因就是:使用sd卡的进程1在进入系统调用后就睡眠了,属于异步占用临界资源,进入系统调用后,控制sd卡,并使用dma搬运数据,此时cpu是空闲的,所以就睡眠,让其他进程运行,提高使用率。此时控制着sd卡的进程还是进程1,属于进程1上下文。问题是:如果这时候运行的进程2也进入了系统调用并且访问sd卡,怎么办?如果进程1一直在运行是没有这样的问题的。为了解决这样的问题,就有了上面的函数__mmc_claim_host这说明了,在内核中进程上下文中是存在抢占的,临界资源的使用是可以异步的,所以要注意保护好临界资源。像一些字符设备,读的时候进程是不会睡眠的,属于同步,不会有上述的问题。疑问:__mmc_claim_host可不可以做出自旋锁一样的效果,在进程1读取文件数据较少的时候,就不用切换进程了呢?
mmc_ios封装io setting控制参数的比如时钟频率,电源开/关,总线宽度等等,其设置函数是
 mmc_host_ops的        void    (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
set_ios设置一些控制参数,比如时钟频率,因为在初始化正常操作的时候时钟是不一样的,初始化的时候一般小于400K,正常操作的时候是26M52M等等高得多的频率。还有就是控制电源以及SD卡的总线宽度,CBPSD总线宽度1,4,8都是支持的,
而set_ios是赋值需要在相应的host驱动中实现,如
kernel/drivers/mmc/host/sprdmci.c中的sdhci_set_ios这才是真正写寄存器的地方
struct mmc_ios {        unsigned int    clock;                  /* clock rate */        unsigned short  vdd;/* vdd stores the bit number of the selected voltage range from below. */        unsigned char   bus_mode;               /* command output mode */#define MMC_BUSMODE_OPENDRAIN   1#define MMC_BUSMODE_PUSHPULL    2        unsigned char   chip_select;            /* SPI chip select */#define MMC_CS_DONTCARE         0#define MMC_CS_HIGH             1#define MMC_CS_LOW              2        unsigned char   power_mode;             /* power supply mode */#define MMC_POWER_OFF           0#define MMC_POWER_UP            1#define MMC_POWER_ON            2        unsigned char   bus_width;              /* data bus width */#define MMC_BUS_WIDTH_1         0#define MMC_BUS_WIDTH_4         2#define MMC_BUS_WIDTH_8         3        unsigned char   timing;                 /* timing specification used */
#define MMC_TIMING_LEGACY       0#define MMC_TIMING_MMC_HS       1#define MMC_TIMING_SD_HS        2};
各项都会封装,其封装过程如下,以vdd为例,
选择ocr中主机支持,且为最低的电压
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr){        int bit;        ocr &= host->ocr_avail;        bit = ffs(ocr);        if (bit) {                bit -= 1;                ocr &= 3 << bit;                host->ios.vdd = bit;                mmc_set_ios(host);        } else {                pr_warning("%s: host doesn't support card's voltages\n",                                mmc_hostname(host));                ocr = 0;        }        return ocr;}
static inline void mmc_set_ios(struct mmc_host *host){        struct mmc_ios *ios = &host->ios;        pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "                "width %u timing %u\n",                 mmc_hostname(host), ios->clock, ios->bus_mode,                 ios->power_mode, ios->chip_select, ios->vdd,                 ios->bus_width, ios->timing);        host->ops->set_ios(host, ios);}
其他各项类似如
void mmc_set_clock(struct mmc_host *host, unsigned int hz)
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode) 
void mmc_set_bus_width(struct mmc_host *host, unsigned int width) 
都在/kernel/drivers/mmc/core/core.c中实现
host->ops->set_ios(host, ios);最终是在
//./3rdparty/wifi/rtl8189es/special/android/kernel/drivers/mmc/host/sprdmci.c
static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 
 sdhci_set_ios中再分发,对应下面的函数
static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
根据host->name判断分别设置vddsd0 vddsd1两个ldo值
void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)