mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-01 08:04:22 +08:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6: (180 commits) leo: disable cursor when leaving graphics mode cg6: disable cursor when leaving graphics mode sparc32: sun4m interrupt mask cleanup drivers/rtc/Kconfig: don't build rtc-cmos.o on sparc32 sparc: arch/sparc/kernel/pmc.c -- extra #include? sparc32: Add more extensive documentation of sun4m interrupts. sparc32: Kill irq_rcvreg from sun4m_irq.c sparc32: Delete master_l10_limit. sparc32: Use PROM device probing for sun4c timers. sparc32: Use PROM device probing for sun4c interrupt register. sparc32: Delete claim_ticker14(). sparc32: Stop calling claim_ticker14() from sun4c_irq.c sparc32: Kill clear_profile_irq btfixup entry. sparc32: Call sun4m_clear_profile_irq() directly from sun4m_smp.c sparc32: Remove #if 0'd code from sun4c_irq.c sparc32: Remove some SMP ifdefs in sun4d_irq.c sparc32: Use PROM infrastructure for probing and mapping sun4d timers. sparc32: Use PROM device probing for sun4m irq registers. sparc32: Use PROM device probing for sun4m timer registers. sparc: Fix user_regset 'n' field values. ...
This commit is contained in:
commit
0710483959
@ -5073,8 +5073,7 @@ struct _snd_pcm_runtime {
|
||||
with <constant>SNDRV_DMA_TYPE_CONTINUOUS</constant> type and the
|
||||
<function>snd_dma_continuous_data(GFP_KERNEL)</function> device pointer,
|
||||
where <constant>GFP_KERNEL</constant> is the kernel allocation flag to
|
||||
use. For the SBUS, <constant>SNDRV_DMA_TYPE_SBUS</constant> and
|
||||
<function>snd_dma_sbus_data(sbus_dev)</function> are used instead.
|
||||
use.
|
||||
For the PCI scatter-gather buffers, use
|
||||
<constant>SNDRV_DMA_TYPE_DEV_SG</constant> with
|
||||
<function>snd_dma_pci_data(pci)</function>
|
||||
|
@ -1,309 +0,0 @@
|
||||
|
||||
Writing SBUS Drivers
|
||||
|
||||
David S. Miller (davem@redhat.com)
|
||||
|
||||
The SBUS driver interfaces of the Linux kernel have been
|
||||
revamped completely for 2.4.x for several reasons. Foremost were
|
||||
performance and complexity concerns. This document details these
|
||||
new interfaces and how they are used to write an SBUS device driver.
|
||||
|
||||
SBUS drivers need to include <asm/sbus.h> to get access
|
||||
to functions and structures described here.
|
||||
|
||||
Probing and Detection
|
||||
|
||||
Each SBUS device inside the machine is described by a
|
||||
structure called "struct sbus_dev". Likewise, each SBUS bus
|
||||
found in the system is described by a "struct sbus_bus". For
|
||||
each SBUS bus, the devices underneath are hung in a tree-like
|
||||
fashion off of the bus structure.
|
||||
|
||||
The SBUS device structure contains enough information
|
||||
for you to implement your device probing algorithm and obtain
|
||||
the bits necessary to run your device. The most commonly
|
||||
used members of this structure, and their typical usage,
|
||||
will be detailed below.
|
||||
|
||||
Here is a piece of skeleton code for performing a device
|
||||
probe in an SBUS driver under Linux:
|
||||
|
||||
static int __devinit mydevice_probe_one(struct sbus_dev *sdev)
|
||||
{
|
||||
struct mysdevice *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
|
||||
|
||||
if (!mp)
|
||||
return -ENODEV;
|
||||
|
||||
...
|
||||
dev_set_drvdata(&sdev->ofdev.dev, mp);
|
||||
return 0;
|
||||
...
|
||||
}
|
||||
|
||||
static int __devinit mydevice_probe(struct of_device *dev,
|
||||
const struct of_device_id *match)
|
||||
{
|
||||
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
|
||||
|
||||
return mydevice_probe_one(sdev);
|
||||
}
|
||||
|
||||
static int __devexit mydevice_remove(struct of_device *dev)
|
||||
{
|
||||
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
|
||||
struct mydevice *mp = dev_get_drvdata(&dev->dev);
|
||||
|
||||
return mydevice_remove_one(sdev, mp);
|
||||
}
|
||||
|
||||
static struct of_device_id mydevice_match[] = {
|
||||
{
|
||||
.name = "mydevice",
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, mydevice_match);
|
||||
|
||||
static struct of_platform_driver mydevice_driver = {
|
||||
.match_table = mydevice_match,
|
||||
.probe = mydevice_probe,
|
||||
.remove = __devexit_p(mydevice_remove),
|
||||
.driver = {
|
||||
.name = "mydevice",
|
||||
},
|
||||
};
|
||||
|
||||
static int __init mydevice_init(void)
|
||||
{
|
||||
return of_register_driver(&mydevice_driver, &sbus_bus_type);
|
||||
}
|
||||
|
||||
static void __exit mydevice_exit(void)
|
||||
{
|
||||
of_unregister_driver(&mydevice_driver);
|
||||
}
|
||||
|
||||
module_init(mydevice_init);
|
||||
module_exit(mydevice_exit);
|
||||
|
||||
The mydevice_match table is a series of entries which
|
||||
describes what SBUS devices your driver is meant for. In the
|
||||
simplest case you specify a string for the 'name' field. Every
|
||||
SBUS device with a 'name' property matching your string will
|
||||
be passed one-by-one to your .probe method.
|
||||
|
||||
You should store away your device private state structure
|
||||
pointer in the drvdata area so that you can retrieve it later on
|
||||
in your .remove method.
|
||||
|
||||
Any memory allocated, registers mapped, IRQs registered,
|
||||
etc. must be undone by your .remove method so that all resources
|
||||
of your device are released by the time it returns.
|
||||
|
||||
You should _NOT_ use the for_each_sbus(), for_each_sbusdev(),
|
||||
and for_all_sbusdev() interfaces. They are deprecated, will be
|
||||
removed, and no new driver should reference them ever.
|
||||
|
||||
Mapping and Accessing I/O Registers
|
||||
|
||||
Each SBUS device structure contains an array of descriptors
|
||||
which describe each register set. We abuse struct resource for that.
|
||||
They each correspond to the "reg" properties provided by the OBP firmware.
|
||||
|
||||
Before you can access your device's registers you must map
|
||||
them. And later if you wish to shutdown your driver (for module
|
||||
unload or similar) you must unmap them. You must treat them as
|
||||
a resource, which you allocate (map) before using and free up
|
||||
(unmap) when you are done with it.
|
||||
|
||||
The mapping information is stored in an opaque value
|
||||
typed as an "unsigned long". This is the type of the return value
|
||||
of the mapping interface, and the arguments to the unmapping
|
||||
interface. Let's say you want to map the first set of registers.
|
||||
Perhaps part of your driver software state structure looks like:
|
||||
|
||||
struct mydevice {
|
||||
unsigned long control_regs;
|
||||
...
|
||||
struct sbus_dev *sdev;
|
||||
...
|
||||
};
|
||||
|
||||
At initialization time you then use the sbus_ioremap
|
||||
interface to map in your registers, like so:
|
||||
|
||||
static void init_one_mydevice(struct sbus_dev *sdev)
|
||||
{
|
||||
struct mydevice *mp;
|
||||
...
|
||||
|
||||
mp->control_regs = sbus_ioremap(&sdev->resource[0], 0,
|
||||
CONTROL_REGS_SIZE, "mydevice regs");
|
||||
if (!mp->control_regs) {
|
||||
/* Failure, cleanup and return. */
|
||||
}
|
||||
}
|
||||
|
||||
Second argument to sbus_ioremap is an offset for
|
||||
cranky devices with broken OBP PROM. The sbus_ioremap uses only
|
||||
a start address and flags from the resource structure.
|
||||
Therefore it is possible to use the same resource to map
|
||||
several sets of registers or even to fabricate a resource
|
||||
structure if driver gets physical address from some private place.
|
||||
This practice is discouraged though. Use whatever OBP PROM
|
||||
provided to you.
|
||||
|
||||
And here is how you might unmap these registers later at
|
||||
driver shutdown or module unload time, using the sbus_iounmap
|
||||
interface:
|
||||
|
||||
static void mydevice_unmap_regs(struct mydevice *mp)
|
||||
{
|
||||
sbus_iounmap(mp->control_regs, CONTROL_REGS_SIZE);
|
||||
}
|
||||
|
||||
Finally, to actually access your registers there are 6
|
||||
interface routines at your disposal. Accesses are byte (8 bit),
|
||||
word (16 bit), or longword (32 bit) sized. Here they are:
|
||||
|
||||
u8 sbus_readb(unsigned long reg) /* read byte */
|
||||
u16 sbus_readw(unsigned long reg) /* read word */
|
||||
u32 sbus_readl(unsigned long reg) /* read longword */
|
||||
void sbus_writeb(u8 value, unsigned long reg) /* write byte */
|
||||
void sbus_writew(u16 value, unsigned long reg) /* write word */
|
||||
void sbus_writel(u32 value, unsigned long reg) /* write longword */
|
||||
|
||||
So, let's say your device has a control register of some sort
|
||||
at offset zero. The following might implement resetting your device:
|
||||
|
||||
#define CONTROL 0x00UL
|
||||
|
||||
#define CONTROL_RESET 0x00000001 /* Reset hardware */
|
||||
|
||||
static void mydevice_reset(struct mydevice *mp)
|
||||
{
|
||||
sbus_writel(CONTROL_RESET, mp->regs + CONTROL);
|
||||
}
|
||||
|
||||
Or perhaps there is a data port register at an offset of
|
||||
16 bytes which allows you to read bytes from a fifo in the device:
|
||||
|
||||
#define DATA 0x10UL
|
||||
|
||||
static u8 mydevice_get_byte(struct mydevice *mp)
|
||||
{
|
||||
return sbus_readb(mp->regs + DATA);
|
||||
}
|
||||
|
||||
It's pretty straightforward, and clueful readers may have
|
||||
noticed that these interfaces mimick the PCI interfaces of the
|
||||
Linux kernel. This was not by accident.
|
||||
|
||||
WARNING:
|
||||
|
||||
DO NOT try to treat these opaque register mapping
|
||||
values as a memory mapped pointer to some structure
|
||||
which you can dereference.
|
||||
|
||||
It may be memory mapped, it may not be. In fact it
|
||||
could be a physical address, or it could be the time
|
||||
of day xor'd with 0xdeadbeef. :-)
|
||||
|
||||
Whatever it is, it's an implementation detail. The
|
||||
interface was done this way to shield the driver
|
||||
author from such complexities.
|
||||
|
||||
Doing DVMA
|
||||
|
||||
SBUS devices can perform DMA transactions in a way similar
|
||||
to PCI but dissimilar to ISA, e.g. DMA masters supply address.
|
||||
In contrast to PCI, however, that address (a bus address) is
|
||||
translated by IOMMU before a memory access is performed and therefore
|
||||
it is virtual. Sun calls this procedure DVMA.
|
||||
|
||||
Linux supports two styles of using SBUS DVMA: "consistent memory"
|
||||
and "streaming DVMA". CPU view of consistent memory chunk is, well,
|
||||
consistent with a view of a device. Think of it as an uncached memory.
|
||||
Typically this way of doing DVMA is not very fast and drivers use it
|
||||
mostly for control blocks or queues. On some CPUs we cannot flush or
|
||||
invalidate individual pages or cache lines and doing explicit flushing
|
||||
over ever little byte in every control block would be wasteful.
|
||||
|
||||
Streaming DVMA is a preferred way to transfer large amounts of data.
|
||||
This process works in the following way:
|
||||
1. a CPU stops accessing a certain part of memory,
|
||||
flushes its caches covering that memory;
|
||||
2. a device does DVMA accesses, then posts an interrupt;
|
||||
3. CPU invalidates its caches and starts to access the memory.
|
||||
|
||||
A single streaming DVMA operation can touch several discontiguous
|
||||
regions of a virtual bus address space. This is called a scatter-gather
|
||||
DVMA.
|
||||
|
||||
[TBD: Why do not we neither Solaris attempt to map disjoint pages
|
||||
into a single virtual chunk with the help of IOMMU, so that non SG
|
||||
DVMA masters would do SG? It'd be very helpful for RAID.]
|
||||
|
||||
In order to perform a consistent DVMA a driver does something
|
||||
like the following:
|
||||
|
||||
char *mem; /* Address in the CPU space */
|
||||
u32 busa; /* Address in the SBus space */
|
||||
|
||||
mem = (char *) sbus_alloc_consistent(sdev, MYMEMSIZE, &busa);
|
||||
|
||||
Then mem is used when CPU accesses this memory and u32
|
||||
is fed to the device so that it can do DVMA. This is typically
|
||||
done with an sbus_writel() into some device register.
|
||||
|
||||
Do not forget to free the DVMA resources once you are done:
|
||||
|
||||
sbus_free_consistent(sdev, MYMEMSIZE, mem, busa);
|
||||
|
||||
Streaming DVMA is more interesting. First you allocate some
|
||||
memory suitable for it or pin down some user pages. Then it all works
|
||||
like this:
|
||||
|
||||
char *mem = argumen1;
|
||||
unsigned int size = argument2;
|
||||
u32 busa; /* Address in the SBus space */
|
||||
|
||||
*mem = 1; /* CPU can access */
|
||||
busa = sbus_map_single(sdev, mem, size);
|
||||
if (busa == 0) .......
|
||||
|
||||
/* Tell the device to use busa here */
|
||||
/* CPU cannot access the memory without sbus_dma_sync_single() */
|
||||
|
||||
sbus_unmap_single(sdev, busa, size);
|
||||
if (*mem == 0) .... /* CPU can access again */
|
||||
|
||||
It is possible to retain mappings and ask the device to
|
||||
access data again and again without calling sbus_unmap_single.
|
||||
However, CPU caches must be invalidated with sbus_dma_sync_single
|
||||
before such access.
|
||||
|
||||
[TBD but what about writeback caches here... do we have any?]
|
||||
|
||||
There is an equivalent set of functions doing the same thing
|
||||
only with several memory segments at once for devices capable of
|
||||
scatter-gather transfers. Use the Source, Luke.
|
||||
|
||||
Examples
|
||||
|
||||
drivers/net/sunhme.c
|
||||
This is a complicated driver which illustrates many concepts
|
||||
discussed above and plus it handles both PCI and SBUS boards.
|
||||
|
||||
drivers/scsi/esp.c
|
||||
Check it out for scatter-gather DVMA.
|
||||
|
||||
drivers/sbus/char/bpp.c
|
||||
A non-DVMA device.
|
||||
|
||||
drivers/net/sunlance.c
|
||||
Lance driver abuses consistent mappings for data transfer.
|
||||
It is a nifty trick which we do not particularly recommend...
|
||||
Just check it out and know that it's legal.
|
@ -20,6 +20,11 @@ config GENERIC_ISA_DMA
|
||||
bool
|
||||
default y
|
||||
|
||||
config GENERIC_GPIO
|
||||
bool
|
||||
help
|
||||
Generic GPIO API support
|
||||
|
||||
config ARCH_NO_VIRT_TO_BUS
|
||||
def_bool y
|
||||
|
||||
@ -69,6 +74,9 @@ config SPARC
|
||||
select HAVE_OPROFILE
|
||||
select HAVE_ARCH_KGDB if !SMP
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
select ARCH_WANT_OPTIONAL_GPIOLIB
|
||||
select RTC_CLASS
|
||||
select RTC_DRV_M48T59
|
||||
|
||||
# Identify this as a Sparc32 build
|
||||
config SPARC32
|
||||
@ -204,17 +212,6 @@ config SUN_PM
|
||||
Enable power management and CPU standby features on supported
|
||||
SPARC platforms.
|
||||
|
||||
config SUN4
|
||||
bool "Support for SUN4 machines (disables SUN4[CDM] support)"
|
||||
depends on !SMP
|
||||
default n
|
||||
help
|
||||
Say Y here if, and only if, your machine is a sun4. Note that
|
||||
a kernel compiled with this option will run only on sun4.
|
||||
(And the current version will probably work only on sun4/330.)
|
||||
|
||||
if !SUN4
|
||||
|
||||
config PCI
|
||||
bool "Support for PCI and PS/2 keyboard/mouse"
|
||||
help
|
||||
@ -227,11 +224,6 @@ config PCI_SYSCALL
|
||||
|
||||
source "drivers/pci/Kconfig"
|
||||
|
||||
endif
|
||||
|
||||
config NO_DMA
|
||||
def_bool !PCI
|
||||
|
||||
config SUN_OPENPROMFS
|
||||
tristate "Openprom tree appears in /proc/openprom"
|
||||
help
|
||||
@ -263,9 +255,7 @@ source "net/Kconfig"
|
||||
|
||||
source "drivers/Kconfig"
|
||||
|
||||
if !SUN4
|
||||
source "drivers/sbus/char/Kconfig"
|
||||
endif
|
||||
|
||||
# This one must be before the filesystem configs. -DaveM
|
||||
|
||||
|
@ -22,7 +22,6 @@ header-y += unistd_64.h
|
||||
|
||||
header-y += apc.h
|
||||
header-y += asi.h
|
||||
header-y += bpp.h
|
||||
header-y += display7seg.h
|
||||
header-y += envctrl.h
|
||||
header-y += fbio.h
|
||||
@ -41,5 +40,4 @@ header-y += reg_64.h
|
||||
header-y += traps.h
|
||||
header-y += uctx.h
|
||||
header-y += utrap.h
|
||||
header-y += vfc_ioctls.h
|
||||
header-y += watchdog.h
|
||||
|
@ -34,12 +34,7 @@
|
||||
/* sun4 probably wants half word accesses to ASI_SEGMAP, while sun4c+
|
||||
likes byte accesses. These are to avoid ifdef mania. */
|
||||
|
||||
#ifdef CONFIG_SUN4
|
||||
#define lduXa lduha
|
||||
#define stXa stha
|
||||
#else
|
||||
#define lduXa lduba
|
||||
#define stXa stba
|
||||
#endif
|
||||
|
||||
#endif /* !(_SPARC_ASMMACRO_H) */
|
||||
|
@ -1,73 +0,0 @@
|
||||
#ifndef _SPARC_BPP_H
|
||||
#define _SPARC_BPP_H
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995 Picture Elements
|
||||
* Stephen Williams
|
||||
* Gus Baldauf
|
||||
*
|
||||
* Linux/SPARC port by Peter Zaitcev.
|
||||
* Integration into SPARC tree by Tom Dyas.
|
||||
*/
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
/*
|
||||
* This is a driver that supports IEEE Std 1284-1994 communications
|
||||
* with compliant or compatible devices. It will use whatever features
|
||||
* the device supports, prefering those that are typically faster.
|
||||
*
|
||||
* When the device is opened, it is left in COMPATIBILITY mode, and
|
||||
* writes work like any printer device. The driver only attempt to
|
||||
* negotiate 1284 modes when needed so that plugs can be pulled,
|
||||
* switch boxes switched, etc., without disrupting things. It will
|
||||
* also leave the device in compatibility mode when closed.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This driver also supplies ioctls to manually manipulate the
|
||||
* pins. This is great for testing devices, or writing code to deal
|
||||
* with bizzarro-mode of the ACME Special TurboThingy Plus.
|
||||
*
|
||||
* NOTE: These ioctl currently do not interact well with
|
||||
* read/write. Caveat emptor.
|
||||
*
|
||||
* PUT_PINS allows us to assign the sense of all the pins, including
|
||||
* the data pins if being driven by the host. The GET_PINS returns the
|
||||
* pins that the peripheral drives, including data if appropriate.
|
||||
*/
|
||||
|
||||
# define BPP_PUT_PINS _IOW('B', 1, int)
|
||||
# define BPP_GET_PINS _IOR('B', 2, char) /* that's bogus - should've been _IO */
|
||||
# define BPP_PUT_DATA _IOW('B', 3, int)
|
||||
# define BPP_GET_DATA _IOR('B', 4, char) /* ditto */
|
||||
|
||||
/*
|
||||
* Set the data bus to input mode. Disengage the data bin driver and
|
||||
* be prepared to read values from the peripheral. If the arg is 0,
|
||||
* then revert the bus to output mode.
|
||||
*/
|
||||
# define BPP_SET_INPUT _IOW('B', 5, int)
|
||||
|
||||
/*
|
||||
* These bits apply to the PUT operation...
|
||||
*/
|
||||
# define BPP_PP_nStrobe 0x0001
|
||||
# define BPP_PP_nAutoFd 0x0002
|
||||
# define BPP_PP_nInit 0x0004
|
||||
# define BPP_PP_nSelectIn 0x0008
|
||||
|
||||
/*
|
||||
* These apply to the GET operation, which also reads the current value
|
||||
* of the previously put values. A bit mask of these will be returned
|
||||
* as a bit mask in the return code of the ioctl().
|
||||
*/
|
||||
# define BPP_GP_nAck 0x0100
|
||||
# define BPP_GP_Busy 0x0200
|
||||
# define BPP_GP_PError 0x0400
|
||||
# define BPP_GP_Select 0x0800
|
||||
# define BPP_GP_nFault 0x1000
|
||||
|
||||
#endif
|
@ -7,10 +7,6 @@
|
||||
#include <asm/cpudata.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPARC64
|
||||
#include <asm/sstate.h>
|
||||
#endif
|
||||
|
||||
extern unsigned long loops_per_jiffy;
|
||||
|
||||
static void __init check_bugs(void)
|
||||
@ -18,7 +14,4 @@ static void __init check_bugs(void)
|
||||
#if defined(CONFIG_SPARC32) && !defined(CONFIG_SMP)
|
||||
cpu_data(0).udelay_val = loops_per_jiffy;
|
||||
#endif
|
||||
#ifdef CONFIG_SPARC64
|
||||
sstate_running();
|
||||
#endif
|
||||
}
|
||||
|
@ -86,7 +86,6 @@ extern struct trap_per_cpu trap_block[NR_CPUS];
|
||||
extern void init_cur_cpu_trap(struct thread_info *);
|
||||
extern void setup_tba(void);
|
||||
extern int ncpus_probed;
|
||||
extern void __init cpu_probe(void);
|
||||
extern const struct seq_operations cpuinfo_op;
|
||||
|
||||
extern unsigned long real_hard_smp_processor_id(void);
|
||||
|
@ -1,11 +1,60 @@
|
||||
#ifndef _ASM_SPARC_DMA_MAPPING_H
|
||||
#define _ASM_SPARC_DMA_MAPPING_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#include <asm-generic/dma-mapping.h>
|
||||
#else
|
||||
#include <asm-generic/dma-mapping-broken.h>
|
||||
#endif /* PCI */
|
||||
struct device;
|
||||
struct scatterlist;
|
||||
struct page;
|
||||
|
||||
#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
|
||||
|
||||
extern int dma_supported(struct device *dev, u64 mask);
|
||||
extern int dma_set_mask(struct device *dev, u64 dma_mask);
|
||||
extern void *dma_alloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t flag);
|
||||
extern void dma_free_coherent(struct device *dev, size_t size,
|
||||
void *cpu_addr, dma_addr_t dma_handle);
|
||||
extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
|
||||
size_t size,
|
||||
enum dma_data_direction direction);
|
||||
extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
|
||||
size_t size,
|
||||
enum dma_data_direction direction);
|
||||
extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size,
|
||||
enum dma_data_direction direction);
|
||||
extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
|
||||
size_t size, enum dma_data_direction direction);
|
||||
extern int dma_map_sg(struct device *dev, struct scatterlist *sg,
|
||||
int nents, enum dma_data_direction direction);
|
||||
extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
|
||||
int nents, enum dma_data_direction direction);
|
||||
extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
|
||||
size_t size,
|
||||
enum dma_data_direction direction);
|
||||
extern void dma_sync_single_for_device(struct device *dev,
|
||||
dma_addr_t dma_handle,
|
||||
size_t size,
|
||||
enum dma_data_direction direction);
|
||||
extern void dma_sync_single_range_for_cpu(struct device *dev,
|
||||
dma_addr_t dma_handle,
|
||||
unsigned long offset,
|
||||
size_t size,
|
||||
enum dma_data_direction direction);
|
||||
extern void dma_sync_single_range_for_device(struct device *dev,
|
||||
dma_addr_t dma_handle,
|
||||
unsigned long offset, size_t size,
|
||||
enum dma_data_direction direction);
|
||||
extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
|
||||
int nelems, enum dma_data_direction direction);
|
||||
extern void dma_sync_sg_for_device(struct device *dev,
|
||||
struct scatterlist *sg, int nelems,
|
||||
enum dma_data_direction direction);
|
||||
extern int dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
|
||||
extern int dma_get_cache_alignment(void);
|
||||
|
||||
#define dma_alloc_noncoherent dma_alloc_coherent
|
||||
#define dma_free_noncoherent dma_free_coherent
|
||||
|
||||
#endif /* _ASM_SPARC_DMA_MAPPING_H */
|
||||
|
@ -1,8 +1,139 @@
|
||||
#ifndef ___ASM_SPARC_DMA_H
|
||||
#define ___ASM_SPARC_DMA_H
|
||||
#if defined(__sparc__) && defined(__arch64__)
|
||||
#include <asm/dma_64.h>
|
||||
#ifndef _ASM_SPARC_DMA_H
|
||||
#define _ASM_SPARC_DMA_H
|
||||
|
||||
/* These are irrelevant for Sparc DMA, but we leave it in so that
|
||||
* things can compile.
|
||||
*/
|
||||
#define MAX_DMA_CHANNELS 8
|
||||
#define DMA_MODE_READ 1
|
||||
#define DMA_MODE_WRITE 2
|
||||
#define MAX_DMA_ADDRESS (~0UL)
|
||||
|
||||
/* Useful constants */
|
||||
#define SIZE_16MB (16*1024*1024)
|
||||
#define SIZE_64K (64*1024)
|
||||
|
||||
/* SBUS DMA controller reg offsets */
|
||||
#define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */
|
||||
#define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */
|
||||
#define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */
|
||||
#define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */
|
||||
|
||||
/* Fields in the cond_reg register */
|
||||
/* First, the version identification bits */
|
||||
#define DMA_DEVICE_ID 0xf0000000 /* Device identification bits */
|
||||
#define DMA_VERS0 0x00000000 /* Sunray DMA version */
|
||||
#define DMA_ESCV1 0x40000000 /* DMA ESC Version 1 */
|
||||
#define DMA_VERS1 0x80000000 /* DMA rev 1 */
|
||||
#define DMA_VERS2 0xa0000000 /* DMA rev 2 */
|
||||
#define DMA_VERHME 0xb0000000 /* DMA hme gate array */
|
||||
#define DMA_VERSPLUS 0x90000000 /* DMA rev 1 PLUS */
|
||||
|
||||
#define DMA_HNDL_INTR 0x00000001 /* An IRQ needs to be handled */
|
||||
#define DMA_HNDL_ERROR 0x00000002 /* We need to take an error */
|
||||
#define DMA_FIFO_ISDRAIN 0x0000000c /* The DMA FIFO is draining */
|
||||
#define DMA_INT_ENAB 0x00000010 /* Turn on interrupts */
|
||||
#define DMA_FIFO_INV 0x00000020 /* Invalidate the FIFO */
|
||||
#define DMA_ACC_SZ_ERR 0x00000040 /* The access size was bad */
|
||||
#define DMA_FIFO_STDRAIN 0x00000040 /* DMA_VERS1 Drain the FIFO */
|
||||
#define DMA_RST_SCSI 0x00000080 /* Reset the SCSI controller */
|
||||
#define DMA_RST_ENET DMA_RST_SCSI /* Reset the ENET controller */
|
||||
#define DMA_ST_WRITE 0x00000100 /* write from device to memory */
|
||||
#define DMA_ENABLE 0x00000200 /* Fire up DMA, handle requests */
|
||||
#define DMA_PEND_READ 0x00000400 /* DMA_VERS1/0/PLUS Pending Read */
|
||||
#define DMA_ESC_BURST 0x00000800 /* 1=16byte 0=32byte */
|
||||
#define DMA_READ_AHEAD 0x00001800 /* DMA read ahead partial longword */
|
||||
#define DMA_DSBL_RD_DRN 0x00001000 /* No EC drain on slave reads */
|
||||
#define DMA_BCNT_ENAB 0x00002000 /* If on, use the byte counter */
|
||||
#define DMA_TERM_CNTR 0x00004000 /* Terminal counter */
|
||||
#define DMA_SCSI_SBUS64 0x00008000 /* HME: Enable 64-bit SBUS mode. */
|
||||
#define DMA_CSR_DISAB 0x00010000 /* No FIFO drains during csr */
|
||||
#define DMA_SCSI_DISAB 0x00020000 /* No FIFO drains during reg */
|
||||
#define DMA_DSBL_WR_INV 0x00020000 /* No EC inval. on slave writes */
|
||||
#define DMA_ADD_ENABLE 0x00040000 /* Special ESC DVMA optimization */
|
||||
#define DMA_E_BURSTS 0x000c0000 /* ENET: SBUS r/w burst mask */
|
||||
#define DMA_E_BURST32 0x00040000 /* ENET: SBUS 32 byte r/w burst */
|
||||
#define DMA_E_BURST16 0x00000000 /* ENET: SBUS 16 byte r/w burst */
|
||||
#define DMA_BRST_SZ 0x000c0000 /* SCSI: SBUS r/w burst size */
|
||||
#define DMA_BRST64 0x000c0000 /* SCSI: 64byte bursts (HME on UltraSparc only) */
|
||||
#define DMA_BRST32 0x00040000 /* SCSI: 32byte bursts */
|
||||
#define DMA_BRST16 0x00000000 /* SCSI: 16byte bursts */
|
||||
#define DMA_BRST0 0x00080000 /* SCSI: no bursts (non-HME gate arrays) */
|
||||
#define DMA_ADDR_DISAB 0x00100000 /* No FIFO drains during addr */
|
||||
#define DMA_2CLKS 0x00200000 /* Each transfer = 2 clock ticks */
|
||||
#define DMA_3CLKS 0x00400000 /* Each transfer = 3 clock ticks */
|
||||
#define DMA_EN_ENETAUI DMA_3CLKS /* Put lance into AUI-cable mode */
|
||||
#define DMA_CNTR_DISAB 0x00800000 /* No IRQ when DMA_TERM_CNTR set */
|
||||
#define DMA_AUTO_NADDR 0x01000000 /* Use "auto nxt addr" feature */
|
||||
#define DMA_SCSI_ON 0x02000000 /* Enable SCSI dma */
|
||||
#define DMA_PARITY_OFF 0x02000000 /* HME: disable parity checking */
|
||||
#define DMA_LOADED_ADDR 0x04000000 /* Address has been loaded */
|
||||
#define DMA_LOADED_NADDR 0x08000000 /* Next address has been loaded */
|
||||
#define DMA_RESET_FAS366 0x08000000 /* HME: Assert RESET to FAS366 */
|
||||
|
||||
/* Values describing the burst-size property from the PROM */
|
||||
#define DMA_BURST1 0x01
|
||||
#define DMA_BURST2 0x02
|
||||
#define DMA_BURST4 0x04
|
||||
#define DMA_BURST8 0x08
|
||||
#define DMA_BURST16 0x10
|
||||
#define DMA_BURST32 0x20
|
||||
#define DMA_BURST64 0x40
|
||||
#define DMA_BURSTBITS 0x7f
|
||||
|
||||
/* From PCI */
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
extern int isa_dma_bridge_buggy;
|
||||
#else
|
||||
#include <asm/dma_32.h>
|
||||
#define isa_dma_bridge_buggy (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPARC32
|
||||
|
||||
/* Routines for data transfer buffers. */
|
||||
BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
|
||||
BTFIXUPDEF_CALL(void, mmu_unlockarea, char *, unsigned long)
|
||||
|
||||
#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len)
|
||||
#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len)
|
||||
|
||||
struct page;
|
||||
struct device;
|
||||
struct scatterlist;
|
||||
|
||||
/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */
|
||||
BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, struct device *, char *, unsigned long)
|
||||
BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct device *, struct scatterlist *, int)
|
||||
BTFIXUPDEF_CALL(void, mmu_release_scsi_one, struct device *, __u32, unsigned long)
|
||||
BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct device *, struct scatterlist *, int)
|
||||
|
||||
#define mmu_get_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_get_scsi_one)(dev,vaddr,len)
|
||||
#define mmu_get_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_get_scsi_sgl)(dev,sg,sz)
|
||||
#define mmu_release_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_release_scsi_one)(dev,vaddr,len)
|
||||
#define mmu_release_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_release_scsi_sgl)(dev,sg,sz)
|
||||
|
||||
/*
|
||||
* mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep.
|
||||
*
|
||||
* The mmu_map_dma_area establishes two mappings in one go.
|
||||
* These mappings point to pages normally mapped at 'va' (linear address).
|
||||
* First mapping is for CPU visible address at 'a', uncached.
|
||||
* This is an alias, but it works because it is an uncached mapping.
|
||||
* Second mapping is for device visible address, or "bus" address.
|
||||
* The bus address is returned at '*pba'.
|
||||
*
|
||||
* These functions seem distinct, but are hard to split. On sun4c,
|
||||
* at least for now, 'a' is equal to bus address, and retured in *pba.
|
||||
* On sun4m, page attributes depend on the CPU type, so we have to
|
||||
* know if we are mapping RAM or I/O, so it has to be an additional argument
|
||||
* to a separate mapping function for CPU visible mappings.
|
||||
*/
|
||||
BTFIXUPDEF_CALL(int, mmu_map_dma_area, struct device *, dma_addr_t *, unsigned long, unsigned long, int len)
|
||||
BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, struct device *, unsigned long busa, int len)
|
||||
|
||||
#define mmu_map_dma_area(dev,pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(dev,pba,va,a,len)
|
||||
#define mmu_unmap_dma_area(dev,ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(dev,ba,len)
|
||||
#endif
|
||||
|
||||
#endif /* !(_ASM_SPARC_DMA_H) */
|
||||
|
@ -1,288 +0,0 @@
|
||||
/* include/asm/dma.h
|
||||
*
|
||||
* Copyright 1995 (C) David S. Miller (davem@davemloft.net)
|
||||
*/
|
||||
|
||||
#ifndef _ASM_SPARC_DMA_H
|
||||
#define _ASM_SPARC_DMA_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/vac-ops.h> /* for invalidate's, etc. */
|
||||
#include <asm/sbus.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
struct page;
|
||||
extern spinlock_t dma_spin_lock;
|
||||
|
||||
static inline unsigned long claim_dma_lock(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&dma_spin_lock, flags);
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline void release_dma_lock(unsigned long flags)
|
||||
{
|
||||
spin_unlock_irqrestore(&dma_spin_lock, flags);
|
||||
}
|
||||
|
||||
/* These are irrelevant for Sparc DMA, but we leave it in so that
|
||||
* things can compile.
|
||||
*/
|
||||
#define MAX_DMA_CHANNELS 8
|
||||
#define MAX_DMA_ADDRESS (~0UL)
|
||||
#define DMA_MODE_READ 1
|
||||
#define DMA_MODE_WRITE 2
|
||||
|
||||
/* Useful constants */
|
||||
#define SIZE_16MB (16*1024*1024)
|
||||
#define SIZE_64K (64*1024)
|
||||
|
||||
/* SBUS DMA controller reg offsets */
|
||||
#define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */
|
||||
#define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */
|
||||
#define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */
|
||||
#define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */
|
||||
|
||||
/* DVMA chip revisions */
|
||||
enum dvma_rev {
|
||||
dvmarev0,
|
||||
dvmaesc1,
|
||||
dvmarev1,
|
||||
dvmarev2,
|
||||
dvmarev3,
|
||||
dvmarevplus,
|
||||
dvmahme
|
||||
};
|
||||
|
||||
#define DMA_HASCOUNT(rev) ((rev)==dvmaesc1)
|
||||
|
||||
/* Linux DMA information structure, filled during probe. */
|
||||
struct sbus_dma {
|
||||
struct sbus_dma *next;
|
||||
struct sbus_dev *sdev;
|
||||
void __iomem *regs;
|
||||
|
||||
/* Status, misc info */
|
||||
int node; /* Prom node for this DMA device */
|
||||
int running; /* Are we doing DMA now? */
|
||||
int allocated; /* Are we "owned" by anyone yet? */
|
||||
|
||||
/* Transfer information. */
|
||||
unsigned long addr; /* Start address of current transfer */
|
||||
int nbytes; /* Size of current transfer */
|
||||
int realbytes; /* For splitting up large transfers, etc. */
|
||||
|
||||
/* DMA revision */
|
||||
enum dvma_rev revision;
|
||||
};
|
||||
|
||||
extern struct sbus_dma *dma_chain;
|
||||
|
||||
/* Broken hardware... */
|
||||
#ifdef CONFIG_SUN4
|
||||
/* Have to sort this out. Does rev0 work fine on sun4[cmd] without isbroken?
|
||||
* Or is rev0 present only on sun4 boxes? -jj */
|
||||
#define DMA_ISBROKEN(dma) ((dma)->revision == dvmarev0 || (dma)->revision == dvmarev1)
|
||||
#else
|
||||
#define DMA_ISBROKEN(dma) ((dma)->revision == dvmarev1)
|
||||
#endif
|
||||
#define DMA_ISESC1(dma) ((dma)->revision == dvmaesc1)
|
||||
|
||||
/* Main routines in dma.c */
|
||||
extern void dvma_init(struct sbus_bus *);
|
||||
|
||||
/* Fields in the cond_reg register */
|
||||
/* First, the version identification bits */
|
||||
#define DMA_DEVICE_ID 0xf0000000 /* Device identification bits */
|
||||
#define DMA_VERS0 0x00000000 /* Sunray DMA version */
|
||||
#define DMA_ESCV1 0x40000000 /* DMA ESC Version 1 */
|
||||
#define DMA_VERS1 0x80000000 /* DMA rev 1 */
|
||||
#define DMA_VERS2 0xa0000000 /* DMA rev 2 */
|
||||
#define DMA_VERHME 0xb0000000 /* DMA hme gate array */
|
||||
#define DMA_VERSPLUS 0x90000000 /* DMA rev 1 PLUS */
|
||||
|
||||
#define DMA_HNDL_INTR 0x00000001 /* An IRQ needs to be handled */
|
||||
#define DMA_HNDL_ERROR 0x00000002 /* We need to take an error */
|
||||
#define DMA_FIFO_ISDRAIN 0x0000000c /* The DMA FIFO is draining */
|
||||
#define DMA_INT_ENAB 0x00000010 /* Turn on interrupts */
|
||||
#define DMA_FIFO_INV 0x00000020 /* Invalidate the FIFO */
|
||||
#define DMA_ACC_SZ_ERR 0x00000040 /* The access size was bad */
|
||||
#define DMA_FIFO_STDRAIN 0x00000040 /* DMA_VERS1 Drain the FIFO */
|
||||
#define DMA_RST_SCSI 0x00000080 /* Reset the SCSI controller */
|
||||
#define DMA_RST_ENET DMA_RST_SCSI /* Reset the ENET controller */
|
||||
#define DMA_RST_BPP DMA_RST_SCSI /* Reset the BPP controller */
|
||||
#define DMA_ST_WRITE 0x00000100 /* write from device to memory */
|
||||
#define DMA_ENABLE 0x00000200 /* Fire up DMA, handle requests */
|
||||
#define DMA_PEND_READ 0x00000400 /* DMA_VERS1/0/PLUS Pending Read */
|
||||
#define DMA_ESC_BURST 0x00000800 /* 1=16byte 0=32byte */
|
||||
#define DMA_READ_AHEAD 0x00001800 /* DMA read ahead partial longword */
|
||||
#define DMA_DSBL_RD_DRN 0x00001000 /* No EC drain on slave reads */
|
||||
#define DMA_BCNT_ENAB 0x00002000 /* If on, use the byte counter */
|
||||
#define DMA_TERM_CNTR 0x00004000 /* Terminal counter */
|
||||
#define DMA_SCSI_SBUS64 0x00008000 /* HME: Enable 64-bit SBUS mode. */
|
||||
#define DMA_CSR_DISAB 0x00010000 /* No FIFO drains during csr */
|
||||
#define DMA_SCSI_DISAB 0x00020000 /* No FIFO drains during reg */
|
||||
#define DMA_DSBL_WR_INV 0x00020000 /* No EC inval. on slave writes */
|
||||
#define DMA_ADD_ENABLE 0x00040000 /* Special ESC DVMA optimization */
|
||||
#define DMA_E_BURSTS 0x000c0000 /* ENET: SBUS r/w burst mask */
|
||||
#define DMA_E_BURST32 0x00040000 /* ENET: SBUS 32 byte r/w burst */
|
||||
#define DMA_E_BURST16 0x00000000 /* ENET: SBUS 16 byte r/w burst */
|
||||
#define DMA_BRST_SZ 0x000c0000 /* SCSI: SBUS r/w burst size */
|
||||
#define DMA_BRST64 0x00080000 /* SCSI: 64byte bursts (HME on UltraSparc only) */
|
||||
#define DMA_BRST32 0x00040000 /* SCSI/BPP: 32byte bursts */
|
||||
#define DMA_BRST16 0x00000000 /* SCSI/BPP: 16byte bursts */
|
||||
#define DMA_BRST0 0x00080000 /* SCSI: no bursts (non-HME gate arrays) */
|
||||
#define DMA_ADDR_DISAB 0x00100000 /* No FIFO drains during addr */
|
||||
#define DMA_2CLKS 0x00200000 /* Each transfer = 2 clock ticks */
|
||||
#define DMA_3CLKS 0x00400000 /* Each transfer = 3 clock ticks */
|
||||
#define DMA_EN_ENETAUI DMA_3CLKS /* Put lance into AUI-cable mode */
|
||||
#define DMA_CNTR_DISAB 0x00800000 /* No IRQ when DMA_TERM_CNTR set */
|
||||
#define DMA_AUTO_NADDR 0x01000000 /* Use "auto nxt addr" feature */
|
||||
#define DMA_SCSI_ON 0x02000000 /* Enable SCSI dma */
|
||||
#define DMA_BPP_ON DMA_SCSI_ON /* Enable BPP dma */
|
||||
#define DMA_PARITY_OFF 0x02000000 /* HME: disable parity checking */
|
||||
#define DMA_LOADED_ADDR 0x04000000 /* Address has been loaded */
|
||||
#define DMA_LOADED_NADDR 0x08000000 /* Next address has been loaded */
|
||||
#define DMA_RESET_FAS366 0x08000000 /* HME: Assert RESET to FAS366 */
|
||||
|
||||
/* Values describing the burst-size property from the PROM */
|
||||
#define DMA_BURST1 0x01
|
||||
#define DMA_BURST2 0x02
|
||||
#define DMA_BURST4 0x04
|
||||
#define DMA_BURST8 0x08
|
||||
#define DMA_BURST16 0x10
|
||||
#define DMA_BURST32 0x20
|
||||
#define DMA_BURST64 0x40
|
||||
#define DMA_BURSTBITS 0x7f
|
||||
|
||||
/* Determine highest possible final transfer address given a base */
|
||||
#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
|
||||
|
||||
/* Yes, I hack a lot of elisp in my spare time... */
|
||||
#define DMA_ERROR_P(regs) ((((regs)->cond_reg) & DMA_HNDL_ERROR))
|
||||
#define DMA_IRQ_P(regs) ((((regs)->cond_reg) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)))
|
||||
#define DMA_WRITE_P(regs) ((((regs)->cond_reg) & DMA_ST_WRITE))
|
||||
#define DMA_OFF(regs) ((((regs)->cond_reg) &= (~DMA_ENABLE)))
|
||||
#define DMA_INTSOFF(regs) ((((regs)->cond_reg) &= (~DMA_INT_ENAB)))
|
||||
#define DMA_INTSON(regs) ((((regs)->cond_reg) |= (DMA_INT_ENAB)))
|
||||
#define DMA_PUNTFIFO(regs) ((((regs)->cond_reg) |= DMA_FIFO_INV))
|
||||
#define DMA_SETSTART(regs, addr) ((((regs)->st_addr) = (char *) addr))
|
||||
#define DMA_BEGINDMA_W(regs) \
|
||||
((((regs)->cond_reg |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB))))
|
||||
#define DMA_BEGINDMA_R(regs) \
|
||||
((((regs)->cond_reg |= ((DMA_ENABLE|DMA_INT_ENAB)&(~DMA_ST_WRITE)))))
|
||||
|
||||
/* For certain DMA chips, we need to disable ints upon irq entry
|
||||
* and turn them back on when we are done. So in any ESP interrupt
|
||||
* handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
|
||||
* when leaving the handler. You have been warned...
|
||||
*/
|
||||
#define DMA_IRQ_ENTRY(dma, dregs) do { \
|
||||
if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
|
||||
} while (0)
|
||||
|
||||
#define DMA_IRQ_EXIT(dma, dregs) do { \
|
||||
if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
|
||||
} while(0)
|
||||
|
||||
#if 0 /* P3 this stuff is inline in ledma.c:init_restart_ledma() */
|
||||
/* Pause until counter runs out or BIT isn't set in the DMA condition
|
||||
* register.
|
||||
*/
|
||||
static inline void sparc_dma_pause(struct sparc_dma_registers *regs,
|
||||
unsigned long bit)
|
||||
{
|
||||
int ctr = 50000; /* Let's find some bugs ;) */
|
||||
|
||||
/* Busy wait until the bit is not set any more */
|
||||
while((regs->cond_reg&bit) && (ctr>0)) {
|
||||
ctr--;
|
||||
__delay(5);
|
||||
}
|
||||
|
||||
/* Check for bogus outcome. */
|
||||
if(!ctr)
|
||||
panic("DMA timeout");
|
||||
}
|
||||
|
||||
/* Reset the friggin' thing... */
|
||||
#define DMA_RESET(dma) do { \
|
||||
struct sparc_dma_registers *regs = dma->regs; \
|
||||
/* Let the current FIFO drain itself */ \
|
||||
sparc_dma_pause(regs, (DMA_FIFO_ISDRAIN)); \
|
||||
/* Reset the logic */ \
|
||||
regs->cond_reg |= (DMA_RST_SCSI); /* assert */ \
|
||||
__delay(400); /* let the bits set ;) */ \
|
||||
regs->cond_reg &= ~(DMA_RST_SCSI); /* de-assert */ \
|
||||
sparc_dma_enable_interrupts(regs); /* Re-enable interrupts */ \
|
||||
/* Enable FAST transfers if available */ \
|
||||
if(dma->revision>dvmarev1) regs->cond_reg |= DMA_3CLKS; \
|
||||
dma->running = 0; \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
#define for_each_dvma(dma) \
|
||||
for((dma) = dma_chain; (dma); (dma) = (dma)->next)
|
||||
|
||||
extern int get_dma_list(char *);
|
||||
extern int request_dma(unsigned int, __const__ char *);
|
||||
extern void free_dma(unsigned int);
|
||||
|
||||
/* From PCI */
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
extern int isa_dma_bridge_buggy;
|
||||
#else
|
||||
#define isa_dma_bridge_buggy (0)
|
||||
#endif
|
||||
|
||||
/* Routines for data transfer buffers. */
|
||||
BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
|
||||
BTFIXUPDEF_CALL(void, mmu_unlockarea, char *, unsigned long)
|
||||
|
||||
#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len)
|
||||
#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len)
|
||||
|
||||
/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */
|
||||
BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, char *, unsigned long, struct sbus_bus *sbus)
|
||||
BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus)
|
||||
BTFIXUPDEF_CALL(void, mmu_release_scsi_one, __u32, unsigned long, struct sbus_bus *sbus)
|
||||
BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus)
|
||||
|
||||
#define mmu_get_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_get_scsi_one)(vaddr,len,sbus)
|
||||
#define mmu_get_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_get_scsi_sgl)(sg,sz,sbus)
|
||||
#define mmu_release_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_release_scsi_one)(vaddr,len,sbus)
|
||||
#define mmu_release_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_release_scsi_sgl)(sg,sz,sbus)
|
||||
|
||||
/*
|
||||
* mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep.
|
||||
*
|
||||
* The mmu_map_dma_area establishes two mappings in one go.
|
||||
* These mappings point to pages normally mapped at 'va' (linear address).
|
||||
* First mapping is for CPU visible address at 'a', uncached.
|
||||
* This is an alias, but it works because it is an uncached mapping.
|
||||
* Second mapping is for device visible address, or "bus" address.
|
||||
* The bus address is returned at '*pba'.
|
||||
*
|
||||
* These functions seem distinct, but are hard to split. On sun4c,
|
||||
* at least for now, 'a' is equal to bus address, and retured in *pba.
|
||||
* On sun4m, page attributes depend on the CPU type, so we have to
|
||||
* know if we are mapping RAM or I/O, so it has to be an additional argument
|
||||
* to a separate mapping function for CPU visible mappings.
|
||||
*/
|
||||
BTFIXUPDEF_CALL(int, mmu_map_dma_area, dma_addr_t *, unsigned long, unsigned long, int len)
|
||||
BTFIXUPDEF_CALL(struct page *, mmu_translate_dvma, unsigned long busa)
|
||||
BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, unsigned long busa, int len)
|
||||
|
||||
#define mmu_map_dma_area(pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(pba,va,a,len)
|
||||
#define mmu_unmap_dma_area(ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(ba,len)
|
||||
#define mmu_translate_dvma(ba) BTFIXUP_CALL(mmu_translate_dvma)(ba)
|
||||
|
||||
#endif /* !(_ASM_SPARC_DMA_H) */
|
@ -1,205 +0,0 @@
|
||||
/*
|
||||
* include/asm/dma.h
|
||||
*
|
||||
* Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
|
||||
*/
|
||||
|
||||
#ifndef _ASM_SPARC64_DMA_H
|
||||
#define _ASM_SPARC64_DMA_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/sbus.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/oplib.h>
|
||||
|
||||
/* These are irrelevant for Sparc DMA, but we leave it in so that
|
||||
* things can compile.
|
||||
*/
|
||||
#define MAX_DMA_CHANNELS 8
|
||||
#define DMA_MODE_READ 1
|
||||
#define DMA_MODE_WRITE 2
|
||||
#define MAX_DMA_ADDRESS (~0UL)
|
||||
|
||||
/* Useful constants */
|
||||
#define SIZE_16MB (16*1024*1024)
|
||||
#define SIZE_64K (64*1024)
|
||||
|
||||
/* SBUS DMA controller reg offsets */
|
||||
#define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */
|
||||
#define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */
|
||||
#define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */
|
||||
#define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */
|
||||
|
||||
/* DVMA chip revisions */
|
||||
enum dvma_rev {
|
||||
dvmarev0,
|
||||
dvmaesc1,
|
||||
dvmarev1,
|
||||
dvmarev2,
|
||||
dvmarev3,
|
||||
dvmarevplus,
|
||||
dvmahme
|
||||
};
|
||||
|
||||
#define DMA_HASCOUNT(rev) ((rev)==dvmaesc1)
|
||||
|
||||
/* Linux DMA information structure, filled during probe. */
|
||||
struct sbus_dma {
|
||||
struct sbus_dma *next;
|
||||
struct sbus_dev *sdev;
|
||||
void __iomem *regs;
|
||||
|
||||
/* Status, misc info */
|
||||
int node; /* Prom node for this DMA device */
|
||||
int running; /* Are we doing DMA now? */
|
||||
int allocated; /* Are we "owned" by anyone yet? */
|
||||
|
||||
/* Transfer information. */
|
||||
u32 addr; /* Start address of current transfer */
|
||||
int nbytes; /* Size of current transfer */
|
||||
int realbytes; /* For splitting up large transfers, etc. */
|
||||
|
||||
/* DMA revision */
|
||||
enum dvma_rev revision;
|
||||
};
|
||||
|
||||
extern struct sbus_dma *dma_chain;
|
||||
|
||||
/* Broken hardware... */
|
||||
#define DMA_ISBROKEN(dma) ((dma)->revision == dvmarev1)
|
||||
#define DMA_ISESC1(dma) ((dma)->revision == dvmaesc1)
|
||||
|
||||
/* Main routines in dma.c */
|
||||
extern void dvma_init(struct sbus_bus *);
|
||||
|
||||
/* Fields in the cond_reg register */
|
||||
/* First, the version identification bits */
|
||||
#define DMA_DEVICE_ID 0xf0000000 /* Device identification bits */
|
||||
#define DMA_VERS0 0x00000000 /* Sunray DMA version */
|
||||
#define DMA_ESCV1 0x40000000 /* DMA ESC Version 1 */
|
||||
#define DMA_VERS1 0x80000000 /* DMA rev 1 */
|
||||
#define DMA_VERS2 0xa0000000 /* DMA rev 2 */
|
||||
#define DMA_VERHME 0xb0000000 /* DMA hme gate array */
|
||||
#define DMA_VERSPLUS 0x90000000 /* DMA rev 1 PLUS */
|
||||
|
||||
#define DMA_HNDL_INTR 0x00000001 /* An IRQ needs to be handled */
|
||||
#define DMA_HNDL_ERROR 0x00000002 /* We need to take an error */
|
||||
#define DMA_FIFO_ISDRAIN 0x0000000c /* The DMA FIFO is draining */
|
||||
#define DMA_INT_ENAB 0x00000010 /* Turn on interrupts */
|
||||
#define DMA_FIFO_INV 0x00000020 /* Invalidate the FIFO */
|
||||
#define DMA_ACC_SZ_ERR 0x00000040 /* The access size was bad */
|
||||
#define DMA_FIFO_STDRAIN 0x00000040 /* DMA_VERS1 Drain the FIFO */
|
||||
#define DMA_RST_SCSI 0x00000080 /* Reset the SCSI controller */
|
||||
#define DMA_RST_ENET DMA_RST_SCSI /* Reset the ENET controller */
|
||||
#define DMA_ST_WRITE 0x00000100 /* write from device to memory */
|
||||
#define DMA_ENABLE 0x00000200 /* Fire up DMA, handle requests */
|
||||
#define DMA_PEND_READ 0x00000400 /* DMA_VERS1/0/PLUS Pending Read */
|
||||
#define DMA_ESC_BURST 0x00000800 /* 1=16byte 0=32byte */
|
||||
#define DMA_READ_AHEAD 0x00001800 /* DMA read ahead partial longword */
|
||||
#define DMA_DSBL_RD_DRN 0x00001000 /* No EC drain on slave reads */
|
||||
#define DMA_BCNT_ENAB 0x00002000 /* If on, use the byte counter */
|
||||
#define DMA_TERM_CNTR 0x00004000 /* Terminal counter */
|
||||
#define DMA_SCSI_SBUS64 0x00008000 /* HME: Enable 64-bit SBUS mode. */
|
||||
#define DMA_CSR_DISAB 0x00010000 /* No FIFO drains during csr */
|
||||
#define DMA_SCSI_DISAB 0x00020000 /* No FIFO drains during reg */
|
||||
#define DMA_DSBL_WR_INV 0x00020000 /* No EC inval. on slave writes */
|
||||
#define DMA_ADD_ENABLE 0x00040000 /* Special ESC DVMA optimization */
|
||||
#define DMA_E_BURSTS 0x000c0000 /* ENET: SBUS r/w burst mask */
|
||||
#define DMA_E_BURST32 0x00040000 /* ENET: SBUS 32 byte r/w burst */
|
||||
#define DMA_E_BURST16 0x00000000 /* ENET: SBUS 16 byte r/w burst */
|
||||
#define DMA_BRST_SZ 0x000c0000 /* SCSI: SBUS r/w burst size */
|
||||
#define DMA_BRST64 0x000c0000 /* SCSI: 64byte bursts (HME on UltraSparc only) */
|
||||
#define DMA_BRST32 0x00040000 /* SCSI: 32byte bursts */
|
||||
#define DMA_BRST16 0x00000000 /* SCSI: 16byte bursts */
|
||||
#define DMA_BRST0 0x00080000 /* SCSI: no bursts (non-HME gate arrays) */
|
||||
#define DMA_ADDR_DISAB 0x00100000 /* No FIFO drains during addr */
|
||||
#define DMA_2CLKS 0x00200000 /* Each transfer = 2 clock ticks */
|
||||
#define DMA_3CLKS 0x00400000 /* Each transfer = 3 clock ticks */
|
||||
#define DMA_EN_ENETAUI DMA_3CLKS /* Put lance into AUI-cable mode */
|
||||
#define DMA_CNTR_DISAB 0x00800000 /* No IRQ when DMA_TERM_CNTR set */
|
||||
#define DMA_AUTO_NADDR 0x01000000 /* Use "auto nxt addr" feature */
|
||||
#define DMA_SCSI_ON 0x02000000 /* Enable SCSI dma */
|
||||
#define DMA_PARITY_OFF 0x02000000 /* HME: disable parity checking */
|
||||
#define DMA_LOADED_ADDR 0x04000000 /* Address has been loaded */
|
||||
#define DMA_LOADED_NADDR 0x08000000 /* Next address has been loaded */
|
||||
#define DMA_RESET_FAS366 0x08000000 /* HME: Assert RESET to FAS366 */
|
||||
|
||||
/* Values describing the burst-size property from the PROM */
|
||||
#define DMA_BURST1 0x01
|
||||
#define DMA_BURST2 0x02
|
||||
#define DMA_BURST4 0x04
|
||||
#define DMA_BURST8 0x08
|
||||
#define DMA_BURST16 0x10
|
||||
#define DMA_BURST32 0x20
|
||||
#define DMA_BURST64 0x40
|
||||
#define DMA_BURSTBITS 0x7f
|
||||
|
||||
/* Determine highest possible final transfer address given a base */
|
||||
#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
|
||||
|
||||
/* Yes, I hack a lot of elisp in my spare time... */
|
||||
#define DMA_ERROR_P(regs) ((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR))
|
||||
#define DMA_IRQ_P(regs) ((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
|
||||
#define DMA_WRITE_P(regs) ((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE))
|
||||
#define DMA_OFF(__regs) \
|
||||
do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
|
||||
tmp &= ~DMA_ENABLE; \
|
||||
sbus_writel(tmp, (__regs) + DMA_CSR); \
|
||||
} while(0)
|
||||
#define DMA_INTSOFF(__regs) \
|
||||
do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
|
||||
tmp &= ~DMA_INT_ENAB; \
|
||||
sbus_writel(tmp, (__regs) + DMA_CSR); \
|
||||
} while(0)
|
||||
#define DMA_INTSON(__regs) \
|
||||
do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
|
||||
tmp |= DMA_INT_ENAB; \
|
||||
sbus_writel(tmp, (__regs) + DMA_CSR); \
|
||||
} while(0)
|
||||
#define DMA_PUNTFIFO(__regs) \
|
||||
do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
|
||||
tmp |= DMA_FIFO_INV; \
|
||||
sbus_writel(tmp, (__regs) + DMA_CSR); \
|
||||
} while(0)
|
||||
#define DMA_SETSTART(__regs, __addr) \
|
||||
sbus_writel((u32)(__addr), (__regs) + DMA_ADDR);
|
||||
#define DMA_BEGINDMA_W(__regs) \
|
||||
do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
|
||||
tmp |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB); \
|
||||
sbus_writel(tmp, (__regs) + DMA_CSR); \
|
||||
} while(0)
|
||||
#define DMA_BEGINDMA_R(__regs) \
|
||||
do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
|
||||
tmp |= (DMA_ENABLE|DMA_INT_ENAB); \
|
||||
tmp &= ~DMA_ST_WRITE; \
|
||||
sbus_writel(tmp, (__regs) + DMA_CSR); \
|
||||
} while(0)
|
||||
|
||||
/* For certain DMA chips, we need to disable ints upon irq entry
|
||||
* and turn them back on when we are done. So in any ESP interrupt
|
||||
* handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
|
||||
* when leaving the handler. You have been warned...
|
||||
*/
|
||||
#define DMA_IRQ_ENTRY(dma, dregs) do { \
|
||||
if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
|
||||
} while (0)
|
||||
|
||||
#define DMA_IRQ_EXIT(dma, dregs) do { \
|
||||
if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
|
||||
} while(0)
|
||||
|
||||
#define for_each_dvma(dma) \
|
||||
for((dma) = dma_chain; (dma); (dma) = (dma)->next)
|
||||
|
||||
/* From PCI */
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
extern int isa_dma_bridge_buggy;
|
||||
#else
|
||||
#define isa_dma_bridge_buggy (0)
|
||||
#endif
|
||||
|
||||
#endif /* !(_ASM_SPARC64_DMA_H) */
|
@ -1,8 +0,0 @@
|
||||
#ifndef ___ASM_SPARC_EBUS_H
|
||||
#define ___ASM_SPARC_EBUS_H
|
||||
#if defined(__sparc__) && defined(__arch64__)
|
||||
#include <asm/ebus_64.h>
|
||||
#else
|
||||
#include <asm/ebus_32.h>
|
||||
#endif
|
||||
#endif
|
@ -1,99 +0,0 @@
|
||||
/*
|
||||
* ebus.h: PCI to Ebus pseudo driver software state.
|
||||
*
|
||||
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
|
||||
*
|
||||
* Adopted for sparc by V. Roganov and G. Raiko.
|
||||
*/
|
||||
|
||||
#ifndef __SPARC_EBUS_H
|
||||
#define __SPARC_EBUS_H
|
||||
|
||||
#ifndef _LINUX_IOPORT_H
|
||||
#include <linux/ioport.h>
|
||||
#endif
|
||||
#include <linux/of_device.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/prom.h>
|
||||
|
||||
struct linux_ebus_child {
|
||||
struct linux_ebus_child *next;
|
||||
struct linux_ebus_device *parent;
|
||||
struct linux_ebus *bus;
|
||||
struct device_node *prom_node;
|
||||
struct resource resource[PROMREG_MAX];
|
||||
int num_addrs;
|
||||
unsigned int irqs[PROMINTR_MAX];
|
||||
int num_irqs;
|
||||
};
|
||||
|
||||
struct linux_ebus_device {
|
||||
struct of_device ofdev;
|
||||
struct linux_ebus_device *next;
|
||||
struct linux_ebus_child *children;
|
||||
struct linux_ebus *bus;
|
||||
struct device_node *prom_node;
|
||||
struct resource resource[PROMREG_MAX];
|
||||
int num_addrs;
|
||||
unsigned int irqs[PROMINTR_MAX];
|
||||
int num_irqs;
|
||||
};
|
||||
#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
|
||||
|
||||
struct linux_ebus {
|
||||
struct of_device ofdev;
|
||||
struct linux_ebus *next;
|
||||
struct linux_ebus_device *devices;
|
||||
struct linux_pbm_info *parent;
|
||||
struct pci_dev *self;
|
||||
struct device_node *prom_node;
|
||||
};
|
||||
#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
|
||||
|
||||
struct linux_ebus_dma {
|
||||
unsigned int dcsr;
|
||||
unsigned int dacr;
|
||||
unsigned int dbcr;
|
||||
};
|
||||
|
||||
#define EBUS_DCSR_INT_PEND 0x00000001
|
||||
#define EBUS_DCSR_ERR_PEND 0x00000002
|
||||
#define EBUS_DCSR_DRAIN 0x00000004
|
||||
#define EBUS_DCSR_INT_EN 0x00000010
|
||||
#define EBUS_DCSR_RESET 0x00000080
|
||||
#define EBUS_DCSR_WRITE 0x00000100
|
||||
#define EBUS_DCSR_EN_DMA 0x00000200
|
||||
#define EBUS_DCSR_CYC_PEND 0x00000400
|
||||
#define EBUS_DCSR_DIAG_RD_DONE 0x00000800
|
||||
#define EBUS_DCSR_DIAG_WR_DONE 0x00001000
|
||||
#define EBUS_DCSR_EN_CNT 0x00002000
|
||||
#define EBUS_DCSR_TC 0x00004000
|
||||
#define EBUS_DCSR_DIS_CSR_DRN 0x00010000
|
||||
#define EBUS_DCSR_BURST_SZ_MASK 0x000c0000
|
||||
#define EBUS_DCSR_BURST_SZ_1 0x00080000
|
||||
#define EBUS_DCSR_BURST_SZ_4 0x00000000
|
||||
#define EBUS_DCSR_BURST_SZ_8 0x00040000
|
||||
#define EBUS_DCSR_BURST_SZ_16 0x000c0000
|
||||
#define EBUS_DCSR_DIAG_EN 0x00100000
|
||||
#define EBUS_DCSR_DIS_ERR_PEND 0x00400000
|
||||
#define EBUS_DCSR_TCI_DIS 0x00800000
|
||||
#define EBUS_DCSR_EN_NEXT 0x01000000
|
||||
#define EBUS_DCSR_DMA_ON 0x02000000
|
||||
#define EBUS_DCSR_A_LOADED 0x04000000
|
||||
#define EBUS_DCSR_NA_LOADED 0x08000000
|
||||
#define EBUS_DCSR_DEV_ID_MASK 0xf0000000
|
||||
|
||||
extern struct linux_ebus *ebus_chain;
|
||||
|
||||
extern void ebus_init(void);
|
||||
|
||||
#define for_each_ebus(bus) \
|
||||
for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
|
||||
|
||||
#define for_each_ebusdev(dev, bus) \
|
||||
for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
|
||||
|
||||
#define for_each_edevchild(dev, child) \
|
||||
for((child) = (dev)->children; (child); (child) = (child)->next)
|
||||
|
||||
#endif /* !(__SPARC_EBUS_H) */
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* ebus.h: PCI to Ebus pseudo driver software state.
|
||||
*
|
||||
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
|
||||
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
|
||||
*/
|
||||
|
||||
#ifndef __SPARC64_EBUS_H
|
||||
#define __SPARC64_EBUS_H
|
||||
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/prom.h>
|
||||
|
||||
struct linux_ebus_child {
|
||||
struct linux_ebus_child *next;
|
||||
struct linux_ebus_device *parent;
|
||||
struct linux_ebus *bus;
|
||||
struct device_node *prom_node;
|
||||
struct resource resource[PROMREG_MAX];
|
||||
int num_addrs;
|
||||
unsigned int irqs[PROMINTR_MAX];
|
||||
int num_irqs;
|
||||
};
|
||||
|
||||
struct linux_ebus_device {
|
||||
struct of_device ofdev;
|
||||
struct linux_ebus_device *next;
|
||||
struct linux_ebus_child *children;
|
||||
struct linux_ebus *bus;
|
||||
struct device_node *prom_node;
|
||||
struct resource resource[PROMREG_MAX];
|
||||
int num_addrs;
|
||||
unsigned int irqs[PROMINTR_MAX];
|
||||
int num_irqs;
|
||||
};
|
||||
#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
|
||||
|
||||
struct linux_ebus {
|
||||
struct of_device ofdev;
|
||||
struct linux_ebus *next;
|
||||
struct linux_ebus_device *devices;
|
||||
struct pci_dev *self;
|
||||
int index;
|
||||
int is_rio;
|
||||
struct device_node *prom_node;
|
||||
};
|
||||
#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
|
||||
|
||||
struct ebus_dma_info {
|
||||
spinlock_t lock;
|
||||
void __iomem *regs;
|
||||
|
||||
unsigned int flags;
|
||||
#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER 0x00000001
|
||||
#define EBUS_DMA_FLAG_TCI_DISABLE 0x00000002
|
||||
|
||||
/* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
|
||||
* set.
|
||||
*/
|
||||
void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
|
||||
void *client_cookie;
|
||||
unsigned int irq;
|
||||
#define EBUS_DMA_EVENT_ERROR 1
|
||||
#define EBUS_DMA_EVENT_DMA 2
|
||||
#define EBUS_DMA_EVENT_DEVICE 4
|
||||
|
||||
unsigned char name[64];
|
||||
};
|
||||
|
||||
extern int ebus_dma_register(struct ebus_dma_info *p);
|
||||
extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
|
||||
extern void ebus_dma_unregister(struct ebus_dma_info *p);
|
||||
extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
|
||||
size_t len);
|
||||
extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
|
||||
extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
|
||||
extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
|
||||
extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
|
||||
|
||||
extern struct linux_ebus *ebus_chain;
|
||||
|
||||
extern void ebus_init(void);
|
||||
|
||||
#define for_each_ebus(bus) \
|
||||
for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
|
||||
|
||||
#define for_each_ebusdev(dev, bus) \
|
||||
for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
|
||||
|
||||
#define for_each_edevchild(dev, child) \
|
||||
for((child) = (dev)->children; (child); (child) = (child)->next)
|
||||
|
||||
#endif /* !(__SPARC64_EBUS_H) */
|
35
arch/sparc/include/asm/ebus_dma.h
Normal file
35
arch/sparc/include/asm/ebus_dma.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef __ASM_SPARC_EBUS_DMA_H
|
||||
#define __ASM_SPARC_EBUS_DMA_H
|
||||
|
||||
struct ebus_dma_info {
|
||||
spinlock_t lock;
|
||||
void __iomem *regs;
|
||||
|
||||
unsigned int flags;
|
||||
#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER 0x00000001
|
||||
#define EBUS_DMA_FLAG_TCI_DISABLE 0x00000002
|
||||
|
||||
/* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
|
||||
* set.
|
||||
*/
|
||||
void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
|
||||
void *client_cookie;
|
||||
unsigned int irq;
|
||||
#define EBUS_DMA_EVENT_ERROR 1
|
||||
#define EBUS_DMA_EVENT_DMA 2
|
||||
#define EBUS_DMA_EVENT_DEVICE 4
|
||||
|
||||
unsigned char name[64];
|
||||
};
|
||||
|
||||
extern int ebus_dma_register(struct ebus_dma_info *p);
|
||||
extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
|
||||
extern void ebus_dma_unregister(struct ebus_dma_info *p);
|
||||
extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
|
||||
size_t len);
|
||||
extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
|
||||
extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
|
||||
extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
|
||||
extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
|
||||
|
||||
#endif /* __ASM_SPARC_EBUS_DMA_H */
|
@ -105,11 +105,8 @@ typedef struct {
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#ifndef CONFIG_SUN4
|
||||
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
#else
|
||||
#define ELF_EXEC_PAGESIZE 8192
|
||||
#endif
|
||||
|
||||
|
||||
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
|
||||
@ -126,7 +123,7 @@ typedef struct {
|
||||
/* Sun4c has none of the capabilities, most sun4m's have them all.
|
||||
* XXX This is gross, set some global variable at boot time. -DaveM
|
||||
*/
|
||||
#define ELF_HWCAP ((ARCH_SUN4C_SUN4) ? 0 : \
|
||||
#define ELF_HWCAP ((ARCH_SUN4C) ? 0 : \
|
||||
(HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
|
||||
HWCAP_SPARC_SWAP | \
|
||||
((srmmu_modtype != Cypress && \
|
||||
|
@ -1,5 +1,4 @@
|
||||
/*
|
||||
* fhc.h: Structures for central/fhc pseudo driver on Sunfire/Starfire/Wildfire.
|
||||
/* fhc.h: FHC and Clock board register definitions.
|
||||
*
|
||||
* Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com)
|
||||
*/
|
||||
@ -7,14 +6,6 @@
|
||||
#ifndef _SPARC64_FHC_H
|
||||
#define _SPARC64_FHC_H
|
||||
|
||||
#include <linux/timer.h>
|
||||
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/upa.h>
|
||||
|
||||
struct linux_fhc;
|
||||
|
||||
/* Clock board register offsets. */
|
||||
#define CLOCK_CTRL 0x00UL /* Main control */
|
||||
#define CLOCK_STAT1 0x10UL /* Status one */
|
||||
@ -29,21 +20,7 @@ struct linux_fhc;
|
||||
#define CLOCK_CTRL_MLED 0x02 /* Mid LED, 1 == on */
|
||||
#define CLOCK_CTRL_RLED 0x01 /* RIght LED, 1 == on */
|
||||
|
||||
struct linux_central {
|
||||
struct linux_fhc *child;
|
||||
unsigned long cfreg;
|
||||
unsigned long clkregs;
|
||||
unsigned long clkver;
|
||||
int slots;
|
||||
struct device_node *prom_node;
|
||||
|
||||
struct linux_prom_ranges central_ranges[PROMREG_MAX];
|
||||
int num_central_ranges;
|
||||
};
|
||||
|
||||
/* Firehose controller register offsets */
|
||||
struct fhc_regs {
|
||||
unsigned long pregs; /* FHC internal regs */
|
||||
#define FHC_PREGS_ID 0x00UL /* FHC ID */
|
||||
#define FHC_ID_VERS 0xf0000000 /* Version of this FHC */
|
||||
#define FHC_ID_PARTID 0x0ffff000 /* Part ID code (0x0f9f == FHC) */
|
||||
@ -90,32 +67,14 @@ struct fhc_regs {
|
||||
#define FHC_JTAG_CTRL_MENAB 0x80000000 /* Indicates this is JTAG Master */
|
||||
#define FHC_JTAG_CTRL_MNONE 0x40000000 /* Indicates no JTAG Master present */
|
||||
#define FHC_PREGS_JCMD 0x100UL /* FHC JTAG Command Register */
|
||||
unsigned long ireg; /* FHC IGN reg */
|
||||
#define FHC_IREG_IGN 0x00UL /* This FHC's IGN */
|
||||
unsigned long ffregs; /* FHC fanfail regs */
|
||||
#define FHC_FFREGS_IMAP 0x00UL /* FHC Fanfail IMAP */
|
||||
#define FHC_FFREGS_ICLR 0x10UL /* FHC Fanfail ICLR */
|
||||
unsigned long sregs; /* FHC system regs */
|
||||
#define FHC_SREGS_IMAP 0x00UL /* FHC System IMAP */
|
||||
#define FHC_SREGS_ICLR 0x10UL /* FHC System ICLR */
|
||||
unsigned long uregs; /* FHC uart regs */
|
||||
#define FHC_UREGS_IMAP 0x00UL /* FHC Uart IMAP */
|
||||
#define FHC_UREGS_ICLR 0x10UL /* FHC Uart ICLR */
|
||||
unsigned long tregs; /* FHC TOD regs */
|
||||
#define FHC_TREGS_IMAP 0x00UL /* FHC TOD IMAP */
|
||||
#define FHC_TREGS_ICLR 0x10UL /* FHC TOD ICLR */
|
||||
};
|
||||
|
||||
struct linux_fhc {
|
||||
struct linux_fhc *next;
|
||||
struct linux_central *parent; /* NULL if not central FHC */
|
||||
struct fhc_regs fhc_regs;
|
||||
int board;
|
||||
int jtag_master;
|
||||
struct device_node *prom_node;
|
||||
|
||||
struct linux_prom_ranges fhc_ranges[PROMREG_MAX];
|
||||
int num_fhc_ranges;
|
||||
};
|
||||
|
||||
#endif /* !(_SPARC64_FHC_H) */
|
||||
|
@ -6,6 +6,9 @@
|
||||
#ifndef __ASM_SPARC_FLOPPY_H
|
||||
#define __ASM_SPARC_FLOPPY_H
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/system.h>
|
||||
@ -343,7 +346,7 @@ static int sun_floppy_init(void)
|
||||
r.flags = fd_regs[0].which_io;
|
||||
r.start = fd_regs[0].phys_addr;
|
||||
sun_fdc = (struct sun_flpy_controller *)
|
||||
sbus_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
|
||||
of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
|
||||
|
||||
/* Last minute sanity check... */
|
||||
if(sun_fdc->status_82072 == 0xff) {
|
||||
@ -385,4 +388,15 @@ static int sparc_eject(void)
|
||||
|
||||
#define EXTRA_FLOPPY_PARAMS
|
||||
|
||||
static DEFINE_SPINLOCK(dma_spin_lock);
|
||||
|
||||
#define claim_dma_lock() \
|
||||
({ unsigned long flags; \
|
||||
spin_lock_irqsave(&dma_spin_lock, flags); \
|
||||
flags; \
|
||||
})
|
||||
|
||||
#define release_dma_lock(__flags) \
|
||||
spin_unlock_irqrestore(&dma_spin_lock, __flags);
|
||||
|
||||
#endif /* !(__ASM_SPARC_FLOPPY_H) */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* floppy.h: Sparc specific parts of the Floppy driver.
|
||||
*
|
||||
* Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
|
||||
* Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net)
|
||||
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
|
||||
*
|
||||
* Ultra/PCI support added: Sep 1997 Eddie C. Dost (ecd@skynet.be)
|
||||
@ -9,18 +9,11 @@
|
||||
#ifndef __ASM_SPARC64_FLOPPY_H
|
||||
#define __ASM_SPARC64_FLOPPY_H
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/idprom.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/auxio.h>
|
||||
#include <asm/sbus.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
|
||||
/*
|
||||
* Define this to enable exchanging drive 0 and 1 if only drive 1 is
|
||||
@ -50,7 +43,7 @@ struct sun_flpy_controller {
|
||||
/* You'll only ever find one controller on an Ultra anyways. */
|
||||
static struct sun_flpy_controller *sun_fdc = (struct sun_flpy_controller *)-1;
|
||||
unsigned long fdc_status;
|
||||
static struct sbus_dev *floppy_sdev = NULL;
|
||||
static struct of_device *floppy_op = NULL;
|
||||
|
||||
struct sun_floppy_ops {
|
||||
unsigned char (*fd_inb) (unsigned long port);
|
||||
@ -291,12 +284,11 @@ static int sun_fd_eject(int drive)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#include <asm/ebus.h>
|
||||
#include <asm/ebus_dma.h>
|
||||
#include <asm/ns87303.h>
|
||||
|
||||
static struct ebus_dma_info sun_pci_fd_ebus_dma;
|
||||
static struct pci_dev *sun_pci_ebus_dev;
|
||||
static struct device *sun_floppy_dev;
|
||||
static int sun_pci_broken_drive = -1;
|
||||
|
||||
struct sun_pci_dma_op {
|
||||
@ -377,7 +369,7 @@ static void sun_pci_fd_enable_dma(void)
|
||||
sun_pci_dma_pending.addr = -1U;
|
||||
|
||||
sun_pci_dma_current.addr =
|
||||
pci_map_single(sun_pci_ebus_dev,
|
||||
dma_map_single(sun_floppy_dev,
|
||||
sun_pci_dma_current.buf,
|
||||
sun_pci_dma_current.len,
|
||||
sun_pci_dma_current.direction);
|
||||
@ -394,7 +386,7 @@ static void sun_pci_fd_disable_dma(void)
|
||||
{
|
||||
ebus_dma_enable(&sun_pci_fd_ebus_dma, 0);
|
||||
if (sun_pci_dma_current.addr != -1U)
|
||||
pci_unmap_single(sun_pci_ebus_dev,
|
||||
dma_unmap_single(sun_floppy_dev,
|
||||
sun_pci_dma_current.addr,
|
||||
sun_pci_dma_current.len,
|
||||
sun_pci_dma_current.direction);
|
||||
@ -404,9 +396,9 @@ static void sun_pci_fd_disable_dma(void)
|
||||
static void sun_pci_fd_set_dma_mode(int mode)
|
||||
{
|
||||
if (mode == DMA_MODE_WRITE)
|
||||
sun_pci_dma_pending.direction = PCI_DMA_TODEVICE;
|
||||
sun_pci_dma_pending.direction = DMA_TO_DEVICE;
|
||||
else
|
||||
sun_pci_dma_pending.direction = PCI_DMA_FROMDEVICE;
|
||||
sun_pci_dma_pending.direction = DMA_FROM_DEVICE;
|
||||
|
||||
ebus_dma_prepare(&sun_pci_fd_ebus_dma, mode != DMA_MODE_WRITE);
|
||||
}
|
||||
@ -538,80 +530,84 @@ static int sun_pci_fd_test_drive(unsigned long port, int drive)
|
||||
#undef MSR
|
||||
#undef DOR
|
||||
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
static int __init ebus_fdthree_p(struct linux_ebus_device *edev)
|
||||
static int __init ebus_fdthree_p(struct device_node *dp)
|
||||
{
|
||||
if (!strcmp(edev->prom_node->name, "fdthree"))
|
||||
if (!strcmp(dp->name, "fdthree"))
|
||||
return 1;
|
||||
if (!strcmp(edev->prom_node->name, "floppy")) {
|
||||
if (!strcmp(dp->name, "floppy")) {
|
||||
const char *compat;
|
||||
|
||||
compat = of_get_property(edev->prom_node,
|
||||
"compatible", NULL);
|
||||
compat = of_get_property(dp, "compatible", NULL);
|
||||
if (compat && !strcmp(compat, "fdthree"))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned long __init sun_floppy_init(void)
|
||||
{
|
||||
char state[128];
|
||||
struct sbus_bus *bus;
|
||||
struct sbus_dev *sdev = NULL;
|
||||
static int initialized = 0;
|
||||
struct device_node *dp;
|
||||
struct of_device *op;
|
||||
const char *prop;
|
||||
char state[128];
|
||||
|
||||
if (initialized)
|
||||
return sun_floppy_types[0];
|
||||
initialized = 1;
|
||||
|
||||
for_all_sbusdev (sdev, bus) {
|
||||
if (!strcmp(sdev->prom_name, "SUNW,fdtwo"))
|
||||
op = NULL;
|
||||
|
||||
for_each_node_by_name(dp, "SUNW,fdtwo") {
|
||||
if (strcmp(dp->parent->name, "sbus"))
|
||||
continue;
|
||||
op = of_find_device_by_node(dp);
|
||||
if (op)
|
||||
break;
|
||||
}
|
||||
if(sdev) {
|
||||
floppy_sdev = sdev;
|
||||
FLOPPY_IRQ = sdev->irqs[0];
|
||||
if (op) {
|
||||
floppy_op = op;
|
||||
FLOPPY_IRQ = op->irqs[0];
|
||||
} else {
|
||||
#ifdef CONFIG_PCI
|
||||
struct linux_ebus *ebus;
|
||||
struct linux_ebus_device *edev = NULL;
|
||||
unsigned long config = 0;
|
||||
struct device_node *ebus_dp;
|
||||
void __iomem *auxio_reg;
|
||||
const char *state_prop;
|
||||
unsigned long config;
|
||||
|
||||
for_each_ebus(ebus) {
|
||||
for_each_ebusdev(edev, ebus) {
|
||||
if (ebus_fdthree_p(edev))
|
||||
goto ebus_done;
|
||||
dp = NULL;
|
||||
for_each_node_by_name(ebus_dp, "ebus") {
|
||||
for (dp = ebus_dp->child; dp; dp = dp->sibling) {
|
||||
if (ebus_fdthree_p(dp))
|
||||
goto found_fdthree;
|
||||
}
|
||||
}
|
||||
ebus_done:
|
||||
if (!edev)
|
||||
found_fdthree:
|
||||
if (!dp)
|
||||
return 0;
|
||||
|
||||
state_prop = of_get_property(edev->prom_node, "status", NULL);
|
||||
op = of_find_device_by_node(dp);
|
||||
if (!op)
|
||||
return 0;
|
||||
|
||||
state_prop = of_get_property(op->node, "status", NULL);
|
||||
if (state_prop && !strncmp(state_prop, "disabled", 8))
|
||||
return 0;
|
||||
|
||||
FLOPPY_IRQ = edev->irqs[0];
|
||||
FLOPPY_IRQ = op->irqs[0];
|
||||
|
||||
/* Make sure the high density bit is set, some systems
|
||||
* (most notably Ultra5/Ultra10) come up with it clear.
|
||||
*/
|
||||
auxio_reg = (void __iomem *) edev->resource[2].start;
|
||||
auxio_reg = (void __iomem *) op->resource[2].start;
|
||||
writel(readl(auxio_reg)|0x2, auxio_reg);
|
||||
|
||||
sun_pci_ebus_dev = ebus->self;
|
||||
sun_floppy_dev = &op->dev;
|
||||
|
||||
spin_lock_init(&sun_pci_fd_ebus_dma.lock);
|
||||
|
||||
/* XXX ioremap */
|
||||
sun_pci_fd_ebus_dma.regs = (void __iomem *)
|
||||
edev->resource[1].start;
|
||||
op->resource[1].start;
|
||||
if (!sun_pci_fd_ebus_dma.regs)
|
||||
return 0;
|
||||
|
||||
@ -625,7 +621,7 @@ static unsigned long __init sun_floppy_init(void)
|
||||
return 0;
|
||||
|
||||
/* XXX ioremap */
|
||||
sun_fdc = (struct sun_flpy_controller *)edev->resource[0].start;
|
||||
sun_fdc = (struct sun_flpy_controller *) op->resource[0].start;
|
||||
|
||||
sun_fdops.fd_inb = sun_pci_fd_inb;
|
||||
sun_fdops.fd_outb = sun_pci_fd_outb;
|
||||
@ -662,12 +658,15 @@ static unsigned long __init sun_floppy_init(void)
|
||||
/*
|
||||
* Find NS87303 SuperIO config registers (through ecpp).
|
||||
*/
|
||||
for_each_ebus(ebus) {
|
||||
for_each_ebusdev(edev, ebus) {
|
||||
if (!strcmp(edev->prom_node->name, "ecpp")) {
|
||||
config = edev->resource[1].start;
|
||||
goto config_done;
|
||||
}
|
||||
config = 0;
|
||||
for (dp = ebus_dp->child; dp; dp = dp->sibling) {
|
||||
if (!strcmp(dp->name, "ecpp")) {
|
||||
struct of_device *ecpp_op;
|
||||
|
||||
ecpp_op = of_find_device_by_node(dp);
|
||||
if (ecpp_op)
|
||||
config = ecpp_op->resource[1].start;
|
||||
goto config_done;
|
||||
}
|
||||
}
|
||||
config_done:
|
||||
@ -716,26 +715,23 @@ static unsigned long __init sun_floppy_init(void)
|
||||
#endif /* PCI_FDC_SWAP_DRIVES */
|
||||
|
||||
return sun_floppy_types[0];
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
prom_getproperty(sdev->prom_node, "status", state, sizeof(state));
|
||||
if(!strncmp(state, "disabled", 8))
|
||||
prop = of_get_property(op->node, "status", NULL);
|
||||
if (prop && !strncmp(state, "disabled", 8))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* We cannot do sbus_ioremap here: it does request_region,
|
||||
* We cannot do of_ioremap here: it does request_region,
|
||||
* which the generic floppy driver tries to do once again.
|
||||
* But we must use the sdev resource values as they have
|
||||
* had parent ranges applied.
|
||||
*/
|
||||
sun_fdc = (struct sun_flpy_controller *)
|
||||
(sdev->resource[0].start +
|
||||
((sdev->resource[0].flags & 0x1ffUL) << 32UL));
|
||||
(op->resource[0].start +
|
||||
((op->resource[0].flags & 0x1ffUL) << 32UL));
|
||||
|
||||
/* Last minute sanity check... */
|
||||
if(sbus_readb(&sun_fdc->status1_82077) == 0xff) {
|
||||
if (sbus_readb(&sun_fdc->status1_82077) == 0xff) {
|
||||
sun_fdc = (struct sun_flpy_controller *)-1;
|
||||
return 0;
|
||||
}
|
||||
|
36
arch/sparc/include/asm/gpio.h
Normal file
36
arch/sparc/include/asm/gpio.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef __ASM_SPARC_GPIO_H
|
||||
#define __ASM_SPARC_GPIO_H
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <asm-generic/gpio.h>
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
|
||||
static inline int gpio_get_value(unsigned int gpio)
|
||||
{
|
||||
return __gpio_get_value(gpio);
|
||||
}
|
||||
|
||||
static inline void gpio_set_value(unsigned int gpio, int value)
|
||||
{
|
||||
__gpio_set_value(gpio, value);
|
||||
}
|
||||
|
||||
static inline int gpio_cansleep(unsigned int gpio)
|
||||
{
|
||||
return __gpio_cansleep(gpio);
|
||||
}
|
||||
|
||||
static inline int gpio_to_irq(unsigned int gpio)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int irq_to_gpio(unsigned int irq)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GPIOLIB */
|
||||
|
||||
#endif /* __ASM_SPARC_GPIO_H */
|
@ -55,8 +55,4 @@ struct iounit_struct {
|
||||
#define IOUNIT_BMAPM_START IOUNIT_BMAP2_END
|
||||
#define IOUNIT_BMAPM_END ((IOUNIT_DMA_SIZE - IOUNIT_DVMA_SIZE) >> PAGE_SHIFT)
|
||||
|
||||
extern __u32 iounit_map_dma_init(struct sbus_bus *, int);
|
||||
#define iounit_map_dma_finish(sbus, addr, len) mmu_release_scsi_one(addr, len, sbus)
|
||||
extern __u32 iounit_map_dma_page(__u32, void *, struct sbus_bus *);
|
||||
|
||||
#endif /* !(_SPARC_IO_UNIT_H) */
|
||||
|
@ -292,14 +292,6 @@ struct pci_dev;
|
||||
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
|
||||
extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
|
||||
|
||||
/*
|
||||
* Bus number may be in res->flags... somewhere.
|
||||
*/
|
||||
extern void __iomem *sbus_ioremap(struct resource *res, unsigned long offset,
|
||||
unsigned long size, char *name);
|
||||
extern void sbus_iounmap(volatile void __iomem *vaddr, unsigned long size);
|
||||
|
||||
|
||||
/*
|
||||
* At the moment, we do not use CMOS_READ anywhere outside of rtc.c,
|
||||
* so rtc_port is static in it. This should not change unless a new
|
||||
@ -308,6 +300,17 @@ extern void sbus_iounmap(volatile void __iomem *vaddr, unsigned long size);
|
||||
#define RTC_PORT(x) (rtc_port + (x))
|
||||
#define RTC_ALWAYS_BCD 0
|
||||
|
||||
static inline int sbus_can_dma_64bit(void)
|
||||
{
|
||||
return 0; /* actually, sparc_cpu_model==sun4d */
|
||||
}
|
||||
static inline int sbus_can_burst64(void)
|
||||
{
|
||||
return 0; /* actually, sparc_cpu_model==sun4d */
|
||||
}
|
||||
struct device;
|
||||
extern void sbus_set_sbus64(struct device *, int);
|
||||
|
||||
#endif
|
||||
|
||||
#define __ARCH_HAS_NO_PAGE_ZERO_MAPPED 1
|
||||
|
@ -482,18 +482,16 @@ struct pci_dev;
|
||||
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
|
||||
extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
|
||||
|
||||
/* Similarly for SBUS. */
|
||||
#define sbus_ioremap(__res, __offset, __size, __name) \
|
||||
({ unsigned long __ret; \
|
||||
__ret = (__res)->start + (((__res)->flags & 0x1ffUL) << 32UL); \
|
||||
__ret += (unsigned long) (__offset); \
|
||||
if (! request_region((__ret), (__size), (__name))) \
|
||||
__ret = 0UL; \
|
||||
(void __iomem *) __ret; \
|
||||
})
|
||||
|
||||
#define sbus_iounmap(__addr, __size) \
|
||||
release_region((unsigned long)(__addr), (__size))
|
||||
static inline int sbus_can_dma_64bit(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
static inline int sbus_can_burst64(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
struct device;
|
||||
extern void sbus_set_sbus64(struct device *, int);
|
||||
|
||||
/*
|
||||
* Convert a physical pointer to a virtual kernel pointer for /dev/mem
|
||||
|
@ -48,6 +48,9 @@ struct strbuf {
|
||||
unsigned long strbuf_control;
|
||||
unsigned long strbuf_pflush;
|
||||
unsigned long strbuf_fsync;
|
||||
unsigned long strbuf_err_stat;
|
||||
unsigned long strbuf_tag_diag;
|
||||
unsigned long strbuf_line_diag;
|
||||
unsigned long strbuf_ctxflush;
|
||||
unsigned long strbuf_ctxmatch_base;
|
||||
unsigned long strbuf_flushflag_pa;
|
||||
|
@ -56,7 +56,6 @@ extern unsigned int sun4u_build_msi(u32 portid, unsigned int *virt_irq_p,
|
||||
unsigned long imap_base,
|
||||
unsigned long iclr_base);
|
||||
extern void sun4u_destroy_msi(unsigned int virt_irq);
|
||||
extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
|
||||
|
||||
extern unsigned char virt_irq_alloc(unsigned int dev_handle,
|
||||
unsigned int dev_ino);
|
||||
|
@ -7,12 +7,8 @@
|
||||
#include <asm/io.h>
|
||||
|
||||
#ifndef RTC_PORT
|
||||
#ifdef CONFIG_PCI
|
||||
extern unsigned long ds1287_regs;
|
||||
#else
|
||||
#define ds1287_regs (0UL)
|
||||
#endif
|
||||
#define RTC_PORT(x) (ds1287_regs + (x))
|
||||
extern unsigned long cmos_regs;
|
||||
#define RTC_PORT(x) (cmos_regs + (x))
|
||||
#define RTC_ALWAYS_BCD 0
|
||||
#endif
|
||||
|
||||
@ -29,6 +25,4 @@ outb_p((addr),RTC_PORT(0)); \
|
||||
outb_p((val),RTC_PORT(1)); \
|
||||
})
|
||||
|
||||
#define RTC_IRQ 8
|
||||
|
||||
#endif /* __ASM_SPARC64_MC146818RTC_H */
|
||||
|
9
arch/sparc/include/asm/memctrl.h
Normal file
9
arch/sparc/include/asm/memctrl.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef _SPARC_MEMCTRL_H
|
||||
#define _SPARC_MEMCTRL_H
|
||||
|
||||
typedef int (*dimm_printer_t)(int synd_code, unsigned long paddr, char *buf, int buflen);
|
||||
|
||||
int register_dimm_printer(dimm_printer_t func);
|
||||
void unregister_dimm_printer(dimm_printer_t func);
|
||||
|
||||
#endif /* _SPARC_MEMCTRL_H */
|
@ -1,8 +0,0 @@
|
||||
#ifndef ___ASM_SPARC_MOSTEK_H
|
||||
#define ___ASM_SPARC_MOSTEK_H
|
||||
#if defined(__sparc__) && defined(__arch64__)
|
||||
#include <asm/mostek_64.h>
|
||||
#else
|
||||
#include <asm/mostek_32.h>
|
||||
#endif
|
||||
#endif
|
@ -1,171 +0,0 @@
|
||||
/*
|
||||
* mostek.h: Describes the various Mostek time of day clock registers.
|
||||
*
|
||||
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
|
||||
* Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
|
||||
* Added intersil code 05/25/98 Chris Davis (cdavis@cois.on.ca)
|
||||
*/
|
||||
|
||||
#ifndef _SPARC_MOSTEK_H
|
||||
#define _SPARC_MOSTEK_H
|
||||
|
||||
#include <asm/idprom.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ)
|
||||
*
|
||||
* Data
|
||||
* Address Function
|
||||
* Bit 7 Bit 6 Bit 5 Bit 4Bit 3 Bit 2 Bit 1 Bit 0
|
||||
* 7ff - - - - - - - - Year 00-99
|
||||
* 7fe 0 0 0 - - - - - Month 01-12
|
||||
* 7fd 0 0 - - - - - - Date 01-31
|
||||
* 7fc 0 FT 0 0 0 - - - Day 01-07
|
||||
* 7fb KS 0 - - - - - - Hours 00-23
|
||||
* 7fa 0 - - - - - - - Minutes 00-59
|
||||
* 7f9 ST - - - - - - - Seconds 00-59
|
||||
* 7f8 W R S - - - - - Control
|
||||
*
|
||||
* * ST is STOP BIT
|
||||
* * W is WRITE BIT
|
||||
* * R is READ BIT
|
||||
* * S is SIGN BIT
|
||||
* * FT is FREQ TEST BIT
|
||||
* * KS is KICK START BIT
|
||||
*/
|
||||
|
||||
/* The Mostek 48t02 real time clock and NVRAM chip. The registers
|
||||
* other than the control register are in binary coded decimal. Some
|
||||
* control bits also live outside the control register.
|
||||
*/
|
||||
#define mostek_read(_addr) readb(_addr)
|
||||
#define mostek_write(_addr,_val) writeb(_val, _addr)
|
||||
#define MOSTEK_EEPROM 0x0000UL
|
||||
#define MOSTEK_IDPROM 0x07d8UL
|
||||
#define MOSTEK_CREG 0x07f8UL
|
||||
#define MOSTEK_SEC 0x07f9UL
|
||||
#define MOSTEK_MIN 0x07faUL
|
||||
#define MOSTEK_HOUR 0x07fbUL
|
||||
#define MOSTEK_DOW 0x07fcUL
|
||||
#define MOSTEK_DOM 0x07fdUL
|
||||
#define MOSTEK_MONTH 0x07feUL
|
||||
#define MOSTEK_YEAR 0x07ffUL
|
||||
|
||||
struct mostek48t02 {
|
||||
volatile char eeprom[2008]; /* This is the eeprom, don't touch! */
|
||||
struct idprom idprom; /* The idprom lives here. */
|
||||
volatile unsigned char creg; /* Control register */
|
||||
volatile unsigned char sec; /* Seconds (0-59) */
|
||||
volatile unsigned char min; /* Minutes (0-59) */
|
||||
volatile unsigned char hour; /* Hour (0-23) */
|
||||
volatile unsigned char dow; /* Day of the week (1-7) */
|
||||
volatile unsigned char dom; /* Day of the month (1-31) */
|
||||
volatile unsigned char month; /* Month of year (1-12) */
|
||||
volatile unsigned char year; /* Year (0-99) */
|
||||
};
|
||||
|
||||
extern spinlock_t mostek_lock;
|
||||
extern void __iomem *mstk48t02_regs;
|
||||
|
||||
/* Control register values. */
|
||||
#define MSTK_CREG_WRITE 0x80 /* Must set this before placing values. */
|
||||
#define MSTK_CREG_READ 0x40 /* Stop updates to allow a clean read. */
|
||||
#define MSTK_CREG_SIGN 0x20 /* Slow/speed clock in calibration mode. */
|
||||
|
||||
/* Control bits that live in the other registers. */
|
||||
#define MSTK_STOP 0x80 /* Stop the clock oscillator. (sec) */
|
||||
#define MSTK_KICK_START 0x80 /* Kick start the clock chip. (hour) */
|
||||
#define MSTK_FREQ_TEST 0x40 /* Frequency test mode. (day) */
|
||||
|
||||
#define MSTK_YEAR_ZERO 1968 /* If year reg has zero, it is 1968. */
|
||||
#define MSTK_CVT_YEAR(yr) ((yr) + MSTK_YEAR_ZERO)
|
||||
|
||||
/* Masks that define how much space each value takes up. */
|
||||
#define MSTK_SEC_MASK 0x7f
|
||||
#define MSTK_MIN_MASK 0x7f
|
||||
#define MSTK_HOUR_MASK 0x3f
|
||||
#define MSTK_DOW_MASK 0x07
|
||||
#define MSTK_DOM_MASK 0x3f
|
||||
#define MSTK_MONTH_MASK 0x1f
|
||||
#define MSTK_YEAR_MASK 0xffU
|
||||
|
||||
/* Binary coded decimal conversion macros. */
|
||||
#define MSTK_REGVAL_TO_DECIMAL(x) (((x) & 0x0F) + 0x0A * ((x) >> 0x04))
|
||||
#define MSTK_DECIMAL_TO_REGVAL(x) ((((x) / 0x0A) << 0x04) + ((x) % 0x0A))
|
||||
|
||||
/* Generic register set and get macros for internal use. */
|
||||
#define MSTK_GET(regs,var,mask) (MSTK_REGVAL_TO_DECIMAL(((struct mostek48t02 *)regs)->var & MSTK_ ## mask ## _MASK))
|
||||
#define MSTK_SET(regs,var,value,mask) do { ((struct mostek48t02 *)regs)->var &= ~(MSTK_ ## mask ## _MASK); ((struct mostek48t02 *)regs)->var |= MSTK_DECIMAL_TO_REGVAL(value) & (MSTK_ ## mask ## _MASK); } while (0)
|
||||
|
||||
/* Macros to make register access easier on our fingers. These give you
|
||||
* the decimal value of the register requested if applicable. You pass
|
||||
* the a pointer to a 'struct mostek48t02'.
|
||||
*/
|
||||
#define MSTK_REG_CREG(regs) (((struct mostek48t02 *)regs)->creg)
|
||||
#define MSTK_REG_SEC(regs) MSTK_GET(regs,sec,SEC)
|
||||
#define MSTK_REG_MIN(regs) MSTK_GET(regs,min,MIN)
|
||||
#define MSTK_REG_HOUR(regs) MSTK_GET(regs,hour,HOUR)
|
||||
#define MSTK_REG_DOW(regs) MSTK_GET(regs,dow,DOW)
|
||||
#define MSTK_REG_DOM(regs) MSTK_GET(regs,dom,DOM)
|
||||
#define MSTK_REG_MONTH(regs) MSTK_GET(regs,month,MONTH)
|
||||
#define MSTK_REG_YEAR(regs) MSTK_GET(regs,year,YEAR)
|
||||
|
||||
#define MSTK_SET_REG_SEC(regs,value) MSTK_SET(regs,sec,value,SEC)
|
||||
#define MSTK_SET_REG_MIN(regs,value) MSTK_SET(regs,min,value,MIN)
|
||||
#define MSTK_SET_REG_HOUR(regs,value) MSTK_SET(regs,hour,value,HOUR)
|
||||
#define MSTK_SET_REG_DOW(regs,value) MSTK_SET(regs,dow,value,DOW)
|
||||
#define MSTK_SET_REG_DOM(regs,value) MSTK_SET(regs,dom,value,DOM)
|
||||
#define MSTK_SET_REG_MONTH(regs,value) MSTK_SET(regs,month,value,MONTH)
|
||||
#define MSTK_SET_REG_YEAR(regs,value) MSTK_SET(regs,year,value,YEAR)
|
||||
|
||||
|
||||
/* The Mostek 48t08 clock chip. Found on Sun4m's I think. It has the
|
||||
* same (basically) layout of the 48t02 chip except for the extra
|
||||
* NVRAM on board (8 KB against the 48t02's 2 KB).
|
||||
*/
|
||||
struct mostek48t08 {
|
||||
char offset[6*1024]; /* Magic things may be here, who knows? */
|
||||
struct mostek48t02 regs; /* Here is what we are interested in. */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SUN4
|
||||
enum sparc_clock_type { MSTK48T02, MSTK48T08, \
|
||||
INTERSIL, MSTK_INVALID };
|
||||
#else
|
||||
enum sparc_clock_type { MSTK48T02, MSTK48T08, \
|
||||
MSTK_INVALID };
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SUN4
|
||||
/* intersil on a sun 4/260 code data from harris doc */
|
||||
struct intersil_dt {
|
||||
volatile unsigned char int_csec;
|
||||
volatile unsigned char int_hour;
|
||||
volatile unsigned char int_min;
|
||||
volatile unsigned char int_sec;
|
||||
volatile unsigned char int_month;
|
||||
volatile unsigned char int_day;
|
||||
volatile unsigned char int_year;
|
||||
volatile unsigned char int_dow;
|
||||
};
|
||||
|
||||
struct intersil {
|
||||
struct intersil_dt clk;
|
||||
struct intersil_dt cmp;
|
||||
volatile unsigned char int_intr_reg;
|
||||
volatile unsigned char int_cmd_reg;
|
||||
};
|
||||
|
||||
#define INTERSIL_STOP 0x0
|
||||
#define INTERSIL_START 0x8
|
||||
#define INTERSIL_INTR_DISABLE 0x0
|
||||
#define INTERSIL_INTR_ENABLE 0x10
|
||||
#define INTERSIL_32K 0x0
|
||||
#define INTERSIL_NORMAL 0x0
|
||||
#define INTERSIL_24H 0x4
|
||||
#define INTERSIL_INT_100HZ 0x2
|
||||
|
||||
/* end of intersil info */
|
||||
#endif
|
||||
|
||||
#endif /* !(_SPARC_MOSTEK_H) */
|
@ -1,143 +0,0 @@
|
||||
/* mostek.h: Describes the various Mostek time of day clock registers.
|
||||
*
|
||||
* Copyright (C) 1995 David S. Miller (davem@davemloft.net)
|
||||
* Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
|
||||
*/
|
||||
|
||||
#ifndef _SPARC64_MOSTEK_H
|
||||
#define _SPARC64_MOSTEK_H
|
||||
|
||||
#include <asm/idprom.h>
|
||||
|
||||
/* M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ)
|
||||
*
|
||||
* Data
|
||||
* Address Function
|
||||
* Bit 7 Bit 6 Bit 5 Bit 4Bit 3 Bit 2 Bit 1 Bit 0
|
||||
* 7ff - - - - - - - - Year 00-99
|
||||
* 7fe 0 0 0 - - - - - Month 01-12
|
||||
* 7fd 0 0 - - - - - - Date 01-31
|
||||
* 7fc 0 FT 0 0 0 - - - Day 01-07
|
||||
* 7fb KS 0 - - - - - - Hours 00-23
|
||||
* 7fa 0 - - - - - - - Minutes 00-59
|
||||
* 7f9 ST - - - - - - - Seconds 00-59
|
||||
* 7f8 W R S - - - - - Control
|
||||
*
|
||||
* * ST is STOP BIT
|
||||
* * W is WRITE BIT
|
||||
* * R is READ BIT
|
||||
* * S is SIGN BIT
|
||||
* * FT is FREQ TEST BIT
|
||||
* * KS is KICK START BIT
|
||||
*/
|
||||
|
||||
/* The Mostek 48t02 real time clock and NVRAM chip. The registers
|
||||
* other than the control register are in binary coded decimal. Some
|
||||
* control bits also live outside the control register.
|
||||
*
|
||||
* We now deal with physical addresses for I/O to the chip. -DaveM
|
||||
*/
|
||||
static inline u8 mostek_read(void __iomem *addr)
|
||||
{
|
||||
u8 ret;
|
||||
|
||||
__asm__ __volatile__("lduba [%1] %2, %0"
|
||||
: "=r" (ret)
|
||||
: "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void mostek_write(void __iomem *addr, u8 val)
|
||||
{
|
||||
__asm__ __volatile__("stba %0, [%1] %2"
|
||||
: /* no outputs */
|
||||
: "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
|
||||
}
|
||||
|
||||
#define MOSTEK_EEPROM 0x0000UL
|
||||
#define MOSTEK_IDPROM 0x07d8UL
|
||||
#define MOSTEK_CREG 0x07f8UL
|
||||
#define MOSTEK_SEC 0x07f9UL
|
||||
#define MOSTEK_MIN 0x07faUL
|
||||
#define MOSTEK_HOUR 0x07fbUL
|
||||
#define MOSTEK_DOW 0x07fcUL
|
||||
#define MOSTEK_DOM 0x07fdUL
|
||||
#define MOSTEK_MONTH 0x07feUL
|
||||
#define MOSTEK_YEAR 0x07ffUL
|
||||
|
||||
extern spinlock_t mostek_lock;
|
||||
extern void __iomem *mstk48t02_regs;
|
||||
|
||||
/* Control register values. */
|
||||
#define MSTK_CREG_WRITE 0x80 /* Must set this before placing values. */
|
||||
#define MSTK_CREG_READ 0x40 /* Stop updates to allow a clean read. */
|
||||
#define MSTK_CREG_SIGN 0x20 /* Slow/speed clock in calibration mode. */
|
||||
|
||||
/* Control bits that live in the other registers. */
|
||||
#define MSTK_STOP 0x80 /* Stop the clock oscillator. (sec) */
|
||||
#define MSTK_KICK_START 0x80 /* Kick start the clock chip. (hour) */
|
||||
#define MSTK_FREQ_TEST 0x40 /* Frequency test mode. (day) */
|
||||
|
||||
#define MSTK_YEAR_ZERO 1968 /* If year reg has zero, it is 1968. */
|
||||
#define MSTK_CVT_YEAR(yr) ((yr) + MSTK_YEAR_ZERO)
|
||||
|
||||
/* Masks that define how much space each value takes up. */
|
||||
#define MSTK_SEC_MASK 0x7f
|
||||
#define MSTK_MIN_MASK 0x7f
|
||||
#define MSTK_HOUR_MASK 0x3f
|
||||
#define MSTK_DOW_MASK 0x07
|
||||
#define MSTK_DOM_MASK 0x3f
|
||||
#define MSTK_MONTH_MASK 0x1f
|
||||
#define MSTK_YEAR_MASK 0xffU
|
||||
|
||||
/* Binary coded decimal conversion macros. */
|
||||
#define MSTK_REGVAL_TO_DECIMAL(x) (((x) & 0x0F) + 0x0A * ((x) >> 0x04))
|
||||
#define MSTK_DECIMAL_TO_REGVAL(x) ((((x) / 0x0A) << 0x04) + ((x) % 0x0A))
|
||||
|
||||
/* Generic register set and get macros for internal use. */
|
||||
#define MSTK_GET(regs,name) \
|
||||
(MSTK_REGVAL_TO_DECIMAL(mostek_read(regs + MOSTEK_ ## name) & MSTK_ ## name ## _MASK))
|
||||
#define MSTK_SET(regs,name,value) \
|
||||
do { u8 __val = mostek_read(regs + MOSTEK_ ## name); \
|
||||
__val &= ~(MSTK_ ## name ## _MASK); \
|
||||
__val |= (MSTK_DECIMAL_TO_REGVAL(value) & \
|
||||
(MSTK_ ## name ## _MASK)); \
|
||||
mostek_write(regs + MOSTEK_ ## name, __val); \
|
||||
} while(0)
|
||||
|
||||
/* Macros to make register access easier on our fingers. These give you
|
||||
* the decimal value of the register requested if applicable. You pass
|
||||
* the a pointer to a 'struct mostek48t02'.
|
||||
*/
|
||||
#define MSTK_REG_CREG(regs) (mostek_read((regs) + MOSTEK_CREG))
|
||||
#define MSTK_REG_SEC(regs) MSTK_GET(regs,SEC)
|
||||
#define MSTK_REG_MIN(regs) MSTK_GET(regs,MIN)
|
||||
#define MSTK_REG_HOUR(regs) MSTK_GET(regs,HOUR)
|
||||
#define MSTK_REG_DOW(regs) MSTK_GET(regs,DOW)
|
||||
#define MSTK_REG_DOM(regs) MSTK_GET(regs,DOM)
|
||||
#define MSTK_REG_MONTH(regs) MSTK_GET(regs,MONTH)
|
||||
#define MSTK_REG_YEAR(regs) MSTK_GET(regs,YEAR)
|
||||
|
||||
#define MSTK_SET_REG_SEC(regs,value) MSTK_SET(regs,SEC,value)
|
||||
#define MSTK_SET_REG_MIN(regs,value) MSTK_SET(regs,MIN,value)
|
||||
#define MSTK_SET_REG_HOUR(regs,value) MSTK_SET(regs,HOUR,value)
|
||||
#define MSTK_SET_REG_DOW(regs,value) MSTK_SET(regs,DOW,value)
|
||||
#define MSTK_SET_REG_DOM(regs,value) MSTK_SET(regs,DOM,value)
|
||||
#define MSTK_SET_REG_MONTH(regs,value) MSTK_SET(regs,MONTH,value)
|
||||
#define MSTK_SET_REG_YEAR(regs,value) MSTK_SET(regs,YEAR,value)
|
||||
|
||||
|
||||
/* The Mostek 48t08 clock chip. Found on Sun4m's I think. It has the
|
||||
* same (basically) layout of the 48t02 chip except for the extra
|
||||
* NVRAM on board (8 KB against the 48t02's 2 KB).
|
||||
*/
|
||||
#define MOSTEK_48T08_OFFSET 0x0000UL /* Lower NVRAM portions */
|
||||
#define MOSTEK_48T08_48T02 0x1800UL /* Offset to 48T02 chip */
|
||||
|
||||
/* SUN5 systems usually have 48t59 model clock chipsets. But we keep the older
|
||||
* clock chip definitions around just in case.
|
||||
*/
|
||||
#define MOSTEK_48T59_OFFSET 0x0000UL /* Lower NVRAM portions */
|
||||
#define MOSTEK_48T59_48T02 0x1800UL /* Offset to 48T02 chip */
|
||||
|
||||
#endif /* !(_SPARC64_MOSTEK_H) */
|
@ -155,17 +155,6 @@ static inline void bw_set_ctrl(int cpu, unsigned ctrl)
|
||||
"i" (ASI_M_CTL));
|
||||
}
|
||||
|
||||
extern unsigned char cpu_leds[32];
|
||||
|
||||
static inline void show_leds(int cpuid)
|
||||
{
|
||||
cpuid &= 0x1e;
|
||||
__asm__ __volatile__ ("stba %0, [%1] %2" : :
|
||||
"r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]),
|
||||
"r" (ECSR_BASE(cpuid) | BB_LEDS),
|
||||
"i" (ASI_M_CTL));
|
||||
}
|
||||
|
||||
static inline unsigned cc_get_ipen(void)
|
||||
{
|
||||
unsigned pending;
|
||||
|
@ -30,6 +30,8 @@ struct of_device
|
||||
extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
|
||||
extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
|
||||
|
||||
extern void of_propagate_archdata(struct of_device *bus);
|
||||
|
||||
/* This is just here during the transition */
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
|
@ -13,9 +13,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
extern struct bus_type ebus_bus_type;
|
||||
extern struct bus_type sbus_bus_type;
|
||||
|
||||
#define of_bus_type of_platform_bus_type /* for compatibility */
|
||||
|
||||
#endif
|
||||
|
@ -21,7 +21,6 @@ enum prom_major_version {
|
||||
PROM_V2, /* sun4c and early sun4m V2 prom */
|
||||
PROM_V3, /* sun4m and later, up to sun4d/sun4e machines V3 */
|
||||
PROM_P1275, /* IEEE compliant ISA based Sun PROM, only sun4u */
|
||||
PROM_SUN4, /* Old sun4 proms are totally different, but we'll shoehorn it to make it fit */
|
||||
};
|
||||
|
||||
extern enum prom_major_version prom_vers;
|
||||
|
@ -8,11 +8,8 @@
|
||||
#ifndef _SPARC_PAGE_H
|
||||
#define _SPARC_PAGE_H
|
||||
|
||||
#ifdef CONFIG_SUN4
|
||||
#define PAGE_SHIFT 13
|
||||
#else
|
||||
#define PAGE_SHIFT 12
|
||||
#endif
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/* I have my suspicions... -DaveM */
|
||||
#define PAGE_SIZE (1UL << PAGE_SHIFT)
|
||||
|
@ -38,6 +38,8 @@
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#define WANT_PAGE_VIRTUAL
|
||||
|
||||
extern void _clear_page(void *page);
|
||||
#define clear_page(X) _clear_page((void *)(X))
|
||||
struct page;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/ebus.h>
|
||||
#include <asm/ebus_dma.h>
|
||||
#include <asm/ns87303.h>
|
||||
#include <asm/prom.h>
|
||||
|
||||
@ -215,7 +215,7 @@ static int __devexit ecpp_remove(struct of_device *op)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id ecpp_match[] = {
|
||||
static const struct of_device_id ecpp_match[] = {
|
||||
{
|
||||
.name = "ecpp",
|
||||
},
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
/* Can be used to override the logic in pci_scan_bus for skipping
|
||||
* already-configured bus numbers - to be used for buggy BIOSes
|
||||
* or architectures with incomplete PCI setup by the loader.
|
||||
|
@ -14,11 +14,7 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/swap.h>
|
||||
#include <asm/types.h>
|
||||
#ifdef CONFIG_SUN4
|
||||
#include <asm/pgtsun4.h>
|
||||
#else
|
||||
#include <asm/pgtsun4c.h>
|
||||
#endif
|
||||
#include <asm/pgtsrmmu.h>
|
||||
#include <asm/vac-ops.h>
|
||||
#include <asm/oplib.h>
|
||||
|
@ -770,6 +770,8 @@ extern void sun4v_patch_tlb_handlers(void);
|
||||
|
||||
extern unsigned long cmdline_memory_size;
|
||||
|
||||
extern asmlinkage void do_sparc64_fault(struct pt_regs *regs);
|
||||
|
||||
#endif /* !(__ASSEMBLY__) */
|
||||
|
||||
#endif /* !(_SPARC64_PGTABLE_H) */
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 2
|
||||
@ -73,6 +74,7 @@ struct of_irq_controller {
|
||||
|
||||
extern struct device_node *of_find_node_by_cpuid(int cpuid);
|
||||
extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
|
||||
extern struct mutex of_set_property_mutex;
|
||||
extern int of_getintprop_default(struct device_node *np,
|
||||
const char *name,
|
||||
int def);
|
||||
@ -94,6 +96,16 @@ static inline void of_node_put(struct device_node *node)
|
||||
{
|
||||
}
|
||||
|
||||
/* These routines are here to provide compatibility with how powerpc
|
||||
* handles IRQ mapping for OF device nodes. We precompute and permanently
|
||||
* register them in the of_device objects, whereas powerpc computes them
|
||||
* on request.
|
||||
*/
|
||||
extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
|
||||
static inline void irq_dispose_mapping(unsigned int virq)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: This is here while we transition from using asm/prom.h
|
||||
* to linux/of.h
|
||||
|
@ -113,6 +113,8 @@ struct sparc_trapf {
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/threads.h>
|
||||
|
||||
static inline int pt_regs_trap_type(struct pt_regs *regs)
|
||||
{
|
||||
return regs->magic & 0x1ff;
|
||||
@ -138,6 +140,7 @@ struct global_reg_snapshot {
|
||||
struct thread_info *thread;
|
||||
unsigned long pad1;
|
||||
};
|
||||
extern struct global_reg_snapshot global_reg_snapshot[NR_CPUS];
|
||||
|
||||
#define __ARCH_WANT_COMPAT_SYS_PTRACE
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
#ifndef _SPARC64_REBOOT_H
|
||||
#define _SPARC64_REBOOT_H
|
||||
|
||||
extern void machine_alt_power_off(void);
|
||||
|
||||
#endif /* _SPARC64_REBOOT_H */
|
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* rtc.h: Definitions for access to the Mostek real time clock
|
||||
*
|
||||
* Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
|
||||
*/
|
||||
|
||||
#ifndef _RTC_H
|
||||
#define _RTC_H
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
struct rtc_time
|
||||
{
|
||||
int sec; /* Seconds (0-59) */
|
||||
int min; /* Minutes (0-59) */
|
||||
int hour; /* Hour (0-23) */
|
||||
int dow; /* Day of the week (1-7) */
|
||||
int dom; /* Day of the month (1-31) */
|
||||
int month; /* Month of year (1-12) */
|
||||
int year; /* Year (0-99) */
|
||||
};
|
||||
|
||||
#define RTCGET _IOR('p', 20, struct rtc_time)
|
||||
#define RTCSET _IOW('p', 21, struct rtc_time)
|
||||
|
||||
#endif
|
@ -1,8 +0,0 @@
|
||||
#ifndef ___ASM_SPARC_SBUS_H
|
||||
#define ___ASM_SPARC_SBUS_H
|
||||
#if defined(__sparc__) && defined(__arch64__)
|
||||
#include <asm/sbus_64.h>
|
||||
#else
|
||||
#include <asm/sbus_32.h>
|
||||
#endif
|
||||
#endif
|
@ -1,153 +0,0 @@
|
||||
/*
|
||||
* sbus.h: Defines for the Sun SBus.
|
||||
*
|
||||
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
|
||||
*/
|
||||
|
||||
#ifndef _SPARC_SBUS_H
|
||||
#define _SPARC_SBUS_H
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/scatterlist.h>
|
||||
|
||||
/* We scan which devices are on the SBus using the PROM node device
|
||||
* tree. SBus devices are described in two different ways. You can
|
||||
* either get an absolute address at which to access the device, or
|
||||
* you can get a SBus 'slot' number and an offset within that slot.
|
||||
*/
|
||||
|
||||
/* The base address at which to calculate device OBIO addresses. */
|
||||
#define SUN_SBUS_BVADDR 0xf8000000
|
||||
#define SBUS_OFF_MASK 0x01ffffff
|
||||
|
||||
/* These routines are used to calculate device address from slot
|
||||
* numbers + offsets, and vice versa.
|
||||
*/
|
||||
|
||||
static inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
|
||||
{
|
||||
return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<25)+(offset));
|
||||
}
|
||||
|
||||
static inline int sbus_dev_slot(unsigned long dev_addr)
|
||||
{
|
||||
return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>25);
|
||||
}
|
||||
|
||||
struct sbus_bus;
|
||||
|
||||
/* Linux SBUS device tables */
|
||||
struct sbus_dev {
|
||||
struct of_device ofdev;
|
||||
struct sbus_bus *bus;
|
||||
struct sbus_dev *next;
|
||||
struct sbus_dev *child;
|
||||
struct sbus_dev *parent;
|
||||
int prom_node;
|
||||
char prom_name[64];
|
||||
int slot;
|
||||
|
||||
struct resource resource[PROMREG_MAX];
|
||||
|
||||
struct linux_prom_registers reg_addrs[PROMREG_MAX];
|
||||
int num_registers;
|
||||
|
||||
struct linux_prom_ranges device_ranges[PROMREG_MAX];
|
||||
int num_device_ranges;
|
||||
|
||||
unsigned int irqs[4];
|
||||
int num_irqs;
|
||||
};
|
||||
#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
|
||||
|
||||
/* This struct describes the SBus(s) found on this machine. */
|
||||
struct sbus_bus {
|
||||
struct of_device ofdev;
|
||||
struct sbus_dev *devices; /* Link to devices on this SBus */
|
||||
struct sbus_bus *next; /* next SBus, if more than one SBus */
|
||||
int prom_node; /* PROM device tree node for this SBus */
|
||||
char prom_name[64]; /* Usually "sbus" or "sbi" */
|
||||
int clock_freq;
|
||||
|
||||
struct linux_prom_ranges sbus_ranges[PROMREG_MAX];
|
||||
int num_sbus_ranges;
|
||||
|
||||
int devid;
|
||||
int board;
|
||||
};
|
||||
#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
|
||||
|
||||
extern struct sbus_bus *sbus_root;
|
||||
|
||||
static inline int
|
||||
sbus_is_slave(struct sbus_dev *dev)
|
||||
{
|
||||
/* XXX Have to write this for sun4c's */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Device probing routines could find these handy */
|
||||
#define for_each_sbus(bus) \
|
||||
for((bus) = sbus_root; (bus); (bus)=(bus)->next)
|
||||
|
||||
#define for_each_sbusdev(device, bus) \
|
||||
for((device) = (bus)->devices; (device); (device)=(device)->next)
|
||||
|
||||
#define for_all_sbusdev(device, bus) \
|
||||
for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
|
||||
for ((device) = (bus)->devices; (device); (device) = (device)->next)
|
||||
|
||||
/* Driver DVMA interfaces. */
|
||||
#define sbus_can_dma_64bit(sdev) (0) /* actually, sparc_cpu_model==sun4d */
|
||||
#define sbus_can_burst64(sdev) (0) /* actually, sparc_cpu_model==sun4d */
|
||||
extern void sbus_set_sbus64(struct sbus_dev *, int);
|
||||
extern void sbus_fill_device_irq(struct sbus_dev *);
|
||||
|
||||
/* These yield IOMMU mappings in consistent mode. */
|
||||
extern void *sbus_alloc_consistent(struct sbus_dev *, long, u32 *dma_addrp);
|
||||
extern void sbus_free_consistent(struct sbus_dev *, long, void *, u32);
|
||||
void prom_adjust_ranges(struct linux_prom_ranges *, int,
|
||||
struct linux_prom_ranges *, int);
|
||||
|
||||
#define SBUS_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL
|
||||
#define SBUS_DMA_TODEVICE DMA_TO_DEVICE
|
||||
#define SBUS_DMA_FROMDEVICE DMA_FROM_DEVICE
|
||||
#define SBUS_DMA_NONE DMA_NONE
|
||||
|
||||
/* All the rest use streaming mode mappings. */
|
||||
extern dma_addr_t sbus_map_single(struct sbus_dev *, void *, size_t, int);
|
||||
extern void sbus_unmap_single(struct sbus_dev *, dma_addr_t, size_t, int);
|
||||
extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int, int);
|
||||
extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int);
|
||||
|
||||
/* Finally, allow explicit synchronization of streamable mappings. */
|
||||
extern void sbus_dma_sync_single_for_cpu(struct sbus_dev *, dma_addr_t, size_t, int);
|
||||
#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
|
||||
extern void sbus_dma_sync_single_for_device(struct sbus_dev *, dma_addr_t, size_t, int);
|
||||
extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, int, int);
|
||||
#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
|
||||
extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int);
|
||||
|
||||
/* Eric Brower (ebrower@usa.net)
|
||||
* Translate SBus interrupt levels to ino values--
|
||||
* this is used when converting sbus "interrupts" OBP
|
||||
* node values to "intr" node values, and is platform
|
||||
* dependent. If only we could call OBP with
|
||||
* "sbus-intr>cpu (sbint -- ino)" from kernel...
|
||||
* See .../drivers/sbus/sbus.c for details.
|
||||
*/
|
||||
BTFIXUPDEF_CALL(unsigned int, sbint_to_irq, struct sbus_dev *sdev, unsigned int)
|
||||
#define sbint_to_irq(sdev, sbint) BTFIXUP_CALL(sbint_to_irq)(sdev, sbint)
|
||||
|
||||
extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
|
||||
extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
|
||||
extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
|
||||
extern int sbus_arch_preinit(void);
|
||||
extern void sbus_arch_postinit(void);
|
||||
|
||||
#endif /* !(_SPARC_SBUS_H) */
|
@ -1,190 +0,0 @@
|
||||
/* sbus.h: Defines for the Sun SBus.
|
||||
*
|
||||
* Copyright (C) 1996, 1999, 2007 David S. Miller (davem@davemloft.net)
|
||||
*/
|
||||
|
||||
#ifndef _SPARC64_SBUS_H
|
||||
#define _SPARC64_SBUS_H
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/iommu.h>
|
||||
#include <asm/scatterlist.h>
|
||||
|
||||
/* We scan which devices are on the SBus using the PROM node device
|
||||
* tree. SBus devices are described in two different ways. You can
|
||||
* either get an absolute address at which to access the device, or
|
||||
* you can get a SBus 'slot' number and an offset within that slot.
|
||||
*/
|
||||
|
||||
/* The base address at which to calculate device OBIO addresses. */
|
||||
#define SUN_SBUS_BVADDR 0x00000000
|
||||
#define SBUS_OFF_MASK 0x0fffffff
|
||||
|
||||
/* These routines are used to calculate device address from slot
|
||||
* numbers + offsets, and vice versa.
|
||||
*/
|
||||
|
||||
static inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
|
||||
{
|
||||
return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<28)+(offset));
|
||||
}
|
||||
|
||||
static inline int sbus_dev_slot(unsigned long dev_addr)
|
||||
{
|
||||
return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>28);
|
||||
}
|
||||
|
||||
struct sbus_bus;
|
||||
|
||||
/* Linux SBUS device tables */
|
||||
struct sbus_dev {
|
||||
struct of_device ofdev;
|
||||
struct sbus_bus *bus;
|
||||
struct sbus_dev *next;
|
||||
struct sbus_dev *child;
|
||||
struct sbus_dev *parent;
|
||||
int prom_node;
|
||||
char prom_name[64];
|
||||
int slot;
|
||||
|
||||
struct resource resource[PROMREG_MAX];
|
||||
|
||||
struct linux_prom_registers reg_addrs[PROMREG_MAX];
|
||||
int num_registers;
|
||||
|
||||
struct linux_prom_ranges device_ranges[PROMREG_MAX];
|
||||
int num_device_ranges;
|
||||
|
||||
unsigned int irqs[4];
|
||||
int num_irqs;
|
||||
};
|
||||
#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
|
||||
|
||||
/* This struct describes the SBus(s) found on this machine. */
|
||||
struct sbus_bus {
|
||||
struct of_device ofdev;
|
||||
struct sbus_dev *devices; /* Tree of SBUS devices */
|
||||
struct sbus_bus *next; /* Next SBUS in system */
|
||||
int prom_node; /* OBP node of SBUS */
|
||||
char prom_name[64]; /* Usually "sbus" or "sbi" */
|
||||
int clock_freq;
|
||||
|
||||
struct linux_prom_ranges sbus_ranges[PROMREG_MAX];
|
||||
int num_sbus_ranges;
|
||||
|
||||
int portid;
|
||||
};
|
||||
#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
|
||||
|
||||
extern struct sbus_bus *sbus_root;
|
||||
|
||||
/* Device probing routines could find these handy */
|
||||
#define for_each_sbus(bus) \
|
||||
for((bus) = sbus_root; (bus); (bus)=(bus)->next)
|
||||
|
||||
#define for_each_sbusdev(device, bus) \
|
||||
for((device) = (bus)->devices; (device); (device)=(device)->next)
|
||||
|
||||
#define for_all_sbusdev(device, bus) \
|
||||
for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
|
||||
for ((device) = (bus)->devices; (device); (device) = (device)->next)
|
||||
|
||||
/* Driver DVMA interfaces. */
|
||||
#define sbus_can_dma_64bit(sdev) (1)
|
||||
#define sbus_can_burst64(sdev) (1)
|
||||
extern void sbus_set_sbus64(struct sbus_dev *, int);
|
||||
extern void sbus_fill_device_irq(struct sbus_dev *);
|
||||
|
||||
static inline void *sbus_alloc_consistent(struct sbus_dev *sdev , size_t size,
|
||||
dma_addr_t *dma_handle)
|
||||
{
|
||||
return dma_alloc_coherent(&sdev->ofdev.dev, size,
|
||||
dma_handle, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
static inline void sbus_free_consistent(struct sbus_dev *sdev, size_t size,
|
||||
void *vaddr, dma_addr_t dma_handle)
|
||||
{
|
||||
return dma_free_coherent(&sdev->ofdev.dev, size, vaddr, dma_handle);
|
||||
}
|
||||
|
||||
#define SBUS_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL
|
||||
#define SBUS_DMA_TODEVICE DMA_TO_DEVICE
|
||||
#define SBUS_DMA_FROMDEVICE DMA_FROM_DEVICE
|
||||
#define SBUS_DMA_NONE DMA_NONE
|
||||
|
||||
/* All the rest use streaming mode mappings. */
|
||||
static inline dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr,
|
||||
size_t size, int direction)
|
||||
{
|
||||
return dma_map_single(&sdev->ofdev.dev, ptr, size,
|
||||
(enum dma_data_direction) direction);
|
||||
}
|
||||
|
||||
static inline void sbus_unmap_single(struct sbus_dev *sdev,
|
||||
dma_addr_t dma_addr, size_t size,
|
||||
int direction)
|
||||
{
|
||||
dma_unmap_single(&sdev->ofdev.dev, dma_addr, size,
|
||||
(enum dma_data_direction) direction);
|
||||
}
|
||||
|
||||
static inline int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg,
|
||||
int nents, int direction)
|
||||
{
|
||||
return dma_map_sg(&sdev->ofdev.dev, sg, nents,
|
||||
(enum dma_data_direction) direction);
|
||||
}
|
||||
|
||||
static inline void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg,
|
||||
int nents, int direction)
|
||||
{
|
||||
dma_unmap_sg(&sdev->ofdev.dev, sg, nents,
|
||||
(enum dma_data_direction) direction);
|
||||
}
|
||||
|
||||
/* Finally, allow explicit synchronization of streamable mappings. */
|
||||
static inline void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev,
|
||||
dma_addr_t dma_handle,
|
||||
size_t size, int direction)
|
||||
{
|
||||
dma_sync_single_for_cpu(&sdev->ofdev.dev, dma_handle, size,
|
||||
(enum dma_data_direction) direction);
|
||||
}
|
||||
#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
|
||||
|
||||
static inline void sbus_dma_sync_single_for_device(struct sbus_dev *sdev,
|
||||
dma_addr_t dma_handle,
|
||||
size_t size, int direction)
|
||||
{
|
||||
/* No flushing needed to sync cpu writes to the device. */
|
||||
}
|
||||
|
||||
static inline void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev,
|
||||
struct scatterlist *sg,
|
||||
int nents, int direction)
|
||||
{
|
||||
dma_sync_sg_for_cpu(&sdev->ofdev.dev, sg, nents,
|
||||
(enum dma_data_direction) direction);
|
||||
}
|
||||
#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
|
||||
|
||||
static inline void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev,
|
||||
struct scatterlist *sg,
|
||||
int nents, int direction)
|
||||
{
|
||||
/* No flushing needed to sync cpu writes to the device. */
|
||||
}
|
||||
|
||||
extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
|
||||
extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
|
||||
extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
|
||||
extern int sbus_arch_preinit(void);
|
||||
extern void sbus_arch_postinit(void);
|
||||
|
||||
#endif /* !(_SPARC64_SBUS_H) */
|
@ -6,8 +6,6 @@
|
||||
#ifndef __SPARC_SPINLOCK_H
|
||||
#define __SPARC_SPINLOCK_H
|
||||
|
||||
#include <linux/threads.h> /* For NR_CPUS */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <asm/psr.h>
|
||||
|
@ -6,8 +6,6 @@
|
||||
#ifndef __SPARC64_SPINLOCK_H
|
||||
#define __SPARC64_SPINLOCK_H
|
||||
|
||||
#include <linux/threads.h> /* For NR_CPUS */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/* To get debugging spinlocks which detect and catch
|
||||
|
@ -1,13 +0,0 @@
|
||||
#ifndef _SPARC64_SSTATE_H
|
||||
#define _SPARC64_SSTATE_H
|
||||
|
||||
extern void sstate_booting(void);
|
||||
extern void sstate_running(void);
|
||||
extern void sstate_halt(void);
|
||||
extern void sstate_poweroff(void);
|
||||
extern void sstate_panic(void);
|
||||
extern void sstate_reboot(void);
|
||||
|
||||
extern void sun4v_sstate_init(void);
|
||||
|
||||
#endif /* _SPARC64_SSTATE_H */
|
@ -12,7 +12,6 @@
|
||||
extern int this_is_starfire;
|
||||
|
||||
extern void check_if_starfire(void);
|
||||
extern void starfire_cpu_setup(void);
|
||||
extern int starfire_hard_smp_processor_id(void);
|
||||
extern void starfire_hookup(int);
|
||||
extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid);
|
||||
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* sun4paddr.h: Various physical addresses on sun4 machines
|
||||
*
|
||||
* Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
|
||||
* Copyright (C) 1998 Chris Davis (cdavis@cois.on.ca)
|
||||
*
|
||||
* Now supports more sun4's
|
||||
*/
|
||||
|
||||
#ifndef _SPARC_SUN4PADDR_H
|
||||
#define _SPARC_SUN4PADDR_H
|
||||
|
||||
#define SUN4_IE_PHYSADDR 0xf5000000
|
||||
#define SUN4_UNUSED_PHYSADDR 0
|
||||
|
||||
/* these work for me */
|
||||
#define SUN4_200_MEMREG_PHYSADDR 0xf4000000
|
||||
#define SUN4_200_CLOCK_PHYSADDR 0xf3000000
|
||||
#define SUN4_200_BWTWO_PHYSADDR 0xfd000000
|
||||
#define SUN4_200_ETH_PHYSADDR 0xf6000000
|
||||
#define SUN4_200_SI_PHYSADDR 0xff200000
|
||||
|
||||
/* these were here before */
|
||||
#define SUN4_300_MEMREG_PHYSADDR 0xf4000000
|
||||
#define SUN4_300_CLOCK_PHYSADDR 0xf2000000
|
||||
#define SUN4_300_TIMER_PHYSADDR 0xef000000
|
||||
#define SUN4_300_ETH_PHYSADDR 0xf9000000
|
||||
#define SUN4_300_BWTWO_PHYSADDR 0xfb400000
|
||||
#define SUN4_300_DMA_PHYSADDR 0xfa001000
|
||||
#define SUN4_300_ESP_PHYSADDR 0xfa000000
|
||||
|
||||
/* Are these right? */
|
||||
#define SUN4_400_MEMREG_PHYSADDR 0xf4000000
|
||||
#define SUN4_400_CLOCK_PHYSADDR 0xf2000000
|
||||
#define SUN4_400_TIMER_PHYSADDR 0xef000000
|
||||
#define SUN4_400_ETH_PHYSADDR 0xf9000000
|
||||
#define SUN4_400_BWTWO_PHYSADDR 0xfb400000
|
||||
#define SUN4_400_DMA_PHYSADDR 0xfa001000
|
||||
#define SUN4_400_ESP_PHYSADDR 0xfa000000
|
||||
|
||||
/*
|
||||
these are the actual values set and used in the code. Unused items set
|
||||
to SUN_UNUSED_PHYSADDR
|
||||
*/
|
||||
|
||||
extern int sun4_memreg_physaddr; /* memory register (ecc?) */
|
||||
extern int sun4_clock_physaddr; /* system clock */
|
||||
extern int sun4_timer_physaddr; /* timer, where applicable */
|
||||
extern int sun4_eth_physaddr; /* onboard ethernet (ie/le) */
|
||||
extern int sun4_si_physaddr; /* sun3 scsi adapter */
|
||||
extern int sun4_bwtwo_physaddr; /* onboard bw2 */
|
||||
extern int sun4_dma_physaddr; /* scsi dma */
|
||||
extern int sun4_esp_physaddr; /* esp scsi */
|
||||
extern int sun4_ie_physaddr; /* interrupt enable */
|
||||
|
||||
#endif /* !(_SPARC_SUN4PADDR_H) */
|
@ -1,83 +0,0 @@
|
||||
/*
|
||||
* sun4prom.h -- interface to sun4 PROM monitor. We don't use most of this,
|
||||
* so most of these are just placeholders.
|
||||
*/
|
||||
|
||||
#ifndef _SUN4PROM_H_
|
||||
#define _SUN4PROM_H_
|
||||
|
||||
/*
|
||||
* Although this looks similar to an romvec for a OpenProm machine, it is
|
||||
* actually closer to what was used in the Sun2 and Sun3.
|
||||
*
|
||||
* V2 entries exist only in version 2 PROMs and later, V3 in version 3 and later.
|
||||
*
|
||||
* Many of the function prototypes are guesses. Some are certainly wrong.
|
||||
* Use with care.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char *initSP; /* Initial system stack ptr */
|
||||
void (*startmon)(void); /* Initial PC for hardware */
|
||||
int *diagberr; /* Bus err handler for diags */
|
||||
struct linux_arguments_v0 **bootParam; /* Info for bootstrapped pgm */
|
||||
unsigned int *memorysize; /* Usable memory in bytes */
|
||||
unsigned char (*getchar)(void); /* Get char from input device */
|
||||
void (*putchar)(char); /* Put char to output device */
|
||||
int (*mayget)(void); /* Maybe get char, or -1 */
|
||||
int (*mayput)(int); /* Maybe put char, or -1 */
|
||||
unsigned char *echo; /* Should getchar echo? */
|
||||
unsigned char *insource; /* Input source selector */
|
||||
unsigned char *outsink; /* Output sink selector */
|
||||
int (*getkey)(void); /* Get next key if one exists */
|
||||
void (*initgetkey)(void); /* Initialize get key */
|
||||
unsigned int *translation; /* Kbd translation selector */
|
||||
unsigned char *keybid; /* Keyboard ID byte */
|
||||
int *screen_x; /* V2: Screen x pos (r/o) */
|
||||
int *screen_y; /* V2: Screen y pos (r/o) */
|
||||
struct keybuf *keybuf; /* Up/down keycode buffer */
|
||||
char *monid; /* Monitor version ID */
|
||||
void (*fbwritechar)(char); /* Write a character to FB */
|
||||
int *fbAddr; /* Address of frame buffer */
|
||||
char **font; /* Font table for FB */
|
||||
void (*fbwritestr)(char *); /* Write string to FB */
|
||||
void (*reboot)(char *); /* e.g. reboot("sd()vmlinux") */
|
||||
unsigned char *linebuf; /* The line input buffer */
|
||||
unsigned char **lineptr; /* Cur pointer into linebuf */
|
||||
int *linesize; /* length of line in linebuf */
|
||||
void (*getline)(char *); /* Get line from user */
|
||||
unsigned char (*getnextchar)(void); /* Get next char from linebuf */
|
||||
unsigned char (*peeknextchar)(void); /* Peek at next char */
|
||||
int *fbthere; /* =1 if frame buffer there */
|
||||
int (*getnum)(void); /* Grab hex num from line */
|
||||
int (*printf)(char *, ...); /* See prom_printf() instead */
|
||||
void (*printhex)(int); /* Format N digits in hex */
|
||||
unsigned char *leds; /* RAM copy of LED register */
|
||||
void (*setLEDs)(unsigned char *); /* Sets LED's and RAM copy */
|
||||
void (*NMIaddr)(void *); /* Addr for level 7 vector */
|
||||
void (*abortentry)(void); /* Entry for keyboard abort */
|
||||
int *nmiclock; /* Counts up in msec */
|
||||
int *FBtype; /* Frame buffer type */
|
||||
unsigned int romvecversion; /* Version number for this romvec */
|
||||
struct globram *globram; /* monitor global variables ??? */
|
||||
void * kbdaddr; /* Addr of keyboard in use */
|
||||
int *keyrinit; /* ms before kbd repeat */
|
||||
unsigned char *keyrtick; /* ms between repetitions */
|
||||
unsigned int *memoryavail; /* V1: Main mem usable size */
|
||||
long *resetaddr; /* where to jump on a reset */
|
||||
long *resetmap; /* pgmap entry for resetaddr */
|
||||
void (*exittomon)(void); /* Exit from user program */
|
||||
unsigned char **memorybitmap; /* V1: &{0 or &bits} */
|
||||
void (*setcxsegmap)(int ctxt, char *va, int pmeg); /* Set seg in any context */
|
||||
void (**vector_cmd)(void *); /* V2: Handler for 'v' cmd */
|
||||
unsigned long *expectedtrapsig; /* V3: Location of the expected trap signal */
|
||||
unsigned long *trapvectorbasetable; /* V3: Address of the trap vector table */
|
||||
int unused1;
|
||||
int unused2;
|
||||
int unused3;
|
||||
int unused4;
|
||||
} linux_sun4_romvec;
|
||||
|
||||
extern linux_sun4_romvec *sun4_romvec;
|
||||
|
||||
#endif /* _SUN4PROM_H_ */
|
@ -34,13 +34,7 @@ enum sparc_cpu {
|
||||
|
||||
extern enum sparc_cpu sparc_cpu_model;
|
||||
|
||||
#ifndef CONFIG_SUN4
|
||||
#define ARCH_SUN4C_SUN4 (sparc_cpu_model==sun4c)
|
||||
#define ARCH_SUN4 0
|
||||
#else
|
||||
#define ARCH_SUN4C_SUN4 1
|
||||
#define ARCH_SUN4 1
|
||||
#endif
|
||||
#define ARCH_SUN4C (sparc_cpu_model==sun4c)
|
||||
|
||||
#define SUN4M_NCPUS 4 /* Architectural limit of sun4m. */
|
||||
|
||||
@ -55,6 +49,7 @@ extern unsigned long empty_zero_page;
|
||||
extern void sun_do_break(void);
|
||||
extern int serial_console;
|
||||
extern int stop_a_enabled;
|
||||
extern int scons_pwroff;
|
||||
|
||||
static inline int con_is_present(void)
|
||||
{
|
||||
|
@ -26,9 +26,8 @@ enum sparc_cpu {
|
||||
|
||||
#define sparc_cpu_model sun4u
|
||||
|
||||
/* This cannot ever be a sun4c nor sun4 :) That's just history. */
|
||||
#define ARCH_SUN4C_SUN4 0
|
||||
#define ARCH_SUN4 0
|
||||
/* This cannot ever be a sun4c :) That's just history. */
|
||||
#define ARCH_SUN4C 0
|
||||
|
||||
extern char reboot_command[];
|
||||
|
||||
@ -118,6 +117,7 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
|
||||
|
||||
extern void sun_do_break(void);
|
||||
extern int stop_a_enabled;
|
||||
extern int scons_pwroff;
|
||||
|
||||
extern void fault_in_user_windows(void);
|
||||
extern void synchronize_user_stack(void);
|
||||
|
@ -80,11 +80,7 @@ register struct thread_info *current_thread_info_reg asm("g6");
|
||||
/*
|
||||
* thread information allocation
|
||||
*/
|
||||
#if PAGE_SHIFT == 13
|
||||
#define THREAD_INFO_ORDER 0
|
||||
#else /* PAGE_SHIFT */
|
||||
#define THREAD_INFO_ORDER 1
|
||||
#endif
|
||||
|
||||
#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
|
||||
|
||||
|
@ -9,96 +9,9 @@
|
||||
#define _SPARC_TIMER_H
|
||||
|
||||
#include <asm/system.h> /* For SUN4M_NCPUS */
|
||||
#include <asm/sun4paddr.h>
|
||||
#include <asm/btfixup.h>
|
||||
|
||||
/* Timer structures. The interrupt timer has two properties which
|
||||
* are the counter (which is handled in do_timer in sched.c) and the limit.
|
||||
* This limit is where the timer's counter 'wraps' around. Oddly enough,
|
||||
* the sun4c timer when it hits the limit wraps back to 1 and not zero
|
||||
* thus when calculating the value at which it will fire a microsecond you
|
||||
* must adjust by one. Thanks SUN for designing such great hardware ;(
|
||||
*/
|
||||
|
||||
/* Note that I am only going to use the timer that interrupts at
|
||||
* Sparc IRQ 10. There is another one available that can fire at
|
||||
* IRQ 14. Currently it is left untouched, we keep the PROM's limit
|
||||
* register value and let the prom take these interrupts. This allows
|
||||
* L1-A to work.
|
||||
*/
|
||||
|
||||
struct sun4c_timer_info {
|
||||
__volatile__ unsigned int cur_count10;
|
||||
__volatile__ unsigned int timer_limit10;
|
||||
__volatile__ unsigned int cur_count14;
|
||||
__volatile__ unsigned int timer_limit14;
|
||||
};
|
||||
|
||||
#define SUN4C_TIMER_PHYSADDR 0xf3000000
|
||||
#ifdef CONFIG_SUN4
|
||||
#define SUN_TIMER_PHYSADDR SUN4_300_TIMER_PHYSADDR
|
||||
#else
|
||||
#define SUN_TIMER_PHYSADDR SUN4C_TIMER_PHYSADDR
|
||||
#endif
|
||||
|
||||
/* A sun4m has two blocks of registers which are probably of the same
|
||||
* structure. LSI Logic's L64851 is told to _decrement_ from the limit
|
||||
* value. Aurora behaves similarly but its limit value is compacted in
|
||||
* other fashion (it's wider). Documented fields are defined here.
|
||||
*/
|
||||
|
||||
/* As with the interrupt register, we have two classes of timer registers
|
||||
* which are per-cpu and master. Per-cpu timers only hit that cpu and are
|
||||
* only level 14 ticks, master timer hits all cpus and is level 10.
|
||||
*/
|
||||
|
||||
#define SUN4M_PRM_CNT_L 0x80000000
|
||||
#define SUN4M_PRM_CNT_LVALUE 0x7FFFFC00
|
||||
|
||||
struct sun4m_timer_percpu_info {
|
||||
__volatile__ unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */
|
||||
__volatile__ unsigned int l14_cur_count;
|
||||
|
||||
/* This register appears to be write only and/or inaccessible
|
||||
* on Uni-Processor sun4m machines.
|
||||
*/
|
||||
__volatile__ unsigned int l14_limit_noclear; /* Data access error is here */
|
||||
|
||||
__volatile__ unsigned int cntrl; /* =1 after POST on Aurora */
|
||||
__volatile__ unsigned char space[PAGE_SIZE - 16];
|
||||
};
|
||||
|
||||
struct sun4m_timer_regs {
|
||||
struct sun4m_timer_percpu_info cpu_timers[SUN4M_NCPUS];
|
||||
volatile unsigned int l10_timer_limit;
|
||||
volatile unsigned int l10_cur_count;
|
||||
|
||||
/* Again, this appears to be write only and/or inaccessible
|
||||
* on uni-processor sun4m machines.
|
||||
*/
|
||||
volatile unsigned int l10_limit_noclear;
|
||||
|
||||
/* This register too, it must be magic. */
|
||||
volatile unsigned int foobar;
|
||||
|
||||
volatile unsigned int cfg; /* equals zero at boot time... */
|
||||
};
|
||||
|
||||
#define SUN4D_PRM_CNT_L 0x80000000
|
||||
#define SUN4D_PRM_CNT_LVALUE 0x7FFFFC00
|
||||
|
||||
struct sun4d_timer_regs {
|
||||
volatile unsigned int l10_timer_limit;
|
||||
volatile unsigned int l10_cur_countx;
|
||||
volatile unsigned int l10_limit_noclear;
|
||||
volatile unsigned int ctrl;
|
||||
volatile unsigned int l10_cur_count;
|
||||
};
|
||||
|
||||
extern struct sun4d_timer_regs *sun4d_timers;
|
||||
|
||||
extern __volatile__ unsigned int *master_l10_counter;
|
||||
extern __volatile__ unsigned int *master_l10_limit;
|
||||
|
||||
/* FIXME: Make do_[gs]ettimeofday btfixup calls */
|
||||
BTFIXUPDEF_CALL(int, bus_do_settimeofday, struct timespec *tv)
|
||||
|
@ -76,11 +76,7 @@
|
||||
* cacheable bit in the pte's of all such pages.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SUN4
|
||||
#define S4CVAC_BADBITS 0x0001e000
|
||||
#else
|
||||
#define S4CVAC_BADBITS 0x0000f000
|
||||
#endif
|
||||
|
||||
/* The following is true if vaddr1 and vaddr2 would cause
|
||||
* a 'bad alias'.
|
||||
@ -94,10 +90,7 @@
|
||||
*/
|
||||
struct sun4c_vac_props {
|
||||
unsigned int num_bytes; /* Size of the cache */
|
||||
unsigned int num_lines; /* Number of cache lines */
|
||||
unsigned int do_hwflushes; /* Hardware flushing available? */
|
||||
enum { VAC_NONE, VAC_WRITE_THROUGH,
|
||||
VAC_WRITE_BACK } type; /* What type of VAC? */
|
||||
unsigned int linesize; /* Size of each line in bytes */
|
||||
unsigned int log2lsize; /* log2(linesize) */
|
||||
unsigned int on; /* VAC is enabled */
|
||||
|
@ -1,58 +0,0 @@
|
||||
/* Copyright (c) 1996 by Manish Vachharajani */
|
||||
|
||||
#ifndef _LINUX_VFC_IOCTLS_H_
|
||||
#define _LINUX_VFC_IOCTLS_H_
|
||||
|
||||
/* IOCTLs */
|
||||
#define VFC_IOCTL(a) (('j' << 8) | a)
|
||||
#define VFCGCTRL (VFC_IOCTL (0)) /* get vfc attributes */
|
||||
#define VFCSCTRL (VFC_IOCTL (1)) /* set vfc attributes */
|
||||
#define VFCGVID (VFC_IOCTL (2)) /* get video decoder attributes */
|
||||
#define VFCSVID (VFC_IOCTL (3)) /* set video decoder attributes */
|
||||
#define VFCHUE (VFC_IOCTL (4)) /* set hue */
|
||||
#define VFCPORTCHG (VFC_IOCTL (5)) /* change port */
|
||||
#define VFCRDINFO (VFC_IOCTL (6)) /* read info */
|
||||
|
||||
/* Options for setting the vfc attributes and status */
|
||||
#define MEMPRST 0x1 /* reset FIFO ptr. */
|
||||
#define CAPTRCMD 0x2 /* start capture and wait */
|
||||
#define DIAGMODE 0x3 /* diag mode */
|
||||
#define NORMMODE 0x4 /* normal mode */
|
||||
#define CAPTRSTR 0x5 /* start capture */
|
||||
#define CAPTRWAIT 0x6 /* wait for capture to finish */
|
||||
|
||||
|
||||
/* Options for the decoder */
|
||||
#define STD_NTSC 0x1 /* NTSC mode */
|
||||
#define STD_PAL 0x2 /* PAL mode */
|
||||
#define COLOR_ON 0x3 /* force color ON */
|
||||
#define MONO 0x4 /* force color OFF */
|
||||
|
||||
/* Values returned by ioctl 2 */
|
||||
|
||||
#define NO_LOCK 1
|
||||
#define NTSC_COLOR 2
|
||||
#define NTSC_NOCOLOR 3
|
||||
#define PAL_COLOR 4
|
||||
#define PAL_NOCOLOR 5
|
||||
|
||||
/* Not too sure what this does yet */
|
||||
/* Options for setting Field number */
|
||||
#define ODD_FIELD 0x1
|
||||
#define EVEN_FIELD 0x0
|
||||
#define ACTIVE_ONLY 0x2
|
||||
#define NON_ACTIVE 0x0
|
||||
|
||||
/* Debug options */
|
||||
#define VFC_I2C_SEND 0
|
||||
#define VFC_I2C_RECV 1
|
||||
|
||||
struct vfc_debug_inout
|
||||
{
|
||||
unsigned long addr;
|
||||
unsigned long ret;
|
||||
unsigned long len;
|
||||
unsigned char __user *buffer;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_VFC_IOCTLS_H_ */
|
@ -57,6 +57,7 @@ static inline void save_and_clear_fpu(void) {
|
||||
" " : : "i" (FPRS_FEF|FPRS_DU) :
|
||||
"o5", "g1", "g2", "g3", "g7", "cc");
|
||||
}
|
||||
extern int vis_emul(struct pt_regs *, unsigned int);
|
||||
#endif
|
||||
|
||||
#endif /* _SPARC64_ASI_H */
|
||||
|
@ -13,15 +13,13 @@ obj-y := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
|
||||
time.o windows.o cpu.o devices.o \
|
||||
tadpole.o tick14.o ptrace.o \
|
||||
unaligned.o una_asm.o muldiv.o \
|
||||
prom.o of_device.o devres.o
|
||||
prom.o of_device.o devres.o dma.o
|
||||
|
||||
devres-y = ../../../kernel/irq/devres.o
|
||||
|
||||
obj-$(CONFIG_PCI) += pcic.o
|
||||
obj-$(CONFIG_SUN4) += sun4setup.o
|
||||
obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
|
||||
obj-$(CONFIG_SUN_AUXIO) += auxio.o
|
||||
obj-$(CONFIG_PCI) += ebus.o
|
||||
obj-$(CONFIG_SUN_PM) += apc.o pmc.o
|
||||
obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o
|
||||
obj-$(CONFIG_SPARC_LED) += led.o
|
||||
|
@ -12,9 +12,10 @@
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/sbus.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/auxio.h>
|
||||
@ -29,11 +30,10 @@
|
||||
#define APC_OBPNAME "power-management"
|
||||
#define APC_DEVNAME "apc"
|
||||
|
||||
volatile static u8 __iomem *regs;
|
||||
static int apc_regsize;
|
||||
static u8 __iomem *regs;
|
||||
static int apc_no_idle __initdata = 0;
|
||||
|
||||
#define apc_readb(offs) (sbus_readb(regs+offs))
|
||||
#define apc_readb(offs) (sbus_readb(regs+offs))
|
||||
#define apc_writeb(val, offs) (sbus_writeb(val, regs+offs))
|
||||
|
||||
/* Specify "apc=noidle" on the kernel command line to
|
||||
@ -69,9 +69,9 @@ static void apc_swift_idle(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void apc_free(void)
|
||||
static inline void apc_free(struct of_device *op)
|
||||
{
|
||||
sbus_iounmap(regs, apc_regsize);
|
||||
of_iounmap(&op->resource[0], regs, resource_size(&op->resource[0]));
|
||||
}
|
||||
|
||||
static int apc_open(struct inode *inode, struct file *f)
|
||||
@ -153,52 +153,56 @@ static const struct file_operations apc_fops = {
|
||||
|
||||
static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
|
||||
|
||||
static int __init apc_probe(void)
|
||||
static int __devinit apc_probe(struct of_device *op,
|
||||
const struct of_device_id *match)
|
||||
{
|
||||
struct sbus_bus *sbus = NULL;
|
||||
struct sbus_dev *sdev = NULL;
|
||||
int iTmp = 0;
|
||||
int err;
|
||||
|
||||
for_each_sbus(sbus) {
|
||||
for_each_sbusdev(sdev, sbus) {
|
||||
if (!strcmp(sdev->prom_name, APC_OBPNAME)) {
|
||||
goto sbus_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sbus_done:
|
||||
if (!sdev) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
apc_regsize = sdev->reg_addrs[0].reg_size;
|
||||
regs = sbus_ioremap(&sdev->resource[0], 0,
|
||||
apc_regsize, APC_OBPNAME);
|
||||
if(!regs) {
|
||||
regs = of_ioremap(&op->resource[0], 0,
|
||||
resource_size(&op->resource[0]), APC_OBPNAME);
|
||||
if (!regs) {
|
||||
printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
iTmp = misc_register(&apc_miscdev);
|
||||
if (iTmp != 0) {
|
||||
err = misc_register(&apc_miscdev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME);
|
||||
apc_free();
|
||||
apc_free(op);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Assign power management IDLE handler */
|
||||
if(!apc_no_idle)
|
||||
if (!apc_no_idle)
|
||||
pm_idle = apc_swift_idle;
|
||||
|
||||
printk(KERN_INFO "%s: power management initialized%s\n",
|
||||
APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
|
||||
APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id __initdata apc_match[] = {
|
||||
{
|
||||
.name = APC_OBPNAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, apc_match);
|
||||
|
||||
static struct of_platform_driver apc_driver = {
|
||||
.name = "apc",
|
||||
.match_table = apc_match,
|
||||
.probe = apc_probe,
|
||||
};
|
||||
|
||||
static int __init apc_init(void)
|
||||
{
|
||||
return of_register_driver(&apc_driver, &of_bus_type);
|
||||
}
|
||||
|
||||
/* This driver is not critical to the boot process
|
||||
* and is easiest to ioremap when SBus is already
|
||||
* initialized, so we install ourselves thusly:
|
||||
*/
|
||||
__initcall(apc_probe);
|
||||
|
||||
__initcall(apc_init);
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/auxio.h>
|
||||
@ -59,7 +61,7 @@ void __init auxio_probe(void)
|
||||
r.flags = auxregs[0].which_io & 0xF;
|
||||
r.start = auxregs[0].phys_addr;
|
||||
r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1;
|
||||
auxio_register = sbus_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
|
||||
auxio_register = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
|
||||
/* Fix the address on sun4m and sun4c. */
|
||||
if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 ||
|
||||
sparc_cpu_model == sun4c)
|
||||
@ -128,7 +130,7 @@ void __init auxio_power_probe(void)
|
||||
r.flags = regs.which_io & 0xF;
|
||||
r.start = regs.phys_addr;
|
||||
r.end = regs.phys_addr + regs.reg_size - 1;
|
||||
auxio_power_register = (unsigned char *) sbus_ioremap(&r, 0,
|
||||
auxio_power_register = (unsigned char *) of_ioremap(&r, 0,
|
||||
regs.reg_size, "auxpower");
|
||||
|
||||
/* Display a quick message on the console. */
|
||||
|
@ -143,7 +143,7 @@ void __init device_scan(void)
|
||||
#endif
|
||||
clock_stop_probe();
|
||||
|
||||
if (ARCH_SUN4C_SUN4)
|
||||
if (ARCH_SUN4C)
|
||||
sun4c_probe_memerr_reg();
|
||||
|
||||
return;
|
||||
|
227
arch/sparc/kernel/dma.c
Normal file
227
arch/sparc/kernel/dma.c
Normal file
@ -0,0 +1,227 @@
|
||||
/* dma.c: PCI and SBUS DMA accessors for 32-bit sparc.
|
||||
*
|
||||
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#include <linux/pci.h>
|
||||
#endif
|
||||
|
||||
#include "dma.h"
|
||||
|
||||
int dma_supported(struct device *dev, u64 mask)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type)
|
||||
return pci_dma_supported(to_pci_dev(dev), mask);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_supported);
|
||||
|
||||
int dma_set_mask(struct device *dev, u64 dma_mask)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type)
|
||||
return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
|
||||
#endif
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_set_mask);
|
||||
|
||||
void *dma_alloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t flag)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type)
|
||||
return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
|
||||
#endif
|
||||
return sbus_alloc_consistent(dev, size, dma_handle);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_alloc_coherent);
|
||||
|
||||
void dma_free_coherent(struct device *dev, size_t size,
|
||||
void *cpu_addr, dma_addr_t dma_handle)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type) {
|
||||
pci_free_consistent(to_pci_dev(dev), size,
|
||||
cpu_addr, dma_handle);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
sbus_free_consistent(dev, size, cpu_addr, dma_handle);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_free_coherent);
|
||||
|
||||
dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
|
||||
size_t size, enum dma_data_direction direction)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type)
|
||||
return pci_map_single(to_pci_dev(dev), cpu_addr,
|
||||
size, (int)direction);
|
||||
#endif
|
||||
return sbus_map_single(dev, cpu_addr, size, (int)direction);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_map_single);
|
||||
|
||||
void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
|
||||
size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type) {
|
||||
pci_unmap_single(to_pci_dev(dev), dma_addr,
|
||||
size, (int)direction);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
sbus_unmap_single(dev, dma_addr, size, (int)direction);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_unmap_single);
|
||||
|
||||
dma_addr_t dma_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type)
|
||||
return pci_map_page(to_pci_dev(dev), page, offset,
|
||||
size, (int)direction);
|
||||
#endif
|
||||
return sbus_map_single(dev, page_address(page) + offset,
|
||||
size, (int)direction);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_map_page);
|
||||
|
||||
void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
|
||||
size_t size, enum dma_data_direction direction)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type) {
|
||||
pci_unmap_page(to_pci_dev(dev), dma_address,
|
||||
size, (int)direction);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
sbus_unmap_single(dev, dma_address, size, (int)direction);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_unmap_page);
|
||||
|
||||
int dma_map_sg(struct device *dev, struct scatterlist *sg,
|
||||
int nents, enum dma_data_direction direction)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type)
|
||||
return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
|
||||
#endif
|
||||
return sbus_map_sg(dev, sg, nents, direction);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_map_sg);
|
||||
|
||||
void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
|
||||
int nents, enum dma_data_direction direction)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type) {
|
||||
pci_unmap_sg(to_pci_dev(dev), sg, nents, (int)direction);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
sbus_unmap_sg(dev, sg, nents, (int)direction);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_unmap_sg);
|
||||
|
||||
void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
|
||||
size_t size, enum dma_data_direction direction)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type) {
|
||||
pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle,
|
||||
size, (int)direction);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
sbus_dma_sync_single_for_cpu(dev, dma_handle, size, (int) direction);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_sync_single_for_cpu);
|
||||
|
||||
void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
|
||||
size_t size, enum dma_data_direction direction)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type) {
|
||||
pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle,
|
||||
size, (int)direction);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
sbus_dma_sync_single_for_device(dev, dma_handle, size, (int) direction);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_sync_single_for_device);
|
||||
|
||||
void dma_sync_single_range_for_cpu(struct device *dev,
|
||||
dma_addr_t dma_handle,
|
||||
unsigned long offset,
|
||||
size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
|
||||
|
||||
void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
|
||||
unsigned long offset, size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_sync_single_range_for_device);
|
||||
|
||||
void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
|
||||
int nelems, enum dma_data_direction direction)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type) {
|
||||
pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg,
|
||||
nelems, (int)direction);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
BUG();
|
||||
}
|
||||
EXPORT_SYMBOL(dma_sync_sg_for_cpu);
|
||||
|
||||
void dma_sync_sg_for_device(struct device *dev,
|
||||
struct scatterlist *sg, int nelems,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (dev->bus == &pci_bus_type) {
|
||||
pci_dma_sync_sg_for_device(to_pci_dev(dev), sg,
|
||||
nelems, (int)direction);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
BUG();
|
||||
}
|
||||
EXPORT_SYMBOL(dma_sync_sg_for_device);
|
||||
|
||||
int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
|
||||
{
|
||||
return (dma_addr == DMA_ERROR_CODE);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_mapping_error);
|
||||
|
||||
int dma_get_cache_alignment(void)
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_get_cache_alignment);
|
14
arch/sparc/kernel/dma.h
Normal file
14
arch/sparc/kernel/dma.h
Normal file
@ -0,0 +1,14 @@
|
||||
void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp);
|
||||
void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba);
|
||||
dma_addr_t sbus_map_single(struct device *dev, void *va,
|
||||
size_t len, int direction);
|
||||
void sbus_unmap_single(struct device *dev, dma_addr_t ba,
|
||||
size_t n, int direction);
|
||||
int sbus_map_sg(struct device *dev, struct scatterlist *sg,
|
||||
int n, int direction);
|
||||
void sbus_unmap_sg(struct device *dev, struct scatterlist *sg,
|
||||
int n, int direction);
|
||||
void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba,
|
||||
size_t size, int direction);
|
||||
void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba,
|
||||
size_t size, int direction);
|
@ -1,393 +0,0 @@
|
||||
/*
|
||||
* ebus.c: PCI to EBus bridge device.
|
||||
*
|
||||
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
|
||||
*
|
||||
* Adopted for sparc by V. Roganov and G. Raiko.
|
||||
* Fixes for different platforms by Pete Zaitcev.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pbm.h>
|
||||
#include <asm/ebus.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/bpp.h>
|
||||
|
||||
struct linux_ebus *ebus_chain = NULL;
|
||||
|
||||
/* We are together with pcic.c under CONFIG_PCI. */
|
||||
extern unsigned int pcic_pin_to_irq(unsigned int, const char *name);
|
||||
|
||||
/*
|
||||
* IRQ Blacklist
|
||||
* Here we list PROMs and systems that are known to supply crap as IRQ numbers.
|
||||
*/
|
||||
struct ebus_device_irq {
|
||||
char *name;
|
||||
unsigned int pin;
|
||||
};
|
||||
|
||||
struct ebus_system_entry {
|
||||
char *esname;
|
||||
struct ebus_device_irq *ipt;
|
||||
};
|
||||
|
||||
static struct ebus_device_irq je1_1[] = {
|
||||
{ "8042", 3 },
|
||||
{ "SUNW,CS4231", 0 },
|
||||
{ "parallel", 0 },
|
||||
{ "se", 2 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Gleb's JE1 supplied reasonable pin numbers, but mine did not (OBP 2.32).
|
||||
* Blacklist the sucker... Note that Gleb's system will work.
|
||||
*/
|
||||
static struct ebus_system_entry ebus_blacklist[] = {
|
||||
{ "SUNW,JavaEngine1", je1_1 },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static struct ebus_device_irq *ebus_blackp = NULL;
|
||||
|
||||
/*
|
||||
*/
|
||||
static inline unsigned long ebus_alloc(size_t size)
|
||||
{
|
||||
return (unsigned long)kmalloc(size, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
static int __init ebus_blacklist_irq(const char *name)
|
||||
{
|
||||
struct ebus_device_irq *dp;
|
||||
|
||||
if ((dp = ebus_blackp) != NULL) {
|
||||
for (; dp->name != NULL; dp++) {
|
||||
if (strcmp(name, dp->name) == 0) {
|
||||
return pcic_pin_to_irq(dp->pin, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init fill_ebus_child(struct device_node *dp,
|
||||
struct linux_ebus_child *dev)
|
||||
{
|
||||
const int *regs;
|
||||
const int *irqs;
|
||||
int i, len;
|
||||
|
||||
dev->prom_node = dp;
|
||||
regs = of_get_property(dp, "reg", &len);
|
||||
if (!regs)
|
||||
len = 0;
|
||||
dev->num_addrs = len / sizeof(regs[0]);
|
||||
|
||||
for (i = 0; i < dev->num_addrs; i++) {
|
||||
if (regs[i] >= dev->parent->num_addrs) {
|
||||
prom_printf("UGH: property for %s was %d, need < %d\n",
|
||||
dev->prom_node->name, len,
|
||||
dev->parent->num_addrs);
|
||||
panic(__func__);
|
||||
}
|
||||
|
||||
/* XXX resource */
|
||||
dev->resource[i].start =
|
||||
dev->parent->resource[regs[i]].start;
|
||||
}
|
||||
|
||||
for (i = 0; i < PROMINTR_MAX; i++)
|
||||
dev->irqs[i] = PCI_IRQ_NONE;
|
||||
|
||||
if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
|
||||
dev->num_irqs = 1;
|
||||
} else {
|
||||
irqs = of_get_property(dp, "interrupts", &len);
|
||||
if (!irqs) {
|
||||
dev->num_irqs = 0;
|
||||
dev->irqs[0] = 0;
|
||||
if (dev->parent->num_irqs != 0) {
|
||||
dev->num_irqs = 1;
|
||||
dev->irqs[0] = dev->parent->irqs[0];
|
||||
}
|
||||
} else {
|
||||
dev->num_irqs = len / sizeof(irqs[0]);
|
||||
if (irqs[0] == 0 || irqs[0] >= 8) {
|
||||
/*
|
||||
* XXX Zero is a valid pin number...
|
||||
* This works as long as Ebus is not wired
|
||||
* to INTA#.
|
||||
*/
|
||||
printk("EBUS: %s got bad irq %d from PROM\n",
|
||||
dev->prom_node->name, irqs[0]);
|
||||
dev->num_irqs = 0;
|
||||
dev->irqs[0] = 0;
|
||||
} else {
|
||||
dev->irqs[0] =
|
||||
pcic_pin_to_irq(irqs[0],
|
||||
dev->prom_node->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __init fill_ebus_device(struct device_node *dp,
|
||||
struct linux_ebus_device *dev)
|
||||
{
|
||||
const struct linux_prom_registers *regs;
|
||||
struct linux_ebus_child *child;
|
||||
struct dev_archdata *sd;
|
||||
const int *irqs;
|
||||
int i, n, len;
|
||||
unsigned long baseaddr;
|
||||
|
||||
dev->prom_node = dp;
|
||||
|
||||
regs = of_get_property(dp, "reg", &len);
|
||||
if (!regs)
|
||||
len = 0;
|
||||
if (len % sizeof(struct linux_prom_registers)) {
|
||||
prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
|
||||
dev->prom_node->name, len,
|
||||
(int)sizeof(struct linux_prom_registers));
|
||||
panic(__func__);
|
||||
}
|
||||
dev->num_addrs = len / sizeof(struct linux_prom_registers);
|
||||
|
||||
for (i = 0; i < dev->num_addrs; i++) {
|
||||
/*
|
||||
* XXX Collect JE-1 PROM
|
||||
*
|
||||
* Example - JS-E with 3.11:
|
||||
* /ebus
|
||||
* regs
|
||||
* 0x00000000, 0x0, 0x00000000, 0x0, 0x00000000,
|
||||
* 0x82000010, 0x0, 0xf0000000, 0x0, 0x01000000,
|
||||
* 0x82000014, 0x0, 0x38800000, 0x0, 0x00800000,
|
||||
* ranges
|
||||
* 0x00, 0x00000000, 0x02000010, 0x0, 0x0, 0x01000000,
|
||||
* 0x01, 0x01000000, 0x02000014, 0x0, 0x0, 0x00800000,
|
||||
* /ebus/8042
|
||||
* regs
|
||||
* 0x00000001, 0x00300060, 0x00000008,
|
||||
* 0x00000001, 0x00300060, 0x00000008,
|
||||
*/
|
||||
n = regs[i].which_io;
|
||||
if (n >= 4) {
|
||||
/* XXX This is copied from old JE-1 by Gleb. */
|
||||
n = (regs[i].which_io - 0x10) >> 2;
|
||||
} else {
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX Now as we have regions, why don't we make an on-demand allocation...
|
||||
*/
|
||||
dev->resource[i].start = 0;
|
||||
if ((baseaddr = dev->bus->self->resource[n].start +
|
||||
regs[i].phys_addr) != 0) {
|
||||
/* dev->resource[i].name = dev->prom_name; */
|
||||
if ((baseaddr = (unsigned long) ioremap(baseaddr,
|
||||
regs[i].reg_size)) == 0) {
|
||||
panic("ebus: unable to remap dev %s",
|
||||
dev->prom_node->name);
|
||||
}
|
||||
}
|
||||
dev->resource[i].start = baseaddr; /* XXX Unaligned */
|
||||
}
|
||||
|
||||
for (i = 0; i < PROMINTR_MAX; i++)
|
||||
dev->irqs[i] = PCI_IRQ_NONE;
|
||||
|
||||
if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
|
||||
dev->num_irqs = 1;
|
||||
} else {
|
||||
irqs = of_get_property(dp, "interrupts", &len);
|
||||
if (!irqs) {
|
||||
dev->num_irqs = 0;
|
||||
if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
|
||||
dev->num_irqs = 1;
|
||||
/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
|
||||
}
|
||||
} else {
|
||||
dev->num_irqs = 1; /* dev->num_irqs = len / sizeof(irqs[0]); */
|
||||
if (irqs[0] == 0 || irqs[0] >= 8) {
|
||||
/* See above for the parent. XXX */
|
||||
printk("EBUS: %s got bad irq %d from PROM\n",
|
||||
dev->prom_node->name, irqs[0]);
|
||||
dev->num_irqs = 0;
|
||||
dev->irqs[0] = 0;
|
||||
} else {
|
||||
dev->irqs[0] =
|
||||
pcic_pin_to_irq(irqs[0],
|
||||
dev->prom_node->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sd = &dev->ofdev.dev.archdata;
|
||||
sd->prom_node = dp;
|
||||
sd->op = &dev->ofdev;
|
||||
sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;
|
||||
|
||||
dev->ofdev.node = dp;
|
||||
dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
|
||||
dev->ofdev.dev.bus = &ebus_bus_type;
|
||||
sprintf(dev->ofdev.dev.bus_id, "ebus[%08x]", dp->node);
|
||||
|
||||
/* Register with core */
|
||||
if (of_device_register(&dev->ofdev) != 0)
|
||||
printk(KERN_DEBUG "ebus: device registration error for %s!\n",
|
||||
dp->path_component_name);
|
||||
|
||||
if ((dp = dp->child) != NULL) {
|
||||
dev->children = (struct linux_ebus_child *)
|
||||
ebus_alloc(sizeof(struct linux_ebus_child));
|
||||
|
||||
child = dev->children;
|
||||
child->next = NULL;
|
||||
child->parent = dev;
|
||||
child->bus = dev->bus;
|
||||
fill_ebus_child(dp, child);
|
||||
|
||||
while ((dp = dp->sibling) != NULL) {
|
||||
child->next = (struct linux_ebus_child *)
|
||||
ebus_alloc(sizeof(struct linux_ebus_child));
|
||||
|
||||
child = child->next;
|
||||
child->next = NULL;
|
||||
child->parent = dev;
|
||||
child->bus = dev->bus;
|
||||
fill_ebus_child(dp, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __init ebus_init(void)
|
||||
{
|
||||
const struct linux_prom_pci_registers *regs;
|
||||
struct linux_pbm_info *pbm;
|
||||
struct linux_ebus_device *dev;
|
||||
struct linux_ebus *ebus;
|
||||
struct ebus_system_entry *sp;
|
||||
struct pci_dev *pdev;
|
||||
struct pcidev_cookie *cookie;
|
||||
struct device_node *dp;
|
||||
struct resource *p;
|
||||
unsigned short pci_command;
|
||||
int len, reg, nreg;
|
||||
int num_ebus = 0;
|
||||
|
||||
dp = of_find_node_by_path("/");
|
||||
for (sp = ebus_blacklist; sp->esname != NULL; sp++) {
|
||||
if (strcmp(dp->name, sp->esname) == 0) {
|
||||
ebus_blackp = sp->ipt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, NULL);
|
||||
if (!pdev)
|
||||
return;
|
||||
|
||||
cookie = pdev->sysdata;
|
||||
dp = cookie->prom_node;
|
||||
|
||||
ebus_chain = ebus = (struct linux_ebus *)
|
||||
ebus_alloc(sizeof(struct linux_ebus));
|
||||
ebus->next = NULL;
|
||||
|
||||
while (dp) {
|
||||
struct device_node *nd;
|
||||
|
||||
ebus->prom_node = dp;
|
||||
ebus->self = pdev;
|
||||
ebus->parent = pbm = cookie->pbm;
|
||||
|
||||
/* Enable BUS Master. */
|
||||
pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
|
||||
pci_command |= PCI_COMMAND_MASTER;
|
||||
pci_write_config_word(pdev, PCI_COMMAND, pci_command);
|
||||
|
||||
regs = of_get_property(dp, "reg", &len);
|
||||
if (!regs) {
|
||||
prom_printf("%s: can't find reg property\n",
|
||||
__func__);
|
||||
prom_halt();
|
||||
}
|
||||
nreg = len / sizeof(struct linux_prom_pci_registers);
|
||||
|
||||
p = &ebus->self->resource[0];
|
||||
for (reg = 0; reg < nreg; reg++) {
|
||||
if (!(regs[reg].which_io & 0x03000000))
|
||||
continue;
|
||||
|
||||
(p++)->start = regs[reg].phys_lo;
|
||||
}
|
||||
|
||||
ebus->ofdev.node = dp;
|
||||
ebus->ofdev.dev.parent = &pdev->dev;
|
||||
ebus->ofdev.dev.bus = &ebus_bus_type;
|
||||
sprintf(ebus->ofdev.dev.bus_id, "ebus%d", num_ebus);
|
||||
|
||||
/* Register with core */
|
||||
if (of_device_register(&ebus->ofdev) != 0)
|
||||
printk(KERN_DEBUG "ebus: device registration error for %s!\n",
|
||||
dp->path_component_name);
|
||||
|
||||
|
||||
nd = dp->child;
|
||||
if (!nd)
|
||||
goto next_ebus;
|
||||
|
||||
ebus->devices = (struct linux_ebus_device *)
|
||||
ebus_alloc(sizeof(struct linux_ebus_device));
|
||||
|
||||
dev = ebus->devices;
|
||||
dev->next = NULL;
|
||||
dev->children = NULL;
|
||||
dev->bus = ebus;
|
||||
fill_ebus_device(nd, dev);
|
||||
|
||||
while ((nd = nd->sibling) != NULL) {
|
||||
dev->next = (struct linux_ebus_device *)
|
||||
ebus_alloc(sizeof(struct linux_ebus_device));
|
||||
|
||||
dev = dev->next;
|
||||
dev->next = NULL;
|
||||
dev->children = NULL;
|
||||
dev->bus = ebus;
|
||||
fill_ebus_device(nd, dev);
|
||||
}
|
||||
|
||||
next_ebus:
|
||||
pdev = pci_get_device(PCI_VENDOR_ID_SUN,
|
||||
PCI_DEVICE_ID_SUN_EBUS, pdev);
|
||||
if (!pdev)
|
||||
break;
|
||||
|
||||
cookie = pdev->sysdata;
|
||||
dp = cookie->prom_node;
|
||||
|
||||
ebus->next = (struct linux_ebus *)
|
||||
ebus_alloc(sizeof(struct linux_ebus));
|
||||
ebus = ebus->next;
|
||||
ebus->next = NULL;
|
||||
++num_ebus;
|
||||
}
|
||||
if (pdev)
|
||||
pci_dev_put(pdev);
|
||||
}
|
@ -20,11 +20,7 @@
|
||||
#include <asm/memreg.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#ifdef CONFIG_SUN4
|
||||
#include <asm/pgtsun4.h>
|
||||
#else
|
||||
#include <asm/pgtsun4c.h>
|
||||
#endif
|
||||
#include <asm/winmacro.h>
|
||||
#include <asm/signal.h>
|
||||
#include <asm/obio.h>
|
||||
@ -276,17 +272,18 @@ smp4m_ticker:
|
||||
*/
|
||||
maybe_smp4m_msg:
|
||||
GET_PROCESSOR4M_ID(o3)
|
||||
set sun4m_interrupts, %l5
|
||||
ld [%l5], %o5
|
||||
sethi %hi(sun4m_irq_percpu), %l5
|
||||
sll %o3, 2, %o3
|
||||
or %l5, %lo(sun4m_irq_percpu), %o5
|
||||
sethi %hi(0x40000000), %o2
|
||||
sll %o3, 12, %o3
|
||||
ld [%o5 + %o3], %o1
|
||||
andcc %o1, %o2, %g0
|
||||
ld [%o1 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending
|
||||
andcc %o3, %o2, %g0
|
||||
be,a smp4m_ticker
|
||||
cmp %l7, 14
|
||||
st %o2, [%o5 + 0x4]
|
||||
st %o2, [%o1 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x40000000
|
||||
WRITE_PAUSE
|
||||
ld [%o5], %g0
|
||||
ld [%o1 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending
|
||||
WRITE_PAUSE
|
||||
or %l0, PSR_PIL, %l4
|
||||
wr %l4, 0x0, %psr
|
||||
@ -304,16 +301,16 @@ linux_trap_ipi15_sun4m:
|
||||
SAVE_ALL
|
||||
sethi %hi(0x80000000), %o2
|
||||
GET_PROCESSOR4M_ID(o0)
|
||||
set sun4m_interrupts, %l5
|
||||
ld [%l5], %o5
|
||||
sll %o0, 12, %o0
|
||||
add %o5, %o0, %o5
|
||||
ld [%o5], %o3
|
||||
sethi %hi(sun4m_irq_percpu), %l5
|
||||
or %l5, %lo(sun4m_irq_percpu), %o5
|
||||
sll %o0, 2, %o0
|
||||
ld [%o5 + %o0], %o5
|
||||
ld [%o5 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending
|
||||
andcc %o3, %o2, %g0
|
||||
be 1f ! Must be an NMI async memory error
|
||||
st %o2, [%o5 + 4]
|
||||
st %o2, [%o5 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x80000000
|
||||
WRITE_PAUSE
|
||||
ld [%o5], %g0
|
||||
ld [%o5 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending
|
||||
WRITE_PAUSE
|
||||
or %l0, PSR_PIL, %l4
|
||||
wr %l4, 0x0, %psr
|
||||
@ -327,12 +324,11 @@ linux_trap_ipi15_sun4m:
|
||||
1:
|
||||
/* NMI async memory error handling. */
|
||||
sethi %hi(0x80000000), %l4
|
||||
sethi %hi(0x4000), %o3
|
||||
sub %o5, %o0, %o5
|
||||
add %o5, %o3, %l5
|
||||
st %l4, [%l5 + 0xc]
|
||||
sethi %hi(sun4m_irq_global), %o5
|
||||
ld [%o5 + %lo(sun4m_irq_global)], %l5
|
||||
st %l4, [%l5 + 0x0c] ! sun4m_irq_global->mask_set=0x80000000
|
||||
WRITE_PAUSE
|
||||
ld [%l5], %g0
|
||||
ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
|
||||
WRITE_PAUSE
|
||||
or %l0, PSR_PIL, %l4
|
||||
wr %l4, 0x0, %psr
|
||||
@ -341,9 +337,9 @@ linux_trap_ipi15_sun4m:
|
||||
WRITE_PAUSE
|
||||
call sun4m_nmi
|
||||
nop
|
||||
st %l4, [%l5 + 0x8]
|
||||
st %l4, [%l5 + 0x08] ! sun4m_irq_global->mask_clear=0x80000000
|
||||
WRITE_PAUSE
|
||||
ld [%l5], %g0
|
||||
ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
|
||||
WRITE_PAUSE
|
||||
RESTORE_ALL
|
||||
|
||||
@ -775,11 +771,7 @@ vac_linesize_patch_32: subcc %l7, 32, %l7
|
||||
* Ugly, but we cant use hardware flushing on the sun4 and we'd require
|
||||
* two instructions (Anton)
|
||||
*/
|
||||
#ifdef CONFIG_SUN4
|
||||
vac_hwflush_patch1_on: nop
|
||||
#else
|
||||
vac_hwflush_patch1_on: addcc %l7, -PAGE_SIZE, %l7
|
||||
#endif
|
||||
|
||||
vac_hwflush_patch2_on: sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG
|
||||
|
||||
@ -798,42 +790,10 @@ vac_hwflush_patch2_on: sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG
|
||||
! %l7 = 1 for textfault
|
||||
! We want error in %l5, vaddr in %l6
|
||||
sun4c_fault:
|
||||
#ifdef CONFIG_SUN4
|
||||
sethi %hi(sun4c_memerr_reg), %l4
|
||||
ld [%l4+%lo(sun4c_memerr_reg)], %l4 ! memerr ctrl reg addr
|
||||
ld [%l4], %l6 ! memerr ctrl reg
|
||||
ld [%l4 + 4], %l5 ! memerr vaddr reg
|
||||
andcc %l6, 0x80, %g0 ! check for error type
|
||||
st %g0, [%l4 + 4] ! clear the error
|
||||
be 0f ! normal error
|
||||
sethi %hi(AC_BUS_ERROR), %l4 ! bus err reg addr
|
||||
|
||||
call prom_halt ! something weird happened
|
||||
! what exactly did happen?
|
||||
! what should we do here?
|
||||
|
||||
0: or %l4, %lo(AC_BUS_ERROR), %l4 ! bus err reg addr
|
||||
lduba [%l4] ASI_CONTROL, %l6 ! bus err reg
|
||||
|
||||
cmp %l7, 1 ! text fault?
|
||||
be 1f ! yes
|
||||
nop
|
||||
|
||||
ld [%l1], %l4 ! load instruction that caused fault
|
||||
srl %l4, 21, %l4
|
||||
andcc %l4, 1, %g0 ! store instruction?
|
||||
|
||||
be 1f ! no
|
||||
sethi %hi(SUN4C_SYNC_BADWRITE), %l4 ! yep
|
||||
! %lo(SUN4C_SYNC_BADWRITE) = 0
|
||||
or %l4, %l6, %l6 ! set write bit to emulate sun4c
|
||||
1:
|
||||
#else
|
||||
sethi %hi(AC_SYNC_ERR), %l4
|
||||
add %l4, 0x4, %l6 ! AC_SYNC_VA in %l6
|
||||
lda [%l6] ASI_CONTROL, %l5 ! Address
|
||||
lda [%l4] ASI_CONTROL, %l6 ! Error, retained for a bit
|
||||
#endif
|
||||
|
||||
andn %l5, 0xfff, %l5 ! Encode all info into l7
|
||||
srl %l6, 14, %l4
|
||||
@ -880,12 +840,7 @@ sun4c_fault:
|
||||
or %l4, %lo(swapper_pg_dir), %l4
|
||||
sll %l6, 2, %l6
|
||||
ld [%l4 + %l6], %l4
|
||||
#ifdef CONFIG_SUN4
|
||||
sethi %hi(PAGE_MASK), %l6
|
||||
andcc %l4, %l6, %g0
|
||||
#else
|
||||
andcc %l4, PAGE_MASK, %g0
|
||||
#endif
|
||||
be sun4c_fault_fromuser
|
||||
lduXa [%l5] ASI_SEGMAP, %l4
|
||||
|
||||
@ -937,11 +892,7 @@ invalid_segment_patch1:
|
||||
ld [%l6 + 0x08], %l3 ! tmp = entry->vaddr
|
||||
|
||||
! Flush segment from the cache.
|
||||
#ifdef CONFIG_SUN4
|
||||
sethi %hi((128 * 1024)), %l7
|
||||
#else
|
||||
sethi %hi((64 * 1024)), %l7
|
||||
#endif
|
||||
9:
|
||||
vac_hwflush_patch1:
|
||||
vac_linesize_patch:
|
||||
@ -1029,12 +980,7 @@ invalid_segment_patch2:
|
||||
or %l4, %lo(swapper_pg_dir), %l4
|
||||
sll %l3, 2, %l3
|
||||
ld [%l4 + %l3], %l4
|
||||
#ifndef CONFIG_SUN4
|
||||
and %l4, PAGE_MASK, %l4
|
||||
#else
|
||||
sethi %hi(PAGE_MASK), %l6
|
||||
and %l4, %l6, %l4
|
||||
#endif
|
||||
|
||||
srl %l5, (PAGE_SHIFT - 2), %l6
|
||||
and %l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6
|
||||
|
@ -63,15 +63,9 @@ cputypvar_sun4m:
|
||||
|
||||
.align 4
|
||||
|
||||
#ifndef CONFIG_SUN4
|
||||
sun4_notsup:
|
||||
.asciz "Sparc-Linux sun4 needs a specially compiled kernel, turn CONFIG_SUN4 on.\n\n"
|
||||
.asciz "Sparc-Linux sun4 support does no longer exist.\n\n"
|
||||
.align 4
|
||||
#else
|
||||
sun4cdm_notsup:
|
||||
.asciz "Kernel compiled with CONFIG_SUN4 cannot run on SUN4C/SUN4M/SUN4D\nTurn CONFIG_SUN4 off.\n\n"
|
||||
.align 4
|
||||
#endif
|
||||
|
||||
sun4e_notsup:
|
||||
.asciz "Sparc-Linux sun4e support does not exist\n\n"
|
||||
@ -780,15 +774,6 @@ execute_in_high_mem:
|
||||
nop
|
||||
|
||||
found_version:
|
||||
#ifdef CONFIG_SUN4
|
||||
/* For people who try sun4 kernels, even if Configure.help advises them. */
|
||||
ld [%g7 + 0x68], %o1
|
||||
set sun4cdm_notsup, %o0
|
||||
call %o1
|
||||
nop
|
||||
b halt_me
|
||||
nop
|
||||
#endif
|
||||
/* Get the machine type via the mysterious romvec node operations. */
|
||||
|
||||
add %g7, 0x1c, %l1
|
||||
@ -1150,15 +1135,6 @@ sun4c_continue_boot:
|
||||
nop
|
||||
|
||||
sun4_init:
|
||||
#ifdef CONFIG_SUN4
|
||||
/* There, happy now Adrian? */
|
||||
set cputypval, %o2 ! Let everyone know we
|
||||
set ' ', %o0 ! are a "sun4 " architecture
|
||||
stb %o0, [%o2 + 0x4]
|
||||
|
||||
b got_prop
|
||||
nop
|
||||
#else
|
||||
sethi %hi(SUN4_PROM_VECTOR+0x84), %o1
|
||||
ld [%o1 + %lo(SUN4_PROM_VECTOR+0x84)], %o1
|
||||
set sun4_notsup, %o0
|
||||
@ -1170,7 +1146,7 @@ sun4_init:
|
||||
nop
|
||||
1: ba 1b ! Cannot exit into KMON
|
||||
nop
|
||||
#endif
|
||||
|
||||
no_sun4e_here:
|
||||
ld [%g7 + 0x68], %o1
|
||||
set sun4e_notsup, %o0
|
||||
|
@ -12,10 +12,6 @@
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/idprom.h>
|
||||
#include <asm/machines.h> /* Fun with Sun released architectures. */
|
||||
#ifdef CONFIG_SUN4
|
||||
#include <asm/sun4paddr.h>
|
||||
extern void sun4setup(void);
|
||||
#endif
|
||||
|
||||
struct idprom *idprom;
|
||||
static struct idprom idprom_buffer;
|
||||
@ -101,7 +97,4 @@ void __init idprom_init(void)
|
||||
idprom->id_ethaddr[0], idprom->id_ethaddr[1],
|
||||
idprom->id_ethaddr[2], idprom->id_ethaddr[3],
|
||||
idprom->id_ethaddr[4], idprom->id_ethaddr[5]);
|
||||
#ifdef CONFIG_SUN4
|
||||
sun4setup();
|
||||
#endif
|
||||
}
|
||||
|
@ -42,10 +42,13 @@
|
||||
#include <asm/vaddrs.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/sbus.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/iommu.h>
|
||||
#include <asm/io-unit.h>
|
||||
|
||||
#include "dma.h"
|
||||
|
||||
#define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */
|
||||
|
||||
@ -139,15 +142,6 @@ void iounmap(volatile void __iomem *virtual)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
void __iomem *sbus_ioremap(struct resource *phyres, unsigned long offset,
|
||||
unsigned long size, char *name)
|
||||
{
|
||||
return _sparc_alloc_io(phyres->flags & 0xF,
|
||||
phyres->start + offset, size, name);
|
||||
}
|
||||
|
||||
void __iomem *of_ioremap(struct resource *res, unsigned long offset,
|
||||
unsigned long size, char *name)
|
||||
{
|
||||
@ -163,13 +157,6 @@ void of_iounmap(struct resource *res, void __iomem *base, unsigned long size)
|
||||
}
|
||||
EXPORT_SYMBOL(of_iounmap);
|
||||
|
||||
/*
|
||||
*/
|
||||
void sbus_iounmap(volatile void __iomem *addr, unsigned long size)
|
||||
{
|
||||
iounmap(addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Meat of mapping
|
||||
*/
|
||||
@ -246,63 +233,19 @@ static void _sparc_free_io(struct resource *res)
|
||||
|
||||
#ifdef CONFIG_SBUS
|
||||
|
||||
void sbus_set_sbus64(struct sbus_dev *sdev, int x)
|
||||
void sbus_set_sbus64(struct device *dev, int x)
|
||||
{
|
||||
printk("sbus_set_sbus64: unsupported\n");
|
||||
}
|
||||
|
||||
extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
|
||||
void __init sbus_fill_device_irq(struct sbus_dev *sdev)
|
||||
{
|
||||
struct linux_prom_irqs irqs[PROMINTR_MAX];
|
||||
int len;
|
||||
|
||||
len = prom_getproperty(sdev->prom_node, "intr",
|
||||
(char *)irqs, sizeof(irqs));
|
||||
if (len != -1) {
|
||||
sdev->num_irqs = len / 8;
|
||||
if (sdev->num_irqs == 0) {
|
||||
sdev->irqs[0] = 0;
|
||||
} else if (sparc_cpu_model == sun4d) {
|
||||
for (len = 0; len < sdev->num_irqs; len++)
|
||||
sdev->irqs[len] =
|
||||
sun4d_build_irq(sdev, irqs[len].pri);
|
||||
} else {
|
||||
for (len = 0; len < sdev->num_irqs; len++)
|
||||
sdev->irqs[len] = irqs[len].pri;
|
||||
}
|
||||
} else {
|
||||
int interrupts[PROMINTR_MAX];
|
||||
|
||||
/* No "intr" node found-- check for "interrupts" node.
|
||||
* This node contains SBus interrupt levels, not IPLs
|
||||
* as in "intr", and no vector values. We convert
|
||||
* SBus interrupt levels to PILs (platform specific).
|
||||
*/
|
||||
len = prom_getproperty(sdev->prom_node, "interrupts",
|
||||
(char *)interrupts, sizeof(interrupts));
|
||||
if (len == -1) {
|
||||
sdev->irqs[0] = 0;
|
||||
sdev->num_irqs = 0;
|
||||
} else {
|
||||
sdev->num_irqs = len / sizeof(int);
|
||||
for (len = 0; len < sdev->num_irqs; len++) {
|
||||
sdev->irqs[len] =
|
||||
sbint_to_irq(sdev, interrupts[len]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a chunk of memory suitable for DMA.
|
||||
* Typically devices use them for control blocks.
|
||||
* CPU may access them without any explicit flushing.
|
||||
*
|
||||
* XXX Some clever people know that sdev is not used and supply NULL. Watch.
|
||||
*/
|
||||
void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
|
||||
void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp)
|
||||
{
|
||||
struct of_device *op = to_of_device(dev);
|
||||
unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
|
||||
unsigned long va;
|
||||
struct resource *res;
|
||||
@ -336,13 +279,10 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
|
||||
* XXX That's where sdev would be used. Currently we load
|
||||
* all iommu tables with the same translations.
|
||||
*/
|
||||
if (mmu_map_dma_area(dma_addrp, va, res->start, len_total) != 0)
|
||||
if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0)
|
||||
goto err_noiommu;
|
||||
|
||||
/* Set the resource name, if known. */
|
||||
if (sdev) {
|
||||
res->name = sdev->prom_name;
|
||||
}
|
||||
res->name = op->node->name;
|
||||
|
||||
return (void *)(unsigned long)res->start;
|
||||
|
||||
@ -356,7 +296,7 @@ err_nopages:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
|
||||
void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba)
|
||||
{
|
||||
struct resource *res;
|
||||
struct page *pgv;
|
||||
@ -383,8 +323,8 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
|
||||
kfree(res);
|
||||
|
||||
/* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */
|
||||
pgv = mmu_translate_dvma(ba);
|
||||
mmu_unmap_dma_area(ba, n);
|
||||
pgv = virt_to_page(p);
|
||||
mmu_unmap_dma_area(dev, ba, n);
|
||||
|
||||
__free_pages(pgv, get_order(n));
|
||||
}
|
||||
@ -394,7 +334,7 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
|
||||
* CPU view of this memory may be inconsistent with
|
||||
* a device view and explicit flushing is necessary.
|
||||
*/
|
||||
dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction)
|
||||
dma_addr_t sbus_map_single(struct device *dev, void *va, size_t len, int direction)
|
||||
{
|
||||
/* XXX why are some lengths signed, others unsigned? */
|
||||
if (len <= 0) {
|
||||
@ -404,17 +344,17 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int dire
|
||||
if (len > 256*1024) { /* __get_free_pages() limit */
|
||||
return 0;
|
||||
}
|
||||
return mmu_get_scsi_one(va, len, sdev->bus);
|
||||
return mmu_get_scsi_one(dev, va, len);
|
||||
}
|
||||
|
||||
void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t ba, size_t n, int direction)
|
||||
void sbus_unmap_single(struct device *dev, dma_addr_t ba, size_t n, int direction)
|
||||
{
|
||||
mmu_release_scsi_one(ba, n, sdev->bus);
|
||||
mmu_release_scsi_one(dev, ba, n);
|
||||
}
|
||||
|
||||
int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
|
||||
int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
|
||||
{
|
||||
mmu_get_scsi_sgl(sg, n, sdev->bus);
|
||||
mmu_get_scsi_sgl(dev, sg, n);
|
||||
|
||||
/*
|
||||
* XXX sparc64 can return a partial length here. sun4c should do this
|
||||
@ -423,145 +363,28 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direct
|
||||
return n;
|
||||
}
|
||||
|
||||
void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
|
||||
void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
|
||||
{
|
||||
mmu_release_scsi_sgl(sg, n, sdev->bus);
|
||||
mmu_release_scsi_sgl(dev, sg, n);
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
|
||||
void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba, size_t size, int direction)
|
||||
{
|
||||
#if 0
|
||||
unsigned long va;
|
||||
struct resource *res;
|
||||
|
||||
/* We do not need the resource, just print a message if invalid. */
|
||||
res = _sparc_find_resource(&_sparc_dvma, ba);
|
||||
if (res == NULL)
|
||||
panic("sbus_dma_sync_single: 0x%x\n", ba);
|
||||
|
||||
va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */
|
||||
/*
|
||||
* XXX This bogosity will be fixed with the iommu rewrite coming soon
|
||||
* to a kernel near you. - Anton
|
||||
*/
|
||||
/* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */
|
||||
#endif
|
||||
}
|
||||
|
||||
void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
|
||||
void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba, size_t size, int direction)
|
||||
{
|
||||
#if 0
|
||||
unsigned long va;
|
||||
struct resource *res;
|
||||
|
||||
/* We do not need the resource, just print a message if invalid. */
|
||||
res = _sparc_find_resource(&_sparc_dvma, ba);
|
||||
if (res == NULL)
|
||||
panic("sbus_dma_sync_single: 0x%x\n", ba);
|
||||
|
||||
va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */
|
||||
/*
|
||||
* XXX This bogosity will be fixed with the iommu rewrite coming soon
|
||||
* to a kernel near you. - Anton
|
||||
*/
|
||||
/* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */
|
||||
#endif
|
||||
}
|
||||
|
||||
void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
|
||||
{
|
||||
printk("sbus_dma_sync_sg_for_cpu: not implemented yet\n");
|
||||
}
|
||||
|
||||
void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
|
||||
{
|
||||
printk("sbus_dma_sync_sg_for_device: not implemented yet\n");
|
||||
}
|
||||
|
||||
/* Support code for sbus_init(). */
|
||||
/*
|
||||
* XXX This functions appears to be a distorted version of
|
||||
* prom_sbus_ranges_init(), with all sun4d stuff cut away.
|
||||
* Ask DaveM what is going on here, how is sun4d supposed to work... XXX
|
||||
*/
|
||||
/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
|
||||
void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
|
||||
{
|
||||
int parent_node = pn->node;
|
||||
|
||||
if (sparc_cpu_model == sun4d) {
|
||||
struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
|
||||
int num_iounit_ranges, len;
|
||||
|
||||
len = prom_getproperty(parent_node, "ranges",
|
||||
(char *) iounit_ranges,
|
||||
sizeof (iounit_ranges));
|
||||
if (len != -1) {
|
||||
num_iounit_ranges =
|
||||
(len / sizeof(struct linux_prom_ranges));
|
||||
prom_adjust_ranges(sbus->sbus_ranges,
|
||||
sbus->num_sbus_ranges,
|
||||
iounit_ranges, num_iounit_ranges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
|
||||
{
|
||||
#ifndef CONFIG_SUN4
|
||||
struct device_node *parent = dp->parent;
|
||||
|
||||
if (sparc_cpu_model != sun4d &&
|
||||
parent != NULL &&
|
||||
!strcmp(parent->name, "iommu")) {
|
||||
extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
|
||||
|
||||
iommu_init(parent->node, sbus);
|
||||
}
|
||||
|
||||
if (sparc_cpu_model == sun4d) {
|
||||
extern void iounit_init(int sbi_node, int iounit_node,
|
||||
struct sbus_bus *sbus);
|
||||
|
||||
iounit_init(dp->node, parent->node, sbus);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
|
||||
{
|
||||
if (sparc_cpu_model == sun4d) {
|
||||
struct device_node *parent = dp->parent;
|
||||
|
||||
sbus->devid = of_getintprop_default(parent, "device-id", 0);
|
||||
sbus->board = of_getintprop_default(parent, "board#", 0);
|
||||
}
|
||||
}
|
||||
|
||||
int __init sbus_arch_preinit(void)
|
||||
static int __init sparc_register_ioport(void)
|
||||
{
|
||||
register_proc_sparc_ioport();
|
||||
|
||||
#ifdef CONFIG_SUN4
|
||||
{
|
||||
extern void sun4_dvma_init(void);
|
||||
sun4_dvma_init();
|
||||
}
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void __init sbus_arch_postinit(void)
|
||||
{
|
||||
if (sparc_cpu_model == sun4d) {
|
||||
extern void sun4d_init_sbi_irq(void);
|
||||
sun4d_init_sbi_irq();
|
||||
}
|
||||
}
|
||||
arch_initcall(sparc_register_ioport);
|
||||
|
||||
#endif /* CONFIG_SBUS */
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
@ -13,7 +13,6 @@ BTFIXUPDEF_CALL(void, enable_irq, unsigned int)
|
||||
BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
|
||||
BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
|
||||
BTFIXUPDEF_CALL(void, clear_clock_irq, void)
|
||||
BTFIXUPDEF_CALL(void, clear_profile_irq, int)
|
||||
BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
|
||||
|
||||
static inline void __disable_irq(unsigned int irq)
|
||||
@ -41,11 +40,6 @@ static inline void clear_clock_irq(void)
|
||||
BTFIXUP_CALL(clear_clock_irq)();
|
||||
}
|
||||
|
||||
static inline void clear_profile_irq(int irq)
|
||||
{
|
||||
BTFIXUP_CALL(clear_profile_irq)(irq);
|
||||
}
|
||||
|
||||
static inline void load_profile_irq(int cpu, int limit)
|
||||
{
|
||||
BTFIXUP_CALL(load_profile_irq)(cpu, limit);
|
||||
|
@ -29,15 +29,38 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
|
||||
}
|
||||
EXPORT_SYMBOL(of_find_device_by_node);
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
struct bus_type ebus_bus_type;
|
||||
EXPORT_SYMBOL(ebus_bus_type);
|
||||
#endif
|
||||
unsigned int irq_of_parse_and_map(struct device_node *node, int index)
|
||||
{
|
||||
struct of_device *op = of_find_device_by_node(node);
|
||||
|
||||
#ifdef CONFIG_SBUS
|
||||
struct bus_type sbus_bus_type;
|
||||
EXPORT_SYMBOL(sbus_bus_type);
|
||||
#endif
|
||||
if (!op || index >= op->num_irqs)
|
||||
return 0;
|
||||
|
||||
return op->irqs[index];
|
||||
}
|
||||
EXPORT_SYMBOL(irq_of_parse_and_map);
|
||||
|
||||
/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
|
||||
* BUS and propagate to all child of_device objects.
|
||||
*/
|
||||
void of_propagate_archdata(struct of_device *bus)
|
||||
{
|
||||
struct dev_archdata *bus_sd = &bus->dev.archdata;
|
||||
struct device_node *bus_dp = bus->node;
|
||||
struct device_node *dp;
|
||||
|
||||
for (dp = bus_dp->child; dp; dp = dp->sibling) {
|
||||
struct of_device *op = of_find_device_by_node(dp);
|
||||
|
||||
op->dev.archdata.iommu = bus_sd->iommu;
|
||||
op->dev.archdata.stc = bus_sd->stc;
|
||||
op->dev.archdata.host_controller = bus_sd->host_controller;
|
||||
op->dev.archdata.numa_node = bus_sd->numa_node;
|
||||
|
||||
if (dp->child)
|
||||
of_propagate_archdata(op);
|
||||
}
|
||||
}
|
||||
|
||||
struct bus_type of_platform_bus_type;
|
||||
EXPORT_SYMBOL(of_platform_bus_type);
|
||||
@ -327,6 +350,27 @@ static int __init build_one_resource(struct device_node *parent,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __init use_1to1_mapping(struct device_node *pp)
|
||||
{
|
||||
/* If we have a ranges property in the parent, use it. */
|
||||
if (of_find_property(pp, "ranges", NULL) != NULL)
|
||||
return 0;
|
||||
|
||||
/* Some SBUS devices use intermediate nodes to express
|
||||
* hierarchy within the device itself. These aren't
|
||||
* real bus nodes, and don't have a 'ranges' property.
|
||||
* But, we should still pass the translation work up
|
||||
* to the SBUS itself.
|
||||
*/
|
||||
if (!strcmp(pp->name, "dma") ||
|
||||
!strcmp(pp->name, "espdma") ||
|
||||
!strcmp(pp->name, "ledma") ||
|
||||
!strcmp(pp->name, "lebuffer"))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int of_resource_verbose;
|
||||
|
||||
static void __init build_device_resources(struct of_device *op,
|
||||
@ -373,10 +417,7 @@ static void __init build_device_resources(struct of_device *op,
|
||||
|
||||
flags = bus->get_flags(reg, 0);
|
||||
|
||||
/* If the immediate parent has no ranges property to apply,
|
||||
* just use a 1<->1 mapping.
|
||||
*/
|
||||
if (of_find_property(pp, "ranges", NULL) == NULL) {
|
||||
if (use_1to1_mapping(pp)) {
|
||||
result = of_read_addr(addr, na);
|
||||
goto build_res;
|
||||
}
|
||||
@ -565,15 +606,6 @@ static int __init of_bus_driver_init(void)
|
||||
int err;
|
||||
|
||||
err = of_bus_type_init(&of_platform_bus_type, "of");
|
||||
#ifdef CONFIG_PCI
|
||||
if (!err)
|
||||
err = of_bus_type_init(&ebus_bus_type, "ebus");
|
||||
#endif
|
||||
#ifdef CONFIG_SBUS
|
||||
if (!err)
|
||||
err = of_bus_type_init(&sbus_bus_type, "sbus");
|
||||
#endif
|
||||
|
||||
if (!err)
|
||||
scan_of_devices();
|
||||
|
||||
|
@ -17,8 +17,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#include <asm/ebus.h>
|
||||
#include <asm/sbus.h> /* for sanity check... */
|
||||
#include <asm/swift.h> /* for cache flushing. */
|
||||
#include <asm/io.h>
|
||||
|
||||
@ -430,7 +428,6 @@ static int __init pcic_init(void)
|
||||
|
||||
pcic_pbm_scan_bus(pcic);
|
||||
|
||||
ebus_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -493,10 +490,6 @@ static void pcic_map_pci_device(struct linux_pcic *pcic,
|
||||
* do ioremap() before accessing PC-style I/O,
|
||||
* we supply virtual, ready to access address.
|
||||
*
|
||||
* Ebus devices do not come here even if
|
||||
* CheerIO makes a similar conversion.
|
||||
* See ebus.c for details.
|
||||
*
|
||||
* Note that request_region()
|
||||
* works for these devices.
|
||||
*
|
||||
@ -677,7 +670,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
|
||||
}
|
||||
|
||||
/*
|
||||
* pcic_pin_to_irq() is exported to ebus.c.
|
||||
* pcic_pin_to_irq() is exported to bus probing code
|
||||
*/
|
||||
unsigned int
|
||||
pcic_pin_to_irq(unsigned int pin, const char *name)
|
||||
@ -904,11 +897,6 @@ static void pcic_enable_irq(unsigned int irq_nr)
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void pcic_clear_profile_irq(int cpu)
|
||||
{
|
||||
printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
static void pcic_load_profile_irq(int cpu, unsigned int limit)
|
||||
{
|
||||
printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
|
||||
@ -934,7 +922,6 @@ void __init sun4m_pci_init_IRQ(void)
|
||||
BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM);
|
||||
}
|
||||
|
||||
|
@ -8,11 +8,11 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/sbus.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/auxio.h>
|
||||
@ -23,17 +23,15 @@
|
||||
* #define PMC_NO_IDLE
|
||||
*/
|
||||
|
||||
#define PMC_MINOR MISC_DYNAMIC_MINOR
|
||||
#define PMC_OBPNAME "SUNW,pmc"
|
||||
#define PMC_DEVNAME "pmc"
|
||||
|
||||
#define PMC_IDLE_REG 0x00
|
||||
#define PMC_IDLE_ON 0x01
|
||||
|
||||
volatile static u8 __iomem *regs;
|
||||
static int pmc_regsize;
|
||||
static u8 __iomem *regs;
|
||||
|
||||
#define pmc_readb(offs) (sbus_readb(regs+offs))
|
||||
#define pmc_readb(offs) (sbus_readb(regs+offs))
|
||||
#define pmc_writeb(val, offs) (sbus_writeb(val, regs+offs))
|
||||
|
||||
/*
|
||||
@ -53,31 +51,11 @@ void pmc_swift_idle(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void pmc_free(void)
|
||||
static int __devinit pmc_probe(struct of_device *op,
|
||||
const struct of_device_id *match)
|
||||
{
|
||||
sbus_iounmap(regs, pmc_regsize);
|
||||
}
|
||||
|
||||
static int __init pmc_probe(void)
|
||||
{
|
||||
struct sbus_bus *sbus = NULL;
|
||||
struct sbus_dev *sdev = NULL;
|
||||
for_each_sbus(sbus) {
|
||||
for_each_sbusdev(sdev, sbus) {
|
||||
if (!strcmp(sdev->prom_name, PMC_OBPNAME)) {
|
||||
goto sbus_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sbus_done:
|
||||
if (!sdev) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pmc_regsize = sdev->reg_addrs[0].reg_size;
|
||||
regs = sbus_ioremap(&sdev->resource[0], 0,
|
||||
pmc_regsize, PMC_OBPNAME);
|
||||
regs = of_ioremap(&op->resource[0], 0,
|
||||
resource_size(&op->resource[0]), PMC_OBPNAME);
|
||||
if (!regs) {
|
||||
printk(KERN_ERR "%s: unable to map registers\n", PMC_DEVNAME);
|
||||
return -ENODEV;
|
||||
@ -92,8 +70,27 @@ sbus_done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id __initdata pmc_match[] = {
|
||||
{
|
||||
.name = PMC_OBPNAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pmc_match);
|
||||
|
||||
static struct of_platform_driver pmc_driver = {
|
||||
.name = "pmc",
|
||||
.match_table = pmc_match,
|
||||
.probe = pmc_probe,
|
||||
};
|
||||
|
||||
static int __init pmc_init(void)
|
||||
{
|
||||
return of_register_driver(&pmc_driver, &of_bus_type);
|
||||
}
|
||||
|
||||
/* This driver is not critical to the boot process
|
||||
* and is easiest to ioremap when SBus is already
|
||||
* initialized, so we install ourselves thusly:
|
||||
*/
|
||||
__initcall(pmc_probe);
|
||||
__initcall(pmc_init);
|
||||
|
@ -75,7 +75,7 @@ void cpu_idle(void)
|
||||
{
|
||||
/* endless idle loop with no priority at all */
|
||||
for (;;) {
|
||||
if (ARCH_SUN4C_SUN4) {
|
||||
if (ARCH_SUN4C) {
|
||||
static int count = HZ;
|
||||
static unsigned long last_jiffies;
|
||||
static unsigned long last_faults;
|
||||
|
@ -54,6 +54,9 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
|
||||
}
|
||||
EXPORT_SYMBOL(of_getintprop_default);
|
||||
|
||||
DEFINE_MUTEX(of_set_property_mutex);
|
||||
EXPORT_SYMBOL(of_set_property_mutex);
|
||||
|
||||
int of_set_property(struct device_node *dp, const char *name, void *val, int len)
|
||||
{
|
||||
struct property **prevp;
|
||||
@ -77,7 +80,10 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
|
||||
void *old_val = prop->value;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&of_set_property_mutex);
|
||||
ret = prom_setprop(dp->node, (char *) name, val, len);
|
||||
mutex_unlock(&of_set_property_mutex);
|
||||
|
||||
err = -EINVAL;
|
||||
if (ret >= 0) {
|
||||
prop->value = new_val;
|
||||
@ -436,7 +442,6 @@ static void __init of_console_init(void)
|
||||
|
||||
switch (prom_vers) {
|
||||
case PROM_V0:
|
||||
case PROM_SUN4:
|
||||
skip = 0;
|
||||
switch (*romvec->pv_stdout) {
|
||||
case PROMDEV_SCREEN:
|
||||
|
@ -213,23 +213,25 @@ void __init setup_arch(char **cmdline_p)
|
||||
/* Initialize PROM console and command line. */
|
||||
*cmdline_p = prom_getbootargs();
|
||||
strcpy(boot_command_line, *cmdline_p);
|
||||
parse_early_param();
|
||||
|
||||
/* Set sparc_cpu_model */
|
||||
sparc_cpu_model = sun_unknown;
|
||||
if(!strcmp(&cputypval,"sun4 ")) { sparc_cpu_model=sun4; }
|
||||
if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; }
|
||||
if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; }
|
||||
if(!strcmp(&cputypval,"sun4s")) { sparc_cpu_model=sun4m; } /* CP-1200 with PROM 2.30 -E */
|
||||
if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
|
||||
if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
|
||||
if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
|
||||
if (!strcmp(&cputypval,"sun4 "))
|
||||
sparc_cpu_model = sun4;
|
||||
if (!strcmp(&cputypval,"sun4c"))
|
||||
sparc_cpu_model = sun4c;
|
||||
if (!strcmp(&cputypval,"sun4m"))
|
||||
sparc_cpu_model = sun4m;
|
||||
if (!strcmp(&cputypval,"sun4s"))
|
||||
sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */
|
||||
if (!strcmp(&cputypval,"sun4d"))
|
||||
sparc_cpu_model = sun4d;
|
||||
if (!strcmp(&cputypval,"sun4e"))
|
||||
sparc_cpu_model = sun4e;
|
||||
if (!strcmp(&cputypval,"sun4u"))
|
||||
sparc_cpu_model = sun4u;
|
||||
|
||||
#ifdef CONFIG_SUN4
|
||||
if (sparc_cpu_model != sun4) {
|
||||
prom_printf("This kernel is for Sun4 architecture only.\n");
|
||||
prom_halt();
|
||||
}
|
||||
#endif
|
||||
printk("ARCH: ");
|
||||
switch(sparc_cpu_model) {
|
||||
case sun4:
|
||||
@ -263,7 +265,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
boot_flags_init(*cmdline_p);
|
||||
|
||||
idprom_init();
|
||||
if (ARCH_SUN4C_SUN4)
|
||||
if (ARCH_SUN4C)
|
||||
sun4c_probe_vac();
|
||||
load_mmu();
|
||||
|
||||
|
@ -38,17 +38,12 @@
|
||||
#include <asm/idprom.h>
|
||||
#include <asm/head.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/mostek.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/checksum.h>
|
||||
#ifdef CONFIG_SBUS
|
||||
#include <asm/sbus.h>
|
||||
#include <asm/dma.h>
|
||||
#endif
|
||||
#ifdef CONFIG_PCI
|
||||
#include <asm/ebus.h>
|
||||
#endif
|
||||
#include <asm/io-unit.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
@ -127,16 +122,11 @@ EXPORT_SYMBOL(phys_cpu_present_map);
|
||||
EXPORT_SYMBOL(__udelay);
|
||||
EXPORT_SYMBOL(__ndelay);
|
||||
EXPORT_SYMBOL(rtc_lock);
|
||||
EXPORT_SYMBOL(mostek_lock);
|
||||
EXPORT_SYMBOL(mstk48t02_regs);
|
||||
#ifdef CONFIG_SUN_AUXIO
|
||||
EXPORT_SYMBOL(set_auxio);
|
||||
EXPORT_SYMBOL(get_auxio);
|
||||
#endif
|
||||
EXPORT_SYMBOL(io_remap_pfn_range);
|
||||
/* P3: iounit_xxx may be needed, sun4d users */
|
||||
/* EXPORT_SYMBOL(iounit_map_dma_init); */
|
||||
/* EXPORT_SYMBOL(iounit_map_dma_page); */
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32));
|
||||
@ -153,24 +143,9 @@ EXPORT_SYMBOL(BTFIXUP_CALL(mmu_release_scsi_one));
|
||||
EXPORT_SYMBOL(BTFIXUP_CALL(pgprot_noncached));
|
||||
|
||||
#ifdef CONFIG_SBUS
|
||||
EXPORT_SYMBOL(sbus_root);
|
||||
EXPORT_SYMBOL(dma_chain);
|
||||
EXPORT_SYMBOL(sbus_set_sbus64);
|
||||
EXPORT_SYMBOL(sbus_alloc_consistent);
|
||||
EXPORT_SYMBOL(sbus_free_consistent);
|
||||
EXPORT_SYMBOL(sbus_map_single);
|
||||
EXPORT_SYMBOL(sbus_unmap_single);
|
||||
EXPORT_SYMBOL(sbus_map_sg);
|
||||
EXPORT_SYMBOL(sbus_unmap_sg);
|
||||
EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu);
|
||||
EXPORT_SYMBOL(sbus_dma_sync_single_for_device);
|
||||
EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu);
|
||||
EXPORT_SYMBOL(sbus_dma_sync_sg_for_device);
|
||||
EXPORT_SYMBOL(sbus_iounmap);
|
||||
EXPORT_SYMBOL(sbus_ioremap);
|
||||
#endif
|
||||
#ifdef CONFIG_PCI
|
||||
EXPORT_SYMBOL(ebus_chain);
|
||||
EXPORT_SYMBOL(insb);
|
||||
EXPORT_SYMBOL(outsb);
|
||||
EXPORT_SYMBOL(insw);
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include "irq.h"
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
@ -31,15 +33,8 @@
|
||||
#include <asm/traps.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/sun4paddr.h>
|
||||
#include <asm/idprom.h>
|
||||
#include <asm/machines.h>
|
||||
#include <asm/sbus.h>
|
||||
|
||||
#if 0
|
||||
static struct resource sun4c_timer_eb = { "sun4c_timer" };
|
||||
static struct resource sun4c_intr_eb = { "sun4c_intr" };
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Bit field defines for the interrupt registers on various
|
||||
@ -64,19 +59,7 @@ static struct resource sun4c_intr_eb = { "sun4c_intr" };
|
||||
*
|
||||
* so don't go making it static, like I tried. sigh.
|
||||
*/
|
||||
unsigned char *interrupt_enable = NULL;
|
||||
|
||||
static int sun4c_pil_map[] = { 0, 1, 2, 3, 5, 7, 8, 9 };
|
||||
|
||||
static unsigned int sun4c_sbint_to_irq(struct sbus_dev *sdev,
|
||||
unsigned int sbint)
|
||||
{
|
||||
if (sbint >= sizeof(sun4c_pil_map)) {
|
||||
printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
|
||||
BUG();
|
||||
}
|
||||
return sun4c_pil_map[sbint];
|
||||
}
|
||||
unsigned char __iomem *interrupt_enable = NULL;
|
||||
|
||||
static void sun4c_disable_irq(unsigned int irq_nr)
|
||||
{
|
||||
@ -85,7 +68,7 @@ static void sun4c_disable_irq(unsigned int irq_nr)
|
||||
|
||||
local_irq_save(flags);
|
||||
irq_nr &= (NR_IRQS - 1);
|
||||
current_mask = *interrupt_enable;
|
||||
current_mask = sbus_readb(interrupt_enable);
|
||||
switch(irq_nr) {
|
||||
case 1:
|
||||
new_mask = ((current_mask) & (~(SUN4C_INT_E1)));
|
||||
@ -103,7 +86,7 @@ static void sun4c_disable_irq(unsigned int irq_nr)
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
*interrupt_enable = new_mask;
|
||||
sbus_writeb(new_mask, interrupt_enable);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
@ -114,7 +97,7 @@ static void sun4c_enable_irq(unsigned int irq_nr)
|
||||
|
||||
local_irq_save(flags);
|
||||
irq_nr &= (NR_IRQS - 1);
|
||||
current_mask = *interrupt_enable;
|
||||
current_mask = sbus_readb(interrupt_enable);
|
||||
switch(irq_nr) {
|
||||
case 1:
|
||||
new_mask = ((current_mask) | SUN4C_INT_E1);
|
||||
@ -132,37 +115,22 @@ static void sun4c_enable_irq(unsigned int irq_nr)
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
*interrupt_enable = new_mask;
|
||||
sbus_writeb(new_mask, interrupt_enable);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
#define TIMER_IRQ 10 /* Also at level 14, but we ignore that one. */
|
||||
#define PROFILE_IRQ 14 /* Level14 ticker.. used by OBP for polling */
|
||||
struct sun4c_timer_info {
|
||||
u32 l10_count;
|
||||
u32 l10_limit;
|
||||
u32 l14_count;
|
||||
u32 l14_limit;
|
||||
};
|
||||
|
||||
volatile struct sun4c_timer_info *sun4c_timers;
|
||||
|
||||
#ifdef CONFIG_SUN4
|
||||
/* This is an ugly hack to work around the
|
||||
current timer code, and make it work with
|
||||
the sun4/260 intersil
|
||||
*/
|
||||
volatile struct sun4c_timer_info sun4_timer;
|
||||
#endif
|
||||
static struct sun4c_timer_info __iomem *sun4c_timers;
|
||||
|
||||
static void sun4c_clear_clock_irq(void)
|
||||
{
|
||||
volatile unsigned int clear_intr;
|
||||
#ifdef CONFIG_SUN4
|
||||
if (idprom->id_machtype == (SM_SUN4 | SM_4_260))
|
||||
clear_intr = sun4_timer.timer_limit10;
|
||||
else
|
||||
#endif
|
||||
clear_intr = sun4c_timers->timer_limit10;
|
||||
}
|
||||
|
||||
static void sun4c_clear_profile_irq(int cpu)
|
||||
{
|
||||
/* Errm.. not sure how to do this.. */
|
||||
sbus_readl(&sun4c_timers->l10_limit);
|
||||
}
|
||||
|
||||
static void sun4c_load_profile_irq(int cpu, unsigned int limit)
|
||||
@ -172,41 +140,48 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit)
|
||||
|
||||
static void __init sun4c_init_timers(irq_handler_t counter_fn)
|
||||
{
|
||||
int irq;
|
||||
const struct linux_prom_irqs *irq;
|
||||
struct device_node *dp;
|
||||
const u32 *addr;
|
||||
int err;
|
||||
|
||||
/* Map the Timer chip, this is implemented in hardware inside
|
||||
* the cache chip on the sun4c.
|
||||
*/
|
||||
#ifdef CONFIG_SUN4
|
||||
if (idprom->id_machtype == (SM_SUN4 | SM_4_260))
|
||||
sun4c_timers = &sun4_timer;
|
||||
else
|
||||
#endif
|
||||
sun4c_timers = ioremap(SUN_TIMER_PHYSADDR,
|
||||
sizeof(struct sun4c_timer_info));
|
||||
dp = of_find_node_by_name(NULL, "counter-timer");
|
||||
if (!dp) {
|
||||
prom_printf("sun4c_init_timers: Unable to find counter-timer\n");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
addr = of_get_property(dp, "address", NULL);
|
||||
if (!addr) {
|
||||
prom_printf("sun4c_init_timers: No address property\n");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
sun4c_timers = (void __iomem *) (unsigned long) addr[0];
|
||||
|
||||
irq = of_get_property(dp, "intr", NULL);
|
||||
if (!irq) {
|
||||
prom_printf("sun4c_init_timers: No intr property\n");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
/* Have the level 10 timer tick at 100HZ. We don't touch the
|
||||
* level 14 timer limit since we are letting the prom handle
|
||||
* them until we have a real console driver so L1-A works.
|
||||
*/
|
||||
sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10);
|
||||
master_l10_counter = &sun4c_timers->cur_count10;
|
||||
master_l10_limit = &sun4c_timers->timer_limit10;
|
||||
sbus_writel((((1000000/HZ) + 1) << 10), &sun4c_timers->l10_limit);
|
||||
|
||||
irq = request_irq(TIMER_IRQ,
|
||||
counter_fn,
|
||||
master_l10_counter = &sun4c_timers->l10_count;
|
||||
|
||||
err = request_irq(irq[0].pri, counter_fn,
|
||||
(IRQF_DISABLED | SA_STATIC_ALLOC),
|
||||
"timer", NULL);
|
||||
if (irq) {
|
||||
prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
|
||||
if (err) {
|
||||
prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err);
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* This does not work on 4/330 */
|
||||
sun4c_enable_irq(10);
|
||||
#endif
|
||||
claim_ticker14(NULL, PROFILE_IRQ, 0);
|
||||
sun4c_disable_irq(irq[1].pri);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
@ -215,41 +190,28 @@ static void sun4c_nop(void) {}
|
||||
|
||||
void __init sun4c_init_IRQ(void)
|
||||
{
|
||||
struct linux_prom_registers int_regs[2];
|
||||
int ie_node;
|
||||
struct device_node *dp;
|
||||
const u32 *addr;
|
||||
|
||||
if (ARCH_SUN4) {
|
||||
interrupt_enable = (char *)
|
||||
ioremap(sun4_ie_physaddr, PAGE_SIZE);
|
||||
} else {
|
||||
struct resource phyres;
|
||||
|
||||
ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
|
||||
"interrupt-enable");
|
||||
if(ie_node == 0)
|
||||
panic("Cannot find /interrupt-enable node");
|
||||
|
||||
/* Depending on the "address" property is bad news... */
|
||||
interrupt_enable = NULL;
|
||||
if (prom_getproperty(ie_node, "reg", (char *) int_regs,
|
||||
sizeof(int_regs)) != -1) {
|
||||
memset(&phyres, 0, sizeof(struct resource));
|
||||
phyres.flags = int_regs[0].which_io;
|
||||
phyres.start = int_regs[0].phys_addr;
|
||||
interrupt_enable = (char *) sbus_ioremap(&phyres, 0,
|
||||
int_regs[0].reg_size, "sun4c_intr");
|
||||
}
|
||||
dp = of_find_node_by_name(NULL, "interrupt-enable");
|
||||
if (!dp) {
|
||||
prom_printf("sun4c_init_IRQ: Unable to find interrupt-enable\n");
|
||||
prom_halt();
|
||||
}
|
||||
if (!interrupt_enable)
|
||||
panic("Cannot map interrupt_enable");
|
||||
|
||||
BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM);
|
||||
addr = of_get_property(dp, "address", NULL);
|
||||
if (!addr) {
|
||||
prom_printf("sun4c_init_IRQ: No address property\n");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
interrupt_enable = (void __iomem *) (unsigned long) addr[0];
|
||||
|
||||
BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP);
|
||||
BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
|
||||
sparc_init_timers = sun4c_init_timers;
|
||||
#ifdef CONFIG_SMP
|
||||
@ -257,6 +219,6 @@ void __init sun4c_init_IRQ(void)
|
||||
BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
|
||||
BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP);
|
||||
#endif
|
||||
*interrupt_enable = (SUN4C_INT_ENABLE);
|
||||
sbus_writeb(SUN4C_INT_ENABLE, interrupt_enable);
|
||||
/* Cannot enable interrupts until OBP ticker is disabled. */
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include <linux/smp.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/processor.h>
|
||||
@ -34,7 +36,6 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/sbus.h>
|
||||
#include <asm/sbi.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/irq_regs.h>
|
||||
@ -44,16 +45,22 @@
|
||||
/* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
|
||||
/* #define DISTRIBUTE_IRQS */
|
||||
|
||||
struct sun4d_timer_regs *sun4d_timers;
|
||||
struct sun4d_timer_regs {
|
||||
u32 l10_timer_limit;
|
||||
u32 l10_cur_countx;
|
||||
u32 l10_limit_noclear;
|
||||
u32 ctrl;
|
||||
u32 l10_cur_count;
|
||||
};
|
||||
|
||||
static struct sun4d_timer_regs __iomem *sun4d_timers;
|
||||
|
||||
#define TIMER_IRQ 10
|
||||
|
||||
#define MAX_STATIC_ALLOC 4
|
||||
extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
|
||||
extern int static_irq_count;
|
||||
unsigned char cpu_leds[32];
|
||||
#ifdef CONFIG_SMP
|
||||
static unsigned char sbus_tid[32];
|
||||
#endif
|
||||
|
||||
static struct irqaction *irq_action[NR_IRQS];
|
||||
extern spinlock_t irq_action_lock;
|
||||
@ -72,9 +79,9 @@ static int sbus_to_pil[] = {
|
||||
};
|
||||
|
||||
static int nsbi;
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
/* Exported for sun4d_smp.c */
|
||||
DEFINE_SPINLOCK(sun4d_imsk_lock);
|
||||
#endif
|
||||
|
||||
int show_sun4d_interrupts(struct seq_file *p, void *v)
|
||||
{
|
||||
@ -257,26 +264,6 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
|
||||
set_irq_regs(old_regs);
|
||||
}
|
||||
|
||||
unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq)
|
||||
{
|
||||
int sbusl = pil_to_sbus[irq];
|
||||
|
||||
if (sbusl)
|
||||
return ((sdev->bus->board + 1) << 5) + (sbusl << 2) + sdev->slot;
|
||||
else
|
||||
return irq;
|
||||
}
|
||||
|
||||
static unsigned int sun4d_sbint_to_irq(struct sbus_dev *sdev,
|
||||
unsigned int sbint)
|
||||
{
|
||||
if (sbint >= sizeof(sbus_to_pil)) {
|
||||
printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
|
||||
BUG();
|
||||
}
|
||||
return sun4d_build_irq(sdev, sbus_to_pil[sbint]);
|
||||
}
|
||||
|
||||
int sun4d_request_irq(unsigned int irq,
|
||||
irq_handler_t handler,
|
||||
unsigned long irqflags, const char * devname, void *dev_id)
|
||||
@ -360,36 +347,28 @@ out:
|
||||
|
||||
static void sun4d_disable_irq(unsigned int irq)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
int tid = sbus_tid[(irq >> 5) - 1];
|
||||
unsigned long flags;
|
||||
#endif
|
||||
|
||||
if (irq < NR_IRQS) return;
|
||||
#ifdef CONFIG_SMP
|
||||
if (irq < NR_IRQS)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&sun4d_imsk_lock, flags);
|
||||
cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
|
||||
spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
|
||||
#else
|
||||
cc_set_imsk(cc_get_imsk() | (1 << sbus_to_pil[(irq >> 2) & 7]));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void sun4d_enable_irq(unsigned int irq)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
int tid = sbus_tid[(irq >> 5) - 1];
|
||||
unsigned long flags;
|
||||
#endif
|
||||
|
||||
if (irq < NR_IRQS) return;
|
||||
#ifdef CONFIG_SMP
|
||||
if (irq < NR_IRQS)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&sun4d_imsk_lock, flags);
|
||||
cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
|
||||
spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
|
||||
#else
|
||||
cc_set_imsk(cc_get_imsk() & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
@ -409,47 +388,55 @@ static void sun4d_set_udt(int cpu)
|
||||
/* Setup IRQ distribution scheme. */
|
||||
void __init sun4d_distribute_irqs(void)
|
||||
{
|
||||
struct device_node *dp;
|
||||
|
||||
#ifdef DISTRIBUTE_IRQS
|
||||
struct sbus_bus *sbus;
|
||||
unsigned long sbus_serving_map;
|
||||
cpumask_t sbus_serving_map;
|
||||
|
||||
sbus_serving_map = cpu_present_map;
|
||||
for_each_sbus(sbus) {
|
||||
if ((sbus->board * 2) == boot_cpu_id && (cpu_present_map & (1 << (sbus->board * 2 + 1))))
|
||||
sbus_tid[sbus->board] = (sbus->board * 2 + 1);
|
||||
else if (cpu_present_map & (1 << (sbus->board * 2)))
|
||||
sbus_tid[sbus->board] = (sbus->board * 2);
|
||||
else if (cpu_present_map & (1 << (sbus->board * 2 + 1)))
|
||||
sbus_tid[sbus->board] = (sbus->board * 2 + 1);
|
||||
for_each_node_by_name(dp, "sbi") {
|
||||
int board = of_getintprop_default(dp, "board#", 0);
|
||||
|
||||
if ((board * 2) == boot_cpu_id && cpu_isset(board * 2 + 1, cpu_present_map))
|
||||
sbus_tid[board] = (board * 2 + 1);
|
||||
else if (cpu_isset(board * 2, cpu_present_map))
|
||||
sbus_tid[board] = (board * 2);
|
||||
else if (cpu_isset(board * 2 + 1, cpu_present_map))
|
||||
sbus_tid[board] = (board * 2 + 1);
|
||||
else
|
||||
sbus_tid[sbus->board] = 0xff;
|
||||
if (sbus_tid[sbus->board] != 0xff)
|
||||
sbus_serving_map &= ~(1 << sbus_tid[sbus->board]);
|
||||
sbus_tid[board] = 0xff;
|
||||
if (sbus_tid[board] != 0xff)
|
||||
cpu_clear(sbus_tid[board], sbus_serving_map);
|
||||
}
|
||||
for_each_sbus(sbus)
|
||||
if (sbus_tid[sbus->board] == 0xff) {
|
||||
for_each_node_by_name(dp, "sbi") {
|
||||
int board = of_getintprop_default(dp, "board#", 0);
|
||||
if (sbus_tid[board] == 0xff) {
|
||||
int i = 31;
|
||||
|
||||
if (!sbus_serving_map)
|
||||
if (cpus_empty(sbus_serving_map))
|
||||
sbus_serving_map = cpu_present_map;
|
||||
while (!(sbus_serving_map & (1 << i)))
|
||||
while (cpu_isset(i, sbus_serving_map))
|
||||
i--;
|
||||
sbus_tid[sbus->board] = i;
|
||||
sbus_serving_map &= ~(1 << i);
|
||||
sbus_tid[board] = i;
|
||||
cpu_clear(i, sbus_serving_map);
|
||||
}
|
||||
for_each_sbus(sbus) {
|
||||
printk("sbus%d IRQs directed to CPU%d\n", sbus->board, sbus_tid[sbus->board]);
|
||||
set_sbi_tid(sbus->devid, sbus_tid[sbus->board] << 3);
|
||||
}
|
||||
for_each_node_by_name(dp, "sbi") {
|
||||
int devid = of_getintprop_default(dp, "device-id", 0);
|
||||
int board = of_getintprop_default(dp, "board#", 0);
|
||||
printk("sbus%d IRQs directed to CPU%d\n", board, sbus_tid[board]);
|
||||
set_sbi_tid(devid, sbus_tid[board] << 3);
|
||||
}
|
||||
#else
|
||||
struct sbus_bus *sbus;
|
||||
int cpuid = cpu_logical_map(1);
|
||||
|
||||
if (cpuid == -1)
|
||||
cpuid = cpu_logical_map(0);
|
||||
for_each_sbus(sbus) {
|
||||
sbus_tid[sbus->board] = cpuid;
|
||||
set_sbi_tid(sbus->devid, cpuid << 3);
|
||||
for_each_node_by_name(dp, "sbi") {
|
||||
int devid = of_getintprop_default(dp, "device-id", 0);
|
||||
int board = of_getintprop_default(dp, "board#", 0);
|
||||
sbus_tid[board] = cpuid;
|
||||
set_sbi_tid(devid, cpuid << 3);
|
||||
}
|
||||
printk("All sbus IRQs directed to CPU%d\n", cpuid);
|
||||
#endif
|
||||
@ -458,13 +445,7 @@ void __init sun4d_distribute_irqs(void)
|
||||
|
||||
static void sun4d_clear_clock_irq(void)
|
||||
{
|
||||
volatile unsigned int clear_intr;
|
||||
clear_intr = sun4d_timers->l10_timer_limit;
|
||||
}
|
||||
|
||||
static void sun4d_clear_profile_irq(int cpu)
|
||||
{
|
||||
bw_get_prof_limit(cpu);
|
||||
sbus_readl(&sun4d_timers->l10_timer_limit);
|
||||
}
|
||||
|
||||
static void sun4d_load_profile_irq(int cpu, unsigned int limit)
|
||||
@ -472,98 +453,121 @@ static void sun4d_load_profile_irq(int cpu, unsigned int limit)
|
||||
bw_set_prof_limit(cpu, limit);
|
||||
}
|
||||
|
||||
static void __init sun4d_init_timers(irq_handler_t counter_fn)
|
||||
static void __init sun4d_load_profile_irqs(void)
|
||||
{
|
||||
int irq;
|
||||
int cpu;
|
||||
struct resource r;
|
||||
int mid;
|
||||
int cpu = 0, mid;
|
||||
|
||||
/* Map the User Timer registers. */
|
||||
memset(&r, 0, sizeof(r));
|
||||
#ifdef CONFIG_SMP
|
||||
r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT;
|
||||
#else
|
||||
r.start = CSR_BASE(0)+BW_TIMER_LIMIT;
|
||||
#endif
|
||||
r.flags = 0xf;
|
||||
sun4d_timers = (struct sun4d_timer_regs *) sbus_ioremap(&r, 0,
|
||||
PAGE_SIZE, "user timer");
|
||||
|
||||
sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
|
||||
master_l10_counter = &sun4d_timers->l10_cur_count;
|
||||
master_l10_limit = &sun4d_timers->l10_timer_limit;
|
||||
|
||||
irq = request_irq(TIMER_IRQ,
|
||||
counter_fn,
|
||||
(IRQF_DISABLED | SA_STATIC_ALLOC),
|
||||
"timer", NULL);
|
||||
if (irq) {
|
||||
prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
/* Enable user timer free run for CPU 0 in BW */
|
||||
/* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
|
||||
|
||||
cpu = 0;
|
||||
while (!cpu_find_by_instance(cpu, NULL, &mid)) {
|
||||
sun4d_load_profile_irq(mid >> 3, 0);
|
||||
cpu++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void __init sun4d_fixup_trap_table(void)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
{
|
||||
unsigned long flags;
|
||||
extern unsigned long lvl14_save[4];
|
||||
struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
|
||||
extern unsigned int real_irq_entry[], smp4d_ticker[];
|
||||
extern unsigned int patchme_maybe_smp_msg[];
|
||||
unsigned long flags;
|
||||
extern unsigned long lvl14_save[4];
|
||||
struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
|
||||
extern unsigned int real_irq_entry[], smp4d_ticker[];
|
||||
extern unsigned int patchme_maybe_smp_msg[];
|
||||
|
||||
/* Adjust so that we jump directly to smp4d_ticker */
|
||||
lvl14_save[2] += smp4d_ticker - real_irq_entry;
|
||||
/* Adjust so that we jump directly to smp4d_ticker */
|
||||
lvl14_save[2] += smp4d_ticker - real_irq_entry;
|
||||
|
||||
/* For SMP we use the level 14 ticker, however the bootup code
|
||||
* has copied the firmware's level 14 vector into the boot cpu's
|
||||
* trap table, we must fix this now or we get squashed.
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
|
||||
trap_table->inst_one = lvl14_save[0];
|
||||
trap_table->inst_two = lvl14_save[1];
|
||||
trap_table->inst_three = lvl14_save[2];
|
||||
trap_table->inst_four = lvl14_save[3];
|
||||
local_flush_cache_all();
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
/* For SMP we use the level 14 ticker, however the bootup code
|
||||
* has copied the firmware's level 14 vector into the boot cpu's
|
||||
* trap table, we must fix this now or we get squashed.
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
|
||||
trap_table->inst_one = lvl14_save[0];
|
||||
trap_table->inst_two = lvl14_save[1];
|
||||
trap_table->inst_three = lvl14_save[2];
|
||||
trap_table->inst_four = lvl14_save[3];
|
||||
local_flush_cache_all();
|
||||
local_irq_restore(flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __init sun4d_init_timers(irq_handler_t counter_fn)
|
||||
{
|
||||
struct device_node *dp;
|
||||
struct resource res;
|
||||
const u32 *reg;
|
||||
int err;
|
||||
|
||||
dp = of_find_node_by_name(NULL, "cpu-unit");
|
||||
if (!dp) {
|
||||
prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
/* Which cpu-unit we use is arbitrary, we can view the bootbus timer
|
||||
* registers via any cpu's mapping. The first 'reg' property is the
|
||||
* bootbus.
|
||||
*/
|
||||
reg = of_get_property(dp, "reg", NULL);
|
||||
if (!reg) {
|
||||
prom_printf("sun4d_init_timers: No reg property\n");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
res.start = reg[1];
|
||||
res.end = reg[2] - 1;
|
||||
res.flags = reg[0] & 0xff;
|
||||
sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
|
||||
sizeof(struct sun4d_timer_regs), "user timer");
|
||||
if (!sun4d_timers) {
|
||||
prom_printf("sun4d_init_timers: Can't map timer regs\n");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
|
||||
|
||||
master_l10_counter = &sun4d_timers->l10_cur_count;
|
||||
|
||||
err = request_irq(TIMER_IRQ, counter_fn,
|
||||
(IRQF_DISABLED | SA_STATIC_ALLOC),
|
||||
"timer", NULL);
|
||||
if (err) {
|
||||
prom_printf("sun4d_init_timers: request_irq() failed with %d\n", err);
|
||||
prom_halt();
|
||||
}
|
||||
sun4d_load_profile_irqs();
|
||||
sun4d_fixup_trap_table();
|
||||
}
|
||||
|
||||
void __init sun4d_init_sbi_irq(void)
|
||||
{
|
||||
struct sbus_bus *sbus;
|
||||
unsigned mask;
|
||||
struct device_node *dp;
|
||||
int target_cpu = 0;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
target_cpu = boot_cpu_id;
|
||||
#endif
|
||||
|
||||
nsbi = 0;
|
||||
for_each_sbus(sbus)
|
||||
for_each_node_by_name(dp, "sbi")
|
||||
nsbi++;
|
||||
sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
|
||||
if (!sbus_actions) {
|
||||
prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n");
|
||||
prom_halt();
|
||||
}
|
||||
for_each_sbus(sbus) {
|
||||
#ifdef CONFIG_SMP
|
||||
extern unsigned char boot_cpu_id;
|
||||
|
||||
set_sbi_tid(sbus->devid, boot_cpu_id << 3);
|
||||
sbus_tid[sbus->board] = boot_cpu_id;
|
||||
#endif
|
||||
for_each_node_by_name(dp, "sbi") {
|
||||
int devid = of_getintprop_default(dp, "device-id", 0);
|
||||
int board = of_getintprop_default(dp, "board#", 0);
|
||||
unsigned int mask;
|
||||
|
||||
set_sbi_tid(devid, target_cpu << 3);
|
||||
sbus_tid[board] = target_cpu;
|
||||
|
||||
/* Get rid of pending irqs from PROM */
|
||||
mask = acquire_sbi(sbus->devid, 0xffffffff);
|
||||
mask = acquire_sbi(devid, 0xffffffff);
|
||||
if (mask) {
|
||||
printk ("Clearing pending IRQs %08x on SBI %d\n", mask, sbus->board);
|
||||
release_sbi(sbus->devid, mask);
|
||||
printk ("Clearing pending IRQs %08x on SBI %d\n", mask, board);
|
||||
release_sbi(devid, mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -572,11 +576,9 @@ void __init sun4d_init_IRQ(void)
|
||||
{
|
||||
local_irq_disable();
|
||||
|
||||
BTFIXUPSET_CALL(sbint_to_irq, sun4d_sbint_to_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
|
||||
sparc_init_timers = sun4d_init_timers;
|
||||
#ifdef CONFIG_SMP
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/sbus.h>
|
||||
#include <asm/sbi.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/cacheflush.h>
|
||||
@ -72,6 +71,17 @@ static void smp_setup_percpu_timer(void);
|
||||
extern void cpu_probe(void);
|
||||
extern void sun4d_distribute_irqs(void);
|
||||
|
||||
static unsigned char cpu_leds[32];
|
||||
|
||||
static inline void show_leds(int cpuid)
|
||||
{
|
||||
cpuid &= 0x1e;
|
||||
__asm__ __volatile__ ("stba %0, [%1] %2" : :
|
||||
"r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]),
|
||||
"r" (ECSR_BASE(cpuid) | BB_LEDS),
|
||||
"i" (ASI_M_CTL));
|
||||
}
|
||||
|
||||
void __init smp4d_callin(void)
|
||||
{
|
||||
int cpuid = hard_smp4d_processor_id();
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/processor.h>
|
||||
@ -35,59 +37,27 @@
|
||||
#include <asm/smp.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/sbus.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#include "irq.h"
|
||||
|
||||
/* On the sun4m, just like the timers, we have both per-cpu and master
|
||||
* interrupt registers.
|
||||
*/
|
||||
|
||||
/* These registers are used for sending/receiving irqs from/to
|
||||
* different cpu's.
|
||||
*/
|
||||
struct sun4m_intreg_percpu {
|
||||
unsigned int tbt; /* Interrupts still pending for this cpu. */
|
||||
|
||||
/* These next two registers are WRITE-ONLY and are only
|
||||
* "on bit" sensitive, "off bits" written have NO affect.
|
||||
*/
|
||||
unsigned int clear; /* Clear this cpus irqs here. */
|
||||
unsigned int set; /* Set this cpus irqs here. */
|
||||
unsigned char space[PAGE_SIZE - 12];
|
||||
struct sun4m_irq_percpu {
|
||||
u32 pending;
|
||||
u32 clear;
|
||||
u32 set;
|
||||
};
|
||||
|
||||
/*
|
||||
* djhr
|
||||
* Actually the clear and set fields in this struct are misleading..
|
||||
* according to the SLAVIO manual (and the same applies for the SEC)
|
||||
* the clear field clears bits in the mask which will ENABLE that IRQ
|
||||
* the set field sets bits in the mask to DISABLE the IRQ.
|
||||
*
|
||||
* Also the undirected_xx address in the SLAVIO is defined as
|
||||
* RESERVED and write only..
|
||||
*
|
||||
* DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
|
||||
* sun4m machines, for MP the layout makes more sense.
|
||||
*/
|
||||
struct sun4m_intregs {
|
||||
struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
|
||||
unsigned int tbt; /* IRQ's that are still pending. */
|
||||
unsigned int irqs; /* Master IRQ bits. */
|
||||
|
||||
/* Again, like the above, two these registers are WRITE-ONLY. */
|
||||
unsigned int clear; /* Clear master IRQ's by setting bits here. */
|
||||
unsigned int set; /* Set master IRQ's by setting bits here. */
|
||||
|
||||
/* This register is both READ and WRITE. */
|
||||
unsigned int undirected_target; /* Which cpu gets undirected irqs. */
|
||||
struct sun4m_irq_global {
|
||||
u32 pending;
|
||||
u32 mask;
|
||||
u32 mask_clear;
|
||||
u32 mask_set;
|
||||
u32 interrupt_target;
|
||||
};
|
||||
|
||||
static unsigned long dummy;
|
||||
|
||||
struct sun4m_intregs *sun4m_interrupts;
|
||||
unsigned long *irq_rcvreg = &dummy;
|
||||
/* Code in entry.S needs to get at these register mappings. */
|
||||
struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
|
||||
struct sun4m_irq_global __iomem *sun4m_irq_global;
|
||||
|
||||
/* Dave Redman (djhr@tadpole.co.uk)
|
||||
* The sun4m interrupt registers.
|
||||
@ -101,8 +71,9 @@ unsigned long *irq_rcvreg = &dummy;
|
||||
|
||||
#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */
|
||||
#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */
|
||||
#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */
|
||||
#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */
|
||||
#define SUN4M_INT_M2S_WRITE_ERR 0x20000000 /* write buffer error */
|
||||
#define SUN4M_INT_ECC_ERR 0x10000000 /* ecc memory error */
|
||||
#define SUN4M_INT_VME_ERR 0x08000000 /* vme async error */
|
||||
#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */
|
||||
#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */
|
||||
#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */
|
||||
@ -113,75 +84,126 @@ unsigned long *irq_rcvreg = &dummy;
|
||||
#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */
|
||||
#define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */
|
||||
#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */
|
||||
#define SUN4M_INT_VMEBITS 0x0000007F /* vme int bits */
|
||||
|
||||
#define SUN4M_INT_ERROR (SUN4M_INT_MODULE_ERR | \
|
||||
SUN4M_INT_M2S_WRITE_ERR | \
|
||||
SUN4M_INT_ECC_ERR | \
|
||||
SUN4M_INT_VME_ERR)
|
||||
|
||||
#define SUN4M_INT_SBUS(x) (1 << (x+7))
|
||||
#define SUN4M_INT_VME(x) (1 << (x))
|
||||
|
||||
/* These tables only apply for interrupts greater than 15..
|
||||
*
|
||||
* any intr value below 0x10 is considered to be a soft-int
|
||||
* this may be useful or it may not.. but that's how I've done it.
|
||||
* and it won't clash with what OBP is telling us about devices.
|
||||
/* Interrupt levels used by OBP */
|
||||
#define OBP_INT_LEVEL_SOFT 0x10
|
||||
#define OBP_INT_LEVEL_ONBOARD 0x20
|
||||
#define OBP_INT_LEVEL_SBUS 0x30
|
||||
#define OBP_INT_LEVEL_VME 0x40
|
||||
|
||||
/* Interrupt level assignment on sun4m:
|
||||
*
|
||||
* take an encoded intr value and lookup if it's valid
|
||||
* then get the mask bits that match from irq_mask
|
||||
* level source
|
||||
* ------------------------------------------------------------
|
||||
* 1 softint-1
|
||||
* 2 softint-2, VME/SBUS level 1
|
||||
* 3 softint-3, VME/SBUS level 2
|
||||
* 4 softint-4, onboard SCSI
|
||||
* 5 softint-5, VME/SBUS level 3
|
||||
* 6 softint-6, onboard ETHERNET
|
||||
* 7 softint-7, VME/SBUS level 4
|
||||
* 8 softint-8, onboard VIDEO
|
||||
* 9 softint-9, VME/SBUS level 5, Module Interrupt
|
||||
* 10 softint-10, system counter/timer
|
||||
* 11 softint-11, VME/SBUS level 6, Floppy
|
||||
* 12 softint-12, Keyboard/Mouse, Serial
|
||||
* 13 softint-13, VME/SBUS level 7, ISDN Audio
|
||||
* 14 softint-14, per-processor counter/timer
|
||||
* 15 softint-15, Asynchronous Errors (broadcast)
|
||||
*
|
||||
* P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee.
|
||||
* Each interrupt source is masked distinctly in the sun4m interrupt
|
||||
* registers. The PIL level alone is therefore ambiguous, since multiple
|
||||
* interrupt sources map to a single PIL.
|
||||
*
|
||||
* This ambiguity is resolved in the 'intr' property for device nodes
|
||||
* in the OF device tree. Each 'intr' property entry is composed of
|
||||
* two 32-bit words. The first word is the IRQ priority value, which
|
||||
* is what we're intersted in. The second word is the IRQ vector, which
|
||||
* is unused.
|
||||
*
|
||||
* The low 4 bits of the IRQ priority indicate the PIL, and the upper
|
||||
* 4 bits indicate onboard vs. SBUS leveled vs. VME leveled. 0x20
|
||||
* means onboard, 0x30 means SBUS leveled, and 0x40 means VME leveled.
|
||||
*
|
||||
* For example, an 'intr' IRQ priority value of 0x24 is onboard SCSI
|
||||
* whereas a value of 0x33 is SBUS level 2. Here are some sample
|
||||
* 'intr' property IRQ priority values from ss4, ss5, ss10, ss20, and
|
||||
* Tadpole S3 GX systems.
|
||||
*
|
||||
* esp: 0x24 onboard ESP SCSI
|
||||
* le: 0x26 onboard Lance ETHERNET
|
||||
* p9100: 0x32 SBUS level 1 P9100 video
|
||||
* bpp: 0x33 SBUS level 2 BPP parallel port device
|
||||
* DBRI: 0x39 SBUS level 5 DBRI ISDN audio
|
||||
* SUNW,leo: 0x39 SBUS level 5 LEO video
|
||||
* pcmcia: 0x3b SBUS level 6 PCMCIA controller
|
||||
* uctrl: 0x3b SBUS level 6 UCTRL device
|
||||
* modem: 0x3d SBUS level 7 MODEM
|
||||
* zs: 0x2c onboard keyboard/mouse/serial
|
||||
* floppy: 0x2b onboard Floppy
|
||||
* power: 0x22 onboard power device (XXX unknown mask bit XXX)
|
||||
*/
|
||||
static unsigned char irq_xlate[32] = {
|
||||
/* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */
|
||||
0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7,
|
||||
0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0
|
||||
|
||||
static unsigned long irq_mask[0x50] = {
|
||||
/* SMP */
|
||||
0, SUN4M_SOFT_INT(1),
|
||||
SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
|
||||
SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
|
||||
SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
|
||||
SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
|
||||
SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
|
||||
SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
|
||||
SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
|
||||
/* soft */
|
||||
0, SUN4M_SOFT_INT(1),
|
||||
SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
|
||||
SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
|
||||
SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
|
||||
SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
|
||||
SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
|
||||
SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
|
||||
SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
|
||||
/* onboard */
|
||||
0, 0, 0, 0,
|
||||
SUN4M_INT_SCSI, 0, SUN4M_INT_ETHERNET, 0,
|
||||
SUN4M_INT_VIDEO, SUN4M_INT_MODULE,
|
||||
SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY,
|
||||
(SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),
|
||||
SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR,
|
||||
/* sbus */
|
||||
0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1),
|
||||
0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3),
|
||||
0, SUN4M_INT_SBUS(4), 0, SUN4M_INT_SBUS(5),
|
||||
0, SUN4M_INT_SBUS(6), 0, 0,
|
||||
/* vme */
|
||||
0, 0, SUN4M_INT_VME(0), SUN4M_INT_VME(1),
|
||||
0, SUN4M_INT_VME(2), 0, SUN4M_INT_VME(3),
|
||||
0, SUN4M_INT_VME(4), 0, SUN4M_INT_VME(5),
|
||||
0, SUN4M_INT_VME(6), 0, 0
|
||||
};
|
||||
|
||||
static unsigned long irq_mask[] = {
|
||||
0, /* illegal index */
|
||||
SUN4M_INT_SCSI, /* 1 irq 4 */
|
||||
SUN4M_INT_ETHERNET, /* 2 irq 6 */
|
||||
SUN4M_INT_VIDEO, /* 3 irq 8 */
|
||||
SUN4M_INT_REALTIME, /* 4 irq 10 */
|
||||
SUN4M_INT_FLOPPY, /* 5 irq 11 */
|
||||
(SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), /* 6 irq 12 */
|
||||
SUN4M_INT_MODULE_ERR, /* 7 irq 15 */
|
||||
SUN4M_INT_SBUS(0), /* 8 irq 2 */
|
||||
SUN4M_INT_SBUS(1), /* 9 irq 3 */
|
||||
SUN4M_INT_SBUS(2), /* 10 irq 5 */
|
||||
SUN4M_INT_SBUS(3), /* 11 irq 7 */
|
||||
SUN4M_INT_SBUS(4), /* 12 irq 9 */
|
||||
SUN4M_INT_SBUS(5), /* 13 irq 11 */
|
||||
SUN4M_INT_SBUS(6) /* 14 irq 13 */
|
||||
};
|
||||
|
||||
static int sun4m_pil_map[] = { 0, 2, 3, 5, 7, 9, 11, 13 };
|
||||
|
||||
static unsigned int sun4m_sbint_to_irq(struct sbus_dev *sdev,
|
||||
unsigned int sbint)
|
||||
{
|
||||
if (sbint >= sizeof(sun4m_pil_map)) {
|
||||
printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
|
||||
BUG();
|
||||
}
|
||||
return sun4m_pil_map[sbint] | 0x30;
|
||||
}
|
||||
|
||||
static unsigned long sun4m_get_irqmask(unsigned int irq)
|
||||
{
|
||||
unsigned long mask;
|
||||
|
||||
if (irq > 0x20) {
|
||||
/* OBIO/SBUS interrupts */
|
||||
irq &= 0x1f;
|
||||
mask = irq_mask[irq_xlate[irq]];
|
||||
if (!mask)
|
||||
printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq);
|
||||
} else {
|
||||
/* Soft Interrupts will come here.
|
||||
* Currently there is no way to trigger them but I'm sure
|
||||
* something could be cooked up.
|
||||
*/
|
||||
irq &= 0xf;
|
||||
mask = SUN4M_SOFT_INT(irq);
|
||||
}
|
||||
if (irq < 0x50)
|
||||
mask = irq_mask[irq];
|
||||
else
|
||||
mask = 0;
|
||||
|
||||
if (!mask)
|
||||
printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n",
|
||||
irq);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
@ -193,9 +215,9 @@ static void sun4m_disable_irq(unsigned int irq_nr)
|
||||
mask = sun4m_get_irqmask(irq_nr);
|
||||
local_irq_save(flags);
|
||||
if (irq_nr > 15)
|
||||
sun4m_interrupts->set = mask;
|
||||
sbus_writel(mask, &sun4m_irq_global->mask_set);
|
||||
else
|
||||
sun4m_interrupts->cpu_intregs[cpu].set = mask;
|
||||
sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
@ -212,13 +234,13 @@ static void sun4m_enable_irq(unsigned int irq_nr)
|
||||
mask = sun4m_get_irqmask(irq_nr);
|
||||
local_irq_save(flags);
|
||||
if (irq_nr > 15)
|
||||
sun4m_interrupts->clear = mask;
|
||||
sbus_writel(mask, &sun4m_irq_global->mask_clear);
|
||||
else
|
||||
sun4m_interrupts->cpu_intregs[cpu].clear = mask;
|
||||
sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
|
||||
local_irq_restore(flags);
|
||||
} else {
|
||||
local_irq_save(flags);
|
||||
sun4m_interrupts->clear = SUN4M_INT_FLOPPY;
|
||||
sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
}
|
||||
@ -236,10 +258,10 @@ static unsigned long cpu_pil_to_imask[16] = {
|
||||
/*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
|
||||
/*10*/ SUN4M_INT_REALTIME,
|
||||
/*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
|
||||
/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
|
||||
/*13*/ SUN4M_INT_AUDIO,
|
||||
/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
|
||||
/*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO,
|
||||
/*14*/ SUN4M_INT_E14,
|
||||
/*15*/ 0x00000000
|
||||
/*15*/ SUN4M_INT_ERROR
|
||||
};
|
||||
|
||||
/* We assume the caller has disabled local interrupts when these are called,
|
||||
@ -247,126 +269,141 @@ static unsigned long cpu_pil_to_imask[16] = {
|
||||
*/
|
||||
static void sun4m_disable_pil_irq(unsigned int pil)
|
||||
{
|
||||
sun4m_interrupts->set = cpu_pil_to_imask[pil];
|
||||
sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set);
|
||||
}
|
||||
|
||||
static void sun4m_enable_pil_irq(unsigned int pil)
|
||||
{
|
||||
sun4m_interrupts->clear = cpu_pil_to_imask[pil];
|
||||
sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static void sun4m_send_ipi(int cpu, int level)
|
||||
{
|
||||
unsigned long mask;
|
||||
|
||||
mask = sun4m_get_irqmask(level);
|
||||
sun4m_interrupts->cpu_intregs[cpu].set = mask;
|
||||
unsigned long mask = sun4m_get_irqmask(level);
|
||||
sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
|
||||
}
|
||||
|
||||
static void sun4m_clear_ipi(int cpu, int level)
|
||||
{
|
||||
unsigned long mask;
|
||||
|
||||
mask = sun4m_get_irqmask(level);
|
||||
sun4m_interrupts->cpu_intregs[cpu].clear = mask;
|
||||
unsigned long mask = sun4m_get_irqmask(level);
|
||||
sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
|
||||
}
|
||||
|
||||
static void sun4m_set_udt(int cpu)
|
||||
{
|
||||
sun4m_interrupts->undirected_target = cpu;
|
||||
sbus_writel(cpu, &sun4m_irq_global->interrupt_target);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define OBIO_INTR 0x20
|
||||
#define TIMER_IRQ (OBIO_INTR | 10)
|
||||
#define PROFILE_IRQ (OBIO_INTR | 14)
|
||||
struct sun4m_timer_percpu {
|
||||
u32 l14_limit;
|
||||
u32 l14_count;
|
||||
u32 l14_limit_noclear;
|
||||
u32 user_timer_start_stop;
|
||||
};
|
||||
|
||||
static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS];
|
||||
|
||||
struct sun4m_timer_global {
|
||||
u32 l10_limit;
|
||||
u32 l10_count;
|
||||
u32 l10_limit_noclear;
|
||||
u32 reserved;
|
||||
u32 timer_config;
|
||||
};
|
||||
|
||||
static struct sun4m_timer_global __iomem *timers_global;
|
||||
|
||||
#define TIMER_IRQ (OBP_INT_LEVEL_ONBOARD | 10)
|
||||
|
||||
static struct sun4m_timer_regs *sun4m_timers;
|
||||
unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
|
||||
|
||||
static void sun4m_clear_clock_irq(void)
|
||||
{
|
||||
volatile unsigned int clear_intr;
|
||||
clear_intr = sun4m_timers->l10_timer_limit;
|
||||
sbus_readl(&timers_global->l10_limit);
|
||||
}
|
||||
|
||||
static void sun4m_clear_profile_irq(int cpu)
|
||||
void sun4m_nmi(struct pt_regs *regs)
|
||||
{
|
||||
volatile unsigned int clear;
|
||||
|
||||
clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit;
|
||||
unsigned long afsr, afar, si;
|
||||
|
||||
printk(KERN_ERR "Aieee: sun4m NMI received!\n");
|
||||
/* XXX HyperSparc hack XXX */
|
||||
__asm__ __volatile__("mov 0x500, %%g1\n\t"
|
||||
"lda [%%g1] 0x4, %0\n\t"
|
||||
"mov 0x600, %%g1\n\t"
|
||||
"lda [%%g1] 0x4, %1\n\t" :
|
||||
"=r" (afsr), "=r" (afar));
|
||||
printk(KERN_ERR "afsr=%08lx afar=%08lx\n", afsr, afar);
|
||||
si = sbus_readl(&sun4m_irq_global->pending);
|
||||
printk(KERN_ERR "si=%08lx\n", si);
|
||||
if (si & SUN4M_INT_MODULE_ERR)
|
||||
printk(KERN_ERR "Module async error\n");
|
||||
if (si & SUN4M_INT_M2S_WRITE_ERR)
|
||||
printk(KERN_ERR "MBus/SBus async error\n");
|
||||
if (si & SUN4M_INT_ECC_ERR)
|
||||
printk(KERN_ERR "ECC memory error\n");
|
||||
if (si & SUN4M_INT_VME_ERR)
|
||||
printk(KERN_ERR "VME async error\n");
|
||||
printk(KERN_ERR "you lose buddy boy...\n");
|
||||
show_regs(regs);
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
/* Exported for sun4m_smp.c */
|
||||
void sun4m_clear_profile_irq(int cpu)
|
||||
{
|
||||
sbus_readl(&timers_percpu[cpu]->l14_limit);
|
||||
}
|
||||
|
||||
static void sun4m_load_profile_irq(int cpu, unsigned int limit)
|
||||
{
|
||||
sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit;
|
||||
sbus_writel(limit, &timers_percpu[cpu]->l14_limit);
|
||||
}
|
||||
|
||||
static void __init sun4m_init_timers(irq_handler_t counter_fn)
|
||||
{
|
||||
int reg_count, irq, cpu;
|
||||
struct linux_prom_registers cnt_regs[PROMREG_MAX];
|
||||
int obio_node, cnt_node;
|
||||
struct resource r;
|
||||
struct device_node *dp = of_find_node_by_name(NULL, "counter");
|
||||
int i, err, len, num_cpu_timers;
|
||||
const u32 *addr;
|
||||
|
||||
cnt_node = 0;
|
||||
if((obio_node =
|
||||
prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
|
||||
(obio_node = prom_getchild (obio_node)) == 0 ||
|
||||
(cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
|
||||
prom_printf("Cannot find /obio/counter node\n");
|
||||
prom_halt();
|
||||
}
|
||||
reg_count = prom_getproperty(cnt_node, "reg",
|
||||
(void *) cnt_regs, sizeof(cnt_regs));
|
||||
reg_count = (reg_count/sizeof(struct linux_prom_registers));
|
||||
|
||||
/* Apply the obio ranges to the timer registers. */
|
||||
prom_apply_obio_ranges(cnt_regs, reg_count);
|
||||
|
||||
cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr;
|
||||
cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size;
|
||||
cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io;
|
||||
for(obio_node = 1; obio_node < 4; obio_node++) {
|
||||
cnt_regs[obio_node].phys_addr =
|
||||
cnt_regs[obio_node-1].phys_addr + PAGE_SIZE;
|
||||
cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
|
||||
cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;
|
||||
if (!dp) {
|
||||
printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset((char*)&r, 0, sizeof(struct resource));
|
||||
/* Map the per-cpu Counter registers. */
|
||||
r.flags = cnt_regs[0].which_io;
|
||||
r.start = cnt_regs[0].phys_addr;
|
||||
sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0,
|
||||
PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt");
|
||||
/* Map the system Counter register. */
|
||||
/* XXX Here we expect consequent calls to yeld adjusent maps. */
|
||||
r.flags = cnt_regs[4].which_io;
|
||||
r.start = cnt_regs[4].phys_addr;
|
||||
sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt");
|
||||
|
||||
sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
|
||||
master_l10_counter = &sun4m_timers->l10_cur_count;
|
||||
master_l10_limit = &sun4m_timers->l10_timer_limit;
|
||||
|
||||
irq = request_irq(TIMER_IRQ,
|
||||
counter_fn,
|
||||
(IRQF_DISABLED | SA_STATIC_ALLOC),
|
||||
"timer", NULL);
|
||||
if (irq) {
|
||||
prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
|
||||
prom_halt();
|
||||
addr = of_get_property(dp, "address", &len);
|
||||
if (!addr) {
|
||||
printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cpu_find_by_instance(1, NULL, NULL)) {
|
||||
for(cpu = 0; cpu < 4; cpu++)
|
||||
sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0;
|
||||
sun4m_interrupts->set = SUN4M_INT_E14;
|
||||
} else {
|
||||
sun4m_timers->cpu_timers[0].l14_timer_limit = 0;
|
||||
|
||||
num_cpu_timers = (len / sizeof(u32)) - 1;
|
||||
for (i = 0; i < num_cpu_timers; i++) {
|
||||
timers_percpu[i] = (void __iomem *)
|
||||
(unsigned long) addr[i];
|
||||
}
|
||||
timers_global = (void __iomem *)
|
||||
(unsigned long) addr[num_cpu_timers];
|
||||
|
||||
sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit);
|
||||
|
||||
master_l10_counter = &timers_global->l10_count;
|
||||
|
||||
err = request_irq(TIMER_IRQ, counter_fn,
|
||||
(IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
|
||||
if (err) {
|
||||
printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n",
|
||||
err);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_cpu_timers; i++)
|
||||
sbus_writel(0, &timers_percpu[i]->l14_limit);
|
||||
if (num_cpu_timers == 4)
|
||||
sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -390,70 +427,43 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
|
||||
|
||||
void __init sun4m_init_IRQ(void)
|
||||
{
|
||||
int ie_node,i;
|
||||
struct linux_prom_registers int_regs[PROMREG_MAX];
|
||||
int num_regs;
|
||||
struct resource r;
|
||||
int mid;
|
||||
|
||||
struct device_node *dp = of_find_node_by_name(NULL, "interrupt");
|
||||
int len, i, mid, num_cpu_iregs;
|
||||
const u32 *addr;
|
||||
|
||||
if (!dp) {
|
||||
printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
addr = of_get_property(dp, "address", &len);
|
||||
if (!addr) {
|
||||
printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
num_cpu_iregs = (len / sizeof(u32)) - 1;
|
||||
for (i = 0; i < num_cpu_iregs; i++) {
|
||||
sun4m_irq_percpu[i] = (void __iomem *)
|
||||
(unsigned long) addr[i];
|
||||
}
|
||||
sun4m_irq_global = (void __iomem *)
|
||||
(unsigned long) addr[num_cpu_iregs];
|
||||
|
||||
local_irq_disable();
|
||||
if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
|
||||
(ie_node = prom_getchild (ie_node)) == 0 ||
|
||||
(ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
|
||||
prom_printf("Cannot find /obio/interrupt node\n");
|
||||
prom_halt();
|
||||
}
|
||||
num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
|
||||
sizeof(int_regs));
|
||||
num_regs = (num_regs/sizeof(struct linux_prom_registers));
|
||||
|
||||
/* Apply the obio ranges to these registers. */
|
||||
prom_apply_obio_ranges(int_regs, num_regs);
|
||||
|
||||
int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
|
||||
int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
|
||||
int_regs[4].which_io = int_regs[num_regs-1].which_io;
|
||||
for(ie_node = 1; ie_node < 4; ie_node++) {
|
||||
int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
|
||||
int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
|
||||
int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
|
||||
}
|
||||
|
||||
memset((char *)&r, 0, sizeof(struct resource));
|
||||
/* Map the interrupt registers for all possible cpus. */
|
||||
r.flags = int_regs[0].which_io;
|
||||
r.start = int_regs[0].phys_addr;
|
||||
sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0,
|
||||
PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu");
|
||||
|
||||
/* Map the system interrupt control registers. */
|
||||
r.flags = int_regs[4].which_io;
|
||||
r.start = int_regs[4].phys_addr;
|
||||
sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
|
||||
|
||||
sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
|
||||
sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set);
|
||||
for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
|
||||
sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff;
|
||||
sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
|
||||
|
||||
if (num_cpu_iregs == 4)
|
||||
sbus_writel(0, &sun4m_irq_global->interrupt_target);
|
||||
|
||||
if (!cpu_find_by_instance(1, NULL, NULL)) {
|
||||
/* system wide interrupts go to cpu 0, this should always
|
||||
* be safe because it is guaranteed to be fitted or OBP doesn't
|
||||
* come up
|
||||
*
|
||||
* Not sure, but writing here on SLAVIO systems may puke
|
||||
* so I don't do it unless there is more than 1 cpu.
|
||||
*/
|
||||
irq_rcvreg = (unsigned long *)
|
||||
&sun4m_interrupts->undirected_target;
|
||||
sun4m_interrupts->undirected_target = 0;
|
||||
}
|
||||
BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
|
||||
sparc_init_timers = sun4m_init_timers;
|
||||
#ifdef CONFIG_SMP
|
||||
@ -461,5 +471,6 @@ void __init sun4m_init_IRQ(void)
|
||||
BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
|
||||
#endif
|
||||
|
||||
/* Cannot enable interrupts until OBP ticker is disabled. */
|
||||
}
|
||||
|
@ -315,6 +315,8 @@ void smp4m_cross_call_irq(void)
|
||||
ccall_info.processors_out[i] = 1;
|
||||
}
|
||||
|
||||
extern void sun4m_clear_profile_irq(int cpu);
|
||||
|
||||
void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs;
|
||||
@ -322,7 +324,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
|
||||
|
||||
old_regs = set_irq_regs(regs);
|
||||
|
||||
clear_profile_irq(cpu);
|
||||
sun4m_clear_profile_irq(cpu);
|
||||
|
||||
profile_tick(CPU_PROFILING);
|
||||
|
||||
|
@ -1,75 +0,0 @@
|
||||
/* sun4setup.c: Setup the hardware address of various items in the sun4
|
||||
* architecture. Called from idprom_init
|
||||
*
|
||||
* Copyright (C) 1998 Chris G. Davis (cdavis@cois.on.ca)
|
||||
*/
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/idprom.h>
|
||||
#include <asm/sun4paddr.h>
|
||||
#include <asm/machines.h>
|
||||
|
||||
int sun4_memreg_physaddr;
|
||||
int sun4_ie_physaddr;
|
||||
int sun4_clock_physaddr;
|
||||
int sun4_timer_physaddr;
|
||||
int sun4_eth_physaddr;
|
||||
int sun4_si_physaddr;
|
||||
int sun4_bwtwo_physaddr;
|
||||
int sun4_zs0_physaddr;
|
||||
int sun4_zs1_physaddr;
|
||||
int sun4_dma_physaddr;
|
||||
int sun4_esp_physaddr;
|
||||
int sun4_ie_physaddr;
|
||||
|
||||
void __init sun4setup(void)
|
||||
{
|
||||
printk("Sun4 Hardware Setup v1.0 18/May/98 Chris Davis (cdavis@cois.on.ca). ");
|
||||
/*
|
||||
setup standard sun4 info
|
||||
*/
|
||||
sun4_ie_physaddr=SUN4_IE_PHYSADDR;
|
||||
|
||||
/*
|
||||
setup model specific info
|
||||
*/
|
||||
switch(idprom->id_machtype) {
|
||||
case (SM_SUN4 | SM_4_260 ):
|
||||
printk("Setup for a SUN4/260\n");
|
||||
sun4_memreg_physaddr=SUN4_200_MEMREG_PHYSADDR;
|
||||
sun4_clock_physaddr=SUN4_200_CLOCK_PHYSADDR;
|
||||
sun4_timer_physaddr=SUN4_UNUSED_PHYSADDR;
|
||||
sun4_eth_physaddr=SUN4_200_ETH_PHYSADDR;
|
||||
sun4_si_physaddr=SUN4_200_SI_PHYSADDR;
|
||||
sun4_bwtwo_physaddr=SUN4_200_BWTWO_PHYSADDR;
|
||||
sun4_dma_physaddr=SUN4_UNUSED_PHYSADDR;
|
||||
sun4_esp_physaddr=SUN4_UNUSED_PHYSADDR;
|
||||
break;
|
||||
case (SM_SUN4 | SM_4_330 ):
|
||||
printk("Setup for a SUN4/330\n");
|
||||
sun4_memreg_physaddr=SUN4_300_MEMREG_PHYSADDR;
|
||||
sun4_clock_physaddr=SUN4_300_CLOCK_PHYSADDR;
|
||||
sun4_timer_physaddr=SUN4_300_TIMER_PHYSADDR;
|
||||
sun4_eth_physaddr=SUN4_300_ETH_PHYSADDR;
|
||||
sun4_si_physaddr=SUN4_UNUSED_PHYSADDR;
|
||||
sun4_bwtwo_physaddr=SUN4_300_BWTWO_PHYSADDR;
|
||||
sun4_dma_physaddr=SUN4_300_DMA_PHYSADDR;
|
||||
sun4_esp_physaddr=SUN4_300_ESP_PHYSADDR;
|
||||
break;
|
||||
case (SM_SUN4 | SM_4_470 ):
|
||||
printk("Setup for a SUN4/470\n");
|
||||
sun4_memreg_physaddr=SUN4_400_MEMREG_PHYSADDR;
|
||||
sun4_clock_physaddr=SUN4_400_CLOCK_PHYSADDR;
|
||||
sun4_timer_physaddr=SUN4_400_TIMER_PHYSADDR;
|
||||
sun4_eth_physaddr=SUN4_400_ETH_PHYSADDR;
|
||||
sun4_si_physaddr=SUN4_UNUSED_PHYSADDR;
|
||||
sun4_bwtwo_physaddr=SUN4_400_BWTWO_PHYSADDR;
|
||||
sun4_dma_physaddr=SUN4_400_DMA_PHYSADDR;
|
||||
sun4_esp_physaddr=SUN4_400_ESP_PHYSADDR;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
|
||||
/* See asm-sparc/uaccess.h */
|
||||
if (len > TASK_SIZE - PAGE_SIZE)
|
||||
return -ENOMEM;
|
||||
if (ARCH_SUN4C_SUN4 && len > 0x20000000)
|
||||
if (ARCH_SUN4C && len > 0x20000000)
|
||||
return -ENOMEM;
|
||||
if (!addr)
|
||||
addr = TASK_UNMAPPED_BASE;
|
||||
@ -65,7 +65,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
|
||||
|
||||
for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
|
||||
/* At this point: (!vmm || addr < vmm->vm_end). */
|
||||
if (ARCH_SUN4C_SUN4 && addr < 0xe0000000 && 0x20000000 - len < addr) {
|
||||
if (ARCH_SUN4C && addr < 0xe0000000 && 0x20000000 - len < addr) {
|
||||
addr = PAGE_OFFSET;
|
||||
vmm = find_vma(current->mm, PAGE_OFFSET);
|
||||
}
|
||||
@ -81,7 +81,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
|
||||
|
||||
asmlinkage unsigned long sparc_brk(unsigned long brk)
|
||||
{
|
||||
if(ARCH_SUN4C_SUN4) {
|
||||
if(ARCH_SUN4C) {
|
||||
if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000))
|
||||
return current->mm->brk;
|
||||
}
|
||||
@ -221,7 +221,7 @@ out:
|
||||
|
||||
int sparc_mmap_check(unsigned long addr, unsigned long len)
|
||||
{
|
||||
if (ARCH_SUN4C_SUN4 &&
|
||||
if (ARCH_SUN4C &&
|
||||
(len > 0x20000000 ||
|
||||
(addr < 0xe0000000 && addr + len > 0x20000000)))
|
||||
return -EINVAL;
|
||||
|
@ -1,31 +1,12 @@
|
||||
/* tick14.c
|
||||
* linux/arch/sparc/kernel/tick14.c
|
||||
*
|
||||
* Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
|
||||
*
|
||||
* This file handles the Sparc specific level14 ticker
|
||||
* This is really useful for profiling OBP uses it for keyboard
|
||||
* aborts and other stuff.
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/timer.h>
|
||||
#include <asm/mostek.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "irq.h"
|
||||
|
||||
extern unsigned long lvl14_save[5];
|
||||
static unsigned long *linux_lvl14 = NULL;
|
||||
@ -56,31 +37,3 @@ void install_obp_ticker(void)
|
||||
linux_lvl14[2] = obp_lvl14[2];
|
||||
linux_lvl14[3] = obp_lvl14[3];
|
||||
}
|
||||
|
||||
void claim_ticker14(irq_handler_t handler,
|
||||
int irq_nr, unsigned int timeout )
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
/* first we copy the obp handler instructions
|
||||
*/
|
||||
__disable_irq(irq_nr);
|
||||
if (!handler)
|
||||
return;
|
||||
|
||||
linux_lvl14 = (unsigned long *)lvl14_save[4];
|
||||
obp_lvl14[0] = linux_lvl14[0];
|
||||
obp_lvl14[1] = linux_lvl14[1];
|
||||
obp_lvl14[2] = linux_lvl14[2];
|
||||
obp_lvl14[3] = linux_lvl14[3];
|
||||
|
||||
if (!request_irq(irq_nr,
|
||||
handler,
|
||||
(IRQF_DISABLED | SA_STATIC_ALLOC),
|
||||
"counter14",
|
||||
NULL)) {
|
||||
install_linux_ticker();
|
||||
load_profile_irq(cpu, timeout);
|
||||
__enable_irq(irq_nr);
|
||||
}
|
||||
}
|
||||
|
@ -23,22 +23,24 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/rtc/m48t59.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/timer.h>
|
||||
#include <asm/mostek.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/idprom.h>
|
||||
#include <asm/machines.h>
|
||||
#include <asm/sun4paddr.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pcic.h>
|
||||
#include <asm/irq_regs.h>
|
||||
@ -46,34 +48,9 @@
|
||||
#include "irq.h"
|
||||
|
||||
DEFINE_SPINLOCK(rtc_lock);
|
||||
static enum sparc_clock_type sp_clock_typ;
|
||||
DEFINE_SPINLOCK(mostek_lock);
|
||||
void __iomem *mstk48t02_regs = NULL;
|
||||
static struct mostek48t08 __iomem *mstk48t08_regs = NULL;
|
||||
static int set_rtc_mmss(unsigned long);
|
||||
static int sbus_do_settimeofday(struct timespec *tv);
|
||||
|
||||
#ifdef CONFIG_SUN4
|
||||
struct intersil *intersil_clock;
|
||||
#define intersil_cmd(intersil_reg, intsil_cmd) intersil_reg->int_cmd_reg = \
|
||||
(intsil_cmd)
|
||||
|
||||
#define intersil_intr(intersil_reg, intsil_cmd) intersil_reg->int_intr_reg = \
|
||||
(intsil_cmd)
|
||||
|
||||
#define intersil_start(intersil_reg) intersil_cmd(intersil_reg, \
|
||||
( INTERSIL_START | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
|
||||
INTERSIL_INTR_ENABLE))
|
||||
|
||||
#define intersil_stop(intersil_reg) intersil_cmd(intersil_reg, \
|
||||
( INTERSIL_STOP | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
|
||||
INTERSIL_INTR_ENABLE))
|
||||
|
||||
#define intersil_read_intr(intersil_reg, towhere) towhere = \
|
||||
intersil_reg->int_intr_reg
|
||||
|
||||
#endif
|
||||
|
||||
unsigned long profile_pc(struct pt_regs *regs)
|
||||
{
|
||||
extern char __copy_user_begin[], __copy_user_end[];
|
||||
@ -96,7 +73,6 @@ unsigned long profile_pc(struct pt_regs *regs)
|
||||
EXPORT_SYMBOL(profile_pc);
|
||||
|
||||
__volatile__ unsigned int *master_l10_counter;
|
||||
__volatile__ unsigned int *master_l10_limit;
|
||||
|
||||
/*
|
||||
* timer_interrupt() needs to keep up the real-time clock,
|
||||
@ -116,15 +92,7 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id)
|
||||
|
||||
/* Protect counter clear so that do_gettimeoffset works */
|
||||
write_seqlock(&xtime_lock);
|
||||
#ifdef CONFIG_SUN4
|
||||
if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
|
||||
(idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
|
||||
int temp;
|
||||
intersil_read_intr(intersil_clock, temp);
|
||||
/* re-enable the irq */
|
||||
enable_pil_irq(10);
|
||||
}
|
||||
#endif
|
||||
|
||||
clear_clock_irq();
|
||||
|
||||
do_timer(1);
|
||||
@ -147,157 +115,56 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
|
||||
static void __devinit kick_start_clock(void)
|
||||
static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
|
||||
{
|
||||
struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
|
||||
unsigned char sec;
|
||||
int i, count;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct m48t59_plat_data *pdata = pdev->dev.platform_data;
|
||||
void __iomem *regs = pdata->ioaddr;
|
||||
unsigned char val = readb(regs + ofs);
|
||||
|
||||
prom_printf("CLOCK: Clock was stopped. Kick start ");
|
||||
|
||||
spin_lock_irq(&mostek_lock);
|
||||
|
||||
/* Turn on the kick start bit to start the oscillator. */
|
||||
regs->creg |= MSTK_CREG_WRITE;
|
||||
regs->sec &= ~MSTK_STOP;
|
||||
regs->hour |= MSTK_KICK_START;
|
||||
regs->creg &= ~MSTK_CREG_WRITE;
|
||||
|
||||
spin_unlock_irq(&mostek_lock);
|
||||
|
||||
/* Delay to allow the clock oscillator to start. */
|
||||
sec = MSTK_REG_SEC(regs);
|
||||
for (i = 0; i < 3; i++) {
|
||||
while (sec == MSTK_REG_SEC(regs))
|
||||
for (count = 0; count < 100000; count++)
|
||||
/* nothing */ ;
|
||||
prom_printf(".");
|
||||
sec = regs->sec;
|
||||
/* the year 0 is 1968 */
|
||||
if (ofs == pdata->offset + M48T59_YEAR) {
|
||||
val += 0x68;
|
||||
if ((val & 0xf) > 9)
|
||||
val += 6;
|
||||
}
|
||||
prom_printf("\n");
|
||||
return val;
|
||||
}
|
||||
|
||||
spin_lock_irq(&mostek_lock);
|
||||
static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct m48t59_plat_data *pdata = pdev->dev.platform_data;
|
||||
void __iomem *regs = pdata->ioaddr;
|
||||
|
||||
/* Turn off kick start and set a "valid" time and date. */
|
||||
regs->creg |= MSTK_CREG_WRITE;
|
||||
regs->hour &= ~MSTK_KICK_START;
|
||||
MSTK_SET_REG_SEC(regs,0);
|
||||
MSTK_SET_REG_MIN(regs,0);
|
||||
MSTK_SET_REG_HOUR(regs,0);
|
||||
MSTK_SET_REG_DOW(regs,5);
|
||||
MSTK_SET_REG_DOM(regs,1);
|
||||
MSTK_SET_REG_MONTH(regs,8);
|
||||
MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
|
||||
regs->creg &= ~MSTK_CREG_WRITE;
|
||||
|
||||
spin_unlock_irq(&mostek_lock);
|
||||
|
||||
/* Ensure the kick start bit is off. If it isn't, turn it off. */
|
||||
while (regs->hour & MSTK_KICK_START) {
|
||||
prom_printf("CLOCK: Kick start still on!\n");
|
||||
|
||||
spin_lock_irq(&mostek_lock);
|
||||
regs->creg |= MSTK_CREG_WRITE;
|
||||
regs->hour &= ~MSTK_KICK_START;
|
||||
regs->creg &= ~MSTK_CREG_WRITE;
|
||||
spin_unlock_irq(&mostek_lock);
|
||||
if (ofs == pdata->offset + M48T59_YEAR) {
|
||||
if (val < 0x68)
|
||||
val += 0x32;
|
||||
else
|
||||
val -= 0x68;
|
||||
if ((val & 0xf) > 9)
|
||||
val += 6;
|
||||
if ((val & 0xf0) > 0x9A)
|
||||
val += 0x60;
|
||||
}
|
||||
|
||||
prom_printf("CLOCK: Kick start procedure successful.\n");
|
||||
writeb(val, regs + ofs);
|
||||
}
|
||||
|
||||
/* Return nonzero if the clock chip battery is low. */
|
||||
static inline int has_low_battery(void)
|
||||
{
|
||||
struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
|
||||
unsigned char data1, data2;
|
||||
static struct m48t59_plat_data m48t59_data = {
|
||||
.read_byte = mostek_read_byte,
|
||||
.write_byte = mostek_write_byte,
|
||||
};
|
||||
|
||||
spin_lock_irq(&mostek_lock);
|
||||
data1 = regs->eeprom[0]; /* Read some data. */
|
||||
regs->eeprom[0] = ~data1; /* Write back the complement. */
|
||||
data2 = regs->eeprom[0]; /* Read back the complement. */
|
||||
regs->eeprom[0] = data1; /* Restore the original value. */
|
||||
spin_unlock_irq(&mostek_lock);
|
||||
/* resource is set at runtime */
|
||||
static struct platform_device m48t59_rtc = {
|
||||
.name = "rtc-m48t59",
|
||||
.id = 0,
|
||||
.num_resources = 1,
|
||||
.dev = {
|
||||
.platform_data = &m48t59_data,
|
||||
},
|
||||
};
|
||||
|
||||
return (data1 == data2); /* Was the write blocked? */
|
||||
}
|
||||
|
||||
static void __devinit mostek_set_system_time(void)
|
||||
{
|
||||
unsigned int year, mon, day, hour, min, sec;
|
||||
struct mostek48t02 *mregs;
|
||||
|
||||
mregs = (struct mostek48t02 *)mstk48t02_regs;
|
||||
if(!mregs) {
|
||||
prom_printf("Something wrong, clock regs not mapped yet.\n");
|
||||
prom_halt();
|
||||
}
|
||||
spin_lock_irq(&mostek_lock);
|
||||
mregs->creg |= MSTK_CREG_READ;
|
||||
sec = MSTK_REG_SEC(mregs);
|
||||
min = MSTK_REG_MIN(mregs);
|
||||
hour = MSTK_REG_HOUR(mregs);
|
||||
day = MSTK_REG_DOM(mregs);
|
||||
mon = MSTK_REG_MONTH(mregs);
|
||||
year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
|
||||
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
|
||||
xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
|
||||
set_normalized_timespec(&wall_to_monotonic,
|
||||
-xtime.tv_sec, -xtime.tv_nsec);
|
||||
mregs->creg &= ~MSTK_CREG_READ;
|
||||
spin_unlock_irq(&mostek_lock);
|
||||
}
|
||||
|
||||
/* Probe for the real time clock chip on Sun4 */
|
||||
static inline void sun4_clock_probe(void)
|
||||
{
|
||||
#ifdef CONFIG_SUN4
|
||||
int temp;
|
||||
struct resource r;
|
||||
|
||||
memset(&r, 0, sizeof(r));
|
||||
if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) {
|
||||
sp_clock_typ = MSTK48T02;
|
||||
r.start = sun4_clock_physaddr;
|
||||
mstk48t02_regs = sbus_ioremap(&r, 0,
|
||||
sizeof(struct mostek48t02), NULL);
|
||||
mstk48t08_regs = NULL; /* To catch weirdness */
|
||||
intersil_clock = NULL; /* just in case */
|
||||
|
||||
/* Kick start the clock if it is completely stopped. */
|
||||
if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
|
||||
kick_start_clock();
|
||||
} else if( idprom->id_machtype == (SM_SUN4 | SM_4_260)) {
|
||||
/* intersil setup code */
|
||||
printk("Clock: INTERSIL at %8x ",sun4_clock_physaddr);
|
||||
sp_clock_typ = INTERSIL;
|
||||
r.start = sun4_clock_physaddr;
|
||||
intersil_clock = (struct intersil *)
|
||||
sbus_ioremap(&r, 0, sizeof(*intersil_clock), "intersil");
|
||||
mstk48t02_regs = 0; /* just be sure */
|
||||
mstk48t08_regs = NULL; /* ditto */
|
||||
/* initialise the clock */
|
||||
|
||||
intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
|
||||
|
||||
intersil_start(intersil_clock);
|
||||
|
||||
intersil_read_intr(intersil_clock, temp);
|
||||
while (!(temp & 0x80))
|
||||
intersil_read_intr(intersil_clock, temp);
|
||||
|
||||
intersil_read_intr(intersil_clock, temp);
|
||||
while (!(temp & 0x80))
|
||||
intersil_read_intr(intersil_clock, temp);
|
||||
|
||||
intersil_stop(intersil_clock);
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SUN4
|
||||
static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
|
||||
{
|
||||
struct device_node *dp = op->node;
|
||||
@ -306,38 +173,26 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id
|
||||
if (!model)
|
||||
return -ENODEV;
|
||||
|
||||
m48t59_rtc.resource = &op->resource[0];
|
||||
if (!strcmp(model, "mk48t02")) {
|
||||
sp_clock_typ = MSTK48T02;
|
||||
|
||||
/* Map the clock register io area read-only */
|
||||
mstk48t02_regs = of_ioremap(&op->resource[0], 0,
|
||||
sizeof(struct mostek48t02),
|
||||
"mk48t02");
|
||||
mstk48t08_regs = NULL; /* To catch weirdness */
|
||||
m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
|
||||
2048, "rtc-m48t59");
|
||||
m48t59_data.type = M48T59RTC_TYPE_M48T02;
|
||||
} else if (!strcmp(model, "mk48t08")) {
|
||||
sp_clock_typ = MSTK48T08;
|
||||
mstk48t08_regs = of_ioremap(&op->resource[0], 0,
|
||||
sizeof(struct mostek48t08),
|
||||
"mk48t08");
|
||||
|
||||
mstk48t02_regs = &mstk48t08_regs->regs;
|
||||
m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
|
||||
8192, "rtc-m48t59");
|
||||
m48t59_data.type = M48T59RTC_TYPE_M48T08;
|
||||
} else
|
||||
return -ENODEV;
|
||||
|
||||
/* Report a low battery voltage condition. */
|
||||
if (has_low_battery())
|
||||
printk(KERN_CRIT "NVRAM: Low battery voltage!\n");
|
||||
|
||||
/* Kick start the clock if it is completely stopped. */
|
||||
if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
|
||||
kick_start_clock();
|
||||
|
||||
mostek_set_system_time();
|
||||
if (platform_device_register(&m48t59_rtc) < 0)
|
||||
printk(KERN_ERR "Registering RTC device failed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id clock_match[] = {
|
||||
static struct of_device_id __initdata clock_match[] = {
|
||||
{
|
||||
.name = "eeprom",
|
||||
},
|
||||
@ -348,7 +203,7 @@ static struct of_platform_driver clock_driver = {
|
||||
.match_table = clock_match,
|
||||
.probe = clock_probe,
|
||||
.driver = {
|
||||
.name = "clock",
|
||||
.name = "rtc",
|
||||
},
|
||||
};
|
||||
|
||||
@ -364,7 +219,6 @@ static int __init clock_init(void)
|
||||
* need to see the clock registers.
|
||||
*/
|
||||
fs_initcall(clock_init);
|
||||
#endif /* !CONFIG_SUN4 */
|
||||
|
||||
static void __init sbus_time_init(void)
|
||||
{
|
||||
@ -372,51 +226,8 @@ static void __init sbus_time_init(void)
|
||||
BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
|
||||
btfixup();
|
||||
|
||||
if (ARCH_SUN4)
|
||||
sun4_clock_probe();
|
||||
|
||||
sparc_init_timers(timer_interrupt);
|
||||
|
||||
#ifdef CONFIG_SUN4
|
||||
if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {
|
||||
mostek_set_system_time();
|
||||
} else if(idprom->id_machtype == (SM_SUN4 | SM_4_260) ) {
|
||||
/* initialise the intersil on sun4 */
|
||||
unsigned int year, mon, day, hour, min, sec;
|
||||
int temp;
|
||||
struct intersil *iregs;
|
||||
|
||||
iregs=intersil_clock;
|
||||
if(!iregs) {
|
||||
prom_printf("Something wrong, clock regs not mapped yet.\n");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
|
||||
disable_pil_irq(10);
|
||||
intersil_stop(iregs);
|
||||
intersil_read_intr(intersil_clock, temp);
|
||||
|
||||
temp = iregs->clk.int_csec;
|
||||
|
||||
sec = iregs->clk.int_sec;
|
||||
min = iregs->clk.int_min;
|
||||
hour = iregs->clk.int_hour;
|
||||
day = iregs->clk.int_day;
|
||||
mon = iregs->clk.int_month;
|
||||
year = MSTK_CVT_YEAR(iregs->clk.int_year);
|
||||
|
||||
enable_pil_irq(10);
|
||||
intersil_start(iregs);
|
||||
|
||||
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
|
||||
xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
|
||||
set_normalized_timespec(&wall_to_monotonic,
|
||||
-xtime.tv_sec, -xtime.tv_nsec);
|
||||
printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
|
||||
local_irq_enable();
|
||||
}
|
||||
@ -522,80 +333,15 @@ static int sbus_do_settimeofday(struct timespec *tv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* BUG: This routine does not handle hour overflow properly; it just
|
||||
* sets the minutes. Usually you won't notice until after reboot!
|
||||
*/
|
||||
static int set_rtc_mmss(unsigned long nowtime)
|
||||
static int set_rtc_mmss(unsigned long secs)
|
||||
{
|
||||
int real_seconds, real_minutes, mostek_minutes;
|
||||
struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
|
||||
unsigned long flags;
|
||||
#ifdef CONFIG_SUN4
|
||||
struct intersil *iregs = intersil_clock;
|
||||
int temp;
|
||||
#endif
|
||||
struct rtc_device *rtc = rtc_class_open("rtc0");
|
||||
int err = -1;
|
||||
|
||||
/* Not having a register set can lead to trouble. */
|
||||
if (!regs) {
|
||||
#ifdef CONFIG_SUN4
|
||||
if(!iregs)
|
||||
return -1;
|
||||
else {
|
||||
temp = iregs->clk.int_csec;
|
||||
|
||||
mostek_minutes = iregs->clk.int_min;
|
||||
|
||||
real_seconds = nowtime % 60;
|
||||
real_minutes = nowtime / 60;
|
||||
if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
|
||||
real_minutes += 30; /* correct for half hour time zone */
|
||||
real_minutes %= 60;
|
||||
|
||||
if (abs(real_minutes - mostek_minutes) < 30) {
|
||||
intersil_stop(iregs);
|
||||
iregs->clk.int_sec=real_seconds;
|
||||
iregs->clk.int_min=real_minutes;
|
||||
intersil_start(iregs);
|
||||
} else {
|
||||
printk(KERN_WARNING
|
||||
"set_rtc_mmss: can't update from %d to %d\n",
|
||||
mostek_minutes, real_minutes);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (rtc) {
|
||||
err = rtc_set_mmss(rtc, secs);
|
||||
rtc_class_close(rtc);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&mostek_lock, flags);
|
||||
/* Read the current RTC minutes. */
|
||||
regs->creg |= MSTK_CREG_READ;
|
||||
mostek_minutes = MSTK_REG_MIN(regs);
|
||||
regs->creg &= ~MSTK_CREG_READ;
|
||||
|
||||
/*
|
||||
* since we're only adjusting minutes and seconds,
|
||||
* don't interfere with hour overflow. This avoids
|
||||
* messing with unknown time zones but requires your
|
||||
* RTC not to be off by more than 15 minutes
|
||||
*/
|
||||
real_seconds = nowtime % 60;
|
||||
real_minutes = nowtime / 60;
|
||||
if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
|
||||
real_minutes += 30; /* correct for half hour time zone */
|
||||
real_minutes %= 60;
|
||||
|
||||
if (abs(real_minutes - mostek_minutes) < 30) {
|
||||
regs->creg |= MSTK_CREG_WRITE;
|
||||
MSTK_SET_REG_SEC(regs,real_seconds);
|
||||
MSTK_SET_REG_MIN(regs,real_minutes);
|
||||
regs->creg &= ~MSTK_CREG_WRITE;
|
||||
spin_unlock_irqrestore(&mostek_lock, flags);
|
||||
return 0;
|
||||
} else {
|
||||
spin_unlock_irqrestore(&mostek_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
@ -43,23 +43,6 @@ void syscall_trace_exit(struct pt_regs *regs)
|
||||
{
|
||||
}
|
||||
|
||||
void sun4m_nmi(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long afsr, afar;
|
||||
|
||||
printk("Aieee: sun4m NMI received!\n");
|
||||
/* XXX HyperSparc hack XXX */
|
||||
__asm__ __volatile__("mov 0x500, %%g1\n\t"
|
||||
"lda [%%g1] 0x4, %0\n\t"
|
||||
"mov 0x600, %%g1\n\t"
|
||||
"lda [%%g1] 0x4, %1\n\t" :
|
||||
"=r" (afsr), "=r" (afar));
|
||||
printk("afsr=%08lx afar=%08lx\n", afsr, afar);
|
||||
printk("you lose buddy boy...\n");
|
||||
show_regs(regs);
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
void sun4d_nmi(struct pt_regs *regs)
|
||||
{
|
||||
printk("Aieee: sun4d NMI received!\n");
|
||||
|
@ -3,13 +3,8 @@
|
||||
|
||||
EXTRA_AFLAGS := -ansi
|
||||
|
||||
obj-y := fault.o init.o loadmmu.o generic.o extable.o btfixup.o
|
||||
|
||||
ifeq ($(CONFIG_SUN4),y)
|
||||
obj-y += nosrmmu.o
|
||||
else
|
||||
obj-y += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
|
||||
endif
|
||||
obj-y := fault.o init.o loadmmu.o generic.o extable.o btfixup.o \
|
||||
srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
|
||||
|
||||
ifdef CONFIG_HIGHMEM
|
||||
obj-y += highmem.o
|
||||
|
@ -20,11 +20,7 @@
|
||||
|
||||
extern char *srmmu_name;
|
||||
static char version[] __initdata = "Boot time fixup v1.6. 4/Mar/98 Jakub Jelinek (jj@ultra.linux.cz). Patching kernel for ";
|
||||
#ifdef CONFIG_SUN4
|
||||
static char str_sun4c[] __initdata = "sun4\n";
|
||||
#else
|
||||
static char str_sun4c[] __initdata = "sun4c\n";
|
||||
#endif
|
||||
static char str_srmmu[] __initdata = "srmmu[%s]/";
|
||||
static char str_iommu[] __initdata = "iommu\n";
|
||||
static char str_iounit[] __initdata = "io-unit\n";
|
||||
@ -86,7 +82,7 @@ void __init btfixup(void)
|
||||
if (!visited) {
|
||||
visited++;
|
||||
printk(version);
|
||||
if (ARCH_SUN4C_SUN4)
|
||||
if (ARCH_SUN4C)
|
||||
printk(str_sun4c);
|
||||
else {
|
||||
printk(str_srmmu, srmmu_name);
|
||||
|
@ -191,7 +191,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
|
||||
* only copy the information from the master page table,
|
||||
* nothing more.
|
||||
*/
|
||||
if (!ARCH_SUN4C_SUN4 && address >= TASK_SIZE)
|
||||
if (!ARCH_SUN4C && address >= TASK_SIZE)
|
||||
goto vmalloc_fault;
|
||||
|
||||
info.si_code = SEGV_MAPERR;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/poison.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/vac-ops.h>
|
||||
@ -480,6 +481,7 @@ void free_initmem (void)
|
||||
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
|
||||
struct page *p;
|
||||
|
||||
memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
|
||||
p = virt_to_page(addr);
|
||||
|
||||
ClearPageReserved(p);
|
||||
@ -488,20 +490,26 @@ void free_initmem (void)
|
||||
totalram_pages++;
|
||||
num_physpages++;
|
||||
}
|
||||
printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
|
||||
printk(KERN_INFO "Freeing unused kernel memory: %dk freed\n",
|
||||
(&__init_end - &__init_begin) >> 10);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
void free_initrd_mem(unsigned long start, unsigned long end)
|
||||
{
|
||||
if (start < end)
|
||||
printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
|
||||
printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
|
||||
(end - start) >> 10);
|
||||
for (; start < end; start += PAGE_SIZE) {
|
||||
struct page *p = virt_to_page(start);
|
||||
struct page *p;
|
||||
|
||||
memset((void *)start, POISON_FREE_INITMEM, PAGE_SIZE);
|
||||
p = virt_to_page(start);
|
||||
|
||||
ClearPageReserved(p);
|
||||
init_page_count(p);
|
||||
__free_page(p);
|
||||
totalram_pages++;
|
||||
num_physpages++;
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,11 @@
|
||||
#include <linux/highmem.h> /* pte_offset_map => kmap_atomic */
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/sbus.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/io-unit.h>
|
||||
#include <asm/mxcc.h>
|
||||
@ -34,13 +35,10 @@
|
||||
#define IOPERM (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
|
||||
#define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
|
||||
|
||||
void __init
|
||||
iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
|
||||
static void __init iounit_iommu_init(struct of_device *op)
|
||||
{
|
||||
iopte_t *xpt, *xptend;
|
||||
struct iounit_struct *iounit;
|
||||
struct linux_prom_registers iommu_promregs[PROMREG_MAX];
|
||||
struct resource r;
|
||||
iopte_t *xpt, *xptend;
|
||||
|
||||
iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
|
||||
if (!iounit) {
|
||||
@ -55,18 +53,13 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
|
||||
iounit->rotor[1] = IOUNIT_BMAP2_START;
|
||||
iounit->rotor[2] = IOUNIT_BMAPM_START;
|
||||
|
||||
xpt = NULL;
|
||||
if(prom_getproperty(sbi_node, "reg", (void *) iommu_promregs,
|
||||
sizeof(iommu_promregs)) != -1) {
|
||||
prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3);
|
||||
memset(&r, 0, sizeof(r));
|
||||
r.flags = iommu_promregs[2].which_io;
|
||||
r.start = iommu_promregs[2].phys_addr;
|
||||
xpt = (iopte_t *) sbus_ioremap(&r, 0, PAGE_SIZE * 16, "XPT");
|
||||
xpt = of_ioremap(&op->resource[2], 0, PAGE_SIZE * 16, "XPT");
|
||||
if (!xpt) {
|
||||
prom_printf("SUN4D: Cannot map External Page Table.");
|
||||
prom_halt();
|
||||
}
|
||||
if(!xpt) panic("Cannot map External Page Table.");
|
||||
|
||||
sbus->ofdev.dev.archdata.iommu = iounit;
|
||||
op->dev.archdata.iommu = iounit;
|
||||
iounit->page_table = xpt;
|
||||
spin_lock_init(&iounit->lock);
|
||||
|
||||
@ -75,6 +68,25 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
|
||||
iopte_val(*xpt++) = 0;
|
||||
}
|
||||
|
||||
static int __init iounit_init(void)
|
||||
{
|
||||
extern void sun4d_init_sbi_irq(void);
|
||||
struct device_node *dp;
|
||||
|
||||
for_each_node_by_name(dp, "sbi") {
|
||||
struct of_device *op = of_find_device_by_node(dp);
|
||||
|
||||
iounit_iommu_init(op);
|
||||
of_propagate_archdata(op);
|
||||
}
|
||||
|
||||
sun4d_init_sbi_irq();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
subsys_initcall(iounit_init);
|
||||
|
||||
/* One has to hold iounit->lock to call this */
|
||||
static unsigned long iounit_get_area(struct iounit_struct *iounit, unsigned long vaddr, int size)
|
||||
{
|
||||
@ -124,10 +136,10 @@ nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus *sbus)
|
||||
static __u32 iounit_get_scsi_one(struct device *dev, char *vaddr, unsigned long len)
|
||||
{
|
||||
struct iounit_struct *iounit = dev->archdata.iommu;
|
||||
unsigned long ret, flags;
|
||||
struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
|
||||
|
||||
spin_lock_irqsave(&iounit->lock, flags);
|
||||
ret = iounit_get_area(iounit, (unsigned long)vaddr, len);
|
||||
@ -135,10 +147,10 @@ static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
|
||||
static void iounit_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
|
||||
{
|
||||
struct iounit_struct *iounit = dev->archdata.iommu;
|
||||
unsigned long flags;
|
||||
struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
|
||||
|
||||
/* FIXME: Cache some resolved pages - often several sg entries are to the same page */
|
||||
spin_lock_irqsave(&iounit->lock, flags);
|
||||
@ -151,10 +163,10 @@ static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus
|
||||
spin_unlock_irqrestore(&iounit->lock, flags);
|
||||
}
|
||||
|
||||
static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
|
||||
static void iounit_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len)
|
||||
{
|
||||
struct iounit_struct *iounit = dev->archdata.iommu;
|
||||
unsigned long flags;
|
||||
struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
|
||||
|
||||
spin_lock_irqsave(&iounit->lock, flags);
|
||||
len = ((vaddr & ~PAGE_MASK) + len + (PAGE_SIZE-1)) >> PAGE_SHIFT;
|
||||
@ -165,11 +177,11 @@ static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_
|
||||
spin_unlock_irqrestore(&iounit->lock, flags);
|
||||
}
|
||||
|
||||
static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
|
||||
static void iounit_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
|
||||
{
|
||||
struct iounit_struct *iounit = dev->archdata.iommu;
|
||||
unsigned long flags;
|
||||
unsigned long vaddr, len;
|
||||
struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
|
||||
|
||||
spin_lock_irqsave(&iounit->lock, flags);
|
||||
while (sz != 0) {
|
||||
@ -185,12 +197,12 @@ static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SBUS
|
||||
static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, int len)
|
||||
static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, __u32 addr, int len)
|
||||
{
|
||||
struct iounit_struct *iounit = dev->archdata.iommu;
|
||||
unsigned long page, end;
|
||||
pgprot_t dvma_prot;
|
||||
iopte_t *iopte;
|
||||
struct sbus_bus *sbus;
|
||||
|
||||
*pba = addr;
|
||||
|
||||
@ -212,12 +224,8 @@ static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, in
|
||||
|
||||
i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
|
||||
|
||||
for_each_sbus(sbus) {
|
||||
struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
|
||||
|
||||
iopte = (iopte_t *)(iounit->page_table + i);
|
||||
*iopte = MKIOPTE(__pa(page));
|
||||
}
|
||||
iopte = (iopte_t *)(iounit->page_table + i);
|
||||
*iopte = MKIOPTE(__pa(page));
|
||||
}
|
||||
addr += PAGE_SIZE;
|
||||
va += PAGE_SIZE;
|
||||
@ -228,23 +236,10 @@ static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, in
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iounit_unmap_dma_area(unsigned long addr, int len)
|
||||
static void iounit_unmap_dma_area(struct device *dev, unsigned long addr, int len)
|
||||
{
|
||||
/* XXX Somebody please fill this in */
|
||||
}
|
||||
|
||||
/* XXX We do not pass sbus device here, bad. */
|
||||
static struct page *iounit_translate_dvma(unsigned long addr)
|
||||
{
|
||||
struct sbus_bus *sbus = sbus_root; /* They are all the same */
|
||||
struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
|
||||
int i;
|
||||
iopte_t *iopte;
|
||||
|
||||
i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
|
||||
iopte = (iopte_t *)(iounit->page_table + i);
|
||||
return pfn_to_page(iopte_val(*iopte) >> (PAGE_SHIFT-4)); /* XXX sun4d guru, help */
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *iounit_lockarea(char *vaddr, unsigned long len)
|
||||
@ -271,54 +266,5 @@ void __init ld_mmu_iounit(void)
|
||||
#ifdef CONFIG_SBUS
|
||||
BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(mmu_translate_dvma, iounit_translate_dvma, BTFIXUPCALL_NORM);
|
||||
#endif
|
||||
}
|
||||
|
||||
__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
|
||||
{
|
||||
int i, j, k, npages;
|
||||
unsigned long rotor, scan, limit;
|
||||
unsigned long flags;
|
||||
__u32 ret;
|
||||
struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
|
||||
|
||||
npages = (size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
|
||||
i = 0x0213;
|
||||
spin_lock_irqsave(&iounit->lock, flags);
|
||||
next: j = (i & 15);
|
||||
rotor = iounit->rotor[j - 1];
|
||||
limit = iounit->limit[j];
|
||||
scan = rotor;
|
||||
nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
|
||||
if (scan + npages > limit) {
|
||||
if (limit != rotor) {
|
||||
limit = rotor;
|
||||
scan = iounit->limit[j - 1];
|
||||
goto nexti;
|
||||
}
|
||||
i >>= 4;
|
||||
if (!(i & 15))
|
||||
panic("iounit_map_dma_init: Couldn't find free iopte slots for %d bytes\n", size);
|
||||
goto next;
|
||||
}
|
||||
for (k = 1, scan++; k < npages; k++)
|
||||
if (test_bit(scan++, iounit->bmap))
|
||||
goto nexti;
|
||||
iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
|
||||
scan -= npages;
|
||||
ret = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT);
|
||||
for (k = 0; k < npages; k++, scan++)
|
||||
set_bit(scan, iounit->bmap);
|
||||
spin_unlock_irqrestore(&iounit->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
|
||||
{
|
||||
int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
|
||||
struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
|
||||
|
||||
iounit->page_table[scan] = MKIOPTE(__pa(((unsigned long)addr) & PAGE_MASK));
|
||||
return vaddr + (((unsigned long)addr) & ~PAGE_MASK);
|
||||
}
|
||||
|
@ -13,10 +13,11 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/highmem.h> /* pte_offset_map => kmap_atomic */
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/sbus.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mxcc.h>
|
||||
#include <asm/mbus.h>
|
||||
@ -55,30 +56,21 @@ static pgprot_t dvma_prot; /* Consistent mapping pte flags */
|
||||
#define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID)
|
||||
#define MKIOPTE(pfn, perm) (((((pfn)<<8) & IOPTE_PAGE) | (perm)) & ~IOPTE_WAZ)
|
||||
|
||||
void __init
|
||||
iommu_init(int iommund, struct sbus_bus *sbus)
|
||||
static void __init sbus_iommu_init(struct of_device *op)
|
||||
{
|
||||
unsigned int impl, vers;
|
||||
unsigned long tmp;
|
||||
struct iommu_struct *iommu;
|
||||
struct linux_prom_registers iommu_promregs[PROMREG_MAX];
|
||||
struct resource r;
|
||||
unsigned int impl, vers;
|
||||
unsigned long *bitmap;
|
||||
unsigned long tmp;
|
||||
|
||||
iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
|
||||
if (!iommu) {
|
||||
prom_printf("Unable to allocate iommu structure\n");
|
||||
prom_halt();
|
||||
}
|
||||
iommu->regs = NULL;
|
||||
if (prom_getproperty(iommund, "reg", (void *) iommu_promregs,
|
||||
sizeof(iommu_promregs)) != -1) {
|
||||
memset(&r, 0, sizeof(r));
|
||||
r.flags = iommu_promregs[0].which_io;
|
||||
r.start = iommu_promregs[0].phys_addr;
|
||||
iommu->regs = (struct iommu_regs *)
|
||||
sbus_ioremap(&r, 0, PAGE_SIZE * 3, "iommu_regs");
|
||||
}
|
||||
|
||||
iommu->regs = of_ioremap(&op->resource[0], 0, PAGE_SIZE * 3,
|
||||
"iommu_regs");
|
||||
if (!iommu->regs) {
|
||||
prom_printf("Cannot map IOMMU registers\n");
|
||||
prom_halt();
|
||||
@ -128,13 +120,29 @@ iommu_init(int iommund, struct sbus_bus *sbus)
|
||||
else
|
||||
iommu->usemap.num_colors = 1;
|
||||
|
||||
printk("IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n",
|
||||
impl, vers, iommu->page_table,
|
||||
(int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES);
|
||||
printk(KERN_INFO "IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n",
|
||||
impl, vers, iommu->page_table,
|
||||
(int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES);
|
||||
|
||||
sbus->ofdev.dev.archdata.iommu = iommu;
|
||||
op->dev.archdata.iommu = iommu;
|
||||
}
|
||||
|
||||
static int __init iommu_init(void)
|
||||
{
|
||||
struct device_node *dp;
|
||||
|
||||
for_each_node_by_name(dp, "iommu") {
|
||||
struct of_device *op = of_find_device_by_node(dp);
|
||||
|
||||
sbus_iommu_init(op);
|
||||
of_propagate_archdata(op);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
subsys_initcall(iommu_init);
|
||||
|
||||
/* This begs to be btfixup-ed by srmmu. */
|
||||
/* Flush the iotlb entries to ram. */
|
||||
/* This could be better if we didn't have to flush whole pages. */
|
||||
@ -164,9 +172,9 @@ static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte)
|
||||
}
|
||||
}
|
||||
|
||||
static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus)
|
||||
static u32 iommu_get_one(struct device *dev, struct page *page, int npages)
|
||||
{
|
||||
struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu;
|
||||
struct iommu_struct *iommu = dev->archdata.iommu;
|
||||
int ioptex;
|
||||
iopte_t *iopte, *iopte0;
|
||||
unsigned int busa, busa0;
|
||||
@ -194,8 +202,7 @@ static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus)
|
||||
return busa0;
|
||||
}
|
||||
|
||||
static u32 iommu_get_scsi_one(char *vaddr, unsigned int len,
|
||||
struct sbus_bus *sbus)
|
||||
static u32 iommu_get_scsi_one(struct device *dev, char *vaddr, unsigned int len)
|
||||
{
|
||||
unsigned long off;
|
||||
int npages;
|
||||
@ -205,22 +212,22 @@ static u32 iommu_get_scsi_one(char *vaddr, unsigned int len,
|
||||
off = (unsigned long)vaddr & ~PAGE_MASK;
|
||||
npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT;
|
||||
page = virt_to_page((unsigned long)vaddr & PAGE_MASK);
|
||||
busa = iommu_get_one(page, npages, sbus);
|
||||
busa = iommu_get_one(dev, page, npages);
|
||||
return busa + off;
|
||||
}
|
||||
|
||||
static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
|
||||
static __u32 iommu_get_scsi_one_noflush(struct device *dev, char *vaddr, unsigned long len)
|
||||
{
|
||||
return iommu_get_scsi_one(vaddr, len, sbus);
|
||||
return iommu_get_scsi_one(dev, vaddr, len);
|
||||
}
|
||||
|
||||
static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
|
||||
static __u32 iommu_get_scsi_one_gflush(struct device *dev, char *vaddr, unsigned long len)
|
||||
{
|
||||
flush_page_for_dma(0);
|
||||
return iommu_get_scsi_one(vaddr, len, sbus);
|
||||
return iommu_get_scsi_one(dev, vaddr, len);
|
||||
}
|
||||
|
||||
static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
|
||||
static __u32 iommu_get_scsi_one_pflush(struct device *dev, char *vaddr, unsigned long len)
|
||||
{
|
||||
unsigned long page = ((unsigned long) vaddr) & PAGE_MASK;
|
||||
|
||||
@ -228,23 +235,23 @@ static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sb
|
||||
flush_page_for_dma(page);
|
||||
page += PAGE_SIZE;
|
||||
}
|
||||
return iommu_get_scsi_one(vaddr, len, sbus);
|
||||
return iommu_get_scsi_one(dev, vaddr, len);
|
||||
}
|
||||
|
||||
static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
|
||||
static void iommu_get_scsi_sgl_noflush(struct device *dev, struct scatterlist *sg, int sz)
|
||||
{
|
||||
int n;
|
||||
|
||||
while (sz != 0) {
|
||||
--sz;
|
||||
n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
|
||||
sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
|
||||
sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
|
||||
sg->dvma_length = (__u32) sg->length;
|
||||
sg = sg_next(sg);
|
||||
}
|
||||
}
|
||||
|
||||
static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
|
||||
static void iommu_get_scsi_sgl_gflush(struct device *dev, struct scatterlist *sg, int sz)
|
||||
{
|
||||
int n;
|
||||
|
||||
@ -252,13 +259,13 @@ static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbu
|
||||
while (sz != 0) {
|
||||
--sz;
|
||||
n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
|
||||
sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
|
||||
sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
|
||||
sg->dvma_length = (__u32) sg->length;
|
||||
sg = sg_next(sg);
|
||||
}
|
||||
}
|
||||
|
||||
static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
|
||||
static void iommu_get_scsi_sgl_pflush(struct device *dev, struct scatterlist *sg, int sz)
|
||||
{
|
||||
unsigned long page, oldpage = 0;
|
||||
int n, i;
|
||||
@ -283,15 +290,15 @@ static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbu
|
||||
}
|
||||
}
|
||||
|
||||
sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
|
||||
sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
|
||||
sg->dvma_length = (__u32) sg->length;
|
||||
sg = sg_next(sg);
|
||||
}
|
||||
}
|
||||
|
||||
static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus)
|
||||
static void iommu_release_one(struct device *dev, u32 busa, int npages)
|
||||
{
|
||||
struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu;
|
||||
struct iommu_struct *iommu = dev->archdata.iommu;
|
||||
int ioptex;
|
||||
int i;
|
||||
|
||||
@ -305,17 +312,17 @@ static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus)
|
||||
bit_map_clear(&iommu->usemap, ioptex, npages);
|
||||
}
|
||||
|
||||
static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
|
||||
static void iommu_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len)
|
||||
{
|
||||
unsigned long off;
|
||||
int npages;
|
||||
|
||||
off = vaddr & ~PAGE_MASK;
|
||||
npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT;
|
||||
iommu_release_one(vaddr & PAGE_MASK, npages, sbus);
|
||||
iommu_release_one(dev, vaddr & PAGE_MASK, npages);
|
||||
}
|
||||
|
||||
static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
|
||||
static void iommu_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
|
||||
{
|
||||
int n;
|
||||
|
||||
@ -323,18 +330,18 @@ static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_b
|
||||
--sz;
|
||||
|
||||
n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
|
||||
iommu_release_one(sg->dvma_address & PAGE_MASK, n, sbus);
|
||||
iommu_release_one(dev, sg->dvma_address & PAGE_MASK, n);
|
||||
sg->dvma_address = 0x21212121;
|
||||
sg = sg_next(sg);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SBUS
|
||||
static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
|
||||
unsigned long addr, int len)
|
||||
static int iommu_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va,
|
||||
unsigned long addr, int len)
|
||||
{
|
||||
struct iommu_struct *iommu = dev->archdata.iommu;
|
||||
unsigned long page, end;
|
||||
struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
|
||||
iopte_t *iopte = iommu->page_table;
|
||||
iopte_t *first;
|
||||
int ioptex;
|
||||
@ -397,9 +404,9 @@ static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iommu_unmap_dma_area(unsigned long busa, int len)
|
||||
static void iommu_unmap_dma_area(struct device *dev, unsigned long busa, int len)
|
||||
{
|
||||
struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
|
||||
struct iommu_struct *iommu = dev->archdata.iommu;
|
||||
iopte_t *iopte = iommu->page_table;
|
||||
unsigned long end;
|
||||
int ioptex = (busa - iommu->start) >> PAGE_SHIFT;
|
||||
@ -417,15 +424,6 @@ static void iommu_unmap_dma_area(unsigned long busa, int len)
|
||||
iommu_invalidate(iommu->regs);
|
||||
bit_map_clear(&iommu->usemap, ioptex, len >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
static struct page *iommu_translate_dvma(unsigned long busa)
|
||||
{
|
||||
struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
|
||||
iopte_t *iopte = iommu->page_table;
|
||||
|
||||
iopte += ((busa - iommu->start) >> PAGE_SHIFT);
|
||||
return pfn_to_page((iopte_val(*iopte) & IOPTE_PAGE) >> (PAGE_SHIFT-4));
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *iommu_lockarea(char *vaddr, unsigned long len)
|
||||
@ -461,7 +459,6 @@ void __init ld_mmu_iommu(void)
|
||||
#ifdef CONFIG_SBUS
|
||||
BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(mmu_unmap_dma_area, iommu_unmap_dma_area, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(mmu_translate_dvma, iommu_translate_dvma, BTFIXUPCALL_NORM);
|
||||
#endif
|
||||
|
||||
if (viking_mxcc_present || srmmu_modtype == HyperSparc) {
|
||||
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* nosrmmu.c: This file is a bunch of dummies for sun4 compiles,
|
||||
* so that it does not need srmmu and avoid ifdefs.
|
||||
*
|
||||
* Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/mbus.h>
|
||||
#include <asm/sbus.h>
|
||||
|
||||
static char shouldnothappen[] __initdata = "SUN4 kernel can only run on SUN4\n";
|
||||
|
||||
enum mbus_module srmmu_modtype;
|
||||
void *srmmu_nocache_pool;
|
||||
|
||||
int vac_cache_size = 0;
|
||||
|
||||
static void __init should_not_happen(void)
|
||||
{
|
||||
prom_printf(shouldnothappen);
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
void __init srmmu_frob_mem_map(unsigned long start_mem)
|
||||
{
|
||||
should_not_happen();
|
||||
}
|
||||
|
||||
unsigned long __init srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
|
||||
{
|
||||
should_not_happen();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init ld_mmu_srmmu(void)
|
||||
{
|
||||
should_not_happen();
|
||||
}
|
||||
|
||||
void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly)
|
||||
{
|
||||
}
|
||||
|
||||
void srmmu_unmapioaddr(unsigned long virt_addr)
|
||||
{
|
||||
}
|
||||
|
||||
__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -31,7 +31,6 @@
|
||||
#include <asm/mbus.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/sbus.h>
|
||||
#include <asm/asi.h>
|
||||
#include <asm/msi.h>
|
||||
#include <asm/mmu_context.h>
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/openprom.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/sun4paddr.h>
|
||||
#include <asm/highmem.h>
|
||||
#include <asm/btfixup.h>
|
||||
#include <asm/cacheflush.h>
|
||||
@ -52,15 +51,11 @@ extern int num_segmaps, num_contexts;
|
||||
|
||||
extern unsigned long page_kernel;
|
||||
|
||||
#ifdef CONFIG_SUN4
|
||||
#define SUN4C_VAC_SIZE sun4c_vacinfo.num_bytes
|
||||
#else
|
||||
/* That's it, we prom_halt() on sun4c if the cache size is something other than 65536.
|
||||
* So let's save some cycles and just use that everywhere except for that bootup
|
||||
* sanity check.
|
||||
*/
|
||||
#define SUN4C_VAC_SIZE 65536
|
||||
#endif
|
||||
|
||||
#define SUN4C_KERNEL_BUCKETS 32
|
||||
|
||||
@ -285,75 +280,32 @@ void __init sun4c_probe_vac(void)
|
||||
{
|
||||
sun4c_disable_vac();
|
||||
|
||||
if (ARCH_SUN4) {
|
||||
switch (idprom->id_machtype) {
|
||||
|
||||
case (SM_SUN4|SM_4_110):
|
||||
sun4c_vacinfo.type = VAC_NONE;
|
||||
sun4c_vacinfo.num_bytes = 0;
|
||||
sun4c_vacinfo.linesize = 0;
|
||||
sun4c_vacinfo.do_hwflushes = 0;
|
||||
prom_printf("No VAC. Get some bucks and buy a real computer.");
|
||||
prom_halt();
|
||||
break;
|
||||
|
||||
case (SM_SUN4|SM_4_260):
|
||||
sun4c_vacinfo.type = VAC_WRITE_BACK;
|
||||
sun4c_vacinfo.num_bytes = 128 * 1024;
|
||||
sun4c_vacinfo.linesize = 16;
|
||||
sun4c_vacinfo.do_hwflushes = 0;
|
||||
break;
|
||||
|
||||
case (SM_SUN4|SM_4_330):
|
||||
sun4c_vacinfo.type = VAC_WRITE_THROUGH;
|
||||
sun4c_vacinfo.num_bytes = 128 * 1024;
|
||||
sun4c_vacinfo.linesize = 16;
|
||||
sun4c_vacinfo.do_hwflushes = 0;
|
||||
break;
|
||||
|
||||
case (SM_SUN4|SM_4_470):
|
||||
sun4c_vacinfo.type = VAC_WRITE_BACK;
|
||||
sun4c_vacinfo.num_bytes = 128 * 1024;
|
||||
sun4c_vacinfo.linesize = 32;
|
||||
sun4c_vacinfo.do_hwflushes = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
prom_printf("Cannot initialize VAC - weird sun4 model idprom->id_machtype = %d", idprom->id_machtype);
|
||||
prom_halt();
|
||||
};
|
||||
if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
|
||||
(idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
|
||||
/* PROM on SS1 lacks this info, to be super safe we
|
||||
* hard code it here since this arch is cast in stone.
|
||||
*/
|
||||
sun4c_vacinfo.num_bytes = 65536;
|
||||
sun4c_vacinfo.linesize = 16;
|
||||
} else {
|
||||
sun4c_vacinfo.type = VAC_WRITE_THROUGH;
|
||||
sun4c_vacinfo.num_bytes =
|
||||
prom_getintdefault(prom_root_node, "vac-size", 65536);
|
||||
sun4c_vacinfo.linesize =
|
||||
prom_getintdefault(prom_root_node, "vac-linesize", 16);
|
||||
}
|
||||
sun4c_vacinfo.do_hwflushes =
|
||||
prom_getintdefault(prom_root_node, "vac-hwflush", 0);
|
||||
|
||||
if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
|
||||
(idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
|
||||
/* PROM on SS1 lacks this info, to be super safe we
|
||||
* hard code it here since this arch is cast in stone.
|
||||
*/
|
||||
sun4c_vacinfo.num_bytes = 65536;
|
||||
sun4c_vacinfo.linesize = 16;
|
||||
} else {
|
||||
sun4c_vacinfo.num_bytes =
|
||||
prom_getintdefault(prom_root_node, "vac-size", 65536);
|
||||
sun4c_vacinfo.linesize =
|
||||
prom_getintdefault(prom_root_node, "vac-linesize", 16);
|
||||
}
|
||||
if (sun4c_vacinfo.do_hwflushes == 0)
|
||||
sun4c_vacinfo.do_hwflushes =
|
||||
prom_getintdefault(prom_root_node, "vac-hwflush", 0);
|
||||
prom_getintdefault(prom_root_node, "vac_hwflush", 0);
|
||||
|
||||
if (sun4c_vacinfo.do_hwflushes == 0)
|
||||
sun4c_vacinfo.do_hwflushes =
|
||||
prom_getintdefault(prom_root_node, "vac_hwflush", 0);
|
||||
|
||||
if (sun4c_vacinfo.num_bytes != 65536) {
|
||||
prom_printf("WEIRD Sun4C VAC cache size, "
|
||||
"tell sparclinux@vger.kernel.org");
|
||||
prom_halt();
|
||||
}
|
||||
if (sun4c_vacinfo.num_bytes != 65536) {
|
||||
prom_printf("WEIRD Sun4C VAC cache size, "
|
||||
"tell sparclinux@vger.kernel.org");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
sun4c_vacinfo.num_lines =
|
||||
(sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
|
||||
switch (sun4c_vacinfo.linesize) {
|
||||
case 16:
|
||||
sun4c_vacinfo.log2lsize = 4;
|
||||
@ -447,49 +399,18 @@ static void __init patch_kernel_fault_handler(void)
|
||||
|
||||
static void __init sun4c_probe_mmu(void)
|
||||
{
|
||||
if (ARCH_SUN4) {
|
||||
switch (idprom->id_machtype) {
|
||||
case (SM_SUN4|SM_4_110):
|
||||
prom_printf("No support for 4100 yet\n");
|
||||
prom_halt();
|
||||
num_segmaps = 256;
|
||||
num_contexts = 8;
|
||||
break;
|
||||
|
||||
case (SM_SUN4|SM_4_260):
|
||||
/* should be 512 segmaps. when it get fixed */
|
||||
num_segmaps = 256;
|
||||
num_contexts = 16;
|
||||
break;
|
||||
|
||||
case (SM_SUN4|SM_4_330):
|
||||
num_segmaps = 256;
|
||||
num_contexts = 16;
|
||||
break;
|
||||
|
||||
case (SM_SUN4|SM_4_470):
|
||||
/* should be 1024 segmaps. when it get fixed */
|
||||
num_segmaps = 256;
|
||||
num_contexts = 64;
|
||||
break;
|
||||
default:
|
||||
prom_printf("Invalid SUN4 model\n");
|
||||
prom_halt();
|
||||
};
|
||||
if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
|
||||
(idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
|
||||
/* Hardcode these just to be safe, PROM on SS1 does
|
||||
* not have this info available in the root node.
|
||||
*/
|
||||
num_segmaps = 128;
|
||||
num_contexts = 8;
|
||||
} else {
|
||||
if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
|
||||
(idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
|
||||
/* Hardcode these just to be safe, PROM on SS1 does
|
||||
* not have this info available in the root node.
|
||||
*/
|
||||
num_segmaps = 128;
|
||||
num_contexts = 8;
|
||||
} else {
|
||||
num_segmaps =
|
||||
prom_getintdefault(prom_root_node, "mmu-npmg", 128);
|
||||
num_contexts =
|
||||
prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
|
||||
}
|
||||
num_segmaps =
|
||||
prom_getintdefault(prom_root_node, "mmu-npmg", 128);
|
||||
num_contexts =
|
||||
prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
|
||||
}
|
||||
patch_kernel_fault_handler();
|
||||
}
|
||||
@ -501,18 +422,14 @@ void __init sun4c_probe_memerr_reg(void)
|
||||
int node;
|
||||
struct linux_prom_registers regs[1];
|
||||
|
||||
if (ARCH_SUN4) {
|
||||
sun4c_memerr_reg = ioremap(sun4_memreg_physaddr, PAGE_SIZE);
|
||||
} else {
|
||||
node = prom_getchild(prom_root_node);
|
||||
node = prom_searchsiblings(prom_root_node, "memory-error");
|
||||
if (!node)
|
||||
return;
|
||||
if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0)
|
||||
return;
|
||||
/* hmm I think regs[0].which_io is zero here anyways */
|
||||
sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
|
||||
}
|
||||
node = prom_getchild(prom_root_node);
|
||||
node = prom_searchsiblings(prom_root_node, "memory-error");
|
||||
if (!node)
|
||||
return;
|
||||
if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0)
|
||||
return;
|
||||
/* hmm I think regs[0].which_io is zero here anyways */
|
||||
sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
|
||||
}
|
||||
|
||||
static inline void sun4c_init_ss2_cache_bug(void)
|
||||
@ -521,7 +438,6 @@ static inline void sun4c_init_ss2_cache_bug(void)
|
||||
|
||||
if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
|
||||
(idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
|
||||
(idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
|
||||
(idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
|
||||
/* Whee.. */
|
||||
printk("SS2 cache bug detected, uncaching trap table page\n");
|
||||
@ -532,8 +448,8 @@ static inline void sun4c_init_ss2_cache_bug(void)
|
||||
}
|
||||
|
||||
/* Addr is always aligned on a page boundary for us already. */
|
||||
static int sun4c_map_dma_area(dma_addr_t *pba, unsigned long va,
|
||||
unsigned long addr, int len)
|
||||
static int sun4c_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va,
|
||||
unsigned long addr, int len)
|
||||
{
|
||||
unsigned long page, end;
|
||||
|
||||
@ -555,14 +471,7 @@ static int sun4c_map_dma_area(dma_addr_t *pba, unsigned long va,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct page *sun4c_translate_dvma(unsigned long busa)
|
||||
{
|
||||
/* Fortunately for us, bus_addr == uncached_virt in sun4c. */
|
||||
unsigned long pte = sun4c_get_pte(busa);
|
||||
return pfn_to_page(pte & SUN4C_PFN_MASK);
|
||||
}
|
||||
|
||||
static void sun4c_unmap_dma_area(unsigned long busa, int len)
|
||||
static void sun4c_unmap_dma_area(struct device *dev, unsigned long busa, int len)
|
||||
{
|
||||
/* Fortunately for us, bus_addr == uncached_virt in sun4c. */
|
||||
/* XXX Implement this */
|
||||
@ -624,11 +533,7 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
|
||||
{
|
||||
unsigned long vaddr;
|
||||
unsigned char pseg, ctx;
|
||||
#ifdef CONFIG_SUN4
|
||||
/* sun4/110 and 260 have no kadb. */
|
||||
if ((idprom->id_machtype != (SM_SUN4 | SM_4_260)) &&
|
||||
(idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
|
||||
#endif
|
||||
|
||||
for (vaddr = KADB_DEBUGGER_BEGVM;
|
||||
vaddr < LINUX_OPPROM_ENDVM;
|
||||
vaddr += SUN4C_REAL_PGDIR_SIZE) {
|
||||
@ -640,9 +545,7 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
|
||||
fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_SUN4
|
||||
}
|
||||
#endif
|
||||
|
||||
for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
|
||||
pseg = sun4c_get_segmap(vaddr);
|
||||
mmu_entry_pool[pseg].locked = 1;
|
||||
@ -1048,14 +951,10 @@ static struct thread_info *sun4c_alloc_thread_info(void)
|
||||
* so we must flush the cache to guarantee consistency.
|
||||
*/
|
||||
sun4c_flush_page(pages);
|
||||
#ifndef CONFIG_SUN4
|
||||
sun4c_flush_page(pages + PAGE_SIZE);
|
||||
#endif
|
||||
|
||||
sun4c_put_pte(addr, BUCKET_PTE(pages));
|
||||
#ifndef CONFIG_SUN4
|
||||
sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_STACK_USAGE
|
||||
memset((void *)addr, 0, PAGE_SIZE << THREAD_INFO_ORDER);
|
||||
@ -1072,13 +971,11 @@ static void sun4c_free_thread_info(struct thread_info *ti)
|
||||
|
||||
/* We are deleting a mapping, so the flush here is mandatory. */
|
||||
sun4c_flush_page(tiaddr);
|
||||
#ifndef CONFIG_SUN4
|
||||
sun4c_flush_page(tiaddr + PAGE_SIZE);
|
||||
#endif
|
||||
|
||||
sun4c_put_pte(tiaddr, 0);
|
||||
#ifndef CONFIG_SUN4
|
||||
sun4c_put_pte(tiaddr + PAGE_SIZE, 0);
|
||||
#endif
|
||||
|
||||
sun4c_bucket[entry] = BUCKET_EMPTY;
|
||||
if (entry < sun4c_lowbucket_avail)
|
||||
sun4c_lowbucket_avail = entry;
|
||||
@ -1211,7 +1108,7 @@ static void sun4c_unlockarea(char *vaddr, unsigned long size)
|
||||
* by implication and fool the page locking code above
|
||||
* if passed to by mistake.
|
||||
*/
|
||||
static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct sbus_bus *sbus)
|
||||
static __u32 sun4c_get_scsi_one(struct device *dev, char *bufptr, unsigned long len)
|
||||
{
|
||||
unsigned long page;
|
||||
|
||||
@ -1223,7 +1120,7 @@ static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct sbus_bus
|
||||
return (__u32)sun4c_lockarea(bufptr, len);
|
||||
}
|
||||
|
||||
static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
|
||||
static void sun4c_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
|
||||
{
|
||||
while (sz != 0) {
|
||||
--sz;
|
||||
@ -1233,14 +1130,14 @@ static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *
|
||||
}
|
||||
}
|
||||
|
||||
static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct sbus_bus *sbus)
|
||||
static void sun4c_release_scsi_one(struct device *dev, __u32 bufptr, unsigned long len)
|
||||
{
|
||||
if (bufptr < sun4c_iobuffer_start)
|
||||
return; /* On kernel stack or similar, see above */
|
||||
sun4c_unlockarea((char *)bufptr, len);
|
||||
}
|
||||
|
||||
static void sun4c_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
|
||||
static void sun4c_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
|
||||
{
|
||||
while (sz != 0) {
|
||||
--sz;
|
||||
@ -2263,7 +2160,6 @@ void __init ld_mmu_sun4c(void)
|
||||
|
||||
BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(mmu_translate_dvma, sun4c_translate_dvma, BTFIXUPCALL_NORM);
|
||||
|
||||
BTFIXUPSET_CALL(sparc_mapiorange, sun4c_mapiorange, BTFIXUPCALL_NORM);
|
||||
BTFIXUPSET_CALL(sparc_unmapiorange, sun4c_unmapiorange, BTFIXUPCALL_NORM);
|
||||
|
@ -4,5 +4,3 @@
|
||||
|
||||
lib-y := bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \
|
||||
palloc.o ranges.o segment.o console.o printf.o tree.o
|
||||
|
||||
lib-$(CONFIG_SUN4) += sun4prom.o
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user