Example #1
0
/*
 * Card detection callback from host.
 */
static void mmc_detect(struct mmc_host *host)
{
	int err;

	BUG_ON(!host);
	BUG_ON(!host->card);

	mmc_claim_host(host);

	/*
	 * Just check if our card has been removed.
	 */
	err = mmc_send_status(host->card, NULL);

	mmc_release_host(host);

	if (err) {
		mmc_remove(host);

		mmc_claim_host(host);
		mmc_detach_bus(host);
		mmc_release_host(host);
	}
}
Example #2
0
/*
 * Card detection - card is alive.
 */
static int mmc_alive(struct mmc_host *host)
{
	return mmc_send_status(host->card, NULL);
}
/**
 *	__mmc_switch - modify EXT_CSD register
 *	@card: the MMC card associated with the data transfer
 *	@set: cmd set values
 *	@index: EXT_CSD register index
 *	@value: value to program into EXT_CSD register
 *	@timeout_ms: timeout (ms) for operation performed by register write,
 *                   timeout of zero implies maximum possible timeout
 *	@use_busy_signal: use the busy signal as response type
 *
 *	Modifies the EXT_CSD register for selected card.
 */
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
	       unsigned int timeout_ms, bool use_busy_signal)
{
	int err;
	struct mmc_command cmd = {0};
	unsigned long timeout;
	u32 status;

	BUG_ON(!card);
	BUG_ON(!card->host);

	cmd.opcode = MMC_SWITCH;
	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
		  (index << 16) |
		  (value << 8) |
		  set;
	cmd.flags = MMC_CMD_AC;
	if (use_busy_signal)
		cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
	else
		cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;


	cmd.cmd_timeout_ms = timeout_ms;

	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
	if (err)
		return err;

	/* No need to check card status in case of unblocking command */
	if (!use_busy_signal)
		return 0;

	/* Must check status to be sure of no errors */
	timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
	do {
		err = mmc_send_status(card, &status);
		if (err) {
			if (err == -EILSEQ && index == EXT_CSD_HS_TIMING) {
				pr_warn("%s: CMD13 error after switching timing\n"
					"%s: this error can be ignored...\n",
					mmc_hostname(card->host),
					mmc_hostname(card->host));
				return 0;
			} else
				return err;
		}
		if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
			break;
		if (mmc_host_is_spi(card->host))
			break;

		/* Timeout if the device never leaves the program state. */
		if (time_after(jiffies, timeout)) {
			pr_err("%s: Card stuck in programming state! %s\n",
				mmc_hostname(card->host), __func__);
			return -ETIMEDOUT;
		}
	} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);

	if (mmc_host_is_spi(card->host)) {
		if (status & R1_SPI_ILLEGAL_COMMAND)
			return -EBADMSG;
	} else {
		if (status & 0xFDFFA000)
			pr_warning("%s: unexpected status %#x after "
			       "switch", mmc_hostname(card->host), status);
		if (status & R1_SWITCH_ERROR)
			return -EBADMSG;
	}

	return 0;
}
/*
 * This needs to be called with host claimed
 * @part: GPP partition part ID, should be 1/2/3/4.
 * @addr: GPP write group unit
 */
int mmc_set_user_wp(struct mmc_card *card, unsigned int part,
		unsigned int wpg)
{
	struct mmc_command cmd = {0};
	int err = 0;
	u32 status = 0;

	if (!card)
		return -ENODEV;

	mmc_claim_host(card->host);

	/*
	 * enable WP to partitions
	 * set bit2 of ext_csd[171], permanent write protect
	 */
	err = mmc_switch_bits(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_USER_WP,
			EXT_CSD_PERMANENT_WP, card->ext_csd.generic_cmd6_time,
			true, true);
	if (err) {
		pr_err("%s: enable permanent write protect err %d!\n",
				__func__, err);
		mmc_release_host(card->host);
		return err;
	}

	err = mmc_switch_part(card, part);
	if (err)
		goto switchback;

	cmd.opcode = MMC_SET_WRITE_PROT;
	cmd.arg = wpg * card->ext_csd.wpg_sz;
	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
	if (err) {
		pr_err("%s: failed to set addr 0x%x write protected, err %d\n",
				__func__, cmd.arg, err);
		goto out;
	}

	/* Must check status to be sure of no errors */
	do {
		err = mmc_send_status(card, &status);
		if (err) {
			pr_err("%s: card status get err %d, status 0x%x\n",
					__func__, err, status);
			goto out;
		}
		if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
			break;
		if (mmc_host_is_spi(card->host))
			break;
	} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);

	if (mmc_host_is_spi(card->host)) {
		if (status & R1_SPI_ILLEGAL_COMMAND) {
			pr_err("%s: error card status 0x%x\n",
					__func__, status);
			err = -EILSEQ;
			goto out;
		}
	} else {
		if (status & 0xFDFFA000)
			pr_warn("%s: unexpected status %#x after switch",
					__func__, status);
		if (status & R1_SWITCH_ERROR) {
			pr_err("%s: card switch error, status 0x%x\n",
					__func__, status);
			err = -EIO;
			goto out;
		}
		if (status & R1_OUT_OF_RANGE) {
			pr_err("%s: addr out of range, status 0x%x\n",
					__func__, status);
			err = -EINVAL;
		}
	}

out:
	err = mmc_switch_part(card, EXT_CSD_PART_CONFIG_ACC_USER);
	if (err) {
		pr_warn("%s: switch to USER partition failed!\n", __func__);
		WARN_ON(err);
	}

