Re: [PATCH 05/18] MMC: OMAP: Introduce new multislot structure and change driver to use it

2008-02-07 Thread Pierre Ossman
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

2008-01-28 Thread Roel Kluin
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

2008-01-28 Thread Carlos Aguiar
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

2008-01-28 Thread Carlos Aguiar
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

2008-01-28 Thread Roel Kluin
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/