Commit 8328258e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc:
  sdhci: release irq during suspend
  sdhci: make isr tolerant of read errors
  mmc: require explicit support for high-speed
  ncpfs: make sure server connection survives a kill
parents 205c911d a715dfc7
Loading
Loading
Loading
Loading
+48 −35
Original line number Diff line number Diff line
@@ -376,10 +376,11 @@ static inline void mmc_set_ios(struct mmc_host *host)
{
	struct mmc_ios *ios = &host->ios;

	pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n",
	pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "
		"width %u timing %u\n",
		 mmc_hostname(host), ios->clock, ios->bus_mode,
		 ios->power_mode, ios->chip_select, ios->vdd,
		 ios->bus_width);
		 ios->bus_width, ios->timing);

	host->ops->set_ios(host, ios);
}
@@ -809,6 +810,7 @@ static void mmc_power_up(struct mmc_host *host)
	host->ios.chip_select = MMC_CS_DONTCARE;
	host->ios.power_mode = MMC_POWER_UP;
	host->ios.bus_width = MMC_BUS_WIDTH_1;
	host->ios.timing = MMC_TIMING_LEGACY;
	mmc_set_ios(host);

	mmc_delay(1);
@@ -828,6 +830,7 @@ static void mmc_power_off(struct mmc_host *host)
	host->ios.chip_select = MMC_CS_DONTCARE;
	host->ios.power_mode = MMC_POWER_OFF;
	host->ios.bus_width = MMC_BUS_WIDTH_1;
	host->ios.timing = MMC_TIMING_LEGACY;
	mmc_set_ios(host);
}

@@ -1112,6 +1115,7 @@ static void mmc_process_ext_csds(struct mmc_host *host)
			continue;
		}

		if (host->caps & MMC_CAP_MMC_HIGHSPEED) {
			/* Activate highspeed support. */
			cmd.opcode = MMC_SWITCH;
			cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
@@ -1130,11 +1134,12 @@ static void mmc_process_ext_csds(struct mmc_host *host)

			mmc_card_set_highspeed(card);

		/* Check for host support for wide-bus modes. */
		if (!(host->caps & MMC_CAP_4_BIT_DATA)) {
			continue;
			host->ios.timing = MMC_TIMING_SD_HS;
			mmc_set_ios(host);
		}

		/* Check for host support for wide-bus modes. */
		if (host->caps & MMC_CAP_4_BIT_DATA) {
			/* Activate 4-bit support. */
			cmd.opcode = MMC_SWITCH;
			cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
@@ -1152,6 +1157,8 @@ static void mmc_process_ext_csds(struct mmc_host *host)
			}

			host->ios.bus_width = MMC_BUS_WIDTH_4;
			mmc_set_ios(host);
		}
	}

	kfree(ext_csd);
@@ -1241,6 +1248,9 @@ static void mmc_read_switch_caps(struct mmc_host *host)
	unsigned char *status;
	struct scatterlist sg;

	if (!(host->caps & MMC_CAP_SD_HIGHSPEED))
		return;

	status = kmalloc(64, GFP_KERNEL);
	if (!status) {
		printk(KERN_WARNING "%s: Unable to allocate buffer for "
@@ -1332,6 +1342,9 @@ static void mmc_read_switch_caps(struct mmc_host *host)
		}

		mmc_card_set_highspeed(card);

		host->ios.timing = MMC_TIMING_SD_HS;
		mmc_set_ios(host);
	}

	kfree(status);
+23 −16
Original line number Diff line number Diff line
@@ -606,7 +606,6 @@ static void sdhci_finish_command(struct sdhci_host *host)
static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
{
	int div;
	u8 ctrl;
	u16 clk;
	unsigned long timeout;

@@ -615,13 +614,6 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)

	writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);

	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
	if (clock > 25000000)
		ctrl |= SDHCI_CTRL_HISPD;
	else
		ctrl &= ~SDHCI_CTRL_HISPD;
	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);

	if (clock == 0)
		goto out;

@@ -761,10 +753,17 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
		sdhci_set_power(host, ios->vdd);

	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);

	if (ios->bus_width == MMC_BUS_WIDTH_4)
		ctrl |= SDHCI_CTRL_4BITBUS;
	else
		ctrl &= ~SDHCI_CTRL_4BITBUS;

	if (ios->timing == MMC_TIMING_SD_HS)
		ctrl |= SDHCI_CTRL_HISPD;
	else
		ctrl &= ~SDHCI_CTRL_HISPD;

	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);

	mmiowb();
