aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/host/sdhci.c63
-rw-r--r--drivers/mmc/host/sdhci.h2
-rw-r--r--include/linux/mmc/sdhci.h1
3 files changed, 49 insertions, 17 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index cc63f5ed2310..b9ed66307ac3 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -838,9 +838,10 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
838} 838}
839 839
840static void sdhci_set_transfer_mode(struct sdhci_host *host, 840static void sdhci_set_transfer_mode(struct sdhci_host *host,
841 struct mmc_data *data) 841 struct mmc_command *cmd)
842{ 842{
843 u16 mode; 843 u16 mode;
844 struct mmc_data *data = cmd->data;
844 845
845 if (data == NULL) 846 if (data == NULL)
846 return; 847 return;
@@ -848,11 +849,14 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
848 WARN_ON(!host->data); 849 WARN_ON(!host->data);
849 850
850 mode = SDHCI_TRNS_BLK_CNT_EN; 851 mode = SDHCI_TRNS_BLK_CNT_EN;
851 if (data->blocks > 1) { 852 if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
852 if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) 853 mode |= SDHCI_TRNS_MULTI;
853 mode |= SDHCI_TRNS_MULTI | SDHCI_TRNS_ACMD12; 854 /*
854 else 855 * If we are sending CMD23, CMD12 never gets sent
855 mode |= SDHCI_TRNS_MULTI; 856 * on successful completion (so no Auto-CMD12).
857 */
858 if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
859 mode |= SDHCI_TRNS_AUTO_CMD12;
856 } 860 }
857 if (data->flags & MMC_DATA_READ) 861 if (data->flags & MMC_DATA_READ)
858 mode |= SDHCI_TRNS_READ; 862 mode |= SDHCI_TRNS_READ;
@@ -893,7 +897,15 @@ static void sdhci_finish_data(struct sdhci_host *host)
893 else 897 else
894 data->bytes_xfered = data->blksz * data->blocks; 898 data->bytes_xfered = data->blksz * data->blocks;
895 899
896 if (data->stop) { 900 /*
901 * Need to send CMD12 if -
902 * a) open-ended multiblock transfer (no CMD23)
903 * b) error in multiblock transfer
904 */
905 if (data->stop &&
906 (data->error ||
907 !host->mrq->sbc)) {
908
897 /* 909 /*
898 * The controller needs a reset of internal state machines 910 * The controller needs a reset of internal state machines
899 * upon error conditions. 911 * upon error conditions.
@@ -949,7 +961,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
949 961
950 sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT); 962 sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
951 963
952 sdhci_set_transfer_mode(host, cmd->data); 964 sdhci_set_transfer_mode(host, cmd);
953 965
954 if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { 966 if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
955 printk(KERN_ERR "%s: Unsupported response type!\n", 967 printk(KERN_ERR "%s: Unsupported response type!\n",
@@ -1004,13 +1016,21 @@ static void sdhci_finish_command(struct sdhci_host *host)
1004 1016
1005 host->cmd->error = 0; 1017 host->cmd->error = 0;
1006 1018
1007 if (host->data && host->data_early) 1019 /* Finished CMD23, now send actual command. */
1008 sdhci_finish_data(host); 1020 if (host->cmd == host->mrq->sbc) {
1021 host->cmd = NULL;
1022 sdhci_send_command(host, host->mrq->cmd);
1023 } else {
1009 1024
1010 if (!host->cmd->data) 1025 /* Processed actual command. */
1011 tasklet_schedule(&host->finish_tasklet); 1026 if (host->data && host->data_early)
1027 sdhci_finish_data(host);
1012 1028
1013 host->cmd = NULL; 1029 if (!host->cmd->data)
1030 tasklet_schedule(&host->finish_tasklet);
1031
1032 host->cmd = NULL;
1033 }
1014} 1034}
1015 1035
1016static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) 1036static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
@@ -1189,7 +1209,12 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
1189#ifndef SDHCI_USE_LEDS_CLASS 1209#ifndef SDHCI_USE_LEDS_CLASS
1190 sdhci_activate_led(host); 1210 sdhci_activate_led(host);
1191#endif 1211#endif
1192 if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) { 1212
1213 /*
1214 * Ensure we don't send the STOP for non-SET_BLOCK_COUNTED
1215 * requests if Auto-CMD12 is enabled.
1216 */
1217 if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) {
1193 if (mrq->stop) { 1218 if (mrq->stop) {
1194 mrq->data->stop = NULL; 1219 mrq->data->stop = NULL;
1195 mrq->stop = NULL; 1220 mrq->stop = NULL;
@@ -1227,7 +1252,10 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
1227 host->mrq = mrq; 1252 host->mrq = mrq;
1228 } 1253 }
1229 1254
1230 sdhci_send_command(host, mrq->cmd); 1255 if (mrq->sbc)
1256 sdhci_send_command(host, mrq->sbc);
1257 else
1258 sdhci_send_command(host, mrq->cmd);
1231 } 1259 }
1232 1260
1233 mmiowb(); 1261 mmiowb();
@@ -2455,7 +2483,10 @@ int sdhci_add_host(struct sdhci_host *host)
2455 } else 2483 } else
2456 mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; 2484 mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
2457 2485
2458 mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE; 2486 mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
2487
2488 if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
2489 host->flags |= SDHCI_AUTO_CMD12;
2459 2490
2460 /* 2491 /*
2461 * A controller may support 8-bit width, but the board itself 2492 * A controller may support 8-bit width, but the board itself
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 7e28eec97f04..2c3fbc5a4c07 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -36,7 +36,7 @@
36#define SDHCI_TRANSFER_MODE 0x0C 36#define SDHCI_TRANSFER_MODE 0x0C
37#define SDHCI_TRNS_DMA 0x01 37#define SDHCI_TRNS_DMA 0x01
38#define SDHCI_TRNS_BLK_CNT_EN 0x02 38#define SDHCI_TRNS_BLK_CNT_EN 0x02
39#define SDHCI_TRNS_ACMD12 0x04 39#define SDHCI_TRNS_AUTO_CMD12 0x04
40#define SDHCI_TRNS_READ 0x10 40#define SDHCI_TRNS_READ 0x10
41#define SDHCI_TRNS_MULTI 0x20 41#define SDHCI_TRNS_MULTI 0x20
42 42
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index e902618d68f4..73e27ba51e99 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -113,6 +113,7 @@ struct sdhci_host {
113#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */ 113#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */
114#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */ 114#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */
115#define SDHCI_NEEDS_RETUNING (1<<5) /* Host needs retuning */ 115#define SDHCI_NEEDS_RETUNING (1<<5) /* Host needs retuning */
116#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */
116 117
117 unsigned int version; /* SDHCI spec. version */ 118 unsigned int version; /* SDHCI spec. version */
118 119
n1395' href='#n1395'>1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419
/* linux/net/ipv4/arp.c
 *
 * Copyright (C) 1994 by Florian  La Roche
 *
 * This module implements the Address Resolution Protocol ARP (RFC 826),
 * which is used to convert IP addresses (or in the future maybe other
 * high-level addresses) into a low-level hardware address (like an Ethernet
 * address).
 *
 * 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 of the License, or (at your option) any later version.
 *
 * Fixes:
 *		Alan Cox	:	Removed the Ethernet assumptions in
 *					Florian's code
 *		Alan Cox	:	Fixed some small errors in the ARP
 *					logic
 *		Alan Cox	:	Allow >4K in /proc
 *		Alan Cox	:	Make ARP add its own protocol entry
 *		Ross Martin     :       Rewrote arp_rcv() and arp_get_info()
 *		Stephen Henson	:	Add AX25 support to arp_get_info()
 *		Alan Cox	:	Drop data when a device is downed.
 *		Alan Cox	:	Use init_timer().
 *		Alan Cox	:	Double lock fixes.
 *		Martin Seine	:	Move the arphdr structure
 *					to if_arp.h for compatibility.
 *					with BSD based programs.
 *		Andrew Tridgell :       Added ARP netmask code and
 *					re-arranged proxy handling.
 *		Alan Cox	:	Changed to use notifiers.
 *		Niibe Yutaka	:	Reply for this device or proxies only.
 *		Alan Cox	:	Don't proxy across hardware types!
 *		Jonathan Naylor :	Added support for NET/ROM.
 *		Mike Shaver     :       RFC1122 checks.
 *		Jonathan Naylor :	Only lookup the hardware address for
 *					the correct hardware type.
 *		Germano Caronni	:	Assorted subtle races.
 *		Craig Schlenter :	Don't modify permanent entry
 *					during arp_rcv.
 *		Russ Nelson	:	Tidied up a few bits.
 *		Alexey Kuznetsov:	Major changes to caching and behaviour,
 *					eg intelligent arp probing and
 *					generation
 *					of host down events.
 *		Alan Cox	:	Missing unlock in device events.
 *		Eckes		:	ARP ioctl control errors.
 *		Alexey Kuznetsov:	Arp free fix.
 *		Manuel Rodriguez:	Gratuitous ARP.
 *              Jonathan Layes  :       Added arpd support through kerneld
 *                                      message queue (960314)
 *		Mike Shaver	:	/proc/sys/net/ipv4/arp_* support
 *		Mike McLagan    :	Routing by source
 *		Stuart Cheshire	:	Metricom and grat arp fixes
 *					*** FOR 2.1 clean this up ***
 *		Lawrence V. Stefani: (08/12/96) Added FDDI support.
 *		Alan Cox 	:	Took the AP1000 nasty FDDI hack and
 *					folded into the mainstream FDDI code.
 *					Ack spit, Linus how did you allow that
 *					one in...
 *		Jes Sorensen	:	Make FDDI work again in 2.1.x and
 *					clean up the APFDDI & gen. FDDI bits.
 *		Alexey Kuznetsov:	new arp state machine;
 *					now it is in net/core/neighbour.c.
 *		Krzysztof Halasa:	Added Frame Relay ARP support.
 *		Arnaldo C. Melo :	convert /proc/net/arp to seq_file
 *		Shmulik Hen:		Split arp_send to arp_create and
 *					arp_xmit so intermediate drivers like
 *					bonding can change the skb before
 *					sending (e.g. insert 8021q tag).
 *		Harald Welte	:	convert to make use of jenkins hash
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/capability.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/errno.h>
#include <linux/in.h>
#include <linux/mm.h>
#include <linux/inet.h>
#include <linux/inetdevice.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/fddidevice.h>
#include <linux/if_arp.h>
#include <linux/trdevice.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/net.h>
#include <linux/rcupdate.h>
#include <linux/jhash.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif

#include <net/net_namespace.h>
#include <net/ip.h>
#include <net/icmp.h>
#include <net/route.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/sock.h>
#include <net/arp.h>
#include <net/ax25.h>
#include <net/netrom.h>
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
#include <net/atmclip.h>
struct neigh_table *clip_tbl_hook;
#endif

#include <asm/system.h>
#include <asm/uaccess.h>

#include <linux/netfilter_arp.h>

/*
 *	Interface to generic neighbour cache.
 */