switchback:
	/*
	 * clear bit2 of ext_csd[171], permanent write protect
	 */
	err = mmc_switch_bits(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_USER_WP,
			EXT_CSD_PERMANENT_WP, card->ext_csd.generic_cmd6_time,
			true, false);
	if (err) {
		pr_err("%s: clear write protect err %d!\n",
				__func__, err);
	}

	mmc_release_host(card->host);

	return err;
}
/*
 * @part: GPP partition part number
 * @addr: GPP write group
 */
int mmc_wp_status(struct mmc_card *card, unsigned int part,
		unsigned int addr, u8 *wp_status)
{
	struct mmc_command cmd = {0};
	struct mmc_data data = {0};
	struct mmc_request mrq = {0};
	struct scatterlist sg;
	u32 status = 0;
	int err = 0;
	u8 *rbuf = NULL;

	if (!card)
		return -ENODEV;

	if (!card->ext_csd.gpp_sz[part - EXT_CSD_PART_CONFIG_ACC_GP0]) {
		pr_err("%s: doesn't have GPP%d\n", __func__,
				part - 3);
		return -ENODEV;
	}

	rbuf = kzalloc(8, GFP_KERNEL);
	if (rbuf == NULL) {
		pr_err("%s: no memory\n", __func__);
		return -ENOMEM;
	}

	cmd.opcode = MMC_SEND_WRITE_PROT_TYPE;
	cmd.arg = addr * card->ext_csd.wpg_sz;
	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;

	data.sg = &sg;
	data.sg_len = 1;
	data.blksz = 8;
	data.blocks = 1;
	data.flags = MMC_DATA_READ;
	sg_init_one(data.sg, rbuf, 8);
	mrq.data = &data;
	mrq.cmd = &cmd;

	mmc_claim_host(card->host);

	mmc_set_data_timeout(&data, card);

	err = mmc_switch_part(card, part);
	if (err) {
		mmc_release_host(card->host);
		dev_err(mmc_dev(card->host), "%s: swith error %d\n",
				__func__, err);
		goto out;
	}

	mmc_wait_for_req(card->host, &mrq);
	if (cmd.error) {
		dev_err(mmc_dev(card->host), "%s: cmd error %d\n",
				__func__, cmd.error);
	}
	if (data.error) {
		dev_err(mmc_dev(card->host), "%s: data error %d\n",
				__func__, data.error);
	}

	/* Must check status to be sure of no errors */
	do {
		err = mmc_send_status(card, &status);
		if (err) {
			pr_err("%s: get card status err %d, status 0x%x\n",
					__func__, err, status);
			goto out;
		}
		if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
			break;
		if (mmc_host_is_spi(card->host))
			break;
	} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);

	if (mmc_host_is_spi(card->host)) {
		if (status & R1_SPI_ILLEGAL_COMMAND) {
			pr_err("%s: error card status 0x%x\n",
					__func__, status);
			goto out;
		}
	} else {
		if (status & 0xFDFFA000)
			pr_warn("%s: unexpected status %#x after switch",
					__func__, status);
		if (status & R1_SWITCH_ERROR) {
			pr_err("%s: card switch error, status 0x%x\n",
					__func__, status);
		}
		if (status & R1_OUT_OF_RANGE) {
			pr_err("%s: addr out of range, status 0x%x\n",
					__func__, status);
			goto out;
		}
	}

	mmc_switch_part(card, EXT_CSD_PART_CONFIG_ACC_USER);

	mmc_release_host(card->host);

	sg_copy_from_buffer(data.sg, 1, rbuf, 8);

	/*
	 * the first write protect group type is in the last two
	 * bits in the last byte read from the device.
	 */
	*wp_status = rbuf[7] & 0x3;

	kfree(rbuf);

	return 0;