@@ -994,7 +993,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)

	intmask = readl(host->ioaddr + SDHCI_INT_STATUS);

	if (!intmask) {
	if (!intmask || intmask == 0xffffffff) {
		result = IRQ_NONE;
		goto out;
	}
@@ -1080,6 +1079,13 @@ static int sdhci_suspend (struct pci_dev *pdev, pm_message_t state)

	pci_save_state(pdev);
	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);

	for (i = 0;i < chip->num_slots;i++) {
		if (!chip->hosts[i])
			continue;
		free_irq(chip->hosts[i]->irq, chip->hosts[i]);
	}

	pci_disable_device(pdev);
	pci_set_power_state(pdev, pci_choose_state(pdev, state));

@@ -1108,6 +1114,11 @@ static int sdhci_resume (struct pci_dev *pdev)
			continue;
		if (chip->hosts[i]->flags & SDHCI_USE_DMA)
			pci_set_master(pdev);
		ret = request_irq(chip->hosts[i]->irq, sdhci_irq,
			IRQF_SHARED, chip->hosts[i]->slot_descr,
			chip->hosts[i]);
		if (ret)
			return ret;
		sdhci_init(chip->hosts[i]);
		mmiowb();
		ret = mmc_resume_host(chip->hosts[i]->mmc);
@@ -1274,6 +1285,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
	mmc->f_max = host->max_clk;
	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;

	if (caps & SDHCI_CAN_DO_HISPD)
		mmc->caps |= MMC_CAP_SD_HIGHSPEED;

	mmc->ocr_avail = 0;
	if (caps & SDHCI_CAN_VDD_330)
		mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
@@ -1282,13 +1296,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
	if (caps & SDHCI_CAN_VDD_180)
		mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;

	if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) {
		printk(KERN_ERR "%s: Controller reports > 25 MHz base clock,"
			" but no high speed support.\n",
			host->slot_descr);
		mmc->f_max = 25000000;
	}

	if (mmc->ocr_avail == 0) {
		printk(KERN_ERR "%s: Hardware doesn't report any "
			"support voltages.\n", host->slot_descr);
+14 −2
Original line number Diff line number Diff line
@@ -576,6 +576,12 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
	server->packet = vmalloc(NCP_PACKET_SIZE);
	if (server->packet == NULL)
		goto out_nls;
	server->txbuf = vmalloc(NCP_PACKET_SIZE);
	if (server->txbuf == NULL)
		goto out_packet;
	server->rxbuf = vmalloc(NCP_PACKET_SIZE);
	if (server->rxbuf == NULL)
		goto out_txbuf;

	sock->sk->sk_data_ready	  = ncp_tcp_data_ready;
	sock->sk->sk_error_report = ncp_tcp_error_report;
@@ -597,7 +603,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
	error = ncp_connect(server);
	ncp_unlock_server(server);
	if (error < 0)
		goto out_packet;
		goto out_rxbuf;
	DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));

	error = -EMSGSIZE;	/* -EREMOTESIDEINCOMPATIBLE */
@@ -666,8 +672,12 @@ out_disconnect:
	ncp_lock_server(server);
	ncp_disconnect(server);
	ncp_unlock_server(server);
out_packet:
out_rxbuf:
	ncp_stop_tasks(server);
	vfree(server->rxbuf);
out_txbuf:
	vfree(server->txbuf);
out_packet:
	vfree(server->packet);
out_nls:
#ifdef CONFIG_NCPFS_NLS
@@ -723,6 +733,8 @@ static void ncp_put_super(struct super_block *sb)

	kfree(server->priv.data);
	kfree(server->auth.object_name);
	vfree(server->rxbuf);
	vfree(server->txbuf);
	vfree(server->packet);
	sb->s_fs_info = NULL;
	kfree(server);
+89 −62
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/socket.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/in.h>
#include <linux/net.h>
@@ -55,10 +56,11 @@ static int _send(struct socket *sock, const void *buff, int len)
struct ncp_request_reply {
	struct list_head req;
	wait_queue_head_t wq;
	struct ncp_reply_header* reply_buf;
	atomic_t refs;
	unsigned char* reply_buf;
	size_t datalen;
	int result;
	enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE } status;
	enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
	struct kvec* tx_ciov;
	size_t tx_totallen;
	size_t tx_iovlen;
@@ -67,6 +69,32 @@ struct ncp_request_reply {
	u_int32_t sign[6];
};

static inline struct ncp_request_reply* ncp_alloc_req(void)
{
	struct ncp_request_reply *req;

	req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL);
	if (!req)
		return NULL;

	init_waitqueue_head(&req->wq);
	atomic_set(&req->refs, (1));
	req->status = RQ_IDLE;

	return req;
}

static void ncp_req_get(struct ncp_request_reply *req)
{
	atomic_inc(&req->refs);
}

static void ncp_req_put(struct ncp_request_reply *req)
{
	if (atomic_dec_and_test(&req->refs))
		kfree(req);
}

