mirror of
https://github.com/torvalds/linux.git
synced 2024-11-29 15:41:36 +00:00
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:
commit
0e2ffbf650
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user