]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/mmc/card/block.c
Merge remote-tracking branches 'spi/topic/spidev', 'spi/topic/sunxi', 'spi/topic...
[linux.git] / drivers / mmc / card / block.c
index 8a0147dfed27d864d419de730499960c54bc202c..c5472e3c923126097fd93f2abf31402a1717c228 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/capability.h>
 #include <linux/compat.h>
 #include <linux/pm_runtime.h>
+#include <linux/idr.h>
 
 #include <linux/mmc/ioctl.h>
 #include <linux/mmc/card.h>
@@ -78,14 +79,14 @@ static int perdev_minors = CONFIG_MMC_BLOCK_MINORS;
 /*
  * We've only got one major, so number of mmcblk devices is
  * limited to (1 << 20) / number of minors per device.  It is also
- * currently limited by the size of the static bitmaps below.
+ * limited by the MAX_DEVICES below.
  */
 static int max_devices;
 
 #define MAX_DEVICES 256
 
-/* TODO: Replace these with struct ida */
-static DECLARE_BITMAP(dev_use, MAX_DEVICES);
+static DEFINE_IDA(mmc_blk_ida);
+static DEFINE_SPINLOCK(mmc_blk_lock);
 
 /*
  * There is one mmc_blk_data per slot.
@@ -178,7 +179,9 @@ static void mmc_blk_put(struct mmc_blk_data *md)
                int devidx = mmc_get_devidx(md->disk);
                blk_cleanup_queue(md->queue.queue);
 
-               __clear_bit(devidx, dev_use);
+               spin_lock(&mmc_blk_lock);
+               ida_remove(&mmc_blk_ida, devidx);
+               spin_unlock(&mmc_blk_lock);
 
                put_disk(md->disk);
                kfree(md);
@@ -352,8 +355,10 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
                goto idata_err;
        }
 
-       if (!idata->buf_bytes)
+       if (!idata->buf_bytes) {
+               idata->buf = NULL;
                return idata;
+       }
 
        idata->buf = kmalloc(idata->buf_bytes, GFP_KERNEL);
        if (!idata->buf) {
@@ -615,6 +620,10 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
 
        ioc_err = __mmc_blk_ioctl_cmd(card, md, idata);
 
+       /* Always switch back to main area after RPMB access */
+       if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
+               mmc_blk_part_switch(card, dev_get_drvdata(&card->dev));
+
        mmc_put_card(card);
 
        err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata);
@@ -682,6 +691,10 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
        for (i = 0; i < num_of_cmds && !ioc_err; i++)
                ioc_err = __mmc_blk_ioctl_cmd(card, md, idata[i]);
 
+       /* Always switch back to main area after RPMB access */
+       if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
+               mmc_blk_part_switch(card, dev_get_drvdata(&card->dev));
+
        mmc_put_card(card);
 
        /* copy to user if data and response */
@@ -745,16 +758,25 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
        if (mmc_card_mmc(card)) {
                u8 part_config = card->ext_csd.part_config;
 
+               if (md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB)
+                       mmc_retune_pause(card->host);
+
                part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
                part_config |= md->part_type;
 
                ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                 EXT_CSD_PART_CONFIG, part_config,
                                 card->ext_csd.part_time);
-               if (ret)
+               if (ret) {
+                       if (md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB)
+                               mmc_retune_unpause(card->host);
                        return ret;
+               }
 
                card->ext_csd.part_config = part_config;
+
+               if (main_md->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB)
+                       mmc_retune_unpause(card->host);
        }
 
        main_md->part_curr = md->part_type;
@@ -945,16 +967,22 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error,
                        req->rq_disk->disk_name, "timed out", name, status);
 
                /* If the status cmd initially failed, retry the r/w cmd */
-               if (!status_valid)
+               if (!status_valid) {
+                       pr_err("%s: status not valid, retrying timeout\n",
+                               req->rq_disk->disk_name);
                        return ERR_RETRY;
+               }
 
                /*
                 * If it was a r/w cmd crc error, or illegal command
                 * (eg, issued in wrong state) then retry - we should
                 * have corrected the state problem above.
                 */
