dect
/
linux-2.6
Archived
13
0
Fork 0

Merge commit master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6 of HEAD

* HEAD:
  [SPARC]: Fix OF register translations under sub-PCI busses.
  [SPARC64]: Refine Sabre wsync logic.
  [SERIAL] sunsu: Handle keyboard and mouse ports directly.
  [SPARC64]: Fix 2 bugs in sabre_irq_build()
  [SPARC64]: Update defconfig.
  [SPARC64]: Fix make headers_install
  [SPARC64]: of_device_register() error checking fix
This commit is contained in:
Linus Torvalds 2006-07-13 07:53:11 -07:00
commit 0e2ffbf650
6 changed files with 391 additions and 239 deletions

View File

@ -183,7 +183,7 @@ struct bus_type of_bus_type = {
};
EXPORT_SYMBOL(of_bus_type);
static inline u64 of_read_addr(u32 *cell, int size)
static inline u64 of_read_addr(const u32 *cell, int size)
{
u64 r = 0;
while (size--)
@ -209,8 +209,8 @@ struct of_bus {
int (*match)(struct device_node *parent);
void (*count_cells)(struct device_node *child,
int *addrc, int *sizec);
u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna);
int (*translate)(u32 *addr, u64 offset, int na);
int (*map)(u32 *addr, const u32 *range,
int na, int ns, int pna);
unsigned int (*get_flags)(u32 *addr);
};
@ -224,27 +224,49 @@ static void of_bus_default_count_cells(struct device_node *dev,
get_cells(dev, addrc, sizec);
}
static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
{
u64 cp, s, da;
cp = of_read_addr(range, na);
s = of_read_addr(range + na + pna, ns);
da = of_read_addr(addr, na);
if (da < cp || da >= (cp + s))
return OF_BAD_ADDR;
return da - cp;
}
static int of_bus_default_translate(u32 *addr, u64 offset, int na)
/* Make sure the least significant 64-bits are in-range. Even
* for 3 or 4 cell values it is a good enough approximation.
*/
static int of_out_of_range(const u32 *addr, const u32 *base,
const u32 *size, int na, int ns)
{
u64 a = of_read_addr(addr, na);
memset(addr, 0, na * 4);
a += offset;
if (na > 1)
addr[na - 2] = a >> 32;
addr[na - 1] = a & 0xffffffffu;
u64 b = of_read_addr(base, na);
if (a < b)
return 1;
b += of_read_addr(size, ns);
if (a >= b)
return 1;
return 0;
}
static int of_bus_default_map(u32 *addr, const u32 *range,
int na, int ns, int pna)
{
u32 result[OF_MAX_ADDR_CELLS];
int i;
if (ns > 2) {
printk("of_device: Cannot handle size cells (%d) > 2.", ns);
return -EINVAL;
}
if (of_out_of_range(addr, range, range + na + pna, na, ns))
return -EINVAL;
/* Start with the parent range base. */
memcpy(result, range + na, pna * 4);
/* Add in the child address offset. */
for (i = 0; i < na; i++)
result[pna - 1 - i] +=
(addr[na - 1 - i] -
range[na - 1 - i]);
memcpy(addr, result, pna * 4);
return 0;
}
@ -254,14 +276,26 @@ static unsigned int of_bus_default_get_flags(u32 *addr)
return IORESOURCE_MEM;
}
/*
* PCI bus specific translator
*/
static int of_bus_pci_match(struct device_node *np)
{
return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex");
if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
/* Do not do PCI specific frobbing if the
* PCI bridge lacks a ranges property. We
* want to pass it through up to the next
* parent as-is, not with the PCI translate
* method which chops off the top address cell.
*/
if (!of_find_property(np, "ranges", NULL))
return 0;
return 1;
}
return 0;
}
static void of_bus_pci_count_cells(struct device_node *np,
@ -273,27 +307,32 @@ static void of_bus_pci_count_cells(struct device_node *np,
*sizec = 2;
}
static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
static int of_bus_pci_map(u32 *addr, const u32 *range,
int na, int ns, int pna)
{
u64 cp, s, da;
u32 result[OF_MAX_ADDR_CELLS];
int i;
/* Check address type match */
if ((addr[0] ^ range[0]) & 0x03000000)
return OF_BAD_ADDR;
return -EINVAL;
/* Read address values, skipping high cell */
cp = of_read_addr(range + 1, na - 1);
s = of_read_addr(range + na + pna, ns);
da = of_read_addr(addr + 1, na - 1);
if (of_out_of_range(addr + 1, range + 1, range + na + pna,
na - 1, ns))
return -EINVAL;
if (da < cp || da >= (cp + s))
return OF_BAD_ADDR;
return da - cp;
}
/* Start with the parent range base. */
memcpy(result, range + na, pna * 4);
static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
{
return of_bus_default_translate(addr + 1, offset, na - 1);
/* Add in the child address offset, skipping high cell. */
for (i = 0; i < na - 1; i++)
result[pna - 1 - i] +=
(addr[na - 1 - i] -
range[na - 1 - i]);
memcpy(addr, result, pna * 4);
return 0;
}
static unsigned int of_bus_pci_get_flags(u32 *addr)
@ -332,16 +371,11 @@ static void of_bus_sbus_count_cells(struct device_node *child,
*sizec = 1;
}
static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna)
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 int of_bus_sbus_translate(u32 *addr, u64 offset, int na)
{
return of_bus_default_translate(addr, offset, na);
}
static unsigned int of_bus_sbus_get_flags(u32 *addr)
{
return IORESOURCE_MEM;
@ -360,7 +394,6 @@ static struct of_bus of_busses[] = {
.match = of_bus_pci_match,
.count_cells = of_bus_pci_count_cells,
.map = of_bus_pci_map,
.translate = of_bus_pci_translate,
.get_flags = of_bus_pci_get_flags,
},
/* SBUS */
@ -370,7 +403,6 @@ static struct of_bus of_busses[] = {
.match = of_bus_sbus_match,
.count_cells = of_bus_sbus_count_cells,
.map = of_bus_sbus_map,
.translate = of_bus_sbus_translate,
.get_flags = of_bus_sbus_get_flags,
},
/* Default */
@ -380,7 +412,6 @@ static struct of_bus of_busses[] = {
.match = NULL,
.count_cells = of_bus_default_count_cells,
.map = of_bus_default_map,
.translate = of_bus_default_translate,
.get_flags = of_bus_default_get_flags,
},
};
@ -405,33 +436,34 @@ static int __init build_one_resource(struct device_node *parent,
u32 *ranges;
unsigned int rlen;
int rone;
u64 offset = OF_BAD_ADDR;
ranges = of_get_property(parent, "ranges", &rlen);
if (ranges == NULL || rlen == 0) {
offset = of_read_addr(addr, na);
memset(addr, 0, pna * 4);
goto finish;
u32 result[OF_MAX_ADDR_CELLS];
int i;
memset(result, 0, pna * 4);
for (i = 0; i < na; i++)
result[pna - 1 - i] =
addr[na - 1 - i];
memcpy(addr, result, pna * 4);
return 0;
}
/* Now walk through the ranges */
rlen /= 4;
rone = na + pna + ns;
for (; rlen >= rone; rlen -= rone, ranges += rone) {
offset = bus->map(addr, ranges, na, ns, pna);
if (offset != OF_BAD_ADDR)
break;
if (!bus->map(addr, ranges, na, ns, pna))
return 0;
}
if (offset == OF_BAD_ADDR)
return 1;
memcpy(addr, ranges + na, 4 * pna);
finish:
/* Translate it into parent bus space */
return pbus->translate(addr, offset, pna);
return 1;
}
static int of_resource_verbose;
static void __init build_device_resources(struct of_device *op,
struct device *parent)
{
@ -497,7 +529,8 @@ static void __init build_device_resources(struct of_device *op,
pbus = of_match_bus(pp);
pbus->count_cells(dp, &pna, &pns);
if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna))
if (build_one_resource(dp, bus, pbus, addr,
dna, dns, pna))
break;
dna = pna;
@ -507,6 +540,12 @@ static void __init build_device_resources(struct of_device *op,
build_res:
memset(r, 0, sizeof(*r));
if (of_resource_verbose)
printk("%s reg[%d] -> %llx\n",
op->node->full_name, index,
result);
if (result != OF_BAD_ADDR) {
r->start = result & 0xffffffff;
r->end = result + size - 1;
@ -643,6 +682,18 @@ static int __init of_bus_driver_init(void)
postcore_initcall(of_bus_driver_init);
static int __init of_debug(char *str)
{
int val = 0;
get_option(&str, &val);
if (val & 1)
of_resource_verbose = 1;
return 1;
}
__setup("of_debug=", of_debug);
int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
/* initialize common driver fields */
@ -695,9 +746,11 @@ int of_device_register(struct of_device *ofdev)
if (rc)
return rc;
device_create_file(&ofdev->dev, &dev_attr_devspec);
rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
if (rc)
device_unregister(&ofdev->dev);
return 0;
return rc;
}
void of_device_unregister(struct of_device *ofdev)

View File

@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.17
# Fri Jun 23 23:17:09 2006
# Linux kernel version: 2.6.18-rc1
# Wed Jul 12 14:00:58 2006
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
@ -18,6 +18,7 @@ CONFIG_SECCOMP=y
CONFIG_HZ_250=y
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
@ -51,10 +52,12 @@ CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@ -127,8 +130,8 @@ CONFIG_SPARSEMEM=y
CONFIG_HAVE_MEMORY_PRESENT=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPARSEMEM_EXTREME=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_RESOURCES_64BIT=y
CONFIG_GENERIC_ISA_DMA=y
CONFIG_SBUS=y
CONFIG_SBUSCHAR=y
@ -203,7 +206,6 @@ CONFIG_TCP_CONG_VEGAS=m
CONFIG_TCP_CONG_SCALABLE=m
CONFIG_TCP_CONG_LP=m
CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_COMPOUND=m
CONFIG_IPV6=m
CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
@ -461,9 +463,8 @@ CONFIG_MD_LINEAR=m
CONFIG_MD_RAID0=m
CONFIG_MD_RAID1=m
CONFIG_MD_RAID10=m
CONFIG_MD_RAID5=m
CONFIG_MD_RAID456=m
# CONFIG_MD_RAID5_RESHAPE is not set
CONFIG_MD_RAID6=m
CONFIG_MD_MULTIPATH=m
# CONFIG_MD_FAULTY is not set
CONFIG_BLK_DEV_DM=m
@ -663,6 +664,7 @@ CONFIG_SERIO_RAW=m
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
@ -693,6 +695,7 @@ CONFIG_UNIX98_PTYS=y
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM is not set
CONFIG_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@ -839,12 +842,13 @@ CONFIG_VIDEO_V4L2=y
#
# Graphics support
#
# CONFIG_FIRMWARE_EDID is not set
CONFIG_FB=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_FIRMWARE_EDID is not set
# CONFIG_FB_BACKLIGHT is not set
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y
# CONFIG_FB_CIRRUS is not set
@ -954,6 +958,18 @@ CONFIG_SND_ALI5451=m
# CONFIG_SND_CMIPCI is not set
# CONFIG_SND_CS4281 is not set
# CONFIG_SND_CS46XX is not set
# CONFIG_SND_DARLA20 is not set
# CONFIG_SND_GINA20 is not set
# CONFIG_SND_LAYLA20 is not set
# CONFIG_SND_DARLA24 is not set
# CONFIG_SND_GINA24 is not set
# CONFIG_SND_LAYLA24 is not set
# CONFIG_SND_MONA is not set
# CONFIG_SND_MIA is not set
# CONFIG_SND_ECHO3G is not set
# CONFIG_SND_INDIGO is not set
# CONFIG_SND_INDIGOIO is not set
# CONFIG_SND_INDIGODJ is not set
# CONFIG_SND_EMU10K1 is not set
# CONFIG_SND_EMU10K1X is not set
# CONFIG_SND_ENS1370 is not set
@ -1263,6 +1279,7 @@ CONFIG_RAMFS=y
# CONFIG_NFSD is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
@ -1331,14 +1348,19 @@ CONFIG_KPROBES=y
#
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_DETECT_SOFTLOCKUP=y
CONFIG_SCHEDSTATS=y
# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_RWSEMS is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_INFO is not set
@ -1402,3 +1424,4 @@ CONFIG_CRC32=y
CONFIG_LIBCRC32C=m
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y

View File

@ -210,7 +210,7 @@ struct bus_type of_bus_type = {
};
EXPORT_SYMBOL(of_bus_type);
static inline u64 of_read_addr(u32 *cell, int size)
static inline u64 of_read_addr(const u32 *cell, int size)
{
u64 r = 0;
while (size--)
@ -236,8 +236,8 @@ struct of_bus {
int (*match)(struct device_node *parent);
void (*count_cells)(struct device_node *child,
int *addrc, int *sizec);
u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna);
int (*translate)(u32 *addr, u64 offset, int na);
int (*map)(u32 *addr, const u32 *range,
int na, int ns, int pna);
unsigned int (*get_flags)(u32 *addr);
};
@ -251,27 +251,49 @@ static void of_bus_default_count_cells(struct device_node *dev,
get_cells(dev, addrc, sizec);
}
static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
{
u64 cp, s, da;
cp = of_read_addr(range, na);
s = of_read_addr(range + na + pna, ns);
da = of_read_addr(addr, na);
if (da < cp || da >= (cp + s))
return OF_BAD_ADDR;
return da - cp;
}
static int of_bus_default_translate(u32 *addr, u64 offset, int na)
/* Make sure the least significant 64-bits are in-range. Even
* for 3 or 4 cell values it is a good enough approximation.
*/
static int of_out_of_range(const u32 *addr, const u32 *base,
const u32 *size, int na, int ns)
{
u64 a = of_read_addr(addr, na);
memset(addr, 0, na * 4);
a += offset;
if (na > 1)
addr[na - 2] = a >> 32;
addr[na - 1] = a & 0xffffffffu;
u64 b = of_read_addr(base, na);
if (a < b)
return 1;
b += of_read_addr(size, ns);
if (a >= b)
return 1;
return 0;
}
static int of_bus_default_map(u32 *addr, const u32 *range,
int na, int ns, int pna)
{
u32 result[OF_MAX_ADDR_CELLS];
int i;
if (ns > 2) {
printk("of_device: Cannot handle size cells (%d) > 2.", ns);
return -EINVAL;
}
if (of_out_of_range(addr, range, range + na + pna, na, ns))
return -EINVAL;
/* Start with the parent range base. */
memcpy(result, range + na, pna * 4);
/* Add in the child address offset. */
for (i = 0; i < na; i++)
result[pna - 1 - i] +=
(addr[na - 1 - i] -
range[na - 1 - i]);
memcpy(addr, result, pna * 4);
return 0;
}
@ -287,7 +309,20 @@ static unsigned int of_bus_default_get_flags(u32 *addr)
static int of_bus_pci_match(struct device_node *np)
{
return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex");
if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
/* Do not do PCI specific frobbing if the
* PCI bridge lacks a ranges property. We
* want to pass it through up to the next
* parent as-is, not with the PCI translate
* method which chops off the top address cell.
*/
if (!of_find_property(np, "ranges", NULL))
return 0;
return 1;
}
return 0;
}
static void of_bus_pci_count_cells(struct device_node *np,
@ -299,27 +334,32 @@ static void of_bus_pci_count_cells(struct device_node *np,
*sizec = 2;
}
static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
static int of_bus_pci_map(u32 *addr, const u32 *range,
int na, int ns, int pna)
{
u64 cp, s, da;
u32 result[OF_MAX_ADDR_CELLS];
int i;
/* Check address type match */
if ((addr[0] ^ range[0]) & 0x03000000)
return OF_BAD_ADDR;
return -EINVAL;
/* Read address values, skipping high cell */
cp = of_read_addr(range + 1, na - 1);
s = of_read_addr(range + na + pna, ns);
da = of_read_addr(addr + 1, na - 1);
if (of_out_of_range(addr + 1, range + 1, range + na + pna,
na - 1, ns))
return -EINVAL;
if (da < cp || da >= (cp + s))
return OF_BAD_ADDR;
return da - cp;
}
/* Start with the parent range base. */
memcpy(result, range + na, pna * 4);
static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
{
return of_bus_default_translate(addr + 1, offset, na - 1);
/* Add in the child address offset, skipping high cell. */
for (i = 0; i < na - 1; i++)
result[pna - 1 - i] +=
(addr[na - 1 - i] -
range[na - 1 - i]);
memcpy(addr, result, pna * 4);
return 0;
}
static unsigned int of_bus_pci_get_flags(u32 *addr)
@ -339,59 +379,6 @@ static unsigned int of_bus_pci_get_flags(u32 *addr)
return flags;
}
/*
* ISA bus specific translator
*/
static int of_bus_isa_match(struct device_node *np)
{
return !strcmp(np->name, "isa");
}
static void of_bus_isa_count_cells(struct device_node *child,
int *addrc, int *sizec)
{
if (addrc)
*addrc = 2;
if (sizec)
*sizec = 1;
}
static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
{
u64 cp, s, da;
/* Check address type match */
if ((addr[0] ^ range[0]) & 0x00000001)
return OF_BAD_ADDR;
/* Read address values, skipping high cell */
cp = of_read_addr(range + 1, na - 1);
s = of_read_addr(range + na + pna, ns);
da = of_read_addr(addr + 1, na - 1);
if (da < cp || da >= (cp + s))
return OF_BAD_ADDR;
return da - cp;
}
static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
{
return of_bus_default_translate(addr + 1, offset, na - 1);
}
static unsigned int of_bus_isa_get_flags(u32 *addr)
{
unsigned int flags = 0;
u32 w = addr[0];
if (w & 1)
flags |= IORESOURCE_IO;
else
flags |= IORESOURCE_MEM;
return flags;
}
/*
* SBUS bus specific translator
*/
@ -411,16 +398,11 @@ static void of_bus_sbus_count_cells(struct device_node *child,
*sizec = 1;
}
static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna)
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 int of_bus_sbus_translate(u32 *addr, u64 offset, int na)
{
return of_bus_default_translate(addr, offset, na);
}
static unsigned int of_bus_sbus_get_flags(u32 *addr)
{
return IORESOURCE_MEM;
@ -439,19 +421,8 @@ static struct of_bus of_busses[] = {
.match = of_bus_pci_match,
.count_cells = of_bus_pci_count_cells,
.map = of_bus_pci_map,
.translate = of_bus_pci_translate,
.get_flags = of_bus_pci_get_flags,
},
/* ISA */
{
.name = "isa",
.addr_prop_name = "reg",
.match = of_bus_isa_match,
.count_cells = of_bus_isa_count_cells,
.map = of_bus_isa_map,
.translate = of_bus_isa_translate,
.get_flags = of_bus_isa_get_flags,
},
/* SBUS */
{
.name = "sbus",
@ -459,7 +430,6 @@ static struct of_bus of_busses[] = {
.match = of_bus_sbus_match,
.count_cells = of_bus_sbus_count_cells,
.map = of_bus_sbus_map,
.translate = of_bus_sbus_translate,
.get_flags = of_bus_sbus_get_flags,
},
/* Default */
@ -469,7 +439,6 @@ static struct of_bus of_busses[] = {
.match = NULL,
.count_cells = of_bus_default_count_cells,
.map = of_bus_default_map,
.translate = of_bus_default_translate,
.get_flags = of_bus_default_get_flags,
},
};
@ -494,33 +463,62 @@ static int __init build_one_resource(struct device_node *parent,
u32 *ranges;
unsigned int rlen;
int rone;
u64 offset = OF_BAD_ADDR;
ranges = of_get_property(parent, "ranges", &rlen);
if (ranges == NULL || rlen == 0) {
offset = of_read_addr(addr, na);
memset(addr, 0, pna * 4);
goto finish;
u32 result[OF_MAX_ADDR_CELLS];
int i;
memset(result, 0, pna * 4);
for (i = 0; i < na; i++)
result[pna - 1 - i] =
addr[na - 1 - i];
memcpy(addr, result, pna * 4);
return 0;
}
/* Now walk through the ranges */
rlen /= 4;
rone = na + pna + ns;
for (; rlen >= rone; rlen -= rone, ranges += rone) {
offset = bus->map(addr, ranges, na, ns, pna);
if (offset != OF_BAD_ADDR)
break;
if (!bus->map(addr, ranges, na, ns, pna))
return 0;
}
if (offset == OF_BAD_ADDR)
return 1;
}
static int __init use_1to1_mapping(struct device_node *pp)
{
char *model;
/* If this is on the PMU bus, don't try to translate it even
* if a ranges property exists.
*/
if (!strcmp(pp->name, "pmu"))
return 1;
memcpy(addr, ranges + na, 4 * pna);
/* If we have a ranges property in the parent, use it. */
if (of_find_property(pp, "ranges", NULL) != NULL)
return 0;
finish:
/* Translate it into parent bus space */
return pbus->translate(addr, offset, pna);
/* If the parent is the dma node of an ISA bus, pass
* the translation up to the root.
*/
if (!strcmp(pp->name, "dma"))
return 0;
/* Similarly for Simba PCI bridges. */
model = of_get_property(pp, "model", NULL);
if (model && !strcmp(model, "SUNW,simba"))
return 0;
return 1;
}
static int of_resource_verbose;
static void __init build_device_resources(struct of_device *op,
struct device *parent)
{
@ -564,15 +562,7 @@ static void __init build_device_resources(struct of_device *op,
memcpy(addr, reg, na * 4);
/* If the immediate parent has no ranges property to apply,
* just use a 1<->1 mapping. Unless it is the 'dma' child
* of an isa bus, which must be passed up towards the root.
*
* Also, don't try to translate PMU bus device registers.
*/
if ((of_find_property(pp, "ranges", NULL) == NULL &&
strcmp(pp->name, "dma") != 0) ||
!strcmp(pp->name, "pmu")) {
if (use_1to1_mapping(pp)) {
result = of_read_addr(addr, na);
goto build_res;
}
@ -591,7 +581,8 @@ static void __init build_device_resources(struct of_device *op,
pbus = of_match_bus(pp);
pbus->count_cells(dp, &pna, &pns);
if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna))
if (build_one_resource(dp, bus, pbus, addr,
dna, dns, pna))
break;
dna = pna;
@ -601,6 +592,12 @@ static void __init build_device_resources(struct of_device *op,
build_res:
memset(r, 0, sizeof(*r));
if (of_resource_verbose)
printk("%s reg[%d] -> %lx\n",
op->node->full_name, index,
result);
if (result != OF_BAD_ADDR) {
if (tlb_type == hypervisor)
result &= 0x0fffffffffffffffUL;
@ -684,6 +681,8 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp,
return ret;
}
static int of_irq_verbose;
static unsigned int __init build_one_device_irq(struct of_device *op,
struct device *parent,
unsigned int irq)
@ -698,10 +697,11 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
if (dp->irq_trans) {
irq = dp->irq_trans->irq_build(dp, irq,
dp->irq_trans->data);
#if 1
printk("%s: direct translate %x --> %x\n",
dp->full_name, orig_irq, irq);
#endif
if (of_irq_verbose)
printk("%s: direct translate %x --> %x\n",
dp->full_name, orig_irq, irq);
return irq;
}
@ -728,12 +728,13 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
iret = apply_interrupt_map(dp, pp,
imap, imlen, imsk,
&irq);
#if 1
printk("%s: Apply [%s:%x] imap --> [%s:%x]\n",
op->node->full_name,
pp->full_name, this_orig_irq,
(iret ? iret->full_name : "NULL"), irq);
#endif
if (of_irq_verbose)
printk("%s: Apply [%s:%x] imap --> [%s:%x]\n",
op->node->full_name,
pp->full_name, this_orig_irq,
(iret ? iret->full_name : "NULL"), irq);
if (!iret)
break;
@ -747,11 +748,13 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
unsigned int this_orig_irq = irq;
irq = pci_irq_swizzle(dp, pp, irq);
#if 1
printk("%s: PCI swizzle [%s] %x --> %x\n",
op->node->full_name,
pp->full_name, this_orig_irq, irq);
#endif
if (of_irq_verbose)
printk("%s: PCI swizzle [%s] "
"%x --> %x\n",
op->node->full_name,
pp->full_name, this_orig_irq,
irq);
}
if (pp->irq_trans) {
@ -767,10 +770,9 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
irq = ip->irq_trans->irq_build(op->node, irq,
ip->irq_trans->data);
#if 1
printk("%s: Apply IRQ trans [%s] %x --> %x\n",
op->node->full_name, ip->full_name, orig_irq, irq);
#endif
if (of_irq_verbose)
printk("%s: Apply IRQ trans [%s] %x --> %x\n",
op->node->full_name, ip->full_name, orig_irq, irq);
return irq;
}
@ -870,6 +872,20 @@ static int __init of_bus_driver_init(void)
postcore_initcall(of_bus_driver_init);
static int __init of_debug(char *str)
{
int val = 0;
get_option(&str, &val);
if (val & 1)
of_resource_verbose = 1;
if (val & 2)
of_irq_verbose = 1;
return 1;
}
__setup("of_debug=", of_debug);
int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
/* initialize common driver fields */
@ -922,9 +938,11 @@ int of_device_register(struct of_device *ofdev)
if (rc)
return rc;
device_create_file(&ofdev->dev, &dev_attr_devspec);
rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
if (rc)
device_unregister(&ofdev->dev);
return 0;
return rc;
}
void of_device_unregister(struct of_device *ofdev)

View File

@ -539,6 +539,45 @@ static unsigned long __sabre_onboard_imap_off[] = {
((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \
(SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
static int sabre_device_needs_wsync(struct device_node *dp)
{
struct device_node *parent = dp->parent;
char *parent_model, *parent_compat;
/* This traversal up towards the root is meant to
* handle two cases:
*
* 1) non-PCI bus sitting under PCI, such as 'ebus'
* 2) the PCI controller interrupts themselves, which
* will use the sabre_irq_build but do not need
* the DMA synchronization handling
*/
while (parent) {
if (!strcmp(parent->type, "pci"))
break;
parent = parent->parent;
}
if (!parent)
return 0;
parent_model = of_get_property(parent,
"model", NULL);
if (parent_model &&
(!strcmp(parent_model, "SUNW,sabre") ||
!strcmp(parent_model, "SUNW,simba")))
return 0;
parent_compat = of_get_property(parent,
"compatible", NULL);
if (parent_compat &&
(!strcmp(parent_compat, "pci108e,a000") ||
!strcmp(parent_compat, "pci108e,a001")))
return 0;
return 1;
}
static unsigned int sabre_irq_build(struct device_node *dp,
unsigned int ino,
void *_data)
@ -577,15 +616,17 @@ static unsigned int sabre_irq_build(struct device_node *dp,
virt_irq = build_irq(inofixup, iclr, imap);
/* If the parent device is a PCI<->PCI bridge other than
* APB, we have to install a pre-handler to ensure that
* all pending DMA is drained before the interrupt handler
* is run.
*/
regs = of_get_property(dp, "reg", NULL);
if (regs &&
((regs->phys_hi >> 16) & 0xff) != irq_data->pci_first_busno) {
if (regs && sabre_device_needs_wsync(dp)) {
irq_install_pre_handler(virt_irq,
sabre_wsync_handler,
(void *) (long) regs->phys_hi,
(void *)
controller_regs +
SABRE_WRSYNC);
(void *) irq_data);
}
return virt_irq;

View File

@ -1406,25 +1406,35 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
struct device_node *dp = op->node;
struct uart_sunsu_port *up;
struct resource *rp;
enum su_type type;
int err;
if (inst >= UART_NR)
return -EINVAL;
type = su_get_type(dp);
if (type == SU_PORT_PORT) {
if (inst >= UART_NR)
return -EINVAL;
up = &sunsu_ports[inst];
} else {
up = kzalloc(sizeof(*up), GFP_KERNEL);
if (!up)
return -ENOMEM;
}
up = &sunsu_ports[inst];
up->port.line = inst;
spin_lock_init(&up->port.lock);
up->su_type = su_get_type(dp);
up->su_type = type;
rp = &op->resource[0];
up->port.mapbase = op->resource[0].start;
up->port.mapbase = rp->start;
up->reg_size = (rp->end - rp->start) + 1;
up->port.membase = of_ioremap(rp, 0, up->reg_size, "su");
if (!up->port.membase)
if (!up->port.membase) {
if (type != SU_PORT_PORT)
kfree(up);
return -ENOMEM;
}
up->port.irq = op->irqs[0];
@ -1436,8 +1446,11 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
err = 0;
if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) {
err = sunsu_kbd_ms_init(up);
if (err)
if (err) {
kfree(up);
goto out_unmap;
}
dev_set_drvdata(&op->dev, up);
return 0;
}
@ -1476,8 +1489,12 @@ static int __devexit su_remove(struct of_device *dev)
#ifdef CONFIG_SERIO
serio_unregister_port(&up->serio);
#endif
} else if (up->port.type != PORT_UNKNOWN)
kfree(up);
} else if (up->port.type != PORT_UNKNOWN) {
uart_remove_one_port(&sunsu_reg, &up->port);
}
dev_set_drvdata(&dev->dev, NULL);
return 0;
}

View File

@ -4,7 +4,7 @@ ALTARCH := sparc
ARCHDEF := defined __sparc__ && defined __arch64__
ALTARCHDEF := defined __sparc__ && !defined __arch64__
unifdef-y := fbio.h perfctr.h
unifdef-y += fbio.h perfctr.h
header-y += apb.h asi.h bbc.h bpp.h display7seg.h envctrl.h floppy.h \
ipc.h kdebug.h mostek.h openprom.h openpromio.h parport.h \
pconf.h psrcompat.h pstate.h reg.h uctx.h utrap.h watchdog.h