Release 4.7 drivers/staging/rts5208/rtsx_transport.c
  
  
/*
 * Driver for Realtek PCI-Express card reader
 *
 * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
 *
 * 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 the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, see <http://www.gnu.org/licenses/>.
 *
 * Author:
 *   Wei WANG (wei_wang@realsil.com.cn)
 *   Micky Ching (micky_ching@realsil.com.cn)
 */
#include <linux/blkdev.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include "rtsx.h"
/***********************************************************************
 * Scatter-gather transfer buffer access routines
 ***********************************************************************/
/*
 * Copy a buffer of length buflen to/from the srb's transfer buffer.
 * (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer
 * points to a list of s-g entries and we ignore srb->request_bufflen.
 * For non-scatter-gather transfers, srb->request_buffer points to the
 * transfer buffer itself and srb->request_bufflen is the buffer's length.)
 * Update the *index and *offset variables so that the next copy will
 * pick up from where this one left off.
 */
unsigned int rtsx_stor_access_xfer_buf(unsigned char *buffer,
				       unsigned int buflen,
				       struct scsi_cmnd *srb,
				       unsigned int *index,
				       unsigned int *offset,
				       enum xfer_buf_dir dir)
{
	unsigned int cnt;
	/* If not using scatter-gather, just transfer the data directly. */
	if (scsi_sg_count(srb) == 0) {
		unsigned char *sgbuffer;
		if (*offset >= scsi_bufflen(srb))
			return 0;
		cnt = min(buflen, scsi_bufflen(srb) - *offset);
		sgbuffer = (unsigned char *)scsi_sglist(srb) + *offset;
		if (dir == TO_XFER_BUF)
			memcpy(sgbuffer, buffer, cnt);
		else
			memcpy(buffer, sgbuffer, cnt);
		*offset += cnt;
	/*
         * Using scatter-gather.  We have to go through the list one entry
         * at a time.  Each s-g entry contains some number of pages, and
         * each page has to be kmap()'ed separately.
         */
	} else {
		struct scatterlist *sg =
				(struct scatterlist *)scsi_sglist(srb)
				+ *index;
		/*
                 * This loop handles a single s-g list entry, which may
                 * include multiple pages.  Find the initial page structure
                 * and the starting offset within the page, and update
                 * the *offset and *index values for the next loop.
                 */
		cnt = 0;
		while (cnt < buflen && *index < scsi_sg_count(srb)) {
			struct page *page = sg_page(sg) +
					((sg->offset + *offset) >> PAGE_SHIFT);
			unsigned int poff = (sg->offset + *offset) &
					    (PAGE_SIZE - 1);
			unsigned int sglen = sg->length - *offset;
			if (sglen > buflen - cnt) {
				/* Transfer ends within this s-g entry */
				sglen = buflen - cnt;
				*offset += sglen;
			} else {
				/* Transfer continues to next s-g entry */
				*offset = 0;
				++*index;
				++sg;
			}
			while (sglen > 0) {
				unsigned int plen = min(sglen, (unsigned int)
						PAGE_SIZE - poff);
				unsigned char *ptr = kmap(page);
				if (dir == TO_XFER_BUF)
					memcpy(ptr + poff, buffer + cnt, plen);
				else
					memcpy(buffer + cnt, ptr + poff, plen);
				kunmap(page);
				/* Start at the beginning of the next page */
				poff = 0;
				++page;
				cnt += plen;
				sglen -= plen;
			}
		}
	}
	/* Return the amount actually transferred */
	return cnt;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 334 | 94.08% | 1 | 33.33% | 
| shaun ren | shaun ren | 21 | 5.92% | 2 | 66.67% | 
 | Total | 355 | 100.00% | 3 | 100.00% | 
/*
 * Store the contents of buffer into srb's transfer buffer and set the
 * SCSI residue.
 */
void rtsx_stor_set_xfer_buf(unsigned char *buffer,
			    unsigned int buflen, struct scsi_cmnd *srb)
{
	unsigned int index = 0, offset = 0;
	rtsx_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset,
				  TO_XFER_BUF);
	if (buflen < scsi_bufflen(srb))
		scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 67 | 100.00% | 1 | 100.00% | 
 | Total | 67 | 100.00% | 1 | 100.00% | 
void rtsx_stor_get_xfer_buf(unsigned char *buffer,
			    unsigned int buflen, struct scsi_cmnd *srb)
{
	unsigned int index = 0, offset = 0;
	rtsx_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset,
				  FROM_XFER_BUF);
	if (buflen < scsi_bufflen(srb))
		scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 67 | 100.00% | 1 | 100.00% | 
 | Total | 67 | 100.00% | 1 | 100.00% | 
/***********************************************************************
 * Transport routines
 ***********************************************************************/
/*
 * Invoke the transport and basic error-handling/recovery methods
 *
 * This is used to send the message to the device and receive the response.
 */
void rtsx_invoke_transport(struct scsi_cmnd *srb, struct rtsx_chip *chip)
{
	int result;
	result = rtsx_scsi_handler(srb, chip);
	/*
         * if the command gets aborted by the higher layers, we need to
         * short-circuit all other processing.
         */
	if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) {
		dev_dbg(rtsx_dev(chip), "-- command was aborted\n");
		srb->result = DID_ABORT << 16;
		goto handle_errors;
	}
	/* if there is a transport error, reset and don't auto-sense */
	if (result == TRANSPORT_ERROR) {
		dev_dbg(rtsx_dev(chip), "-- transport indicates error, resetting\n");
		srb->result = DID_ERROR << 16;
		goto handle_errors;
	}
	srb->result = SAM_STAT_GOOD;
	/*
         * If we have a failure, we're going to do a REQUEST_SENSE
         * automatically.  Note that we differentiate between a command
         * "failure" and an "error" in the transport mechanism.
         */
	if (result == TRANSPORT_FAILED) {
		/* set the result so the higher layers expect this data */
		srb->result = SAM_STAT_CHECK_CONDITION;
		memcpy(srb->sense_buffer,
		       (unsigned char *)&chip->sense_buffer[SCSI_LUN(srb)],
		       sizeof(struct sense_data_t));
	}
	return;
handle_errors:
	return;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 129 | 88.97% | 1 | 25.00% | 
| fabio falzoi | fabio falzoi | 12 | 8.28% | 1 | 25.00% | 
| shaun ren | shaun ren | 4 | 2.76% | 2 | 50.00% | 
 | Total | 145 | 100.00% | 4 | 100.00% | 
void rtsx_add_cmd(struct rtsx_chip *chip,
		  u8 cmd_type, u16 reg_addr, u8 mask, u8 data)
{
	u32 *cb = (u32 *)(chip->host_cmds_ptr);
	u32 val = 0;
	val |= (u32)(cmd_type & 0x03) << 30;
	val |= (u32)(reg_addr & 0x3FFF) << 16;
	val |= (u32)mask << 8;
	val |= (u32)data;
	spin_lock_irq(&chip->rtsx->reg_lock);
	if (chip->ci < (HOST_CMDS_BUF_LEN / 4))
		cb[(chip->ci)++] = cpu_to_le32(val);
	spin_unlock_irq(&chip->rtsx->reg_lock);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 130 | 100.00% | 1 | 100.00% | 
 | Total | 130 | 100.00% | 1 | 100.00% | 
void rtsx_send_cmd_no_wait(struct rtsx_chip *chip)
{
	u32 val = BIT(31);
	rtsx_writel(chip, RTSX_HCBAR, chip->host_cmds_addr);
	val |= (u32)(chip->ci * 4) & 0x00FFFFFF;
	/* Hardware Auto Response */
	val |= 0x40000000;
	rtsx_writel(chip, RTSX_HCBCTLR, val);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 55 | 94.83% | 1 | 50.00% | 
| bhaktipriya shridhar | bhaktipriya shridhar | 3 | 5.17% | 1 | 50.00% | 
 | Total | 58 | 100.00% | 2 | 100.00% | 
int rtsx_send_cmd(struct rtsx_chip *chip, u8 card, int timeout)
{
	struct rtsx_dev *rtsx = chip->rtsx;
	struct completion trans_done;
	u32 val = BIT(31);
	long timeleft;
	int err = 0;
	if (card == SD_CARD)
		rtsx->check_card_cd = SD_EXIST;
	else if (card == MS_CARD)
		rtsx->check_card_cd = MS_EXIST;
	else if (card == XD_CARD)
		rtsx->check_card_cd = XD_EXIST;
	else
		rtsx->check_card_cd = 0;
	spin_lock_irq(&rtsx->reg_lock);
	/* set up data structures for the wakeup system */
	rtsx->done = &trans_done;
	rtsx->trans_result = TRANS_NOT_READY;
	init_completion(&trans_done);
	rtsx->trans_state = STATE_TRANS_CMD;
	rtsx_writel(chip, RTSX_HCBAR, chip->host_cmds_addr);
	val |= (u32)(chip->ci * 4) & 0x00FFFFFF;
	/* Hardware Auto Response */
	val |= 0x40000000;
	rtsx_writel(chip, RTSX_HCBCTLR, val);
	spin_unlock_irq(&rtsx->reg_lock);
	/* Wait for TRANS_OK_INT */
	timeleft = wait_for_completion_interruptible_timeout(
		&trans_done, msecs_to_jiffies(timeout));
	if (timeleft <= 0) {
		dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
			chip->int_reg);
		err = -ETIMEDOUT;
		rtsx_trace(chip);
		goto finish_send_cmd;
	}
	spin_lock_irq(&rtsx->reg_lock);
	if (rtsx->trans_result == TRANS_RESULT_FAIL)
		err = -EIO;
	else if (rtsx->trans_result == TRANS_RESULT_OK)
		err = 0;
	spin_unlock_irq(&rtsx->reg_lock);
finish_send_cmd:
	rtsx->done = NULL;
	rtsx->trans_state = STATE_TRANS_NONE;
	if (err < 0)
		rtsx_stop_cmd(chip, card);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 277 | 94.54% | 1 | 20.00% | 
| fabio falzoi | fabio falzoi | 6 | 2.05% | 1 | 20.00% | 
| joe perches | joe perches | 4 | 1.37% | 1 | 20.00% | 
| nicholas mc guire | nicholas mc guire | 3 | 1.02% | 1 | 20.00% | 
| bhaktipriya shridhar | bhaktipriya shridhar | 3 | 1.02% | 1 | 20.00% | 
 | Total | 293 | 100.00% | 5 | 100.00% | 
static inline void rtsx_add_sg_tbl(
	struct rtsx_chip *chip, u32 addr, u32 len, u8 option)
{
	u64 *sgb = (u64 *)(chip->host_sg_tbl_ptr);
	u64 val = 0;
	u32 temp_len = 0;
	u8  temp_opt = 0;
	do {
		if (len > 0x80000) {
			temp_len = 0x80000;
			temp_opt = option & (~SG_END);
		} else {
			temp_len = len;
			temp_opt = option;
		}
		val = ((u64)addr << 32) | ((u64)temp_len << 12) | temp_opt;
		if (chip->sgi < (HOST_SG_TBL_BUF_LEN / 8))
			sgb[(chip->sgi)++] = cpu_to_le64(val);
		len -= temp_len;
		addr += temp_len;
	} while (len);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 147 | 100.00% | 1 | 100.00% | 
 | Total | 147 | 100.00% | 1 | 100.00% | 
static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card,
					     struct scatterlist *sg, int num_sg,
					     unsigned int *index,
					     unsigned int *offset, int size,
					     enum dma_data_direction dma_dir,
					     int timeout)
{
	struct rtsx_dev *rtsx = chip->rtsx;
	struct completion trans_done;
	u8 dir;
	int sg_cnt, i, resid;
	int err = 0;
	long timeleft;
	struct scatterlist *sg_ptr;
	u32 val = TRIG_DMA;
	if (!sg || (num_sg <= 0) || !offset || !index)
		return -EIO;
	if (dma_dir == DMA_TO_DEVICE)
		dir = HOST_TO_DEVICE;
	else if (dma_dir == DMA_FROM_DEVICE)
		dir = DEVICE_TO_HOST;
	else
		return -ENXIO;
	if (card == SD_CARD)
		rtsx->check_card_cd = SD_EXIST;
	else if (card == MS_CARD)
		rtsx->check_card_cd = MS_EXIST;
	else if (card == XD_CARD)
		rtsx->check_card_cd = XD_EXIST;
	else
		rtsx->check_card_cd = 0;
	spin_lock_irq(&rtsx->reg_lock);
	/* set up data structures for the wakeup system */
	rtsx->done = &trans_done;
	rtsx->trans_state = STATE_TRANS_SG;
	rtsx->trans_result = TRANS_NOT_READY;
	spin_unlock_irq(&rtsx->reg_lock);
	sg_cnt = dma_map_sg(&rtsx->pci->dev, sg, num_sg, dma_dir);
	resid = size;
	sg_ptr = sg;
	chip->sgi = 0;
	/*
         * Usually the next entry will be @sg@ + 1, but if this sg element
         * is part of a chained scatterlist, it could jump to the start of
         * a new scatterlist array. So here we use sg_next to move to
         * the proper sg.
         */
	for (i = 0; i < *index; i++)
		sg_ptr = sg_next(sg_ptr);
	for (i = *index; i < sg_cnt; i++) {
		dma_addr_t addr;
		unsigned int len;
		u8 option;
		addr = sg_dma_address(sg_ptr);
		len = sg_dma_len(sg_ptr);
		dev_dbg(rtsx_dev(chip), "DMA addr: 0x%x, Len: 0x%x\n",
			(unsigned int)addr, len);
		dev_dbg(rtsx_dev(chip), "*index = %d, *offset = %d\n",
			*index, *offset);
		addr += *offset;
		if ((len - *offset) > resid) {
			*offset += resid;
			len = resid;
			resid = 0;
		} else {
			resid -= (len - *offset);
			len -= *offset;
			*offset = 0;
			*index = *index + 1;
		}
		if ((i == (sg_cnt - 1)) || !resid)
			option = SG_VALID | SG_END | SG_TRANS_DATA;
		else
			option = SG_VALID | SG_TRANS_DATA;
		rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option);
		if (!resid)
			break;
		sg_ptr = sg_next(sg_ptr);
	}
	dev_dbg(rtsx_dev(chip), "SG table count = %d\n", chip->sgi);
	val |= (u32)(dir & 0x01) << 29;
	val |= ADMA_MODE;
	spin_lock_irq(&rtsx->reg_lock);
	init_completion(&trans_done);
	rtsx_writel(chip, RTSX_HDBAR, chip->host_sg_tbl_addr);
	rtsx_writel(chip, RTSX_HDBCTLR, val);
	spin_unlock_irq(&rtsx->reg_lock);
	timeleft = wait_for_completion_interruptible_timeout(
		&trans_done, msecs_to_jiffies(timeout));
	if (timeleft <= 0) {
		dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
			__func__, __LINE__);
		dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
			chip->int_reg);
		err = -ETIMEDOUT;
		goto out;
	}
	spin_lock_irq(&rtsx->reg_lock);
	if (rtsx->trans_result == TRANS_RESULT_FAIL) {
		err = -EIO;
		spin_unlock_irq(&rtsx->reg_lock);
		goto out;
	}
	spin_unlock_irq(&rtsx->reg_lock);
	/* Wait for TRANS_OK_INT */
	spin_lock_irq(&rtsx->reg_lock);
	if (rtsx->trans_result == TRANS_NOT_READY) {
		init_completion(&trans_done);
		spin_unlock_irq(&rtsx->reg_lock);
		timeleft = wait_for_completion_interruptible_timeout(
			&trans_done, msecs_to_jiffies(timeout));
		if (timeleft <= 0) {
			dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
				__func__, __LINE__);
			dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
				chip->int_reg);
			err = -ETIMEDOUT;
			goto out;
		}
	} else {
		spin_unlock_irq(&rtsx->reg_lock);
	}
	spin_lock_irq(&rtsx->reg_lock);
	if (rtsx->trans_result == TRANS_RESULT_FAIL)
		err = -EIO;
	else if (rtsx->trans_result == TRANS_RESULT_OK)
		err = 0;
	spin_unlock_irq(&rtsx->reg_lock);
