forked from Minki/linux
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6: (67 commits) [SCSI] SUNESP: Complete driver rewrite to version 2.0 [SPARC64]: Convert PCI over to generic struct iommu/strbuf. [SPARC]: device_node name constification fallout [SPARC64]: Convert SBUS over to generic iommu/strbuf structs. [SPARC64]: Add generic iommu and strbuf structs to iommu.h [SPARC64]: Consolidate {sbus,pci}_iommu_arena. [SPARC]: Make device_node name and type const [SPARC64]: constify some paramaters of OF routines [TIGON3]: of_get_property() returns const. [SPARC64]: Fix PCI rework to adhere to of_get_property() const return. [SPARC64]: Document and fix calculation of pages_avail. [SPARC64]: Make sure pbm->prom_node is setup easly enough in psycho.c [SPARC64]: Use bootmem_bootmap_pages() in choose_bootmap_pfn(). [SPARC64]: Add proper header file extern for cmdline_memory_size. [SPARC64]: Kill sparc_ultra_dump_{i,d}tlb() [SPARC64]: Use DECLARE_BITMAP and BITS_TO_LONGS in mm/init.c [SPARC64]: Give move verbose show_mem() output just like i386. [SPARC64]: Mark show_mem() printk's with KERN_INFO. [SPARC64]: Kill kvaddr_to_phys() and friends. [SPARC64]: Privatize sun4u_get_pte() and fix name. ...
This commit is contained in:
commit
0278ef8b48
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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("/");
|
||||
|
@ -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;
|
||||
struct of_device *op = of_find_device_by_node(isa_dev->prom_node);
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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", ®len);
|
||||
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);
|
||||
|
||||
|
@ -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,715 +15,8 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
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;
|
||||
|
||||
list_for_each_entry(dev, &pbus->devices, bus_list)
|
||||
pdev_record_assignments(pbm, dev);
|
||||
|
||||
list_for_each_entry(bus, &pbus->children, node)
|
||||
pci_record_assignments(pbm, bus);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
int class = pdev->class >> 8;
|
||||
|
||||
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;
|
||||
|
||||
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));
|
||||
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 &= ~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)));
|
||||
}
|
||||
}
|
||||
|
||||
void __init pci_assign_unassigned(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_assign_unassigned(pbm, dev);
|
||||
|
||||
list_for_each_entry(bus, &pbus->children, node)
|
||||
pci_assign_unassigned(pbm, bus);
|
||||
}
|
||||
|
||||
static void __init pdev_fixup_irq(struct pci_dev *pdev)
|
||||
{
|
||||
struct pcidev_cookie *pcp = pdev->sysdata;
|
||||
struct of_device *op = pcp->op;
|
||||
|
||||
if (op->irqs[0] == 0xffffffff) {
|
||||
pdev->irq = PCI_IRQ_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
pdev->irq = op->irqs[0];
|
||||
|
||||
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, <imer);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ltimer);
|
||||
}
|
||||
|
||||
void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
|
||||
struct pci_bus *pbus)
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
int all_are_66mhz;
|
||||
u16 status;
|
||||
|
||||
if (pbm->is_66mhz_capable == 0) {
|
||||
all_are_66mhz = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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;
|
||||
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)
|
||||
static void pci_register_legacy_regions(struct resource *io_res,
|
||||
struct resource *mem_res)
|
||||
{
|
||||
struct resource *p;
|
||||
|
||||
@ -760,6 +52,102 @@ void pci_register_legacy_regions(struct resource *io_res,
|
||||
request_resource(mem_res, p);
|
||||
}
|
||||
|
||||
static void pci_register_iommu_region(struct pci_pbm_info *pbm)
|
||||
{
|
||||
const u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL);
|
||||
|
||||
if (vdma) {
|
||||
struct resource *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) vdma[0];
|
||||
rp->end = rp->start + (unsigned long) vdma[1] - 1UL;
|
||||
rp->flags = IORESOURCE_BUSY;
|
||||
request_resource(&pbm->mem_space, rp);
|
||||
}
|
||||
}
|
||||
|
||||
void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
|
||||
{
|
||||
const struct linux_prom_pci_ranges *pbm_ranges;
|
||||
int i, saw_mem, saw_io;
|
||||
int num_pbm_ranges;
|
||||
|
||||
saw_mem = saw_io = 0;
|
||||
pbm_ranges = of_get_property(pbm->prom_node, "ranges", &i);
|
||||
num_pbm_ranges = i / sizeof(*pbm_ranges);
|
||||
|
||||
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;
|
||||
|
||||
parent_phys_hi = pr->parent_phys_hi;
|
||||
parent_phys_lo = pr->parent_phys_lo;
|
||||
if (tlb_type == hypervisor)
|
||||
parent_phys_hi &= 0x0fffffff;
|
||||
|
||||
type = (pr->child_phys_hi >> 24) & 0x3;
|
||||
a = (((unsigned long)parent_phys_hi << 32UL) |
|
||||
((unsigned long)parent_phys_lo << 0UL));
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
/* PCI config space, 16MB */
|
||||
pbm->config_space = a;
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
pci_register_iommu_region(pbm);
|
||||
}
|
||||
|
||||
/* Generic helper routines for PCI error reporting. */
|
||||
void pci_scan_for_target_abort(struct pci_controller_info *p,
|
||||
struct pci_pbm_info *pbm,
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 & 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);
|
||||
|
@ -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 & 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);
|
||||
pbus = pci_scan_one_pbm(&p->pbm_A);
|
||||
if (!pbus)
|
||||
return;
|
||||
|
||||
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 = pbus;
|
||||
|
||||
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->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);
|
||||
}
|
||||
|
||||
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;
|
||||
pbm = &p->pbm_A;
|
||||
pbm->name = dp->full_name;
|
||||
printk("%s: SABRE PCI Bus Module\n", pbm->name);
|
||||
|
||||
prop = of_find_property(node, "model", NULL);
|
||||
if (!prop || strncmp(prop->value, "SUNW,simba", prop->length))
|
||||
goto next_pci;
|
||||
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;
|
||||
|
||||
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_register_toplevel_resources(p, pbm);
|
||||
|
||||
next_pci:
|
||||
node = node->sibling;
|
||||
}
|
||||
if (simbas_found == 0) {
|
||||
struct resource *rp;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
@ -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)
|
||||
static void schizo_scan_bus(struct pci_controller_info *p)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 & 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)
|
||||
|
@ -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 & 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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
return new_compare;
|
||||
__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 ((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)
|
||||
#define USEC_AFTER 500000
|
||||
#define USEC_BEFORE 500000
|
||||
|
||||
static void sync_cmos_clock(unsigned long dummy);
|
||||
|
||||
static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
|
||||
|
||||
static void sync_cmos_clock(unsigned long dummy)
|
||||
{
|
||||
/* last time the cmos clock got updated */
|
||||
static long last_rtc_update;
|
||||
struct timeval now, next;
|
||||
int fail = 1;
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
}
|
||||
|
||||
irqreturn_t timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
unsigned long ticks, compare, pstate;
|
||||
|
||||
write_seqlock(&xtime_lock);
|
||||
|
||||
do {
|
||||
#ifndef CONFIG_SMP
|
||||
profile_tick(CPU_PROFILING);
|
||||
update_process_times(user_mode(get_irq_regs()));
|
||||
#endif
|
||||
do_timer(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);
|
||||
|
||||
void timer_interrupt(int irq, struct pt_regs *regs)
|
||||
{
|
||||
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();
|
||||
|
||||
kstat_this_cpu.irqs[0]++;
|
||||
|
||||
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.
|
||||
*/
|
||||
__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,
|
||||
};
|
||||
|
||||
/* The quotient formula is taken from the IA64 port. */
|
||||
#define SPARC64_NSEC_PER_CYC_SHIFT 10UL
|
||||
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();
|
||||
|
||||
sparc64_cpu_interpolator.frequency = clock;
|
||||
register_time_interpolator(&sparc64_cpu_interpolator);
|
||||
|
||||
/* Now that the interpolator is registered, it is
|
||||
* safe to start the timer ticking.
|
||||
*/
|
||||
sparc64_start_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 ||
|
||||
|
@ -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)
|
||||
|
@ -122,26 +122,21 @@ static void __init read_obp_memory(const char *property,
|
||||
size = 0UL;
|
||||
base = new_base;
|
||||
}
|
||||
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(®s[i], ®s[i + 1],
|
||||
(ents - i - 1) * sizeof(regs[0]));
|
||||
i--;
|
||||
ents--;
|
||||
continue;
|
||||
}
|
||||
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--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
*num_ents = ents;
|
||||
|
||||
sort(regs, ents, sizeof(struct linux_prom64_registers),
|
||||
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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"))
|
||||
|
@ -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;
|
||||
struct device_node *dp = pci_device_to_OF_node(pdev);
|
||||
const unsigned char *addr;
|
||||
int len;
|
||||
|
||||
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;
|
||||
}
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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)))
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
4394
drivers/scsi/esp.c
4394
drivers/scsi/esp.c
File diff suppressed because it is too large
Load Diff
@ -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) */
|
2710
drivers/scsi/esp_scsi.c
Normal file
2710
drivers/scsi/esp_scsi.c
Normal file
File diff suppressed because it is too large
Load Diff
560
drivers/scsi/esp_scsi.h
Normal file
560
drivers/scsi/esp_scsi.h
Normal file
@ -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) */
|
@ -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.
|
||||
|
634
drivers/scsi/sun_esp.c
Normal file
634
drivers/scsi/sun_esp.c
Normal file
@ -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);
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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 *);
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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) */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) */
|
||||
|
@ -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.
|
||||
|
@ -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) */
|
||||
|
@ -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);
|
||||
|
@ -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) */
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
28
lib/string.c
28
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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user