void ncp_tcp_data_ready(struct sock *sk, int len)
{
	struct ncp_server *server = sk->sk_user_data;
@@ -101,14 +129,17 @@ void ncpdgram_timeout_call(unsigned long v)
	schedule_work(&server->timeout_tq);
}

static inline void ncp_finish_request(struct ncp_request_reply *req, int result)
static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
{
	req->result = result;
	if (req->status != RQ_ABANDONED)
		memcpy(req->reply_buf, server->rxbuf, req->datalen);
	req->status = RQ_DONE;
	wake_up_all(&req->wq);
	ncp_req_put(req);
}

static void __abort_ncp_connection(struct ncp_server *server, struct ncp_request_reply *aborted, int err)
static void __abort_ncp_connection(struct ncp_server *server)
{
	struct ncp_request_reply *req;

@@ -118,31 +149,19 @@ static void __abort_ncp_connection(struct ncp_server *server, struct ncp_request
		req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
		
		list_del_init(&req->req);
		if (req == aborted) {
			ncp_finish_request(req, err);
		} else {
			ncp_finish_request(req, -EIO);
		}
		ncp_finish_request(server, req, -EIO);
	}
	req = server->rcv.creq;
	if (req) {
		server->rcv.creq = NULL;
		if (req == aborted) {
			ncp_finish_request(req, err);
		} else {
			ncp_finish_request(req, -EIO);
		}
		ncp_finish_request(server, req, -EIO);
		server->rcv.ptr = NULL;
		server->rcv.state = 0;
	}
	req = server->tx.creq;
	if (req) {
		server->tx.creq = NULL;
		if (req == aborted) {
			ncp_finish_request(req, err);
		} else {
			ncp_finish_request(req, -EIO);
		}
		ncp_finish_request(server, req, -EIO);
	}
}