out:
	rtsx->done = NULL;
	rtsx->trans_state = STATE_TRANS_NONE;
	dma_unmap_sg(&rtsx->pci->dev, sg, num_sg, dma_dir);
	if (err < 0)
		rtsx_stop_cmd(chip, card);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 771 | 93.91% | 1 | 20.00% | 
| fabio falzoi | fabio falzoi | 42 | 5.12% | 1 | 20.00% | 
| nicholas mc guire | nicholas mc guire | 6 | 0.73% | 1 | 20.00% | 
| shaun ren | shaun ren | 2 | 0.24% | 2 | 40.00% | 
 | Total | 821 | 100.00% | 5 | 100.00% | 
static int rtsx_transfer_sglist_adma(struct rtsx_chip *chip, u8 card,
				     struct scatterlist *sg, int num_sg,
				     enum dma_data_direction dma_dir,
				     int timeout)
{
	struct rtsx_dev *rtsx = chip->rtsx;
	struct completion trans_done;
	u8 dir;
	int buf_cnt, i;
	int err = 0;
	long timeleft;
	struct scatterlist *sg_ptr;
	if (!sg || (num_sg <= 0))
		return -EIO;
	if (dma_dir == DMA_TO_DEVICE)
		dir = HOST_TO_DEVICE;
	else if (dma_dir == DMA_FROM_DEVICE)
		dir = DEVICE_TO_HOST;
	else
		return -ENXIO;
	if (card == SD_CARD)
		rtsx->check_card_cd = SD_EXIST;
	else if (card == MS_CARD)
		rtsx->check_card_cd = MS_EXIST;
	else if (card == XD_CARD)
		rtsx->check_card_cd = XD_EXIST;
	else
		rtsx->check_card_cd = 0;
	spin_lock_irq(&rtsx->reg_lock);
	/* set up data structures for the wakeup system */
	rtsx->done = &trans_done;
	rtsx->trans_state = STATE_TRANS_SG;
	rtsx->trans_result = TRANS_NOT_READY;
	spin_unlock_irq(&rtsx->reg_lock);
	buf_cnt = dma_map_sg(&rtsx->pci->dev, sg, num_sg, dma_dir);
	sg_ptr = sg;
	for (i = 0; i <= buf_cnt / (HOST_SG_TBL_BUF_LEN / 8); i++) {
		u32 val = TRIG_DMA;
		int sg_cnt, j;
		if (i == buf_cnt / (HOST_SG_TBL_BUF_LEN / 8))
			sg_cnt = buf_cnt % (HOST_SG_TBL_BUF_LEN / 8);
		else
			sg_cnt = HOST_SG_TBL_BUF_LEN / 8;
		chip->sgi = 0;
		for (j = 0; j < sg_cnt; j++) {
			dma_addr_t addr = sg_dma_address(sg_ptr);
			unsigned int len = sg_dma_len(sg_ptr);
			u8 option;
			dev_dbg(rtsx_dev(chip), "DMA addr: 0x%x, Len: 0x%x\n",
				(unsigned int)addr, len);
			if (j == (sg_cnt - 1))
				option = SG_VALID | SG_END | SG_TRANS_DATA;
			else
				option = SG_VALID | SG_TRANS_DATA;
			rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option);
			sg_ptr = sg_next(sg_ptr);
		}
		dev_dbg(rtsx_dev(chip), "SG table count = %d\n", chip->sgi);
		val |= (u32)(dir & 0x01) << 29;
		val |= ADMA_MODE;
		spin_lock_irq(&rtsx->reg_lock);
		init_completion(&trans_done);
		rtsx_writel(chip, RTSX_HDBAR, chip->host_sg_tbl_addr);
		rtsx_writel(chip, RTSX_HDBCTLR, val);
		spin_unlock_irq(&rtsx->reg_lock);
		timeleft = wait_for_completion_interruptible_timeout(
			&trans_done, msecs_to_jiffies(timeout));
		if (timeleft <= 0) {
			dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
				__func__, __LINE__);
			dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
				chip->int_reg);
			err = -ETIMEDOUT;
			goto out;
		}
		spin_lock_irq(&rtsx->reg_lock);
		if (rtsx->trans_result == TRANS_RESULT_FAIL) {
			err = -EIO;
			spin_unlock_irq(&rtsx->reg_lock);
			goto out;
		}
		spin_unlock_irq(&rtsx->reg_lock);
		sg_ptr += sg_cnt;
	}
	/* Wait for TRANS_OK_INT */
	spin_lock_irq(&rtsx->reg_lock);
	if (rtsx->trans_result == TRANS_NOT_READY) {
		init_completion(&trans_done);
		spin_unlock_irq(&rtsx->reg_lock);
		timeleft = wait_for_completion_interruptible_timeout(
			&trans_done, msecs_to_jiffies(timeout));
		if (timeleft <= 0) {
			dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
				__func__, __LINE__);
			dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
				chip->int_reg);
			err = -ETIMEDOUT;
			goto out;
		}
	} else {
		spin_unlock_irq(&rtsx->reg_lock);
	}
	spin_lock_irq(&rtsx->reg_lock);
	if (rtsx->trans_result == TRANS_RESULT_FAIL)
		err = -EIO;
	else if (rtsx->trans_result == TRANS_RESULT_OK)
		err = 0;
	spin_unlock_irq(&rtsx->reg_lock);