out:
	kfree(rbuf);

	return -EPERM;
}
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
		 unsigned int timeout_ms, bool use_busy_signal,
		 bool ignore_timeout)
{
	int err;
	struct mmc_command cmd = {0};
	unsigned long timeout;
	u32 status;

	BUG_ON(!card);
	BUG_ON(!card->host);

	cmd.opcode = MMC_SWITCH;
	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
		  (index << 16) |
		  (value << 8) |
		  set;
	cmd.flags = MMC_CMD_AC;
	if (use_busy_signal)
		cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
	else
		cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;


	cmd.cmd_timeout_ms = timeout_ms;
	cmd.ignore_timeout = ignore_timeout;

	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
	if (err)
		return err;

	
	if (!use_busy_signal)
		return 0;

	
	timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
	do {
		err = mmc_send_status(card, &status);
		if (err)
			return err;
		if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
			break;
		if (mmc_host_is_spi(card->host))
			break;

		
		if (time_after(jiffies, timeout)) {
			pr_err("%s: Card stuck in programming state! %s\n",
				mmc_hostname(card->host), __func__);
			return -ETIMEDOUT;
		}
	} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);

	if (mmc_host_is_spi(card->host)) {
		if (status & R1_SPI_ILLEGAL_COMMAND)
			return -EBADMSG;
	} else {
		if (status & 0xFDFFA000)
			pr_warning("%s: unexpected status %#x after "
			       "switch", mmc_hostname(card->host), status);
		if (status & R1_SWITCH_ERROR)
			return -EBADMSG;
	}

	return 0;
}
Example #7
0
static int mmc_queue_thread(void *d)
{
	struct mmc_queue *mq = d;
	struct request_queue *q = mq->queue;
	struct request *req;
	//ruanmeisi_20100603
	int issue_ret = 0;

#ifdef CONFIG_MMC_PERF_PROFILING
	ktime_t start, diff;
	struct mmc_host *host = mq->card->host;
	unsigned long bytes_xfer;
#endif


	current->flags |= PF_MEMALLOC;

	down(&mq->thread_sem);
	do {
        req = NULL;

		//ruanmeisi_20100603
		if (kthread_should_stop()) {
			remove_all_req(mq);
			break;
		}
		//end
		spin_lock_irq(q->queue_lock);
		set_current_state(TASK_INTERRUPTIBLE);
		if (!blk_queue_plugged(q))
			req = blk_fetch_request(q);
		mq->req = req;
		spin_unlock_irq(q->queue_lock);

		if (!req) {
			if (kthread_should_stop()) {
				set_current_state(TASK_RUNNING);
				break;
			}
			up(&mq->thread_sem);
			schedule();
			down(&mq->thread_sem);
			continue;
		}
		set_current_state(TASK_RUNNING);
#ifdef CONFIG_MMC_AUTO_SUSPEND
		mmc_auto_suspend(mq->card->host, 0);
#endif
#ifdef CONFIG_MMC_BLOCK_PARANOID_RESUME
		if (mq->check_status) {
			struct mmc_command cmd;
			int retries = 3;

			do {
				int err;

				cmd.opcode = MMC_SEND_STATUS;
				cmd.arg = mq->card->rca << 16;
				cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;

				mmc_claim_host(mq->card->host);
				err = mmc_wait_for_cmd(mq->card->host, &cmd, 5);
				mmc_release_host(mq->card->host);

				if (err) {
					printk(KERN_ERR "%s: failed to get status (%d)\n",
					       __func__, err);
					msleep(5);
					retries--;
					continue;
				}
				printk(KERN_DEBUG "%s: status 0x%.8x\n", __func__, cmd.resp[0]);
			} while (retries &&
				(!(cmd.resp[0] & R1_READY_FOR_DATA) ||
				(R1_CURRENT_STATE(cmd.resp[0]) == 7)));
			mq->check_status = 0;
                }
#endif
//ruanmeisi_20100529
	
		
		#ifdef CONFIG_MMC_PERF_PROFILING
		bytes_xfer = blk_rq_bytes(req);
		if (rq_data_dir(req) == READ) {
			start = ktime_get();
			issue_ret = mq->issue_fn(mq, req);
			diff = ktime_sub(ktime_get(), start);
			host->perf.rbytes_mmcq += bytes_xfer;
			host->perf.rtime_mmcq =
				ktime_add(host->perf.rtime_mmcq, diff);
		} else {
			start = ktime_get();
			issue_ret = mq->issue_fn(mq, req);
			diff = ktime_sub(ktime_get(), start);
			host->perf.wbytes_mmcq += bytes_xfer;
			host->perf.wtime_mmcq =
				ktime_add(host->perf.wtime_mmcq, diff);
		}
#else
				issue_ret = mq->issue_fn(mq, req);
#endif

		//ruanmeisi
		if (0 == issue_ret) {
			int err;
			mmc_claim_host(mq->card->host);
			err = mmc_send_status(mq->card, NULL);
			mmc_release_host(mq->card->host);
			if (err) {
				printk(KERN_ERR "rms:%s: failed to get status (%d) maybe the card is removed\n",
				       __func__, err);
				//sdcard is removed?
				mmc_detect_change(mq->card->host, 0);
				msleep(500);
				//set_current_state(TASK_INTERRUPTIBLE);
				//schedule_timeout(HZ / 2);
				continue;
			}
		}
	} while (1);
	up(&mq->thread_sem);

	return 0;
}
Example #8
0
/**
 *	__mmc_switch - modify EXT_CSD register
 *	@card: the MMC card associated with the data transfer
 *	@set: cmd set values
 *	@index: EXT_CSD register index
 *	@value: value to program into EXT_CSD register
 *	@timeout_ms: timeout (ms) for operation performed by register write,
 *                   timeout of zero implies maximum possible timeout
 *	@use_busy_signal: use the busy signal as response type
 *
 *	Modifies the EXT_CSD register for selected card.
 */
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
	       unsigned int timeout_ms, bool use_busy_signal)
{
	int err;
	struct mmc_command cmd = {0};
	unsigned int ignore;
	unsigned long timeout;
	u32 status;
	int retry_times = 3;

	BUG_ON(!card);
	BUG_ON(!card->host);

	cmd.opcode = MMC_SWITCH;
	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
		  (index << 16) |
		  (value << 8) |
		  set;
	cmd.flags = MMC_CMD_AC;
	if (use_busy_signal)
		cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
	else
		cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;


	cmd.cmd_timeout_ms = timeout_ms;

	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
	if (err)
		return err;

	/* No need to check card status in case of unblocking command */
	if (!use_busy_signal)
		return 0;

retry:
	/* Must check status to be sure of no errors */
	timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
	ignore = (index == EXT_CSD_HS_TIMING) ? MMC_RSP_CRC : 0;

	do {
		err = mmc_send_status(card, &status, ignore);
		if (err)
			return err;
		if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
			break;
		if (mmc_host_is_spi(card->host))
			break;

		/* Timeout if the device never leaves the program state. */
		if (time_after(jiffies, timeout)) {
			pr_err("%s: Card stuck in programming state! %s\n",
				mmc_hostname(card->host), __func__);
			return -ETIMEDOUT;
		}
	} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);

	if (mmc_host_is_spi(card->host)) {
		if (status & R1_SPI_ILLEGAL_COMMAND)
			return -EBADMSG;
	} else {
		if (status & 0xFDFFA000)
			pr_warning("%s: unexpected status %#x after "
			       "switch", mmc_hostname(card->host), status);
		if (status & R1_SWITCH_ERROR) {
			/* Means  Set HS200 bit and Driver Strength value in the HS_TIMING [185]*/
			if (((value & 0x3) == MMC_HS_TIMING_HS200) && retry_times) {
				mmc_set_timing(card->host, MMC_TIMING_MMC_HS200);
				retry_times--;
				pr_err("%s: Card set to HS200 status read should be retry! \n",
					mmc_hostname(card->host));
				goto retry;
			}
			return -EBADMSG;
		}
	}

	return 0;
}
Example #9
0
int mmc_write_prot_off_part(const char *part) {
    int rc, fd;
    struct mmc_part_info info;
    char device[PATH_MAX], *test;
    __u8 extcsd[512];
    __u32 rca, wp_grp_sz;
    uint32_t i, wpst, wped;
    bool is_sharp = is_sharp_dev();

    rc = mmc_part_info_get(part, &info);
    if (rc < 0)
        return -1;
    strncpy(device, info.path, sizeof(device));
    test = strstr(device, "mmcblk");
    if (test) {
        test += 6;
        while (isdigit(*test))
            test++;
        *test = '\0';
    }
    fd = open(device, O_RDWR);
    if (fd < 0)
        return -1;
    rc = mmc_read_extcsd(fd, extcsd);
    if (rc) {
        close(fd);
        return -1;
    }
    rc = mmc_get_wp_grp_sz(extcsd, &wp_grp_sz);
    if (rc) {
        close(fd);
        return -1;
    }
    wpst = info.offset & ~(wp_grp_sz - 1);
    wped = (info.offset + info.size) & ~(wp_grp_sz - 1);
    rc = mmc_send_rca(fd, &rca);
    if (rc) {
        // close(fd);
        // return -1;
        rca = 0x0001;
    }
    rc = mmc_set_class_6_ctrl(fd, 0);
    if (rc) {
        close(fd);
        return -1;
    }
    for (i = wpst; i < wped; i += wp_grp_sz) {
        __u32 status = 0;

        if (is_sharp && mmc_sh_pre_clr_wp(fd)) {
            // printf("failed mmc_sh_pre_clr_wp, %d\n", i);
            break;
        }
        // clear 1 group
        rc = mmc_clr_write_prot(fd, i);
        if (rc) {
            // printf("failed mmc_clr_write_prot, %d\n", i);
            break;
        }
        rc = mmc_send_status(fd, rca, &status);
        if (rc) {
            // printf("failed mmc_send_status, %d\n", i);
            break;
        }
    }
    close(fd);

    return i == wped ? 0 : -1;
}
Example #10
0
int mmc_write_prot_off() {
    int rc, fd;
    char device[PATH_MAX];
    __u8 extcsd[512];
    __u32 rca, card_sz, wp_grp_sz;
    __u32 i, loop;
    bool is_sharp = is_sharp_dev();

    rc = mmc_get_dev("system", device);
    if (rc)
        return -1;
    fd = open(device, O_RDWR);
    if (fd < 0)
        return -1;
    rc = mmc_read_extcsd(fd, extcsd);
    if (rc) {
        close(fd);
        return -1;
    }
    rc = mmc_get_card_sz(extcsd, &card_sz);
    if (rc) {
        close(fd);
        return -1;
    }
    rc = mmc_get_wp_grp_sz(extcsd, &wp_grp_sz);
    if (rc) {
        close(fd);
        return -1;
    }
    rc = mmc_send_rca(fd, &rca);
    if (rc) {
        // close(fd);
        // return -1;
        rca = 0x0001;
    }
    rc = mmc_set_class_6_ctrl(fd, 0);
    if (rc) {
        close(fd);
        return -1;
    }
    loop = card_sz / wp_grp_sz;
    for (i = 0; i < loop; i++) {
        __u32 status = 0;

        if (is_sharp && mmc_sh_pre_clr_wp(fd)) {
            // printf("failed mmc_sh_pre_clr_wp, %d\n", i * wp_grp_sz);
            break;
        }
        // clear 1 group
        rc = mmc_clr_write_prot(fd, i * wp_grp_sz);
        if (rc) {
            // printf("failed mmc_clr_write_prot, %d\n", i * wp_grp_sz);
            break;
        }
        rc = mmc_send_status(fd, rca, &status);
        if (rc) {
            // printf("failed mmc_send_status, %d\n", i * wp_grp_sz);
            break;
        }
    }
    close(fd);

    return i == loop ? 0 : -1;
}
Example #11
0
/*
 * Handle the detection and initialisation of a card.
 *
 * In the case of a resume, "oldcard" will contain the card
 * we're trying to reinitialise.
 */
