summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/alpha/lib/Makefile1
-rw-r--r--arch/alpha/lib/strcasecmp.c26
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c2
-rw-r--r--arch/powerpc/lib/Makefile5
-rw-r--r--arch/powerpc/lib/strcase.c25
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c2
-rw-r--r--arch/ppc/lib/Makefile2
-rw-r--r--arch/ppc/lib/strcase.c24
-rw-r--r--arch/sh/lib/Makefile2
-rw-r--r--arch/sh/lib/strcasecmp.c26
-rw-r--r--arch/sparc/kernel/ebus.c14
-rw-r--r--arch/sparc/kernel/of_device.c21
-rw-r--r--arch/sparc/kernel/pcic.c4
-rw-r--r--arch/sparc/kernel/prom.c19
-rw-r--r--arch/sparc/kernel/time.c2
-rw-r--r--arch/sparc64/Kconfig15
-rw-r--r--arch/sparc64/kernel/central.c12
-rw-r--r--arch/sparc64/kernel/chmc.c4
-rw-r--r--arch/sparc64/kernel/ebus.c14
-rw-r--r--arch/sparc64/kernel/irq.c28
-rw-r--r--arch/sparc64/kernel/isa.c36
-rw-r--r--arch/sparc64/kernel/of_device.c59
-rw-r--r--arch/sparc64/kernel/pci.c599
-rw-r--r--arch/sparc64/kernel/pci_common.c806
-rw-r--r--arch/sparc64/kernel/pci_impl.h33
-rw-r--r--arch/sparc64/kernel/pci_iommu.c104
-rw-r--r--arch/sparc64/kernel/pci_psycho.c154
-rw-r--r--arch/sparc64/kernel/pci_sabre.c465
-rw-r--r--arch/sparc64/kernel/pci_schizo.c295
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c402
-rw-r--r--arch/sparc64/kernel/process.c15
-rw-r--r--arch/sparc64/kernel/prom.c39
-rw-r--r--arch/sparc64/kernel/sbus.c243
-rw-r--r--arch/sparc64/kernel/smp.c116
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c1
-rw-r--r--arch/sparc64/kernel/time.c484
-rw-r--r--arch/sparc64/kernel/ttable.S6
-rw-r--r--arch/sparc64/mm/init.c280
-rw-r--r--arch/sparc64/solaris/misc.c3
-rw-r--r--arch/xtensa/lib/Makefile2
-rw-r--r--arch/xtensa/lib/strcasecmp.c32
-rw-r--r--drivers/mtd/maps/sun_uflash.c4
-rw-r--r--drivers/net/sungem.c37
-rw-r--r--drivers/net/sungem.h2
-rw-r--r--drivers/net/sunhme.c24
-rw-r--r--drivers/net/tg3.c31
-rw-r--r--drivers/net/tulip/de2104x.c2
-rw-r--r--drivers/net/tulip/de4x5.c10
-rw-r--r--drivers/net/tulip/tulip_core.c30
-rw-r--r--drivers/net/tulip/winbond-840.c2
-rw-r--r--drivers/net/tulip/xircom_tulip_cb.c2
-rw-r--r--drivers/sbus/char/envctrl.c8
-rw-r--r--drivers/sbus/char/flash.c2
-rw-r--r--drivers/sbus/char/openprom.c22
-rw-r--r--drivers/sbus/sbus.c4
-rw-r--r--drivers/scsi/Kconfig6
-rw-r--r--drivers/scsi/Makefile3
-rw-r--r--drivers/scsi/esp.c4394
-rw-r--r--drivers/scsi/esp.h406
-rw-r--r--drivers/scsi/esp_scsi.c2710
-rw-r--r--drivers/scsi/esp_scsi.h560
-rw-r--r--drivers/scsi/qlogicpti.c2
-rw-r--r--drivers/scsi/sun_esp.c634
-rw-r--r--drivers/serial/sunsu.c4
-rw-r--r--drivers/video/aty/atyfb_base.c6
-rw-r--r--drivers/video/aty/radeon_base.c12
-rw-r--r--drivers/video/aty/radeon_monitor.c16
-rw-r--r--drivers/video/aty/radeonfb.h4
-rw-r--r--drivers/video/cg3.c2
-rw-r--r--drivers/video/igafb.c24
-rw-r--r--include/asm-alpha/string.h2
-rw-r--r--include/asm-powerpc/string.h2
-rw-r--r--include/asm-sh/string.h3
-rw-r--r--include/asm-sparc/prom.h14
-rw-r--r--include/asm-sparc64/cpudata.h4
-rw-r--r--include/asm-sparc64/device.h18
-rw-r--r--include/asm-sparc64/ebus.h2
-rw-r--r--include/asm-sparc64/floppy.h4
-rw-r--r--include/asm-sparc64/io.h8
-rw-r--r--include/asm-sparc64/iommu.h51
-rw-r--r--include/asm-sparc64/isa.h2
-rw-r--r--include/asm-sparc64/parport.h2
-rw-r--r--include/asm-sparc64/pbm.h132
-rw-r--r--include/asm-sparc64/pci.h2
-rw-r--r--include/asm-sparc64/pgtable.h16
-rw-r--r--include/asm-sparc64/prom.h12
-rw-r--r--include/asm-sparc64/smp.h4
-rw-r--r--include/asm-sparc64/sparsemem.h2
-rw-r--r--include/asm-sparc64/timer.h17
-rw-r--r--include/asm-sparc64/ttable.h27
-rw-r--r--include/linux/string.h6
-rw-r--r--lib/string.c28
-rw-r--r--sound/sparc/amd7930.c4
-rw-r--r--sound/sparc/cs4231.c2
94 files changed, 5648 insertions, 8101 deletions
diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile
index 21cf624d732..ea098f3b629 100644
--- a/arch/alpha/lib/Makefile
+++ b/arch/alpha/lib/Makefile
@@ -36,7 +36,6 @@ lib-y = __divqu.o __remqu.o __divlu.o __remlu.o \
$(ev6-y)csum_ipv6_magic.o \
$(ev6-y)clear_page.o \
$(ev6-y)copy_page.o \
- strcasecmp.o \
fpreg.o \
callback_srm.o srm_puts.o srm_printk.o
diff --git a/arch/alpha/lib/strcasecmp.c b/arch/alpha/lib/strcasecmp.c
deleted file mode 100644
index 4e57a216fea..00000000000
--- a/arch/alpha/lib/strcasecmp.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * linux/arch/alpha/lib/strcasecmp.c
- */
-
-#include <linux/string.h>
-
-
-/* We handle nothing here except the C locale. Since this is used in
- only one place, on strings known to contain only 7 bit ASCII, this
- is ok. */
-
-int strcasecmp(const char *a, const char *b)
-{
- int ca, cb;
-
- do {
- ca = *a++ & 0xff;
- cb = *b++ & 0xff;
- if (ca >= 'A' && ca <= 'Z')
- ca += 'a' - 'A';
- if (cb >= 'A' && cb <= 'Z')
- cb += 'a' - 'A';
- } while (ca == cb && ca != '\0');
-
- return ca - cb;
-}
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index ecee596d28f..2f8e9c02c92 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -84,8 +84,6 @@ EXPORT_SYMBOL(strncpy);
EXPORT_SYMBOL(strcat);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strcasecmp);
-EXPORT_SYMBOL(strncasecmp);
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_generic);
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 4b1ba49fbd9..450258de7ca 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -7,13 +7,12 @@ EXTRA_CFLAGS += -mno-minimal-toc
endif
ifeq ($(CONFIG_PPC_MERGE),y)
-obj-y := string.o strcase.o
+obj-y := string.o
obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o
endif
obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \
- memcpy_64.o usercopy_64.o mem_64.o string.o \
- strcase.o
+ memcpy_64.o usercopy_64.o mem_64.o string.o
obj-$(CONFIG_QUICC_ENGINE) += rheap.o
obj-$(CONFIG_XMON) += sstep.o
obj-$(CONFIG_KPROBES) += sstep.o
diff --git a/arch/powerpc/lib/strcase.c b/arch/powerpc/lib/strcase.c
deleted file mode 100644
index f8ec1eba3fd..00000000000
--- a/arch/powerpc/lib/strcase.c
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <linux/types.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-
-int strcasecmp(const char *s1, const char *s2)
-{
- int c1, c2;
-
- do {
- c1 = tolower(*s1++);
- c2 = tolower(*s2++);
- } while (c1 == c2 && c1 != 0);
- return c1 - c2;
-}
-
-int strncasecmp(const char *s1, const char *s2, size_t n)
-{
- int c1, c2;
-
- do {
- c1 = tolower(*s1++);
- c2 = tolower(*s2++);
- } while ((--n > 0) && c1 == c2 && c1 != 0);
- return c1 - c2;
-}
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 1318b6f4c3d..4ad499605d0 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -93,8 +93,6 @@ EXPORT_SYMBOL(strncpy);
EXPORT_SYMBOL(strcat);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strcasecmp);
-EXPORT_SYMBOL(strncasecmp);
EXPORT_SYMBOL(__div64_32);
EXPORT_SYMBOL(csum_partial);
diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile
index 50358e4ea15..422bef9bae7 100644
--- a/arch/ppc/lib/Makefile
+++ b/arch/ppc/lib/Makefile
@@ -2,7 +2,7 @@
# Makefile for ppc-specific library files..
#
-obj-y := checksum.o string.o strcase.o div64.o
+obj-y := checksum.o string.o div64.o
obj-$(CONFIG_8xx) += rheap.o
obj-$(CONFIG_CPM2) += rheap.o
diff --git a/arch/ppc/lib/strcase.c b/arch/ppc/lib/strcase.c
deleted file mode 100644
index 3b0094cc2b5..00000000000
--- a/arch/ppc/lib/strcase.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include <linux/ctype.h>
-#include <linux/types.h>
-
-int strcasecmp(const char *s1, const char *s2)
-{
- int c1, c2;
-
- do {
- c1 = tolower(*s1++);
- c2 = tolower(*s2++);
- } while (c1 == c2 && c1 != 0);
- return c1 - c2;
-}
-
-int strncasecmp(const char *s1, const char *s2, size_t n)
-{
- int c1, c2;
-
- do {
- c1 = tolower(*s1++);
- c2 = tolower(*s2++);
- } while ((--n > 0) && c1 == c2 && c1 != 0);
- return c1 - c2;
-}
diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile
index b5681e3f968..0b9cca5c7cb 100644
--- a/arch/sh/lib/Makefile
+++ b/arch/sh/lib/Makefile
@@ -3,7 +3,7 @@
#
lib-y = delay.o memset.o memmove.o memchr.o \
- checksum.o strcasecmp.o strlen.o div64.o udivdi3.o \
+ checksum.o strlen.o div64.o udivdi3.o \
div64-generic.o
memcpy-y := memcpy.o
diff --git a/arch/sh/lib/strcasecmp.c b/arch/sh/lib/strcasecmp.c
deleted file mode 100644
index 4e57a216fea..00000000000
--- a/arch/sh/lib/strcasecmp.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * linux/arch/alpha/lib/strcasecmp.c
- */
-
-#include <linux/string.h>
-
-
-/* We handle nothing here except the C locale. Since this is used in
- only one place, on strings known to contain only 7 bit ASCII, this
- is ok. */
-
-int strcasecmp(const char *a, const char *b)
-{
- int ca, cb;
-
- do {
- ca = *a++ & 0xff;
- cb = *b++ & 0xff;
- if (ca >= 'A' && ca <= 'Z')
- ca += 'a' - 'A';
- if (cb >= 'A' && cb <= 'Z')
- cb += 'a' - 'A';
- } while (ca == cb && ca != '\0');
-
- return ca - cb;
-}
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
index ba58c3a061f..7bb86b9cdaa 100644
--- a/arch/sparc/kernel/ebus.c
+++ b/arch/sparc/kernel/ebus.c
@@ -25,7 +25,7 @@
struct linux_ebus *ebus_chain = NULL;
/* We are together with pcic.c under CONFIG_PCI. */
-extern unsigned int pcic_pin_to_irq(unsigned int, char *name);
+extern unsigned int pcic_pin_to_irq(unsigned int, const char *name);
/*
* IRQ Blacklist
@@ -69,7 +69,7 @@ static inline unsigned long ebus_alloc(size_t size)
/*
*/
-int __init ebus_blacklist_irq(char *name)
+int __init ebus_blacklist_irq(const char *name)
{
struct ebus_device_irq *dp;
@@ -86,8 +86,8 @@ int __init ebus_blacklist_irq(char *name)
void __init fill_ebus_child(struct device_node *dp,
struct linux_ebus_child *dev)
{
- int *regs;
- int *irqs;
+ const int *regs;
+ const int *irqs;
int i, len;
dev->prom_node = dp;
@@ -146,9 +146,9 @@ void __init fill_ebus_child(struct device_node *dp,
void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
{
- struct linux_prom_registers *regs;
+ const struct linux_prom_registers *regs;
struct linux_ebus_child *child;
- int *irqs;
+ const int *irqs;
int i, n, len;
unsigned long baseaddr;
@@ -269,7 +269,7 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d
void __init ebus_init(void)
{
- struct linux_prom_pci_registers *regs;
+ const struct linux_prom_pci_registers *regs;
struct linux_pbm_info *pbm;
struct linux_ebus_device *dev;
struct linux_ebus *ebus;
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index 48c24f7518c..fd7f8cb668a 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -210,7 +210,7 @@ struct of_bus {
int *addrc, int *sizec);
int (*map)(u32 *addr, const u32 *range,
int na, int ns, int pna);
- unsigned int (*get_flags)(u32 *addr);
+ unsigned int (*get_flags)(const u32 *addr);
};
/*
@@ -270,7 +270,7 @@ static int of_bus_default_map(u32 *addr, const u32 *range,
return 0;
}
-static unsigned int of_bus_default_get_flags(u32 *addr)
+static unsigned int of_bus_default_get_flags(const u32 *addr)
{
return IORESOURCE_MEM;
}
@@ -334,7 +334,7 @@ static int of_bus_pci_map(u32 *addr, const u32 *range,
return 0;
}
-static unsigned int of_bus_pci_get_flags(u32 *addr)
+static unsigned int of_bus_pci_get_flags(const u32 *addr)
{
unsigned int flags = 0;
u32 w = addr[0];
@@ -375,7 +375,7 @@ static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna)
return of_bus_default_map(addr, range, na, ns, pna);
}
-static unsigned int of_bus_sbus_get_flags(u32 *addr)
+static unsigned int of_bus_sbus_get_flags(const u32 *addr)
{
return IORESOURCE_MEM;
}
@@ -432,7 +432,7 @@ static int __init build_one_resource(struct device_node *parent,
u32 *addr,
int na, int ns, int pna)
{
- u32 *ranges;
+ const u32 *ranges;
unsigned int rlen;
int rone;
@@ -470,7 +470,7 @@ static void __init build_device_resources(struct of_device *op,
struct of_bus *bus;
int na, ns;
int index, num_reg;
- void *preg;
+ const void *preg;
if (!parent)
return;
@@ -492,7 +492,7 @@ static void __init build_device_resources(struct of_device *op,
for (index = 0; index < num_reg; index++) {
struct resource *r = &op->resource[index];
u32 addr[OF_MAX_ADDR_CELLS];
- u32 *reg = (preg + (index * ((na + ns) * 4)));
+ const u32 *reg = (preg + (index * ((na + ns) * 4)));
struct device_node *dp = op->node;
struct device_node *pp = p_op->node;
struct of_bus *pbus, *dbus;
@@ -559,7 +559,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
struct device *parent)
{
struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
- struct linux_prom_irqs *intr;
+ const struct linux_prom_irqs *intr;
int len, i;
if (!op)
@@ -579,7 +579,8 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
for (i = 0; i < op->num_irqs; i++)
op->irqs[i] = intr[i].pri;
} else {
- unsigned int *irq = of_get_property(dp, "interrupts", &len);
+ const unsigned int *irq =
+ of_get_property(dp, "interrupts", &len);
if (irq) {
op->num_irqs = len / sizeof(unsigned int);
@@ -594,7 +595,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0,
};
struct device_node *io_unit, *sbi = dp->parent;
- struct linux_prom_registers *regs;
+ const struct linux_prom_registers *regs;
int board, slot;
while (sbi) {
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 1c927c538b8..5ca7e8f42bd 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -37,8 +37,6 @@
#include <asm/irq_regs.h>
-unsigned int pcic_pin_to_irq(unsigned int pin, char *name);
-
/*
* I studied different documents and many live PROMs both from 2.30
* family and 3.xx versions. I came to the amazing conclusion: there is
@@ -681,7 +679,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
* pcic_pin_to_irq() is exported to ebus.c.
*/
unsigned int
-pcic_pin_to_irq(unsigned int pin, char *name)
+pcic_pin_to_irq(unsigned int pin, const char *name)
{
struct linux_pcic *pcic = &pcic0;
unsigned int irq;
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
index 2cc302b6bec..eed140b3c73 100644
--- a/arch/sparc/kernel/prom.c
+++ b/arch/sparc/kernel/prom.c
@@ -32,12 +32,13 @@ static struct device_node *allnodes;
*/
static DEFINE_RWLOCK(devtree_lock);
-int of_device_is_compatible(struct device_node *device, const char *compat)
+int of_device_is_compatible(const struct device_node *device,
+ const char *compat)
{
const char* cp;
int cplen, l;
- cp = (char *) of_get_property(device, "compatible", &cplen);
+ cp = of_get_property(device, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
@@ -150,13 +151,14 @@ struct device_node *of_find_compatible_node(struct device_node *from,
}
EXPORT_SYMBOL(of_find_compatible_node);
-struct property *of_find_property(struct device_node *np, const char *name,
+struct property *of_find_property(const struct device_node *np,
+ const char *name,
int *lenp)
{
struct property *pp;
for (pp = np->properties; pp != 0; pp = pp->next) {
- if (strcmp(pp->name, name) == 0) {
+ if (strcasecmp(pp->name, name) == 0) {
if (lenp != 0)
*lenp = pp->length;
break;
@@ -170,7 +172,8 @@ EXPORT_SYMBOL(of_find_property);
* Find a property with a given name for a given node
* and return the value.
*/
-void *of_get_property(struct device_node *np, const char *name, int *lenp)
+const void *of_get_property(const struct device_node *np, const char *name,
+ int *lenp)
{
struct property *pp = of_find_property(np,name,lenp);
return pp ? pp->value : NULL;
@@ -192,7 +195,7 @@ EXPORT_SYMBOL(of_getintprop_default);
int of_n_addr_cells(struct device_node *np)
{
- int* ip;
+ const int* ip;
do {
if (np->parent)
np = np->parent;
@@ -207,7 +210,7 @@ EXPORT_SYMBOL(of_n_addr_cells);
int of_n_size_cells(struct device_node *np)
{
- int* ip;
+ const int* ip;
do {
if (np->parent)
np = np->parent;
@@ -239,7 +242,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
while (*prevp) {
struct property *prop = *prevp;
- if (!strcmp(prop->name, name)) {
+ if (!strcasecmp(prop->name, name)) {
void *old_val = prop->value;
int ret;
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 9bb1240aaf8..f1401b57ccc 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -301,7 +301,7 @@ static __inline__ void sun4_clock_probe(void)
static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->node;
- char *model = of_get_property(dp, "model", NULL);
+ const char *model = of_get_property(dp, "model", NULL);
if (!model)
return -ENODEV;
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 1a6348b565f..590a41b864b 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -19,6 +19,14 @@ config SPARC64
SPARC64 ports; its web page is available at
<http://www.ultralinux.org/>.
+config GENERIC_TIME
+ bool
+ default y
+
+config GENERIC_CLOCKEVENTS
+ bool
+ default y
+
config 64BIT
def_bool y
@@ -34,10 +42,6 @@ config LOCKDEP_SUPPORT
bool
default y
-config TIME_INTERPOLATION
- bool
- default y
-
config ARCH_MAY_HAVE_PC_FDC
bool
default y
@@ -113,6 +117,8 @@ config GENERIC_HARDIRQS
menu "General machine setup"
+source "kernel/time/Kconfig"
+
config SMP
bool "Symmetric multi-processing support"
---help---
@@ -214,6 +220,7 @@ config ARCH_SPARSEMEM_ENABLE
config ARCH_SPARSEMEM_DEFAULT
def_bool y
+ select SPARSEMEM_STATIC
config LARGE_ALLOCS
def_bool y
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
index e724c54af02..c65b2f9c98d 100644
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -32,7 +32,7 @@ static void central_probe_failure(int line)
static void central_ranges_init(struct linux_central *central)
{
struct device_node *dp = central->prom_node;
- void *pval;
+ const void *pval;
int len;
central->num_central_ranges = 0;
@@ -47,7 +47,7 @@ static void central_ranges_init(struct linux_central *central)
static void fhc_ranges_init(struct linux_fhc *fhc)
{
struct device_node *dp = fhc->prom_node;
- void *pval;
+ const void *pval;
int len;
fhc->num_fhc_ranges = 0;
@@ -119,7 +119,7 @@ static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r)
static void probe_other_fhcs(void)
{
struct device_node *dp;
- struct linux_prom64_registers *fpregs;
+ const struct linux_prom64_registers *fpregs;
for_each_node_by_name(dp, "fhc") {
struct linux_fhc *fhc;
@@ -190,7 +190,8 @@ static void probe_clock_board(struct linux_central *central,
struct device_node *fp)
{
struct device_node *dp;
- struct linux_prom_registers cregs[3], *pr;
+ struct linux_prom_registers cregs[3];
+ const struct linux_prom_registers *pr;
int nslots, tmp, nregs;
dp = fp->child;
@@ -299,7 +300,8 @@ static void init_all_fhc_hw(void)
void central_probe(void)
{
- struct linux_prom_registers fpregs[6], *pr;
+ struct linux_prom_registers fpregs[6];
+ const struct linux_prom_registers *pr;
struct linux_fhc *fhc;
struct device_node *dp, *fp;
int err;
diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c
index 9699abeb990..777d3457704 100644
--- a/arch/sparc64/kernel/chmc.c
+++ b/arch/sparc64/kernel/chmc.c
@@ -343,8 +343,8 @@ static int init_one_mctrl(struct device_node *dp)
{
struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
int portid = of_getintprop_default(dp, "portid", -1);
- struct linux_prom64_registers *regs;
- void *pval;
+ const struct linux_prom64_registers *regs;
+ const void *pval;
int len;
if (!mp)
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 35bf895fdee..0ace17bafba 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -285,7 +285,7 @@ static void __init fill_ebus_child(struct device_node *dp,
int non_standard_regs)
{
struct of_device *op;
- int *regs;
+ const int *regs;
int i, len;
dev->prom_node = dp;
@@ -438,11 +438,9 @@ static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p)
void __init ebus_init(void)
{
- struct pci_pbm_info *pbm;
struct linux_ebus_device *dev;
struct linux_ebus *ebus;
struct pci_dev *pdev;
- struct pcidev_cookie *cookie;
struct device_node *dp;
int is_rio;
int num_ebus = 0;
@@ -453,8 +451,7 @@ void __init ebus_init(void)
return;
}
- cookie = pdev->sysdata;
- dp = cookie->prom_node;
+ dp = pci_device_to_OF_node(pdev);
ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
ebus->next = NULL;
@@ -480,8 +477,7 @@ void __init ebus_init(void)
break;
}
ebus->is_rio = is_rio;
- cookie = pdev->sysdata;
- dp = cookie->prom_node;
+ dp = pci_device_to_OF_node(pdev);
continue;
}
printk("ebus%d:", num_ebus);
@@ -489,7 +485,6 @@ void __init ebus_init(void)
ebus->index = num_ebus;
ebus->prom_node = dp;
ebus->self = pdev;
- ebus->parent = pbm = cookie->pbm;
ebus->ofdev.node = dp;
ebus->ofdev.dev.parent = &pdev->dev;
@@ -531,8 +526,7 @@ void __init ebus_init(void)
if (!pdev)
break;
- cookie = pdev->sysdata;
- dp = cookie->prom_node;
+ dp = pci_device_to_OF_node(pdev);
ebus->next = ebus_alloc(sizeof(struct linux_ebus));
ebus = ebus->next;
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index c443db18437..6241e3dbbd5 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -589,32 +589,6 @@ void ack_bad_irq(unsigned int virt_irq)
ino, virt_irq);
}
-#ifndef CONFIG_SMP
-extern irqreturn_t timer_interrupt(int, void *);
-
-void timer_irq(int irq, struct pt_regs *regs)
-{
- unsigned long clr_mask = 1 << irq;
- unsigned long tick_mask = tick_ops->softint_mask;
- struct pt_regs *old_regs;
-
- if (get_softint() & tick_mask) {
- irq = 0;
- clr_mask = tick_mask;
- }
- clear_softint(clr_mask);
-
- old_regs = set_irq_regs(regs);
- irq_enter();
-
- kstat_this_cpu.irqs[0]++;
- timer_interrupt(irq, NULL);
-
- irq_exit();
- set_irq_regs(old_regs);
-}
-#endif
-
void handler_irq(int irq, struct pt_regs *regs)
{
struct ino_bucket *bucket;
@@ -653,7 +627,7 @@ static u64 prom_limit0, prom_limit1;
static void map_prom_timers(void)
{
struct device_node *dp;
- unsigned int *addr;
+ const unsigned int *addr;
/* PROM timer node hangs out in the top level of device siblings... */
dp = of_find_node_by_path("/");
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
index 98721a8f861..6a6882e57ff 100644
--- a/arch/sparc64/kernel/isa.c
+++ b/arch/sparc64/kernel/isa.c
@@ -24,27 +24,9 @@ static void __init report_dev(struct sparc_isa_device *isa_dev, int child)
static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev)
{
- struct linux_prom_registers *pregs;
- unsigned long base, len;
- int prop_len;
-
- pregs = of_get_property(isa_dev->prom_node, "reg", &prop_len);
- if (!pregs)
- return;
-
- /* Only the first one is interesting. */
- len = pregs[0].reg_size;
- base = (((unsigned long)pregs[0].which_io << 32) |
- (unsigned long)pregs[0].phys_addr);
- base += isa_dev->bus->parent->io_space.start;
-
- isa_dev->resource.start = base;
- isa_dev->resource.end = (base + len - 1UL);
- isa_dev->resource.flags = IORESOURCE_IO;
- isa_dev->resource.name = isa_dev->prom_node->name;
+ struct of_device *op = of_find_device_by_node(isa_dev->prom_node);
- request_resource(&isa_dev->bus->parent->io_space,
- &isa_dev->resource);
+ memcpy(&isa_dev->resource, &op->resource[0], sizeof(struct resource));
}
static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev)
@@ -158,19 +140,10 @@ void __init isa_init(void)
pdev = NULL;
while ((pdev = pci_get_device(vendor, device, pdev)) != NULL) {
- struct pcidev_cookie *pdev_cookie;
- struct pci_pbm_info *pbm;
struct sparc_isa_bridge *isa_br;
struct device_node *dp;
- pdev_cookie = pdev->sysdata;
- if (!pdev_cookie) {
- printk("ISA: Warning, ISA bridge ignored due to "
- "lack of OBP data.\n");
- continue;
- }
- pbm = pdev_cookie->pbm;
- dp = pdev_cookie->prom_node;
+ dp = pci_device_to_OF_node(pdev);
isa_br = kzalloc(sizeof(*isa_br), GFP_KERNEL);
if (!isa_br) {
@@ -195,10 +168,9 @@ void __init isa_init(void)
isa_br->next = isa_chain;
isa_chain = isa_br;
- isa_br->parent = pbm;
isa_br->self = pdev;
isa_br->index = index++;
- isa_br->prom_node = pdev_cookie->prom_node;
+ isa_br->prom_node = dp;
printk("isa%d:", isa_br->index);
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index fb9bf1e4d03..9ac9a307999 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -245,7 +245,7 @@ struct of_bus {
int *addrc, int *sizec);
int (*map)(u32 *addr, const u32 *range,
int na, int ns, int pna);
- unsigned int (*get_flags)(u32 *addr);
+ unsigned int (*get_flags)(const u32 *addr);
};
/*
@@ -305,7 +305,7 @@ static int of_bus_default_map(u32 *addr, const u32 *range,
return 0;
}
-static unsigned int of_bus_default_get_flags(u32 *addr)
+static unsigned int of_bus_default_get_flags(const u32 *addr)
{
return IORESOURCE_MEM;
}
@@ -317,6 +317,11 @@ static unsigned int of_bus_default_get_flags(u32 *addr)
static int of_bus_pci_match(struct device_node *np)
{
if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
+ const char *model = of_get_property(np, "model", NULL);
+
+ if (model && !strcmp(model, "SUNW,simba"))
+ return 0;
+
/* Do not do PCI specific frobbing if the
* PCI bridge lacks a ranges property. We
* want to pass it through up to the next
@@ -332,6 +337,21 @@ static int of_bus_pci_match(struct device_node *np)
return 0;
}
+static int of_bus_simba_match(struct device_node *np)
+{
+ const char *model = of_get_property(np, "model", NULL);
+
+ if (model && !strcmp(model, "SUNW,simba"))
+ return 1;
+ return 0;
+}
+
+static int of_bus_simba_map(u32 *addr, const u32 *range,
+ int na, int ns, int pna)
+{
+ return 0;
+}
+
static void of_bus_pci_count_cells(struct device_node *np,
int *addrc, int *sizec)
{
@@ -369,7 +389,7 @@ static int of_bus_pci_map(u32 *addr, const u32 *range,
return 0;
}
-static unsigned int of_bus_pci_get_flags(u32 *addr)
+static unsigned int of_bus_pci_get_flags(const u32 *addr)
{
unsigned int flags = 0;
u32 w = addr[0];
@@ -436,6 +456,15 @@ static struct of_bus of_busses[] = {
.map = of_bus_pci_map,
.get_flags = of_bus_pci_get_flags,
},
+ /* SIMBA */
+ {
+ .name = "simba",
+ .addr_prop_name = "assigned-addresses",
+ .match = of_bus_simba_match,
+ .count_cells = of_bus_pci_count_cells,
+ .map = of_bus_simba_map,
+ .get_flags = of_bus_pci_get_flags,
+ },
/* SBUS */
{
.name = "sbus",
@@ -482,7 +511,7 @@ static int __init build_one_resource(struct device_node *parent,
u32 *addr,
int na, int ns, int pna)
{
- u32 *ranges;
+ const u32 *ranges;
unsigned int rlen;
int rone;
@@ -513,7 +542,7 @@ static int __init build_one_resource(struct device_node *parent,
static int __init use_1to1_mapping(struct device_node *pp)
{
- char *model;
+ const char *model;
/* If this is on the PMU bus, don't try to translate it even
* if a ranges property exists.
@@ -548,7 +577,7 @@ static void __init build_device_resources(struct of_device *op,
struct of_bus *bus;
int na, ns;
int index, num_reg;
- void *preg;
+ const void *preg;
if (!parent)
return;
@@ -578,7 +607,7 @@ static void __init build_device_resources(struct of_device *op,
for (index = 0; index < num_reg; index++) {
struct resource *r = &op->resource[index];
u32 addr[OF_MAX_ADDR_CELLS];
- u32 *reg = (preg + (index * ((na + ns) * 4)));
+ const u32 *reg = (preg + (index * ((na + ns) * 4)));
struct device_node *dp = op->node;
struct device_node *pp = p_op->node;
struct of_bus *pbus, *dbus;
@@ -643,14 +672,14 @@ static void __init build_device_resources(struct of_device *op,
static struct device_node * __init
apply_interrupt_map(struct device_node *dp, struct device_node *pp,
- u32 *imap, int imlen, u32 *imask,
+ const u32 *imap, int imlen, const u32 *imask,
unsigned int *irq_p)
{
struct device_node *cp;
unsigned int irq = *irq_p;
struct of_bus *bus;
phandle handle;
- u32 *reg;
+ const u32 *reg;
int na, num_reg, i;
bus = of_match_bus(pp);
@@ -705,7 +734,7 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp,
struct device_node *pp,
unsigned int irq)
{
- struct linux_prom_pci_registers *regs;
+ const struct linux_prom_pci_registers *regs;
unsigned int bus, devfn, slot, ret;
if (irq < 1 || irq > 4)
@@ -730,12 +759,6 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp,
* D: 2-bit slot number, derived from PCI device number as
* (dev - 1) for bus A, or (dev - 2) for bus B
* L: 2-bit line number
- *
- * Actually, more "portable" way to calculate the funky
- * slot number is to subtract pbm->pci_first_slot from the
- * device number, and that's exactly what the pre-OF
- * sparc64 code did, but we're building this stuff generically
- * using the OBP tree, not in the PCI controller layer.
*/
if (bus & 0x80) {
/* PBM-A */
@@ -794,7 +817,7 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
pp = dp->parent;
ip = NULL;
while (pp) {
- void *imap, *imsk;
+ const void *imap, *imsk;
int imlen;
imap = of_get_property(pp, "interrupt-map", &imlen);
@@ -859,7 +882,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
struct device *parent)
{
struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
- unsigned int *irq;
+ const unsigned int *irq;
int len, i;
if (!op)
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 12109886bb1..023af41ad68 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -1,9 +1,11 @@
-/* $Id: pci.c,v 1.39 2002/01/05 01:13:43 davem Exp $
- * pci.c: UltraSparc PCI controller support.
+/* pci.c: UltraSparc PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
* Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ * OF tree based PCI bus probing taken from the PowerPC port
+ * with minor modifications, see there for credits.
*/
#include <linux/module.h>
@@ -24,6 +26,9 @@
#include <asm/ebus.h>
#include <asm/isa.h>
#include <asm/prom.h>
+#include <asm/apb.h>
+
+#include "pci_impl.h"
unsigned long pci_memspace_mask = 0xffffffffUL;
@@ -277,10 +282,10 @@ int __init pcic_present(void)
return pci_controller_scan(pci_is_controller);
}
-struct pci_iommu_ops *pci_iommu_ops;
+const struct pci_iommu_ops *pci_iommu_ops;
EXPORT_SYMBOL(pci_iommu_ops);
-extern struct pci_iommu_ops pci_sun4u_iommu_ops,
+extern const struct pci_iommu_ops pci_sun4u_iommu_ops,
pci_sun4v_iommu_ops;
/* Find each controller in the system, attach and initialize
@@ -300,6 +305,467 @@ static void __init pci_controller_probe(void)
pci_controller_scan(pci_controller_init);
}
+static unsigned long pci_parse_of_flags(u32 addr0)
+{
+ unsigned long flags = 0;
+
+ if (addr0 & 0x02000000) {
+ flags = IORESOURCE_MEM | PCI_BASE_ADDRESS_SPACE_MEMORY;
+ flags |= (addr0 >> 22) & PCI_BASE_ADDRESS_MEM_TYPE_64;
+ flags |= (addr0 >> 28) & PCI_BASE_ADDRESS_MEM_TYPE_1M;
+ if (addr0 & 0x40000000)
+ flags |= IORESOURCE_PREFETCH
+ | PCI_BASE_ADDRESS_MEM_PREFETCH;
+ } else if (addr0 & 0x01000000)
+ flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO;
+ return flags;
+}
+
+/* The of_device layer has translated all of the assigned-address properties
+ * into physical address resources, we only have to figure out the register
+ * mapping.
+ */
+static void pci_parse_of_addrs(struct of_device *op,
+ struct device_node *node,
+ struct pci_dev *dev)
+{
+ struct resource *op_res;
+ const u32 *addrs;
+ int proplen;
+
+ addrs = of_get_property(node, "assigned-addresses", &proplen);
+ if (!addrs)
+ return;
+ printk(" parse addresses (%d bytes) @ %p\n", proplen, addrs);
+ op_res = &op->resource[0];
+ for (; proplen >= 20; proplen -= 20, addrs += 5, op_res++) {
+ struct resource *res;
+ unsigned long flags;
+ int i;
+
+ flags = pci_parse_of_flags(addrs[0]);
+ if (!flags)
+ continue;
+ i = addrs[0] & 0xff;
+ printk(" start: %lx, end: %lx, i: %x\n",
+ op_res->start, op_res->end, i);
+
+ if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {
+ res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
+ } else if (i == dev->rom_base_reg) {
+ res = &dev->resource[PCI_ROM_RESOURCE];
+ flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+ } else {
+ printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i);
+ continue;
+ }
+ res->start = op_res->start;
+ res->end = op_res->end;
+ res->flags = flags;
+ res->name = pci_name(dev);
+ }
+}
+
+struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
+ struct device_node *node,
+ struct pci_bus *bus, int devfn,
+ int host_controller)
+{
+ struct dev_archdata *sd;
+ struct pci_dev *dev;
+ const char *type;
+ u32 class;
+
+ dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ sd = &dev->dev.archdata;
+ sd->iommu = pbm->iommu;
+ sd->stc = &pbm->stc;
+ sd->host_controller = pbm;
+ sd->prom_node = node;
+ sd->op = of_find_device_by_node(node);
+ sd->msi_num = 0xffffffff;
+
+ type = of_get_property(node, "device_type", NULL);
+ if (type == NULL)
+ type = "";
+
+ printk(" create device, devfn: %x, type: %s hostcontroller(%d)\n",
+ devfn, type, host_controller);
+
+ dev->bus = bus;
+ dev->sysdata = node;
+ dev->dev.parent = bus->bridge;
+ dev->dev.bus = &pci_bus_type;
+ dev->devfn = devfn;
+ dev->multifunction = 0; /* maybe a lie? */
+
+ if (host_controller) {
+ dev->vendor = 0x108e;
+ dev->device = 0x8000;
+ dev->subsystem_vendor = 0x0000;
+ dev->subsystem_device = 0x0000;
+ dev->cfg_size = 256;
+ dev->class = PCI_CLASS_BRIDGE_HOST << 8;
+ sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
+ 0x00, PCI_SLOT(devfn), PCI_FUNC(devfn));
+ } else {
+ dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);
+ dev->device = of_getintprop_default(node, "device-id", 0xffff);
+ dev->subsystem_vendor =
+ of_getintprop_default(node, "subsystem-vendor-id", 0);
+ dev->subsystem_device =
+ of_getintprop_default(node, "subsystem-id", 0);
+
+ dev->cfg_size = pci_cfg_space_size(dev);
+
+ /* We can't actually use the firmware value, we have
+ * to read what is in the register right now. One
+ * reason is that in the case of IDE interfaces the
+ * firmware can sample the value before the the IDE
+ * interface is programmed into native mode.
+ */
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
+ dev->class = class >> 8;
+
+ sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
+ dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
+ }
+ printk(" class: 0x%x device name: %s\n",
+ dev->class, pci_name(dev));
+
+ dev->current_state = 4; /* unknown power state */
+ dev->error_state = pci_channel_io_normal;
+
+ if (host_controller) {
+ dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
+ dev->rom_base_reg = PCI_ROM_ADDRESS1;
+ dev->irq = PCI_IRQ_NONE;
+ } else {
+ if (!strcmp(type, "pci") || !strcmp(type, "pciex")) {
+ /* a PCI-PCI bridge */
+ dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
+ dev->rom_base_reg = PCI_ROM_ADDRESS1;
+ } else if (!strcmp(type, "cardbus")) {
+ dev->hdr_type = PCI_HEADER_TYPE_CARDBUS;
+ } else {
+ dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
+ dev->rom_base_reg = PCI_ROM_ADDRESS;
+
+ dev->irq = sd->op->irqs[0];
+ if (dev->irq == 0xffffffff)
+ dev->irq = PCI_IRQ_NONE;
+ }
+ }
+ pci_parse_of_addrs(sd->op, node, dev);
+
+ printk(" adding to system ...\n");
+
+ pci_device_add(dev, bus);
+
+ return dev;
+}
+
+static void __init apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
+{
+ u32 idx, first, last;
+
+ first = 8;
+ last = 0;
+ for (idx = 0; idx < 8; idx++) {
+ if ((map & (1 << idx)) != 0) {
+ if (first > idx)
+ first = idx;
+ if (last < idx)
+ last = idx;
+ }
+ }
+
+ *first_p = first;
+ *last_p = last;
+}
+
+static void __init pci_resource_adjust(struct resource *res,
+ struct resource *root)
+{
+ res->start += root->start;
+ res->end += root->start;
+}
+
+/* Cook up fake bus resources for SUNW,simba PCI bridges which lack
+ * a proper 'ranges' property.
+ */
+static void __init apb_fake_ranges(struct pci_dev *dev,
+ struct pci_bus *bus,
+ struct pci_pbm_info *pbm)
+{
+ struct resource *res;
+ u32 first, last;
+ u8 map;
+
+ pci_read_config_byte(dev, APB_IO_ADDRESS_MAP, &map);
+ apb_calc_first_last(map, &first, &last);
+ res = bus->resource[0];
+ res->start = (first << 21);
+ res->end = (last << 21) + ((1 << 21) - 1);
+ res->flags = IORESOURCE_IO;
+ pci_resource_adjust(res, &pbm->io_space);
+
+ pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map);
+ apb_calc_first_last(map, &first, &last);
+ res = bus->resource[1];
+ res->start = (first << 21);
+ res->end = (last << 21) + ((1 << 21) - 1);
+ res->flags = IORESOURCE_MEM;
+ pci_resource_adjust(res, &pbm->mem_space);
+}
+
+static void __init pci_of_scan_bus(struct pci_pbm_info *pbm,
+ struct device_node *node,
+ struct pci_bus *bus);
+
+#define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1])
+
+void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
+ struct device_node *node,
+ struct pci_dev *dev)
+{
+ struct pci_bus *bus;
+ const u32 *busrange, *ranges;
+ int len, i, simba;
+ struct resource *res;
+ unsigned int flags;
+ u64 size;
+
+ printk("of_scan_pci_bridge(%s)\n", node->full_name);
+
+ /* parse bus-range property */
+ busrange = of_get_property(node, "bus-range", &len);
+ if (busrange == NULL || len != 8) {
+ printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n",
+ node->full_name);
+ return;
+ }
+ ranges = of_get_property(node, "ranges", &len);
+ simba = 0;
+ if (ranges == NULL) {
+ const char *model = of_get_property(node, "model", NULL);
+ if (model && !strcmp(model, "SUNW,simba")) {
+ simba = 1;
+ } else {
+ printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
+ node->full_name);
+ return;
+ }
+ }
+
+ bus = pci_add_new_bus(dev->bus, dev, busrange[0]);
+ if (!bus) {
+ printk(KERN_ERR "Failed to create pci bus for %s\n",
+ node->full_name);
+ return;
+ }
+
+ bus->primary = dev->bus->number;
+ bus->subordinate = busrange[1];
+ bus->bridge_ctl = 0;
+
+ /* parse ranges property, or cook one up by hand for Simba */
+ /* PCI #address-cells == 3 and #size-cells == 2 always */
+ res = &dev->resource[PCI_BRIDGE_RESOURCES];
+ for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) {
+ res->flags = 0;
+ bus->resource[i] = res;
+ ++res;
+ }
+ if (simba) {
+ apb_fake_ranges(dev, bus, pbm);
+ goto simba_cont;
+ }
+ i = 1;
+ for (; len >= 32; len -= 32, ranges += 8) {
+ struct resource *root;
+
+ flags = pci_parse_of_flags(ranges[0]);
+ size = GET_64BIT(ranges, 6);
+ if (flags == 0 || size == 0)
+ continue;
+ if (flags & IORESOURCE_IO) {
+ res = bus->resource[0];
+ if (res->flags) {
+ printk(KERN_ERR "PCI: ignoring extra I/O range"
+ " for bridge %s\n", node->full_name);
+ continue;
+ }
+ root = &pbm->io_space;
+ } else {
+ if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) {
+ printk(KERN_ERR "PCI: too many memory ranges"
+ " for bridge %s\n", node->full_name);
+ continue;
+ }
+ res = bus->resource[i];
+ ++i;
+ root = &pbm->mem_space;
+ }
+
+ res->start = GET_64BIT(ranges, 1);
+ res->end = res->start + size - 1;
+ res->flags = flags;
+
+ /* Another way to implement this would be to add an of_device
+ * layer routine that can calculate a resource for a given
+ * range property value in a PCI device.
+ */
+ pci_resource_adjust(res, root);
+ }
+simba_cont:
+ sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
+ bus->number);
+ printk(" bus name: %s\n", bus->name);
+
+ pci_of_scan_bus(pbm, node, bus);
+}
+
+static void __init pci_of_scan_bus(struct pci_pbm_info *pbm,
+ struct device_node *node,
+ struct pci_bus *bus)
+{
+ struct device_node *child;
+ const u32 *reg;
+ int reglen, devfn;
+ struct pci_dev *dev;
+
+ printk("PCI: scan_bus[%s] bus no %d\n",
+ node->full_name, bus->number);
+
+ child = NULL;
+ while ((child = of_get_next_child(node, child)) != NULL) {
+ printk(" * %s\n", child->full_name);
+ reg = of_get_property(child, "reg", &reglen);
+ if (reg == NULL || reglen < 20)
+ continue;
+ devfn = (reg[0] >> 8) & 0xff;
+
+ /* create a new pci_dev for this device */
+ dev = of_create_pci_dev(pbm, child, bus, devfn, 0);
+ if (!dev)
+ continue;
+ printk("PCI: dev header type: %x\n", dev->hdr_type);
+
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+ dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+ of_scan_pci_bridge(pbm, child, dev);
+ }
+}
+
+static ssize_t
+show_pciobppath_attr(struct device * dev, struct device_attribute * attr, char * buf)
+{
+ struct pci_dev *pdev;
+ struct device_node *dp;
+
+ pdev = to_pci_dev(dev);
+ dp = pdev->dev.archdata.prom_node;
+
+ return snprintf (buf, PAGE_SIZE, "%s\n", dp->full_name);
+}
+
+static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_pciobppath_attr, NULL);
+
+static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+ struct pci_bus *child_bus;
+ int err;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ /* we don't really care if we can create this file or
+ * not, but we need to assign the result of the call
+ * or the world will fall under alien invasion and
+ * everybody will be frozen on a spaceship ready to be
+ * eaten on alpha centauri by some green and jelly
+ * humanoid.
+ */
+ err = sysfs_create_file(&dev->dev.kobj, &dev_attr_obppath.attr);
+ }
+ list_for_each_entry(child_bus, &bus->children, node)
+ pci_bus_register_of_sysfs(child_bus);
+}
+
+int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev,
+ unsigned int devfn,
+ int where, int size,
+ u32 *value)
+{
+ static u8 fake_pci_config[] = {
+ 0x8e, 0x10, /* Vendor: 0x108e (Sun) */
+ 0x00, 0x80, /* Device: 0x8000 (PBM) */
+ 0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */
+ 0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */
+ 0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */
+ 0x00, /* Cacheline: 0x00 */
+ 0x40, /* Latency: 0x40 */
+ 0x00, /* Header-Type: 0x00 normal */
+ };
+
+ *value = 0;
+ if (where >= 0 && where < sizeof(fake_pci_config) &&
+ (where + size) >= 0 &&
+ (where + size) < sizeof(fake_pci_config) &&
+ size <= sizeof(u32)) {
+ while (size--) {
+ *value <<= 8;
+ *value |= fake_pci_config[where + size];
+ }
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
+ unsigned int devfn,
+ int where, int size,
+ u32 value)
+{
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm)
+{
+ struct pci_controller_info *p = pbm->parent;
+ struct device_node *node = pbm->prom_node;
+ struct pci_dev *host_pdev;
+ struct pci_bus *bus;
+
+ printk("PCI: Scanning PBM %s\n", node->full_name);
+
+ /* XXX parent device? XXX */
+ bus = pci_create_bus(NULL, pbm->pci_first_busno, p->pci_ops, pbm);
+ if (!bus) {
+ printk(KERN_ERR "Failed to create bus for %s\n",
+ node->full_name);
+ return NULL;
+ }
+ bus->secondary = pbm->pci_first_busno;
+ bus->subordinate = pbm->pci_last_busno;
+
+ bus->resource[0] = &pbm->io_space;
+ bus->resource[1] = &pbm->mem_space;
+
+ /* Create the dummy host bridge and link it in. */
+ host_pdev = of_create_pci_dev(pbm, node, bus, 0x00, 1);
+ bus->self = host_pdev;
+
+ pci_of_scan_bus(pbm, node, bus);
+ pci_bus_add_devices(bus);
+ pci_bus_register_of_sysfs(bus);
+
+ return bus;
+}
+
static void __init pci_scan_each_controller_bus(void)
{
struct pci_controller_info *p;
@@ -360,8 +826,33 @@ void pcibios_align_resource(void *data, struct resource *res,
{
}
-int pcibios_enable_device(struct pci_dev *pdev, int mask)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
{
+ u16 cmd, oldcmd;
+ int i;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ oldcmd = cmd;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *res = &dev->resource[i];
+
+ /* Only set up the requested stuff */
+ if (!(mask & (1<<i)))
+ continue;
+
+ if (res->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (res->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+
+ if (cmd != oldcmd) {
+ printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n",
+ pci_name(dev), cmd);
+ /* Enable the appropriate bits in the PCI command register. */
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
return 0;
}
@@ -380,7 +871,7 @@ void pcibios_resource_to_bus(struct pci_dev *pdev, struct pci_bus_region *region
else
root = &pbm->mem_space;
- pbm->parent->resource_adjust(pdev, &zero_res, root);
+ pci_resource_adjust(&zero_res, root);
region->start = res->start - zero_res.start;
region->end = res->end - zero_res.start;
@@ -401,7 +892,7 @@ void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res,
else
root = &pbm->mem_space;
- pbm->parent->resource_adjust(pdev, res, root);
+ pci_resource_adjust(res, root);
}
EXPORT_SYMBOL(pcibios_bus_to_resource);
@@ -422,55 +913,17 @@ char * __devinit pcibios_setup(char *str)
static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state)
{
- struct pcidev_cookie *pcp = pdev->sysdata;
- struct pci_pbm_info *pbm;
+ struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
struct pci_controller_info *p;
unsigned long space_size, user_offset, user_size;
- if (!pcp)
- return -ENXIO;
- pbm = pcp->pbm;
- if (!pbm)
- return -ENXIO;
-
p = pbm->parent;
- if (p->pbms_same_domain) {
- unsigned long lowest, highest;
-
- lowest = ~0UL; highest = 0UL;
- if (mmap_state == pci_mmap_io) {
- if (p->pbm_A.io_space.flags) {
- lowest = p->pbm_A.io_space.start;
- highest = p->pbm_A.io_space.end + 1;
- }
- if (p->pbm_B.io_space.flags) {
- if (lowest > p->pbm_B.io_space.start)
- lowest = p->pbm_B.io_space.start;
- if (highest < p->pbm_B.io_space.end + 1)
- highest = p->pbm_B.io_space.end + 1;
- }
- space_size = highest - lowest;
- } else {
- if (p->pbm_A.mem_space.flags) {
- lowest = p->pbm_A.mem_space.start;
- highest = p->pbm_A.mem_space.end + 1;
- }
- if (p->pbm_B.mem_space.flags) {
- if (lowest > p->pbm_B.mem_space.start)
- lowest = p->pbm_B.mem_space.start;
- if (highest < p->pbm_B.mem_space.end + 1)
- highest = p->pbm_B.mem_space.end + 1;
- }
- space_size = highest - lowest;
- }
+ if (mmap_state == pci_mmap_io) {
+ space_size = (pbm->io_space.end -
+ pbm->io_space.start) + 1;
} else {
- if (mmap_state == pci_mmap_io) {
- space_size = (pbm->io_space.end -
- pbm->io_space.start) + 1;
- } else {
- space_size = (pbm->mem_space.end -
- pbm->mem_space.start) + 1;
- }
+ space_size = (pbm->mem_space.end -
+ pbm->mem_space.start) + 1;
}
/* Make sure the request is in range. */
@@ -481,31 +934,12 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc
(user_offset + user_size) > space_size)
return -EINVAL;
- if (p->pbms_same_domain) {
- unsigned long lowest = ~0UL;
-
- if (mmap_state == pci_mmap_io) {
- if (p->pbm_A.io_space.flags)
- lowest = p->pbm_A.io_space.start;
- if (p->pbm_B.io_space.flags &&
- lowest > p->pbm_B.io_space.start)
- lowest = p->pbm_B.io_space.start;
- } else {
- if (p->pbm_A.mem_space.flags)
- lowest = p->pbm_A.mem_space.start;
- if (p->pbm_B.mem_space.flags &&
- lowest > p->pbm_B.mem_space.start)
- lowest = p->pbm_B.mem_space.start;
- }
- vma->vm_pgoff = (lowest + user_offset) >> PAGE_SHIFT;
+ if (mmap_state == pci_mmap_io) {
+ vma->vm_pgoff = (pbm->io_space.start +
+ user_offset) >> PAGE_SHIFT;
} else {
- if (mmap_state == pci_mmap_io) {
- vma->vm_pgoff = (pbm->io_space.start +
- user_offset) >> PAGE_SHIFT;
- } else {
- vma->vm_pgoff = (pbm->mem_space.start +
- user_offset) >> PAGE_SHIFT;
- }
+ vma->vm_pgoff = (pbm->mem_space.start +
+ user_offset) >> PAGE_SHIFT;
}
return 0;
@@ -639,9 +1073,8 @@ int pci_domain_nr(struct pci_bus *pbus)
struct pci_controller_info *p = pbm->parent;
ret = p->index;
- if (p->pbms_same_domain == 0)
- ret = ((ret << 1) +
- ((pbm == &pbm->parent->pbm_B) ? 1 : 0));
+ ret = ((ret << 1) +
+ ((pbm == &pbm->parent->pbm_B) ? 1 : 0));
}
return ret;
@@ -651,8 +1084,7 @@ EXPORT_SYMBOL(pci_domain_nr);
#ifdef CONFIG_PCI_MSI
int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
{
- struct pcidev_cookie *pcp = pdev->sysdata;
- struct pci_pbm_info *pbm = pcp->pbm;
+ struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
struct pci_controller_info *p = pbm->parent;
int virt_irq, err;
@@ -670,8 +1102,7 @@ void arch_teardown_msi_irq(unsigned int virt_irq)
{
struct msi_desc *entry = get_irq_msi(virt_irq);
struct pci_dev *pdev = entry->dev;
- struct pcidev_cookie *pcp = pdev->sysdata;
- struct pci_pbm_info *pbm = pcp->pbm;
+ struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
struct pci_controller_info *p = pbm->parent;
if (!pbm->msi_num || !p->setup_msi_irq)
@@ -683,9 +1114,7 @@ void arch_teardown_msi_irq(unsigned int virt_irq)
struct device_node *pci_device_to_OF_node(struct pci_dev *pdev)
{
- struct pcidev_cookie *pc = pdev->sysdata;
-
- return pc->op->node;
+ return pdev->dev.archdata.prom_node;
}
EXPORT_SYMBOL(pci_device_to_OF_node);
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 5a92cb90ebe..1e6aeedf43c 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -1,7 +1,6 @@
-/* $Id: pci_common.c,v 1.29 2002/02/01 00:56:03 davem Exp $
- * pci_common.c: PCI controller common support.
+/* pci_common.c: PCI controller common support.
*
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
*/
#include <linux/string.h>
@@ -16,748 +15,137 @@
#include "pci_impl.h"
-/* Fix self device of BUS and hook it into BUS->self.
- * The pci_scan_bus does not do this for the host bridge.
- */
-void __init pci_fixup_host_bridge_self(struct pci_bus *pbus)
-{
- struct pci_dev *pdev;
-
- list_for_each_entry(pdev, &pbus->devices, bus_list) {
- if (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) {
- pbus->self = pdev;
- return;
- }
- }
-
- prom_printf("PCI: Critical error, cannot find host bridge PDEV.\n");
- prom_halt();
-}
-
-/* Find the OBP PROM device tree node for a PCI device. */
-static struct device_node * __init
-find_device_prom_node(struct pci_pbm_info *pbm, struct pci_dev *pdev,
- struct device_node *bus_node,
- struct linux_prom_pci_registers **pregs,
- int *nregs)
+static void pci_register_legacy_regions(struct resource *io_res,
+ struct resource *mem_res)
{
- struct device_node *dp;
-
- *nregs = 0;
-
- /*
- * Return the PBM's PROM node in case we are it's PCI device,
- * as the PBM's reg property is different to standard PCI reg
- * properties. We would delete this device entry otherwise,
- * which confuses XFree86's device probing...
- */
- if ((pdev->bus->number == pbm->pci_bus->number) && (pdev->devfn == 0) &&
- (pdev->vendor == PCI_VENDOR_ID_SUN) &&
- (pdev->device == PCI_DEVICE_ID_SUN_PBM ||
- pdev->device == PCI_DEVICE_ID_SUN_SCHIZO ||
- pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO ||
- pdev->device == PCI_DEVICE_ID_SUN_SABRE ||
- pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD))
- return bus_node;
-
- dp = bus_node->child;
- while (dp) {
- struct linux_prom_pci_registers *regs;
- struct property *prop;
- int len;
-
- prop = of_find_property(dp, "reg", &len);
- if (!prop)
- goto do_next_sibling;
-
- regs = prop->value;
- if (((regs[0].phys_hi >> 8) & 0xff) == pdev->devfn) {
- *pregs = regs;
- *nregs = len / sizeof(struct linux_prom_pci_registers);
- return dp;
- }
-
- do_next_sibling:
- dp = dp->sibling;
- }
-
- return NULL;
-}
+ struct resource *p;
-/* Older versions of OBP on PCI systems encode 64-bit MEM
- * space assignments incorrectly, this fixes them up. We also
- * take the opportunity here to hide other kinds of bogus
- * assignments.
- */
-static void __init fixup_obp_assignments(struct pci_dev *pdev,
- struct pcidev_cookie *pcp)
-{
- int i;
-
- if (pdev->vendor == PCI_VENDOR_ID_AL &&
- (pdev->device == PCI_DEVICE_ID_AL_M7101 ||
- pdev->device == PCI_DEVICE_ID_AL_M1533)) {
- int i;
-
- /* Zap all of the normal resources, they are
- * meaningless and generate bogus resource collision
- * messages. This is OpenBoot's ill-fated attempt to
- * represent the implicit resources that these devices
- * have.
- */
- pcp->num_prom_assignments = 0;
- for (i = 0; i < 6; i++) {
- pdev->resource[i].start =
- pdev->resource[i].end =
- pdev->resource[i].flags = 0;
- }
- pdev->resource[PCI_ROM_RESOURCE].start =
- pdev->resource[PCI_ROM_RESOURCE].end =
- pdev->resource[PCI_ROM_RESOURCE].flags = 0;
+ /* VGA Video RAM. */
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
return;
- }
-
- for (i = 0; i < pcp->num_prom_assignments; i++) {
- struct linux_prom_pci_registers *ap;
- int space;
- ap = &pcp->prom_assignments[i];
- space = ap->phys_hi >> 24;
- if ((space & 0x3) == 2 &&
- (space & 0x4) != 0) {
- ap->phys_hi &= ~(0x7 << 24);
- ap->phys_hi |= 0x3 << 24;
- }
- }
-}
-
-static ssize_t
-show_pciobppath_attr(struct device * dev, struct device_attribute * attr, char * buf)
-{
- struct pci_dev *pdev;
- struct pcidev_cookie *sysdata;
-
- pdev = to_pci_dev(dev);
- sysdata = pdev->sysdata;
-
- return snprintf (buf, PAGE_SIZE, "%s\n", sysdata->prom_node->full_name);
-}
-
-static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_pciobppath_attr, NULL);
+ p->name = "Video RAM area";
+ p->start = mem_res->start + 0xa0000UL;
+ p->end = p->start + 0x1ffffUL;
+ p->flags = IORESOURCE_BUSY;
+ request_resource(mem_res, p);
-/* Fill in the PCI device cookie sysdata for the given
- * PCI device. This cookie is the means by which one
- * can get to OBP and PCI controller specific information
- * for a PCI device.
- */
-static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
- struct pci_dev *pdev,
- struct device_node *bus_node)
-{
- struct linux_prom_pci_registers *pregs = NULL;
- struct pcidev_cookie *pcp;
- struct device_node *dp;
- struct property *prop;
- int nregs, len, err;
-
- dp = find_device_prom_node(pbm, pdev, bus_node,
- &pregs, &nregs);
- if (!dp) {
- /* If it is not in the OBP device tree then
- * there must be a damn good reason for it.
- *
- * So what we do is delete the device from the
- * PCI device tree completely. This scenario
- * is seen, for example, on CP1500 for the
- * second EBUS/HappyMeal pair if the external
- * connector for it is not present.
- */
- pci_remove_bus_device(pdev);
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
return;
- }
-
- pcp = kzalloc(sizeof(*pcp), GFP_ATOMIC);
- if (pcp == NULL) {
- prom_printf("PCI_COOKIE: Fatal malloc error, aborting...\n");
- prom_halt();
- }
- pcp->pbm = pbm;
- pcp->prom_node = dp;
- pcp->op = of_find_device_by_node(dp);
- memcpy(pcp->prom_regs, pregs,
- nregs * sizeof(struct linux_prom_pci_registers));
- pcp->num_prom_regs = nregs;
-
- /* We can't have the pcidev_cookie assignments be just
- * direct pointers into the property value, since they
- * are potentially modified by the probing process.
- */
- prop = of_find_property(dp, "assigned-addresses", &len);
- if (!prop) {
- pcp->num_prom_assignments = 0;
- } else {
- memcpy(pcp->prom_assignments, prop->value, len);
- pcp->num_prom_assignments =
- (len / sizeof(pcp->prom_assignments[0]));
- }
-
- if (strcmp(dp->name, "ebus") == 0) {
- struct linux_prom_ebus_ranges *erng;
- int iter;
-
- /* EBUS is special... */
- prop = of_find_property(dp, "ranges", &len);
- if (!prop) {
- prom_printf("EBUS: Fatal error, no range property\n");
- prom_halt();
- }
- erng = prop->value;
- len = (len / sizeof(erng[0]));
- for (iter = 0; iter < len; iter++) {
- struct linux_prom_ebus_ranges *ep = &erng[iter];
- struct linux_prom_pci_registers *ap;
-
- ap = &pcp->prom_assignments[iter];
-
- ap->phys_hi = ep->parent_phys_hi;
- ap->phys_mid = ep->parent_phys_mid;
- ap->phys_lo = ep->parent_phys_lo;
- ap->size_hi = 0;
- ap->size_lo = ep->size;
- }
- pcp->num_prom_assignments = len;
- }
-
- fixup_obp_assignments(pdev, pcp);
-
- pdev->sysdata = pcp;
-
- /* we don't really care if we can create this file or not,
- * but we need to assign the result of the call or the world will fall
- * under alien invasion and everybody will be frozen on a spaceship
- * ready to be eaten on alpha centauri by some green and jelly humanoid.
- */
- err = sysfs_create_file(&pdev->dev.kobj, &dev_attr_obppath.attr);
-}
-
-void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus,
- struct pci_pbm_info *pbm,
- struct device_node *dp)
-{
- struct pci_dev *pdev, *pdev_next;
- struct pci_bus *this_pbus, *pbus_next;
-
- /* This must be _safe because the cookie fillin
- routine can delete devices from the tree. */
- list_for_each_entry_safe(pdev, pdev_next, &pbus->devices, bus_list)
- pdev_cookie_fillin(pbm, pdev, dp);
-
- list_for_each_entry_safe(this_pbus, pbus_next, &pbus->children, node) {
- struct pcidev_cookie *pcp = this_pbus->self->sysdata;
-
- pci_fill_in_pbm_cookies(this_pbus, pbm, pcp->prom_node);
- }
-}
-static void __init bad_assignment(struct pci_dev *pdev,
- struct linux_prom_pci_registers *ap,
- struct resource *res,
- int do_prom_halt)
-{
- prom_printf("PCI: Bogus PROM assignment. BUS[%02x] DEVFN[%x]\n",
- pdev->bus->number, pdev->devfn);
- if (ap)
- prom_printf("PCI: phys[%08x:%08x:%08x] size[%08x:%08x]\n",
- ap->phys_hi, ap->phys_mid, ap->phys_lo,
- ap->size_hi, ap->size_lo);
- if (res)
- prom_printf("PCI: RES[%016lx-->%016lx:(%lx)]\n",
- res->start, res->end, res->flags);
- if (do_prom_halt)
- prom_halt();
-}
-
-static struct resource *
-__init get_root_resource(struct linux_prom_pci_registers *ap,
- struct pci_pbm_info *pbm)
-{
- int space = (ap->phys_hi >> 24) & 3;
-
- switch (space) {
- case 0:
- /* Configuration space, silently ignore it. */
- return NULL;
-
- case 1:
- /* 16-bit IO space */
- return &pbm->io_space;
-
- case 2:
- /* 32-bit MEM space */
- return &pbm->mem_space;
-
- case 3:
- /* 64-bit MEM space, these are allocated out of
- * the 32-bit mem_space range for the PBM, ie.
- * we just zero out the upper 32-bits.
- */
- return &pbm->mem_space;
-
- default:
- printk("PCI: What is resource space %x?\n", space);
- return NULL;
- };
-}
-
-static struct resource *
-__init get_device_resource(struct linux_prom_pci_registers *ap,
- struct pci_dev *pdev)
-{
- struct resource *res;
- int breg = (ap->phys_hi & 0xff);
-
- switch (breg) {
- case PCI_ROM_ADDRESS:
- /* Unfortunately I have seen several cases where
- * buggy FCODE uses a space value of '1' (I/O space)
- * in the register property for the ROM address
- * so disable this sanity check for now.
- */
-#if 0
- {
- int space = (ap->phys_hi >> 24) & 3;
-
- /* It had better be MEM space. */
- if (space != 2)
- bad_assignment(pdev, ap, NULL, 0);
- }
-#endif
- res = &pdev->resource[PCI_ROM_RESOURCE];
- break;
-
- case PCI_BASE_ADDRESS_0:
- case PCI_BASE_ADDRESS_1:
- case PCI_BASE_ADDRESS_2:
- case PCI_BASE_ADDRESS_3:
- case PCI_BASE_ADDRESS_4:
- case PCI_BASE_ADDRESS_5:
- res = &pdev->resource[(breg - PCI_BASE_ADDRESS_0) / 4];
- break;
-
- default:
- bad_assignment(pdev, ap, NULL, 0);
- res = NULL;
- break;
- };
-
- return res;
-}
-
-static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
- struct pci_dev *pdev)
-{
- struct pcidev_cookie *pcp = pdev->sysdata;
- int i;
-
- for (i = 0; i < pcp->num_prom_assignments; i++) {
- struct linux_prom_pci_registers *ap;
- struct resource *root, *res;
-
- /* The format of this property is specified in
- * the PCI Bus Binding to IEEE1275-1994.
- */
- ap = &pcp->prom_assignments[i];
- root = get_root_resource(ap, pbm);
- res = get_device_resource(ap, pdev);
- if (root == NULL || res == NULL ||
- res->flags == 0)
- continue;
-
- /* Ok we know which resource this PROM assignment is
- * for, sanity check it.
- */
- if ((res->start & 0xffffffffUL) != ap->phys_lo)
- bad_assignment(pdev, ap, res, 1);
-
- /* If it is a 64-bit MEM space assignment, verify that
- * the resource is too and that the upper 32-bits match.
- */
- if (((ap->phys_hi >> 24) & 3) == 3) {
- if (((res->flags & IORESOURCE_MEM) == 0) ||
- ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
- != PCI_BASE_ADDRESS_MEM_TYPE_64))
- bad_assignment(pdev, ap, res, 1);
- if ((res->start >> 32) != ap->phys_mid)
- bad_assignment(pdev, ap, res, 1);
-
- /* PBM cannot generate cpu initiated PIOs
- * to the full 64-bit space. Therefore the
- * upper 32-bits better be zero. If it is
- * not, just skip it and we will assign it
- * properly ourselves.
- */
- if ((res->start >> 32) != 0UL) {
- printk(KERN_ERR "PCI: OBP assigns out of range MEM address "
- "%016lx for region %ld on device %s\n",
- res->start, (res - &pdev->resource[0]), pci_name(pdev));
- continue;
- }
- }
-
- /* Adjust the resource into the physical address space
- * of this PBM.
- */
- pbm->parent->resource_adjust(pdev, res, root);
-
- if (request_resource(root, res) < 0) {
- int rnum;
-
- /* OK, there is some conflict. But this is fine
- * since we'll reassign it in the fixup pass.
- *
- * Do not print the warning for ROM resources
- * as such a conflict is quite common and
- * harmless as the ROM bar is disabled.
- */
- rnum = (res - &pdev->resource[0]);
- if (rnum != PCI_ROM_RESOURCE)
- printk(KERN_ERR "PCI: Resource collision, "
- "region %d "
- "[%016lx:%016lx] of device %s\n",
- rnum,
- res->start, res->end,
- pci_name(pdev));
- }
- }
-}
-
-void __init pci_record_assignments(struct pci_pbm_info *pbm,
- struct pci_bus *pbus)
-{
- struct pci_dev *dev;
- struct pci_bus *bus;
+ p->name = "System ROM";
+ p->start = mem_res->start + 0xf0000UL;
+ p->end = p->start + 0xffffUL;
+ p->flags = IORESOURCE_BUSY;
+ request_resource(mem_res, p);
- list_for_each_entry(dev, &pbus->devices, bus_list)
- pdev_record_assignments(pbm, dev);
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return;
- list_for_each_entry(bus, &pbus->children, node)
- pci_record_assignments(pbm, bus);
+ p->name = "Video ROM";
+ p->start = mem_res->start + 0xc0000UL;
+ p->end = p->start + 0x7fffUL;
+ p->flags = IORESOURCE_BUSY;
+ request_resource(mem_res, p);
}
-/* Return non-zero if PDEV has implicit I/O resources even
- * though it may not have an I/O base address register
- * active.
- */
-static int __init has_implicit_io(struct pci_dev *pdev)
+static void pci_register_iommu_region(struct pci_pbm_info *pbm)
{
- int class = pdev->class >> 8;
+ const u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL);
- if (class == PCI_CLASS_NOT_DEFINED ||
- class == PCI_CLASS_NOT_DEFINED_VGA ||
- class == PCI_CLASS_STORAGE_IDE ||
- (pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
- return 1;
+ if (vdma) {
+ struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL);
- return 0;
-}
-
-static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm,
- struct pci_dev *pdev)
-{
- u32 reg;
- u16 cmd;
- int i, io_seen, mem_seen;
-
- io_seen = mem_seen = 0;
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct resource *root, *res;
- unsigned long size, min, max, align;
-
- res = &pdev->resource[i];
-
- if (res->flags & IORESOURCE_IO)
- io_seen++;
- else if (res->flags & IORESOURCE_MEM)
- mem_seen++;
-
- /* If it is already assigned or the resource does
- * not exist, there is nothing to do.
- */
- if (res->parent != NULL || res->flags == 0UL)
- continue;
-
- /* Determine the root we allocate from. */
- if (res->flags & IORESOURCE_IO) {
- root = &pbm->io_space;
- min = root->start + 0x400UL;
- max = root->end;
- } else {
- root = &pbm->mem_space;
- min = root->start;
- max = min + 0x80000000UL;
- }
-
- size = res->end - res->start;
- align = size + 1;
- if (allocate_resource(root, res, size + 1, min, max, align, NULL, NULL) < 0) {
- /* uh oh */
- prom_printf("PCI: Failed to allocate resource %d for %s\n",
- i, pci_name(pdev));
+ if (!rp) {
+ prom_printf("Cannot allocate IOMMU resource.\n");
prom_halt();
}
-
- /* Update PCI config space. */
- pbm->parent->base_address_update(pdev, i);
- }
-
- /* Special case, disable the ROM. Several devices
- * act funny (ie. do not respond to memory space writes)
- * when it is left enabled. A good example are Qlogic,ISP
- * adapters.
- */
- pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &reg);
- reg &= ~PCI_ROM_ADDRESS_ENABLE;
- pci_write_config_dword(pdev, PCI_ROM_ADDRESS, reg);
-
- /* If we saw I/O or MEM resources, enable appropriate
- * bits in PCI command register.
- */
- if (io_seen || mem_seen) {
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- if (io_seen || has_implicit_io(pdev))
- cmd |= PCI_COMMAND_IO;
- if (mem_seen)
- cmd |= PCI_COMMAND_MEMORY;
- pci_write_config_word(pdev, PCI_COMMAND, cmd);
- }
-
- /* If this is a PCI bridge or an IDE controller,
- * enable bus mastering. In the former case also
- * set the cache line size correctly.
- */
- if (((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) ||
- (((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) &&
- ((pdev->class & 0x80) != 0))) {
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- cmd |= PCI_COMMAND_MASTER;
- pci_write_config_word(pdev, PCI_COMMAND, cmd);
-
- if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
- pci_write_config_byte(pdev,
- PCI_CACHE_LINE_SIZE,
- (64 / sizeof(u32)));
+ rp->name = "IOMMU";
+ rp->start = pbm->mem_space.start + (unsigned long) vdma[0];
+ rp->end = rp->start + (unsigned long) vdma[1] - 1UL;
+ rp->flags = IORESOURCE_BUSY;
+ request_resource(&pbm->mem_space, rp);
}
}
-void __init pci_assign_unassigned(struct pci_pbm_info *pbm,
- struct pci_bus *pbus)
+void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
{
- struct pci_dev *dev;
- struct pci_bus *bus;
-
- list_for_each_entry(dev, &pbus->devices, bus_list)
- pdev_assign_unassigned(pbm, dev);
+ const struct linux_prom_pci_ranges *pbm_ranges;
+ int i, saw_mem, saw_io;
+ int num_pbm_ranges;
- list_for_each_entry(bus, &pbus->children, node)
- pci_assign_unassigned(pbm, bus);
-}
+ saw_mem = saw_io = 0;
+ pbm_ranges = of_get_property(pbm->prom_node, "ranges", &i);
+ num_pbm_ranges = i / sizeof(*pbm_ranges);
-static void __init pdev_fixup_irq(struct pci_dev *pdev)
-{
- struct pcidev_cookie *pcp = pdev->sysdata;
- struct of_device *op = pcp->op;
+ for (i = 0; i < num_pbm_ranges; i++) {
+ const struct linux_prom_pci_ranges *pr = &pbm_ranges[i];
+ unsigned long a;
+ u32 parent_phys_hi, parent_phys_lo;
+ int type;
- if (op->irqs[0] == 0xffffffff) {
- pdev->irq = PCI_IRQ_NONE;
- return;
- }
+ parent_phys_hi = pr->parent_phys_hi;
+ parent_phys_lo = pr->parent_phys_lo;
+ if (tlb_type == hypervisor)
+ parent_phys_hi &= 0x0fffffff;
- pdev->irq = op->irqs[0];
+ type = (pr->child_phys_hi >> 24) & 0x3;
+ a = (((unsigned long)parent_phys_hi << 32UL) |
+ ((unsigned long)parent_phys_lo << 0UL));
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
- pdev->irq & PCI_IRQ_INO);
-}
-
-void __init pci_fixup_irq(struct pci_pbm_info *pbm,
- struct pci_bus *pbus)
-{
- struct pci_dev *dev;
- struct pci_bus *bus;
-
- list_for_each_entry(dev, &pbus->devices, bus_list)
- pdev_fixup_irq(dev);
-
- list_for_each_entry(bus, &pbus->children, node)
- pci_fixup_irq(pbm, bus);
-}
-
-static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz)
-{
- u16 cmd;
- u8 hdr_type, min_gnt, ltimer;
-
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- cmd |= PCI_COMMAND_MASTER;
- pci_write_config_word(pdev, PCI_COMMAND, cmd);
-
- /* Read it back, if the mastering bit did not
- * get set, the device does not support bus
- * mastering so we have nothing to do here.
- */
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- if ((cmd & PCI_COMMAND_MASTER) == 0)
- return;
-
- /* Set correct cache line size, 64-byte on all
- * Sparc64 PCI systems. Note that the value is
- * measured in 32-bit words.
- */
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
- 64 / sizeof(u32));
-
- pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr_type);
- hdr_type &= ~0x80;
- if (hdr_type != PCI_HEADER_TYPE_NORMAL)
- return;
-
- /* If the latency timer is already programmed with a non-zero
- * value, assume whoever set it (OBP or whoever) knows what
- * they are doing.
- */
- pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &ltimer);
- if (ltimer != 0)
- return;
-
- /* XXX Since I'm tipping off the min grant value to
- * XXX choose a suitable latency timer value, I also
- * XXX considered making use of the max latency value
- * XXX as well. Unfortunately I've seen too many bogusly
- * XXX low settings for it to the point where it lacks
- * XXX any usefulness. In one case, an ethernet card
- * XXX claimed a min grant of 10 and a max latency of 5.
- * XXX Now, if I had two such cards on the same bus I
- * XXX could not set the desired burst period (calculated
- * XXX from min grant) without violating the max latency
- * XXX bound. Duh...
- * XXX
- * XXX I blame dumb PC bios implementors for stuff like
- * XXX this, most of them don't even try to do something
- * XXX sensible with latency timer values and just set some
- * XXX default value (usually 32) into every device.
- */
-
- pci_read_config_byte(pdev, PCI_MIN_GNT, &min_gnt);
-
- if (min_gnt == 0) {
- /* If no min_gnt setting then use a default
- * value.
- */
- if (is_66mhz)
- ltimer = 16;
- else
- ltimer = 32;
- } else {
- int shift_factor;
-
- if (is_66mhz)
- shift_factor = 2;
- else
- shift_factor = 3;
-
- /* Use a default value when the min_gnt value
- * is erroneously high.
- */
- if (((unsigned int) min_gnt << shift_factor) > 512 ||
- ((min_gnt << shift_factor) & 0xff) == 0) {
- ltimer = 8 << shift_factor;
- } else {
- ltimer = min_gnt << shift_factor;
- }
- }
+ switch (type) {
+ case 0:
+ /* PCI config space, 16MB */
+ pbm->config_space = a;
+ break;
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ltimer);
-}
+ case 1:
+ /* 16-bit IO space, 16MB */
+ pbm->io_space.start = a;
+ pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL);
+ pbm->io_space.flags = IORESOURCE_IO;
+ saw_io = 1;
+ break;
-void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
- struct pci_bus *pbus)
-{
- struct pci_dev *pdev;
- int all_are_66mhz;
- u16 status;
+ case 2:
+ /* 32-bit MEM space, 2GB */
+ pbm->mem_space.start = a;
+ pbm->mem_space.end = a + (0x80000000UL - 1UL);
+ pbm->mem_space.flags = IORESOURCE_MEM;
+ saw_mem = 1;
+ break;
- if (pbm->is_66mhz_capable == 0) {
- all_are_66mhz = 0;
- goto out;
- }
+ case 3:
+ /* XXX 64-bit MEM handling XXX */
- all_are_66mhz = 1;
- list_for_each_entry(pdev, &pbus->devices, bus_list) {
- pci_read_config_word(pdev, PCI_STATUS, &status);
- if (!(status & PCI_STATUS_66MHZ)) {
- all_are_66mhz = 0;
+ default:
break;
- }
+ };
}
-out:
- pbm->all_devs_66mhz = all_are_66mhz;
-
- printk("PCI%d(PBM%c): Bus running at %dMHz\n",
- pbm->parent->index,
- (pbm == &pbm->parent->pbm_A) ? 'A' : 'B',
- (all_are_66mhz ? 66 : 33));
-}
-
-void pci_setup_busmastering(struct pci_pbm_info *pbm,
- struct pci_bus *pbus)
-{
- struct pci_dev *dev;
- struct pci_bus *bus;
- int is_66mhz;
-
- is_66mhz = pbm->is_66mhz_capable && pbm->all_devs_66mhz;
-
- list_for_each_entry(dev, &pbus->devices, bus_list)
- pdev_setup_busmastering(dev, is_66mhz);
-
- list_for_each_entry(bus, &pbus->children, node)
- pci_setup_busmastering(pbm, bus);
-}
-
-void pci_register_legacy_regions(struct resource *io_res,
- struct resource *mem_res)
-{
- struct resource *p;
-
- /* VGA Video RAM. */
- p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (!p)
- return;
- p->name = "Video RAM area";
- p->start = mem_res->start + 0xa0000UL;
- p->end = p->start + 0x1ffffUL;
- p->flags = IORESOURCE_BUSY;
- request_resource(mem_res, p);
+ if (!saw_io || !saw_mem) {
+ prom_printf("%s: Fatal error, missing %s PBM range.\n",
+ pbm->name,
+ (!saw_io ? "IO" : "MEM"));
+ prom_halt();
+ }
- p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (!p)
- return;
+ printk("%s: PCI IO[%lx] MEM[%lx]\n",
+ pbm->name,
+ pbm->io_space.start,
+ pbm->mem_space.start);
- p->name = "System ROM";
- p->start = mem_res->start + 0xf0000UL;
- p->end = p->start + 0xffffUL;
- p->flags = IORESOURCE_BUSY;
- request_resource(mem_res, p);
+ pbm->io_space.name = pbm->mem_space.name = pbm->name;
- p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (!p)
- return;
+ request_resource(&ioport_resource, &pbm->io_space);
+ request_resource(&iomem_resource, &pbm->mem_space);
- p->name = "Video ROM";
- p->start = mem_res->start + 0xc0000UL;
- p->end = p->start + 0x7fffUL;
- p->flags = IORESOURCE_BUSY;
- request_resource(mem_res, p);
+ pci_register_legacy_regions(&pbm->io_space,
+ &pbm->mem_space);
+ pci_register_iommu_region(pbm);
}
/* Generic helper routines for PCI error reporting. */
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index 971e2bea30b..1208583fcb8 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -1,7 +1,6 @@
-/* $Id: pci_impl.h,v 1.9 2001/06/13 06:34:30 davem Exp $
- * pci_impl.h: Helper definitions for PCI controller support.
+/* pci_impl.h: Helper definitions for PCI controller support.
*
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
*/
#ifndef PCI_IMPL_H
@@ -13,26 +12,22 @@
#include <asm/prom.h>
extern struct pci_controller_info *pci_controller_root;
+extern unsigned long pci_memspace_mask;
extern int pci_num_controllers;
/* PCI bus scanning and fixup support. */
-extern void pci_fixup_host_bridge_self(struct pci_bus *pbus);
-extern void pci_fill_in_pbm_cookies(struct pci_bus *pbus,
- struct pci_pbm_info *pbm,
- struct device_node *prom_node);
-extern void pci_record_assignments(struct pci_pbm_info *pbm,
- struct pci_bus *pbus);
-extern void pci_assign_unassigned(struct pci_pbm_info *pbm,
- struct pci_bus *pbus);
-extern void pci_fixup_irq(struct pci_pbm_info *pbm,
- struct pci_bus *pbus);
-extern void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
- struct pci_bus *pbus);
-extern void pci_setup_busmastering(struct pci_pbm_info *pbm,
- struct pci_bus *pbus);
-extern void pci_register_legacy_regions(struct resource *io_res,
- struct resource *mem_res);
+extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
+extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
+
+extern int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev,
+ unsigned int devfn,
+ int where, int size,
+ u32 *value);
+extern int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
+ unsigned int devfn,
+ int where, int size,
+ u32 value);
/* Error reporting support. */
extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
index 7aca0f33f88..66712772f49 100644
--- a/arch/sparc64/kernel/pci_iommu.c
+++ b/arch/sparc64/kernel/pci_iommu.c
@@ -1,7 +1,6 @@
-/* $Id: pci_iommu.c,v 1.17 2001/12/17 07:05:09 davem Exp $
- * pci_iommu.c: UltraSparc PCI controller IOM/STC support.
+/* pci_iommu.c: UltraSparc PCI controller IOM/STC support.
*
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
* Copyright (C) 1999, 2000 Jakub Jelinek (jakub@redhat.com)
*/
@@ -36,7 +35,7 @@
"i" (ASI_PHYS_BYPASS_EC_E))
/* Must be invoked under the IOMMU lock. */
-static void __iommu_flushall(struct pci_iommu *iommu)
+static void __iommu_flushall(struct iommu *iommu)
{
unsigned long tag;
int entry;
@@ -64,7 +63,7 @@ static void __iommu_flushall(struct pci_iommu *iommu)
#define IOPTE_IS_DUMMY(iommu, iopte) \
((iopte_val(*iopte) & IOPTE_PAGE) == (iommu)->dummy_page_pa)
-static inline void iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte)
+static inline void iopte_make_dummy(struct iommu *iommu, iopte_t *iopte)
{
unsigned long val = iopte_val(*iopte);
@@ -75,9 +74,9 @@ static inline void iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte)
}
/* Based largely upon the ppc64 iommu allocator. */
-static long pci_arena_alloc(struct pci_iommu *iommu, unsigned long npages)
+static long pci_arena_alloc(struct iommu *iommu, unsigned long npages)
{
- struct pci_iommu_arena *arena = &iommu->arena;
+ struct iommu_arena *arena = &iommu->arena;
unsigned long n, i, start, end, limit;
int pass;
@@ -116,7 +115,7 @@ again:
return n;
}
-static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages)
+static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages)
{
unsigned long i;
@@ -124,7 +123,7 @@ static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, un
__clear_bit(i, arena->map);
}
-void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask)
+void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask)
{
unsigned long i, tsbbase, order, sz, num_tsb_entries;
@@ -170,7 +169,7 @@ void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset,
iopte_make_dummy(iommu, &iommu->page_table[i]);
}
-static inline iopte_t *alloc_npages(struct pci_iommu *iommu, unsigned long npages)
+static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages)
{
long entry;
@@ -181,12 +180,12 @@ static inline iopte_t *alloc_npages(struct pci_iommu *iommu, unsigned long npage
return iommu->page_table + entry;
}
-static inline void free_npages(struct pci_iommu *iommu, dma_addr_t base, unsigned long npages)
+static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages)
{
pci_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages);
}
-static int iommu_alloc_ctx(struct pci_iommu *iommu)
+static int iommu_alloc_ctx(struct iommu *iommu)
{
int lowest = iommu->ctx_lowest_free;
int sz = IOMMU_NUM_CTXS - lowest;
@@ -205,7 +204,7 @@ static int iommu_alloc_ctx(struct pci_iommu *iommu)
return n;
}
-static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx)
+static inline void iommu_free_ctx(struct iommu *iommu, int ctx)
{
if (likely(ctx)) {
__clear_bit(ctx, iommu->ctx_bitmap);
@@ -220,8 +219,7 @@ static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx)
*/
static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
+ struct iommu *iommu;
iopte_t *iopte;
unsigned long flags, order, first_page;
void *ret;
@@ -237,8 +235,7 @@ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr
return NULL;
memset((char *)first_page, 0, PAGE_SIZE << order);
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
+ iommu = pdev->dev.archdata.iommu;
spin_lock_irqsave(&iommu->lock, flags);
iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT);
@@ -268,14 +265,12 @@ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr
/* Free and unmap a consistent DMA translation. */
static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
+ struct iommu *iommu;
iopte_t *iopte;
unsigned long flags, order, npages;
npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
+ iommu = pdev->dev.archdata.iommu;
iopte = iommu->page_table +
((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
@@ -295,18 +290,16 @@ static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu,
*/
static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
- struct pci_strbuf *strbuf;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
iopte_t *base;
unsigned long flags, npages, oaddr;
unsigned long i, base_paddr, ctx;
u32 bus_addr, ret;
unsigned long iopte_protection;
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- strbuf = &pcp->pbm->stc;
+ iommu = pdev->dev.archdata.iommu;
+ strbuf = pdev->dev.archdata.stc;
if (unlikely(direction == PCI_DMA_NONE))
goto bad_no_ctx;
@@ -349,7 +342,7 @@ bad_no_ctx:
return PCI_DMA_ERROR_CODE;
}
-static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction)
+static void pci_strbuf_flush(struct strbuf *strbuf, struct iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction)
{
int limit;
@@ -416,9 +409,8 @@ do_flush_sync:
/* Unmap a single streaming mode DMA translation. */
static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
- struct pci_strbuf *strbuf;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
iopte_t *base;
unsigned long flags, npages, ctx, i;
@@ -428,9 +420,8 @@ static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_
return;
}
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- strbuf = &pcp->pbm->stc;
+ iommu = pdev->dev.archdata.iommu;
+ strbuf = pdev->dev.archdata.stc;
npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
npages >>= IO_PAGE_SHIFT;
@@ -549,9 +540,8 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,
*/
static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
- struct pci_strbuf *strbuf;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
unsigned long flags, ctx, npages, iopte_protection;
iopte_t *base;
u32 dma_base;
@@ -570,9 +560,8 @@ static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n
return 1;
}
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- strbuf = &pcp->pbm->stc;
+ iommu = pdev->dev.archdata.iommu;
+ strbuf = pdev->dev.archdata.stc;
if (unlikely(direction == PCI_DMA_NONE))
goto bad_no_ctx;
@@ -636,9 +625,8 @@ bad_no_ctx:
/* Unmap a set of streaming mode DMA translations. */
static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
- struct pci_strbuf *strbuf;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
iopte_t *base;
unsigned long flags, ctx, i, npages;
u32 bus_addr;
@@ -648,9 +636,8 @@ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in
WARN_ON(1);
}
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- strbuf = &pcp->pbm->stc;
+ iommu = pdev->dev.archdata.iommu;
+ strbuf = pdev->dev.archdata.stc;
bus_addr = sglist->dma_address & IO_PAGE_MASK;
@@ -696,14 +683,12 @@ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in
*/
static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
- struct pci_strbuf *strbuf;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
unsigned long flags, ctx, npages;
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- strbuf = &pcp->pbm->stc;
+ iommu = pdev->dev.archdata.iommu;
+ strbuf = pdev->dev.archdata.stc;
if (!strbuf->strbuf_enabled)
return;
@@ -736,15 +721,13 @@ static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_
*/
static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
- struct pci_strbuf *strbuf;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
unsigned long flags, ctx, npages, i;
u32 bus_addr;
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- strbuf = &pcp->pbm->stc;
+ iommu = pdev->dev.archdata.iommu;
+ strbuf = pdev->dev.archdata.stc;
if (!strbuf->strbuf_enabled)
return;
@@ -775,7 +758,7 @@ static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist
spin_unlock_irqrestore(&iommu->lock, flags);
}
-struct pci_iommu_ops pci_sun4u_iommu_ops = {
+const struct pci_iommu_ops pci_sun4u_iommu_ops = {
.alloc_consistent = pci_4u_alloc_consistent,
.free_consistent = pci_4u_free_consistent,
.map_single = pci_4u_map_single,
@@ -809,13 +792,12 @@ static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
int pci_dma_supported(struct pci_dev *pdev, u64 device_mask)
{
- struct pcidev_cookie *pcp = pdev->sysdata;
u64 dma_addr_mask;
if (pdev == NULL) {
dma_addr_mask = 0xffffffff;
} else {
- struct pci_iommu *iommu = pcp->pbm->iommu;
+ struct iommu *iommu = pdev->dev.archdata.iommu;
dma_addr_mask = iommu->dma_addr_mask;
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index fda5db223d9..253d40ec224 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -1,7 +1,6 @@
-/* $Id: pci_psycho.c,v 1.33 2002/02/01 00:58:33 davem Exp $
- * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
+/* pci_psycho.c: PSYCHO/U2P specific PCI controller support.
*
- * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
+ * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net)
* Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
*/
@@ -119,6 +118,10 @@ static int psycho_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
u16 tmp16;
u8 tmp8;
+ if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+ size, value);
+
switch (size) {
case 1:
*value = 0xff;
@@ -172,6 +175,9 @@ static int psycho_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
unsigned char bus = bus_dev->number;
u32 *addr;
+ if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+ size, value);
addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
if (!addr)
return PCIBIOS_SUCCESSFUL;
@@ -263,7 +269,7 @@ static void __psycho_check_one_stc(struct pci_controller_info *p,
struct pci_pbm_info *pbm,
int is_pbm_a)
{
- struct pci_strbuf *strbuf = &pbm->stc;
+ struct strbuf *strbuf = &pbm->stc;
unsigned long regbase = p->pbm_A.controller_regs;
unsigned long err_base, tag_base, line_base;
u64 control;
@@ -412,7 +418,7 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
unsigned long afar,
enum psycho_error_type type)
{
- struct pci_iommu *iommu = p->pbm_A.iommu;
+ struct iommu *iommu = p->pbm_A.iommu;
unsigned long iommu_tag[16];
unsigned long iommu_data[16];
unsigned long flags;
@@ -895,59 +901,6 @@ static void psycho_register_error_handlers(struct pci_controller_info *p)
}
/* PSYCHO boot time probing and initialization. */
-static void psycho_resource_adjust(struct pci_dev *pdev,
- struct resource *res,
- struct resource *root)
-{
- res->start += root->start;
- res->end += root->start;
-}
-
-static void psycho_base_address_update(struct pci_dev *pdev, int resource)
-{
- struct pcidev_cookie *pcp = pdev->sysdata;
- struct pci_pbm_info *pbm = pcp->pbm;
- struct resource *res, *root;
- u32 reg;
- int where, size, is_64bit;
-
- res = &pdev->resource[resource];
- if (resource < 6) {
- where = PCI_BASE_ADDRESS_0 + (resource * 4);
- } else if (resource == PCI_ROM_RESOURCE) {
- where = pdev->rom_base_reg;
- } else {
- /* Somebody might have asked allocation of a non-standard resource */
- return;
- }
-
- is_64bit = 0;
- if (res->flags & IORESOURCE_IO)
- root = &pbm->io_space;
- else {
- root = &pbm->mem_space;
- if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
- == PCI_BASE_ADDRESS_MEM_TYPE_64)
- is_64bit = 1;
- }
-
- size = res->end - res->start;
- pci_read_config_dword(pdev, where, &reg);
- reg = ((reg & size) |
- (((u32)(res->start - root->start)) & ~size));
- if (resource == PCI_ROM_RESOURCE) {
- reg |= PCI_ROM_ADDRESS_ENABLE;
- res->flags |= IORESOURCE_ROM_ENABLE;
- }
- pci_write_config_dword(pdev, where, reg);
-
- /* This knows that the upper 32-bits of the address
- * must be zero. Our PCI common layer enforces this.
- */
- if (is_64bit)
- pci_write_config_dword(pdev, where + 4, 0);
-}
-
static void pbm_config_busmastering(struct pci_pbm_info *pbm)
{
u8 *addr;
@@ -968,28 +921,7 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
static void pbm_scan_bus(struct pci_controller_info *p,
struct pci_pbm_info *pbm)
{
- struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
-
- if (!cookie) {
- prom_printf("PSYCHO: Critical allocation failure.\n");
- prom_halt();
- }
-
- /* All we care about is the PBM. */
- cookie->pbm = pbm;
-
- pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno,
- p->pci_ops,
- pbm);
- pci_fixup_host_bridge_self(pbm->pci_bus);
- pbm->pci_bus->self->sysdata = cookie;
-
- pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node);
- pci_record_assignments(pbm, pbm->pci_bus);
- pci_assign_unassigned(pbm, pbm->pci_bus);
- pci_fixup_irq(pbm, pbm->pci_bus);
- pci_determine_66mhz_disposition(pbm, pbm->pci_bus);
- pci_setup_busmastering(pbm, pbm->pci_bus);
+ pbm->pci_bus = pci_scan_one_pbm(pbm);
}
static void psycho_scan_bus(struct pci_controller_info *p)
@@ -1009,7 +941,7 @@ static void psycho_scan_bus(struct pci_controller_info *p)
static void psycho_iommu_init(struct pci_controller_info *p)
{
- struct pci_iommu *iommu = p->pbm_A.iommu;
+ struct iommu *iommu = p->pbm_A.iommu;
unsigned long i;
u64 control;
@@ -1094,19 +1026,6 @@ static void psycho_controller_hwinit(struct pci_controller_info *p)
psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG, tmp);
}
-static void pbm_register_toplevel_resources(struct pci_controller_info *p,
- struct pci_pbm_info *pbm)
-{
- char *name = pbm->name;
-
- pbm->io_space.name = pbm->mem_space.name = name;
-
- request_resource(&ioport_resource, &pbm->io_space);
- request_resource(&iomem_resource, &pbm->mem_space);
- pci_register_legacy_regions(&pbm->io_space,
- &pbm->mem_space);
-}
-
static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
struct pci_pbm_info *pbm,
int is_pbm_a)
@@ -1172,19 +1091,11 @@ static void psycho_pbm_init(struct pci_controller_info *p,
unsigned int *busrange;
struct property *prop;
struct pci_pbm_info *pbm;
- int len;
- if (is_pbm_a) {
+ if (is_pbm_a)
pbm = &p->pbm_A;
- pbm->pci_first_slot = 1;
- pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_A;
- pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_A;
- } else {
+ else
pbm = &p->pbm_B;
- pbm->pci_first_slot = 2;
- pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_B;
- pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_B;
- }
pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
pbm->chip_version = 0;
@@ -1196,41 +1107,15 @@ static void psycho_pbm_init(struct pci_controller_info *p,
if (prop)
pbm->chip_revision = *(int *) prop->value;
- pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE;
- pbm->io_space.flags = IORESOURCE_IO;
- pbm->mem_space.end = pbm->mem_space.start + PSYCHO_MEMSPACE_SIZE;
- pbm->mem_space.flags = IORESOURCE_MEM;
-
pbm->parent = p;
pbm->prom_node = dp;
pbm->name = dp->full_name;
- pbm_register_toplevel_resources(p, pbm);
-
printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n",
pbm->name,
pbm->chip_version, pbm->chip_revision);
- prop = of_find_property(dp, "ranges", &len);
- if (prop) {
- pbm->pbm_ranges = prop->value;
- pbm->num_pbm_ranges =
- (len / sizeof(struct linux_prom_pci_ranges));
- } else {
- pbm->num_pbm_ranges = 0;
- }
-
- prop = of_find_property(dp, "interrupt-map", &len);
- if (prop) {
- pbm->pbm_intmap = prop->value;
- pbm->num_pbm_intmap =
- (len / sizeof(struct linux_prom_pci_intmap));
-
- prop = of_find_property(dp, "interrupt-map-mask", NULL);
- pbm->pbm_intmask = prop->value;
- } else {
- pbm->num_pbm_intmap = 0;
- }
+ pci_determine_mem_io_space(pbm);
prop = of_find_property(dp, "bus-range", NULL);
busrange = prop->value;
@@ -1246,7 +1131,7 @@ void psycho_init(struct device_node *dp, char *model_name)
{
struct linux_prom64_registers *pr_regs;
struct pci_controller_info *p;
- struct pci_iommu *iommu;
+ struct iommu *iommu;
struct property *prop;
u32 upa_portid;
int is_pbm_a;
@@ -1269,7 +1154,7 @@ void psycho_init(struct device_node *dp, char *model_name)
prom_printf("PSYCHO: Fatal memory allocation error.\n");
prom_halt();
}
- iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+ iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
if (!iommu) {
prom_printf("PSYCHO: Fatal memory allocation error.\n");
prom_halt();
@@ -1282,10 +1167,7 @@ void psycho_init(struct device_node *dp, char *model_name)
p->pbm_A.portid = upa_portid;
p->pbm_B.portid = upa_portid;
p->index = pci_num_controllers++;
- p->pbms_same_domain = 0;
p->scan_bus = psycho_scan_bus;
- p->base_address_update = psycho_base_address_update;
- p->resource_adjust = psycho_resource_adjust;
p->pci_ops = &psycho_ops;
prop = of_find_property(dp, "reg", NULL);
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index 94bb681f232..397862fbd9e 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -1,7 +1,6 @@
-/* $Id: pci_sabre.c,v 1.42 2002/01/23 11:27:32 davem Exp $
- * pci_sabre.c: Sabre specific PCI controller support.
+/* pci_sabre.c: Sabre specific PCI controller support.
*
- * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
+ * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net)
* Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
*/
@@ -254,9 +253,6 @@ static int __sabre_out_of_range(struct pci_pbm_info *pbm,
return 0;
return ((pbm->parent == 0) ||
- ((pbm == &pbm->parent->pbm_B) &&
- (bus == pbm->pci_first_busno) &&
- PCI_SLOT(devfn) > 8) ||
((pbm == &pbm->parent->pbm_A) &&
(bus == pbm->pci_first_busno) &&
PCI_SLOT(devfn) > 8));
@@ -322,6 +318,12 @@ static int __sabre_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
static int sabre_read_pci_cfg(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 *value)
{
+ struct pci_pbm_info *pbm = bus->sysdata;
+
+ if (bus == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_read_pci_cfg(bus, devfn, where,
+ size, value);
+
if (!bus->number && sabre_out_of_range(devfn)) {
switch (size) {
case 1:
@@ -438,6 +440,12 @@ static int __sabre_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
static int sabre_write_pci_cfg(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 value)
{
+ struct pci_pbm_info *pbm = bus->sysdata;
+
+ if (bus == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_write_pci_cfg(bus, devfn, where,
+ size, value);
+
if (bus->number)
return __sabre_write_pci_cfg(bus, devfn, where, size, value);
@@ -490,7 +498,7 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
unsigned long afsr,
unsigned long afar)
{
- struct pci_iommu *iommu = p->pbm_A.iommu;
+ struct iommu *iommu = p->pbm_A.iommu;
unsigned long iommu_tag[16];
unsigned long iommu_data[16];
unsigned long flags;
@@ -710,8 +718,8 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
p->index);
ret = IRQ_HANDLED;
}
- pci_read_config_word(sabre_root_bus->self,
- PCI_STATUS, &stat);
+ pci_bus_read_config_word(sabre_root_bus, 0,
+ PCI_STATUS, &stat);
if (stat & (PCI_STATUS_PARITY |
PCI_STATUS_SIG_TARGET_ABORT |
PCI_STATUS_REC_TARGET_ABORT |
@@ -719,8 +727,8 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
PCI_STATUS_SIG_SYSTEM_ERROR)) {
printk("SABRE%d: PCI bus error, PCI_STATUS[%04x]\n",
p->index, stat);
- pci_write_config_word(sabre_root_bus->self,
- PCI_STATUS, 0xffff);
+ pci_bus_write_config_word(sabre_root_bus, 0,
+ PCI_STATUS, 0xffff);
ret = IRQ_HANDLED;
}
return ret;
@@ -800,12 +808,10 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) {
sabre_check_iommu_error(p, afsr, afar);
pci_scan_for_target_abort(p, &p->pbm_A, p->pbm_A.pci_bus);
- pci_scan_for_target_abort(p, &p->pbm_B, p->pbm_B.pci_bus);
}
- if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA)) {
+ if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA))
pci_scan_for_master_abort(p, &p->pbm_A, p->pbm_A.pci_bus);
- pci_scan_for_master_abort(p, &p->pbm_B, p->pbm_B.pci_bus);
- }
+
/* For excessive retries, SABRE/PBM will abort the device
* and there is no way to specifically check for excessive
* retries in the config space status registers. So what
@@ -813,10 +819,8 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
* abort events.
*/
- if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR)) {
+ if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR))
pci_scan_for_parity_error(p, &p->pbm_A, p->pbm_A.pci_bus);
- pci_scan_for_parity_error(p, &p->pbm_B, p->pbm_B.pci_bus);
- }
return IRQ_HANDLED;
}
@@ -869,144 +873,52 @@ static void sabre_register_error_handlers(struct pci_controller_info *p)
sabre_write(base + SABRE_PCICTRL, tmp);
}
-static void sabre_resource_adjust(struct pci_dev *pdev,
- struct resource *res,
- struct resource *root)
-{
- struct pci_pbm_info *pbm = pdev->bus->sysdata;
- unsigned long base;
-
- if (res->flags & IORESOURCE_IO)
- base = pbm->controller_regs + SABRE_IOSPACE;
- else
- base = pbm->controller_regs + SABRE_MEMSPACE;
-
- res->start += base;
- res->end += base;
-}
-
-static void sabre_base_address_update(struct pci_dev *pdev, int resource)
-{
- struct pcidev_cookie *pcp = pdev->sysdata;
- struct pci_pbm_info *pbm = pcp->pbm;
- struct resource *res;
- unsigned long base;
- u32 reg;
- int where, size, is_64bit;
-
- res = &pdev->resource[resource];
- if (resource < 6) {
- where = PCI_BASE_ADDRESS_0 + (resource * 4);
- } else if (resource == PCI_ROM_RESOURCE) {
- where = pdev->rom_base_reg;
- } else {
- /* Somebody might have asked allocation of a non-standard resource */
- return;
- }
-
- is_64bit = 0;
- if (res->flags & IORESOURCE_IO)
- base = pbm->controller_regs + SABRE_IOSPACE;
- else {
- base = pbm->controller_regs + SABRE_MEMSPACE;
- if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
- == PCI_BASE_ADDRESS_MEM_TYPE_64)
- is_64bit = 1;
- }
-
- size = res->end - res->start;
- pci_read_config_dword(pdev, where, &reg);
- reg = ((reg & size) |
- (((u32)(res->start - base)) & ~size));
- if (resource == PCI_ROM_RESOURCE) {
- reg |= PCI_ROM_ADDRESS_ENABLE;
- res->flags |= IORESOURCE_ROM_ENABLE;
- }
- pci_write_config_dword(pdev, where, reg);
-
- /* This knows that the upper 32-bits of the address
- * must be zero. Our PCI common layer enforces this.
- */
- if (is_64bit)
- pci_write_config_dword(pdev, where + 4, 0);
-}
-
static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
{
struct pci_dev *pdev;
list_for_each_entry(pdev, &sabre_bus->devices, bus_list) {
-
if (pdev->vendor == PCI_VENDOR_ID_SUN &&
pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
- u32 word32;
u16 word16;
- sabre_read_pci_cfg(pdev->bus, pdev->devfn,
- PCI_COMMAND, 2, &word32);
- word16 = (u16) word32;
+ pci_read_config_word(pdev, PCI_COMMAND, &word16);
word16 |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
PCI_COMMAND_IO;
- word32 = (u32) word16;
- sabre_write_pci_cfg(pdev->bus, pdev->devfn,
- PCI_COMMAND, 2, word32);
+ pci_write_config_word(pdev, PCI_COMMAND, word16);
/* Status register bits are "write 1 to clear". */
- sabre_write_pci_cfg(pdev->bus, pdev->devfn,
- PCI_STATUS, 2, 0xffff);
- sabre_write_pci_cfg(pdev->bus, pdev->devfn,
- PCI_SEC_STATUS, 2, 0xffff);
+ pci_write_config_word(pdev, PCI_STATUS, 0xffff);
+ pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff);
/* Use a primary/seconday latency timer value
* of 64.
*/
- sabre_write_pci_cfg(pdev->bus, pdev->devfn,
- PCI_LATENCY_TIMER, 1, 64);
- sabre_write_pci_cfg(pdev->bus, pdev->devfn,
- PCI_SEC_LATENCY_TIMER, 1, 64);
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+ pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64);
/* Enable reporting/forwarding of master aborts,
* parity, and SERR.
*/
- sabre_write_pci_cfg(pdev->bus, pdev->devfn,
- PCI_BRIDGE_CONTROL, 1,
- (PCI_BRIDGE_CTL_PARITY |
- PCI_BRIDGE_CTL_SERR |
- PCI_BRIDGE_CTL_MASTER_ABORT));
+ pci_write_config_byte(pdev, PCI_BRIDGE_CONTROL,
+ (PCI_BRIDGE_CTL_PARITY |
+ PCI_BRIDGE_CTL_SERR |
+ PCI_BRIDGE_CTL_MASTER_ABORT));
}
}
}
-static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm)
-{
- struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
-
- if (!cookie) {
- prom_printf("SABRE: Critical allocation failure.\n");
- prom_halt();
- }
-
- /* All we care about is the PBM. */
- cookie->pbm = pbm;
-
- return cookie;
-}
-
static void sabre_scan_bus(struct pci_controller_info *p)
{
static int once;
- struct pci_bus *sabre_bus, *pbus;
- struct pci_pbm_info *pbm;
- struct pcidev_cookie *cookie;
- int sabres_scanned;
+ struct pci_bus *pbus;
/* The APB bridge speaks to the Sabre host PCI bridge
* at 66Mhz, but the front side of APB runs at 33Mhz
* for both segments.
*/
p->pbm_A.is_66mhz_capable = 0;
- p->pbm_B.is_66mhz_capable = 0;
/* This driver has not been verified to handle
* multiple SABREs yet, so trap this.
@@ -1020,56 +932,13 @@ static void sabre_scan_bus(struct pci_controller_info *p)
}
once++;
- cookie = alloc_bridge_cookie(&p->pbm_A);
-
- sabre_bus = pci_scan_bus(p->pci_first_busno,
- p->pci_ops,
- &p->pbm_A);
- pci_fixup_host_bridge_self(sabre_bus);
- sabre_bus->self->sysdata = cookie;
-
- sabre_root_bus = sabre_bus;
-
- apb_init(p, sabre_bus);
-
- sabres_scanned = 0;
-
- list_for_each_entry(pbus, &sabre_bus->children, node) {
-
- if (pbus->number == p->pbm_A.pci_first_busno) {
- pbm = &p->pbm_A;
- } else if (pbus->number == p->pbm_B.pci_first_busno) {
- pbm = &p->pbm_B;
- } else
- continue;
-
- cookie = alloc_bridge_cookie(pbm);
- pbus->self->sysdata = cookie;
-
- sabres_scanned++;
+ pbus = pci_scan_one_pbm(&p->pbm_A);
+ if (!pbus)
+ return;
- pbus->sysdata = pbm;
- pbm->pci_bus = pbus;
- pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node);
- pci_record_assignments(pbm, pbus);
- pci_assign_unassigned(pbm, pbus);
- pci_fixup_irq(pbm, pbus);
- pci_determine_66mhz_disposition(pbm, pbus);
- pci_setup_busmastering(pbm, pbus);
- }
+ sabre_root_bus = pbus;
- if (!sabres_scanned) {
- /* Hummingbird, no APBs. */
- pbm = &p->pbm_A;
- sabre_bus->sysdata = pbm;
- pbm->pci_bus = sabre_bus;
- pci_fill_in_pbm_cookies(sabre_bus, pbm, pbm->prom_node);
- pci_record_assignments(pbm, sabre_bus);
- pci_assign_unassigned(pbm, sabre_bus);
- pci_fixup_irq(pbm, sabre_bus);
- pci_determine_66mhz_disposition(pbm, sabre_bus);
- pci_setup_busmastering(pbm, sabre_bus);
- }
+ apb_init(p, pbus);
sabre_register_error_handlers(p);
}
@@ -1078,7 +947,7 @@ static void sabre_iommu_init(struct pci_controller_info *p,
int tsbsize, unsigned long dvma_offset,
u32 dma_mask)
{
- struct pci_iommu *iommu = p->pbm_A.iommu;
+ struct iommu *iommu = p->pbm_A.iommu;
unsigned long i;
u64 control;
@@ -1126,224 +995,31 @@ static void sabre_iommu_init(struct pci_controller_info *p,
sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control);
}
-static void pbm_register_toplevel_resources(struct pci_controller_info *p,
- struct pci_pbm_info *pbm)
-{
- char *name = pbm->name;
- unsigned long ibase = p->pbm_A.controller_regs + SABRE_IOSPACE;
- unsigned long mbase = p->pbm_A.controller_regs + SABRE_MEMSPACE;
- unsigned int devfn;
- unsigned long first, last, i;
- u8 *addr, map;
-
- sprintf(name, "SABRE%d PBM%c",
- p->index,
- (pbm == &p->pbm_A ? 'A' : 'B'));
- pbm->io_space.name = pbm->mem_space.name = name;
-
- devfn = PCI_DEVFN(1, (pbm == &p->pbm_A) ? 0 : 1);
- addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_IO_ADDRESS_MAP);
- map = 0;
- pci_config_read8(addr, &map);
-
- first = 8;
- last = 0;
- for (i = 0; i < 8; i++) {
- if ((map & (1 << i)) != 0) {
- if (first > i)
- first = i;
- if (last < i)
- last = i;
- }
- }
- pbm->io_space.start = ibase + (first << 21UL);
- pbm->io_space.end = ibase + (last << 21UL) + ((1 << 21UL) - 1);
- pbm->io_space.flags = IORESOURCE_IO;
-
- addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_MEM_ADDRESS_MAP);
- map = 0;
- pci_config_read8(addr, &map);
-
- first = 8;
- last = 0;
- for (i = 0; i < 8; i++) {
- if ((map & (1 << i)) != 0) {
- if (first > i)
- first = i;
- if (last < i)
- last = i;
- }
- }
- pbm->mem_space.start = mbase + (first << 29UL);
- pbm->mem_space.end = mbase + (last << 29UL) + ((1 << 29UL) - 1);
- pbm->mem_space.flags = IORESOURCE_MEM;
-
- if (request_resource(&ioport_resource, &pbm->io_space) < 0) {
- prom_printf("Cannot register PBM-%c's IO space.\n",
- (pbm == &p->pbm_A ? 'A' : 'B'));
- prom_halt();
- }
- if (request_resource(&iomem_resource, &pbm->mem_space) < 0) {
- prom_printf("Cannot register PBM-%c's MEM space.\n",
- (pbm == &p->pbm_A ? 'A' : 'B'));
- prom_halt();
- }
-
- /* Register legacy regions if this PBM covers that area. */
- if (pbm->io_space.start == ibase &&
- pbm->mem_space.start == mbase)
- pci_register_legacy_regions(&pbm->io_space,
- &pbm->mem_space);
-}
-
-static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_start, u32 dma_end)
+static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp)
{
struct pci_pbm_info *pbm;
- struct device_node *node;
- struct property *prop;
- u32 *busrange;
- int len, simbas_found;
-
- simbas_found = 0;
- node = dp->child;
- while (node != NULL) {
- if (strcmp(node->name, "pci"))
- goto next_pci;
-
- prop = of_find_property(node, "model", NULL);
- if (!prop || strncmp(prop->value, "SUNW,simba", prop->length))
- goto next_pci;
-
- simbas_found++;
-
- prop = of_find_property(node, "bus-range", NULL);
- busrange = prop->value;
- if (busrange[0] == 1)
- pbm = &p->pbm_B;
- else
- pbm = &p->pbm_A;
-
- pbm->name = node->full_name;
- printk("%s: SABRE PCI Bus Module\n", pbm->name);
-
- pbm->chip_type = PBM_CHIP_TYPE_SABRE;
- pbm->parent = p;
- pbm->prom_node = node;
- pbm->pci_first_slot = 1;
- pbm->pci_first_busno = busrange[0];
- pbm->pci_last_busno = busrange[1];
-
- prop = of_find_property(node, "ranges", &len);
- if (prop) {
- pbm->pbm_ranges = prop->value;
- pbm->num_pbm_ranges =
- (len / sizeof(struct linux_prom_pci_ranges));
- } else {
- pbm->num_pbm_ranges = 0;
- }
- prop = of_find_property(node, "interrupt-map", &len);
- if (prop) {
- pbm->pbm_intmap = prop->value;
- pbm->num_pbm_intmap =
- (len / sizeof(struct linux_prom_pci_intmap));
-
- prop = of_find_property(node, "interrupt-map-mask",
- NULL);
- pbm->pbm_intmask = prop->value;
- } else {
- pbm->num_pbm_intmap = 0;
- }
+ pbm = &p->pbm_A;
+ pbm->name = dp->full_name;
+ printk("%s: SABRE PCI Bus Module\n", pbm->name);
- pbm_register_toplevel_resources(p, pbm);
-
- next_pci:
- node = node->sibling;
- }
- if (simbas_found == 0) {
- struct resource *rp;
+ pbm->chip_type = PBM_CHIP_TYPE_SABRE;
+ pbm->parent = p;
+ pbm->prom_node = dp;
+ pbm->pci_first_busno = p->pci_first_busno;
+ pbm->pci_last_busno = p->pci_last_busno;
- /* No APBs underneath, probably this is a hummingbird
- * system.
- */
- pbm = &p->pbm_A;
- pbm->parent = p;
- pbm->prom_node = dp;
- pbm->pci_first_busno = p->pci_first_busno;
- pbm->pci_last_busno = p->pci_last_busno;
-
- prop = of_find_property(dp, "ranges", &len);
- if (prop) {
- pbm->pbm_ranges = prop->value;
- pbm->num_pbm_ranges =
- (len / sizeof(struct linux_prom_pci_ranges));
- } else {
- pbm->num_pbm_ranges = 0;
- }
-
- prop = of_find_property(dp, "interrupt-map", &len);
- if (prop) {
- pbm->pbm_intmap = prop->value;
- pbm->num_pbm_intmap =
- (len / sizeof(struct linux_prom_pci_intmap));
-
- prop = of_find_property(dp, "interrupt-map-mask",
- NULL);
- pbm->pbm_intmask = prop->value;
- } else {
- pbm->num_pbm_intmap = 0;
- }
-
- pbm->name = dp->full_name;
- printk("%s: SABRE PCI Bus Module\n", pbm->name);
-
- pbm->io_space.name = pbm->mem_space.name = pbm->name;
-
- /* Hack up top-level resources. */
- pbm->io_space.start = p->pbm_A.controller_regs + SABRE_IOSPACE;
- pbm->io_space.end = pbm->io_space.start + (1UL << 24) - 1UL;
- pbm->io_space.flags = IORESOURCE_IO;
-
- pbm->mem_space.start =
- (p->pbm_A.controller_regs + SABRE_MEMSPACE);
- pbm->mem_space.end =
- (pbm->mem_space.start + ((1UL << 32UL) - 1UL));
- pbm->mem_space.flags = IORESOURCE_MEM;
-
- if (request_resource(&ioport_resource, &pbm->io_space) < 0) {
- prom_printf("Cannot register Hummingbird's IO space.\n");
- prom_halt();
- }
- if (request_resource(&iomem_resource, &pbm->mem_space) < 0) {
- prom_printf("Cannot register Hummingbird's MEM space.\n");
- prom_halt();
- }
-
- rp = kmalloc(sizeof(*rp), GFP_KERNEL);
- if (!rp) {
- prom_printf("Cannot allocate IOMMU resource.\n");
- prom_halt();
- }
- rp->name = "IOMMU";
- rp->start = pbm->mem_space.start + (unsigned long) dma_start;
- rp->end = pbm->mem_space.start + (unsigned long) dma_end - 1UL;
- rp->flags = IORESOURCE_BUSY;
- request_resource(&pbm->mem_space, rp);
-
- pci_register_legacy_regions(&pbm->io_space,
- &pbm->mem_space);
- }
+ pci_determine_mem_io_space(pbm);
}
void sabre_init(struct device_node *dp, char *model_name)
{
- struct linux_prom64_registers *pr_regs;
+ const struct linux_prom64_registers *pr_regs;
struct pci_controller_info *p;
- struct pci_iommu *iommu;
- struct property *prop;
+ struct iommu *iommu;
int tsbsize;
- u32 *busrange;
- u32 *vdma;
+ const u32 *busrange;
+ const u32 *vdma;
u32 upa_portid, dma_mask;
u64 clear_irq;
@@ -1351,13 +1027,9 @@ void sabre_init(struct device_node *dp, char *model_name)
if (!strcmp(model_name, "pci108e,a001"))
hummingbird_p = 1;
else if (!strcmp(model_name, "SUNW,sabre")) {
- prop = of_find_property(dp, "compatible", NULL);
- if (prop) {
- const char *compat = prop->value;
-
- if (!strcmp(compat, "pci108e,a001"))
- hummingbird_p = 1;
- }
+ const char *compat = of_get_property(dp, "compatible", NULL);
+ if (compat && !strcmp(compat, "pci108e,a001"))
+ hummingbird_p = 1;
if (!hummingbird_p) {
struct device_node *dp;
@@ -1381,37 +1053,28 @@ void sabre_init(struct device_node *dp, char *model_name)
prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n");
prom_halt();
}
- p->pbm_A.iommu = p->pbm_B.iommu = iommu;
+ p->pbm_A.iommu = iommu;
- upa_portid = 0xff;
- prop = of_find_property(dp, "upa-portid", NULL);
- if (prop)
- upa_portid = *(u32 *) prop->value;
+ upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
p->next = pci_controller_root;
pci_controller_root = p;
p->pbm_A.portid = upa_portid;
- p->pbm_B.portid = upa_portid;
p->index = pci_num_controllers++;
- p->pbms_same_domain = 1;
p->scan_bus = sabre_scan_bus;
- p->base_address_update = sabre_base_address_update;
- p->resource_adjust = sabre_resource_adjust;
p->pci_ops = &sabre_ops;
/*
* Map in SABRE register set and report the presence of this SABRE.
*/
- prop = of_find_property(dp, "reg", NULL);
- pr_regs = prop->value;
+ pr_regs = of_get_property(dp, "reg", NULL);
/*
* First REG in property is base of entire SABRE register space.
*/
p->pbm_A.controller_regs = pr_regs[0].phys_addr;
- p->pbm_B.controller_regs = pr_regs[0].phys_addr;
/* Clear interrupts */
@@ -1429,11 +1092,10 @@ void sabre_init(struct device_node *dp, char *model_name)
SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
/* Now map in PCI config space for entire SABRE. */
- p->pbm_A.config_space = p->pbm_B.config_space =
+ p->pbm_A.config_space =
(p->pbm_A.controller_regs + SABRE_CONFIGSPACE);
- prop = of_find_property(dp, "virtual-dma", NULL);
- vdma = prop->value;
+ vdma = of_get_property(dp, "virtual-dma", NULL);
dma_mask = vdma[0];
switch(vdma[1]) {
@@ -1457,13 +1119,12 @@ void sabre_init(struct device_node *dp, char *model_name)
sabre_iommu_init(p, tsbsize, vdma[0], dma_mask);
- prop = of_find_property(dp, "bus-range", NULL);
- busrange = prop->value;
+ busrange = of_get_property(dp, "bus-range", NULL);
p->pci_first_busno = busrange[0];
p->pci_last_busno = busrange[1];
/*
* Look for APB underneath.
*/
- sabre_pbm_init(p, dp, vdma[0], vdma[0] + vdma[1]);
+ sabre_pbm_init(p, dp);
}
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 66911b126ae..91a7385e5d3 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -1,7 +1,6 @@
-/* $Id: pci_schizo.c,v 1.24 2002/01/23 11:27:32 davem Exp $
- * pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support.
+/* pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support.
*
- * Copyright (C) 2001, 2002, 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2002, 2003, 2007 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@@ -126,6 +125,9 @@ static int schizo_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
u16 tmp16;
u8 tmp8;
+ if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+ size, value);
switch (size) {
case 1:
*value = 0xff;
@@ -179,6 +181,9 @@ static int schizo_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
unsigned char bus = bus_dev->number;
u32 *addr;
+ if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+ size, value);
addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
if (!addr)
return PCIBIOS_SUCCESSFUL;
@@ -274,7 +279,7 @@ struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm,
enum schizo_error_type type)
{
- struct pci_strbuf *strbuf = &pbm->stc;
+ struct strbuf *strbuf = &pbm->stc;
unsigned long regbase = pbm->pbm_regs;
unsigned long err_base, tag_base, line_base;
u64 control;
@@ -382,7 +387,7 @@ static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm,
static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
enum schizo_error_type type)
{
- struct pci_iommu *iommu = pbm->iommu;
+ struct iommu *iommu = pbm->iommu;
unsigned long iommu_tag[16];
unsigned long iommu_data[16];
unsigned long flags;
@@ -1229,42 +1234,8 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
pci_config_write8(addr, 64);
}
-static void pbm_scan_bus(struct pci_controller_info *p,
- struct pci_pbm_info *pbm)
-{
- struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
-
- if (!cookie) {
- prom_printf("%s: Critical allocation failure.\n", pbm->name);
- prom_halt();
- }
-
- /* All we care about is the PBM. */
- cookie->pbm = pbm;
-
- pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno,
- p->pci_ops,
- pbm);
- pci_fixup_host_bridge_self(pbm->pci_bus);
- pbm->pci_bus->self->sysdata = cookie;
-
- pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node);
- pci_record_assignments(pbm, pbm->pci_bus);
- pci_assign_unassigned(pbm, pbm->pci_bus);
- pci_fixup_irq(pbm, pbm->pci_bus);
- pci_determine_66mhz_disposition(pbm, pbm->pci_bus);
- pci_setup_busmastering(pbm, pbm->pci_bus);
-}
-
-static void __schizo_scan_bus(struct pci_controller_info *p,
- int chip_type)
+static void schizo_scan_bus(struct pci_controller_info *p)
{
- if (!p->pbm_B.prom_node || !p->pbm_A.prom_node) {
- printk("PCI: Only one PCI bus module of controller found.\n");
- printk("PCI: Ignoring entire controller.\n");
- return;
- }
-
pbm_config_busmastering(&p->pbm_B);
p->pbm_B.is_66mhz_capable =
(of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL)
@@ -1273,154 +1244,19 @@ static void __schizo_scan_bus(struct pci_controller_info *p,
p->pbm_A.is_66mhz_capable =
(of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL)
!= NULL);
- pbm_scan_bus(p, &p->pbm_B);
- pbm_scan_bus(p, &p->pbm_A);
+
+ p->pbm_B.pci_bus = pci_scan_one_pbm(&p->pbm_B);
+ p->pbm_A.pci_bus = pci_scan_one_pbm(&p->pbm_A);
/* After the PCI bus scan is complete, we can register
* the error interrupt handlers.
*/
- if (chip_type == PBM_CHIP_TYPE_TOMATILLO)
+ if (p->pbm_B.chip_type == PBM_CHIP_TYPE_TOMATILLO)
tomatillo_register_error_handlers(p);
else
schizo_register_error_handlers(p);
}
-static void schizo_scan_bus(struct pci_controller_info *p)
-{
- __schizo_scan_bus(p, PBM_CHIP_TYPE_SCHIZO);
-}
-
-static void tomatillo_scan_bus(struct pci_controller_info *p)
-{
- __schizo_scan_bus(p, PBM_CHIP_TYPE_TOMATILLO);
-}
-
-static void schizo_base_address_update(struct pci_dev *pdev, int resource)
-{
- struct pcidev_cookie *pcp = pdev->sysdata;
- struct pci_pbm_info *pbm = pcp->pbm;
- struct resource *res, *root;
- u32 reg;
- int where, size, is_64bit;
-
- res = &pdev->resource[resource];
- if (resource < 6) {
- where = PCI_BASE_ADDRESS_0 + (resource * 4);
- } else if (resource == PCI_ROM_RESOURCE) {
- where = pdev->rom_base_reg;
- } else {
- /* Somebody might have asked allocation of a non-standard resource */
- return;
- }
-
- is_64bit = 0;
- if (res->flags & IORESOURCE_IO)
- root = &pbm->io_space;
- else {
- root = &pbm->mem_space;
- if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
- == PCI_BASE_ADDRESS_MEM_TYPE_64)
- is_64bit = 1;
- }
-
- size = res->end - res->start;
- pci_read_config_dword(pdev, where, &reg);
- reg = ((reg & size) |
- (((u32)(res->start - root->start)) & ~size));
- if (resource == PCI_ROM_RESOURCE) {
- reg |= PCI_ROM_ADDRESS_ENABLE;
- res->flags |= IORESOURCE_ROM_ENABLE;
- }
- pci_write_config_dword(pdev, where, reg);
-
- /* This knows that the upper 32-bits of the address
- * must be zero. Our PCI common layer enforces this.
- */
- if (is_64bit)
- pci_write_config_dword(pdev, where + 4, 0);
-}
-
-static void schizo_resource_adjust(struct pci_dev *pdev,
- struct resource *res,
- struct resource *root)
-{
- res->start += root->start;
- res->end += root->start;
-}
-
-/* Use ranges property to determine where PCI MEM, I/O, and Config
- * space are for this PCI bus module.
- */
-static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm)
-{
- int i, saw_cfg, saw_mem, saw_io;
-
- saw_cfg = saw_mem = saw_io = 0;
- for (i = 0; i < pbm->num_pbm_ranges; i++) {
- struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i];
- unsigned long a;
- int type;
-
- type = (pr->child_phys_hi >> 24) & 0x3;
- a = (((unsigned long)pr->parent_phys_hi << 32UL) |
- ((unsigned long)pr->parent_phys_lo << 0UL));
-
- switch (type) {
- case 0:
- /* PCI config space, 16MB */
- pbm->config_space = a;
- saw_cfg = 1;
- break;
-
- case 1:
- /* 16-bit IO space, 16MB */
- pbm->io_space.start = a;
- pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL);
- pbm->io_space.flags = IORESOURCE_IO;
- saw_io = 1;
- break;
-
- case 2:
- /* 32-bit MEM space, 2GB */
- pbm->mem_space.start = a;
- pbm->mem_space.end = a + (0x80000000UL - 1UL);
- pbm->mem_space.flags = IORESOURCE_MEM;
- saw_mem = 1;
- break;
-
- default:
- break;
- };
- }
-
- if (!saw_cfg || !saw_io || !saw_mem) {
- prom_printf("%s: Fatal error, missing %s PBM range.\n",
- pbm->name,
- ((!saw_cfg ?
- "CFG" :
- (!saw_io ?
- "IO" : "MEM"))));
- prom_halt();
- }
-
- printk("%s: PCI CFG[%lx] IO[%lx] MEM[%lx]\n",
- pbm->name,
- pbm->config_space,
- pbm->io_space.start,
- pbm->mem_space.start);
-}
-
-static void pbm_register_toplevel_resources(struct pci_controller_info *p,
- struct pci_pbm_info *pbm)
-{
- pbm->io_space.name = pbm->mem_space.name = pbm->name;
-
- request_resource(&ioport_resource, &pbm->io_space);
- request_resource(&iomem_resource, &pbm->mem_space);
- pci_register_legacy_regions(&pbm->io_space,
- &pbm->mem_space);
-}
-
#define SCHIZO_STRBUF_CONTROL (0x02800UL)
#define SCHIZO_STRBUF_FLUSH (0x02808UL)
#define SCHIZO_STRBUF_FSYNC (0x02810UL)
@@ -1472,7 +1308,7 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
{
- struct pci_iommu *iommu = pbm->iommu;
+ struct iommu *iommu = pbm->iommu;
unsigned long i, tagbase, database;
struct property *prop;
u32 vdma[2], dma_mask;
@@ -1654,14 +1490,12 @@ static void schizo_pbm_init(struct pci_controller_info *p,
struct device_node *dp, u32 portid,
int chip_type)
{
- struct linux_prom64_registers *regs;
- struct property *prop;
- unsigned int *busrange;
+ const struct linux_prom64_registers *regs;
+ const unsigned int *busrange;
struct pci_pbm_info *pbm;
const char *chipset_name;
- u32 *ino_bitmap;
+ const u32 *ino_bitmap;
int is_pbm_a;
- int len;
switch (chip_type) {
case PBM_CHIP_TYPE_TOMATILLO:
@@ -1689,11 +1523,9 @@ static void schizo_pbm_init(struct pci_controller_info *p,
* 3) PBM PCI config space
* 4) Ichip regs
*/
- prop = of_find_property(dp, "reg", NULL);
- regs = prop->value;
+ regs = of_get_property(dp, "reg", NULL);
is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000);
-
if (is_pbm_a)
pbm = &p->pbm_A;
else
@@ -1702,17 +1534,10 @@ static void schizo_pbm_init(struct pci_controller_info *p,
pbm->portid = portid;
pbm->parent = p;
pbm->prom_node = dp;
- pbm->pci_first_slot = 1;
pbm->chip_type = chip_type;
- pbm->chip_version = 0;
- prop = of_find_property(dp, "version#", NULL);
- if (prop)
- pbm->chip_version = *(int *) prop->value;
- pbm->chip_revision = 0;
- prop = of_find_property(dp, "module-revision#", NULL);
- if (prop)
- pbm->chip_revision = *(int *) prop->value;
+ pbm->chip_version = of_getintprop_default(dp, "version#", 0);
+ pbm->chip_revision = of_getintprop_default(dp, "module-version#", 0);
pbm->pbm_regs = regs[0].phys_addr;
pbm->controller_regs = regs[1].phys_addr - 0x10000UL;
@@ -1723,40 +1548,18 @@ static void schizo_pbm_init(struct pci_controller_info *p,
pbm->name = dp->full_name;
printk("%s: %s PCI Bus Module ver[%x:%x]\n",
- pbm->name,
- (chip_type == PBM_CHIP_TYPE_TOMATILLO ?
- "TOMATILLO" : "SCHIZO"),
+ pbm->name, chipset_name,
pbm->chip_version, pbm->chip_revision);
schizo_pbm_hw_init(pbm);
- prop = of_find_property(dp, "ranges", &len);
- pbm->pbm_ranges = prop->value;
- pbm->num_pbm_ranges =
- (len / sizeof(struct linux_prom_pci_ranges));
+ pci_determine_mem_io_space(pbm);
- schizo_determine_mem_io_space(pbm);
- pbm_register_toplevel_resources(p, pbm);
-
- prop = of_find_property(dp, "interrupt-map", &len);
- if (prop) {
- pbm->pbm_intmap = prop->value;
- pbm->num_pbm_intmap =
- (len / sizeof(struct linux_prom_pci_intmap));
-
- prop = of_find_property(dp, "interrupt-map-mask", NULL);
- pbm->pbm_intmask = prop->value;
- } else {
- pbm->num_pbm_intmap = 0;
- }
-
- prop = of_find_property(dp, "ino-bitmap", NULL);
- ino_bitmap = prop->value;
+ ino_bitmap = of_get_property(dp, "ino-bitmap", NULL);
pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
((u64)ino_bitmap[0] << 0UL));
- prop = of_find_property(dp, "bus-range", NULL);
- busrange = prop->value;
+ busrange = of_get_property(dp, "bus-range", NULL);
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
@@ -1777,15 +1580,10 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
static void __schizo_init(struct device_node *dp, char *model_name, int chip_type)
{
struct pci_controller_info *p;
- struct pci_iommu *iommu;
- struct property *prop;
- int is_pbm_a;
+ struct iommu *iommu;
u32 portid;
- portid = 0xff;
- prop = of_find_property(dp, "portid", NULL);
- if (prop)
- portid = *(u32 *) prop->value;
+ portid = of_getintprop_default(dp, "portid", 0xff);
for (p = pci_controller_root; p; p = p->next) {
struct pci_pbm_info *pbm;
@@ -1798,48 +1596,43 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ
&p->pbm_B);
if (portid_compare(pbm->portid, portid, chip_type)) {
- is_pbm_a = (p->pbm_A.prom_node == NULL);
schizo_pbm_init(p, dp, portid, chip_type);
return;
}
}
p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
- if (!p) {
- prom_printf("SCHIZO: Fatal memory allocation error.\n");
- prom_halt();
- }
+ if (!p)
+ goto memfail;
+
+ iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
+ if (!iommu)
+ goto memfail;
- iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
- if (!iommu) {
- prom_printf("SCHIZO: Fatal memory allocation error.\n");
- prom_halt();
- }
p->pbm_A.iommu = iommu;
- iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
- if (!iommu) {
- prom_printf("SCHIZO: Fatal memory allocation error.\n");
- prom_halt();
- }
+ iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
+ if (!iommu)
+ goto memfail;
+
p->pbm_B.iommu = iommu;
p->next = pci_controller_root;
pci_controller_root = p;
p->index = pci_num_controllers++;
- p->pbms_same_domain = 0;
- p->scan_bus = (chip_type == PBM_CHIP_TYPE_TOMATILLO ?
- tomatillo_scan_bus :
- schizo_scan_bus);
- p->base_address_update = schizo_base_address_update;
- p->resource_adjust = schizo_resource_adjust;
+ p->scan_bus = schizo_scan_bus;
p->pci_ops = &schizo_ops;
/* Like PSYCHO we have a 2GB aligned area for memory space. */
pci_memspace_mask = 0x7fffffffUL;
schizo_pbm_init(p, dp, portid, chip_type);
+ return;
+
+memfail:
+ prom_printf("SCHIZO: Fatal memory allocation error.\n");
+ prom_halt();
}
void schizo_init(struct device_node *dp, char *model_name)
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index ec22cd61ec8..94295c21932 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -1,6 +1,6 @@
/* pci_sun4v.c: SUN4V specific PCI controller support.
*
- * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@@ -29,7 +29,7 @@
#define PGLIST_NENTS (PAGE_SIZE / sizeof(u64))
-struct pci_iommu_batch {
+struct iommu_batch {
struct pci_dev *pdev; /* Device mapping is for. */
unsigned long prot; /* IOMMU page protections */
unsigned long entry; /* Index into IOTSB. */
@@ -37,12 +37,12 @@ struct pci_iommu_batch {
unsigned long npages; /* Number of pages in list. */
};
-static DEFINE_PER_CPU(struct pci_iommu_batch, pci_iommu_batch);
+static DEFINE_PER_CPU(struct iommu_batch, pci_iommu_batch);
/* Interrupts must be disabled. */
static inline void pci_iommu_batch_start(struct pci_dev *pdev, unsigned long prot, unsigned long entry)
{
- struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
+ struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
p->pdev = pdev;
p->prot = prot;
@@ -51,10 +51,10 @@ static inline void pci_iommu_batch_start(struct pci_dev *pdev, unsigned long pro
}
/* Interrupts must be disabled. */
-static long pci_iommu_batch_flush(struct pci_iommu_batch *p)
+static long pci_iommu_batch_flush(struct iommu_batch *p)
{
- struct pcidev_cookie *pcp = p->pdev->sysdata;
- unsigned long devhandle = pcp->pbm->devhandle;
+ struct pci_pbm_info *pbm = p->pdev->dev.archdata.host_controller;
+ unsigned long devhandle = pbm->devhandle;
unsigned long prot = p->prot;
unsigned long entry = p->entry;
u64 *pglist = p->pglist;
@@ -89,7 +89,7 @@ static long pci_iommu_batch_flush(struct pci_iommu_batch *p)
/* Interrupts must be disabled. */
static inline long pci_iommu_batch_add(u64 phys_page)
{
- struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
+ struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
BUG_ON(p->npages >= PGLIST_NENTS);
@@ -103,14 +103,14 @@ static inline long pci_iommu_batch_add(u64 phys_page)
/* Interrupts must be disabled. */
static inline long pci_iommu_batch_end(void)
{
- struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
+ struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
BUG_ON(p->npages >= PGLIST_NENTS);
return pci_iommu_batch_flush(p);
}
-static long pci_arena_alloc(struct pci_iommu_arena *arena, unsigned long npages)
+static long pci_arena_alloc(struct iommu_arena *arena, unsigned long npages)
{
unsigned long n, i, start, end, limit;
int pass;
@@ -149,7 +149,7 @@ again:
return n;
}
-static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages)
+static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages)
{
unsigned long i;
@@ -159,8 +159,7 @@ static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, un
static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
+ struct iommu *iommu;
unsigned long flags, order, first_page, npages, n;
void *ret;
long entry;
@@ -178,8 +177,7 @@ static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr
memset((char *)first_page, 0, PAGE_SIZE << order);
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
+ iommu = pdev->dev.archdata.iommu;
spin_lock_irqsave(&iommu->lock, flags);
entry = pci_arena_alloc(&iommu->arena, npages);
@@ -226,15 +224,15 @@ arena_alloc_fail:
static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
+ struct pci_pbm_info *pbm;
+ struct iommu *iommu;
unsigned long flags, order, npages, entry;
u32 devhandle;
npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- devhandle = pcp->pbm->devhandle;
+ iommu = pdev->dev.archdata.iommu;
+ pbm = pdev->dev.archdata.host_controller;
+ devhandle = pbm->devhandle;
entry = ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
spin_lock_irqsave(&iommu->lock, flags);
@@ -259,16 +257,14 @@ static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu,
static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
+ struct iommu *iommu;
unsigned long flags, npages, oaddr;
unsigned long i, base_paddr;
u32 bus_addr, ret;
unsigned long prot;
long entry;
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
+ iommu = pdev->dev.archdata.iommu;
if (unlikely(direction == PCI_DMA_NONE))
goto bad;
@@ -324,8 +320,8 @@ iommu_map_fail:
static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
+ struct pci_pbm_info *pbm;
+ struct iommu *iommu;
unsigned long flags, npages;
long entry;
u32 devhandle;
@@ -336,9 +332,9 @@ static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_
return;
}
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- devhandle = pcp->pbm->devhandle;
+ iommu = pdev->dev.archdata.iommu;
+ pbm = pdev->dev.archdata.host_controller;
+ devhandle = pbm->devhandle;
npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
npages >>= IO_PAGE_SHIFT;
@@ -460,8 +456,7 @@ iommu_map_failed:
static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
+ struct iommu *iommu;
unsigned long flags, npages, prot;
u32 dma_base;
struct scatterlist *sgtmp;
@@ -480,8 +475,7 @@ static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n
return 1;
}
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
+ iommu = pdev->dev.archdata.iommu;
if (unlikely(direction == PCI_DMA_NONE))
goto bad;
@@ -537,8 +531,8 @@ iommu_map_failed:
static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
+ struct pci_pbm_info *pbm;
+ struct iommu *iommu;
unsigned long flags, i, npages;
long entry;
u32 devhandle, bus_addr;
@@ -548,9 +542,9 @@ static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in
WARN_ON(1);
}
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- devhandle = pcp->pbm->devhandle;
+ iommu = pdev->dev.archdata.iommu;
+ pbm = pdev->dev.archdata.host_controller;
+ devhandle = pbm->devhandle;
bus_addr = sglist->dma_address & IO_PAGE_MASK;
@@ -589,7 +583,7 @@ static void pci_4v_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist
/* Nothing to do... */
}
-struct pci_iommu_ops pci_sun4v_iommu_ops = {
+const struct pci_iommu_ops pci_sun4v_iommu_ops = {
.alloc_consistent = pci_4v_alloc_consistent,
.free_consistent = pci_4v_free_consistent,
.map_single = pci_4v_map_single,
@@ -600,132 +594,12 @@ struct pci_iommu_ops pci_sun4v_iommu_ops = {
.dma_sync_sg_for_cpu = pci_4v_dma_sync_sg_for_cpu,
};
-/* SUN4V PCI configuration space accessors. */
-
-struct pdev_entry {
- struct pdev_entry *next;
- u32 devhandle;
- unsigned int bus;
- unsigned int device;
- unsigned int func;
-};
-
-#define PDEV_HTAB_SIZE 16
-#define PDEV_HTAB_MASK (PDEV_HTAB_SIZE - 1)
-static struct pdev_entry *pdev_htab[PDEV_HTAB_SIZE];
-
-static inline unsigned int pdev_hashfn(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func)
-{
- unsigned int val;
-
- val = (devhandle ^ (devhandle >> 4));
- val ^= bus;
- val ^= device;
- val ^= func;
-
- return val & PDEV_HTAB_MASK;
-}
-
-static int pdev_htab_add(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func)
-{
- struct pdev_entry *p = kmalloc(sizeof(*p), GFP_KERNEL);
- struct pdev_entry **slot;
-
- if (!p)
- return -ENOMEM;
-
- slot = &pdev_htab[pdev_hashfn(devhandle, bus, device, func)];
- p->next = *slot;
- *slot = p;
-
- p->devhandle = devhandle;
- p->bus = bus;
- p->device = device;
- p->func = func;
-
- return 0;
-}
-
-/* Recursively descend into the OBP device tree, rooted at toplevel_node,
- * looking for a PCI device matching bus and devfn.
- */
-static int obp_find(struct device_node *toplevel_node, unsigned int bus, unsigned int devfn)
-{
- toplevel_node = toplevel_node->child;
-
- while (toplevel_node != NULL) {
- struct linux_prom_pci_registers *regs;
- struct property *prop;
- int ret;
-
- ret = obp_find(toplevel_node, bus, devfn);
- if (ret != 0)
- return ret;
-
- prop = of_find_property(toplevel_node, "reg", NULL);
- if (!prop)
- goto next_sibling;
-
- regs = prop->value;
- if (((regs->phys_hi >> 16) & 0xff) == bus &&
- ((regs->phys_hi >> 8) & 0xff) == devfn)
- break;
-
- next_sibling:
- toplevel_node = toplevel_node->sibling;
- }
-
- return toplevel_node != NULL;
-}
-
-static int pdev_htab_populate(struct pci_pbm_info *pbm)
-{
- u32 devhandle = pbm->devhandle;
- unsigned int bus;
-
- for (bus = pbm->pci_first_busno; bus <= pbm->pci_last_busno; bus++) {
- unsigned int devfn;
-
- for (devfn = 0; devfn < 256; devfn++) {
- unsigned int device = PCI_SLOT(devfn);
- unsigned int func = PCI_FUNC(devfn);
-
- if (obp_find(pbm->prom_node, bus, devfn)) {
- int err = pdev_htab_add(devhandle, bus,
- device, func);
- if (err)
- return err;
- }
- }
- }
-
- return 0;
-}
-
-static struct pdev_entry *pdev_find(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func)
-{
- struct pdev_entry *p;
-
- p = pdev_htab[pdev_hashfn(devhandle, bus, device, func)];
- while (p) {
- if (p->devhandle == devhandle &&
- p->bus == bus &&
- p->device == device &&
- p->func == func)
- break;
-
- p = p->next;
- }
-
- return p;
-}
-
static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func)
{
if (bus < pbm->pci_first_busno ||
bus > pbm->pci_last_busno)
return 1;
- return pdev_find(pbm->devhandle, bus, device, func) == NULL;
+ return 0;
}
static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
@@ -738,6 +612,9 @@ static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
unsigned int func = PCI_FUNC(devfn);
unsigned long ret;
+ if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+ size, value);
if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
ret = ~0UL;
} else {
@@ -776,6 +653,9 @@ static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
unsigned int func = PCI_FUNC(devfn);
unsigned long ret;
+ if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+ size, value);
if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
/* Do nothing. */
} else {
@@ -800,27 +680,7 @@ static struct pci_ops pci_sun4v_ops = {
static void pbm_scan_bus(struct pci_controller_info *p,
struct pci_pbm_info *pbm)
{
- struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
-
- if (!cookie) {
- prom_printf("%s: Critical allocation failure.\n", pbm->name);
- prom_halt();
- }
-
- /* All we care about is the PBM. */
- cookie->pbm = pbm;
-
- pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm);
-#if 0
- pci_fixup_host_bridge_self(pbm->pci_bus);
- pbm->pci_bus->self->sysdata = cookie;
-#endif
- pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node);
- pci_record_assignments(pbm, pbm->pci_bus);
- pci_assign_unassigned(pbm, pbm->pci_bus);
- pci_fixup_irq(pbm, pbm->pci_bus);
- pci_determine_66mhz_disposition(pbm, pbm->pci_bus);
- pci_setup_busmastering(pbm, pbm->pci_bus);
+ pbm->pci_bus = pci_scan_one_pbm(pbm);
}
static void pci_sun4v_scan_bus(struct pci_controller_info *p)
@@ -844,130 +704,10 @@ static void pci_sun4v_scan_bus(struct pci_controller_info *p)
/* XXX register error interrupt handlers XXX */
}
-static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource)
-{
- struct pcidev_cookie *pcp = pdev->sysdata;
- struct pci_pbm_info *pbm = pcp->pbm;
- struct resource *res, *root;
- u32 reg;
- int where, size, is_64bit;
-
- res = &pdev->resource[resource];
- if (resource < 6) {
- where = PCI_BASE_ADDRESS_0 + (resource * 4);
- } else if (resource == PCI_ROM_RESOURCE) {
- where = pdev->rom_base_reg;
- } else {
- /* Somebody might have asked allocation of a non-standard resource */
- return;
- }
-
- /* XXX 64-bit MEM handling is not %100 correct... XXX */
- is_64bit = 0;
- if (res->flags & IORESOURCE_IO)
- root = &pbm->io_space;
- else {
- root = &pbm->mem_space;
- if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
- == PCI_BASE_ADDRESS_MEM_TYPE_64)
- is_64bit = 1;
- }
-
- size = res->end - res->start;
- pci_read_config_dword(pdev, where, &reg);
- reg = ((reg & size) |
- (((u32)(res->start - root->start)) & ~size));
- if (resource == PCI_ROM_RESOURCE) {
- reg |= PCI_ROM_ADDRESS_ENABLE;
- res->flags |= IORESOURCE_ROM_ENABLE;
- }
- pci_write_config_dword(pdev, where, reg);
-
- /* This knows that the upper 32-bits of the address
- * must be zero. Our PCI common layer enforces this.
- */
- if (is_64bit)
- pci_write_config_dword(pdev, where + 4, 0);
-}
-
-static void pci_sun4v_resource_adjust(struct pci_dev *pdev,
- struct resource *res,
- struct resource *root)
-{
- res->start += root->start;
- res->end += root->start;
-}
-
-/* Use ranges property to determine where PCI MEM, I/O, and Config
- * space are for this PCI bus module.
- */
-static void pci_sun4v_determine_mem_io_space(struct pci_pbm_info *pbm)
-{
- int i, saw_mem, saw_io;
-
- saw_mem = saw_io = 0;
- for (i = 0; i < pbm->num_pbm_ranges; i++) {
- struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i];
- unsigned long a;
- int type;
-
- type = (pr->child_phys_hi >> 24) & 0x3;
- a = (((unsigned long)pr->parent_phys_hi << 32UL) |
- ((unsigned long)pr->parent_phys_lo << 0UL));
-
- switch (type) {
- case 1:
- /* 16-bit IO space, 16MB */
- pbm->io_space.start = a;
- pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL);
- pbm->io_space.flags = IORESOURCE_IO;
- saw_io = 1;
- break;
-
- case 2:
- /* 32-bit MEM space, 2GB */
- pbm->mem_space.start = a;
- pbm->mem_space.end = a + (0x80000000UL - 1UL);
- pbm->mem_space.flags = IORESOURCE_MEM;
- saw_mem = 1;
- break;
-
- case 3:
- /* XXX 64-bit MEM handling XXX */
-
- default:
- break;
- };
- }
-
- if (!saw_io || !saw_mem) {
- prom_printf("%s: Fatal error, missing %s PBM range.\n",
- pbm->name,
- (!saw_io ? "IO" : "MEM"));
- prom_halt();
- }
-
- printk("%s: PCI IO[%lx] MEM[%lx]\n",
- pbm->name,
- pbm->io_space.start,
- pbm->mem_space.start);
-}
-
-static void pbm_register_toplevel_resources(struct pci_controller_info *p,
- struct pci_pbm_info *pbm)
-{
- pbm->io_space.name = pbm->mem_space.name = pbm->name;
-
- request_resource(&ioport_resource, &pbm->io_space);
- request_resource(&iomem_resource, &pbm->mem_space);
- pci_register_legacy_regions(&pbm->io_space,
- &pbm->mem_space);
-}
-
static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
- struct pci_iommu *iommu)
+ struct iommu *iommu)
{
- struct pci_iommu_arena *arena = &iommu->arena;
+ struct iommu_arena *arena = &iommu->arena;
unsigned long i, cnt = 0;
u32 devhandle;
@@ -994,7 +734,7 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
{
- struct pci_iommu *iommu = pbm->iommu;
+ struct iommu *iommu = pbm->iommu;
struct property *prop;
unsigned long num_tsb_entries, sz;
u32 vdma[2], dma_mask, dma_offset;
@@ -1281,7 +1021,7 @@ h_error:
static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
{
- u32 *val;
+ const u32 *val;
int len;
val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
@@ -1289,16 +1029,16 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
goto no_msi;
pbm->msiq_num = *val;
if (pbm->msiq_num) {
- struct msiq_prop {
+ const struct msiq_prop {
u32 first_msiq;
u32 num_msiq;
u32 first_devino;
} *mqp;
- struct msi_range_prop {
+ const struct msi_range_prop {
u32 first_msi;
u32 num_msi;
} *mrng;
- struct addr_range_prop {
+ const struct addr_range_prop {
u32 msi32_high;
u32 msi32_low;
u32 msi32_len;
@@ -1410,8 +1150,7 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p,
struct pci_dev *pdev,
struct msi_desc *entry)
{
- struct pcidev_cookie *pcp = pdev->sysdata;
- struct pci_pbm_info *pbm = pcp->pbm;
+ struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
unsigned long devino, msiqid;
struct msi_msg msg;
int msi_num, err;
@@ -1455,7 +1194,7 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p,
if (pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_VALID))
goto out_err;
- pcp->msi_num = msi_num;
+ pdev->dev.archdata.msi_num = msi_num;
if (entry->msi_attrib.is_64) {
msg.address_hi = pbm->msi64_start >> 32;
@@ -1484,12 +1223,11 @@ out_err:
static void pci_sun4v_teardown_msi_irq(unsigned int virt_irq,
struct pci_dev *pdev)
{
- struct pcidev_cookie *pcp = pdev->sysdata;
- struct pci_pbm_info *pbm = pcp->pbm;
+ struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
unsigned long msiqid, err;
unsigned int msi_num;
- msi_num = pcp->msi_num;
+ msi_num = pdev->dev.archdata.msi_num;
err = pci_sun4v_msi_getmsiq(pbm->devhandle, msi_num, &msiqid);
if (err) {
printk(KERN_ERR "%s: getmsiq gives error %lu\n",
@@ -1516,8 +1254,6 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
{
struct pci_pbm_info *pbm;
- struct property *prop;
- int len, i;
if (devhandle & 0x40)
pbm = &p->pbm_B;
@@ -1526,7 +1262,6 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
pbm->parent = p;
pbm->prom_node = dp;
- pbm->pci_first_slot = 1;
pbm->devhandle = devhandle;
@@ -1534,39 +1269,17 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
printk("%s: SUN4V PCI Bus Module\n", pbm->name);
- prop = of_find_property(dp, "ranges", &len);
- pbm->pbm_ranges = prop->value;
- pbm->num_pbm_ranges =
- (len / sizeof(struct linux_prom_pci_ranges));
-
- /* Mask out the top 8 bits of the ranges, leaving the real
- * physical address.
- */
- for (i = 0; i < pbm->num_pbm_ranges; i++)
- pbm->pbm_ranges[i].parent_phys_hi &= 0x0fffffff;
-
- pci_sun4v_determine_mem_io_space(pbm);
- pbm_register_toplevel_resources(p, pbm);
-
- prop = of_find_property(dp, "interrupt-map", &len);
- pbm->pbm_intmap = prop->value;
- pbm->num_pbm_intmap =
- (len / sizeof(struct linux_prom_pci_intmap));
-
- prop = of_find_property(dp, "interrupt-map-mask", NULL);
- pbm->pbm_intmask = prop->value;
+ pci_determine_mem_io_space(pbm);
pci_sun4v_get_bus_range(pbm);
pci_sun4v_iommu_init(pbm);
pci_sun4v_msi_init(pbm);
-
- pdev_htab_populate(pbm);
}
void sun4v_pci_init(struct device_node *dp, char *model_name)
{
struct pci_controller_info *p;
- struct pci_iommu *iommu;
+ struct iommu *iommu;
struct property *prop;
struct linux_prom64_registers *regs;
u32 devhandle;
@@ -1606,13 +1319,13 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
if (!p)
goto fatal_memory_error;
- iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+ iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
if (!iommu)
goto fatal_memory_error;
p->pbm_A.iommu = iommu;
- iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+ iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
if (!iommu)
goto fatal_memory_error;
@@ -1622,11 +1335,8 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
pci_controller_root = p;
p->index = pci_num_controllers++;
- p->pbms_same_domain = 0;
p->scan_bus = pci_sun4v_scan_bus;
- p->base_address_update = pci_sun4v_base_address_update;
- p->resource_adjust = pci_sun4v_resource_adjust;
#ifdef CONFIG_PCI_MSI
p->setup_msi_irq = pci_sun4v_setup_msi_irq;
p->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index b291060c25a..a114151f9fb 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -28,6 +28,7 @@
#include <linux/reboot.h>
#include <linux/delay.h>
#include <linux/compat.h>
+#include <linux/tick.h>
#include <linux/init.h>
#include <asm/oplib.h>
@@ -88,12 +89,14 @@ void cpu_idle(void)
set_thread_flag(TIF_POLLING_NRFLAG);
while(1) {
- if (need_resched()) {
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- }
- sparc64_yield();
+ tick_nohz_stop_sched_tick();
+ while (!need_resched())
+ sparc64_yield();
+ tick_nohz_restart_sched_tick();
+
+ preempt_enable_no_resched();
+ schedule();
+ preempt_disable();
}
}
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 0917c24c4f0..5e1fcd05160 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -36,12 +36,13 @@ static struct device_node *allnodes;
*/
static DEFINE_RWLOCK(devtree_lock);
-int of_device_is_compatible(struct device_node *device, const char *compat)
+int of_device_is_compatible(const struct device_node *device,
+ const char *compat)
{
const char* cp;
int cplen, l;
- cp = (char *) of_get_property(device, "compatible", &cplen);
+ cp = of_get_property(device, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
@@ -154,13 +155,14 @@ struct device_node *of_find_compatible_node(struct device_node *from,
}
EXPORT_SYMBOL(of_find_compatible_node);
-struct property *of_find_property(struct device_node *np, const char *name,
+struct property *of_find_property(const struct device_node *np,
+ const char *name,
int *lenp)
{
struct property *pp;
for (pp = np->properties; pp != 0; pp = pp->next) {
- if (strcmp(pp->name, name) == 0) {
+ if (strcasecmp(pp->name, name) == 0) {
if (lenp != 0)
*lenp = pp->length;
break;
@@ -174,7 +176,8 @@ EXPORT_SYMBOL(of_find_property);
* Find a property with a given name for a given node
* and return the value.
*/
-void *of_get_property(struct device_node *np, const char *name, int *lenp)
+const void *of_get_property(const struct device_node *np, const char *name,
+ int *lenp)
{
struct property *pp = of_find_property(np,name,lenp);
return pp ? pp->value : NULL;
@@ -196,7 +199,7 @@ EXPORT_SYMBOL(of_getintprop_default);
int of_n_addr_cells(struct device_node *np)
{
- int* ip;
+ const int* ip;
do {
if (np->parent)
np = np->parent;
@@ -211,7 +214,7 @@ EXPORT_SYMBOL(of_n_addr_cells);
int of_n_size_cells(struct device_node *np)
{
- int* ip;
+ const int* ip;
do {
if (np->parent)
np = np->parent;
@@ -243,7 +246,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
while (*prevp) {
struct property *prop = *prevp;
- if (!strcmp(prop->name, name)) {
+ if (!strcasecmp(prop->name, name)) {
void *old_val = prop->value;
int ret;
@@ -397,7 +400,7 @@ static unsigned int psycho_irq_build(struct device_node *dp,
static void psycho_irq_trans_init(struct device_node *dp)
{
- struct linux_prom64_registers *regs;
+ const struct linux_prom64_registers *regs;
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->irq_build = psycho_irq_build;
@@ -547,7 +550,7 @@ static unsigned long __sabre_onboard_imap_off[] = {
static int sabre_device_needs_wsync(struct device_node *dp)
{
struct device_node *parent = dp->parent;
- char *parent_model, *parent_compat;
+ const char *parent_model, *parent_compat;
/* This traversal up towards the root is meant to
* handle two cases:
@@ -589,7 +592,7 @@ static unsigned int sabre_irq_build(struct device_node *dp,
{
struct sabre_irq_data *irq_data = _data;
unsigned long controller_regs = irq_data->controller_regs;
- struct linux_prom_pci_registers *regs;
+ const struct linux_prom_pci_registers *regs;
unsigned long imap, iclr;
unsigned long imap_off, iclr_off;
int inofixup = 0;
@@ -639,9 +642,9 @@ static unsigned int sabre_irq_build(struct device_node *dp,
static void sabre_irq_trans_init(struct device_node *dp)
{
- struct linux_prom64_registers *regs;
+ const struct linux_prom64_registers *regs;
struct sabre_irq_data *irq_data;
- u32 *busrange;
+ const u32 *busrange;
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->irq_build = sabre_irq_build;
@@ -795,7 +798,7 @@ static unsigned int schizo_irq_build(struct device_node *dp,
static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo)
{
- struct linux_prom64_registers *regs;
+ const struct linux_prom64_registers *regs;
struct schizo_irq_data *irq_data;
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
@@ -836,7 +839,7 @@ static unsigned int pci_sun4v_irq_build(struct device_node *dp,
static void pci_sun4v_irq_trans_init(struct device_node *dp)
{
- struct linux_prom64_registers *regs;
+ const struct linux_prom64_registers *regs;
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->irq_build = pci_sun4v_irq_build;
@@ -940,7 +943,7 @@ static unsigned int sbus_of_build_irq(struct device_node *dp,
void *_data)
{
unsigned long reg_base = (unsigned long) _data;
- struct linux_prom_registers *regs;
+ const struct linux_prom_registers *regs;
unsigned long imap, iclr;
int sbus_slot = 0;
int sbus_level = 0;
@@ -994,7 +997,7 @@ static unsigned int sbus_of_build_irq(struct device_node *dp,
static void sbus_irq_trans_init(struct device_node *dp)
{
- struct linux_prom64_registers *regs;
+ const struct linux_prom64_registers *regs;
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->irq_build = sbus_of_build_irq;
@@ -1080,7 +1083,7 @@ static unsigned int sun4v_vdev_irq_build(struct device_node *dp,
static void sun4v_vdev_irq_trans_init(struct device_node *dp)
{
- struct linux_prom64_registers *regs;
+ const struct linux_prom64_registers *regs;
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->irq_build = sun4v_vdev_irq_build;
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index 14f78fb5e89..3b05428cc90 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -26,23 +26,9 @@
#define MAP_BASE ((u32)0xc0000000)
-struct sbus_iommu_arena {
- unsigned long *map;
- unsigned int hint;
- unsigned int limit;
-};
-
-struct sbus_iommu {
- spinlock_t lock;
-
- struct sbus_iommu_arena arena;
-
- iopte_t *page_table;
- unsigned long strbuf_regs;
- unsigned long iommu_regs;
- unsigned long sbus_control_reg;
-
- volatile unsigned long strbuf_flushflag;
+struct sbus_info {
+ struct iommu iommu;
+ struct strbuf strbuf;
};
/* Offsets from iommu_regs */
@@ -58,16 +44,17 @@ struct sbus_iommu {
#define IOMMU_DRAM_VALID (1UL << 30UL)
-static void __iommu_flushall(struct sbus_iommu *iommu)
+static void __iommu_flushall(struct iommu *iommu)
{
- unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG;
+ unsigned long tag;
int entry;
+ tag = iommu->iommu_control + (IOMMU_TAGDIAG - IOMMU_CONTROL);
for (entry = 0; entry < 16; entry++) {
upa_writeq(0, tag);
tag += 8UL;
}
- upa_readq(iommu->sbus_control_reg);
+ upa_readq(iommu->write_complete_reg);
}
/* Offsets from strbuf_regs */
@@ -82,15 +69,14 @@ static void __iommu_flushall(struct sbus_iommu *iommu)
#define STRBUF_TAG_VALID 0x02UL
-static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages, int direction)
+static void sbus_strbuf_flush(struct iommu *iommu, struct strbuf *strbuf, u32 base, unsigned long npages, int direction)
{
unsigned long n;
int limit;
n = npages;
while (n--)
- upa_writeq(base + (n << IO_PAGE_SHIFT),
- iommu->strbuf_regs + STRBUF_PFLUSH);
+ upa_writeq(base + (n << IO_PAGE_SHIFT), strbuf->strbuf_pflush);
/* If the device could not have possibly put dirty data into
* the streaming cache, no flush-flag synchronization needs
@@ -99,15 +85,14 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long
if (direction == SBUS_DMA_TODEVICE)
return;
- iommu->strbuf_flushflag = 0UL;
+ *(strbuf->strbuf_flushflag) = 0UL;
/* Whoopee cushion! */
- upa_writeq(__pa(&iommu->strbuf_flushflag),
- iommu->strbuf_regs + STRBUF_FSYNC);
- upa_readq(iommu->sbus_control_reg);
+ upa_writeq(strbuf->strbuf_flushflag_pa, strbuf->strbuf_fsync);
+ upa_readq(iommu->write_complete_reg);
limit = 100000;
- while (iommu->strbuf_flushflag == 0UL) {
+ while (*(strbuf->strbuf_flushflag) == 0UL) {
limit--;
if (!limit)
break;
@@ -121,9 +106,9 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long
}
/* Based largely upon the ppc64 iommu allocator. */
-static long sbus_arena_alloc(struct sbus_iommu *iommu, unsigned long npages)
+static long sbus_arena_alloc(struct iommu *iommu, unsigned long npages)
{
- struct sbus_iommu_arena *arena = &iommu->arena;
+ struct iommu_arena *arena = &iommu->arena;
unsigned long n, i, start, end, limit;
int pass;
@@ -162,7 +147,7 @@ again:
return n;
}
-static void sbus_arena_free(struct sbus_iommu_arena *arena, unsigned long base, unsigned long npages)
+static void sbus_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages)
{
unsigned long i;
@@ -170,7 +155,7 @@ static void sbus_arena_free(struct sbus_iommu_arena *arena, unsigned long base,
__clear_bit(i, arena->map);
}
-static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize)
+static void sbus_iommu_table_init(struct iommu *iommu, unsigned int tsbsize)
{
unsigned long tsbbase, order, sz, num_tsb_entries;
@@ -178,13 +163,14 @@ static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize
/* Setup initial software IOMMU state. */
spin_lock_init(&iommu->lock);
+ iommu->page_table_map_base = MAP_BASE;
/* Allocate and initialize the free area map. */
sz = num_tsb_entries / 8;
sz = (sz + 7UL) & ~7UL;
iommu->arena.map = kzalloc(sz, GFP_KERNEL);
if (!iommu->arena.map) {
- prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
+ prom_printf("SBUS_IOMMU: Error, kmalloc(arena.map) failed.\n");
prom_halt();
}
iommu->arena.limit = num_tsb_entries;
@@ -200,7 +186,7 @@ static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize
memset(iommu->page_table, 0, tsbsize);
}
-static inline iopte_t *alloc_npages(struct sbus_iommu *iommu, unsigned long npages)
+static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages)
{
long entry;
@@ -211,14 +197,15 @@ static inline iopte_t *alloc_npages(struct sbus_iommu *iommu, unsigned long npag
return iommu->page_table + entry;
}
-static inline void free_npages(struct sbus_iommu *iommu, dma_addr_t base, unsigned long npages)
+static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages)
{
sbus_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages);
}
void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma_addr)
{
- struct sbus_iommu *iommu;
+ struct sbus_info *info;
+ struct iommu *iommu;
iopte_t *iopte;
unsigned long flags, order, first_page;
void *ret;
@@ -234,7 +221,8 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma
return NULL;
memset((char *)first_page, 0, PAGE_SIZE << order);
- iommu = sdev->bus->iommu;
+ info = sdev->bus->iommu;
+ iommu = &info->iommu;
spin_lock_irqsave(&iommu->lock, flags);
iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT);
@@ -245,7 +233,7 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma
return NULL;
}
- *dvma_addr = (MAP_BASE +
+ *dvma_addr = (iommu->page_table_map_base +
((iopte - iommu->page_table) << IO_PAGE_SHIFT));
ret = (void *) first_page;
npages = size >> IO_PAGE_SHIFT;
@@ -263,18 +251,20 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma
void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_addr_t dvma)
{
- struct sbus_iommu *iommu;
+ struct sbus_info *info;
+ struct iommu *iommu;
iopte_t *iopte;
unsigned long flags, order, npages;
npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
- iommu = sdev->bus->iommu;
+ info = sdev->bus->iommu;
+ iommu = &info->iommu;
iopte = iommu->page_table +
- ((dvma - MAP_BASE) >> IO_PAGE_SHIFT);
+ ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
spin_lock_irqsave(&iommu->lock, flags);
- free_npages(iommu, dvma - MAP_BASE, npages);
+ free_npages(iommu, dvma - iommu->page_table_map_base, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
@@ -285,14 +275,16 @@ void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_add
dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int direction)
{
- struct sbus_iommu *iommu;
+ struct sbus_info *info;
+ struct iommu *iommu;
iopte_t *base;
unsigned long flags, npages, oaddr;
unsigned long i, base_paddr;
u32 bus_addr, ret;
unsigned long iopte_protection;
- iommu = sdev->bus->iommu;
+ info = sdev->bus->iommu;
+ iommu = &info->iommu;
if (unlikely(direction == SBUS_DMA_NONE))
BUG();
@@ -308,7 +300,7 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int dire
if (unlikely(!base))
BUG();
- bus_addr = (MAP_BASE +
+ bus_addr = (iommu->page_table_map_base +
((base - iommu->page_table) << IO_PAGE_SHIFT));
ret = bus_addr | (oaddr & ~IO_PAGE_MASK);
base_paddr = __pa(oaddr & IO_PAGE_MASK);
@@ -325,7 +317,9 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int dire
void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction)
{
- struct sbus_iommu *iommu = sdev->bus->iommu;
+ struct sbus_info *info = sdev->bus->iommu;
+ struct iommu *iommu = &info->iommu;
+ struct strbuf *strbuf = &info->strbuf;
iopte_t *base;
unsigned long flags, npages, i;
@@ -335,15 +329,15 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, in
npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
npages >>= IO_PAGE_SHIFT;
base = iommu->page_table +
- ((bus_addr - MAP_BASE) >> IO_PAGE_SHIFT);
+ ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
bus_addr &= IO_PAGE_MASK;
spin_lock_irqsave(&iommu->lock, flags);
- sbus_strbuf_flush(iommu, bus_addr, npages, direction);
+ sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction);
for (i = 0; i < npages; i++)
iopte_val(base[i]) = 0UL;
- free_npages(iommu, bus_addr - MAP_BASE, npages);
+ free_npages(iommu, bus_addr - iommu->page_table_map_base, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
}
@@ -425,7 +419,8 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,
int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)
{
- struct sbus_iommu *iommu;
+ struct sbus_info *info;
+ struct iommu *iommu;
unsigned long flags, npages, iopte_protection;
iopte_t *base;
u32 dma_base;
@@ -442,7 +437,8 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i
return 1;
}
- iommu = sdev->bus->iommu;
+ info = sdev->bus->iommu;
+ iommu = &info->iommu;
if (unlikely(direction == SBUS_DMA_NONE))
BUG();
@@ -456,7 +452,7 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i
if (unlikely(base == NULL))
BUG();
- dma_base = MAP_BASE +
+ dma_base = iommu->page_table_map_base +
((base - iommu->page_table) << IO_PAGE_SHIFT);
/* Normalize DVMA addresses. */
@@ -485,7 +481,9 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i
void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)
{
- struct sbus_iommu *iommu;
+ struct sbus_info *info;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
iopte_t *base;
unsigned long flags, i, npages;
u32 bus_addr;
@@ -493,7 +491,9 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems
if (unlikely(direction == SBUS_DMA_NONE))
BUG();
- iommu = sdev->bus->iommu;
+ info = sdev->bus->iommu;
+ iommu = &info->iommu;
+ strbuf = &info->strbuf;
bus_addr = sglist->dma_address & IO_PAGE_MASK;
@@ -505,29 +505,33 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems
bus_addr) >> IO_PAGE_SHIFT;
base = iommu->page_table +
- ((bus_addr - MAP_BASE) >> IO_PAGE_SHIFT);
+ ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
spin_lock_irqsave(&iommu->lock, flags);
- sbus_strbuf_flush(iommu, bus_addr, npages, direction);
+ sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction);
for (i = 0; i < npages; i++)
iopte_val(base[i]) = 0UL;
- free_npages(iommu, bus_addr - MAP_BASE, npages);
+ free_npages(iommu, bus_addr - iommu->page_table_map_base, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
}
void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction)
{
- struct sbus_iommu *iommu;
+ struct sbus_info *info;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
unsigned long flags, npages;
- iommu = sdev->bus->iommu;
+ info = sdev->bus->iommu;
+ iommu = &info->iommu;
+ strbuf = &info->strbuf;
npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
npages >>= IO_PAGE_SHIFT;
bus_addr &= IO_PAGE_MASK;
spin_lock_irqsave(&iommu->lock, flags);
- sbus_strbuf_flush(iommu, bus_addr, npages, direction);
+ sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction);
spin_unlock_irqrestore(&iommu->lock, flags);
}
@@ -537,11 +541,15 @@ void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t base, siz
void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)
{
- struct sbus_iommu *iommu;
+ struct sbus_info *info;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
unsigned long flags, npages, i;
u32 bus_addr;
- iommu = sdev->bus->iommu;
+ info = sdev->bus->iommu;
+ iommu = &info->iommu;
+ strbuf = &info->strbuf;
bus_addr = sglist[0].dma_address & IO_PAGE_MASK;
for (i = 0; i < nelems; i++) {
@@ -553,7 +561,7 @@ void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sglist,
- bus_addr) >> IO_PAGE_SHIFT;
spin_lock_irqsave(&iommu->lock, flags);
- sbus_strbuf_flush(iommu, bus_addr, npages, direction);
+ sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction);
spin_unlock_irqrestore(&iommu->lock, flags);
}
@@ -564,12 +572,13 @@ void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg,
/* Enable 64-bit DVMA mode for the given device. */
void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
{
- struct sbus_iommu *iommu = sdev->bus->iommu;
+ struct sbus_info *info = sdev->bus->iommu;
+ struct iommu *iommu = &info->iommu;
int slot = sdev->slot;
unsigned long cfg_reg;
u64 val;
- cfg_reg = iommu->sbus_control_reg;
+ cfg_reg = iommu->write_complete_reg;
switch (slot) {
case 0:
cfg_reg += 0x20UL;
@@ -704,8 +713,9 @@ static unsigned long sysio_imap_to_iclr(unsigned long imap)
unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
{
struct sbus_bus *sbus = (struct sbus_bus *)buscookie;
- struct sbus_iommu *iommu = sbus->iommu;
- unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL;
+ struct sbus_info *info = sbus->iommu;
+ struct iommu *iommu = &info->iommu;
+ unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned long imap, iclr;
int sbus_level = 0;
@@ -766,8 +776,9 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
{
struct sbus_bus *sbus = dev_id;
- struct sbus_iommu *iommu = sbus->iommu;
- unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL;
+ struct sbus_info *info = sbus->iommu;
+ struct iommu *iommu = &info->iommu;
+ unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned long afsr_reg, afar_reg;
unsigned long afsr, afar, error_bits;
int reported;
@@ -838,8 +849,9 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
{
struct sbus_bus *sbus = dev_id;
- struct sbus_iommu *iommu = sbus->iommu;
- unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL;
+ struct sbus_info *info = sbus->iommu;
+ struct iommu *iommu = &info->iommu;
+ unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned long afsr_reg, afar_reg;
unsigned long afsr, afar, error_bits;
int reported;
@@ -915,12 +927,13 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
{
struct sbus_bus *sbus = dev_id;
- struct sbus_iommu *iommu = sbus->iommu;
+ struct sbus_info *info = sbus->iommu;
+ struct iommu *iommu = &info->iommu;
unsigned long afsr_reg, afar_reg, reg_base;
unsigned long afsr, afar, error_bits;
int reported;
- reg_base = iommu->sbus_control_reg - 0x2000UL;
+ reg_base = iommu->write_complete_reg - 0x2000UL;
afsr_reg = reg_base + SYSIO_SBUS_AFSR;
afar_reg = reg_base + SYSIO_SBUS_AFAR;
@@ -982,8 +995,9 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
{
- struct sbus_iommu *iommu = sbus->iommu;
- unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL;
+ struct sbus_info *info = sbus->iommu;
+ struct iommu *iommu = &info->iommu;
+ unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned int irq;
u64 control;
@@ -1017,18 +1031,20 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
SYSIO_ECNTRL_CEEN),
reg_base + ECC_CONTROL);
- control = upa_readq(iommu->sbus_control_reg);
+ control = upa_readq(iommu->write_complete_reg);
control |= 0x100UL; /* SBUS Error Interrupt Enable */
- upa_writeq(control, iommu->sbus_control_reg);
+ upa_writeq(control, iommu->write_complete_reg);
}
/* Boot time initialization. */
static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
{
- struct linux_prom64_registers *pr;
+ const struct linux_prom64_registers *pr;
struct device_node *dp;
- struct sbus_iommu *iommu;
- unsigned long regs;
+ struct sbus_info *info;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
+ unsigned long regs, reg_base;
u64 control;
int i;
@@ -1043,33 +1059,42 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
}
regs = pr->phys_addr;
- iommu = kmalloc(sizeof(*iommu) + SMP_CACHE_BYTES, GFP_ATOMIC);
- if (iommu == NULL) {
- prom_printf("sbus_iommu_init: Fatal error, kmalloc(iommu) failed\n");
+ info = kzalloc(sizeof(*info), GFP_ATOMIC);
+ if (info == NULL) {
+ prom_printf("sbus_iommu_init: Fatal error, "
+ "kmalloc(info) failed\n");
prom_halt();
}
- /* Align on E$ line boundary. */
- iommu = (struct sbus_iommu *)
- (((unsigned long)iommu + (SMP_CACHE_BYTES - 1UL)) &
- ~(SMP_CACHE_BYTES - 1UL));
+ iommu = &info->iommu;
+ strbuf = &info->strbuf;
- memset(iommu, 0, sizeof(*iommu));
+ reg_base = regs + SYSIO_IOMMUREG_BASE;
+ iommu->iommu_control = reg_base + IOMMU_CONTROL;
+ iommu->iommu_tsbbase = reg_base + IOMMU_TSBBASE;
+ iommu->iommu_flush = reg_base + IOMMU_FLUSH;
- /* Setup spinlock. */
- spin_lock_init(&iommu->lock);
+ reg_base = regs + SYSIO_STRBUFREG_BASE;
+ strbuf->strbuf_control = reg_base + STRBUF_CONTROL;
+ strbuf->strbuf_pflush = reg_base + STRBUF_PFLUSH;
+ strbuf->strbuf_fsync = reg_base + STRBUF_FSYNC;
- /* Init register offsets. */
- iommu->iommu_regs = regs + SYSIO_IOMMUREG_BASE;
- iommu->strbuf_regs = regs + SYSIO_STRBUFREG_BASE;
+ strbuf->strbuf_enabled = 1;
+
+ strbuf->strbuf_flushflag = (volatile unsigned long *)
+ ((((unsigned long)&strbuf->__flushflag_buf[0])
+ + 63UL)
+ & ~63UL);
+ strbuf->strbuf_flushflag_pa = (unsigned long)
+ __pa(strbuf->strbuf_flushflag);
/* The SYSIO SBUS control register is used for dummy reads
* in order to ensure write completion.
*/
- iommu->sbus_control_reg = regs + 0x2000UL;
+ iommu->write_complete_reg = regs + 0x2000UL;
/* Link into SYSIO software state. */
- sbus->iommu = iommu;
+ sbus->iommu = info;
printk("SYSIO: UPA portID %x, at %016lx\n",
sbus->portid, regs);
@@ -1077,40 +1102,44 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
/* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */
sbus_iommu_table_init(iommu, IO_TSB_SIZE);
- control = upa_readq(iommu->iommu_regs + IOMMU_CONTROL);
+ control = upa_readq(iommu->iommu_control);
control = ((7UL << 16UL) |
(0UL << 2UL) |
(1UL << 1UL) |
(1UL << 0UL));
- upa_writeq(control, iommu->iommu_regs + IOMMU_CONTROL);
+ upa_writeq(control, iommu->iommu_control);
/* Clean out any cruft in the IOMMU using
* diagnostic accesses.
*/
for (i = 0; i < 16; i++) {
- unsigned long dram = iommu->iommu_regs + IOMMU_DRAMDIAG;
- unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG;
+ unsigned long dram, tag;
+
+ dram = iommu->iommu_control + (IOMMU_DRAMDIAG - IOMMU_CONTROL);
+ tag = iommu->iommu_control + (IOMMU_TAGDIAG - IOMMU_CONTROL);
dram += (unsigned long)i * 8UL;
tag += (unsigned long)i * 8UL;
upa_writeq(0, dram);
upa_writeq(0, tag);
}
- upa_readq(iommu->sbus_control_reg);
+ upa_readq(iommu->write_complete_reg);
/* Give the TSB to SYSIO. */
- upa_writeq(__pa(iommu->page_table), iommu->iommu_regs + IOMMU_TSBBASE);
+ upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);
/* Setup streaming buffer, DE=1 SB_EN=1 */
control = (1UL << 1UL) | (1UL << 0UL);
- upa_writeq(control, iommu->strbuf_regs + STRBUF_CONTROL);
+ upa_writeq(control, strbuf->strbuf_control);
/* Clear out the tags using diagnostics. */
for (i = 0; i < 16; i++) {
unsigned long ptag, ltag;
- ptag = iommu->strbuf_regs + STRBUF_PTAGDIAG;
- ltag = iommu->strbuf_regs + STRBUF_LTAGDIAG;
+ ptag = strbuf->strbuf_control +
+ (STRBUF_PTAGDIAG - STRBUF_CONTROL);
+ ltag = strbuf->strbuf_control +
+ (STRBUF_LTAGDIAG - STRBUF_CONTROL);
ptag += (unsigned long)i * 8UL;
ltag += (unsigned long)i * 8UL;
@@ -1119,9 +1148,9 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
}
/* Enable DVMA arbitration for all devices/slots. */
- control = upa_readq(iommu->sbus_control_reg);
+ control = upa_readq(iommu->write_complete_reg);
control |= 0x3fUL;
- upa_writeq(control, iommu->sbus_control_reg);
+ upa_writeq(control, iommu->write_complete_reg);
/* Now some Xfire specific grot... */
if (this_is_starfire)
@@ -1133,7 +1162,7 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
void sbus_fill_device_irq(struct sbus_dev *sdev)
{
struct device_node *dp = of_find_node_by_phandle(sdev->prom_node);
- struct linux_prom_irqs *irqs;
+ const struct linux_prom_irqs *irqs;
irqs = of_get_property(dp, "interrupts", NULL);
if (!irqs) {
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index fc99f7b8012..d4f0a70f484 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -45,7 +45,7 @@
extern void calibrate_delay(void);
/* Please don't make this stuff initdata!!! --DaveM */
-static unsigned char boot_cpu_id;
+unsigned char boot_cpu_id;
cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE;
cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE;
@@ -81,8 +81,6 @@ void __init smp_store_cpu_info(int id)
struct device_node *dp;
int def;
- /* multiplier and counter set by
- smp_setup_percpu_timer() */
cpu_data(id).udelay_val = loops_per_jiffy;
cpu_find_by_mid(id, &dp);
@@ -125,7 +123,7 @@ void __init smp_store_cpu_info(int id)
cpu_data(id).ecache_size, cpu_data(id).ecache_line_size);
}
-static void smp_setup_percpu_timer(void);
+extern void setup_sparc64_timer(void);
static volatile unsigned long callin_flag = 0;
@@ -140,7 +138,7 @@ void __init smp_callin(void)
__flush_tlb_all();
- smp_setup_percpu_timer();
+ setup_sparc64_timer();
if (cheetah_pcache_forced_on)
cheetah_enable_pcache();
@@ -177,8 +175,6 @@ void cpu_panic(void)
panic("SMP bolixed\n");
}
-static unsigned long current_tick_offset __read_mostly;
-
/* This tick register synchronization scheme is taken entirely from
* the ia64 port, see arch/ia64/kernel/smpboot.c for details and credit.
*
@@ -261,7 +257,7 @@ void smp_synchronize_tick_client(void)
} else
adj = -delta;
- tick_ops->add_tick(adj, current_tick_offset);
+ tick_ops->add_tick(adj);
}
#if DEBUG_TICK_SYNC
t[i].rt = rt;
@@ -1180,117 +1176,15 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs)
preempt_enable();
}
-#define prof_multiplier(__cpu) cpu_data(__cpu).multiplier
-#define prof_counter(__cpu) cpu_data(__cpu).counter
-
-void smp_percpu_timer_interrupt(struct pt_regs *regs)
-{
- unsigned long compare, tick, pstate;
- int cpu = smp_processor_id();
- int user = user_mode(regs);
- struct pt_regs *old_regs;
-
- /*
- * Check for level 14 softint.
- */
- {
- unsigned long tick_mask = tick_ops->softint_mask;
-
- if (!(get_softint() & tick_mask)) {
- extern void handler_irq(int, struct pt_regs *);
-
- handler_irq(14, regs);
- return;
- }
- clear_softint(tick_mask);
- }
-
- old_regs = set_irq_regs(regs);
- do {
- profile_tick(CPU_PROFILING);
- if (!--prof_counter(cpu)) {
- irq_enter();
-
- if (cpu == boot_cpu_id) {
- kstat_this_cpu.irqs[0]++;
- timer_tick_interrupt(regs);
- }
-
- update_process_times(user);
-
- irq_exit();
-
- prof_counter(cpu) = prof_multiplier(cpu);
- }
-
- /* Guarantee that the following sequences execute
- * uninterrupted.
- */
- __asm__ __volatile__("rdpr %%pstate, %0\n\t"
- "wrpr %0, %1, %%pstate"
- : "=r" (pstate)
- : "i" (PSTATE_IE));
-
- compare = tick_ops->add_compare(current_tick_offset);
- tick = tick_ops->get_tick();
-
- /* Restore PSTATE_IE. */
- __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
- : /* no outputs */
- : "r" (pstate));
- } while (time_after_eq(tick, compare));
- set_irq_regs(old_regs);
-}
-
-static void __init smp_setup_percpu_timer(void)
-{
- int cpu = smp_processor_id();
- unsigned long pstate;
-
- prof_counter(cpu) = prof_multiplier(cpu) = 1;
-
- /* Guarantee that the following sequences execute
- * uninterrupted.
- */
- __asm__ __volatile__("rdpr %%pstate, %0\n\t"
- "wrpr %0, %1, %%pstate"
- : "=r" (pstate)
- : "i" (PSTATE_IE));
-
- tick_ops->init_tick(current_tick_offset);
-
- /* Restore PSTATE_IE. */
- __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
- : /* no outputs */
- : "r" (pstate));
-}
-
void __init smp_tick_init(void)
{
boot_cpu_id = hard_smp_processor_id();
- current_tick_offset = timer_tick_offset;
-
- prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1;
}
/* /proc/profile writes can call this, don't __init it please. */
-static DEFINE_SPINLOCK(prof_setup_lock);
-
int setup_profiling_timer(unsigned int multiplier)
{
- unsigned long flags;
- int i;
-
- if ((!multiplier) || (timer_tick_offset / multiplier) < 1000)
- return -EINVAL;
-
- spin_lock_irqsave(&prof_setup_lock, flags);
- for_each_possible_cpu(i)
- prof_multiplier(i) = multiplier;
- current_tick_offset = (timer_tick_offset / multiplier);
- spin_unlock_irqrestore(&prof_setup_lock, flags);
-
- return 0;
+ return -EINVAL;
}
static void __init smp_tune_scheduling(void)
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index beffc82a1e8..d00f51a5683 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -212,7 +212,6 @@ EXPORT_SYMBOL(insl);
#ifdef CONFIG_PCI
EXPORT_SYMBOL(ebus_chain);
EXPORT_SYMBOL(isa_chain);
-EXPORT_SYMBOL(pci_memspace_mask);
EXPORT_SYMBOL(pci_alloc_consistent);
EXPORT_SYMBOL(pci_free_consistent);
EXPORT_SYMBOL(pci_map_single);
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index f84da4f1b70..259063f41f9 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -31,6 +31,9 @@
#include <linux/profile.h>
#include <linux/miscdevice.h>
#include <linux/rtc.h>
+#include <linux/kernel_stat.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
#include <asm/oplib.h>
#include <asm/mostek.h>
@@ -60,6 +63,7 @@ static void __iomem *mstk48t59_regs;
static int set_rtc_mmss(unsigned long);
#define TICK_PRIV_BIT (1UL << 63)
+#define TICKCMP_IRQ_BIT (1UL << 63)
#ifdef CONFIG_SMP
unsigned long profile_pc(struct pt_regs *regs)
@@ -93,21 +97,22 @@ static void tick_disable_protection(void)
: "g2");
}
-static void tick_init_tick(unsigned long offset)
+static void tick_disable_irq(void)
{
- tick_disable_protection();
-
__asm__ __volatile__(
- " rd %%tick, %%g1\n"
- " andn %%g1, %1, %%g1\n"
" ba,pt %%xcc, 1f\n"
- " add %%g1, %0, %%g1\n"
+ " nop\n"
" .align 64\n"
- "1: wr %%g1, 0x0, %%tick_cmpr\n"
+ "1: wr %0, 0x0, %%tick_cmpr\n"
" rd %%tick_cmpr, %%g0"
: /* no outputs */
- : "r" (offset), "r" (TICK_PRIV_BIT)
- : "g1");
+ : "r" (TICKCMP_IRQ_BIT));
+}
+
+static void tick_init_tick(void)
+{
+ tick_disable_protection();
+ tick_disable_irq();
}
static unsigned long tick_get_tick(void)
@@ -121,20 +126,14 @@ static unsigned long tick_get_tick(void)
return ret & ~TICK_PRIV_BIT;
}
-static unsigned long tick_get_compare(void)
+static int tick_add_compare(unsigned long adj)
{
- unsigned long ret;
+ unsigned long orig_tick, new_tick, new_compare;
- __asm__ __volatile__("rd %%tick_cmpr, %0\n\t"
- "mov %0, %0"
- : "=r" (ret));
+ __asm__ __volatile__("rd %%tick, %0"
+ : "=r" (orig_tick));
- return ret;
-}
-
-static unsigned long tick_add_compare(unsigned long adj)
-{
- unsigned long new_compare;
+ orig_tick &= ~TICKCMP_IRQ_BIT;
/* Workaround for Spitfire Errata (#54 I think??), I discovered
* this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
@@ -145,44 +144,41 @@ static unsigned long tick_add_compare(unsigned long adj)
* at the start of an I-cache line, and perform a dummy
* read back from %tick_cmpr right after writing to it. -DaveM
*/
- __asm__ __volatile__("rd %%tick_cmpr, %0\n\t"
- "ba,pt %%xcc, 1f\n\t"
- " add %0, %1, %0\n\t"
+ __asm__ __volatile__("ba,pt %%xcc, 1f\n\t"
+ " add %1, %2, %0\n\t"
".align 64\n"
"1:\n\t"
"wr %0, 0, %%tick_cmpr\n\t"
- "rd %%tick_cmpr, %%g0"
- : "=&r" (new_compare)
- : "r" (adj));
+ "rd %%tick_cmpr, %%g0\n\t"
+ : "=r" (new_compare)
+ : "r" (orig_tick), "r" (adj));
- return new_compare;
+ __asm__ __volatile__("rd %%tick, %0"
+ : "=r" (new_tick));
+ new_tick &= ~TICKCMP_IRQ_BIT;
+
+ return ((long)(new_tick - (orig_tick+adj))) > 0L;
}
-static unsigned long tick_add_tick(unsigned long adj, unsigned long offset)
+static unsigned long tick_add_tick(unsigned long adj)
{
- unsigned long new_tick, tmp;
+ unsigned long new_tick;
/* Also need to handle Blackbird bug here too. */
__asm__ __volatile__("rd %%tick, %0\n\t"
- "add %0, %2, %0\n\t"
+ "add %0, %1, %0\n\t"
"wrpr %0, 0, %%tick\n\t"
- "andn %0, %4, %1\n\t"
- "ba,pt %%xcc, 1f\n\t"
- " add %1, %3, %1\n\t"
- ".align 64\n"
- "1:\n\t"
- "wr %1, 0, %%tick_cmpr\n\t"
- "rd %%tick_cmpr, %%g0"
- : "=&r" (new_tick), "=&r" (tmp)
- : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT));
+ : "=&r" (new_tick)
+ : "r" (adj));
return new_tick;
}
static struct sparc64_tick_ops tick_operations __read_mostly = {
+ .name = "tick",
.init_tick = tick_init_tick,
+ .disable_irq = tick_disable_irq,
.get_tick = tick_get_tick,
- .get_compare = tick_get_compare,
.add_tick = tick_add_tick,
.add_compare = tick_add_compare,
.softint_mask = 1UL << 0,
@@ -190,7 +186,15 @@ static struct sparc64_tick_ops tick_operations __read_mostly = {
struct sparc64_tick_ops *tick_ops __read_mostly = &tick_operations;
-static void stick_init_tick(unsigned long offset)
+static void stick_disable_irq(void)
+{
+ __asm__ __volatile__(
+ "wr %0, 0x0, %%asr25"
+ : /* no outputs */
+ : "r" (TICKCMP_IRQ_BIT));
+}
+
+static void stick_init_tick(void)
{
/* Writes to the %tick and %stick register are not
* allowed on sun4v. The Hypervisor controls that
@@ -198,6 +202,7 @@ static void stick_init_tick(unsigned long offset)
*/
if (tlb_type != hypervisor) {
tick_disable_protection();
+ tick_disable_irq();
/* Let the user get at STICK too. */
__asm__ __volatile__(
@@ -209,14 +214,7 @@ static void stick_init_tick(unsigned long offset)
: "g1", "g2");
}
- __asm__ __volatile__(
- " rd %%asr24, %%g1\n"
- " andn %%g1, %1, %%g1\n"
- " add %%g1, %0, %%g1\n"
- " wr %%g1, 0x0, %%asr25"
- : /* no outputs */
- : "r" (offset), "r" (TICK_PRIV_BIT)
- : "g1");
+ stick_disable_irq();
}
static unsigned long stick_get_tick(void)
@@ -229,49 +227,43 @@ static unsigned long stick_get_tick(void)
return ret & ~TICK_PRIV_BIT;
}
-static unsigned long stick_get_compare(void)
+static unsigned long stick_add_tick(unsigned long adj)
{
- unsigned long ret;
-
- __asm__ __volatile__("rd %%asr25, %0"
- : "=r" (ret));
-
- return ret;
-}
-
-static unsigned long stick_add_tick(unsigned long adj, unsigned long offset)
-{
- unsigned long new_tick, tmp;
+ unsigned long new_tick;
__asm__ __volatile__("rd %%asr24, %0\n\t"
- "add %0, %2, %0\n\t"
+ "add %0, %1, %0\n\t"
"wr %0, 0, %%asr24\n\t"
- "andn %0, %4, %1\n\t"
- "add %1, %3, %1\n\t"
- "wr %1, 0, %%asr25"
- : "=&r" (new_tick), "=&r" (tmp)
- : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT));
+ : "=&r" (new_tick)
+ : "r" (adj));
return new_tick;
}
-static unsigned long stick_add_compare(unsigned long adj)
+static int stick_add_compare(unsigned long adj)
{
- unsigned long new_compare;
+ unsigned long orig_tick, new_tick;
- __asm__ __volatile__("rd %%asr25, %0\n\t"
- "add %0, %1, %0\n\t"
- "wr %0, 0, %%asr25"
- : "=&r" (new_compare)
- : "r" (adj));
+ __asm__ __volatile__("rd %%asr24, %0"
+ : "=r" (orig_tick));
+ orig_tick &= ~TICKCMP_IRQ_BIT;
+
+ __asm__ __volatile__("wr %0, 0, %%asr25"
+ : /* no outputs */
+ : "r" (orig_tick + adj));
+
+ __asm__ __volatile__("rd %%asr24, %0"
+ : "=r" (new_tick));
+ new_tick &= ~TICKCMP_IRQ_BIT;
- return new_compare;
+ return ((long)(new_tick - (orig_tick+adj))) > 0L;
}
static struct sparc64_tick_ops stick_operations __read_mostly = {
+ .name = "stick",
.init_tick = stick_init_tick,
+ .disable_irq = stick_disable_irq,
.get_tick = stick_get_tick,
- .get_compare = stick_get_compare,
.add_tick = stick_add_tick,
.add_compare = stick_add_compare,
.softint_mask = 1UL << 16,
@@ -320,20 +312,6 @@ static unsigned long __hbird_read_stick(void)
return ret;
}
-static unsigned long __hbird_read_compare(void)
-{
- unsigned long low, high;
- unsigned long addr = HBIRD_STICKCMP_ADDR;
-
- __asm__ __volatile__("ldxa [%2] %3, %0\n\t"
- "add %2, 0x8, %2\n\t"
- "ldxa [%2] %3, %1"
- : "=&r" (low), "=&r" (high), "=&r" (addr)
- : "i" (ASI_PHYS_BYPASS_EC_E), "2" (addr));
-
- return (high << 32UL) | low;
-}
-
static void __hbird_write_stick(unsigned long val)
{
unsigned long low = (val & 0xffffffffUL);
@@ -364,10 +342,13 @@ static void __hbird_write_compare(unsigned long val)
"i" (ASI_PHYS_BYPASS_EC_E));
}
-static void hbtick_init_tick(unsigned long offset)
+static void hbtick_disable_irq(void)
{
- unsigned long val;
+ __hbird_write_compare(TICKCMP_IRQ_BIT);
+}
+static void hbtick_init_tick(void)
+{
tick_disable_protection();
/* XXX This seems to be necessary to 'jumpstart' Hummingbird
@@ -377,8 +358,7 @@ static void hbtick_init_tick(unsigned long offset)
*/
__hbird_write_stick(__hbird_read_stick());
- val = __hbird_read_stick() & ~TICK_PRIV_BIT;
- __hbird_write_compare(val + offset);
+ hbtick_disable_irq();
}
static unsigned long hbtick_get_tick(void)
@@ -386,122 +366,95 @@ static unsigned long hbtick_get_tick(void)
return __hbird_read_stick() & ~TICK_PRIV_BIT;
}
-static unsigned long hbtick_get_compare(void)
-{
- return __hbird_read_compare();
-}
-
-static unsigned long hbtick_add_tick(unsigned long adj, unsigned long offset)
+static unsigned long hbtick_add_tick(unsigned long adj)
{
unsigned long val;
val = __hbird_read_stick() + adj;
__hbird_write_stick(val);
- val &= ~TICK_PRIV_BIT;
- __hbird_write_compare(val + offset);
-
return val;
}
-static unsigned long hbtick_add_compare(unsigned long adj)
+static int hbtick_add_compare(unsigned long adj)
{
- unsigned long val = __hbird_read_compare() + adj;
+ unsigned long val = __hbird_read_stick();
+ unsigned long val2;
- val &= ~TICK_PRIV_BIT;
+ val &= ~TICKCMP_IRQ_BIT;
+ val += adj;
__hbird_write_compare(val);
- return val;
+ val2 = __hbird_read_stick() & ~TICKCMP_IRQ_BIT;
+
+ return ((long)(val2 - val)) > 0L;
}
static struct sparc64_tick_ops hbtick_operations __read_mostly = {
+ .name = "hbtick",
.init_tick = hbtick_init_tick,
+ .disable_irq = hbtick_disable_irq,
.get_tick = hbtick_get_tick,
- .get_compare = hbtick_get_compare,
.add_tick = hbtick_add_tick,
.add_compare = hbtick_add_compare,
.softint_mask = 1UL << 0,
};
-/* timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- *
- * NOTE: On SUN5 systems the ticker interrupt comes in using 2
- * interrupts, one at level14 and one with softint bit 0.
- */
-unsigned long timer_tick_offset __read_mostly;
-
static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
#define TICK_SIZE (tick_nsec / 1000)
-static inline void timer_check_rtc(void)
-{
- /* last time the cmos clock got updated */
- static long last_rtc_update;
-
- /* Determine when to update the Mostek clock. */
- if (ntp_synced() &&
- xtime.tv_sec > last_rtc_update + 660 &&
- (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
- (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
- if (set_rtc_mmss(xtime.tv_sec) == 0)
- last_rtc_update = xtime.tv_sec;
- else
- last_rtc_update = xtime.tv_sec - 600;
- /* do it again in 60 s */
- }
-}
+#define USEC_AFTER 500000
+#define USEC_BEFORE 500000
-irqreturn_t timer_interrupt(int irq, void *dev_id)
-{
- unsigned long ticks, compare, pstate;
+static void sync_cmos_clock(unsigned long dummy);
- write_seqlock(&xtime_lock);
+static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
- do {
-#ifndef CONFIG_SMP
- profile_tick(CPU_PROFILING);
- update_process_times(user_mode(get_irq_regs()));
-#endif
- do_timer(1);
+static void sync_cmos_clock(unsigned long dummy)
+{
+ struct timeval now, next;
+ int fail = 1;
- /* Guarantee that the following sequences execute
- * uninterrupted.
+ /*
+ * If we have an externally synchronized Linux clock, then update
+ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+ * called as close as possible to 500 ms before the new second starts.
+ * This code is run on a timer. If the clock is set, that timer
+ * may not expire at the correct time. Thus, we adjust...
+ */
+ if (!ntp_synced())
+ /*
+ * Not synced, exit, do not restart a timer (if one is
+ * running, let it run out).
*/
- __asm__ __volatile__("rdpr %%pstate, %0\n\t"
- "wrpr %0, %1, %%pstate"
- : "=r" (pstate)
- : "i" (PSTATE_IE));
+ return;
- compare = tick_ops->add_compare(timer_tick_offset);
- ticks = tick_ops->get_tick();
+ do_gettimeofday(&now);
+ if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
+ now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
+ fail = set_rtc_mmss(now.tv_sec);
- /* Restore PSTATE_IE. */
- __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
- : /* no outputs */
- : "r" (pstate));
- } while (time_after_eq(ticks, compare));
+ next.tv_usec = USEC_AFTER - now.tv_usec;
+ if (next.tv_usec <= 0)
+ next.tv_usec += USEC_PER_SEC;
- timer_check_rtc();
+ if (!fail)
+ next.tv_sec = 659;
+ else
+ next.tv_sec = 0;
- write_sequnlock(&xtime_lock);
-
- return IRQ_HANDLED;
+ if (next.tv_usec >= USEC_PER_SEC) {
+ next.tv_sec++;
+ next.tv_usec -= USEC_PER_SEC;
+ }
+ mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
}
-#ifdef CONFIG_SMP
-void timer_tick_interrupt(struct pt_regs *regs)
+void notify_arch_cmos_timer(void)
{
- write_seqlock(&xtime_lock);
-
- do_timer(1);
-
- timer_check_rtc();
-
- write_sequnlock(&xtime_lock);
+ mod_timer(&sync_cmos_timer, jiffies + 1);
}
-#endif
/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
static void __init kick_start_clock(void)
@@ -751,7 +704,7 @@ retry:
return -EOPNOTSUPP;
}
-static int __init clock_model_matches(char *model)
+static int __init clock_model_matches(const char *model)
{
if (strcmp(model, "mk48t02") &&
strcmp(model, "mk48t08") &&
@@ -768,7 +721,7 @@ static int __init clock_model_matches(char *model)
static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->node;
- char *model = of_get_property(dp, "model", NULL);
+ const char *model = of_get_property(dp, "model", NULL);
unsigned long size, flags;
void __iomem *regs;
@@ -900,7 +853,6 @@ static unsigned long sparc64_init_timers(void)
prop = of_find_property(dp, "stick-frequency", NULL);
}
clock = *(unsigned int *) prop->value;
- timer_tick_offset = clock / HZ;
#ifdef CONFIG_SMP
smp_tick_init();
@@ -909,26 +861,6 @@ static unsigned long sparc64_init_timers(void)
return clock;
}
-static void sparc64_start_timers(void)
-{
- unsigned long pstate;
-
- /* Guarantee that the following sequences execute
- * uninterrupted.
- */
- __asm__ __volatile__("rdpr %%pstate, %0\n\t"
- "wrpr %0, %1, %%pstate"
- : "=r" (pstate)
- : "i" (PSTATE_IE));
-
- tick_ops->init_tick(timer_tick_offset);
-
- /* Restore PSTATE_IE. */
- __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
- : /* no outputs */
- : "r" (pstate));
-}
-
struct freq_table {
unsigned long clock_tick_ref;
unsigned int ref_freq;
@@ -975,29 +907,148 @@ static struct notifier_block sparc64_cpufreq_notifier_block = {
#endif /* CONFIG_CPU_FREQ */
-static struct time_interpolator sparc64_cpu_interpolator = {
- .source = TIME_SOURCE_CPU,
- .shift = 16,
- .mask = 0xffffffffffffffffLL
+static int sparc64_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ return tick_ops->add_compare(delta) ? -ETIME : 0;
+}
+
+static void sparc64_timer_setup(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_ONESHOT:
+ break;
+
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ tick_ops->disable_irq();
+ break;
+
+ case CLOCK_EVT_MODE_PERIODIC:
+ case CLOCK_EVT_MODE_UNUSED:
+ WARN_ON(1);
+ break;
+ };
+}
+
+static struct clock_event_device sparc64_clockevent = {
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = sparc64_timer_setup,
+ .set_next_event = sparc64_next_event,
+ .rating = 100,
+ .shift = 30,
+ .irq = -1,
};
+static DEFINE_PER_CPU(struct clock_event_device, sparc64_events);
-/* The quotient formula is taken from the IA64 port. */
-#define SPARC64_NSEC_PER_CYC_SHIFT 10UL
-void __init time_init(void)
+void timer_interrupt(int irq, struct pt_regs *regs)
{
- unsigned long clock = sparc64_init_timers();
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ unsigned long tick_mask = tick_ops->softint_mask;
+ int cpu = smp_processor_id();
+ struct clock_event_device *evt = &per_cpu(sparc64_events, cpu);
+
+ clear_softint(tick_mask);
+
+ irq_enter();
- sparc64_cpu_interpolator.frequency = clock;
- register_time_interpolator(&sparc64_cpu_interpolator);
+ kstat_this_cpu.irqs[0]++;
- /* Now that the interpolator is registered, it is
- * safe to start the timer ticking.
+ if (unlikely(!evt->event_handler)) {
+ printk(KERN_WARNING
+ "Spurious SPARC64 timer interrupt on cpu %d\n", cpu);
+ } else
+ evt->event_handler(evt);
+
+ irq_exit();
+
+ set_irq_regs(old_regs);
+}
+
+void __devinit setup_sparc64_timer(void)
+{
+ struct clock_event_device *sevt;
+ unsigned long pstate;
+
+ /* Guarantee that the following sequences execute
+ * uninterrupted.
*/
- sparc64_start_timers();
+ __asm__ __volatile__("rdpr %%pstate, %0\n\t"
+ "wrpr %0, %1, %%pstate"
+ : "=r" (pstate)
+ : "i" (PSTATE_IE));
+
+ tick_ops->init_tick();
+
+ /* Restore PSTATE_IE. */
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+ : /* no outputs */
+ : "r" (pstate));
+
+ sevt = &__get_cpu_var(sparc64_events);
+
+ memcpy(sevt, &sparc64_clockevent, sizeof(*sevt));
+ sevt->cpumask = cpumask_of_cpu(smp_processor_id());
+
+ clockevents_register_device(sevt);
+}
+
+#define SPARC64_NSEC_PER_CYC_SHIFT 32UL
+
+static struct clocksource clocksource_tick = {
+ .rating = 100,
+ .mask = CLOCKSOURCE_MASK(64),
+ .shift = 16,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void __init setup_clockevent_multiplier(unsigned long hz)
+{
+ unsigned long mult, shift = 32;
+
+ while (1) {
+ mult = div_sc(hz, NSEC_PER_SEC, shift);
+ if (mult && (mult >> 32UL) == 0UL)
+ break;
+
+ shift--;
+ }
+
+ sparc64_clockevent.shift = shift;
+ sparc64_clockevent.mult = mult;
+}
+
+void __init time_init(void)
+{
+ unsigned long clock = sparc64_init_timers();
timer_ticks_per_nsec_quotient =
- (((NSEC_PER_SEC << SPARC64_NSEC_PER_CYC_SHIFT) +
- (clock / 2)) / clock);
+ clocksource_hz2mult(clock, SPARC64_NSEC_PER_CYC_SHIFT);
+
+ clocksource_tick.name = tick_ops->name;
+ clocksource_tick.mult =
+ clocksource_hz2mult(clock,
+ clocksource_tick.shift);
+ clocksource_tick.read = tick_ops->get_tick;
+
+ printk("clocksource: mult[%x] shift[%d]\n",
+ clocksource_tick.mult, clocksource_tick.shift);
+
+ clocksource_register(&clocksource_tick);
+
+ sparc64_clockevent.name = tick_ops->name;
+
+ setup_clockevent_multiplier(clock);
+
+ sparc64_clockevent.max_delta_ns =
+ clockevent_delta2ns(0x7fffffffffffffff, &sparc64_clockevent);
+ sparc64_clockevent.min_delta_ns =
+ clockevent_delta2ns(0xF, &sparc64_clockevent);
+
+ printk("clockevent: mult[%lx] shift[%d]\n",
+ sparc64_clockevent.mult, sparc64_clockevent.shift);
+
+ setup_sparc64_timer();
#ifdef CONFIG_CPU_FREQ
cpufreq_register_notifier(&sparc64_cpufreq_notifier_block,
@@ -1126,10 +1177,6 @@ static int set_rtc_mmss(unsigned long nowtime)
#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */
static unsigned char mini_rtc_status; /* bitmapped status byte. */
-/* months start at 0 now */
-static unsigned char days_in_mo[] =
-{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
#define FEBRUARY 2
#define STARTOFTIME 1970
#define SECDAY 86400L
@@ -1278,8 +1325,7 @@ static int mini_rtc_ioctl(struct inode *inode, struct file *file,
case RTC_SET_TIME: /* Set the RTC */
{
- int year;
- unsigned char leap_yr;
+ int year, days;
if (!capable(CAP_SYS_TIME))
return -EACCES;
@@ -1288,14 +1334,14 @@ static int mini_rtc_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
year = wtime.tm_year + 1900;
- leap_yr = ((!(year % 4) && (year % 100)) ||
- !(year % 400));
+ days = month_days[wtime.tm_mon] +
+ ((wtime.tm_mon == 1) && leapyear(year));
- if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1))
+ if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) ||
+ (wtime.tm_mday < 1))
return -EINVAL;
- if (wtime.tm_mday < 0 || wtime.tm_mday >
- (days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr)))
+ if (wtime.tm_mday < 0 || wtime.tm_mday > days)
return -EINVAL;
if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index d7d2a8bdc66..7575aa371da 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -60,11 +60,7 @@ tl0_irq4: BTRAP(0x44)
tl0_irq5: TRAP_IRQ(handler_irq, 5)
tl0_irq6: BTRAP(0x46) BTRAP(0x47) BTRAP(0x48) BTRAP(0x49)
tl0_irq10: BTRAP(0x4a) BTRAP(0x4b) BTRAP(0x4c) BTRAP(0x4d)
-#ifndef CONFIG_SMP
-tl0_irq14: TRAP_IRQ(timer_irq, 14)
-#else
-tl0_irq14: TICK_SMP_IRQ
-#endif
+tl0_irq14: TRAP_IRQ(timer_interrupt, 14)
tl0_irq15: TRAP_IRQ(handler_irq, 15)
tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55)
tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b)
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index f146071a4b2..cafadcbcdf3 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -122,24 +122,19 @@ static void __init read_obp_memory(const char *property,
size = 0UL;
base = new_base;
}
- regs[i].phys_addr = base;
- regs[i].reg_size = size;
- }
-
- for (i = 0; i < ents; i++) {
- if (regs[i].reg_size == 0UL) {
- int j;
-
- for (j = i; j < ents - 1; j++) {
- regs[j].phys_addr =
- regs[j+1].phys_addr;
- regs[j].reg_size =
- regs[j+1].reg_size;
- }
-
- ents--;
+ if (size == 0UL) {
+ /* If it is empty, simply get rid of it.
+ * This simplifies the logic of the other
+ * functions that process these arrays.
+ */
+ memmove(&regs[i], &regs[i + 1],
+ (ents - i - 1) * sizeof(regs[0]));
i--;
+ ents--;
+ continue;
}
+ regs[i].phys_addr = base;
+ regs[i].reg_size = size;
}
*num_ents = ents;
@@ -154,15 +149,6 @@ unsigned long *sparc64_valid_addr_bitmap __read_mostly;
unsigned long kern_base __read_mostly;
unsigned long kern_size __read_mostly;
-/* get_new_mmu_context() uses "cache + 1". */
-DEFINE_SPINLOCK(ctx_alloc_lock);
-unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
-#define CTX_BMAP_SLOTS (1UL << (CTX_NR_BITS - 6))
-unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
-
-/* References to special section boundaries */
-extern char _start[], _end[];
-
/* Initial ramdisk setup */
extern unsigned long sparc_ramdisk_image64;
extern unsigned int sparc_ramdisk_image;
@@ -406,19 +392,70 @@ void __kprobes flush_icache_range(unsigned long start, unsigned long end)
if (tlb_type == spitfire) {
unsigned long kaddr;
- for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE)
- __flush_icache_page(__get_phys(kaddr));
+ /* This code only runs on Spitfire cpus so this is
+ * why we can assume _PAGE_PADDR_4U.
+ */
+ for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE) {
+ unsigned long paddr, mask = _PAGE_PADDR_4U;
+
+ if (kaddr >= PAGE_OFFSET)
+ paddr = kaddr & mask;
+ else {
+ pgd_t *pgdp = pgd_offset_k(kaddr);
+ pud_t *pudp = pud_offset(pgdp, kaddr);
+ pmd_t *pmdp = pmd_offset(pudp, kaddr);
+ pte_t *ptep = pte_offset_kernel(pmdp, kaddr);
+
+ paddr = pte_val(*ptep) & mask;
+ }
+ __flush_icache_page(paddr);
+ }
}
}
void show_mem(void)
{
- printk("Mem-info:\n");
+ unsigned long total = 0, reserved = 0;
+ unsigned long shared = 0, cached = 0;
+ pg_data_t *pgdat;
+
+ printk(KERN_INFO "Mem-info:\n");
show_free_areas();
- printk("Free swap: %6ldkB\n",
+ printk(KERN_INFO "Free swap: %6ldkB\n",
nr_swap_pages << (PAGE_SHIFT-10));
- printk("%ld pages of RAM\n", num_physpages);
- printk("%lu free pages\n", nr_free_pages());
+ for_each_online_pgdat(pgdat) {
+ unsigned long i, flags;
+
+ pgdat_resize_lock(pgdat, &flags);
+ for (i = 0; i < pgdat->node_spanned_pages; i++) {
+ struct page *page = pgdat_page_nr(pgdat, i);
+ total++;
+ if (PageReserved(page))
+ reserved++;
+ else if (PageSwapCache(page))
+ cached++;
+ else if (page_count(page))
+ shared += page_count(page) - 1;
+ }
+ pgdat_resize_unlock(pgdat, &flags);
+ }
+
+ printk(KERN_INFO "%lu pages of RAM\n", total);
+ printk(KERN_INFO "%lu reserved pages\n", reserved);
+ printk(KERN_INFO "%lu pages shared\n", shared);
+ printk(KERN_INFO "%lu pages swap cached\n", cached);
+
+ printk(KERN_INFO "%lu pages dirty\n",
+ global_page_state(NR_FILE_DIRTY));
+ printk(KERN_INFO "%lu pages writeback\n",
+ global_page_state(NR_WRITEBACK));
+ printk(KERN_INFO "%lu pages mapped\n",
+ global_page_state(NR_FILE_MAPPED));
+ printk(KERN_INFO "%lu pages slab\n",
+ global_page_state(NR_SLAB_RECLAIMABLE) +
+ global_page_state(NR_SLAB_UNRECLAIMABLE));
+ printk(KERN_INFO "%lu pages pagetables\n",
+ global_page_state(NR_PAGETABLE));
}
void mmu_info(struct seq_file *m)
@@ -658,6 +695,13 @@ void __flush_dcache_range(unsigned long start, unsigned long end)
}
#endif /* DCACHE_ALIASING_POSSIBLE */
+/* get_new_mmu_context() uses "cache + 1". */
+DEFINE_SPINLOCK(ctx_alloc_lock);
+unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
+#define MAX_CTX_NR (1UL << CTX_NR_BITS)
+#define CTX_BMAP_SLOTS BITS_TO_LONGS(MAX_CTX_NR)
+DECLARE_BITMAP(mmu_context_bmap, MAX_CTX_NR);
+
/* Caller does TLB context flushing on local CPU if necessary.
* The caller also ensures that CTX_VALID(mm->context) is false.
*
@@ -717,95 +761,6 @@ out:
smp_new_mmu_context_version();
}
-void sparc_ultra_dump_itlb(void)
-{
- int slot;
-
- if (tlb_type == spitfire) {
- printk ("Contents of itlb: ");
- for (slot = 0; slot < 14; slot++) printk (" ");
- printk ("%2x:%016lx,%016lx\n",
- 0,
- spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0));
- for (slot = 1; slot < 64; slot+=3) {
- printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n",
- slot,
- spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot),
- slot+1,
- spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1),
- slot+2,
- spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2));
- }
- } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
- printk ("Contents of itlb0:\n");
- for (slot = 0; slot < 16; slot+=2) {
- printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
- slot,
- cheetah_get_litlb_tag(slot), cheetah_get_litlb_data(slot),
- slot+1,
- cheetah_get_litlb_tag(slot+1), cheetah_get_litlb_data(slot+1));
- }
- printk ("Contents of itlb2:\n");
- for (slot = 0; slot < 128; slot+=2) {
- printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
- slot,
- cheetah_get_itlb_tag(slot), cheetah_get_itlb_data(slot),
- slot+1,
- cheetah_get_itlb_tag(slot+1), cheetah_get_itlb_data(slot+1));
- }
- }
-}
-
-void sparc_ultra_dump_dtlb(void)
-{
- int slot;
-
- if (tlb_type == spitfire) {
- printk ("Contents of dtlb: ");
- for (slot = 0; slot < 14; slot++) printk (" ");
- printk ("%2x:%016lx,%016lx\n", 0,
- spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0));
- for (slot = 1; slot < 64; slot+=3) {
- printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n",
- slot,
- spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot),
- slot+1,
- spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1),
- slot+2,
- spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
- }
- } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
- printk ("Contents of dtlb0:\n");
- for (slot = 0; slot < 16; slot+=2) {
- printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
- slot,
- cheetah_get_ldtlb_tag(slot), cheetah_get_ldtlb_data(slot),
- slot+1,
- cheetah_get_ldtlb_tag(slot+1), cheetah_get_ldtlb_data(slot+1));
- }
- printk ("Contents of dtlb2:\n");
- for (slot = 0; slot < 512; slot+=2) {
- printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
- slot,
- cheetah_get_dtlb_tag(slot, 2), cheetah_get_dtlb_data(slot, 2),
- slot+1,
- cheetah_get_dtlb_tag(slot+1, 2), cheetah_get_dtlb_data(slot+1, 2));
- }
- if (tlb_type == cheetah_plus) {
- printk ("Contents of dtlb3:\n");
- for (slot = 0; slot < 512; slot+=2) {
- printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
- slot,
- cheetah_get_dtlb_tag(slot, 3), cheetah_get_dtlb_data(slot, 3),
- slot+1,
- cheetah_get_dtlb_tag(slot+1, 3), cheetah_get_dtlb_data(slot+1, 3));
- }
- }
- }
-}
-
-extern unsigned long cmdline_memory_size;
-
/* Find a free area for the bootmem map, avoiding the kernel image
* and the initial ramdisk.
*/
@@ -815,8 +770,8 @@ static unsigned long __init choose_bootmap_pfn(unsigned long start_pfn,
unsigned long avoid_start, avoid_end, bootmap_size;
int i;
- bootmap_size = ((end_pfn - start_pfn) + 7) / 8;
- bootmap_size = ALIGN(bootmap_size, sizeof(long));
+ bootmap_size = bootmem_bootmap_pages(end_pfn - start_pfn);
+ bootmap_size <<= PAGE_SHIFT;
avoid_start = avoid_end = 0;
#ifdef CONFIG_BLK_DEV_INITRD
@@ -983,6 +938,20 @@ static void __init trim_pavail(unsigned long *cur_size_p,
}
}
+/* About pages_avail, this is the value we will use to calculate
+ * the zholes_size[] argument given to free_area_init_node(). The
+ * page allocator uses this to calculate nr_kernel_pages,
+ * nr_all_pages and zone->present_pages. On NUMA it is used
+ * to calculate zone->min_unmapped_pages and zone->min_slab_pages.
+ *
+ * So this number should really be set to what the page allocator
+ * actually ends up with. This means:
+ * 1) It should include bootmem map pages, we'll release those.
+ * 2) It should not include the kernel image, except for the
+ * __init sections which we will also release.
+ * 3) It should include the initrd image, since we'll release
+ * that too.
+ */
static unsigned long __init bootmem_init(unsigned long *pages_avail,
unsigned long phys_base)
{
@@ -1069,7 +1038,6 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
initrd_start, initrd_end);
#endif
reserve_bootmem(initrd_start, size);
- *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
initrd_start += PAGE_OFFSET;
initrd_end += PAGE_OFFSET;
@@ -1082,6 +1050,11 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
reserve_bootmem(kern_base, kern_size);
*pages_avail -= PAGE_ALIGN(kern_size) >> PAGE_SHIFT;
+ /* Add back in the initmem pages. */
+ size = ((unsigned long)(__init_end) & PAGE_MASK) -
+ PAGE_ALIGN((unsigned long)__init_begin);
+ *pages_avail += size >> PAGE_SHIFT;
+
/* Reserve the bootmem map. We do not account for it
* in pages_avail because we will release that memory
* in free_all_bootmem.
@@ -1092,7 +1065,6 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
(bootmap_pfn << PAGE_SHIFT), size);
#endif
reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size);
- *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
for (i = 0; i < pavail_ents; i++) {
unsigned long start_pfn, end_pfn;
@@ -1584,6 +1556,10 @@ void __init mem_init(void)
#ifdef CONFIG_DEBUG_BOOTMEM
prom_printf("mem_init: Calling free_all_bootmem().\n");
#endif
+
+ /* We subtract one to account for the mem_map_zero page
+ * allocated below.
+ */
totalram_pages = num_physpages = free_all_bootmem() - 1;
/*
@@ -1883,62 +1859,6 @@ static unsigned long kern_large_tte(unsigned long paddr)
return val | paddr;
}
-/*
- * Translate PROM's mapping we capture at boot time into physical address.
- * The second parameter is only set from prom_callback() invocations.
- */
-unsigned long prom_virt_to_phys(unsigned long promva, int *error)
-{
- unsigned long mask;
- int i;
-
- mask = _PAGE_PADDR_4U;
- if (tlb_type == hypervisor)
- mask = _PAGE_PADDR_4V;
-
- for (i = 0; i < prom_trans_ents; i++) {
- struct linux_prom_translation *p = &prom_trans[i];
-
- if (promva >= p->virt &&
- promva < (p->virt + p->size)) {
- unsigned long base = p->data & mask;
-
- if (error)
- *error = 0;
- return base + (promva & (8192 - 1));
- }
- }
- if (error)
- *error = 1;
- return 0UL;
-}
-
-/* XXX We should kill off this ugly thing at so me point. XXX */
-unsigned long sun4u_get_pte(unsigned long addr)
-{
- pgd_t *pgdp;
- pud_t *pudp;
- pmd_t *pmdp;
- pte_t *ptep;
- unsigned long mask = _PAGE_PADDR_4U;
-
- if (tlb_type == hypervisor)
- mask = _PAGE_PADDR_4V;
-
- if (addr >= PAGE_OFFSET)
- return addr & mask;
-
- if ((addr >= LOW_OBP_ADDRESS) && (addr < HI_OBP_ADDRESS))
- return prom_virt_to_phys(addr, NULL);
-
- pgdp = pgd_offset_k(addr);
- pudp = pud_offset(pgdp, addr);
- pmdp = pmd_offset(pudp, addr);
- ptep = pte_offset_kernel(pmdp, addr);
-
- return pte_val(*ptep) & mask;
-}
-
/* If not locked, zap it. */
void __flush_tlb_all(void)
{
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
index 9fcaad6dd11..542c808ec2c 100644
--- a/arch/sparc64/solaris/misc.c
+++ b/arch/sparc64/solaris/misc.c
@@ -224,7 +224,8 @@ static char *serial(char *buffer, int sz)
*buffer = 0;
if (dp) {
- char *val = of_get_property(dp, "system-board-serial#", &len);
+ const char *val =
+ of_get_property(dp, "system-board-serial#", &len);
if (val && len > 0) {
if (len > sz)
diff --git a/arch/xtensa/lib/Makefile b/arch/xtensa/lib/Makefile
index ed935b58e8a..6c4fdd86acd 100644
--- a/arch/xtensa/lib/Makefile
+++ b/arch/xtensa/lib/Makefile
@@ -2,6 +2,6 @@
# Makefile for Xtensa-specific library files.
#
-lib-y += memcopy.o memset.o checksum.o strcasecmp.o \
+lib-y += memcopy.o memset.o checksum.o \
usercopy.o strncpy_user.o strnlen_user.o
lib-$(CONFIG_PCI) += pci-auto.o
diff --git a/arch/xtensa/lib/strcasecmp.c b/arch/xtensa/lib/strcasecmp.c
deleted file mode 100644
index 165b2d6effa..00000000000
--- a/arch/xtensa/lib/strcasecmp.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * linux/arch/xtensa/lib/strcasecmp.c
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file "COPYING" in the main directory of
- * this archive for more details.
- *
- * Copyright (C) 2002 Tensilica Inc.
- */
-
-#include <linux/string.h>
-
-
-/* We handle nothing here except the C locale. Since this is used in
- only one place, on strings known to contain only 7 bit ASCII, this
- is ok. */
-
-int strcasecmp(const char *a, const char *b)
-{
- int ca, cb;
-
- do {
- ca = *a++ & 0xff;
- cb = *b++ & 0xff;
- if (ca >= 'A' && ca <= 'Z')
- ca += 'a' - 'A';
- if (cb >= 'A' && cb <= 'Z')
- cb += 'a' - 'A';
- } while (ca == cb && ca != '\0');
-
- return ca - cb;
-}
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c
index 4db2055cee3..001af7f7ddd 100644
--- a/drivers/mtd/maps/sun_uflash.c
+++ b/drivers/mtd/maps/sun_uflash.c
@@ -39,7 +39,7 @@ MODULE_VERSION("2.0");
static LIST_HEAD(device_list);
struct uflash_dev {
- char *name; /* device name */
+ const char *name; /* device name */
struct map_info map; /* mtd map info */
struct mtd_info *mtd; /* mtd info */
};
@@ -80,7 +80,7 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
up->name = of_get_property(dp, "model", NULL);
if (up->name && 0 < strlen(up->name))
- up->map.name = up->name;
+ up->map.name = (char *)up->name;
up->map.phys = res->start;
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 9df1038ec6b..5da73212ac9 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -64,11 +64,9 @@
#include <asm/uaccess.h>
#include <asm/irq.h>
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
#include <asm/idprom.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/pbm.h>
+#include <asm/prom.h>
#endif
#ifdef CONFIG_PPC_PMAC
@@ -2846,7 +2844,7 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return rc;
}
-#if (!defined(__sparc__) && !defined(CONFIG_PPC_PMAC))
+#if (!defined(CONFIG_SPARC) && !defined(CONFIG_PPC_PMAC))
/* Fetch MAC address from vital product data of PCI ROM. */
static int find_eth_addr_in_vpd(void __iomem *rom_base, int len, unsigned char *dev_addr)
{
@@ -2901,36 +2899,19 @@ static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr)
static int __devinit gem_get_device_address(struct gem *gp)
{
-#if defined(__sparc__) || defined(CONFIG_PPC_PMAC)
+#if defined(CONFIG_SPARC) || defined(CONFIG_PPC_PMAC)
struct net_device *dev = gp->dev;
-#endif
-
-#if defined(__sparc__)
- struct pci_dev *pdev = gp->pdev;
- struct pcidev_cookie *pcp = pdev->sysdata;
- int use_idprom = 1;
-
- if (pcp != NULL) {
- unsigned char *addr;
- int len;
-
- addr = of_get_property(pcp->prom_node, "local-mac-address",
- &len);
- if (addr && len == 6) {
- use_idprom = 0;
- memcpy(dev->dev_addr, addr, 6);
- }
- }
- if (use_idprom)
- memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
-#elif defined(CONFIG_PPC_PMAC)
const unsigned char *addr;
addr = get_property(gp->of_node, "local-mac-address", NULL);
if (addr == NULL) {
+#ifdef CONFIG_SPARC
+ addr = idprom->id_ethaddr;
+#else
printk("\n");
printk(KERN_ERR "%s: can't get mac-address\n", dev->name);
return -1;
+#endif
}
memcpy(dev->dev_addr, addr, 6);
#else
@@ -3088,7 +3069,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
/* On Apple, we want a reference to the Open Firmware device-tree
* node. We use it for clock control.
*/
-#ifdef CONFIG_PPC_PMAC
+#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC)
gp->of_node = pci_device_to_OF_node(pdev);
#endif
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
index a70067c85cc..58cf87c5751 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -1025,7 +1025,7 @@ struct gem {
struct pci_dev *pdev;
struct net_device *dev;
-#ifdef CONFIG_PPC_PMAC
+#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC)
struct device_node *of_node;
#endif
};
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 5304d7b94e5..51c3fe2108a 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -55,9 +55,6 @@
#ifdef CONFIG_PCI
#include <linux/pci.h>
-#ifdef CONFIG_SPARC
-#include <asm/pbm.h>
-#endif
#endif
#include "sunhme.h"
@@ -2701,7 +2698,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
dev->dev_addr[i] = macaddr[i];
macaddr[5]++;
} else {
- unsigned char *addr;
+ const unsigned char *addr;
int len;
addr = of_get_property(dp, "local-mac-address", &len);
@@ -2983,7 +2980,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
{
struct quattro *qp = NULL;
#ifdef CONFIG_SPARC
- struct pcidev_cookie *pcp;
+ struct device_node *dp;
#endif
struct happy_meal *hp;
struct net_device *dev;
@@ -2995,13 +2992,8 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
/* Now make sure pci_dev cookie is there. */
#ifdef CONFIG_SPARC
- pcp = pdev->sysdata;
- if (pcp == NULL) {
- printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n");
- return -ENODEV;
- }
-
- strcpy(prom_name, pcp->prom_node->name);
+ dp = pci_device_to_OF_node(pdev);
+ strcpy(prom_name, dp->name);
#else
if (is_quattro_p(pdev))
strcpy(prom_name, "SUNW,qfe");
@@ -3078,11 +3070,11 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
macaddr[5]++;
} else {
#ifdef CONFIG_SPARC
- unsigned char *addr;
+ const unsigned char *addr;
int len;
if (qfe_slot != -1 &&
- (addr = of_get_property(pcp->prom_node,
+ (addr = of_get_property(dp,
"local-mac-address", &len)) != NULL
&& len == 6) {
memcpy(dev->dev_addr, addr, 6);
@@ -3102,7 +3094,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
hp->tcvregs = (hpreg_base + 0x7000UL);
#ifdef CONFIG_SPARC
- hp->hm_revision = of_getintprop_default(pcp->prom_node, "hm-rev", 0xff);
+ hp->hm_revision = of_getintprop_default(dp, "hm-rev", 0xff);
if (hp->hm_revision == 0xff) {
unsigned char prev;
@@ -3297,7 +3289,7 @@ static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_devic
{
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct device_node *dp = dev->node;
- char *model = of_get_property(dp, "model", NULL);
+ const char *model = of_get_property(dp, "model", NULL);
int is_qfe = (match->data != NULL);
if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 38383e4e07a..9488f49ea56 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -47,10 +47,9 @@
#include <asm/byteorder.h>
#include <asm/uaccess.h>
-#ifdef CONFIG_SPARC64
+#ifdef CONFIG_SPARC
#include <asm/idprom.h>
-#include <asm/oplib.h>
-#include <asm/pbm.h>
+#include <asm/prom.h>
#endif
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
@@ -10987,24 +10986,20 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
return err;
}
-#ifdef CONFIG_SPARC64
+#ifdef CONFIG_SPARC
static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp)
{
struct net_device *dev = tp->dev;
struct pci_dev *pdev = tp->pdev;
- struct pcidev_cookie *pcp = pdev->sysdata;
-
- if (pcp != NULL) {
- unsigned char *addr;
- int len;
-
- addr = of_get_property(pcp->prom_node, "local-mac-address",
- &len);
- if (addr && len == 6) {
- memcpy(dev->dev_addr, addr, 6);
- memcpy(dev->perm_addr, dev->dev_addr, 6);
- return 0;
- }
+ struct device_node *dp = pci_device_to_OF_node(pdev);
+ const unsigned char *addr;
+ int len;
+
+ addr = of_get_property(dp, "local-mac-address", &len);
+ if (addr && len == 6) {
+ memcpy(dev->dev_addr, addr, 6);
+ memcpy(dev->perm_addr, dev->dev_addr, 6);
+ return 0;
}
return -ENODEV;
}
@@ -11025,7 +11020,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
u32 hi, lo, mac_offset;
int addr_ok = 0;
-#ifdef CONFIG_SPARC64
+#ifdef CONFIG_SPARC
if (!tg3_get_macaddr_sparc(tp))
return 0;
#endif
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index d19f8568440..861729806dc 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -63,7 +63,7 @@ MODULE_PARM_DESC (debug, "de2104x bitmapped message enable number");
/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
- || defined(__sparc__) || defined(__ia64__) \
+ || defined(CONFIG_SPARC) || defined(__ia64__) \
|| defined(__sh__) || defined(__mips__)
static int rx_copybreak = 1518;
#else
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index e40ddb86958..62143f92c23 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -1160,7 +1160,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
sprintf(lp->adapter_name,"%s (%s)", name, gendev->bus_id);
lp->dma_size = (NUM_RX_DESC + NUM_TX_DESC) * sizeof(struct de4x5_desc);
-#if defined(__alpha__) || defined(__powerpc__) || defined(__sparc_v9__) || defined(DE4X5_DO_MEMCPY)
+#if defined(__alpha__) || defined(__powerpc__) || defined(CONFIG_SPARC) || defined(DE4X5_DO_MEMCPY)
lp->dma_size += RX_BUFF_SZ * NUM_RX_DESC + DE4X5_ALIGN;
#endif
lp->rx_ring = dma_alloc_coherent(gendev, lp->dma_size,
@@ -1175,7 +1175,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
** Set up the RX descriptor ring (Intels)
** Allocate contiguous receive buffers, long word aligned (Alphas)
*/
-#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
+#if !defined(__alpha__) && !defined(__powerpc__) && !defined(CONFIG_SPARC) && !defined(DE4X5_DO_MEMCPY)
for (i=0; i<NUM_RX_DESC; i++) {
lp->rx_ring[i].status = 0;
lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
@@ -1252,11 +1252,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
mii_get_phy(dev);
}
-#ifndef __sparc_v9__
printk(" and requires IRQ%d (provided by %s).\n", dev->irq,
-#else
- printk(" and requires IRQ%x (provided by %s).\n", dev->irq,
-#endif
((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
}
@@ -3627,7 +3623,7 @@ de4x5_alloc_rx_buff(struct net_device *dev, int index, int len)
struct de4x5_private *lp = netdev_priv(dev);
struct sk_buff *p;
-#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
+#if !defined(__alpha__) && !defined(__powerpc__) && !defined(CONFIG_SPARC) && !defined(DE4X5_DO_MEMCPY)
struct sk_buff *ret;
u_long i=0, tmp;
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index e3774a52237..e9bf526ec53 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -36,8 +36,8 @@
#include <asm/unaligned.h>
#include <asm/uaccess.h>
-#ifdef __sparc__
-#include <asm/pbm.h>
+#ifdef CONFIG_SPARC
+#include <asm/prom.h>
#endif
static char version[] __devinitdata =
@@ -67,7 +67,7 @@ const char * const medianame[32] = {
/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
- || defined(__sparc__) || defined(__ia64__) \
+ || defined(CONFIG_SPARC) || defined(__ia64__) \
|| defined(__sh__) || defined(__mips__)
static int rx_copybreak = 1518;
#else
@@ -91,7 +91,7 @@ static int rx_copybreak = 100;
static int csr0 = 0x01A00000 | 0xE000;
#elif defined(__i386__) || defined(__powerpc__) || defined(__x86_64__)
static int csr0 = 0x01A00000 | 0x8000;
-#elif defined(__sparc__) || defined(__hppa__)
+#elif defined(CONFIG_SPARC) || defined(__hppa__)
/* The UltraSparc PCI controllers will disconnect at every 64-byte
* crossing anyways so it makes no sense to tell Tulip to burst
* any more than that.
@@ -1315,7 +1315,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
/* DM9102A has troubles with MRM & clear reserved bits 24:22, 20, 16, 7:1 */
if (tulip_uli_dm_quirk(pdev)) {
csr0 &= ~0x01f100ff;
-#if defined(__sparc__)
+#if defined(CONFIG_SPARC)
csr0 = (csr0 & ~0xff00) | 0xe000;
#endif
}
@@ -1535,23 +1535,19 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
Many PCI BIOSes also incorrectly report the IRQ line, so we correct
that here as well. */
if (sum == 0 || sum == 6*0xff) {
-#if defined(__sparc__)
- struct pcidev_cookie *pcp = pdev->sysdata;
+#if defined(CONFIG_SPARC)
+ struct device_node *dp = pci_device_to_OF_node(pdev);
+ const unsigned char *addr;
+ int len;
#endif
eeprom_missing = 1;
for (i = 0; i < 5; i++)
dev->dev_addr[i] = last_phys_addr[i];
dev->dev_addr[i] = last_phys_addr[i] + 1;
-#if defined(__sparc__)
- if (pcp) {
- unsigned char *addr;
- int len;
-
- addr = of_get_property(pcp->prom_node,
- "local-mac-address", &len);
- if (addr && len == 6)
- memcpy(dev->dev_addr, addr, 6);
- }
+#if defined(CONFIG_SPARC)
+ addr = of_get_property(dp, "local-mac-address", &len);
+ if (addr && len == 6)
+ memcpy(dev->dev_addr, addr, 6);
#endif
#if defined(__i386__) || defined(__x86_64__) /* Patch up x86 BIOS bug. */
if (last_irq)
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index d74fa871de1..5b71ac78bca 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -902,7 +902,7 @@ static void init_registers(struct net_device *dev)
}
#elif defined(__powerpc__) || defined(__i386__) || defined(__alpha__) || defined(__ia64__) || defined(__x86_64__)
i |= 0xE000;
-#elif defined(__sparc__) || defined (CONFIG_PARISC)
+#elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC)
i |= 0x4800;
#else
#warning Processor architecture undefined
diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
index 696b3b8aac8..f6417292737 100644
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -65,7 +65,7 @@ static int rx_copybreak = 100;
static int csr0 = 0x01A00000 | 0xE000;
#elif defined(__powerpc__)
static int csr0 = 0x01B00000 | 0x8000;
-#elif defined(__sparc__)
+#elif defined(CONFIG_SPARC)
static int csr0 = 0x01B00080 | 0x8000;
#elif defined(__i386__)
static int csr0 = 0x01A00000 | 0x8000;
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 2cea4f5d208..f2be2ead874 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -726,7 +726,7 @@ static struct miscdevice envctrl_dev = {
* Return: None.
*/
static void envctrl_set_mon(struct i2c_child_t *pchild,
- char *chnl_desc,
+ const char *chnl_desc,
int chnl_no)
{
/* Firmware only has temperature type. It does not distinguish
@@ -763,8 +763,8 @@ static void envctrl_set_mon(struct i2c_child_t *pchild,
static void envctrl_init_adc(struct i2c_child_t *pchild, struct device_node *dp)
{
int i = 0, len;
- char *pos;
- unsigned int *pval;
+ const char *pos;
+ const unsigned int *pval;
/* Firmware describe channels into a stream separated by a '\0'. */
pos = of_get_property(dp, "channels-description", &len);
@@ -859,7 +859,7 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
{
int len, i, tbls_size = 0;
struct device_node *dp = edev_child->prom_node;
- void *pval;
+ const void *pval;
/* Get device address. */
pval = of_get_property(dp, "reg", &len);
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index 6e99507aeb1..262f01e6859 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -190,7 +190,7 @@ static int __init flash_init(void)
}
if (!sdev) {
#ifdef CONFIG_PCI
- struct linux_prom_registers *ebus_regs;
+ const struct linux_prom_registers *ebus_regs;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 5041c9dfbe3..fbfeb89a6f3 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -44,7 +44,6 @@
#include <asm/openpromio.h>
#ifdef CONFIG_PCI
#include <linux/pci.h>
-#include <asm/pbm.h>
#endif
MODULE_AUTHOR("Thomas K. Dyas (tdyas@noc.rutgers.edu) and Eddie C. Dost (ecd@skynet.be)");
@@ -141,7 +140,7 @@ static int copyout(void __user *info, struct openpromio *opp, int len)
static int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize)
{
- void *pval;
+ const void *pval;
int len;
if (!dp ||
@@ -248,18 +247,17 @@ static int oprompci2node(void __user *argp, struct device_node *dp, struct openp
if (bufsize >= 2*sizeof(int)) {
#ifdef CONFIG_PCI
struct pci_dev *pdev;
- struct pcidev_cookie *pcp;
+ struct device_node *dp;
+
pdev = pci_get_bus_and_slot (((int *) op->oprom_array)[0],
((int *) op->oprom_array)[1]);
- pcp = pdev->sysdata;
- if (pcp != NULL) {
- dp = pcp->prom_node;
- data->current_node = dp;
- *((int *)op->oprom_array) = dp->node;
- op->oprom_size = sizeof(int);
- err = copyout(argp, op, bufsize + sizeof(int));
- }
+ dp = pci_device_to_OF_node(pdev);
+ data->current_node = dp;
+ *((int *)op->oprom_array) = dp->node;
+ op->oprom_size = sizeof(int);
+ err = copyout(argp, op, bufsize + sizeof(int));
+
pci_dev_put(pdev);
#endif
}
@@ -410,7 +408,7 @@ static int opiocget(void __user *argp, DATA *data)
struct opiocdesc op;
struct device_node *dp;
char *str;
- void *pval;
+ const void *pval;
int err, len;
if (copy_from_user(&op, argp, sizeof(op)))
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 6349dd617f8..eee590a51d8 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -35,7 +35,7 @@ struct sbus_bus *sbus_root;
static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
{
unsigned long base;
- void *pval;
+ const void *pval;
int len, err;
sdev->prom_node = dp->node;
@@ -86,7 +86,7 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde
static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
{
- void *pval;
+ const void *pval;
int len;
pval = of_get_property(dp, "ranges", &len);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 4cd280e8696..fcc4cb6c7f4 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1763,9 +1763,15 @@ config SUN3X_ESP
The ESP was an on-board SCSI controller used on Sun 3/80
machines. Say Y here to compile in support for it.
+config SCSI_ESP_CORE
+ tristate "ESP Scsi Driver Core"
+ depends on SCSI
+ select SCSI_SPI_ATTRS
+
config SCSI_SUNESP
tristate "Sparc ESP Scsi Driver"
depends on SBUS && SCSI
+ select SCSI_ESP_CORE
help
This is the driver for the Sun ESP SCSI host adapter. The ESP
chipset is present in most SPARC SBUS-based computers.
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 79ecf4ebe6e..70cff4c599d 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -106,7 +106,8 @@ obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o
obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/
obj-$(CONFIG_MEGARAID_SAS) += megaraid/
obj-$(CONFIG_SCSI_ACARD) += atp870u.o
-obj-$(CONFIG_SCSI_SUNESP) += esp.o
+obj-$(CONFIG_SCSI_ESP_CORE) += esp_scsi.o
+obj-$(CONFIG_SCSI_SUNESP) += sun_esp.o
obj-$(CONFIG_SCSI_GDTH) += gdth.o
obj-$(CONFIG_SCSI_INITIO) += initio.o
obj-$(CONFIG_SCSI_INIA100) += a100u2w.o
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
deleted file mode 100644
index 2c2fe80bc42..00000000000
--- a/drivers/scsi/esp.c
+++ /dev/null
@@ -1,4394 +0,0 @@
-/* esp.c: ESP Sun SCSI driver.
- *
- * Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net)
- */
-
-/* TODO:
- *
- * 1) Maybe disable parity checking in config register one for SCSI1
- * targets. (Gilmore says parity error on the SBus can lock up
- * old sun4c's)
- * 2) Add support for DMA2 pipelining.
- * 3) Add tagged queueing.
- */
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-
-#include "esp.h"
-
-#include <asm/sbus.h>
-#include <asm/dma.h>
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <asm/pgtable.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#ifndef __sparc_v9__
-#include <asm/machines.h>
-#include <asm/idprom.h>
-#endif
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_eh.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_tcq.h>
-
-#define DRV_VERSION "1.101"
-
-#define DEBUG_ESP
-/* #define DEBUG_ESP_HME */
-/* #define DEBUG_ESP_DATA */
-/* #define DEBUG_ESP_QUEUE */
-/* #define DEBUG_ESP_DISCONNECT */
-/* #define DEBUG_ESP_STATUS */
-/* #define DEBUG_ESP_PHASES */
-/* #define DEBUG_ESP_WORKBUS */
-/* #define DEBUG_STATE_MACHINE */
-/* #define DEBUG_ESP_CMDS */
-/* #define DEBUG_ESP_IRQS */
-/* #define DEBUG_SDTR */
-/* #define DEBUG_ESP_SG */
-
-/* Use the following to sprinkle debugging messages in a way which
- * suits you if combinations of the above become too verbose when
- * trying to track down a specific problem.
- */
-/* #define DEBUG_ESP_MISC */
-
-#if defined(DEBUG_ESP)
-#define ESPLOG(foo) printk foo
-#else
-#define ESPLOG(foo)
-#endif /* (DEBUG_ESP) */
-
-#if defined(DEBUG_ESP_HME)
-#define ESPHME(foo) printk foo
-#else
-#define ESPHME(foo)
-#endif
-
-#if defined(DEBUG_ESP_DATA)
-#define ESPDATA(foo) printk foo
-#else
-#define ESPDATA(foo)
-#endif
-
-#if defined(DEBUG_ESP_QUEUE)
-#define ESPQUEUE(foo) printk foo
-#else
-#define ESPQUEUE(foo)
-#endif
-
-#if defined(DEBUG_ESP_DISCONNECT)
-#define ESPDISC(foo) printk foo
-#else
-#define ESPDISC(foo)
-#endif
-
-#if defined(DEBUG_ESP_STATUS)
-#define ESPSTAT(foo) printk foo
-#else
-#define ESPSTAT(foo)
-#endif
-
-#if defined(DEBUG_ESP_PHASES)
-#define ESPPHASE(foo) printk foo
-#else
-#define ESPPHASE(foo)
-#endif
-
-#if defined(DEBUG_ESP_WORKBUS)
-#define ESPBUS(foo) printk foo
-#else
-#define ESPBUS(foo)
-#endif
-
-#if defined(DEBUG_ESP_IRQS)
-#define ESPIRQ(foo) printk foo
-#else
-#define ESPIRQ(foo)
-#endif
-
-#if defined(DEBUG_SDTR)
-#define ESPSDTR(foo) printk foo
-#else
-#define ESPSDTR(foo)
-#endif
-
-#if defined(DEBUG_ESP_MISC)
-#define ESPMISC(foo) printk foo
-#else
-#define ESPMISC(foo)
-#endif
-
-/* Command phase enumeration. */
-enum {
- not_issued = 0x00, /* Still in the issue_SC queue. */
-
- /* Various forms of selecting a target. */
-#define in_slct_mask 0x10
- in_slct_norm = 0x10, /* ESP is arbitrating, normal selection */
- in_slct_stop = 0x11, /* ESP will select, then stop with IRQ */
- in_slct_msg = 0x12, /* select, then send a message */
- in_slct_tag = 0x13, /* select and send tagged queue msg */
- in_slct_sneg = 0x14, /* select and acquire sync capabilities */
-
- /* Any post selection activity. */
-#define in_phases_mask 0x20
- in_datain = 0x20, /* Data is transferring from the bus */
- in_dataout = 0x21, /* Data is transferring to the bus */
- in_data_done = 0x22, /* Last DMA data operation done (maybe) */
- in_msgin = 0x23, /* Eating message from target */
- in_msgincont = 0x24, /* Eating more msg bytes from target */
- in_msgindone = 0x25, /* Decide what to do with what we got */
- in_msgout = 0x26, /* Sending message to target */
- in_msgoutdone = 0x27, /* Done sending msg out */
- in_cmdbegin = 0x28, /* Sending cmd after abnormal selection */
- in_cmdend = 0x29, /* Done sending slow cmd */
- in_status = 0x2a, /* Was in status phase, finishing cmd */
- in_freeing = 0x2b, /* freeing the bus for cmd cmplt or disc */
- in_the_dark = 0x2c, /* Don't know what bus phase we are in */
-
- /* Special states, ie. not normal bus transitions... */
-#define in_spec_mask 0x80
- in_abortone = 0x80, /* Aborting one command currently */
- in_abortall = 0x81, /* Blowing away all commands we have */
- in_resetdev = 0x82, /* SCSI target reset in progress */
- in_resetbus = 0x83, /* SCSI bus reset in progress */
- in_tgterror = 0x84, /* Target did something stupid */
-};
-
-enum {
- /* Zero has special meaning, see skipahead[12]. */
-/*0*/ do_never,
-
-/*1*/ do_phase_determine,
-/*2*/ do_reset_bus,
-/*3*/ do_reset_complete,
-/*4*/ do_work_bus,
-/*5*/ do_intr_end
-};
-
-/* Forward declarations. */
-static irqreturn_t esp_intr(int irq, void *dev_id);
-
-/* Debugging routines */
-struct esp_cmdstrings {
- u8 cmdchar;
- char *text;
-} esp_cmd_strings[] = {
- /* Miscellaneous */
- { ESP_CMD_NULL, "ESP_NOP", },
- { ESP_CMD_FLUSH, "FIFO_FLUSH", },
- { ESP_CMD_RC, "RSTESP", },
- { ESP_CMD_RS, "RSTSCSI", },
- /* Disconnected State Group */
- { ESP_CMD_RSEL, "RESLCTSEQ", },
- { ESP_CMD_SEL, "SLCTNATN", },
- { ESP_CMD_SELA, "SLCTATN", },
- { ESP_CMD_SELAS, "SLCTATNSTOP", },
- { ESP_CMD_ESEL, "ENSLCTRESEL", },
- { ESP_CMD_DSEL, "DISSELRESEL", },
- { ESP_CMD_SA3, "SLCTATN3", },
- { ESP_CMD_RSEL3, "RESLCTSEQ", },
- /* Target State Group */
- { ESP_CMD_SMSG, "SNDMSG", },
- { ESP_CMD_SSTAT, "SNDSTATUS", },
- { ESP_CMD_SDATA, "SNDDATA", },
- { ESP_CMD_DSEQ, "DISCSEQ", },
- { ESP_CMD_TSEQ, "TERMSEQ", },
- { ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", },
- { ESP_CMD_DCNCT, "DISC", },
- { ESP_CMD_RMSG, "RCVMSG", },
- { ESP_CMD_RCMD, "RCVCMD", },
- { ESP_CMD_RDATA, "RCVDATA", },
- { ESP_CMD_RCSEQ, "RCVCMDSEQ", },
- /* Initiator State Group */
- { ESP_CMD_TI, "TRANSINFO", },
- { ESP_CMD_ICCSEQ, "INICMDSEQCOMP", },
- { ESP_CMD_MOK, "MSGACCEPTED", },
- { ESP_CMD_TPAD, "TPAD", },
- { ESP_CMD_SATN, "SATN", },
- { ESP_CMD_RATN, "RATN", },
-};
-#define NUM_ESP_COMMANDS ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings)))
-
-/* Print textual representation of an ESP command */
-static inline void esp_print_cmd(u8 espcmd)
-{
- u8 dma_bit = espcmd & ESP_CMD_DMA;
- int i;
-
- espcmd &= ~dma_bit;
- for (i = 0; i < NUM_ESP_COMMANDS; i++)
- if (esp_cmd_strings[i].cmdchar == espcmd)
- break;
- if (i == NUM_ESP_COMMANDS)
- printk("ESP_Unknown");
- else
- printk("%s%s", esp_cmd_strings[i].text,
- ((dma_bit) ? "+DMA" : ""));
-}
-
-/* Print the status register's value */
-static inline void esp_print_statreg(u8 statreg)
-{
- u8 phase;
-
- printk("STATUS<");
- phase = statreg & ESP_STAT_PMASK;
- printk("%s,", (phase == ESP_DOP ? "DATA-OUT" :
- (phase == ESP_DIP ? "DATA-IN" :
- (phase == ESP_CMDP ? "COMMAND" :
- (phase == ESP_STATP ? "STATUS" :
- (phase == ESP_MOP ? "MSG-OUT" :
- (phase == ESP_MIP ? "MSG_IN" :
- "unknown")))))));
- if (statreg & ESP_STAT_TDONE)
- printk("TRANS_DONE,");
- if (statreg & ESP_STAT_TCNT)
- printk("TCOUNT_ZERO,");
- if (statreg & ESP_STAT_PERR)
- printk("P_ERROR,");
- if (statreg & ESP_STAT_SPAM)
- printk("SPAM,");
- if (statreg & ESP_STAT_INTR)
- printk("IRQ,");
- printk(">");
-}
-
-/* Print the interrupt register's value */
-static inline void esp_print_ireg(u8 intreg)
-{
- printk("INTREG< ");
- if (intreg & ESP_INTR_S)
- printk("SLCT_NATN ");
- if (intreg & ESP_INTR_SATN)
- printk("SLCT_ATN ");
- if (intreg & ESP_INTR_RSEL)
- printk("RSLCT ");
- if (intreg & ESP_INTR_FDONE)
- printk("FDONE ");
- if (intreg & ESP_INTR_BSERV)
- printk("BSERV ");
- if (intreg & ESP_INTR_DC)
- printk("DISCNCT ");
- if (intreg & ESP_INTR_IC)
- printk("ILL_CMD ");
- if (intreg & ESP_INTR_SR)
- printk("SCSI_BUS_RESET ");
- printk(">");
-}
-
-/* Print the sequence step registers contents */
-static inline void esp_print_seqreg(u8 stepreg)
-{
- stepreg &= ESP_STEP_VBITS;
- printk("STEP<%s>",
- (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" :
- (stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" :
- (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" :
- (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" :
- (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" :
- "UNKNOWN"))))));
-}
-
-static char *phase_string(int phase)
-{
- switch (phase) {
- case not_issued:
- return "UNISSUED";
- case in_slct_norm:
- return "SLCTNORM";
- case in_slct_stop:
- return "SLCTSTOP";
- case in_slct_msg:
- return "SLCTMSG";
- case in_slct_tag:
- return "SLCTTAG";
- case in_slct_sneg:
- return "SLCTSNEG";
- case in_datain:
- return "DATAIN";
- case in_dataout:
- return "DATAOUT";
- case in_data_done:
- return "DATADONE";
- case in_msgin:
- return "MSGIN";
- case in_msgincont:
- return "MSGINCONT";
- case in_msgindone:
- return "MSGINDONE";
- case in_msgout:
- return "MSGOUT";
- case in_msgoutdone:
- return "MSGOUTDONE";
- case in_cmdbegin:
- return "CMDBEGIN";
- case in_cmdend:
- return "CMDEND";
- case in_status:
- return "STATUS";
- case in_freeing:
- return "FREEING";
- case in_the_dark:
- return "CLUELESS";
- case in_abortone:
- return "ABORTONE";
- case in_abortall:
- return "ABORTALL";
- case in_resetdev:
- return "RESETDEV";
- case in_resetbus:
- return "RESETBUS";
- case in_tgterror:
- return "TGTERROR";
- default:
- return "UNKNOWN";
- };
-}
-
-#ifdef DEBUG_STATE_MACHINE
-static inline void esp_advance_phase(struct scsi_cmnd *s, int newphase)
-{
- ESPLOG(("<%s>", phase_string(newphase)));
- s->SCp.sent_command = s->SCp.phase;
- s->SCp.phase = newphase;
-}
-#else
-#define esp_advance_phase(__s, __newphase) \
- (__s)->SCp.sent_command = (__s)->SCp.phase; \
- (__s)->SCp.phase = (__newphase);
-#endif
-
-#ifdef DEBUG_ESP_CMDS
-static inline void esp_cmd(struct esp *esp, u8 cmd)
-{
- esp->espcmdlog[esp->espcmdent] = cmd;
- esp->espcmdent = (esp->espcmdent + 1) & 31;
- sbus_writeb(cmd, esp->eregs + ESP_CMD);
-}
-#else
-#define esp_cmd(__esp, __cmd) \
- sbus_writeb((__cmd), ((__esp)->eregs) + ESP_CMD)
-#endif
-
-#define ESP_INTSOFF(__dregs) \
- sbus_writel(sbus_readl((__dregs)+DMA_CSR)&~(DMA_INT_ENAB), (__dregs)+DMA_CSR)
-#define ESP_INTSON(__dregs) \
- sbus_writel(sbus_readl((__dregs)+DMA_CSR)|DMA_INT_ENAB, (__dregs)+DMA_CSR)
-#define ESP_IRQ_P(__dregs) \
- (sbus_readl((__dregs)+DMA_CSR) & (DMA_HNDL_INTR|DMA_HNDL_ERROR))
-
-/* How we use the various Linux SCSI data structures for operation.
- *
- * struct scsi_cmnd:
- *
- * We keep track of the synchronous capabilities of a target
- * in the device member, using sync_min_period and
- * sync_max_offset. These are the values we directly write
- * into the ESP registers while running a command. If offset
- * is zero the ESP will use asynchronous transfers.
- * If the borken flag is set we assume we shouldn't even bother
- * trying to negotiate for synchronous transfer as this target
- * is really stupid. If we notice the target is dropping the
- * bus, and we have been allowing it to disconnect, we clear
- * the disconnect flag.
- */
-
-
-/* Manipulation of the ESP command queues. Thanks to the aha152x driver
- * and its author, Juergen E. Fischer, for the methods used here.
- * Note that these are per-ESP queues, not global queues like
- * the aha152x driver uses.
- */
-static inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
-{
- struct scsi_cmnd *end;
-
- new_SC->host_scribble = (unsigned char *) NULL;
- if (!*SC)
- *SC = new_SC;
- else {
- for (end=*SC;end->host_scribble;end=(struct scsi_cmnd *)end->host_scribble)
- ;
- end->host_scribble = (unsigned char *) new_SC;
- }
-}
-
-static inline void prepend_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
-{
- new_SC->host_scribble = (unsigned char *) *SC;
- *SC = new_SC;
-}
-
-static inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd **SC)
-{
- struct scsi_cmnd *ptr;
- ptr = *SC;
- if (ptr)
- *SC = (struct scsi_cmnd *) (*SC)->host_scribble;
- return ptr;
-}
-
-static inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC, int target, int lun)
-{
- struct scsi_cmnd *ptr, *prev;
-
- for (ptr = *SC, prev = NULL;
- ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
- prev = ptr, ptr = (struct scsi_cmnd *) ptr->host_scribble)
- ;
- if (ptr) {
- if (prev)
- prev->host_scribble=ptr->host_scribble;
- else
- *SC=(struct scsi_cmnd *)ptr->host_scribble;
- }
- return ptr;
-}
-
-/* Resetting various pieces of the ESP scsi driver chipset/buses. */
-static void esp_reset_dma(struct esp *esp)
-{
- int can_do_burst16, can_do_burst32, can_do_burst64;
- int can_do_sbus64;
- u32 tmp;
-
- can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
- can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;
- can_do_burst64 = 0;
- can_do_sbus64 = 0;
- if (sbus_can_dma_64bit(esp->sdev))
- can_do_sbus64 = 1;
- if (sbus_can_burst64(esp->sdev))
- can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;
-
- /* Punt the DVMA into a known state. */
- if (esp->dma->revision != dvmahme) {
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- sbus_writel(tmp | DMA_RST_SCSI, esp->dregs + DMA_CSR);
- sbus_writel(tmp & ~DMA_RST_SCSI, esp->dregs + DMA_CSR);
- }
- switch (esp->dma->revision) {
- case dvmahme:
- /* This is the HME DVMA gate array. */
-
- sbus_writel(DMA_RESET_FAS366, esp->dregs + DMA_CSR);
- sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR);
-
- esp->prev_hme_dmacsr = (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB);
- esp->prev_hme_dmacsr &= ~(DMA_ENABLE|DMA_ST_WRITE|DMA_BRST_SZ);
-
- if (can_do_burst64)
- esp->prev_hme_dmacsr |= DMA_BRST64;
- else if (can_do_burst32)
- esp->prev_hme_dmacsr |= DMA_BRST32;
-
- if (can_do_sbus64) {
- esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
- sbus_set_sbus64(esp->sdev, esp->bursts);
- }
-
- /* This chip is horrible. */
- while (sbus_readl(esp->dregs + DMA_CSR) & DMA_PEND_READ)
- udelay(1);
-
- sbus_writel(0, esp->dregs + DMA_CSR);
- sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
-
- /* This is necessary to avoid having the SCSI channel
- * engine lock up on us.
- */
- sbus_writel(0, esp->dregs + DMA_ADDR);
-
- break;
- case dvmarev2:
- /* This is the gate array found in the sun4m
- * NCR SBUS I/O subsystem.
- */
- if (esp->erev != esp100) {
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- sbus_writel(tmp | DMA_3CLKS, esp->dregs + DMA_CSR);
- }
- break;
- case dvmarev3:
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- tmp &= ~DMA_3CLKS;
- tmp |= DMA_2CLKS;
- if (can_do_burst32) {
- tmp &= ~DMA_BRST_SZ;
- tmp |= DMA_BRST32;
- }
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- break;
- case dvmaesc1:
- /* This is the DMA unit found on SCSI/Ether cards. */
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- tmp |= DMA_ADD_ENABLE;
- tmp &= ~DMA_BCNT_ENAB;
- if (!can_do_burst32 && can_do_burst16) {
- tmp |= DMA_ESC_BURST;
- } else {
- tmp &= ~(DMA_ESC_BURST);
- }
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- break;
- default:
- break;
- };
- ESP_INTSON(esp->dregs);
-}
-
-/* Reset the ESP chip, _not_ the SCSI bus. */
-static void __init esp_reset_esp(struct esp *esp)
-{
- u8 family_code, version;
- int i;
-
- /* Now reset the ESP chip */
- esp_cmd(esp, ESP_CMD_RC);
- esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
- esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
-
- /* Reload the configuration registers */
- sbus_writeb(esp->cfact, esp->eregs + ESP_CFACT);
- esp->prev_stp = 0;
- sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
- esp->prev_soff = 0;
- sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
- sbus_writeb(esp->neg_defp, esp->eregs + ESP_TIMEO);
-
- /* This is the only point at which it is reliable to read
- * the ID-code for a fast ESP chip variants.
- */
- esp->max_period = ((35 * esp->ccycle) / 1000);
- if (esp->erev == fast) {
- version = sbus_readb(esp->eregs + ESP_UID);
- family_code = (version & 0xf8) >> 3;
- if (family_code == 0x02)
- esp->erev = fas236;
- else if (family_code == 0x0a)
- esp->erev = fashme; /* Version is usually '5'. */
- else
- esp->erev = fas100a;
- ESPMISC(("esp%d: FAST chip is %s (family=%d, version=%d)\n",
- esp->esp_id,
- (esp->erev == fas236) ? "fas236" :
- ((esp->erev == fas100a) ? "fas100a" :
- "fasHME"), family_code, (version & 7)));
-
- esp->min_period = ((4 * esp->ccycle) / 1000);
- } else {
- esp->min_period = ((5 * esp->ccycle) / 1000);
- }
- esp->max_period = (esp->max_period + 3)>>2;
- esp->min_period = (esp->min_period + 3)>>2;
-
- sbus_writeb(esp->config1, esp->eregs + ESP_CFG1);
- switch (esp->erev) {
- case esp100:
- /* nothing to do */
- break;
- case esp100a:
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- break;
- case esp236:
- /* Slow 236 */
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- esp->prev_cfg3 = esp->config3[0];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- break;
- case fashme:
- esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
- /* fallthrough... */
- case fas236:
- /* Fast 236 or HME */
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- for (i = 0; i < 16; i++) {
- if (esp->erev == fashme) {
- u8 cfg3;
-
- cfg3 = ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH;
- if (esp->scsi_id >= 8)
- cfg3 |= ESP_CONFIG3_IDBIT3;
- esp->config3[i] |= cfg3;
- } else {
- esp->config3[i] |= ESP_CONFIG3_FCLK;
- }
- }
- esp->prev_cfg3 = esp->config3[0];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- if (esp->erev == fashme) {
- esp->radelay = 80;
- } else {
- if (esp->diff)
- esp->radelay = 0;
- else
- esp->radelay = 96;
- }
- break;
- case fas100a:
- /* Fast 100a */
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- for (i = 0; i < 16; i++)
- esp->config3[i] |= ESP_CONFIG3_FCLOCK;
- esp->prev_cfg3 = esp->config3[0];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- esp->radelay = 32;
- break;
- default:
- panic("esp: what could it be... I wonder...");
- break;
- };
-
- /* Eat any bitrot in the chip */
- sbus_readb(esp->eregs + ESP_INTRPT);
- udelay(100);
-}
-
-/* This places the ESP into a known state at boot time. */
-static void __init esp_bootup_reset(struct esp *esp)
-{
- u8 tmp;
-
- /* Reset the DMA */
- esp_reset_dma(esp);
-
- /* Reset the ESP */
- esp_reset_esp(esp);
-
- /* Reset the SCSI bus, but tell ESP not to generate an irq */
- tmp = sbus_readb(esp->eregs + ESP_CFG1);
- tmp |= ESP_CONFIG1_SRRDISAB;
- sbus_writeb(tmp, esp->eregs + ESP_CFG1);
-
- esp_cmd(esp, ESP_CMD_RS);
- udelay(400);
-
- sbus_writeb(esp->config1, esp->eregs + ESP_CFG1);
-
- /* Eat any bitrot in the chip and we are done... */
- sbus_readb(esp->eregs + ESP_INTRPT);
-}
-
-static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev)
-{
- struct sbus_dev *sdev = esp->sdev;
- struct sbus_dma *dma;
-
- if (dma_sdev != NULL) {
- for_each_dvma(dma) {
- if (dma->sdev == dma_sdev)
- break;
- }
- } else {
- for_each_dvma(dma) {
- /* If allocated already, can't use it. */
- if (dma->allocated)
- continue;
-
- if (dma->sdev == NULL)
- break;
-
- /* If bus + slot are the same and it has the
- * correct OBP name, it's ours.
- */
- if (sdev->bus == dma->sdev->bus &&
- sdev->slot == dma->sdev->slot &&
- (!strcmp(dma->sdev->prom_name, "dma") ||
- !strcmp(dma->sdev->prom_name, "espdma")))
- break;
- }
- }
-
- /* If we don't know how to handle the dvma,
- * do not use this device.
- */
- if (dma == NULL) {
- printk("Cannot find dvma for ESP%d's SCSI\n", esp->esp_id);
- return -1;
- }
- if (dma->allocated) {
- printk("esp%d: can't use my espdma\n", esp->esp_id);
- return -1;
- }
- dma->allocated = 1;
- esp->dma = dma;
- esp->dregs = dma->regs;
-
- return 0;
-}
-
-static int __init esp_map_regs(struct esp *esp, int hme)
-{
- struct sbus_dev *sdev = esp->sdev;
- struct resource *res;
-
- /* On HME, two reg sets exist, first is DVMA,
- * second is ESP registers.
- */
- if (hme)
- res = &sdev->resource[1];
- else
- res = &sdev->resource[0];
-
- esp->eregs = sbus_ioremap(res, 0, ESP_REG_SIZE, "ESP Registers");
-
- if (esp->eregs == 0)
- return -1;
- return 0;
-}
-
-static int __init esp_map_cmdarea(struct esp *esp)
-{
- struct sbus_dev *sdev = esp->sdev;
-
- esp->esp_command = sbus_alloc_consistent(sdev, 16,
- &esp->esp_command_dvma);
- if (esp->esp_command == NULL ||
- esp->esp_command_dvma == 0)
- return -1;
- return 0;
-}
-
-static int __init esp_register_irq(struct esp *esp)
-{
- esp->ehost->irq = esp->irq = esp->sdev->irqs[0];
-
- /* We used to try various overly-clever things to
- * reduce the interrupt processing overhead on
- * sun4c/sun4m when multiple ESP's shared the
- * same IRQ. It was too complex and messy to
- * sanely maintain.
- */
- if (request_irq(esp->ehost->irq, esp_intr,
- IRQF_SHARED, "ESP SCSI", esp)) {
- printk("esp%d: Cannot acquire irq line\n",
- esp->esp_id);
- return -1;
- }
-
- printk("esp%d: IRQ %d ", esp->esp_id,
- esp->ehost->irq);
-
- return 0;
-}
-
-static void __init esp_get_scsi_id(struct esp *esp)
-{
- struct sbus_dev *sdev = esp->sdev;
- struct device_node *dp = sdev->ofdev.node;
-
- esp->scsi_id = of_getintprop_default(dp,
- "initiator-id",
- -1);
- if (esp->scsi_id == -1)
- esp->scsi_id = of_getintprop_default(dp,
- "scsi-initiator-id",
- -1);
- if (esp->scsi_id == -1)
- esp->scsi_id = (sdev->bus == NULL) ? 7 :
- of_getintprop_default(sdev->bus->ofdev.node,
- "scsi-initiator-id",
- 7);
- esp->ehost->this_id = esp->scsi_id;
- esp->scsi_id_mask = (1 << esp->scsi_id);
-
-}
-
-static void __init esp_get_clock_params(struct esp *esp)
-{
- struct sbus_dev *sdev = esp->sdev;
- int prom_node = esp->prom_node;
- int sbus_prom_node;
- unsigned int fmhz;
- u8 ccf;
-
- if (sdev != NULL && sdev->bus != NULL)
- sbus_prom_node = sdev->bus->prom_node;
- else
- sbus_prom_node = 0;
-
- /* This is getting messy but it has to be done
- * correctly or else you get weird behavior all
- * over the place. We are trying to basically
- * figure out three pieces of information.
- *
- * a) Clock Conversion Factor
- *
- * This is a representation of the input
- * crystal clock frequency going into the
- * ESP on this machine. Any operation whose
- * timing is longer than 400ns depends on this
- * value being correct. For example, you'll
- * get blips for arbitration/selection during
- * high load or with multiple targets if this
- * is not set correctly.
- *
- * b) Selection Time-Out
- *
- * The ESP isn't very bright and will arbitrate
- * for the bus and try to select a target
- * forever if you let it. This value tells
- * the ESP when it has taken too long to
- * negotiate and that it should interrupt
- * the CPU so we can see what happened.
- * The value is computed as follows (from
- * NCR/Symbios chip docs).
- *
- * (Time Out Period) * (Input Clock)
- * STO = ----------------------------------
- * (8192) * (Clock Conversion Factor)
- *
- * You usually want the time out period to be
- * around 250ms, I think we'll set it a little
- * bit higher to account for fully loaded SCSI
- * bus's and slow devices that don't respond so
- * quickly to selection attempts. (yeah, I know
- * this is out of spec. but there is a lot of
- * buggy pieces of firmware out there so bite me)
- *
- * c) Imperical constants for synchronous offset
- * and transfer period register values
- *
- * This entails the smallest and largest sync
- * period we could ever handle on this ESP.
- */
-
- fmhz = prom_getintdefault(prom_node, "clock-frequency", -1);
- if (fmhz == -1)
- fmhz = (!sbus_prom_node) ? 0 :
- prom_getintdefault(sbus_prom_node, "clock-frequency", -1);
-
- if (fmhz <= (5000000))
- ccf = 0;
- else
- ccf = (((5000000 - 1) + (fmhz))/(5000000));
-
- if (!ccf || ccf > 8) {
- /* If we can't find anything reasonable,
- * just assume 20MHZ. This is the clock
- * frequency of the older sun4c's where I've
- * been unable to find the clock-frequency
- * PROM property. All other machines provide
- * useful values it seems.
- */
- ccf = ESP_CCF_F4;
- fmhz = (20000000);
- }
-
- if (ccf == (ESP_CCF_F7 + 1))
- esp->cfact = ESP_CCF_F0;
- else if (ccf == ESP_CCF_NEVER)
- esp->cfact = ESP_CCF_F2;
- else
- esp->cfact = ccf;
- esp->raw_cfact = ccf;
-
- esp->cfreq = fmhz;
- esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
- esp->ctick = ESP_TICK(ccf, esp->ccycle);
- esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
- esp->sync_defp = SYNC_DEFP_SLOW;
-
- printk("SCSI ID %d Clk %dMHz CCYC=%d CCF=%d TOut %d ",
- esp->scsi_id, (fmhz / 1000000),
- (int)esp->ccycle, (int)ccf, (int) esp->neg_defp);
-}
-
-static void __init esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
-{
- struct sbus_dev *sdev = esp->sdev;
- u8 bursts;
-
- bursts = prom_getintdefault(esp->prom_node, "burst-sizes", 0xff);
-
- if (dma) {
- u8 tmp = prom_getintdefault(dma->prom_node,
- "burst-sizes", 0xff);
- if (tmp != 0xff)
- bursts &= tmp;
- }
-
- if (sdev->bus) {
- u8 tmp = prom_getintdefault(sdev->bus->prom_node,
- "burst-sizes", 0xff);
- if (tmp != 0xff)
- bursts &= tmp;
- }
-
- if (bursts == 0xff ||
- (bursts & DMA_BURST16) == 0 ||
- (bursts & DMA_BURST32) == 0)
- bursts = (DMA_BURST32 - 1);
-
- esp->bursts = bursts;
-}
-
-static void __init esp_get_revision(struct esp *esp)
-{
- u8 tmp;
-
- esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
- esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
-
- tmp = sbus_readb(esp->eregs + ESP_CFG2);
- tmp &= ~ESP_CONFIG2_MAGIC;
- if (tmp != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
- /* If what we write to cfg2 does not come back, cfg2
- * is not implemented, therefore this must be a plain
- * esp100.
- */
- esp->erev = esp100;
- printk("NCR53C90(esp100)\n");
- } else {
- esp->config2 = 0;
- esp->prev_cfg3 = esp->config3[0] = 5;
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- sbus_writeb(0, esp->eregs + ESP_CFG3);
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-
- tmp = sbus_readb(esp->eregs + ESP_CFG3);
- if (tmp != 5) {
- /* The cfg2 register is implemented, however
- * cfg3 is not, must be esp100a.
- */
- esp->erev = esp100a;
- printk("NCR53C90A(esp100a)\n");
- } else {
- int target;
-
- for (target = 0; target < 16; target++)
- esp->config3[target] = 0;
- esp->prev_cfg3 = 0;
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-
- /* All of cfg{1,2,3} implemented, must be one of
- * the fas variants, figure out which one.
- */
- if (esp->raw_cfact > ESP_CCF_F5) {
- esp->erev = fast;
- esp->sync_defp = SYNC_DEFP_FAST;
- printk("NCR53C9XF(espfast)\n");
- } else {
- esp->erev = esp236;
- printk("NCR53C9x(esp236)\n");
- }
- esp->config2 = 0;
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- }
- }
-}
-
-static void __init esp_init_swstate(struct esp *esp)
-{
- int i;
-
- /* Command queues... */
- esp->current_SC = NULL;
- esp->disconnected_SC = NULL;
- esp->issue_SC = NULL;
-
- /* Target and current command state... */
- esp->targets_present = 0;
- esp->resetting_bus = 0;
- esp->snip = 0;
-
- init_waitqueue_head(&esp->reset_queue);
-
- /* Debugging... */
- for(i = 0; i < 32; i++)
- esp->espcmdlog[i] = 0;
- esp->espcmdent = 0;
-
- /* MSG phase state... */
- for(i = 0; i < 16; i++) {
- esp->cur_msgout[i] = 0;
- esp->cur_msgin[i] = 0;
- }
- esp->prevmsgout = esp->prevmsgin = 0;
- esp->msgout_len = esp->msgin_len = 0;
-
- /* Clear the one behind caches to hold unmatchable values. */
- esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff;
- esp->prev_hme_dmacsr = 0xffffffff;
-}
-
-static int __init detect_one_esp(struct scsi_host_template *tpnt,
- struct device *dev,
- struct sbus_dev *esp_dev,
- struct sbus_dev *espdma,
- struct sbus_bus *sbus,
- int hme)
-{
- static int instance;
- struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp));
- struct esp *esp;
-
- if (!esp_host)
- return -ENOMEM;
-
- if (hme)
- esp_host->max_id = 16;
- esp = (struct esp *) esp_host->hostdata;
- esp->ehost = esp_host;
- esp->sdev = esp_dev;
- esp->esp_id = instance;
- esp->prom_node = esp_dev->prom_node;
- prom_getstring(esp->prom_node, "name", esp->prom_name,
- sizeof(esp->prom_name));
-
- if (esp_find_dvma(esp, espdma) < 0)
- goto fail_unlink;
- if (esp_map_regs(esp, hme) < 0) {
- printk("ESP registers unmappable");
- goto fail_dvma_release;
- }
- if (esp_map_cmdarea(esp) < 0) {
- printk("ESP DVMA transport area unmappable");
- goto fail_unmap_regs;
- }
- if (esp_register_irq(esp) < 0)
- goto fail_unmap_cmdarea;
-
- esp_get_scsi_id(esp);
-
- esp->diff = prom_getbool(esp->prom_node, "differential");
- if (esp->diff)
- printk("Differential ");
-
- esp_get_clock_params(esp);
- esp_get_bursts(esp, espdma);
- esp_get_revision(esp);
- esp_init_swstate(esp);
-
- esp_bootup_reset(esp);
-
- if (scsi_add_host(esp_host, dev))
- goto fail_free_irq;
-
- dev_set_drvdata(&esp_dev->ofdev.dev, esp);
-
- scsi_scan_host(esp_host);
- instance++;
-
- return 0;
-
-fail_free_irq:
- free_irq(esp->ehost->irq, esp);
-
-fail_unmap_cmdarea:
- sbus_free_consistent(esp->sdev, 16,
- (void *) esp->esp_command,
- esp->esp_command_dvma);
-
-fail_unmap_regs:
- sbus_iounmap(esp->eregs, ESP_REG_SIZE);
-
-fail_dvma_release:
- esp->dma->allocated = 0;
-
-fail_unlink:
- scsi_host_put(esp_host);
- return -1;
-}
-
-/* Detecting ESP chips on the machine. This is the simple and easy
- * version.
- */
-static int __devexit esp_remove_common(struct esp *esp)
-{
- unsigned int irq = esp->ehost->irq;
-
- scsi_remove_host(esp->ehost);
-
- ESP_INTSOFF(esp->dregs);
-#if 0
- esp_reset_dma(esp);
- esp_reset_esp(esp);
-#endif
-
- free_irq(irq, esp);
- sbus_free_consistent(esp->sdev, 16,
- (void *) esp->esp_command, esp->esp_command_dvma);
- sbus_iounmap(esp->eregs, ESP_REG_SIZE);
- esp->dma->allocated = 0;
-
- scsi_host_put(esp->ehost);
-
- return 0;
-}
-
-
-#ifdef CONFIG_SUN4
-
-#include <asm/sun4paddr.h>
-
-static struct sbus_dev sun4_esp_dev;
-
-static int __init esp_sun4_probe(struct scsi_host_template *tpnt)
-{
- if (sun4_esp_physaddr) {
- memset(&sun4_esp_dev, 0, sizeof(sun4_esp_dev));
- sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
- sun4_esp_dev.irqs[0] = 4;
- sun4_esp_dev.resource[0].start = sun4_esp_physaddr;
- sun4_esp_dev.resource[0].end =
- sun4_esp_physaddr + ESP_REG_SIZE - 1;
- sun4_esp_dev.resource[0].flags = IORESOURCE_IO;
-
- return detect_one_esp(tpnt, NULL,
- &sun4_esp_dev, NULL, NULL, 0);
- }
- return 0;
-}
-
-static int __devexit esp_sun4_remove(void)
-{
- struct of_device *dev = &sun4_esp_dev.ofdev;
- struct esp *esp = dev_get_drvdata(&dev->dev);
-
- return esp_remove_common(esp);
-}
-
-#else /* !CONFIG_SUN4 */
-
-static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- struct device_node *dp = dev->node;
- struct sbus_dev *dma_sdev = NULL;
- int hme = 0;
-
- if (dp->parent &&
- (!strcmp(dp->parent->name, "espdma") ||
- !strcmp(dp->parent->name, "dma")))
- dma_sdev = sdev->parent;
- else if (!strcmp(dp->name, "SUNW,fas")) {
- dma_sdev = sdev;
- hme = 1;
- }
-
- return detect_one_esp(match->data, &dev->dev,
- sdev, dma_sdev, sdev->bus, hme);
-}
-
-static int __devexit esp_sbus_remove(struct of_device *dev)
-{
- struct esp *esp = dev_get_drvdata(&dev->dev);
-
- return esp_remove_common(esp);
-}
-
-#endif /* !CONFIG_SUN4 */
-
-/* The info function will return whatever useful
- * information the developer sees fit. If not provided, then
- * the name field will be used instead.
- */
-static const char *esp_info(struct Scsi_Host *host)
-{
- struct esp *esp;
-
- esp = (struct esp *) host->hostdata;
- switch (esp->erev) {
- case esp100:
- return "Sparc ESP100 (NCR53C90)";
- case esp100a:
- return "Sparc ESP100A (NCR53C90A)";
- case esp236:
- return "Sparc ESP236";
- case fas236:
- return "Sparc ESP236-FAST";
- case fashme:
- return "Sparc ESP366-HME";
- case fas100a:
- return "Sparc ESP100A-FAST";
- default:
- return "Bogon ESP revision";
- };
-}
-
-/* From Wolfgang Stanglmeier's NCR scsi driver. */
-struct info_str
-{
- char *buffer;
- int length;
- int offset;
- int pos;
-};
-
-static void copy_mem_info(struct info_str *info, char *data, int len)
-{
- if (info->pos + len > info->length)
- len = info->length - info->pos;
-
- if (info->pos + len < info->offset) {
- info->pos += len;
- return;
- }
- if (info->pos < info->offset) {
- data += (info->offset - info->pos);
- len -= (info->offset - info->pos);
- }
-
- if (len > 0) {
- memcpy(info->buffer + info->pos, data, len);
- info->pos += len;
- }
-}
-
-static int copy_info(struct info_str *info, char *fmt, ...)
-{
- va_list args;
- char buf[81];
- int len;
-
- va_start(args, fmt);
- len = vsprintf(buf, fmt, args);
- va_end(args);
-
- copy_mem_info(info, buf, len);
- return len;
-}
-
-static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len)
-{
- struct scsi_device *sdev;
- struct info_str info;
- int i;
-
- info.buffer = ptr;
- info.length = len;
- info.offset = offset;
- info.pos = 0;
-
- copy_info(&info, "Sparc ESP Host Adapter:\n");
- copy_info(&info, "\tPROM node\t\t%08x\n", (unsigned int) esp->prom_node);
- copy_info(&info, "\tPROM name\t\t%s\n", esp->prom_name);
- copy_info(&info, "\tESP Model\t\t");
- switch (esp->erev) {
- case esp100:
- copy_info(&info, "ESP100\n");
- break;
- case esp100a:
- copy_info(&info, "ESP100A\n");
- break;
- case esp236:
- copy_info(&info, "ESP236\n");
- break;
- case fas236:
- copy_info(&info, "FAS236\n");
- break;
- case fas100a:
- copy_info(&info, "FAS100A\n");
- break;
- case fast:
- copy_info(&info, "FAST\n");
- break;
- case fashme:
- copy_info(&info, "Happy Meal FAS\n");
- break;
- case espunknown:
- default:
- copy_info(&info, "Unknown!\n");
- break;
- };
- copy_info(&info, "\tDMA Revision\t\t");
- switch (esp->dma->revision) {
- case dvmarev0:
- copy_info(&info, "Rev 0\n");
- break;
- case dvmaesc1:
- copy_info(&info, "ESC Rev 1\n");
- break;
- case dvmarev1:
- copy_info(&info, "Rev 1\n");
- break;
- case dvmarev2:
- copy_info(&info, "Rev 2\n");
- break;
- case dvmarev3:
- copy_info(&info, "Rev 3\n");
- break;
- case dvmarevplus:
- copy_info(&info, "Rev 1+\n");
- break;
- case dvmahme:
- copy_info(&info, "Rev HME/FAS\n");
- break;
- default:
- copy_info(&info, "Unknown!\n");
- break;
- };
- copy_info(&info, "\tLive Targets\t\t[ ");
- for (i = 0; i < 15; i++) {
- if (esp->targets_present & (1 << i))
- copy_info(&info, "%d ", i);
- }
- copy_info(&info, "]\n\n");
-
- /* Now describe the state of each existing target. */
- copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\tWide\n");
-
- shost_for_each_device(sdev, esp->ehost) {
- struct esp_device *esp_dev = sdev->hostdata;
- uint id = sdev->id;
-
- if (!(esp->targets_present & (1 << id)))
- continue;
-
- copy_info(&info, "%d\t\t", id);
- copy_info(&info, "%08lx\t", esp->config3[id]);
- copy_info(&info, "[%02lx,%02lx]\t\t\t",
- esp_dev->sync_max_offset,
- esp_dev->sync_min_period);
- copy_info(&info, "%s\t\t",
- esp_dev->disconnect ? "yes" : "no");
- copy_info(&info, "%s\n",
- (esp->config3[id] & ESP_CONFIG3_EWIDE) ? "yes" : "no");
- }
- return info.pos > info.offset? info.pos - info.offset : 0;
-}
-
-/* ESP proc filesystem code. */
-static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
- int length, int inout)
-{
- struct esp *esp = (struct esp *) host->hostdata;
-
- if (inout)
- return -EINVAL; /* not yet */
-
- if (start)
- *start = buffer;
-
- return esp_host_info(esp, buffer, offset, length);
-}
-
-static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
-{
- if (sp->use_sg == 0) {
- sp->SCp.this_residual = sp->request_bufflen;
- sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
- sp->SCp.buffers_residual = 0;
- if (sp->request_bufflen) {
- sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer,
- sp->SCp.this_residual,
- sp->sc_data_direction);
- sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in);
- } else {
- sp->SCp.ptr = NULL;
- }
- } else {
- sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
- sp->SCp.buffers_residual = sbus_map_sg(esp->sdev,
- sp->SCp.buffer,
- sp->use_sg,
- sp->sc_data_direction);
- sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer);
- sp->SCp.ptr = (char *) ((unsigned long)sg_dma_address(sp->SCp.buffer));
- }
-}
-
-static void esp_release_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
-{
- if (sp->use_sg) {
- sbus_unmap_sg(esp->sdev, sp->request_buffer, sp->use_sg,
- sp->sc_data_direction);
- } else if (sp->request_bufflen) {
- sbus_unmap_single(esp->sdev,
- sp->SCp.have_data_in,
- sp->request_bufflen,
- sp->sc_data_direction);
- }
-}
-
-static void esp_restore_pointers(struct esp *esp, struct scsi_cmnd *sp)
-{
- struct esp_pointers *ep = &esp->data_pointers[sp->device->id];
-
- sp->SCp.ptr = ep->saved_ptr;
- sp->SCp.buffer = ep->saved_buffer;
- sp->SCp.this_residual = ep->saved_this_residual;
- sp->SCp.buffers_residual = ep->saved_buffers_residual;
-}
-
-static void esp_save_pointers(struct esp *esp, struct scsi_cmnd *sp)
-{
- struct esp_pointers *ep = &esp->data_pointers[sp->device->id];
-
- ep->saved_ptr = sp->SCp.ptr;
- ep->saved_buffer = sp->SCp.buffer;
- ep->saved_this_residual = sp->SCp.this_residual;
- ep->saved_buffers_residual = sp->SCp.buffers_residual;
-}
-
-/* Some rules:
- *
- * 1) Never ever panic while something is live on the bus.
- * If there is to be any chance of syncing the disks this
- * rule is to be obeyed.
- *
- * 2) Any target that causes a foul condition will no longer
- * have synchronous transfers done to it, no questions
- * asked.
- *
- * 3) Keep register accesses to a minimum. Think about some
- * day when we have Xbus machines this is running on and
- * the ESP chip is on the other end of the machine on a
- * different board from the cpu where this is running.
- */
-
-/* Fire off a command. We assume the bus is free and that the only
- * case where we could see an interrupt is where we have disconnected
- * commands active and they are trying to reselect us.
- */
-static inline void esp_check_cmd(struct esp *esp, struct scsi_cmnd *sp)
-{
- switch (sp->cmd_len) {
- case 6:
- case 10:
- case 12:
- esp->esp_slowcmd = 0;
- break;
-
- default:
- esp->esp_slowcmd = 1;
- esp->esp_scmdleft = sp->cmd_len;
- esp->esp_scmdp = &sp->cmnd[0];
- break;
- };
-}
-
-static inline void build_sync_nego_msg(struct esp *esp, int period, int offset)
-{
- esp->cur_msgout[0] = EXTENDED_MESSAGE;
- esp->cur_msgout[1] = 3;
- esp->cur_msgout[2] = EXTENDED_SDTR;
- esp->cur_msgout[3] = period;
- esp->cur_msgout[4] = offset;
- esp->msgout_len = 5;
-}
-
-/* SIZE is in bits, currently HME only supports 16 bit wide transfers. */
-static inline void build_wide_nego_msg(struct esp *esp, int size)
-{
- esp->cur_msgout[0] = EXTENDED_MESSAGE;
- esp->cur_msgout[1] = 2;
- esp->cur_msgout[2] = EXTENDED_WDTR;
- switch (size) {
- case 32:
- esp->cur_msgout[3] = 2;
- break;
- case 16:
- esp->cur_msgout[3] = 1;
- break;
- case 8:
- default:
- esp->cur_msgout[3] = 0;
- break;
- };
-
- esp->msgout_len = 4;
-}
-
-static void esp_exec_cmd(struct esp *esp)
-{
- struct scsi_cmnd *SCptr;
- struct scsi_device *SDptr;
- struct esp_device *esp_dev;
- volatile u8 *cmdp = esp->esp_command;
- u8 the_esp_command;
- int lun, target;
- int i;
-
- /* Hold off if we have disconnected commands and
- * an IRQ is showing...
- */
- if (esp->disconnected_SC && ESP_IRQ_P(esp->dregs))
- return;
-
- /* Grab first member of the issue queue. */
- SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);
-
- /* Safe to panic here because current_SC is null. */
- if (!SCptr)
- panic("esp: esp_exec_cmd and issue queue is NULL");
-
- SDptr = SCptr->device;
- esp_dev = SDptr->hostdata;
- lun = SCptr->device->lun;
- target = SCptr->device->id;
-
- esp->snip = 0;
- esp->msgout_len = 0;
-
- /* Send it out whole, or piece by piece? The ESP
- * only knows how to automatically send out 6, 10,
- * and 12 byte commands. I used to think that the
- * Linux SCSI code would never throw anything other
- * than that to us, but then again there is the
- * SCSI generic driver which can send us anything.
- */
- esp_check_cmd(esp, SCptr);
-
- /* If arbitration/selection is successful, the ESP will leave
- * ATN asserted, causing the target to go into message out
- * phase. The ESP will feed the target the identify and then
- * the target can only legally go to one of command,
- * datain/out, status, or message in phase, or stay in message
- * out phase (should we be trying to send a sync negotiation
- * message after the identify). It is not allowed to drop
- * BSY, but some buggy targets do and we check for this
- * condition in the selection complete code. Most of the time
- * we'll make the command bytes available to the ESP and it
- * will not interrupt us until it finishes command phase, we
- * cannot do this for command sizes the ESP does not
- * understand and in this case we'll get interrupted right
- * when the target goes into command phase.
- *
- * It is absolutely _illegal_ in the presence of SCSI-2 devices
- * to use the ESP select w/o ATN command. When SCSI-2 devices are
- * present on the bus we _must_ always go straight to message out
- * phase with an identify message for the target. Being that
- * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2
- * selections should not confuse SCSI-1 we hope.
- */
-
- if (esp_dev->sync) {
- /* this targets sync is known */
-#ifndef __sparc_v9__
-do_sync_known:
-#endif
- if (esp_dev->disconnect)
- *cmdp++ = IDENTIFY(1, lun);
- else
- *cmdp++ = IDENTIFY(0, lun);
-
- if (esp->esp_slowcmd) {
- the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
- esp_advance_phase(SCptr, in_slct_stop);
- } else {
- the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
- esp_advance_phase(SCptr, in_slct_norm);
- }
- } else if (!(esp->targets_present & (1<<target)) || !(esp_dev->disconnect)) {
- /* After the bootup SCSI code sends both the
- * TEST_UNIT_READY and INQUIRY commands we want
- * to at least attempt allowing the device to
- * disconnect.
- */
- ESPMISC(("esp: Selecting device for first time. target=%d "
- "lun=%d\n", target, SCptr->device->lun));
- if (!SDptr->borken && !esp_dev->disconnect)
- esp_dev->disconnect = 1;
-
- *cmdp++ = IDENTIFY(0, lun);
- esp->prevmsgout = NOP;
- esp_advance_phase(SCptr, in_slct_norm);
- the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
-
- /* Take no chances... */
- esp_dev->sync_max_offset = 0;
- esp_dev->sync_min_period = 0;
- } else {
- /* Sorry, I have had way too many problems with
- * various CDROM devices on ESP. -DaveM
- */
- int cdrom_hwbug_wkaround = 0;
-
-#ifndef __sparc_v9__
- /* Never allow disconnects or synchronous transfers on
- * SparcStation1 and SparcStation1+. Allowing those
- * to be enabled seems to lockup the machine completely.
- */
- if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
- /* But we are nice and allow tapes and removable
- * disks (but not CDROMs) to disconnect.
- */
- if(SDptr->type == TYPE_TAPE ||
- (SDptr->type != TYPE_ROM && SDptr->removable))
- esp_dev->disconnect = 1;
- else
- esp_dev->disconnect = 0;
- esp_dev->sync_max_offset = 0;
- esp_dev->sync_min_period = 0;
- esp_dev->sync = 1;
- esp->snip = 0;
- goto do_sync_known;
- }
-#endif /* !(__sparc_v9__) */
-
- /* We've talked to this guy before,
- * but never negotiated. Let's try,
- * need to attempt WIDE first, before
- * sync nego, as per SCSI 2 standard.
- */
- if (esp->erev == fashme && !esp_dev->wide) {
- if (!SDptr->borken &&
- SDptr->type != TYPE_ROM &&
- SDptr->removable == 0) {
- build_wide_nego_msg(esp, 16);
- esp_dev->wide = 1;
- esp->wnip = 1;
- goto after_nego_msg_built;
- } else {
- esp_dev->wide = 1;
- /* Fall through and try sync. */
- }
- }
-
- if (!SDptr->borken) {
- if ((SDptr->type == TYPE_ROM)) {
- /* Nice try sucker... */
- ESPMISC(("esp%d: Disabling sync for buggy "
- "CDROM.\n", esp->esp_id));
- cdrom_hwbug_wkaround = 1;
- build_sync_nego_msg(esp, 0, 0);
- } else if (SDptr->removable != 0) {
- ESPMISC(("esp%d: Not negotiating sync/wide but "
- "allowing disconnect for removable media.\n",
- esp->esp_id));
- build_sync_nego_msg(esp, 0, 0);
- } else {
- build_sync_nego_msg(esp, esp->sync_defp, 15);
- }
- } else {
- build_sync_nego_msg(esp, 0, 0);
- }
- esp_dev->sync = 1;
- esp->snip = 1;
-
-after_nego_msg_built:
- /* A fix for broken SCSI1 targets, when they disconnect
- * they lock up the bus and confuse ESP. So disallow
- * disconnects for SCSI1 targets for now until we
- * find a better fix.
- *
- * Addendum: This is funny, I figured out what was going
- * on. The blotzed SCSI1 target would disconnect,
- * one of the other SCSI2 targets or both would be
- * disconnected as well. The SCSI1 target would
- * stay disconnected long enough that we start
- * up a command on one of the SCSI2 targets. As
- * the ESP is arbitrating for the bus the SCSI1
- * target begins to arbitrate as well to reselect
- * the ESP. The SCSI1 target refuses to drop it's
- * ID bit on the data bus even though the ESP is
- * at ID 7 and is the obvious winner for any
- * arbitration. The ESP is a poor sport and refuses
- * to lose arbitration, it will continue indefinitely
- * trying to arbitrate for the bus and can only be
- * stopped via a chip reset or SCSI bus reset.
- * Therefore _no_ disconnects for SCSI1 targets
- * thank you very much. ;-)
- */
- if(((SDptr->scsi_level < 3) &&
- (SDptr->type != TYPE_TAPE) &&
- SDptr->removable == 0) ||
- cdrom_hwbug_wkaround || SDptr->borken) {
- ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
- "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
- esp_dev->disconnect = 0;
- *cmdp++ = IDENTIFY(0, lun);
- } else {
- *cmdp++ = IDENTIFY(1, lun);
- }
-
- /* ESP fifo is only so big...
- * Make this look like a slow command.
- */
- esp->esp_slowcmd = 1;
- esp->esp_scmdleft = SCptr->cmd_len;
- esp->esp_scmdp = &SCptr->cmnd[0];
-
- the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
- esp_advance_phase(SCptr, in_slct_msg);
- }
-
- if (!esp->esp_slowcmd)
- for (i = 0; i < SCptr->cmd_len; i++)
- *cmdp++ = SCptr->cmnd[i];
-
- /* HME sucks... */
- if (esp->erev == fashme)
- sbus_writeb((target & 0xf) | (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT),
- esp->eregs + ESP_BUSID);
- else
- sbus_writeb(target & 7, esp->eregs + ESP_BUSID);
- if (esp->prev_soff != esp_dev->sync_max_offset ||
- esp->prev_stp != esp_dev->sync_min_period ||
- (esp->erev > esp100a &&
- esp->prev_cfg3 != esp->config3[target])) {
- esp->prev_soff = esp_dev->sync_max_offset;
- esp->prev_stp = esp_dev->sync_min_period;
- sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
- sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
- if (esp->erev > esp100a) {
- esp->prev_cfg3 = esp->config3[target];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- }
- }
- i = (cmdp - esp->esp_command);
-
- if (esp->erev == fashme) {
- esp_cmd(esp, ESP_CMD_FLUSH); /* Grrr! */
-
- /* Set up the DMA and HME counters */
- sbus_writeb(i, esp->eregs + ESP_TCLOW);
- sbus_writeb(0, esp->eregs + ESP_TCMED);
- sbus_writeb(0, esp->eregs + FAS_RLO);
- sbus_writeb(0, esp->eregs + FAS_RHI);
- esp_cmd(esp, the_esp_command);
-
- /* Talk about touchy hardware... */
- esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
- (DMA_SCSI_DISAB | DMA_ENABLE)) &
- ~(DMA_ST_WRITE));
- sbus_writel(16, esp->dregs + DMA_COUNT);
- sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
- sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
- } else {
- u32 tmp;
-
- /* Set up the DMA and ESP counters */
- sbus_writeb(i, esp->eregs + ESP_TCLOW);
- sbus_writeb(0, esp->eregs + ESP_TCMED);
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- tmp &= ~DMA_ST_WRITE;
- tmp |= DMA_ENABLE;
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- if (esp->dma->revision == dvmaesc1) {
- if (i) /* Workaround ESC gate array SBUS rerun bug. */
- sbus_writel(PAGE_SIZE, esp->dregs + DMA_COUNT);
- }
- sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
-
- /* Tell ESP to "go". */
- esp_cmd(esp, the_esp_command);
- }
-}
-
-/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */
-static int esp_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
-{
- struct esp *esp;
-
- /* Set up func ptr and initial driver cmd-phase. */
- SCpnt->scsi_done = done;
- SCpnt->SCp.phase = not_issued;
-
- /* We use the scratch area. */
- ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->device->lun));
- ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->device->lun));
-
- esp = (struct esp *) SCpnt->device->host->hostdata;
- esp_get_dmabufs(esp, SCpnt);
- esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */
-
- SCpnt->SCp.Status = CHECK_CONDITION;
- SCpnt->SCp.Message = 0xff;
- SCpnt->SCp.sent_command = 0;
-
- /* Place into our queue. */
- if (SCpnt->cmnd[0] == REQUEST_SENSE) {
- ESPQUEUE(("RQSENSE\n"));
- prepend_SC(&esp->issue_SC, SCpnt);
- } else {
- ESPQUEUE(("\n"));
- append_SC(&esp->issue_SC, SCpnt);
- }
-
- /* Run it now if we can. */
- if (!esp->current_SC && !esp->resetting_bus)
- esp_exec_cmd(esp);
-
- return 0;
-}
-
-/* Dump driver state. */
-static void esp_dump_cmd(struct scsi_cmnd *SCptr)
-{
- ESPLOG(("[tgt<%02x> lun<%02x> "
- "pphase<%s> cphase<%s>]",
- SCptr->device->id, SCptr->device->lun,
- phase_string(SCptr->SCp.sent_command),
- phase_string(SCptr->SCp.phase)));
-}
-
-static void esp_dump_state(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
-#ifdef DEBUG_ESP_CMDS
- int i;
-#endif
-
- ESPLOG(("esp%d: dumping state\n", esp->esp_id));
- ESPLOG(("esp%d: dma -- cond_reg<%08x> addr<%08x>\n",
- esp->esp_id,
- sbus_readl(esp->dregs + DMA_CSR),
- sbus_readl(esp->dregs + DMA_ADDR)));
- ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
- esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));
- ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
- esp->esp_id,
- sbus_readb(esp->eregs + ESP_STATUS),
- sbus_readb(esp->eregs + ESP_SSTEP),
- sbus_readb(esp->eregs + ESP_INTRPT)));
-#ifdef DEBUG_ESP_CMDS
- printk("esp%d: last ESP cmds [", esp->esp_id);
- i = (esp->espcmdent - 1) & 31;
- printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
- i = (i - 1) & 31;
- printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
- i = (i - 1) & 31;
- printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
- i = (i - 1) & 31;
- printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
- printk("]\n");
-#endif /* (DEBUG_ESP_CMDS) */
-
- if (SCptr) {
- ESPLOG(("esp%d: current command ", esp->esp_id));
- esp_dump_cmd(SCptr);
- }
- ESPLOG(("\n"));
- SCptr = esp->disconnected_SC;
- ESPLOG(("esp%d: disconnected ", esp->esp_id));
- while (SCptr) {
- esp_dump_cmd(SCptr);
- SCptr = (struct scsi_cmnd *) SCptr->host_scribble;
- }
- ESPLOG(("\n"));
-}
-
-/* Abort a command. The host_lock is acquired by caller. */
-static int esp_abort(struct scsi_cmnd *SCptr)
-{
- struct esp *esp = (struct esp *) SCptr->device->host->hostdata;
- int don;
-
- ESPLOG(("esp%d: Aborting command\n", esp->esp_id));
- esp_dump_state(esp);
-
- /* Wheee, if this is the current command on the bus, the
- * best we can do is assert ATN and wait for msgout phase.
- * This should even fix a hung SCSI bus when we lose state
- * in the driver and timeout because the eventual phase change
- * will cause the ESP to (eventually) give an interrupt.
- */
- if (esp->current_SC == SCptr) {
- esp->cur_msgout[0] = ABORT;
- esp->msgout_len = 1;
- esp->msgout_ctr = 0;
- esp_cmd(esp, ESP_CMD_SATN);
- return SUCCESS;
- }
-
- /* If it is still in the issue queue then we can safely
- * call the completion routine and report abort success.
- */
- don = (sbus_readl(esp->dregs + DMA_CSR) & DMA_INT_ENAB);
- if (don) {
- ESP_INTSOFF(esp->dregs);
- }
- if (esp->issue_SC) {
- struct scsi_cmnd **prev, *this;
- for (prev = (&esp->issue_SC), this = esp->issue_SC;
- this != NULL;
- prev = (struct scsi_cmnd **) &(this->host_scribble),
- this = (struct scsi_cmnd *) this->host_scribble) {
-
- if (this == SCptr) {
- *prev = (struct scsi_cmnd *) this->host_scribble;
- this->host_scribble = NULL;
-
- esp_release_dmabufs(esp, this);
- this->result = DID_ABORT << 16;
- this->scsi_done(this);
-
- if (don)
- ESP_INTSON(esp->dregs);
-
- return SUCCESS;
- }
- }
- }
-
- /* Yuck, the command to abort is disconnected, it is not
- * worth trying to abort it now if something else is live
- * on the bus at this time. So, we let the SCSI code wait
- * a little bit and try again later.
- */
- if (esp->current_SC) {
- if (don)
- ESP_INTSON(esp->dregs);
- return FAILED;
- }
-
- /* It's disconnected, we have to reconnect to re-establish
- * the nexus and tell the device to abort. However, we really
- * cannot 'reconnect' per se. Don't try to be fancy, just
- * indicate failure, which causes our caller to reset the whole
- * bus.
- */
-
- if (don)
- ESP_INTSON(esp->dregs);
-
- return FAILED;
-}
-
-/* We've sent ESP_CMD_RS to the ESP, the interrupt had just
- * arrived indicating the end of the SCSI bus reset. Our job
- * is to clean out the command queues and begin re-execution
- * of SCSI commands once more.
- */
-static int esp_finish_reset(struct esp *esp)
-{
- struct scsi_cmnd *sp = esp->current_SC;
-
- /* Clean up currently executing command, if any. */
- if (sp != NULL) {
- esp->current_SC = NULL;
-
- esp_release_dmabufs(esp, sp);
- sp->result = (DID_RESET << 16);
-
- sp->scsi_done(sp);
- }
-
- /* Clean up disconnected queue, they have been invalidated
- * by the bus reset.
- */
- if (esp->disconnected_SC) {
- while ((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) {
- esp_release_dmabufs(esp, sp);
- sp->result = (DID_RESET << 16);
-
- sp->scsi_done(sp);
- }
- }
-
- /* SCSI bus reset is complete. */
- esp->resetting_bus = 0;
- wake_up(&esp->reset_queue);
-
- /* Ok, now it is safe to get commands going once more. */
- if (esp->issue_SC)
- esp_exec_cmd(esp);
-
- return do_intr_end;
-}
-
-static int esp_do_resetbus(struct esp *esp)
-{
- ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));
- esp->resetting_bus = 1;
- esp_cmd(esp, ESP_CMD_RS);
-
- return do_intr_end;
-}
-
-/* Reset ESP chip, reset hanging bus, then kill active and
- * disconnected commands for targets without soft reset.
- *
- * The host_lock is acquired by caller.
- */
-static int esp_reset(struct scsi_cmnd *SCptr)
-{
- struct esp *esp = (struct esp *) SCptr->device->host->hostdata;
-
- spin_lock_irq(esp->ehost->host_lock);
- (void) esp_do_resetbus(esp);
- spin_unlock_irq(esp->ehost->host_lock);
-
- wait_event(esp->reset_queue, (esp->resetting_bus == 0));
-
- return SUCCESS;
-}
-
-/* Internal ESP done function. */
-static void esp_done(struct esp *esp, int error)
-{
- struct scsi_cmnd *done_SC = esp->current_SC;
-
- esp->current_SC = NULL;
-
- esp_release_dmabufs(esp, done_SC);
- done_SC->result = error;
-
- done_SC->scsi_done(done_SC);
-
- /* Bus is free, issue any commands in the queue. */
- if (esp->issue_SC && !esp->current_SC)
- esp_exec_cmd(esp);
-
-}
-
-/* Wheee, ESP interrupt engine. */
-
-/* Forward declarations. */
-static int esp_do_phase_determine(struct esp *esp);
-static int esp_do_data_finale(struct esp *esp);
-static int esp_select_complete(struct esp *esp);
-static int esp_do_status(struct esp *esp);
-static int esp_do_msgin(struct esp *esp);
-static int esp_do_msgindone(struct esp *esp);
-static int esp_do_msgout(struct esp *esp);
-static int esp_do_cmdbegin(struct esp *esp);
-
-#define sreg_datainp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)
-#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP)
-
-/* Read any bytes found in the FAS366 fifo, storing them into
- * the ESP driver software state structure.
- */
-static void hme_fifo_read(struct esp *esp)
-{
- u8 count = 0;
- u8 status = esp->sreg;
-
- /* Cannot safely frob the fifo for these following cases, but
- * we must always read the fifo when the reselect interrupt
- * is pending.
- */
- if (((esp->ireg & ESP_INTR_RSEL) == 0) &&
- (sreg_datainp(status) ||
- sreg_dataoutp(status) ||
- (esp->current_SC &&
- esp->current_SC->SCp.phase == in_data_done))) {
- ESPHME(("<wkaround_skipped>"));
- } else {
- unsigned long fcnt = sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES;
-
- /* The HME stores bytes in multiples of 2 in the fifo. */
- ESPHME(("hme_fifo[fcnt=%d", (int)fcnt));
- while (fcnt) {
- esp->hme_fifo_workaround_buffer[count++] =
- sbus_readb(esp->eregs + ESP_FDATA);
- esp->hme_fifo_workaround_buffer[count++] =
- sbus_readb(esp->eregs + ESP_FDATA);
- ESPHME(("<%02x,%02x>", esp->hme_fifo_workaround_buffer[count-2], esp->hme_fifo_workaround_buffer[count-1]));
- fcnt--;
- }
- if (sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_F1BYTE) {
- ESPHME(("<poke_byte>"));
- sbus_writeb(0, esp->eregs + ESP_FDATA);
- esp->hme_fifo_workaround_buffer[count++] =
- sbus_readb(esp->eregs + ESP_FDATA);
- ESPHME(("<%02x,0x00>", esp->hme_fifo_workaround_buffer[count-1]));
- ESPHME(("CMD_FLUSH"));
- esp_cmd(esp, ESP_CMD_FLUSH);
- } else {
- ESPHME(("no_xtra_byte"));
- }
- }
- ESPHME(("wkarnd_cnt=%d]", (int)count));
- esp->hme_fifo_workaround_count = count;
-}
-
-static inline void hme_fifo_push(struct esp *esp, u8 *bytes, u8 count)
-{
- esp_cmd(esp, ESP_CMD_FLUSH);
- while (count) {
- u8 tmp = *bytes++;
- sbus_writeb(tmp, esp->eregs + ESP_FDATA);
- sbus_writeb(0, esp->eregs + ESP_FDATA);
- count--;
- }
-}
-
-/* We try to avoid some interrupts by jumping ahead and see if the ESP
- * has gotten far enough yet. Hence the following.
- */
-static inline int skipahead1(struct esp *esp, struct scsi_cmnd *scp,
- int prev_phase, int new_phase)
-{
- if (scp->SCp.sent_command != prev_phase)
- return 0;
- if (ESP_IRQ_P(esp->dregs)) {
- /* Yes, we are able to save an interrupt. */
- if (esp->erev == fashme)
- esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);
- esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR));
- esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);
- if (esp->erev == fashme) {
- /* This chip is really losing. */
- ESPHME(("HME["));
- /* Must latch fifo before reading the interrupt
- * register else garbage ends up in the FIFO
- * which confuses the driver utterly.
- * Happy Meal indeed....
- */
- ESPHME(("fifo_workaround]"));
- if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
- (esp->sreg2 & ESP_STAT2_F1BYTE))
- hme_fifo_read(esp);
- }
- if (!(esp->ireg & ESP_INTR_SR))
- return 0;
- else
- return do_reset_complete;
- }
- /* Ho hum, target is taking forever... */
- scp->SCp.sent_command = new_phase; /* so we don't recurse... */
- return do_intr_end;
-}
-
-static inline int skipahead2(struct esp *esp, struct scsi_cmnd *scp,
- int prev_phase1, int prev_phase2, int new_phase)
-{
- if (scp->SCp.sent_command != prev_phase1 &&
- scp->SCp.sent_command != prev_phase2)
- return 0;
- if (ESP_IRQ_P(esp->dregs)) {
- /* Yes, we are able to save an interrupt. */
- if (esp->erev == fashme)
- esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);
- esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR));
- esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);
- if (esp->erev == fashme) {
- /* This chip is really losing. */
- ESPHME(("HME["));
-
- /* Must latch fifo before reading the interrupt
- * register else garbage ends up in the FIFO
- * which confuses the driver utterly.
- * Happy Meal indeed....
- */
- ESPHME(("fifo_workaround]"));
- if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
- (esp->sreg2 & ESP_STAT2_F1BYTE))
- hme_fifo_read(esp);
- }
- if (!(esp->ireg & ESP_INTR_SR))
- return 0;
- else
- return do_reset_complete;
- }
- /* Ho hum, target is taking forever... */
- scp->SCp.sent_command = new_phase; /* so we don't recurse... */
- return do_intr_end;
-}
-
-/* Now some dma helpers. */
-static void dma_setup(struct esp *esp, __u32 addr, int count, int write)
-{
- u32 nreg = sbus_readl(esp->dregs + DMA_CSR);
-
- if (write)
- nreg |= DMA_ST_WRITE;
- else
- nreg &= ~(DMA_ST_WRITE);
- nreg |= DMA_ENABLE;
- sbus_writel(nreg, esp->dregs + DMA_CSR);
- if (esp->dma->revision == dvmaesc1) {
- /* This ESC gate array sucks! */
- __u32 src = addr;
- __u32 dest = src + count;
-
- if (dest & (PAGE_SIZE - 1))
- count = PAGE_ALIGN(count);
- sbus_writel(count, esp->dregs + DMA_COUNT);
- }
- sbus_writel(addr, esp->dregs + DMA_ADDR);
-}
-
-static void dma_drain(struct esp *esp)
-{
- u32 tmp;
-
- if (esp->dma->revision == dvmahme)
- return;
- if ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_FIFO_ISDRAIN) {
- switch (esp->dma->revision) {
- default:
- tmp |= DMA_FIFO_STDRAIN;
- sbus_writel(tmp, esp->dregs + DMA_CSR);
-
- case dvmarev3:
- case dvmaesc1:
- while (sbus_readl(esp->dregs + DMA_CSR) & DMA_FIFO_ISDRAIN)
- udelay(1);
- };
- }
-}
-
-static void dma_invalidate(struct esp *esp)
-{
- u32 tmp;
-
- if (esp->dma->revision == dvmahme) {
- sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR);
-
- esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
- (DMA_PARITY_OFF | DMA_2CLKS |
- DMA_SCSI_DISAB | DMA_INT_ENAB)) &
- ~(DMA_ST_WRITE | DMA_ENABLE));
-
- sbus_writel(0, esp->dregs + DMA_CSR);
- sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
-
- /* This is necessary to avoid having the SCSI channel
- * engine lock up on us.
- */
- sbus_writel(0, esp->dregs + DMA_ADDR);
- } else {
- while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ)
- udelay(1);
-
- tmp &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);
- tmp |= DMA_FIFO_INV;
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- tmp &= ~DMA_FIFO_INV;
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- }
-}
-
-static inline void dma_flashclear(struct esp *esp)
-{
- dma_drain(esp);
- dma_invalidate(esp);
-}
-
-static int dma_can_transfer(struct esp *esp, struct scsi_cmnd *sp)
-{
- __u32 base, end, sz;
-
- if (esp->dma->revision == dvmarev3) {
- sz = sp->SCp.this_residual;
- if (sz > 0x1000000)
- sz = 0x1000000;
- } else {
- base = ((__u32)((unsigned long)sp->SCp.ptr));
- base &= (0x1000000 - 1);
- end = (base + sp->SCp.this_residual);
- if (end > 0x1000000)
- end = 0x1000000;
- sz = (end - base);
- }
- return sz;
-}
-
-/* Misc. esp helper macros. */
-#define esp_setcount(__eregs, __cnt, __hme) \
- sbus_writeb(((__cnt)&0xff), (__eregs) + ESP_TCLOW); \
- sbus_writeb((((__cnt)>>8)&0xff), (__eregs) + ESP_TCMED); \
- if (__hme) { \
- sbus_writeb((((__cnt)>>16)&0xff), (__eregs) + FAS_RLO); \
- sbus_writeb(0, (__eregs) + FAS_RHI); \
- }
-
-#define esp_getcount(__eregs, __hme) \
- ((sbus_readb((__eregs) + ESP_TCLOW)&0xff) | \
- ((sbus_readb((__eregs) + ESP_TCMED)&0xff) << 8) | \
- ((__hme) ? sbus_readb((__eregs) + FAS_RLO) << 16 : 0))
-
-#define fcount(__esp) \
- (((__esp)->erev == fashme) ? \
- (__esp)->hme_fifo_workaround_count : \
- sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_FBYTES)
-
-#define fnzero(__esp) \
- (((__esp)->erev == fashme) ? 0 : \
- sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_ONOTZERO)
-
-/* XXX speculative nops unnecessary when continuing amidst a data phase
- * XXX even on esp100!!! another case of flooding the bus with I/O reg
- * XXX writes...
- */
-#define esp_maybe_nop(__esp) \
- if ((__esp)->erev == esp100) \
- esp_cmd((__esp), ESP_CMD_NULL)
-
-#define sreg_to_dataphase(__sreg) \
- ((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain)
-
-/* The ESP100 when in synchronous data phase, can mistake a long final
- * REQ pulse from the target as an extra byte, it places whatever is on
- * the data lines into the fifo. For now, we will assume when this
- * happens that the target is a bit quirky and we don't want to
- * be talking synchronously to it anyways. Regardless, we need to
- * tell the ESP to eat the extraneous byte so that we can proceed
- * to the next phase.
- */
-static int esp100_sync_hwbug(struct esp *esp, struct scsi_cmnd *sp, int fifocnt)
-{
- /* Do not touch this piece of code. */
- if ((!(esp->erev == esp100)) ||
- (!(sreg_datainp((esp->sreg = sbus_readb(esp->eregs + ESP_STATUS))) &&
- !fifocnt) &&
- !(sreg_dataoutp(esp->sreg) && !fnzero(esp)))) {
- if (sp->SCp.phase == in_dataout)
- esp_cmd(esp, ESP_CMD_FLUSH);
- return 0;
- } else {
- /* Async mode for this guy. */
- build_sync_nego_msg(esp, 0, 0);
-
- /* Ack the bogus byte, but set ATN first. */
- esp_cmd(esp, ESP_CMD_SATN);
- esp_cmd(esp, ESP_CMD_MOK);
- return 1;
- }
-}
-
-/* This closes the window during a selection with a reselect pending, because
- * we use DMA for the selection process the FIFO should hold the correct
- * contents if we get reselected during this process. So we just need to
- * ack the possible illegal cmd interrupt pending on the esp100.
- */
-static inline int esp100_reconnect_hwbug(struct esp *esp)
-{
- u8 tmp;
-
- if (esp->erev != esp100)
- return 0;
- tmp = sbus_readb(esp->eregs + ESP_INTRPT);
- if (tmp & ESP_INTR_SR)
- return 1;
- return 0;
-}
-
-/* This verifies the BUSID bits during a reselection so that we know which
- * target is talking to us.
- */
-static inline int reconnect_target(struct esp *esp)
-{
- int it, me = esp->scsi_id_mask, targ = 0;
-
- if (2 != fcount(esp))
- return -1;
- if (esp->erev == fashme) {
- /* HME does not latch it's own BUS ID bits during
- * a reselection. Also the target number is given
- * as an unsigned char, not as a sole bit number
- * like the other ESP's do.
- * Happy Meal indeed....
- */
- targ = esp->hme_fifo_workaround_buffer[0];
- } else {
- it = sbus_readb(esp->eregs + ESP_FDATA);
- if (!(it & me))
- return -1;
- it &= ~me;
- if (it & (it - 1))
- return -1;
- while (!(it & 1))
- targ++, it >>= 1;
- }
- return targ;
-}
-
-/* This verifies the identify from the target so that we know which lun is
- * being reconnected.
- */
-static inline int reconnect_lun(struct esp *esp)
-{
- int lun;
-
- if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)
- return -1;
- if (esp->erev == fashme)
- lun = esp->hme_fifo_workaround_buffer[1];
- else
- lun = sbus_readb(esp->eregs + ESP_FDATA);
-
- /* Yes, you read this correctly. We report lun of zero
- * if we see parity error. ESP reports parity error for
- * the lun byte, and this is the only way to hope to recover
- * because the target is connected.
- */
- if (esp->sreg & ESP_STAT_PERR)
- return 0;
-
- /* Check for illegal bits being set in the lun. */
- if ((lun & 0x40) || !(lun & 0x80))
- return -1;
-
- return lun & 7;
-}
-
-/* This puts the driver in a state where it can revitalize a command that
- * is being continued due to reselection.
- */
-static inline void esp_connect(struct esp *esp, struct scsi_cmnd *sp)
-{
- struct esp_device *esp_dev = sp->device->hostdata;
-
- if (esp->prev_soff != esp_dev->sync_max_offset ||
- esp->prev_stp != esp_dev->sync_min_period ||
- (esp->erev > esp100a &&
- esp->prev_cfg3 != esp->config3[sp->device->id])) {
- esp->prev_soff = esp_dev->sync_max_offset;
- esp->prev_stp = esp_dev->sync_min_period;
- sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
- sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
- if (esp->erev > esp100a) {
- esp->prev_cfg3 = esp->config3[sp->device->id];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- }
- }
- esp->current_SC = sp;
-}
-
-/* This will place the current working command back into the issue queue
- * if we are to receive a reselection amidst a selection attempt.
- */
-static inline void esp_reconnect(struct esp *esp, struct scsi_cmnd *sp)
-{
- if (!esp->disconnected_SC)
- ESPLOG(("esp%d: Weird, being reselected but disconnected "
- "command queue is empty.\n", esp->esp_id));
- esp->snip = 0;
- esp->current_SC = NULL;
- sp->SCp.phase = not_issued;
- append_SC(&esp->issue_SC, sp);
-}
-
-/* Begin message in phase. */
-static int esp_do_msgin(struct esp *esp)
-{
- /* Must be very careful with the fifo on the HME */
- if ((esp->erev != fashme) ||
- !(sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_FEMPTY))
- esp_cmd(esp, ESP_CMD_FLUSH);
- esp_maybe_nop(esp);
- esp_cmd(esp, ESP_CMD_TI);
- esp->msgin_len = 1;
- esp->msgin_ctr = 0;
- esp_advance_phase(esp->current_SC, in_msgindone);
- return do_work_bus;
-}
-
-/* This uses various DMA csr fields and the fifo flags count value to
- * determine how many bytes were successfully sent/received by the ESP.
- */
-static inline int esp_bytes_sent(struct esp *esp, int fifo_count)
-{
- int rval = sbus_readl(esp->dregs + DMA_ADDR) - esp->esp_command_dvma;
-
- if (esp->dma->revision == dvmarev1)
- rval -= (4 - ((sbus_readl(esp->dregs + DMA_CSR) & DMA_READ_AHEAD)>>11));
- return rval - fifo_count;
-}
-
-static inline void advance_sg(struct scsi_cmnd *sp)
-{
- ++sp->SCp.buffer;
- --sp->SCp.buffers_residual;
- sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer);
- sp->SCp.ptr = (char *)((unsigned long)sg_dma_address(sp->SCp.buffer));
-}
-
-/* Please note that the way I've coded these routines is that I _always_
- * check for a disconnect during any and all information transfer
- * phases. The SCSI standard states that the target _can_ cause a BUS
- * FREE condition by dropping all MSG/CD/IO/BSY signals. Also note
- * that during information transfer phases the target controls every
- * change in phase, the only thing the initiator can do is "ask" for
- * a message out phase by driving ATN true. The target can, and sometimes
- * will, completely ignore this request so we cannot assume anything when
- * we try to force a message out phase to abort/reset a target. Most of
- * the time the target will eventually be nice and go to message out, so
- * we may have to hold on to our state about what we want to tell the target
- * for some period of time.
- */
-
-/* I think I have things working here correctly. Even partial transfers
- * within a buffer or sub-buffer should not upset us at all no matter
- * how bad the target and/or ESP fucks things up.
- */
-static int esp_do_data(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- int thisphase, hmuch;
-
- ESPDATA(("esp_do_data: "));
- esp_maybe_nop(esp);
- thisphase = sreg_to_dataphase(esp->sreg);
- esp_advance_phase(SCptr, thisphase);
- ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT"));
- hmuch = dma_can_transfer(esp, SCptr);
- if (hmuch > (64 * 1024) && (esp->erev != fashme))
- hmuch = (64 * 1024);
- ESPDATA(("hmuch<%d> ", hmuch));
- esp->current_transfer_size = hmuch;
-
- if (esp->erev == fashme) {
- u32 tmp = esp->prev_hme_dmacsr;
-
- /* Always set the ESP count registers first. */
- esp_setcount(esp->eregs, hmuch, 1);
-
- /* Get the DMA csr computed. */
- tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
- if (thisphase == in_datain)
- tmp |= DMA_ST_WRITE;
- else
- tmp &= ~(DMA_ST_WRITE);
- esp->prev_hme_dmacsr = tmp;
-
- ESPDATA(("DMA|TI --> do_intr_end\n"));
- if (thisphase == in_datain) {
- sbus_writel(hmuch, esp->dregs + DMA_COUNT);
- esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
- } else {
- esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
- sbus_writel(hmuch, esp->dregs + DMA_COUNT);
- }
- sbus_writel((__u32)((unsigned long)SCptr->SCp.ptr), esp->dregs+DMA_ADDR);
- sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
- } else {
- esp_setcount(esp->eregs, hmuch, 0);
- dma_setup(esp, ((__u32)((unsigned long)SCptr->SCp.ptr)),
- hmuch, (thisphase == in_datain));
- ESPDATA(("DMA|TI --> do_intr_end\n"));
- esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
- }
- return do_intr_end;
-}
-
-/* See how successful the data transfer was. */
-static int esp_do_data_finale(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- struct esp_device *esp_dev = SCptr->device->hostdata;
- int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0;
-
- ESPDATA(("esp_do_data_finale: "));
-
- if (SCptr->SCp.phase == in_datain) {
- if (esp->sreg & ESP_STAT_PERR) {
- /* Yuck, parity error. The ESP asserts ATN
- * so that we can go to message out phase
- * immediately and inform the target that
- * something bad happened.
- */
- ESPLOG(("esp%d: data bad parity detected.\n",
- esp->esp_id));
- esp->cur_msgout[0] = INITIATOR_ERROR;
- esp->msgout_len = 1;
- }
- dma_drain(esp);
- }
- dma_invalidate(esp);
-
- /* This could happen for the above parity error case. */
- if (esp->ireg != ESP_INTR_BSERV) {
- /* Please go to msgout phase, please please please... */
- ESPLOG(("esp%d: !BSERV after data, probably to msgout\n",
- esp->esp_id));
- return esp_do_phase_determine(esp);
- }
-
- /* Check for partial transfers and other horrible events.
- * Note, here we read the real fifo flags register even
- * on HME broken adapters because we skip the HME fifo
- * workaround code in esp_handle() if we are doing data
- * phase things. We don't want to fuck directly with
- * the fifo like that, especially if doing synchronous
- * transfers! Also, will need to double the count on
- * HME if we are doing wide transfers, as the HME fifo
- * will move and count 16-bit quantities during wide data.
- * SMCC _and_ Qlogic can both bite me.
- */
- fifocnt = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES);
- if (esp->erev != fashme)
- ecount = esp_getcount(esp->eregs, 0);
- bytes_sent = esp->current_transfer_size;
-
- ESPDATA(("trans_sz(%d), ", bytes_sent));
- if (esp->erev == fashme) {
- if (!(esp->sreg & ESP_STAT_TCNT)) {
- ecount = esp_getcount(esp->eregs, 1);
- bytes_sent -= ecount;
- }
-
- /* Always subtract any cruft remaining in the FIFO. */
- if (esp->prev_cfg3 & ESP_CONFIG3_EWIDE)
- fifocnt <<= 1;
- if (SCptr->SCp.phase == in_dataout)
- bytes_sent -= fifocnt;
-
- /* I have an IBM disk which exhibits the following
- * behavior during writes to it. It disconnects in
- * the middle of a partial transfer, the current sglist
- * buffer is 1024 bytes, the disk stops data transfer
- * at 512 bytes.
- *
- * However the FAS366 reports that 32 more bytes were
- * transferred than really were. This is precisely
- * the size of a fully loaded FIFO in wide scsi mode.
- * The FIFO state recorded indicates that it is empty.
- *
- * I have no idea if this is a bug in the FAS366 chip
- * or a bug in the firmware on this IBM disk. In any
- * event the following seems to be a good workaround. -DaveM
- */
- if (bytes_sent != esp->current_transfer_size &&
- SCptr->SCp.phase == in_dataout) {
- int mask = (64 - 1);
-
- if ((esp->prev_cfg3 & ESP_CONFIG3_EWIDE) == 0)
- mask >>= 1;
-
- if (bytes_sent & mask)
- bytes_sent -= (bytes_sent & mask);
- }
- } else {
- if (!(esp->sreg & ESP_STAT_TCNT))
- bytes_sent -= ecount;
- if (SCptr->SCp.phase == in_dataout)
- bytes_sent -= fifocnt;
- }
-
- ESPDATA(("bytes_sent(%d), ", bytes_sent));
-
- /* If we were in synchronous mode, check for peculiarities. */
- if (esp->erev == fashme) {
- if (esp_dev->sync_max_offset) {
- if (SCptr->SCp.phase == in_dataout)
- esp_cmd(esp, ESP_CMD_FLUSH);
- } else {
- esp_cmd(esp, ESP_CMD_FLUSH);
- }
- } else {
- if (esp_dev->sync_max_offset)
- bogus_data = esp100_sync_hwbug(esp, SCptr, fifocnt);
- else
- esp_cmd(esp, ESP_CMD_FLUSH);
- }
-
- /* Until we are sure of what has happened, we are certainly
- * in the dark.
- */
- esp_advance_phase(SCptr, in_the_dark);
-
- if (bytes_sent < 0) {
- /* I've seen this happen due to lost state in this
- * driver. No idea why it happened, but allowing
- * this value to be negative caused things to
- * lock up. This allows greater chance of recovery.
- * In fact every time I've seen this, it has been
- * a driver bug without question.
- */
- ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id));
- ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n",
- esp->esp_id,
- esp->current_transfer_size, fifocnt, ecount));
- ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n",
- esp->esp_id,
- SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual));
- ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id,
- SCptr->device->id));
- SCptr->device->borken = 1;
- esp_dev->sync = 0;
- bytes_sent = 0;
- }
-
- /* Update the state of our transfer. */
- SCptr->SCp.ptr += bytes_sent;
- SCptr->SCp.this_residual -= bytes_sent;
- if (SCptr->SCp.this_residual < 0) {
- /* shit */
- ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id));
- SCptr->SCp.this_residual = 0;
- }
-
- /* Maybe continue. */
- if (!bogus_data) {
- ESPDATA(("!bogus_data, "));
-
- /* NO MATTER WHAT, we advance the scatterlist,
- * if the target should decide to disconnect
- * in between scatter chunks (which is common)
- * we could die horribly! I used to have the sg
- * advance occur only if we are going back into
- * (or are staying in) a data phase, you can
- * imagine the hell I went through trying to
- * figure this out.
- */
- if (SCptr->use_sg && !SCptr->SCp.this_residual)
- advance_sg(SCptr);
- if (sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) {
- ESPDATA(("to more data\n"));
- return esp_do_data(esp);
- }
- ESPDATA(("to new phase\n"));
- return esp_do_phase_determine(esp);
- }
- /* Bogus data, just wait for next interrupt. */
- ESPLOG(("esp%d: bogus_data during end of data phase\n",
- esp->esp_id));
- return do_intr_end;
-}
-
-/* We received a non-good status return at the end of
- * running a SCSI command. This is used to decide if
- * we should clear our synchronous transfer state for
- * such a device when that happens.
- *
- * The idea is that when spinning up a disk or rewinding
- * a tape, we don't want to go into a loop re-negotiating
- * synchronous capabilities over and over.
- */
-static int esp_should_clear_sync(struct scsi_cmnd *sp)
-{
- u8 cmd = sp->cmnd[0];
-
- /* These cases are for spinning up a disk and
- * waiting for that spinup to complete.
- */
- if (cmd == START_STOP)
- return 0;
-
- if (cmd == TEST_UNIT_READY)
- return 0;
-
- /* One more special case for SCSI tape drives,
- * this is what is used to probe the device for
- * completion of a rewind or tape load operation.
- */
- if (sp->device->type == TYPE_TAPE) {
- if (cmd == MODE_SENSE)
- return 0;
- }
-
- return 1;
-}
-
-/* Either a command is completing or a target is dropping off the bus
- * to continue the command in the background so we can do other work.
- */
-static int esp_do_freebus(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- struct esp_device *esp_dev = SCptr->device->hostdata;
- int rval;
-
- rval = skipahead2(esp, SCptr, in_status, in_msgindone, in_freeing);
- if (rval)
- return rval;
- if (esp->ireg != ESP_INTR_DC) {
- ESPLOG(("esp%d: Target will not disconnect\n", esp->esp_id));
- return do_reset_bus; /* target will not drop BSY... */
- }
- esp->msgout_len = 0;
- esp->prevmsgout = NOP;
- if (esp->prevmsgin == COMMAND_COMPLETE) {
- /* Normal end of nexus. */
- if (esp->disconnected_SC || (esp->erev == fashme))
- esp_cmd(esp, ESP_CMD_ESEL);
-
- if (SCptr->SCp.Status != GOOD &&
- SCptr->SCp.Status != CONDITION_GOOD &&
- ((1<<SCptr->device->id) & esp->targets_present) &&
- esp_dev->sync &&
- esp_dev->sync_max_offset) {
- /* SCSI standard says that the synchronous capabilities
- * should be renegotiated at this point. Most likely
- * we are about to request sense from this target
- * in which case we want to avoid using sync
- * transfers until we are sure of the current target
- * state.
- */
- ESPMISC(("esp: Status <%d> for target %d lun %d\n",
- SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun));
-
- /* But don't do this when spinning up a disk at
- * boot time while we poll for completion as it
- * fills up the console with messages. Also, tapes
- * can report not ready many times right after
- * loading up a tape.
- */
- if (esp_should_clear_sync(SCptr) != 0)
- esp_dev->sync = 0;
- }
- ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
- esp_done(esp, ((SCptr->SCp.Status & 0xff) |
- ((SCptr->SCp.Message & 0xff)<<8) |
- (DID_OK << 16)));
- } else if (esp->prevmsgin == DISCONNECT) {
- /* Normal disconnect. */
- esp_cmd(esp, ESP_CMD_ESEL);
- ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
- append_SC(&esp->disconnected_SC, SCptr);
- esp->current_SC = NULL;
- if (esp->issue_SC)
- esp_exec_cmd(esp);
- } else {
- /* Driver bug, we do not expect a disconnect here
- * and should not have advanced the state engine
- * to in_freeing.
- */
- ESPLOG(("esp%d: last msg not disc and not cmd cmplt.\n",
- esp->esp_id));
- return do_reset_bus;
- }
- return do_intr_end;
-}
-
-/* When a reselect occurs, and we cannot find the command to
- * reconnect to in our queues, we do this.
- */
-static int esp_bad_reconnect(struct esp *esp)
-{
- struct scsi_cmnd *sp;
-
- ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n",
- esp->esp_id));
- ESPLOG(("QUEUE DUMP\n"));
- sp = esp->issue_SC;
- ESPLOG(("esp%d: issue_SC[", esp->esp_id));
- while (sp) {
- ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
- sp = (struct scsi_cmnd *) sp->host_scribble;
- }
- ESPLOG(("]\n"));
- sp = esp->current_SC;
- ESPLOG(("esp%d: current_SC[", esp->esp_id));
- if (sp)
- ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
- else
- ESPLOG(("<NULL>"));
- ESPLOG(("]\n"));
- sp = esp->disconnected_SC;
- ESPLOG(("esp%d: disconnected_SC[", esp->esp_id));
- while (sp) {
- ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
- sp = (struct scsi_cmnd *) sp->host_scribble;
- }
- ESPLOG(("]\n"));
- return do_reset_bus;
-}
-
-/* Do the needy when a target tries to reconnect to us. */
-static int esp_do_reconnect(struct esp *esp)
-{
- int lun, target;
- struct scsi_cmnd *SCptr;
-
- /* Check for all bogus conditions first. */
- target = reconnect_target(esp);
- if (target < 0) {
- ESPDISC(("bad bus bits\n"));
- return do_reset_bus;
- }
- lun = reconnect_lun(esp);
- if (lun < 0) {
- ESPDISC(("target=%2x, bad identify msg\n", target));
- return do_reset_bus;
- }
-
- /* Things look ok... */
- ESPDISC(("R<%02x,%02x>", target, lun));
-
- /* Must not flush FIFO or DVMA on HME. */
- if (esp->erev != fashme) {
- esp_cmd(esp, ESP_CMD_FLUSH);
- if (esp100_reconnect_hwbug(esp))
- return do_reset_bus;
- esp_cmd(esp, ESP_CMD_NULL);
- }
-
- SCptr = remove_SC(&esp->disconnected_SC, (u8) target, (u8) lun);
- if (!SCptr)
- return esp_bad_reconnect(esp);
-
- esp_connect(esp, SCptr);
- esp_cmd(esp, ESP_CMD_MOK);
-
- if (esp->erev == fashme)
- sbus_writeb(((SCptr->device->id & 0xf) |
- (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT)),
- esp->eregs + ESP_BUSID);
-
- /* Reconnect implies a restore pointers operation. */
- esp_restore_pointers(esp, SCptr);
-
- esp->snip = 0;
- esp_advance_phase(SCptr, in_the_dark);
- return do_intr_end;
-}
-
-/* End of NEXUS (hopefully), pick up status + message byte then leave if
- * all goes well.
- */
-static int esp_do_status(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- int intr, rval;
-
- rval = skipahead1(esp, SCptr, in_the_dark, in_status);
- if (rval)
- return rval;
- intr = esp->ireg;
- ESPSTAT(("esp_do_status: "));
- if (intr != ESP_INTR_DC) {
- int message_out = 0; /* for parity problems */
-
- /* Ack the message. */
- ESPSTAT(("ack msg, "));
- esp_cmd(esp, ESP_CMD_MOK);
-
- if (esp->erev != fashme) {
- dma_flashclear(esp);
-
- /* Wait till the first bits settle. */
- while (esp->esp_command[0] == 0xff)
- udelay(1);
- } else {
- esp->esp_command[0] = esp->hme_fifo_workaround_buffer[0];
- esp->esp_command[1] = esp->hme_fifo_workaround_buffer[1];
- }
-
- ESPSTAT(("got something, "));
- /* ESP chimes in with one of
- *
- * 1) function done interrupt:
- * both status and message in bytes
- * are available
- *
- * 2) bus service interrupt:
- * only status byte was acquired
- *
- * 3) Anything else:
- * can't happen, but we test for it
- * anyways
- *
- * ALSO: If bad parity was detected on either
- * the status _or_ the message byte then
- * the ESP has asserted ATN on the bus
- * and we must therefore wait for the
- * next phase change.
- */
- if (intr & ESP_INTR_FDONE) {
- /* We got it all, hallejulia. */
- ESPSTAT(("got both, "));
- SCptr->SCp.Status = esp->esp_command[0];
- SCptr->SCp.Message = esp->esp_command[1];
- esp->prevmsgin = SCptr->SCp.Message;
- esp->cur_msgin[0] = SCptr->SCp.Message;
- if (esp->sreg & ESP_STAT_PERR) {
- /* There was bad parity for the
- * message byte, the status byte
- * was ok.
- */
- message_out = MSG_PARITY_ERROR;
- }
- } else if (intr == ESP_INTR_BSERV) {
- /* Only got status byte. */
- ESPLOG(("esp%d: got status only, ", esp->esp_id));
- if (!(esp->sreg & ESP_STAT_PERR)) {
- SCptr->SCp.Status = esp->esp_command[0];
- SCptr->SCp.Message = 0xff;
- } else {
- /* The status byte had bad parity.
- * we leave the scsi_pointer Status
- * field alone as we set it to a default
- * of CHECK_CONDITION in esp_queue.
- */
- message_out = INITIATOR_ERROR;
- }
- } else {
- /* This shouldn't happen ever. */
- ESPSTAT(("got bolixed\n"));
- esp_advance_phase(SCptr, in_the_dark);
- return esp_do_phase_determine(esp);
- }
-
- if (!message_out) {
- ESPSTAT(("status=%2x msg=%2x, ", SCptr->SCp.Status,
- SCptr->SCp.Message));
- if (SCptr->SCp.Message == COMMAND_COMPLETE) {
- ESPSTAT(("and was COMMAND_COMPLETE\n"));
- esp_advance_phase(SCptr, in_freeing);
- return esp_do_freebus(esp);
- } else {
- ESPLOG(("esp%d: and _not_ COMMAND_COMPLETE\n",
- esp->esp_id));
- esp->msgin_len = esp->msgin_ctr = 1;
- esp_advance_phase(SCptr, in_msgindone);
- return esp_do_msgindone(esp);
- }
- } else {
- /* With luck we'll be able to let the target
- * know that bad parity happened, it will know
- * which byte caused the problems and send it
- * again. For the case where the status byte
- * receives bad parity, I do not believe most
- * targets recover very well. We'll see.
- */
- ESPLOG(("esp%d: bad parity somewhere mout=%2x\n",
- esp->esp_id, message_out));
- esp->cur_msgout[0] = message_out;
- esp->msgout_len = esp->msgout_ctr = 1;
- esp_advance_phase(SCptr, in_the_dark);
- return esp_do_phase_determine(esp);
- }
- } else {
- /* If we disconnect now, all hell breaks loose. */
- ESPLOG(("esp%d: whoops, disconnect\n", esp->esp_id));
- esp_advance_phase(SCptr, in_the_dark);
- return esp_do_phase_determine(esp);
- }
-}
-
-static int esp_enter_status(struct esp *esp)
-{
- u8 thecmd = ESP_CMD_ICCSEQ;
-
- esp_cmd(esp, ESP_CMD_FLUSH);
- if (esp->erev != fashme) {
- u32 tmp;
-
- esp->esp_command[0] = esp->esp_command[1] = 0xff;
- sbus_writeb(2, esp->eregs + ESP_TCLOW);
- sbus_writeb(0, esp->eregs + ESP_TCMED);
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- tmp |= (DMA_ST_WRITE | DMA_ENABLE);
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- if (esp->dma->revision == dvmaesc1)
- sbus_writel(0x100, esp->dregs + DMA_COUNT);
- sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
- thecmd |= ESP_CMD_DMA;
- }
- esp_cmd(esp, thecmd);
- esp_advance_phase(esp->current_SC, in_status);
-
- return esp_do_status(esp);
-}
-
-static int esp_disconnect_amidst_phases(struct esp *esp)
-{
- struct scsi_cmnd *sp = esp->current_SC;
- struct esp_device *esp_dev = sp->device->hostdata;
-
- /* This means real problems if we see this
- * here. Unless we were actually trying
- * to force the device to abort/reset.
- */
- ESPLOG(("esp%d Disconnect amidst phases, ", esp->esp_id));
- ESPLOG(("pphase<%s> cphase<%s>, ",
- phase_string(sp->SCp.phase),
- phase_string(sp->SCp.sent_command)));
-
- if (esp->disconnected_SC != NULL || (esp->erev == fashme))
- esp_cmd(esp, ESP_CMD_ESEL);
-
- switch (esp->cur_msgout[0]) {
- default:
- /* We didn't expect this to happen at all. */
- ESPLOG(("device is bolixed\n"));
- esp_advance_phase(sp, in_tgterror);
- esp_done(esp, (DID_ERROR << 16));
- break;
-
- case BUS_DEVICE_RESET:
- ESPLOG(("device reset successful\n"));
- esp_dev->sync_max_offset = 0;
- esp_dev->sync_min_period = 0;
- esp_dev->sync = 0;
- esp_advance_phase(sp, in_resetdev);
- esp_done(esp, (DID_RESET << 16));
- break;
-
- case ABORT:
- ESPLOG(("device abort successful\n"));
- esp_advance_phase(sp, in_abortone);
- esp_done(esp, (DID_ABORT << 16));
- break;
-
- };
- return do_intr_end;
-}
-
-static int esp_enter_msgout(struct esp *esp)
-{
- esp_advance_phase(esp->current_SC, in_msgout);
- return esp_do_msgout(esp);
-}
-
-static int esp_enter_msgin(struct esp *esp)
-{
- esp_advance_phase(esp->current_SC, in_msgin);
- return esp_do_msgin(esp);
-}
-
-static int esp_enter_cmd(struct esp *esp)
-{
- esp_advance_phase(esp->current_SC, in_cmdbegin);
- return esp_do_cmdbegin(esp);
-}
-
-static int esp_enter_badphase(struct esp *esp)
-{
- ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id,
- esp->sreg & ESP_STAT_PMASK));
- return do_reset_bus;
-}
-
-typedef int (*espfunc_t)(struct esp *);
-
-static espfunc_t phase_vector[] = {
- esp_do_data, /* ESP_DOP */
- esp_do_data, /* ESP_DIP */
- esp_enter_cmd, /* ESP_CMDP */
- esp_enter_status, /* ESP_STATP */
- esp_enter_badphase, /* ESP_STAT_PMSG */
- esp_enter_badphase, /* ESP_STAT_PMSG | ESP_STAT_PIO */
- esp_enter_msgout, /* ESP_MOP */
- esp_enter_msgin, /* ESP_MIP */
-};
-
-/* The target has control of the bus and we have to see where it has
- * taken us.
- */
-static int esp_do_phase_determine(struct esp *esp)
-{
- if ((esp->ireg & ESP_INTR_DC) != 0)
- return esp_disconnect_amidst_phases(esp);
- return phase_vector[esp->sreg & ESP_STAT_PMASK](esp);
-}
-
-/* First interrupt after exec'ing a cmd comes here. */
-static int esp_select_complete(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- struct esp_device *esp_dev = SCptr->device->hostdata;
- int cmd_bytes_sent, fcnt;
-
- if (esp->erev != fashme)
- esp->seqreg = (sbus_readb(esp->eregs + ESP_SSTEP) & ESP_STEP_VBITS);
-
- if (esp->erev == fashme)
- fcnt = esp->hme_fifo_workaround_count;
- else
- fcnt = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES);
-
- cmd_bytes_sent = esp_bytes_sent(esp, fcnt);
- dma_invalidate(esp);
-
- /* Let's check to see if a reselect happened
- * while we we're trying to select. This must
- * be checked first.
- */
- if (esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) {
- esp_reconnect(esp, SCptr);
- return esp_do_reconnect(esp);
- }
-
- /* Looks like things worked, we should see a bus service &
- * a function complete interrupt at this point. Note we
- * are doing a direct comparison because we don't want to
- * be fooled into thinking selection was successful if
- * ESP_INTR_DC is set, see below.
- */
- if (esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) {
- /* target speaks... */
- esp->targets_present |= (1<<SCptr->device->id);
-
- /* What if the target ignores the sdtr? */
- if (esp->snip)
- esp_dev->sync = 1;
-
- /* See how far, if at all, we got in getting
- * the information out to the target.
- */
- switch (esp->seqreg) {
- default:
-
- case ESP_STEP_ASEL:
- /* Arbitration won, target selected, but
- * we are in some phase which is not command
- * phase nor is it message out phase.
- *
- * XXX We've confused the target, obviously.
- * XXX So clear it's state, but we also end
- * XXX up clearing everyone elses. That isn't
- * XXX so nice. I'd like to just reset this
- * XXX target, but if I cannot even get it's
- * XXX attention and finish selection to talk
- * XXX to it, there is not much more I can do.
- * XXX If we have a loaded bus we're going to
- * XXX spend the next second or so renegotiating
- * XXX for synchronous transfers.
- */
- ESPLOG(("esp%d: STEP_ASEL for tgt %d\n",
- esp->esp_id, SCptr->device->id));
-
- case ESP_STEP_SID:
- /* Arbitration won, target selected, went
- * to message out phase, sent one message
- * byte, then we stopped. ATN is asserted
- * on the SCSI bus and the target is still
- * there hanging on. This is a legal
- * sequence step if we gave the ESP a select
- * and stop command.
- *
- * XXX See above, I could set the borken flag
- * XXX in the device struct and retry the
- * XXX command. But would that help for
- * XXX tagged capable targets?
- */
-
- case ESP_STEP_NCMD:
- /* Arbitration won, target selected, maybe
- * sent the one message byte in message out
- * phase, but we did not go to command phase
- * in the end. Actually, we could have sent
- * only some of the message bytes if we tried
- * to send out the entire identify and tag
- * message using ESP_CMD_SA3.
- */
- cmd_bytes_sent = 0;
- break;
-
- case ESP_STEP_PPC:
- /* No, not the powerPC pinhead. Arbitration
- * won, all message bytes sent if we went to
- * message out phase, went to command phase
- * but only part of the command was sent.
- *
- * XXX I've seen this, but usually in conjunction
- * XXX with a gross error which appears to have
- * XXX occurred between the time I told the
- * XXX ESP to arbitrate and when I got the
- * XXX interrupt. Could I have misloaded the
- * XXX command bytes into the fifo? Actually,
- * XXX I most likely missed a phase, and therefore
- * XXX went into never never land and didn't even
- * XXX know it. That was the old driver though.
- * XXX What is even more peculiar is that the ESP
- * XXX showed the proper function complete and
- * XXX bus service bits in the interrupt register.
- */
-
- case ESP_STEP_FINI4:
- case ESP_STEP_FINI5:
- case ESP_STEP_FINI6:
- case ESP_STEP_FINI7:
- /* Account for the identify message */
- if (SCptr->SCp.phase == in_slct_norm)
- cmd_bytes_sent -= 1;
- };
-
- if (esp->erev != fashme)
- esp_cmd(esp, ESP_CMD_NULL);
-
- /* Be careful, we could really get fucked during synchronous
- * data transfers if we try to flush the fifo now.
- */
- if ((esp->erev != fashme) && /* not a Happy Meal and... */
- !fcnt && /* Fifo is empty and... */
- /* either we are not doing synchronous transfers or... */
- (!esp_dev->sync_max_offset ||
- /* We are not going into data in phase. */
- ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP)))
- esp_cmd(esp, ESP_CMD_FLUSH); /* flush is safe */
-
- /* See how far we got if this is not a slow command. */
- if (!esp->esp_slowcmd) {
- if (cmd_bytes_sent < 0)
- cmd_bytes_sent = 0;
- if (cmd_bytes_sent != SCptr->cmd_len) {
- /* Crapola, mark it as a slowcmd
- * so that we have some chance of
- * keeping the command alive with
- * good luck.
- *
- * XXX Actually, if we didn't send it all
- * XXX this means either we didn't set things
- * XXX up properly (driver bug) or the target
- * XXX or the ESP detected parity on one of
- * XXX the command bytes. This makes much
- * XXX more sense, and therefore this code
- * XXX should be changed to send out a
- * XXX parity error message or if the status
- * XXX register shows no parity error then
- * XXX just expect the target to bring the
- * XXX bus into message in phase so that it
- * XXX can send us the parity error message.
- * XXX SCSI sucks...
- */
- esp->esp_slowcmd = 1;
- esp->esp_scmdp = &(SCptr->cmnd[cmd_bytes_sent]);
- esp->esp_scmdleft = (SCptr->cmd_len - cmd_bytes_sent);
- }
- }
-
- /* Now figure out where we went. */
- esp_advance_phase(SCptr, in_the_dark);
- return esp_do_phase_determine(esp);
- }
-
- /* Did the target even make it? */
- if (esp->ireg == ESP_INTR_DC) {
- /* wheee... nobody there or they didn't like
- * what we told it to do, clean up.
- */
-
- /* If anyone is off the bus, but working on
- * a command in the background for us, tell
- * the ESP to listen for them.
- */
- if (esp->disconnected_SC)
- esp_cmd(esp, ESP_CMD_ESEL);
-
- if (((1<<SCptr->device->id) & esp->targets_present) &&
- esp->seqreg != 0 &&
- (esp->cur_msgout[0] == EXTENDED_MESSAGE) &&
- (SCptr->SCp.phase == in_slct_msg ||
- SCptr->SCp.phase == in_slct_stop)) {
- /* shit */
- esp->snip = 0;
- ESPLOG(("esp%d: Failed synchronous negotiation for target %d "
- "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
- esp_dev->sync_max_offset = 0;
- esp_dev->sync_min_period = 0;
- esp_dev->sync = 1; /* so we don't negotiate again */
-
- /* Run the command again, this time though we
- * won't try to negotiate for synchronous transfers.
- *
- * XXX I'd like to do something like send an
- * XXX INITIATOR_ERROR or ABORT message to the
- * XXX target to tell it, "Sorry I confused you,
- * XXX please come back and I will be nicer next
- * XXX time". But that requires having the target
- * XXX on the bus, and it has dropped BSY on us.
- */
- esp->current_SC = NULL;
- esp_advance_phase(SCptr, not_issued);
- prepend_SC(&esp->issue_SC, SCptr);
- esp_exec_cmd(esp);
- return do_intr_end;
- }
-
- /* Ok, this is normal, this is what we see during boot
- * or whenever when we are scanning the bus for targets.
- * But first make sure that is really what is happening.
- */
- if (((1<<SCptr->device->id) & esp->targets_present)) {
- ESPLOG(("esp%d: Warning, live target %d not responding to "
- "selection.\n", esp->esp_id, SCptr->device->id));
-
- /* This _CAN_ happen. The SCSI standard states that
- * the target is to _not_ respond to selection if
- * _it_ detects bad parity on the bus for any reason.
- * Therefore, we assume that if we've talked successfully
- * to this target before, bad parity is the problem.
- */
- esp_done(esp, (DID_PARITY << 16));
- } else {
- /* Else, there really isn't anyone there. */
- ESPMISC(("esp: selection failure, maybe nobody there?\n"));
- ESPMISC(("esp: target %d lun %d\n",
- SCptr->device->id, SCptr->device->lun));
- esp_done(esp, (DID_BAD_TARGET << 16));
- }
- return do_intr_end;
- }
-
- ESPLOG(("esp%d: Selection failure.\n", esp->esp_id));
- printk("esp%d: Currently -- ", esp->esp_id);
- esp_print_ireg(esp->ireg); printk(" ");
- esp_print_statreg(esp->sreg); printk(" ");
- esp_print_seqreg(esp->seqreg); printk("\n");
- printk("esp%d: New -- ", esp->esp_id);
- esp->sreg = sbus_readb(esp->eregs + ESP_STATUS);
- esp->seqreg = sbus_readb(esp->eregs + ESP_SSTEP);
- esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);
- esp_print_ireg(esp->ireg); printk(" ");
- esp_print_statreg(esp->sreg); printk(" ");
- esp_print_seqreg(esp->seqreg); printk("\n");
- ESPLOG(("esp%d: resetting bus\n", esp->esp_id));
- return do_reset_bus; /* ugh... */
-}
-
-/* Continue reading bytes for msgin phase. */
-static int esp_do_msgincont(struct esp *esp)
-{
- if (esp->ireg & ESP_INTR_BSERV) {
- /* in the right phase too? */
- if ((esp->sreg & ESP_STAT_PMASK) == ESP_MIP) {
- /* phew... */
- esp_cmd(esp, ESP_CMD_TI);
- esp_advance_phase(esp->current_SC, in_msgindone);
- return do_intr_end;
- }
-
- /* We changed phase but ESP shows bus service,
- * in this case it is most likely that we, the
- * hacker who has been up for 20hrs straight
- * staring at the screen, drowned in coffee
- * smelling like retched cigarette ashes
- * have miscoded something..... so, try to
- * recover as best we can.
- */
- ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id));
- }
- esp_advance_phase(esp->current_SC, in_the_dark);
- return do_phase_determine;
-}
-
-static int check_singlebyte_msg(struct esp *esp)
-{
- esp->prevmsgin = esp->cur_msgin[0];
- if (esp->cur_msgin[0] & 0x80) {
- /* wheee... */
- ESPLOG(("esp%d: target sends identify amidst phases\n",
- esp->esp_id));
- esp_advance_phase(esp->current_SC, in_the_dark);
- return 0;
- } else if (((esp->cur_msgin[0] & 0xf0) == 0x20) ||
- (esp->cur_msgin[0] == EXTENDED_MESSAGE)) {
- esp->msgin_len = 2;
- esp_advance_phase(esp->current_SC, in_msgincont);
- return 0;
- }
- esp_advance_phase(esp->current_SC, in_the_dark);
- switch (esp->cur_msgin[0]) {
- default:
- /* We don't want to hear about it. */
- ESPLOG(("esp%d: msg %02x which we don't know about\n", esp->esp_id,
- esp->cur_msgin[0]));
- return MESSAGE_REJECT;
-
- case NOP:
- ESPLOG(("esp%d: target %d sends a nop\n", esp->esp_id,
- esp->current_SC->device->id));
- return 0;
-
- case RESTORE_POINTERS:
- /* In this case we might also have to backup the
- * "slow command" pointer. It is rare to get such
- * a save/restore pointer sequence so early in the
- * bus transition sequences, but cover it.
- */
- if (esp->esp_slowcmd) {
- esp->esp_scmdleft = esp->current_SC->cmd_len;
- esp->esp_scmdp = &esp->current_SC->cmnd[0];
- }
- esp_restore_pointers(esp, esp->current_SC);
- return 0;
-
- case SAVE_POINTERS:
- esp_save_pointers(esp, esp->current_SC);
- return 0;
-
- case COMMAND_COMPLETE:
- case DISCONNECT:
- /* Freeing the bus, let it go. */
- esp->current_SC->SCp.phase = in_freeing;
- return 0;
-
- case MESSAGE_REJECT:
- ESPMISC(("msg reject, "));
- if (esp->prevmsgout == EXTENDED_MESSAGE) {
- struct esp_device *esp_dev = esp->current_SC->device->hostdata;
-
- /* Doesn't look like this target can
- * do synchronous or WIDE transfers.
- */
- ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n"));
- esp_dev->sync = 1;
- esp_dev->wide = 1;
- esp_dev->sync_min_period = 0;
- esp_dev->sync_max_offset = 0;
- return 0;
- } else {
- ESPMISC(("not sync nego, sending ABORT\n"));
- return ABORT;
- }
- };
-}
-
-/* Target negotiates for synchronous transfers before we do, this
- * is legal although very strange. What is even funnier is that
- * the SCSI2 standard specifically recommends against targets doing
- * this because so many initiators cannot cope with this occurring.
- */
-static int target_with_ants_in_pants(struct esp *esp,
- struct scsi_cmnd *SCptr,
- struct esp_device *esp_dev)
-{
- if (esp_dev->sync || SCptr->device->borken) {
- /* sorry, no can do */
- ESPSDTR(("forcing to async, "));
- build_sync_nego_msg(esp, 0, 0);
- esp_dev->sync = 1;
- esp->snip = 1;
- ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id));
- esp_advance_phase(SCptr, in_the_dark);
- return EXTENDED_MESSAGE;
- }
-
- /* Ok, we'll check them out... */
- return 0;
-}
-
-static void sync_report(struct esp *esp)
-{
- int msg3, msg4;
- char *type;
-
- msg3 = esp->cur_msgin[3];
- msg4 = esp->cur_msgin[4];
- if (msg4) {
- int hz = 1000000000 / (msg3 * 4);
- int integer = hz / 1000000;
- int fraction = (hz - (integer * 1000000)) / 10000;
- if ((esp->erev == fashme) &&
- (esp->config3[esp->current_SC->device->id] & ESP_CONFIG3_EWIDE)) {
- type = "FAST-WIDE";
- integer <<= 1;
- fraction <<= 1;
- } else if ((msg3 * 4) < 200) {
- type = "FAST";
- } else {
- type = "synchronous";
- }
-
- /* Do not transform this back into one big printk
- * again, it triggers a bug in our sparc64-gcc272
- * sibling call optimization. -DaveM
- */
- ESPLOG((KERN_INFO "esp%d: target %d ",
- esp->esp_id, esp->current_SC->device->id));
- ESPLOG(("[period %dns offset %d %d.%02dMHz ",
- (int) msg3 * 4, (int) msg4,
- integer, fraction));
- ESPLOG(("%s SCSI%s]\n", type,
- (((msg3 * 4) < 200) ? "-II" : "")));
- } else {
- ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n",
- esp->esp_id, esp->current_SC->device->id));
- }
-}
-
-static int check_multibyte_msg(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- struct esp_device *esp_dev = SCptr->device->hostdata;
- u8 regval = 0;
- int message_out = 0;
-
- ESPSDTR(("chk multibyte msg: "));
- if (esp->cur_msgin[2] == EXTENDED_SDTR) {
- int period = esp->cur_msgin[3];
- int offset = esp->cur_msgin[4];
-
- ESPSDTR(("is sync nego response, "));
- if (!esp->snip) {
- int rval;
-
- /* Target negotiates first! */
- ESPSDTR(("target jumps the gun, "));
- message_out = EXTENDED_MESSAGE; /* we must respond */
- rval = target_with_ants_in_pants(esp, SCptr, esp_dev);
- if (rval)
- return rval;
- }
-
- ESPSDTR(("examining sdtr, "));
-
- /* Offset cannot be larger than ESP fifo size. */
- if (offset > 15) {
- ESPSDTR(("offset too big %2x, ", offset));
- offset = 15;
- ESPSDTR(("sending back new offset\n"));
- build_sync_nego_msg(esp, period, offset);
- return EXTENDED_MESSAGE;
- }
-
- if (offset && period > esp->max_period) {
- /* Yeee, async for this slow device. */
- ESPSDTR(("period too long %2x, ", period));
- build_sync_nego_msg(esp, 0, 0);
- ESPSDTR(("hoping for msgout\n"));
- esp_advance_phase(esp->current_SC, in_the_dark);
- return EXTENDED_MESSAGE;
- } else if (offset && period < esp->min_period) {
- ESPSDTR(("period too short %2x, ", period));
- period = esp->min_period;
- if (esp->erev > esp236)
- regval = 4;
- else
- regval = 5;
- } else if (offset) {
- int tmp;
-
- ESPSDTR(("period is ok, "));
- tmp = esp->ccycle / 1000;
- regval = (((period << 2) + tmp - 1) / tmp);
- if (regval && ((esp->erev == fas100a ||
- esp->erev == fas236 ||
- esp->erev == fashme))) {
- if (period >= 50)
- regval--;
- }
- }
-
- if (offset) {
- u8 bit;
-
- esp_dev->sync_min_period = (regval & 0x1f);
- esp_dev->sync_max_offset = (offset | esp->radelay);
- if (esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme) {
- if ((esp->erev == fas100a) || (esp->erev == fashme))
- bit = ESP_CONFIG3_FAST;
- else
- bit = ESP_CONFIG3_FSCSI;
- if (period < 50) {
- /* On FAS366, if using fast-20 synchronous transfers
- * we need to make sure the REQ/ACK assert/deassert
- * control bits are clear.
- */
- if (esp->erev == fashme)
- esp_dev->sync_max_offset &= ~esp->radelay;
- esp->config3[SCptr->device->id] |= bit;
- } else {
- esp->config3[SCptr->device->id] &= ~bit;
- }
- esp->prev_cfg3 = esp->config3[SCptr->device->id];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- }
- esp->prev_soff = esp_dev->sync_max_offset;
- esp->prev_stp = esp_dev->sync_min_period;
- sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
- sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
- ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
- esp_dev->sync_max_offset,
- esp_dev->sync_min_period,
- esp->config3[SCptr->device->id]));
-
- esp->snip = 0;
- } else if (esp_dev->sync_max_offset) {
- u8 bit;
-
- /* back to async mode */
- ESPSDTR(("unaccaptable sync nego, forcing async\n"));
- esp_dev->sync_max_offset = 0;
- esp_dev->sync_min_period = 0;
- esp->prev_soff = 0;
- esp->prev_stp = 0;
- sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
- sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
- if (esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme) {
- if ((esp->erev == fas100a) || (esp->erev == fashme))
- bit = ESP_CONFIG3_FAST;
- else
- bit = ESP_CONFIG3_FSCSI;
- esp->config3[SCptr->device->id] &= ~bit;
- esp->prev_cfg3 = esp->config3[SCptr->device->id];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- }
- }
-
- sync_report(esp);
-
- ESPSDTR(("chk multibyte msg: sync is known, "));
- esp_dev->sync = 1;
-
- if (message_out) {
- ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n",
- esp->esp_id));
- build_sync_nego_msg(esp, period, offset);
- esp_advance_phase(SCptr, in_the_dark);
- return EXTENDED_MESSAGE;
- }
-
- ESPSDTR(("returning zero\n"));
- esp_advance_phase(SCptr, in_the_dark); /* ...or else! */
- return 0;
- } else if (esp->cur_msgin[2] == EXTENDED_WDTR) {
- int size = 8 << esp->cur_msgin[3];
-
- esp->wnip = 0;
- if (esp->erev != fashme) {
- ESPLOG(("esp%d: AIEEE wide msg received and not HME.\n",
- esp->esp_id));
- message_out = MESSAGE_REJECT;
- } else if (size > 16) {
- ESPLOG(("esp%d: AIEEE wide transfer for %d size "
- "not supported.\n", esp->esp_id, size));
- message_out = MESSAGE_REJECT;
- } else {
- /* Things look good; let's see what we got. */
- if (size == 16) {
- /* Set config 3 register for this target. */
- esp->config3[SCptr->device->id] |= ESP_CONFIG3_EWIDE;
- } else {
- /* Just make sure it was one byte sized. */
- if (size != 8) {
- ESPLOG(("esp%d: Aieee, wide nego of %d size.\n",
- esp->esp_id, size));
- message_out = MESSAGE_REJECT;
- goto finish;
- }
- /* Pure paranoia. */
- esp->config3[SCptr->device->id] &= ~(ESP_CONFIG3_EWIDE);
- }
- esp->prev_cfg3 = esp->config3[SCptr->device->id];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-
- /* Regardless, next try for sync transfers. */
- build_sync_nego_msg(esp, esp->sync_defp, 15);
- esp_dev->sync = 1;
- esp->snip = 1;
- message_out = EXTENDED_MESSAGE;
- }
- } else if (esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) {
- ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id));
- message_out = MESSAGE_REJECT;
- }
-finish:
- esp_advance_phase(SCptr, in_the_dark);
- return message_out;
-}
-
-static int esp_do_msgindone(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- int message_out = 0, it = 0, rval;
-
- rval = skipahead1(esp, SCptr, in_msgin, in_msgindone);
- if (rval)
- return rval;
- if (SCptr->SCp.sent_command != in_status) {
- if (!(esp->ireg & ESP_INTR_DC)) {
- if (esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) {
- message_out = MSG_PARITY_ERROR;
- esp_cmd(esp, ESP_CMD_FLUSH);
- } else if (esp->erev != fashme &&
- (it = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES)) != 1) {
- /* We certainly dropped the ball somewhere. */
- message_out = INITIATOR_ERROR;
- esp_cmd(esp, ESP_CMD_FLUSH);
- } else if (!esp->msgin_len) {
- if (esp->erev == fashme)
- it = esp->hme_fifo_workaround_buffer[0];
- else
- it = sbus_readb(esp->eregs + ESP_FDATA);
- esp_advance_phase(SCptr, in_msgincont);
- } else {
- /* it is ok and we want it */
- if (esp->erev == fashme)
- it = esp->cur_msgin[esp->msgin_ctr] =
- esp->hme_fifo_workaround_buffer[0];
- else
- it = esp->cur_msgin[esp->msgin_ctr] =
- sbus_readb(esp->eregs + ESP_FDATA);
- esp->msgin_ctr++;
- }
- } else {
- esp_advance_phase(SCptr, in_the_dark);
- return do_work_bus;
- }
- } else {
- it = esp->cur_msgin[0];
- }
- if (!message_out && esp->msgin_len) {
- if (esp->msgin_ctr < esp->msgin_len) {
- esp_advance_phase(SCptr, in_msgincont);
- } else if (esp->msgin_len == 1) {
- message_out = check_singlebyte_msg(esp);
- } else if (esp->msgin_len == 2) {
- if (esp->cur_msgin[0] == EXTENDED_MESSAGE) {
- if ((it + 2) >= 15) {
- message_out = MESSAGE_REJECT;
- } else {
- esp->msgin_len = (it + 2);
- esp_advance_phase(SCptr, in_msgincont);
- }
- } else {
- message_out = MESSAGE_REJECT; /* foo on you */
- }
- } else {
- message_out = check_multibyte_msg(esp);
- }
- }
- if (message_out < 0) {
- return -message_out;
- } else if (message_out) {
- if (((message_out != 1) &&
- ((message_out < 0x20) || (message_out & 0x80))))
- esp->msgout_len = 1;
- esp->cur_msgout[0] = message_out;
- esp_cmd(esp, ESP_CMD_SATN);
- esp_advance_phase(SCptr, in_the_dark);
- esp->msgin_len = 0;
- }
- esp->sreg = sbus_readb(esp->eregs + ESP_STATUS);
- esp->sreg &= ~(ESP_STAT_INTR);
- if ((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD))
- esp_cmd(esp, ESP_CMD_MOK);
- if ((SCptr->SCp.sent_command == in_msgindone) &&
- (SCptr->SCp.phase == in_freeing))
- return esp_do_freebus(esp);
- return do_intr_end;
-}
-
-static int esp_do_cmdbegin(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
-
- esp_advance_phase(SCptr, in_cmdend);
- if (esp->erev == fashme) {
- u32 tmp = sbus_readl(esp->dregs + DMA_CSR);
- int i;
-
- for (i = 0; i < esp->esp_scmdleft; i++)
- esp->esp_command[i] = *esp->esp_scmdp++;
- esp->esp_scmdleft = 0;
- esp_cmd(esp, ESP_CMD_FLUSH);
- esp_setcount(esp->eregs, i, 1);
- esp_cmd(esp, (ESP_CMD_DMA | ESP_CMD_TI));
- tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
- tmp &= ~(DMA_ST_WRITE);
- sbus_writel(i, esp->dregs + DMA_COUNT);
- sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- } else {
- u8 tmp;
-
- esp_cmd(esp, ESP_CMD_FLUSH);
- tmp = *esp->esp_scmdp++;
- esp->esp_scmdleft--;
- sbus_writeb(tmp, esp->eregs + ESP_FDATA);
- esp_cmd(esp, ESP_CMD_TI);
- }
- return do_intr_end;
-}
-
-static int esp_do_cmddone(struct esp *esp)
-{
- if (esp->erev == fashme)
- dma_invalidate(esp);
- else
- esp_cmd(esp, ESP_CMD_NULL);
-
- if (esp->ireg & ESP_INTR_BSERV) {
- esp_advance_phase(esp->current_SC, in_the_dark);
- return esp_do_phase_determine(esp);
- }
-
- ESPLOG(("esp%d: in do_cmddone() but didn't get BSERV interrupt.\n",
- esp->esp_id));
- return do_reset_bus;
-}
-
-static int esp_do_msgout(struct esp *esp)
-{
- esp_cmd(esp, ESP_CMD_FLUSH);
- switch (esp->msgout_len) {
- case 1:
- if (esp->erev == fashme)
- hme_fifo_push(esp, &esp->cur_msgout[0], 1);
- else
- sbus_writeb(esp->cur_msgout[0], esp->eregs + ESP_FDATA);
-
- esp_cmd(esp, ESP_CMD_TI);
- break;
-
- case 2:
- esp->esp_command[0] = esp->cur_msgout[0];
- esp->esp_command[1] = esp->cur_msgout[1];
-
- if (esp->erev == fashme) {
- hme_fifo_push(esp, &esp->cur_msgout[0], 2);
- esp_cmd(esp, ESP_CMD_TI);
- } else {
- dma_setup(esp, esp->esp_command_dvma, 2, 0);
- esp_setcount(esp->eregs, 2, 0);
- esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
- }
- break;
-
- case 4:
- esp->esp_command[0] = esp->cur_msgout[0];
- esp->esp_command[1] = esp->cur_msgout[1];
- esp->esp_command[2] = esp->cur_msgout[2];
- esp->esp_command[3] = esp->cur_msgout[3];
- esp->snip = 1;
-
- if (esp->erev == fashme) {
- hme_fifo_push(esp, &esp->cur_msgout[0], 4);
- esp_cmd(esp, ESP_CMD_TI);
- } else {
- dma_setup(esp, esp->esp_command_dvma, 4, 0);
- esp_setcount(esp->eregs, 4, 0);
- esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
- }
- break;
-
- case 5:
- esp->esp_command[0] = esp->cur_msgout[0];
- esp->esp_command[1] = esp->cur_msgout[1];
- esp->esp_command[2] = esp->cur_msgout[2];
- esp->esp_command[3] = esp->cur_msgout[3];
- esp->esp_command[4] = esp->cur_msgout[4];
- esp->snip = 1;
-
- if (esp->erev == fashme) {
- hme_fifo_push(esp, &esp->cur_msgout[0], 5);
- esp_cmd(esp, ESP_CMD_TI);
- } else {
- dma_setup(esp, esp->esp_command_dvma, 5, 0);
- esp_setcount(esp->eregs, 5, 0);
- esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
- }
- break;
-
- default:
- /* whoops */
- ESPMISC(("bogus msgout sending NOP\n"));
- esp->cur_msgout[0] = NOP;
-
- if (esp->erev == fashme) {
- hme_fifo_push(esp, &esp->cur_msgout[0], 1);
- } else {
- sbus_writeb(esp->cur_msgout[0], esp->eregs + ESP_FDATA);
- }
-
- esp->msgout_len = 1;
- esp_cmd(esp, ESP_CMD_TI);
- break;
- };
-
- esp_advance_phase(esp->current_SC, in_msgoutdone);
- return do_intr_end;
-}
-
-static int esp_do_msgoutdone(struct esp *esp)
-{
- if (esp->msgout_len > 1) {
- /* XXX HME/FAS ATN deassert workaround required,
- * XXX no DMA flushing, only possible ESP_CMD_FLUSH
- * XXX to kill the fifo.
- */
- if (esp->erev != fashme) {
- u32 tmp;
-
- while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ)
- udelay(1);
- tmp &= ~DMA_ENABLE;
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- dma_invalidate(esp);
- } else {
- esp_cmd(esp, ESP_CMD_FLUSH);
- }
- }
- if (!(esp->ireg & ESP_INTR_DC)) {
- if (esp->erev != fashme)
- esp_cmd(esp, ESP_CMD_NULL);
- switch (esp->sreg & ESP_STAT_PMASK) {
- case ESP_MOP:
- /* whoops, parity error */
- ESPLOG(("esp%d: still in msgout, parity error assumed\n",
- esp->esp_id));
- if (esp->msgout_len > 1)
- esp_cmd(esp, ESP_CMD_SATN);
- esp_advance_phase(esp->current_SC, in_msgout);
- return do_work_bus;
-
- case ESP_DIP:
- break;
-
- default:
- /* Happy Meal fifo is touchy... */
- if ((esp->erev != fashme) &&
- !fcount(esp) &&
- !(((struct esp_device *)esp->current_SC->device->hostdata)->sync_max_offset))
- esp_cmd(esp, ESP_CMD_FLUSH);
- break;
-
- };
- } else {
- ESPLOG(("esp%d: disconnect, resetting bus\n", esp->esp_id));
- return do_reset_bus;
- }
-
- /* If we sent out a synchronous negotiation message, update
- * our state.
- */
- if (esp->cur_msgout[2] == EXTENDED_MESSAGE &&
- esp->cur_msgout[4] == EXTENDED_SDTR) {
- esp->snip = 1; /* anal retentiveness... */
- }
-
- esp->prevmsgout = esp->cur_msgout[0];
- esp->msgout_len = 0;
- esp_advance_phase(esp->current_SC, in_the_dark);
- return esp_do_phase_determine(esp);
-}
-
-static int esp_bus_unexpected(struct esp *esp)
-{
- ESPLOG(("esp%d: command in weird state %2x\n",
- esp->esp_id, esp->current_SC->SCp.phase));
- return do_reset_bus;
-}
-
-static espfunc_t bus_vector[] = {
- esp_do_data_finale,
- esp_do_data_finale,
- esp_bus_unexpected,
- esp_do_msgin,
- esp_do_msgincont,
- esp_do_msgindone,
- esp_do_msgout,
- esp_do_msgoutdone,
- esp_do_cmdbegin,
- esp_do_cmddone,
- esp_do_status,
- esp_do_freebus,
- esp_do_phase_determine,
- esp_bus_unexpected,
- esp_bus_unexpected,
- esp_bus_unexpected,
-};
-
-/* This is the second tier in our dual-level SCSI state machine. */
-static int esp_work_bus(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- unsigned int phase;
-
- ESPBUS(("esp_work_bus: "));
- if (!SCptr) {
- ESPBUS(("reconnect\n"));
- return esp_do_reconnect(esp);
- }
- phase = SCptr->SCp.phase;
- if ((phase & 0xf0) == in_phases_mask)
- return bus_vector[(phase & 0x0f)](esp);
- else if ((phase & 0xf0) == in_slct_mask)
- return esp_select_complete(esp);
- else
- return esp_bus_unexpected(esp);
-}
-
-static espfunc_t isvc_vector[] = {
- NULL,
- esp_do_phase_determine,
- esp_do_resetbus,
- esp_finish_reset,
- esp_work_bus
-};
-
-/* Main interrupt handler for an esp adapter. */
-static void esp_handle(struct esp *esp)
-{
- struct scsi_cmnd *SCptr;
- int what_next = do_intr_end;
-
- SCptr = esp->current_SC;
-
- /* Check for errors. */
- esp->sreg = sbus_readb(esp->eregs + ESP_STATUS);
- esp->sreg &= (~ESP_STAT_INTR);
- if (esp->erev == fashme) {
- esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);
- esp->seqreg = (sbus_readb(esp->eregs + ESP_SSTEP) & ESP_STEP_VBITS);
- }
-
- if (esp->sreg & (ESP_STAT_SPAM)) {
- /* Gross error, could be due to one of:
- *
- * - top of fifo overwritten, could be because
- * we tried to do a synchronous transfer with
- * an offset greater than ESP fifo size
- *
- * - top of command register overwritten
- *
- * - DMA setup to go in one direction, SCSI
- * bus points in the other, whoops
- *
- * - weird phase change during asynchronous
- * data phase while we are initiator
- */
- ESPLOG(("esp%d: Gross error sreg=%2x\n", esp->esp_id, esp->sreg));
-
- /* If a command is live on the bus we cannot safely
- * reset the bus, so we'll just let the pieces fall
- * where they may. Here we are hoping that the
- * target will be able to cleanly go away soon
- * so we can safely reset things.
- */
- if (!SCptr) {
- ESPLOG(("esp%d: No current cmd during gross error, "
- "resetting bus\n", esp->esp_id));
- what_next = do_reset_bus;
- goto state_machine;
- }
- }
-
- if (sbus_readl(esp->dregs + DMA_CSR) & DMA_HNDL_ERROR) {
- /* A DMA gate array error. Here we must
- * be seeing one of two things. Either the
- * virtual to physical address translation
- * on the SBUS could not occur, else the
- * translation it did get pointed to a bogus
- * page. Ho hum...
- */
- ESPLOG(("esp%d: DMA error %08x\n", esp->esp_id,
- sbus_readl(esp->dregs + DMA_CSR)));
-
- /* DMA gate array itself must be reset to clear the
- * error condition.
- */
- esp_reset_dma(esp);
-
- what_next = do_reset_bus;
- goto state_machine;
- }
-
- esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT); /* Unlatch intr reg */
-
- if (esp->erev == fashme) {
- /* This chip is really losing. */
- ESPHME(("HME["));
-
- ESPHME(("sreg2=%02x,", esp->sreg2));
- /* Must latch fifo before reading the interrupt
- * register else garbage ends up in the FIFO
- * which confuses the driver utterly.
- */
- if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
- (esp->sreg2 & ESP_STAT2_F1BYTE)) {
- ESPHME(("fifo_workaround]"));
- hme_fifo_read(esp);
- } else {
- ESPHME(("no_fifo_workaround]"));
- }
- }
-
- /* No current cmd is only valid at this point when there are
- * commands off the bus or we are trying a reset.
- */
- if (!SCptr && !esp->disconnected_SC && !(esp->ireg & ESP_INTR_SR)) {
- /* Panic is safe, since current_SC is null. */
- ESPLOG(("esp%d: no command in esp_handle()\n", esp->esp_id));
- panic("esp_handle: current_SC == penguin within interrupt!");
- }
-
- if (esp->ireg & (ESP_INTR_IC)) {
- /* Illegal command fed to ESP. Outside of obvious
- * software bugs that could cause this, there is
- * a condition with esp100 where we can confuse the
- * ESP into an erroneous illegal command interrupt
- * because it does not scrape the FIFO properly
- * for reselection. See esp100_reconnect_hwbug()
- * to see how we try very hard to avoid this.
- */
- ESPLOG(("esp%d: invalid command\n", esp->esp_id));
-
- esp_dump_state(esp);
-
- if (SCptr != NULL) {
- /* Devices with very buggy firmware can drop BSY
- * during a scatter list interrupt when using sync
- * mode transfers. We continue the transfer as
- * expected, the target drops the bus, the ESP
- * gets confused, and we get a illegal command
- * interrupt because the bus is in the disconnected
- * state now and ESP_CMD_TI is only allowed when
- * a nexus is alive on the bus.
- */
- ESPLOG(("esp%d: Forcing async and disabling disconnect for "
- "target %d\n", esp->esp_id, SCptr->device->id));
- SCptr->device->borken = 1; /* foo on you */
- }
-
- what_next = do_reset_bus;
- } else if (!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) {
- if (SCptr) {
- unsigned int phase = SCptr->SCp.phase;
-
- if (phase & in_phases_mask) {
- what_next = esp_work_bus(esp);
- } else if (phase & in_slct_mask) {
- what_next = esp_select_complete(esp);
- } else {
- ESPLOG(("esp%d: interrupt for no good reason...\n",
- esp->esp_id));
- what_next = do_intr_end;
- }
- } else {
- ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n",
- esp->esp_id));
- what_next = do_reset_bus;
- }
- } else if (esp->ireg & ESP_INTR_SR) {
- ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id));
- what_next = do_reset_complete;
- } else if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN)) {
- ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n",
- esp->esp_id));
- what_next = do_reset_bus;
- } else if (esp->ireg & ESP_INTR_RSEL) {
- if (SCptr == NULL) {
- /* This is ok. */
- what_next = esp_do_reconnect(esp);
- } else if (SCptr->SCp.phase & in_slct_mask) {
- /* Only selection code knows how to clean
- * up properly.
- */
- ESPDISC(("Reselected during selection attempt\n"));
- what_next = esp_select_complete(esp);
- } else {
- ESPLOG(("esp%d: Reselected while bus is busy\n",
- esp->esp_id));
- what_next = do_reset_bus;
- }
- }
-
- /* This is tier-one in our dual level SCSI state machine. */
-state_machine:
- while (what_next != do_intr_end) {
- if (what_next >= do_phase_determine &&
- what_next < do_intr_end) {
- what_next = isvc_vector[what_next](esp);
- } else {
- /* state is completely lost ;-( */
- ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n",
- esp->esp_id));
- what_next = do_reset_bus;
- }
- }
-}
-
-/* Service only the ESP described by dev_id. */
-static irqreturn_t esp_intr(int irq, void *dev_id)
-{
- struct esp *esp = dev_id;
- unsigned long flags;
-
- spin_lock_irqsave(esp->ehost->host_lock, flags);
- if (ESP_IRQ_P(esp->dregs)) {
- ESP_INTSOFF(esp->dregs);
-
- ESPIRQ(("I[%d:%d](", smp_processor_id(), esp->esp_id));
- esp_handle(esp);
- ESPIRQ((")"));
-
- ESP_INTSON(esp->dregs);
- }
- spin_unlock_irqrestore(esp->ehost->host_lock, flags);
-
- return IRQ_HANDLED;
-}
-
-static int esp_slave_alloc(struct scsi_device *SDptr)
-{
- struct esp_device *esp_dev =
- kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
-
- if (!esp_dev)
- return -ENOMEM;
- memset(esp_dev, 0, sizeof(struct esp_device));
- SDptr->hostdata = esp_dev;
- return 0;
-}
-
-static void esp_slave_destroy(struct scsi_device *SDptr)
-{
- struct esp *esp = (struct esp *) SDptr->host->hostdata;
-
- esp->targets_present &= ~(1 << SDptr->id);
- kfree(SDptr->hostdata);
- SDptr->hostdata = NULL;
-}
-
-static struct scsi_host_template esp_template = {
- .module = THIS_MODULE,
- .name = "esp",
- .info = esp_info,
- .slave_alloc = esp_slave_alloc,
- .slave_destroy = esp_slave_destroy,
- .queuecommand = esp_queue,
- .eh_abort_handler = esp_abort,
- .eh_bus_reset_handler = esp_reset,
- .can_queue = 7,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = 1,
- .use_clustering = ENABLE_CLUSTERING,
- .proc_name = "esp",
- .proc_info = esp_proc_info,
-};
-
-#ifndef CONFIG_SUN4
-static struct of_device_id esp_match[] = {
- {
- .name = "SUNW,esp",
- .data = &esp_template,
- },
- {
- .name = "SUNW,fas",
- .data = &esp_template,
- },
- {
- .name = "esp",
- .data = &esp_template,
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, esp_match);
-
-static struct of_platform_driver esp_sbus_driver = {
- .name = "esp",
- .match_table = esp_match,
- .probe = esp_sbus_probe,
- .remove = __devexit_p(esp_sbus_remove),
-};
-#endif
-
-static int __init esp_init(void)
-{
-#ifdef CONFIG_SUN4
- return esp_sun4_probe(&esp_template);
-#else
- return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
-#endif
-}
-
-static void __exit esp_exit(void)
-{
-#ifdef CONFIG_SUN4
- esp_sun4_remove();
-#else
- of_unregister_driver(&esp_sbus_driver);
-#endif
-}
-
-MODULE_DESCRIPTION("ESP Sun SCSI driver");
-MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
-module_init(esp_init);
-module_exit(esp_exit);
diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h
deleted file mode 100644
index a98cda9121f..00000000000
--- a/drivers/scsi/esp.h
+++ /dev/null
@@ -1,406 +0,0 @@
-/* $Id: esp.h,v 1.29 2001/12/11 04:55:47 davem Exp $
- * esp.h: Defines and structures for the Sparc ESP (Enhanced SCSI
- * Processor) driver under Linux.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _SPARC_ESP_H
-#define _SPARC_ESP_H
-
-/* For dvma controller register definitions. */
-#include <asm/dma.h>
-
-/* The ESP SCSI controllers have their register sets in three
- * "classes":
- *
- * 1) Registers which are both read and write.
- * 2) Registers which are read only.
- * 3) Registers which are write only.
- *
- * Yet, they all live within the same IO space.
- */
-
-/* All the ESP registers are one byte each and are accessed longwords
- * apart with a big-endian ordering to the bytes.
- */
- /* Access Description Offset */
-#define ESP_TCLOW 0x00UL /* rw Low bits of the transfer count 0x00 */
-#define ESP_TCMED 0x04UL /* rw Mid bits of the transfer count 0x04 */
-#define ESP_FDATA 0x08UL /* rw FIFO data bits 0x08 */
-#define ESP_CMD 0x0cUL /* rw SCSI command bits 0x0c */
-#define ESP_STATUS 0x10UL /* ro ESP status register 0x10 */
-#define ESP_BUSID ESP_STATUS /* wo Bus ID for select/reselect 0x10 */
-#define ESP_INTRPT 0x14UL /* ro Kind of interrupt 0x14 */
-#define ESP_TIMEO ESP_INTRPT /* wo Timeout value for select/resel 0x14 */
-#define ESP_SSTEP 0x18UL /* ro Sequence step register 0x18 */
-#define ESP_STP ESP_SSTEP /* wo Transfer period per sync 0x18 */
-#define ESP_FFLAGS 0x1cUL /* ro Bits of current FIFO info 0x1c */
-#define ESP_SOFF ESP_FFLAGS /* wo Sync offset 0x1c */
-#define ESP_CFG1 0x20UL /* rw First configuration register 0x20 */
-#define ESP_CFACT 0x24UL /* wo Clock conversion factor 0x24 */
-#define ESP_STATUS2 ESP_CFACT /* ro HME status2 register 0x24 */
-#define ESP_CTEST 0x28UL /* wo Chip test register 0x28 */
-#define ESP_CFG2 0x2cUL /* rw Second configuration register 0x2c */
-#define ESP_CFG3 0x30UL /* rw Third configuration register 0x30 */
-#define ESP_TCHI 0x38UL /* rw High bits of transfer count 0x38 */
-#define ESP_UID ESP_TCHI /* ro Unique ID code 0x38 */
-#define FAS_RLO ESP_TCHI /* rw HME extended counter 0x38 */
-#define ESP_FGRND 0x3cUL /* rw Data base for fifo 0x3c */
-#define FAS_RHI ESP_FGRND /* rw HME extended counter 0x3c */
-#define ESP_REG_SIZE 0x40UL
-
-/* Various revisions of the ESP board. */
-enum esp_rev {
- esp100 = 0x00, /* NCR53C90 - very broken */
- esp100a = 0x01, /* NCR53C90A */
- esp236 = 0x02,
- fas236 = 0x03,
- fas100a = 0x04,
- fast = 0x05,
- fashme = 0x06,
- espunknown = 0x07
-};
-
-/* We allocate one of these for each scsi device and attach it to
- * SDptr->hostdata for use in the driver
- */
-struct esp_device {
- unsigned char sync_min_period;
- unsigned char sync_max_offset;
- unsigned sync:1;
- unsigned wide:1;
- unsigned disconnect:1;
-};
-
-struct scsi_cmnd;
-
-/* We get one of these for each ESP probed. */
-struct esp {
- void __iomem *eregs; /* ESP controller registers */
- void __iomem *dregs; /* DMA controller registers */
- struct sbus_dma *dma; /* DMA controller sw state */
- struct Scsi_Host *ehost; /* Backpointer to SCSI Host */
- struct sbus_dev *sdev; /* Pointer to SBus entry */
-
- /* ESP Configuration Registers */
- u8 config1; /* Copy of the 1st config register */
- u8 config2; /* Copy of the 2nd config register */
- u8 config3[16]; /* Copy of the 3rd config register */
-
- /* The current command we are sending to the ESP chip. This esp_command
- * ptr needs to be mapped in DVMA area so we can send commands and read
- * from the ESP fifo without burning precious CPU cycles. Programmed I/O
- * sucks when we have the DVMA to do it for us. The ESP is stupid and will
- * only send out 6, 10, and 12 byte SCSI commands, others we need to send
- * one byte at a time. esp_slowcmd being set says that we are doing one
- * of the command types ESP doesn't understand, esp_scmdp keeps track of
- * which byte we are sending, esp_scmdleft says how many bytes to go.
- */
- volatile u8 *esp_command; /* Location of command (CPU view) */
- __u32 esp_command_dvma;/* Location of command (DVMA view) */
- unsigned char esp_clen; /* Length of this command */
- unsigned char esp_slowcmd;
- unsigned char *esp_scmdp;
- unsigned char esp_scmdleft;
-
- /* The following are used to determine the cause of an IRQ. Upon every
- * IRQ entry we synchronize these with the hardware registers.
- */
- u8 ireg; /* Copy of ESP interrupt register */
- u8 sreg; /* Copy of ESP status register */
- u8 seqreg; /* Copy of ESP sequence step register */
- u8 sreg2; /* Copy of HME status2 register */
-
- /* To save register writes to the ESP, which can be expensive, we
- * keep track of the previous value that various registers had for
- * the last target we connected to. If they are the same for the
- * current target, we skip the register writes as they are not needed.
- */
- u8 prev_soff, prev_stp;
- u8 prev_cfg3, __cache_pad;
-
- /* We also keep a cache of the previous FAS/HME DMA CSR register value. */
- u32 prev_hme_dmacsr;
-
- /* The HME is the biggest piece of shit I have ever seen. */
- u8 hme_fifo_workaround_buffer[16 * 2];
- u8 hme_fifo_workaround_count;
-
- /* For each target we keep track of save/restore data
- * pointer information. This needs to be updated majorly
- * when we add support for tagged queueing. -DaveM
- */
- struct esp_pointers {
- char *saved_ptr;
- struct scatterlist *saved_buffer;
- int saved_this_residual;
- int saved_buffers_residual;
- } data_pointers[16] /*XXX [MAX_TAGS_PER_TARGET]*/;
-
- /* Clock periods, frequencies, synchronization, etc. */
- unsigned int cfreq; /* Clock frequency in HZ */
- unsigned int cfact; /* Clock conversion factor */
- unsigned int raw_cfact; /* Raw copy from probing */
- unsigned int ccycle; /* One ESP clock cycle */
- unsigned int ctick; /* One ESP clock time */
- unsigned int radelay; /* FAST chip req/ack delay */
- unsigned int neg_defp; /* Default negotiation period */
- unsigned int sync_defp; /* Default sync transfer period */
- unsigned int max_period; /* longest our period can be */
- unsigned int min_period; /* shortest period we can withstand */
-
- struct esp *next; /* Next ESP we probed or NULL */
- char prom_name[64]; /* Name of ESP device from prom */
- int prom_node; /* Prom node where ESP found */
- int esp_id; /* Unique per-ESP ID number */
-
- /* For slow to medium speed input clock rates we shoot for 5mb/s,
- * but for high input clock rates we try to do 10mb/s although I
- * don't think a transfer can even run that fast with an ESP even
- * with DMA2 scatter gather pipelining.
- */
-#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */
-#define SYNC_DEFP_FAST 0x19 /* 10mb/s */
-
- unsigned int snip; /* Sync. negotiation in progress */
- unsigned int wnip; /* WIDE negotiation in progress */
- unsigned int targets_present;/* targets spoken to before */
-
- int current_transfer_size; /* Set at beginning of data dma */
-
- u8 espcmdlog[32]; /* Log of current esp cmds sent. */
- u8 espcmdent; /* Current entry in esp cmd log. */
-
- /* Misc. info about this ESP */
- enum esp_rev erev; /* ESP revision */
- int irq; /* SBus IRQ for this ESP */
- int scsi_id; /* Who am I as initiator? */
- int scsi_id_mask; /* Bitmask of 'me'. */
- int diff; /* Differential SCSI bus? */
- int bursts; /* Burst sizes our DVMA supports */
-
- /* Our command queues, only one cmd lives in the current_SC queue. */
- struct scsi_cmnd *issue_SC; /* Commands to be issued */
- struct scsi_cmnd *current_SC; /* Who is currently working the bus */
- struct scsi_cmnd *disconnected_SC;/* Commands disconnected from the bus */
-
- /* Message goo */
- u8 cur_msgout[16];
- u8 cur_msgin[16];
- u8 prevmsgout, prevmsgin;
- u8 msgout_len, msgin_len;
- u8 msgout_ctr, msgin_ctr;
-
- /* States that we cannot keep in the per cmd structure because they
- * cannot be assosciated with any specific command.
- */
- u8 resetting_bus;
- wait_queue_head_t reset_queue;
-};
-
-/* Bitfield meanings for the above registers. */
-
-/* ESP config reg 1, read-write, found on all ESP chips */
-#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */
-#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */
-#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */
-#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */
-#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */
-#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */
-
-/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */
-#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236) */
-#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236) */
-#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */
-#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tmode only) */
-#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */
-#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */
-#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236) */
-#define ESP_CONFIG2_DISPINT 0x20 /* Disable pause irq (hme) */
-#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,esp216) */
-#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (esp236) */
-#define ESP_CONFIG2_MKDONE 0x40 /* HME magic feature */
-#define ESP_CONFIG2_HME32 0x80 /* HME 32 extended */
-#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */
-
-/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */
-#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/hme) */
-#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236) */
-#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a/hme) */
-#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236) */
-#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a/hme) */
-#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236) */
-#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a/hme) */
-#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236) */
-#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a/hme) */
-#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236) */
-#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236) */
-#define ESP_CONFIG3_IDBIT3 0x20 /* Bit 3 of HME SCSI-ID (hme) */
-#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236) */
-#define ESP_CONFIG3_EWIDE 0x40 /* Enable Wide-SCSI (hme) */
-#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */
-#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */
-
-/* ESP command register read-write */
-/* Group 1 commands: These may be sent at any point in time to the ESP
- * chip. None of them can generate interrupts 'cept
- * the "SCSI bus reset" command if you have not disabled
- * SCSI reset interrupts in the config1 ESP register.
- */
-#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */
-#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */
-#define ESP_CMD_RC 0x02 /* Chip reset */
-#define ESP_CMD_RS 0x03 /* SCSI bus reset */
-
-/* Group 2 commands: ESP must be an initiator and connected to a target
- * for these commands to work.
- */
-#define ESP_CMD_TI 0x10 /* Transfer Information */
-#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */
-#define ESP_CMD_MOK 0x12 /* Message okie-dokie */
-#define ESP_CMD_TPAD 0x18 /* Transfer Pad */
-#define ESP_CMD_SATN 0x1a /* Set ATN */
-#define ESP_CMD_RATN 0x1b /* De-assert ATN */
-
-/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected
- * to a target as the initiator for these commands to work.
- */
-#define ESP_CMD_SMSG 0x20 /* Send message */
-#define ESP_CMD_SSTAT 0x21 /* Send status */
-#define ESP_CMD_SDATA 0x22 /* Send data */
-#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */
-#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */
-#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */
-#define ESP_CMD_DCNCT 0x27 /* Disconnect */
-#define ESP_CMD_RMSG 0x28 /* Receive Message */
-#define ESP_CMD_RCMD 0x29 /* Receive Command */
-#define ESP_CMD_RDATA 0x2a /* Receive Data */
-#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */
-
-/* Group 4 commands: The ESP must be in the disconnected state and must
- * not be connected to any targets as initiator for
- * these commands to work.
- */
-#define ESP_CMD_RSEL 0x40 /* Reselect */
-#define ESP_CMD_SEL 0x41 /* Select w/o ATN */
-#define ESP_CMD_SELA 0x42 /* Select w/ATN */
-#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */
-#define ESP_CMD_ESEL 0x44 /* Enable selection */
-#define ESP_CMD_DSEL 0x45 /* Disable selections */
-#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */
-#define ESP_CMD_RSEL3 0x47 /* Reselect3 */
-
-/* This bit enables the ESP's DMA on the SBus */
-#define ESP_CMD_DMA 0x80 /* Do DMA? */
-
-
-/* ESP status register read-only */
-#define ESP_STAT_PIO 0x01 /* IO phase bit */
-#define ESP_STAT_PCD 0x02 /* CD phase bit */
-#define ESP_STAT_PMSG 0x04 /* MSG phase bit */
-#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */
-#define ESP_STAT_TDONE 0x08 /* Transfer Completed */
-#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */
-#define ESP_STAT_PERR 0x20 /* Parity error */
-#define ESP_STAT_SPAM 0x40 /* Real bad error */
-/* This indicates the 'interrupt pending' condition on esp236, it is a reserved
- * bit on other revs of the ESP.
- */
-#define ESP_STAT_INTR 0x80 /* Interrupt */
-
-/* HME only: status 2 register */
-#define ESP_STAT2_SCHBIT 0x01 /* Upper bits 3-7 of sstep enabled */
-#define ESP_STAT2_FFLAGS 0x02 /* The fifo flags are now latched */
-#define ESP_STAT2_XCNT 0x04 /* The transfer counter is latched */
-#define ESP_STAT2_CREGA 0x08 /* The command reg is active now */
-#define ESP_STAT2_WIDE 0x10 /* Interface on this adapter is wide */
-#define ESP_STAT2_F1BYTE 0x20 /* There is one byte at top of fifo */
-#define ESP_STAT2_FMSB 0x40 /* Next byte in fifo is most significant */
-#define ESP_STAT2_FEMPTY 0x80 /* FIFO is empty */
-
-/* The status register can be masked with ESP_STAT_PMASK and compared
- * with the following values to determine the current phase the ESP
- * (at least thinks it) is in. For our purposes we also add our own
- * software 'done' bit for our phase management engine.
- */
-#define ESP_DOP (0) /* Data Out */
-#define ESP_DIP (ESP_STAT_PIO) /* Data In */
-#define ESP_CMDP (ESP_STAT_PCD) /* Command */
-#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */
-#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */
-#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */
-
-/* ESP interrupt register read-only */
-#define ESP_INTR_S 0x01 /* Select w/o ATN */
-#define ESP_INTR_SATN 0x02 /* Select w/ATN */
-#define ESP_INTR_RSEL 0x04 /* Reselected */
-#define ESP_INTR_FDONE 0x08 /* Function done */
-#define ESP_INTR_BSERV 0x10 /* Bus service */
-#define ESP_INTR_DC 0x20 /* Disconnect */
-#define ESP_INTR_IC 0x40 /* Illegal command given */
-#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */
-
-/* Interrupt status macros */
-#define ESP_SRESET_IRQ(esp) ((esp)->intreg & (ESP_INTR_SR))
-#define ESP_ILLCMD_IRQ(esp) ((esp)->intreg & (ESP_INTR_IC))
-#define ESP_SELECT_WITH_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_SATN))
-#define ESP_SELECT_WITHOUT_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_S))
-#define ESP_SELECTION_IRQ(esp) ((ESP_SELECT_WITH_ATN_IRQ(esp)) || \
- (ESP_SELECT_WITHOUT_ATN_IRQ(esp)))
-#define ESP_RESELECTION_IRQ(esp) ((esp)->intreg & (ESP_INTR_RSEL))
-
-/* ESP sequence step register read-only */
-#define ESP_STEP_VBITS 0x07 /* Valid bits */
-#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */
-#define ESP_STEP_SID 0x01 /* One msg byte sent */
-#define ESP_STEP_NCMD 0x02 /* Was not in command phase */
-#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd
- * bytes to be lost
- */
-#define ESP_STEP_FINI4 0x04 /* Command was sent ok */
-
-/* Ho hum, some ESP's set the step register to this as well... */
-#define ESP_STEP_FINI5 0x05
-#define ESP_STEP_FINI6 0x06
-#define ESP_STEP_FINI7 0x07
-
-/* ESP chip-test register read-write */
-#define ESP_TEST_TARG 0x01 /* Target test mode */
-#define ESP_TEST_INI 0x02 /* Initiator test mode */
-#define ESP_TEST_TS 0x04 /* Tristate test mode */
-
-/* ESP unique ID register read-only, found on fas236+fas100a only */
-#define ESP_UID_F100A 0x00 /* ESP FAS100A */
-#define ESP_UID_F236 0x02 /* ESP FAS236 */
-#define ESP_UID_REV 0x07 /* ESP revision */
-#define ESP_UID_FAM 0xf8 /* ESP family */
-
-/* ESP fifo flags register read-only */
-/* Note that the following implies a 16 byte FIFO on the ESP. */
-#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */
-#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100) */
-#define ESP_FF_SSTEP 0xe0 /* Sequence step */
-
-/* ESP clock conversion factor register write-only */
-#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */
-#define ESP_CCF_NEVER 0x01 /* Set it to this and die */
-#define ESP_CCF_F2 0x02 /* 10MHz */
-#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */
-#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */
-#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */
-#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */
-#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */
-
-/* HME only... */
-#define ESP_BUSID_RESELID 0x10
-#define ESP_BUSID_CTR32BIT 0x40
-
-#define ESP_BUS_TIMEOUT 275 /* In milli-seconds */
-#define ESP_TIMEO_CONST 8192
-#define ESP_NEG_DEFP(mhz, cfact) \
- ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
-#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
-#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
-
-#endif /* !(_SPARC_ESP_H) */
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
new file mode 100644
index 00000000000..3cd5bf723da
--- /dev/null
+++ b/drivers/scsi/esp_scsi.c
@@ -0,0 +1,2710 @@
+/* esp_scsi.c: ESP SCSI driver.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/completion.h>
+#include <linux/kallsyms.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "esp_scsi.h"
+
+#define DRV_MODULE_NAME "esp"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_VERSION "2.000"
+#define DRV_MODULE_RELDATE "April 19, 2007"
+
+/* SCSI bus reset settle time in seconds. */
+static int esp_bus_reset_settle = 3;
+
+static u32 esp_debug;
+#define ESP_DEBUG_INTR 0x00000001
+#define ESP_DEBUG_SCSICMD 0x00000002
+#define ESP_DEBUG_RESET 0x00000004
+#define ESP_DEBUG_MSGIN 0x00000008
+#define ESP_DEBUG_MSGOUT 0x00000010
+#define ESP_DEBUG_CMDDONE 0x00000020
+#define ESP_DEBUG_DISCONNECT 0x00000040
+#define ESP_DEBUG_DATASTART 0x00000080
+#define ESP_DEBUG_DATADONE 0x00000100
+#define ESP_DEBUG_RECONNECT 0x00000200
+#define ESP_DEBUG_AUTOSENSE 0x00000400
+
+#define esp_log_intr(f, a...) \
+do { if (esp_debug & ESP_DEBUG_INTR) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_reset(f, a...) \
+do { if (esp_debug & ESP_DEBUG_RESET) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_msgin(f, a...) \
+do { if (esp_debug & ESP_DEBUG_MSGIN) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_msgout(f, a...) \
+do { if (esp_debug & ESP_DEBUG_MSGOUT) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_cmddone(f, a...) \
+do { if (esp_debug & ESP_DEBUG_CMDDONE) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_disconnect(f, a...) \
+do { if (esp_debug & ESP_DEBUG_DISCONNECT) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_datastart(f, a...) \
+do { if (esp_debug & ESP_DEBUG_DATASTART) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_datadone(f, a...) \
+do { if (esp_debug & ESP_DEBUG_DATADONE) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_reconnect(f, a...) \
+do { if (esp_debug & ESP_DEBUG_RECONNECT) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_autosense(f, a...) \
+do { if (esp_debug & ESP_DEBUG_AUTOSENSE) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_read8(REG) esp->ops->esp_read8(esp, REG)
+#define esp_write8(VAL,REG) esp->ops->esp_write8(esp, VAL, REG)
+
+static void esp_log_fill_regs(struct esp *esp,
+ struct esp_event_ent *p)
+{
+ p->sreg = esp->sreg;
+ p->seqreg = esp->seqreg;
+ p->sreg2 = esp->sreg2;
+ p->ireg = esp->ireg;
+ p->select_state = esp->select_state;
+ p->event = esp->event;
+}
+
+void scsi_esp_cmd(struct esp *esp, u8 val)
+{
+ struct esp_event_ent *p;
+ int idx = esp->esp_event_cur;
+
+ p = &esp->esp_event_log[idx];
+ p->type = ESP_EVENT_TYPE_CMD;
+ p->val = val;
+ esp_log_fill_regs(esp, p);
+
+ esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);
+
+ esp_write8(val, ESP_CMD);
+}
+EXPORT_SYMBOL(scsi_esp_cmd);
+
+static void esp_event(struct esp *esp, u8 val)
+{
+ struct esp_event_ent *p;
+ int idx = esp->esp_event_cur;
+
+ p = &esp->esp_event_log[idx];
+ p->type = ESP_EVENT_TYPE_EVENT;
+ p->val = val;
+ esp_log_fill_regs(esp, p);
+
+ esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);
+
+ esp->event = val;
+}
+
+static void esp_dump_cmd_log(struct esp *esp)
+{
+ int idx = esp->esp_event_cur;
+ int stop = idx;
+
+ printk(KERN_INFO PFX "esp%d: Dumping command log\n",
+ esp->host->unique_id);
+ do {
+ struct esp_event_ent *p = &esp->esp_event_log[idx];
+
+ printk(KERN_INFO PFX "esp%d: ent[%d] %s ",
+ esp->host->unique_id, idx,
+ p->type == ESP_EVENT_TYPE_CMD ? "CMD" : "EVENT");
+
+ printk("val[%02x] sreg[%02x] seqreg[%02x] "
+ "sreg2[%02x] ireg[%02x] ss[%02x] event[%02x]\n",
+ p->val, p->sreg, p->seqreg,
+ p->sreg2, p->ireg, p->select_state, p->event);
+
+ idx = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);
+ } while (idx != stop);
+}
+
+static void esp_flush_fifo(struct esp *esp)
+{
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ if (esp->rev == ESP236) {
+ int lim = 1000;
+
+ while (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES) {
+ if (--lim == 0) {
+ printk(KERN_ALERT PFX "esp%d: ESP_FF_BYTES "
+ "will not clear!\n",
+ esp->host->unique_id);
+ break;
+ }
+ udelay(1);
+ }
+ }
+}
+
+static void hme_read_fifo(struct esp *esp)
+{
+ int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
+ int idx = 0;
+
+ while (fcnt--) {
+ esp->fifo[idx++] = esp_read8(ESP_FDATA);
+ esp->fifo[idx++] = esp_read8(ESP_FDATA);
+ }
+ if (esp->sreg2 & ESP_STAT2_F1BYTE) {
+ esp_write8(0, ESP_FDATA);
+ esp->fifo[idx++] = esp_read8(ESP_FDATA);
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ }
+ esp->fifo_cnt = idx;
+}
+
+static void esp_set_all_config3(struct esp *esp, u8 val)
+{
+ int i;
+
+ for (i = 0; i < ESP_MAX_TARGET; i++)
+ esp->target[i].esp_config3 = val;
+}
+
+/* Reset the ESP chip, _not_ the SCSI bus. */
+static void esp_reset_esp(struct esp *esp)
+{
+ u8 family_code, version;
+
+ /* Now reset the ESP chip */
+ scsi_esp_cmd(esp, ESP_CMD_RC);
+ scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
+ scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
+
+ /* Reload the configuration registers */
+ esp_write8(esp->cfact, ESP_CFACT);
+
+ esp->prev_stp = 0;
+ esp_write8(esp->prev_stp, ESP_STP);
+
+ esp->prev_soff = 0;
+ esp_write8(esp->prev_soff, ESP_SOFF);
+
+ esp_write8(esp->neg_defp, ESP_TIMEO);
+
+ /* This is the only point at which it is reliable to read
+ * the ID-code for a fast ESP chip variants.
+ */
+ esp->max_period = ((35 * esp->ccycle) / 1000);
+ if (esp->rev == FAST) {
+ version = esp_read8(ESP_UID);
+ family_code = (version & 0xf8) >> 3;
+ if (family_code == 0x02)
+ esp->rev = FAS236;
+ else if (family_code == 0x0a)
+ esp->rev = FASHME; /* Version is usually '5'. */
+ else
+ esp->rev = FAS100A;
+ esp->min_period = ((4 * esp->ccycle) / 1000);
+ } else {
+ esp->min_period = ((5 * esp->ccycle) / 1000);
+ }
+ esp->max_period = (esp->max_period + 3)>>2;
+ esp->min_period = (esp->min_period + 3)>>2;
+
+ esp_write8(esp->config1, ESP_CFG1);
+ switch (esp->rev) {
+ case ESP100:
+ /* nothing to do */
+ break;
+
+ case ESP100A:
+ esp_write8(esp->config2, ESP_CFG2);
+ break;
+
+ case ESP236:
+ /* Slow 236 */
+ esp_write8(esp->config2, ESP_CFG2);
+ esp->prev_cfg3 = esp->target[0].esp_config3;
+ esp_write8(esp->prev_cfg3, ESP_CFG3);
+ break;
+
+ case FASHME:
+ esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
+ /* fallthrough... */
+
+ case FAS236:
+ /* Fast 236 or HME */
+ esp_write8(esp->config2, ESP_CFG2);
+ if (esp->rev == FASHME) {
+ u8 cfg3 = esp->target[0].esp_config3;
+
+ cfg3 |= ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH;
+ if (esp->scsi_id >= 8)
+ cfg3 |= ESP_CONFIG3_IDBIT3;
+ esp_set_all_config3(esp, cfg3);
+ } else {
+ u32 cfg3 = esp->target[0].esp_config3;
+
+ cfg3 |= ESP_CONFIG3_FCLK;
+ esp_set_all_config3(esp, cfg3);
+ }
+ esp->prev_cfg3 = esp->target[0].esp_config3;
+ esp_write8(esp->prev_cfg3, ESP_CFG3);
+ if (esp->rev == FASHME) {
+ esp->radelay = 80;
+ } else {
+ if (esp->flags & ESP_FLAG_DIFFERENTIAL)
+ esp->radelay = 0;
+ else
+ esp->radelay = 96;
+ }
+ break;
+
+ case FAS100A:
+ /* Fast 100a */
+ esp_write8(esp->config2, ESP_CFG2);
+ esp_set_all_config3(esp,
+ (esp->target[0].esp_config3 |
+ ESP_CONFIG3_FCLOCK));
+ esp->prev_cfg3 = esp->target[0].esp_config3;
+ esp_write8(esp->prev_cfg3, ESP_CFG3);
+ esp->radelay = 32;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Eat any bitrot in the chip */
+ esp_read8(ESP_INTRPT);
+ udelay(100);
+}
+
+static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd)
+{
+ struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
+ struct scatterlist *sg = cmd->request_buffer;
+ int dir = cmd->sc_data_direction;
+ int total, i;
+
+ if (dir == DMA_NONE)
+ return;
+
+ BUG_ON(cmd->use_sg == 0);
+
+ spriv->u.num_sg = esp->ops->map_sg(esp, sg,
+ cmd->use_sg, dir);
+ spriv->cur_residue = sg_dma_len(sg);
+ spriv->cur_sg = sg;
+
+ total = 0;
+ for (i = 0; i < spriv->u.num_sg; i++)
+ total += sg_dma_len(&sg[i]);
+ spriv->tot_residue = total;
+}
+
+static dma_addr_t esp_cur_dma_addr(struct esp_cmd_entry *ent,
+ struct scsi_cmnd *cmd)
+{
+ struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ return ent->sense_dma +
+ (ent->sense_ptr - cmd->sense_buffer);
+ }
+
+ return sg_dma_address(p->cur_sg) +
+ (sg_dma_len(p->cur_sg) -
+ p->cur_residue);
+}
+
+static unsigned int esp_cur_dma_len(struct esp_cmd_entry *ent,
+ struct scsi_cmnd *cmd)
+{
+ struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ return SCSI_SENSE_BUFFERSIZE -
+ (ent->sense_ptr - cmd->sense_buffer);
+ }
+ return p->cur_residue;
+}
+
+static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent,
+ struct scsi_cmnd *cmd, unsigned int len)
+{
+ struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ ent->sense_ptr += len;
+ return;
+ }
+
+ p->cur_residue -= len;
+ p->tot_residue -= len;
+ if (p->cur_residue < 0 || p->tot_residue < 0) {
+ printk(KERN_ERR PFX "esp%d: Data transfer overflow.\n",
+ esp->host->unique_id);
+ printk(KERN_ERR PFX "esp%d: cur_residue[%d] tot_residue[%d] "
+ "len[%u]\n",
+ esp->host->unique_id,
+ p->cur_residue, p->tot_residue, len);
+ p->cur_residue = 0;
+ p->tot_residue = 0;
+ }
+ if (!p->cur_residue && p->tot_residue) {
+ p->cur_sg++;
+ p->cur_residue = sg_dma_len(p->cur_sg);
+ }
+}
+
+static void esp_unmap_dma(struct esp *esp, struct scsi_cmnd *cmd)
+{
+ struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
+ int dir = cmd->sc_data_direction;
+
+ if (dir == DMA_NONE)
+ return;
+
+ esp->ops->unmap_sg(esp, cmd->request_buffer,
+ spriv->u.num_sg, dir);
+}
+
+static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ struct scsi_cmnd *cmd = ent->cmd;
+ struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ ent->saved_sense_ptr = ent->sense_ptr;
+ return;
+ }
+ ent->saved_cur_residue = spriv->cur_residue;
+ ent->saved_cur_sg = spriv->cur_sg;
+ ent->saved_tot_residue = spriv->tot_residue;
+}
+
+static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ struct scsi_cmnd *cmd = ent->cmd;
+ struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ ent->sense_ptr = ent->saved_sense_ptr;
+ return;
+ }
+ spriv->cur_residue = ent->saved_cur_residue;
+ spriv->cur_sg = ent->saved_cur_sg;
+ spriv->tot_residue = ent->saved_tot_residue;
+}
+
+static void esp_check_command_len(struct esp *esp, struct scsi_cmnd *cmd)
+{
+ if (cmd->cmd_len == 6 ||
+ cmd->cmd_len == 10 ||
+ cmd->cmd_len == 12) {
+ esp->flags &= ~ESP_FLAG_DOING_SLOWCMD;
+ } else {
+ esp->flags |= ESP_FLAG_DOING_SLOWCMD;
+ }
+}
+
+static void esp_write_tgt_config3(struct esp *esp, int tgt)
+{
+ if (esp->rev > ESP100A) {
+ u8 val = esp->target[tgt].esp_config3;
+
+ if (val != esp->prev_cfg3) {
+ esp->prev_cfg3 = val;
+ esp_write8(val, ESP_CFG3);
+ }
+ }
+}
+
+static void esp_write_tgt_sync(struct esp *esp, int tgt)
+{
+ u8 off = esp->target[tgt].esp_offset;
+ u8 per = esp->target[tgt].esp_period;
+
+ if (off != esp->prev_soff) {
+ esp->prev_soff = off;
+ esp_write8(off, ESP_SOFF);
+ }
+ if (per != esp->prev_stp) {
+ esp->prev_stp = per;
+ esp_write8(per, ESP_STP);
+ }
+}
+
+static u32 esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len)
+{
+ if (esp->rev == FASHME) {
+ /* Arbitrary segment boundaries, 24-bit counts. */
+ if (dma_len > (1U << 24))
+ dma_len = (1U << 24);
+ } else {
+ u32 base, end;
+
+ /* ESP chip limits other variants by 16-bits of transfer
+ * count. Actually on FAS100A and FAS236 we could get
+ * 24-bits of transfer count by enabling ESP_CONFIG2_FENAB
+ * in the ESP_CFG2 register but that causes other unwanted
+ * changes so we don't use it currently.
+ */
+ if (dma_len > (1U << 16))
+ dma_len = (1U << 16);
+
+ /* All of the DMA variants hooked up to these chips
+ * cannot handle crossing a 24-bit address boundary.
+ */
+ base = dma_addr & ((1U << 24) - 1U);
+ end = base + dma_len;
+ if (end > (1U << 24))
+ end = (1U <<24);
+ dma_len = end - base;
+ }
+ return dma_len;
+}
+
+static int esp_need_to_nego_wide(struct esp_target_data *tp)
+{
+ struct scsi_target *target = tp->starget;
+
+ return spi_width(target) != tp->nego_goal_width;
+}
+
+static int esp_need_to_nego_sync(struct esp_target_data *tp)
+{
+ struct scsi_target *target = tp->starget;
+
+ /* When offset is zero, period is "don't care". */
+ if (!spi_offset(target) && !tp->nego_goal_offset)
+ return 0;
+
+ if (spi_offset(target) == tp->nego_goal_offset &&
+ spi_period(target) == tp->nego_goal_period)
+ return 0;
+
+ return 1;
+}
+
+static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
+ struct esp_lun_data *lp)
+{
+ if (!ent->tag[0]) {
+ /* Non-tagged, slot already taken? */
+ if (lp->non_tagged_cmd)
+ return -EBUSY;
+
+ if (lp->hold) {
+ /* We are being held by active tagged
+ * commands.
+ */
+ if (lp->num_tagged)
+ return -EBUSY;
+
+ /* Tagged commands completed, we can unplug
+ * the queue and run this untagged command.
+ */
+ lp->hold = 0;
+ } else if (lp->num_tagged) {
+ /* Plug the queue until num_tagged decreases
+ * to zero in esp_free_lun_tag.
+ */
+ lp->hold = 1;
+ return -EBUSY;
+ }
+
+ lp->non_tagged_cmd = ent;
+ return 0;
+ } else {
+ /* Tagged command, see if blocked by a
+ * non-tagged one.
+ */
+ if (lp->non_tagged_cmd || lp->hold)
+ return -EBUSY;
+ }
+
+ BUG_ON(lp->tagged_cmds[ent->tag[1]]);
+
+ lp->tagged_cmds[ent->tag[1]] = ent;
+ lp->num_tagged++;
+
+ return 0;
+}
+
+static void esp_free_lun_tag(struct esp_cmd_entry *ent,
+ struct esp_lun_data *lp)
+{
+ if (ent->tag[0]) {
+ BUG_ON(lp->tagged_cmds[ent->tag[1]] != ent);
+ lp->tagged_cmds[ent->tag[1]] = NULL;
+ lp->num_tagged--;
+ } else {
+ BUG_ON(lp->non_tagged_cmd != ent);
+ lp->non_tagged_cmd = NULL;
+ }
+}
+
+/* When a contingent allegiance conditon is created, we force feed a
+ * REQUEST_SENSE command to the device to fetch the sense data. I
+ * tried many other schemes, relying on the scsi error handling layer
+ * to send out the REQUEST_SENSE automatically, but this was difficult
+ * to get right especially in the presence of applications like smartd
+ * which use SG_IO to send out their own REQUEST_SENSE commands.
+ */
+static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ struct scsi_cmnd *cmd = ent->cmd;
+ struct scsi_device *dev = cmd->device;
+ int tgt, lun;
+ u8 *p, val;
+
+ tgt = dev->id;
+ lun = dev->lun;
+
+
+ if (!ent->sense_ptr) {
+ esp_log_autosense("esp%d: Doing auto-sense for "
+ "tgt[%d] lun[%d]\n",
+ esp->host->unique_id, tgt, lun);
+
+ ent->sense_ptr = cmd->sense_buffer;
+ ent->sense_dma = esp->ops->map_single(esp,
+ ent->sense_ptr,
+ SCSI_SENSE_BUFFERSIZE,
+ DMA_FROM_DEVICE);
+ }
+ ent->saved_sense_ptr = ent->sense_ptr;
+
+ esp->active_cmd = ent;
+
+ p = esp->command_block;
+ esp->msg_out_len = 0;
+
+ *p++ = IDENTIFY(0, lun);
+ *p++ = REQUEST_SENSE;
+ *p++ = ((dev->scsi_level <= SCSI_2) ?
+ (lun << 5) : 0);
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = SCSI_SENSE_BUFFERSIZE;
+ *p++ = 0;
+
+ esp->select_state = ESP_SELECT_BASIC;
+
+ val = tgt;
+ if (esp->rev == FASHME)
+ val |= ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT;
+ esp_write8(val, ESP_BUSID);
+
+ esp_write_tgt_sync(esp, tgt);
+ esp_write_tgt_config3(esp, tgt);
+
+ val = (p - esp->command_block);
+
+ if (esp->rev == FASHME)
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ esp->ops->send_dma_cmd(esp, esp->command_block_dma,
+ val, 16, 0, ESP_CMD_DMA | ESP_CMD_SELA);
+}
+
+static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp)
+{
+ struct esp_cmd_entry *ent;
+
+ list_for_each_entry(ent, &esp->queued_cmds, list) {
+ struct scsi_cmnd *cmd = ent->cmd;
+ struct scsi_device *dev = cmd->device;
+ struct esp_lun_data *lp = dev->hostdata;
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ ent->tag[0] = 0;
+ ent->tag[1] = 0;
+ return ent;
+ }
+
+ if (!scsi_populate_tag_msg(cmd, &ent->tag[0])) {
+ ent->tag[0] = 0;
+ ent->tag[1] = 0;
+ }
+
+ if (esp_alloc_lun_tag(ent, lp) < 0)
+ continue;
+
+ return ent;
+ }
+
+ return NULL;
+}
+
+static void esp_maybe_execute_command(struct esp *esp)
+{
+ struct esp_target_data *tp;
+ struct esp_lun_data *lp;
+ struct scsi_device *dev;
+ struct scsi_cmnd *cmd;
+ struct esp_cmd_entry *ent;
+ int tgt, lun, i;
+ u32 val, start_cmd;
+ u8 *p;
+
+ if (esp->active_cmd ||
+ (esp->flags & ESP_FLAG_RESETTING))
+ return;
+
+ ent = find_and_prep_issuable_command(esp);
+ if (!ent)
+ return;
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ esp_autosense(esp, ent);
+ return;
+ }
+
+ cmd = ent->cmd;
+ dev = cmd->device;
+ tgt = dev->id;
+ lun = dev->lun;
+ tp = &esp->target[tgt];
+ lp = dev->hostdata;
+
+ list_del(&ent->list);
+ list_add(&ent->list, &esp->active_cmds);
+
+ esp->active_cmd = ent;
+
+ esp_map_dma(esp, cmd);
+ esp_save_pointers(esp, ent);
+
+ esp_check_command_len(esp, cmd);
+
+ p = esp->command_block;
+
+ esp->msg_out_len = 0;
+ if (tp->flags & ESP_TGT_CHECK_NEGO) {
+ /* Need to negotiate. If the target is broken
+ * go for synchronous transfers and non-wide.
+ */
+ if (tp->flags & ESP_TGT_BROKEN) {
+ tp->flags &= ~ESP_TGT_DISCONNECT;
+ tp->nego_goal_period = 0;
+ tp->nego_goal_offset = 0;
+ tp->nego_goal_width = 0;
+ tp->nego_goal_tags = 0;
+ }
+
+ /* If the settings are not changing, skip this. */
+ if (spi_width(tp->starget) == tp->nego_goal_width &&
+ spi_period(tp->starget) == tp->nego_goal_period &&
+ spi_offset(tp->starget) == tp->nego_goal_offset) {
+ tp->flags &= ~ESP_TGT_CHECK_NEGO;
+ goto build_identify;
+ }
+
+ if (esp->rev == FASHME && esp_need_to_nego_wide(tp)) {
+ esp->msg_out_len =
+ spi_populate_width_msg(&esp->msg_out[0],
+ (tp->nego_goal_width ?
+ 1 : 0));
+ tp->flags |= ESP_TGT_NEGO_WIDE;
+ } else if (esp_need_to_nego_sync(tp)) {
+ esp->msg_out_len =
+ spi_populate_sync_msg(&esp->msg_out[0],
+ tp->nego_goal_period,
+ tp->nego_goal_offset);
+ tp->flags |= ESP_TGT_NEGO_SYNC;
+ } else {
+ tp->flags &= ~ESP_TGT_CHECK_NEGO;
+ }
+
+ /* Process it like a slow command. */
+ if (tp->flags & (ESP_TGT_NEGO_WIDE | ESP_TGT_NEGO_SYNC))
+ esp->flags |= ESP_FLAG_DOING_SLOWCMD;
+ }
+
+build_identify:
+ /* If we don't have a lun-data struct yet, we're probing
+ * so do not disconnect. Also, do not disconnect unless
+ * we have a tag on this command.
+ */
+ if (lp && (tp->flags & ESP_TGT_DISCONNECT) && ent->tag[0])
+ *p++ = IDENTIFY(1, lun);
+ else
+ *p++ = IDENTIFY(0, lun);
+
+ if (ent->tag[0] && esp->rev == ESP100) {
+ /* ESP100 lacks select w/atn3 command, use select
+ * and stop instead.
+ */
+ esp->flags |= ESP_FLAG_DOING_SLOWCMD;
+ }
+
+ if (!(esp->flags & ESP_FLAG_DOING_SLOWCMD)) {
+ start_cmd = ESP_CMD_DMA | ESP_CMD_SELA;
+ if (ent->tag[0]) {
+ *p++ = ent->tag[0];
+ *p++ = ent->tag[1];
+
+ start_cmd = ESP_CMD_DMA | ESP_CMD_SA3;
+ }
+
+ for (i = 0; i < cmd->cmd_len; i++)
+ *p++ = cmd->cmnd[i];
+
+ esp->select_state = ESP_SELECT_BASIC;
+ } else {
+ esp->cmd_bytes_left = cmd->cmd_len;
+ esp->cmd_bytes_ptr = &cmd->cmnd[0];
+
+ if (ent->tag[0]) {
+ for (i = esp->msg_out_len - 1;
+ i >= 0; i--)
+ esp->msg_out[i + 2] = esp->msg_out[i];
+ esp->msg_out[0] = ent->tag[0];
+ esp->msg_out[1] = ent->tag[1];
+ esp->msg_out_len += 2;
+ }
+
+ start_cmd = ESP_CMD_DMA | ESP_CMD_SELAS;
+ esp->select_state = ESP_SELECT_MSGOUT;
+ }
+ val = tgt;
+ if (esp->rev == FASHME)
+ val |= ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT;
+ esp_write8(val, ESP_BUSID);
+
+ esp_write_tgt_sync(esp, tgt);
+ esp_write_tgt_config3(esp, tgt);
+
+ val = (p - esp->command_block);
+
+ if (esp_debug & ESP_DEBUG_SCSICMD) {
+ printk("ESP: tgt[%d] lun[%d] scsi_cmd [ ", tgt, lun);
+ for (i = 0; i < cmd->cmd_len; i++)
+ printk("%02x ", cmd->cmnd[i]);
+ printk("]\n");
+ }
+
+ if (esp->rev == FASHME)
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ esp->ops->send_dma_cmd(esp, esp->command_block_dma,
+ val, 16, 0, start_cmd);
+}
+
+static struct esp_cmd_entry *esp_get_ent(struct esp *esp)
+{
+ struct list_head *head = &esp->esp_cmd_pool;
+ struct esp_cmd_entry *ret;
+
+ if (list_empty(head)) {
+ ret = kzalloc(sizeof(struct esp_cmd_entry), GFP_ATOMIC);
+ } else {
+ ret = list_entry(head->next, struct esp_cmd_entry, list);
+ list_del(&ret->list);
+ memset(ret, 0, sizeof(*ret));
+ }
+ return ret;
+}
+
+static void esp_put_ent(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ list_add(&ent->list, &esp->esp_cmd_pool);
+}
+
+static void esp_cmd_is_done(struct esp *esp, struct esp_cmd_entry *ent,
+ struct scsi_cmnd *cmd, unsigned int result)
+{
+ struct scsi_device *dev = cmd->device;
+ int tgt = dev->id;
+ int lun = dev->lun;
+
+ esp->active_cmd = NULL;
+ esp_unmap_dma(esp, cmd);
+ esp_free_lun_tag(ent, dev->hostdata);
+ cmd->result = result;
+
+ if (ent->eh_done) {
+ complete(ent->eh_done);
+ ent->eh_done = NULL;
+ }
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ esp->ops->unmap_single(esp, ent->sense_dma,
+ SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+ ent->sense_ptr = NULL;
+
+ /* Restore the message/status bytes to what we actually
+ * saw originally. Also, report that we are providing
+ * the sense data.
+ */
+ cmd->result = ((DRIVER_SENSE << 24) |
+ (DID_OK << 16) |
+ (COMMAND_COMPLETE << 8) |
+ (SAM_STAT_CHECK_CONDITION << 0));
+
+ ent->flags &= ~ESP_CMD_FLAG_AUTOSENSE;
+ if (esp_debug & ESP_DEBUG_AUTOSENSE) {
+ int i;
+
+ printk("esp%d: tgt[%d] lun[%d] AUTO SENSE[ ",
+ esp->host->unique_id, tgt, lun);
+ for (i = 0; i < 18; i++)
+ printk("%02x ", cmd->sense_buffer[i]);
+ printk("]\n");
+ }
+ }
+
+ cmd->scsi_done(cmd);
+
+ list_del(&ent->list);
+ esp_put_ent(esp, ent);
+
+ esp_maybe_execute_command(esp);
+}
+
+static unsigned int compose_result(unsigned int status, unsigned int message,
+ unsigned int driver_code)
+{
+ return (status | (message << 8) | (driver_code << 16));
+}
+
+static void esp_event_queue_full(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ struct scsi_device *dev = ent->cmd->device;
+ struct esp_lun_data *lp = dev->hostdata;
+
+ scsi_track_queue_full(dev, lp->num_tagged - 1);
+}
+
+static int esp_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+ struct scsi_device *dev = cmd->device;
+ struct esp *esp = host_to_esp(dev->host);
+ struct esp_cmd_priv *spriv;
+ struct esp_cmd_entry *ent;
+
+ ent = esp_get_ent(esp);
+ if (!ent)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ ent->cmd = cmd;
+
+ cmd->scsi_done = done;
+
+ spriv = ESP_CMD_PRIV(cmd);
+ spriv->u.dma_addr = ~(dma_addr_t)0x0;
+
+ list_add_tail(&ent->list, &esp->queued_cmds);
+
+ esp_maybe_execute_command(esp);
+
+ return 0;
+}
+
+static int esp_check_gross_error(struct esp *esp)
+{
+ if (esp->sreg & ESP_STAT_SPAM) {
+ /* Gross Error, could be one of:
+ * - top of fifo overwritten
+ * - top of command register overwritten
+ * - DMA programmed with wrong direction
+ * - improper phase change
+ */
+ printk(KERN_ERR PFX "esp%d: Gross error sreg[%02x]\n",
+ esp->host->unique_id, esp->sreg);
+ /* XXX Reset the chip. XXX */
+ return 1;
+ }
+ return 0;
+}
+
+static int esp_check_spur_intr(struct esp *esp)
+{
+ switch (esp->rev) {
+ case ESP100:
+ case ESP100A:
+ /* The interrupt pending bit of the status register cannot
+ * be trusted on these revisions.
+ */
+ esp->sreg &= ~ESP_STAT_INTR;
+ break;
+
+ default:
+ if (!(esp->sreg & ESP_STAT_INTR)) {
+ esp->ireg = esp_read8(ESP_INTRPT);
+ if (esp->ireg & ESP_INTR_SR)
+ return 1;
+
+ /* If the DMA is indicating interrupt pending and the
+ * ESP is not, the only possibility is a DMA error.
+ */
+ if (!esp->ops->dma_error(esp)) {
+ printk(KERN_ERR PFX "esp%d: Spurious irq, "
+ "sreg=%x.\n",
+ esp->host->unique_id, esp->sreg);
+ return -1;
+ }
+
+ printk(KERN_ERR PFX "esp%d: DMA error\n",
+ esp->host->unique_id);
+
+ /* XXX Reset the chip. XXX */
+ return -1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static void esp_schedule_reset(struct esp *esp)
+{
+ esp_log_reset("ESP: esp_schedule_reset() from %p\n",
+ __builtin_return_address(0));
+ esp->flags |= ESP_FLAG_RESETTING;
+ esp_event(esp, ESP_EVENT_RESET);
+}
+
+/* In order to avoid having to add a special half-reconnected state
+ * into the driver we just sit here and poll through the rest of
+ * the reselection process to get the tag message bytes.
+ */
+static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp,
+ struct esp_lun_data *lp)
+{
+ struct esp_cmd_entry *ent;
+ int i;
+
+ if (!lp->num_tagged) {
+ printk(KERN_ERR PFX "esp%d: Reconnect w/num_tagged==0\n",
+ esp->host->unique_id);
+ return NULL;
+ }
+
+ esp_log_reconnect("ESP: reconnect tag, ");
+
+ for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) {
+ if (esp->ops->irq_pending(esp))
+ break;
+ }
+ if (i == ESP_QUICKIRQ_LIMIT) {
+ printk(KERN_ERR PFX "esp%d: Reconnect IRQ1 timeout\n",
+ esp->host->unique_id);
+ return NULL;
+ }
+
+ esp->sreg = esp_read8(ESP_STATUS);
+ esp->ireg = esp_read8(ESP_INTRPT);
+
+ esp_log_reconnect("IRQ(%d:%x:%x), ",
+ i, esp->ireg, esp->sreg);
+
+ if (esp->ireg & ESP_INTR_DC) {
+ printk(KERN_ERR PFX "esp%d: Reconnect, got disconnect.\n",
+ esp->host->unique_id);
+ return NULL;
+ }
+
+ if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) {
+ printk(KERN_ERR PFX "esp%d: Reconnect, not MIP sreg[%02x].\n",
+ esp->host->unique_id, esp->sreg);
+ return NULL;
+ }
+
+ /* DMA in the tag bytes... */
+ esp->command_block[0] = 0xff;
+ esp->command_block[1] = 0xff;
+ esp->ops->send_dma_cmd(esp, esp->command_block_dma,
+ 2, 2, 1, ESP_CMD_DMA | ESP_CMD_TI);
+
+ /* ACK the msssage. */
+ scsi_esp_cmd(esp, ESP_CMD_MOK);
+
+ for (i = 0; i < ESP_RESELECT_TAG_LIMIT; i++) {
+ if (esp->ops->irq_pending(esp)) {
+ esp->sreg = esp_read8(ESP_STATUS);
+ esp->ireg = esp_read8(ESP_INTRPT);
+ if (esp->ireg & ESP_INTR_FDONE)
+ break;
+ }
+ udelay(1);
+ }
+ if (i == ESP_RESELECT_TAG_LIMIT) {
+ printk(KERN_ERR PFX "esp%d: Reconnect IRQ2 timeout\n",
+ esp->host->unique_id);
+ return NULL;
+ }
+ esp->ops->dma_drain(esp);
+ esp->ops->dma_invalidate(esp);
+
+ esp_log_reconnect("IRQ2(%d:%x:%x) tag[%x:%x]\n",
+ i, esp->ireg, esp->sreg,
+ esp->command_block[0],
+ esp->command_block[1]);
+
+ if (esp->command_block[0] < SIMPLE_QUEUE_TAG ||
+ esp->command_block[0] > ORDERED_QUEUE_TAG) {
+ printk(KERN_ERR PFX "esp%d: Reconnect, bad tag "
+ "type %02x.\n",
+ esp->host->unique_id, esp->command_block[0]);
+ return NULL;
+ }
+
+ ent = lp->tagged_cmds[esp->command_block[1]];
+ if (!ent) {
+ printk(KERN_ERR PFX "esp%d: Reconnect, no entry for "
+ "tag %02x.\n",
+ esp->host->unique_id, esp->command_block[1]);
+ return NULL;
+ }
+
+ return ent;
+}
+
+static int esp_reconnect(struct esp *esp)
+{
+ struct esp_cmd_entry *ent;
+ struct esp_target_data *tp;
+ struct esp_lun_data *lp;
+ struct scsi_device *dev;
+ int target, lun;
+
+ BUG_ON(esp->active_cmd);
+ if (esp->rev == FASHME) {
+ /* FASHME puts the target and lun numbers directly
+ * into the fifo.
+ */
+ target = esp->fifo[0];
+ lun = esp->fifo[1] & 0x7;
+ } else {
+ u8 bits = esp_read8(ESP_FDATA);
+
+ /* Older chips put the lun directly into the fifo, but
+ * the target is given as a sample of the arbitration
+ * lines on the bus at reselection time. So we should
+ * see the ID of the ESP and the one reconnecting target
+ * set in the bitmap.
+ */
+ if (!(bits & esp->scsi_id_mask))
+ goto do_reset;
+ bits &= ~esp->scsi_id_mask;
+ if (!bits || (bits & (bits - 1)))
+ goto do_reset;
+
+ target = ffs(bits) - 1;
+ lun = (esp_read8(ESP_FDATA) & 0x7);
+
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ if (esp->rev == ESP100) {
+ u8 ireg = esp_read8(ESP_INTRPT);
+ /* This chip has a bug during reselection that can
+ * cause a spurious illegal-command interrupt, which
+ * we simply ACK here. Another possibility is a bus
+ * reset so we must check for that.
+ */
+ if (ireg & ESP_INTR_SR)
+ goto do_reset;
+ }
+ scsi_esp_cmd(esp, ESP_CMD_NULL);
+ }
+
+ esp_write_tgt_sync(esp, target);
+ esp_write_tgt_config3(esp, target);
+
+ scsi_esp_cmd(esp, ESP_CMD_MOK);
+
+ if (esp->rev == FASHME)
+ esp_write8(target | ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT,
+ ESP_BUSID);
+
+ tp = &esp->target[target];
+ dev = __scsi_device_lookup_by_target(tp->starget, lun);
+ if (!dev) {
+ printk(KERN_ERR PFX "esp%d: Reconnect, no lp "
+ "tgt[%u] lun[%u]\n",
+ esp->host->unique_id, target, lun);
+ goto do_reset;
+ }
+ lp = dev->hostdata;
+
+ ent = lp->non_tagged_cmd;
+ if (!ent) {
+ ent = esp_reconnect_with_tag(esp, lp);
+ if (!ent)
+ goto do_reset;
+ }
+
+ esp->active_cmd = ent;
+
+ if (ent->flags & ESP_CMD_FLAG_ABORT) {
+ esp->msg_out[0] = ABORT_TASK_SET;
+ esp->msg_out_len = 1;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+ }
+
+ esp_event(esp, ESP_EVENT_CHECK_PHASE);
+ esp_restore_pointers(esp, ent);
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ return 1;
+
+do_reset:
+ esp_schedule_reset(esp);
+ return 0;
+}
+
+static int esp_finish_select(struct esp *esp)
+{
+ struct esp_cmd_entry *ent;
+ struct scsi_cmnd *cmd;
+ u8 orig_select_state;
+
+ orig_select_state = esp->select_state;
+
+ /* No longer selecting. */
+ esp->select_state = ESP_SELECT_NONE;
+
+ esp->seqreg = esp_read8(ESP_SSTEP) & ESP_STEP_VBITS;
+ ent = esp->active_cmd;
+ cmd = ent->cmd;
+
+ if (esp->ops->dma_error(esp)) {
+ /* If we see a DMA error during or as a result of selection,
+ * all bets are off.
+ */
+ esp_schedule_reset(esp);
+ esp_cmd_is_done(esp, ent, cmd, (DID_ERROR << 16));
+ return 0;
+ }
+
+ esp->ops->dma_invalidate(esp);
+
+ if (esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) {
+ struct esp_target_data *tp = &esp->target[cmd->device->id];
+
+ /* Carefully back out of the selection attempt. Release
+ * resources (such as DMA mapping & TAG) and reset state (such
+ * as message out and command delivery variables).
+ */
+ if (!(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) {
+ esp_unmap_dma(esp, cmd);
+ esp_free_lun_tag(ent, cmd->device->hostdata);
+ tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_NEGO_WIDE);
+ esp->flags &= ~ESP_FLAG_DOING_SLOWCMD;
+ esp->cmd_bytes_ptr = NULL;
+ esp->cmd_bytes_left = 0;
+ } else {
+ esp->ops->unmap_single(esp, ent->sense_dma,
+ SCSI_SENSE_BUFFERSIZE,
+ DMA_FROM_DEVICE);
+ ent->sense_ptr = NULL;
+ }
+
+ /* Now that the state is unwound properly, put back onto
+ * the issue queue. This command is no longer active.
+ */
+ list_del(&ent->list);
+ list_add(&ent->list, &esp->queued_cmds);
+ esp->active_cmd = NULL;
+
+ /* Return value ignored by caller, it directly invokes
+ * esp_reconnect().
+ */
+ return 0;
+ }
+
+ if (esp->ireg == ESP_INTR_DC) {
+ struct scsi_device *dev = cmd->device;
+
+ /* Disconnect. Make sure we re-negotiate sync and
+ * wide parameters if this target starts responding
+ * again in the future.
+ */
+ esp->target[dev->id].flags |= ESP_TGT_CHECK_NEGO;
+
+ scsi_esp_cmd(esp, ESP_CMD_ESEL);
+ esp_cmd_is_done(esp, ent, cmd, (DID_BAD_TARGET << 16));
+ return 1;
+ }
+
+ if (esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) {
+ /* Selection successful. On pre-FAST chips we have
+ * to do a NOP and possibly clean out the FIFO.
+ */
+ if (esp->rev <= ESP236) {
+ int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
+
+ scsi_esp_cmd(esp, ESP_CMD_NULL);
+
+ if (!fcnt &&
+ (!esp->prev_soff ||
+ ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP)))
+ esp_flush_fifo(esp);
+ }
+
+ /* If we are doing a slow command, negotiation, etc.
+ * we'll do the right thing as we transition to the
+ * next phase.
+ */
+ esp_event(esp, ESP_EVENT_CHECK_PHASE);
+ return 0;
+ }
+
+ printk("ESP: Unexpected selection completion ireg[%x].\n",
+ esp->ireg);
+ esp_schedule_reset(esp);
+ return 0;
+}
+
+static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent,
+ struct scsi_cmnd *cmd)
+{
+ int fifo_cnt, ecount, bytes_sent, flush_fifo;
+
+ fifo_cnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
+ if (esp->prev_cfg3 & ESP_CONFIG3_EWIDE)
+ fifo_cnt <<= 1;
+
+ ecount = 0;
+ if (!(esp->sreg & ESP_STAT_TCNT)) {
+ ecount = ((unsigned int)esp_read8(ESP_TCLOW) |
+ (((unsigned int)esp_read8(ESP_TCMED)) << 8));
+ if (esp->rev == FASHME)
+ ecount |= ((unsigned int)esp_read8(FAS_RLO)) << 16;
+ }
+
+ bytes_sent = esp->data_dma_len;
+ bytes_sent -= ecount;
+
+ if (!(ent->flags & ESP_CMD_FLAG_WRITE))
+ bytes_sent -= fifo_cnt;
+
+ flush_fifo = 0;
+ if (!esp->prev_soff) {
+ /* Synchronous data transfer, always flush fifo. */
+ flush_fifo = 1;
+ } else {
+ if (esp->rev == ESP100) {
+ u32 fflags, phase;
+
+ /* ESP100 has a chip bug where in the synchronous data
+ * phase it can mistake a final long REQ pulse from the
+ * target as an extra data byte. Fun.
+ *
+ * To detect this case we resample the status register
+ * and fifo flags. If we're still in a data phase and
+ * we see spurious chunks in the fifo, we return error
+ * to the caller which should reset and set things up
+ * such that we only try future transfers to this
+ * target in synchronous mode.
+ */
+ esp->sreg = esp_read8(ESP_STATUS);
+ phase = esp->sreg & ESP_STAT_PMASK;
+ fflags = esp_read8(ESP_FFLAGS);
+
+ if ((phase == ESP_DOP &&
+ (fflags & ESP_FF_ONOTZERO)) ||
+ (phase == ESP_DIP &&
+ (fflags & ESP_FF_FBYTES)))
+ return -1;
+ }
+ if (!(ent->flags & ESP_CMD_FLAG_WRITE))
+ flush_fifo = 1;
+ }
+
+ if (flush_fifo)
+ esp_flush_fifo(esp);
+
+ return bytes_sent;
+}
+
+static void esp_setsync(struct esp *esp, struct esp_target_data *tp,
+ u8 scsi_period, u8 scsi_offset,
+ u8 esp_stp, u8 esp_soff)
+{
+ spi_period(tp->starget) = scsi_period;
+ spi_offset(tp->starget) = scsi_offset;
+ spi_width(tp->starget) = (tp->flags & ESP_TGT_WIDE) ? 1 : 0;
+
+ if (esp_soff) {
+ esp_stp &= 0x1f;
+ esp_soff |= esp->radelay;
+ if (esp->rev >= FAS236) {
+ u8 bit = ESP_CONFIG3_FSCSI;
+ if (esp->rev >= FAS100A)
+ bit = ESP_CONFIG3_FAST;
+
+ if (scsi_period < 50) {
+ if (esp->rev == FASHME)
+ esp_soff &= ~esp->radelay;
+ tp->esp_config3 |= bit;
+ } else {
+ tp->esp_config3 &= ~bit;
+ }
+ esp->prev_cfg3 = tp->esp_config3;
+ esp_write8(esp->prev_cfg3, ESP_CFG3);
+ }
+ }
+
+ tp->esp_period = esp->prev_stp = esp_stp;
+ tp->esp_offset = esp->prev_soff = esp_soff;
+
+ esp_write8(esp_soff, ESP_SOFF);
+ esp_write8(esp_stp, ESP_STP);
+
+ tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_CHECK_NEGO);
+
+ spi_display_xfer_agreement(tp->starget);
+}
+
+static void esp_msgin_reject(struct esp *esp)
+{
+ struct esp_cmd_entry *ent = esp->active_cmd;
+ struct scsi_cmnd *cmd = ent->cmd;
+ struct esp_target_data *tp;
+ int tgt;
+
+ tgt = cmd->device->id;
+ tp = &esp->target[tgt];
+
+ if (tp->flags & ESP_TGT_NEGO_WIDE) {
+ tp->flags &= ~(ESP_TGT_NEGO_WIDE | ESP_TGT_WIDE);
+
+ if (!esp_need_to_nego_sync(tp)) {
+ tp->flags &= ~ESP_TGT_CHECK_NEGO;
+ scsi_esp_cmd(esp, ESP_CMD_RATN);
+ } else {
+ esp->msg_out_len =
+ spi_populate_sync_msg(&esp->msg_out[0],
+ tp->nego_goal_period,
+ tp->nego_goal_offset);
+ tp->flags |= ESP_TGT_NEGO_SYNC;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+ }
+ return;
+ }
+
+ if (tp->flags & ESP_TGT_NEGO_SYNC) {
+ tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_CHECK_NEGO);
+ tp->esp_period = 0;
+ tp->esp_offset = 0;
+ esp_setsync(esp, tp, 0, 0, 0, 0);
+ scsi_esp_cmd(esp, ESP_CMD_RATN);
+ return;
+ }
+
+ esp->msg_out[0] = ABORT_TASK_SET;
+ esp->msg_out_len = 1;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+}
+
+static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp)
+{
+ u8 period = esp->msg_in[3];
+ u8 offset = esp->msg_in[4];
+ u8 stp;
+
+ if (!(tp->flags & ESP_TGT_NEGO_SYNC))
+ goto do_reject;
+
+ if (offset > 15)
+ goto do_reject;
+
+ if (offset) {
+ int rounded_up, one_clock;
+
+ if (period > esp->max_period) {
+ period = offset = 0;
+ goto do_sdtr;
+ }
+ if (period < esp->min_period)
+ goto do_reject;
+
+ one_clock = esp->ccycle / 1000;
+ rounded_up = (period << 2);
+ rounded_up = (rounded_up + one_clock - 1) / one_clock;
+ stp = rounded_up;
+ if (stp && esp->rev >= FAS236) {
+ if (stp >= 50)
+ stp--;
+ }
+ } else {
+ stp = 0;
+ }
+
+ esp_setsync(esp, tp, period, offset, stp, offset);
+ return;
+
+do_reject:
+ esp->msg_out[0] = MESSAGE_REJECT;
+ esp->msg_out_len = 1;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+ return;
+
+do_sdtr:
+ tp->nego_goal_period = period;
+ tp->nego_goal_offset = offset;
+ esp->msg_out_len =
+ spi_populate_sync_msg(&esp->msg_out[0],
+ tp->nego_goal_period,
+ tp->nego_goal_offset);
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+}
+
+static void esp_msgin_wdtr(struct esp *esp, struct esp_target_data *tp)
+{
+ int size = 8 << esp->msg_in[3];
+ u8 cfg3;
+
+ if (esp->rev != FASHME)
+ goto do_reject;
+
+ if (size != 8 && size != 16)
+ goto do_reject;
+
+ if (!(tp->flags & ESP_TGT_NEGO_WIDE))
+ goto do_reject;
+
+ cfg3 = tp->esp_config3;
+ if (size == 16) {
+ tp->flags |= ESP_TGT_WIDE;
+ cfg3 |= ESP_CONFIG3_EWIDE;
+ } else {
+ tp->flags &= ~ESP_TGT_WIDE;
+ cfg3 &= ~ESP_CONFIG3_EWIDE;
+ }
+ tp->esp_config3 = cfg3;
+ esp->prev_cfg3 = cfg3;
+ esp_write8(cfg3, ESP_CFG3);
+
+ tp->flags &= ~ESP_TGT_NEGO_WIDE;
+
+ spi_period(tp->starget) = 0;
+ spi_offset(tp->starget) = 0;
+ if (!esp_need_to_nego_sync(tp)) {
+ tp->flags &= ~ESP_TGT_CHECK_NEGO;
+ scsi_esp_cmd(esp, ESP_CMD_RATN);
+ } else {
+ esp->msg_out_len =
+ spi_populate_sync_msg(&esp->msg_out[0],
+ tp->nego_goal_period,
+ tp->nego_goal_offset);
+ tp->flags |= ESP_TGT_NEGO_SYNC;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+ }
+ return;
+
+do_reject:
+ esp->msg_out[0] = MESSAGE_REJECT;
+ esp->msg_out_len = 1;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+}
+
+static void esp_msgin_extended(struct esp *esp)
+{
+ struct esp_cmd_entry *ent = esp->active_cmd;
+ struct scsi_cmnd *cmd = ent->cmd;
+ struct esp_target_data *tp;
+ int tgt = cmd->device->id;
+
+ tp = &esp->target[tgt];
+ if (esp->msg_in[2] == EXTENDED_SDTR) {
+ esp_msgin_sdtr(esp, tp);
+ return;
+ }
+ if (esp->msg_in[2] == EXTENDED_WDTR) {
+ esp_msgin_wdtr(esp, tp);
+ return;
+ }
+
+ printk("ESP: Unexpected extended msg type %x\n",
+ esp->msg_in[2]);
+
+ esp->msg_out[0] = ABORT_TASK_SET;
+ esp->msg_out_len = 1;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+}
+
+/* Analyze msgin bytes received from target so far. Return non-zero
+ * if there are more bytes needed to complete the message.
+ */
+static int esp_msgin_process(struct esp *esp)
+{
+ u8 msg0 = esp->msg_in[0];
+ int len = esp->msg_in_len;
+
+ if (msg0 & 0x80) {
+ /* Identify */
+ printk("ESP: Unexpected msgin identify\n");
+ return 0;
+ }
+
+ switch (msg0) {
+ case EXTENDED_MESSAGE:
+ if (len == 1)
+ return 1;
+ if (len < esp->msg_in[1] + 2)
+ return 1;
+ esp_msgin_extended(esp);
+ return 0;
+
+ case IGNORE_WIDE_RESIDUE: {
+ struct esp_cmd_entry *ent;
+ struct esp_cmd_priv *spriv;
+ if (len == 1)
+ return 1;
+
+ if (esp->msg_in[1] != 1)
+ goto do_reject;
+
+ ent = esp->active_cmd;
+ spriv = ESP_CMD_PRIV(ent->cmd);
+
+ if (spriv->cur_residue == sg_dma_len(spriv->cur_sg)) {
+ spriv->cur_sg--;
+ spriv->cur_residue = 1;
+ } else
+ spriv->cur_residue++;
+ spriv->tot_residue++;
+ return 0;
+ }
+ case NOP:
+ return 0;
+ case RESTORE_POINTERS:
+ esp_restore_pointers(esp, esp->active_cmd);
+ return 0;
+ case SAVE_POINTERS:
+ esp_save_pointers(esp, esp->active_cmd);
+ return 0;
+
+ case COMMAND_COMPLETE:
+ case DISCONNECT: {
+ struct esp_cmd_entry *ent = esp->active_cmd;
+
+ ent->message = msg0;
+ esp_event(esp, ESP_EVENT_FREE_BUS);
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ return 0;
+ }
+ case MESSAGE_REJECT:
+ esp_msgin_reject(esp);
+ return 0;
+
+ default:
+ do_reject:
+ esp->msg_out[0] = MESSAGE_REJECT;
+ esp->msg_out_len = 1;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+ return 0;
+ }
+}
+
+static int esp_process_event(struct esp *esp)
+{
+ int write;
+
+again:
+ write = 0;
+ switch (esp->event) {
+ case ESP_EVENT_CHECK_PHASE:
+ switch (esp->sreg & ESP_STAT_PMASK) {
+ case ESP_DOP:
+ esp_event(esp, ESP_EVENT_DATA_OUT);
+ break;
+ case ESP_DIP:
+ esp_event(esp, ESP_EVENT_DATA_IN);
+ break;
+ case ESP_STATP:
+ esp_flush_fifo(esp);
+ scsi_esp_cmd(esp, ESP_CMD_ICCSEQ);
+ esp_event(esp, ESP_EVENT_STATUS);
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ return 1;
+
+ case ESP_MOP:
+ esp_event(esp, ESP_EVENT_MSGOUT);
+ break;
+
+ case ESP_MIP:
+ esp_event(esp, ESP_EVENT_MSGIN);
+ break;
+
+ case ESP_CMDP:
+ esp_event(esp, ESP_EVENT_CMD_START);
+ break;
+
+ default:
+ printk("ESP: Unexpected phase, sreg=%02x\n",
+ esp->sreg);
+ esp_schedule_reset(esp);
+ return 0;
+ }
+ goto again;
+ break;
+
+ case ESP_EVENT_DATA_IN:
+ write = 1;
+ /* fallthru */
+
+ case ESP_EVENT_DATA_OUT: {
+ struct esp_cmd_entry *ent = esp->active_cmd;
+ struct scsi_cmnd *cmd = ent->cmd;
+ dma_addr_t dma_addr = esp_cur_dma_addr(ent, cmd);
+ unsigned int dma_len = esp_cur_dma_len(ent, cmd);
+
+ if (esp->rev == ESP100)
+ scsi_esp_cmd(esp, ESP_CMD_NULL);
+
+ if (write)
+ ent->flags |= ESP_CMD_FLAG_WRITE;
+ else
+ ent->flags &= ~ESP_CMD_FLAG_WRITE;
+
+ dma_len = esp_dma_length_limit(esp, dma_addr, dma_len);
+ esp->data_dma_len = dma_len;
+
+ if (!dma_len) {
+ printk(KERN_ERR PFX "esp%d: DMA length is zero!\n",
+ esp->host->unique_id);
+ printk(KERN_ERR PFX "esp%d: cur adr[%08x] len[%08x]\n",
+ esp->host->unique_id,
+ esp_cur_dma_addr(ent, cmd),
+ esp_cur_dma_len(ent, cmd));
+ esp_schedule_reset(esp);
+ return 0;
+ }
+
+ esp_log_datastart("ESP: start data addr[%08x] len[%u] "
+ "write(%d)\n",
+ dma_addr, dma_len, write);
+
+ esp->ops->send_dma_cmd(esp, dma_addr, dma_len, dma_len,
+ write, ESP_CMD_DMA | ESP_CMD_TI);
+ esp_event(esp, ESP_EVENT_DATA_DONE);
+ break;
+ }
+ case ESP_EVENT_DATA_DONE: {
+ struct esp_cmd_entry *ent = esp->active_cmd;
+ struct scsi_cmnd *cmd = ent->cmd;
+ int bytes_sent;
+
+ if (esp->ops->dma_error(esp)) {
+ printk("ESP: data done, DMA error, resetting\n");
+ esp_schedule_reset(esp);
+ return 0;
+ }
+
+ if (ent->flags & ESP_CMD_FLAG_WRITE) {
+ /* XXX parity errors, etc. XXX */
+
+ esp->ops->dma_drain(esp);
+ }
+ esp->ops->dma_invalidate(esp);
+
+ if (esp->ireg != ESP_INTR_BSERV) {
+ /* We should always see exactly a bus-service
+ * interrupt at the end of a successful transfer.
+ */
+ printk("ESP: data done, not BSERV, resetting\n");
+ esp_schedule_reset(esp);
+ return 0;
+ }
+
+ bytes_sent = esp_data_bytes_sent(esp, ent, cmd);
+
+ esp_log_datadone("ESP: data done flgs[%x] sent[%d]\n",
+ ent->flags, bytes_sent);
+
+ if (bytes_sent < 0) {
+ /* XXX force sync mode for this target XXX */
+ esp_schedule_reset(esp);
+ return 0;
+ }
+
+ esp_advance_dma(esp, ent, cmd, bytes_sent);
+ esp_event(esp, ESP_EVENT_CHECK_PHASE);
+ goto again;
+ break;
+ }
+
+ case ESP_EVENT_STATUS: {
+ struct esp_cmd_entry *ent = esp->active_cmd;
+
+ if (esp->ireg & ESP_INTR_FDONE) {
+ ent->status = esp_read8(ESP_FDATA);
+ ent->message = esp_read8(ESP_FDATA);
+ scsi_esp_cmd(esp, ESP_CMD_MOK);
+ } else if (esp->ireg == ESP_INTR_BSERV) {
+ ent->status = esp_read8(ESP_FDATA);
+ ent->message = 0xff;
+ esp_event(esp, ESP_EVENT_MSGIN);
+ return 0;
+ }
+
+ if (ent->message != COMMAND_COMPLETE) {
+ printk("ESP: Unexpected message %x in status\n",
+ ent->message);
+ esp_schedule_reset(esp);
+ return 0;
+ }
+
+ esp_event(esp, ESP_EVENT_FREE_BUS);
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ break;
+ }
+ case ESP_EVENT_FREE_BUS: {
+ struct esp_cmd_entry *ent = esp->active_cmd;
+ struct scsi_cmnd *cmd = ent->cmd;
+
+ if (ent->message == COMMAND_COMPLETE ||
+ ent->message == DISCONNECT)
+ scsi_esp_cmd(esp, ESP_CMD_ESEL);
+
+ if (ent->message == COMMAND_COMPLETE) {
+ esp_log_cmddone("ESP: Command done status[%x] "
+ "message[%x]\n",
+ ent->status, ent->message);
+ if (ent->status == SAM_STAT_TASK_SET_FULL)
+ esp_event_queue_full(esp, ent);
+
+ if (ent->status == SAM_STAT_CHECK_CONDITION &&
+ !(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) {
+ ent->flags |= ESP_CMD_FLAG_AUTOSENSE;
+ esp_autosense(esp, ent);
+ } else {
+ esp_cmd_is_done(esp, ent, cmd,
+ compose_result(ent->status,
+ ent->message,
+ DID_OK));
+ }
+ } else if (ent->message == DISCONNECT) {
+ esp_log_disconnect("ESP: Disconnecting tgt[%d] "
+ "tag[%x:%x]\n",
+ cmd->device->id,
+ ent->tag[0], ent->tag[1]);
+
+ esp->active_cmd = NULL;
+ esp_maybe_execute_command(esp);
+ } else {
+ printk("ESP: Unexpected message %x in freebus\n",
+ ent->message);
+ esp_schedule_reset(esp);
+ return 0;
+ }
+ if (esp->active_cmd)
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ break;
+ }
+ case ESP_EVENT_MSGOUT: {
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+
+ if (esp_debug & ESP_DEBUG_MSGOUT) {
+ int i;
+ printk("ESP: Sending message [ ");
+ for (i = 0; i < esp->msg_out_len; i++)
+ printk("%02x ", esp->msg_out[i]);
+ printk("]\n");
+ }
+
+ if (esp->rev == FASHME) {
+ int i;
+
+ /* Always use the fifo. */
+ for (i = 0; i < esp->msg_out_len; i++) {
+ esp_write8(esp->msg_out[i], ESP_FDATA);
+ esp_write8(0, ESP_FDATA);
+ }
+ scsi_esp_cmd(esp, ESP_CMD_TI);
+ } else {
+ if (esp->msg_out_len == 1) {
+ esp_write8(esp->msg_out[0], ESP_FDATA);
+ scsi_esp_cmd(esp, ESP_CMD_TI);
+ } else {
+ /* Use DMA. */
+ memcpy(esp->command_block,
+ esp->msg_out,
+ esp->msg_out_len);
+
+ esp->ops->send_dma_cmd(esp,
+ esp->command_block_dma,
+ esp->msg_out_len,
+ esp->msg_out_len,
+ 0,
+ ESP_CMD_DMA|ESP_CMD_TI);
+ }
+ }
+ esp_event(esp, ESP_EVENT_MSGOUT_DONE);
+ break;
+ }
+ case ESP_EVENT_MSGOUT_DONE:
+ if (esp->rev == FASHME) {
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ } else {
+ if (esp->msg_out_len > 1)
+ esp->ops->dma_invalidate(esp);
+ }
+
+ if (!(esp->ireg & ESP_INTR_DC)) {
+ if (esp->rev != FASHME)
+ scsi_esp_cmd(esp, ESP_CMD_NULL);
+ }
+ esp_event(esp, ESP_EVENT_CHECK_PHASE);
+ goto again;
+ case ESP_EVENT_MSGIN:
+ if (esp->ireg & ESP_INTR_BSERV) {
+ if (esp->rev == FASHME) {
+ if (!(esp_read8(ESP_STATUS2) &
+ ESP_STAT2_FEMPTY))
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ } else {
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ if (esp->rev == ESP100)
+ scsi_esp_cmd(esp, ESP_CMD_NULL);
+ }
+ scsi_esp_cmd(esp, ESP_CMD_TI);
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ return 1;
+ }
+ if (esp->ireg & ESP_INTR_FDONE) {
+ u8 val;
+
+ if (esp->rev == FASHME)
+ val = esp->fifo[0];
+ else
+ val = esp_read8(ESP_FDATA);
+ esp->msg_in[esp->msg_in_len++] = val;
+
+ esp_log_msgin("ESP: Got msgin byte %x\n", val);
+
+ if (!esp_msgin_process(esp))
+ esp->msg_in_len = 0;
+
+ if (esp->rev == FASHME)
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+
+ scsi_esp_cmd(esp, ESP_CMD_MOK);
+
+ if (esp->event != ESP_EVENT_FREE_BUS)
+ esp_event(esp, ESP_EVENT_CHECK_PHASE);
+ } else {
+ printk("ESP: MSGIN neither BSERV not FDON, resetting");
+ esp_schedule_reset(esp);
+ return 0;
+ }
+ break;
+ case ESP_EVENT_CMD_START:
+ memcpy(esp->command_block, esp->cmd_bytes_ptr,
+ esp->cmd_bytes_left);
+ if (esp->rev == FASHME)
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ esp->ops->send_dma_cmd(esp, esp->command_block_dma,
+ esp->cmd_bytes_left, 16, 0,
+ ESP_CMD_DMA | ESP_CMD_TI);
+ esp_event(esp, ESP_EVENT_CMD_DONE);
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ break;
+ case ESP_EVENT_CMD_DONE:
+ esp->ops->dma_invalidate(esp);
+ if (esp->ireg & ESP_INTR_BSERV) {
+ esp_event(esp, ESP_EVENT_CHECK_PHASE);
+ goto again;
+ }
+ esp_schedule_reset(esp);
+ return 0;
+ break;
+
+ case ESP_EVENT_RESET:
+ scsi_esp_cmd(esp, ESP_CMD_RS);
+ break;
+
+ default:
+ printk("ESP: Unexpected event %x, resetting\n",
+ esp->event);
+ esp_schedule_reset(esp);
+ return 0;
+ break;
+ }
+ return 1;
+}
+
+static void esp_reset_cleanup_one(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ struct scsi_cmnd *cmd = ent->cmd;
+
+ esp_unmap_dma(esp, cmd);
+ esp_free_lun_tag(ent, cmd->device->hostdata);
+ cmd->result = DID_RESET << 16;
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ esp->ops->unmap_single(esp, ent->sense_dma,
+ SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+ ent->sense_ptr = NULL;
+ }
+
+ cmd->scsi_done(cmd);
+ list_del(&ent->list);
+ esp_put_ent(esp, ent);
+}
+
+static void esp_clear_hold(struct scsi_device *dev, void *data)
+{
+ struct esp_lun_data *lp = dev->hostdata;
+
+ BUG_ON(lp->num_tagged);
+ lp->hold = 0;
+}
+
+static void esp_reset_cleanup(struct esp *esp)
+{
+ struct esp_cmd_entry *ent, *tmp;
+ int i;
+
+ list_for_each_entry_safe(ent, tmp, &esp->queued_cmds, list) {
+ struct scsi_cmnd *cmd = ent->cmd;
+
+ list_del(&ent->list);
+ cmd->result = DID_RESET << 16;
+ cmd->scsi_done(cmd);
+ esp_put_ent(esp, ent);
+ }
+
+ list_for_each_entry_safe(ent, tmp, &esp->active_cmds, list) {
+ if (ent == esp->active_cmd)
+ esp->active_cmd = NULL;
+ esp_reset_cleanup_one(esp, ent);
+ }
+
+ BUG_ON(esp->active_cmd != NULL);
+
+ /* Force renegotiation of sync/wide transfers. */
+ for (i = 0; i < ESP_MAX_TARGET; i++) {
+ struct esp_target_data *tp = &esp->target[i];
+
+ tp->esp_period = 0;
+ tp->esp_offset = 0;
+ tp->esp_config3 &= ~(ESP_CONFIG3_EWIDE |
+ ESP_CONFIG3_FSCSI |
+ ESP_CONFIG3_FAST);
+ tp->flags &= ~ESP_TGT_WIDE;
+ tp->flags |= ESP_TGT_CHECK_NEGO;
+
+ if (tp->starget)
+ starget_for_each_device(tp->starget, NULL,
+ esp_clear_hold);
+ }
+}
+
+/* Runs under host->lock */
+static void __esp_interrupt(struct esp *esp)
+{
+ int finish_reset, intr_done;
+ u8 phase;
+
+ esp->sreg = esp_read8(ESP_STATUS);
+
+ if (esp->flags & ESP_FLAG_RESETTING) {
+ finish_reset = 1;
+ } else {
+ if (esp_check_gross_error(esp))
+ return;
+
+ finish_reset = esp_check_spur_intr(esp);
+ if (finish_reset < 0)
+ return;
+ }
+
+ esp->ireg = esp_read8(ESP_INTRPT);
+
+ if (esp->ireg & ESP_INTR_SR)
+ finish_reset = 1;
+
+ if (finish_reset) {
+ esp_reset_cleanup(esp);
+ if (esp->eh_reset) {
+ complete(esp->eh_reset);
+ esp->eh_reset = NULL;
+ }
+ return;
+ }
+
+ phase = (esp->sreg & ESP_STAT_PMASK);
+ if (esp->rev == FASHME) {
+ if (((phase != ESP_DIP && phase != ESP_DOP) &&
+ esp->select_state == ESP_SELECT_NONE &&
+ esp->event != ESP_EVENT_STATUS &&
+ esp->event != ESP_EVENT_DATA_DONE) ||
+ (esp->ireg & ESP_INTR_RSEL)) {
+ esp->sreg2 = esp_read8(ESP_STATUS2);
+ if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
+ (esp->sreg2 & ESP_STAT2_F1BYTE))
+ hme_read_fifo(esp);
+ }
+ }
+
+ esp_log_intr("ESP: intr sreg[%02x] seqreg[%02x] "
+ "sreg2[%02x] ireg[%02x]\n",
+ esp->sreg, esp->seqreg, esp->sreg2, esp->ireg);
+
+ intr_done = 0;
+
+ if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN | ESP_INTR_IC)) {
+ printk("ESP: unexpected IREG %02x\n", esp->ireg);
+ if (esp->ireg & ESP_INTR_IC)
+ esp_dump_cmd_log(esp);
+
+ esp_schedule_reset(esp);
+ } else {
+ if (!(esp->ireg & ESP_INTR_RSEL)) {
+ /* Some combination of FDONE, BSERV, DC. */
+ if (esp->select_state != ESP_SELECT_NONE)
+ intr_done = esp_finish_select(esp);
+ } else if (esp->ireg & ESP_INTR_RSEL) {
+ if (esp->active_cmd)
+ (void) esp_finish_select(esp);
+ intr_done = esp_reconnect(esp);
+ }
+ }
+ while (!intr_done)
+ intr_done = esp_process_event(esp);
+}
+
+irqreturn_t scsi_esp_intr(int irq, void *dev_id)
+{
+ struct esp *esp = dev_id;
+ unsigned long flags;
+ irqreturn_t ret;
+
+ spin_lock_irqsave(esp->host->host_lock, flags);
+ ret = IRQ_NONE;
+ if (esp->ops->irq_pending(esp)) {
+ ret = IRQ_HANDLED;
+ for (;;) {
+ int i;
+
+ __esp_interrupt(esp);
+ if (!(esp->flags & ESP_FLAG_QUICKIRQ_CHECK))
+ break;
+ esp->flags &= ~ESP_FLAG_QUICKIRQ_CHECK;
+
+ for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) {
+ if (esp->ops->irq_pending(esp))
+ break;
+ }
+ if (i == ESP_QUICKIRQ_LIMIT)
+ break;
+ }
+ }
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(scsi_esp_intr);
+
+static void __devinit esp_get_revision(struct esp *esp)
+{
+ u8 val;
+
+ esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
+ esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
+ esp_write8(esp->config2, ESP_CFG2);
+
+ val = esp_read8(ESP_CFG2);
+ val &= ~ESP_CONFIG2_MAGIC;
+ if (val != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
+ /* If what we write to cfg2 does not come back, cfg2 is not
+ * implemented, therefore this must be a plain esp100.
+ */
+ esp->rev = ESP100;
+ } else {
+ esp->config2 = 0;
+ esp_set_all_config3(esp, 5);
+ esp->prev_cfg3 = 5;
+ esp_write8(esp->config2, ESP_CFG2);
+ esp_write8(0, ESP_CFG3);
+ esp_write8(esp->prev_cfg3, ESP_CFG3);
+
+ val = esp_read8(ESP_CFG3);
+ if (val != 5) {
+ /* The cfg2 register is implemented, however
+ * cfg3 is not, must be esp100a.
+ */
+ esp->rev = ESP100A;
+ } else {
+ esp_set_all_config3(esp, 0);
+ esp->prev_cfg3 = 0;
+ esp_write8(esp->prev_cfg3, ESP_CFG3);
+
+ /* All of cfg{1,2,3} implemented, must be one of
+ * the fas variants, figure out which one.
+ */
+ if (esp->cfact == 0 || esp->cfact > ESP_CCF_F5) {
+ esp->rev = FAST;
+ esp->sync_defp = SYNC_DEFP_FAST;
+ } else {
+ esp->rev = ESP236;
+ }
+ esp->config2 = 0;
+ esp_write8(esp->config2, ESP_CFG2);
+ }
+ }
+}
+
+static void __devinit esp_init_swstate(struct esp *esp)
+{
+ int i;
+
+ INIT_LIST_HEAD(&esp->queued_cmds);
+ INIT_LIST_HEAD(&esp->active_cmds);
+ INIT_LIST_HEAD(&esp->esp_cmd_pool);
+
+ /* Start with a clear state, domain validation (via ->slave_configure,
+ * spi_dv_device()) will attempt to enable SYNC, WIDE, and tagged
+ * commands.
+ */
+ for (i = 0 ; i < ESP_MAX_TARGET; i++) {
+ esp->target[i].flags = 0;
+ esp->target[i].nego_goal_period = 0;
+ esp->target[i].nego_goal_offset = 0;
+ esp->target[i].nego_goal_width = 0;
+ esp->target[i].nego_goal_tags = 0;
+ }
+}
+
+/* This places the ESP into a known state at boot time. */
+static void __devinit esp_bootup_reset(struct esp *esp)
+{
+ u8 val;
+
+ /* Reset the DMA */
+ esp->ops->reset_dma(esp);
+
+ /* Reset the ESP */
+ esp_reset_esp(esp);
+
+ /* Reset the SCSI bus, but tell ESP not to generate an irq */
+ val = esp_read8(ESP_CFG1);
+ val |= ESP_CONFIG1_SRRDISAB;
+ esp_write8(val, ESP_CFG1);
+
+ scsi_esp_cmd(esp, ESP_CMD_RS);
+ udelay(400);
+
+ esp_write8(esp->config1, ESP_CFG1);
+
+ /* Eat any bitrot in the chip and we are done... */
+ esp_read8(ESP_INTRPT);
+}
+
+static void __devinit esp_set_clock_params(struct esp *esp)
+{
+ int fmhz;
+ u8 ccf;
+
+ /* This is getting messy but it has to be done correctly or else
+ * you get weird behavior all over the place. We are trying to
+ * basically figure out three pieces of information.
+ *
+ * a) Clock Conversion Factor
+ *
+ * This is a representation of the input crystal clock frequency
+ * going into the ESP on this machine. Any operation whose timing
+ * is longer than 400ns depends on this value being correct. For
+ * example, you'll get blips for arbitration/selection during high
+ * load or with multiple targets if this is not set correctly.
+ *
+ * b) Selection Time-Out
+ *
+ * The ESP isn't very bright and will arbitrate for the bus and try
+ * to select a target forever if you let it. This value tells the
+ * ESP when it has taken too long to negotiate and that it should
+ * interrupt the CPU so we can see what happened. The value is
+ * computed as follows (from NCR/Symbios chip docs).
+ *
+ * (Time Out Period) * (Input Clock)
+ * STO = ----------------------------------
+ * (8192) * (Clock Conversion Factor)
+ *
+ * We use a time out period of 250ms (ESP_BUS_TIMEOUT).
+ *
+ * c) Imperical constants for synchronous offset and transfer period
+ * register values
+ *
+ * This entails the smallest and largest sync period we could ever
+ * handle on this ESP.
+ */
+ fmhz = esp->cfreq;
+
+ ccf = ((fmhz / 1000000) + 4) / 5;
+ if (ccf == 1)
+ ccf = 2;
+
+ /* If we can't find anything reasonable, just assume 20MHZ.
+ * This is the clock frequency of the older sun4c's where I've
+ * been unable to find the clock-frequency PROM property. All
+ * other machines provide useful values it seems.
+ */
+ if (fmhz <= 5000000 || ccf < 1 || ccf > 8) {
+ fmhz = 20000000;
+ ccf = 4;
+ }
+
+ esp->cfact = (ccf == 8 ? 0 : ccf);
+ esp->cfreq = fmhz;
+ esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
+ esp->ctick = ESP_TICK(ccf, esp->ccycle);
+ esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
+ esp->sync_defp = SYNC_DEFP_SLOW;
+}
+
+static const char *esp_chip_names[] = {
+ "ESP100",
+ "ESP100A",
+ "ESP236",
+ "FAS236",
+ "FAS100A",
+ "FAST",
+ "FASHME",
+};
+
+static struct scsi_transport_template *esp_transport_template;
+
+int __devinit scsi_esp_register(struct esp *esp, struct device *dev)
+{
+ static int instance;
+ int err;
+
+ esp->host->transportt = esp_transport_template;
+ esp->host->max_lun = ESP_MAX_LUN;
+ esp->host->cmd_per_lun = 2;
+
+ esp_set_clock_params(esp);
+
+ esp_get_revision(esp);
+
+ esp_init_swstate(esp);
+
+ esp_bootup_reset(esp);
+
+ printk(KERN_INFO PFX "esp%u, regs[%1p:%1p] irq[%u]\n",
+ esp->host->unique_id, esp->regs, esp->dma_regs,
+ esp->host->irq);
+ printk(KERN_INFO PFX "esp%u is a %s, %u MHz (ccf=%u), SCSI ID %u\n",
+ esp->host->unique_id, esp_chip_names[esp->rev],
+ esp->cfreq / 1000000, esp->cfact, esp->scsi_id);
+
+ /* Let the SCSI bus reset settle. */
+ ssleep(esp_bus_reset_settle);
+
+ err = scsi_add_host(esp->host, dev);
+ if (err)
+ return err;
+
+ esp->host->unique_id = instance++;
+
+ scsi_scan_host(esp->host);
+
+ return 0;
+}
+EXPORT_SYMBOL(scsi_esp_register);
+
+void __devexit scsi_esp_unregister(struct esp *esp)
+{
+ scsi_remove_host(esp->host);
+}
+EXPORT_SYMBOL(scsi_esp_unregister);
+
+static int esp_slave_alloc(struct scsi_device *dev)
+{
+ struct esp *esp = host_to_esp(dev->host);
+ struct esp_target_data *tp = &esp->target[dev->id];
+ struct esp_lun_data *lp;
+
+ lp = kzalloc(sizeof(*lp), GFP_KERNEL);
+ if (!lp)
+ return -ENOMEM;
+ dev->hostdata = lp;
+
+ tp->starget = dev->sdev_target;
+
+ spi_min_period(tp->starget) = esp->min_period;
+ spi_max_offset(tp->starget) = 15;
+
+ if (esp->flags & ESP_FLAG_WIDE_CAPABLE)
+ spi_max_width(tp->starget) = 1;
+ else
+ spi_max_width(tp->starget) = 0;
+
+ return 0;
+}
+
+static int esp_slave_configure(struct scsi_device *dev)
+{
+ struct esp *esp = host_to_esp(dev->host);
+ struct esp_target_data *tp = &esp->target[dev->id];
+ int goal_tags, queue_depth;
+
+ goal_tags = 0;
+
+ if (dev->tagged_supported) {
+ /* XXX make this configurable somehow XXX */
+ goal_tags = ESP_DEFAULT_TAGS;
+
+ if (goal_tags > ESP_MAX_TAG)
+ goal_tags = ESP_MAX_TAG;
+ }
+
+ queue_depth = goal_tags;
+ if (queue_depth < dev->host->cmd_per_lun)
+ queue_depth = dev->host->cmd_per_lun;
+
+ if (goal_tags) {
+ scsi_set_tag_type(dev, MSG_ORDERED_TAG);
+ scsi_activate_tcq(dev, queue_depth);
+ } else {
+ scsi_deactivate_tcq(dev, queue_depth);
+ }
+ tp->flags |= ESP_TGT_DISCONNECT;
+
+ if (!spi_initial_dv(dev->sdev_target))
+ spi_dv_device(dev);
+
+ return 0;
+}
+
+static void esp_slave_destroy(struct scsi_device *dev)
+{
+ struct esp_lun_data *lp = dev->hostdata;
+
+ kfree(lp);
+ dev->hostdata = NULL;
+}
+
+static int esp_eh_abort_handler(struct scsi_cmnd *cmd)
+{
+ struct esp *esp = host_to_esp(cmd->device->host);
+ struct esp_cmd_entry *ent, *tmp;
+ struct completion eh_done;
+ unsigned long flags;
+
+ /* XXX This helps a lot with debugging but might be a bit
+ * XXX much for the final driver.
+ */
+ spin_lock_irqsave(esp->host->host_lock, flags);
+ printk(KERN_ERR PFX "esp%d: Aborting command [%p:%02x]\n",
+ esp->host->unique_id, cmd, cmd->cmnd[0]);
+ ent = esp->active_cmd;
+ if (ent)
+ printk(KERN_ERR PFX "esp%d: Current command [%p:%02x]\n",
+ esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
+ list_for_each_entry(ent, &esp->queued_cmds, list) {
+ printk(KERN_ERR PFX "esp%d: Queued command [%p:%02x]\n",
+ esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
+ }
+ list_for_each_entry(ent, &esp->active_cmds, list) {
+ printk(KERN_ERR PFX "esp%d: Active command [%p:%02x]\n",
+ esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
+ }
+ esp_dump_cmd_log(esp);
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ spin_lock_irqsave(esp->host->host_lock, flags);
+
+ ent = NULL;
+ list_for_each_entry(tmp, &esp->queued_cmds, list) {
+ if (tmp->cmd == cmd) {
+ ent = tmp;
+ break;
+ }
+ }
+
+ if (ent) {
+ /* Easiest case, we didn't even issue the command
+ * yet so it is trivial to abort.
+ */
+ list_del(&ent->list);
+
+ cmd->result = DID_ABORT << 16;
+ cmd->scsi_done(cmd);
+
+ esp_put_ent(esp, ent);
+
+ goto out_success;
+ }
+
+ init_completion(&eh_done);
+
+ ent = esp->active_cmd;
+ if (ent && ent->cmd == cmd) {
+ /* Command is the currently active command on
+ * the bus. If we already have an output message
+ * pending, no dice.
+ */
+ if (esp->msg_out_len)
+ goto out_failure;
+
+ /* Send out an abort, encouraging the target to
+ * go to MSGOUT phase by asserting ATN.
+ */
+ esp->msg_out[0] = ABORT_TASK_SET;
+ esp->msg_out_len = 1;
+ ent->eh_done = &eh_done;
+
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+ } else {
+ /* The command is disconnected. This is not easy to
+ * abort. For now we fail and let the scsi error
+ * handling layer go try a scsi bus reset or host
+ * reset.
+ *
+ * What we could do is put together a scsi command
+ * solely for the purpose of sending an abort message
+ * to the target. Coming up with all the code to
+ * cook up scsi commands, special case them everywhere,
+ * etc. is for questionable gain and it would be better
+ * if the generic scsi error handling layer could do at
+ * least some of that for us.
+ *
+ * Anyways this is an area for potential future improvement
+ * in this driver.
+ */
+ goto out_failure;
+ }
+
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ if (!wait_for_completion_timeout(&eh_done, 5 * HZ)) {
+ spin_lock_irqsave(esp->host->host_lock, flags);
+ ent->eh_done = NULL;
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ return FAILED;
+ }
+
+ return SUCCESS;
+
+out_success:
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+ return SUCCESS;
+
+out_failure:
+ /* XXX This might be a good location to set ESP_TGT_BROKEN
+ * XXX since we know which target/lun in particular is
+ * XXX causing trouble.
+ */
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+ return FAILED;
+}
+
+static int esp_eh_bus_reset_handler(struct scsi_cmnd *cmd)
+{
+ struct esp *esp = host_to_esp(cmd->device->host);
+ struct completion eh_reset;
+ unsigned long flags;
+
+ init_completion(&eh_reset);
+
+ spin_lock_irqsave(esp->host->host_lock, flags);
+
+ esp->eh_reset = &eh_reset;
+
+ /* XXX This is too simple... We should add lots of
+ * XXX checks here so that if we find that the chip is
+ * XXX very wedged we return failure immediately so
+ * XXX that we can perform a full chip reset.
+ */
+ esp->flags |= ESP_FLAG_RESETTING;
+ scsi_esp_cmd(esp, ESP_CMD_RS);
+
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ ssleep(esp_bus_reset_settle);
+
+ if (!wait_for_completion_timeout(&eh_reset, 5 * HZ)) {
+ spin_lock_irqsave(esp->host->host_lock, flags);
+ esp->eh_reset = NULL;
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+/* All bets are off, reset the entire device. */
+static int esp_eh_host_reset_handler(struct scsi_cmnd *cmd)
+{
+ struct esp *esp = host_to_esp(cmd->device->host);
+ unsigned long flags;
+
+ spin_lock_irqsave(esp->host->host_lock, flags);
+ esp_bootup_reset(esp);
+ esp_reset_cleanup(esp);
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ ssleep(esp_bus_reset_settle);
+
+ return SUCCESS;
+}
+
+static const char *esp_info(struct Scsi_Host *host)
+{
+ return "esp";
+}
+
+struct scsi_host_template scsi_esp_template = {
+ .module = THIS_MODULE,
+ .name = "esp",
+ .info = esp_info,
+ .queuecommand = esp_queuecommand,
+ .slave_alloc = esp_slave_alloc,
+ .slave_configure = esp_slave_configure,
+ .slave_destroy = esp_slave_destroy,
+ .eh_abort_handler = esp_eh_abort_handler,
+ .eh_bus_reset_handler = esp_eh_bus_reset_handler,
+ .eh_host_reset_handler = esp_eh_host_reset_handler,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .use_clustering = ENABLE_CLUSTERING,
+ .max_sectors = 0xffff,
+ .skip_settle_delay = 1,
+};
+EXPORT_SYMBOL(scsi_esp_template);
+
+static void esp_get_signalling(struct Scsi_Host *host)
+{
+ struct esp *esp = host_to_esp(host);
+ enum spi_signal_type type;
+
+ if (esp->flags & ESP_FLAG_DIFFERENTIAL)
+ type = SPI_SIGNAL_HVD;
+ else
+ type = SPI_SIGNAL_SE;
+
+ spi_signalling(host) = type;
+}
+
+static void esp_set_offset(struct scsi_target *target, int offset)
+{
+ struct Scsi_Host *host = dev_to_shost(target->dev.parent);
+ struct esp *esp = host_to_esp(host);
+ struct esp_target_data *tp = &esp->target[target->id];
+
+ tp->nego_goal_offset = offset;
+ tp->flags |= ESP_TGT_CHECK_NEGO;
+}
+
+static void esp_set_period(struct scsi_target *target, int period)
+{
+ struct Scsi_Host *host = dev_to_shost(target->dev.parent);
+ struct esp *esp = host_to_esp(host);
+ struct esp_target_data *tp = &esp->target[target->id];
+
+ tp->nego_goal_period = period;
+ tp->flags |= ESP_TGT_CHECK_NEGO;
+}
+
+static void esp_set_width(struct scsi_target *target, int width)
+{
+ struct Scsi_Host *host = dev_to_shost(target->dev.parent);
+ struct esp *esp = host_to_esp(host);
+ struct esp_target_data *tp = &esp->target[target->id];
+
+ tp->nego_goal_width = (width ? 1 : 0);
+ tp->flags |= ESP_TGT_CHECK_NEGO;
+}
+
+static struct spi_function_template esp_transport_ops = {
+ .set_offset = esp_set_offset,
+ .show_offset = 1,
+ .set_period = esp_set_period,
+ .show_period = 1,
+ .set_width = esp_set_width,
+ .show_width = 1,
+ .get_signalling = esp_get_signalling,
+};
+
+static int __init esp_init(void)
+{
+ BUILD_BUG_ON(sizeof(struct scsi_pointer) <
+ sizeof(struct esp_cmd_priv));
+
+ esp_transport_template = spi_attach_transport(&esp_transport_ops);
+ if (!esp_transport_template)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void __exit esp_exit(void)
+{
+ spi_release_transport(esp_transport_template);
+}
+
+MODULE_DESCRIPTION("ESP SCSI driver core");
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_param(esp_bus_reset_settle, int, 0);
+MODULE_PARM_DESC(esp_bus_reset_settle,
+ "ESP scsi bus reset delay in seconds");
+
+module_param(esp_debug, int, 0);
+MODULE_PARM_DESC(esp_debug,
+"ESP bitmapped debugging message enable value:\n"
+" 0x00000001 Log interrupt events\n"
+" 0x00000002 Log scsi commands\n"
+" 0x00000004 Log resets\n"
+" 0x00000008 Log message in events\n"
+" 0x00000010 Log message out events\n"
+" 0x00000020 Log command completion\n"
+" 0x00000040 Log disconnects\n"
+" 0x00000080 Log data start\n"
+" 0x00000100 Log data done\n"
+" 0x00000200 Log reconnects\n"
+" 0x00000400 Log auto-sense data\n"
+);
+
+module_init(esp_init);
+module_exit(esp_exit);
diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
new file mode 100644
index 00000000000..8d4a6690401
--- /dev/null
+++ b/drivers/scsi/esp_scsi.h
@@ -0,0 +1,560 @@
+/* esp_scsi.h: Defines and structures for the ESP drier.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#ifndef _ESP_SCSI_H
+#define _ESP_SCSI_H
+
+ /* Access Description Offset */
+#define ESP_TCLOW 0x00UL /* rw Low bits transfer count 0x00 */
+#define ESP_TCMED 0x01UL /* rw Mid bits transfer count 0x04 */
+#define ESP_FDATA 0x02UL /* rw FIFO data bits 0x08 */
+#define ESP_CMD 0x03UL /* rw SCSI command bits 0x0c */
+#define ESP_STATUS 0x04UL /* ro ESP status register 0x10 */
+#define ESP_BUSID ESP_STATUS /* wo BusID for sel/resel 0x10 */
+#define ESP_INTRPT 0x05UL /* ro Kind of interrupt 0x14 */
+#define ESP_TIMEO ESP_INTRPT /* wo Timeout for sel/resel 0x14 */
+#define ESP_SSTEP 0x06UL /* ro Sequence step register 0x18 */
+#define ESP_STP ESP_SSTEP /* wo Transfer period/sync 0x18 */
+#define ESP_FFLAGS 0x07UL /* ro Bits current FIFO info 0x1c */
+#define ESP_SOFF ESP_FFLAGS /* wo Sync offset 0x1c */
+#define ESP_CFG1 0x08UL /* rw First cfg register 0x20 */
+#define ESP_CFACT 0x09UL /* wo Clock conv factor 0x24 */
+#define ESP_STATUS2 ESP_CFACT /* ro HME status2 register 0x24 */
+#define ESP_CTEST 0x0aUL /* wo Chip test register 0x28 */
+#define ESP_CFG2 0x0bUL /* rw Second cfg register 0x2c */
+#define ESP_CFG3 0x0cUL /* rw Third cfg register 0x30 */
+#define ESP_TCHI 0x0eUL /* rw High bits transf count 0x38 */
+#define ESP_UID ESP_TCHI /* ro Unique ID code 0x38 */
+#define FAS_RLO ESP_TCHI /* rw HME extended counter 0x38 */
+#define ESP_FGRND 0x0fUL /* rw Data base for fifo 0x3c */
+#define FAS_RHI ESP_FGRND /* rw HME extended counter 0x3c */
+
+#define SBUS_ESP_REG_SIZE 0x40UL
+
+/* Bitfield meanings for the above registers. */
+
+/* ESP config reg 1, read-write, found on all ESP chips */
+#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */
+#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */
+#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */
+#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */
+#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */
+#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */
+
+/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */
+#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236) */
+#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236) */
+#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */
+#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tgtmode) */
+#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */
+#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */
+#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236) */
+#define ESP_CONFIG2_DISPINT 0x20 /* Disable pause irq (hme) */
+#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,216) */
+#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (236) */
+#define ESP_CONFIG2_MKDONE 0x40 /* HME magic feature */
+#define ESP_CONFIG2_HME32 0x80 /* HME 32 extended */
+#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */
+
+/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */
+#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/hme) */
+#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236) */
+#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a/hme) */
+#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236) */
+#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a/hme) */
+#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236) */
+#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a/hme) */
+#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236) */
+#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a/hme) */
+#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236) */
+#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236) */
+#define ESP_CONFIG3_IDBIT3 0x20 /* Bit 3 of HME SCSI-ID (hme) */
+#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236) */
+#define ESP_CONFIG3_EWIDE 0x40 /* Enable Wide-SCSI (hme) */
+#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */
+#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */
+
+/* ESP command register read-write */
+/* Group 1 commands: These may be sent at any point in time to the ESP
+ * chip. None of them can generate interrupts 'cept
+ * the "SCSI bus reset" command if you have not disabled
+ * SCSI reset interrupts in the config1 ESP register.
+ */
+#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */
+#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */
+#define ESP_CMD_RC 0x02 /* Chip reset */
+#define ESP_CMD_RS 0x03 /* SCSI bus reset */
+
+/* Group 2 commands: ESP must be an initiator and connected to a target
+ * for these commands to work.
+ */
+#define ESP_CMD_TI 0x10 /* Transfer Information */
+#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */
+#define ESP_CMD_MOK 0x12 /* Message okie-dokie */
+#define ESP_CMD_TPAD 0x18 /* Transfer Pad */
+#define ESP_CMD_SATN 0x1a /* Set ATN */
+#define ESP_CMD_RATN 0x1b /* De-assert ATN */
+
+/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected
+ * to a target as the initiator for these commands to work.
+ */
+#define ESP_CMD_SMSG 0x20 /* Send message */
+#define ESP_CMD_SSTAT 0x21 /* Send status */
+#define ESP_CMD_SDATA 0x22 /* Send data */
+#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */
+#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */
+#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */
+#define ESP_CMD_DCNCT 0x27 /* Disconnect */
+#define ESP_CMD_RMSG 0x28 /* Receive Message */
+#define ESP_CMD_RCMD 0x29 /* Receive Command */
+#define ESP_CMD_RDATA 0x2a /* Receive Data */
+#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */
+
+/* Group 4 commands: The ESP must be in the disconnected state and must
+ * not be connected to any targets as initiator for
+ * these commands to work.
+ */
+#define ESP_CMD_RSEL 0x40 /* Reselect */
+#define ESP_CMD_SEL 0x41 /* Select w/o ATN */
+#define ESP_CMD_SELA 0x42 /* Select w/ATN */
+#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */
+#define ESP_CMD_ESEL 0x44 /* Enable selection */
+#define ESP_CMD_DSEL 0x45 /* Disable selections */
+#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */
+#define ESP_CMD_RSEL3 0x47 /* Reselect3 */
+
+/* This bit enables the ESP's DMA on the SBus */
+#define ESP_CMD_DMA 0x80 /* Do DMA? */
+
+/* ESP status register read-only */
+#define ESP_STAT_PIO 0x01 /* IO phase bit */
+#define ESP_STAT_PCD 0x02 /* CD phase bit */
+#define ESP_STAT_PMSG 0x04 /* MSG phase bit */
+#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */
+#define ESP_STAT_TDONE 0x08 /* Transfer Completed */
+#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */
+#define ESP_STAT_PERR 0x20 /* Parity error */
+#define ESP_STAT_SPAM 0x40 /* Real bad error */
+/* This indicates the 'interrupt pending' condition on esp236, it is a reserved
+ * bit on other revs of the ESP.
+ */
+#define ESP_STAT_INTR 0x80 /* Interrupt */
+
+/* The status register can be masked with ESP_STAT_PMASK and compared
+ * with the following values to determine the current phase the ESP
+ * (at least thinks it) is in. For our purposes we also add our own
+ * software 'done' bit for our phase management engine.
+ */
+#define ESP_DOP (0) /* Data Out */
+#define ESP_DIP (ESP_STAT_PIO) /* Data In */
+#define ESP_CMDP (ESP_STAT_PCD) /* Command */
+#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */
+#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */
+#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */
+
+/* HME only: status 2 register */
+#define ESP_STAT2_SCHBIT 0x01 /* Upper bits 3-7 of sstep enabled */
+#define ESP_STAT2_FFLAGS 0x02 /* The fifo flags are now latched */
+#define ESP_STAT2_XCNT 0x04 /* The transfer counter is latched */
+#define ESP_STAT2_CREGA 0x08 /* The command reg is active now */
+#define ESP_STAT2_WIDE 0x10 /* Interface on this adapter is wide */
+#define ESP_STAT2_F1BYTE 0x20 /* There is one byte at top of fifo */
+#define ESP_STAT2_FMSB 0x40 /* Next byte in fifo is most significant */
+#define ESP_STAT2_FEMPTY 0x80 /* FIFO is empty */
+
+/* ESP interrupt register read-only */
+#define ESP_INTR_S 0x01 /* Select w/o ATN */
+#define ESP_INTR_SATN 0x02 /* Select w/ATN */
+#define ESP_INTR_RSEL 0x04 /* Reselected */
+#define ESP_INTR_FDONE 0x08 /* Function done */
+#define ESP_INTR_BSERV 0x10 /* Bus service */
+#define ESP_INTR_DC 0x20 /* Disconnect */
+#define ESP_INTR_IC 0x40 /* Illegal command given */
+#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */
+
+/* ESP sequence step register read-only */
+#define ESP_STEP_VBITS 0x07 /* Valid bits */
+#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */
+#define ESP_STEP_SID 0x01 /* One msg byte sent */
+#define ESP_STEP_NCMD 0x02 /* Was not in command phase */
+#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd
+ * bytes to be lost
+ */
+#define ESP_STEP_FINI4 0x04 /* Command was sent ok */
+
+/* Ho hum, some ESP's set the step register to this as well... */
+#define ESP_STEP_FINI5 0x05
+#define ESP_STEP_FINI6 0x06
+#define ESP_STEP_FINI7 0x07
+
+/* ESP chip-test register read-write */
+#define ESP_TEST_TARG 0x01 /* Target test mode */
+#define ESP_TEST_INI 0x02 /* Initiator test mode */
+#define ESP_TEST_TS 0x04 /* Tristate test mode */
+
+/* ESP unique ID register read-only, found on fas236+fas100a only */
+#define ESP_UID_F100A 0x00 /* ESP FAS100A */
+#define ESP_UID_F236 0x02 /* ESP FAS236 */
+#define ESP_UID_REV 0x07 /* ESP revision */
+#define ESP_UID_FAM 0xf8 /* ESP family */
+
+/* ESP fifo flags register read-only */
+/* Note that the following implies a 16 byte FIFO on the ESP. */
+#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */
+#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100) */
+#define ESP_FF_SSTEP 0xe0 /* Sequence step */
+
+/* ESP clock conversion factor register write-only */
+#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */
+#define ESP_CCF_NEVER 0x01 /* Set it to this and die */
+#define ESP_CCF_F2 0x02 /* 10MHz */
+#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */
+#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */
+#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */
+#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */
+#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */
+
+/* HME only... */
+#define ESP_BUSID_RESELID 0x10
+#define ESP_BUSID_CTR32BIT 0x40
+
+#define ESP_BUS_TIMEOUT 250 /* In milli-seconds */
+#define ESP_TIMEO_CONST 8192
+#define ESP_NEG_DEFP(mhz, cfact) \
+ ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
+#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
+#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
+
+/* For slow to medium speed input clock rates we shoot for 5mb/s, but for high
+ * input clock rates we try to do 10mb/s although I don't think a transfer can
+ * even run that fast with an ESP even with DMA2 scatter gather pipelining.
+ */
+#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */
+#define SYNC_DEFP_FAST 0x19 /* 10mb/s */
+
+struct esp_cmd_priv {
+ union {
+ dma_addr_t dma_addr;
+ int num_sg;
+ } u;
+
+ unsigned int cur_residue;
+ struct scatterlist *cur_sg;
+ unsigned int tot_residue;
+};
+#define ESP_CMD_PRIV(CMD) ((struct esp_cmd_priv *)(&(CMD)->SCp))
+
+enum esp_rev {
+ ESP100 = 0x00, /* NCR53C90 - very broken */
+ ESP100A = 0x01, /* NCR53C90A */
+ ESP236 = 0x02,
+ FAS236 = 0x03,
+ FAS100A = 0x04,
+ FAST = 0x05,
+ FASHME = 0x06,
+};
+
+struct esp_cmd_entry {
+ struct list_head list;
+
+ struct scsi_cmnd *cmd;
+
+ unsigned int saved_cur_residue;
+ struct scatterlist *saved_cur_sg;
+ unsigned int saved_tot_residue;
+
+ u8 flags;
+#define ESP_CMD_FLAG_WRITE 0x01 /* DMA is a write */
+#define ESP_CMD_FLAG_ABORT 0x02 /* being aborted */
+#define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */
+
+ u8 tag[2];
+
+ u8 status;
+ u8 message;
+
+ unsigned char *sense_ptr;
+ unsigned char *saved_sense_ptr;
+ dma_addr_t sense_dma;
+
+ struct completion *eh_done;
+};
+
+/* XXX make this configurable somehow XXX */
+#define ESP_DEFAULT_TAGS 16
+
+#define ESP_MAX_TARGET 16
+#define ESP_MAX_LUN 8
+#define ESP_MAX_TAG 256
+
+struct esp_lun_data {
+ struct esp_cmd_entry *non_tagged_cmd;
+ int num_tagged;
+ int hold;
+ struct esp_cmd_entry *tagged_cmds[ESP_MAX_TAG];
+};
+
+struct esp_target_data {
+ /* These are the ESP_STP, ESP_SOFF, and ESP_CFG3 register values which
+ * match the currently negotiated settings for this target. The SCSI
+ * protocol values are maintained in spi_{offset,period,wide}(starget).
+ */
+ u8 esp_period;
+ u8 esp_offset;
+ u8 esp_config3;
+
+ u8 flags;
+#define ESP_TGT_WIDE 0x01
+#define ESP_TGT_DISCONNECT 0x02
+#define ESP_TGT_NEGO_WIDE 0x04
+#define ESP_TGT_NEGO_SYNC 0x08
+#define ESP_TGT_CHECK_NEGO 0x40
+#define ESP_TGT_BROKEN 0x80
+
+ /* When ESP_TGT_CHECK_NEGO is set, on the next scsi command to this
+ * device we will try to negotiate the following parameters.
+ */
+ u8 nego_goal_period;
+ u8 nego_goal_offset;
+ u8 nego_goal_width;
+ u8 nego_goal_tags;
+
+ struct scsi_target *starget;
+};
+
+struct esp_event_ent {
+ u8 type;
+#define ESP_EVENT_TYPE_EVENT 0x01
+#define ESP_EVENT_TYPE_CMD 0x02
+ u8 val;
+
+ u8 sreg;
+ u8 seqreg;
+ u8 sreg2;
+ u8 ireg;
+ u8 select_state;
+ u8 event;
+ u8 __pad;
+};
+
+struct esp;
+struct esp_driver_ops {
+ /* Read and write the ESP 8-bit registers. On some
+ * applications of the ESP chip the registers are at 4-byte
+ * instead of 1-byte intervals.
+ */
+ void (*esp_write8)(struct esp *esp, u8 val, unsigned long reg);
+ u8 (*esp_read8)(struct esp *esp, unsigned long reg);
+
+ /* Map and unmap DMA memory. Eventually the driver will be
+ * converted to the generic DMA API as soon as SBUS is able to
+ * cope with that. At such time we can remove this.
+ */
+ dma_addr_t (*map_single)(struct esp *esp, void *buf,
+ size_t sz, int dir);
+ int (*map_sg)(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir);
+ void (*unmap_single)(struct esp *esp, dma_addr_t addr,
+ size_t sz, int dir);
+ void (*unmap_sg)(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir);
+
+ /* Return non-zero if there is an IRQ pending. Usually this
+ * status bit lives in the DMA controller sitting in front of
+ * the ESP. This has to be accurate or else the ESP interrupt
+ * handler will not run.
+ */
+ int (*irq_pending)(struct esp *esp);
+
+ /* Reset the DMA engine entirely. On return, ESP interrupts
+ * should be enabled. Often the interrupt enabling is
+ * controlled in the DMA engine.
+ */
+ void (*reset_dma)(struct esp *esp);
+
+ /* Drain any pending DMA in the DMA engine after a transfer.
+ * This is for writes to memory.
+ */
+ void (*dma_drain)(struct esp *esp);
+
+ /* Invalidate the DMA engine after a DMA transfer. */
+ void (*dma_invalidate)(struct esp *esp);
+
+ /* Setup an ESP command that will use a DMA transfer.
+ * The 'esp_count' specifies what transfer length should be
+ * programmed into the ESP transfer counter registers, whereas
+ * the 'dma_count' is the length that should be programmed into
+ * the DMA controller. Usually they are the same. If 'write'
+ * is non-zero, this transfer is a write into memory. 'cmd'
+ * holds the ESP command that should be issued by calling
+ * scsi_esp_cmd() at the appropriate time while programming
+ * the DMA hardware.
+ */
+ void (*send_dma_cmd)(struct esp *esp, u32 dma_addr, u32 esp_count,
+ u32 dma_count, int write, u8 cmd);
+
+ /* Return non-zero if the DMA engine is reporting an error
+ * currently.
+ */
+ int (*dma_error)(struct esp *esp);
+};
+
+#define ESP_MAX_MSG_SZ 8
+#define ESP_EVENT_LOG_SZ 32
+
+#define ESP_QUICKIRQ_LIMIT 100
+#define ESP_RESELECT_TAG_LIMIT 2500
+
+struct esp {
+ void __iomem *regs;
+ void __iomem *dma_regs;
+
+ const struct esp_driver_ops *ops;
+
+ struct Scsi_Host *host;
+ void *dev;
+
+ struct esp_cmd_entry *active_cmd;
+
+ struct list_head queued_cmds;
+ struct list_head active_cmds;
+
+ u8 *command_block;
+ dma_addr_t command_block_dma;
+
+ unsigned int data_dma_len;
+
+ /* The following are used to determine the cause of an IRQ. Upon every
+ * IRQ entry we synchronize these with the hardware registers.
+ */
+ u8 sreg;
+ u8 seqreg;
+ u8 sreg2;
+ u8 ireg;
+
+ u32 prev_hme_dmacsr;
+ u8 prev_soff;
+ u8 prev_stp;
+ u8 prev_cfg3;
+ u8 __pad;
+
+ struct list_head esp_cmd_pool;
+
+ struct esp_target_data target[ESP_MAX_TARGET];
+
+ int fifo_cnt;
+ u8 fifo[16];
+
+ struct esp_event_ent esp_event_log[ESP_EVENT_LOG_SZ];
+ int esp_event_cur;
+
+ u8 msg_out[ESP_MAX_MSG_SZ];
+ int msg_out_len;
+
+ u8 msg_in[ESP_MAX_MSG_SZ];
+ int msg_in_len;
+
+ u8 bursts;
+ u8 config1;
+ u8 config2;
+
+ u8 scsi_id;
+ u32 scsi_id_mask;
+
+ enum esp_rev rev;
+
+ u32 flags;
+#define ESP_FLAG_DIFFERENTIAL 0x00000001
+#define ESP_FLAG_RESETTING 0x00000002
+#define ESP_FLAG_DOING_SLOWCMD 0x00000004
+#define ESP_FLAG_WIDE_CAPABLE 0x00000008
+#define ESP_FLAG_QUICKIRQ_CHECK 0x00000010
+
+ u8 select_state;
+#define ESP_SELECT_NONE 0x00 /* Not selecting */
+#define ESP_SELECT_BASIC 0x01 /* Select w/o MSGOUT phase */
+#define ESP_SELECT_MSGOUT 0x02 /* Select with MSGOUT */
+
+ /* When we are not selecting, we are expecting an event. */
+ u8 event;
+#define ESP_EVENT_NONE 0x00
+#define ESP_EVENT_CMD_START 0x01
+#define ESP_EVENT_CMD_DONE 0x02
+#define ESP_EVENT_DATA_IN 0x03
+#define ESP_EVENT_DATA_OUT 0x04
+#define ESP_EVENT_DATA_DONE 0x05
+#define ESP_EVENT_MSGIN 0x06
+#define ESP_EVENT_MSGIN_MORE 0x07
+#define ESP_EVENT_MSGIN_DONE 0x08
+#define ESP_EVENT_MSGOUT 0x09
+#define ESP_EVENT_MSGOUT_DONE 0x0a
+#define ESP_EVENT_STATUS 0x0b
+#define ESP_EVENT_FREE_BUS 0x0c
+#define ESP_EVENT_CHECK_PHASE 0x0d
+#define ESP_EVENT_RESET 0x10
+
+ /* Probed in esp_get_clock_params() */
+ u32 cfact;
+ u32 cfreq;
+ u32 ccycle;
+ u32 ctick;
+ u32 neg_defp;
+ u32 sync_defp;
+
+ /* Computed in esp_reset_esp() */
+ u32 max_period;
+ u32 min_period;
+ u32 radelay;
+
+ /* Slow command state. */
+ u8 *cmd_bytes_ptr;
+ int cmd_bytes_left;
+
+ struct completion *eh_reset;
+
+ struct sbus_dma *dma;
+};
+
+#define host_to_esp(host) ((struct esp *)(host)->hostdata)
+
+/* A front-end driver for the ESP chip should do the following in
+ * it's device probe routine:
+ * 1) Allocate the host and private area using scsi_host_alloc()
+ * with size 'sizeof(struct esp)'. The first argument to
+ * scsi_host_alloc() should be &scsi_esp_template.
+ * 2) Set host->max_id as appropriate.
+ * 3) Set esp->host to the scsi_host itself, and esp->dev
+ * to the device object pointer.
+ * 4) Hook up esp->ops to the front-end implementation.
+ * 5) If the ESP chip supports wide transfers, set ESP_FLAG_WIDE_CAPABLE
+ * in esp->flags.
+ * 6) Map the DMA and ESP chip registers.
+ * 7) DMA map the ESP command block, store the DMA address
+ * in esp->command_block_dma.
+ * 8) Register the scsi_esp_intr() interrupt handler.
+ * 9) Probe for and provide the following chip properties:
+ * esp->scsi_id (assign to esp->host->this_id too)
+ * esp->scsi_id_mask
+ * If ESP bus is differential, set ESP_FLAG_DIFFERENTIAL
+ * esp->cfreq
+ * DMA burst bit mask in esp->bursts, if necessary
+ * 10) Perform any actions necessary before the ESP device can
+ * be programmed for the first time. On some configs, for
+ * example, the DMA engine has to be reset before ESP can
+ * be programmed.
+ * 11) If necessary, call dev_set_drvdata() as needed.
+ * 12) Call scsi_esp_register() with prepared 'esp' structure
+ * and a device pointer if possible.
+ * 13) Check scsi_esp_register() return value, release all resources
+ * if an error was returned.
+ */
+extern struct scsi_host_template scsi_esp_template;
+extern int scsi_esp_register(struct esp *, struct device *);
+
+extern void scsi_esp_unregister(struct esp *);
+extern irqreturn_t scsi_esp_intr(int, void *);
+extern void scsi_esp_cmd(struct esp *, u8);
+
+#endif /* !(_ESP_SCSI_H) */
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 9f10689905a..c4195ea869e 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -1403,7 +1403,7 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi
struct scsi_host_template *tpnt = match->data;
struct Scsi_Host *host;
struct qlogicpti *qpti;
- char *fcode;
+ const char *fcode;
/* Sometimes Antares cards come up not completely
* setup, and we get a report of a zero IRQ.
diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c
new file mode 100644
index 00000000000..8c766bcd109
--- /dev/null
+++ b/drivers/scsi/sun_esp.c
@@ -0,0 +1,634 @@
+/* sun_esp.c: ESP front-end for Sparc SBUS systems.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <asm/sbus.h>
+
+#include <scsi/scsi_host.h>
+
+#include "esp_scsi.h"
+
+#define DRV_MODULE_NAME "sun_esp"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_VERSION "1.000"
+#define DRV_MODULE_RELDATE "April 19, 2007"
+
+#define dma_read32(REG) \
+ sbus_readl(esp->dma_regs + (REG))
+#define dma_write32(VAL, REG) \
+ sbus_writel((VAL), esp->dma_regs + (REG))
+
+static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sdev)
+{
+ struct sbus_dev *sdev = esp->dev;
+ struct sbus_dma *dma;
+
+ if (dma_sdev != NULL) {
+ for_each_dvma(dma) {
+ if (dma->sdev == dma_sdev)
+ break;
+ }
+ } else {
+ for_each_dvma(dma) {
+ if (dma->sdev == NULL)
+ break;
+
+ /* If bus + slot are the same and it has the
+ * correct OBP name, it's ours.
+ */
+ if (sdev->bus == dma->sdev->bus &&
+ sdev->slot == dma->sdev->slot &&
+ (!strcmp(dma->sdev->prom_name, "dma") ||
+ !strcmp(dma->sdev->prom_name, "espdma")))
+ break;
+ }
+ }
+
+ if (dma == NULL) {
+ printk(KERN_ERR PFX "[%s] Cannot find dma.\n",
+ sdev->ofdev.node->full_name);
+ return -ENODEV;
+ }
+ esp->dma = dma;
+ esp->dma_regs = dma->regs;
+
+ return 0;
+
+}
+
+static int __devinit esp_sbus_map_regs(struct esp *esp, int hme)
+{
+ struct sbus_dev *sdev = esp->dev;
+ struct resource *res;
+
+ /* On HME, two reg sets exist, first is DVMA,
+ * second is ESP registers.
+ */
+ if (hme)
+ res = &sdev->resource[1];
+ else
+ res = &sdev->resource[0];
+
+ esp->regs = sbus_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");
+ if (!esp->regs)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int __devinit esp_sbus_map_command_block(struct esp *esp)
+{
+ struct sbus_dev *sdev = esp->dev;
+
+ esp->command_block = sbus_alloc_consistent(sdev, 16,
+ &esp->command_block_dma);
+ if (!esp->command_block)
+ return -ENOMEM;
+ return 0;
+}
+
+static int __devinit esp_sbus_register_irq(struct esp *esp)
+{
+ struct Scsi_Host *host = esp->host;
+ struct sbus_dev *sdev = esp->dev;
+
+ host->irq = sdev->irqs[0];
+ return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);
+}
+
+static void __devinit esp_get_scsi_id(struct esp *esp)
+{
+ struct sbus_dev *sdev = esp->dev;
+ struct device_node *dp = sdev->ofdev.node;
+
+ esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff);
+ if (esp->scsi_id != 0xff)
+ goto done;
+
+ esp->scsi_id = of_getintprop_default(dp, "scsi-initiator-id", 0xff);
+ if (esp->scsi_id != 0xff)
+ goto done;
+
+ if (!sdev->bus) {
+ /* SUN4 */
+ esp->scsi_id = 7;
+ goto done;
+ }
+
+ esp->scsi_id = of_getintprop_default(sdev->bus->ofdev.node,
+ "scsi-initiator-id", 7);
+
+done:
+ esp->host->this_id = esp->scsi_id;
+ esp->scsi_id_mask = (1 << esp->scsi_id);
+}
+
+static void __devinit esp_get_differential(struct esp *esp)
+{
+ struct sbus_dev *sdev = esp->dev;
+ struct device_node *dp = sdev->ofdev.node;
+
+ if (of_find_property(dp, "differential", NULL))
+ esp->flags |= ESP_FLAG_DIFFERENTIAL;
+ else
+ esp->flags &= ~ESP_FLAG_DIFFERENTIAL;
+}
+
+static void __devinit esp_get_clock_params(struct esp *esp)
+{
+ struct sbus_dev *sdev = esp->dev;
+ struct device_node *dp = sdev->ofdev.node;
+ struct device_node *bus_dp;
+ int fmhz;
+
+ bus_dp = NULL;
+ if (sdev != NULL && sdev->bus != NULL)
+ bus_dp = sdev->bus->ofdev.node;
+
+ fmhz = of_getintprop_default(dp, "clock-frequency", 0);
+ if (fmhz == 0)
+ fmhz = (!bus_dp) ? 0 :
+ of_getintprop_default(bus_dp, "clock-frequency", 0);
+
+ esp->cfreq = fmhz;
+}
+
+static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
+{
+ struct sbus_dev *sdev = esp->dev;
+ struct device_node *dp = sdev->ofdev.node;
+ u8 bursts;
+
+ bursts = of_getintprop_default(dp, "burst-sizes", 0xff);
+ if (dma) {
+ struct device_node *dma_dp = dma->ofdev.node;
+ u8 val = of_getintprop_default(dma_dp, "burst-sizes", 0xff);
+ if (val != 0xff)
+ bursts &= val;
+ }
+
+ if (sdev->bus) {
+ u8 val = of_getintprop_default(sdev->bus->ofdev.node,
+ "burst-sizes", 0xff);
+ if (val != 0xff)
+ bursts &= val;
+ }
+
+ if (bursts == 0xff ||
+ (bursts & DMA_BURST16) == 0 ||
+ (bursts & DMA_BURST32) == 0)
+ bursts = (DMA_BURST32 - 1);
+
+ esp->bursts = bursts;
+}
+
+static void __devinit esp_sbus_get_props(struct esp *esp, struct sbus_dev *espdma)
+{
+ esp_get_scsi_id(esp);
+ esp_get_differential(esp);
+ esp_get_clock_params(esp);
+ esp_get_bursts(esp, espdma);
+}
+
+static void sbus_esp_write8(struct esp *esp, u8 val, unsigned long reg)
+{
+ sbus_writeb(val, esp->regs + (reg * 4UL));
+}
+
+static u8 sbus_esp_read8(struct esp *esp, unsigned long reg)
+{
+ return sbus_readb(esp->regs + (reg * 4UL));
+}
+
+static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf,
+ size_t sz, int dir)
+{
+ return sbus_map_single(esp->dev, buf, sz, dir);
+}
+
+static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir)
+{
+ return sbus_map_sg(esp->dev, sg, num_sg, dir);
+}
+
+static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr,
+ size_t sz, int dir)
+{
+ sbus_unmap_single(esp->dev, addr, sz, dir);
+}
+
+static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir)
+{
+ sbus_unmap_sg(esp->dev, sg, num_sg, dir);
+}
+
+static int sbus_esp_irq_pending(struct esp *esp)
+{
+ if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
+ return 1;
+ return 0;
+}
+
+static void sbus_esp_reset_dma(struct esp *esp)
+{
+ int can_do_burst16, can_do_burst32, can_do_burst64;
+ int can_do_sbus64, lim;
+ u32 val;
+
+ can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
+ can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;
+ can_do_burst64 = 0;
+ can_do_sbus64 = 0;
+ if (sbus_can_dma_64bit(esp->dev))
+ can_do_sbus64 = 1;
+ if (sbus_can_burst64(esp->sdev))
+ can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;
+
+ /* Put the DVMA into a known state. */
+ if (esp->dma->revision != dvmahme) {
+ val = dma_read32(DMA_CSR);
+ dma_write32(val | DMA_RST_SCSI, DMA_CSR);
+ dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
+ }
+ switch (esp->dma->revision) {
+ case dvmahme:
+ dma_write32(DMA_RESET_FAS366, DMA_CSR);
+ dma_write32(DMA_RST_SCSI, DMA_CSR);
+
+ esp->prev_hme_dmacsr = (DMA_PARITY_OFF | DMA_2CLKS |
+ DMA_SCSI_DISAB | DMA_INT_ENAB);
+
+ esp->prev_hme_dmacsr &= ~(DMA_ENABLE | DMA_ST_WRITE |
+ DMA_BRST_SZ);
+
+ if (can_do_burst64)
+ esp->prev_hme_dmacsr |= DMA_BRST64;
+ else if (can_do_burst32)
+ esp->prev_hme_dmacsr |= DMA_BRST32;
+
+ if (can_do_sbus64) {
+ esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
+ sbus_set_sbus64(esp->dev, esp->bursts);
+ }
+
+ lim = 1000;
+ while (dma_read32(DMA_CSR) & DMA_PEND_READ) {
+ if (--lim == 0) {
+ printk(KERN_ALERT PFX "esp%d: DMA_PEND_READ "
+ "will not clear!\n",
+ esp->host->unique_id);
+ break;
+ }
+ udelay(1);
+ }
+
+ dma_write32(0, DMA_CSR);
+ dma_write32(esp->prev_hme_dmacsr, DMA_CSR);
+
+ dma_write32(0, DMA_ADDR);
+ break;
+
+ case dvmarev2:
+ if (esp->rev != ESP100) {
+ val = dma_read32(DMA_CSR);
+ dma_write32(val | DMA_3CLKS, DMA_CSR);
+ }
+ break;
+
+ case dvmarev3:
+ val = dma_read32(DMA_CSR);
+ val &= ~DMA_3CLKS;
+ val |= DMA_2CLKS;
+ if (can_do_burst32) {
+ val &= ~DMA_BRST_SZ;
+ val |= DMA_BRST32;
+ }
+ dma_write32(val, DMA_CSR);
+ break;
+
+ case dvmaesc1:
+ val = dma_read32(DMA_CSR);
+ val |= DMA_ADD_ENABLE;
+ val &= ~DMA_BCNT_ENAB;
+ if (!can_do_burst32 && can_do_burst16) {
+ val |= DMA_ESC_BURST;
+ } else {
+ val &= ~(DMA_ESC_BURST);
+ }
+ dma_write32(val, DMA_CSR);
+ break;
+
+ default:
+ break;
+ }
+
+ /* Enable interrupts. */
+ val = dma_read32(DMA_CSR);
+ dma_write32(val | DMA_INT_ENAB, DMA_CSR);
+}
+
+static void sbus_esp_dma_drain(struct esp *esp)
+{
+ u32 csr;
+ int lim;
+
+ if (esp->dma->revision == dvmahme)
+ return;
+
+ csr = dma_read32(DMA_CSR);
+ if (!(csr & DMA_FIFO_ISDRAIN))
+ return;
+
+ if (esp->dma->revision != dvmarev3 && esp->dma->revision != dvmaesc1)
+ dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);
+
+ lim = 1000;
+ while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) {
+ if (--lim == 0) {
+ printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n",
+ esp->host->unique_id);
+ break;
+ }
+ udelay(1);
+ }
+}
+
+static void sbus_esp_dma_invalidate(struct esp *esp)
+{
+ if (esp->dma->revision == dvmahme) {
+ dma_write32(DMA_RST_SCSI, DMA_CSR);
+
+ esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
+ (DMA_PARITY_OFF | DMA_2CLKS |
+ DMA_SCSI_DISAB | DMA_INT_ENAB)) &
+ ~(DMA_ST_WRITE | DMA_ENABLE));
+
+ dma_write32(0, DMA_CSR);
+ dma_write32(esp->prev_hme_dmacsr, DMA_CSR);
+
+ /* This is necessary to avoid having the SCSI channel
+ * engine lock up on us.
+ */
+ dma_write32(0, DMA_ADDR);
+ } else {
+ u32 val;
+ int lim;
+
+ lim = 1000;
+ while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) {
+ if (--lim == 0) {
+ printk(KERN_ALERT PFX "esp%d: DMA will not "
+ "invalidate!\n", esp->host->unique_id);
+ break;
+ }
+ udelay(1);
+ }
+
+ val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);
+ val |= DMA_FIFO_INV;
+ dma_write32(val, DMA_CSR);
+ val &= ~DMA_FIFO_INV;
+ dma_write32(val, DMA_CSR);
+ }
+}
+
+static void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
+ u32 dma_count, int write, u8 cmd)
+{
+ u32 csr;
+
+ BUG_ON(!(cmd & ESP_CMD_DMA));
+
+ sbus_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
+ sbus_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
+ if (esp->rev == FASHME) {
+ sbus_esp_write8(esp, (esp_count >> 16) & 0xff, FAS_RLO);
+ sbus_esp_write8(esp, 0, FAS_RHI);
+
+ scsi_esp_cmd(esp, cmd);
+
+ csr = esp->prev_hme_dmacsr;
+ csr |= DMA_SCSI_DISAB | DMA_ENABLE;
+ if (write)
+ csr |= DMA_ST_WRITE;
+ else
+ csr &= ~DMA_ST_WRITE;
+ esp->prev_hme_dmacsr = csr;
+
+ dma_write32(dma_count, DMA_COUNT);
+ dma_write32(addr, DMA_ADDR);
+ dma_write32(csr, DMA_CSR);
+ } else {
+ csr = dma_read32(DMA_CSR);
+ csr |= DMA_ENABLE;
+ if (write)
+ csr |= DMA_ST_WRITE;
+ else
+ csr &= ~DMA_ST_WRITE;
+ dma_write32(csr, DMA_CSR);
+ if (esp->dma->revision == dvmaesc1) {
+ u32 end = PAGE_ALIGN(addr + dma_count + 16U);
+ dma_write32(end - addr, DMA_COUNT);
+ }
+ dma_write32(addr, DMA_ADDR);
+
+ scsi_esp_cmd(esp, cmd);
+ }
+
+}
+
+static int sbus_esp_dma_error(struct esp *esp)
+{
+ u32 csr = dma_read32(DMA_CSR);
+
+ if (csr & DMA_HNDL_ERROR)
+ return 1;
+
+ return 0;
+}
+
+static const struct esp_driver_ops sbus_esp_ops = {
+ .esp_write8 = sbus_esp_write8,
+ .esp_read8 = sbus_esp_read8,
+ .map_single = sbus_esp_map_single,
+ .map_sg = sbus_esp_map_sg,
+ .unmap_single = sbus_esp_unmap_single,
+ .unmap_sg = sbus_esp_unmap_sg,
+ .irq_pending = sbus_esp_irq_pending,
+ .reset_dma = sbus_esp_reset_dma,
+ .dma_drain = sbus_esp_dma_drain,
+ .dma_invalidate = sbus_esp_dma_invalidate,
+ .send_dma_cmd = sbus_esp_send_dma_cmd,
+ .dma_error = sbus_esp_dma_error,
+};
+
+static int __devinit esp_sbus_probe_one(struct device *dev,
+ struct sbus_dev *esp_dev,
+ struct sbus_dev *espdma,
+ struct sbus_bus *sbus,
+ int hme)
+{
+ struct scsi_host_template *tpnt = &scsi_esp_template;
+ struct Scsi_Host *host;
+ struct esp *esp;
+ int err;
+
+ host = scsi_host_alloc(tpnt, sizeof(struct esp));
+
+ err = -ENOMEM;
+ if (!host)
+ goto fail;
+
+ host->max_id = (hme ? 16 : 8);
+ esp = host_to_esp(host);
+
+ esp->host = host;
+ esp->dev = esp_dev;
+ esp->ops = &sbus_esp_ops;
+
+ if (hme)
+ esp->flags |= ESP_FLAG_WIDE_CAPABLE;
+
+ err = esp_sbus_find_dma(esp, espdma);
+ if (err < 0)
+ goto fail_unlink;
+
+ err = esp_sbus_map_regs(esp, hme);
+ if (err < 0)
+ goto fail_unlink;
+
+ err = esp_sbus_map_command_block(esp);
+ if (err < 0)
+ goto fail_unmap_regs;
+
+ err = esp_sbus_register_irq(esp);
+ if (err < 0)
+ goto fail_unmap_command_block;
+
+ esp_sbus_get_props(esp, espdma);
+
+ /* Before we try to touch the ESP chip, ESC1 dma can
+ * come up with the reset bit set, so make sure that
+ * is clear first.
+ */
+ if (esp->dma->revision == dvmaesc1) {
+ u32 val = dma_read32(DMA_CSR);
+
+ dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
+ }
+
+ dev_set_drvdata(&esp_dev->ofdev.dev, esp);
+
+ err = scsi_esp_register(esp, dev);
+ if (err)
+ goto fail_free_irq;
+
+ return 0;
+
+fail_free_irq:
+ free_irq(host->irq, esp);
+fail_unmap_command_block:
+ sbus_free_consistent(esp->dev, 16,
+ esp->command_block,
+ esp->command_block_dma);
+fail_unmap_regs:
+ sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+fail_unlink:
+ scsi_host_put(host);
+fail:
+ return err;
+}
+
+static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct device_node *dp = dev->node;
+ struct sbus_dev *dma_sdev = NULL;
+ int hme = 0;
+
+ if (dp->parent &&
+ (!strcmp(dp->parent->name, "espdma") ||
+ !strcmp(dp->parent->name, "dma")))
+ dma_sdev = sdev->parent;
+ else if (!strcmp(dp->name, "SUNW,fas")) {
+ dma_sdev = sdev;
+ hme = 1;
+ }
+
+ return esp_sbus_probe_one(&dev->dev, sdev, dma_sdev,
+ sdev->bus, hme);
+}
+
+static int __devexit esp_sbus_remove(struct of_device *dev)
+{
+ struct esp *esp = dev_get_drvdata(&dev->dev);
+ unsigned int irq = esp->host->irq;
+ u32 val;
+
+ scsi_esp_unregister(esp);
+
+ /* Disable interrupts. */
+ val = dma_read32(DMA_CSR);
+ dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);
+
+ free_irq(irq, esp);
+ sbus_free_consistent(esp->dev, 16,
+ esp->command_block,
+ esp->command_block_dma);
+ sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+
+ scsi_host_put(esp->host);
+
+ return 0;
+}
+
+static struct of_device_id esp_match[] = {
+ {
+ .name = "SUNW,esp",
+ },
+ {
+ .name = "SUNW,fas",
+ },
+ {
+ .name = "esp",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, esp_match);
+
+static struct of_platform_driver esp_sbus_driver = {
+ .name = "esp",
+ .match_table = esp_match,
+ .probe = esp_sbus_probe,
+ .remove = __devexit_p(esp_sbus_remove),
+};
+
+static int __init sunesp_init(void)
+{
+ return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit sunesp_exit(void)
+{
+ of_unregister_driver(&esp_sbus_driver);
+}
+
+MODULE_DESCRIPTION("Sun ESP SCSI driver");
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(sunesp_init);
+module_exit(sunesp_exit);
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 96a852aa190..bfd44177a21 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1387,8 +1387,8 @@ static enum su_type __devinit su_get_type(struct device_node *dp)
struct device_node *ap = of_find_node_by_path("/aliases");
if (ap) {
- char *keyb = of_get_property(ap, "keyboard", NULL);
- char *ms = of_get_property(ap, "mouse", NULL);
+ const char *keyb = of_get_property(ap, "keyboard", NULL);
+ const char *ms = of_get_property(ap, "mouse", NULL);
if (keyb) {
if (dp == of_find_node_by_path(keyb))
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index d7627fc4f11..8514f2a6f06 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2899,7 +2899,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
struct fb_info *info, unsigned long addr)
{
struct atyfb_par *par = info->par;
- struct pcidev_cookie *pcp;
+ struct device_node *dp;
char prop[128];
int node, len, i, j, ret;
u32 mem, chip_id;
@@ -3037,8 +3037,8 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
node = 0;
}
- pcp = pdev->sysdata;
- if (node == pcp->prom_node->node) {
+ dp = pci_device_to_OF_node(pdev);
+ if (node == dp->node) {
struct fb_var_screeninfo *var = &default_var;
unsigned int N, P, Q, M, T, R;
u32 v_total, h_total;
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 1bf6f42eb40..a4b3fd185de 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -410,7 +410,7 @@ static int __devinit radeon_find_mem_vbios(struct radeonfb_info *rinfo)
}
#endif
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
/*
* Read XTAL (ref clock), SCLK and MCLK from Open Firmware device
* tree. Hopefully, ATI OF driver is kind enough to fill these
@@ -440,7 +440,7 @@ static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
return 0;
}
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
/*
* Read PLL infos from chip registers
@@ -645,7 +645,7 @@ static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo)
rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
/*
* Retrieve PLL infos from Open Firmware first
*/
@@ -653,7 +653,7 @@ static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo)
printk(KERN_INFO "radeonfb: Retrieved PLL infos from Open Firmware\n");
goto found;
}
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
/*
* Check out if we have an X86 which gave us some PLL informations
@@ -2231,7 +2231,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
rinfo->family == CHIP_FAMILY_RS200)
rinfo->errata |= CHIP_ERRATA_PLL_DELAY;
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
/* On PPC, we obtain the OF device-node pointer to the firmware
* data for this chip
*/
@@ -2240,6 +2240,8 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
printk(KERN_WARNING "radeonfb (%s): Cannot match card to OF node !\n",
pci_name(rinfo->pdev));
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
+#ifdef CONFIG_PPC_OF
/* On PPC, the firmware sets up a memory mapping that tends
* to cause lockups when enabling the engine. We reconfigure
* the card internal memory mappings properly
diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
index 38c7dbf8c15..737b5c09dbd 100644
--- a/drivers/video/aty/radeon_monitor.c
+++ b/drivers/video/aty/radeon_monitor.c
@@ -52,7 +52,7 @@ static char *radeon_get_mon_name(int type)
}
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
/*
* Try to find monitor informations & EDID data out of the Open Firmware
* device-tree. This also contains some "hacks" to work around a few machine
@@ -156,7 +156,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_
}
return MT_NONE;
}
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
@@ -495,11 +495,11 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
* Old single head cards
*/
if (!rinfo->has_CRTC2) {
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
if (rinfo->mon1_type == MT_NONE)
rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0,
&rinfo->mon1_EDID);
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
#ifdef CONFIG_FB_RADEON_I2C
if (rinfo->mon1_type == MT_NONE)
rinfo->mon1_type =
@@ -544,11 +544,11 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
/*
* Probe primary head (DVI or laptop internal panel)
*/
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
if (rinfo->mon1_type == MT_NONE)
rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0,
&rinfo->mon1_EDID);
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
#ifdef CONFIG_FB_RADEON_I2C
if (rinfo->mon1_type == MT_NONE)
rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_dvi,
@@ -572,11 +572,11 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
/*
* Probe secondary head (mostly VGA, can be DVI)
*/
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
if (rinfo->mon2_type == MT_NONE)
rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1,
&rinfo->mon2_EDID);
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || defined(CONFIG_SPARC) */
#ifdef CONFIG_FB_RADEON_I2C
if (rinfo->mon2_type == MT_NONE)
rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_vga,
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index d5ff224a625..31900036028 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -16,7 +16,7 @@
#include <asm/io.h>
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
#include <asm/prom.h>
#endif
@@ -292,7 +292,7 @@ struct radeonfb_info {
unsigned long fb_local_base;
struct pci_dev *pdev;
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
struct device_node *of_node;
#endif
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index 767c850f8eb..f042428a84f 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -266,7 +266,7 @@ static void __devinit cg3_init_fix(struct fb_info *info, int linebytes,
static void __devinit cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
struct device_node *dp)
{
- char *params;
+ const char *params;
char *p;
int ww, hh;
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index 90592fb5915..eb1a4812ad1 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -44,8 +44,8 @@
#include <asm/io.h>
-#ifdef __sparc__
-#include <asm/pbm.h>
+#ifdef CONFIG_SPARC
+#include <asm/prom.h>
#include <asm/pcic.h>
#endif
@@ -96,7 +96,7 @@ struct fb_var_screeninfo default_var = {
.vmode = FB_VMODE_NONINTERLACED
};
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
struct fb_var_screeninfo default_var_1024x768 __initdata = {
/* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
.xres = 1024,
@@ -188,7 +188,7 @@ static inline void iga_outb(struct iga_par *par, unsigned char val,
pci_outb(par, val, reg+1);
}
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC */
/*
* Very important functionality for the JavaEngine1 computer:
@@ -217,7 +217,7 @@ static void iga_blank_border(struct iga_par *par)
iga_outb(par, 0, IGA_EXT_CNTRL, IGA_IDX_OVERSCAN_COLOR + i);
}
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
static int igafb_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
@@ -271,7 +271,7 @@ static int igafb_mmap(struct fb_info *info,
vma->vm_flags |= VM_IO;
return 0;
}
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC */
static int igafb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
@@ -323,7 +323,7 @@ static struct fb_ops igafb_ops = {
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
.fb_mmap = igafb_mmap,
#endif
};
@@ -424,7 +424,7 @@ int __init igafb_init(void)
par->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK;
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
/*
* The following is sparc specific and this is why:
*
@@ -477,8 +477,8 @@ int __init igafb_init(void)
* Set default vmode and cmode from PROM properties.
*/
{
- struct pcidev_cookie *cookie = pdev->sysdata;
- int node = cookie->prom_node;
+ struct device_node *dp = pci_device_to_OF_node(pdev);
+ int node = dp->node;
int width = prom_getintdefault(node, "width", 1024);
int height = prom_getintdefault(node, "height", 768);
int depth = prom_getintdefault(node, "depth", 8);
@@ -534,7 +534,7 @@ int __init igafb_init(void)
kfree(info);
}
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
/*
* Add /dev/fb mmap values.
*/
@@ -552,7 +552,7 @@ int __init igafb_init(void)
par->mmap_map[1].size = PAGE_SIZE * 2; /* X wants 2 pages */
par->mmap_map[1].prot_mask = SRMMU_CACHE;
par->mmap_map[1].prot_flag = SRMMU_WRITE;
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC */
return 0;
}
diff --git a/include/asm-alpha/string.h b/include/asm-alpha/string.h
index 9e44fea669b..b02b8a28294 100644
--- a/include/asm-alpha/string.h
+++ b/include/asm-alpha/string.h
@@ -61,8 +61,6 @@ extern void * __memsetw(void *dest, unsigned short, size_t count);
? __constant_c_memset((s),0x0001000100010001UL*(unsigned short)(c),(n)) \
: __memsetw((s),(c),(n)))
-extern int strcasecmp(const char *, const char *);
-
#endif /* __KERNEL__ */
#endif /* __ALPHA_STRING_H__ */
diff --git a/include/asm-powerpc/string.h b/include/asm-powerpc/string.h
index faa407f33c6..aa40f92c298 100644
--- a/include/asm-powerpc/string.h
+++ b/include/asm-powerpc/string.h
@@ -14,8 +14,6 @@
#define __HAVE_ARCH_MEMCMP
#define __HAVE_ARCH_MEMCHR
-extern int strcasecmp(const char *, const char *);
-extern int strncasecmp(const char *, const char *, __kernel_size_t);
extern char * strcpy(char *,const char *);
extern char * strncpy(char *,const char *, __kernel_size_t);
extern __kernel_size_t strlen(const char *);
diff --git a/include/asm-sh/string.h b/include/asm-sh/string.h
index 95bc7db006b..55f8db6bc1d 100644
--- a/include/asm-sh/string.h
+++ b/include/asm-sh/string.h
@@ -126,9 +126,6 @@ extern void *memchr(const void *__s, int __c, size_t __n);
#define __HAVE_ARCH_STRLEN
extern size_t strlen(const char *);
-/* arch/sh/lib/strcasecmp.c */
-extern int strcasecmp(const char *, const char *);
-
#endif /* __KERNEL__ */
#endif /* __ASM_SH_STRING_H */
diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h
index 274868d8598..9ea105ebe2f 100644
--- a/include/asm-sparc/prom.h
+++ b/include/asm-sparc/prom.h
@@ -35,8 +35,8 @@ struct property {
};
struct device_node {
- char *name;
- char *type;
+ const char *name;
+ const char *type;
phandle node;
char *path_component_name;
char *full_name;
@@ -85,12 +85,14 @@ extern struct device_node *of_find_node_by_phandle(phandle handle);
extern struct device_node *of_get_parent(const struct device_node *node);
extern struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev);
-extern struct property *of_find_property(struct device_node *np,
+extern struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp);
-extern int of_device_is_compatible(struct device_node *device, const char *);
-extern void *of_get_property(struct device_node *node, const char *name,
- int *lenp);
+extern int of_device_is_compatible(const struct device_node *device,
+ const char *);
+extern const void *of_get_property(const struct device_node *node,
+ const char *name,
+ int *lenp);
#define get_property(node,name,lenp) of_get_property(node,name,lenp)
extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
extern int of_getintprop_default(struct device_node *np,
diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h
index f2cc9411b4c..e89922d6718 100644
--- a/include/asm-sparc64/cpudata.h
+++ b/include/asm-sparc64/cpudata.h
@@ -17,8 +17,8 @@
typedef struct {
/* Dcache line 1 */
unsigned int __softirq_pending; /* must be 1st, see rtrap.S */
- unsigned int multiplier;
- unsigned int counter;
+ unsigned int __pad0_1;
+ unsigned int __pad0_2;
unsigned int __pad1;
unsigned long clock_tick; /* %tick's per second */
unsigned long udelay_val;
diff --git a/include/asm-sparc64/device.h b/include/asm-sparc64/device.h
index d8f9872b0e2..d5a4559b955 100644
--- a/include/asm-sparc64/device.h
+++ b/include/asm-sparc64/device.h
@@ -3,5 +3,21 @@
*
* This file is released under the GPLv2
*/
-#include <asm-generic/device.h>
+#ifndef _ASM_SPARC64_DEVICE_H
+#define _ASM_SPARC64_DEVICE_H
+struct device_node;
+struct of_device;
+
+struct dev_archdata {
+ void *iommu;
+ void *stc;
+ void *host_controller;
+
+ struct device_node *prom_node;
+ struct of_device *op;
+
+ unsigned int msi_num;
+};
+
+#endif /* _ASM_SPARC64_DEVICE_H */
diff --git a/include/asm-sparc64/ebus.h b/include/asm-sparc64/ebus.h
index a4afe9d5703..9c1c6db2a79 100644
--- a/include/asm-sparc64/ebus.h
+++ b/include/asm-sparc64/ebus.h
@@ -8,7 +8,6 @@
#ifndef __SPARC64_EBUS_H
#define __SPARC64_EBUS_H
-#include <asm/pbm.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/of_device.h>
@@ -41,7 +40,6 @@ struct linux_ebus {
struct of_device ofdev;
struct linux_ebus *next;
struct linux_ebus_device *devices;
- struct pci_pbm_info *parent;
struct pci_dev *self;
int index;
int is_rio;
diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h
index 331013a0053..4aa0925e1b1 100644
--- a/include/asm-sparc64/floppy.h
+++ b/include/asm-sparc64/floppy.h
@@ -549,7 +549,7 @@ static int __init ebus_fdthree_p(struct linux_ebus_device *edev)
if (!strcmp(edev->prom_node->name, "fdthree"))
return 1;
if (!strcmp(edev->prom_node->name, "floppy")) {
- char *compat;
+ const char *compat;
compat = of_get_property(edev->prom_node,
"compatible", NULL);
@@ -661,7 +661,7 @@ static unsigned long __init sun_floppy_init(void)
struct linux_ebus_device *edev = NULL;
unsigned long config = 0;
void __iomem *auxio_reg;
- char *state_prop;
+ const char *state_prop;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h
index 30b912d8e8b..ad595b67984 100644
--- a/include/asm-sparc64/io.h
+++ b/include/asm-sparc64/io.h
@@ -24,14 +24,6 @@ extern unsigned long kern_base, kern_size;
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
#define BIO_VMERGE_BOUNDARY 8192
-/* Different PCI controllers we support have their PCI MEM space
- * mapped to an either 2GB (Psycho) or 4GB (Sabre) aligned area,
- * so need to chop off the top 33 or 32 bits.
- */
-extern unsigned long pci_memspace_mask;
-
-#define bus_dvma_to_mem(__vaddr) ((__vaddr) & pci_memspace_mask)
-
static __inline__ u8 _inb(unsigned long addr)
{
u8 ret;
diff --git a/include/asm-sparc64/iommu.h b/include/asm-sparc64/iommu.h
index 0de7a3da79c..e199594a1e9 100644
--- a/include/asm-sparc64/iommu.h
+++ b/include/asm-sparc64/iommu.h
@@ -7,15 +7,50 @@
#define _SPARC64_IOMMU_H
/* The format of an iopte in the page tables. */
-#define IOPTE_VALID 0x8000000000000000UL /* IOPTE is valid */
-#define IOPTE_64K 0x2000000000000000UL /* IOPTE is for 64k page */
-#define IOPTE_STBUF 0x1000000000000000UL /* DVMA can use streaming buffer */
-#define IOPTE_INTRA 0x0800000000000000UL /* SBUS slot-->slot direct transfer*/
-#define IOPTE_CONTEXT 0x07ff800000000000UL /* Context number */
-#define IOPTE_PAGE 0x00007fffffffe000UL /* Physical page number (PA[42:13])*/
-#define IOPTE_CACHE 0x0000000000000010UL /* Cached (in UPA E-cache) */
-#define IOPTE_WRITE 0x0000000000000002UL /* Writeable */
+#define IOPTE_VALID 0x8000000000000000UL
+#define IOPTE_64K 0x2000000000000000UL
+#define IOPTE_STBUF 0x1000000000000000UL
+#define IOPTE_INTRA 0x0800000000000000UL
+#define IOPTE_CONTEXT 0x07ff800000000000UL
+#define IOPTE_PAGE 0x00007fffffffe000UL
+#define IOPTE_CACHE 0x0000000000000010UL
+#define IOPTE_WRITE 0x0000000000000002UL
#define IOMMU_NUM_CTXS 4096
+struct iommu_arena {
+ unsigned long *map;
+ unsigned int hint;
+ unsigned int limit;
+};
+
+struct iommu {
+ spinlock_t lock;
+ struct iommu_arena arena;
+ iopte_t *page_table;
+ u32 page_table_map_base;
+ unsigned long iommu_control;
+ unsigned long iommu_tsbbase;
+ unsigned long iommu_flush;
+ unsigned long iommu_ctxflush;
+ unsigned long write_complete_reg;
+ unsigned long dummy_page;
+ unsigned long dummy_page_pa;
+ unsigned long ctx_lowest_free;
+ DECLARE_BITMAP(ctx_bitmap, IOMMU_NUM_CTXS);
+ u32 dma_addr_mask;
+};
+
+struct strbuf {
+ int strbuf_enabled;
+ unsigned long strbuf_control;
+ unsigned long strbuf_pflush;
+ unsigned long strbuf_fsync;
+ unsigned long strbuf_ctxflush;
+ unsigned long strbuf_ctxmatch_base;
+ unsigned long strbuf_flushflag_pa;
+ volatile unsigned long *strbuf_flushflag;
+ volatile unsigned long __flushflag_buf[(64+(64-1)) / sizeof(long)];
+};
+
#endif /* !(_SPARC_IOMMU_H) */
diff --git a/include/asm-sparc64/isa.h b/include/asm-sparc64/isa.h
index d9728b9031f..ecd9290f78d 100644
--- a/include/asm-sparc64/isa.h
+++ b/include/asm-sparc64/isa.h
@@ -7,7 +7,6 @@
#ifndef __SPARC64_ISA_H
#define __SPARC64_ISA_H
-#include <asm/pbm.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/of_device.h>
@@ -29,7 +28,6 @@ struct sparc_isa_bridge {
struct of_device ofdev;
struct sparc_isa_bridge *next;
struct sparc_isa_device *devices;
- struct pci_pbm_info *parent;
struct pci_dev *self;
int index;
struct device_node *prom_node;
diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h
index 284dfd01a33..6340a5253a3 100644
--- a/include/asm-sparc64/parport.h
+++ b/include/asm-sparc64/parport.h
@@ -103,7 +103,7 @@ static int ebus_ecpp_p(struct linux_ebus_device *edev)
if (!strcmp(edev->prom_node->name, "ecpp"))
return 1;
if (!strcmp(edev->prom_node->name, "parallel")) {
- char *compat;
+ const char *compat;
compat = of_get_property(edev->prom_node,
"compatible", NULL);
diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h
index 7a246d8a182..c008cecca14 100644
--- a/include/asm-sparc64/pbm.h
+++ b/include/asm-sparc64/pbm.h
@@ -1,7 +1,6 @@
-/* $Id: pbm.h,v 1.27 2001/08/12 13:18:23 davem Exp $
- * pbm.h: UltraSparc PCI controller software state.
+/* pbm.h: UltraSparc PCI controller software state.
*
- * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net)
*/
#ifndef __SPARC64_PBM_H
@@ -30,90 +29,7 @@
* PCI bus.
*/
-struct pci_controller_info;
-
-/* This contains the software state necessary to drive a PCI
- * controller's IOMMU.
- */
-struct pci_iommu_arena {
- unsigned long *map;
- unsigned int hint;
- unsigned int limit;
-};
-
-struct pci_iommu {
- /* This protects the controller's IOMMU and all
- * streaming buffers underneath.
- */
- spinlock_t lock;
-
- struct pci_iommu_arena arena;
-
- /* IOMMU page table, a linear array of ioptes. */
- iopte_t *page_table; /* The page table itself. */
-
- /* Base PCI memory space address where IOMMU mappings
- * begin.
- */
- u32 page_table_map_base;
-
- /* IOMMU Controller Registers */
- unsigned long iommu_control; /* IOMMU control register */
- unsigned long iommu_tsbbase; /* IOMMU page table base register */
- unsigned long iommu_flush; /* IOMMU page flush register */
- unsigned long iommu_ctxflush; /* IOMMU context flush register */
-
- /* This is a register in the PCI controller, which if
- * read will have no side-effects but will guarantee
- * completion of all previous writes into IOMMU/STC.
- */
- unsigned long write_complete_reg;
-
- /* In order to deal with some buggy third-party PCI bridges that
- * do wrong prefetching, we never mark valid mappings as invalid.
- * Instead we point them at this dummy page.
- */
- unsigned long dummy_page;
- unsigned long dummy_page_pa;
-
- /* CTX allocation. */
- unsigned long ctx_lowest_free;
- unsigned long ctx_bitmap[IOMMU_NUM_CTXS / (sizeof(unsigned long) * 8)];
-
- /* Here a PCI controller driver describes the areas of
- * PCI memory space where DMA to/from physical memory
- * are addressed. Drivers interrogate the PCI layer
- * if their device has addressing limitations. They
- * do so via pci_dma_supported, and pass in a mask of
- * DMA address bits their device can actually drive.
- *
- * The test for being usable is:
- * (device_mask & dma_addr_mask) == dma_addr_mask
- */
- u32 dma_addr_mask;
-};
-
-extern void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask);
-
-/* This describes a PCI bus module's streaming buffer. */
-struct pci_strbuf {
- int strbuf_enabled; /* Present and using it? */
-
- /* Streaming Buffer Control Registers */
- unsigned long strbuf_control; /* STC control register */
- unsigned long strbuf_pflush; /* STC page flush register */
- unsigned long strbuf_fsync; /* STC flush synchronization reg */
- unsigned long strbuf_ctxflush; /* STC context flush register */
- unsigned long strbuf_ctxmatch_base; /* STC context flush match reg */
- unsigned long strbuf_flushflag_pa; /* Physical address of flush flag */
- volatile unsigned long *strbuf_flushflag; /* The flush flag itself */
-
- /* And this is the actual flush flag area.
- * We allocate extra because the chips require
- * a 64-byte aligned area.
- */
- volatile unsigned long __flushflag_buf[(64 + (64 - 1)) / sizeof(long)];
-};
+extern void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask);
#define PCI_STC_FLUSHFLAG_INIT(STC) \
(*((STC)->strbuf_flushflag) = 0UL)
@@ -126,6 +42,8 @@ struct pci_strbuf {
#define PROM_PCIRNG_MAX 64
#define PROM_PCIIMAP_MAX 64
+struct pci_controller_info;
+
struct pci_pbm_info {
/* PCI controller we sit under. */
struct pci_controller_info *parent;
@@ -160,11 +78,6 @@ struct pci_pbm_info {
/* OBP specific information. */
struct device_node *prom_node;
- struct linux_prom_pci_ranges *pbm_ranges;
- int num_pbm_ranges;
- struct linux_prom_pci_intmap *pbm_intmap;
- int num_pbm_intmap;
- struct linux_prom_pci_intmask *pbm_intmask;
u64 ino_bitmap;
/* PBM I/O and Memory space resources. */
@@ -197,13 +110,10 @@ struct pci_pbm_info {
#endif /* !(CONFIG_PCI_MSI) */
/* This PBM's streaming buffer. */
- struct pci_strbuf stc;
+ struct strbuf stc;
/* IOMMU state, potentially shared by both PBM segments. */
- struct pci_iommu *iommu;
-
- /* PCI slot mapping. */
- unsigned int pci_first_slot;
+ struct iommu *iommu;
/* Now things for the actual PCI bus probes. */
unsigned int pci_first_busno;
@@ -220,17 +130,12 @@ struct pci_controller_info {
*/
int index;
- /* Do the PBMs both exist in the same PCI domain? */
- int pbms_same_domain;
-
/* The PCI bus modules controlled by us. */
struct pci_pbm_info pbm_A;
struct pci_pbm_info pbm_B;
/* Operations which are controller specific. */
void (*scan_bus)(struct pci_controller_info *);
- void (*base_address_update)(struct pci_dev *, int);
- void (*resource_adjust)(struct pci_dev *, struct resource *, struct resource *);
#ifdef CONFIG_PCI_MSI
int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
@@ -244,27 +149,4 @@ struct pci_controller_info {
unsigned int pci_last_busno;
};
-/* PCI devices which are not bridges have this placed in their pci_dev
- * sysdata member. This makes OBP aware PCI device drivers easier to
- * code.
- */
-struct pcidev_cookie {
- struct pci_pbm_info *pbm;
- struct device_node *prom_node;
- struct of_device *op;
- struct linux_prom_pci_registers prom_regs[PROMREG_MAX];
- int num_prom_regs;
- struct linux_prom_pci_registers prom_assignments[PROMREG_MAX];
- int num_prom_assignments;
-#ifdef CONFIG_PCI_MSI
- unsigned int msi_num;
-#endif
-};
-
-/* Currently these are the same across all PCI controllers
- * we support. Someday they may not be...
- */
-#define PCI_IRQ_IGN 0x000007c0 /* Interrupt Group Number */
-#define PCI_IRQ_INO 0x0000003f /* Interrupt Number */
-
#endif /* !(__SPARC64_PBM_H) */
diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h
index b14a725b430..47cea16e1ba 100644
--- a/include/asm-sparc64/pci.h
+++ b/include/asm-sparc64/pci.h
@@ -54,7 +54,7 @@ struct pci_iommu_ops {
void (*dma_sync_sg_for_cpu)(struct pci_dev *, struct scatterlist *, int, int);
};
-extern struct pci_iommu_ops *pci_iommu_ops;
+extern const struct pci_iommu_ops *pci_iommu_ops;
/* Allocate and map kernel buffer using consistent mode DMA for a device.
* hwdev should be valid struct pci_dev pointer for PCI devices.
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index b12be7a869f..46705ef47d2 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -737,20 +737,6 @@ extern unsigned long pte_file(pte_t);
extern pte_t pgoff_to_pte(unsigned long);
#define PTE_FILE_MAX_BITS (64UL - PAGE_SHIFT - 1UL)
-extern unsigned long prom_virt_to_phys(unsigned long, int *);
-
-extern unsigned long sun4u_get_pte(unsigned long);
-
-static inline unsigned long __get_phys(unsigned long addr)
-{
- return sun4u_get_pte(addr);
-}
-
-static inline int __get_iospace(unsigned long addr)
-{
- return ((sun4u_get_pte(addr) & 0xf0000000) >> 28);
-}
-
extern unsigned long *sparc64_valid_addr_bitmap;
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
@@ -791,6 +777,8 @@ extern void pgtable_cache_init(void);
extern void sun4v_register_fault_status(void);
extern void sun4v_ktsb_register(void);
+extern unsigned long cmdline_memory_size;
+
#endif /* !(__ASSEMBLY__) */
#endif /* !(_SPARC64_PGTABLE_H) */
diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h
index 0eca2d98627..ddad5f99ac7 100644
--- a/include/asm-sparc64/prom.h
+++ b/include/asm-sparc64/prom.h
@@ -36,8 +36,8 @@ struct property {
struct of_irq_controller;
struct device_node {
- char *name;
- char *type;
+ const char *name;
+ const char *type;
phandle node;
char *path_component_name;
char *full_name;
@@ -93,11 +93,13 @@ extern struct device_node *of_find_node_by_phandle(phandle handle);
extern struct device_node *of_get_parent(const struct device_node *node);
extern struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev);
-extern struct property *of_find_property(struct device_node *np,
+extern struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp);
-extern int of_device_is_compatible(struct device_node *device, const char *);
-extern void *of_get_property(struct device_node *node, const char *name,
+extern int of_device_is_compatible(const struct device_node *device,
+ const char *);
+extern const void *of_get_property(const struct device_node *node,
+ const char *name,
int *lenp);
#define get_property(node,name,lenp) of_get_property(node,name,lenp)
extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h
index 388249b751c..cca54804b72 100644
--- a/include/asm-sparc64/smp.h
+++ b/include/asm-sparc64/smp.h
@@ -42,15 +42,15 @@ extern int hard_smp_processor_id(void);
#define raw_smp_processor_id() (current_thread_info()->cpu)
extern void smp_setup_cpu_possible_map(void);
+extern unsigned char boot_cpu_id;
#endif /* !(__ASSEMBLY__) */
#else
#define smp_setup_cpu_possible_map() do { } while (0)
+#define boot_cpu_id (0)
#endif /* !(CONFIG_SMP) */
-#define NO_PROC_ID 0xFF
-
#endif /* !(_SPARC64_SMP_H) */
diff --git a/include/asm-sparc64/sparsemem.h b/include/asm-sparc64/sparsemem.h
index ed5c9d8541e..77bcd2bfa53 100644
--- a/include/asm-sparc64/sparsemem.h
+++ b/include/asm-sparc64/sparsemem.h
@@ -3,7 +3,7 @@
#ifdef __KERNEL__
-#define SECTION_SIZE_BITS 26
+#define SECTION_SIZE_BITS 31
#define MAX_PHYSADDR_BITS 42
#define MAX_PHYSMEM_BITS 42
diff --git a/include/asm-sparc64/timer.h b/include/asm-sparc64/timer.h
index d435594df78..ccbd6944886 100644
--- a/include/asm-sparc64/timer.h
+++ b/include/asm-sparc64/timer.h
@@ -11,22 +11,19 @@
struct sparc64_tick_ops {
- void (*init_tick)(unsigned long);
unsigned long (*get_tick)(void);
- unsigned long (*get_compare)(void);
- unsigned long (*add_tick)(unsigned long, unsigned long);
- unsigned long (*add_compare)(unsigned long);
+ int (*add_compare)(unsigned long);
unsigned long softint_mask;
+ void (*disable_irq)(void);
+
+ void (*init_tick)(void);
+ unsigned long (*add_tick)(unsigned long);
+
+ char *name;
};
extern struct sparc64_tick_ops *tick_ops;
-#ifdef CONFIG_SMP
-extern unsigned long timer_tick_offset;
-struct pt_regs;
-extern void timer_tick_interrupt(struct pt_regs *);
-#endif
-
extern unsigned long sparc64_get_clock_tick(unsigned int cpu);
#endif /* _SPARC64_TIMER_H */
diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h
index c2a16e18849..bbb9c8f13d6 100644
--- a/include/asm-sparc64/ttable.h
+++ b/include/asm-sparc64/ttable.h
@@ -157,23 +157,6 @@
ba,a,pt %xcc, rtrap_irq; \
.previous;
-#define TICK_SMP_IRQ \
- rdpr %pil, %g2; \
- wrpr %g0, 15, %pil; \
- sethi %hi(1f-4), %g7; \
- ba,pt %xcc, etrap_irq; \
- or %g7, %lo(1f-4), %g7; \
- nop; \
- nop; \
- nop; \
- .subsection 2; \
-1: call trace_hardirqs_off; \
- nop; \
- call smp_percpu_timer_interrupt; \
- add %sp, PTREGS_OFF, %o0; \
- ba,a,pt %xcc, rtrap_irq; \
- .previous;
-
#else
#define TRAP_IRQ(routine, level) \
@@ -186,16 +169,6 @@
add %sp, PTREGS_OFF, %o1; \
ba,a,pt %xcc, rtrap_irq;
-#define TICK_SMP_IRQ \
- rdpr %pil, %g2; \
- wrpr %g0, 15, %pil; \
- sethi %hi(109f), %g7; \
- ba,pt %xcc, etrap_irq; \
-109: or %g7, %lo(109b), %g7; \
- call smp_percpu_timer_interrupt; \
- add %sp, PTREGS_OFF, %o0; \
- ba,a,pt %xcc, rtrap_irq;
-
#endif
#define TRAP_IVEC TRAP_NOSAVE(do_ivec)
diff --git a/include/linux/string.h b/include/linux/string.h
index 4f69ef9e6eb..7f2eb6a477f 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -47,6 +47,12 @@ extern int strncmp(const char *,const char *,__kernel_size_t);
#ifndef __HAVE_ARCH_STRNICMP
extern int strnicmp(const char *, const char *, __kernel_size_t);
#endif
+#ifndef __HAVE_ARCH_STRCASECMP
+extern int strcasecmp(const char *s1, const char *s2);
+#endif
+#ifndef __HAVE_ARCH_STRNCASECMP
+extern int strncasecmp(const char *s1, const char *s2, size_t n);
+#endif
#ifndef __HAVE_ARCH_STRCHR
extern char * strchr(const char *,int);
#endif
diff --git a/lib/string.c b/lib/string.c
index bab440fb0df..5efafed3d6b 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -60,6 +60,34 @@ int strnicmp(const char *s1, const char *s2, size_t len)
EXPORT_SYMBOL(strnicmp);
#endif
+#ifndef __HAVE_ARCH_STRCASECMP
+int strcasecmp(const char *s1, const char *s2)
+{
+ int c1, c2;
+
+ do {
+ c1 = tolower(*s1++);
+ c2 = tolower(*s2++);
+ } while (c1 == c2 && c1 != 0);
+ return c1 - c2;
+}
+EXPORT_SYMBOL(strcasecmp);
+#endif
+
+#ifndef __HAVE_ARCH_STRNCASECMP
+int strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ int c1, c2;
+
+ do {
+ c1 = tolower(*s1++);
+ c2 = tolower(*s2++);
+ } while ((--n > 0) && c1 == c2 && c1 != 0);
+ return c1 - c2;
+}
+EXPORT_SYMBOL(strncasecmp);
+#endif
+
#ifndef __HAVE_ARCH_STRCPY
/**
* strcpy - Copy a %NUL terminated string
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
index c899786f30f..07962a35f24 100644
--- a/sound/sparc/amd7930.c
+++ b/sound/sparc/amd7930.c
@@ -1067,8 +1067,8 @@ out_err:
static int __devinit amd7930_obio_attach(struct device_node *dp)
{
- struct linux_prom_registers *regs;
- struct linux_prom_irqs *irqp;
+ const struct linux_prom_registers *regs;
+ const struct linux_prom_irqs *irqp;
struct resource res, *rp;
int len;
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index f5956d557f7..900a00de35f 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -2284,7 +2284,7 @@ static int __init cs4231_init(void)
if (!strcmp(edev->prom_node->name, "SUNW,CS4231")) {
match = 1;
} else if (!strcmp(edev->prom_node->name, "audio")) {
- char *compat;
+ const char *compat;
compat = of_get_property(edev->prom_node,
"compatible", NULL);