out:
	rtsx->done = NULL;
	rtsx->trans_state = STATE_TRANS_NONE;
	dma_unmap_sg(&rtsx->pci->dev, sg, num_sg, dma_dir);
	if (err < 0)
		rtsx_stop_cmd(chip, card);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 697 | 94.19% | 1 | 25.00% | 
| fabio falzoi | fabio falzoi | 36 | 4.86% | 1 | 25.00% | 
| nicholas mc guire | nicholas mc guire | 6 | 0.81% | 1 | 25.00% | 
| shaun ren | shaun ren | 1 | 0.14% | 1 | 25.00% | 
 | Total | 740 | 100.00% | 4 | 100.00% | 
static int rtsx_transfer_buf(struct rtsx_chip *chip, u8 card, void *buf,
			     size_t len, enum dma_data_direction dma_dir,
			     int timeout)
{
	struct rtsx_dev *rtsx = chip->rtsx;
	struct completion trans_done;
	dma_addr_t addr;
	u8 dir;
	int err = 0;
	u32 val = BIT(31);
	long timeleft;
	if (!buf || (len <= 0))
		return -EIO;
	if (dma_dir == DMA_TO_DEVICE)
		dir = HOST_TO_DEVICE;
	else if (dma_dir == DMA_FROM_DEVICE)
		dir = DEVICE_TO_HOST;
	else
		return -ENXIO;
	addr = dma_map_single(&rtsx->pci->dev, buf, len, dma_dir);
	if (dma_mapping_error(&rtsx->pci->dev, addr))
		return -ENOMEM;
	if (card == SD_CARD)
		rtsx->check_card_cd = SD_EXIST;
	else if (card == MS_CARD)
		rtsx->check_card_cd = MS_EXIST;
	else if (card == XD_CARD)
		rtsx->check_card_cd = XD_EXIST;
	else
		rtsx->check_card_cd = 0;
	val |= (u32)(dir & 0x01) << 29;
	val |= (u32)(len & 0x00FFFFFF);
	spin_lock_irq(&rtsx->reg_lock);
	/* set up data structures for the wakeup system */
	rtsx->done = &trans_done;
	init_completion(&trans_done);
	rtsx->trans_state = STATE_TRANS_BUF;
	rtsx->trans_result = TRANS_NOT_READY;
	rtsx_writel(chip, RTSX_HDBAR, addr);
	rtsx_writel(chip, RTSX_HDBCTLR, val);
	spin_unlock_irq(&rtsx->reg_lock);
	/* Wait for TRANS_OK_INT */
	timeleft = wait_for_completion_interruptible_timeout(
		&trans_done, msecs_to_jiffies(timeout));
	if (timeleft <= 0) {
		dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
			__func__, __LINE__);
		dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
			chip->int_reg);
		err = -ETIMEDOUT;
		goto out;
	}
	spin_lock_irq(&rtsx->reg_lock);
	if (rtsx->trans_result == TRANS_RESULT_FAIL)
		err = -EIO;
	else if (rtsx->trans_result == TRANS_RESULT_OK)
		err = 0;
	spin_unlock_irq(&rtsx->reg_lock);