static int mmc_init_card(struct mmc_host *host, u32 ocr,
	struct mmc_card *oldcard)
{
	struct mmc_card *card;
	int err, count;
	u32 cid[4];
	unsigned int max_dtr;
	u32 status;

	BUG_ON(!host);
	WARN_ON(!host->claimed);

	/*
	 * Since we're changing the OCR value, we seem to
	 * need to tell some cards to go back to the idle
	 * state.  We wait 1ms to give cards time to
	 * respond.
	 */
	mmc_go_idle(host);

	/* The extra bit indicates that we support high capacity */
	err = mmc_send_op_cond(host, ocr | (1 << 30), NULL);
	if (err)
		goto err;

	/*
	 * For SPI, enable CRC as appropriate.
	 */
	if (mmc_host_is_spi(host)) {
		err = mmc_spi_set_crc(host, use_spi_crc);
		if (err)
			goto err;
	}

	/*
	 * Fetch CID from card.
	 */
	if (mmc_host_is_spi(host))
		err = mmc_send_cid(host, cid);
	else
		err = mmc_all_send_cid(host, cid);
	if (err)
		goto err;

	if (oldcard) {
		if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
			err = -ENOENT;
			goto err;
		}

		card = oldcard;
	} else {
		/*
		 * Allocate card structure.
		 */
		card = mmc_alloc_card(host, &mmc_type);
		if (IS_ERR(card)) {
			err = PTR_ERR(card);
			goto err;
		}

		card->type = MMC_TYPE_MMC;
		card->rca = 1;
		memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
	}

	/*
	 * For native busses:  set card RCA and quit open drain mode.
	 */
	if (!mmc_host_is_spi(host)) {
		err = mmc_set_relative_addr(card);
		if (err)
			goto free_card;

		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
	}

	if (!oldcard) {
		/*
		 * Fetch CSD from card.
		 */
		err = mmc_send_csd(card, card->raw_csd);
		if (err)
			goto free_card;

		err = mmc_decode_csd(card);
		if (err)
			goto free_card;
		err = mmc_decode_cid(card);
		if (err)
			goto free_card;
	}

	/*
	 * Select card, as all following commands rely on that.
	 */
	if (!mmc_host_is_spi(host)) {
		err = mmc_select_card(card);
		if (err)
			goto free_card;
	}

	if (!oldcard) {
		/*
		 * Fetch and process extended CSD.
		 */
		err = mmc_read_ext_csd(card);
		if (err)
			goto free_card;
	}

	/*
	 * Activate high speed (if supported)
	 */
	if ((card->ext_csd.hs_max_dtr != 0) &&
		(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
			EXT_CSD_HS_TIMING, 1);
		if (err)
			goto free_card;

		mmc_card_set_highspeed(card);

		mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
	}

	count = 0;
	do {
		err = mmc_send_status(card, &status);
		if (err)
			goto free_card;
		if (status & R1_READY_FOR_DATA)
			break;
		else
			mdelay(1);
	} while (++count < WAIT_CMD6_MAX);

	/*
	 * Compute bus speed.
	 */
	max_dtr = (unsigned int)-1;

	if (mmc_card_highspeed(card)) {
		if (max_dtr > card->ext_csd.hs_max_dtr)
			max_dtr = card->ext_csd.hs_max_dtr;
	} else if (max_dtr > card->csd.max_dtr) {
		max_dtr = card->csd.max_dtr;
	}

	mmc_set_clock(host, max_dtr);

	/*
	 * Activate wide bus (if supported).
	 */
	if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
		unsigned ext_csd_bit, bus_width;

		if (host->caps & MMC_CAP_8_BIT_DATA) {
			ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
			bus_width = MMC_BUS_WIDTH_8;
		} else {
			ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
			bus_width = MMC_BUS_WIDTH_4;
		}

		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
				 EXT_CSD_BUS_WIDTH, ext_csd_bit);

		if (err)
			goto free_card;

		mmc_set_bus_width(card->host, bus_width);

		count = 0;
		do {
			err = mmc_send_status(card, &status);
			if (err)
				goto free_card;
			if (status & R1_READY_FOR_DATA)
				break;
			else
				mdelay(1);
		} while (++count < WAIT_CMD6_MAX);
	}

	if (!oldcard)
		host->card = card;

	return 0;

