Re: [PATCH 05/18] MMC: OMAP: Introduce new multislot structure and change driver to use it
On Mon, 28 Jan 2008 15:07:23 -0400 Carlos Aguiar <[EMAIL PROTECTED]> wrote: > From: Juha Yrjola <[EMAIL PROTECTED]> > > Introduce new MMC multislot structure and change driver to use it. > > Note that MMC clocking is now enabled in mmc_omap_select_slot() > and disabled in mmc_omap_release_slot(). > > Signed-off-by: Juha Yrjola <[EMAIL PROTECTED]> > Signed-off-by: Jarkko Lavinen <[EMAIL PROTECTED]> > Signed-off-by: Carlos Eduardo Aguiar <[EMAIL PROTECTED]> > Signed-off-by: Tony Lindgren <[EMAIL PROTECTED]> > --- I still think this muxed mmc host thing is a bad idea, but it's your nightmare... > + > +/* Access to the R/O switch is required for production testing > + * purposes. */ > +static ssize_t > +mmc_omap_show_ro(struct device *dev, struct device_attribute *attr, char > *buf) > +{ > + struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev); > + struct mmc_omap_slot *slot = mmc_priv(mmc); > + > + return sprintf(buf, "%d\n", slot->pdata->get_ro(mmc_dev(mmc), > + slot->id)); > +} > + > +static DEVICE_ATTR(ro, S_IRUGO, mmc_omap_show_ro, NULL); > + This is unrelated to the slot stuff and should be in its own patch. Also, it should probably be in the core, not a driver. > + > + mmc->caps = MMC_CAP_MULTIWRITE | MMC_CAP_MMC_HIGHSPEED | > + MMC_CAP_SD_HIGHSPEED; This is also unrelated. From what I've seen, the OMAP is a SD controller and does not support high speed MMC. The fact that you also conditionally set the max frequency later also suggests that this code is entirely incorrect. > + > + r = mmc_add_host(mmc); > + if (r < 0) > + return r; > + > + if (slot->pdata->name != NULL) { > + r = device_create_file(>class_dev, > + _attr_slot_name); > + if (r < 0) > + goto err_remove_host; > + } > + > + if (slot->pdata->get_ro != NULL) { > + r = device_create_file(>class_dev, > + _attr_ro); > + } > + You have a bit of a race here with userspace in case you use the uevent to trigger things. -- -- Pierre Ossman Linux kernel, MMC maintainerhttp://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 05/18] MMC: OMAP: Introduce new multislot structure and change driver to use it
Carlos Aguiar wrote: > From: Juha Yrjola <[EMAIL PROTECTED]> > > Introduce new MMC multislot structure and change driver to use it. > diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c It could be that I misunderstand, but... > @@ -897,19 +1037,106 @@ static const struct mmc_host_ops mmc_omap_ops = { > .get_ro = mmc_omap_get_ro, > }; > > -static int __init mmc_omap_probe(struct platform_device *pdev) > +static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id) > { > - struct omap_mmc_conf *minfo = pdev->dev.platform_data; > + struct mmc_omap_slot *slot = NULL; > struct mmc_host *mmc; > + int r; > + > + mmc = mmc_alloc_host(sizeof(struct mmc_omap_slot), host->dev); since you mmc_alloc_host here... > + if (mmc == NULL) > + return -ENOMEM; > + > + slot = mmc_priv(mmc); > + slot->host = host; > + slot->mmc = mmc; > + slot->id = id; > + slot->pdata = >pdata->slots[id]; > + > + host->slots[id] = slot; > + > + mmc->caps = MMC_CAP_MULTIWRITE | MMC_CAP_MMC_HIGHSPEED | > + MMC_CAP_SD_HIGHSPEED; > + if (host->pdata->conf.wire4) > + mmc->caps |= MMC_CAP_4_BIT_DATA; > + > + mmc->ops = _omap_ops; > + mmc->f_min = 40; > + > + if (cpu_class_is_omap2()) > + mmc->f_max = 4800; > + else > + mmc->f_max = 2400; > + if (host->pdata->max_freq) > + mmc->f_max = min(host->pdata->max_freq, mmc->f_max); > + mmc->ocr_avail = slot->pdata->ocr_mask; > + > + /* Use scatterlist DMA to reduce per-transfer costs. > + * NOTE max_seg_size assumption that small blocks aren't > + * normally used (except e.g. for reading SD registers). > + */ > + mmc->max_phys_segs = 32; > + mmc->max_hw_segs = 32; > + mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */ > + mmc->max_blk_count = 2048; /* NBLK is 11 bits (+1) */ > + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; > + mmc->max_seg_size = mmc->max_req_size; > + > + r = mmc_add_host(mmc); > + if (r < 0) > + return r; shouldn't you mmc_free_host(mmc) here? > + > + if (slot->pdata->name != NULL) { > + r = device_create_file(>class_dev, > + _attr_slot_name); > + if (r < 0) > + goto err_remove_host; > + } > + > + if (slot->pdata->get_ro != NULL) { > + r = device_create_file(>class_dev, > + _attr_ro); > + } > + > + return 0; > + > +err_remove_slot_name: This label has no goto, so the 2 lines below are dead code... Ok, now I see It's in the next patch. (maybe better to put these lines in that patch?) > + if (slot->pdata->name != NULL) > + device_remove_file(>class_dev, _attr_ro); > +err_remove_host: > + mmc_remove_host(mmc); and maybe mmc_free_host(mmc) here? > + return r; > +} from mmc_omap_probe() + for (i = 0; i < pdata->nr_slots; i++) { + ret = mmc_omap_new_slot(host, i); + if (ret < 0) { + while (--i >= 0) + mmc_omap_remove_slot(host->slots[i]); mmc_omap_remove_slot() does a mmc_free_host(), but note the decrement of i: the current isn't freed. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 05/18] MMC: OMAP: Introduce new multislot structure and change driver to use it
From: Juha Yrjola <[EMAIL PROTECTED]> Introduce new MMC multislot structure and change driver to use it. Note that MMC clocking is now enabled in mmc_omap_select_slot() and disabled in mmc_omap_release_slot(). Signed-off-by: Juha Yrjola <[EMAIL PROTECTED]> Signed-off-by: Jarkko Lavinen <[EMAIL PROTECTED]> Signed-off-by: Carlos Eduardo Aguiar <[EMAIL PROTECTED]> Signed-off-by: Tony Lindgren <[EMAIL PROTECTED]> --- drivers/mmc/host/omap.c | 424 +-- include/asm-arm/arch-omap/mmc.h |2 + 2 files changed, 322 insertions(+), 104 deletions(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 721955a..35719e7 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -96,6 +97,22 @@ * when the cover switch is open */ #define OMAP_MMC_SWITCH_POLL_DELAY 500 +struct mmc_omap_host; + +struct mmc_omap_slot { + int id; + unsigned intvdd; + u16 saved_con; + u16 bus_mode; + unsigned intfclk_freq; + unsignedpowered:1; + + struct mmc_request *mrq; + struct mmc_omap_host*host; + struct mmc_host *mmc; + struct omap_mmc_slot_data *pdata; +}; + struct mmc_omap_host { int initialized; int suspended; @@ -130,13 +147,112 @@ struct mmc_omap_host { unsigneddma_len; short power_pin; - short wp_pin; - struct work_struct switch_work; - struct timer_list switch_timer; - int switch_last_state; + struct mmc_omap_slot*slots[OMAP_MMC_MAX_SLOTS]; + struct mmc_omap_slot*current_slot; + spinlock_t slot_lock; + wait_queue_head_t slot_wq; + int nr_slots; + + struct omap_mmc_platform_data *pdata; }; +static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed) +{ + struct mmc_omap_host *host = slot->host; + unsigned long flags; + + if (claimed) + goto no_claim; + spin_lock_irqsave(>slot_lock, flags); + while (host->mmc != NULL) { + spin_unlock_irqrestore(>slot_lock, flags); + wait_event(host->slot_wq, host->mmc == NULL); + spin_lock_irqsave(>slot_lock, flags); + } + host->mmc = slot->mmc; + spin_unlock_irqrestore(>slot_lock, flags); +no_claim: + clk_enable(host->fclk); + if (host->current_slot != slot) { + if (host->pdata->switch_slot != NULL) + host->pdata->switch_slot(mmc_dev(slot->mmc), slot->id); + host->current_slot = slot; + } + + /* Doing the dummy read here seems to work around some bug +* at least in OMAP24xx silicon where the command would not +* start after writing the CMD register. Sigh. */ + OMAP_MMC_READ(host, CON); + + OMAP_MMC_WRITE(host, CON, slot->saved_con); +} + +static void mmc_omap_start_request(struct mmc_omap_host *host, + struct mmc_request *req); + +static void mmc_omap_release_slot(struct mmc_omap_slot *slot) +{ + struct mmc_omap_host *host = slot->host; + unsigned long flags; + int i; + + BUG_ON(slot == NULL || host->mmc == NULL); + clk_disable(host->fclk); + + spin_lock_irqsave(>slot_lock, flags); + /* Check for any pending requests */ + for (i = 0; i < host->nr_slots; i++) { + struct mmc_omap_slot *new_slot; + struct mmc_request *rq; + + if (host->slots[i] == NULL || host->slots[i]->mrq == NULL) + continue; + + new_slot = host->slots[i]; + /* The current slot should not have a request in queue */ + BUG_ON(new_slot == host->current_slot); + + host->mmc = new_slot->mmc; + spin_unlock_irqrestore(>slot_lock, flags); + mmc_omap_select_slot(new_slot, 1); + rq = new_slot->mrq; + new_slot->mrq = NULL; + mmc_omap_start_request(host, rq); + return; + } + + host->mmc = NULL; + wake_up(>slot_wq); + spin_unlock_irqrestore(>slot_lock, flags); +} + +/* Access to the R/O switch is required for production testing + * purposes. */ +static ssize_t +mmc_omap_show_ro(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev); + struct mmc_omap_slot *slot = mmc_priv(mmc); + + return sprintf(buf, "%d\n", slot->pdata->get_ro(mmc_dev(mmc), + slot->id)); +} +
[PATCH 05/18] MMC: OMAP: Introduce new multislot structure and change driver to use it
From: Juha Yrjola [EMAIL PROTECTED] Introduce new MMC multislot structure and change driver to use it. Note that MMC clocking is now enabled in mmc_omap_select_slot() and disabled in mmc_omap_release_slot(). Signed-off-by: Juha Yrjola [EMAIL PROTECTED] Signed-off-by: Jarkko Lavinen [EMAIL PROTECTED] Signed-off-by: Carlos Eduardo Aguiar [EMAIL PROTECTED] Signed-off-by: Tony Lindgren [EMAIL PROTECTED] --- drivers/mmc/host/omap.c | 424 +-- include/asm-arm/arch-omap/mmc.h |2 + 2 files changed, 322 insertions(+), 104 deletions(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 721955a..35719e7 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -33,6 +33,7 @@ #include asm/mach-types.h #include asm/arch/board.h +#include asm/arch/mmc.h #include asm/arch/gpio.h #include asm/arch/dma.h #include asm/arch/mux.h @@ -96,6 +97,22 @@ * when the cover switch is open */ #define OMAP_MMC_SWITCH_POLL_DELAY 500 +struct mmc_omap_host; + +struct mmc_omap_slot { + int id; + unsigned intvdd; + u16 saved_con; + u16 bus_mode; + unsigned intfclk_freq; + unsignedpowered:1; + + struct mmc_request *mrq; + struct mmc_omap_host*host; + struct mmc_host *mmc; + struct omap_mmc_slot_data *pdata; +}; + struct mmc_omap_host { int initialized; int suspended; @@ -130,13 +147,112 @@ struct mmc_omap_host { unsigneddma_len; short power_pin; - short wp_pin; - struct work_struct switch_work; - struct timer_list switch_timer; - int switch_last_state; + struct mmc_omap_slot*slots[OMAP_MMC_MAX_SLOTS]; + struct mmc_omap_slot*current_slot; + spinlock_t slot_lock; + wait_queue_head_t slot_wq; + int nr_slots; + + struct omap_mmc_platform_data *pdata; }; +static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed) +{ + struct mmc_omap_host *host = slot-host; + unsigned long flags; + + if (claimed) + goto no_claim; + spin_lock_irqsave(host-slot_lock, flags); + while (host-mmc != NULL) { + spin_unlock_irqrestore(host-slot_lock, flags); + wait_event(host-slot_wq, host-mmc == NULL); + spin_lock_irqsave(host-slot_lock, flags); + } + host-mmc = slot-mmc; + spin_unlock_irqrestore(host-slot_lock, flags); +no_claim: + clk_enable(host-fclk); + if (host-current_slot != slot) { + if (host-pdata-switch_slot != NULL) + host-pdata-switch_slot(mmc_dev(slot-mmc), slot-id); + host-current_slot = slot; + } + + /* Doing the dummy read here seems to work around some bug +* at least in OMAP24xx silicon where the command would not +* start after writing the CMD register. Sigh. */ + OMAP_MMC_READ(host, CON); + + OMAP_MMC_WRITE(host, CON, slot-saved_con); +} + +static void mmc_omap_start_request(struct mmc_omap_host *host, + struct mmc_request *req); + +static void mmc_omap_release_slot(struct mmc_omap_slot *slot) +{ + struct mmc_omap_host *host = slot-host; + unsigned long flags; + int i; + + BUG_ON(slot == NULL || host-mmc == NULL); + clk_disable(host-fclk); + + spin_lock_irqsave(host-slot_lock, flags); + /* Check for any pending requests */ + for (i = 0; i host-nr_slots; i++) { + struct mmc_omap_slot *new_slot; + struct mmc_request *rq; + + if (host-slots[i] == NULL || host-slots[i]-mrq == NULL) + continue; + + new_slot = host-slots[i]; + /* The current slot should not have a request in queue */ + BUG_ON(new_slot == host-current_slot); + + host-mmc = new_slot-mmc; + spin_unlock_irqrestore(host-slot_lock, flags); + mmc_omap_select_slot(new_slot, 1); + rq = new_slot-mrq; + new_slot-mrq = NULL; + mmc_omap_start_request(host, rq); + return; + } + + host-mmc = NULL; + wake_up(host-slot_wq); + spin_unlock_irqrestore(host-slot_lock, flags); +} + +/* Access to the R/O switch is required for production testing + * purposes. */ +static ssize_t +mmc_omap_show_ro(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev); + struct mmc_omap_slot *slot = mmc_priv(mmc); + + return sprintf(buf, %d\n, slot-pdata-get_ro(mmc_dev(mmc),
Re: [PATCH 05/18] MMC: OMAP: Introduce new multislot structure and change driver to use it
Carlos Aguiar wrote: From: Juha Yrjola [EMAIL PROTECTED] Introduce new MMC multislot structure and change driver to use it. diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c It could be that I misunderstand, but... @@ -897,19 +1037,106 @@ static const struct mmc_host_ops mmc_omap_ops = { .get_ro = mmc_omap_get_ro, }; -static int __init mmc_omap_probe(struct platform_device *pdev) +static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id) { - struct omap_mmc_conf *minfo = pdev-dev.platform_data; + struct mmc_omap_slot *slot = NULL; struct mmc_host *mmc; + int r; + + mmc = mmc_alloc_host(sizeof(struct mmc_omap_slot), host-dev); since you mmc_alloc_host here... + if (mmc == NULL) + return -ENOMEM; + + slot = mmc_priv(mmc); + slot-host = host; + slot-mmc = mmc; + slot-id = id; + slot-pdata = host-pdata-slots[id]; + + host-slots[id] = slot; + + mmc-caps = MMC_CAP_MULTIWRITE | MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_SD_HIGHSPEED; + if (host-pdata-conf.wire4) + mmc-caps |= MMC_CAP_4_BIT_DATA; + + mmc-ops = mmc_omap_ops; + mmc-f_min = 40; + + if (cpu_class_is_omap2()) + mmc-f_max = 4800; + else + mmc-f_max = 2400; + if (host-pdata-max_freq) + mmc-f_max = min(host-pdata-max_freq, mmc-f_max); + mmc-ocr_avail = slot-pdata-ocr_mask; + + /* Use scatterlist DMA to reduce per-transfer costs. + * NOTE max_seg_size assumption that small blocks aren't + * normally used (except e.g. for reading SD registers). + */ + mmc-max_phys_segs = 32; + mmc-max_hw_segs = 32; + mmc-max_blk_size = 2048; /* BLEN is 11 bits (+1) */ + mmc-max_blk_count = 2048; /* NBLK is 11 bits (+1) */ + mmc-max_req_size = mmc-max_blk_size * mmc-max_blk_count; + mmc-max_seg_size = mmc-max_req_size; + + r = mmc_add_host(mmc); + if (r 0) + return r; shouldn't you mmc_free_host(mmc) here? + + if (slot-pdata-name != NULL) { + r = device_create_file(mmc-class_dev, + dev_attr_slot_name); + if (r 0) + goto err_remove_host; + } + + if (slot-pdata-get_ro != NULL) { + r = device_create_file(mmc-class_dev, + dev_attr_ro); + } + + return 0; + +err_remove_slot_name: This label has no goto, so the 2 lines below are dead code... Ok, now I see It's in the next patch. (maybe better to put these lines in that patch?) + if (slot-pdata-name != NULL) + device_remove_file(mmc-class_dev, dev_attr_ro); +err_remove_host: + mmc_remove_host(mmc); and maybe mmc_free_host(mmc) here? + return r; +} from mmc_omap_probe() + for (i = 0; i pdata-nr_slots; i++) { + ret = mmc_omap_new_slot(host, i); + if (ret 0) { + while (--i = 0) + mmc_omap_remove_slot(host-slots[i]); mmc_omap_remove_slot() does a mmc_free_host(), but note the decrement of i: the current isn't freed. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/