static u32 arp_hash(const void *pkey, const struct net_device *dev);
static int arp_constructor(struct neighbour *neigh);
static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb);
static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb);
static void parp_redo(struct sk_buff *skb);

static struct neigh_ops arp_generic_ops = {
	.family =		AF_INET,
	.solicit =		arp_solicit,
	.error_report =		arp_error_report,
	.output =		neigh_resolve_output,
	.connected_output =	neigh_connected_output,
	.hh_output =		dev_queue_xmit,
	.queue_xmit =		dev_queue_xmit,
};

static struct neigh_ops arp_hh_ops = {
	.family =		AF_INET,
	.solicit =		arp_solicit,
	.error_report =		arp_error_report,
	.output =		neigh_resolve_output,
	.connected_output =	neigh_resolve_output,
	.hh_output =		dev_queue_xmit,
	.queue_xmit =		dev_queue_xmit,
};

static struct neigh_ops arp_direct_ops = {
	.family =		AF_INET,
	.output =		dev_queue_xmit,
	.connected_output =	dev_queue_xmit,
	.hh_output =		dev_queue_xmit,
	.queue_xmit =		dev_queue_xmit,
};

struct neigh_ops arp_broken_ops = {
	.family =		AF_INET,
	.solicit =		arp_solicit,
	.error_report =		arp_error_report,
	.output =		neigh_compat_output,
	.connected_output =	neigh_compat_output,
	.hh_output =		dev_queue_xmit,