free_card:
	if (!oldcard)
		mmc_remove_card(card);
err:

	return err;
}
Example #12
0
int mmc_test_mem_card(struct mmc_test_config *cfg)
{
    int id, count, forever;
    int ret, chk_result, tid = 0, result = 0;
    unsigned int chunks, chunk_blks, left_blks, pass = 0, fail = 0;
    unsigned int total_blks;
    unsigned int i, j;
    unsigned int blksz;
    unsigned int clkhz;    
    char pattern = 0;
    char *buf;
    unsigned long blknr;
    struct mmc_host *host;
    struct mmc_card *card;

    id    = cfg->id;
    count = cfg->count;
    buf   = cfg->buf;
    blknr = cfg->blknr;
    blksz = cfg->blksz;

    chk_result = cfg->chk_result;
    chunk_blks = cfg->chunk_blks;
    total_blks = (cfg->total_size + blksz - 1) / blksz;
    forever    = (count == -1) ? 1 : 0;

    host = mmc_get_host(id);
    card = mmc_get_card(id);

    while (forever || count--) {
        printf("[TST] ==============================================\n");
        printf("[TST] BEGIN: %d/%d, No Stop(%d)\n", 
            (cfg->count != -1) ? cfg->count - count : 0, 
            (cfg->count != -1) ? cfg->count : 0, forever);
        printf("[TST] ----------------------------------------------\n");
        printf("[TST] Mode    : %d\n", cfg->mode);
        printf("[TST] Clock   : %d kHz\n", cfg->clock / 1000);
        printf("[TST] BusWidth: %d bits\n", cfg->buswidth);
        printf("[TST] BurstSz : %d bytes\n", 0x1 << cfg->burstsz);
        printf("[TST] BlkAddr : %xh\n", blknr);
        printf("[TST] BlkSize : %dbytes\n", blksz);
        printf("[TST] TstBlks : %d\n", total_blks);
#if defined(BB_MT6575)
        printf("[TST] AutoCMD : 12(%d), 23(%d)\n", 
            (cfg->autocmd & MSDC_AUTOCMD12) ? 1 : 0, 
            (cfg->autocmd & MSDC_AUTOCMD23) ? 1 : 0);
#endif
        printf("[TST] ----------------------------------------------\n");


        if (mmc_init_host(host, id) != 0) {
            result = -__LINE__;
            goto failure;
        }
        if (mmc_init_card(host, card) != 0) {
            result = -__LINE__;
            goto failure;
        }
#if defined(BB_MT6575)
        msdc_set_dma(host, (u8)cfg->burstsz, (u32)cfg->flags);
        msdc_set_autocmd(host, cfg->autocmd, 1);
#endif

        /* change uhs-1 mode */
#if 0        
        if (mmc_card_uhs1(card)) {
            if (mmc_switch_uhs1(host, card, cfg->uhsmode) != 0) {
                result = -__LINE__;
                goto failure;
            }
        }
#endif

        /* change clock */
        if (cfg->clock) {
            clkhz = card->maxhz < cfg->clock ? card->maxhz : cfg->clock;
            mmc_set_clock(host, mmc_card_ddr(card), clkhz); 
        }
        if (mmc_card_sd(card) && cfg->buswidth == HOST_BUS_WIDTH_8) {
            printf("[TST] SD card doesn't support 8-bit bus width (SKIP)\n");
            result = MMC_ERR_NONE;
        }
        if (mmc_set_bus_width(host, card, cfg->buswidth) != 0) {
            result = -__LINE__;
            goto failure;
        }

        /* cmd16 is illegal while card is in ddr mode */
        if (!(mmc_card_mmc(card) && mmc_card_ddr(card))) {
            if (mmc_set_blk_length(host, blksz) != 0) {
                result = -__LINE__;
                goto failure;            
            }
        }

#if defined(BB_MT6575)
        if (cfg->piobits) {
            printf("[TST] PIO bits: %d\n", cfg->piobits);
            msdc_set_pio_bits(host, cfg->piobits);
        }
#endif
        tid = result = 0;        

        if (mmc_erase_start(card, blknr * blksz) != MMC_ERR_NONE) {
            result = -__LINE__;
            goto failure;
        }
        if (mmc_erase_end(card, (blknr + total_blks) * blksz) != MMC_ERR_NONE) {
            result = -__LINE__;
            goto failure;
        }
        if (mmc_erase(card, MMC_ERASE_NORMAL) != MMC_ERR_NONE) {
            result = -__LINE__;
            goto failure;        
        }
        printf("[TST] 0x%x - 0x%x Erased\n", blknr * blksz, 
            (blknr + total_blks) * blksz);

        mmc_send_status(host, card, &status);

        if (cfg->tst_single) {
            /* single block write */
            for (i = 0; i < total_blks; i++) {
                pattern = (i + count) % 256;
                memset(buf, pattern, blksz);
                ret = mmc_block_write(id, blknr + i, 1, (unsigned long*)buf);
                if (ret != MMC_ERR_NONE) {
                    printf("test single block write failed (%d)\n", i);
                    result = -__LINE__;
                    goto failure;
                }
            }

            printf(TC_MSG, host->id, result == 0 ? "PASS" : "FAIL", tid++, 
                "test single block write\n");

            if (result)
                break;
            
            /* single block read */
            for (i = 0; i < total_blks && !result; i++) {
                pattern = (i + count) % 256;
                /* populate buffer with different pattern */
                memset(buf, pattern + 1, blksz);
                ret = mmc_block_read(id, blknr + i, 1, (unsigned long*)buf);
                if (ret != MMC_ERR_NONE) {
                    result = -__LINE__;
                    goto failure;
                }
                if (chk_result) {
                    for (j = 0; j < blksz; j++) {
                        if (buf[j] != pattern) {
                            result = -__LINE__;
                            goto failure;
                        }
                    }
                }
            }
            printf(TC_MSG, host->id, result == 0 ? "PASS" : "FAIL", tid++, 
                "test single block read\n");

            if (result) {
                printf("[SD%d]\t\tread back pattern(0x%.2x) failed\n", 
                    id, pattern);
                goto failure;
            }
        }

        mmc_send_status(host, card, &status);
        
        if (cfg->tst_multiple) {
            /* multiple block write */
            chunks = total_blks / chunk_blks;
            left_blks = total_blks % chunk_blks;   
            for (i = 0; i < chunks; i++) {
                pattern = (i + count) % 256;
                memset(buf, pattern, blksz * chunk_blks);
                ret = mmc_block_write(id, blknr + i * chunk_blks, 
                    chunk_blks, (unsigned long*)buf);
                if (ret != MMC_ERR_NONE) {
                    result = -__LINE__;
                    goto failure;
                }
            }
            
            if (!result && left_blks) {
                pattern = (i + count) % 256;
                memset(buf, pattern, blksz * left_blks);
                ret = mmc_block_write(id, blknr + chunks * chunk_blks, 
                    left_blks, (unsigned long*)buf);
                if (ret != MMC_ERR_NONE) {
                    result = -__LINE__;
                    goto failure;
                }
            }

            printf(TC_MSG, host->id, result == 0 ? "PASS" : "FAIL", tid++, 
                "test multiple block write\n");

            if (result)
                goto failure;

            /* multiple block read */
            for (i = 0; i < chunks; i++) {
                pattern = (i + count) % 256;
                /* populate buffer with different pattern */
                memset(buf, pattern + 1, blksz);
                ret = mmc_block_read(id, blknr + i * chunk_blks, 
                    chunk_blks, (unsigned long*)buf);
                if (ret != MMC_ERR_NONE) {
                    printf("[SD%d]\t\tread %d blks failed(ret = %d blks)\n",
                        host->id, chunk_blks, ret);
                    result = -__LINE__;
                    goto failure;
                }
                if (chk_result) {
                    for (j = 0; j < chunk_blks * blksz; j++) {
                        if (buf[j] == pattern)
                            continue;
                        result = -__LINE__;
                        printf("[SD%d]\t\t%xh = %x (!= %x)\n",
                            host->id, blknr + i * chunk_blks + j, buf[j], pattern);
                        goto failure;
                    }
                }
            }

            if (!result && left_blks) {
                pattern = i % 256;
                /* populate buffer with different pattern */
                memset(buf, pattern + 1, blksz);
                ret = mmc_block_read(id, blknr + chunks * chunk_blks, 
                    left_blks, (unsigned long*)buf);
                if (ret != MMC_ERR_NONE) {
                    printf("[SD%d]\t\tread %d blks failed(ret = %d blks)\n",
                        host->id, left_blks, ret);
                    result = -__LINE__;
                    goto failure;
                }
                if (chk_result) {
                    for (j = 0; j < left_blks * blksz; j++) {
                        if (buf[j] == pattern)
                            continue;
                        printf("[SD%d]\t\t%xh = %x (!= %x)\n",
                            host->id, blknr + chunks * chunk_blks + j, buf[j], pattern);
                        result = -__LINE__;
                        goto failure;
                    }
                }
            }

            printf(TC_MSG, host->id, result == 0 ? "PASS" : "FAIL", tid++, 
                "test multiple block read\n");

            if (result)
                goto failure;
        }

        mmc_send_status(host, card, &status);

        if (cfg->tst_interleave) {
            /* multiple block write */
            chunks = total_blks / chunk_blks;
            left_blks = total_blks % chunk_blks;   
            for (i = 0; i < chunks; i++) {
                pattern = (i + count) % 256;
                memset(buf, pattern, blksz * chunk_blks);
                ret = mmc_block_write(id, blknr + i * chunk_blks, 
                    chunk_blks, (unsigned long*)buf);
                if (ret != MMC_ERR_NONE) {
                    result = -__LINE__;
                    goto failure;
                }

                /* populate buffer with different pattern */
                memset(buf, pattern + 1, blksz * chunk_blks);
                ret = mmc_block_read(id, blknr + i * chunk_blks, 
                    chunk_blks, (unsigned long*)buf);
                if (ret != MMC_ERR_NONE) {
                    result = -__LINE__;
                    goto failure;
                }
                if (chk_result) {
                    for (j = 0; j < chunk_blks * blksz; j++) {
                        if (buf[j] == pattern) 
                            continue;
                        result = -__LINE__;
                        goto failure;
                    }
                }                
            }           

            if (!result && left_blks) {
                pattern = (i + count) % 256;
                memset(buf, pattern, blksz * left_blks);
                ret = mmc_block_write(id, blknr + chunks * chunk_blks, 
                    left_blks, (unsigned long*)buf);
                if (ret != MMC_ERR_NONE) {
                    result = -__LINE__;
                    goto failure;
                }

                /* populate buffer with different pattern */
                memset(buf, pattern + 1, blksz * left_blks);
                ret = mmc_block_read(id, blknr + chunks * chunk_blks, 
                    left_blks, (unsigned long*)buf);
                if (ret != MMC_ERR_NONE) {
                    result = -__LINE__;
                    break;
                }
                if (chk_result) {
                    for (j = 0; j < left_blks * blksz; j++) {
                        if (buf[j] == pattern)
                            continue;
                        result = -__LINE__;
                        goto failure;
                    }
                }
            }

            printf(TC_MSG, host->id, result == 0 ? "PASS" : "FAIL", tid++, 
                "test multiple block interleave write-read\n");

            if (result)
                goto failure;
        }
        if (cfg->desc) {
            printf("[TST] ----------------------------------------------\n");
            printf("[TST] Report - %s \n", cfg->desc);
            printf("[TST] ----------------------------------------------\n");
        }
        mmc_prof_dump(id);

failure:
        if (result) {
            printf("[SD%d] mmc test failed (%d)\n", host->id, result);
            fail++;
        } else {
            pass++;
        }
        printf("[TST] ----------------------------------------------\n");
        printf("[TST] Test Result: TOTAL(%d/%d), PASS(%d), FAIL(%d) \n", 
            cfg->count - count, cfg->count, pass, fail);
        printf("[TST] ----------------------------------------------\n");    
    	//mdelay(1000);
    }

    return result;
}
Example #13
0
// extern struct partition partitions[];
static ssize_t mmc_wr_prot_write(struct file *filp,
		const char __user *ubuf, size_t cnt,
		loff_t *ppos)
{
	struct mmc_card *card = filp->private_data;
	unsigned int wp_group_size;
	unsigned int set_clear_wp, status;
	int ret, i;
	unsigned int addr = 0;
	unsigned int init_addr = 0;
	unsigned int loop_count = 0;
	unsigned int size = 0;
	char *cmd_buffer;

	// struct mmc_request mrq = {NULL};
	struct mmc_command cmd = {0};

	struct emmc_partition *p_emmc_partition;

	pr_info("[HW]: eMMC protect driver built on %s @ %s\n", __DATE__, __TIME__);

	if( ubuf == NULL){
		pr_info("[HW]:%s: NULL pointer \n", __func__);
		return -1;
	}

	cmd_buffer = kmalloc(sizeof(char)*cnt, GFP_KERNEL);
	if (cmd_buffer == NULL) {
		return -ENOMEM;
	}
	memset(cmd_buffer, 0, sizeof(char)*cnt);

	if(copy_from_user(cmd_buffer, ubuf, cnt)){
		kfree(cmd_buffer);
		return -EFAULT;
	}

	pr_info("[HW]:%s: input arg = %s, cnt = %d \n", __func__, cmd_buffer, cnt);

	if(strncmp(cmd_buffer, "disable_prot", strlen("disable_prot")) == 0){
		set_clear_wp = 0;
	}else if(strncmp(cmd_buffer, "enable_prot", strlen("enable_prot")) == 0){
		set_clear_wp = 1;
	}
	else{
		kfree(cmd_buffer);
		return -1;
	}

	// mrq.cmd = &cmd;
	// mrq.data = &data;

	wp_group_size =(512 * 1024) * card->ext_csd.raw_hc_erase_gap_size
		* card->ext_csd.raw_hc_erase_grp_size / 512;

	p_emmc_partition = g_emmc_partition;
	for(i = 0; i < MAX_EMMC_PARTITION_NUM; i++){
		if(p_emmc_partition->flags == 0)
			break;
		if(strcmp(p_emmc_partition->name, "system") == 0){
			addr = (unsigned int)(p_emmc_partition->start);
			size = (unsigned int)(p_emmc_partition->size_sectors);
			pr_info("[HW]:%s: partitionname = %s \n", __func__, p_emmc_partition->name);
			pr_info("[HW]:%s: partition start from = 0x%08x \n", __func__, addr);
			pr_info("[HW]:%s: partition size = 0x%08x \n", __func__, size);
			break;
		}
		p_emmc_partition++;
	}

	if(strcmp(p_emmc_partition->name, "")  == 0){
		pr_info("[HW]:%s: can not find partition system \n", __func__);
		kfree(cmd_buffer);
		return -1;
	}

	pr_info("[HW]:%s: card->ext_csd.raw_hc_erase_gap_size = 0x%02x,  card->ext_csd.raw_hc_erase_grp_size = 0x%02x \n", __func__, \
			card->ext_csd.raw_hc_erase_gap_size, card->ext_csd.raw_hc_erase_grp_size);

	pr_info("[HW]:%s, size = 0x%08x, wp_group_size = 0x%08x, unit is block \n", \
			__func__, size, wp_group_size);
	if (wp_group_size == 0) {
		pr_info("[HW]:%s:invalid wp_group_size=0x%08x.", __func__, wp_group_size);
		kfree(cmd_buffer);
		return -2;
	}

	init_addr = addr;

	if(addr % wp_group_size == 0){

	}else{
		addr = (addr / wp_group_size) * wp_group_size + wp_group_size;
		pr_info("[HW]:%s: setting start area is not muti size of wp_group_size\n", __func__);
	}

	loop_count = (init_addr + size - addr) / wp_group_size;

	pr_info("[HW]:%s:prot_start_sec_addr = 0x%08x \n", __func__, addr);
	pr_info("[HW]:%s:loop_count = %x \n", __func__, loop_count);

	cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;

	if (set_clear_wp){
		cmd.opcode = MMC_SET_WRITE_PROT;
	}else{
		cmd.opcode = MMC_CLR_WRITE_PROT;
	}

	for (i = 0; i < loop_count; i++) {

		/* Sending CMD28 for each WP group size
		   address is in sectors already */

		cmd.arg = addr + (i * wp_group_size);
		pr_info("[HW:%s:loop_count = %d, cmd.arg = 0x%08x, cmd.opcode = %d, \n", __func__, i, cmd.arg, cmd.opcode);

		mmc_claim_host(card->host);
		ret = mmc_wait_for_cmd(card->host, &cmd, 3);
		mmc_release_host(card->host);

		if (ret) {
			pr_err("[HW]:%s:mmc_wait_for_cmd return err = %d \n", __func__, ret);
			kfree(cmd_buffer);
			return -3;
		}

		/* Sending CMD13 to check card status */
		do {
			mmc_claim_host(card->host);
			ret = mmc_send_status(card, &status);
			mmc_release_host(card->host);
			if (R1_CURRENT_STATE(status) == R1_STATE_TRAN)
				break;
		}while ((!ret) && (R1_CURRENT_STATE(status) == R1_STATE_PRG));

		if (ret) {
			pr_err("[HW]:%s: mmc_send_status return err = %d \n", __func__, ret);
			kfree(cmd_buffer);
			return -4;
		}
	}

	pr_info("[HW]: %s: end sector = 0x%08x \n", __func__, size + init_addr);
	pr_info("[HW]: %s: size = 0x%08x \n", __func__,  size);
	kfree(cmd_buffer);
	return size;
}