dect
/
linux-2.6
Archived
13
0
Fork 0

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:
Linus Torvalds 2008-10-12 11:40:55 -07:00
commit 0710483959
233 changed files with 8513 additions and 15254 deletions

View File

@ -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>

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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) */

View File

@ -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

View File

@ -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
}

View File

@ -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);

View File

@ -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 */

View File

@ -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) */

View File

@ -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) */

View File

@ -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) */

View File

@ -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

View File

@ -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) */

View File

@ -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) */

View 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 */

View File

@ -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 && \

View File

@ -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) */

View File

@ -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) */

View File

@ -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;
}

View 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 */

View File

@ -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) */

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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 */

View 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 */

View File

@ -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

View File

@ -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) */

View File

@ -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) */

View File

@ -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;

View File

@ -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>

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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",
},

View File

@ -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.

View File

@ -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>

View File

@ -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) */

View File

@ -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

View File

@ -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

View File

@ -1,6 +0,0 @@
#ifndef _SPARC64_REBOOT_H
#define _SPARC64_REBOOT_H
extern void machine_alt_power_off(void);
#endif /* _SPARC64_REBOOT_H */

View File

@ -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

View File

@ -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

View File

@ -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) */

View File

@ -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) */

View File

@ -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>

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -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) */

View File

@ -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_ */

View File

@ -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)
{

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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 */

View File

@ -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_ */

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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. */

View File

@ -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
View 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
View 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);

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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);

View File

@ -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();

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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:

View File

@ -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();

View File

@ -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);

View File

@ -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. */
}

View File

@ -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

View File

@ -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();

View File

@ -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. */
}

View File

@ -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);

View File

@ -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:
;
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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");

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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++;
}
}

View File

@ -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);
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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>

View File

@ -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);

View File

@ -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