@@ -160,10 +179,12 @@ static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_req
			break;
		case RQ_QUEUED:
			list_del_init(&req->req);
			ncp_finish_request(req, err);
			ncp_finish_request(server, req, err);
			break;
		case RQ_INPROGRESS:
			__abort_ncp_connection(server, req, err);
			req->status = RQ_ABANDONED;
			break;
		case RQ_ABANDONED:
			break;
	}
}
@@ -177,7 +198,7 @@ static inline void ncp_abort_request(struct ncp_server *server, struct ncp_reque

static inline void __ncptcp_abort(struct ncp_server *server)
{
	__abort_ncp_connection(server, NULL, 0);
	__abort_ncp_connection(server);
}

static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
@@ -294,6 +315,11 @@ static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_r

static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
{
	/* we copy the data so that we do not depend on the caller
	   staying alive */
	memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len);
	req->tx_iov[1].iov_base = server->txbuf;

	if (server->ncp_sock->type == SOCK_STREAM)
		ncptcp_start_request(server, req);
	else
@@ -308,6 +334,7 @@ static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *
		printk(KERN_ERR "ncpfs: tcp: Server died\n");
		return -EIO;
	}
	ncp_req_get(req);
	if (server->tx.creq || server->rcv.creq) {
		req->status = RQ_QUEUED;
		list_add_tail(&req->req, &server->tx.requests);
@@ -409,7 +436,7 @@ void ncpdgram_rcv_proc(struct work_struct *work)
					server->timeout_last = NCP_MAX_RPC_TIMEOUT;
					mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
				} else if (reply.type == NCP_REPLY) {
					result = _recv(sock, (void*)req->reply_buf, req->datalen, MSG_DONTWAIT);
					result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
#ifdef CONFIG_NCPFS_PACKET_SIGNING
					if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
						if (result < 8 + 8) {
@@ -419,7 +446,7 @@ void ncpdgram_rcv_proc(struct work_struct *work)
							
							result -= 8;
							hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
							if (sign_verify_reply(server, ((char*)req->reply_buf) + hdrl, result - hdrl, cpu_to_le32(result), ((char*)req->reply_buf) + result)) {
							if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
								printk(KERN_INFO "ncpfs: Signature violation\n");
								result = -EIO;
							}
@@ -428,7 +455,7 @@ void ncpdgram_rcv_proc(struct work_struct *work)
#endif
					del_timer(&server->timeout_tm);
				     	server->rcv.creq = NULL;
					ncp_finish_request(req, result);
					ncp_finish_request(server, req, result);
					__ncp_next_request(server);
					mutex_unlock(&server->rcv.creq_mutex);
					continue;
@@ -478,12 +505,6 @@ void ncpdgram_timeout_proc(struct work_struct *work)
	mutex_unlock(&server->rcv.creq_mutex);
}

static inline void ncp_init_req(struct ncp_request_reply* req)
{
	init_waitqueue_head(&req->wq);
	req->status = RQ_IDLE;
}

static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
{
	int result;
@@ -601,8 +622,8 @@ skipdata:;
					goto skipdata;
				}
				req->datalen = datalen - 8;
				req->reply_buf->type = NCP_REPLY;
				server->rcv.ptr = (unsigned char*)(req->reply_buf) + 2;
				((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
				server->rcv.ptr = server->rxbuf + 2;
				server->rcv.len = datalen - 10;
				server->rcv.state = 1;
				break;
@@ -615,12 +636,12 @@ skipdata:;
			case 1:
				req = server->rcv.creq;
				if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
					if (req->reply_buf->sequence != server->sequence) {
					if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
						printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
						__ncp_abort_request(server, req, -EIO);
						return -EIO;
					}
					if ((req->reply_buf->conn_low | (req->reply_buf->conn_high << 8)) != server->connection) {
					if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
						printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n");
						__ncp_abort_request(server, req, -EIO);
						return -EIO;
@@ -628,14 +649,14 @@ skipdata:;
				}
#ifdef CONFIG_NCPFS_PACKET_SIGNING				
				if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
					if (sign_verify_reply(server, (unsigned char*)(req->reply_buf) + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
					if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
						printk(KERN_ERR "ncpfs: tcp: Signature violation\n");
						__ncp_abort_request(server, req, -EIO);
						return -EIO;
					}
				}
#endif				
				ncp_finish_request(req, req->datalen);
				ncp_finish_request(server, req, req->datalen);
			nextreq:;
				__ncp_next_request(server);
			case 2:
@@ -645,7 +666,7 @@ skipdata:;
				server->rcv.state = 0;
				break;
			case 3:
				ncp_finish_request(server->rcv.creq, -EIO);
				ncp_finish_request(server, server->rcv.creq, -EIO);
				goto nextreq;
			case 5:
				info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
@@ -675,28 +696,39 @@ void ncp_tcp_tx_proc(struct work_struct *work)
}

static int do_ncp_rpc_call(struct ncp_server *server, int size,
		struct ncp_reply_header* reply_buf, int max_reply_size)
		unsigned char* reply_buf, int max_reply_size)
{
	int result;
	struct ncp_request_reply req;

	ncp_init_req(&req);
	req.reply_buf = reply_buf;
	req.datalen = max_reply_size;
	req.tx_iov[1].iov_base = server->packet;
	req.tx_iov[1].iov_len = size;
	req.tx_iovlen = 1;
	req.tx_totallen = size;
	req.tx_type = *(u_int16_t*)server->packet;

	result = ncp_add_request(server, &req);
	if (result < 0) {
		return result;
	}
	if (wait_event_interruptible(req.wq, req.status == RQ_DONE)) {
		ncp_abort_request(server, &req, -EIO);
	struct ncp_request_reply *req;

	req = ncp_alloc_req();
	if (!req)
		return -ENOMEM;

	req->reply_buf = reply_buf;
	req->datalen = max_reply_size;
	req->tx_iov[1].iov_base = server->packet;
	req->tx_iov[1].iov_len = size;
	req->tx_iovlen = 1;
	req->tx_totallen = size;
	req->tx_type = *(u_int16_t*)server->packet;

	result = ncp_add_request(server, req);
	if (result < 0)
		goto out;

	if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) {
		ncp_abort_request(server, req, -EINTR);
		result = -EINTR;
		goto out;
	}
	return req.result;

	result = req->result;

out:
	ncp_req_put(req);

	return result;
}

/*
@@ -751,11 +783,6 @@ static int ncp_do_request(struct ncp_server *server, int size,

	DDPRINTK("do_ncp_rpc_call returned %d\n", result);

	if (result < 0) {
		/* There was a problem with I/O, so the connections is
		 * no longer usable. */
		ncp_invalidate_conn(server);
	}
	return result;
}

+8 −0
Original line number Diff line number Diff line
@@ -62,6 +62,12 @@ struct mmc_ios {

#define MMC_BUS_WIDTH_1		0
#define MMC_BUS_WIDTH_4		2

	unsigned char	timing;			/* timing specification used */

#define MMC_TIMING_LEGACY	0
#define MMC_TIMING_MMC_HS	1
#define MMC_TIMING_SD_HS	2
};

struct mmc_host_ops {
@@ -87,6 +93,8 @@ struct mmc_host {
#define MMC_CAP_4_BIT_DATA	(1 << 0)	/* Can the host do 4 bit transfers */
#define MMC_CAP_MULTIWRITE	(1 << 1)	/* Can accurately report bytes sent to card on error */
#define MMC_CAP_BYTEBLOCK	(1 << 2)	/* Can do non-log2 block sizes */
#define MMC_CAP_MMC_HIGHSPEED	(1 << 3)	/* Can do MMC high-speed timing */
#define MMC_CAP_SD_HIGHSPEED	(1 << 4)	/* Can do SD high-speed timing */

	/* host specific block data */
	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
Loading