diff options
Diffstat (limited to 'drivers/mmc/core')
| -rw-r--r-- | drivers/mmc/core/core.c | 41 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/core/sd.c | 6 | ||||
| -rw-r--r-- | drivers/mmc/core/sdio_cis.c | 6 | ||||
| -rw-r--r-- | drivers/mmc/core/sdio_io.c | 167 | 
5 files changed, 175 insertions, 47 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 01ced4c5a61..3ee5b8c3b5c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -3,7 +3,7 @@   *   *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.   *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. - *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. + *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.   *  MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.   *   * This program is free software; you can redistribute it and/or modify @@ -295,6 +295,33 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)  EXPORT_SYMBOL(mmc_set_data_timeout);  /** + *	mmc_align_data_size - pads a transfer size to a more optimal value + *	@card: the MMC card associated with the data transfer + *	@sz: original transfer size + * + *	Pads the original data size with a number of extra bytes in + *	order to avoid controller bugs and/or performance hits + *	(e.g. some controllers revert to PIO for certain sizes). + * + *	Returns the improved size, which might be unmodified. + * + *	Note that this function is only relevant when issuing a + *	single scatter gather entry. + */ +unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz) +{ +	/* +	 * FIXME: We don't have a system for the controller to tell +	 * the core about its problems yet, so for now we just 32-bit +	 * align the size. +	 */ +	sz = ((sz + 3) / 4) * 4; + +	return sz; +} +EXPORT_SYMBOL(mmc_align_data_size); + +/**   *	__mmc_claim_host - exclusively claim a host   *	@host: mmc host to claim   *	@abort: whether or not the operation should be aborted @@ -638,6 +665,9 @@ void mmc_rescan(struct work_struct *work)  		 */  		mmc_bus_put(host); +		if (host->ops->get_cd && host->ops->get_cd(host) == 0) +			goto out; +  		mmc_claim_host(host);  		mmc_power_up(host); @@ -652,7 +682,7 @@ void mmc_rescan(struct work_struct *work)  		if (!err) {  			if (mmc_attach_sdio(host, ocr))  				mmc_power_off(host); -			return; +			goto out;  		}  		/* @@ -662,7 +692,7 @@ void mmc_rescan(struct work_struct *work)  		if (!err) {  			if (mmc_attach_sd(host, ocr))  				mmc_power_off(host); -			return; +			goto out;  		}  		/* @@ -672,7 +702,7 @@ void mmc_rescan(struct work_struct *work)  		if (!err) {  			if (mmc_attach_mmc(host, ocr))  				mmc_power_off(host); -			return; +			goto out;  		}  		mmc_release_host(host); @@ -683,6 +713,9 @@ void mmc_rescan(struct work_struct *work)  		mmc_bus_put(host);  	} +out: +	if (host->caps & MMC_CAP_NEEDS_POLL) +		mmc_schedule_delayed_work(&host->detect, HZ);  }  void mmc_start_host(struct mmc_host *host) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 3da29eef8f7..fdd7c760be8 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -288,7 +288,7 @@ static struct device_type mmc_type = {  /*   * Handle the detection and initialisation of a card.   * - * In the case of a resume, "curcard" will contain the 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, diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 7ef3b15c5e3..26fc098d77c 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -326,7 +326,7 @@ static struct device_type sd_type = {  /*   * Handle the detection and initialisation of a card.   * - * In the case of a resume, "curcard" will contain the card + * In the case of a resume, "oldcard" will contain the card   * we're trying to reinitialise.   */  static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, @@ -494,13 +494,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,  	 * Check if read-only switch is active.  	 */  	if (!oldcard) { -		if (!host->ops->get_ro) { +		if (!host->ops->get_ro || host->ops->get_ro(host) < 0) {  			printk(KERN_WARNING "%s: host does not "  				"support reading read-only "  				"switch. assuming write-enable.\n",  				mmc_hostname(host));  		} else { -			if (host->ops->get_ro(host)) +			if (host->ops->get_ro(host) > 0)  				mmc_card_set_readonly(card);  		}  	} diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index d5e51b1c7b3..956bd767750 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -129,6 +129,12 @@ static int cistpl_funce_func(struct sdio_func *func,  	/* TPLFE_MAX_BLK_SIZE */  	func->max_blksize = buf[12] | (buf[13] << 8); +	/* TPLFE_ENABLE_TIMEOUT_VAL, present in ver 1.1 and above */ +	if (vsn > SDIO_SDIO_REV_1_00) +		func->enable_timeout = (buf[28] | (buf[29] << 8)) * 10; +	else +		func->enable_timeout = jiffies_to_msecs(HZ); +  	return 0;  } diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 625b92ce9ce..f61fc2d4cd0 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -1,7 +1,7 @@  /*   *  linux/drivers/mmc/core/sdio_io.c   * - *  Copyright 2007 Pierre Ossman + *  Copyright 2007-2008 Pierre Ossman   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -76,11 +76,7 @@ int sdio_enable_func(struct sdio_func *func)  	if (ret)  		goto err; -	/* -	 * FIXME: This should timeout based on information in the CIS, -	 * but we don't have card to parse that yet. -	 */ -	timeout = jiffies + HZ; +	timeout = jiffies + msecs_to_jiffies(func->enable_timeout);  	while (1) {  		ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IORx, 0, ®); @@ -167,10 +163,8 @@ int sdio_set_block_size(struct sdio_func *func, unsigned blksz)  		return -EINVAL;  	if (blksz == 0) { -		blksz = min(min( -			func->max_blksize, -			func->card->host->max_blk_size), -			512u); +		blksz = min(func->max_blksize, func->card->host->max_blk_size); +		blksz = min(blksz, 512u);  	}  	ret = mmc_io_rw_direct(func->card, 1, 0, @@ -186,9 +180,116 @@ int sdio_set_block_size(struct sdio_func *func, unsigned blksz)  	func->cur_blksize = blksz;  	return 0;  } -  EXPORT_SYMBOL_GPL(sdio_set_block_size); +/* + * Calculate the maximum byte mode transfer size + */ +static inline unsigned int sdio_max_byte_size(struct sdio_func *func) +{ +	unsigned mval =	min(func->card->host->max_seg_size, +			    func->card->host->max_blk_size); +	mval = min(mval, func->max_blksize); +	return min(mval, 512u); /* maximum size for byte mode */ +} + +/** + *	sdio_align_size - pads a transfer size to a more optimal value + *	@func: SDIO function + *	@sz: original transfer size + * + *	Pads the original data size with a number of extra bytes in + *	order to avoid controller bugs and/or performance hits + *	(e.g. some controllers revert to PIO for certain sizes). + * + *	If possible, it will also adjust the size so that it can be + *	handled in just a single request. + * + *	Returns the improved size, which might be unmodified. + */ +unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz) +{ +	unsigned int orig_sz; +	unsigned int blk_sz, byte_sz; +	unsigned chunk_sz; + +	orig_sz = sz; + +	/* +	 * Do a first check with the controller, in case it +	 * wants to increase the size up to a point where it +	 * might need more than one block. +	 */ +	sz = mmc_align_data_size(func->card, sz); + +	/* +	 * If we can still do this with just a byte transfer, then +	 * we're done. +	 */ +	if (sz <= sdio_max_byte_size(func)) +		return sz; + +	if (func->card->cccr.multi_block) { +		/* +		 * Check if the transfer is already block aligned +		 */ +		if ((sz % func->cur_blksize) == 0) +			return sz; + +		/* +		 * Realign it so that it can be done with one request, +		 * and recheck if the controller still likes it. +		 */ +		blk_sz = ((sz + func->cur_blksize - 1) / +			func->cur_blksize) * func->cur_blksize; +		blk_sz = mmc_align_data_size(func->card, blk_sz); + +		/* +		 * This value is only good if it is still just +		 * one request. +		 */ +		if ((blk_sz % func->cur_blksize) == 0) +			return blk_sz; + +		/* +		 * We failed to do one request, but at least try to +		 * pad the remainder properly. +		 */ +		byte_sz = mmc_align_data_size(func->card, +				sz % func->cur_blksize); +		if (byte_sz <= sdio_max_byte_size(func)) { +			blk_sz = sz / func->cur_blksize; +			return blk_sz * func->cur_blksize + byte_sz; +		} +	} else { +		/* +		 * We need multiple requests, so first check that the +		 * controller can handle the chunk size; +		 */ +		chunk_sz = mmc_align_data_size(func->card, +				sdio_max_byte_size(func)); +		if (chunk_sz == sdio_max_byte_size(func)) { +			/* +			 * Fix up the size of the remainder (if any) +			 */ +			byte_sz = orig_sz % chunk_sz; +			if (byte_sz) { +				byte_sz = mmc_align_data_size(func->card, +						byte_sz); +			} + +			return (orig_sz / chunk_sz) * chunk_sz + byte_sz; +		} +	} + +	/* +	 * The controller is simply incapable of transferring the size +	 * we want in decent manner, so just return the original size. +	 */ +	return orig_sz; +} +EXPORT_SYMBOL_GPL(sdio_align_size); +  /* Split an arbitrarily sized data transfer into several   * IO_RW_EXTENDED commands. */  static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, @@ -199,14 +300,13 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,  	int ret;  	/* Do the bulk of the transfer using block mode (if supported). */ -	if (func->card->cccr.multi_block) { +	if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) {  		/* Blocks per command is limited by host count, host transfer  		 * size (we only use a single sg entry) and the maximum for  		 * IO_RW_EXTENDED of 511 blocks. */ -		max_blocks = min(min( -			func->card->host->max_blk_count, -			func->card->host->max_seg_size / func->cur_blksize), -			511u); +		max_blocks = min(func->card->host->max_blk_count, +			func->card->host->max_seg_size / func->cur_blksize); +		max_blocks = min(max_blocks, 511u);  		while (remainder > func->cur_blksize) {  			unsigned blocks; @@ -231,11 +331,7 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,  	/* Write the remainder using byte mode. */  	while (remainder > 0) { -		size = remainder; -		if (size > func->cur_blksize) -			size = func->cur_blksize; -		if (size > 512) -			size = 512; /* maximum size for byte mode */ +		size = min(remainder, sdio_max_byte_size(func));  		ret = mmc_io_rw_extended(func->card, write, func->num, addr,  			 incr_addr, buf, 1, size); @@ -260,11 +356,10 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,   *	function. If there is a problem reading the address, 0xff   *	is returned and @err_ret will contain the error code.   */ -unsigned char sdio_readb(struct sdio_func *func, unsigned int addr, -	int *err_ret) +u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret)  {  	int ret; -	unsigned char val; +	u8 val;  	BUG_ON(!func); @@ -293,8 +388,7 @@ EXPORT_SYMBOL_GPL(sdio_readb);   *	function. @err_ret will contain the status of the actual   *	transfer.   */ -void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, -	int *err_ret) +void sdio_writeb(struct sdio_func *func, u8 b, unsigned int addr, int *err_ret)  {  	int ret; @@ -355,7 +449,6 @@ int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr,  {  	return sdio_io_rw_ext_helper(func, 0, addr, 0, dst, count);  } -  EXPORT_SYMBOL_GPL(sdio_readsb);  /** @@ -385,8 +478,7 @@ EXPORT_SYMBOL_GPL(sdio_writesb);   *	function. If there is a problem reading the address, 0xffff   *	is returned and @err_ret will contain the error code.   */ -unsigned short sdio_readw(struct sdio_func *func, unsigned int addr, -	int *err_ret) +u16 sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret)  {  	int ret; @@ -400,7 +492,7 @@ unsigned short sdio_readw(struct sdio_func *func, unsigned int addr,  		return 0xFFFF;  	} -	return le16_to_cpu(*(u16*)func->tmpbuf); +	return le16_to_cpup((__le16 *)func->tmpbuf);  }  EXPORT_SYMBOL_GPL(sdio_readw); @@ -415,12 +507,11 @@ EXPORT_SYMBOL_GPL(sdio_readw);   *	function. @err_ret will contain the status of the actual   *	transfer.   */ -void sdio_writew(struct sdio_func *func, unsigned short b, unsigned int addr, -	int *err_ret) +void sdio_writew(struct sdio_func *func, u16 b, unsigned int addr, int *err_ret)  {  	int ret; -	*(u16*)func->tmpbuf = cpu_to_le16(b); +	*(__le16 *)func->tmpbuf = cpu_to_le16(b);  	ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 2);  	if (err_ret) @@ -439,8 +530,7 @@ EXPORT_SYMBOL_GPL(sdio_writew);   *	0xffffffff is returned and @err_ret will contain the error   *	code.   */ -unsigned long sdio_readl(struct sdio_func *func, unsigned int addr, -	int *err_ret) +u32 sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret)  {  	int ret; @@ -454,7 +544,7 @@ unsigned long sdio_readl(struct sdio_func *func, unsigned int addr,  		return 0xFFFFFFFF;  	} -	return le32_to_cpu(*(u32*)func->tmpbuf); +	return le32_to_cpup((__le32 *)func->tmpbuf);  }  EXPORT_SYMBOL_GPL(sdio_readl); @@ -469,12 +559,11 @@ EXPORT_SYMBOL_GPL(sdio_readl);   *	function. @err_ret will contain the status of the actual   *	transfer.   */ -void sdio_writel(struct sdio_func *func, unsigned long b, unsigned int addr, -	int *err_ret) +void sdio_writel(struct sdio_func *func, u32 b, unsigned int addr, int *err_ret)  {  	int ret; -	*(u32*)func->tmpbuf = cpu_to_le32(b); +	*(__le32 *)func->tmpbuf = cpu_to_le32(b);  	ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 4);  	if (err_ret)  |