-               if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND))
+               if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND)) {
+                       pr_err("%s: command error, retrying timeout\n",
+                               req->rq_disk->disk_name);
                        return ERR_RETRY;
+               }
 
                /* Otherwise abort the command */
                return ERR_ABORT;
@@ -1760,8 +1788,8 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
 
        packed_cmd_hdr = packed->cmd_hdr;
        memset(packed_cmd_hdr, 0, sizeof(packed->cmd_hdr));
-       packed_cmd_hdr[0] = (packed->nr_entries << 16) |
-               (PACKED_CMD_WR << 8) | PACKED_CMD_VER;
+       packed_cmd_hdr[0] = cpu_to_le32((packed->nr_entries << 16) |
+               (PACKED_CMD_WR << 8) | PACKED_CMD_VER);
        hdr_blocks = mmc_large_sector(card) ? 8 : 1;
 
        /*
@@ -1775,14 +1803,14 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
                        ((brq->data.blocks * brq->data.blksz) >=
                         card->ext_csd.data_tag_unit_size);
                /* Argument of CMD23 */
-               packed_cmd_hdr[(i * 2)] =
+               packed_cmd_hdr[(i * 2)] = cpu_to_le32(
                        (do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
                        (do_data_tag ? MMC_CMD23_ARG_TAG_REQ : 0) |
-                       blk_rq_sectors(prq);
+                       blk_rq_sectors(prq));
                /* Argument of CMD18 or CMD25 */
-               packed_cmd_hdr[((i * 2)) + 1] =
+               packed_cmd_hdr[((i * 2)) + 1] = cpu_to_le32(
                        mmc_card_blockaddr(card) ?
-                       blk_rq_pos(prq) : blk_rq_pos(prq) << 9;
+                       blk_rq_pos(prq) : blk_rq_pos(prq) << 9);
                packed->blocks += blk_rq_sectors(prq);
                i++;
        }
@@ -2189,10 +2217,23 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
        struct mmc_blk_data *md;
        int devidx, ret;
 
-       devidx = find_first_zero_bit(dev_use, max_devices);
-       if (devidx >= max_devices)
-               return ERR_PTR(-ENOSPC);
-       __set_bit(devidx, dev_use);
+again:
+       if (!ida_pre_get(&mmc_blk_ida, GFP_KERNEL))
+               return ERR_PTR(-ENOMEM);
+
+       spin_lock(&mmc_blk_lock);
+       ret = ida_get_new(&mmc_blk_ida, &devidx);
+       spin_unlock(&mmc_blk_lock);
+
+       if (ret == -EAGAIN)
+               goto again;
+       else if (ret)
+               return ERR_PTR(ret);
+
+       if (devidx >= max_devices) {
+               ret = -ENOSPC;
+               goto out;
+       }
 
        md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
        if (!md) {
@@ -2271,7 +2312,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
            ((card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) ||
             card->ext_csd.rel_sectors)) {
                md->flags |= MMC_BLK_REL_WR;
-               blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA);
+               blk_queue_write_cache(md->queue.queue, true, true);
        }
 
        if (mmc_card_mmc(card) &&
@@ -2289,6 +2330,9 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
  err_kfree:
        kfree(md);
  out:
+       spin_lock(&mmc_blk_lock);
+       ida_remove(&mmc_blk_ida, devidx);
+       spin_unlock(&mmc_blk_lock);
        return ERR_PTR(ret);
 }
 
@@ -2494,11 +2538,12 @@ static const struct mmc_fixup blk_fixups[] =
                  MMC_QUIRK_BLK_NO_CMD23),
 
        /*
-        * Some Micron MMC cards needs longer data read timeout than
-        * indicated in CSD.
+        * Some MMC cards need longer data read timeout than indicated in CSD.
         */
        MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc,
                  MMC_QUIRK_LONG_READ_TIME),
+       MMC_FIXUP("008GE0", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_LONG_READ_TIME),
 
        /*
         * On these Samsung MoviNAND parts, performing secure erase or