out:
	rtsx->done = NULL;
	rtsx->trans_state = STATE_TRANS_NONE;
	dma_unmap_single(&rtsx->pci->dev, addr, len, dma_dir);
	if (err < 0)
		rtsx_stop_cmd(chip, card);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 386 | 93.01% | 1 | 16.67% | 
| fabio falzoi | fabio falzoi | 12 | 2.89% | 1 | 16.67% | 
| haneen mohammed | haneen mohammed | 10 | 2.41% | 1 | 16.67% | 
| nicholas mc guire | nicholas mc guire | 3 | 0.72% | 1 | 16.67% | 
| bhaktipriya shridhar | bhaktipriya shridhar | 3 | 0.72% | 1 | 16.67% | 
| shaun ren | shaun ren | 1 | 0.24% | 1 | 16.67% | 
 | Total | 415 | 100.00% | 6 | 100.00% | 
int rtsx_transfer_data_partial(struct rtsx_chip *chip, u8 card,
			       void *buf, size_t len, int use_sg,
			       unsigned int *index, unsigned int *offset,
			       enum dma_data_direction dma_dir, int timeout)
{
	int err = 0;
	/* don't transfer data during abort processing */
	if (rtsx_chk_stat(chip, RTSX_STAT_ABORT))
		return -EIO;
	if (use_sg) {
		struct scatterlist *sg = buf;
		err = rtsx_transfer_sglist_adma_partial(chip, card, sg, use_sg,
							index, offset, (int)len,
							dma_dir, timeout);
	} else {
		err = rtsx_transfer_buf(chip, card,
					buf, len, dma_dir, timeout);
	}
	if (err < 0) {
		if (RTSX_TST_DELINK(chip)) {
			RTSX_CLR_DELINK(chip);
			chip->need_reinit = SD_CARD | MS_CARD | XD_CARD;
			rtsx_reinit_cards(chip, 1);
		}
	}
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 148 | 92.50% | 1 | 50.00% | 
| shaun ren | shaun ren | 12 | 7.50% | 1 | 50.00% | 
 | Total | 160 | 100.00% | 2 | 100.00% | 
int rtsx_transfer_data(struct rtsx_chip *chip, u8 card, void *buf, size_t len,
		       int use_sg, enum dma_data_direction dma_dir, int timeout)
{
	int err = 0;
	dev_dbg(rtsx_dev(chip), "use_sg = %d\n", use_sg);
	/* don't transfer data during abort processing */
	if (rtsx_chk_stat(chip, RTSX_STAT_ABORT))
		return -EIO;
	if (use_sg) {
		err = rtsx_transfer_sglist_adma(chip, card,
						(struct scatterlist *)buf,
						use_sg, dma_dir, timeout);
	} else {
		err = rtsx_transfer_buf(chip, card, buf, len, dma_dir, timeout);
	}
	if (err < 0) {
		if (RTSX_TST_DELINK(chip)) {
			RTSX_CLR_DELINK(chip);
			chip->need_reinit = SD_CARD | MS_CARD | XD_CARD;
			rtsx_reinit_cards(chip, 1);
		}
	}
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 145 | 96.03% | 1 | 50.00% | 
| fabio falzoi | fabio falzoi | 6 | 3.97% | 1 | 50.00% | 
 | Total | 151 | 100.00% | 2 | 100.00% | 
Overall Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| micky ching | micky ching | 3367 | 94.39% | 1 | 10.00% | 
| fabio falzoi | fabio falzoi | 114 | 3.20% | 1 | 10.00% | 
| shaun ren | shaun ren | 45 | 1.26% | 4 | 40.00% | 
| nicholas mc guire | nicholas mc guire | 18 | 0.50% | 1 | 10.00% | 
| haneen mohammed | haneen mohammed | 10 | 0.28% | 1 | 10.00% | 
| bhaktipriya shridhar | bhaktipriya shridhar | 9 | 0.25% | 1 | 10.00% | 
| joe perches | joe perches | 4 | 0.11% | 1 | 10.00% | 
 | Total | 3567 | 100.00% | 10 | 100.00% | 
  
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.