diff --git a/[refs] b/[refs] index 98b56eec33be..df36186b9944 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 06270d5d6aefb46b88bf44a7c5b1b9b3ef352c48 +refs/heads/master: e1e23bb0513520035ec934fa3483507cb6648b7c diff --git a/trunk/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/trunk/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index 87a7c07ab658..b54cb5048dfa 100644 --- a/trunk/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/trunk/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -5073,7 +5073,8 @@ struct _snd_pcm_runtime { with SNDRV_DMA_TYPE_CONTINUOUS type and the snd_dma_continuous_data(GFP_KERNEL) device pointer, where GFP_KERNEL is the kernel allocation flag to - use. + use. For the SBUS, SNDRV_DMA_TYPE_SBUS and + snd_dma_sbus_data(sbus_dev) are used instead. For the PCI scatter-gather buffers, use SNDRV_DMA_TYPE_DEV_SG with snd_dma_pci_data(pci) diff --git a/trunk/Documentation/sparc/sbus_drivers.txt b/trunk/Documentation/sparc/sbus_drivers.txt new file mode 100644 index 000000000000..eb1e28ad8822 --- /dev/null +++ b/trunk/Documentation/sparc/sbus_drivers.txt @@ -0,0 +1,309 @@ + + 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 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. diff --git a/trunk/arch/sparc/Kconfig b/trunk/arch/sparc/Kconfig index 97671dac12a6..a214002114ed 100644 --- a/trunk/arch/sparc/Kconfig +++ b/trunk/arch/sparc/Kconfig @@ -20,11 +20,6 @@ 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 @@ -74,9 +69,6 @@ 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 @@ -212,6 +204,17 @@ 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 @@ -224,6 +227,11 @@ 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 @@ -255,7 +263,9 @@ source "net/Kconfig" source "drivers/Kconfig" +if !SUN4 source "drivers/sbus/char/Kconfig" +endif # This one must be before the filesystem configs. -DaveM diff --git a/trunk/arch/sparc/include/asm/Kbuild b/trunk/arch/sparc/include/asm/Kbuild index 2ba7183bc1f0..a5f0ce734ff7 100644 --- a/trunk/arch/sparc/include/asm/Kbuild +++ b/trunk/arch/sparc/include/asm/Kbuild @@ -22,6 +22,7 @@ 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 @@ -40,4 +41,5 @@ 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 diff --git a/trunk/arch/sparc/include/asm/asmmacro.h b/trunk/arch/sparc/include/asm/asmmacro.h index a995bf8aba3f..a619a4d97aae 100644 --- a/trunk/arch/sparc/include/asm/asmmacro.h +++ b/trunk/arch/sparc/include/asm/asmmacro.h @@ -34,7 +34,12 @@ /* 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) */ diff --git a/trunk/arch/sparc/include/asm/bpp.h b/trunk/arch/sparc/include/asm/bpp.h new file mode 100644 index 000000000000..31f515e499a7 --- /dev/null +++ b/trunk/arch/sparc/include/asm/bpp.h @@ -0,0 +1,73 @@ +#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 + +/* + * 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 diff --git a/trunk/arch/sparc/include/asm/bugs.h b/trunk/arch/sparc/include/asm/bugs.h index 61d86bbbe2b2..e179bc12f64a 100644 --- a/trunk/arch/sparc/include/asm/bugs.h +++ b/trunk/arch/sparc/include/asm/bugs.h @@ -7,6 +7,10 @@ #include #endif +#ifdef CONFIG_SPARC64 +#include +#endif + extern unsigned long loops_per_jiffy; static void __init check_bugs(void) @@ -14,4 +18,7 @@ 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 } diff --git a/trunk/arch/sparc/include/asm/cpudata_64.h b/trunk/arch/sparc/include/asm/cpudata_64.h index 7da7c13d23c4..532975ecfe10 100644 --- a/trunk/arch/sparc/include/asm/cpudata_64.h +++ b/trunk/arch/sparc/include/asm/cpudata_64.h @@ -86,6 +86,7 @@ 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); diff --git a/trunk/arch/sparc/include/asm/dma-mapping_32.h b/trunk/arch/sparc/include/asm/dma-mapping_32.h index 8a57ea0573e6..f3a641e6b2c8 100644 --- a/trunk/arch/sparc/include/asm/dma-mapping_32.h +++ b/trunk/arch/sparc/include/asm/dma-mapping_32.h @@ -1,60 +1,11 @@ #ifndef _ASM_SPARC_DMA_MAPPING_H #define _ASM_SPARC_DMA_MAPPING_H -#include -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 +#ifdef CONFIG_PCI +#include +#else +#include +#endif /* PCI */ #endif /* _ASM_SPARC_DMA_MAPPING_H */ diff --git a/trunk/arch/sparc/include/asm/dma.h b/trunk/arch/sparc/include/asm/dma.h index b554927bbaf6..aa1d90ac04c5 100644 --- a/trunk/arch/sparc/include/asm/dma.h +++ b/trunk/arch/sparc/include/asm/dma.h @@ -1,139 +1,8 @@ -#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; +#ifndef ___ASM_SPARC_DMA_H +#define ___ASM_SPARC_DMA_H +#if defined(__sparc__) && defined(__arch64__) +#include #else -#define isa_dma_bridge_buggy (0) +#include #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) */ diff --git a/trunk/arch/sparc/include/asm/dma_32.h b/trunk/arch/sparc/include/asm/dma_32.h new file mode 100644 index 000000000000..cf7189c0079b --- /dev/null +++ b/trunk/arch/sparc/include/asm/dma_32.h @@ -0,0 +1,288 @@ +/* include/asm/dma.h + * + * Copyright 1995 (C) David S. Miller (davem@davemloft.net) + */ + +#ifndef _ASM_SPARC_DMA_H +#define _ASM_SPARC_DMA_H + +#include +#include + +#include /* for invalidate's, etc. */ +#include +#include +#include +#include +#include +#include + +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) */ diff --git a/trunk/arch/sparc/include/asm/dma_64.h b/trunk/arch/sparc/include/asm/dma_64.h new file mode 100644 index 000000000000..46a8aecffc02 --- /dev/null +++ b/trunk/arch/sparc/include/asm/dma_64.h @@ -0,0 +1,205 @@ +/* + * 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 +#include +#include + +#include +#include +#include + +/* 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) */ diff --git a/trunk/arch/sparc/include/asm/ebus.h b/trunk/arch/sparc/include/asm/ebus.h new file mode 100644 index 000000000000..83a6d16c22e6 --- /dev/null +++ b/trunk/arch/sparc/include/asm/ebus.h @@ -0,0 +1,8 @@ +#ifndef ___ASM_SPARC_EBUS_H +#define ___ASM_SPARC_EBUS_H +#if defined(__sparc__) && defined(__arch64__) +#include +#else +#include +#endif +#endif diff --git a/trunk/arch/sparc/include/asm/ebus_32.h b/trunk/arch/sparc/include/asm/ebus_32.h new file mode 100644 index 000000000000..f91f0b267ce1 --- /dev/null +++ b/trunk/arch/sparc/include/asm/ebus_32.h @@ -0,0 +1,99 @@ +/* + * 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 +#endif +#include +#include +#include + +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) */ diff --git a/trunk/arch/sparc/include/asm/ebus_64.h b/trunk/arch/sparc/include/asm/ebus_64.h new file mode 100644 index 000000000000..14c6a111f60c --- /dev/null +++ b/trunk/arch/sparc/include/asm/ebus_64.h @@ -0,0 +1,95 @@ +/* + * 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 + +#include +#include + +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) */ diff --git a/trunk/arch/sparc/include/asm/ebus_dma.h b/trunk/arch/sparc/include/asm/ebus_dma.h deleted file mode 100644 index f07a5b541c98..000000000000 --- a/trunk/arch/sparc/include/asm/ebus_dma.h +++ /dev/null @@ -1,35 +0,0 @@ -#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 */ diff --git a/trunk/arch/sparc/include/asm/elf_32.h b/trunk/arch/sparc/include/asm/elf_32.h index b7ab60547827..d043f80bc2fd 100644 --- a/trunk/arch/sparc/include/asm/elf_32.h +++ b/trunk/arch/sparc/include/asm/elf_32.h @@ -105,8 +105,11 @@ 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 @@ -123,7 +126,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) ? 0 : \ +#define ELF_HWCAP ((ARCH_SUN4C_SUN4) ? 0 : \ (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \ HWCAP_SPARC_SWAP | \ ((srmmu_modtype != Cypress && \ diff --git a/trunk/arch/sparc/include/asm/fhc.h b/trunk/arch/sparc/include/asm/fhc.h index 57f1b303ad54..788cbc46a116 100644 --- a/trunk/arch/sparc/include/asm/fhc.h +++ b/trunk/arch/sparc/include/asm/fhc.h @@ -1,4 +1,5 @@ -/* fhc.h: FHC and Clock board register definitions. +/* + * fhc.h: Structures for central/fhc pseudo driver on Sunfire/Starfire/Wildfire. * * Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com) */ @@ -6,6 +7,14 @@ #ifndef _SPARC64_FHC_H #define _SPARC64_FHC_H +#include + +#include +#include +#include + +struct linux_fhc; + /* Clock board register offsets. */ #define CLOCK_CTRL 0x00UL /* Main control */ #define CLOCK_STAT1 0x10UL /* Status one */ @@ -20,7 +29,21 @@ #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) */ @@ -67,14 +90,32 @@ #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) */ diff --git a/trunk/arch/sparc/include/asm/floppy_32.h b/trunk/arch/sparc/include/asm/floppy_32.h index c792830636de..ae3f00bf22ff 100644 --- a/trunk/arch/sparc/include/asm/floppy_32.h +++ b/trunk/arch/sparc/include/asm/floppy_32.h @@ -6,9 +6,6 @@ #ifndef __ASM_SPARC_FLOPPY_H #define __ASM_SPARC_FLOPPY_H -#include -#include - #include #include #include @@ -346,7 +343,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 *) - of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy"); + sbus_ioremap(&r, 0, fd_regs[0].reg_size, "floppy"); /* Last minute sanity check... */ if(sun_fdc->status_82072 == 0xff) { @@ -388,15 +385,4 @@ 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) */ diff --git a/trunk/arch/sparc/include/asm/floppy_64.h b/trunk/arch/sparc/include/asm/floppy_64.h index 36439d67ad71..c39db1060bc7 100644 --- a/trunk/arch/sparc/include/asm/floppy_64.h +++ b/trunk/arch/sparc/include/asm/floppy_64.h @@ -1,6 +1,6 @@ /* floppy.h: Sparc specific parts of the Floppy driver. * - * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996, 2007 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,11 +9,18 @@ #ifndef __ASM_SPARC64_FLOPPY_H #define __ASM_SPARC64_FLOPPY_H -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include + /* * Define this to enable exchanging drive 0 and 1 if only drive 1 is @@ -43,7 +50,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 of_device *floppy_op = NULL; +static struct sbus_dev *floppy_sdev = NULL; struct sun_floppy_ops { unsigned char (*fd_inb) (unsigned long port); @@ -284,11 +291,12 @@ static int sun_fd_eject(int drive) return 0; } -#include +#ifdef CONFIG_PCI +#include #include static struct ebus_dma_info sun_pci_fd_ebus_dma; -static struct device *sun_floppy_dev; +static struct pci_dev *sun_pci_ebus_dev; static int sun_pci_broken_drive = -1; struct sun_pci_dma_op { @@ -369,7 +377,7 @@ static void sun_pci_fd_enable_dma(void) sun_pci_dma_pending.addr = -1U; sun_pci_dma_current.addr = - dma_map_single(sun_floppy_dev, + pci_map_single(sun_pci_ebus_dev, sun_pci_dma_current.buf, sun_pci_dma_current.len, sun_pci_dma_current.direction); @@ -386,7 +394,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) - dma_unmap_single(sun_floppy_dev, + pci_unmap_single(sun_pci_ebus_dev, sun_pci_dma_current.addr, sun_pci_dma_current.len, sun_pci_dma_current.direction); @@ -396,9 +404,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 = DMA_TO_DEVICE; + sun_pci_dma_pending.direction = PCI_DMA_TODEVICE; else - sun_pci_dma_pending.direction = DMA_FROM_DEVICE; + sun_pci_dma_pending.direction = PCI_DMA_FROMDEVICE; ebus_dma_prepare(&sun_pci_fd_ebus_dma, mode != DMA_MODE_WRITE); } @@ -530,84 +538,80 @@ static int sun_pci_fd_test_drive(unsigned long port, int drive) #undef MSR #undef DOR -static int __init ebus_fdthree_p(struct device_node *dp) +#endif /* CONFIG_PCI */ + +#ifdef CONFIG_PCI +static int __init ebus_fdthree_p(struct linux_ebus_device *edev) { - if (!strcmp(dp->name, "fdthree")) + if (!strcmp(edev->prom_node->name, "fdthree")) return 1; - if (!strcmp(dp->name, "floppy")) { + if (!strcmp(edev->prom_node->name, "floppy")) { const char *compat; - compat = of_get_property(dp, "compatible", NULL); + compat = of_get_property(edev->prom_node, + "compatible", NULL); if (compat && !strcmp(compat, "fdthree")) return 1; } return 0; } +#endif static unsigned long __init sun_floppy_init(void) { - static int initialized = 0; - struct device_node *dp; - struct of_device *op; - const char *prop; char state[128]; + struct sbus_bus *bus; + struct sbus_dev *sdev = NULL; + static int initialized = 0; if (initialized) return sun_floppy_types[0]; initialized = 1; - 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) + for_all_sbusdev (sdev, bus) { + if (!strcmp(sdev->prom_name, "SUNW,fdtwo")) break; } - if (op) { - floppy_op = op; - FLOPPY_IRQ = op->irqs[0]; + if(sdev) { + floppy_sdev = sdev; + FLOPPY_IRQ = sdev->irqs[0]; } else { - struct device_node *ebus_dp; +#ifdef CONFIG_PCI + struct linux_ebus *ebus; + struct linux_ebus_device *edev = NULL; + unsigned long config = 0; void __iomem *auxio_reg; const char *state_prop; - unsigned long config; - 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; + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (ebus_fdthree_p(edev)) + goto ebus_done; } } - found_fdthree: - if (!dp) - return 0; - - op = of_find_device_by_node(dp); - if (!op) + ebus_done: + if (!edev) return 0; - state_prop = of_get_property(op->node, "status", NULL); + state_prop = of_get_property(edev->prom_node, "status", NULL); if (state_prop && !strncmp(state_prop, "disabled", 8)) return 0; - FLOPPY_IRQ = op->irqs[0]; + FLOPPY_IRQ = edev->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 *) op->resource[2].start; + auxio_reg = (void __iomem *) edev->resource[2].start; writel(readl(auxio_reg)|0x2, auxio_reg); - sun_floppy_dev = &op->dev; + sun_pci_ebus_dev = ebus->self; spin_lock_init(&sun_pci_fd_ebus_dma.lock); /* XXX ioremap */ sun_pci_fd_ebus_dma.regs = (void __iomem *) - op->resource[1].start; + edev->resource[1].start; if (!sun_pci_fd_ebus_dma.regs) return 0; @@ -621,7 +625,7 @@ static unsigned long __init sun_floppy_init(void) return 0; /* XXX ioremap */ - sun_fdc = (struct sun_flpy_controller *) op->resource[0].start; + sun_fdc = (struct sun_flpy_controller *)edev->resource[0].start; sun_fdops.fd_inb = sun_pci_fd_inb; sun_fdops.fd_outb = sun_pci_fd_outb; @@ -658,15 +662,12 @@ static unsigned long __init sun_floppy_init(void) /* * Find NS87303 SuperIO config registers (through ecpp). */ - 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; + 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_done: @@ -715,23 +716,26 @@ static unsigned long __init sun_floppy_init(void) #endif /* PCI_FDC_SWAP_DRIVES */ return sun_floppy_types[0]; +#else + return 0; +#endif } - prop = of_get_property(op->node, "status", NULL); - if (prop && !strncmp(state, "disabled", 8)) + prom_getproperty(sdev->prom_node, "status", state, sizeof(state)); + if(!strncmp(state, "disabled", 8)) return 0; /* - * We cannot do of_ioremap here: it does request_region, + * We cannot do sbus_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 *) - (op->resource[0].start + - ((op->resource[0].flags & 0x1ffUL) << 32UL)); + (sdev->resource[0].start + + ((sdev->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; } diff --git a/trunk/arch/sparc/include/asm/gpio.h b/trunk/arch/sparc/include/asm/gpio.h deleted file mode 100644 index a0e3ac0af599..000000000000 --- a/trunk/arch/sparc/include/asm/gpio.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __ASM_SPARC_GPIO_H -#define __ASM_SPARC_GPIO_H - -#include -#include - -#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 */ diff --git a/trunk/arch/sparc/include/asm/io-unit.h b/trunk/arch/sparc/include/asm/io-unit.h index 01ab2f613e91..96823b47fd45 100644 --- a/trunk/arch/sparc/include/asm/io-unit.h +++ b/trunk/arch/sparc/include/asm/io-unit.h @@ -55,4 +55,8 @@ 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) */ diff --git a/trunk/arch/sparc/include/asm/io_32.h b/trunk/arch/sparc/include/asm/io_32.h index 93fe21e02c86..10d7da450070 100644 --- a/trunk/arch/sparc/include/asm/io_32.h +++ b/trunk/arch/sparc/include/asm/io_32.h @@ -292,6 +292,14 @@ 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 @@ -300,17 +308,6 @@ extern void pci_iounmap(struct pci_dev *dev, void __iomem *); #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 diff --git a/trunk/arch/sparc/include/asm/io_64.h b/trunk/arch/sparc/include/asm/io_64.h index 4aee21dc9c6f..0bff078ffdd0 100644 --- a/trunk/arch/sparc/include/asm/io_64.h +++ b/trunk/arch/sparc/include/asm/io_64.h @@ -482,16 +482,18 @@ 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 *); -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); +/* 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)) /* * Convert a physical pointer to a virtual kernel pointer for /dev/mem diff --git a/trunk/arch/sparc/include/asm/iommu_64.h b/trunk/arch/sparc/include/asm/iommu_64.h index caf798b56191..d7b9afcba08b 100644 --- a/trunk/arch/sparc/include/asm/iommu_64.h +++ b/trunk/arch/sparc/include/asm/iommu_64.h @@ -48,9 +48,6 @@ 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; diff --git a/trunk/arch/sparc/include/asm/irq_64.h b/trunk/arch/sparc/include/asm/irq_64.h index 71673eca3660..e3dd9303643d 100644 --- a/trunk/arch/sparc/include/asm/irq_64.h +++ b/trunk/arch/sparc/include/asm/irq_64.h @@ -56,6 +56,7 @@ 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); diff --git a/trunk/arch/sparc/include/asm/mc146818rtc_64.h b/trunk/arch/sparc/include/asm/mc146818rtc_64.h index 7238d174e0e3..e9c0fcc25c6f 100644 --- a/trunk/arch/sparc/include/asm/mc146818rtc_64.h +++ b/trunk/arch/sparc/include/asm/mc146818rtc_64.h @@ -7,8 +7,12 @@ #include #ifndef RTC_PORT -extern unsigned long cmos_regs; -#define RTC_PORT(x) (cmos_regs + (x)) +#ifdef CONFIG_PCI +extern unsigned long ds1287_regs; +#else +#define ds1287_regs (0UL) +#endif +#define RTC_PORT(x) (ds1287_regs + (x)) #define RTC_ALWAYS_BCD 0 #endif @@ -25,4 +29,6 @@ outb_p((addr),RTC_PORT(0)); \ outb_p((val),RTC_PORT(1)); \ }) +#define RTC_IRQ 8 + #endif /* __ASM_SPARC64_MC146818RTC_H */ diff --git a/trunk/arch/sparc/include/asm/memctrl.h b/trunk/arch/sparc/include/asm/memctrl.h deleted file mode 100644 index 4065c56af7b6..000000000000 --- a/trunk/arch/sparc/include/asm/memctrl.h +++ /dev/null @@ -1,9 +0,0 @@ -#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 */ diff --git a/trunk/arch/sparc/include/asm/mostek.h b/trunk/arch/sparc/include/asm/mostek.h new file mode 100644 index 000000000000..433be3e0a69b --- /dev/null +++ b/trunk/arch/sparc/include/asm/mostek.h @@ -0,0 +1,8 @@ +#ifndef ___ASM_SPARC_MOSTEK_H +#define ___ASM_SPARC_MOSTEK_H +#if defined(__sparc__) && defined(__arch64__) +#include +#else +#include +#endif +#endif diff --git a/trunk/arch/sparc/include/asm/mostek_32.h b/trunk/arch/sparc/include/asm/mostek_32.h new file mode 100644 index 000000000000..a99590c4c507 --- /dev/null +++ b/trunk/arch/sparc/include/asm/mostek_32.h @@ -0,0 +1,171 @@ +/* + * 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 +#include + +/* 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) */ diff --git a/trunk/arch/sparc/include/asm/mostek_64.h b/trunk/arch/sparc/include/asm/mostek_64.h new file mode 100644 index 000000000000..c5652de2ace2 --- /dev/null +++ b/trunk/arch/sparc/include/asm/mostek_64.h @@ -0,0 +1,143 @@ +/* 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 + +/* 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) */ diff --git a/trunk/arch/sparc/include/asm/obio.h b/trunk/arch/sparc/include/asm/obio.h index 4ade0c8a2c79..1a7544ceb574 100644 --- a/trunk/arch/sparc/include/asm/obio.h +++ b/trunk/arch/sparc/include/asm/obio.h @@ -155,6 +155,17 @@ 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; diff --git a/trunk/arch/sparc/include/asm/of_device.h b/trunk/arch/sparc/include/asm/of_device.h index a5d9811f9697..bba777a416d3 100644 --- a/trunk/arch/sparc/include/asm/of_device.h +++ b/trunk/arch/sparc/include/asm/of_device.h @@ -30,8 +30,6 @@ 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 diff --git a/trunk/arch/sparc/include/asm/of_platform.h b/trunk/arch/sparc/include/asm/of_platform.h index 90da99059f83..2348ab90a57c 100644 --- a/trunk/arch/sparc/include/asm/of_platform.h +++ b/trunk/arch/sparc/include/asm/of_platform.h @@ -13,6 +13,9 @@ * */ +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 diff --git a/trunk/arch/sparc/include/asm/oplib_32.h b/trunk/arch/sparc/include/asm/oplib_32.h index 699da05235c8..b2631da259e0 100644 --- a/trunk/arch/sparc/include/asm/oplib_32.h +++ b/trunk/arch/sparc/include/asm/oplib_32.h @@ -21,6 +21,7 @@ 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; diff --git a/trunk/arch/sparc/include/asm/page_32.h b/trunk/arch/sparc/include/asm/page_32.h index d1806edc0958..cf5fb70ca1c1 100644 --- a/trunk/arch/sparc/include/asm/page_32.h +++ b/trunk/arch/sparc/include/asm/page_32.h @@ -8,8 +8,11 @@ #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) diff --git a/trunk/arch/sparc/include/asm/page_64.h b/trunk/arch/sparc/include/asm/page_64.h index 4274ed13ddb2..b579b910ef51 100644 --- a/trunk/arch/sparc/include/asm/page_64.h +++ b/trunk/arch/sparc/include/asm/page_64.h @@ -38,8 +38,6 @@ #ifndef __ASSEMBLY__ -#define WANT_PAGE_VIRTUAL - extern void _clear_page(void *page); #define clear_page(X) _clear_page((void *)(X)) struct page; diff --git a/trunk/arch/sparc/include/asm/parport.h b/trunk/arch/sparc/include/asm/parport.h index dff3f0253aa8..d9830621c906 100644 --- a/trunk/arch/sparc/include/asm/parport.h +++ b/trunk/arch/sparc/include/asm/parport.h @@ -8,7 +8,7 @@ #include -#include +#include #include #include @@ -215,7 +215,7 @@ static int __devexit ecpp_remove(struct of_device *op) return 0; } -static const struct of_device_id ecpp_match[] = { +static struct of_device_id ecpp_match[] = { { .name = "ecpp", }, diff --git a/trunk/arch/sparc/include/asm/pci_32.h b/trunk/arch/sparc/include/asm/pci_32.h index b41c4c198159..0ee949d220c0 100644 --- a/trunk/arch/sparc/include/asm/pci_32.h +++ b/trunk/arch/sparc/include/asm/pci_32.h @@ -3,8 +3,6 @@ #ifdef __KERNEL__ -#include - /* 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. diff --git a/trunk/arch/sparc/include/asm/pgtable_32.h b/trunk/arch/sparc/include/asm/pgtable_32.h index e0cabe790ec1..08237fda8874 100644 --- a/trunk/arch/sparc/include/asm/pgtable_32.h +++ b/trunk/arch/sparc/include/asm/pgtable_32.h @@ -14,7 +14,11 @@ #include #include #include +#ifdef CONFIG_SUN4 +#include +#else #include +#endif #include #include #include diff --git a/trunk/arch/sparc/include/asm/pgtable_64.h b/trunk/arch/sparc/include/asm/pgtable_64.h index b049abf9902f..bb9ec2cce355 100644 --- a/trunk/arch/sparc/include/asm/pgtable_64.h +++ b/trunk/arch/sparc/include/asm/pgtable_64.h @@ -770,8 +770,6 @@ 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) */ diff --git a/trunk/arch/sparc/include/asm/prom.h b/trunk/arch/sparc/include/asm/prom.h index 900d44714f8d..fd55522481cd 100644 --- a/trunk/arch/sparc/include/asm/prom.h +++ b/trunk/arch/sparc/include/asm/prom.h @@ -18,7 +18,6 @@ */ #include #include -#include #include #define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 2 @@ -74,7 +73,6 @@ 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); @@ -96,16 +94,6 @@ 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 diff --git a/trunk/arch/sparc/include/asm/ptrace_64.h b/trunk/arch/sparc/include/asm/ptrace_64.h index 3d3e9c161d8b..06e4914c13f4 100644 --- a/trunk/arch/sparc/include/asm/ptrace_64.h +++ b/trunk/arch/sparc/include/asm/ptrace_64.h @@ -113,8 +113,6 @@ struct sparc_trapf { #ifdef __KERNEL__ -#include - static inline int pt_regs_trap_type(struct pt_regs *regs) { return regs->magic & 0x1ff; @@ -140,7 +138,6 @@ 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 diff --git a/trunk/arch/sparc/include/asm/reboot.h b/trunk/arch/sparc/include/asm/reboot.h new file mode 100644 index 000000000000..3f3f43f5be5e --- /dev/null +++ b/trunk/arch/sparc/include/asm/reboot.h @@ -0,0 +1,6 @@ +#ifndef _SPARC64_REBOOT_H +#define _SPARC64_REBOOT_H + +extern void machine_alt_power_off(void); + +#endif /* _SPARC64_REBOOT_H */ diff --git a/trunk/arch/sparc/include/asm/rtc.h b/trunk/arch/sparc/include/asm/rtc.h new file mode 100644 index 000000000000..f9ecb1fe2ecd --- /dev/null +++ b/trunk/arch/sparc/include/asm/rtc.h @@ -0,0 +1,26 @@ +/* + * 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 + +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 diff --git a/trunk/arch/sparc/include/asm/sbus.h b/trunk/arch/sparc/include/asm/sbus.h new file mode 100644 index 000000000000..f82481ab44db --- /dev/null +++ b/trunk/arch/sparc/include/asm/sbus.h @@ -0,0 +1,8 @@ +#ifndef ___ASM_SPARC_SBUS_H +#define ___ASM_SPARC_SBUS_H +#if defined(__sparc__) && defined(__arch64__) +#include +#else +#include +#endif +#endif diff --git a/trunk/arch/sparc/include/asm/sbus_32.h b/trunk/arch/sparc/include/asm/sbus_32.h new file mode 100644 index 000000000000..a7b4fa21931d --- /dev/null +++ b/trunk/arch/sparc/include/asm/sbus_32.h @@ -0,0 +1,153 @@ +/* + * 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 +#include +#include + +#include +#include +#include + +/* 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) */ diff --git a/trunk/arch/sparc/include/asm/sbus_64.h b/trunk/arch/sparc/include/asm/sbus_64.h new file mode 100644 index 000000000000..b606c14343fb --- /dev/null +++ b/trunk/arch/sparc/include/asm/sbus_64.h @@ -0,0 +1,190 @@ +/* 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 +#include +#include + +#include +#include +#include +#include + +/* 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) */ diff --git a/trunk/arch/sparc/include/asm/spinlock_32.h b/trunk/arch/sparc/include/asm/spinlock_32.h index bf2d532593e3..de2249b267c6 100644 --- a/trunk/arch/sparc/include/asm/spinlock_32.h +++ b/trunk/arch/sparc/include/asm/spinlock_32.h @@ -6,6 +6,8 @@ #ifndef __SPARC_SPINLOCK_H #define __SPARC_SPINLOCK_H +#include /* For NR_CPUS */ + #ifndef __ASSEMBLY__ #include diff --git a/trunk/arch/sparc/include/asm/spinlock_64.h b/trunk/arch/sparc/include/asm/spinlock_64.h index 120cfe4577c7..0006fe9f8c7a 100644 --- a/trunk/arch/sparc/include/asm/spinlock_64.h +++ b/trunk/arch/sparc/include/asm/spinlock_64.h @@ -6,6 +6,8 @@ #ifndef __SPARC64_SPINLOCK_H #define __SPARC64_SPINLOCK_H +#include /* For NR_CPUS */ + #ifndef __ASSEMBLY__ /* To get debugging spinlocks which detect and catch diff --git a/trunk/arch/sparc/include/asm/sstate.h b/trunk/arch/sparc/include/asm/sstate.h new file mode 100644 index 000000000000..a7c35dbcb281 --- /dev/null +++ b/trunk/arch/sparc/include/asm/sstate.h @@ -0,0 +1,13 @@ +#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 */ diff --git a/trunk/arch/sparc/include/asm/starfire.h b/trunk/arch/sparc/include/asm/starfire.h index d56ce60a5992..07bafd31e33c 100644 --- a/trunk/arch/sparc/include/asm/starfire.h +++ b/trunk/arch/sparc/include/asm/starfire.h @@ -12,6 +12,7 @@ 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); diff --git a/trunk/arch/sparc/include/asm/sun4paddr.h b/trunk/arch/sparc/include/asm/sun4paddr.h new file mode 100644 index 000000000000..d52985f19f42 --- /dev/null +++ b/trunk/arch/sparc/include/asm/sun4paddr.h @@ -0,0 +1,56 @@ +/* + * 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) */ diff --git a/trunk/arch/sparc/include/asm/sun4prom.h b/trunk/arch/sparc/include/asm/sun4prom.h new file mode 100644 index 000000000000..9c8b4cbf629a --- /dev/null +++ b/trunk/arch/sparc/include/asm/sun4prom.h @@ -0,0 +1,83 @@ +/* + * 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_ */ diff --git a/trunk/arch/sparc/include/asm/system_32.h b/trunk/arch/sparc/include/asm/system_32.h index 8623fc48fe24..b4b024445fc9 100644 --- a/trunk/arch/sparc/include/asm/system_32.h +++ b/trunk/arch/sparc/include/asm/system_32.h @@ -34,7 +34,13 @@ enum sparc_cpu { extern enum sparc_cpu sparc_cpu_model; -#define ARCH_SUN4C (sparc_cpu_model==sun4c) +#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 SUN4M_NCPUS 4 /* Architectural limit of sun4m. */ @@ -49,7 +55,6 @@ 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) { diff --git a/trunk/arch/sparc/include/asm/system_64.h b/trunk/arch/sparc/include/asm/system_64.h index 8759f2a1b837..db9e742a406a 100644 --- a/trunk/arch/sparc/include/asm/system_64.h +++ b/trunk/arch/sparc/include/asm/system_64.h @@ -26,8 +26,9 @@ enum sparc_cpu { #define sparc_cpu_model sun4u -/* This cannot ever be a sun4c :) That's just history. */ -#define ARCH_SUN4C 0 +/* This cannot ever be a sun4c nor sun4 :) That's just history. */ +#define ARCH_SUN4C_SUN4 0 +#define ARCH_SUN4 0 extern char reboot_command[]; @@ -117,7 +118,6 @@ 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); diff --git a/trunk/arch/sparc/include/asm/thread_info_32.h b/trunk/arch/sparc/include/asm/thread_info_32.h index 29899fd5b1b2..cbb892d0dff0 100644 --- a/trunk/arch/sparc/include/asm/thread_info_32.h +++ b/trunk/arch/sparc/include/asm/thread_info_32.h @@ -80,7 +80,11 @@ 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 diff --git a/trunk/arch/sparc/include/asm/timer_32.h b/trunk/arch/sparc/include/asm/timer_32.h index 2ec030ef3810..361e53898dd7 100644 --- a/trunk/arch/sparc/include/asm/timer_32.h +++ b/trunk/arch/sparc/include/asm/timer_32.h @@ -9,9 +9,96 @@ #define _SPARC_TIMER_H #include /* For SUN4M_NCPUS */ +#include #include +/* 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) diff --git a/trunk/arch/sparc/include/asm/vac-ops.h b/trunk/arch/sparc/include/asm/vac-ops.h index a63e88ef0426..d10527611f11 100644 --- a/trunk/arch/sparc/include/asm/vac-ops.h +++ b/trunk/arch/sparc/include/asm/vac-ops.h @@ -76,7 +76,11 @@ * 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'. @@ -90,7 +94,10 @@ */ 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 */ diff --git a/trunk/arch/sparc/include/asm/vfc_ioctls.h b/trunk/arch/sparc/include/asm/vfc_ioctls.h new file mode 100644 index 000000000000..af8b69007b22 --- /dev/null +++ b/trunk/arch/sparc/include/asm/vfc_ioctls.h @@ -0,0 +1,58 @@ +/* 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_ */ diff --git a/trunk/arch/sparc/include/asm/visasm.h b/trunk/arch/sparc/include/asm/visasm.h index 39ca301920db..de797b9bf552 100644 --- a/trunk/arch/sparc/include/asm/visasm.h +++ b/trunk/arch/sparc/include/asm/visasm.h @@ -57,7 +57,6 @@ 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 */ diff --git a/trunk/arch/sparc/kernel/Makefile b/trunk/arch/sparc/kernel/Makefile index 2d6582095099..6e03a2a7863c 100644 --- a/trunk/arch/sparc/kernel/Makefile +++ b/trunk/arch/sparc/kernel/Makefile @@ -13,13 +13,15 @@ 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 dma.o + prom.o of_device.o devres.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 diff --git a/trunk/arch/sparc/kernel/apc.c b/trunk/arch/sparc/kernel/apc.c index 4dd1ba752ce6..5267d48fb2c6 100644 --- a/trunk/arch/sparc/kernel/apc.c +++ b/trunk/arch/sparc/kernel/apc.c @@ -12,10 +12,9 @@ #include #include #include -#include -#include #include +#include #include #include #include @@ -30,10 +29,11 @@ #define APC_OBPNAME "power-management" #define APC_DEVNAME "apc" -static u8 __iomem *regs; +volatile static u8 __iomem *regs; +static int apc_regsize; 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(struct of_device *op) +static inline void apc_free(void) { - of_iounmap(&op->resource[0], regs, resource_size(&op->resource[0])); + sbus_iounmap(regs, apc_regsize); } static int apc_open(struct inode *inode, struct file *f) @@ -153,56 +153,52 @@ static const struct file_operations apc_fops = { static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops }; -static int __devinit apc_probe(struct of_device *op, - const struct of_device_id *match) +static int __init apc_probe(void) { - int err; + struct sbus_bus *sbus = NULL; + struct sbus_dev *sdev = NULL; + int iTmp = 0; + + for_each_sbus(sbus) { + for_each_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, APC_OBPNAME)) { + goto sbus_done; + } + } + } - regs = of_ioremap(&op->resource[0], 0, - resource_size(&op->resource[0]), APC_OBPNAME); - if (!regs) { +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) { printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME); return -ENODEV; } - err = misc_register(&apc_miscdev); - if (err) { + iTmp = misc_register(&apc_miscdev); + if (iTmp != 0) { printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME); - apc_free(op); + apc_free(); 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_init); +__initcall(apc_probe); + diff --git a/trunk/arch/sparc/kernel/auxio.c b/trunk/arch/sparc/kernel/auxio.c index 09c857215a52..baf4ed3fb0f3 100644 --- a/trunk/arch/sparc/kernel/auxio.c +++ b/trunk/arch/sparc/kernel/auxio.c @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include #include #include @@ -61,7 +59,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 = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio"); + auxio_register = sbus_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) @@ -130,7 +128,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 *) of_ioremap(&r, 0, + auxio_power_register = (unsigned char *) sbus_ioremap(&r, 0, regs.reg_size, "auxpower"); /* Display a quick message on the console. */ diff --git a/trunk/arch/sparc/kernel/devices.c b/trunk/arch/sparc/kernel/devices.c index ad656b044b8c..b240b8863fd0 100644 --- a/trunk/arch/sparc/kernel/devices.c +++ b/trunk/arch/sparc/kernel/devices.c @@ -143,7 +143,7 @@ void __init device_scan(void) #endif clock_stop_probe(); - if (ARCH_SUN4C) + if (ARCH_SUN4C_SUN4) sun4c_probe_memerr_reg(); return; diff --git a/trunk/arch/sparc/kernel/dma.c b/trunk/arch/sparc/kernel/dma.c deleted file mode 100644 index ebc8403b035e..000000000000 --- a/trunk/arch/sparc/kernel/dma.c +++ /dev/null @@ -1,227 +0,0 @@ -/* dma.c: PCI and SBUS DMA accessors for 32-bit sparc. - * - * Copyright (C) 2008 David S. Miller - */ - -#include -#include -#include -#include -#include - -#ifdef CONFIG_PCI -#include -#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); diff --git a/trunk/arch/sparc/kernel/dma.h b/trunk/arch/sparc/kernel/dma.h deleted file mode 100644 index f8d8951adb53..000000000000 --- a/trunk/arch/sparc/kernel/dma.h +++ /dev/null @@ -1,14 +0,0 @@ -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); diff --git a/trunk/arch/sparc/kernel/ebus.c b/trunk/arch/sparc/kernel/ebus.c new file mode 100644 index 000000000000..97294232259c --- /dev/null +++ b/trunk/arch/sparc/kernel/ebus.c @@ -0,0 +1,393 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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); +} diff --git a/trunk/arch/sparc/kernel/entry.S b/trunk/arch/sparc/kernel/entry.S index faf9ccd9ef5d..e8cdf715a546 100644 --- a/trunk/arch/sparc/kernel/entry.S +++ b/trunk/arch/sparc/kernel/entry.S @@ -20,7 +20,11 @@ #include #include #include +#ifdef CONFIG_SUN4 +#include +#else #include +#endif #include #include #include @@ -272,18 +276,17 @@ smp4m_ticker: */ maybe_smp4m_msg: GET_PROCESSOR4M_ID(o3) - sethi %hi(sun4m_irq_percpu), %l5 - sll %o3, 2, %o3 - or %l5, %lo(sun4m_irq_percpu), %o5 + set sun4m_interrupts, %l5 + ld [%l5], %o5 sethi %hi(0x40000000), %o2 + sll %o3, 12, %o3 ld [%o5 + %o3], %o1 - ld [%o1 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending - andcc %o3, %o2, %g0 + andcc %o1, %o2, %g0 be,a smp4m_ticker cmp %l7, 14 - st %o2, [%o1 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x40000000 + st %o2, [%o5 + 0x4] WRITE_PAUSE - ld [%o1 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending + ld [%o5], %g0 WRITE_PAUSE or %l0, PSR_PIL, %l4 wr %l4, 0x0, %psr @@ -301,16 +304,16 @@ linux_trap_ipi15_sun4m: SAVE_ALL sethi %hi(0x80000000), %o2 GET_PROCESSOR4M_ID(o0) - 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 + set sun4m_interrupts, %l5 + ld [%l5], %o5 + sll %o0, 12, %o0 + add %o5, %o0, %o5 + ld [%o5], %o3 andcc %o3, %o2, %g0 be 1f ! Must be an NMI async memory error - st %o2, [%o5 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x80000000 + st %o2, [%o5 + 4] WRITE_PAUSE - ld [%o5 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending + ld [%o5], %g0 WRITE_PAUSE or %l0, PSR_PIL, %l4 wr %l4, 0x0, %psr @@ -324,11 +327,12 @@ linux_trap_ipi15_sun4m: 1: /* NMI async memory error handling. */ sethi %hi(0x80000000), %l4 - sethi %hi(sun4m_irq_global), %o5 - ld [%o5 + %lo(sun4m_irq_global)], %l5 - st %l4, [%l5 + 0x0c] ! sun4m_irq_global->mask_set=0x80000000 + sethi %hi(0x4000), %o3 + sub %o5, %o0, %o5 + add %o5, %o3, %l5 + st %l4, [%l5 + 0xc] WRITE_PAUSE - ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending + ld [%l5], %g0 WRITE_PAUSE or %l0, PSR_PIL, %l4 wr %l4, 0x0, %psr @@ -337,9 +341,9 @@ linux_trap_ipi15_sun4m: WRITE_PAUSE call sun4m_nmi nop - st %l4, [%l5 + 0x08] ! sun4m_irq_global->mask_clear=0x80000000 + st %l4, [%l5 + 0x8] WRITE_PAUSE - ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending + ld [%l5], %g0 WRITE_PAUSE RESTORE_ALL @@ -771,7 +775,11 @@ 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 @@ -790,10 +798,42 @@ 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 @@ -840,7 +880,12 @@ 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 @@ -892,7 +937,11 @@ 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: @@ -980,7 +1029,12 @@ 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 diff --git a/trunk/arch/sparc/kernel/head.S b/trunk/arch/sparc/kernel/head.S index 2d325fd84579..50d9a16af795 100644 --- a/trunk/arch/sparc/kernel/head.S +++ b/trunk/arch/sparc/kernel/head.S @@ -63,9 +63,15 @@ cputypvar_sun4m: .align 4 +#ifndef CONFIG_SUN4 sun4_notsup: - .asciz "Sparc-Linux sun4 support does no longer exist.\n\n" + .asciz "Sparc-Linux sun4 needs a specially compiled kernel, turn CONFIG_SUN4 on.\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" @@ -774,6 +780,15 @@ 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 @@ -1135,6 +1150,15 @@ 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 @@ -1146,7 +1170,7 @@ sun4_init: nop 1: ba 1b ! Cannot exit into KMON nop - +#endif no_sun4e_here: ld [%g7 + 0x68], %o1 set sun4e_notsup, %o0 diff --git a/trunk/arch/sparc/kernel/idprom.c b/trunk/arch/sparc/kernel/idprom.c index 223a6582e1e2..fc511f3c4c18 100644 --- a/trunk/arch/sparc/kernel/idprom.c +++ b/trunk/arch/sparc/kernel/idprom.c @@ -12,6 +12,10 @@ #include #include #include /* Fun with Sun released architectures. */ +#ifdef CONFIG_SUN4 +#include +extern void sun4setup(void); +#endif struct idprom *idprom; static struct idprom idprom_buffer; @@ -97,4 +101,7 @@ 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 } diff --git a/trunk/arch/sparc/kernel/ioport.c b/trunk/arch/sparc/kernel/ioport.c index 4f025b36934b..2a8a847764d8 100644 --- a/trunk/arch/sparc/kernel/ioport.c +++ b/trunk/arch/sparc/kernel/ioport.c @@ -42,13 +42,10 @@ #include #include #include +#include #include #include #include -#include -#include - -#include "dma.h" #define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */ @@ -142,6 +139,15 @@ 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) { @@ -157,6 +163,13 @@ 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 */ @@ -233,19 +246,63 @@ static void _sparc_free_io(struct resource *res) #ifdef CONFIG_SBUS -void sbus_set_sbus64(struct device *dev, int x) +void sbus_set_sbus64(struct sbus_dev *sdev, 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 device *dev, long len, u32 *dma_addrp) +void *sbus_alloc_consistent(struct sbus_dev *sdev, 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; @@ -279,10 +336,13 @@ void *sbus_alloc_consistent(struct device *dev, 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(dev, dma_addrp, va, res->start, len_total) != 0) + if (mmu_map_dma_area(dma_addrp, va, res->start, len_total) != 0) goto err_noiommu; - res->name = op->node->name; + /* Set the resource name, if known. */ + if (sdev) { + res->name = sdev->prom_name; + } return (void *)(unsigned long)res->start; @@ -296,7 +356,7 @@ void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp) return NULL; } -void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba) +void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) { struct resource *res; struct page *pgv; @@ -323,8 +383,8 @@ void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba) kfree(res); /* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */ - pgv = virt_to_page(p); - mmu_unmap_dma_area(dev, ba, n); + pgv = mmu_translate_dvma(ba); + mmu_unmap_dma_area(ba, n); __free_pages(pgv, get_order(n)); } @@ -334,7 +394,7 @@ void sbus_free_consistent(struct device *dev, 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 device *dev, void *va, size_t len, int direction) +dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction) { /* XXX why are some lengths signed, others unsigned? */ if (len <= 0) { @@ -344,17 +404,17 @@ dma_addr_t sbus_map_single(struct device *dev, void *va, size_t len, int directi if (len > 256*1024) { /* __get_free_pages() limit */ return 0; } - return mmu_get_scsi_one(dev, va, len); + return mmu_get_scsi_one(va, len, sdev->bus); } -void sbus_unmap_single(struct device *dev, dma_addr_t ba, size_t n, int direction) +void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t ba, size_t n, int direction) { - mmu_release_scsi_one(dev, ba, n); + mmu_release_scsi_one(ba, n, sdev->bus); } -int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction) +int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) { - mmu_get_scsi_sgl(dev, sg, n); + mmu_get_scsi_sgl(sg, n, sdev->bus); /* * XXX sparc64 can return a partial length here. sun4c should do this @@ -363,28 +423,145 @@ int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction return n; } -void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n, int direction) +void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) +{ + mmu_release_scsi_sgl(sg, n, sdev->bus); +} + +/* + */ +void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, 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) { - mmu_release_scsi_sgl(dev, sg, n); +#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_cpu(struct device *dev, dma_addr_t ba, size_t size, int direction) +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_single_for_device(struct device *dev, dma_addr_t ba, size_t size, int direction) +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); + } + } } -static int __init sparc_register_ioport(void) +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) { register_proc_sparc_ioport(); +#ifdef CONFIG_SUN4 + { + extern void sun4_dvma_init(void); + sun4_dvma_init(); + } + return 1; +#else return 0; +#endif } -arch_initcall(sparc_register_ioport); - +void __init sbus_arch_postinit(void) +{ + if (sparc_cpu_model == sun4d) { + extern void sun4d_init_sbi_irq(void); + sun4d_init_sbi_irq(); + } +} #endif /* CONFIG_SBUS */ #ifdef CONFIG_PCI diff --git a/trunk/arch/sparc/kernel/irq.h b/trunk/arch/sparc/kernel/irq.h index db7513881530..32ef3ebd0a88 100644 --- a/trunk/arch/sparc/kernel/irq.h +++ b/trunk/arch/sparc/kernel/irq.h @@ -13,6 +13,7 @@ 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) @@ -40,6 +41,11 @@ 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); diff --git a/trunk/arch/sparc/kernel/of_device.c b/trunk/arch/sparc/kernel/of_device.c index 0837bd52e28f..f58c537446a8 100644 --- a/trunk/arch/sparc/kernel/of_device.c +++ b/trunk/arch/sparc/kernel/of_device.c @@ -29,38 +29,15 @@ struct of_device *of_find_device_by_node(struct device_node *dp) } EXPORT_SYMBOL(of_find_device_by_node); -unsigned int irq_of_parse_and_map(struct device_node *node, int index) -{ - struct of_device *op = of_find_device_by_node(node); - - 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); +#ifdef CONFIG_PCI +struct bus_type ebus_bus_type; +EXPORT_SYMBOL(ebus_bus_type); +#endif - 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); - } -} +#ifdef CONFIG_SBUS +struct bus_type sbus_bus_type; +EXPORT_SYMBOL(sbus_bus_type); +#endif struct bus_type of_platform_bus_type; EXPORT_SYMBOL(of_platform_bus_type); @@ -350,27 +327,6 @@ 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, @@ -417,7 +373,10 @@ static void __init build_device_resources(struct of_device *op, flags = bus->get_flags(reg, 0); - if (use_1to1_mapping(pp)) { + /* If the immediate parent has no ranges property to apply, + * just use a 1<->1 mapping. + */ + if (of_find_property(pp, "ranges", NULL) == NULL) { result = of_read_addr(addr, na); goto build_res; } @@ -606,6 +565,15 @@ 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(); diff --git a/trunk/arch/sparc/kernel/pcic.c b/trunk/arch/sparc/kernel/pcic.c index 462584e55fba..a6a6f9823370 100644 --- a/trunk/arch/sparc/kernel/pcic.c +++ b/trunk/arch/sparc/kernel/pcic.c @@ -17,6 +17,8 @@ #include #include +#include +#include /* for sanity check... */ #include /* for cache flushing. */ #include @@ -428,6 +430,7 @@ static int __init pcic_init(void) pcic_pbm_scan_bus(pcic); + ebus_init(); return 0; } @@ -490,6 +493,10 @@ 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. * @@ -670,7 +677,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) } /* - * pcic_pin_to_irq() is exported to bus probing code + * pcic_pin_to_irq() is exported to ebus.c. */ unsigned int pcic_pin_to_irq(unsigned int pin, const char *name) @@ -897,6 +904,11 @@ 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__); @@ -922,6 +934,7 @@ 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); } diff --git a/trunk/arch/sparc/kernel/pmc.c b/trunk/arch/sparc/kernel/pmc.c index 2afcfab4f11c..7eca8871ff47 100644 --- a/trunk/arch/sparc/kernel/pmc.c +++ b/trunk/arch/sparc/kernel/pmc.c @@ -8,11 +8,11 @@ #include #include #include +#include #include -#include -#include #include +#include #include #include #include @@ -23,15 +23,17 @@ * #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 -static u8 __iomem *regs; +volatile static u8 __iomem *regs; +static int pmc_regsize; -#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)) /* @@ -51,11 +53,31 @@ void pmc_swift_idle(void) #endif } -static int __devinit pmc_probe(struct of_device *op, - const struct of_device_id *match) +static inline void pmc_free(void) { - regs = of_ioremap(&op->resource[0], 0, - resource_size(&op->resource[0]), PMC_OBPNAME); + 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); if (!regs) { printk(KERN_ERR "%s: unable to map registers\n", PMC_DEVNAME); return -ENODEV; @@ -70,27 +92,8 @@ static int __devinit pmc_probe(struct of_device *op, 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_init); +__initcall(pmc_probe); diff --git a/trunk/arch/sparc/kernel/process.c b/trunk/arch/sparc/kernel/process.c index e8c43ffe317e..4bb430940a61 100644 --- a/trunk/arch/sparc/kernel/process.c +++ b/trunk/arch/sparc/kernel/process.c @@ -75,7 +75,7 @@ void cpu_idle(void) { /* endless idle loop with no priority at all */ for (;;) { - if (ARCH_SUN4C) { + if (ARCH_SUN4C_SUN4) { static int count = HZ; static unsigned long last_jiffies; static unsigned long last_faults; diff --git a/trunk/arch/sparc/kernel/prom.c b/trunk/arch/sparc/kernel/prom.c index eee5efcfe50e..cd4fb79aa3a8 100644 --- a/trunk/arch/sparc/kernel/prom.c +++ b/trunk/arch/sparc/kernel/prom.c @@ -54,9 +54,6 @@ 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; @@ -80,10 +77,7 @@ 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; @@ -442,6 +436,7 @@ 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: diff --git a/trunk/arch/sparc/kernel/setup.c b/trunk/arch/sparc/kernel/setup.c index 24fe3078bd4b..9e451b21202e 100644 --- a/trunk/arch/sparc/kernel/setup.c +++ b/trunk/arch/sparc/kernel/setup.c @@ -213,25 +213,23 @@ 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: @@ -265,7 +263,7 @@ void __init setup_arch(char **cmdline_p) boot_flags_init(*cmdline_p); idprom_init(); - if (ARCH_SUN4C) + if (ARCH_SUN4C_SUN4) sun4c_probe_vac(); load_mmu(); diff --git a/trunk/arch/sparc/kernel/sparc_ksyms.c b/trunk/arch/sparc/kernel/sparc_ksyms.c index b0dfff848653..b23cea5ca5d1 100644 --- a/trunk/arch/sparc/kernel/sparc_ksyms.c +++ b/trunk/arch/sparc/kernel/sparc_ksyms.c @@ -38,12 +38,17 @@ #include #include #include +#include #include #include #include #ifdef CONFIG_SBUS +#include #include #endif +#ifdef CONFIG_PCI +#include +#endif #include #include @@ -122,11 +127,16 @@ 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)); @@ -143,9 +153,24 @@ 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); diff --git a/trunk/arch/sparc/kernel/sun4c_irq.c b/trunk/arch/sparc/kernel/sun4c_irq.c index 5dc8a5769489..340fc395fe2d 100644 --- a/trunk/arch/sparc/kernel/sun4c_irq.c +++ b/trunk/arch/sparc/kernel/sun4c_irq.c @@ -18,8 +18,6 @@ #include #include #include -#include -#include #include "irq.h" #include @@ -33,8 +31,15 @@ #include #include #include +#include #include #include +#include + +#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 @@ -59,7 +64,19 @@ * * so don't go making it static, like I tried. sigh. */ -unsigned char __iomem *interrupt_enable = NULL; +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]; +} static void sun4c_disable_irq(unsigned int irq_nr) { @@ -68,7 +85,7 @@ static void sun4c_disable_irq(unsigned int irq_nr) local_irq_save(flags); irq_nr &= (NR_IRQS - 1); - current_mask = sbus_readb(interrupt_enable); + current_mask = *interrupt_enable; switch(irq_nr) { case 1: new_mask = ((current_mask) & (~(SUN4C_INT_E1))); @@ -86,7 +103,7 @@ static void sun4c_disable_irq(unsigned int irq_nr) local_irq_restore(flags); return; } - sbus_writeb(new_mask, interrupt_enable); + *interrupt_enable = new_mask; local_irq_restore(flags); } @@ -97,7 +114,7 @@ static void sun4c_enable_irq(unsigned int irq_nr) local_irq_save(flags); irq_nr &= (NR_IRQS - 1); - current_mask = sbus_readb(interrupt_enable); + current_mask = *interrupt_enable; switch(irq_nr) { case 1: new_mask = ((current_mask) | SUN4C_INT_E1); @@ -115,22 +132,37 @@ static void sun4c_enable_irq(unsigned int irq_nr) local_irq_restore(flags); return; } - sbus_writeb(new_mask, interrupt_enable); + *interrupt_enable = new_mask; local_irq_restore(flags); } -struct sun4c_timer_info { - u32 l10_count; - u32 l10_limit; - u32 l14_count; - u32 l14_limit; -}; +#define TIMER_IRQ 10 /* Also at level 14, but we ignore that one. */ +#define PROFILE_IRQ 14 /* Level14 ticker.. used by OBP for polling */ + +volatile struct sun4c_timer_info *sun4c_timers; -static struct sun4c_timer_info __iomem *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 void sun4c_clear_clock_irq(void) { - sbus_readl(&sun4c_timers->l10_limit); + 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.. */ } static void sun4c_load_profile_irq(int cpu, unsigned int limit) @@ -140,48 +172,41 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit) static void __init sun4c_init_timers(irq_handler_t counter_fn) { - const struct linux_prom_irqs *irq; - struct device_node *dp; - const u32 *addr; - int err; - - dp = of_find_node_by_name(NULL, "counter-timer"); - if (!dp) { - prom_printf("sun4c_init_timers: Unable to find counter-timer\n"); - prom_halt(); - } + int irq; - 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(); - } + /* 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)); /* 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. */ - sbus_writel((((1000000/HZ) + 1) << 10), &sun4c_timers->l10_limit); + sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10); + master_l10_counter = &sun4c_timers->cur_count10; + master_l10_limit = &sun4c_timers->timer_limit10; - master_l10_counter = &sun4c_timers->l10_count; - - err = request_irq(irq[0].pri, counter_fn, + irq = request_irq(TIMER_IRQ, + counter_fn, (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); - if (err) { - prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err); + if (irq) { + prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); prom_halt(); } - sun4c_disable_irq(irq[1].pri); +#if 0 + /* This does not work on 4/330 */ + sun4c_enable_irq(10); +#endif + claim_ticker14(NULL, PROFILE_IRQ, 0); } #ifdef CONFIG_SMP @@ -190,28 +215,41 @@ static void sun4c_nop(void) {} void __init sun4c_init_IRQ(void) { - struct device_node *dp; - const u32 *addr; + struct linux_prom_registers int_regs[2]; + int ie_node; - 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 (ARCH_SUN4) { + interrupt_enable = (char *) + ioremap(sun4_ie_physaddr, PAGE_SIZE); + } else { + struct resource phyres; - addr = of_get_property(dp, "address", NULL); - if (!addr) { - prom_printf("sun4c_init_IRQ: No address property\n"); - prom_halt(); - } + ie_node = prom_searchsiblings (prom_getchild(prom_root_node), + "interrupt-enable"); + if(ie_node == 0) + panic("Cannot find /interrupt-enable node"); - interrupt_enable = (void __iomem *) (unsigned long) addr[0]; + /* 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"); + } + } + if (!interrupt_enable) + panic("Cannot map interrupt_enable"); + BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM); 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 @@ -219,6 +257,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 - sbus_writeb(SUN4C_INT_ENABLE, interrupt_enable); + *interrupt_enable = (SUN4C_INT_ENABLE); /* Cannot enable interrupts until OBP ticker is disabled. */ } diff --git a/trunk/arch/sparc/kernel/sun4d_irq.c b/trunk/arch/sparc/kernel/sun4d_irq.c index d3cb76ce418b..1290b5998f83 100644 --- a/trunk/arch/sparc/kernel/sun4d_irq.c +++ b/trunk/arch/sparc/kernel/sun4d_irq.c @@ -19,8 +19,6 @@ #include #include #include -#include -#include #include #include @@ -36,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -45,22 +44,16 @@ /* 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 { - 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; - +struct sun4d_timer_regs *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; @@ -79,9 +72,9 @@ static int sbus_to_pil[] = { }; static int nsbi; - -/* Exported for sun4d_smp.c */ +#ifdef CONFIG_SMP DEFINE_SPINLOCK(sun4d_imsk_lock); +#endif int show_sun4d_interrupts(struct seq_file *p, void *v) { @@ -264,6 +257,26 @@ 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) @@ -347,28 +360,36 @@ int sun4d_request_irq(unsigned int irq, 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; - + if (irq < NR_IRQS) return; +#ifdef CONFIG_SMP 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; - + if (irq < NR_IRQS) return; +#ifdef CONFIG_SMP 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 @@ -388,55 +409,47 @@ static void sun4d_set_udt(int cpu) /* Setup IRQ distribution scheme. */ void __init sun4d_distribute_irqs(void) { - struct device_node *dp; - #ifdef DISTRIBUTE_IRQS - cpumask_t sbus_serving_map; + struct sbus_bus *sbus; + unsigned long sbus_serving_map; sbus_serving_map = cpu_present_map; - 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); + 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); else - sbus_tid[board] = 0xff; - if (sbus_tid[board] != 0xff) - cpu_clear(sbus_tid[board], sbus_serving_map); + sbus_tid[sbus->board] = 0xff; + if (sbus_tid[sbus->board] != 0xff) + sbus_serving_map &= ~(1 << sbus_tid[sbus->board]); } - for_each_node_by_name(dp, "sbi") { - int board = of_getintprop_default(dp, "board#", 0); - if (sbus_tid[board] == 0xff) { + for_each_sbus(sbus) + if (sbus_tid[sbus->board] == 0xff) { int i = 31; - if (cpus_empty(sbus_serving_map)) + if (!sbus_serving_map) sbus_serving_map = cpu_present_map; - while (cpu_isset(i, sbus_serving_map)) + while (!(sbus_serving_map & (1 << i))) i--; - sbus_tid[board] = i; - cpu_clear(i, sbus_serving_map); + sbus_tid[sbus->board] = i; + sbus_serving_map &= ~(1 << i); } - } - 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); + 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); } #else + struct sbus_bus *sbus; int cpuid = cpu_logical_map(1); if (cpuid == -1) cpuid = cpu_logical_map(0); - 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); + for_each_sbus(sbus) { + sbus_tid[sbus->board] = cpuid; + set_sbi_tid(sbus->devid, cpuid << 3); } printk("All sbus IRQs directed to CPU%d\n", cpuid); #endif @@ -445,129 +458,112 @@ void __init sun4d_distribute_irqs(void) static void sun4d_clear_clock_irq(void) { - sbus_readl(&sun4d_timers->l10_timer_limit); + volatile unsigned int clear_intr; + clear_intr = sun4d_timers->l10_timer_limit; } -static void sun4d_load_profile_irq(int cpu, unsigned int limit) +static void sun4d_clear_profile_irq(int cpu) { - bw_set_prof_limit(cpu, limit); + bw_get_prof_limit(cpu); } -static void __init sun4d_load_profile_irqs(void) -{ - int cpu = 0, mid; - - while (!cpu_find_by_instance(cpu, NULL, &mid)) { - sun4d_load_profile_irq(mid >> 3, 0); - cpu++; - } -} - -static void __init sun4d_fixup_trap_table(void) +static void sun4d_load_profile_irq(int cpu, unsigned int limit) { -#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[]; - - /* 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); -#endif + bw_set_prof_limit(cpu, limit); } 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(); - } + int irq; + int cpu; + struct resource r; + int mid; - /* 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); + /* 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; - err = request_irq(TIMER_IRQ, counter_fn, + irq = 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); + if (irq) { + prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); prom_halt(); } - sun4d_load_profile_irqs(); - sun4d_fixup_trap_table(); + + /* 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++; + } + +#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[]; + + /* 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); + } +#endif } void __init sun4d_init_sbi_irq(void) { - struct device_node *dp; - int target_cpu = 0; - -#ifdef CONFIG_SMP - target_cpu = boot_cpu_id; -#endif + struct sbus_bus *sbus; + unsigned mask; nsbi = 0; - for_each_node_by_name(dp, "sbi") + for_each_sbus(sbus) 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_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; - + 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 /* Get rid of pending irqs from PROM */ - mask = acquire_sbi(devid, 0xffffffff); + mask = acquire_sbi(sbus->devid, 0xffffffff); if (mask) { - printk ("Clearing pending IRQs %08x on SBI %d\n", mask, board); - release_sbi(devid, mask); + printk ("Clearing pending IRQs %08x on SBI %d\n", mask, sbus->board); + release_sbi(sbus->devid, mask); } } } @@ -576,9 +572,11 @@ 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 diff --git a/trunk/arch/sparc/kernel/sun4d_smp.c b/trunk/arch/sparc/kernel/sun4d_smp.c index ce3d45db94e9..446767e8f569 100644 --- a/trunk/arch/sparc/kernel/sun4d_smp.c +++ b/trunk/arch/sparc/kernel/sun4d_smp.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -71,17 +72,6 @@ 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(); diff --git a/trunk/arch/sparc/kernel/sun4m_irq.c b/trunk/arch/sparc/kernel/sun4m_irq.c index f10317179ee6..94e02de960ea 100644 --- a/trunk/arch/sparc/kernel/sun4m_irq.c +++ b/trunk/arch/sparc/kernel/sun4m_irq.c @@ -20,8 +20,6 @@ #include #include #include -#include -#include #include #include @@ -37,27 +35,59 @@ #include #include #include +#include #include #include "irq.h" -struct sun4m_irq_percpu { - u32 pending; - u32 clear; - u32 set; +/* 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_global { - u32 pending; - u32 mask; - u32 mask_clear; - u32 mask_set; - u32 interrupt_target; +/* + * 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. */ }; -/* 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; +static unsigned long dummy; + +struct sun4m_intregs *sun4m_interrupts; +unsigned long *irq_rcvreg = &dummy; /* Dave Redman (djhr@tadpole.co.uk) * The sun4m interrupt registers. @@ -71,9 +101,8 @@ struct sun4m_irq_global __iomem *sun4m_irq_global; #define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ #define SUN4M_INT_MODULE_ERR 0x40000000 /* module 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_M2S_WRITE 0x20000000 /* write buffer error */ +#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */ #define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ #define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ #define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ @@ -84,126 +113,75 @@ struct sun4m_irq_global __iomem *sun4m_irq_global; #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)) -/* 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: - * - * 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) +/* 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. * - * 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. + * take an encoded intr value and lookup if it's valid + * then get the mask bits that match from irq_mask * - * 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) + * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee. */ +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 < 0x50) - mask = irq_mask[irq]; - else - mask = 0; - - if (!mask) - printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n", - irq); - + 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); + } return mask; } @@ -215,9 +193,9 @@ static void sun4m_disable_irq(unsigned int irq_nr) mask = sun4m_get_irqmask(irq_nr); local_irq_save(flags); if (irq_nr > 15) - sbus_writel(mask, &sun4m_irq_global->mask_set); + sun4m_interrupts->set = mask; else - sbus_writel(mask, &sun4m_irq_percpu[cpu]->set); + sun4m_interrupts->cpu_intregs[cpu].set = mask; local_irq_restore(flags); } @@ -234,13 +212,13 @@ static void sun4m_enable_irq(unsigned int irq_nr) mask = sun4m_get_irqmask(irq_nr); local_irq_save(flags); if (irq_nr > 15) - sbus_writel(mask, &sun4m_irq_global->mask_clear); + sun4m_interrupts->clear = mask; else - sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear); + sun4m_interrupts->cpu_intregs[cpu].clear = mask; local_irq_restore(flags); } else { local_irq_save(flags); - sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear); + sun4m_interrupts->clear = SUN4M_INT_FLOPPY; local_irq_restore(flags); } } @@ -258,10 +236,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_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO, +/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, +/*13*/ SUN4M_INT_AUDIO, /*14*/ SUN4M_INT_E14, -/*15*/ SUN4M_INT_ERROR +/*15*/ 0x00000000 }; /* We assume the caller has disabled local interrupts when these are called, @@ -269,141 +247,126 @@ static unsigned long cpu_pil_to_imask[16] = { */ static void sun4m_disable_pil_irq(unsigned int pil) { - sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set); + sun4m_interrupts->set = cpu_pil_to_imask[pil]; } static void sun4m_enable_pil_irq(unsigned int pil) { - sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear); + sun4m_interrupts->clear = cpu_pil_to_imask[pil]; } #ifdef CONFIG_SMP static void sun4m_send_ipi(int cpu, int level) { - unsigned long mask = sun4m_get_irqmask(level); - sbus_writel(mask, &sun4m_irq_percpu[cpu]->set); + unsigned long mask; + + mask = sun4m_get_irqmask(level); + sun4m_interrupts->cpu_intregs[cpu].set = mask; } static void sun4m_clear_ipi(int cpu, int level) { - unsigned long mask = sun4m_get_irqmask(level); - sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear); + unsigned long mask; + + mask = sun4m_get_irqmask(level); + sun4m_interrupts->cpu_intregs[cpu].clear = mask; } static void sun4m_set_udt(int cpu) { - sbus_writel(cpu, &sun4m_irq_global->interrupt_target); + sun4m_interrupts->undirected_target = cpu; } #endif -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) +#define OBIO_INTR 0x20 +#define TIMER_IRQ (OBIO_INTR | 10) +#define PROFILE_IRQ (OBIO_INTR | 14) +static struct sun4m_timer_regs *sun4m_timers; unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); static void sun4m_clear_clock_irq(void) { - sbus_readl(&timers_global->l10_limit); -} - -void sun4m_nmi(struct pt_regs *regs) -{ - 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(); + volatile unsigned int clear_intr; + clear_intr = sun4m_timers->l10_timer_limit; } -/* Exported for sun4m_smp.c */ -void sun4m_clear_profile_irq(int cpu) +static void sun4m_clear_profile_irq(int cpu) { - sbus_readl(&timers_percpu[cpu]->l14_limit); + volatile unsigned int clear; + + clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit; } static void sun4m_load_profile_irq(int cpu, unsigned int limit) { - sbus_writel(limit, &timers_percpu[cpu]->l14_limit); + sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit; } static void __init sun4m_init_timers(irq_handler_t counter_fn) { - struct device_node *dp = of_find_node_by_name(NULL, "counter"); - int i, err, len, num_cpu_timers; - const u32 *addr; - - if (!dp) { - printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n"); - return; + int reg_count, irq, cpu; + struct linux_prom_registers cnt_regs[PROMREG_MAX]; + int obio_node, cnt_node; + struct resource r; + + 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(); } - - addr = of_get_property(dp, "address", &len); - if (!addr) { - printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n"); - return; + 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; } - num_cpu_timers = (len / sizeof(u32)) - 1; - for (i = 0; i < num_cpu_timers; i++) { - timers_percpu[i] = (void __iomem *) - (unsigned long) addr[i]; + 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(); } - 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; + + 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; } - - 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; @@ -427,43 +390,70 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn) void __init sun4m_init_IRQ(void) { - 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; + int ie_node,i; + struct linux_prom_registers int_regs[PROMREG_MAX]; + int num_regs; + struct resource r; + int mid; + + 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(); } - - addr = of_get_property(dp, "address", &len); - if (!addr) { - printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n"); - return; + 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; } - 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]; + 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"); - local_irq_disable(); + /* 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"); - sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set); + sun4m_interrupts->set = ~SUN4M_INT_MASKALL; for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) - sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear); - - if (num_cpu_iregs == 4) - sbus_writel(0, &sun4m_irq_global->interrupt_target); - + sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff; + + 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 @@ -471,6 +461,5 @@ 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. */ } diff --git a/trunk/arch/sparc/kernel/sun4m_smp.c b/trunk/arch/sparc/kernel/sun4m_smp.c index 0c564ba9e709..9964890dc1db 100644 --- a/trunk/arch/sparc/kernel/sun4m_smp.c +++ b/trunk/arch/sparc/kernel/sun4m_smp.c @@ -315,8 +315,6 @@ 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; @@ -324,7 +322,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs) old_regs = set_irq_regs(regs); - sun4m_clear_profile_irq(cpu); + clear_profile_irq(cpu); profile_tick(CPU_PROFILING); diff --git a/trunk/arch/sparc/kernel/sun4setup.c b/trunk/arch/sparc/kernel/sun4setup.c new file mode 100644 index 000000000000..229a52f55f16 --- /dev/null +++ b/trunk/arch/sparc/kernel/sun4setup.c @@ -0,0 +1,75 @@ +/* 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 +#include +#include +#include +#include + +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: + ; + } +} + diff --git a/trunk/arch/sparc/kernel/sys_sparc.c b/trunk/arch/sparc/kernel/sys_sparc.c index 03035c852a43..4d73421559c3 100644 --- a/trunk/arch/sparc/kernel/sys_sparc.c +++ b/trunk/arch/sparc/kernel/sys_sparc.c @@ -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 && len > 0x20000000) + if (ARCH_SUN4C_SUN4 && 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 && addr < 0xe0000000 && 0x20000000 - len < addr) { + if (ARCH_SUN4C_SUN4 && 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) { + if(ARCH_SUN4C_SUN4) { if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000)) return current->mm->brk; } @@ -221,7 +221,7 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void __user int sparc_mmap_check(unsigned long addr, unsigned long len) { - if (ARCH_SUN4C && + if (ARCH_SUN4C_SUN4 && (len > 0x20000000 || (addr < 0xe0000000 && addr + len > 0x20000000))) return -EINVAL; diff --git a/trunk/arch/sparc/kernel/tick14.c b/trunk/arch/sparc/kernel/tick14.c index 138bbf5f8724..707bfda86570 100644 --- a/trunk/arch/sparc/kernel/tick14.c +++ b/trunk/arch/sparc/kernel/tick14.c @@ -1,12 +1,31 @@ /* 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 +#include #include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "irq.h" extern unsigned long lvl14_save[5]; static unsigned long *linux_lvl14 = NULL; @@ -37,3 +56,31 @@ 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); + } +} diff --git a/trunk/arch/sparc/kernel/time.c b/trunk/arch/sparc/kernel/time.c index 62c1d94cb434..0762f5db1924 100644 --- a/trunk/arch/sparc/kernel/time.c +++ b/trunk/arch/sparc/kernel/time.c @@ -23,24 +23,22 @@ #include #include #include -#include -#include #include #include #include #include #include -#include #include -#include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -48,9 +46,34 @@ #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[]; @@ -73,6 +96,7 @@ 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, @@ -92,7 +116,15 @@ 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); @@ -115,56 +147,157 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id) return IRQ_HANDLED; } -static unsigned char mostek_read_byte(struct device *dev, u32 ofs) +/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ +static void __devinit kick_start_clock(void) { - 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); - - /* the year 0 is 1968 */ - if (ofs == pdata->offset + M48T59_YEAR) { - val += 0x68; - if ((val & 0xf) > 9) - val += 6; + struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; + unsigned char sec; + int i, count; + + 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; + } + prom_printf("\n"); + + spin_lock_irq(&mostek_lock); + + /* 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); } - return val; + + prom_printf("CLOCK: Kick start procedure successful.\n"); } -static void mostek_write_byte(struct device *dev, u32 ofs, u8 val) +/* Return nonzero if the clock chip battery is low. */ +static inline int has_low_battery(void) { - struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; - void __iomem *regs = pdata->ioaddr; - - 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; - } - writeb(val, regs + ofs); + struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; + unsigned char data1, data2; + + 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); + + return (data1 == data2); /* Was the write blocked? */ } -static struct m48t59_plat_data m48t59_data = { - .read_byte = mostek_read_byte, - .write_byte = mostek_write_byte, -}; +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); +} -/* resource is set at runtime */ -static struct platform_device m48t59_rtc = { - .name = "rtc-m48t59", - .id = 0, - .num_resources = 1, - .dev = { - .platform_data = &m48t59_data, - }, -}; +/* 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; @@ -173,26 +306,38 @@ 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 */ - m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0, - 2048, "rtc-m48t59"); - m48t59_data.type = M48T59RTC_TYPE_M48T02; + mstk48t02_regs = of_ioremap(&op->resource[0], 0, + sizeof(struct mostek48t02), + "mk48t02"); + mstk48t08_regs = NULL; /* To catch weirdness */ } else if (!strcmp(model, "mk48t08")) { - m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0, - 8192, "rtc-m48t59"); - m48t59_data.type = M48T59RTC_TYPE_M48T08; + sp_clock_typ = MSTK48T08; + mstk48t08_regs = of_ioremap(&op->resource[0], 0, + sizeof(struct mostek48t08), + "mk48t08"); + + mstk48t02_regs = &mstk48t08_regs->regs; } else return -ENODEV; - if (platform_device_register(&m48t59_rtc) < 0) - printk(KERN_ERR "Registering RTC device failed\n"); + /* 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(); return 0; } -static struct of_device_id __initdata clock_match[] = { +static struct of_device_id clock_match[] = { { .name = "eeprom", }, @@ -203,7 +348,7 @@ static struct of_platform_driver clock_driver = { .match_table = clock_match, .probe = clock_probe, .driver = { - .name = "rtc", + .name = "clock", }, }; @@ -219,6 +364,7 @@ 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) { @@ -226,8 +372,51 @@ 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(); } @@ -333,15 +522,80 @@ static int sbus_do_settimeofday(struct timespec *tv) return 0; } -static int set_rtc_mmss(unsigned long secs) +/* + * 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) { - struct rtc_device *rtc = rtc_class_open("rtc0"); - int err = -1; + 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 - if (rtc) { - err = rtc_set_mmss(rtc, secs); - rtc_class_close(rtc); + /* 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 } - return err; + 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; + } } diff --git a/trunk/arch/sparc/kernel/traps.c b/trunk/arch/sparc/kernel/traps.c index 2b7d50659036..5d45d5fd8c99 100644 --- a/trunk/arch/sparc/kernel/traps.c +++ b/trunk/arch/sparc/kernel/traps.c @@ -43,6 +43,23 @@ 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"); diff --git a/trunk/arch/sparc/mm/Makefile b/trunk/arch/sparc/mm/Makefile index ea88955d97ff..109c8b22cb38 100644 --- a/trunk/arch/sparc/mm/Makefile +++ b/trunk/arch/sparc/mm/Makefile @@ -3,8 +3,13 @@ EXTRA_AFLAGS := -ansi -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 +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 ifdef CONFIG_HIGHMEM obj-y += highmem.o diff --git a/trunk/arch/sparc/mm/btfixup.c b/trunk/arch/sparc/mm/btfixup.c index 5175ac2f4820..a312d127d47a 100644 --- a/trunk/arch/sparc/mm/btfixup.c +++ b/trunk/arch/sparc/mm/btfixup.c @@ -20,7 +20,11 @@ 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"; @@ -82,7 +86,7 @@ void __init btfixup(void) if (!visited) { visited++; printk(version); - if (ARCH_SUN4C) + if (ARCH_SUN4C_SUN4) printk(str_sun4c); else { printk(str_srmmu, srmmu_name); diff --git a/trunk/arch/sparc/mm/fault.c b/trunk/arch/sparc/mm/fault.c index a507e1174662..3604c2e86709 100644 --- a/trunk/arch/sparc/mm/fault.c +++ b/trunk/arch/sparc/mm/fault.c @@ -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 && address >= TASK_SIZE) + if (!ARCH_SUN4C_SUN4 && address >= TASK_SIZE) goto vmalloc_fault; info.si_code = SEGV_MAPERR; diff --git a/trunk/arch/sparc/mm/init.c b/trunk/arch/sparc/mm/init.c index 677c1e187a23..e103f1bb3777 100644 --- a/trunk/arch/sparc/mm/init.c +++ b/trunk/arch/sparc/mm/init.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -481,7 +480,6 @@ 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); @@ -490,26 +488,20 @@ 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; - - memset((void *)start, POISON_FREE_INITMEM, PAGE_SIZE); - p = virt_to_page(start); + struct page *p = virt_to_page(start); ClearPageReserved(p); init_page_count(p); __free_page(p); - totalram_pages++; num_physpages++; } } diff --git a/trunk/arch/sparc/mm/io-unit.c b/trunk/arch/sparc/mm/io-unit.c index daadf5f88050..f167835db3df 100644 --- a/trunk/arch/sparc/mm/io-unit.c +++ b/trunk/arch/sparc/mm/io-unit.c @@ -12,11 +12,10 @@ #include /* pte_offset_map => kmap_atomic */ #include #include -#include -#include #include #include +#include #include #include #include @@ -35,10 +34,13 @@ #define IOPERM (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID) #define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM) -static void __init iounit_iommu_init(struct of_device *op) +void __init +iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus) { - struct iounit_struct *iounit; iopte_t *xpt, *xptend; + struct iounit_struct *iounit; + struct linux_prom_registers iommu_promregs[PROMREG_MAX]; + struct resource r; iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC); if (!iounit) { @@ -53,13 +55,18 @@ static void __init iounit_iommu_init(struct of_device *op) iounit->rotor[1] = IOUNIT_BMAP2_START; iounit->rotor[2] = IOUNIT_BMAPM_START; - xpt = of_ioremap(&op->resource[2], 0, PAGE_SIZE * 16, "XPT"); - if (!xpt) { - prom_printf("SUN4D: Cannot map External Page Table."); - prom_halt(); + 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"); } + if(!xpt) panic("Cannot map External Page Table."); - op->dev.archdata.iommu = iounit; + sbus->ofdev.dev.archdata.iommu = iounit; iounit->page_table = xpt; spin_lock_init(&iounit->lock); @@ -68,25 +75,6 @@ static void __init iounit_iommu_init(struct of_device *op) 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) { @@ -136,10 +124,10 @@ nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan); return vaddr; } -static __u32 iounit_get_scsi_one(struct device *dev, char *vaddr, unsigned long len) +static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus *sbus) { - 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); @@ -147,10 +135,10 @@ static __u32 iounit_get_scsi_one(struct device *dev, char *vaddr, unsigned long return ret; } -static void iounit_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz) +static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { - 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); @@ -163,10 +151,10 @@ static void iounit_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int spin_unlock_irqrestore(&iounit->lock, flags); } -static void iounit_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len) +static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus) { - 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; @@ -177,11 +165,11 @@ static void iounit_release_scsi_one(struct device *dev, __u32 vaddr, unsigned lo spin_unlock_irqrestore(&iounit->lock, flags); } -static void iounit_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz) +static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { - 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) { @@ -197,12 +185,12 @@ static void iounit_release_scsi_sgl(struct device *dev, struct scatterlist *sg, } #ifdef CONFIG_SBUS -static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, __u32 addr, int len) +static int iounit_map_dma_area(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; @@ -224,8 +212,12 @@ static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned lon i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT); - iopte = (iopte_t *)(iounit->page_table + i); - *iopte = MKIOPTE(__pa(page)); + for_each_sbus(sbus) { + struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu; + + iopte = (iopte_t *)(iounit->page_table + i); + *iopte = MKIOPTE(__pa(page)); + } } addr += PAGE_SIZE; va += PAGE_SIZE; @@ -236,10 +228,23 @@ static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned lon return 0; } -static void iounit_unmap_dma_area(struct device *dev, unsigned long addr, int len) +static void iounit_unmap_dma_area(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) @@ -266,5 +271,54 @@ 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); +} diff --git a/trunk/arch/sparc/mm/iommu.c b/trunk/arch/sparc/mm/iommu.c index e7a499e3aa3c..4b934270f05e 100644 --- a/trunk/arch/sparc/mm/iommu.c +++ b/trunk/arch/sparc/mm/iommu.c @@ -13,11 +13,10 @@ #include #include /* pte_offset_map => kmap_atomic */ #include -#include -#include #include #include +#include #include #include #include @@ -56,21 +55,30 @@ 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) -static void __init sbus_iommu_init(struct of_device *op) +void __init +iommu_init(int iommund, struct sbus_bus *sbus) { - struct iommu_struct *iommu; unsigned int impl, vers; - unsigned long *bitmap; unsigned long tmp; + struct iommu_struct *iommu; + struct linux_prom_registers iommu_promregs[PROMREG_MAX]; + struct resource r; + unsigned long *bitmap; iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC); if (!iommu) { prom_printf("Unable to allocate iommu structure\n"); prom_halt(); } - - iommu->regs = of_ioremap(&op->resource[0], 0, PAGE_SIZE * 3, - "iommu_regs"); + 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"); + } if (!iommu->regs) { prom_printf("Cannot map IOMMU registers\n"); prom_halt(); @@ -120,29 +128,13 @@ static void __init sbus_iommu_init(struct of_device *op) else iommu->usemap.num_colors = 1; - 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); - - 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); - } + 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); - return 0; + sbus->ofdev.dev.archdata.iommu = iommu; } -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. */ @@ -172,9 +164,9 @@ static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte) } } -static u32 iommu_get_one(struct device *dev, struct page *page, int npages) +static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus) { - struct iommu_struct *iommu = dev->archdata.iommu; + struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu; int ioptex; iopte_t *iopte, *iopte0; unsigned int busa, busa0; @@ -202,7 +194,8 @@ static u32 iommu_get_one(struct device *dev, struct page *page, int npages) return busa0; } -static u32 iommu_get_scsi_one(struct device *dev, char *vaddr, unsigned int len) +static u32 iommu_get_scsi_one(char *vaddr, unsigned int len, + struct sbus_bus *sbus) { unsigned long off; int npages; @@ -212,22 +205,22 @@ static u32 iommu_get_scsi_one(struct device *dev, 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(dev, page, npages); + busa = iommu_get_one(page, npages, sbus); return busa + off; } -static __u32 iommu_get_scsi_one_noflush(struct device *dev, char *vaddr, unsigned long len) +static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct sbus_bus *sbus) { - return iommu_get_scsi_one(dev, vaddr, len); + return iommu_get_scsi_one(vaddr, len, sbus); } -static __u32 iommu_get_scsi_one_gflush(struct device *dev, char *vaddr, unsigned long len) +static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct sbus_bus *sbus) { flush_page_for_dma(0); - return iommu_get_scsi_one(dev, vaddr, len); + return iommu_get_scsi_one(vaddr, len, sbus); } -static __u32 iommu_get_scsi_one_pflush(struct device *dev, char *vaddr, unsigned long len) +static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sbus_bus *sbus) { unsigned long page = ((unsigned long) vaddr) & PAGE_MASK; @@ -235,23 +228,23 @@ static __u32 iommu_get_scsi_one_pflush(struct device *dev, char *vaddr, unsigned flush_page_for_dma(page); page += PAGE_SIZE; } - return iommu_get_scsi_one(dev, vaddr, len); + return iommu_get_scsi_one(vaddr, len, sbus); } -static void iommu_get_scsi_sgl_noflush(struct device *dev, struct scatterlist *sg, int sz) +static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { int n; while (sz != 0) { --sz; n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; - sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset; + sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset; sg->dvma_length = (__u32) sg->length; sg = sg_next(sg); } } -static void iommu_get_scsi_sgl_gflush(struct device *dev, struct scatterlist *sg, int sz) +static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { int n; @@ -259,13 +252,13 @@ static void iommu_get_scsi_sgl_gflush(struct device *dev, struct scatterlist *sg while (sz != 0) { --sz; n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; - sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset; + sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset; sg->dvma_length = (__u32) sg->length; sg = sg_next(sg); } } -static void iommu_get_scsi_sgl_pflush(struct device *dev, struct scatterlist *sg, int sz) +static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { unsigned long page, oldpage = 0; int n, i; @@ -290,15 +283,15 @@ static void iommu_get_scsi_sgl_pflush(struct device *dev, struct scatterlist *sg } } - sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset; + sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset; sg->dvma_length = (__u32) sg->length; sg = sg_next(sg); } } -static void iommu_release_one(struct device *dev, u32 busa, int npages) +static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus) { - struct iommu_struct *iommu = dev->archdata.iommu; + struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu; int ioptex; int i; @@ -312,17 +305,17 @@ static void iommu_release_one(struct device *dev, u32 busa, int npages) bit_map_clear(&iommu->usemap, ioptex, npages); } -static void iommu_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len) +static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus) { unsigned long off; int npages; off = vaddr & ~PAGE_MASK; npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT; - iommu_release_one(dev, vaddr & PAGE_MASK, npages); + iommu_release_one(vaddr & PAGE_MASK, npages, sbus); } -static void iommu_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz) +static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { int n; @@ -330,18 +323,18 @@ static void iommu_release_scsi_sgl(struct device *dev, struct scatterlist *sg, i --sz; n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; - iommu_release_one(dev, sg->dvma_address & PAGE_MASK, n); + iommu_release_one(sg->dvma_address & PAGE_MASK, n, sbus); sg->dvma_address = 0x21212121; sg = sg_next(sg); } } #ifdef CONFIG_SBUS -static int iommu_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, - unsigned long addr, int len) +static int iommu_map_dma_area(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; @@ -404,9 +397,9 @@ static int iommu_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long return 0; } -static void iommu_unmap_dma_area(struct device *dev, unsigned long busa, int len) +static void iommu_unmap_dma_area(unsigned long busa, int len) { - struct iommu_struct *iommu = dev->archdata.iommu; + struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu; iopte_t *iopte = iommu->page_table; unsigned long end; int ioptex = (busa - iommu->start) >> PAGE_SHIFT; @@ -424,6 +417,15 @@ static void iommu_unmap_dma_area(struct device *dev, 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) @@ -459,6 +461,7 @@ 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) { diff --git a/trunk/arch/sparc/mm/nosrmmu.c b/trunk/arch/sparc/mm/nosrmmu.c new file mode 100644 index 000000000000..3701f70fc30a --- /dev/null +++ b/trunk/arch/sparc/mm/nosrmmu.c @@ -0,0 +1,59 @@ +/* + * 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 +#include +#include +#include +#include + +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; +} diff --git a/trunk/arch/sparc/mm/srmmu.c b/trunk/arch/sparc/mm/srmmu.c index 6a5d7cabc044..ee30462598fc 100644 --- a/trunk/arch/sparc/mm/srmmu.c +++ b/trunk/arch/sparc/mm/srmmu.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/sparc/mm/sun4c.c b/trunk/arch/sparc/mm/sun4c.c index fe65aeeb3947..d1782f6368be 100644 --- a/trunk/arch/sparc/mm/sun4c.c +++ b/trunk/arch/sparc/mm/sun4c.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -51,11 +52,15 @@ 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 @@ -280,32 +285,75 @@ void __init sun4c_probe_vac(void) { sun4c_disable_vac(); - 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; + 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(); + }; } else { - 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); + sun4c_vacinfo.type = VAC_WRITE_THROUGH; - if (sun4c_vacinfo.do_hwflushes == 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); + } sun4c_vacinfo.do_hwflushes = - prom_getintdefault(prom_root_node, "vac_hwflush", 0); + 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.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(); + } } + sun4c_vacinfo.num_lines = + (sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize); switch (sun4c_vacinfo.linesize) { case 16: sun4c_vacinfo.log2lsize = 4; @@ -399,18 +447,49 @@ static void __init patch_kernel_fault_handler(void) static void __init sun4c_probe_mmu(void) { - 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; + 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(); + }; } else { - num_segmaps = - prom_getintdefault(prom_root_node, "mmu-npmg", 128); - num_contexts = - prom_getintdefault(prom_root_node, "mmu-nctx", 0x8); + 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); + } } patch_kernel_fault_handler(); } @@ -422,14 +501,18 @@ void __init sun4c_probe_memerr_reg(void) int node; struct linux_prom_registers regs[1]; - 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); + 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); + } } static inline void sun4c_init_ss2_cache_bug(void) @@ -438,6 +521,7 @@ 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"); @@ -448,8 +532,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(struct device *dev, dma_addr_t *pba, unsigned long va, - unsigned long addr, int len) +static int sun4c_map_dma_area(dma_addr_t *pba, unsigned long va, + unsigned long addr, int len) { unsigned long page, end; @@ -471,7 +555,14 @@ static int sun4c_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long return 0; } -static void sun4c_unmap_dma_area(struct device *dev, unsigned long busa, int len) +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) { /* Fortunately for us, bus_addr == uncached_virt in sun4c. */ /* XXX Implement this */ @@ -533,7 +624,11 @@ 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) { @@ -545,7 +640,9 @@ 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; @@ -951,10 +1048,14 @@ 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); @@ -971,11 +1072,13 @@ 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; @@ -1108,7 +1211,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(struct device *dev, char *bufptr, unsigned long len) +static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct sbus_bus *sbus) { unsigned long page; @@ -1120,7 +1223,7 @@ static __u32 sun4c_get_scsi_one(struct device *dev, char *bufptr, unsigned long return (__u32)sun4c_lockarea(bufptr, len); } -static void sun4c_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz) +static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { while (sz != 0) { --sz; @@ -1130,14 +1233,14 @@ static void sun4c_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int s } } -static void sun4c_release_scsi_one(struct device *dev, __u32 bufptr, unsigned long len) +static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct sbus_bus *sbus) { 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 device *dev, struct scatterlist *sg, int sz) +static void sun4c_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { while (sz != 0) { --sz; @@ -2160,6 +2263,7 @@ 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); diff --git a/trunk/arch/sparc/prom/Makefile b/trunk/arch/sparc/prom/Makefile index 8f7e18546c97..7f5eacfcfbcf 100644 --- a/trunk/arch/sparc/prom/Makefile +++ b/trunk/arch/sparc/prom/Makefile @@ -4,3 +4,5 @@ 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 diff --git a/trunk/arch/sparc/prom/bootstr.c b/trunk/arch/sparc/prom/bootstr.c index 916831da7e67..5a35c768ff7c 100644 --- a/trunk/arch/sparc/prom/bootstr.c +++ b/trunk/arch/sparc/prom/bootstr.c @@ -6,12 +6,15 @@ #include #include +#include #include #define BARG_LEN 256 static char barg_buf[BARG_LEN] = { 0 }; static char fetched __initdata = 0; +extern linux_sun4_romvec *sun4_romvec; + char * __init prom_getbootargs(void) { @@ -25,6 +28,7 @@ prom_getbootargs(void) switch(prom_vers) { case PROM_V0: + case PROM_SUN4: cp = barg_buf; /* Start from 1 and go over fd(0,0,0)kernel */ for(iter = 1; iter < 8; iter++) { diff --git a/trunk/arch/sparc/prom/console.c b/trunk/arch/sparc/prom/console.c index b3075d73fc19..790057a34616 100644 --- a/trunk/arch/sparc/prom/console.c +++ b/trunk/arch/sparc/prom/console.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,7 @@ prom_nbgetchar(void) spin_lock_irqsave(&prom_lock, flags); switch(prom_vers) { case PROM_V0: + case PROM_SUN4: i = (*(romvec->pv_nbgetchar))(); break; case PROM_V2: @@ -61,6 +63,7 @@ prom_nbputchar(char c) spin_lock_irqsave(&prom_lock, flags); switch(prom_vers) { case PROM_V0: + case PROM_SUN4: i = (*(romvec->pv_nbputchar))(c); break; case PROM_V2: diff --git a/trunk/arch/sparc/prom/init.c b/trunk/arch/sparc/prom/init.c index 873217c6d823..729f87066945 100644 --- a/trunk/arch/sparc/prom/init.c +++ b/trunk/arch/sparc/prom/init.c @@ -11,10 +11,12 @@ #include #include +#include struct linux_romvec *romvec; enum prom_major_version prom_vers; unsigned int prom_rev, prom_prev; +linux_sun4_romvec *sun4_romvec; /* The root node of the prom device tree. */ int prom_root_node; @@ -32,6 +34,10 @@ extern void prom_ranges_init(void); void __init prom_init(struct linux_romvec *rp) { +#ifdef CONFIG_SUN4 + extern struct linux_romvec *sun4_prom_init(void); + rp = sun4_prom_init(); +#endif romvec = rp; switch(romvec->pv_romvers) { @@ -44,6 +50,9 @@ void __init prom_init(struct linux_romvec *rp) case 3: prom_vers = PROM_V3; break; + case 40: + prom_vers = PROM_SUN4; + break; default: prom_printf("PROMLIB: Bad PROM version %d\n", romvec->pv_romvers); @@ -67,8 +76,11 @@ void __init prom_init(struct linux_romvec *rp) prom_ranges_init(); +#ifndef CONFIG_SUN4 + /* SUN4 prints this in sun4_prom_init */ printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n", romvec->pv_romvers, prom_rev); +#endif /* Initialization successful. */ return; diff --git a/trunk/arch/sparc/prom/memory.c b/trunk/arch/sparc/prom/memory.c index fac7899a29c3..947f047dc95a 100644 --- a/trunk/arch/sparc/prom/memory.c +++ b/trunk/arch/sparc/prom/memory.c @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -45,6 +46,15 @@ static int __init prom_meminit_v2(void) return num_ents; } +static int __init prom_meminit_sun4(void) +{ +#ifdef CONFIG_SUN4 + sp_banks[0].base_addr = 0; + sp_banks[0].num_bytes = *(sun4_romvec->memoryavail); +#endif + return 1; +} + static int sp_banks_cmp(const void *a, const void *b) { const struct sparc_phys_banks *x = a, *y = b; @@ -71,6 +81,10 @@ void __init prom_meminit(void) num_ents = prom_meminit_v2(); break; + case PROM_SUN4: + num_ents = prom_meminit_sun4(); + break; + default: break; } diff --git a/trunk/arch/sparc/prom/ranges.c b/trunk/arch/sparc/prom/ranges.c index 64579a376419..f9b7def35f6e 100644 --- a/trunk/arch/sparc/prom/ranges.c +++ b/trunk/arch/sparc/prom/ranges.c @@ -9,6 +9,7 @@ #include #include #include +#include #include struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX]; diff --git a/trunk/arch/sparc/prom/sun4prom.c b/trunk/arch/sparc/prom/sun4prom.c new file mode 100644 index 000000000000..00390a2652aa --- /dev/null +++ b/trunk/arch/sparc/prom/sun4prom.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 1996 The Australian National University. + * Copyright (C) 1996 Fujitsu Laboratories Limited + * Copyright (C) 1997 Michael A. Griffith (grif@acm.org) + * Copyright (C) 1997 Sun Weenie (ko@ko.reno.nv.us) + * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + * + * fake a really simple Sun prom for the SUN4 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct linux_romvec sun4romvec; +static struct idprom sun4_idprom; + +struct property { + char *name; + char *value; + int length; +}; + +struct node { + int level; + struct property *properties; +}; + +struct property null_properties = { NULL, NULL, -1 }; + +struct property root_properties[] = { + {"device_type", "cpu", 4}, + {"idprom", (char *)&sun4_idprom, sizeof(struct idprom)}, + {NULL, NULL, -1} +}; + +struct node nodes[] = { + { 0, &null_properties }, + { 0, root_properties }, + { -1,&null_properties } +}; + + +static int no_nextnode(int node) +{ + if (nodes[node].level == nodes[node+1].level) + return node+1; + return -1; +} + +static int no_child(int node) +{ + if (nodes[node].level == nodes[node+1].level-1) + return node+1; + return -1; +} + +static struct property *find_property(int node,char *name) +{ + struct property *prop = &nodes[node].properties[0]; + while (prop && prop->name) { + if (strcmp(prop->name,name) == 0) return prop; + prop++; + } + return NULL; +} + +static int no_proplen(int node,char *name) +{ + struct property *prop = find_property(node,name); + if (prop) return prop->length; + return -1; +} + +static int no_getprop(int node,char *name,char *value) +{ + struct property *prop = find_property(node,name); + if (prop) { + memcpy(value,prop->value,prop->length); + return 1; + } + return -1; +} + +static int no_setprop(int node,char *name,char *value,int len) +{ + return -1; +} + +static char *no_nextprop(int node,char *name) +{ + struct property *prop = find_property(node,name); + if (prop) return prop[1].name; + return NULL; +} + +static struct linux_nodeops sun4_nodeops = { + no_nextnode, + no_child, + no_proplen, + no_getprop, + no_setprop, + no_nextprop +}; + +static int synch_hook; + +struct linux_romvec * __init sun4_prom_init(void) +{ + int i; + unsigned char x; + char *p; + + p = (char *)&sun4_idprom; + for (i = 0; i < sizeof(sun4_idprom); i++) { + __asm__ __volatile__ ("lduba [%1] %2, %0" : "=r" (x) : + "r" (AC_IDPROM + i), "i" (ASI_CONTROL)); + *p++ = x; + } + + memset(&sun4romvec,0,sizeof(sun4romvec)); + + sun4_romvec = (linux_sun4_romvec *) SUN4_PROM_VECTOR; + + sun4romvec.pv_romvers = 40; + sun4romvec.pv_nodeops = &sun4_nodeops; + sun4romvec.pv_reboot = sun4_romvec->reboot; + sun4romvec.pv_abort = sun4_romvec->abortentry; + sun4romvec.pv_halt = sun4_romvec->exittomon; + sun4romvec.pv_synchook = (void (**)(void))&synch_hook; + sun4romvec.pv_setctxt = sun4_romvec->setcxsegmap; + sun4romvec.pv_v0bootargs = sun4_romvec->bootParam; + sun4romvec.pv_nbgetchar = sun4_romvec->mayget; + sun4romvec.pv_nbputchar = sun4_romvec->mayput; + sun4romvec.pv_stdin = sun4_romvec->insource; + sun4romvec.pv_stdout = sun4_romvec->outsink; + + /* + * We turn on the LEDs to let folks without monitors or + * terminals know we booted. Nothing too fancy now. They + * are all on, except for LED 5, which blinks. When we + * have more time, we can teach the penguin to say "By your + * command" or "Activating turbo boost, Michael". :-) + */ + sun4_romvec->setLEDs(NULL); + + printk("PROMLIB: Old Sun4 boot PROM monitor %s, romvec version %d\n", + sun4_romvec->monid, + sun4_romvec->romvecversion); + + return &sun4romvec; +} diff --git a/trunk/arch/sparc64/Kconfig b/trunk/arch/sparc64/Kconfig index 5446e2a499b1..36b4b7ab9cfb 100644 --- a/trunk/arch/sparc64/Kconfig +++ b/trunk/arch/sparc64/Kconfig @@ -18,13 +18,6 @@ config SPARC64 select HAVE_ARCH_KGDB select USE_GENERIC_SMP_HELPERS if SMP select HAVE_ARCH_TRACEHOOK - select ARCH_WANT_OPTIONAL_GPIOLIB - select RTC_CLASS - select RTC_DRV_M48T59 - select RTC_DRV_CMOS - select RTC_DRV_BQ4802 - select RTC_DRV_SUN4V - select RTC_DRV_STARFIRE config GENERIC_TIME bool @@ -38,11 +31,6 @@ config GENERIC_CLOCKEVENTS bool default y -config GENERIC_GPIO - bool - help - Generic GPIO API support - config 64BIT def_bool y @@ -197,17 +185,6 @@ config US2E_FREQ If in doubt, say N. -config US3_MC - tristate "UltraSPARC-III Memory Controller driver" - default y - help - This adds a driver for the UltraSPARC-III memory controller. - Loading this driver allows exact mnemonic strings to be - printed in the event of a memory error, so that the faulty DIMM - on the motherboard can be matched to the error. - - If in doubt, say Y, as this information can be very useful. - # Global things across all Sun machines. config GENERIC_LOCKBREAK bool diff --git a/trunk/arch/sparc64/Makefile b/trunk/arch/sparc64/Makefile index c7214abc0d84..b785a395b12f 100644 --- a/trunk/arch/sparc64/Makefile +++ b/trunk/arch/sparc64/Makefile @@ -7,7 +7,7 @@ # Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) # -CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64 +CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -m64 # Undefine sparc when processing vmlinux.lds - it is used # And teach CPP we are doing 64 bit builds (for this case) diff --git a/trunk/arch/sparc64/kernel/Makefile b/trunk/arch/sparc64/kernel/Makefile index c0b8009ab196..418b5782096e 100644 --- a/trunk/arch/sparc64/kernel/Makefile +++ b/trunk/arch/sparc64/kernel/Makefile @@ -7,16 +7,16 @@ EXTRA_CFLAGS := -Werror extra-y := head.o init_task.o vmlinux.lds -obj-y := process.o setup.o cpu.o idprom.o reboot.o \ +obj-y := process.o setup.o cpu.o idprom.o \ traps.o auxio.o una_asm.o sysfs.o iommu.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ - unaligned.o central.o starfire.o \ - power.o sbus.o sparc64_ksyms.o ebus.o \ + unaligned.o central.o pci.o starfire.o \ + power.o sbus.o sparc64_ksyms.o chmc.o \ visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_STACKTRACE) += stacktrace.o -obj-$(CONFIG_PCI) += pci.o pci_common.o psycho_common.o \ +obj-$(CONFIG_PCI) += ebus.o pci_common.o \ pci_psycho.o pci_sabre.o pci_schizo.o \ pci_sun4v.o pci_sun4v_asm.o pci_fire.o obj-$(CONFIG_PCI_MSI) += pci_msi.o @@ -25,7 +25,6 @@ obj-$(CONFIG_COMPAT) += sys32.o sys_sparc32.o signal32.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o -obj-$(CONFIG_US3_MC) += chmc.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o obj-$(CONFIG_AUDIT) += audit.o diff --git a/trunk/arch/sparc64/kernel/auxio.c b/trunk/arch/sparc64/kernel/auxio.c index 858beda86524..dd5c7bf87619 100644 --- a/trunk/arch/sparc64/kernel/auxio.c +++ b/trunk/arch/sparc64/kernel/auxio.c @@ -109,7 +109,7 @@ void auxio_set_lte(int on) } } -static struct of_device_id __initdata auxio_match[] = { +static struct of_device_id auxio_match[] = { { .name = "auxio", }, diff --git a/trunk/arch/sparc64/kernel/central.c b/trunk/arch/sparc64/kernel/central.c index 05f1c916db06..f2e87d0d7e1d 100644 --- a/trunk/arch/sparc64/kernel/central.c +++ b/trunk/arch/sparc64/kernel/central.c @@ -1,268 +1,461 @@ /* central.c: Central FHC driver for Sunfire/Starfire/Wildfire. * - * Copyright (C) 1997, 1999, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 1997, 1999 David S. Miller (davem@davemloft.net) */ #include #include #include +#include +#include +#include #include -#include -#include +#include +#include #include -#include - -struct clock_board { - void __iomem *clock_freq_regs; - void __iomem *clock_regs; - void __iomem *clock_ver_reg; - int num_slots; - struct resource leds_resource; - struct platform_device leds_pdev; -}; - -struct fhc { - void __iomem *pregs; - bool central; - bool jtag_master; - int board_num; - struct resource leds_resource; - struct platform_device leds_pdev; -}; - -static int __devinit clock_board_calc_nslots(struct clock_board *p) -{ - u8 reg = upa_readb(p->clock_regs + CLOCK_STAT1) & 0xc0; +#include - switch (reg) { - case 0x40: - return 16; +static struct linux_central *central_bus = NULL; +static struct linux_fhc *fhc_list = NULL; - case 0xc0: - return 8; +#define IS_CENTRAL_FHC(__fhc) ((__fhc) == central_bus->child) - case 0x80: - reg = 0; - if (p->clock_ver_reg) - reg = upa_readb(p->clock_ver_reg); - if (reg) { - if (reg & 0x80) - return 4; - else - return 5; - } - /* Fallthrough */ - default: - return 4; - } +static void central_probe_failure(int line) +{ + prom_printf("CENTRAL: Critical device probe failure at central.c:%d\n", + line); + prom_halt(); } -static int __devinit clock_board_probe(struct of_device *op, - const struct of_device_id *match) +static void central_ranges_init(struct linux_central *central) { - struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL); - int err = -ENOMEM; - - if (!p) { - printk(KERN_ERR "clock_board: Cannot allocate struct clock_board\n"); - goto out; + struct device_node *dp = central->prom_node; + const void *pval; + int len; + + central->num_central_ranges = 0; + pval = of_get_property(dp, "ranges", &len); + if (pval) { + memcpy(central->central_ranges, pval, len); + central->num_central_ranges = + (len / sizeof(struct linux_prom_ranges)); } +} - p->clock_freq_regs = of_ioremap(&op->resource[0], 0, - resource_size(&op->resource[0]), - "clock_board_freq"); - if (!p->clock_freq_regs) { - printk(KERN_ERR "clock_board: Cannot map clock_freq_regs\n"); - goto out_free; +static void fhc_ranges_init(struct linux_fhc *fhc) +{ + struct device_node *dp = fhc->prom_node; + const void *pval; + int len; + + fhc->num_fhc_ranges = 0; + pval = of_get_property(dp, "ranges", &len); + if (pval) { + memcpy(fhc->fhc_ranges, pval, len); + fhc->num_fhc_ranges = + (len / sizeof(struct linux_prom_ranges)); } +} - p->clock_regs = of_ioremap(&op->resource[1], 0, - resource_size(&op->resource[1]), - "clock_board_regs"); - if (!p->clock_regs) { - printk(KERN_ERR "clock_board: Cannot map clock_regs\n"); - goto out_unmap_clock_freq_regs; +/* Range application routines are exported to various drivers, + * so do not __init this. + */ +static void adjust_regs(struct linux_prom_registers *regp, int nregs, + struct linux_prom_ranges *rangep, int nranges) +{ + int regc, rngc; + + for (regc = 0; regc < nregs; regc++) { + for (rngc = 0; rngc < nranges; rngc++) + if (regp[regc].which_io == rangep[rngc].ot_child_space) + break; /* Fount it */ + if (rngc == nranges) /* oops */ + central_probe_failure(__LINE__); + regp[regc].which_io = rangep[rngc].ot_parent_space; + regp[regc].phys_addr -= rangep[rngc].ot_child_base; + regp[regc].phys_addr += rangep[rngc].ot_parent_base; } +} - if (op->resource[2].flags) { - p->clock_ver_reg = of_ioremap(&op->resource[2], 0, - resource_size(&op->resource[2]), - "clock_ver_reg"); - if (!p->clock_ver_reg) { - printk(KERN_ERR "clock_board: Cannot map clock_ver_reg\n"); - goto out_unmap_clock_regs; - } - } +/* Apply probed fhc ranges to registers passed, if no ranges return. */ +static void apply_fhc_ranges(struct linux_fhc *fhc, + struct linux_prom_registers *regs, + int nregs) +{ + if (fhc->num_fhc_ranges) + adjust_regs(regs, nregs, fhc->fhc_ranges, + fhc->num_fhc_ranges); +} + +/* Apply probed central ranges to registers passed, if no ranges return. */ +static void apply_central_ranges(struct linux_central *central, + struct linux_prom_registers *regs, int nregs) +{ + if (central->num_central_ranges) + adjust_regs(regs, nregs, central->central_ranges, + central->num_central_ranges); +} - p->num_slots = clock_board_calc_nslots(p); +static void * __init central_alloc_bootmem(unsigned long size) +{ + void *ret; - p->leds_resource.start = (unsigned long) - (p->clock_regs + CLOCK_CTRL); - p->leds_resource.end = p->leds_resource.end; - p->leds_resource.name = "leds"; + ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL); + if (ret != NULL) + memset(ret, 0, size); - p->leds_pdev.name = "sunfire-clockboard-leds"; - p->leds_pdev.resource = &p->leds_resource; - p->leds_pdev.num_resources = 1; - p->leds_pdev.dev.parent = &op->dev; + return ret; +} - err = platform_device_register(&p->leds_pdev); - if (err) { - printk(KERN_ERR "clock_board: Could not register LEDS " - "platform device\n"); - goto out_unmap_clock_ver_reg; +static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r) +{ + unsigned long ret = ((unsigned long) r->which_io) << 32; + + return ret | (unsigned long) r->phys_addr; +} + +static void __init probe_other_fhcs(void) +{ + struct device_node *dp; + const struct linux_prom64_registers *fpregs; + + for_each_node_by_name(dp, "fhc") { + struct linux_fhc *fhc; + int board; + u32 tmp; + + if (dp->parent && + dp->parent->parent != NULL) + continue; + + fhc = (struct linux_fhc *) + central_alloc_bootmem(sizeof(struct linux_fhc)); + if (fhc == NULL) + central_probe_failure(__LINE__); + + /* Link it into the FHC chain. */ + fhc->next = fhc_list; + fhc_list = fhc; + + /* Toplevel FHCs have no parent. */ + fhc->parent = NULL; + + fhc->prom_node = dp; + fhc_ranges_init(fhc); + + /* Non-central FHC's have 64-bit OBP format registers. */ + fpregs = of_get_property(dp, "reg", NULL); + if (!fpregs) + central_probe_failure(__LINE__); + + /* Only central FHC needs special ranges applied. */ + fhc->fhc_regs.pregs = fpregs[0].phys_addr; + fhc->fhc_regs.ireg = fpregs[1].phys_addr; + fhc->fhc_regs.ffregs = fpregs[2].phys_addr; + fhc->fhc_regs.sregs = fpregs[3].phys_addr; + fhc->fhc_regs.uregs = fpregs[4].phys_addr; + fhc->fhc_regs.tregs = fpregs[5].phys_addr; + + board = of_getintprop_default(dp, "board#", -1); + fhc->board = board; + + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL); + if ((tmp & FHC_JTAG_CTRL_MENAB) != 0) + fhc->jtag_master = 1; + else + fhc->jtag_master = 0; + + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID); + printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %s\n", + board, + (tmp & FHC_ID_VERS) >> 28, + (tmp & FHC_ID_PARTID) >> 12, + (tmp & FHC_ID_MANUF) >> 1, + (fhc->jtag_master ? "(JTAG Master)" : "")); + + /* This bit must be set in all non-central FHC's in + * the system. When it is clear, this identifies + * the central board. + */ + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); + tmp |= FHC_CONTROL_IXIST; + upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); } +} - printk(KERN_INFO "clock_board: Detected %d slot Enterprise system.\n", - p->num_slots); +static void probe_clock_board(struct linux_central *central, + struct linux_fhc *fhc, + struct device_node *fp) +{ + struct device_node *dp; + struct linux_prom_registers cregs[3]; + const struct linux_prom_registers *pr; + int nslots, tmp, nregs; + + dp = fp->child; + while (dp) { + if (!strcmp(dp->name, "clock-board")) + break; + dp = dp->sibling; + } + if (!dp) + central_probe_failure(__LINE__); - err = 0; -out: - return err; + pr = of_get_property(dp, "reg", &nregs); + if (!pr) + central_probe_failure(__LINE__); -out_unmap_clock_ver_reg: - if (p->clock_ver_reg) - of_iounmap(&op->resource[2], p->clock_ver_reg, - resource_size(&op->resource[2])); + memcpy(cregs, pr, nregs); + nregs /= sizeof(struct linux_prom_registers); -out_unmap_clock_regs: - of_iounmap(&op->resource[1], p->clock_regs, - resource_size(&op->resource[1])); + apply_fhc_ranges(fhc, &cregs[0], nregs); + apply_central_ranges(central, &cregs[0], nregs); + central->cfreg = prom_reg_to_paddr(&cregs[0]); + central->clkregs = prom_reg_to_paddr(&cregs[1]); -out_unmap_clock_freq_regs: - of_iounmap(&op->resource[0], p->clock_freq_regs, - resource_size(&op->resource[0])); + if (nregs == 2) + central->clkver = 0UL; + else + central->clkver = prom_reg_to_paddr(&cregs[2]); -out_free: - kfree(p); - goto out; + tmp = upa_readb(central->clkregs + CLOCK_STAT1); + tmp &= 0xc0; + switch(tmp) { + case 0x40: + nslots = 16; + break; + case 0xc0: + nslots = 8; + break; + case 0x80: + if (central->clkver != 0UL && + upa_readb(central->clkver) != 0) { + if ((upa_readb(central->clkver) & 0x80) != 0) + nslots = 4; + else + nslots = 5; + break; + } + default: + nslots = 4; + break; + }; + central->slots = nslots; + printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]\n", + central->slots, upa_readb(central->cfreg), + (central->clkver ? upa_readb(central->clkver) : 0x00)); } -static struct of_device_id __initdata clock_board_match[] = { - { - .name = "clock-board", - }, - {}, -}; - -static struct of_platform_driver clock_board_driver = { - .match_table = clock_board_match, - .probe = clock_board_probe, - .driver = { - .name = "clock_board", - }, -}; - -static int __devinit fhc_probe(struct of_device *op, - const struct of_device_id *match) +static void ZAP(unsigned long iclr, unsigned long imap) { - struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL); - int err = -ENOMEM; - u32 reg; + u32 imap_tmp; + + upa_writel(0, iclr); + upa_readl(iclr); + imap_tmp = upa_readl(imap); + imap_tmp &= ~(0x80000000); + upa_writel(imap_tmp, imap); + upa_readl(imap); +} - if (!p) { - printk(KERN_ERR "fhc: Cannot allocate struct fhc\n"); - goto out; +static void init_all_fhc_hw(void) +{ + struct linux_fhc *fhc; + + for (fhc = fhc_list; fhc != NULL; fhc = fhc->next) { + u32 tmp; + + /* Clear all of the interrupt mapping registers + * just in case OBP left them in a foul state. + */ + ZAP(fhc->fhc_regs.ffregs + FHC_FFREGS_ICLR, + fhc->fhc_regs.ffregs + FHC_FFREGS_IMAP); + ZAP(fhc->fhc_regs.sregs + FHC_SREGS_ICLR, + fhc->fhc_regs.sregs + FHC_SREGS_IMAP); + ZAP(fhc->fhc_regs.uregs + FHC_UREGS_ICLR, + fhc->fhc_regs.uregs + FHC_UREGS_IMAP); + ZAP(fhc->fhc_regs.tregs + FHC_TREGS_ICLR, + fhc->fhc_regs.tregs + FHC_TREGS_IMAP); + + /* Setup FHC control register. */ + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); + + /* All non-central boards have this bit set. */ + if (! IS_CENTRAL_FHC(fhc)) + tmp |= FHC_CONTROL_IXIST; + + /* For all FHCs, clear the firmware synchronization + * line and both low power mode enables. + */ + tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | + FHC_CONTROL_SLINE); + + upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); + upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); } - if (!strcmp(op->node->parent->name, "central")) - p->central = true; - - p->pregs = of_ioremap(&op->resource[0], 0, - resource_size(&op->resource[0]), - "fhc_pregs"); - if (!p->pregs) { - printk(KERN_ERR "fhc: Cannot map pregs\n"); - goto out_free; - } +} - if (p->central) { - reg = upa_readl(p->pregs + FHC_PREGS_BSR); - p->board_num = ((reg >> 16) & 1) | ((reg >> 12) & 0x0e); - } else { - p->board_num = of_getintprop_default(op->node, "board#", -1); - if (p->board_num == -1) { - printk(KERN_ERR "fhc: No board# property\n"); - goto out_unmap_pregs; - } - if (upa_readl(p->pregs + FHC_PREGS_JCTRL) & FHC_JTAG_CTRL_MENAB) - p->jtag_master = true; +void __init central_probe(void) +{ + struct linux_prom_registers fpregs[6]; + const struct linux_prom_registers *pr; + struct linux_fhc *fhc; + struct device_node *dp, *fp; + int err; + + dp = of_find_node_by_name(NULL, "central"); + if (!dp) { + if (this_is_starfire) + starfire_cpu_setup(); + return; } - if (!p->central) { - p->leds_resource.start = (unsigned long) - (p->pregs + FHC_PREGS_CTRL); - p->leds_resource.end = p->leds_resource.end; - p->leds_resource.name = "leds"; - - p->leds_pdev.name = "sunfire-fhc-leds"; - p->leds_pdev.resource = &p->leds_resource; - p->leds_pdev.num_resources = 1; - p->leds_pdev.dev.parent = &op->dev; - - err = platform_device_register(&p->leds_pdev); - if (err) { - printk(KERN_ERR "fhc: Could not register LEDS " - "platform device\n"); - goto out_unmap_pregs; - } + /* Ok we got one, grab some memory for software state. */ + central_bus = (struct linux_central *) + central_alloc_bootmem(sizeof(struct linux_central)); + if (central_bus == NULL) + central_probe_failure(__LINE__); + + fhc = (struct linux_fhc *) + central_alloc_bootmem(sizeof(struct linux_fhc)); + if (fhc == NULL) + central_probe_failure(__LINE__); + + /* First init central. */ + central_bus->child = fhc; + central_bus->prom_node = dp; + central_ranges_init(central_bus); + + /* And then central's FHC. */ + fhc->next = fhc_list; + fhc_list = fhc; + + fhc->parent = central_bus; + fp = dp->child; + while (fp) { + if (!strcmp(fp->name, "fhc")) + break; + fp = fp->sibling; } - reg = upa_readl(p->pregs + FHC_PREGS_CTRL); + if (!fp) + central_probe_failure(__LINE__); + + fhc->prom_node = fp; + fhc_ranges_init(fhc); + + /* Now, map in FHC register set. */ + pr = of_get_property(fp, "reg", NULL); + if (!pr) + central_probe_failure(__LINE__); + memcpy(fpregs, pr, sizeof(fpregs)); + + apply_central_ranges(central_bus, &fpregs[0], 6); + + fhc->fhc_regs.pregs = prom_reg_to_paddr(&fpregs[0]); + fhc->fhc_regs.ireg = prom_reg_to_paddr(&fpregs[1]); + fhc->fhc_regs.ffregs = prom_reg_to_paddr(&fpregs[2]); + fhc->fhc_regs.sregs = prom_reg_to_paddr(&fpregs[3]); + fhc->fhc_regs.uregs = prom_reg_to_paddr(&fpregs[4]); + fhc->fhc_regs.tregs = prom_reg_to_paddr(&fpregs[5]); + + /* Obtain board number from board status register, Central's + * FHC lacks "board#" property. + */ + err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_BSR); + fhc->board = (((err >> 16) & 0x01) | + ((err >> 12) & 0x0e)); + + fhc->jtag_master = 0; + + /* Attach the clock board registers for CENTRAL. */ + probe_clock_board(central_bus, fhc, fp); + + err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID); + printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n", + fhc->board, + ((err & FHC_ID_VERS) >> 28), + ((err & FHC_ID_PARTID) >> 12), + ((err & FHC_ID_MANUF) >> 1)); + + probe_other_fhcs(); + + init_all_fhc_hw(); +} - if (!p->central) - reg |= FHC_CONTROL_IXIST; +static inline void fhc_ledblink(struct linux_fhc *fhc, int on) +{ + u32 tmp; - reg &= ~(FHC_CONTROL_AOFF | - FHC_CONTROL_BOFF | - FHC_CONTROL_SLINE); + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); - upa_writel(reg, p->pregs + FHC_PREGS_CTRL); - upa_readl(p->pregs + FHC_PREGS_CTRL); + /* NOTE: reverse logic on this bit */ + if (on) + tmp &= ~(FHC_CONTROL_RLED); + else + tmp |= FHC_CONTROL_RLED; + tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE); - reg = upa_readl(p->pregs + FHC_PREGS_ID); - printk(KERN_INFO "fhc: Board #%d, Version[%x] PartID[%x] Manuf[%x] %s\n", - p->board_num, - (reg & FHC_ID_VERS) >> 28, - (reg & FHC_ID_PARTID) >> 12, - (reg & FHC_ID_MANUF) >> 1, - (p->jtag_master ? - "(JTAG Master)" : - (p->central ? "(Central)" : ""))); + upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); + upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); +} - err = 0; +static inline void central_ledblink(struct linux_central *central, int on) +{ + u8 tmp; -out: - return err; + tmp = upa_readb(central->clkregs + CLOCK_CTRL); -out_unmap_pregs: - of_iounmap(&op->resource[0], p->pregs, resource_size(&op->resource[0])); + /* NOTE: reverse logic on this bit */ + if (on) + tmp &= ~(CLOCK_CTRL_RLED); + else + tmp |= CLOCK_CTRL_RLED; -out_free: - kfree(p); - goto out; + upa_writeb(tmp, central->clkregs + CLOCK_CTRL); + upa_readb(central->clkregs + CLOCK_CTRL); } -static struct of_device_id __initdata fhc_match[] = { - { - .name = "fhc", - }, - {}, -}; - -static struct of_platform_driver fhc_driver = { - .match_table = fhc_match, - .probe = fhc_probe, - .driver = { - .name = "fhc", - }, -}; - -static int __init sunfire_init(void) +static struct timer_list sftimer; +static int led_state; + +static void sunfire_timer(unsigned long __ignored) { - (void) of_register_driver(&fhc_driver, &of_platform_bus_type); - (void) of_register_driver(&clock_board_driver, &of_platform_bus_type); - return 0; + struct linux_fhc *fhc; + + central_ledblink(central_bus, led_state); + for (fhc = fhc_list; fhc != NULL; fhc = fhc->next) + if (! IS_CENTRAL_FHC(fhc)) + fhc_ledblink(fhc, led_state); + led_state = ! led_state; + sftimer.expires = jiffies + (HZ >> 1); + add_timer(&sftimer); } -subsys_initcall(sunfire_init); +/* After PCI/SBUS busses have been probed, this is called to perform + * final initialization of all FireHose Controllers in the system. + */ +void firetruck_init(void) +{ + struct linux_central *central = central_bus; + u8 ctrl; + + /* No central bus, nothing to do. */ + if (central == NULL) + return; + + /* OBP leaves it on, turn it off so clock board timer LED + * is in sync with FHC ones. + */ + ctrl = upa_readb(central->clkregs + CLOCK_CTRL); + ctrl &= ~(CLOCK_CTRL_RLED); + upa_writeb(ctrl, central->clkregs + CLOCK_CTRL); + + led_state = 0; + init_timer(&sftimer); + sftimer.data = 0; + sftimer.function = &sunfire_timer; + sftimer.expires = jiffies + (HZ >> 1); + add_timer(&sftimer); +} diff --git a/trunk/arch/sparc64/kernel/chmc.c b/trunk/arch/sparc64/kernel/chmc.c index 967b04886822..6d4f02e8a4cf 100644 --- a/trunk/arch/sparc64/kernel/chmc.c +++ b/trunk/arch/sparc64/kernel/chmc.c @@ -1,6 +1,6 @@ -/* chmc.c: Driver for UltraSPARC-III memory controller. +/* memctrlr.c: Driver for UltraSPARC-III memory controller. * - * Copyright (C) 2001, 2007, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 2001, 2007 David S. Miller (davem@davemloft.net) */ #include @@ -13,64 +13,45 @@ #include #include #include -#include -#include #include #include #include #include #include -#include #include -#include - -#define DRV_MODULE_NAME "chmc" -#define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "0.2" - -MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); -MODULE_DESCRIPTION("UltraSPARC-III memory controller driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_MODULE_VERSION); - -static int mc_type; -#define MC_TYPE_SAFARI 1 -#define MC_TYPE_JBUS 2 - -static dimm_printer_t us3mc_dimm_printer; #define CHMCTRL_NDGRPS 2 #define CHMCTRL_NDIMMS 4 -#define CHMC_DIMMS_PER_MC (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS) +#define DIMMS_PER_MC (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS) /* OBP memory-layout property format. */ -struct chmc_obp_map { +struct obp_map { unsigned char dimm_map[144]; unsigned char pin_map[576]; }; #define DIMM_LABEL_SZ 8 -struct chmc_obp_mem_layout { +struct obp_mem_layout { /* One max 8-byte string label per DIMM. Usually * this matches the label on the motherboard where * that DIMM resides. */ - char dimm_labels[CHMC_DIMMS_PER_MC][DIMM_LABEL_SZ]; + char dimm_labels[DIMMS_PER_MC][DIMM_LABEL_SZ]; /* If symmetric use map[0], else it is * asymmetric and map[1] should be used. */ - char symmetric; + char symmetric; - struct chmc_obp_map map[2]; + struct obp_map map[2]; }; #define CHMCTRL_NBANKS 4 -struct chmc_bank_info { - struct chmc *p; +struct bank_info { + struct mctrl_info *mp; int bank_id; u64 raw_reg; @@ -84,406 +65,28 @@ struct chmc_bank_info { unsigned long size; }; -struct chmc { - struct list_head list; - int portid; - - struct chmc_obp_mem_layout layout_prop; - int layout_size; - - void __iomem *regs; +struct mctrl_info { + struct list_head list; + int portid; - u64 timing_control1; - u64 timing_control2; - u64 timing_control3; - u64 timing_control4; - u64 memaddr_control; + struct obp_mem_layout layout_prop; + int layout_size; - struct chmc_bank_info logical_banks[CHMCTRL_NBANKS]; -}; - -#define JBUSMC_REGS_SIZE 8 - -#define JB_MC_REG1_DIMM2_BANK3 0x8000000000000000UL -#define JB_MC_REG1_DIMM1_BANK1 0x4000000000000000UL -#define JB_MC_REG1_DIMM2_BANK2 0x2000000000000000UL -#define JB_MC_REG1_DIMM1_BANK0 0x1000000000000000UL -#define JB_MC_REG1_XOR 0x0000010000000000UL -#define JB_MC_REG1_ADDR_GEN_2 0x000000e000000000UL -#define JB_MC_REG1_ADDR_GEN_2_SHIFT 37 -#define JB_MC_REG1_ADDR_GEN_1 0x0000001c00000000UL -#define JB_MC_REG1_ADDR_GEN_1_SHIFT 34 -#define JB_MC_REG1_INTERLEAVE 0x0000000001800000UL -#define JB_MC_REG1_INTERLEAVE_SHIFT 23 -#define JB_MC_REG1_DIMM2_PTYPE 0x0000000000200000UL -#define JB_MC_REG1_DIMM2_PTYPE_SHIFT 21 -#define JB_MC_REG1_DIMM1_PTYPE 0x0000000000100000UL -#define JB_MC_REG1_DIMM1_PTYPE_SHIFT 20 - -#define PART_TYPE_X8 0 -#define PART_TYPE_X4 1 - -#define INTERLEAVE_NONE 0 -#define INTERLEAVE_SAME 1 -#define INTERLEAVE_INTERNAL 2 -#define INTERLEAVE_BOTH 3 - -#define ADDR_GEN_128MB 0 -#define ADDR_GEN_256MB 1 -#define ADDR_GEN_512MB 2 -#define ADDR_GEN_1GB 3 - -#define JB_NUM_DIMM_GROUPS 2 -#define JB_NUM_DIMMS_PER_GROUP 2 -#define JB_NUM_DIMMS (JB_NUM_DIMM_GROUPS * JB_NUM_DIMMS_PER_GROUP) - -struct jbusmc_obp_map { - unsigned char dimm_map[18]; - unsigned char pin_map[144]; -}; - -struct jbusmc_obp_mem_layout { - /* One max 8-byte string label per DIMM. Usually - * this matches the label on the motherboard where - * that DIMM resides. - */ - char dimm_labels[JB_NUM_DIMMS][DIMM_LABEL_SZ]; - - /* If symmetric use map[0], else it is - * asymmetric and map[1] should be used. - */ - char symmetric; - - struct jbusmc_obp_map map; - - char _pad; -}; + void __iomem *regs; -struct jbusmc_dimm_group { - struct jbusmc *controller; - int index; - u64 base_addr; - u64 size; -}; + u64 timing_control1; + u64 timing_control2; + u64 timing_control3; + u64 timing_control4; + u64 memaddr_control; -struct jbusmc { - void __iomem *regs; - u64 mc_reg_1; - u32 portid; - struct jbusmc_obp_mem_layout layout; - int layout_len; - int num_dimm_groups; - struct jbusmc_dimm_group dimm_groups[JB_NUM_DIMM_GROUPS]; - struct list_head list; + struct bank_info logical_banks[CHMCTRL_NBANKS]; }; -static DEFINE_SPINLOCK(mctrl_list_lock); static LIST_HEAD(mctrl_list); -static void mc_list_add(struct list_head *list) -{ - spin_lock(&mctrl_list_lock); - list_add(list, &mctrl_list); - spin_unlock(&mctrl_list_lock); -} - -static void mc_list_del(struct list_head *list) -{ - spin_lock(&mctrl_list_lock); - list_del_init(list); - spin_unlock(&mctrl_list_lock); -} - -#define SYNDROME_MIN -1 -#define SYNDROME_MAX 144 - -/* Covert syndrome code into the way the bits are positioned - * on the bus. - */ -static int syndrome_to_qword_code(int syndrome_code) -{ - if (syndrome_code < 128) - syndrome_code += 16; - else if (syndrome_code < 128 + 9) - syndrome_code -= (128 - 7); - else if (syndrome_code < (128 + 9 + 3)) - syndrome_code -= (128 + 9 - 4); - else - syndrome_code -= (128 + 9 + 3); - return syndrome_code; -} - -/* All this magic has to do with how a cache line comes over the wire - * on Safari and JBUS. A 64-bit line comes over in 1 or more quadword - * cycles, each of which transmit ECC/MTAG info as well as the actual - * data. - */ -#define L2_LINE_SIZE 64 -#define L2_LINE_ADDR_MSK (L2_LINE_SIZE - 1) -#define QW_PER_LINE 4 -#define QW_BYTES (L2_LINE_SIZE / QW_PER_LINE) -#define QW_BITS 144 -#define SAFARI_LAST_BIT (576 - 1) -#define JBUS_LAST_BIT (144 - 1) - -static void get_pin_and_dimm_str(int syndrome_code, unsigned long paddr, - int *pin_p, char **dimm_str_p, void *_prop, - int base_dimm_offset) -{ - int qword_code = syndrome_to_qword_code(syndrome_code); - int cache_line_offset; - int offset_inverse; - int dimm_map_index; - int map_val; - - if (mc_type == MC_TYPE_JBUS) { - struct jbusmc_obp_mem_layout *p = _prop; - - /* JBUS */ - cache_line_offset = qword_code; - offset_inverse = (JBUS_LAST_BIT - cache_line_offset); - dimm_map_index = offset_inverse / 8; - map_val = p->map.dimm_map[dimm_map_index]; - map_val = ((map_val >> ((7 - (offset_inverse & 7)))) & 1); - *dimm_str_p = p->dimm_labels[base_dimm_offset + map_val]; - *pin_p = p->map.pin_map[cache_line_offset]; - } else { - struct chmc_obp_mem_layout *p = _prop; - struct chmc_obp_map *mp; - int qword; - - /* Safari */ - if (p->symmetric) - mp = &p->map[0]; - else - mp = &p->map[1]; - - qword = (paddr & L2_LINE_ADDR_MSK) / QW_BYTES; - cache_line_offset = ((3 - qword) * QW_BITS) + qword_code; - offset_inverse = (SAFARI_LAST_BIT - cache_line_offset); - dimm_map_index = offset_inverse >> 2; - map_val = mp->dimm_map[dimm_map_index]; - map_val = ((map_val >> ((3 - (offset_inverse & 3)) << 1)) & 0x3); - *dimm_str_p = p->dimm_labels[base_dimm_offset + map_val]; - *pin_p = mp->pin_map[cache_line_offset]; - } -} - -static struct jbusmc_dimm_group *jbusmc_find_dimm_group(unsigned long phys_addr) -{ - struct jbusmc *p; - - list_for_each_entry(p, &mctrl_list, list) { - int i; - - for (i = 0; i < p->num_dimm_groups; i++) { - struct jbusmc_dimm_group *dp = &p->dimm_groups[i]; - - if (phys_addr < dp->base_addr || - (dp->base_addr + dp->size) <= phys_addr) - continue; - - return dp; - } - } - return NULL; -} - -static int jbusmc_print_dimm(int syndrome_code, - unsigned long phys_addr, - char *buf, int buflen) -{ - struct jbusmc_obp_mem_layout *prop; - struct jbusmc_dimm_group *dp; - struct jbusmc *p; - int first_dimm; - - dp = jbusmc_find_dimm_group(phys_addr); - if (dp == NULL || - syndrome_code < SYNDROME_MIN || - syndrome_code > SYNDROME_MAX) { - buf[0] = '?'; - buf[1] = '?'; - buf[2] = '?'; - buf[3] = '\0'; - } - p = dp->controller; - prop = &p->layout; - - first_dimm = dp->index * JB_NUM_DIMMS_PER_GROUP; - - if (syndrome_code != SYNDROME_MIN) { - char *dimm_str; - int pin; - - get_pin_and_dimm_str(syndrome_code, phys_addr, &pin, - &dimm_str, prop, first_dimm); - sprintf(buf, "%s, pin %3d", dimm_str, pin); - } else { - int dimm; - - /* Multi-bit error, we just dump out all the - * dimm labels associated with this dimm group. - */ - for (dimm = 0; dimm < JB_NUM_DIMMS_PER_GROUP; dimm++) { - sprintf(buf, "%s ", - prop->dimm_labels[first_dimm + dimm]); - buf += strlen(buf); - } - } - - return 0; -} - -static u64 __devinit jbusmc_dimm_group_size(u64 base, - const struct linux_prom64_registers *mem_regs, - int num_mem_regs) -{ - u64 max = base + (8UL * 1024 * 1024 * 1024); - u64 max_seen = base; - int i; - - for (i = 0; i < num_mem_regs; i++) { - const struct linux_prom64_registers *ent; - u64 this_base; - u64 this_end; - - ent = &mem_regs[i]; - this_base = ent->phys_addr; - this_end = this_base + ent->reg_size; - if (base < this_base || base >= this_end) - continue; - if (this_end > max) - this_end = max; - if (this_end > max_seen) - max_seen = this_end; - } - - return max_seen - base; -} - -static void __devinit jbusmc_construct_one_dimm_group(struct jbusmc *p, - unsigned long index, - const struct linux_prom64_registers *mem_regs, - int num_mem_regs) -{ - struct jbusmc_dimm_group *dp = &p->dimm_groups[index]; - - dp->controller = p; - dp->index = index; - - dp->base_addr = (p->portid * (64UL * 1024 * 1024 * 1024)); - dp->base_addr += (index * (8UL * 1024 * 1024 * 1024)); - dp->size = jbusmc_dimm_group_size(dp->base_addr, mem_regs, num_mem_regs); -} - -static void __devinit jbusmc_construct_dimm_groups(struct jbusmc *p, - const struct linux_prom64_registers *mem_regs, - int num_mem_regs) -{ - if (p->mc_reg_1 & JB_MC_REG1_DIMM1_BANK0) { - jbusmc_construct_one_dimm_group(p, 0, mem_regs, num_mem_regs); - p->num_dimm_groups++; - } - if (p->mc_reg_1 & JB_MC_REG1_DIMM2_BANK2) { - jbusmc_construct_one_dimm_group(p, 1, mem_regs, num_mem_regs); - p->num_dimm_groups++; - } -} - -static int __devinit jbusmc_probe(struct of_device *op, - const struct of_device_id *match) -{ - const struct linux_prom64_registers *mem_regs; - struct device_node *mem_node; - int err, len, num_mem_regs; - struct jbusmc *p; - const u32 *prop; - const void *ml; - - err = -ENODEV; - mem_node = of_find_node_by_path("/memory"); - if (!mem_node) { - printk(KERN_ERR PFX "Cannot find /memory node.\n"); - goto out; - } - mem_regs = of_get_property(mem_node, "reg", &len); - if (!mem_regs) { - printk(KERN_ERR PFX "Cannot get reg property of /memory node.\n"); - goto out; - } - num_mem_regs = len / sizeof(*mem_regs); - - err = -ENOMEM; - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) { - printk(KERN_ERR PFX "Cannot allocate struct jbusmc.\n"); - goto out; - } - - INIT_LIST_HEAD(&p->list); - - err = -ENODEV; - prop = of_get_property(op->node, "portid", &len); - if (!prop || len != 4) { - printk(KERN_ERR PFX "Cannot find portid.\n"); - goto out_free; - } - - p->portid = *prop; - - prop = of_get_property(op->node, "memory-control-register-1", &len); - if (!prop || len != 8) { - printk(KERN_ERR PFX "Cannot get memory control register 1.\n"); - goto out_free; - } - - p->mc_reg_1 = ((u64)prop[0] << 32) | (u64) prop[1]; - - err = -ENOMEM; - p->regs = of_ioremap(&op->resource[0], 0, JBUSMC_REGS_SIZE, "jbusmc"); - if (!p->regs) { - printk(KERN_ERR PFX "Cannot map jbusmc regs.\n"); - goto out_free; - } - - err = -ENODEV; - ml = of_get_property(op->node, "memory-layout", &p->layout_len); - if (!ml) { - printk(KERN_ERR PFX "Cannot get memory layout property.\n"); - goto out_iounmap; - } - if (p->layout_len > sizeof(p->layout)) { - printk(KERN_ERR PFX "Unexpected memory-layout size %d\n", - p->layout_len); - goto out_iounmap; - } - memcpy(&p->layout, ml, p->layout_len); - - jbusmc_construct_dimm_groups(p, mem_regs, num_mem_regs); - - mc_list_add(&p->list); - - printk(KERN_INFO PFX "UltraSPARC-IIIi memory controller at %s\n", - op->node->full_name); - - dev_set_drvdata(&op->dev, p); - - err = 0; - -out: - return err; - -out_iounmap: - of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE); - -out_free: - kfree(p); - goto out; -} - /* Does BANK decode PHYS_ADDR? */ -static int chmc_bank_match(struct chmc_bank_info *bp, unsigned long phys_addr) +static int bank_match(struct bank_info *bp, unsigned long phys_addr) { unsigned long upper_bits = (phys_addr & PA_UPPER_BITS) >> PA_UPPER_BITS_SHIFT; unsigned long lower_bits = (phys_addr & PA_LOWER_BITS) >> PA_LOWER_BITS_SHIFT; @@ -515,18 +118,25 @@ static int chmc_bank_match(struct chmc_bank_info *bp, unsigned long phys_addr) } /* Given PHYS_ADDR, search memory controller banks for a match. */ -static struct chmc_bank_info *chmc_find_bank(unsigned long phys_addr) +static struct bank_info *find_bank(unsigned long phys_addr) { - struct chmc *p; + struct list_head *mctrl_head = &mctrl_list; + struct list_head *mctrl_entry = mctrl_head->next; - list_for_each_entry(p, &mctrl_list, list) { + for (;;) { + struct mctrl_info *mp = + list_entry(mctrl_entry, struct mctrl_info, list); int bank_no; + if (mctrl_entry == mctrl_head) + break; + mctrl_entry = mctrl_entry->next; + for (bank_no = 0; bank_no < CHMCTRL_NBANKS; bank_no++) { - struct chmc_bank_info *bp; + struct bank_info *bp; - bp = &p->logical_banks[bank_no]; - if (chmc_bank_match(bp, phys_addr)) + bp = &mp->logical_banks[bank_no]; + if (bank_match(bp, phys_addr)) return bp; } } @@ -535,15 +145,17 @@ static struct chmc_bank_info *chmc_find_bank(unsigned long phys_addr) } /* This is the main purpose of this driver. */ -static int chmc_print_dimm(int syndrome_code, - unsigned long phys_addr, - char *buf, int buflen) +#define SYNDROME_MIN -1 +#define SYNDROME_MAX 144 +int chmc_getunumber(int syndrome_code, + unsigned long phys_addr, + char *buf, int buflen) { - struct chmc_bank_info *bp; - struct chmc_obp_mem_layout *prop; + struct bank_info *bp; + struct obp_mem_layout *prop; int bank_in_controller, first_dimm; - bp = chmc_find_bank(phys_addr); + bp = find_bank(phys_addr); if (bp == NULL || syndrome_code < SYNDROME_MIN || syndrome_code > SYNDROME_MAX) { @@ -554,18 +166,60 @@ static int chmc_print_dimm(int syndrome_code, return 0; } - prop = &bp->p->layout_prop; + prop = &bp->mp->layout_prop; bank_in_controller = bp->bank_id & (CHMCTRL_NBANKS - 1); first_dimm = (bank_in_controller & (CHMCTRL_NDGRPS - 1)); first_dimm *= CHMCTRL_NDIMMS; if (syndrome_code != SYNDROME_MIN) { - char *dimm_str; - int pin; + struct obp_map *map; + int qword, where_in_line, where, map_index, map_offset; + unsigned int map_val; - get_pin_and_dimm_str(syndrome_code, phys_addr, &pin, - &dimm_str, prop, first_dimm); - sprintf(buf, "%s, pin %3d", dimm_str, pin); + /* Yaay, single bit error so we can figure out + * the exact dimm. + */ + if (prop->symmetric) + map = &prop->map[0]; + else + map = &prop->map[1]; + + /* Covert syndrome code into the way the bits are + * positioned on the bus. + */ + if (syndrome_code < 144 - 16) + syndrome_code += 16; + else if (syndrome_code < 144) + syndrome_code -= (144 - 7); + else if (syndrome_code < (144 + 3)) + syndrome_code -= (144 + 3 - 4); + else + syndrome_code -= 144 + 3; + + /* All this magic has to do with how a cache line + * comes over the wire on Safari. A 64-bit line + * comes over in 4 quadword cycles, each of which + * transmit ECC/MTAG info as well as the actual + * data. 144 bits per quadword, 576 total. + */ +#define LINE_SIZE 64 +#define LINE_ADDR_MSK (LINE_SIZE - 1) +#define QW_PER_LINE 4 +#define QW_BYTES (LINE_SIZE / QW_PER_LINE) +#define QW_BITS 144 +#define LAST_BIT (576 - 1) + + qword = (phys_addr & LINE_ADDR_MSK) / QW_BYTES; + where_in_line = ((3 - qword) * QW_BITS) + syndrome_code; + where = (LAST_BIT - where_in_line); + map_index = where >> 2; + map_offset = where & 0x3; + map_val = map->dimm_map[map_index]; + map_val = ((map_val >> ((3 - map_offset) << 1)) & (2 - 1)); + + sprintf(buf, "%s, pin %3d", + prop->dimm_labels[first_dimm + map_val], + map->pin_map[where_in_line]); } else { int dimm; @@ -586,7 +240,7 @@ static int chmc_print_dimm(int syndrome_code, * the code is executing, you must use special ASI load/store else * you go through the global mapping. */ -static u64 chmc_read_mcreg(struct chmc *p, unsigned long offset) +static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset) { unsigned long ret, this_cpu; @@ -594,14 +248,14 @@ static u64 chmc_read_mcreg(struct chmc *p, unsigned long offset) this_cpu = real_hard_smp_processor_id(); - if (p->portid == this_cpu) { + if (mp->portid == this_cpu) { __asm__ __volatile__("ldxa [%1] %2, %0" : "=r" (ret) : "r" (offset), "i" (ASI_MCU_CTRL_REG)); } else { __asm__ __volatile__("ldxa [%1] %2, %0" : "=r" (ret) - : "r" (p->regs + offset), + : "r" (mp->regs + offset), "i" (ASI_PHYS_BYPASS_EC_E)); } @@ -611,253 +265,178 @@ static u64 chmc_read_mcreg(struct chmc *p, unsigned long offset) } #if 0 /* currently unused */ -static void chmc_write_mcreg(struct chmc *p, unsigned long offset, u64 val) +static void write_mcreg(struct mctrl_info *mp, unsigned long offset, u64 val) { - if (p->portid == smp_processor_id()) { + if (mp->portid == smp_processor_id()) { __asm__ __volatile__("stxa %0, [%1] %2" : : "r" (val), "r" (offset), "i" (ASI_MCU_CTRL_REG)); } else { __asm__ __volatile__("ldxa %0, [%1] %2" : : "r" (val), - "r" (p->regs + offset), + "r" (mp->regs + offset), "i" (ASI_PHYS_BYPASS_EC_E)); } } #endif -static void chmc_interpret_one_decode_reg(struct chmc *p, int which_bank, u64 val) +static void interpret_one_decode_reg(struct mctrl_info *mp, int which_bank, u64 val) { - struct chmc_bank_info *bp = &p->logical_banks[which_bank]; - - bp->p = p; - bp->bank_id = (CHMCTRL_NBANKS * p->portid) + which_bank; - bp->raw_reg = val; - bp->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT; - bp->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT; - bp->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT; - bp->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT; - bp->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT; - - bp->base = (bp->um); - bp->base &= ~(bp->uk); - bp->base <<= PA_UPPER_BITS_SHIFT; - - switch(bp->lk) { + struct bank_info *p = &mp->logical_banks[which_bank]; + + p->mp = mp; + p->bank_id = (CHMCTRL_NBANKS * mp->portid) + which_bank; + p->raw_reg = val; + p->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT; + p->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT; + p->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT; + p->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT; + p->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT; + + p->base = (p->um); + p->base &= ~(p->uk); + p->base <<= PA_UPPER_BITS_SHIFT; + + switch(p->lk) { case 0xf: default: - bp->interleave = 1; + p->interleave = 1; break; case 0xe: - bp->interleave = 2; + p->interleave = 2; break; case 0xc: - bp->interleave = 4; + p->interleave = 4; break; case 0x8: - bp->interleave = 8; + p->interleave = 8; break; case 0x0: - bp->interleave = 16; + p->interleave = 16; break; }; /* UK[10] is reserved, and UK[11] is not set for the SDRAM * bank size definition. */ - bp->size = (((unsigned long)bp->uk & - ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT; - bp->size /= bp->interleave; + p->size = (((unsigned long)p->uk & + ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT; + p->size /= p->interleave; } -static void chmc_fetch_decode_regs(struct chmc *p) +static void fetch_decode_regs(struct mctrl_info *mp) { - if (p->layout_size == 0) + if (mp->layout_size == 0) return; - chmc_interpret_one_decode_reg(p, 0, - chmc_read_mcreg(p, CHMCTRL_DECODE1)); - chmc_interpret_one_decode_reg(p, 1, - chmc_read_mcreg(p, CHMCTRL_DECODE2)); - chmc_interpret_one_decode_reg(p, 2, - chmc_read_mcreg(p, CHMCTRL_DECODE3)); - chmc_interpret_one_decode_reg(p, 3, - chmc_read_mcreg(p, CHMCTRL_DECODE4)); + interpret_one_decode_reg(mp, 0, + read_mcreg(mp, CHMCTRL_DECODE1)); + interpret_one_decode_reg(mp, 1, + read_mcreg(mp, CHMCTRL_DECODE2)); + interpret_one_decode_reg(mp, 2, + read_mcreg(mp, CHMCTRL_DECODE3)); + interpret_one_decode_reg(mp, 3, + read_mcreg(mp, CHMCTRL_DECODE4)); } -static int __devinit chmc_probe(struct of_device *op, - const struct of_device_id *match) +static int init_one_mctrl(struct device_node *dp) { - struct device_node *dp = op->node; - unsigned long ver; + struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL); + int portid = of_getintprop_default(dp, "portid", -1); + const struct linux_prom64_registers *regs; const void *pval; - int len, portid; - struct chmc *p; - int err; - - err = -ENODEV; - __asm__ ("rdpr %%ver, %0" : "=r" (ver)); - if ((ver >> 32UL) == __JALAPENO_ID || - (ver >> 32UL) == __SERRANO_ID) - goto out; + int len; - portid = of_getintprop_default(dp, "portid", -1); + if (!mp) + return -1; if (portid == -1) - goto out; + goto fail; + mp->portid = portid; pval = of_get_property(dp, "memory-layout", &len); - if (pval && len > sizeof(p->layout_prop)) { - printk(KERN_ERR PFX "Unexpected memory-layout property " - "size %d.\n", len); - goto out; + mp->layout_size = len; + if (!pval) + mp->layout_size = 0; + else { + if (mp->layout_size > sizeof(mp->layout_prop)) + goto fail; + memcpy(&mp->layout_prop, pval, len); } - err = -ENOMEM; - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) { - printk(KERN_ERR PFX "Could not allocate struct chmc.\n"); - goto out; - } + regs = of_get_property(dp, "reg", NULL); + if (!regs || regs->reg_size != 0x48) + goto fail; - p->portid = portid; - p->layout_size = len; - if (!pval) - p->layout_size = 0; - else - memcpy(&p->layout_prop, pval, len); - - p->regs = of_ioremap(&op->resource[0], 0, 0x48, "chmc"); - if (!p->regs) { - printk(KERN_ERR PFX "Could not map registers.\n"); - goto out_free; - } + mp->regs = ioremap(regs->phys_addr, regs->reg_size); + if (mp->regs == NULL) + goto fail; - if (p->layout_size != 0UL) { - p->timing_control1 = chmc_read_mcreg(p, CHMCTRL_TCTRL1); - p->timing_control2 = chmc_read_mcreg(p, CHMCTRL_TCTRL2); - p->timing_control3 = chmc_read_mcreg(p, CHMCTRL_TCTRL3); - p->timing_control4 = chmc_read_mcreg(p, CHMCTRL_TCTRL4); - p->memaddr_control = chmc_read_mcreg(p, CHMCTRL_MACTRL); + if (mp->layout_size != 0UL) { + mp->timing_control1 = read_mcreg(mp, CHMCTRL_TCTRL1); + mp->timing_control2 = read_mcreg(mp, CHMCTRL_TCTRL2); + mp->timing_control3 = read_mcreg(mp, CHMCTRL_TCTRL3); + mp->timing_control4 = read_mcreg(mp, CHMCTRL_TCTRL4); + mp->memaddr_control = read_mcreg(mp, CHMCTRL_MACTRL); } - chmc_fetch_decode_regs(p); + fetch_decode_regs(mp); - mc_list_add(&p->list); + list_add(&mp->list, &mctrl_list); - printk(KERN_INFO PFX "UltraSPARC-III memory controller at %s [%s]\n", + /* Report the device. */ + printk(KERN_INFO "%s: US3 memory controller at %p [%s]\n", dp->full_name, - (p->layout_size ? "ACTIVE" : "INACTIVE")); - - dev_set_drvdata(&op->dev, p); - - err = 0; - -out: - return err; - -out_free: - kfree(p); - goto out; -} + mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE")); -static int __devinit us3mc_probe(struct of_device *op, - const struct of_device_id *match) -{ - if (mc_type == MC_TYPE_SAFARI) - return chmc_probe(op, match); - else if (mc_type == MC_TYPE_JBUS) - return jbusmc_probe(op, match); - return -ENODEV; -} - -static void __devexit chmc_destroy(struct of_device *op, struct chmc *p) -{ - list_del(&p->list); - of_iounmap(&op->resource[0], p->regs, 0x48); - kfree(p); -} - -static void __devexit jbusmc_destroy(struct of_device *op, struct jbusmc *p) -{ - mc_list_del(&p->list); - of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE); - kfree(p); -} - -static int __devexit us3mc_remove(struct of_device *op) -{ - void *p = dev_get_drvdata(&op->dev); - - if (p) { - if (mc_type == MC_TYPE_SAFARI) - chmc_destroy(op, p); - else if (mc_type == MC_TYPE_JBUS) - jbusmc_destroy(op, p); - } return 0; -} - -static const struct of_device_id us3mc_match[] = { - { - .name = "memory-controller", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, us3mc_match); - -static struct of_platform_driver us3mc_driver = { - .name = "us3mc", - .match_table = us3mc_match, - .probe = us3mc_probe, - .remove = __devexit_p(us3mc_remove), -}; -static inline bool us3mc_platform(void) -{ - if (tlb_type == cheetah || tlb_type == cheetah_plus) - return true; - return false; +fail: + if (mp) { + if (mp->regs != NULL) + iounmap(mp->regs); + kfree(mp); + } + return -1; } -static int __init us3mc_init(void) +static int __init chmc_init(void) { - unsigned long ver; - int ret; + struct device_node *dp; - if (!us3mc_platform()) + /* This driver is only for cheetah platforms. */ + if (tlb_type != cheetah && tlb_type != cheetah_plus) return -ENODEV; - __asm__ ("rdpr %%ver, %0" : "=r" (ver)); - if ((ver >> 32UL) == __JALAPENO_ID || - (ver >> 32UL) == __SERRANO_ID) { - mc_type = MC_TYPE_JBUS; - us3mc_dimm_printer = jbusmc_print_dimm; - } else { - mc_type = MC_TYPE_SAFARI; - us3mc_dimm_printer = chmc_print_dimm; - } + for_each_node_by_name(dp, "memory-controller") + init_one_mctrl(dp); - ret = register_dimm_printer(us3mc_dimm_printer); + for_each_node_by_name(dp, "mc-us3") + init_one_mctrl(dp); - if (!ret) { - ret = of_register_driver(&us3mc_driver, &of_bus_type); - if (ret) - unregister_dimm_printer(us3mc_dimm_printer); - } - return ret; + return 0; } -static void __exit us3mc_cleanup(void) +static void __exit chmc_cleanup(void) { - if (us3mc_platform()) { - unregister_dimm_printer(us3mc_dimm_printer); - of_unregister_driver(&us3mc_driver); + struct list_head *head = &mctrl_list; + struct list_head *tmp = head->next; + + for (;;) { + struct mctrl_info *p = + list_entry(tmp, struct mctrl_info, list); + if (tmp == head) + break; + tmp = tmp->next; + + list_del(&p->list); + iounmap(p->regs); + kfree(p); } } -module_init(us3mc_init); -module_exit(us3mc_cleanup); +module_init(chmc_init); +module_exit(chmc_cleanup); diff --git a/trunk/arch/sparc64/kernel/cpu.c b/trunk/arch/sparc64/kernel/cpu.c index 0c9ac83ed0a8..0097c08dc600 100644 --- a/trunk/arch/sparc64/kernel/cpu.c +++ b/trunk/arch/sparc64/kernel/cpu.c @@ -1,7 +1,7 @@ /* cpu.c: Dinky routines to look for the kind of Sparc cpu * we are on. * - * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net) */ #include @@ -19,86 +19,53 @@ DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 }; -struct cpu_chip_info { - unsigned short manuf; - unsigned short impl; - const char *cpu_name; - const char *fp_name; +struct cpu_iu_info { + short manuf; + short impl; + char* cpu_name; /* should be enough I hope... */ }; -static const struct cpu_chip_info cpu_chips[] = { - { - .manuf = 0x17, - .impl = 0x10, - .cpu_name = "TI UltraSparc I (SpitFire)", - .fp_name = "UltraSparc I integrated FPU", - }, - { - .manuf = 0x22, - .impl = 0x10, - .cpu_name = "TI UltraSparc I (SpitFire)", - .fp_name = "UltraSparc I integrated FPU", - }, - { - .manuf = 0x17, - .impl = 0x11, - .cpu_name = "TI UltraSparc II (BlackBird)", - .fp_name = "UltraSparc II integrated FPU", - }, - { - .manuf = 0x17, - .impl = 0x12, - .cpu_name = "TI UltraSparc IIi (Sabre)", - .fp_name = "UltraSparc IIi integrated FPU", - }, - { - .manuf = 0x17, - .impl = 0x13, - .cpu_name = "TI UltraSparc IIe (Hummingbird)", - .fp_name = "UltraSparc IIe integrated FPU", - }, - { - .manuf = 0x3e, - .impl = 0x14, - .cpu_name = "TI UltraSparc III (Cheetah)", - .fp_name = "UltraSparc III integrated FPU", - }, - { - .manuf = 0x3e, - .impl = 0x15, - .cpu_name = "TI UltraSparc III+ (Cheetah+)", - .fp_name = "UltraSparc III+ integrated FPU", - }, - { - .manuf = 0x3e, - .impl = 0x16, - .cpu_name = "TI UltraSparc IIIi (Jalapeno)", - .fp_name = "UltraSparc IIIi integrated FPU", - }, - { - .manuf = 0x3e, - .impl = 0x18, - .cpu_name = "TI UltraSparc IV (Jaguar)", - .fp_name = "UltraSparc IV integrated FPU", - }, - { - .manuf = 0x3e, - .impl = 0x19, - .cpu_name = "TI UltraSparc IV+ (Panther)", - .fp_name = "UltraSparc IV+ integrated FPU", - }, - { - .manuf = 0x3e, - .impl = 0x22, - .cpu_name = "TI UltraSparc IIIi+ (Serrano)", - .fp_name = "UltraSparc IIIi+ integrated FPU", - }, +struct cpu_fp_info { + short manuf; + short impl; + char fpu_vers; + char* fp_name; }; -#define NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips) +static struct cpu_fp_info linux_sparc_fpu[] = { + { 0x17, 0x10, 0, "UltraSparc I integrated FPU"}, + { 0x22, 0x10, 0, "UltraSparc I integrated FPU"}, + { 0x17, 0x11, 0, "UltraSparc II integrated FPU"}, + { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"}, + { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"}, + { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"}, + { 0x3e, 0x15, 0, "UltraSparc III+ integrated FPU"}, + { 0x3e, 0x16, 0, "UltraSparc IIIi integrated FPU"}, + { 0x3e, 0x18, 0, "UltraSparc IV integrated FPU"}, + { 0x3e, 0x19, 0, "UltraSparc IV+ integrated FPU"}, + { 0x3e, 0x22, 0, "UltraSparc IIIi+ integrated FPU"}, +}; + +#define NSPARCFPU ARRAY_SIZE(linux_sparc_fpu) + +static struct cpu_iu_info linux_sparc_chips[] = { + { 0x17, 0x10, "TI UltraSparc I (SpitFire)"}, + { 0x22, 0x10, "TI UltraSparc I (SpitFire)"}, + { 0x17, 0x11, "TI UltraSparc II (BlackBird)"}, + { 0x17, 0x12, "TI UltraSparc IIi (Sabre)"}, + { 0x17, 0x13, "TI UltraSparc IIe (Hummingbird)"}, + { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"}, + { 0x3e, 0x15, "TI UltraSparc III+ (Cheetah+)"}, + { 0x3e, 0x16, "TI UltraSparc IIIi (Jalapeno)"}, + { 0x3e, 0x18, "TI UltraSparc IV (Jaguar)"}, + { 0x3e, 0x19, "TI UltraSparc IV+ (Panther)"}, + { 0x3e, 0x22, "TI UltraSparc IIIi+ (Serrano)"}, +}; -const char *sparc_cpu_type; -const char *sparc_fpu_type; +#define NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips) + +char *sparc_cpu_type; +char *sparc_fpu_type; static void __init sun4v_cpu_probe(void) { @@ -122,45 +89,68 @@ static void __init sun4v_cpu_probe(void) } } -static const struct cpu_chip_info * __init find_cpu_chip(unsigned short manuf, - unsigned short impl) +void __init cpu_probe(void) { + unsigned long ver, fpu_vers, manuf, impl, fprs; int i; + + if (tlb_type == hypervisor) { + sun4v_cpu_probe(); + return; + } - for (i = 0; i < ARRAY_SIZE(cpu_chips); i++) { - const struct cpu_chip_info *p = &cpu_chips[i]; + fprs = fprs_read(); + fprs_write(FPRS_FEF); + __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" + : "=&r" (ver) + : "r" (&fpu_vers)); + fprs_write(fprs); + + manuf = ((ver >> 48) & 0xffff); + impl = ((ver >> 32) & 0xffff); + + fpu_vers = ((fpu_vers >> 17) & 0x7); + +retry: + for (i = 0; i < NSPARCCHIPS; i++) { + if (linux_sparc_chips[i].manuf == manuf) { + if (linux_sparc_chips[i].impl == impl) { + sparc_cpu_type = + linux_sparc_chips[i].cpu_name; + break; + } + } + } - if (p->manuf == manuf && p->impl == impl) - return p; + if (i == NSPARCCHIPS) { + /* Maybe it is a cheetah+ derivative, report it as cheetah+ + * in that case until we learn the real names. + */ + if (manuf == 0x3e && + impl > 0x15) { + impl = 0x15; + goto retry; + } else { + printk("DEBUG: manuf[%lx] impl[%lx]\n", + manuf, impl); + } + sparc_cpu_type = "Unknown CPU"; } - return NULL; -} -static int __init cpu_type_probe(void) -{ - if (tlb_type == hypervisor) { - sun4v_cpu_probe(); - } else { - unsigned long ver, manuf, impl; - const struct cpu_chip_info *p; - - __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver)); - - manuf = ((ver >> 48) & 0xffff); - impl = ((ver >> 32) & 0xffff); - - p = find_cpu_chip(manuf, impl); - if (p) { - sparc_cpu_type = p->cpu_name; - sparc_fpu_type = p->fp_name; - } else { - printk(KERN_ERR "CPU: Unknown chip, manuf[%lx] impl[%lx]\n", - manuf, impl); - sparc_cpu_type = "Unknown CPU"; - sparc_fpu_type = "Unknown FPU"; + for (i = 0; i < NSPARCFPU; i++) { + if (linux_sparc_fpu[i].manuf == manuf && + linux_sparc_fpu[i].impl == impl) { + if (linux_sparc_fpu[i].fpu_vers == fpu_vers) { + sparc_fpu_type = + linux_sparc_fpu[i].fp_name; + break; + } } } - return 0; -} -arch_initcall(cpu_type_probe); + if (i == NSPARCFPU) { + printk("DEBUG: manuf[%lx] impl[%lx] fsr.vers[%lx]\n", + manuf, impl, fpu_vers); + sparc_fpu_type = "Unknown FPU"; + } +} diff --git a/trunk/arch/sparc64/kernel/ds.c b/trunk/arch/sparc64/kernel/ds.c index f52e0534d91d..d0fa5aa38934 100644 --- a/trunk/arch/sparc64/kernel/ds.c +++ b/trunk/arch/sparc64/kernel/ds.c @@ -1,6 +1,6 @@ /* ds.c: Domain Services driver for Logical Domains * - * Copyright (C) 2007, 2008 David S. Miller + * Copyright (C) 2007 David S. Miller */ #include @@ -1217,7 +1217,7 @@ static int ds_remove(struct vio_dev *vdev) return 0; } -static struct vio_device_id __initdata ds_match[] = { +static struct vio_device_id ds_match[] = { { .type = "domain-services-port", }, diff --git a/trunk/arch/sparc64/kernel/ebus.c b/trunk/arch/sparc64/kernel/ebus.c index 77dbf6d45faf..60d36d142559 100644 --- a/trunk/arch/sparc64/kernel/ebus.c +++ b/trunk/arch/sparc64/kernel/ebus.c @@ -1,4 +1,5 @@ -/* ebus.c: EBUS DMA library code. +/* + * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -8,12 +9,24 @@ #include #include #include +#include +#include #include #include - -#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include #include +/* EBUS dma library. */ + #define EBDMA_CSR 0x00UL /* Control/Status */ #define EBDMA_ADDR 0x04UL /* DMA Address */ #define EBDMA_COUNT 0x08UL /* DMA Count */ @@ -255,3 +268,283 @@ void ebus_dma_enable(struct ebus_dma_info *p, int on) spin_unlock_irqrestore(&p->lock, flags); } EXPORT_SYMBOL(ebus_dma_enable); + +struct linux_ebus *ebus_chain = NULL; + +static inline void *ebus_alloc(size_t size) +{ + void *mem; + + mem = kzalloc(size, GFP_ATOMIC); + if (!mem) + panic("ebus_alloc: out of memory"); + return mem; +} + +static void __init fill_ebus_child(struct device_node *dp, + struct linux_ebus_child *dev, + int non_standard_regs) +{ + struct of_device *op; + const int *regs; + int i, len; + + dev->prom_node = dp; + printk(" (%s)", dp->name); + + regs = of_get_property(dp, "reg", &len); + if (!regs) + dev->num_addrs = 0; + else + dev->num_addrs = len / sizeof(regs[0]); + + if (non_standard_regs) { + /* This is to handle reg properties which are not + * in the parent relative format. One example are + * children of the i2c device on CompactPCI systems. + * + * So, for such devices we just record the property + * raw in the child resources. + */ + for (i = 0; i < dev->num_addrs; i++) + dev->resource[i].start = regs[i]; + } else { + for (i = 0; i < dev->num_addrs; i++) { + int rnum = regs[i]; + if (rnum >= dev->parent->num_addrs) { + prom_printf("UGH: property for %s was %d, need < %d\n", + dp->name, len, dev->parent->num_addrs); + prom_halt(); + } + dev->resource[i].start = dev->parent->resource[i].start; + dev->resource[i].end = dev->parent->resource[i].end; + dev->resource[i].flags = IORESOURCE_MEM; + dev->resource[i].name = dp->name; + } + } + + op = of_find_device_by_node(dp); + if (!op) { + dev->num_irqs = 0; + } else { + dev->num_irqs = op->num_irqs; + for (i = 0; i < dev->num_irqs; i++) + dev->irqs[i] = op->irqs[i]; + } + + if (!dev->num_irqs) { + /* + * Oh, well, some PROMs don't export interrupts + * property to children of EBus devices... + * + * Be smart about PS/2 keyboard and mouse. + */ + if (!strcmp(dev->parent->prom_node->name, "8042")) { + if (!strcmp(dev->prom_node->name, "kb_ps2")) { + dev->num_irqs = 1; + dev->irqs[0] = dev->parent->irqs[0]; + } else { + dev->num_irqs = 1; + dev->irqs[0] = dev->parent->irqs[1]; + } + } + } +} + +static int __init child_regs_nonstandard(struct linux_ebus_device *dev) +{ + if (!strcmp(dev->prom_node->name, "i2c") || + !strcmp(dev->prom_node->name, "SUNW,lombus")) + return 1; + return 0; +} + +static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev) +{ + struct linux_ebus_child *child; + struct dev_archdata *sd; + struct of_device *op; + int i, len; + + dev->prom_node = dp; + + printk(" [%s", dp->name); + + op = of_find_device_by_node(dp); + if (!op) { + dev->num_addrs = 0; + dev->num_irqs = 0; + } else { + const int *regs = of_get_property(dp, "reg", &len); + + if (!regs) + len = 0; + dev->num_addrs = len / sizeof(struct linux_prom_registers); + + for (i = 0; i < dev->num_addrs; i++) + memcpy(&dev->resource[i], + &op->resource[i], + sizeof(struct resource)); + + dev->num_irqs = op->num_irqs; + for (i = 0; i < dev->num_irqs; i++) + dev->irqs[i] = op->irqs[i]; + } + + sd = &dev->ofdev.dev.archdata; + sd->prom_node = dp; + sd->op = &dev->ofdev; + sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu; + sd->stc = dev->bus->ofdev.dev.parent->archdata.stc; + sd->numa_node = dev->bus->ofdev.dev.parent->archdata.numa_node; + + dev->ofdev.node = dp; + dev->ofdev.dev.parent = &dev->bus->ofdev.dev; + dev->ofdev.dev.bus = &ebus_bus_type; + dev_set_name(&dev->ofdev.dev, "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); + + dp = dp->child; + if (dp) { + printk(" ->"); + dev->children = 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, + child_regs_nonstandard(dev)); + + while ((dp = dp->sibling) != NULL) { + child->next = 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, + child_regs_nonstandard(dev)); + } + } + printk("]"); +} + +static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p) +{ + struct pci_dev *pdev = start; + + while ((pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_ANY_ID, pdev))) + if (pdev->device == PCI_DEVICE_ID_SUN_EBUS || + pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS) + break; + + *is_rio_p = !!(pdev && (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS)); + + return pdev; +} + +void __init ebus_init(void) +{ + struct linux_ebus_device *dev; + struct linux_ebus *ebus; + struct pci_dev *pdev; + struct device_node *dp; + int is_rio; + int num_ebus = 0; + + pdev = find_next_ebus(NULL, &is_rio); + if (!pdev) { + printk("ebus: No EBus's found.\n"); + return; + } + + dp = pci_device_to_OF_node(pdev); + + ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus)); + ebus->next = NULL; + ebus->is_rio = is_rio; + + while (dp) { + struct device_node *child; + + /* SUNW,pci-qfe uses four empty ebuses on it. + I think we should not consider them here, + as they have half of the properties this + code expects and once we do PCI hot-plug, + we'd have to tweak with the ebus_chain + in the runtime after initialization. -jj */ + if (!dp->child) { + pdev = find_next_ebus(pdev, &is_rio); + if (!pdev) { + if (ebus == ebus_chain) { + ebus_chain = NULL; + printk("ebus: No EBus's found.\n"); + return; + } + break; + } + ebus->is_rio = is_rio; + dp = pci_device_to_OF_node(pdev); + continue; + } + printk("ebus%d:", num_ebus); + + ebus->index = num_ebus; + ebus->prom_node = dp; + ebus->self = pdev; + + ebus->ofdev.node = dp; + ebus->ofdev.dev.parent = &pdev->dev; + ebus->ofdev.dev.bus = &ebus_bus_type; + dev_set_name(&ebus->ofdev.dev, "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); + + + child = dp->child; + if (!child) + goto next_ebus; + + ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device)); + + dev = ebus->devices; + dev->next = NULL; + dev->children = NULL; + dev->bus = ebus; + fill_ebus_device(child, dev); + + while ((child = child->sibling) != NULL) { + dev->next = ebus_alloc(sizeof(struct linux_ebus_device)); + + dev = dev->next; + dev->next = NULL; + dev->children = NULL; + dev->bus = ebus; + fill_ebus_device(child, dev); + } + + next_ebus: + printk("\n"); + + pdev = find_next_ebus(pdev, &is_rio); + if (!pdev) + break; + + dp = pci_device_to_OF_node(pdev); + + ebus->next = ebus_alloc(sizeof(struct linux_ebus)); + ebus = ebus->next; + ebus->next = NULL; + ebus->is_rio = is_rio; + ++num_ebus; + } + pci_dev_put(pdev); /* XXX for the case, when ebusnd is 0, is it OK? */ +} diff --git a/trunk/arch/sparc64/kernel/entry.h b/trunk/arch/sparc64/kernel/entry.h index 34d7ab5e10d2..fc294a292899 100644 --- a/trunk/arch/sparc64/kernel/entry.h +++ b/trunk/arch/sparc64/kernel/entry.h @@ -5,8 +5,8 @@ #include #include -extern const char *sparc_cpu_type; -extern const char *sparc_fpu_type; +extern char *sparc_cpu_type; +extern char *sparc_fpu_type; extern void __init per_cpu_patch(void); extern void __init sun4v_patch(void); @@ -22,8 +22,7 @@ extern void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags); -extern asmlinkage int syscall_trace_enter(struct pt_regs *regs); -extern asmlinkage void syscall_trace_leave(struct pt_regs *regs); +extern asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p); extern void bad_trap_tl1(struct pt_regs *regs, long lvl); diff --git a/trunk/arch/sparc64/kernel/head.S b/trunk/arch/sparc64/kernel/head.S index 353226fa0239..c9afef093d51 100644 --- a/trunk/arch/sparc64/kernel/head.S +++ b/trunk/arch/sparc64/kernel/head.S @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sparc64/kernel/hvapi.c b/trunk/arch/sparc64/kernel/hvapi.c index 1d272c3b5740..691760b5b012 100644 --- a/trunk/arch/sparc64/kernel/hvapi.c +++ b/trunk/arch/sparc64/kernel/hvapi.c @@ -9,6 +9,7 @@ #include #include +#include /* If the hypervisor indicates that the API setting * calls are unsupported, by returning HV_EBADTRAP or @@ -183,6 +184,8 @@ void __init sun4v_hvapi_init(void) if (sun4v_hvapi_register(group, major, &minor)) goto bad; + sun4v_sstate_init(); + return; bad: diff --git a/trunk/arch/sparc64/kernel/hvcalls.S b/trunk/arch/sparc64/kernel/hvcalls.S index e066269d1594..a2810f3ac70f 100644 --- a/trunk/arch/sparc64/kernel/hvcalls.S +++ b/trunk/arch/sparc64/kernel/hvcalls.S @@ -3,75 +3,89 @@ * * returns %o0: sysino */ -ENTRY(sun4v_devino_to_sysino) + .globl sun4v_devino_to_sysino + .type sun4v_devino_to_sysino,#function +sun4v_devino_to_sysino: mov HV_FAST_INTR_DEVINO2SYSINO, %o5 ta HV_FAST_TRAP retl mov %o1, %o0 -ENDPROC(sun4v_devino_to_sysino) + .size sun4v_devino_to_sysino, .-sun4v_devino_to_sysino /* %o0: sysino * * returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED}) */ -ENTRY(sun4v_intr_getenabled) + .globl sun4v_intr_getenabled + .type sun4v_intr_getenabled,#function +sun4v_intr_getenabled: mov HV_FAST_INTR_GETENABLED, %o5 ta HV_FAST_TRAP retl mov %o1, %o0 -ENDPROC(sun4v_intr_getenabled) + .size sun4v_intr_getenabled, .-sun4v_intr_getenabled /* %o0: sysino * %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED}) */ -ENTRY(sun4v_intr_setenabled) + .globl sun4v_intr_setenabled + .type sun4v_intr_setenabled,#function +sun4v_intr_setenabled: mov HV_FAST_INTR_SETENABLED, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_intr_setenabled) + .size sun4v_intr_setenabled, .-sun4v_intr_setenabled /* %o0: sysino * * returns %o0: intr_state (HV_INTR_STATE_*) */ -ENTRY(sun4v_intr_getstate) + .globl sun4v_intr_getstate + .type sun4v_intr_getstate,#function +sun4v_intr_getstate: mov HV_FAST_INTR_GETSTATE, %o5 ta HV_FAST_TRAP retl mov %o1, %o0 -ENDPROC(sun4v_intr_getstate) + .size sun4v_intr_getstate, .-sun4v_intr_getstate /* %o0: sysino * %o1: intr_state (HV_INTR_STATE_*) */ -ENTRY(sun4v_intr_setstate) + .globl sun4v_intr_setstate + .type sun4v_intr_setstate,#function +sun4v_intr_setstate: mov HV_FAST_INTR_SETSTATE, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_intr_setstate) + .size sun4v_intr_setstate, .-sun4v_intr_setstate /* %o0: sysino * * returns %o0: cpuid */ -ENTRY(sun4v_intr_gettarget) + .globl sun4v_intr_gettarget + .type sun4v_intr_gettarget,#function +sun4v_intr_gettarget: mov HV_FAST_INTR_GETTARGET, %o5 ta HV_FAST_TRAP retl mov %o1, %o0 -ENDPROC(sun4v_intr_gettarget) + .size sun4v_intr_gettarget, .-sun4v_intr_gettarget /* %o0: sysino * %o1: cpuid */ -ENTRY(sun4v_intr_settarget) + .globl sun4v_intr_settarget + .type sun4v_intr_settarget,#function +sun4v_intr_settarget: mov HV_FAST_INTR_SETTARGET, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_intr_settarget) + .size sun4v_intr_settarget, .-sun4v_intr_settarget /* %o0: cpuid * %o1: pc @@ -80,31 +94,37 @@ ENDPROC(sun4v_intr_settarget) * * returns %o0: status */ -ENTRY(sun4v_cpu_start) + .globl sun4v_cpu_start + .type sun4v_cpu_start,#function +sun4v_cpu_start: mov HV_FAST_CPU_START, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_cpu_start) + .size sun4v_cpu_start, .-sun4v_cpu_start /* %o0: cpuid * * returns %o0: status */ -ENTRY(sun4v_cpu_stop) + .globl sun4v_cpu_stop + .type sun4v_cpu_stop,#function +sun4v_cpu_stop: mov HV_FAST_CPU_STOP, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_cpu_stop) + .size sun4v_cpu_stop, .-sun4v_cpu_stop /* returns %o0: status */ -ENTRY(sun4v_cpu_yield) + .globl sun4v_cpu_yield + .type sun4v_cpu_yield, #function +sun4v_cpu_yield: mov HV_FAST_CPU_YIELD, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_cpu_yield) + .size sun4v_cpu_yield, .-sun4v_cpu_yield /* %o0: type * %o1: queue paddr @@ -112,12 +132,14 @@ ENDPROC(sun4v_cpu_yield) * * returns %o0: status */ -ENTRY(sun4v_cpu_qconf) + .globl sun4v_cpu_qconf + .type sun4v_cpu_qconf,#function +sun4v_cpu_qconf: mov HV_FAST_CPU_QCONF, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_cpu_qconf) + .size sun4v_cpu_qconf, .-sun4v_cpu_qconf /* %o0: num cpus in cpu list * %o1: cpu list paddr @@ -125,19 +147,23 @@ ENDPROC(sun4v_cpu_qconf) * * returns %o0: status */ -ENTRY(sun4v_cpu_mondo_send) + .globl sun4v_cpu_mondo_send + .type sun4v_cpu_mondo_send,#function +sun4v_cpu_mondo_send: mov HV_FAST_CPU_MONDO_SEND, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_cpu_mondo_send) + .size sun4v_cpu_mondo_send, .-sun4v_cpu_mondo_send /* %o0: CPU ID * * returns %o0: -status if status non-zero, else * %o0: cpu state as HV_CPU_STATE_* */ -ENTRY(sun4v_cpu_state) + .globl sun4v_cpu_state + .type sun4v_cpu_state,#function +sun4v_cpu_state: mov HV_FAST_CPU_STATE, %o5 ta HV_FAST_TRAP brnz,pn %o0, 1f @@ -145,7 +171,7 @@ ENTRY(sun4v_cpu_state) mov %o1, %o0 1: retl nop -ENDPROC(sun4v_cpu_state) + .size sun4v_cpu_state, .-sun4v_cpu_state /* %o0: virtual address * %o1: must be zero @@ -154,24 +180,28 @@ ENDPROC(sun4v_cpu_state) * * returns %o0: status */ -ENTRY(sun4v_mmu_map_perm_addr) + .globl sun4v_mmu_map_perm_addr + .type sun4v_mmu_map_perm_addr,#function +sun4v_mmu_map_perm_addr: mov HV_FAST_MMU_MAP_PERM_ADDR, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_mmu_map_perm_addr) + .size sun4v_mmu_map_perm_addr, .-sun4v_mmu_map_perm_addr /* %o0: number of TSB descriptions * %o1: TSB descriptions real address * * returns %o0: status */ -ENTRY(sun4v_mmu_tsb_ctx0) + .globl sun4v_mmu_tsb_ctx0 + .type sun4v_mmu_tsb_ctx0,#function +sun4v_mmu_tsb_ctx0: mov HV_FAST_MMU_TSB_CTX0, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_mmu_tsb_ctx0) + .size sun4v_mmu_tsb_ctx0, .-sun4v_mmu_tsb_ctx0 /* %o0: API group number * %o1: pointer to unsigned long major number storage @@ -179,7 +209,9 @@ ENDPROC(sun4v_mmu_tsb_ctx0) * * returns %o0: status */ -ENTRY(sun4v_get_version) + .globl sun4v_get_version + .type sun4v_get_version,#function +sun4v_get_version: mov HV_CORE_GET_VER, %o5 mov %o1, %o3 mov %o2, %o4 @@ -187,7 +219,7 @@ ENTRY(sun4v_get_version) stx %o1, [%o3] retl stx %o2, [%o4] -ENDPROC(sun4v_get_version) + .size sun4v_get_version, .-sun4v_get_version /* %o0: API group number * %o1: desired major number @@ -196,43 +228,51 @@ ENDPROC(sun4v_get_version) * * returns %o0: status */ -ENTRY(sun4v_set_version) + .globl sun4v_set_version + .type sun4v_set_version,#function +sun4v_set_version: mov HV_CORE_SET_VER, %o5 mov %o3, %o4 ta HV_CORE_TRAP retl stx %o1, [%o4] -ENDPROC(sun4v_set_version) + .size sun4v_set_version, .-sun4v_set_version /* %o0: pointer to unsigned long time * * returns %o0: status */ -ENTRY(sun4v_tod_get) + .globl sun4v_tod_get + .type sun4v_tod_get,#function +sun4v_tod_get: mov %o0, %o4 mov HV_FAST_TOD_GET, %o5 ta HV_FAST_TRAP stx %o1, [%o4] retl nop -ENDPROC(sun4v_tod_get) + .size sun4v_tod_get, .-sun4v_tod_get /* %o0: time * * returns %o0: status */ -ENTRY(sun4v_tod_set) + .globl sun4v_tod_set + .type sun4v_tod_set,#function +sun4v_tod_set: mov HV_FAST_TOD_SET, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_tod_set) + .size sun4v_tod_set, .-sun4v_tod_set /* %o0: pointer to unsigned long status * * returns %o0: signed character */ -ENTRY(sun4v_con_getchar) + .globl sun4v_con_getchar + .type sun4v_con_getchar,#function +sun4v_con_getchar: mov %o0, %o4 mov HV_FAST_CONS_GETCHAR, %o5 clr %o0 @@ -241,18 +281,20 @@ ENTRY(sun4v_con_getchar) stx %o0, [%o4] retl sra %o1, 0, %o0 -ENDPROC(sun4v_con_getchar) + .size sun4v_con_getchar, .-sun4v_con_getchar /* %o0: signed long character * * returns %o0: status */ -ENTRY(sun4v_con_putchar) + .globl sun4v_con_putchar + .type sun4v_con_putchar,#function +sun4v_con_putchar: mov HV_FAST_CONS_PUTCHAR, %o5 ta HV_FAST_TRAP retl sra %o0, 0, %o0 -ENDPROC(sun4v_con_putchar) + .size sun4v_con_putchar, .-sun4v_con_putchar /* %o0: buffer real address * %o1: buffer size @@ -260,7 +302,9 @@ ENDPROC(sun4v_con_putchar) * * returns %o0: status */ -ENTRY(sun4v_con_read) + .globl sun4v_con_read + .type sun4v_con_read,#function +sun4v_con_read: mov %o2, %o4 mov HV_FAST_CONS_READ, %o5 ta HV_FAST_TRAP @@ -274,7 +318,7 @@ ENTRY(sun4v_con_read) stx %o1, [%o4] 1: retl nop -ENDPROC(sun4v_con_read) + .size sun4v_con_read, .-sun4v_con_read /* %o0: buffer real address * %o1: buffer size @@ -282,37 +326,43 @@ ENDPROC(sun4v_con_read) * * returns %o0: status */ -ENTRY(sun4v_con_write) + .globl sun4v_con_write + .type sun4v_con_write,#function +sun4v_con_write: mov %o2, %o4 mov HV_FAST_CONS_WRITE, %o5 ta HV_FAST_TRAP stx %o1, [%o4] retl nop -ENDPROC(sun4v_con_write) + .size sun4v_con_write, .-sun4v_con_write /* %o0: soft state * %o1: address of description string * * returns %o0: status */ -ENTRY(sun4v_mach_set_soft_state) + .globl sun4v_mach_set_soft_state + .type sun4v_mach_set_soft_state,#function +sun4v_mach_set_soft_state: mov HV_FAST_MACH_SET_SOFT_STATE, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_mach_set_soft_state) + .size sun4v_mach_set_soft_state, .-sun4v_mach_set_soft_state /* %o0: exit code * * Does not return. */ -ENTRY(sun4v_mach_exit) + .globl sun4v_mach_exit + .type sun4v_mach_exit,#function +sun4v_mach_exit: mov HV_FAST_MACH_EXIT, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_mach_exit) + .size sun4v_mach_exit, .-sun4v_mach_exit /* %o0: buffer real address * %o1: buffer length @@ -320,38 +370,44 @@ ENDPROC(sun4v_mach_exit) * * returns %o0: status */ -ENTRY(sun4v_mach_desc) + .globl sun4v_mach_desc + .type sun4v_mach_desc,#function +sun4v_mach_desc: mov %o2, %o4 mov HV_FAST_MACH_DESC, %o5 ta HV_FAST_TRAP stx %o1, [%o4] retl nop -ENDPROC(sun4v_mach_desc) + .size sun4v_mach_desc, .-sun4v_mach_desc /* %o0: new timeout in milliseconds * %o1: pointer to unsigned long orig_timeout * * returns %o0: status */ -ENTRY(sun4v_mach_set_watchdog) + .globl sun4v_mach_set_watchdog + .type sun4v_mach_set_watchdog,#function +sun4v_mach_set_watchdog: mov %o1, %o4 mov HV_FAST_MACH_SET_WATCHDOG, %o5 ta HV_FAST_TRAP stx %o1, [%o4] retl nop -ENDPROC(sun4v_mach_set_watchdog) + .size sun4v_mach_set_watchdog, .-sun4v_mach_set_watchdog /* No inputs and does not return. */ -ENTRY(sun4v_mach_sir) + .globl sun4v_mach_sir + .type sun4v_mach_sir,#function +sun4v_mach_sir: mov %o1, %o4 mov HV_FAST_MACH_SIR, %o5 ta HV_FAST_TRAP stx %o1, [%o4] retl nop -ENDPROC(sun4v_mach_sir) + .size sun4v_mach_sir, .-sun4v_mach_sir /* %o0: channel * %o1: ra @@ -359,12 +415,14 @@ ENDPROC(sun4v_mach_sir) * * returns %o0: status */ -ENTRY(sun4v_ldc_tx_qconf) + .globl sun4v_ldc_tx_qconf + .type sun4v_ldc_tx_qconf,#function +sun4v_ldc_tx_qconf: mov HV_FAST_LDC_TX_QCONF, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_ldc_tx_qconf) + .size sun4v_ldc_tx_qconf, .-sun4v_ldc_tx_qconf /* %o0: channel * %o1: pointer to unsigned long ra @@ -372,7 +430,9 @@ ENDPROC(sun4v_ldc_tx_qconf) * * returns %o0: status */ -ENTRY(sun4v_ldc_tx_qinfo) + .globl sun4v_ldc_tx_qinfo + .type sun4v_ldc_tx_qinfo,#function +sun4v_ldc_tx_qinfo: mov %o1, %g1 mov %o2, %g2 mov HV_FAST_LDC_TX_QINFO, %o5 @@ -381,7 +441,7 @@ ENTRY(sun4v_ldc_tx_qinfo) stx %o2, [%g2] retl nop -ENDPROC(sun4v_ldc_tx_qinfo) + .size sun4v_ldc_tx_qinfo, .-sun4v_ldc_tx_qinfo /* %o0: channel * %o1: pointer to unsigned long head_off @@ -390,7 +450,9 @@ ENDPROC(sun4v_ldc_tx_qinfo) * * returns %o0: status */ -ENTRY(sun4v_ldc_tx_get_state) + .globl sun4v_ldc_tx_get_state + .type sun4v_ldc_tx_get_state,#function +sun4v_ldc_tx_get_state: mov %o1, %g1 mov %o2, %g2 mov %o3, %g3 @@ -401,19 +463,21 @@ ENTRY(sun4v_ldc_tx_get_state) stx %o3, [%g3] retl nop -ENDPROC(sun4v_ldc_tx_get_state) + .size sun4v_ldc_tx_get_state, .-sun4v_ldc_tx_get_state /* %o0: channel * %o1: tail_off * * returns %o0: status */ -ENTRY(sun4v_ldc_tx_set_qtail) + .globl sun4v_ldc_tx_set_qtail + .type sun4v_ldc_tx_set_qtail,#function +sun4v_ldc_tx_set_qtail: mov HV_FAST_LDC_TX_SET_QTAIL, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_ldc_tx_set_qtail) + .size sun4v_ldc_tx_set_qtail, .-sun4v_ldc_tx_set_qtail /* %o0: channel * %o1: ra @@ -421,12 +485,14 @@ ENDPROC(sun4v_ldc_tx_set_qtail) * * returns %o0: status */ -ENTRY(sun4v_ldc_rx_qconf) + .globl sun4v_ldc_rx_qconf + .type sun4v_ldc_rx_qconf,#function +sun4v_ldc_rx_qconf: mov HV_FAST_LDC_RX_QCONF, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_ldc_rx_qconf) + .size sun4v_ldc_rx_qconf, .-sun4v_ldc_rx_qconf /* %o0: channel * %o1: pointer to unsigned long ra @@ -434,7 +500,9 @@ ENDPROC(sun4v_ldc_rx_qconf) * * returns %o0: status */ -ENTRY(sun4v_ldc_rx_qinfo) + .globl sun4v_ldc_rx_qinfo + .type sun4v_ldc_rx_qinfo,#function +sun4v_ldc_rx_qinfo: mov %o1, %g1 mov %o2, %g2 mov HV_FAST_LDC_RX_QINFO, %o5 @@ -443,7 +511,7 @@ ENTRY(sun4v_ldc_rx_qinfo) stx %o2, [%g2] retl nop -ENDPROC(sun4v_ldc_rx_qinfo) + .size sun4v_ldc_rx_qinfo, .-sun4v_ldc_rx_qinfo /* %o0: channel * %o1: pointer to unsigned long head_off @@ -452,7 +520,9 @@ ENDPROC(sun4v_ldc_rx_qinfo) * * returns %o0: status */ -ENTRY(sun4v_ldc_rx_get_state) + .globl sun4v_ldc_rx_get_state + .type sun4v_ldc_rx_get_state,#function +sun4v_ldc_rx_get_state: mov %o1, %g1 mov %o2, %g2 mov %o3, %g3 @@ -463,19 +533,21 @@ ENTRY(sun4v_ldc_rx_get_state) stx %o3, [%g3] retl nop -ENDPROC(sun4v_ldc_rx_get_state) + .size sun4v_ldc_rx_get_state, .-sun4v_ldc_rx_get_state /* %o0: channel * %o1: head_off * * returns %o0: status */ -ENTRY(sun4v_ldc_rx_set_qhead) + .globl sun4v_ldc_rx_set_qhead + .type sun4v_ldc_rx_set_qhead,#function +sun4v_ldc_rx_set_qhead: mov HV_FAST_LDC_RX_SET_QHEAD, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_ldc_rx_set_qhead) + .size sun4v_ldc_rx_set_qhead, .-sun4v_ldc_rx_set_qhead /* %o0: channel * %o1: ra @@ -483,12 +555,14 @@ ENDPROC(sun4v_ldc_rx_set_qhead) * * returns %o0: status */ -ENTRY(sun4v_ldc_set_map_table) + .globl sun4v_ldc_set_map_table + .type sun4v_ldc_set_map_table,#function +sun4v_ldc_set_map_table: mov HV_FAST_LDC_SET_MAP_TABLE, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_ldc_set_map_table) + .size sun4v_ldc_set_map_table, .-sun4v_ldc_set_map_table /* %o0: channel * %o1: pointer to unsigned long ra @@ -496,7 +570,9 @@ ENDPROC(sun4v_ldc_set_map_table) * * returns %o0: status */ -ENTRY(sun4v_ldc_get_map_table) + .globl sun4v_ldc_get_map_table + .type sun4v_ldc_get_map_table,#function +sun4v_ldc_get_map_table: mov %o1, %g1 mov %o2, %g2 mov HV_FAST_LDC_GET_MAP_TABLE, %o5 @@ -505,7 +581,7 @@ ENTRY(sun4v_ldc_get_map_table) stx %o2, [%g2] retl nop -ENDPROC(sun4v_ldc_get_map_table) + .size sun4v_ldc_get_map_table, .-sun4v_ldc_get_map_table /* %o0: channel * %o1: dir_code @@ -516,14 +592,16 @@ ENDPROC(sun4v_ldc_get_map_table) * * returns %o0: status */ -ENTRY(sun4v_ldc_copy) + .globl sun4v_ldc_copy + .type sun4v_ldc_copy,#function +sun4v_ldc_copy: mov %o5, %g1 mov HV_FAST_LDC_COPY, %o5 ta HV_FAST_TRAP stx %o1, [%g1] retl nop -ENDPROC(sun4v_ldc_copy) + .size sun4v_ldc_copy, .-sun4v_ldc_copy /* %o0: channel * %o1: cookie @@ -532,7 +610,9 @@ ENDPROC(sun4v_ldc_copy) * * returns %o0: status */ -ENTRY(sun4v_ldc_mapin) + .globl sun4v_ldc_mapin + .type sun4v_ldc_mapin,#function +sun4v_ldc_mapin: mov %o2, %g1 mov %o3, %g2 mov HV_FAST_LDC_MAPIN, %o5 @@ -541,18 +621,20 @@ ENTRY(sun4v_ldc_mapin) stx %o2, [%g2] retl nop -ENDPROC(sun4v_ldc_mapin) + .size sun4v_ldc_mapin, .-sun4v_ldc_mapin /* %o0: ra * * returns %o0: status */ -ENTRY(sun4v_ldc_unmap) + .globl sun4v_ldc_unmap + .type sun4v_ldc_unmap,#function +sun4v_ldc_unmap: mov HV_FAST_LDC_UNMAP, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_ldc_unmap) + .size sun4v_ldc_unmap, .-sun4v_ldc_unmap /* %o0: channel * %o1: cookie @@ -560,12 +642,14 @@ ENDPROC(sun4v_ldc_unmap) * * returns %o0: status */ -ENTRY(sun4v_ldc_revoke) + .globl sun4v_ldc_revoke + .type sun4v_ldc_revoke,#function +sun4v_ldc_revoke: mov HV_FAST_LDC_REVOKE, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_ldc_revoke) + .size sun4v_ldc_revoke, .-sun4v_ldc_revoke /* %o0: device handle * %o1: device INO @@ -573,14 +657,16 @@ ENDPROC(sun4v_ldc_revoke) * * returns %o0: status */ -ENTRY(sun4v_vintr_get_cookie) + .globl sun4v_vintr_get_cookie + .type sun4v_vintr_get_cookie,#function +sun4v_vintr_get_cookie: mov %o2, %g1 mov HV_FAST_VINTR_GET_COOKIE, %o5 ta HV_FAST_TRAP stx %o1, [%g1] retl nop -ENDPROC(sun4v_vintr_get_cookie) + .size sun4v_vintr_get_cookie, .-sun4v_vintr_get_cookie /* %o0: device handle * %o1: device INO @@ -588,12 +674,14 @@ ENDPROC(sun4v_vintr_get_cookie) * * returns %o0: status */ -ENTRY(sun4v_vintr_set_cookie) + .globl sun4v_vintr_set_cookie + .type sun4v_vintr_set_cookie,#function +sun4v_vintr_set_cookie: mov HV_FAST_VINTR_SET_COOKIE, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_vintr_set_cookie) + .size sun4v_vintr_set_cookie, .-sun4v_vintr_set_cookie /* %o0: device handle * %o1: device INO @@ -601,14 +689,16 @@ ENDPROC(sun4v_vintr_set_cookie) * * returns %o0: status */ -ENTRY(sun4v_vintr_get_valid) + .globl sun4v_vintr_get_valid + .type sun4v_vintr_get_valid,#function +sun4v_vintr_get_valid: mov %o2, %g1 mov HV_FAST_VINTR_GET_VALID, %o5 ta HV_FAST_TRAP stx %o1, [%g1] retl nop -ENDPROC(sun4v_vintr_get_valid) + .size sun4v_vintr_get_valid, .-sun4v_vintr_get_valid /* %o0: device handle * %o1: device INO @@ -616,12 +706,14 @@ ENDPROC(sun4v_vintr_get_valid) * * returns %o0: status */ -ENTRY(sun4v_vintr_set_valid) + .globl sun4v_vintr_set_valid + .type sun4v_vintr_set_valid,#function +sun4v_vintr_set_valid: mov HV_FAST_VINTR_SET_VALID, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_vintr_set_valid) + .size sun4v_vintr_set_valid, .-sun4v_vintr_set_valid /* %o0: device handle * %o1: device INO @@ -629,14 +721,16 @@ ENDPROC(sun4v_vintr_set_valid) * * returns %o0: status */ -ENTRY(sun4v_vintr_get_state) + .globl sun4v_vintr_get_state + .type sun4v_vintr_get_state,#function +sun4v_vintr_get_state: mov %o2, %g1 mov HV_FAST_VINTR_GET_STATE, %o5 ta HV_FAST_TRAP stx %o1, [%g1] retl nop -ENDPROC(sun4v_vintr_get_state) + .size sun4v_vintr_get_state, .-sun4v_vintr_get_state /* %o0: device handle * %o1: device INO @@ -644,12 +738,14 @@ ENDPROC(sun4v_vintr_get_state) * * returns %o0: status */ -ENTRY(sun4v_vintr_set_state) + .globl sun4v_vintr_set_state + .type sun4v_vintr_set_state,#function +sun4v_vintr_set_state: mov HV_FAST_VINTR_SET_STATE, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_vintr_set_state) + .size sun4v_vintr_set_state, .-sun4v_vintr_set_state /* %o0: device handle * %o1: device INO @@ -657,14 +753,16 @@ ENDPROC(sun4v_vintr_set_state) * * returns %o0: status */ -ENTRY(sun4v_vintr_get_target) + .globl sun4v_vintr_get_target + .type sun4v_vintr_get_target,#function +sun4v_vintr_get_target: mov %o2, %g1 mov HV_FAST_VINTR_GET_TARGET, %o5 ta HV_FAST_TRAP stx %o1, [%g1] retl nop -ENDPROC(sun4v_vintr_get_target) + .size sun4v_vintr_get_target, .-sun4v_vintr_get_target /* %o0: device handle * %o1: device INO @@ -672,12 +770,14 @@ ENDPROC(sun4v_vintr_get_target) * * returns %o0: status */ -ENTRY(sun4v_vintr_set_target) + .globl sun4v_vintr_set_target + .type sun4v_vintr_set_target,#function +sun4v_vintr_set_target: mov HV_FAST_VINTR_SET_TARGET, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_vintr_set_target) + .size sun4v_vintr_set_target, .-sun4v_vintr_set_target /* %o0: NCS sub-function * %o1: sub-function arg real-address @@ -685,14 +785,18 @@ ENDPROC(sun4v_vintr_set_target) * * returns %o0: status */ -ENTRY(sun4v_ncs_request) + .globl sun4v_ncs_request + .type sun4v_ncs_request,#function +sun4v_ncs_request: mov HV_FAST_NCS_REQUEST, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_ncs_request) + .size sun4v_ncs_request, .-sun4v_ncs_request -ENTRY(sun4v_svc_send) + .globl sun4v_svc_send + .type sun4v_svc_send,#function +sun4v_svc_send: save %sp, -192, %sp mov %i0, %o0 mov %i1, %o1 @@ -702,9 +806,11 @@ ENTRY(sun4v_svc_send) stx %o1, [%i3] ret restore -ENDPROC(sun4v_svc_send) + .size sun4v_svc_send, .-sun4v_svc_send -ENTRY(sun4v_svc_recv) + .globl sun4v_svc_recv + .type sun4v_svc_recv,#function +sun4v_svc_recv: save %sp, -192, %sp mov %i0, %o0 mov %i1, %o1 @@ -714,50 +820,62 @@ ENTRY(sun4v_svc_recv) stx %o1, [%i3] ret restore -ENDPROC(sun4v_svc_recv) + .size sun4v_svc_recv, .-sun4v_svc_recv -ENTRY(sun4v_svc_getstatus) + .globl sun4v_svc_getstatus + .type sun4v_svc_getstatus,#function +sun4v_svc_getstatus: mov HV_FAST_SVC_GETSTATUS, %o5 mov %o1, %o4 ta HV_FAST_TRAP stx %o1, [%o4] retl nop -ENDPROC(sun4v_svc_getstatus) + .size sun4v_svc_getstatus, .-sun4v_svc_getstatus -ENTRY(sun4v_svc_setstatus) + .globl sun4v_svc_setstatus + .type sun4v_svc_setstatus,#function +sun4v_svc_setstatus: mov HV_FAST_SVC_SETSTATUS, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_svc_setstatus) + .size sun4v_svc_setstatus, .-sun4v_svc_setstatus -ENTRY(sun4v_svc_clrstatus) + .globl sun4v_svc_clrstatus + .type sun4v_svc_clrstatus,#function +sun4v_svc_clrstatus: mov HV_FAST_SVC_CLRSTATUS, %o5 ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_svc_clrstatus) + .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus -ENTRY(sun4v_mmustat_conf) + .globl sun4v_mmustat_conf + .type sun4v_mmustat_conf,#function +sun4v_mmustat_conf: mov %o1, %o4 mov HV_FAST_MMUSTAT_CONF, %o5 ta HV_FAST_TRAP stx %o1, [%o4] retl nop -ENDPROC(sun4v_mmustat_conf) + .size sun4v_mmustat_conf, .-sun4v_mmustat_conf -ENTRY(sun4v_mmustat_info) + .globl sun4v_mmustat_info + .type sun4v_mmustat_info,#function +sun4v_mmustat_info: mov %o0, %o4 mov HV_FAST_MMUSTAT_INFO, %o5 ta HV_FAST_TRAP stx %o1, [%o4] retl nop -ENDPROC(sun4v_mmustat_info) + .size sun4v_mmustat_info, .-sun4v_mmustat_info -ENTRY(sun4v_mmu_demap_all) + .globl sun4v_mmu_demap_all + .type sun4v_mmu_demap_all,#function +sun4v_mmu_demap_all: clr %o0 clr %o1 mov HV_MMU_ALL, %o2 @@ -765,4 +883,4 @@ ENTRY(sun4v_mmu_demap_all) ta HV_FAST_TRAP retl nop -ENDPROC(sun4v_mmu_demap_all) + .size sun4v_mmu_demap_all, .-sun4v_mmu_demap_all diff --git a/trunk/arch/sparc64/kernel/irq.c b/trunk/arch/sparc64/kernel/irq.c index 52fc836f464d..7495bc774685 100644 --- a/trunk/arch/sparc64/kernel/irq.c +++ b/trunk/arch/sparc64/kernel/irq.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/sparc64/kernel/of_device.c b/trunk/arch/sparc64/kernel/of_device.c index 0f616ae3246c..100ebd527499 100644 --- a/trunk/arch/sparc64/kernel/of_device.c +++ b/trunk/arch/sparc64/kernel/of_device.c @@ -55,38 +55,15 @@ struct of_device *of_find_device_by_node(struct device_node *dp) } EXPORT_SYMBOL(of_find_device_by_node); -unsigned int irq_of_parse_and_map(struct device_node *node, int index) -{ - struct of_device *op = of_find_device_by_node(node); - - 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; +#ifdef CONFIG_PCI +struct bus_type ebus_bus_type; +EXPORT_SYMBOL(ebus_bus_type); +#endif - 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); - } -} +#ifdef CONFIG_SBUS +struct bus_type sbus_bus_type; +EXPORT_SYMBOL(sbus_bus_type); +#endif struct bus_type of_platform_bus_type; EXPORT_SYMBOL(of_platform_bus_type); @@ -401,7 +378,8 @@ static int __init build_one_resource(struct device_node *parent, int na, int ns, int pna) { const u32 *ranges; - int rone, rlen; + unsigned int rlen; + int rone; ranges = of_get_property(parent, "ranges", &rlen); if (ranges == NULL || rlen == 0) { @@ -443,17 +421,8 @@ static int __init use_1to1_mapping(struct device_node *pp) /* If the parent is the dma node of an ISA bus, pass * the translation up to the root. - * - * 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")) + if (!strcmp(pp->name, "dma")) return 0; /* Similarly for all PCI bridges, if we get this far @@ -875,6 +844,15 @@ 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(); diff --git a/trunk/arch/sparc64/kernel/pci.c b/trunk/arch/sparc64/kernel/pci.c index 242ac1ccae7d..80dad76f8b81 100644 --- a/trunk/arch/sparc64/kernel/pci.c +++ b/trunk/arch/sparc64/kernel/pci.c @@ -18,17 +18,32 @@ #include #include #include -#include -#include #include #include #include +#include #include #include #include "pci_impl.h" +#ifndef CONFIG_PCI +/* A "nop" PCI implementation. */ +asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, + unsigned char *buf) +{ + return 0; +} +asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, + unsigned char *buf) +{ + return 0; +} +#else + /* List of all PCI controllers found in the system. */ struct pci_pbm_info *pci_pbm_root = NULL; @@ -164,6 +179,97 @@ void pci_config_write32(u32 *addr, u32 val) spin_unlock_irqrestore(&pci_poke_lock, flags); } +/* Probe for all PCI controllers in the system. */ +extern void sabre_init(struct device_node *, const char *); +extern void psycho_init(struct device_node *, const char *); +extern void schizo_init(struct device_node *, const char *); +extern void schizo_plus_init(struct device_node *, const char *); +extern void tomatillo_init(struct device_node *, const char *); +extern void sun4v_pci_init(struct device_node *, const char *); +extern void fire_pci_init(struct device_node *, const char *); + +static struct { + char *model_name; + void (*init)(struct device_node *, const char *); +} pci_controller_table[] __initdata = { + { "SUNW,sabre", sabre_init }, + { "pci108e,a000", sabre_init }, + { "pci108e,a001", sabre_init }, + { "SUNW,psycho", psycho_init }, + { "pci108e,8000", psycho_init }, + { "SUNW,schizo", schizo_init }, + { "pci108e,8001", schizo_init }, + { "SUNW,schizo+", schizo_plus_init }, + { "pci108e,8002", schizo_plus_init }, + { "SUNW,tomatillo", tomatillo_init }, + { "pci108e,a801", tomatillo_init }, + { "SUNW,sun4v-pci", sun4v_pci_init }, + { "pciex108e,80f0", fire_pci_init }, +}; +#define PCI_NUM_CONTROLLER_TYPES ARRAY_SIZE(pci_controller_table) + +static int __init pci_controller_init(const char *model_name, int namelen, struct device_node *dp) +{ + int i; + + for (i = 0; i < PCI_NUM_CONTROLLER_TYPES; i++) { + if (!strncmp(model_name, + pci_controller_table[i].model_name, + namelen)) { + pci_controller_table[i].init(dp, model_name); + return 1; + } + } + + return 0; +} + +static int __init pci_controller_scan(int (*handler)(const char *, int, struct device_node *)) +{ + struct device_node *dp; + int count = 0; + + for_each_node_by_name(dp, "pci") { + struct property *prop; + int len; + + prop = of_find_property(dp, "model", &len); + if (!prop) + prop = of_find_property(dp, "compatible", &len); + + if (prop) { + const char *model = prop->value; + int item_len = 0; + + /* Our value may be a multi-valued string in the + * case of some compatible properties. For sanity, + * only try the first one. + */ + while (model[item_len] && len) { + len--; + item_len++; + } + + if (handler(model, item_len, dp)) + count++; + } + } + + return count; +} + +/* Find each controller in the system, attach and initialize + * software state structure for each and link into the + * pci_pbm_root. Setup the controller enough such + * that bus scanning can be done. + */ +static void __init pci_controller_probe(void) +{ + printk("PCI: Probing for controllers.\n"); + + pci_controller_scan(pci_controller_init); +} + static int ofpci_verbose; static int __init ofpci_debug(char *str) @@ -242,12 +348,11 @@ static void pci_parse_of_addrs(struct of_device *op, } } -static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, - struct device_node *node, - struct pci_bus *bus, int devfn) +struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, + struct device_node *node, + struct pci_bus *bus, int devfn) { struct dev_archdata *sd; - struct of_device *op; struct pci_dev *dev; const char *type; u32 class; @@ -261,17 +366,14 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, sd->stc = &pbm->stc; sd->host_controller = pbm; sd->prom_node = node; - sd->op = op = of_find_device_by_node(node); + sd->op = of_find_device_by_node(node); sd->numa_node = pbm->numa_node; - sd = &op->dev.archdata; + sd = &sd->op->dev.archdata; sd->iommu = pbm->iommu; sd->stc = &pbm->stc; sd->numa_node = pbm->numa_node; - if (!strcmp(node->name, "ebus")) - of_propagate_archdata(op); - type = of_get_property(node, "device_type", NULL); if (type == NULL) type = ""; @@ -673,15 +775,15 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus) pci_bus_register_of_sysfs(child_bus); } -struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm, - struct device *parent) +struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm) { - struct device_node *node = pbm->op->node; + struct device_node *node = pbm->prom_node; struct pci_bus *bus; printk("PCI: Scanning PBM %s\n", node->full_name); - bus = pci_create_bus(parent, pbm->pci_first_busno, pbm->pci_ops, pbm); + /* XXX parent device? XXX */ + bus = pci_create_bus(NULL, pbm->pci_first_busno, pbm->pci_ops, pbm); if (!bus) { printk(KERN_ERR "Failed to create bus for %s\n", node->full_name); @@ -700,6 +802,32 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm, return bus; } +static void __init pci_scan_each_controller_bus(void) +{ + struct pci_pbm_info *pbm; + + for (pbm = pci_pbm_root; pbm; pbm = pbm->next) + pbm->scan_bus(pbm); +} + +extern void power_init(void); + +static int __init pcibios_init(void) +{ + pci_controller_probe(); + if (pci_pbm_root == NULL) + return 0; + + pci_scan_each_controller_bus(); + + ebus_init(); + power_init(); + + return 0; +} + +subsys_initcall(pcibios_init); + void __devinit pcibios_fixup_bus(struct pci_bus *pbus) { struct pci_pbm_info *pbm = pbus->sysdata; @@ -977,14 +1105,14 @@ int pcibus_to_node(struct pci_bus *pbus) EXPORT_SYMBOL(pcibus_to_node); #endif -/* Return the domain number for this pci bus */ +/* Return the domain nuber for this pci bus */ int pci_domain_nr(struct pci_bus *pbus) { struct pci_pbm_info *pbm = pbus->sysdata; int ret; - if (!pbm) { + if (pbm == NULL || pbm->parent == NULL) { ret = -ENXIO; } else { ret = pbm->index; @@ -998,7 +1126,7 @@ EXPORT_SYMBOL(pci_domain_nr); int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) { struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; - unsigned int virt_irq; + int virt_irq; if (!pbm->setup_msi_irq) return -EINVAL; @@ -1012,8 +1140,10 @@ void arch_teardown_msi_irq(unsigned int virt_irq) struct pci_dev *pdev = entry->dev; struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; - if (pbm->teardown_msi_irq) - pbm->teardown_msi_irq(virt_irq, pdev); + if (!pbm->teardown_msi_irq) + return; + + return pbm->teardown_msi_irq(virt_irq, pdev); } #endif /* !(CONFIG_PCI_MSI) */ @@ -1085,3 +1215,5 @@ void pci_resource_to_user(const struct pci_dev *pdev, int bar, *start = rp->start - offset; *end = rp->end - offset; } + +#endif /* !(CONFIG_PCI) */ diff --git a/trunk/arch/sparc64/kernel/pci_common.c b/trunk/arch/sparc64/kernel/pci_common.c index 23b88082d0b2..09a5ec200c61 100644 --- a/trunk/arch/sparc64/kernel/pci_common.c +++ b/trunk/arch/sparc64/kernel/pci_common.c @@ -314,12 +314,12 @@ struct pci_ops sun4v_pci_ops = { void pci_get_pbm_props(struct pci_pbm_info *pbm) { - const u32 *val = of_get_property(pbm->op->node, "bus-range", NULL); + const u32 *val = of_get_property(pbm->prom_node, "bus-range", NULL); pbm->pci_first_busno = val[0]; pbm->pci_last_busno = val[1]; - val = of_get_property(pbm->op->node, "ino-bitmap", NULL); + val = of_get_property(pbm->prom_node, "ino-bitmap", NULL); if (val) { pbm->ino_bitmap = (((u64)val[1] << 32UL) | ((u64)val[0] << 0UL)); @@ -365,7 +365,7 @@ static void pci_register_legacy_regions(struct resource *io_res, static void pci_register_iommu_region(struct pci_pbm_info *pbm) { - const u32 *vdma = of_get_property(pbm->op->node, "virtual-dma", NULL); + const u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL); if (vdma) { struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL); @@ -389,7 +389,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) int num_pbm_ranges; saw_mem = saw_io = 0; - pbm_ranges = of_get_property(pbm->op->node, "ranges", &i); + pbm_ranges = of_get_property(pbm->prom_node, "ranges", &i); if (!pbm_ranges) { prom_printf("PCI: Fatal error, missing PBM ranges property " " for %s\n", diff --git a/trunk/arch/sparc64/kernel/pci_fire.c b/trunk/arch/sparc64/kernel/pci_fire.c index 9462b68f4894..d23bb6f53cda 100644 --- a/trunk/arch/sparc64/kernel/pci_fire.c +++ b/trunk/arch/sparc64/kernel/pci_fire.c @@ -8,16 +8,34 @@ #include #include #include -#include +#include #include #include -#include #include "pci_impl.h" -#define DRIVER_NAME "fire" -#define PFX DRIVER_NAME ": " +#define fire_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define fire_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory") + +static void __init pci_fire_scan_bus(struct pci_pbm_info *pbm) +{ + pbm->pci_bus = pci_scan_one_pbm(pbm); + + /* XXX register error interrupt handlers XXX */ +} #define FIRE_IOMMU_CONTROL 0x40000UL #define FIRE_IOMMU_TSBBASE 0x40008UL @@ -51,21 +69,21 @@ static int pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm) /* * Invalidate TLB Entries. */ - upa_writeq(~(u64)0, iommu->iommu_flushinv); + fire_write(iommu->iommu_flushinv, ~(u64)0); err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask, pbm->numa_node); if (err) return err; - upa_writeq(__pa(iommu->page_table) | 0x7UL, iommu->iommu_tsbbase); + fire_write(iommu->iommu_tsbbase, __pa(iommu->page_table) | 0x7UL); - control = upa_readq(iommu->iommu_control); + control = fire_read(iommu->iommu_control); control |= (0x00000400 /* TSB cache snoop enable */ | 0x00000300 /* Cache mode */ | 0x00000002 /* Bypass enable */ | 0x00000001 /* Translation enable */); - upa_writeq(control, iommu->iommu_control); + fire_write(iommu->iommu_control, control); return 0; } @@ -147,7 +165,7 @@ struct pci_msiq_entry { static int pci_fire_get_head(struct pci_pbm_info *pbm, unsigned long msiqid, unsigned long *head) { - *head = upa_readq(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid)); + *head = fire_read(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid)); return 0; } @@ -173,7 +191,8 @@ static int pci_fire_dequeue_msi(struct pci_pbm_info *pbm, unsigned long msiqid, *msi = msi_num = ((ep->word0 & MSIQ_WORD0_DATA0) >> MSIQ_WORD0_DATA0_SHIFT); - upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi_num)); + fire_write(pbm->pbm_regs + MSI_CLEAR(msi_num), + MSI_CLEAR_EQWR_N); /* Clear the entry. */ ep->word0 &= ~MSIQ_WORD0_FMT_TYPE; @@ -189,7 +208,7 @@ static int pci_fire_dequeue_msi(struct pci_pbm_info *pbm, unsigned long msiqid, static int pci_fire_set_head(struct pci_pbm_info *pbm, unsigned long msiqid, unsigned long head) { - upa_writeq(head, pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid)); + fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid), head); return 0; } @@ -198,16 +217,17 @@ static int pci_fire_msi_setup(struct pci_pbm_info *pbm, unsigned long msiqid, { u64 val; - val = upa_readq(pbm->pbm_regs + MSI_MAP(msi)); + val = fire_read(pbm->pbm_regs + MSI_MAP(msi)); val &= ~(MSI_MAP_EQNUM); val |= msiqid; - upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi)); + fire_write(pbm->pbm_regs + MSI_MAP(msi), val); - upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi)); + fire_write(pbm->pbm_regs + MSI_CLEAR(msi), + MSI_CLEAR_EQWR_N); - val = upa_readq(pbm->pbm_regs + MSI_MAP(msi)); + val = fire_read(pbm->pbm_regs + MSI_MAP(msi)); val |= MSI_MAP_VALID; - upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi)); + fire_write(pbm->pbm_regs + MSI_MAP(msi), val); return 0; } @@ -217,12 +237,12 @@ static int pci_fire_msi_teardown(struct pci_pbm_info *pbm, unsigned long msi) unsigned long msiqid; u64 val; - val = upa_readq(pbm->pbm_regs + MSI_MAP(msi)); + val = fire_read(pbm->pbm_regs + MSI_MAP(msi)); msiqid = (val & MSI_MAP_EQNUM); val &= ~MSI_MAP_VALID; - upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi)); + fire_write(pbm->pbm_regs + MSI_MAP(msi), val); return 0; } @@ -241,19 +261,22 @@ static int pci_fire_msiq_alloc(struct pci_pbm_info *pbm) memset((char *)pages, 0, PAGE_SIZE << order); pbm->msi_queues = (void *) pages; - upa_writeq((EVENT_QUEUE_BASE_ADDR_ALL_ONES | - __pa(pbm->msi_queues)), - pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG); + fire_write(pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG, + (EVENT_QUEUE_BASE_ADDR_ALL_ONES | + __pa(pbm->msi_queues))); - upa_writeq(pbm->portid << 6, pbm->pbm_regs + IMONDO_DATA0); - upa_writeq(0, pbm->pbm_regs + IMONDO_DATA1); + fire_write(pbm->pbm_regs + IMONDO_DATA0, + pbm->portid << 6); + fire_write(pbm->pbm_regs + IMONDO_DATA1, 0); - upa_writeq(pbm->msi32_start, pbm->pbm_regs + MSI_32BIT_ADDR); - upa_writeq(pbm->msi64_start, pbm->pbm_regs + MSI_64BIT_ADDR); + fire_write(pbm->pbm_regs + MSI_32BIT_ADDR, + pbm->msi32_start); + fire_write(pbm->pbm_regs + MSI_64BIT_ADDR, + pbm->msi64_start); for (i = 0; i < pbm->msiq_num; i++) { - upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_HEAD(i)); - upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_TAIL(i)); + fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(i), 0); + fire_write(pbm->pbm_regs + EVENT_QUEUE_TAIL(i), 0); } return 0; @@ -287,9 +310,9 @@ static int pci_fire_msiq_build_irq(struct pci_pbm_info *pbm, /* XXX iterate amongst the 4 IRQ controllers XXX */ int_ctrlr = (1UL << 6); - val = upa_readq(imap_reg); + val = fire_read(imap_reg); val |= (1UL << 63) | int_ctrlr; - upa_writeq(val, imap_reg); + fire_write(imap_reg, val); fixup = ((pbm->portid << 6) | devino) - int_ctrlr; @@ -297,8 +320,9 @@ static int pci_fire_msiq_build_irq(struct pci_pbm_info *pbm, if (!virt_irq) return -ENOMEM; - upa_writeq(EVENT_QUEUE_CONTROL_SET_EN, - pbm->pbm_regs + EVENT_QUEUE_CONTROL_SET(msiqid)); + fire_write(pbm->pbm_regs + + EVENT_QUEUE_CONTROL_SET(msiqid), + EVENT_QUEUE_CONTROL_SET_EN); return virt_irq; } @@ -366,65 +390,77 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm) { u64 val; - upa_writeq(FIRE_PARITY_ENAB, - pbm->controller_regs + FIRE_PARITY_CONTROL); + fire_write(pbm->controller_regs + FIRE_PARITY_CONTROL, + FIRE_PARITY_ENAB); - upa_writeq((FIRE_FATAL_RESET_SPARE | + fire_write(pbm->controller_regs + FIRE_FATAL_RESET_CTL, + (FIRE_FATAL_RESET_SPARE | FIRE_FATAL_RESET_MB | FIRE_FATAL_RESET_CPE | FIRE_FATAL_RESET_APE | FIRE_FATAL_RESET_PIO | FIRE_FATAL_RESET_JW | FIRE_FATAL_RESET_JI | - FIRE_FATAL_RESET_JR), - pbm->controller_regs + FIRE_FATAL_RESET_CTL); + FIRE_FATAL_RESET_JR)); - upa_writeq(~(u64)0, pbm->controller_regs + FIRE_CORE_INTR_ENABLE); + fire_write(pbm->controller_regs + FIRE_CORE_INTR_ENABLE, ~(u64)0); - val = upa_readq(pbm->pbm_regs + FIRE_TLU_CTRL); + val = fire_read(pbm->pbm_regs + FIRE_TLU_CTRL); val |= (FIRE_TLU_CTRL_TIM | FIRE_TLU_CTRL_QDET | FIRE_TLU_CTRL_CFG); - upa_writeq(val, pbm->pbm_regs + FIRE_TLU_CTRL); - upa_writeq(0, pbm->pbm_regs + FIRE_TLU_DEV_CTRL); - upa_writeq(FIRE_TLU_LINK_CTRL_CLK, - pbm->pbm_regs + FIRE_TLU_LINK_CTRL); - - upa_writeq(0, pbm->pbm_regs + FIRE_LPU_RESET); - upa_writeq(FIRE_LPU_LLCFG_VC0, pbm->pbm_regs + FIRE_LPU_LLCFG); - upa_writeq((FIRE_LPU_FCTRL_UCTRL_N | FIRE_LPU_FCTRL_UCTRL_P), - pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL); - upa_writeq(((0xffff << 16) | (0x0000 << 0)), - pbm->pbm_regs + FIRE_LPU_TXL_FIFOP); - upa_writeq(3000000, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2); - upa_writeq(500000, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3); - upa_writeq((2 << 16) | (140 << 8), - pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4); - upa_writeq(0, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5); - - upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_DMC_IENAB); - upa_writeq(0, pbm->pbm_regs + FIRE_DMC_DBG_SEL_A); - upa_writeq(0, pbm->pbm_regs + FIRE_DMC_DBG_SEL_B); - - upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_PEC_IENAB); + fire_write(pbm->pbm_regs + FIRE_TLU_CTRL, val); + fire_write(pbm->pbm_regs + FIRE_TLU_DEV_CTRL, 0); + fire_write(pbm->pbm_regs + FIRE_TLU_LINK_CTRL, + FIRE_TLU_LINK_CTRL_CLK); + + fire_write(pbm->pbm_regs + FIRE_LPU_RESET, 0); + fire_write(pbm->pbm_regs + FIRE_LPU_LLCFG, + FIRE_LPU_LLCFG_VC0); + fire_write(pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL, + (FIRE_LPU_FCTRL_UCTRL_N | + FIRE_LPU_FCTRL_UCTRL_P)); + fire_write(pbm->pbm_regs + FIRE_LPU_TXL_FIFOP, + ((0xffff << 16) | (0x0000 << 0))); + fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2, 3000000); + fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3, 500000); + fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4, + (2 << 16) | (140 << 8)); + fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5, 0); + + fire_write(pbm->pbm_regs + FIRE_DMC_IENAB, ~(u64)0); + fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_A, 0); + fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_B, 0); + + fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0); } -static int __init pci_fire_pbm_init(struct pci_pbm_info *pbm, - struct of_device *op, u32 portid) +static int __init pci_fire_pbm_init(struct pci_controller_info *p, + struct device_node *dp, u32 portid) { const struct linux_prom64_registers *regs; - struct device_node *dp = op->node; + struct pci_pbm_info *pbm; int err; + if ((portid & 1) == 0) + pbm = &p->pbm_A; + else + pbm = &p->pbm_B; + + pbm->next = pci_pbm_root; + pci_pbm_root = pbm; + pbm->numa_node = -1; + pbm->scan_bus = pci_fire_scan_bus; pbm->pci_ops = &sun4u_pci_ops; pbm->config_space_reg_bits = 12; pbm->index = pci_num_pbms++; pbm->portid = portid; - pbm->op = op; + pbm->parent = p; + pbm->prom_node = dp; pbm->name = dp->full_name; regs = of_get_property(dp, "reg", NULL); @@ -445,77 +481,53 @@ static int __init pci_fire_pbm_init(struct pci_pbm_info *pbm, pci_fire_msi_init(pbm); - pbm->pci_bus = pci_scan_one_pbm(pbm, &op->dev); - - /* XXX register error interrupt handlers XXX */ - - pbm->next = pci_pbm_root; - pci_pbm_root = pbm; + return 0; +} +static inline int portid_compare(u32 x, u32 y) +{ + if (x == (y ^ 1)) + return 1; return 0; } -static int __devinit fire_probe(struct of_device *op, - const struct of_device_id *match) +void __init fire_pci_init(struct device_node *dp, const char *model_name) { - struct device_node *dp = op->node; - struct pci_pbm_info *pbm; + struct pci_controller_info *p; + u32 portid = of_getintprop_default(dp, "portid", 0xff); struct iommu *iommu; - u32 portid; - int err; - - portid = of_getintprop_default(dp, "portid", 0xff); + struct pci_pbm_info *pbm; - err = -ENOMEM; - pbm = kzalloc(sizeof(*pbm), GFP_KERNEL); - if (!pbm) { - printk(KERN_ERR PFX "Cannot allocate pci_pbminfo.\n"); - goto out_err; + for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { + if (portid_compare(pbm->portid, portid)) { + if (pci_fire_pbm_init(pbm->parent, dp, portid)) + goto fatal_memory_error; + return; + } } - iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL); - if (!iommu) { - printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n"); - goto out_free_controller; - } + p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); + if (!p) + goto fatal_memory_error; - pbm->iommu = iommu; + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); + if (!iommu) + goto fatal_memory_error; - err = pci_fire_pbm_init(pbm, op, portid); - if (err) - goto out_free_iommu; + p->pbm_A.iommu = iommu; - dev_set_drvdata(&op->dev, pbm); + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); + if (!iommu) + goto fatal_memory_error; - return 0; + p->pbm_B.iommu = iommu; -out_free_iommu: - kfree(pbm->iommu); - -out_free_controller: - kfree(pbm); + if (pci_fire_pbm_init(p, dp, portid)) + goto fatal_memory_error; -out_err: - return err; -} - -static struct of_device_id __initdata fire_match[] = { - { - .name = "pci", - .compatible = "pciex108e,80f0", - }, - {}, -}; + return; -static struct of_platform_driver fire_driver = { - .name = DRIVER_NAME, - .match_table = fire_match, - .probe = fire_probe, -}; - -static int __init fire_init(void) -{ - return of_register_driver(&fire_driver, &of_bus_type); +fatal_memory_error: + prom_printf("PCI_FIRE: Fatal memory allocation error.\n"); + prom_halt(); } - -subsys_initcall(fire_init); diff --git a/trunk/arch/sparc64/kernel/pci_impl.h b/trunk/arch/sparc64/kernel/pci_impl.h index 03186824327e..c385d126be11 100644 --- a/trunk/arch/sparc64/kernel/pci_impl.h +++ b/trunk/arch/sparc64/kernel/pci_impl.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -57,11 +56,15 @@ struct sparc64_msiq_cookie { }; #endif +struct pci_controller_info; + struct pci_pbm_info { struct pci_pbm_info *next; - struct pci_pbm_info *sibling; int index; + /* PCI controller we sit under. */ + struct pci_controller_info *parent; + /* Physical address base of controller registers. */ unsigned long controller_regs; @@ -91,7 +94,7 @@ struct pci_pbm_info { char *name; /* OBP specific information. */ - struct of_device *op; + struct device_node *prom_node; u64 ino_bitmap; /* PBM I/O and Memory space resources. */ @@ -104,10 +107,6 @@ struct pci_pbm_info { /* This will be 12 on PCI-E controllers, 8 elsewhere. */ unsigned long config_space_reg_bits; - unsigned long pci_afsr; - unsigned long pci_afar; - unsigned long pci_csr; - /* State of 66MHz capabilities on this PBM. */ int is_66mhz_capable; int all_devs_66mhz; @@ -147,19 +146,25 @@ struct pci_pbm_info { unsigned int pci_first_busno; unsigned int pci_last_busno; struct pci_bus *pci_bus; + void (*scan_bus)(struct pci_pbm_info *); struct pci_ops *pci_ops; int numa_node; }; +struct pci_controller_info { + /* The PCI bus modules controlled by us. */ + struct pci_pbm_info pbm_A; + struct pci_pbm_info pbm_B; +}; + extern struct pci_pbm_info *pci_pbm_root; extern int pci_num_pbms; /* PCI bus scanning and fixup support. */ extern void pci_get_pbm_props(struct pci_pbm_info *pbm); -extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm, - struct device *parent); +extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm); extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm); /* Error reporting support. */ @@ -178,8 +183,4 @@ extern void pci_config_write32(u32 *addr, u32 val); extern struct pci_ops sun4u_pci_ops; extern struct pci_ops sun4v_pci_ops; -extern volatile int pci_poke_in_progress; -extern volatile int pci_poke_cpu; -extern volatile int pci_poke_faulted; - #endif /* !(PCI_IMPL_H) */ diff --git a/trunk/arch/sparc64/kernel/pci_msi.c b/trunk/arch/sparc64/kernel/pci_msi.c index 2e680f34f727..60c71e350212 100644 --- a/trunk/arch/sparc64/kernel/pci_msi.c +++ b/trunk/arch/sparc64/kernel/pci_msi.c @@ -323,7 +323,7 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm, const u32 *val; int len; - val = of_get_property(pbm->op->node, "#msi-eqs", &len); + val = of_get_property(pbm->prom_node, "#msi-eqs", &len); if (!val || len != 4) goto no_msi; pbm->msiq_num = *val; @@ -346,16 +346,16 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm, u32 msi64_len; } *arng; - val = of_get_property(pbm->op->node, "msi-eq-size", &len); + val = of_get_property(pbm->prom_node, "msi-eq-size", &len); if (!val || len != 4) goto no_msi; pbm->msiq_ent_count = *val; - mqp = of_get_property(pbm->op->node, + mqp = of_get_property(pbm->prom_node, "msi-eq-to-devino", &len); if (!mqp) - mqp = of_get_property(pbm->op->node, + mqp = of_get_property(pbm->prom_node, "msi-eq-devino", &len); if (!mqp || len != sizeof(struct msiq_prop)) goto no_msi; @@ -363,27 +363,27 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm, pbm->msiq_first = mqp->first_msiq; pbm->msiq_first_devino = mqp->first_devino; - val = of_get_property(pbm->op->node, "#msi", &len); + val = of_get_property(pbm->prom_node, "#msi", &len); if (!val || len != 4) goto no_msi; pbm->msi_num = *val; - mrng = of_get_property(pbm->op->node, "msi-ranges", &len); + mrng = of_get_property(pbm->prom_node, "msi-ranges", &len); if (!mrng || len != sizeof(struct msi_range_prop)) goto no_msi; pbm->msi_first = mrng->first_msi; - val = of_get_property(pbm->op->node, "msi-data-mask", &len); + val = of_get_property(pbm->prom_node, "msi-data-mask", &len); if (!val || len != 4) goto no_msi; pbm->msi_data_mask = *val; - val = of_get_property(pbm->op->node, "msix-data-width", &len); + val = of_get_property(pbm->prom_node, "msix-data-width", &len); if (!val || len != 4) goto no_msi; pbm->msix_data_width = *val; - arng = of_get_property(pbm->op->node, "msi-address-ranges", + arng = of_get_property(pbm->prom_node, "msi-address-ranges", &len); if (!arng || len != sizeof(struct addr_range_prop)) goto no_msi; diff --git a/trunk/arch/sparc64/kernel/pci_psycho.c b/trunk/arch/sparc64/kernel/pci_psycho.c index dfb3ec892987..f85b6bebb0be 100644 --- a/trunk/arch/sparc64/kernel/pci_psycho.c +++ b/trunk/arch/sparc64/kernel/pci_psycho.c @@ -17,14 +17,29 @@ #include #include #include -#include +#include #include "pci_impl.h" #include "iommu_common.h" -#include "psycho_common.h" -#define DRIVER_NAME "psycho" -#define PFX DRIVER_NAME ": " +/* All PSYCHO registers are 64-bits. The following accessor + * routines are how they are accessed. The REG parameter + * is a physical address. + */ +#define psycho_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define psycho_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory") /* Misc. PSYCHO PCI controller register offsets and definitions. */ #define PSYCHO_CONTROL 0x0010UL @@ -52,7 +67,37 @@ #define PSYCHO_PCICTRL_RESV4 0x00000000000000c0UL /* Reserved */ #define PSYCHO_PCICTRL_AEN 0x000000000000003fUL /* PCI DVMA Arbitration Enable */ +/* U2P Programmer's Manual, page 13-55, configuration space + * address format: + * + * 32 24 23 16 15 11 10 8 7 2 1 0 + * --------------------------------------------------------- + * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 | + * --------------------------------------------------------- + */ +#define PSYCHO_CONFIG_BASE(PBM) \ + ((PBM)->config_space | (1UL << 24)) +#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG) \ + (((unsigned long)(BUS) << 16) | \ + ((unsigned long)(DEVFN) << 8) | \ + ((unsigned long)(REG))) + +static void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm, + unsigned char bus, + unsigned int devfn, + int where) +{ + if (!pbm) + return NULL; + return (void *) + (PSYCHO_CONFIG_BASE(pbm) | + PSYCHO_CONFIG_ENCODE(bus, devfn, where)); +} + /* PSYCHO error handling support. */ +enum psycho_error_type { + UE_ERR, CE_ERR, PCI_ERR +}; /* Helper function of IOMMU error checking, which checks out * the state of the streaming buffers. The IOMMU lock is @@ -77,10 +122,129 @@ #define PSYCHO_STC_DATA_B 0xc000UL #define PSYCHO_STC_ERR_A 0xb400UL #define PSYCHO_STC_ERR_B 0xc400UL +#define PSYCHO_STCERR_WRITE 0x0000000000000002UL /* Write Error */ +#define PSYCHO_STCERR_READ 0x0000000000000001UL /* Read Error */ #define PSYCHO_STC_TAG_A 0xb800UL #define PSYCHO_STC_TAG_B 0xc800UL +#define PSYCHO_STCTAG_PPN 0x0fffffff00000000UL /* Physical Page Number */ +#define PSYCHO_STCTAG_VPN 0x00000000ffffe000UL /* Virtual Page Number */ +#define PSYCHO_STCTAG_VALID 0x0000000000000002UL /* Valid */ +#define PSYCHO_STCTAG_WRITE 0x0000000000000001UL /* Writable */ #define PSYCHO_STC_LINE_A 0xb900UL #define PSYCHO_STC_LINE_B 0xc900UL +#define PSYCHO_STCLINE_LINDX 0x0000000001e00000UL /* LRU Index */ +#define PSYCHO_STCLINE_SPTR 0x00000000001f8000UL /* Dirty Data Start Pointer */ +#define PSYCHO_STCLINE_LADDR 0x0000000000007f00UL /* Line Address */ +#define PSYCHO_STCLINE_EPTR 0x00000000000000fcUL /* Dirty Data End Pointer */ +#define PSYCHO_STCLINE_VALID 0x0000000000000002UL /* Valid */ +#define PSYCHO_STCLINE_FOFN 0x0000000000000001UL /* Fetch Outstanding / Flush Necessary */ + +static DEFINE_SPINLOCK(stc_buf_lock); +static unsigned long stc_error_buf[128]; +static unsigned long stc_tag_buf[16]; +static unsigned long stc_line_buf[16]; + +static void __psycho_check_one_stc(struct pci_pbm_info *pbm, + int is_pbm_a) +{ + struct strbuf *strbuf = &pbm->stc; + unsigned long regbase = pbm->controller_regs; + unsigned long err_base, tag_base, line_base; + u64 control; + int i; + + if (is_pbm_a) { + err_base = regbase + PSYCHO_STC_ERR_A; + tag_base = regbase + PSYCHO_STC_TAG_A; + line_base = regbase + PSYCHO_STC_LINE_A; + } else { + err_base = regbase + PSYCHO_STC_ERR_B; + tag_base = regbase + PSYCHO_STC_TAG_B; + line_base = regbase + PSYCHO_STC_LINE_B; + } + + spin_lock(&stc_buf_lock); + + /* This is __REALLY__ dangerous. When we put the + * streaming buffer into diagnostic mode to probe + * it's tags and error status, we _must_ clear all + * of the line tag valid bits before re-enabling + * the streaming buffer. If any dirty data lives + * in the STC when we do this, we will end up + * invalidating it before it has a chance to reach + * main memory. + */ + control = psycho_read(strbuf->strbuf_control); + psycho_write(strbuf->strbuf_control, + (control | PSYCHO_STRBUF_CTRL_DENAB)); + for (i = 0; i < 128; i++) { + unsigned long val; + + val = psycho_read(err_base + (i * 8UL)); + psycho_write(err_base + (i * 8UL), 0UL); + stc_error_buf[i] = val; + } + for (i = 0; i < 16; i++) { + stc_tag_buf[i] = psycho_read(tag_base + (i * 8UL)); + stc_line_buf[i] = psycho_read(line_base + (i * 8UL)); + psycho_write(tag_base + (i * 8UL), 0UL); + psycho_write(line_base + (i * 8UL), 0UL); + } + + /* OK, state is logged, exit diagnostic mode. */ + psycho_write(strbuf->strbuf_control, control); + + for (i = 0; i < 16; i++) { + int j, saw_error, first, last; + + saw_error = 0; + first = i * 8; + last = first + 8; + for (j = first; j < last; j++) { + unsigned long errval = stc_error_buf[j]; + if (errval != 0) { + saw_error++; + printk("%s: STC_ERR(%d)[wr(%d)rd(%d)]\n", + pbm->name, + j, + (errval & PSYCHO_STCERR_WRITE) ? 1 : 0, + (errval & PSYCHO_STCERR_READ) ? 1 : 0); + } + } + if (saw_error != 0) { + unsigned long tagval = stc_tag_buf[i]; + unsigned long lineval = stc_line_buf[i]; + printk("%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n", + pbm->name, + i, + ((tagval & PSYCHO_STCTAG_PPN) >> 19UL), + (tagval & PSYCHO_STCTAG_VPN), + ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0), + ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0)); + printk("%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)" + "V(%d)FOFN(%d)]\n", + pbm->name, + i, + ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL), + ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL), + ((lineval & PSYCHO_STCLINE_LADDR) >> 8UL), + ((lineval & PSYCHO_STCLINE_EPTR) >> 2UL), + ((lineval & PSYCHO_STCLINE_VALID) ? 1 : 0), + ((lineval & PSYCHO_STCLINE_FOFN) ? 1 : 0)); + } + } + + spin_unlock(&stc_buf_lock); +} + +static void __psycho_check_stc_error(struct pci_pbm_info *pbm, + unsigned long afsr, + unsigned long afar, + enum psycho_error_type type) +{ + __psycho_check_one_stc(pbm, + (pbm == &pbm->parent->pbm_A)); +} /* When an Uncorrectable Error or a PCI Error happens, we * interrogate the IOMMU state to see if it is the cause. @@ -107,7 +271,122 @@ #define PSYCHO_IOMMU_TSBBASE 0x0208UL #define PSYCHO_IOMMU_FLUSH 0x0210UL #define PSYCHO_IOMMU_TAG 0xa580UL +#define PSYCHO_IOMMU_TAG_ERRSTS (0x3UL << 23UL) +#define PSYCHO_IOMMU_TAG_ERR (0x1UL << 22UL) +#define PSYCHO_IOMMU_TAG_WRITE (0x1UL << 21UL) +#define PSYCHO_IOMMU_TAG_STREAM (0x1UL << 20UL) +#define PSYCHO_IOMMU_TAG_SIZE (0x1UL << 19UL) +#define PSYCHO_IOMMU_TAG_VPAGE 0x7ffffUL #define PSYCHO_IOMMU_DATA 0xa600UL +#define PSYCHO_IOMMU_DATA_VALID (1UL << 30UL) +#define PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL) +#define PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL +static void psycho_check_iommu_error(struct pci_pbm_info *pbm, + unsigned long afsr, + unsigned long afar, + enum psycho_error_type type) +{ + struct iommu *iommu = pbm->iommu; + unsigned long iommu_tag[16]; + unsigned long iommu_data[16]; + unsigned long flags; + u64 control; + int i; + + spin_lock_irqsave(&iommu->lock, flags); + control = psycho_read(iommu->iommu_control); + if (control & PSYCHO_IOMMU_CTRL_XLTEERR) { + char *type_string; + + /* Clear the error encountered bit. */ + control &= ~PSYCHO_IOMMU_CTRL_XLTEERR; + psycho_write(iommu->iommu_control, control); + + switch((control & PSYCHO_IOMMU_CTRL_XLTESTAT) >> 25UL) { + case 0: + type_string = "Protection Error"; + break; + case 1: + type_string = "Invalid Error"; + break; + case 2: + type_string = "TimeOut Error"; + break; + case 3: + default: + type_string = "ECC Error"; + break; + }; + printk("%s: IOMMU Error, type[%s]\n", + pbm->name, type_string); + + /* Put the IOMMU into diagnostic mode and probe + * it's TLB for entries with error status. + * + * It is very possible for another DVMA to occur + * while we do this probe, and corrupt the system + * further. But we are so screwed at this point + * that we are likely to crash hard anyways, so + * get as much diagnostic information to the + * console as we can. + */ + psycho_write(iommu->iommu_control, + control | PSYCHO_IOMMU_CTRL_DENAB); + for (i = 0; i < 16; i++) { + unsigned long base = pbm->controller_regs; + + iommu_tag[i] = + psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL)); + iommu_data[i] = + psycho_read(base + PSYCHO_IOMMU_DATA + (i * 8UL)); + + /* Now clear out the entry. */ + psycho_write(base + PSYCHO_IOMMU_TAG + (i * 8UL), 0); + psycho_write(base + PSYCHO_IOMMU_DATA + (i * 8UL), 0); + } + + /* Leave diagnostic mode. */ + psycho_write(iommu->iommu_control, control); + + for (i = 0; i < 16; i++) { + unsigned long tag, data; + + tag = iommu_tag[i]; + if (!(tag & PSYCHO_IOMMU_TAG_ERR)) + continue; + + data = iommu_data[i]; + switch((tag & PSYCHO_IOMMU_TAG_ERRSTS) >> 23UL) { + case 0: + type_string = "Protection Error"; + break; + case 1: + type_string = "Invalid Error"; + break; + case 2: + type_string = "TimeOut Error"; + break; + case 3: + default: + type_string = "ECC Error"; + break; + }; + printk("%s: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n", + pbm->name, i, type_string, + ((tag & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0), + ((tag & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0), + ((tag & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8), + (tag & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT); + printk("%s: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n", + pbm->name, i, + ((data & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0), + ((data & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0), + (data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT); + } + } + __psycho_check_stc_error(pbm, afsr, afar, type); + spin_unlock_irqrestore(&iommu->lock, flags); +} /* Uncorrectable Errors. Cause of the error and the address are * recorded in the UE_AFSR and UE_AFAR of PSYCHO. They are errors @@ -131,14 +410,15 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id) { struct pci_pbm_info *pbm = dev_id; + struct pci_controller_info *p = pbm->parent; unsigned long afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR; unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR; unsigned long afsr, afar, error_bits; int reported; /* Latch uncorrectable error status. */ - afar = upa_readq(afar_reg); - afsr = upa_readq(afsr_reg); + afar = psycho_read(afar_reg); + afsr = psycho_read(afsr_reg); /* Clear the primary/secondary error status bits. */ error_bits = afsr & @@ -146,7 +426,7 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id) PSYCHO_UEAFSR_SPIO | PSYCHO_UEAFSR_SDRD | PSYCHO_UEAFSR_SDWR); if (!error_bits) return IRQ_NONE; - upa_writeq(error_bits, afsr_reg); + psycho_write(afsr_reg, error_bits); /* Log the error. */ printk("%s: Uncorrectable Error, primary error type[%s]\n", @@ -183,9 +463,8 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id) printk("]\n"); /* Interrogate both IOMMUs for error status. */ - psycho_check_iommu_error(pbm, afsr, afar, UE_ERR); - if (pbm->sibling) - psycho_check_iommu_error(pbm->sibling, afsr, afar, UE_ERR); + psycho_check_iommu_error(&p->pbm_A, afsr, afar, UE_ERR); + psycho_check_iommu_error(&p->pbm_B, afsr, afar, UE_ERR); return IRQ_HANDLED; } @@ -216,8 +495,8 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id) int reported; /* Latch error status. */ - afar = upa_readq(afar_reg); - afsr = upa_readq(afsr_reg); + afar = psycho_read(afar_reg); + afsr = psycho_read(afsr_reg); /* Clear primary/secondary error status bits. */ error_bits = afsr & @@ -225,7 +504,7 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id) PSYCHO_CEAFSR_SPIO | PSYCHO_CEAFSR_SDRD | PSYCHO_CEAFSR_SDWR); if (!error_bits) return IRQ_NONE; - upa_writeq(error_bits, afsr_reg); + psycho_write(afsr_reg, error_bits); /* Log the error. */ printk("%s: Correctable Error, primary error type[%s]\n", @@ -275,9 +554,164 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id) */ #define PSYCHO_PCI_AFSR_A 0x2010UL #define PSYCHO_PCI_AFSR_B 0x4010UL +#define PSYCHO_PCIAFSR_PMA 0x8000000000000000UL /* Primary Master Abort Error */ +#define PSYCHO_PCIAFSR_PTA 0x4000000000000000UL /* Primary Target Abort Error */ +#define PSYCHO_PCIAFSR_PRTRY 0x2000000000000000UL /* Primary Excessive Retries */ +#define PSYCHO_PCIAFSR_PPERR 0x1000000000000000UL /* Primary Parity Error */ +#define PSYCHO_PCIAFSR_SMA 0x0800000000000000UL /* Secondary Master Abort Error */ +#define PSYCHO_PCIAFSR_STA 0x0400000000000000UL /* Secondary Target Abort Error */ +#define PSYCHO_PCIAFSR_SRTRY 0x0200000000000000UL /* Secondary Excessive Retries */ +#define PSYCHO_PCIAFSR_SPERR 0x0100000000000000UL /* Secondary Parity Error */ +#define PSYCHO_PCIAFSR_RESV1 0x00ff000000000000UL /* Reserved */ +#define PSYCHO_PCIAFSR_BMSK 0x0000ffff00000000UL /* Bytemask of failed transfer */ +#define PSYCHO_PCIAFSR_BLK 0x0000000080000000UL /* Trans was block operation */ +#define PSYCHO_PCIAFSR_RESV2 0x0000000040000000UL /* Reserved */ +#define PSYCHO_PCIAFSR_MID 0x000000003e000000UL /* MID causing the error */ +#define PSYCHO_PCIAFSR_RESV3 0x0000000001ffffffUL /* Reserved */ #define PSYCHO_PCI_AFAR_A 0x2018UL #define PSYCHO_PCI_AFAR_B 0x4018UL +static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm_a) +{ + unsigned long csr_reg, csr, csr_error_bits; + irqreturn_t ret = IRQ_NONE; + u16 stat, *addr; + + if (is_pbm_a) { + csr_reg = pbm->controller_regs + PSYCHO_PCIA_CTRL; + } else { + csr_reg = pbm->controller_regs + PSYCHO_PCIB_CTRL; + } + csr = psycho_read(csr_reg); + csr_error_bits = + csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR); + if (csr_error_bits) { + /* Clear the errors. */ + psycho_write(csr_reg, csr); + + /* Log 'em. */ + if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR) + printk("%s: PCI streaming byte hole error asserted.\n", + pbm->name); + if (csr_error_bits & PSYCHO_PCICTRL_SERR) + printk("%s: PCI SERR signal asserted.\n", pbm->name); + ret = IRQ_HANDLED; + } + addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno, + 0, PCI_STATUS); + pci_config_read16(addr, &stat); + if (stat & (PCI_STATUS_PARITY | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT | + PCI_STATUS_REC_MASTER_ABORT | + PCI_STATUS_SIG_SYSTEM_ERROR)) { + printk("%s: PCI bus error, PCI_STATUS[%04x]\n", + pbm->name, stat); + pci_config_write16(addr, 0xffff); + ret = IRQ_HANDLED; + } + return ret; +} + +static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id) +{ + struct pci_pbm_info *pbm = dev_id; + struct pci_controller_info *p = pbm->parent; + unsigned long afsr_reg, afar_reg; + unsigned long afsr, afar, error_bits; + int is_pbm_a, reported; + + is_pbm_a = (pbm == &pbm->parent->pbm_A); + if (is_pbm_a) { + afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_A; + afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_A; + } else { + afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_B; + afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_B; + } + + /* Latch error status. */ + afar = psycho_read(afar_reg); + afsr = psycho_read(afsr_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA | + PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR | + PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA | + PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR); + if (!error_bits) + return psycho_pcierr_intr_other(pbm, is_pbm_a); + psycho_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("%s: PCI Error, primary error type[%s]\n", + pbm->name, + (((error_bits & PSYCHO_PCIAFSR_PMA) ? + "Master Abort" : + ((error_bits & PSYCHO_PCIAFSR_PTA) ? + "Target Abort" : + ((error_bits & PSYCHO_PCIAFSR_PRTRY) ? + "Excessive Retries" : + ((error_bits & PSYCHO_PCIAFSR_PPERR) ? + "Parity Error" : "???")))))); + printk("%s: bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n", + pbm->name, + (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL, + (afsr & PSYCHO_PCIAFSR_MID) >> 25UL, + (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0); + printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar); + printk("%s: PCI Secondary errors [", pbm->name); + reported = 0; + if (afsr & PSYCHO_PCIAFSR_SMA) { + reported++; + printk("(Master Abort)"); + } + if (afsr & PSYCHO_PCIAFSR_STA) { + reported++; + printk("(Target Abort)"); + } + if (afsr & PSYCHO_PCIAFSR_SRTRY) { + reported++; + printk("(Excessive Retries)"); + } + if (afsr & PSYCHO_PCIAFSR_SPERR) { + reported++; + printk("(Parity Error)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); + + /* For the error types shown, scan PBM's PCI bus for devices + * which have logged that error type. + */ + + /* If we see a Target Abort, this could be the result of an + * IOMMU translation error of some sort. It is extremely + * useful to log this information as usually it indicates + * a bug in the IOMMU support code or a PCI device driver. + */ + if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) { + psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR); + pci_scan_for_target_abort(pbm, pbm->pci_bus); + } + if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA)) + pci_scan_for_master_abort(pbm, pbm->pci_bus); + + /* For excessive retries, PSYCHO/PBM will abort the device + * and there is no way to specifically check for excessive + * retries in the config space status registers. So what + * we hope is that we'll catch it via the master/target + * abort events. + */ + + if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR)) + pci_scan_for_parity_error(pbm, pbm->pci_bus); + + return IRQ_HANDLED; +} + /* XXX What about PowerFail/PowerManagement??? -DaveM */ #define PSYCHO_ECC_CTRL 0x0020 #define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */ @@ -285,7 +719,7 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id) #define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */ static void psycho_register_error_handlers(struct pci_pbm_info *pbm) { - struct of_device *op = of_find_device_by_node(pbm->op->node); + struct of_device *op = of_find_device_by_node(pbm->prom_node); unsigned long base = pbm->controller_regs; u64 tmp; int err; @@ -328,26 +762,27 @@ static void psycho_register_error_handlers(struct pci_pbm_info *pbm) "err=%d\n", pbm->name, err); /* Enable UE and CE interrupts for controller. */ - upa_writeq((PSYCHO_ECCCTRL_EE | - PSYCHO_ECCCTRL_UE | - PSYCHO_ECCCTRL_CE), base + PSYCHO_ECC_CTRL); + psycho_write(base + PSYCHO_ECC_CTRL, + (PSYCHO_ECCCTRL_EE | + PSYCHO_ECCCTRL_UE | + PSYCHO_ECCCTRL_CE)); /* Enable PCI Error interrupts and clear error * bits for each PBM. */ - tmp = upa_readq(base + PSYCHO_PCIA_CTRL); + tmp = psycho_read(base + PSYCHO_PCIA_CTRL); tmp |= (PSYCHO_PCICTRL_SERR | PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); tmp &= ~(PSYCHO_PCICTRL_SBH_INT); - upa_writeq(tmp, base + PSYCHO_PCIA_CTRL); + psycho_write(base + PSYCHO_PCIA_CTRL, tmp); - tmp = upa_readq(base + PSYCHO_PCIB_CTRL); + tmp = psycho_read(base + PSYCHO_PCIB_CTRL); tmp |= (PSYCHO_PCICTRL_SERR | PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); tmp &= ~(PSYCHO_PCICTRL_SBH_INT); - upa_writeq(tmp, base + PSYCHO_PCIB_CTRL); + psycho_write(base + PSYCHO_PCIB_CTRL, tmp); } /* PSYCHO boot time probing and initialization. */ @@ -368,12 +803,11 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm) pci_config_write8(addr, 64); } -static void __init psycho_scan_bus(struct pci_pbm_info *pbm, - struct device *parent) +static void __init psycho_scan_bus(struct pci_pbm_info *pbm) { pbm_config_busmastering(pbm); pbm->is_66mhz_capable = 0; - pbm->pci_bus = pci_scan_one_pbm(pbm, parent); + pbm->pci_bus = pci_scan_one_pbm(pbm); /* After the PCI bus scan is complete, we can register * the error interrupt handlers. @@ -381,6 +815,61 @@ static void __init psycho_scan_bus(struct pci_pbm_info *pbm, psycho_register_error_handlers(pbm); } +static int psycho_iommu_init(struct pci_pbm_info *pbm) +{ + struct iommu *iommu = pbm->iommu; + unsigned long i; + u64 control; + int err; + + /* Register addresses. */ + iommu->iommu_control = pbm->controller_regs + PSYCHO_IOMMU_CONTROL; + iommu->iommu_tsbbase = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE; + iommu->iommu_flush = pbm->controller_regs + PSYCHO_IOMMU_FLUSH; + iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL); + + /* PSYCHO's IOMMU lacks ctx flushing. */ + iommu->iommu_ctxflush = 0; + + /* We use the main control register of PSYCHO as the write + * completion register. + */ + iommu->write_complete_reg = pbm->controller_regs + PSYCHO_CONTROL; + + /* + * Invalidate TLB Entries. + */ + control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL); + control |= PSYCHO_IOMMU_CTRL_DENAB; + psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control); + for(i = 0; i < 16; i++) { + psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0); + psycho_write(pbm->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0); + } + + /* Leave diag mode enabled for full-flushing done + * in pci_iommu.c + */ + err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff, + pbm->numa_node); + if (err) + return err; + + psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE, + __pa(iommu->page_table)); + + control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL); + control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ); + control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB); + psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control); + + /* If necessary, hook us up for starfire IRQ translations. */ + if (this_is_starfire) + starfire_hookup(pbm->portid); + + return 0; +} + #define PSYCHO_IRQ_RETRY 0x1a00UL #define PSYCHO_PCIA_DIAG 0x2020UL #define PSYCHO_PCIB_DIAG 0x4020UL @@ -397,28 +886,28 @@ static void psycho_controller_hwinit(struct pci_pbm_info *pbm) { u64 tmp; - upa_writeq(5, pbm->controller_regs + PSYCHO_IRQ_RETRY); + psycho_write(pbm->controller_regs + PSYCHO_IRQ_RETRY, 5); /* Enable arbiter for all PCI slots. */ - tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_CTRL); + tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_CTRL); tmp |= PSYCHO_PCICTRL_AEN; - upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_CTRL); + psycho_write(pbm->controller_regs + PSYCHO_PCIA_CTRL, tmp); - tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_CTRL); + tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_CTRL); tmp |= PSYCHO_PCICTRL_AEN; - upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_CTRL); + psycho_write(pbm->controller_regs + PSYCHO_PCIB_CTRL, tmp); /* Disable DMA write / PIO read synchronization on * both PCI bus segments. * [ U2P Erratum 1243770, STP2223BGA data sheet ] */ - tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_DIAG); + tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_DIAG); tmp |= PSYCHO_PCIDIAG_DDWSYNC; - upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_DIAG); + psycho_write(pbm->controller_regs + PSYCHO_PCIA_DIAG, tmp); - tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_DIAG); + tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_DIAG); tmp |= PSYCHO_PCIDIAG_DDWSYNC; - upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_DIAG); + psycho_write(pbm->controller_regs + PSYCHO_PCIB_DIAG, tmp); } static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm, @@ -431,16 +920,10 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm, pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A; pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A; pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_A; - pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_A; - pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_A; - pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_A; } else { pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_B; pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B; pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B; - pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_B; - pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_B; - pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_B; } /* PSYCHO's streaming buffer lacks ctx flushing. */ pbm->stc.strbuf_ctxflush = 0; @@ -463,7 +946,7 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm, */ #undef PSYCHO_STRBUF_RERUN_ENABLE #undef PSYCHO_STRBUF_RERUN_DISABLE - control = upa_readq(pbm->stc.strbuf_control); + control = psycho_read(pbm->stc.strbuf_control); control |= PSYCHO_STRBUF_CTRL_ENAB; control &= ~(PSYCHO_STRBUF_CTRL_LENAB | PSYCHO_STRBUF_CTRL_LPTR); #ifdef PSYCHO_STRBUF_RERUN_ENABLE @@ -473,7 +956,7 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm, control |= PSYCHO_STRBUF_CTRL_RRDIS; #endif #endif - upa_writeq(control, pbm->stc.strbuf_control); + psycho_write(pbm->stc.strbuf_control, control); pbm->stc.strbuf_enabled = 1; } @@ -485,134 +968,111 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm, #define PSYCHO_MEMSPACE_B 0x180000000UL #define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL -static void __init psycho_pbm_init(struct pci_pbm_info *pbm, - struct of_device *op, int is_pbm_a) -{ - psycho_pbm_init_common(pbm, op, "PSYCHO", PBM_CHIP_TYPE_PSYCHO); - psycho_pbm_strbuf_init(pbm, is_pbm_a); - psycho_scan_bus(pbm, &op->dev); -} - -static struct pci_pbm_info * __devinit psycho_find_sibling(u32 upa_portid) +static void __init psycho_pbm_init(struct pci_controller_info *p, + struct device_node *dp, int is_pbm_a) { + struct property *prop; struct pci_pbm_info *pbm; - for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { - if (pbm->portid == upa_portid) - return pbm; - } - return NULL; -} + if (is_pbm_a) + pbm = &p->pbm_A; + else + pbm = &p->pbm_B; -#define PSYCHO_CONFIGSPACE 0x001000000UL + pbm->next = pci_pbm_root; + pci_pbm_root = pbm; -static int __devinit psycho_probe(struct of_device *op, - const struct of_device_id *match) -{ - const struct linux_prom64_registers *pr_regs; - struct device_node *dp = op->node; - struct pci_pbm_info *pbm; - struct iommu *iommu; - int is_pbm_a, err; - u32 upa_portid; + pbm->numa_node = -1; - upa_portid = of_getintprop_default(dp, "upa-portid", 0xff); + pbm->scan_bus = psycho_scan_bus; + pbm->pci_ops = &sun4u_pci_ops; + pbm->config_space_reg_bits = 8; - err = -ENOMEM; - pbm = kzalloc(sizeof(*pbm), GFP_KERNEL); - if (!pbm) { - printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n"); - goto out_err; - } + pbm->index = pci_num_pbms++; - pbm->sibling = psycho_find_sibling(upa_portid); - if (pbm->sibling) { - iommu = pbm->sibling->iommu; - } else { - iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL); - if (!iommu) { - printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n"); - goto out_free_controller; - } - } + pbm->chip_type = PBM_CHIP_TYPE_PSYCHO; + pbm->chip_version = 0; + prop = of_find_property(dp, "version#", NULL); + if (prop) + pbm->chip_version = *(int *) prop->value; + pbm->chip_revision = 0; + prop = of_find_property(dp, "module-revision#", NULL); + if (prop) + pbm->chip_revision = *(int *) prop->value; - pbm->iommu = iommu; - pbm->portid = upa_portid; + pbm->parent = p; + pbm->prom_node = dp; + pbm->name = dp->full_name; - pr_regs = of_get_property(dp, "reg", NULL); - err = -ENODEV; - if (!pr_regs) { - printk(KERN_ERR PFX "No reg property.\n"); - goto out_free_iommu; - } + printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n", + pbm->name, + pbm->chip_version, pbm->chip_revision); - is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); + pci_determine_mem_io_space(pbm); - pbm->controller_regs = pr_regs[2].phys_addr; - pbm->config_space = (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE); + pci_get_pbm_props(pbm); - if (is_pbm_a) { - pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_A; - pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_A; - pbm->pci_csr = pbm->controller_regs + PSYCHO_PCIA_CTRL; - } else { - pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_B; - pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_B; - pbm->pci_csr = pbm->controller_regs + PSYCHO_PCIB_CTRL; - } + psycho_pbm_strbuf_init(pbm, is_pbm_a); +} - psycho_controller_hwinit(pbm); - if (!pbm->sibling) { - err = psycho_iommu_init(pbm, 128, 0xc0000000, - 0xffffffff, PSYCHO_CONTROL); - if (err) - goto out_free_iommu; +#define PSYCHO_CONFIGSPACE 0x001000000UL - /* If necessary, hook us up for starfire IRQ translations. */ - if (this_is_starfire) - starfire_hookup(pbm->portid); - } +void __init psycho_init(struct device_node *dp, char *model_name) +{ + struct linux_prom64_registers *pr_regs; + struct pci_controller_info *p; + struct pci_pbm_info *pbm; + struct iommu *iommu; + struct property *prop; + u32 upa_portid; + int is_pbm_a; - psycho_pbm_init(pbm, op, is_pbm_a); + upa_portid = 0xff; + prop = of_find_property(dp, "upa-portid", NULL); + if (prop) + upa_portid = *(u32 *) prop->value; - pbm->next = pci_pbm_root; - pci_pbm_root = pbm; + for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { + struct pci_controller_info *p = pbm->parent; + + if (p->pbm_A.portid == upa_portid) { + is_pbm_a = (p->pbm_A.prom_node == NULL); + psycho_pbm_init(p, dp, is_pbm_a); + return; + } + } - if (pbm->sibling) - pbm->sibling->sibling = pbm; + p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); + if (!p) + goto fatal_memory_error; + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); + if (!iommu) + goto fatal_memory_error; - dev_set_drvdata(&op->dev, pbm); + p->pbm_A.iommu = p->pbm_B.iommu = iommu; - return 0; + p->pbm_A.portid = upa_portid; + p->pbm_B.portid = upa_portid; -out_free_iommu: - if (!pbm->sibling) - kfree(pbm->iommu); + prop = of_find_property(dp, "reg", NULL); + pr_regs = prop->value; -out_free_controller: - kfree(pbm); + p->pbm_A.controller_regs = pr_regs[2].phys_addr; + p->pbm_B.controller_regs = pr_regs[2].phys_addr; -out_err: - return err; -} + p->pbm_A.config_space = p->pbm_B.config_space = + (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE); -static struct of_device_id __initdata psycho_match[] = { - { - .name = "pci", - .compatible = "pci108e,8000", - }, - {}, -}; + psycho_controller_hwinit(&p->pbm_A); -static struct of_platform_driver psycho_driver = { - .name = DRIVER_NAME, - .match_table = psycho_match, - .probe = psycho_probe, -}; + if (psycho_iommu_init(&p->pbm_A)) + goto fatal_memory_error; -static int __init psycho_init(void) -{ - return of_register_driver(&psycho_driver, &of_bus_type); -} + is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); + psycho_pbm_init(p, dp, is_pbm_a); + return; -subsys_initcall(psycho_init); +fatal_memory_error: + prom_printf("PSYCHO: Fatal memory allocation error.\n"); + prom_halt(); +} diff --git a/trunk/arch/sparc64/kernel/pci_sabre.c b/trunk/arch/sparc64/kernel/pci_sabre.c index 713257b6963c..ade5184e75d1 100644 --- a/trunk/arch/sparc64/kernel/pci_sabre.c +++ b/trunk/arch/sparc64/kernel/pci_sabre.c @@ -16,15 +16,31 @@ #include #include #include +#include +#include #include -#include #include "pci_impl.h" #include "iommu_common.h" -#include "psycho_common.h" -#define DRIVER_NAME "sabre" -#define PFX DRIVER_NAME ": " +/* All SABRE registers are 64-bits. The following accessor + * routines are how they are accessed. The REG parameter + * is a physical address. + */ +#define sabre_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define sabre_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory") /* SABRE PCI controller register offsets and definitions. */ #define SABRE_UE_AFSR 0x0030UL @@ -192,6 +208,95 @@ static int hummingbird_p; static struct pci_bus *sabre_root_bus; +/* SABRE error handling support. */ +static void sabre_check_iommu_error(struct pci_pbm_info *pbm, + unsigned long afsr, + unsigned long afar) +{ + struct iommu *iommu = pbm->iommu; + unsigned long iommu_tag[16]; + unsigned long iommu_data[16]; + unsigned long flags; + u64 control; + int i; + + spin_lock_irqsave(&iommu->lock, flags); + control = sabre_read(iommu->iommu_control); + if (control & SABRE_IOMMUCTRL_ERR) { + char *type_string; + + /* Clear the error encountered bit. + * NOTE: On Sabre this is write 1 to clear, + * which is different from Psycho. + */ + sabre_write(iommu->iommu_control, control); + switch((control & SABRE_IOMMUCTRL_ERRSTS) >> 25UL) { + case 1: + type_string = "Invalid Error"; + break; + case 3: + type_string = "ECC Error"; + break; + default: + type_string = "Unknown"; + break; + }; + printk("%s: IOMMU Error, type[%s]\n", + pbm->name, type_string); + + /* Enter diagnostic mode and probe for error'd + * entries in the IOTLB. + */ + control &= ~(SABRE_IOMMUCTRL_ERRSTS | SABRE_IOMMUCTRL_ERR); + sabre_write(iommu->iommu_control, + (control | SABRE_IOMMUCTRL_DENAB)); + for (i = 0; i < 16; i++) { + unsigned long base = pbm->controller_regs; + + iommu_tag[i] = + sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL)); + iommu_data[i] = + sabre_read(base + SABRE_IOMMU_DATA + (i * 8UL)); + sabre_write(base + SABRE_IOMMU_TAG + (i * 8UL), 0); + sabre_write(base + SABRE_IOMMU_DATA + (i * 8UL), 0); + } + sabre_write(iommu->iommu_control, control); + + for (i = 0; i < 16; i++) { + unsigned long tag, data; + + tag = iommu_tag[i]; + if (!(tag & SABRE_IOMMUTAG_ERR)) + continue; + + data = iommu_data[i]; + switch((tag & SABRE_IOMMUTAG_ERRSTS) >> 23UL) { + case 1: + type_string = "Invalid Error"; + break; + case 3: + type_string = "ECC Error"; + break; + default: + type_string = "Unknown"; + break; + }; + printk("%s: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n", + pbm->name, i, tag, type_string, + ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0), + ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8), + ((tag & SABRE_IOMMUTAG_VPN) << IOMMU_PAGE_SHIFT)); + printk("%s: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n", + pbm->name, i, data, + ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0), + ((data & SABRE_IOMMUDATA_USED) ? 1 : 0), + ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0), + ((data & SABRE_IOMMUDATA_PPN) << IOMMU_PAGE_SHIFT)); + } + } + spin_unlock_irqrestore(&iommu->lock, flags); +} + static irqreturn_t sabre_ue_intr(int irq, void *dev_id) { struct pci_pbm_info *pbm = dev_id; @@ -201,8 +306,8 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id) int reported; /* Latch uncorrectable error status. */ - afar = upa_readq(afar_reg); - afsr = upa_readq(afsr_reg); + afar = sabre_read(afar_reg); + afsr = sabre_read(afsr_reg); /* Clear the primary/secondary error status bits. */ error_bits = afsr & @@ -211,7 +316,7 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id) SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE); if (!error_bits) return IRQ_NONE; - upa_writeq(error_bits, afsr_reg); + sabre_write(afsr_reg, error_bits); /* Log the error. */ printk("%s: Uncorrectable Error, primary error type[%s%s]\n", @@ -247,7 +352,7 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id) printk("]\n"); /* Interrogate IOMMU for error status. */ - psycho_check_iommu_error(pbm, afsr, afar, UE_ERR); + sabre_check_iommu_error(pbm, afsr, afar); return IRQ_HANDLED; } @@ -261,8 +366,8 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id) int reported; /* Latch error status. */ - afar = upa_readq(afar_reg); - afsr = upa_readq(afsr_reg); + afar = sabre_read(afar_reg); + afsr = sabre_read(afsr_reg); /* Clear primary/secondary error status bits. */ error_bits = afsr & @@ -270,7 +375,7 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id) SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR); if (!error_bits) return IRQ_NONE; - upa_writeq(error_bits, afsr_reg); + sabre_write(afsr_reg, error_bits); /* Log the error. */ printk("%s: Correctable Error, primary error type[%s]\n", @@ -308,9 +413,136 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t sabre_pcierr_intr_other(struct pci_pbm_info *pbm) +{ + unsigned long csr_reg, csr, csr_error_bits; + irqreturn_t ret = IRQ_NONE; + u16 stat; + + csr_reg = pbm->controller_regs + SABRE_PCICTRL; + csr = sabre_read(csr_reg); + csr_error_bits = + csr & SABRE_PCICTRL_SERR; + if (csr_error_bits) { + /* Clear the errors. */ + sabre_write(csr_reg, csr); + + /* Log 'em. */ + if (csr_error_bits & SABRE_PCICTRL_SERR) + printk("%s: PCI SERR signal asserted.\n", + pbm->name); + ret = IRQ_HANDLED; + } + pci_bus_read_config_word(sabre_root_bus, 0, + PCI_STATUS, &stat); + if (stat & (PCI_STATUS_PARITY | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT | + PCI_STATUS_REC_MASTER_ABORT | + PCI_STATUS_SIG_SYSTEM_ERROR)) { + printk("%s: PCI bus error, PCI_STATUS[%04x]\n", + pbm->name, stat); + pci_bus_write_config_word(sabre_root_bus, 0, + PCI_STATUS, 0xffff); + ret = IRQ_HANDLED; + } + return ret; +} + +static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id) +{ + struct pci_pbm_info *pbm = dev_id; + unsigned long afsr_reg, afar_reg; + unsigned long afsr, afar, error_bits; + int reported; + + afsr_reg = pbm->controller_regs + SABRE_PIOAFSR; + afar_reg = pbm->controller_regs + SABRE_PIOAFAR; + + /* Latch error status. */ + afar = sabre_read(afar_reg); + afsr = sabre_read(afsr_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_PTA | + SABRE_PIOAFSR_PRTRY | SABRE_PIOAFSR_PPERR | + SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA | + SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR); + if (!error_bits) + return sabre_pcierr_intr_other(pbm); + sabre_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("%s: PCI Error, primary error type[%s]\n", + pbm->name, + (((error_bits & SABRE_PIOAFSR_PMA) ? + "Master Abort" : + ((error_bits & SABRE_PIOAFSR_PTA) ? + "Target Abort" : + ((error_bits & SABRE_PIOAFSR_PRTRY) ? + "Excessive Retries" : + ((error_bits & SABRE_PIOAFSR_PPERR) ? + "Parity Error" : "???")))))); + printk("%s: bytemask[%04lx] was_block(%d)\n", + pbm->name, + (afsr & SABRE_PIOAFSR_BMSK) >> 32UL, + (afsr & SABRE_PIOAFSR_BLK) ? 1 : 0); + printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar); + printk("%s: PCI Secondary errors [", pbm->name); + reported = 0; + if (afsr & SABRE_PIOAFSR_SMA) { + reported++; + printk("(Master Abort)"); + } + if (afsr & SABRE_PIOAFSR_STA) { + reported++; + printk("(Target Abort)"); + } + if (afsr & SABRE_PIOAFSR_SRTRY) { + reported++; + printk("(Excessive Retries)"); + } + if (afsr & SABRE_PIOAFSR_SPERR) { + reported++; + printk("(Parity Error)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); + + /* For the error types shown, scan both PCI buses for devices + * which have logged that error type. + */ + + /* If we see a Target Abort, this could be the result of an + * IOMMU translation error of some sort. It is extremely + * useful to log this information as usually it indicates + * a bug in the IOMMU support code or a PCI device driver. + */ + if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) { + sabre_check_iommu_error(pbm, afsr, afar); + pci_scan_for_target_abort(pbm, pbm->pci_bus); + } + if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA)) + pci_scan_for_master_abort(pbm, pbm->pci_bus); + + /* For excessive retries, SABRE/PBM will abort the device + * and there is no way to specifically check for excessive + * retries in the config space status registers. So what + * we hope is that we'll catch it via the master/target + * abort events. + */ + + if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR)) + pci_scan_for_parity_error(pbm, pbm->pci_bus); + + return IRQ_HANDLED; +} + static void sabre_register_error_handlers(struct pci_pbm_info *pbm) { - struct device_node *dp = pbm->op->node; + struct device_node *dp = pbm->prom_node; struct of_device *op; unsigned long base = pbm->controller_regs; u64 tmp; @@ -336,34 +568,33 @@ static void sabre_register_error_handlers(struct pci_pbm_info *pbm) * registering the handler so that we don't get spurious * interrupts. */ - upa_writeq((SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR | - SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | - SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE), - base + SABRE_UE_AFSR); + sabre_write(base + SABRE_UE_AFSR, + (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR | + SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | + SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE)); err = request_irq(op->irqs[1], sabre_ue_intr, 0, "SABRE_UE", pbm); if (err) printk(KERN_WARNING "%s: Couldn't register UE, err=%d.\n", pbm->name, err); - upa_writeq((SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | - SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR), - base + SABRE_CE_AFSR); - + sabre_write(base + SABRE_CE_AFSR, + (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | + SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR)); err = request_irq(op->irqs[2], sabre_ce_intr, 0, "SABRE_CE", pbm); if (err) printk(KERN_WARNING "%s: Couldn't register CE, err=%d.\n", pbm->name, err); - err = request_irq(op->irqs[0], psycho_pcierr_intr, 0, + err = request_irq(op->irqs[0], sabre_pcierr_intr, 0, "SABRE_PCIERR", pbm); if (err) printk(KERN_WARNING "%s: Couldn't register PCIERR, err=%d.\n", pbm->name, err); - tmp = upa_readq(base + SABRE_PCICTRL); + tmp = sabre_read(base + SABRE_PCICTRL); tmp |= SABRE_PCICTRL_ERREN; - upa_writeq(tmp, base + SABRE_PCICTRL); + sabre_write(base + SABRE_PCICTRL, tmp); } static void apb_init(struct pci_bus *sabre_bus) @@ -402,8 +633,7 @@ static void apb_init(struct pci_bus *sabre_bus) } } -static void __init sabre_scan_bus(struct pci_pbm_info *pbm, - struct device *parent) +static void __init sabre_scan_bus(struct pci_pbm_info *pbm) { static int once; @@ -426,12 +656,12 @@ static void __init sabre_scan_bus(struct pci_pbm_info *pbm, * to live at bus 0. */ if (once != 0) { - printk(KERN_ERR PFX "Multiple controllers unsupported.\n"); - return; + prom_printf("SABRE: Multiple controllers unsupported.\n"); + prom_halt(); } once++; - pbm->pci_bus = pci_scan_one_pbm(pbm, parent); + pbm->pci_bus = pci_scan_one_pbm(pbm); if (!pbm->pci_bus) return; @@ -442,58 +672,133 @@ static void __init sabre_scan_bus(struct pci_pbm_info *pbm, sabre_register_error_handlers(pbm); } -static void __init sabre_pbm_init(struct pci_pbm_info *pbm, - struct of_device *op) +static int sabre_iommu_init(struct pci_pbm_info *pbm, + int tsbsize, unsigned long dvma_offset, + u32 dma_mask) +{ + struct iommu *iommu = pbm->iommu; + unsigned long i; + u64 control; + int err; + + /* Register addresses. */ + iommu->iommu_control = pbm->controller_regs + SABRE_IOMMU_CONTROL; + iommu->iommu_tsbbase = pbm->controller_regs + SABRE_IOMMU_TSBBASE; + iommu->iommu_flush = pbm->controller_regs + SABRE_IOMMU_FLUSH; + iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL); + iommu->write_complete_reg = pbm->controller_regs + SABRE_WRSYNC; + /* Sabre's IOMMU lacks ctx flushing. */ + iommu->iommu_ctxflush = 0; + + /* Invalidate TLB Entries. */ + control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL); + control |= SABRE_IOMMUCTRL_DENAB; + sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control); + + for(i = 0; i < 16; i++) { + sabre_write(pbm->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0); + sabre_write(pbm->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0); + } + + /* Leave diag mode enabled for full-flushing done + * in pci_iommu.c + */ + err = iommu_table_init(iommu, tsbsize * 1024 * 8, + dvma_offset, dma_mask, pbm->numa_node); + if (err) + return err; + + sabre_write(pbm->controller_regs + SABRE_IOMMU_TSBBASE, + __pa(iommu->page_table)); + + control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL); + control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ); + control |= SABRE_IOMMUCTRL_ENAB; + switch(tsbsize) { + case 64: + control |= SABRE_IOMMU_TSBSZ_64K; + break; + case 128: + control |= SABRE_IOMMU_TSBSZ_128K; + break; + default: + prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); + prom_halt(); + break; + } + sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control); + + return 0; +} + +static void __init sabre_pbm_init(struct pci_controller_info *p, + struct pci_pbm_info *pbm, struct device_node *dp) { - psycho_pbm_init_common(pbm, op, "SABRE", PBM_CHIP_TYPE_SABRE); - pbm->pci_afsr = pbm->controller_regs + SABRE_PIOAFSR; - pbm->pci_afar = pbm->controller_regs + SABRE_PIOAFAR; - pbm->pci_csr = pbm->controller_regs + SABRE_PCICTRL; - sabre_scan_bus(pbm, &op->dev); + pbm->name = dp->full_name; + printk("%s: SABRE PCI Bus Module\n", pbm->name); + + pbm->numa_node = -1; + + pbm->scan_bus = sabre_scan_bus; + pbm->pci_ops = &sun4u_pci_ops; + pbm->config_space_reg_bits = 8; + + pbm->index = pci_num_pbms++; + + pbm->chip_type = PBM_CHIP_TYPE_SABRE; + pbm->parent = p; + pbm->prom_node = dp; + pci_get_pbm_props(pbm); + + pci_determine_mem_io_space(pbm); } -static int __devinit sabre_probe(struct of_device *op, - const struct of_device_id *match) +void __init sabre_init(struct device_node *dp, char *model_name) { const struct linux_prom64_registers *pr_regs; - struct device_node *dp = op->node; + struct pci_controller_info *p; struct pci_pbm_info *pbm; - u32 upa_portid, dma_mask; struct iommu *iommu; - int tsbsize, err; + int tsbsize; const u32 *vdma; + u32 upa_portid, dma_mask; u64 clear_irq; - hummingbird_p = (match->data != NULL); - if (!hummingbird_p) { - struct device_node *cpu_dp; - - /* Of course, Sun has to encode things a thousand - * different ways, inconsistently. - */ - for_each_node_by_type(cpu_dp, "cpu") { - if (!strcmp(cpu_dp->name, "SUNW,UltraSPARC-IIe")) - hummingbird_p = 1; + hummingbird_p = 0; + if (!strcmp(model_name, "pci108e,a001")) + hummingbird_p = 1; + else if (!strcmp(model_name, "SUNW,sabre")) { + const char *compat = of_get_property(dp, "compatible", NULL); + if (compat && !strcmp(compat, "pci108e,a001")) + hummingbird_p = 1; + if (!hummingbird_p) { + struct device_node *dp; + + /* Of course, Sun has to encode things a thousand + * different ways, inconsistently. + */ + for_each_node_by_type(dp, "cpu") { + if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe")) + hummingbird_p = 1; + } } } - err = -ENOMEM; - pbm = kzalloc(sizeof(*pbm), GFP_KERNEL); - if (!pbm) { - printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n"); - goto out_err; - } - - iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); - if (!iommu) { - printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n"); - goto out_free_controller; - } + p = kzalloc(sizeof(*p), GFP_ATOMIC); + if (!p) + goto fatal_memory_error; + iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC); + if (!iommu) + goto fatal_memory_error; + pbm = &p->pbm_A; pbm->iommu = iommu; upa_portid = of_getintprop_default(dp, "upa-portid", 0xff); + pbm->next = pci_pbm_root; + pci_pbm_root = pbm; + pbm->portid = upa_portid; /* @@ -501,11 +806,6 @@ static int __devinit sabre_probe(struct of_device *op, */ pr_regs = of_get_property(dp, "reg", NULL); - err = -ENODEV; - if (!pr_regs) { - printk(KERN_ERR PFX "No reg property\n"); - goto out_free_iommu; - } /* * First REG in property is base of entire SABRE register space. @@ -516,25 +816,22 @@ static int __devinit sabre_probe(struct of_device *op, /* PCI first */ for (clear_irq = SABRE_ICLR_A_SLOT0; clear_irq < SABRE_ICLR_B_SLOT0 + 0x80; clear_irq += 8) - upa_writeq(0x0UL, pbm->controller_regs + clear_irq); + sabre_write(pbm->controller_regs + clear_irq, 0x0UL); /* Then OBIO */ for (clear_irq = SABRE_ICLR_SCSI; clear_irq < SABRE_ICLR_SCSI + 0x80; clear_irq += 8) - upa_writeq(0x0UL, pbm->controller_regs + clear_irq); + sabre_write(pbm->controller_regs + clear_irq, 0x0UL); /* Error interrupts are enabled later after the bus scan. */ - upa_writeq((SABRE_PCICTRL_MRLEN | SABRE_PCICTRL_SERR | - SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN), - pbm->controller_regs + SABRE_PCICTRL); + sabre_write(pbm->controller_regs + SABRE_PCICTRL, + (SABRE_PCICTRL_MRLEN | SABRE_PCICTRL_SERR | + SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN)); /* Now map in PCI config space for entire SABRE. */ - pbm->config_space = pbm->controller_regs + SABRE_CONFIGSPACE; + pbm->config_space = + (pbm->controller_regs + SABRE_CONFIGSPACE); vdma = of_get_property(dp, "virtual-dma", NULL); - if (!vdma) { - printk(KERN_ERR PFX "No virtual-dma property\n"); - goto out_free_iommu; - } dma_mask = vdma[0]; switch(vdma[1]) { @@ -552,58 +849,20 @@ static int __devinit sabre_probe(struct of_device *op, tsbsize = 128; break; default: - printk(KERN_ERR PFX "Strange virtual-dma size.\n"); - goto out_free_iommu; + prom_printf("SABRE: strange virtual-dma size.\n"); + prom_halt(); } - err = psycho_iommu_init(pbm, tsbsize, vdma[0], dma_mask, SABRE_WRSYNC); - if (err) - goto out_free_iommu; + if (sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask)) + goto fatal_memory_error; /* * Look for APB underneath. */ - sabre_pbm_init(pbm, op); + sabre_pbm_init(p, pbm, dp); + return; - pbm->next = pci_pbm_root; - pci_pbm_root = pbm; - - dev_set_drvdata(&op->dev, pbm); - - return 0; - -out_free_iommu: - kfree(pbm->iommu); - -out_free_controller: - kfree(pbm); - -out_err: - return err; -} - -static struct of_device_id __initdata sabre_match[] = { - { - .name = "pci", - .compatible = "pci108e,a001", - .data = (void *) 1, - }, - { - .name = "pci", - .compatible = "pci108e,a000", - }, - {}, -}; - -static struct of_platform_driver sabre_driver = { - .name = DRIVER_NAME, - .match_table = sabre_match, - .probe = sabre_probe, -}; - -static int __init sabre_init(void) -{ - return of_register_driver(&sabre_driver, &of_bus_type); +fatal_memory_error: + prom_printf("SABRE: Fatal memory allocation error.\n"); + prom_halt(); } - -subsys_initcall(sabre_init); diff --git a/trunk/arch/sparc64/kernel/pci_schizo.c b/trunk/arch/sparc64/kernel/pci_schizo.c index 45d9dba1ba11..9248c6737f0e 100644 --- a/trunk/arch/sparc64/kernel/pci_schizo.c +++ b/trunk/arch/sparc64/kernel/pci_schizo.c @@ -1,6 +1,6 @@ /* pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support. * - * Copyright (C) 2001, 2002, 2003, 2007, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 2001, 2002, 2003, 2007 David S. Miller (davem@davemloft.net) */ #include @@ -13,15 +13,32 @@ #include #include +#include #include #include -#include +#include #include "pci_impl.h" #include "iommu_common.h" -#define DRIVER_NAME "schizo" -#define PFX DRIVER_NAME ": " +/* All SCHIZO registers are 64-bits. The following accessor + * routines are how they are accessed. The REG parameter + * is a physical address. + */ +#define schizo_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define schizo_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory") /* This is a convention that at least Excalibur and Merlin * follow. I suppose the SCHIZO used in Starcat and friends @@ -146,25 +163,25 @@ static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm, * invalidating it before it has a chance to reach * main memory. */ - control = upa_readq(strbuf->strbuf_control); - upa_writeq((control | SCHIZO_STRBUF_CTRL_DENAB), - strbuf->strbuf_control); + control = schizo_read(strbuf->strbuf_control); + schizo_write(strbuf->strbuf_control, + (control | SCHIZO_STRBUF_CTRL_DENAB)); for (i = 0; i < 128; i++) { unsigned long val; - val = upa_readq(err_base + (i * 8UL)); - upa_writeq(0UL, err_base + (i * 8UL)); + val = schizo_read(err_base + (i * 8UL)); + schizo_write(err_base + (i * 8UL), 0UL); stc_error_buf[i] = val; } for (i = 0; i < 16; i++) { - stc_tag_buf[i] = upa_readq(tag_base + (i * 8UL)); - stc_line_buf[i] = upa_readq(line_base + (i * 8UL)); - upa_writeq(0UL, tag_base + (i * 8UL)); - upa_writeq(0UL, line_base + (i * 8UL)); + stc_tag_buf[i] = schizo_read(tag_base + (i * 8UL)); + stc_line_buf[i] = schizo_read(line_base + (i * 8UL)); + schizo_write(tag_base + (i * 8UL), 0UL); + schizo_write(line_base + (i * 8UL), 0UL); } /* OK, state is logged, exit diagnostic mode. */ - upa_writeq(control, strbuf->strbuf_control); + schizo_write(strbuf->strbuf_control, control); for (i = 0; i < 16; i++) { int j, saw_error, first, last; @@ -241,14 +258,14 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm, int i; spin_lock_irqsave(&iommu->lock, flags); - control = upa_readq(iommu->iommu_control); + control = schizo_read(iommu->iommu_control); if (control & SCHIZO_IOMMU_CTRL_XLTEERR) { unsigned long base; char *type_string; /* Clear the error encountered bit. */ control &= ~SCHIZO_IOMMU_CTRL_XLTEERR; - upa_writeq(control, iommu->iommu_control); + schizo_write(iommu->iommu_control, control); switch((control & SCHIZO_IOMMU_CTRL_XLTESTAT) >> 25UL) { case 0: @@ -278,24 +295,24 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm, * get as much diagnostic information to the * console as we can. */ - upa_writeq(control | SCHIZO_IOMMU_CTRL_DENAB, - iommu->iommu_control); + schizo_write(iommu->iommu_control, + control | SCHIZO_IOMMU_CTRL_DENAB); base = pbm->pbm_regs; for (i = 0; i < 16; i++) { iommu_tag[i] = - upa_readq(base + SCHIZO_IOMMU_TAG + (i * 8UL)); + schizo_read(base + SCHIZO_IOMMU_TAG + (i * 8UL)); iommu_data[i] = - upa_readq(base + SCHIZO_IOMMU_DATA + (i * 8UL)); + schizo_read(base + SCHIZO_IOMMU_DATA + (i * 8UL)); /* Now clear out the entry. */ - upa_writeq(0, base + SCHIZO_IOMMU_TAG + (i * 8UL)); - upa_writeq(0, base + SCHIZO_IOMMU_DATA + (i * 8UL)); + schizo_write(base + SCHIZO_IOMMU_TAG + (i * 8UL), 0); + schizo_write(base + SCHIZO_IOMMU_DATA + (i * 8UL), 0); } /* Leave diagnostic mode. */ - upa_writeq(control, iommu->iommu_control); + schizo_write(iommu->iommu_control, control); for (i = 0; i < 16; i++) { unsigned long tag, data; @@ -340,12 +357,11 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm, spin_unlock_irqrestore(&iommu->lock, flags); } -static void schizo_check_iommu_error(struct pci_pbm_info *pbm, +static void schizo_check_iommu_error(struct pci_controller_info *p, enum schizo_error_type type) { - schizo_check_iommu_error_pbm(pbm, type); - if (pbm->sibling) - schizo_check_iommu_error_pbm(pbm->sibling, type); + schizo_check_iommu_error_pbm(&p->pbm_A, type); + schizo_check_iommu_error_pbm(&p->pbm_B, type); } /* Uncorrectable ECC error status gathering. */ @@ -370,13 +386,14 @@ static void schizo_check_iommu_error(struct pci_pbm_info *pbm, static irqreturn_t schizo_ue_intr(int irq, void *dev_id) { struct pci_pbm_info *pbm = dev_id; + struct pci_controller_info *p = pbm->parent; unsigned long afsr_reg = pbm->controller_regs + SCHIZO_UE_AFSR; unsigned long afar_reg = pbm->controller_regs + SCHIZO_UE_AFAR; unsigned long afsr, afar, error_bits; int reported, limit; /* Latch uncorrectable error status. */ - afar = upa_readq(afar_reg); + afar = schizo_read(afar_reg); /* If either of the error pending bits are set in the * AFSR, the error status is being actively updated by @@ -384,7 +401,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id) */ limit = 1000; do { - afsr = upa_readq(afsr_reg); + afsr = schizo_read(afsr_reg); } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit); /* Clear the primary/secondary error status bits. */ @@ -393,7 +410,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id) SCHIZO_UEAFSR_SPIO | SCHIZO_UEAFSR_SDMA); if (!error_bits) return IRQ_NONE; - upa_writeq(error_bits, afsr_reg); + schizo_write(afsr_reg, error_bits); /* Log the error. */ printk("%s: Uncorrectable Error, primary error type[%s]\n", @@ -432,7 +449,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id) printk("]\n"); /* Interrogate IOMMU for error status. */ - schizo_check_iommu_error(pbm, UE_ERR); + schizo_check_iommu_error(p, UE_ERR); return IRQ_HANDLED; } @@ -464,7 +481,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id) int reported, limit; /* Latch error status. */ - afar = upa_readq(afar_reg); + afar = schizo_read(afar_reg); /* If either of the error pending bits are set in the * AFSR, the error status is being actively updated by @@ -472,7 +489,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id) */ limit = 1000; do { - afsr = upa_readq(afsr_reg); + afsr = schizo_read(afsr_reg); } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit); /* Clear primary/secondary error status bits. */ @@ -481,7 +498,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id) SCHIZO_CEAFSR_SPIO | SCHIZO_CEAFSR_SDMA); if (!error_bits) return IRQ_NONE; - upa_writeq(error_bits, afsr_reg); + schizo_write(afsr_reg, error_bits); /* Log the error. */ printk("%s: Correctable Error, primary error type[%s]\n", @@ -583,7 +600,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm) u16 stat; csr_reg = pbm->pbm_regs + SCHIZO_PCI_CTRL; - csr = upa_readq(csr_reg); + csr = schizo_read(csr_reg); csr_error_bits = csr & (SCHIZO_PCICTRL_BUS_UNUS | SCHIZO_PCICTRL_TTO_ERR | @@ -593,7 +610,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm) SCHIZO_PCICTRL_SERR); if (csr_error_bits) { /* Clear the errors. */ - upa_writeq(csr, csr_reg); + schizo_write(csr_reg, csr); /* Log 'em. */ if (csr_error_bits & SCHIZO_PCICTRL_BUS_UNUS) @@ -633,6 +650,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm) static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id) { struct pci_pbm_info *pbm = dev_id; + struct pci_controller_info *p = pbm->parent; unsigned long afsr_reg, afar_reg, base; unsigned long afsr, afar, error_bits; int reported; @@ -643,8 +661,8 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id) afar_reg = base + SCHIZO_PCI_AFAR; /* Latch error status. */ - afar = upa_readq(afar_reg); - afsr = upa_readq(afsr_reg); + afar = schizo_read(afar_reg); + afsr = schizo_read(afsr_reg); /* Clear primary/secondary error status bits. */ error_bits = afsr & @@ -656,7 +674,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id) SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS); if (!error_bits) return schizo_pcierr_intr_other(pbm); - upa_writeq(error_bits, afsr_reg); + schizo_write(afsr_reg, error_bits); /* Log the error. */ printk("%s: PCI Error, primary error type[%s]\n", @@ -726,7 +744,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id) * a bug in the IOMMU support code or a PCI device driver. */ if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) { - schizo_check_iommu_error(pbm, PCI_ERR); + schizo_check_iommu_error(p, PCI_ERR); pci_scan_for_target_abort(pbm, pbm->pci_bus); } if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA)) @@ -787,11 +805,12 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id) static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id) { struct pci_pbm_info *pbm = dev_id; + struct pci_controller_info *p = pbm->parent; u64 errlog; - errlog = upa_readq(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG); - upa_writeq(errlog & ~(SAFARI_ERRLOG_ERROUT), - pbm->controller_regs + SCHIZO_SAFARI_ERRLOG); + errlog = schizo_read(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG); + schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG, + errlog & ~(SAFARI_ERRLOG_ERROUT)); if (!(errlog & BUS_ERROR_UNMAP)) { printk("%s: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n", @@ -802,7 +821,7 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id) printk("%s: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n", pbm->name); - schizo_check_iommu_error(pbm, SAFARI_ERR); + schizo_check_iommu_error(p, SAFARI_ERR); return IRQ_HANDLED; } @@ -844,7 +863,7 @@ static int pbm_routes_this_ino(struct pci_pbm_info *pbm, u32 ino) */ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm) { - struct of_device *op = of_find_device_by_node(pbm->op->node); + struct of_device *op = of_find_device_by_node(pbm->prom_node); u64 tmp, err_mask, err_no_mask; int err; @@ -891,9 +910,10 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm) } /* Enable UE and CE interrupts for controller. */ - upa_writeq((SCHIZO_ECCCTRL_EE | - SCHIZO_ECCCTRL_UE | - SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL); + schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL, + (SCHIZO_ECCCTRL_EE | + SCHIZO_ECCCTRL_UE | + SCHIZO_ECCCTRL_CE)); /* Enable PCI Error interrupts and clear error * bits. @@ -906,10 +926,10 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm) err_no_mask = SCHIZO_PCICTRL_DTO_ERR; - tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL); + tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL); tmp |= err_mask; tmp &= ~err_no_mask; - upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL); + schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp); err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | @@ -918,7 +938,7 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm) SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | SCHIZO_PCIAFSR_STTO); - upa_writeq(err_mask, pbm->pbm_regs + SCHIZO_PCI_AFSR); + schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR, err_mask); err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR | BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD | @@ -930,16 +950,16 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm) BUS_ERROR_APERR | BUS_ERROR_UNMAP | BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT); - upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask), - pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL); + schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL, + (SCHIZO_SAFERRCTRL_EN | err_mask)); - upa_writeq((SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)), - pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL); + schizo_write(pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL, + (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP))); } static void schizo_register_error_handlers(struct pci_pbm_info *pbm) { - struct of_device *op = of_find_device_by_node(pbm->op->node); + struct of_device *op = of_find_device_by_node(pbm->prom_node); u64 tmp, err_mask, err_no_mask; int err; @@ -986,9 +1006,10 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm) } /* Enable UE and CE interrupts for controller. */ - upa_writeq((SCHIZO_ECCCTRL_EE | - SCHIZO_ECCCTRL_UE | - SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL); + schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL, + (SCHIZO_ECCCTRL_EE | + SCHIZO_ECCCTRL_UE | + SCHIZO_ECCCTRL_CE)); err_mask = (SCHIZO_PCICTRL_BUS_UNUS | SCHIZO_PCICTRL_ESLCK | @@ -1004,18 +1025,18 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm) /* Enable PCI Error interrupts and clear error * bits for each PBM. */ - tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL); + tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL); tmp |= err_mask; tmp &= ~err_no_mask; - upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL); + schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp); - upa_writeq((SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | - SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | - SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS | - SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA | - SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | - SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS), - pbm->pbm_regs + SCHIZO_PCI_AFSR); + schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR, + (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | + SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | + SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS | + SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA | + SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | + SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS)); /* Make all Safari error conditions fatal except unmapped * errors which we make generate interrupts. @@ -1042,8 +1063,8 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm) BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB); #endif - upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask), - pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL); + schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL, + (SCHIZO_SAFERRCTRL_EN | err_mask)); } static void pbm_config_busmastering(struct pci_pbm_info *pbm) @@ -1063,15 +1084,14 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm) pci_config_write8(addr, 64); } -static void __devinit schizo_scan_bus(struct pci_pbm_info *pbm, - struct device *parent) +static void __init schizo_scan_bus(struct pci_pbm_info *pbm) { pbm_config_busmastering(pbm); pbm->is_66mhz_capable = - (of_find_property(pbm->op->node, "66mhz-capable", NULL) + (of_find_property(pbm->prom_node, "66mhz-capable", NULL) != NULL); - pbm->pci_bus = pci_scan_one_pbm(pbm, parent); + pbm->pci_bus = pci_scan_one_pbm(pbm); if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) tomatillo_register_error_handlers(pbm); @@ -1113,12 +1133,12 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm) * streaming buffer and leave the rerun-disable * setting however OBP set it. */ - control = upa_readq(pbm->stc.strbuf_control); + control = schizo_read(pbm->stc.strbuf_control); control &= ~(SCHIZO_STRBUF_CTRL_LPTR | SCHIZO_STRBUF_CTRL_LENAB | SCHIZO_STRBUF_CTRL_DENAB); control |= SCHIZO_STRBUF_CTRL_ENAB; - upa_writeq(control, pbm->stc.strbuf_control); + schizo_write(pbm->stc.strbuf_control, control); pbm->stc.strbuf_enabled = 1; } @@ -1130,17 +1150,24 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm) static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm) { - static const u32 vdma_default[] = { 0xc0000000, 0x40000000 }; - unsigned long i, tagbase, database; struct iommu *iommu = pbm->iommu; + unsigned long i, tagbase, database; + struct property *prop; + u32 vdma[2], dma_mask; int tsbsize, err; - const u32 *vdma; - u32 dma_mask; u64 control; - vdma = of_get_property(pbm->op->node, "virtual-dma", NULL); - if (!vdma) - vdma = vdma_default; + prop = of_find_property(pbm->prom_node, "virtual-dma", NULL); + if (prop) { + u32 *val = prop->value; + + vdma[0] = val[0]; + vdma[1] = val[1]; + } else { + /* No property, use default values. */ + vdma[0] = 0xc0000000; + vdma[1] = 0x40000000; + } dma_mask = vdma[0]; switch (vdma[1]) { @@ -1160,9 +1187,9 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm) break; default: - printk(KERN_ERR PFX "Strange virtual-dma size.\n"); - return -EINVAL; - } + prom_printf("SCHIZO: strange virtual-dma size.\n"); + prom_halt(); + }; /* Register addresses, SCHIZO has iommu ctx flushing. */ iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL; @@ -1179,15 +1206,15 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm) /* * Invalidate TLB Entries. */ - control = upa_readq(iommu->iommu_control); + control = schizo_read(iommu->iommu_control); control |= SCHIZO_IOMMU_CTRL_DENAB; - upa_writeq(control, iommu->iommu_control); + schizo_write(iommu->iommu_control, control); tagbase = SCHIZO_IOMMU_TAG, database = SCHIZO_IOMMU_DATA; - for (i = 0; i < 16; i++) { - upa_writeq(0, pbm->pbm_regs + tagbase + (i * 8UL)); - upa_writeq(0, pbm->pbm_regs + database + (i * 8UL)); + for(i = 0; i < 16; i++) { + schizo_write(pbm->pbm_regs + tagbase + (i * 8UL), 0); + schizo_write(pbm->pbm_regs + database + (i * 8UL), 0); } /* Leave diag mode enabled for full-flushing done @@ -1195,14 +1222,12 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm) */ err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask, pbm->numa_node); - if (err) { - printk(KERN_ERR PFX "iommu_table_init() fails with %d\n", err); + if (err) return err; - } - upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase); + schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table)); - control = upa_readq(iommu->iommu_control); + control = schizo_read(iommu->iommu_control); control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ); switch (tsbsize) { case 64: @@ -1211,10 +1236,10 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm) case 128: control |= SCHIZO_IOMMU_TSBSZ_128K; break; - } + }; control |= SCHIZO_IOMMU_CTRL_ENAB; - upa_writeq(control, iommu->iommu_control); + schizo_write(iommu->iommu_control, control); return 0; } @@ -1255,11 +1280,12 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm) static void schizo_pbm_hw_init(struct pci_pbm_info *pbm) { + struct property *prop; u64 tmp; - upa_writeq(5, pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY); + schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5); - tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL); + tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL); /* Enable arbiter for all PCI slots. */ tmp |= 0xff; @@ -1268,7 +1294,8 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm) pbm->chip_version >= 0x2) tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT; - if (!of_find_property(pbm->op->node, "no-bus-parking", NULL)) + prop = of_find_property(pbm->prom_node, "no-bus-parking", NULL); + if (!prop) tmp |= SCHIZO_PCICTRL_PARK; else tmp &= ~SCHIZO_PCICTRL_PARK; @@ -1284,13 +1311,13 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm) SCHIZO_PCICTRL_RDO_PREF | SCHIZO_PCICTRL_RDL_PREF); - upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL); + schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp); - tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_DIAG); + tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_DIAG); tmp &= ~(SCHIZO_PCIDIAG_D_RTRYARB | SCHIZO_PCIDIAG_D_RETRY | SCHIZO_PCIDIAG_D_INTSYNC); - upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_DIAG); + schizo_write(pbm->pbm_regs + SCHIZO_PCI_DIAG, tmp); if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { /* Clear prefetch lengths to workaround a bug in @@ -1302,16 +1329,17 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm) TOMATILLO_IOC_RDONE_CPENAB | TOMATILLO_IOC_RDLINE_CPENAB); - upa_writeq(tmp, pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR); + schizo_write(pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR, + tmp); } } -static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm, - struct of_device *op, u32 portid, - int chip_type) +static int __init schizo_pbm_init(struct pci_controller_info *p, + struct device_node *dp, u32 portid, + int chip_type) { const struct linux_prom64_registers *regs; - struct device_node *dp = op->node; + struct pci_pbm_info *pbm; const char *chipset_name; int is_pbm_a, err; @@ -1344,19 +1372,25 @@ static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm, regs = of_get_property(dp, "reg", NULL); is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000); + if (is_pbm_a) + pbm = &p->pbm_A; + else + pbm = &p->pbm_B; pbm->next = pci_pbm_root; pci_pbm_root = pbm; pbm->numa_node = -1; + pbm->scan_bus = schizo_scan_bus; pbm->pci_ops = &sun4u_pci_ops; pbm->config_space_reg_bits = 8; pbm->index = pci_num_pbms++; pbm->portid = portid; - pbm->op = op; + pbm->parent = p; + pbm->prom_node = dp; pbm->chip_type = chip_type; pbm->chip_version = of_getintprop_default(dp, "version#", 0); @@ -1386,8 +1420,6 @@ static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm, schizo_pbm_strbuf_init(pbm); - schizo_scan_bus(pbm, &op->dev); - return 0; } @@ -1401,104 +1433,62 @@ static inline int portid_compare(u32 x, u32 y, int chip_type) return (x == y); } -static struct pci_pbm_info * __devinit schizo_find_sibling(u32 portid, - int chip_type) +static void __init __schizo_init(struct device_node *dp, char *model_name, + int chip_type) { - struct pci_pbm_info *pbm; - - for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { - if (portid_compare(pbm->portid, portid, chip_type)) - return pbm; - } - return NULL; -} - -static int __devinit __schizo_init(struct of_device *op, unsigned long chip_type) -{ - struct device_node *dp = op->node; + struct pci_controller_info *p; struct pci_pbm_info *pbm; struct iommu *iommu; u32 portid; - int err; portid = of_getintprop_default(dp, "portid", 0xff); - err = -ENOMEM; - pbm = kzalloc(sizeof(*pbm), GFP_KERNEL); - if (!pbm) { - printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n"); - goto out_err; - } - - pbm->sibling = schizo_find_sibling(portid, chip_type); - - iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL); - if (!iommu) { - printk(KERN_ERR PFX "Cannot allocate PBM A iommu.\n"); - goto out_free_pbm; + for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { + if (portid_compare(pbm->portid, portid, chip_type)) { + if (schizo_pbm_init(pbm->parent, dp, + portid, chip_type)) + goto fatal_memory_error; + return; + } } - pbm->iommu = iommu; + p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); + if (!p) + goto fatal_memory_error; - if (schizo_pbm_init(pbm, op, portid, chip_type)) - goto out_free_iommu; + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); + if (!iommu) + goto fatal_memory_error; - if (pbm->sibling) - pbm->sibling->sibling = pbm; + p->pbm_A.iommu = iommu; - dev_set_drvdata(&op->dev, pbm); + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); + if (!iommu) + goto fatal_memory_error; - return 0; + p->pbm_B.iommu = iommu; -out_free_iommu: - kfree(pbm->iommu); + if (schizo_pbm_init(p, dp, portid, chip_type)) + goto fatal_memory_error; -out_free_pbm: - kfree(pbm); + return; -out_err: - return err; +fatal_memory_error: + prom_printf("SCHIZO: Fatal memory allocation error.\n"); + prom_halt(); } -static int __devinit schizo_probe(struct of_device *op, - const struct of_device_id *match) +void __init schizo_init(struct device_node *dp, char *model_name) { - return __schizo_init(op, (unsigned long) match->data); + __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO); } -/* The ordering of this table is very important. Some Tomatillo - * nodes announce that they are compatible with both pci108e,a801 - * and pci108e,8001. So list the chips in reverse chronological - * order. - */ -static struct of_device_id __initdata schizo_match[] = { - { - .name = "pci", - .compatible = "pci108e,a801", - .data = (void *) PBM_CHIP_TYPE_TOMATILLO, - }, - { - .name = "pci", - .compatible = "pci108e,8002", - .data = (void *) PBM_CHIP_TYPE_SCHIZO_PLUS, - }, - { - .name = "pci", - .compatible = "pci108e,8001", - .data = (void *) PBM_CHIP_TYPE_SCHIZO, - }, - {}, -}; - -static struct of_platform_driver schizo_driver = { - .name = DRIVER_NAME, - .match_table = schizo_match, - .probe = schizo_probe, -}; - -static int __init schizo_init(void) +void __init schizo_plus_init(struct device_node *dp, char *model_name) { - return of_register_driver(&schizo_driver, &of_bus_type); + __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS); } -subsys_initcall(schizo_init); +void __init tomatillo_init(struct device_node *dp, char *model_name) +{ + __schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO); +} diff --git a/trunk/arch/sparc64/kernel/pci_sun4v.c b/trunk/arch/sparc64/kernel/pci_sun4v.c index e86c73ec167b..a104c80d319d 100644 --- a/trunk/arch/sparc64/kernel/pci_sun4v.c +++ b/trunk/arch/sparc64/kernel/pci_sun4v.c @@ -13,10 +13,12 @@ #include #include #include -#include #include #include +#include +#include +#include #include #include @@ -25,9 +27,6 @@ #include "pci_sun4v.h" -#define DRIVER_NAME "pci_sun4v" -#define PFX DRIVER_NAME ": " - static unsigned long vpci_major = 1; static unsigned long vpci_minor = 1; @@ -42,7 +41,6 @@ struct iommu_batch { }; static DEFINE_PER_CPU(struct iommu_batch, iommu_batch); -static int iommu_batch_initialized; /* Interrupts must be disabled. */ static inline void iommu_batch_start(struct device *dev, unsigned long prot, unsigned long entry) @@ -544,16 +542,15 @@ static const struct dma_ops sun4v_dma_ops = { .sync_sg_for_cpu = dma_4v_sync_sg_for_cpu, }; -static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm, - struct device *parent) +static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm) { struct property *prop; struct device_node *dp; - dp = pbm->op->node; + dp = pbm->prom_node; prop = of_find_property(dp, "66mhz-capable", NULL); pbm->is_66mhz_capable = (prop != NULL); - pbm->pci_bus = pci_scan_one_pbm(pbm, parent); + pbm->pci_bus = pci_scan_one_pbm(pbm); /* XXX register error interrupt handlers XXX */ } @@ -586,22 +583,29 @@ static unsigned long __init probe_existing_entries(struct pci_pbm_info *pbm, return cnt; } -static int __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) +static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) { - static const u32 vdma_default[] = { 0x80000000, 0x80000000 }; struct iommu *iommu = pbm->iommu; + struct property *prop; unsigned long num_tsb_entries, sz, tsbsize; - u32 dma_mask, dma_offset; - const u32 *vdma; - - vdma = of_get_property(pbm->op->node, "virtual-dma", NULL); - if (!vdma) - vdma = vdma_default; + u32 vdma[2], dma_mask, dma_offset; + + prop = of_find_property(pbm->prom_node, "virtual-dma", NULL); + if (prop) { + u32 *val = prop->value; + + vdma[0] = val[0]; + vdma[1] = val[1]; + } else { + /* No property, use default values. */ + vdma[0] = 0x80000000; + vdma[1] = 0x80000000; + } if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) { - printk(KERN_ERR PFX "Strange virtual-dma[%08x:%08x].\n", - vdma[0], vdma[1]); - return -EINVAL; + prom_printf("PCI-SUN4V: strange virtual-dma[%08x:%08x].\n", + vdma[0], vdma[1]); + prom_halt(); }; dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL); @@ -621,8 +625,8 @@ static int __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) sz = (sz + 7UL) & ~7UL; iommu->arena.map = kzalloc(sz, GFP_KERNEL); if (!iommu->arena.map) { - printk(KERN_ERR PFX "Error, kmalloc(arena.map) failed.\n"); - return -ENOMEM; + prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); + prom_halt(); } iommu->arena.limit = num_tsb_entries; @@ -630,8 +634,6 @@ static int __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) if (sz) printk("%s: Imported %lu TSB entries from OBP\n", pbm->name, sz); - - return 0; } #ifdef CONFIG_PCI_MSI @@ -888,20 +890,29 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm) } #endif /* !(CONFIG_PCI_MSI) */ -static int __init pci_sun4v_pbm_init(struct pci_pbm_info *pbm, - struct of_device *op, u32 devhandle) +static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, + struct device_node *dp, u32 devhandle) { - struct device_node *dp = op->node; - int err; + struct pci_pbm_info *pbm; + + if (devhandle & 0x40) + pbm = &p->pbm_B; + else + pbm = &p->pbm_A; + + pbm->next = pci_pbm_root; + pci_pbm_root = pbm; pbm->numa_node = of_node_to_nid(dp); + pbm->scan_bus = pci_sun4v_scan_bus; pbm->pci_ops = &sun4v_pci_ops; pbm->config_space_reg_bits = 12; pbm->index = pci_num_pbms++; - pbm->op = op; + pbm->parent = p; + pbm->prom_node = dp; pbm->devhandle = devhandle; @@ -913,120 +924,82 @@ static int __init pci_sun4v_pbm_init(struct pci_pbm_info *pbm, pci_determine_mem_io_space(pbm); pci_get_pbm_props(pbm); - - err = pci_sun4v_iommu_init(pbm); - if (err) - return err; - + pci_sun4v_iommu_init(pbm); pci_sun4v_msi_init(pbm); - - pci_sun4v_scan_bus(pbm, &op->dev); - - pbm->next = pci_pbm_root; - pci_pbm_root = pbm; - - return 0; } -static int __devinit pci_sun4v_probe(struct of_device *op, - const struct of_device_id *match) +void __init sun4v_pci_init(struct device_node *dp, char *model_name) { - const struct linux_prom64_registers *regs; static int hvapi_negotiated = 0; + struct pci_controller_info *p; struct pci_pbm_info *pbm; - struct device_node *dp; struct iommu *iommu; + struct property *prop; + struct linux_prom64_registers *regs; u32 devhandle; - int i, err; - - dp = op->node; + int i; if (!hvapi_negotiated++) { - err = sun4v_hvapi_register(HV_GRP_PCI, - vpci_major, - &vpci_minor); + int err = sun4v_hvapi_register(HV_GRP_PCI, + vpci_major, + &vpci_minor); if (err) { - printk(KERN_ERR PFX "Could not register hvapi, " - "err=%d\n", err); - return err; + prom_printf("SUN4V_PCI: Could not register hvapi, " + "err=%d\n", err); + prom_halt(); } - printk(KERN_INFO PFX "Registered hvapi major[%lu] minor[%lu]\n", + printk("SUN4V_PCI: Registered hvapi major[%lu] minor[%lu]\n", vpci_major, vpci_minor); dma_ops = &sun4v_dma_ops; } - regs = of_get_property(dp, "reg", NULL); - err = -ENODEV; - if (!regs) { - printk(KERN_ERR PFX "Could not find config registers\n"); - goto out_err; + prop = of_find_property(dp, "reg", NULL); + if (!prop) { + prom_printf("SUN4V_PCI: Could not find config registers\n"); + prom_halt(); } - devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff; - - err = -ENOMEM; - if (!iommu_batch_initialized) { - for_each_possible_cpu(i) { - unsigned long page = get_zeroed_page(GFP_KERNEL); + regs = prop->value; - if (!page) - goto out_err; + devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff; - per_cpu(iommu_batch, i).pglist = (u64 *) page; + for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { + if (pbm->devhandle == (devhandle ^ 0x40)) { + pci_sun4v_pbm_init(pbm->parent, dp, devhandle); + return; } - iommu_batch_initialized = 1; - } - - pbm = kzalloc(sizeof(*pbm), GFP_KERNEL); - if (!pbm) { - printk(KERN_ERR PFX "Could not allocate pci_pbm_info\n"); - goto out_err; } - iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL); - if (!iommu) { - printk(KERN_ERR PFX "Could not allocate pbm iommu\n"); - goto out_free_controller; - } - - pbm->iommu = iommu; + for_each_possible_cpu(i) { + unsigned long page = get_zeroed_page(GFP_ATOMIC); - err = pci_sun4v_pbm_init(pbm, op, devhandle); - if (err) - goto out_free_iommu; + if (!page) + goto fatal_memory_error; - dev_set_drvdata(&op->dev, pbm); + per_cpu(iommu_batch, i).pglist = (u64 *) page; + } - return 0; + p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); + if (!p) + goto fatal_memory_error; -out_free_iommu: - kfree(pbm->iommu); + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); + if (!iommu) + goto fatal_memory_error; -out_free_controller: - kfree(pbm); + p->pbm_A.iommu = iommu; -out_err: - return err; -} + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); + if (!iommu) + goto fatal_memory_error; -static struct of_device_id __initdata pci_sun4v_match[] = { - { - .name = "pci", - .compatible = "SUNW,sun4v-pci", - }, - {}, -}; + p->pbm_B.iommu = iommu; -static struct of_platform_driver pci_sun4v_driver = { - .name = DRIVER_NAME, - .match_table = pci_sun4v_match, - .probe = pci_sun4v_probe, -}; + pci_sun4v_pbm_init(p, dp, devhandle); + return; -static int __init pci_sun4v_init(void) -{ - return of_register_driver(&pci_sun4v_driver, &of_bus_type); +fatal_memory_error: + prom_printf("SUN4V_PCI: Fatal memory allocation error.\n"); + prom_halt(); } - -subsys_initcall(pci_sun4v_init); diff --git a/trunk/arch/sparc64/kernel/pci_sun4v_asm.S b/trunk/arch/sparc64/kernel/pci_sun4v_asm.S index e606d46c6815..ecb81f389b06 100644 --- a/trunk/arch/sparc64/kernel/pci_sun4v_asm.S +++ b/trunk/arch/sparc64/kernel/pci_sun4v_asm.S @@ -1,9 +1,8 @@ /* pci_sun4v_asm: Hypervisor calls for PCI support. * - * Copyright (C) 2006, 2008 David S. Miller + * Copyright (C) 2006 David S. Miller */ -#include #include /* %o0: devhandle @@ -15,7 +14,8 @@ * returns %o0: -status if status was non-zero, else * %o0: num pages mapped */ -ENTRY(pci_sun4v_iommu_map) + .globl pci_sun4v_iommu_map +pci_sun4v_iommu_map: mov %o5, %g1 mov HV_FAST_PCI_IOMMU_MAP, %o5 ta HV_FAST_TRAP @@ -24,7 +24,6 @@ ENTRY(pci_sun4v_iommu_map) mov %o1, %o0 1: retl nop -ENDPROC(pci_sun4v_iommu_map) /* %o0: devhandle * %o1: tsbid @@ -32,12 +31,12 @@ ENDPROC(pci_sun4v_iommu_map) * * returns %o0: num ttes demapped */ -ENTRY(pci_sun4v_iommu_demap) + .globl pci_sun4v_iommu_demap +pci_sun4v_iommu_demap: mov HV_FAST_PCI_IOMMU_DEMAP, %o5 ta HV_FAST_TRAP retl mov %o1, %o0 -ENDPROC(pci_sun4v_iommu_demap) /* %o0: devhandle * %o1: tsbid @@ -46,7 +45,8 @@ ENDPROC(pci_sun4v_iommu_demap) * * returns %o0: status */ -ENTRY(pci_sun4v_iommu_getmap) + .globl pci_sun4v_iommu_getmap +pci_sun4v_iommu_getmap: mov %o2, %o4 mov HV_FAST_PCI_IOMMU_GETMAP, %o5 ta HV_FAST_TRAP @@ -54,7 +54,6 @@ ENTRY(pci_sun4v_iommu_getmap) stx %o2, [%o3] retl mov %o0, %o0 -ENDPROC(pci_sun4v_iommu_getmap) /* %o0: devhandle * %o1: pci_device @@ -66,14 +65,14 @@ ENDPROC(pci_sun4v_iommu_getmap) * If there is an error, the data will be returned * as all 1's. */ -ENTRY(pci_sun4v_config_get) + .globl pci_sun4v_config_get +pci_sun4v_config_get: mov HV_FAST_PCI_CONFIG_GET, %o5 ta HV_FAST_TRAP brnz,a,pn %o1, 1f mov -1, %o2 1: retl mov %o2, %o0 -ENDPROC(pci_sun4v_config_get) /* %o0: devhandle * %o1: pci_device @@ -86,14 +85,14 @@ ENDPROC(pci_sun4v_config_get) * status will be zero if the operation completed * successfully, else -1 if not */ -ENTRY(pci_sun4v_config_put) + .globl pci_sun4v_config_put +pci_sun4v_config_put: mov HV_FAST_PCI_CONFIG_PUT, %o5 ta HV_FAST_TRAP brnz,a,pn %o1, 1f mov -1, %o1 1: retl mov %o1, %o0 -ENDPROC(pci_sun4v_config_put) /* %o0: devhandle * %o1: msiqid @@ -105,12 +104,12 @@ ENDPROC(pci_sun4v_config_put) * status will be zero if the operation completed * successfully, else -1 if not */ -ENTRY(pci_sun4v_msiq_conf) + .globl pci_sun4v_msiq_conf +pci_sun4v_msiq_conf: mov HV_FAST_PCI_MSIQ_CONF, %o5 ta HV_FAST_TRAP retl mov %o0, %o0 -ENDPROC(pci_sun4v_msiq_conf) /* %o0: devhandle * %o1: msiqid @@ -119,7 +118,8 @@ ENDPROC(pci_sun4v_msiq_conf) * * returns %o0: status */ -ENTRY(pci_sun4v_msiq_info) + .globl pci_sun4v_msiq_info +pci_sun4v_msiq_info: mov %o2, %o4 mov HV_FAST_PCI_MSIQ_INFO, %o5 ta HV_FAST_TRAP @@ -127,7 +127,6 @@ ENTRY(pci_sun4v_msiq_info) stx %o2, [%o3] retl mov %o0, %o0 -ENDPROC(pci_sun4v_msiq_info) /* %o0: devhandle * %o1: msiqid @@ -135,13 +134,13 @@ ENDPROC(pci_sun4v_msiq_info) * * returns %o0: status */ -ENTRY(pci_sun4v_msiq_getvalid) + .globl pci_sun4v_msiq_getvalid +pci_sun4v_msiq_getvalid: mov HV_FAST_PCI_MSIQ_GETVALID, %o5 ta HV_FAST_TRAP stx %o1, [%o2] retl mov %o0, %o0 -ENDPROC(pci_sun4v_msiq_getvalid) /* %o0: devhandle * %o1: msiqid @@ -149,12 +148,12 @@ ENDPROC(pci_sun4v_msiq_getvalid) * * returns %o0: status */ -ENTRY(pci_sun4v_msiq_setvalid) + .globl pci_sun4v_msiq_setvalid +pci_sun4v_msiq_setvalid: mov HV_FAST_PCI_MSIQ_SETVALID, %o5 ta HV_FAST_TRAP retl mov %o0, %o0 -ENDPROC(pci_sun4v_msiq_setvalid) /* %o0: devhandle * %o1: msiqid @@ -162,13 +161,13 @@ ENDPROC(pci_sun4v_msiq_setvalid) * * returns %o0: status */ -ENTRY(pci_sun4v_msiq_getstate) + .globl pci_sun4v_msiq_getstate +pci_sun4v_msiq_getstate: mov HV_FAST_PCI_MSIQ_GETSTATE, %o5 ta HV_FAST_TRAP stx %o1, [%o2] retl mov %o0, %o0 -ENDPROC(pci_sun4v_msiq_getstate) /* %o0: devhandle * %o1: msiqid @@ -176,12 +175,12 @@ ENDPROC(pci_sun4v_msiq_getstate) * * returns %o0: status */ -ENTRY(pci_sun4v_msiq_setstate) + .globl pci_sun4v_msiq_setstate +pci_sun4v_msiq_setstate: mov HV_FAST_PCI_MSIQ_SETSTATE, %o5 ta HV_FAST_TRAP retl mov %o0, %o0 -ENDPROC(pci_sun4v_msiq_setstate) /* %o0: devhandle * %o1: msiqid @@ -189,13 +188,13 @@ ENDPROC(pci_sun4v_msiq_setstate) * * returns %o0: status */ -ENTRY(pci_sun4v_msiq_gethead) + .globl pci_sun4v_msiq_gethead +pci_sun4v_msiq_gethead: mov HV_FAST_PCI_MSIQ_GETHEAD, %o5 ta HV_FAST_TRAP stx %o1, [%o2] retl mov %o0, %o0 -ENDPROC(pci_sun4v_msiq_gethead) /* %o0: devhandle * %o1: msiqid @@ -203,12 +202,12 @@ ENDPROC(pci_sun4v_msiq_gethead) * * returns %o0: status */ -ENTRY(pci_sun4v_msiq_sethead) + .globl pci_sun4v_msiq_sethead +pci_sun4v_msiq_sethead: mov HV_FAST_PCI_MSIQ_SETHEAD, %o5 ta HV_FAST_TRAP retl mov %o0, %o0 -ENDPROC(pci_sun4v_msiq_sethead) /* %o0: devhandle * %o1: msiqid @@ -216,13 +215,13 @@ ENDPROC(pci_sun4v_msiq_sethead) * * returns %o0: status */ -ENTRY(pci_sun4v_msiq_gettail) + .globl pci_sun4v_msiq_gettail +pci_sun4v_msiq_gettail: mov HV_FAST_PCI_MSIQ_GETTAIL, %o5 ta HV_FAST_TRAP stx %o1, [%o2] retl mov %o0, %o0 -ENDPROC(pci_sun4v_msiq_gettail) /* %o0: devhandle * %o1: msinum @@ -230,13 +229,13 @@ ENDPROC(pci_sun4v_msiq_gettail) * * returns %o0: status */ -ENTRY(pci_sun4v_msi_getvalid) + .globl pci_sun4v_msi_getvalid +pci_sun4v_msi_getvalid: mov HV_FAST_PCI_MSI_GETVALID, %o5 ta HV_FAST_TRAP stx %o1, [%o2] retl mov %o0, %o0 -ENDPROC(pci_sun4v_msi_getvalid) /* %o0: devhandle * %o1: msinum @@ -244,12 +243,12 @@ ENDPROC(pci_sun4v_msi_getvalid) * * returns %o0: status */ -ENTRY(pci_sun4v_msi_setvalid) + .globl pci_sun4v_msi_setvalid +pci_sun4v_msi_setvalid: mov HV_FAST_PCI_MSI_SETVALID, %o5 ta HV_FAST_TRAP retl mov %o0, %o0 -ENDPROC(pci_sun4v_msi_setvalid) /* %o0: devhandle * %o1: msinum @@ -257,13 +256,13 @@ ENDPROC(pci_sun4v_msi_setvalid) * * returns %o0: status */ -ENTRY(pci_sun4v_msi_getmsiq) + .globl pci_sun4v_msi_getmsiq +pci_sun4v_msi_getmsiq: mov HV_FAST_PCI_MSI_GETMSIQ, %o5 ta HV_FAST_TRAP stx %o1, [%o2] retl mov %o0, %o0 -ENDPROC(pci_sun4v_msi_getmsiq) /* %o0: devhandle * %o1: msinum @@ -272,12 +271,12 @@ ENDPROC(pci_sun4v_msi_getmsiq) * * returns %o0: status */ -ENTRY(pci_sun4v_msi_setmsiq) + .globl pci_sun4v_msi_setmsiq +pci_sun4v_msi_setmsiq: mov HV_FAST_PCI_MSI_SETMSIQ, %o5 ta HV_FAST_TRAP retl mov %o0, %o0 -ENDPROC(pci_sun4v_msi_setmsiq) /* %o0: devhandle * %o1: msinum @@ -285,13 +284,13 @@ ENDPROC(pci_sun4v_msi_setmsiq) * * returns %o0: status */ -ENTRY(pci_sun4v_msi_getstate) + .globl pci_sun4v_msi_getstate +pci_sun4v_msi_getstate: mov HV_FAST_PCI_MSI_GETSTATE, %o5 ta HV_FAST_TRAP stx %o1, [%o2] retl mov %o0, %o0 -ENDPROC(pci_sun4v_msi_getstate) /* %o0: devhandle * %o1: msinum @@ -299,12 +298,12 @@ ENDPROC(pci_sun4v_msi_getstate) * * returns %o0: status */ -ENTRY(pci_sun4v_msi_setstate) + .globl pci_sun4v_msi_setstate +pci_sun4v_msi_setstate: mov HV_FAST_PCI_MSI_SETSTATE, %o5 ta HV_FAST_TRAP retl mov %o0, %o0 -ENDPROC(pci_sun4v_msi_setstate) /* %o0: devhandle * %o1: msinum @@ -312,13 +311,13 @@ ENDPROC(pci_sun4v_msi_setstate) * * returns %o0: status */ -ENTRY(pci_sun4v_msg_getmsiq) + .globl pci_sun4v_msg_getmsiq +pci_sun4v_msg_getmsiq: mov HV_FAST_PCI_MSG_GETMSIQ, %o5 ta HV_FAST_TRAP stx %o1, [%o2] retl mov %o0, %o0 -ENDPROC(pci_sun4v_msg_getmsiq) /* %o0: devhandle * %o1: msinum @@ -326,12 +325,12 @@ ENDPROC(pci_sun4v_msg_getmsiq) * * returns %o0: status */ -ENTRY(pci_sun4v_msg_setmsiq) + .globl pci_sun4v_msg_setmsiq +pci_sun4v_msg_setmsiq: mov HV_FAST_PCI_MSG_SETMSIQ, %o5 ta HV_FAST_TRAP retl mov %o0, %o0 -ENDPROC(pci_sun4v_msg_setmsiq) /* %o0: devhandle * %o1: msinum @@ -339,13 +338,13 @@ ENDPROC(pci_sun4v_msg_setmsiq) * * returns %o0: status */ -ENTRY(pci_sun4v_msg_getvalid) + .globl pci_sun4v_msg_getvalid +pci_sun4v_msg_getvalid: mov HV_FAST_PCI_MSG_GETVALID, %o5 ta HV_FAST_TRAP stx %o1, [%o2] retl mov %o0, %o0 -ENDPROC(pci_sun4v_msg_getvalid) /* %o0: devhandle * %o1: msinum @@ -353,10 +352,10 @@ ENDPROC(pci_sun4v_msg_getvalid) * * returns %o0: status */ -ENTRY(pci_sun4v_msg_setvalid) + .globl pci_sun4v_msg_setvalid +pci_sun4v_msg_setvalid: mov HV_FAST_PCI_MSG_SETVALID, %o5 ta HV_FAST_TRAP retl mov %o0, %o0 -ENDPROC(pci_sun4v_msg_setvalid) diff --git a/trunk/arch/sparc64/kernel/power.c b/trunk/arch/sparc64/kernel/power.c index 076cad7f9757..3bb987a6d03c 100644 --- a/trunk/arch/sparc64/kernel/power.c +++ b/trunk/arch/sparc64/kernel/power.c @@ -1,17 +1,34 @@ /* power.c: Power management driver. * - * Copyright (C) 1999, 2007, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) */ #include #include #include +#include +#include +#include #include +#include +#include #include #include +#include +#include #include #include +#include +#include + +#include + +/* + * sysctl - toggle power-off restriction for serial console + * systems in machine_power_off() + */ +int scons_pwroff = 1; static void __iomem *power_reg; @@ -23,6 +40,31 @@ static irqreturn_t power_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static void (*poweroff_method)(void) = machine_alt_power_off; + +void machine_power_off(void) +{ + sstate_poweroff(); + if (strcmp(of_console_device->type, "serial") || scons_pwroff) { + if (power_reg) { + /* Both register bits seem to have the + * same effect, so until I figure out + * what the difference is... + */ + writel(AUXIO_PCIO_CPWR_OFF | AUXIO_PCIO_SPWR_OFF, power_reg); + } else { + if (poweroff_method != NULL) { + poweroff_method(); + /* not reached */ + } + } + } + machine_halt(); +} + +void (*pm_power_off)(void) = machine_power_off; +EXPORT_SYMBOL(pm_power_off); + static int __init has_button_interrupt(unsigned int irq, struct device_node *dp) { if (irq == 0xffffffff) @@ -43,6 +85,8 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id printk(KERN_INFO "%s: Control reg at %lx\n", op->node->name, res->start); + poweroff_method = machine_halt; /* able to use the standard halt */ + if (has_button_interrupt(irq, op->node)) { if (request_irq(irq, power_handler, 0, "power", NULL) < 0) @@ -52,7 +96,7 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id return 0; } -static struct of_device_id __initdata power_match[] = { +static struct of_device_id power_match[] = { { .name = "power", }, @@ -67,9 +111,8 @@ static struct of_platform_driver power_driver = { }, }; -static int __init power_init(void) +void __init power_init(void) { - return of_register_driver(&power_driver, &of_platform_bus_type); + of_register_driver(&power_driver, &of_platform_bus_type); + return; } - -device_initcall(power_init); diff --git a/trunk/arch/sparc64/kernel/process.c b/trunk/arch/sparc64/kernel/process.c index d5e2acef9877..15f4178592e7 100644 --- a/trunk/arch/sparc64/kernel/process.c +++ b/trunk/arch/sparc64/kernel/process.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include #include +#include #include #include #include @@ -44,6 +46,8 @@ #include #include #include +#include +#include #include #include #include @@ -111,6 +115,35 @@ void cpu_idle(void) } } +void machine_halt(void) +{ + sstate_halt(); + prom_halt(); + panic("Halt failed!"); +} + +void machine_alt_power_off(void) +{ + sstate_poweroff(); + prom_halt_power_off(); + panic("Power-off failed!"); +} + +void machine_restart(char * cmd) +{ + char *p; + + sstate_reboot(); + p = strchr (reboot_command, '\n'); + if (p) *p = 0; + if (cmd) + prom_reboot(cmd); + if (*reboot_command) + prom_reboot(reboot_command); + prom_reboot(""); + panic("Reboot failed!"); +} + #ifdef CONFIG_COMPAT static void show_regwindow32(struct pt_regs *regs) { @@ -215,6 +248,7 @@ static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs, global_reg_snapshot[this_cpu].o7 = regs->u_regs[UREG_I7]; if (regs->tstate & TSTATE_PRIV) { + struct thread_info *tp = current_thread_info(); struct reg_window *rw; rw = (struct reg_window *) @@ -270,6 +304,7 @@ void __trigger_all_cpu_backtrace(void) for_each_online_cpu(cpu) { struct global_reg_snapshot *gp = &global_reg_snapshot[cpu]; + struct thread_info *tp; __global_reg_poll(gp); diff --git a/trunk/arch/sparc64/kernel/prom.c b/trunk/arch/sparc64/kernel/prom.c index dbba82f9b142..7151513f156e 100644 --- a/trunk/arch/sparc64/kernel/prom.c +++ b/trunk/arch/sparc64/kernel/prom.c @@ -38,7 +38,7 @@ struct device_node *of_find_node_by_phandle(phandle handle) { struct device_node *np; - for (np = allnodes; np; np = np->allnext) + for (np = allnodes; np != 0; np = np->allnext) if (np->node == handle) break; @@ -59,9 +59,6 @@ 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; @@ -85,10 +82,7 @@ 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, name, val, len); - mutex_unlock(&of_set_property_mutex); - err = -EINVAL; if (ret >= 0) { prop->value = new_val; @@ -951,30 +945,22 @@ static void __init irq_trans_init(struct device_node *dp) for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) { struct irq_trans *t = &pci_irq_trans_table[i]; - if (!strcmp(model, t->name)) { - t->init(dp); - return; - } + if (!strcmp(model, t->name)) + return t->init(dp); } } #endif #ifdef CONFIG_SBUS if (!strcmp(dp->name, "sbus") || - !strcmp(dp->name, "sbi")) { - sbus_irq_trans_init(dp); - return; - } + !strcmp(dp->name, "sbi")) + return sbus_irq_trans_init(dp); #endif if (!strcmp(dp->name, "fhc") && - !strcmp(dp->parent->name, "central")) { - central_irq_trans_init(dp); - return; - } + !strcmp(dp->parent->name, "central")) + return central_irq_trans_init(dp); if (!strcmp(dp->name, "virtual-devices") || - !strcmp(dp->name, "niu")) { - sun4v_vdev_irq_trans_init(dp); - return; - } + !strcmp(dp->name, "niu")) + return sun4v_vdev_irq_trans_init(dp); } static int is_root_node(const struct device_node *dp) @@ -1245,49 +1231,32 @@ static void __init __build_path_component(struct device_node *dp, char *tmp_buf) if (parent != NULL) { if (!strcmp(parent->type, "pci") || - !strcmp(parent->type, "pciex")) { - pci_path_component(dp, tmp_buf); - return; - } - if (!strcmp(parent->type, "sbus")) { - sbus_path_component(dp, tmp_buf); - return; - } - if (!strcmp(parent->type, "upa")) { - upa_path_component(dp, tmp_buf); - return; - } - if (!strcmp(parent->type, "ebus")) { - ebus_path_component(dp, tmp_buf); - return; - } + !strcmp(parent->type, "pciex")) + return pci_path_component(dp, tmp_buf); + if (!strcmp(parent->type, "sbus")) + return sbus_path_component(dp, tmp_buf); + if (!strcmp(parent->type, "upa")) + return upa_path_component(dp, tmp_buf); + if (!strcmp(parent->type, "ebus")) + return ebus_path_component(dp, tmp_buf); if (!strcmp(parent->name, "usb") || - !strcmp(parent->name, "hub")) { - usb_path_component(dp, tmp_buf); - return; - } - if (!strcmp(parent->type, "i2c")) { - i2c_path_component(dp, tmp_buf); - return; - } - if (!strcmp(parent->type, "firewire")) { - ieee1394_path_component(dp, tmp_buf); - return; - } - if (!strcmp(parent->type, "virtual-devices")) { - vdev_path_component(dp, tmp_buf); - return; - } + !strcmp(parent->name, "hub")) + return usb_path_component(dp, tmp_buf); + if (!strcmp(parent->type, "i2c")) + return i2c_path_component(dp, tmp_buf); + if (!strcmp(parent->type, "firewire")) + return ieee1394_path_component(dp, tmp_buf); + if (!strcmp(parent->type, "virtual-devices")) + return vdev_path_component(dp, tmp_buf); + /* "isa" is handled with platform naming */ } /* Use platform naming convention. */ - if (tlb_type == hypervisor) { - sun4v_path_component(dp, tmp_buf); - return; - } else { - sun4u_path_component(dp, tmp_buf); - } + if (tlb_type == hypervisor) + return sun4v_path_component(dp, tmp_buf); + else + return sun4u_path_component(dp, tmp_buf); } static char * __init build_path_component(struct device_node *dp) diff --git a/trunk/arch/sparc64/kernel/psycho_common.c b/trunk/arch/sparc64/kernel/psycho_common.c deleted file mode 100644 index 790996428c14..000000000000 --- a/trunk/arch/sparc64/kernel/psycho_common.c +++ /dev/null @@ -1,470 +0,0 @@ -/* psycho_common.c: Code common to PSYCHO and derivative PCI controllers. - * - * Copyright (C) 2008 David S. Miller - */ -#include -#include - -#include - -#include "pci_impl.h" -#include "iommu_common.h" -#include "psycho_common.h" - -#define PSYCHO_STRBUF_CTRL_DENAB 0x0000000000000002UL -#define PSYCHO_STCERR_WRITE 0x0000000000000002UL -#define PSYCHO_STCERR_READ 0x0000000000000001UL -#define PSYCHO_STCTAG_PPN 0x0fffffff00000000UL -#define PSYCHO_STCTAG_VPN 0x00000000ffffe000UL -#define PSYCHO_STCTAG_VALID 0x0000000000000002UL -#define PSYCHO_STCTAG_WRITE 0x0000000000000001UL -#define PSYCHO_STCLINE_LINDX 0x0000000001e00000UL -#define PSYCHO_STCLINE_SPTR 0x00000000001f8000UL -#define PSYCHO_STCLINE_LADDR 0x0000000000007f00UL -#define PSYCHO_STCLINE_EPTR 0x00000000000000fcUL -#define PSYCHO_STCLINE_VALID 0x0000000000000002UL -#define PSYCHO_STCLINE_FOFN 0x0000000000000001UL - -static DEFINE_SPINLOCK(stc_buf_lock); -static unsigned long stc_error_buf[128]; -static unsigned long stc_tag_buf[16]; -static unsigned long stc_line_buf[16]; - -static void psycho_check_stc_error(struct pci_pbm_info *pbm) -{ - unsigned long err_base, tag_base, line_base; - struct strbuf *strbuf = &pbm->stc; - u64 control; - int i; - - if (!strbuf->strbuf_control) - return; - - err_base = strbuf->strbuf_err_stat; - tag_base = strbuf->strbuf_tag_diag; - line_base = strbuf->strbuf_line_diag; - - spin_lock(&stc_buf_lock); - - /* This is __REALLY__ dangerous. When we put the streaming - * buffer into diagnostic mode to probe it's tags and error - * status, we _must_ clear all of the line tag valid bits - * before re-enabling the streaming buffer. If any dirty data - * lives in the STC when we do this, we will end up - * invalidating it before it has a chance to reach main - * memory. - */ - control = upa_readq(strbuf->strbuf_control); - upa_writeq(control | PSYCHO_STRBUF_CTRL_DENAB, strbuf->strbuf_control); - for (i = 0; i < 128; i++) { - u64 val; - - val = upa_readq(err_base + (i * 8UL)); - upa_writeq(0UL, err_base + (i * 8UL)); - stc_error_buf[i] = val; - } - for (i = 0; i < 16; i++) { - stc_tag_buf[i] = upa_readq(tag_base + (i * 8UL)); - stc_line_buf[i] = upa_readq(line_base + (i * 8UL)); - upa_writeq(0UL, tag_base + (i * 8UL)); - upa_writeq(0UL, line_base + (i * 8UL)); - } - - /* OK, state is logged, exit diagnostic mode. */ - upa_writeq(control, strbuf->strbuf_control); - - for (i = 0; i < 16; i++) { - int j, saw_error, first, last; - - saw_error = 0; - first = i * 8; - last = first + 8; - for (j = first; j < last; j++) { - u64 errval = stc_error_buf[j]; - if (errval != 0) { - saw_error++; - printk(KERN_ERR "%s: STC_ERR(%d)[wr(%d)" - "rd(%d)]\n", - pbm->name, - j, - (errval & PSYCHO_STCERR_WRITE) ? 1 : 0, - (errval & PSYCHO_STCERR_READ) ? 1 : 0); - } - } - if (saw_error != 0) { - u64 tagval = stc_tag_buf[i]; - u64 lineval = stc_line_buf[i]; - printk(KERN_ERR "%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)" - "V(%d)W(%d)]\n", - pbm->name, - i, - ((tagval & PSYCHO_STCTAG_PPN) >> 19UL), - (tagval & PSYCHO_STCTAG_VPN), - ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0), - ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0)); - printk(KERN_ERR "%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)" - "LADDR(%lx)EP(%lx)V(%d)FOFN(%d)]\n", - pbm->name, - i, - ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL), - ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL), - ((lineval & PSYCHO_STCLINE_LADDR) >> 8UL), - ((lineval & PSYCHO_STCLINE_EPTR) >> 2UL), - ((lineval & PSYCHO_STCLINE_VALID) ? 1 : 0), - ((lineval & PSYCHO_STCLINE_FOFN) ? 1 : 0)); - } - } - - spin_unlock(&stc_buf_lock); -} - -#define PSYCHO_IOMMU_TAG 0xa580UL -#define PSYCHO_IOMMU_DATA 0xa600UL - -static void psycho_record_iommu_tags_and_data(struct pci_pbm_info *pbm, - u64 *tag, u64 *data) -{ - int i; - - for (i = 0; i < 16; i++) { - unsigned long base = pbm->controller_regs; - unsigned long off = i * 8UL; - - tag[i] = upa_readq(base + PSYCHO_IOMMU_TAG+off); - data[i] = upa_readq(base + PSYCHO_IOMMU_DATA+off); - - /* Now clear out the entry. */ - upa_writeq(0, base + PSYCHO_IOMMU_TAG + off); - upa_writeq(0, base + PSYCHO_IOMMU_DATA + off); - } -} - -#define PSYCHO_IOMMU_TAG_ERRSTS (0x3UL << 23UL) -#define PSYCHO_IOMMU_TAG_ERR (0x1UL << 22UL) -#define PSYCHO_IOMMU_TAG_WRITE (0x1UL << 21UL) -#define PSYCHO_IOMMU_TAG_STREAM (0x1UL << 20UL) -#define PSYCHO_IOMMU_TAG_SIZE (0x1UL << 19UL) -#define PSYCHO_IOMMU_TAG_VPAGE 0x7ffffUL -#define PSYCHO_IOMMU_DATA_VALID (1UL << 30UL) -#define PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL) -#define PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL - -static void psycho_dump_iommu_tags_and_data(struct pci_pbm_info *pbm, - u64 *tag, u64 *data) -{ - int i; - - for (i = 0; i < 16; i++) { - u64 tag_val, data_val; - const char *type_str; - tag_val = tag[i]; - if (!(tag_val & PSYCHO_IOMMU_TAG_ERR)) - continue; - - data_val = data[i]; - switch((tag_val & PSYCHO_IOMMU_TAG_ERRSTS) >> 23UL) { - case 0: - type_str = "Protection Error"; - break; - case 1: - type_str = "Invalid Error"; - break; - case 2: - type_str = "TimeOut Error"; - break; - case 3: - default: - type_str = "ECC Error"; - break; - } - - printk(KERN_ERR "%s: IOMMU TAG(%d)[error(%s) wr(%d) " - "str(%d) sz(%dK) vpg(%08lx)]\n", - pbm->name, i, type_str, - ((tag_val & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0), - ((tag_val & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0), - ((tag_val & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8), - (tag_val & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT); - printk(KERN_ERR "%s: IOMMU DATA(%d)[valid(%d) cache(%d) " - "ppg(%016lx)]\n", - pbm->name, i, - ((data_val & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0), - ((data_val & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0), - (data_val & PSYCHO_IOMMU_DATA_PPAGE)<iommu; - unsigned long flags; - - spin_lock_irqsave(&iommu->lock, flags); - control = upa_readq(iommu->iommu_control); - if (control & PSYCHO_IOMMU_CTRL_XLTEERR) { - const char *type_str; - - control &= ~PSYCHO_IOMMU_CTRL_XLTEERR; - upa_writeq(control, iommu->iommu_control); - - switch ((control & PSYCHO_IOMMU_CTRL_XLTESTAT) >> 25UL) { - case 0: - type_str = "Protection Error"; - break; - case 1: - type_str = "Invalid Error"; - break; - case 2: - type_str = "TimeOut Error"; - break; - case 3: - default: - type_str = "ECC Error"; - break; - }; - printk(KERN_ERR "%s: IOMMU Error, type[%s]\n", - pbm->name, type_str); - - /* It is very possible for another DVMA to occur while - * we do this probe, and corrupt the system further. - * But we are so screwed at this point that we are - * likely to crash hard anyways, so get as much - * diagnostic information to the console as we can. - */ - psycho_record_iommu_tags_and_data(pbm, iommu_tag, iommu_data); - psycho_dump_iommu_tags_and_data(pbm, iommu_tag, iommu_data); - } - psycho_check_stc_error(pbm); - spin_unlock_irqrestore(&iommu->lock, flags); -} - -#define PSYCHO_PCICTRL_SBH_ERR 0x0000000800000000UL -#define PSYCHO_PCICTRL_SERR 0x0000000400000000UL - -static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm) -{ - irqreturn_t ret = IRQ_NONE; - u64 csr, csr_error_bits; - u16 stat, *addr; - - csr = upa_readq(pbm->pci_csr); - csr_error_bits = csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR); - if (csr_error_bits) { - /* Clear the errors. */ - upa_writeq(csr, pbm->pci_csr); - - /* Log 'em. */ - if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR) - printk(KERN_ERR "%s: PCI streaming byte hole " - "error asserted.\n", pbm->name); - if (csr_error_bits & PSYCHO_PCICTRL_SERR) - printk(KERN_ERR "%s: PCI SERR signal asserted.\n", - pbm->name); - ret = IRQ_HANDLED; - } - addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno, - 0, PCI_STATUS); - pci_config_read16(addr, &stat); - if (stat & (PCI_STATUS_PARITY | - PCI_STATUS_SIG_TARGET_ABORT | - PCI_STATUS_REC_TARGET_ABORT | - PCI_STATUS_REC_MASTER_ABORT | - PCI_STATUS_SIG_SYSTEM_ERROR)) { - printk(KERN_ERR "%s: PCI bus error, PCI_STATUS[%04x]\n", - pbm->name, stat); - pci_config_write16(addr, 0xffff); - ret = IRQ_HANDLED; - } - return ret; -} - -#define PSYCHO_PCIAFSR_PMA 0x8000000000000000UL -#define PSYCHO_PCIAFSR_PTA 0x4000000000000000UL -#define PSYCHO_PCIAFSR_PRTRY 0x2000000000000000UL -#define PSYCHO_PCIAFSR_PPERR 0x1000000000000000UL -#define PSYCHO_PCIAFSR_SMA 0x0800000000000000UL -#define PSYCHO_PCIAFSR_STA 0x0400000000000000UL -#define PSYCHO_PCIAFSR_SRTRY 0x0200000000000000UL -#define PSYCHO_PCIAFSR_SPERR 0x0100000000000000UL -#define PSYCHO_PCIAFSR_RESV1 0x00ff000000000000UL -#define PSYCHO_PCIAFSR_BMSK 0x0000ffff00000000UL -#define PSYCHO_PCIAFSR_BLK 0x0000000080000000UL -#define PSYCHO_PCIAFSR_RESV2 0x0000000040000000UL -#define PSYCHO_PCIAFSR_MID 0x000000003e000000UL -#define PSYCHO_PCIAFSR_RESV3 0x0000000001ffffffUL - -irqreturn_t psycho_pcierr_intr(int irq, void *dev_id) -{ - struct pci_pbm_info *pbm = dev_id; - u64 afsr, afar, error_bits; - int reported; - - afsr = upa_readq(pbm->pci_afsr); - afar = upa_readq(pbm->pci_afar); - error_bits = afsr & - (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA | - PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR | - PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA | - PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR); - if (!error_bits) - return psycho_pcierr_intr_other(pbm); - upa_writeq(error_bits, pbm->pci_afsr); - printk(KERN_ERR "%s: PCI Error, primary error type[%s]\n", - pbm->name, - (((error_bits & PSYCHO_PCIAFSR_PMA) ? - "Master Abort" : - ((error_bits & PSYCHO_PCIAFSR_PTA) ? - "Target Abort" : - ((error_bits & PSYCHO_PCIAFSR_PRTRY) ? - "Excessive Retries" : - ((error_bits & PSYCHO_PCIAFSR_PPERR) ? - "Parity Error" : "???")))))); - printk(KERN_ERR "%s: bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n", - pbm->name, - (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL, - (afsr & PSYCHO_PCIAFSR_MID) >> 25UL, - (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0); - printk(KERN_ERR "%s: PCI AFAR [%016lx]\n", pbm->name, afar); - printk(KERN_ERR "%s: PCI Secondary errors [", pbm->name); - reported = 0; - if (afsr & PSYCHO_PCIAFSR_SMA) { - reported++; - printk("(Master Abort)"); - } - if (afsr & PSYCHO_PCIAFSR_STA) { - reported++; - printk("(Target Abort)"); - } - if (afsr & PSYCHO_PCIAFSR_SRTRY) { - reported++; - printk("(Excessive Retries)"); - } - if (afsr & PSYCHO_PCIAFSR_SPERR) { - reported++; - printk("(Parity Error)"); - } - if (!reported) - printk("(none)"); - printk("]\n"); - - if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) { - psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR); - pci_scan_for_target_abort(pbm, pbm->pci_bus); - } - if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA)) - pci_scan_for_master_abort(pbm, pbm->pci_bus); - - if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR)) - pci_scan_for_parity_error(pbm, pbm->pci_bus); - - return IRQ_HANDLED; -} - -static void psycho_iommu_flush(struct pci_pbm_info *pbm) -{ - int i; - - for (i = 0; i < 16; i++) { - unsigned long off = i * 8; - - upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_TAG + off); - upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_DATA + off); - } -} - -#define PSYCHO_IOMMU_CONTROL 0x0200UL -#define PSYCHO_IOMMU_CTRL_TSBSZ 0x0000000000070000UL -#define PSYCHO_IOMMU_TSBSZ_1K 0x0000000000000000UL -#define PSYCHO_IOMMU_TSBSZ_2K 0x0000000000010000UL -#define PSYCHO_IOMMU_TSBSZ_4K 0x0000000000020000UL -#define PSYCHO_IOMMU_TSBSZ_8K 0x0000000000030000UL -#define PSYCHO_IOMMU_TSBSZ_16K 0x0000000000040000UL -#define PSYCHO_IOMMU_TSBSZ_32K 0x0000000000050000UL -#define PSYCHO_IOMMU_TSBSZ_64K 0x0000000000060000UL -#define PSYCHO_IOMMU_TSBSZ_128K 0x0000000000070000UL -#define PSYCHO_IOMMU_CTRL_TBWSZ 0x0000000000000004UL -#define PSYCHO_IOMMU_CTRL_DENAB 0x0000000000000002UL -#define PSYCHO_IOMMU_CTRL_ENAB 0x0000000000000001UL -#define PSYCHO_IOMMU_FLUSH 0x0210UL -#define PSYCHO_IOMMU_TSBBASE 0x0208UL - -int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize, - u32 dvma_offset, u32 dma_mask, - unsigned long write_complete_offset) -{ - struct iommu *iommu = pbm->iommu; - u64 control; - int err; - - iommu->iommu_control = pbm->controller_regs + PSYCHO_IOMMU_CONTROL; - iommu->iommu_tsbbase = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE; - iommu->iommu_flush = pbm->controller_regs + PSYCHO_IOMMU_FLUSH; - iommu->iommu_tags = pbm->controller_regs + PSYCHO_IOMMU_TAG; - iommu->write_complete_reg = (pbm->controller_regs + - write_complete_offset); - - iommu->iommu_ctxflush = 0; - - control = upa_readq(iommu->iommu_control); - control |= PSYCHO_IOMMU_CTRL_DENAB; - upa_writeq(control, iommu->iommu_control); - - psycho_iommu_flush(pbm); - - /* Leave diag mode enabled for full-flushing done in pci_iommu.c */ - err = iommu_table_init(iommu, tsbsize * 1024 * 8, - dvma_offset, dma_mask, pbm->numa_node); - if (err) - return err; - - upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase); - - control = upa_readq(iommu->iommu_control); - control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ); - control |= PSYCHO_IOMMU_CTRL_ENAB; - - switch (tsbsize) { - case 64: - control |= PSYCHO_IOMMU_TSBSZ_64K; - break; - case 128: - control |= PSYCHO_IOMMU_TSBSZ_128K; - break; - default: - return -EINVAL; - } - - upa_writeq(control, iommu->iommu_control); - - return 0; - -} - -void psycho_pbm_init_common(struct pci_pbm_info *pbm, struct of_device *op, - const char *chip_name, int chip_type) -{ - struct device_node *dp = op->node; - - pbm->name = dp->full_name; - pbm->numa_node = -1; - pbm->chip_type = chip_type; - pbm->chip_version = of_getintprop_default(dp, "version#", 0); - pbm->chip_revision = of_getintprop_default(dp, "module-revision#", 0); - pbm->op = op; - pbm->pci_ops = &sun4u_pci_ops; - pbm->config_space_reg_bits = 8; - pbm->index = pci_num_pbms++; - pci_get_pbm_props(pbm); - pci_determine_mem_io_space(pbm); - - printk(KERN_INFO "%s: %s PCI Bus Module ver[%x:%x]\n", - pbm->name, chip_name, - pbm->chip_version, pbm->chip_revision); -} diff --git a/trunk/arch/sparc64/kernel/psycho_common.h b/trunk/arch/sparc64/kernel/psycho_common.h deleted file mode 100644 index 092c278ef28d..000000000000 --- a/trunk/arch/sparc64/kernel/psycho_common.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _PSYCHO_COMMON_H -#define _PSYCHO_COMMON_H - -/* U2P Programmer's Manual, page 13-55, configuration space - * address format: - * - * 32 24 23 16 15 11 10 8 7 2 1 0 - * --------------------------------------------------------- - * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 | - * --------------------------------------------------------- - */ -#define PSYCHO_CONFIG_BASE(PBM) \ - ((PBM)->config_space | (1UL << 24)) -#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG) \ - (((unsigned long)(BUS) << 16) | \ - ((unsigned long)(DEVFN) << 8) | \ - ((unsigned long)(REG))) - -static inline void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm, - unsigned char bus, - unsigned int devfn, - int where) -{ - return (void *) - (PSYCHO_CONFIG_BASE(pbm) | - PSYCHO_CONFIG_ENCODE(bus, devfn, where)); -} - -enum psycho_error_type { - UE_ERR, CE_ERR, PCI_ERR -}; - -extern void psycho_check_iommu_error(struct pci_pbm_info *pbm, - unsigned long afsr, - unsigned long afar, - enum psycho_error_type type); - -extern irqreturn_t psycho_pcierr_intr(int irq, void *dev_id); - -extern int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize, - u32 dvma_offset, u32 dma_mask, - unsigned long write_complete_offset); - -extern void psycho_pbm_init_common(struct pci_pbm_info *pbm, - struct of_device *op, - const char *chip_name, int chip_type); - -#endif /* _PSYCHO_COMMON_H */ diff --git a/trunk/arch/sparc64/kernel/ptrace.c b/trunk/arch/sparc64/kernel/ptrace.c index f43adbc773ca..10306e476e38 100644 --- a/trunk/arch/sparc64/kernel/ptrace.c +++ b/trunk/arch/sparc64/kernel/ptrace.c @@ -1050,17 +1050,31 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return ret; } -asmlinkage int syscall_trace_enter(struct pt_regs *regs) +asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p) { int ret = 0; /* do the secure computing check first */ secure_computing(regs->u_regs[UREG_G1]); - if (test_thread_flag(TIF_SYSCALL_TRACE)) - ret = tracehook_report_syscall_entry(regs); + if (unlikely(current->audit_context) && syscall_exit_p) { + unsigned long tstate = regs->tstate; + int result = AUDITSC_SUCCESS; + + if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) + result = AUDITSC_FAILURE; + + audit_syscall_exit(result, regs->u_regs[UREG_I0]); + } + + if (test_thread_flag(TIF_SYSCALL_TRACE)) { + if (syscall_exit_p) + tracehook_report_syscall_exit(regs, 0); + else + ret = tracehook_report_syscall_entry(regs); + } - if (unlikely(current->audit_context) && !ret) + if (unlikely(current->audit_context) && !syscall_exit_p && !ret) audit_syscall_entry((test_thread_flag(TIF_32BIT) ? AUDIT_ARCH_SPARC : AUDIT_ARCH_SPARC64), @@ -1072,19 +1086,3 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs) return ret; } - -asmlinkage void syscall_trace_leave(struct pt_regs *regs) -{ - if (unlikely(current->audit_context)) { - unsigned long tstate = regs->tstate; - int result = AUDITSC_SUCCESS; - - if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) - result = AUDITSC_FAILURE; - - audit_syscall_exit(result, regs->u_regs[UREG_I0]); - } - - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(regs, 0); -} diff --git a/trunk/arch/sparc64/kernel/reboot.c b/trunk/arch/sparc64/kernel/reboot.c deleted file mode 100644 index ef89d3d69748..000000000000 --- a/trunk/arch/sparc64/kernel/reboot.c +++ /dev/null @@ -1,53 +0,0 @@ -/* reboot.c: reboot/shutdown/halt/poweroff handling - * - * Copyright (C) 2008 David S. Miller - */ -#include -#include -#include -#include - -#include -#include -#include - -/* sysctl - toggle power-off restriction for serial console - * systems in machine_power_off() - */ -int scons_pwroff = 1; - -/* This isn't actually used, it exists merely to satisfy the - * reference in kernel/sys.c - */ -void (*pm_power_off)(void) = machine_power_off; -EXPORT_SYMBOL(pm_power_off); - -void machine_power_off(void) -{ - if (strcmp(of_console_device->type, "serial") || scons_pwroff) - prom_halt_power_off(); - - prom_halt(); -} - -void machine_halt(void) -{ - prom_halt(); - panic("Halt failed!"); -} - -void machine_restart(char *cmd) -{ - char *p; - - p = strchr(reboot_command, '\n'); - if (p) - *p = 0; - if (cmd) - prom_reboot(cmd); - if (*reboot_command) - prom_reboot(reboot_command); - prom_reboot(""); - panic("Reboot failed!"); -} - diff --git a/trunk/arch/sparc64/kernel/sbus.c b/trunk/arch/sparc64/kernel/sbus.c index 2ead310066d1..e33a8a660e9e 100644 --- a/trunk/arch/sparc64/kernel/sbus.c +++ b/trunk/arch/sparc64/kernel/sbus.c @@ -11,17 +11,15 @@ #include #include #include -#include -#include #include +#include #include #include #include #include #include #include -#include #include #include "iommu_common.h" @@ -54,23 +52,13 @@ #define STRBUF_TAG_VALID 0x02UL /* Enable 64-bit DVMA mode for the given device. */ -void sbus_set_sbus64(struct device *dev, int bursts) +void sbus_set_sbus64(struct sbus_dev *sdev, int bursts) { - struct iommu *iommu = dev->archdata.iommu; - struct of_device *op = to_of_device(dev); - const struct linux_prom_registers *regs; + struct iommu *iommu = sdev->ofdev.dev.archdata.iommu; + int slot = sdev->slot; unsigned long cfg_reg; - int slot; u64 val; - regs = of_get_property(op->node, "reg", NULL); - if (!regs) { - printk(KERN_ERR "sbus_set_sbus64: Cannot find regs for %s\n", - op->node->full_name); - return; - } - slot = regs->which_io; - cfg_reg = iommu->write_complete_reg; switch (slot) { case 0: @@ -203,9 +191,10 @@ static unsigned long sysio_imap_to_iclr(unsigned long imap) return imap + diff; } -static unsigned int sbus_build_irq(struct of_device *op, unsigned int ino) +unsigned int sbus_build_irq(void *buscookie, unsigned int ino) { - struct iommu *iommu = op->dev.archdata.iommu; + struct sbus_bus *sbus = (struct sbus_bus *)buscookie; + struct iommu *iommu = sbus->ofdev.dev.archdata.iommu; unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; unsigned long imap, iclr; int sbus_level = 0; @@ -266,12 +255,12 @@ static unsigned int sbus_build_irq(struct of_device *op, unsigned int ino) #define SYSIO_UEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */ static irqreturn_t sysio_ue_handler(int irq, void *dev_id) { - struct of_device *op = dev_id; - struct iommu *iommu = op->dev.archdata.iommu; + struct sbus_bus *sbus = dev_id; + struct iommu *iommu = sbus->ofdev.dev.archdata.iommu; unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; unsigned long afsr_reg, afar_reg; unsigned long afsr, afar, error_bits; - int reported, portid; + int reported; afsr_reg = reg_base + SYSIO_UE_AFSR; afar_reg = reg_base + SYSIO_UE_AFAR; @@ -286,11 +275,9 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id) SYSIO_UEAFSR_SPIO | SYSIO_UEAFSR_SDRD | SYSIO_UEAFSR_SDWR); upa_writeq(error_bits, afsr_reg); - portid = of_getintprop_default(op->node, "portid", -1); - /* Log the error. */ printk("SYSIO[%x]: Uncorrectable ECC Error, primary error type[%s]\n", - portid, + sbus->portid, (((error_bits & SYSIO_UEAFSR_PPIO) ? "PIO" : ((error_bits & SYSIO_UEAFSR_PDRD) ? @@ -298,12 +285,12 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id) ((error_bits & SYSIO_UEAFSR_PDWR) ? "DVMA Write" : "???"))))); printk("SYSIO[%x]: DOFF[%lx] SIZE[%lx] MID[%lx]\n", - portid, + sbus->portid, (afsr & SYSIO_UEAFSR_DOFF) >> 45UL, (afsr & SYSIO_UEAFSR_SIZE) >> 42UL, (afsr & SYSIO_UEAFSR_MID) >> 37UL); - printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar); - printk("SYSIO[%x]: Secondary UE errors [", portid); + printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar); + printk("SYSIO[%x]: Secondary UE errors [", sbus->portid); reported = 0; if (afsr & SYSIO_UEAFSR_SPIO) { reported++; @@ -340,12 +327,12 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id) #define SYSIO_CEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */ static irqreturn_t sysio_ce_handler(int irq, void *dev_id) { - struct of_device *op = dev_id; - struct iommu *iommu = op->dev.archdata.iommu; + struct sbus_bus *sbus = dev_id; + struct iommu *iommu = sbus->ofdev.dev.archdata.iommu; unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; unsigned long afsr_reg, afar_reg; unsigned long afsr, afar, error_bits; - int reported, portid; + int reported; afsr_reg = reg_base + SYSIO_CE_AFSR; afar_reg = reg_base + SYSIO_CE_AFAR; @@ -360,10 +347,8 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id) SYSIO_CEAFSR_SPIO | SYSIO_CEAFSR_SDRD | SYSIO_CEAFSR_SDWR); upa_writeq(error_bits, afsr_reg); - portid = of_getintprop_default(op->node, "portid", -1); - printk("SYSIO[%x]: Correctable ECC Error, primary error type[%s]\n", - portid, + sbus->portid, (((error_bits & SYSIO_CEAFSR_PPIO) ? "PIO" : ((error_bits & SYSIO_CEAFSR_PDRD) ? @@ -375,14 +360,14 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id) * XXX UDB CE trap handler does... -DaveM */ printk("SYSIO[%x]: DOFF[%lx] ECC Syndrome[%lx] Size[%lx] MID[%lx]\n", - portid, + sbus->portid, (afsr & SYSIO_CEAFSR_DOFF) >> 45UL, (afsr & SYSIO_CEAFSR_ESYND) >> 48UL, (afsr & SYSIO_CEAFSR_SIZE) >> 42UL, (afsr & SYSIO_CEAFSR_MID) >> 37UL); - printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar); + printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar); - printk("SYSIO[%x]: Secondary CE errors [", portid); + printk("SYSIO[%x]: Secondary CE errors [", sbus->portid); reported = 0; if (afsr & SYSIO_CEAFSR_SPIO) { reported++; @@ -419,11 +404,11 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id) #define SYSIO_SBAFSR_RESV3 0x0000001fffffffffUL /* Reserved */ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id) { - struct of_device *op = dev_id; - struct iommu *iommu = op->dev.archdata.iommu; + struct sbus_bus *sbus = dev_id; + struct iommu *iommu = sbus->ofdev.dev.archdata.iommu; unsigned long afsr_reg, afar_reg, reg_base; unsigned long afsr, afar, error_bits; - int reported, portid; + int reported; reg_base = iommu->write_complete_reg - 0x2000UL; afsr_reg = reg_base + SYSIO_SBUS_AFSR; @@ -438,11 +423,9 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id) SYSIO_SBAFSR_SLE | SYSIO_SBAFSR_STO | SYSIO_SBAFSR_SBERR); upa_writeq(error_bits, afsr_reg); - portid = of_getintprop_default(op->node, "portid", -1); - /* Log the error. */ printk("SYSIO[%x]: SBUS Error, primary error type[%s] read(%d)\n", - portid, + sbus->portid, (((error_bits & SYSIO_SBAFSR_PLE) ? "Late PIO Error" : ((error_bits & SYSIO_SBAFSR_PTO) ? @@ -451,11 +434,11 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id) "Error Ack" : "???")))), (afsr & SYSIO_SBAFSR_RD) ? 1 : 0); printk("SYSIO[%x]: size[%lx] MID[%lx]\n", - portid, + sbus->portid, (afsr & SYSIO_SBAFSR_SIZE) >> 42UL, (afsr & SYSIO_SBAFSR_MID) >> 37UL); - printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar); - printk("SYSIO[%x]: Secondary SBUS errors [", portid); + printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar); + printk("SYSIO[%x]: Secondary SBUS errors [", sbus->portid); reported = 0; if (afsr & SYSIO_SBAFSR_SLE) { reported++; @@ -487,37 +470,34 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id) #define SYSIO_CE_INO 0x35 #define SYSIO_SBUSERR_INO 0x36 -static void __init sysio_register_error_handlers(struct of_device *op) +static void __init sysio_register_error_handlers(struct sbus_bus *sbus) { - struct iommu *iommu = op->dev.archdata.iommu; + struct iommu *iommu = sbus->ofdev.dev.archdata.iommu; unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; unsigned int irq; u64 control; - int portid; - - portid = of_getintprop_default(op->node, "portid", -1); - irq = sbus_build_irq(op, SYSIO_UE_INO); + irq = sbus_build_irq(sbus, SYSIO_UE_INO); if (request_irq(irq, sysio_ue_handler, 0, - "SYSIO_UE", op) < 0) { + "SYSIO_UE", sbus) < 0) { prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n", - portid); + sbus->portid); prom_halt(); } - irq = sbus_build_irq(op, SYSIO_CE_INO); + irq = sbus_build_irq(sbus, SYSIO_CE_INO); if (request_irq(irq, sysio_ce_handler, 0, - "SYSIO_CE", op) < 0) { + "SYSIO_CE", sbus) < 0) { prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n", - portid); + sbus->portid); prom_halt(); } - irq = sbus_build_irq(op, SYSIO_SBUSERR_INO); + irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO); if (request_irq(irq, sysio_sbus_error_handler, 0, - "SYSIO_SBERR", op) < 0) { + "SYSIO_SBERR", sbus) < 0) { prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n", - portid); + sbus->portid); prom_halt(); } @@ -533,15 +513,19 @@ static void __init sysio_register_error_handlers(struct of_device *op) } /* Boot time initialization. */ -static void __init sbus_iommu_init(struct of_device *op) +static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) { const struct linux_prom64_registers *pr; - struct device_node *dp = op->node; + struct device_node *dp; struct iommu *iommu; struct strbuf *strbuf; unsigned long regs, reg_base; - int i, portid; u64 control; + int i; + + dp = of_find_node_by_phandle(__node); + + sbus->portid = of_getintprop_default(dp, "upa-portid", -1); pr = of_get_property(dp, "reg", NULL); if (!pr) { @@ -558,9 +542,9 @@ static void __init sbus_iommu_init(struct of_device *op) if (!strbuf) goto fatal_memory_error; - op->dev.archdata.iommu = iommu; - op->dev.archdata.stc = strbuf; - op->dev.archdata.numa_node = -1; + sbus->ofdev.dev.archdata.iommu = iommu; + sbus->ofdev.dev.archdata.stc = strbuf; + sbus->ofdev.dev.archdata.numa_node = -1; reg_base = regs + SYSIO_IOMMUREG_BASE; iommu->iommu_control = reg_base + IOMMU_CONTROL; @@ -588,9 +572,8 @@ static void __init sbus_iommu_init(struct of_device *op) */ iommu->write_complete_reg = regs + 0x2000UL; - portid = of_getintprop_default(op->node, "portid", -1); - printk(KERN_INFO "SYSIO: UPA portID %x, at %016lx\n", - portid, regs); + printk("SYSIO: UPA portID %x, at %016lx\n", + sbus->portid, regs); /* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */ if (iommu_table_init(iommu, IO_TSB_SIZE, MAP_BASE, 0xffffffff, -1)) @@ -648,27 +631,56 @@ static void __init sbus_iommu_init(struct of_device *op) /* Now some Xfire specific grot... */ if (this_is_starfire) - starfire_hookup(portid); + starfire_hookup(sbus->portid); - sysio_register_error_handlers(op); + sysio_register_error_handlers(sbus); return; fatal_memory_error: prom_printf("sbus_iommu_init: Fatal memory allocation error.\n"); } -static int __init sbus_init(void) +void sbus_fill_device_irq(struct sbus_dev *sdev) { - struct device_node *dp; + struct device_node *dp = of_find_node_by_phandle(sdev->prom_node); + const struct linux_prom_irqs *irqs; - for_each_node_by_name(dp, "sbus") { - struct of_device *op = of_find_device_by_node(dp); + irqs = of_get_property(dp, "interrupts", NULL); + if (!irqs) { + sdev->irqs[0] = 0; + sdev->num_irqs = 0; + } else { + unsigned int pri = irqs[0].pri; + + sdev->num_irqs = 1; + if (pri < 0x20) + pri += sdev->slot * 8; - sbus_iommu_init(op); - of_propagate_archdata(op); + sdev->irqs[0] = sbus_build_irq(sdev->bus, pri); } +} +void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus) +{ +} + +void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp) +{ + sbus_iommu_init(dp->node, sbus); +} + +void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp) +{ +} + +int __init sbus_arch_preinit(void) +{ return 0; } -subsys_initcall(sbus_init); +void __init sbus_arch_postinit(void) +{ + extern void firetruck_init(void); + + firetruck_init(); +} diff --git a/trunk/arch/sparc64/kernel/sparc64_ksyms.c b/trunk/arch/sparc64/kernel/sparc64_ksyms.c index 30bba8b0a3b0..0804f71df6cb 100644 --- a/trunk/arch/sparc64/kernel/sparc64_ksyms.c +++ b/trunk/arch/sparc64/kernel/sparc64_ksyms.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -43,8 +44,12 @@ #include #include #ifdef CONFIG_SBUS +#include #include #endif +#ifdef CONFIG_PCI +#include +#endif #include #include #include @@ -63,6 +68,7 @@ extern void *__memscan_zero(void *, size_t); extern void *__memscan_generic(void *, int, size_t); extern int __memcmp(const void *, const void *, __kernel_size_t); extern __kernel_size_t strlen(const char *); +extern void syscall_trace(struct pt_regs *, int); extern void sys_sigsuspend(void); extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg); extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *); @@ -148,12 +154,26 @@ EXPORT_SYMBOL(flush_dcache_page); EXPORT_SYMBOL(__flush_dcache_range); #endif +EXPORT_SYMBOL(mostek_lock); +EXPORT_SYMBOL(mstk48t02_regs); #ifdef CONFIG_SUN_AUXIO EXPORT_SYMBOL(auxio_set_led); EXPORT_SYMBOL(auxio_set_lte); #endif #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); #endif EXPORT_SYMBOL(outsb); EXPORT_SYMBOL(outsw); @@ -162,6 +182,7 @@ EXPORT_SYMBOL(insb); EXPORT_SYMBOL(insw); EXPORT_SYMBOL(insl); #ifdef CONFIG_PCI +EXPORT_SYMBOL(ebus_chain); EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); EXPORT_SYMBOL(pci_map_single); @@ -279,5 +300,3 @@ EXPORT_SYMBOL(xor_niagara_2); EXPORT_SYMBOL(xor_niagara_3); EXPORT_SYMBOL(xor_niagara_4); EXPORT_SYMBOL(xor_niagara_5); - -EXPORT_SYMBOL_GPL(real_hard_smp_processor_id); diff --git a/trunk/arch/sparc64/kernel/sstate.c b/trunk/arch/sparc64/kernel/sstate.c index 8cdbe5946b43..5b6e75b7f052 100644 --- a/trunk/arch/sparc64/kernel/sstate.c +++ b/trunk/arch/sparc64/kernel/sstate.c @@ -1,15 +1,14 @@ /* sstate.c: System soft state support. * - * Copyright (C) 2007, 2008 David S. Miller + * Copyright (C) 2007 David S. Miller */ #include #include -#include #include #include -#include +#include #include #include #include @@ -51,33 +50,30 @@ static const char rebooting_msg[32] __attribute__((aligned(32))) = static const char panicing_msg[32] __attribute__((aligned(32))) = "Linux panicing"; -static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused) +void sstate_booting(void) { - const char *msg; - - switch (type) { - case SYS_DOWN: - default: - msg = rebooting_msg; - break; - - case SYS_HALT: - msg = halting_msg; - break; + do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg); +} - case SYS_POWER_OFF: - msg = poweroff_msg; - break; - } +void sstate_running(void) +{ + do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg); +} - do_set_sstate(HV_SOFT_STATE_TRANSITION, msg); +void sstate_halt(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, halting_msg); +} - return NOTIFY_OK; +void sstate_poweroff(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, poweroff_msg); } -static struct notifier_block sstate_reboot_notifier = { - .notifier_call = sstate_reboot_call, -}; +void sstate_reboot(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, rebooting_msg); +} static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr) { @@ -91,37 +87,18 @@ static struct notifier_block sstate_panic_block = { .priority = INT_MAX, }; -static int __init sstate_init(void) +void __init sun4v_sstate_init(void) { unsigned long major, minor; - if (tlb_type != hypervisor) - return 0; - major = 1; minor = 0; if (sun4v_hvapi_register(HV_GRP_SOFT_STATE, major, &minor)) - return 0; + return; hv_supports_soft_state = 1; prom_sun4v_guest_soft_state(); - - do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg); - atomic_notifier_chain_register(&panic_notifier_list, &sstate_panic_block); - register_reboot_notifier(&sstate_reboot_notifier); - - return 0; } - -core_initcall(sstate_init); - -static int __init sstate_running(void) -{ - do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg); - return 0; -} - -late_initcall(sstate_running); diff --git a/trunk/arch/sparc64/kernel/starfire.c b/trunk/arch/sparc64/kernel/starfire.c index 060d0f3a6151..7461581b3bb9 100644 --- a/trunk/arch/sparc64/kernel/starfire.c +++ b/trunk/arch/sparc64/kernel/starfire.c @@ -28,6 +28,11 @@ void check_if_starfire(void) this_is_starfire = 1; } +void starfire_cpu_setup(void) +{ + /* Currently, nothing to do. */ +} + int starfire_hard_smp_processor_id(void) { return upa_readl(0x1fff40000d0UL); diff --git a/trunk/arch/sparc64/kernel/sys_sparc32.c b/trunk/arch/sparc64/kernel/sys_sparc32.c index 3320c9d0075f..3d118531baff 100644 --- a/trunk/arch/sparc64/kernel/sys_sparc32.c +++ b/trunk/arch/sparc64/kernel/sys_sparc32.c @@ -575,6 +575,14 @@ asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); } +/* These are here just in case some old sparc32 binary calls it. */ +asmlinkage long sys32_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; +} + asmlinkage compat_ssize_t sys32_pread64(unsigned int fd, char __user *ubuf, compat_size_t count, diff --git a/trunk/arch/sparc64/kernel/syscalls.S b/trunk/arch/sparc64/kernel/syscalls.S index 7a6786a71363..a2f24270ed8a 100644 --- a/trunk/arch/sparc64/kernel/syscalls.S +++ b/trunk/arch/sparc64/kernel/syscalls.S @@ -65,8 +65,9 @@ sys32_rt_sigreturn: andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 be,pt %icc, rtrap nop - call syscall_trace_leave - add %sp, PTREGS_OFF, %o0 + add %sp, PTREGS_OFF, %o0 + call syscall_trace + mov 1, %o1 ba,pt %xcc, rtrap nop @@ -158,8 +159,9 @@ linux_sparc_ni_syscall: or %l7, %lo(sys_ni_syscall), %l7 linux_syscall_trace32: - call syscall_trace_enter - add %sp, PTREGS_OFF, %o0 + add %sp, PTREGS_OFF, %o0 + call syscall_trace + clr %o1 brnz,pn %o0, 3f mov -ENOSYS, %o0 srl %i0, 0, %o0 @@ -170,8 +172,9 @@ linux_syscall_trace32: srl %i3, 0, %o3 linux_syscall_trace: - call syscall_trace_enter - add %sp, PTREGS_OFF, %o0 + add %sp, PTREGS_OFF, %o0 + call syscall_trace + clr %o1 brnz,pn %o0, 3f mov -ENOSYS, %o0 mov %i0, %o0 @@ -272,8 +275,9 @@ ret_sys_call: b,pt %xcc, rtrap stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] linux_syscall_trace2: - call syscall_trace_leave - add %sp, PTREGS_OFF, %o0 + add %sp, PTREGS_OFF, %o0 + call syscall_trace + mov 1, %o1 stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC] ba,pt %xcc, rtrap stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] diff --git a/trunk/arch/sparc64/kernel/systbls.S b/trunk/arch/sparc64/kernel/systbls.S index 5daee4b04dd5..0fdbf3ba956e 100644 --- a/trunk/arch/sparc64/kernel/systbls.S +++ b/trunk/arch/sparc64/kernel/systbls.S @@ -23,7 +23,7 @@ sys_call_table32: /*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys32_mknod /*15*/ .word sys_chmod, sys_lchown16, sparc_brk, sys32_perfctr, sys32_lseek /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16 -/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys_pause +/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause /*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice .word sys_chown, sys_sync, sys32_kill, compat_sys_newstat, sys32_sendfile /*40*/ .word compat_sys_newlstat, sys_dup, sys_pipe, compat_sys_times, sys_getuid diff --git a/trunk/arch/sparc64/kernel/time.c b/trunk/arch/sparc64/kernel/time.c index 80d71a5ce1e3..cc16fdcf98af 100644 --- a/trunk/arch/sparc64/kernel/time.c +++ b/trunk/arch/sparc64/kernel/time.c @@ -30,14 +30,13 @@ #include #include #include -#include #include #include #include #include -#include #include +#include #include #include #include @@ -51,7 +50,18 @@ #include "entry.h" +DEFINE_SPINLOCK(mostek_lock); DEFINE_SPINLOCK(rtc_lock); +void __iomem *mstk48t02_regs = NULL; +#ifdef CONFIG_PCI +unsigned long ds1287_regs = 0UL; +static void __iomem *bq4802_regs; +#endif + +static void __iomem *mstk48t08_regs; +static void __iomem *mstk48t59_regs; + +static int set_rtc_mmss(unsigned long); #define TICK_PRIV_BIT (1UL << 63) #define TICKCMP_IRQ_BIT (1UL << 63) @@ -395,167 +405,313 @@ static unsigned long timer_ticks_per_nsec_quotient __read_mostly; int update_persistent_clock(struct timespec now) { - struct rtc_device *rtc = rtc_class_open("rtc0"); - int err = -1; + return set_rtc_mmss(now.tv_sec); +} - if (rtc) { - err = rtc_set_mmss(rtc, now.tv_sec); - rtc_class_close(rtc); +/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ +static void __init kick_start_clock(void) +{ + void __iomem *regs = mstk48t02_regs; + u8 sec, tmp; + int i, count; + + prom_printf("CLOCK: Clock was stopped. Kick start "); + + spin_lock_irq(&mostek_lock); + + /* Turn on the kick start bit to start the oscillator. */ + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + tmp = mostek_read(regs + MOSTEK_SEC); + tmp &= ~MSTK_STOP; + mostek_write(regs + MOSTEK_SEC, tmp); + tmp = mostek_read(regs + MOSTEK_HOUR); + tmp |= MSTK_KICK_START; + mostek_write(regs + MOSTEK_HOUR, tmp); + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + + 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 = MSTK_REG_SEC(regs); + } + prom_printf("\n"); + + spin_lock_irq(&mostek_lock); + + /* Turn off kick start and set a "valid" time and date. */ + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + tmp = mostek_read(regs + MOSTEK_HOUR); + tmp &= ~MSTK_KICK_START; + mostek_write(regs + MOSTEK_HOUR, tmp); + 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); + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + + spin_unlock_irq(&mostek_lock); + + /* Ensure the kick start bit is off. If it isn't, turn it off. */ + while (mostek_read(regs + MOSTEK_HOUR) & MSTK_KICK_START) { + prom_printf("CLOCK: Kick start still on!\n"); + + spin_lock_irq(&mostek_lock); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + + tmp = mostek_read(regs + MOSTEK_HOUR); + tmp &= ~MSTK_KICK_START; + mostek_write(regs + MOSTEK_HOUR, tmp); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + + spin_unlock_irq(&mostek_lock); } - return err; + prom_printf("CLOCK: Kick start procedure successful.\n"); } -unsigned long cmos_regs; -EXPORT_SYMBOL(cmos_regs); +/* Return nonzero if the clock chip battery is low. */ +static int __init has_low_battery(void) +{ + void __iomem *regs = mstk48t02_regs; + u8 data1, data2; -static struct resource rtc_cmos_resource; + spin_lock_irq(&mostek_lock); -static struct platform_device rtc_cmos_device = { - .name = "rtc_cmos", - .id = -1, - .resource = &rtc_cmos_resource, - .num_resources = 1, -}; + data1 = mostek_read(regs + MOSTEK_EEPROM); /* Read some data. */ + mostek_write(regs + MOSTEK_EEPROM, ~data1); /* Write back the complement. */ + data2 = mostek_read(regs + MOSTEK_EEPROM); /* Read back the complement. */ + mostek_write(regs + MOSTEK_EEPROM, data1); /* Restore original value. */ -static int __devinit rtc_probe(struct of_device *op, const struct of_device_id *match) + spin_unlock_irq(&mostek_lock); + + return (data1 == data2); /* Was the write blocked? */ +} + +static void __init mostek_set_system_time(void __iomem *mregs) { - struct resource *r; + unsigned int year, mon, day, hour, min, sec; + u8 tmp; - printk(KERN_INFO "%s: RTC regs at 0x%lx\n", - op->node->full_name, op->resource[0].start); + spin_lock_irq(&mostek_lock); - /* The CMOS RTC driver only accepts IORESOURCE_IO, so cons - * up a fake resource so that the probe works for all cases. - * When the RTC is behind an ISA bus it will have IORESOURCE_IO - * already, whereas when it's behind EBUS is will be IORESOURCE_MEM. - */ + /* Traditional Mostek chip. */ + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp |= MSTK_CREG_READ; + mostek_write(mregs + MOSTEK_CREG, tmp); - r = &rtc_cmos_resource; - r->flags = IORESOURCE_IO; - r->name = op->resource[0].name; - r->start = op->resource[0].start; - r->end = op->resource[0].end; + 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) ); - cmos_regs = op->resource[0].start; - return platform_device_register(&rtc_cmos_device); + 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); + + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_READ; + mostek_write(mregs + MOSTEK_CREG, tmp); + + spin_unlock_irq(&mostek_lock); } -static struct of_device_id __initdata rtc_match[] = { - { - .name = "rtc", - .compatible = "m5819", - }, - { - .name = "rtc", - .compatible = "isa-m5819p", - }, - { - .name = "rtc", - .compatible = "isa-m5823p", - }, - { - .name = "rtc", - .compatible = "ds1287", - }, - {}, -}; +/* Probe for the real time clock chip. */ +static void __init set_system_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + void __iomem *mregs = mstk48t02_regs; +#ifdef CONFIG_PCI + unsigned long dregs = ds1287_regs; + void __iomem *bregs = bq4802_regs; +#else + unsigned long dregs = 0UL; + void __iomem *bregs = 0UL; +#endif -static struct of_platform_driver rtc_driver = { - .match_table = rtc_match, - .probe = rtc_probe, - .driver = { - .name = "rtc", - }, -}; + if (!mregs && !dregs && !bregs) { + prom_printf("Something wrong, clock regs not mapped yet.\n"); + prom_halt(); + } -static struct platform_device rtc_bq4802_device = { - .name = "rtc-bq4802", - .id = -1, - .num_resources = 1, -}; + if (mregs) { + mostek_set_system_time(mregs); + return; + } -static int __devinit bq4802_probe(struct of_device *op, const struct of_device_id *match) -{ + if (bregs) { + unsigned char val = readb(bregs + 0x0e); + unsigned int century; - printk(KERN_INFO "%s: BQ4802 regs at 0x%lx\n", - op->node->full_name, op->resource[0].start); + /* BQ4802 RTC chip. */ - rtc_bq4802_device.resource = &op->resource[0]; - return platform_device_register(&rtc_bq4802_device); -} + writeb(val | 0x08, bregs + 0x0e); -static struct of_device_id __initdata bq4802_match[] = { - { - .name = "rtc", - .compatible = "bq4802", - }, -}; + sec = readb(bregs + 0x00); + min = readb(bregs + 0x02); + hour = readb(bregs + 0x04); + day = readb(bregs + 0x06); + mon = readb(bregs + 0x09); + year = readb(bregs + 0x0a); + century = readb(bregs + 0x0f); -static struct of_platform_driver bq4802_driver = { - .match_table = bq4802_match, - .probe = bq4802_probe, - .driver = { - .name = "bq4802", - }, -}; + writeb(val, bregs + 0x0e); + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + BCD_TO_BIN(century); + + year += (century * 100); + } else { + /* Dallas 12887 RTC chip. */ + + do { + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + } while (sec != CMOS_READ(RTC_SECONDS)); + + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + if ((year += 1900) < 1970) + year += 100; + } -static unsigned char mostek_read_byte(struct device *dev, u32 ofs) + 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); +} + +/* davem suggests we keep this within the 4M locked kernel image */ +static u32 starfire_get_time(void) { - struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; - void __iomem *regs; - unsigned char val; + static char obp_gettod[32]; + static u32 unix_tod; - regs = (void __iomem *) pdev->resource[0].start; - val = readb(regs + ofs); + sprintf(obp_gettod, "h# %08x unix-gettod", + (unsigned int) (long) &unix_tod); + prom_feval(obp_gettod); - /* the year 0 is 1968 */ - if (ofs == pdata->offset + M48T59_YEAR) { - val += 0x68; - if ((val & 0xf) > 9) - val += 6; - } - return val; + return unix_tod; } -static void mostek_write_byte(struct device *dev, u32 ofs, u8 val) +static int starfire_set_time(u32 val) { - struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; - void __iomem *regs; + /* Do nothing, time is set using the service processor + * console on this platform. + */ + return 0; +} - regs = (void __iomem *) pdev->resource[0].start; - 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; +static u32 hypervisor_get_time(void) +{ + unsigned long ret, time; + int retries = 10000; + +retry: + ret = sun4v_tod_get(&time); + if (ret == HV_EOK) + return time; + if (ret == HV_EWOULDBLOCK) { + if (--retries > 0) { + udelay(100); + goto retry; + } + printk(KERN_WARNING "SUN4V: tod_get() timed out.\n"); + return 0; } - writeb(val, regs + ofs); + printk(KERN_WARNING "SUN4V: tod_get() not supported.\n"); + return 0; } -static struct m48t59_plat_data m48t59_data = { - .read_byte = mostek_read_byte, - .write_byte = mostek_write_byte, -}; +static int hypervisor_set_time(u32 secs) +{ + unsigned long ret; + int retries = 10000; + +retry: + ret = sun4v_tod_set(secs); + if (ret == HV_EOK) + return 0; + if (ret == HV_EWOULDBLOCK) { + if (--retries > 0) { + udelay(100); + goto retry; + } + printk(KERN_WARNING "SUN4V: tod_set() timed out.\n"); + return -EAGAIN; + } + printk(KERN_WARNING "SUN4V: tod_set() not supported.\n"); + return -EOPNOTSUPP; +} -static struct platform_device m48t59_rtc = { - .name = "rtc-m48t59", - .id = 0, - .num_resources = 1, - .dev = { - .platform_data = &m48t59_data, - }, -}; +static int __init clock_model_matches(const char *model) +{ + if (strcmp(model, "mk48t02") && + strcmp(model, "mk48t08") && + strcmp(model, "mk48t59") && + strcmp(model, "m5819") && + strcmp(model, "m5819p") && + strcmp(model, "m5823") && + strcmp(model, "ds1287") && + strcmp(model, "bq4802")) + return 0; + + return 1; +} -static int __devinit mostek_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) { struct device_node *dp = op->node; + const char *model = of_get_property(dp, "model", NULL); + const char *compat = of_get_property(dp, "compatible", NULL); + unsigned long size, flags; + void __iomem *regs; + + if (!model) + model = compat; + + if (!model || !clock_model_matches(model)) + return -ENODEV; /* On an Enterprise system there can be multiple mostek clocks. * We should only match the one that is on the central FHC bus. @@ -564,51 +720,88 @@ static int __devinit mostek_probe(struct of_device *op, const struct of_device_i strcmp(dp->parent->parent->name, "central") != 0) return -ENODEV; - printk(KERN_INFO "%s: Mostek regs at 0x%lx\n", - dp->full_name, op->resource[0].start); + size = (op->resource[0].end - op->resource[0].start) + 1; + regs = of_ioremap(&op->resource[0], 0, size, "clock"); + if (!regs) + return -ENOMEM; + +#ifdef CONFIG_PCI + if (!strcmp(model, "ds1287") || + !strcmp(model, "m5819") || + !strcmp(model, "m5819p") || + !strcmp(model, "m5823")) { + ds1287_regs = (unsigned long) regs; + } else if (!strcmp(model, "bq4802")) { + bq4802_regs = regs; + } else +#endif + if (model[5] == '0' && model[6] == '2') { + mstk48t02_regs = regs; + } else if(model[5] == '0' && model[6] == '8') { + mstk48t08_regs = regs; + mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; + } else { + mstk48t59_regs = regs; + mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; + } + + printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, regs); + + local_irq_save(flags); + + if (mstk48t02_regs != NULL) { + /* Report a low battery voltage condition. */ + if (has_low_battery()) + prom_printf("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(); + } + + set_system_time(); + + local_irq_restore(flags); - m48t59_rtc.resource = &op->resource[0]; - return platform_device_register(&m48t59_rtc); + return 0; } -static struct of_device_id __initdata mostek_match[] = { +static struct of_device_id clock_match[] = { { .name = "eeprom", }, + { + .name = "rtc", + }, {}, }; -static struct of_platform_driver mostek_driver = { - .match_table = mostek_match, - .probe = mostek_probe, +static struct of_platform_driver clock_driver = { + .match_table = clock_match, + .probe = clock_probe, .driver = { - .name = "mostek", + .name = "clock", }, }; -static struct platform_device rtc_sun4v_device = { - .name = "rtc-sun4v", - .id = -1, -}; - -static struct platform_device rtc_starfire_device = { - .name = "rtc-starfire", - .id = -1, -}; - static int __init clock_init(void) { - if (this_is_starfire) - return platform_device_register(&rtc_starfire_device); - - if (tlb_type == hypervisor) - return platform_device_register(&rtc_sun4v_device); - - (void) of_register_driver(&rtc_driver, &of_platform_bus_type); - (void) of_register_driver(&mostek_driver, &of_platform_bus_type); - (void) of_register_driver(&bq4802_driver, &of_platform_bus_type); + if (this_is_starfire) { + xtime.tv_sec = starfire_get_time(); + xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); + set_normalized_timespec(&wall_to_monotonic, + -xtime.tv_sec, -xtime.tv_nsec); + return 0; + } + if (tlb_type == hypervisor) { + xtime.tv_sec = hypervisor_get_time(); + xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); + set_normalized_timespec(&wall_to_monotonic, + -xtime.tv_sec, -xtime.tv_nsec); + return 0; + } - return 0; + return of_register_driver(&clock_driver, &of_platform_bus_type); } /* Must be after subsys_initcall() so that busses are probed. Must @@ -621,7 +814,7 @@ fs_initcall(clock_init); static unsigned long sparc64_init_timers(void) { struct device_node *dp; - unsigned long freq; + unsigned long clock; dp = of_find_node_by_path("/"); if (tlb_type == spitfire) { @@ -634,17 +827,17 @@ static unsigned long sparc64_init_timers(void) if (manuf == 0x17 && impl == 0x13) { /* Hummingbird, aka Ultra-IIe */ tick_ops = &hbtick_operations; - freq = of_getintprop_default(dp, "stick-frequency", 0); + clock = of_getintprop_default(dp, "stick-frequency", 0); } else { tick_ops = &tick_operations; - freq = local_cpu_data().clock_tick; + clock = local_cpu_data().clock_tick; } } else { tick_ops = &stick_operations; - freq = of_getintprop_default(dp, "stick-frequency", 0); + clock = of_getintprop_default(dp, "stick-frequency", 0); } - return freq; + return clock; } struct freq_table { @@ -836,16 +1029,16 @@ EXPORT_SYMBOL(udelay); void __init time_init(void) { - unsigned long freq = sparc64_init_timers(); + unsigned long clock = sparc64_init_timers(); - tb_ticks_per_usec = freq / USEC_PER_SEC; + tb_ticks_per_usec = clock / USEC_PER_SEC; timer_ticks_per_nsec_quotient = - clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT); + clocksource_hz2mult(clock, SPARC64_NSEC_PER_CYC_SHIFT); clocksource_tick.name = tick_ops->name; clocksource_tick.mult = - clocksource_hz2mult(freq, + clocksource_hz2mult(clock, clocksource_tick.shift); clocksource_tick.read = tick_ops->get_tick; @@ -856,7 +1049,7 @@ void __init time_init(void) sparc64_clockevent.name = tick_ops->name; - setup_clockevent_multiplier(freq); + setup_clockevent_multiplier(clock); sparc64_clockevent.max_delta_ns = clockevent_delta2ns(0x7fffffffffffffffUL, &sparc64_clockevent); @@ -877,8 +1070,672 @@ unsigned long long sched_clock(void) >> SPARC64_NSEC_PER_CYC_SHIFT; } +static int set_rtc_mmss(unsigned long nowtime) +{ + int real_seconds, real_minutes, chip_minutes; + void __iomem *mregs = mstk48t02_regs; +#ifdef CONFIG_PCI + unsigned long dregs = ds1287_regs; + void __iomem *bregs = bq4802_regs; +#else + unsigned long dregs = 0UL; + void __iomem *bregs = 0UL; +#endif + unsigned long flags; + u8 tmp; + + /* + * Not having a register set can lead to trouble. + * Also starfire doesn't have a tod clock. + */ + if (!mregs && !dregs && !bregs) + return -1; + + if (mregs) { + spin_lock_irqsave(&mostek_lock, flags); + + /* Read the current RTC minutes. */ + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp |= MSTK_CREG_READ; + mostek_write(mregs + MOSTEK_CREG, tmp); + + chip_minutes = MSTK_REG_MIN(mregs); + + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_READ; + mostek_write(mregs + MOSTEK_CREG, tmp); + + /* + * 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 - chip_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - chip_minutes) < 30) { + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(mregs + MOSTEK_CREG, tmp); + + MSTK_SET_REG_SEC(mregs,real_seconds); + MSTK_SET_REG_MIN(mregs,real_minutes); + + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(mregs + MOSTEK_CREG, tmp); + + spin_unlock_irqrestore(&mostek_lock, flags); + + return 0; + } else { + spin_unlock_irqrestore(&mostek_lock, flags); + + return -1; + } + } else if (bregs) { + int retval = 0; + unsigned char val = readb(bregs + 0x0e); + + /* BQ4802 RTC chip. */ + + writeb(val | 0x08, bregs + 0x0e); + + chip_minutes = readb(bregs + 0x02); + BCD_TO_BIN(chip_minutes); + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - chip_minutes) + 15)/30) & 1) + real_minutes += 30; + real_minutes %= 60; + + if (abs(real_minutes - chip_minutes) < 30) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + writeb(real_seconds, bregs + 0x00); + writeb(real_minutes, bregs + 0x02); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + chip_minutes, real_minutes); + retval = -1; + } + + writeb(val, bregs + 0x0e); + + return retval; + } else { + int retval = 0; + unsigned char save_control, save_freq_select; + + /* Stolen from arch/i386/kernel/time.c, see there for + * credits and descriptive comments. + */ + spin_lock_irqsave(&rtc_lock, flags); + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + chip_minutes = CMOS_READ(RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + BCD_TO_BIN(chip_minutes); + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - chip_minutes) + 15)/30) & 1) + real_minutes += 30; + real_minutes %= 60; + + if (abs(real_minutes - chip_minutes) < 30) { + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + } + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + chip_minutes, real_minutes); + retval = -1; + } + + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock_irqrestore(&rtc_lock, flags); + + return retval; + } +} + +#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ +static unsigned char mini_rtc_status; /* bitmapped status byte. */ + +#define FEBRUARY 2 +#define STARTOFTIME 1970 +#define SECDAY 86400L +#define SECYR (SECDAY * 365) +#define leapyear(year) ((year) % 4 == 0 && \ + ((year) % 100 != 0 || (year) % 400 == 0)) +#define days_in_year(a) (leapyear(a) ? 366 : 365) +#define days_in_month(a) (month_days[(a) - 1]) + +static int month_days[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) + */ +static void GregorianDay(struct rtc_time * tm) +{ + int leapsToDate; + int lastYear; + int day; + int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + lastYear = tm->tm_year - 1; + + /* + * Number of leap corrections to apply up to end of last year + */ + leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400; + + /* + * This year is a leap year if it is divisible by 4 except when it is + * divisible by 100 unless it is divisible by 400 + * + * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was + */ + day = tm->tm_mon > 2 && leapyear(tm->tm_year); + + day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + + tm->tm_mday; + + tm->tm_wday = day % 7; +} + +static void to_tm(int tim, struct rtc_time *tm) +{ + register int i; + register long hms, day; + + day = tim / SECDAY; + hms = tim % SECDAY; + + /* Hours, minutes, seconds are easy */ + tm->tm_hour = hms / 3600; + tm->tm_min = (hms % 3600) / 60; + tm->tm_sec = (hms % 3600) % 60; + + /* Number of years in days */ + for (i = STARTOFTIME; day >= days_in_year(i); i++) + day -= days_in_year(i); + tm->tm_year = i; + + /* Number of months in days left */ + if (leapyear(tm->tm_year)) + days_in_month(FEBRUARY) = 29; + for (i = 1; day >= days_in_month(i); i++) + day -= days_in_month(i); + days_in_month(FEBRUARY) = 28; + tm->tm_mon = i; + + /* Days are what is left over (+1) from all that. */ + tm->tm_mday = day + 1; + + /* + * Determine the day of week + */ + GregorianDay(tm); +} + +/* Both Starfire and SUN4V give us seconds since Jan 1st, 1970, + * aka Unix time. So we have to convert to/from rtc_time. + */ +static void starfire_get_rtc_time(struct rtc_time *time) +{ + u32 seconds = starfire_get_time(); + + to_tm(seconds, time); + time->tm_year -= 1900; + time->tm_mon -= 1; +} + +static int starfire_set_rtc_time(struct rtc_time *time) +{ + u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1, + time->tm_mday, time->tm_hour, + time->tm_min, time->tm_sec); + + return starfire_set_time(seconds); +} + +static void hypervisor_get_rtc_time(struct rtc_time *time) +{ + u32 seconds = hypervisor_get_time(); + + to_tm(seconds, time); + time->tm_year -= 1900; + time->tm_mon -= 1; +} + +static int hypervisor_set_rtc_time(struct rtc_time *time) +{ + u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1, + time->tm_mday, time->tm_hour, + time->tm_min, time->tm_sec); + + return hypervisor_set_time(seconds); +} + +#ifdef CONFIG_PCI +static void bq4802_get_rtc_time(struct rtc_time *time) +{ + unsigned char val = readb(bq4802_regs + 0x0e); + unsigned int century; + + writeb(val | 0x08, bq4802_regs + 0x0e); + + time->tm_sec = readb(bq4802_regs + 0x00); + time->tm_min = readb(bq4802_regs + 0x02); + time->tm_hour = readb(bq4802_regs + 0x04); + time->tm_mday = readb(bq4802_regs + 0x06); + time->tm_mon = readb(bq4802_regs + 0x09); + time->tm_year = readb(bq4802_regs + 0x0a); + time->tm_wday = readb(bq4802_regs + 0x08); + century = readb(bq4802_regs + 0x0f); + + writeb(val, bq4802_regs + 0x0e); + + BCD_TO_BIN(time->tm_sec); + BCD_TO_BIN(time->tm_min); + BCD_TO_BIN(time->tm_hour); + BCD_TO_BIN(time->tm_mday); + BCD_TO_BIN(time->tm_mon); + BCD_TO_BIN(time->tm_year); + BCD_TO_BIN(time->tm_wday); + BCD_TO_BIN(century); + + time->tm_year += (century * 100); + time->tm_year -= 1900; + + time->tm_mon--; +} + +static int bq4802_set_rtc_time(struct rtc_time *time) +{ + unsigned char val = readb(bq4802_regs + 0x0e); + unsigned char sec, min, hrs, day, mon, yrs, century; + unsigned int year; + + year = time->tm_year + 1900; + century = year / 100; + yrs = year % 100; + + mon = time->tm_mon + 1; /* tm_mon starts at zero */ + day = time->tm_mday; + hrs = time->tm_hour; + min = time->tm_min; + sec = time->tm_sec; + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + BIN_TO_BCD(century); + + writeb(val | 0x08, bq4802_regs + 0x0e); + + writeb(sec, bq4802_regs + 0x00); + writeb(min, bq4802_regs + 0x02); + writeb(hrs, bq4802_regs + 0x04); + writeb(day, bq4802_regs + 0x06); + writeb(mon, bq4802_regs + 0x09); + writeb(yrs, bq4802_regs + 0x0a); + writeb(century, bq4802_regs + 0x0f); + + writeb(val, bq4802_regs + 0x0e); + + return 0; +} + +static void cmos_get_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned char ctrl; + + rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); + rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); + rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); + rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); + rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); + rtc_tm->tm_year = CMOS_READ(RTC_YEAR); + rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK); + + ctrl = CMOS_READ(RTC_CONTROL); + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BCD_TO_BIN(rtc_tm->tm_sec); + BCD_TO_BIN(rtc_tm->tm_min); + BCD_TO_BIN(rtc_tm->tm_hour); + BCD_TO_BIN(rtc_tm->tm_mday); + BCD_TO_BIN(rtc_tm->tm_mon); + BCD_TO_BIN(rtc_tm->tm_year); + BCD_TO_BIN(rtc_tm->tm_wday); + } + + if (rtc_tm->tm_year <= 69) + rtc_tm->tm_year += 100; + + rtc_tm->tm_mon--; +} + +static int cmos_set_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned char mon, day, hrs, min, sec; + unsigned char save_control, save_freq_select; + unsigned int yrs; + + yrs = rtc_tm->tm_year; + mon = rtc_tm->tm_mon + 1; + day = rtc_tm->tm_mday; + hrs = rtc_tm->tm_hour; + min = rtc_tm->tm_min; + sec = rtc_tm->tm_sec; + + if (yrs >= 100) + yrs -= 100; + + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + } + + save_control = CMOS_READ(RTC_CONTROL); + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DAY_OF_MONTH); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); + + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + return 0; +} +#endif /* CONFIG_PCI */ + +static void mostek_get_rtc_time(struct rtc_time *rtc_tm) +{ + void __iomem *regs = mstk48t02_regs; + u8 tmp; + + spin_lock_irq(&mostek_lock); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_READ; + mostek_write(regs + MOSTEK_CREG, tmp); + + rtc_tm->tm_sec = MSTK_REG_SEC(regs); + rtc_tm->tm_min = MSTK_REG_MIN(regs); + rtc_tm->tm_hour = MSTK_REG_HOUR(regs); + rtc_tm->tm_mday = MSTK_REG_DOM(regs); + rtc_tm->tm_mon = MSTK_REG_MONTH(regs); + rtc_tm->tm_year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) ); + rtc_tm->tm_wday = MSTK_REG_DOW(regs); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_READ; + mostek_write(regs + MOSTEK_CREG, tmp); + + spin_unlock_irq(&mostek_lock); + + rtc_tm->tm_mon--; + rtc_tm->tm_wday--; + rtc_tm->tm_year -= 1900; +} + +static int mostek_set_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned char mon, day, hrs, min, sec, wday; + void __iomem *regs = mstk48t02_regs; + unsigned int yrs; + u8 tmp; + + yrs = rtc_tm->tm_year + 1900; + mon = rtc_tm->tm_mon + 1; + day = rtc_tm->tm_mday; + wday = rtc_tm->tm_wday + 1; + hrs = rtc_tm->tm_hour; + min = rtc_tm->tm_min; + sec = rtc_tm->tm_sec; + + spin_lock_irq(&mostek_lock); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + + MSTK_SET_REG_SEC(regs, sec); + MSTK_SET_REG_MIN(regs, min); + MSTK_SET_REG_HOUR(regs, hrs); + MSTK_SET_REG_DOW(regs, wday); + MSTK_SET_REG_DOM(regs, day); + MSTK_SET_REG_MONTH(regs, mon); + MSTK_SET_REG_YEAR(regs, yrs - MSTK_YEAR_ZERO); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + + spin_unlock_irq(&mostek_lock); + + return 0; +} + +struct mini_rtc_ops { + void (*get_rtc_time)(struct rtc_time *); + int (*set_rtc_time)(struct rtc_time *); +}; + +static struct mini_rtc_ops starfire_rtc_ops = { + .get_rtc_time = starfire_get_rtc_time, + .set_rtc_time = starfire_set_rtc_time, +}; + +static struct mini_rtc_ops hypervisor_rtc_ops = { + .get_rtc_time = hypervisor_get_rtc_time, + .set_rtc_time = hypervisor_set_rtc_time, +}; + +#ifdef CONFIG_PCI +static struct mini_rtc_ops bq4802_rtc_ops = { + .get_rtc_time = bq4802_get_rtc_time, + .set_rtc_time = bq4802_set_rtc_time, +}; + +static struct mini_rtc_ops cmos_rtc_ops = { + .get_rtc_time = cmos_get_rtc_time, + .set_rtc_time = cmos_set_rtc_time, +}; +#endif /* CONFIG_PCI */ + +static struct mini_rtc_ops mostek_rtc_ops = { + .get_rtc_time = mostek_get_rtc_time, + .set_rtc_time = mostek_set_rtc_time, +}; + +static struct mini_rtc_ops *mini_rtc_ops; + +static inline void mini_get_rtc_time(struct rtc_time *time) +{ + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + mini_rtc_ops->get_rtc_time(time); + spin_unlock_irqrestore(&rtc_lock, flags); +} + +static inline int mini_set_rtc_time(struct rtc_time *time) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&rtc_lock, flags); + err = mini_rtc_ops->set_rtc_time(time); + spin_unlock_irqrestore(&rtc_lock, flags); + + return err; +} + +static int mini_rtc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct rtc_time wtime; + void __user *argp = (void __user *)arg; + + switch (cmd) { + + case RTC_PLL_GET: + return -EINVAL; + + case RTC_PLL_SET: + return -EINVAL; + + case RTC_UIE_OFF: /* disable ints from RTC updates. */ + return 0; + + case RTC_UIE_ON: /* enable ints for RTC updates. */ + return -EINVAL; + + case RTC_RD_TIME: /* Read the time/date from RTC */ + /* this doesn't get week-day, who cares */ + memset(&wtime, 0, sizeof(wtime)); + mini_get_rtc_time(&wtime); + + return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0; + + case RTC_SET_TIME: /* Set the RTC */ + { + int year, days; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + if (copy_from_user(&wtime, argp, sizeof(wtime))) + return -EFAULT; + + year = wtime.tm_year + 1900; + days = month_days[wtime.tm_mon] + + ((wtime.tm_mon == 1) && leapyear(year)); + + if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || + (wtime.tm_mday < 1)) + return -EINVAL; + + if (wtime.tm_mday < 0 || wtime.tm_mday > days) + return -EINVAL; + + if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 || + wtime.tm_min < 0 || wtime.tm_min >= 60 || + wtime.tm_sec < 0 || wtime.tm_sec >= 60) + return -EINVAL; + + return mini_set_rtc_time(&wtime); + } + } + + return -EINVAL; +} + +static int mini_rtc_open(struct inode *inode, struct file *file) +{ + lock_kernel(); + if (mini_rtc_status & RTC_IS_OPEN) { + unlock_kernel(); + return -EBUSY; + } + + mini_rtc_status |= RTC_IS_OPEN; + unlock_kernel(); + + return 0; +} + +static int mini_rtc_release(struct inode *inode, struct file *file) +{ + mini_rtc_status &= ~RTC_IS_OPEN; + return 0; +} + + +static const struct file_operations mini_rtc_fops = { + .owner = THIS_MODULE, + .ioctl = mini_rtc_ioctl, + .open = mini_rtc_open, + .release = mini_rtc_release, +}; + +static struct miscdevice rtc_mini_dev = +{ + .minor = RTC_MINOR, + .name = "rtc", + .fops = &mini_rtc_fops, +}; + +static int __init rtc_mini_init(void) +{ + int retval; + + if (tlb_type == hypervisor) + mini_rtc_ops = &hypervisor_rtc_ops; + else if (this_is_starfire) + mini_rtc_ops = &starfire_rtc_ops; +#ifdef CONFIG_PCI + else if (bq4802_regs) + mini_rtc_ops = &bq4802_rtc_ops; + else if (ds1287_regs) + mini_rtc_ops = &cmos_rtc_ops; +#endif /* CONFIG_PCI */ + else if (mstk48t02_regs) + mini_rtc_ops = &mostek_rtc_ops; + else + return -ENODEV; + + printk(KERN_INFO "Mini RTC Driver\n"); + + retval = misc_register(&rtc_mini_dev); + if (retval < 0) + return retval; + + return 0; +} + +static void __exit rtc_mini_exit(void) +{ + misc_deregister(&rtc_mini_dev); +} + int __devinit read_current_timer(unsigned long *timer_val) { *timer_val = tick_ops->get_tick(); return 0; } + +module_init(rtc_mini_init); +module_exit(rtc_mini_exit); diff --git a/trunk/arch/sparc64/kernel/traps.c b/trunk/arch/sparc64/kernel/traps.c index 81ccd22e78d4..c824df13f589 100644 --- a/trunk/arch/sparc64/kernel/traps.c +++ b/trunk/arch/sparc64/kernel/traps.c @@ -38,7 +38,6 @@ #include #include #include -#include #include "entry.h" #include "kstack.h" @@ -130,56 +129,6 @@ void do_BUG(const char *file, int line) } #endif -static DEFINE_SPINLOCK(dimm_handler_lock); -static dimm_printer_t dimm_handler; - -static int sprintf_dimm(int synd_code, unsigned long paddr, char *buf, int buflen) -{ - unsigned long flags; - int ret = -ENODEV; - - spin_lock_irqsave(&dimm_handler_lock, flags); - if (dimm_handler) { - ret = dimm_handler(synd_code, paddr, buf, buflen); - } else if (tlb_type == spitfire) { - if (prom_getunumber(synd_code, paddr, buf, buflen) == -1) - ret = -EINVAL; - else - ret = 0; - } else - ret = -ENODEV; - spin_unlock_irqrestore(&dimm_handler_lock, flags); - - return ret; -} - -int register_dimm_printer(dimm_printer_t func) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&dimm_handler_lock, flags); - if (!dimm_handler) - dimm_handler = func; - else - ret = -EEXIST; - spin_unlock_irqrestore(&dimm_handler_lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(register_dimm_printer); - -void unregister_dimm_printer(dimm_printer_t func) -{ - unsigned long flags; - - spin_lock_irqsave(&dimm_handler_lock, flags); - if (dimm_handler == func) - dimm_handler = NULL; - spin_unlock_irqrestore(&dimm_handler_lock, flags); -} -EXPORT_SYMBOL_GPL(unregister_dimm_printer); - void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) { siginfo_t info; @@ -342,7 +291,10 @@ void sun4v_data_access_exception_tl1(struct pt_regs *regs, unsigned long addr, u } #ifdef CONFIG_PCI -#include "pci_impl.h" +/* This is really pathetic... */ +extern volatile int pci_poke_in_progress; +extern volatile int pci_poke_cpu; +extern volatile int pci_poke_faulted; #endif /* When access exceptions happen, we must do this. */ @@ -424,7 +376,8 @@ static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, un if (udbl & bit) { scode = ecc_syndrome_table[udbl & 0xff]; - if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0) + if (prom_getunumber(scode, afar, + memmod_str, sizeof(memmod_str)) == -1) p = syndrome_unknown; else p = memmod_str; @@ -435,7 +388,8 @@ static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, un if (udbh & bit) { scode = ecc_syndrome_table[udbh & 0xff]; - if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0) + if (prom_getunumber(scode, afar, + memmod_str, sizeof(memmod_str)) == -1) p = syndrome_unknown; else p = memmod_str; @@ -1108,6 +1062,8 @@ static const char *cheetah_get_string(unsigned long bit) return "???"; } +extern int chmc_getunumber(int, unsigned long, char *, int); + static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *info, unsigned long afsr, unsigned long afar, int recoverable) { @@ -1149,7 +1105,7 @@ static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *in syndrome = (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT; syndrome = cheetah_ecc_syntab[syndrome]; - ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum)); + ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum)); if (ret != -1) printk("%s" "ERROR(%d): AFAR E-syndrome [%s]\n", (recoverable ? KERN_WARNING : KERN_CRIT), @@ -1160,7 +1116,7 @@ static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *in syndrome = (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT; syndrome = cheetah_mtag_syntab[syndrome]; - ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum)); + ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum)); if (ret != -1) printk("%s" "ERROR(%d): AFAR M-syndrome [%s]\n", (recoverable ? KERN_WARNING : KERN_CRIT), @@ -2268,6 +2224,7 @@ void die_if_kernel(char *str, struct pt_regs *regs) extern int handle_popc(u32 insn, struct pt_regs *regs); extern int handle_ldf_stq(u32 insn, struct pt_regs *regs); +extern int vis_emul(struct pt_regs *, unsigned int); void do_illegal_instruction(struct pt_regs *regs) { diff --git a/trunk/arch/sparc64/kernel/vio.c b/trunk/arch/sparc64/kernel/vio.c index 92b1f8ec01de..a490077891a4 100644 --- a/trunk/arch/sparc64/kernel/vio.c +++ b/trunk/arch/sparc64/kernel/vio.c @@ -152,7 +152,7 @@ show_pciobppath_attr(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_pciobppath_attr, NULL); -static struct device_node *cdev_node; +struct device_node *cdev_node; static struct vio_dev *root_vdev; static u64 cdev_cfg_handle; @@ -371,9 +371,9 @@ static struct mdesc_notifier_client vio_ds_notifier = { .node_name = "domain-services-port", }; -static const char *channel_devices_node = "channel-devices"; -static const char *channel_devices_compat = "SUNW,sun4v-channel-devices"; -static const char *cfg_handle_prop = "cfg-handle"; +const char *channel_devices_node = "channel-devices"; +const char *channel_devices_compat = "SUNW,sun4v-channel-devices"; +const char *cfg_handle_prop = "cfg-handle"; static int __init vio_init(void) { diff --git a/trunk/arch/sparc64/kernel/visemul.c b/trunk/arch/sparc64/kernel/visemul.c index 9e05cb5cb855..c3fd64706b53 100644 --- a/trunk/arch/sparc64/kernel/visemul.c +++ b/trunk/arch/sparc64/kernel/visemul.c @@ -243,7 +243,7 @@ static inline unsigned int *fps_regaddr(struct fpustate *f, struct edge_tab { u16 left, right; }; -static struct edge_tab edge8_tab[8] = { +struct edge_tab edge8_tab[8] = { { 0xff, 0x80 }, { 0x7f, 0xc0 }, { 0x3f, 0xe0 }, @@ -253,7 +253,7 @@ static struct edge_tab edge8_tab[8] = { { 0x03, 0xfe }, { 0x01, 0xff }, }; -static struct edge_tab edge8_tab_l[8] = { +struct edge_tab edge8_tab_l[8] = { { 0xff, 0x01 }, { 0xfe, 0x03 }, { 0xfc, 0x07 }, @@ -263,23 +263,23 @@ static struct edge_tab edge8_tab_l[8] = { { 0xc0, 0x7f }, { 0x80, 0xff }, }; -static struct edge_tab edge16_tab[4] = { +struct edge_tab edge16_tab[4] = { { 0xf, 0x8 }, { 0x7, 0xc }, { 0x3, 0xe }, { 0x1, 0xf }, }; -static struct edge_tab edge16_tab_l[4] = { +struct edge_tab edge16_tab_l[4] = { { 0xf, 0x1 }, { 0xe, 0x3 }, { 0xc, 0x7 }, { 0x8, 0xf }, }; -static struct edge_tab edge32_tab[2] = { +struct edge_tab edge32_tab[2] = { { 0x3, 0x2 }, { 0x1, 0x3 }, }; -static struct edge_tab edge32_tab_l[2] = { +struct edge_tab edge32_tab_l[2] = { { 0x3, 0x1 }, { 0x2, 0x3 }, }; diff --git a/trunk/arch/sparc64/mm/fault.c b/trunk/arch/sparc64/mm/fault.c index a9e474bf6385..ea7d7ae76bc2 100644 --- a/trunk/arch/sparc64/mm/fault.c +++ b/trunk/arch/sparc64/mm/fault.c @@ -51,6 +51,43 @@ static inline int notify_page_fault(struct pt_regs *regs) } #endif +/* + * To debug kernel to catch accesses to certain virtual/physical addresses. + * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints. + * flags = VM_READ watches memread accesses, flags = VM_WRITE watches memwrite accesses. + * Caller passes in a 64bit aligned addr, with mask set to the bytes that need to be + * watched. This is only useful on a single cpu machine for now. After the watchpoint + * is detected, the process causing it will be killed, thus preventing an infinite loop. + */ +void set_brkpt(unsigned long addr, unsigned char mask, int flags, int mode) +{ + unsigned long lsubits; + + __asm__ __volatile__("ldxa [%%g0] %1, %0" + : "=r" (lsubits) + : "i" (ASI_LSU_CONTROL)); + lsubits &= ~(LSU_CONTROL_PM | LSU_CONTROL_VM | + LSU_CONTROL_PR | LSU_CONTROL_VR | + LSU_CONTROL_PW | LSU_CONTROL_VW); + + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (addr), "r" (mode ? VIRT_WATCHPOINT : PHYS_WATCHPOINT), + "i" (ASI_DMMU)); + + lsubits |= ((unsigned long)mask << (mode ? 25 : 33)); + if (flags & VM_READ) + lsubits |= (mode ? LSU_CONTROL_VR : LSU_CONTROL_PR); + if (flags & VM_WRITE) + lsubits |= (mode ? LSU_CONTROL_VW : LSU_CONTROL_PW); + __asm__ __volatile__("stxa %0, [%%g0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (lsubits), "i" (ASI_LSU_CONTROL) + : "memory"); +} + static void __kprobes unhandled_fault(unsigned long address, struct task_struct *tsk, struct pt_regs *regs) diff --git a/trunk/arch/sparc64/mm/init.c b/trunk/arch/sparc64/mm/init.c index 3c10daf8fc01..a41df7bef035 100644 --- a/trunk/arch/sparc64/mm/init.c +++ b/trunk/arch/sparc64/mm/init.c @@ -46,11 +46,15 @@ #include #include #include +#include #include #include #include -#include "init.h" +#define MAX_PHYS_ADDRESS (1UL << 42UL) +#define KPTE_BITMAP_CHUNK_SZ (256UL * 1024UL * 1024UL) +#define KPTE_BITMAP_BYTES \ + ((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 8) unsigned long kern_linear_pte_xor[2] __read_mostly; @@ -412,9 +416,17 @@ void mmu_info(struct seq_file *m) #endif /* CONFIG_DEBUG_DCFLUSH */ } +struct linux_prom_translation { + unsigned long virt; + unsigned long size; + unsigned long data; +}; + +/* Exported for kernel TLB miss handling in ktlb.S */ struct linux_prom_translation prom_trans[512] __read_mostly; unsigned int prom_trans_ents __read_mostly; +/* Exported for SMP bootup purposes. */ unsigned long kern_locked_tte_data; /* The obp translations are saved based on 8k pagesize, since obp can @@ -926,10 +938,6 @@ int of_node_to_nid(struct device_node *dp) int count, nid; u64 grp; - /* This is the right thing to do on currently supported - * SUN4U NUMA platforms as well, as the PCI controller does - * not sit behind any particular memory controller. - */ if (!mlgroups) return -1; @@ -1198,44 +1206,8 @@ static int __init numa_parse_mdesc(void) return err; } -static int __init numa_parse_jbus(void) -{ - unsigned long cpu, index; - - /* NUMA node id is encoded in bits 36 and higher, and there is - * a 1-to-1 mapping from CPU ID to NUMA node ID. - */ - index = 0; - for_each_present_cpu(cpu) { - numa_cpu_lookup_table[cpu] = index; - numa_cpumask_lookup_table[index] = cpumask_of_cpu(cpu); - node_masks[index].mask = ~((1UL << 36UL) - 1UL); - node_masks[index].val = cpu << 36UL; - - index++; - } - num_node_masks = index; - - add_node_ranges(); - - for (index = 0; index < num_node_masks; index++) { - allocate_node_data(index); - node_set_online(index); - } - - return 0; -} - static int __init numa_parse_sun4u(void) { - if (tlb_type == cheetah || tlb_type == cheetah_plus) { - unsigned long ver; - - __asm__ ("rdpr %%ver, %0" : "=r" (ver)); - if ((ver >> 32UL) == __JALAPENO_ID || - (ver >> 32UL) == __SERRANO_ID) - return numa_parse_jbus(); - } return -1; } @@ -1661,6 +1633,8 @@ void __cpuinit sun4v_ktsb_register(void) /* paging_init() sets up the page tables */ +extern void central_probe(void); + static unsigned long last_valid_pfn; pgd_t swapper_pg_dir[2048]; @@ -1705,6 +1679,8 @@ void __init paging_init(void) kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; kern_size = (unsigned long)&_end - (unsigned long)KERNBASE; + sstate_booting(); + /* Invalidate both kernel TSBs. */ memset(swapper_tsb, 0x40, sizeof(swapper_tsb)); #ifndef CONFIG_DEBUG_PAGEALLOC @@ -1827,6 +1803,9 @@ void __init paging_init(void) } printk("Booting Linux...\n"); + + central_probe(); + cpu_probe(); } int __init page_in_phys_avail(unsigned long paddr) @@ -2053,6 +2032,7 @@ pgprot_t PAGE_COPY __read_mostly; pgprot_t PAGE_SHARED __read_mostly; EXPORT_SYMBOL(PAGE_SHARED); +pgprot_t PAGE_EXEC __read_mostly; unsigned long pg_iobits __read_mostly; unsigned long _PAGE_IE __read_mostly; @@ -2065,6 +2045,14 @@ unsigned long _PAGE_CACHE __read_mostly; EXPORT_SYMBOL(_PAGE_CACHE); #ifdef CONFIG_SPARSEMEM_VMEMMAP + +#define VMEMMAP_CHUNK_SHIFT 22 +#define VMEMMAP_CHUNK (1UL << VMEMMAP_CHUNK_SHIFT) +#define VMEMMAP_CHUNK_MASK ~(VMEMMAP_CHUNK - 1UL) +#define VMEMMAP_ALIGN(x) (((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK) + +#define VMEMMAP_SIZE ((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \ + sizeof(struct page *)) >> VMEMMAP_CHUNK_SHIFT) unsigned long vmemmap_table[VMEMMAP_SIZE]; int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) @@ -2148,6 +2136,7 @@ static void __init sun4u_pgprot_init(void) _PAGE_CACHE_4U | _PAGE_P_4U | __ACCESS_BITS_4U | __DIRTY_BITS_4U | _PAGE_EXEC_4U | _PAGE_L_4U); + PAGE_EXEC = __pgprot(_PAGE_EXEC_4U); _PAGE_IE = _PAGE_IE_4U; _PAGE_E = _PAGE_E_4U; @@ -2158,10 +2147,10 @@ static void __init sun4u_pgprot_init(void) #ifdef CONFIG_DEBUG_PAGEALLOC kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4U) ^ - 0xfffff80000000000UL; + 0xfffff80000000000; #else kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^ - 0xfffff80000000000UL; + 0xfffff80000000000; #endif kern_linear_pte_xor[0] |= (_PAGE_CP_4U | _PAGE_CV_4U | _PAGE_P_4U | _PAGE_W_4U); @@ -2199,6 +2188,7 @@ static void __init sun4v_pgprot_init(void) __ACCESS_BITS_4V | __DIRTY_BITS_4V | _PAGE_EXEC_4V); PAGE_KERNEL_LOCKED = PAGE_KERNEL; + PAGE_EXEC = __pgprot(_PAGE_EXEC_4V); _PAGE_IE = _PAGE_IE_4V; _PAGE_E = _PAGE_E_4V; @@ -2206,20 +2196,20 @@ static void __init sun4v_pgprot_init(void) #ifdef CONFIG_DEBUG_PAGEALLOC kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^ - 0xfffff80000000000UL; + 0xfffff80000000000; #else kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^ - 0xfffff80000000000UL; + 0xfffff80000000000; #endif kern_linear_pte_xor[0] |= (_PAGE_CP_4V | _PAGE_CV_4V | _PAGE_P_4V | _PAGE_W_4V); #ifdef CONFIG_DEBUG_PAGEALLOC kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^ - 0xfffff80000000000UL; + 0xfffff80000000000; #else kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZ256MB_4V) ^ - 0xfffff80000000000UL; + 0xfffff80000000000; #endif kern_linear_pte_xor[1] |= (_PAGE_CP_4V | _PAGE_CV_4V | _PAGE_P_4V | _PAGE_W_4V); diff --git a/trunk/arch/sparc64/mm/init.h b/trunk/arch/sparc64/mm/init.h deleted file mode 100644 index 16063870a489..000000000000 --- a/trunk/arch/sparc64/mm/init.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef _SPARC64_MM_INIT_H -#define _SPARC64_MM_INIT_H - -/* Most of the symbols in this file are defined in init.c and - * marked non-static so that assembler code can get at them. - */ - -#define MAX_PHYS_ADDRESS (1UL << 42UL) -#define KPTE_BITMAP_CHUNK_SZ (256UL * 1024UL * 1024UL) -#define KPTE_BITMAP_BYTES \ - ((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 8) - -extern unsigned long kern_linear_pte_xor[2]; -extern unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)]; -extern unsigned int sparc64_highest_unlocked_tlb_ent; -extern unsigned long sparc64_kern_pri_context; -extern unsigned long sparc64_kern_pri_nuc_bits; -extern unsigned long sparc64_kern_sec_context; -extern void mmu_info(struct seq_file *m); - -struct linux_prom_translation { - unsigned long virt; - unsigned long size; - unsigned long data; -}; - -/* Exported for kernel TLB miss handling in ktlb.S */ -extern struct linux_prom_translation prom_trans[512]; -extern unsigned int prom_trans_ents; - -/* Exported for SMP bootup purposes. */ -extern unsigned long kern_locked_tte_data; - -extern void prom_world(int enter); - -extern void free_initmem(void); - -#ifdef CONFIG_SPARSEMEM_VMEMMAP -#define VMEMMAP_CHUNK_SHIFT 22 -#define VMEMMAP_CHUNK (1UL << VMEMMAP_CHUNK_SHIFT) -#define VMEMMAP_CHUNK_MASK ~(VMEMMAP_CHUNK - 1UL) -#define VMEMMAP_ALIGN(x) (((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK) - -#define VMEMMAP_SIZE ((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \ - sizeof(struct page *)) >> VMEMMAP_CHUNK_SHIFT) -extern unsigned long vmemmap_table[VMEMMAP_SIZE]; -#endif - -#endif /* _SPARC64_MM_INIT_H */ diff --git a/trunk/arch/sparc64/mm/tlb.c b/trunk/arch/sparc64/mm/tlb.c index d8f21e24a82f..ae24919cba7c 100644 --- a/trunk/arch/sparc64/mm/tlb.c +++ b/trunk/arch/sparc64/mm/tlb.c @@ -19,7 +19,7 @@ /* Heavily inspired by the ppc64 code. */ -DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers) = { 0, }; void flush_tlb_pending(void) { diff --git a/trunk/arch/x86/kernel/process_64.c b/trunk/arch/x86/kernel/process_64.c index 2a8ccb9238b4..b6b508ea7110 100644 --- a/trunk/arch/x86/kernel/process_64.c +++ b/trunk/arch/x86/kernel/process_64.c @@ -754,12 +754,12 @@ unsigned long get_wchan(struct task_struct *p) if (!p || p == current || p->state == TASK_RUNNING) return 0; stack = (unsigned long)task_stack_page(p); - if (p->thread.sp < stack || p->thread.sp > stack+THREAD_SIZE) + if (p->thread.sp < stack || p->thread.sp >= stack+THREAD_SIZE) return 0; fp = *(u64 *)(p->thread.sp); do { if (fp < (unsigned long)stack || - fp > (unsigned long)stack+THREAD_SIZE) + fp >= (unsigned long)stack+THREAD_SIZE) return 0; ip = *(u64 *)(fp+8); if (!in_sched_functions(ip)) diff --git a/trunk/drivers/acpi/glue.c b/trunk/drivers/acpi/glue.c index 3c578ef78c48..8dd3336efd7e 100644 --- a/trunk/drivers/acpi/glue.c +++ b/trunk/drivers/acpi/glue.c @@ -369,6 +369,7 @@ static int __init acpi_rtc_init(void) DBG("RTC unavailable?\n"); return 0; } -module_init(acpi_rtc_init); +/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */ +fs_initcall(acpi_rtc_init); #endif diff --git a/trunk/drivers/ata/Kconfig b/trunk/drivers/ata/Kconfig index 78fbec8ceda0..f17cd4b572f8 100644 --- a/trunk/drivers/ata/Kconfig +++ b/trunk/drivers/ata/Kconfig @@ -7,6 +7,7 @@ menuconfig ATA depends on HAS_IOMEM depends on BLOCK depends on !(M32R || M68K) || BROKEN + depends on !SUN4 || BROKEN select SCSI ---help--- If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or diff --git a/trunk/drivers/atm/fore200e.c b/trunk/drivers/atm/fore200e.c index 937c9c0ef4c9..73338d231db9 100644 --- a/trunk/drivers/atm/fore200e.c +++ b/trunk/drivers/atm/fore200e.c @@ -47,9 +47,8 @@ #include #ifdef CONFIG_SBUS -#include -#include #include +#include #include #include #include @@ -662,189 +661,249 @@ fore200e_pca_proc_read(struct fore200e* fore200e, char *page) #ifdef CONFIG_SBUS -static u32 fore200e_sba_read(volatile u32 __iomem *addr) +static u32 +fore200e_sba_read(volatile u32 __iomem *addr) { return sbus_readl(addr); } -static void fore200e_sba_write(u32 val, volatile u32 __iomem *addr) + +static void +fore200e_sba_write(u32 val, volatile u32 __iomem *addr) { sbus_writel(val, addr); } -static u32 fore200e_sba_dma_map(struct fore200e *fore200e, void* virt_addr, int size, int direction) -{ - struct of_device *op = fore200e->bus_dev; - u32 dma_addr; - dma_addr = dma_map_single(&op->dev, virt_addr, size, direction); +static u32 +fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction) +{ + u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size, direction); - DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n", - virt_addr, size, direction, dma_addr); + DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n", + virt_addr, size, direction, dma_addr); - return dma_addr; + return dma_addr; } -static void fore200e_sba_dma_unmap(struct fore200e *fore200e, u32 dma_addr, int size, int direction) -{ - struct of_device *op = fore200e->bus_dev; - DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", - dma_addr, size, direction); +static void +fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction) +{ + DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", + dma_addr, size, direction); - dma_unmap_single(&op->dev, dma_addr, size, direction); + sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction); } -static void fore200e_sba_dma_sync_for_cpu(struct fore200e *fore200e, u32 dma_addr, int size, int direction) -{ - struct of_device *op = fore200e->bus_dev; - DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); +static void +fore200e_sba_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, int direction) +{ + DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - dma_sync_single_for_cpu(&op->dev, dma_addr, size, direction); + sbus_dma_sync_single_for_cpu((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction); } -static void fore200e_sba_dma_sync_for_device(struct fore200e *fore200e, u32 dma_addr, int size, int direction) +static void +fore200e_sba_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int size, int direction) { - struct of_device *op = fore200e->bus_dev; + DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - - dma_sync_single_for_device(&op->dev, dma_addr, size, direction); + sbus_dma_sync_single_for_device((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction); } -/* Allocate a DVMA consistent chunk of memory intended to act as a communication mechanism - * (to hold descriptors, status, queues, etc.) shared by the driver and the adapter. - */ -static int fore200e_sba_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk, - int size, int nbr, int alignment) -{ - struct of_device *op = fore200e->bus_dev; - chunk->alloc_size = chunk->align_size = size * nbr; +/* allocate a DVMA consistent chunk of memory intended to act as a communication mechanism + (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ - /* returned chunks are page-aligned */ - chunk->alloc_addr = dma_alloc_coherent(&op->dev, chunk->alloc_size, - &chunk->dma_addr, GFP_ATOMIC); +static int +fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, + int size, int nbr, int alignment) +{ + chunk->alloc_size = chunk->align_size = size * nbr; - if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0)) - return -ENOMEM; + /* returned chunks are page-aligned */ + chunk->alloc_addr = sbus_alloc_consistent((struct sbus_dev*)fore200e->bus_dev, + chunk->alloc_size, + &chunk->dma_addr); + + if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0)) + return -ENOMEM; - chunk->align_addr = chunk->alloc_addr; + chunk->align_addr = chunk->alloc_addr; - return 0; + return 0; } + /* free a DVMA consistent chunk of memory */ -static void fore200e_sba_dma_chunk_free(struct fore200e *fore200e, struct chunk *chunk) -{ - struct of_device *op = fore200e->bus_dev; - dma_free_coherent(&op->dev, chunk->alloc_size, - chunk->alloc_addr, chunk->dma_addr); +static void +fore200e_sba_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) +{ + sbus_free_consistent((struct sbus_dev*)fore200e->bus_dev, + chunk->alloc_size, + chunk->alloc_addr, + chunk->dma_addr); } -static void fore200e_sba_irq_enable(struct fore200e *fore200e) + +static void +fore200e_sba_irq_enable(struct fore200e* fore200e) { - u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; - fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr); + u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; + fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr); } -static int fore200e_sba_irq_check(struct fore200e *fore200e) + +static int +fore200e_sba_irq_check(struct fore200e* fore200e) { - return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ; + return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ; } -static void fore200e_sba_irq_ack(struct fore200e *fore200e) + +static void +fore200e_sba_irq_ack(struct fore200e* fore200e) { - u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; - fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr); + u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; + fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr); } -static void fore200e_sba_reset(struct fore200e *fore200e) + +static void +fore200e_sba_reset(struct fore200e* fore200e) { - fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr); - fore200e_spin(10); - fore200e->bus->write(0, fore200e->regs.sba.hcr); + fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr); + fore200e_spin(10); + fore200e->bus->write(0, fore200e->regs.sba.hcr); } -static int __init fore200e_sba_map(struct fore200e *fore200e) + +static int __init +fore200e_sba_map(struct fore200e* fore200e) { - struct of_device *op = fore200e->bus_dev; - unsigned int bursts; + struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; + unsigned int bursts; - /* gain access to the SBA specific registers */ - fore200e->regs.sba.hcr = of_ioremap(&op->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR"); - fore200e->regs.sba.bsr = of_ioremap(&op->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR"); - fore200e->regs.sba.isr = of_ioremap(&op->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR"); - fore200e->virt_base = of_ioremap(&op->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM"); + /* gain access to the SBA specific registers */ + fore200e->regs.sba.hcr = sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR"); + fore200e->regs.sba.bsr = sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR"); + fore200e->regs.sba.isr = sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR"); + fore200e->virt_base = sbus_ioremap(&sbus_dev->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM"); - if (!fore200e->virt_base) { - printk(FORE200E "unable to map RAM of device %s\n", fore200e->name); - return -EFAULT; - } + if (fore200e->virt_base == NULL) { + printk(FORE200E "unable to map RAM of device %s\n", fore200e->name); + return -EFAULT; + } - DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); + DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); - fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */ + fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */ - /* get the supported DVMA burst sizes */ - bursts = of_getintprop_default(op->node->parent, "burst-sizes", 0x00); + /* get the supported DVMA burst sizes */ + bursts = prom_getintdefault(sbus_dev->bus->prom_node, "burst-sizes", 0x00); - if (sbus_can_dma_64bit()) - sbus_set_sbus64(&op->dev, bursts); + if (sbus_can_dma_64bit(sbus_dev)) + sbus_set_sbus64(sbus_dev, bursts); - fore200e->state = FORE200E_STATE_MAP; - return 0; + fore200e->state = FORE200E_STATE_MAP; + return 0; } -static void fore200e_sba_unmap(struct fore200e *fore200e) -{ - struct of_device *op = fore200e->bus_dev; - of_iounmap(&op->resource[0], fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH); - of_iounmap(&op->resource[1], fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH); - of_iounmap(&op->resource[2], fore200e->regs.sba.isr, SBA200E_ISR_LENGTH); - of_iounmap(&op->resource[3], fore200e->virt_base, SBA200E_RAM_LENGTH); +static void +fore200e_sba_unmap(struct fore200e* fore200e) +{ + sbus_iounmap(fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH); + sbus_iounmap(fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH); + sbus_iounmap(fore200e->regs.sba.isr, SBA200E_ISR_LENGTH); + sbus_iounmap(fore200e->virt_base, SBA200E_RAM_LENGTH); } -static int __init fore200e_sba_configure(struct fore200e *fore200e) + +static int __init +fore200e_sba_configure(struct fore200e* fore200e) { - fore200e->state = FORE200E_STATE_CONFIGURE; - return 0; + fore200e->state = FORE200E_STATE_CONFIGURE; + return 0; } -static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_data *prom) + +static struct fore200e* __init +fore200e_sba_detect(const struct fore200e_bus* bus, int index) { - struct of_device *op = fore200e->bus_dev; - const u8 *prop; - int len; + struct fore200e* fore200e; + struct sbus_bus* sbus_bus; + struct sbus_dev* sbus_dev = NULL; + + unsigned int count = 0; + + for_each_sbus (sbus_bus) { + for_each_sbusdev (sbus_dev, sbus_bus) { + if (strcmp(sbus_dev->prom_name, SBA200E_PROM_NAME) == 0) { + if (count >= index) + goto found; + count++; + } + } + } + return NULL; + + found: + if (sbus_dev->num_registers != 4) { + printk(FORE200E "this %s device has %d instead of 4 registers\n", + bus->model_name, sbus_dev->num_registers); + return NULL; + } + + fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL); + if (fore200e == NULL) + return NULL; - prop = of_get_property(op->node, "madaddrlo2", &len); - if (!prop) - return -ENODEV; - memcpy(&prom->mac_addr[4], prop, 4); + fore200e->bus = bus; + fore200e->bus_dev = sbus_dev; + fore200e->irq = sbus_dev->irqs[ 0 ]; - prop = of_get_property(op->node, "madaddrhi4", &len); - if (!prop) - return -ENODEV; - memcpy(&prom->mac_addr[2], prop, 4); + fore200e->phys_base = (unsigned long)sbus_dev; - prom->serial_number = of_getintprop_default(op->node, "serialnumber", 0); - prom->hw_revision = of_getintprop_default(op->node, "promversion", 0); + sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); - return 0; + return fore200e; } -static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page) + +static int __init +fore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom) { - struct of_device *op = fore200e->bus_dev; - const struct linux_prom_registers *regs; + struct sbus_dev* sbus_dev = (struct sbus_dev*) fore200e->bus_dev; + int len; + + len = prom_getproperty(sbus_dev->prom_node, "macaddrlo2", &prom->mac_addr[ 4 ], 4); + if (len < 0) + return -EBUSY; + + len = prom_getproperty(sbus_dev->prom_node, "macaddrhi4", &prom->mac_addr[ 2 ], 4); + if (len < 0) + return -EBUSY; + + prom_getproperty(sbus_dev->prom_node, "serialnumber", + (char*)&prom->serial_number, sizeof(prom->serial_number)); + + prom_getproperty(sbus_dev->prom_node, "promversion", + (char*)&prom->hw_revision, sizeof(prom->hw_revision)); + + return 0; +} - regs = of_get_property(op->node, "reg", NULL); - return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", - (regs ? regs->which_io : 0), op->node->name); +static int +fore200e_sba_proc_read(struct fore200e* fore200e, char *page) +{ + struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; + + return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name); } #endif /* CONFIG_SBUS */ @@ -2513,7 +2572,7 @@ fore200e_load_and_start_fw(struct fore200e* fore200e) device = &((struct pci_dev *) fore200e->bus_dev)->dev; #ifdef CONFIG_SBUS else if (strcmp(fore200e->bus->model_name, "SBA-200E") == 0) - device = &((struct of_device *) fore200e->bus_dev)->dev; + device = &((struct sbus_dev *) fore200e->bus_dev)->ofdev.dev; #endif else return err; @@ -2642,66 +2701,6 @@ fore200e_init(struct fore200e* fore200e) return 0; } -#ifdef CONFIG_SBUS -static int __devinit fore200e_sba_probe(struct of_device *op, - const struct of_device_id *match) -{ - const struct fore200e_bus *bus = match->data; - struct fore200e *fore200e; - static int index = 0; - int err; - - fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL); - if (!fore200e) - return -ENOMEM; - - fore200e->bus = bus; - fore200e->bus_dev = op; - fore200e->irq = op->irqs[0]; - fore200e->phys_base = op->resource[0].start; - - sprintf(fore200e->name, "%s-%d", bus->model_name, index); - - err = fore200e_init(fore200e); - if (err < 0) { - fore200e_shutdown(fore200e); - kfree(fore200e); - return err; - } - - index++; - dev_set_drvdata(&op->dev, fore200e); - - return 0; -} - -static int __devexit fore200e_sba_remove(struct of_device *op) -{ - struct fore200e *fore200e = dev_get_drvdata(&op->dev); - - fore200e_shutdown(fore200e); - kfree(fore200e); - - return 0; -} - -static const struct of_device_id fore200e_sba_match[] = { - { - .name = SBA200E_PROM_NAME, - .data = (void *) &fore200e_bus[1], - }, - {}, -}; -MODULE_DEVICE_TABLE(of, fore200e_sba_match); - -static struct of_platform_driver fore200e_sba_driver = { - .name = "fore_200e", - .match_table = fore200e_sba_match, - .probe = fore200e_sba_probe, - .remove = __devexit_p(fore200e_sba_remove), -}; -#endif - #ifdef CONFIG_PCI static int __devinit fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) @@ -2785,40 +2784,67 @@ static struct pci_driver fore200e_pca_driver = { }; #endif -static int __init fore200e_module_init(void) + +static int __init +fore200e_module_init(void) { - int err; + const struct fore200e_bus* bus; + struct fore200e* fore200e; + int index; - printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n"); + printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n"); -#ifdef CONFIG_SBUS - err = of_register_driver(&fore200e_sba_driver, &of_bus_type); - if (err) - return err; -#endif + /* for each configured bus interface */ + for (bus = fore200e_bus; bus->model_name; bus++) { + + /* detect all boards present on that bus */ + for (index = 0; bus->detect && (fore200e = bus->detect(bus, index)); index++) { + + printk(FORE200E "device %s found at 0x%lx, IRQ %s\n", + fore200e->bus->model_name, + fore200e->phys_base, fore200e_irq_itoa(fore200e->irq)); + + sprintf(fore200e->name, "%s-%d", bus->model_name, index); + + if (fore200e_init(fore200e) < 0) { + + fore200e_shutdown(fore200e); + break; + } + + list_add(&fore200e->entry, &fore200e_boards); + } + } #ifdef CONFIG_PCI - err = pci_register_driver(&fore200e_pca_driver); + if (!pci_register_driver(&fore200e_pca_driver)) + return 0; #endif -#ifdef CONFIG_SBUS - if (err) - of_unregister_driver(&fore200e_sba_driver); -#endif + if (!list_empty(&fore200e_boards)) + return 0; - return err; + return -ENODEV; } -static void __exit fore200e_module_cleanup(void) + +static void __exit +fore200e_module_cleanup(void) { + struct fore200e *fore200e, *next; + #ifdef CONFIG_PCI - pci_unregister_driver(&fore200e_pca_driver); -#endif -#ifdef CONFIG_SBUS - of_unregister_driver(&fore200e_sba_driver); + pci_unregister_driver(&fore200e_pca_driver); #endif + + list_for_each_entry_safe(fore200e, next, &fore200e_boards, entry) { + fore200e_shutdown(fore200e); + kfree(fore200e); + } + DPRINTK(1, "module being removed\n"); } + static int fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) { @@ -3137,6 +3163,7 @@ static const struct fore200e_bus fore200e_bus[] = { fore200e_pca_dma_sync_for_device, fore200e_pca_dma_chunk_alloc, fore200e_pca_dma_chunk_free, + NULL, fore200e_pca_configure, fore200e_pca_map, fore200e_pca_reset, @@ -3158,6 +3185,7 @@ static const struct fore200e_bus fore200e_bus[] = { fore200e_sba_dma_sync_for_device, fore200e_sba_dma_chunk_alloc, fore200e_sba_dma_chunk_free, + fore200e_sba_detect, fore200e_sba_configure, fore200e_sba_map, fore200e_sba_reset, diff --git a/trunk/drivers/atm/fore200e.h b/trunk/drivers/atm/fore200e.h index 7f97c09aaea5..5c6e7adcb19c 100644 --- a/trunk/drivers/atm/fore200e.h +++ b/trunk/drivers/atm/fore200e.h @@ -778,9 +778,9 @@ typedef struct fore200e_pca_regs { /* SBA-200E registers */ typedef struct fore200e_sba_regs { - u32 __iomem *hcr; /* address of host control register */ - u32 __iomem *bsr; /* address of burst transfer size register */ - u32 __iomem *isr; /* address of interrupt level selection register */ + volatile u32 __iomem *hcr; /* address of host control register */ + volatile u32 __iomem *bsr; /* address of burst transfer size register */ + volatile u32 __iomem *isr; /* address of interrupt level selection register */ } fore200e_sba_regs_t; @@ -810,6 +810,7 @@ typedef struct fore200e_bus { void (*dma_sync_for_device)(struct fore200e*, u32, int, int); int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int); void (*dma_chunk_free)(struct fore200e*, struct chunk*); + struct fore200e* (*detect)(const struct fore200e_bus*, int); int (*configure)(struct fore200e*); int (*map)(struct fore200e*); void (*reset)(struct fore200e*); diff --git a/trunk/drivers/block/sunvdc.c b/trunk/drivers/block/sunvdc.c index 953c0b83d758..a8de037ecd4a 100644 --- a/trunk/drivers/block/sunvdc.c +++ b/trunk/drivers/block/sunvdc.c @@ -1,6 +1,6 @@ /* sunvdc.c: Sun LDOM Virtual Disk Client. * - * Copyright (C) 2007, 2008 David S. Miller + * Copyright (C) 2007 David S. Miller */ #include @@ -834,7 +834,7 @@ static int vdc_port_remove(struct vio_dev *vdev) return 0; } -static const struct vio_device_id vdc_port_match[] = { +static struct vio_device_id vdc_port_match[] = { { .type = "vdc-port", }, diff --git a/trunk/drivers/char/hw_random/n2-drv.c b/trunk/drivers/char/hw_random/n2-drv.c index 8859aeac2d25..5220f541df25 100644 --- a/trunk/drivers/char/hw_random/n2-drv.c +++ b/trunk/drivers/char/hw_random/n2-drv.c @@ -736,7 +736,7 @@ static int __devexit n2rng_remove(struct of_device *op) return 0; } -static const struct of_device_id n2rng_match[] = { +static struct of_device_id n2rng_match[] = { { .name = "random-number-generator", .compatible = "SUNW,n2-rng", diff --git a/trunk/drivers/char/rtc.c b/trunk/drivers/char/rtc.c index b47710c17885..f53d4d00faf0 100644 --- a/trunk/drivers/char/rtc.c +++ b/trunk/drivers/char/rtc.c @@ -88,12 +88,12 @@ #endif #ifdef CONFIG_SPARC32 -#include -#include -#include +#include +#include +#include static unsigned long rtc_port; -static int rtc_irq; +static int rtc_irq = PCI_IRQ_NONE; #endif #ifdef CONFIG_HPET_RTC_IRQ @@ -973,8 +973,8 @@ static int __init rtc_init(void) char *guess = NULL; #endif #ifdef CONFIG_SPARC32 - struct device_node *ebus_dp; - struct of_device *op; + struct linux_ebus *ebus; + struct linux_ebus_device *edev; #else void *r; #ifdef RTC_IRQ @@ -983,16 +983,12 @@ static int __init rtc_init(void) #endif #ifdef CONFIG_SPARC32 - for_each_node_by_name(ebus_dp, "ebus") { - struct device_node *dp; - for (dp = ebus_dp; dp; dp = dp->sibling) { - if (!strcmp(dp->name, "rtc")) { - op = of_find_device_by_node(dp); - if (op) { - rtc_port = op->resource[0].start; - rtc_irq = op->irqs[0]; - goto found; - } + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (strcmp(edev->prom_node->name, "rtc") == 0) { + rtc_port = edev->resource[0].start; + rtc_irq = edev->irqs[0]; + goto found; } } } @@ -1001,7 +997,7 @@ static int __init rtc_init(void) return -EIO; found: - if (!rtc_irq) { + if (rtc_irq == PCI_IRQ_NONE) { rtc_has_irq = 0; goto no_irq; } diff --git a/trunk/drivers/hwmon/Kconfig b/trunk/drivers/hwmon/Kconfig index ebacc0af40fe..3309e862f317 100644 --- a/trunk/drivers/hwmon/Kconfig +++ b/trunk/drivers/hwmon/Kconfig @@ -800,13 +800,6 @@ config SENSORS_W83627EHF This driver can also be built as a module. If so, the module will be called w83627ehf. -config SENSORS_ULTRA45 - tristate "Sun Ultra45 PIC16F747" - depends on SPARC64 - help - This driver provides support for the Ultra45 workstation environmental - sensors. - config SENSORS_HDAPS tristate "IBM Hard Drive Active Protection System (hdaps)" depends on INPUT && X86 diff --git a/trunk/drivers/hwmon/Makefile b/trunk/drivers/hwmon/Makefile index 042d5a78622e..6babc801b348 100644 --- a/trunk/drivers/hwmon/Makefile +++ b/trunk/drivers/hwmon/Makefile @@ -41,7 +41,6 @@ obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o -obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o diff --git a/trunk/drivers/hwmon/ultra45_env.c b/trunk/drivers/hwmon/ultra45_env.c deleted file mode 100644 index 68e90abeba96..000000000000 --- a/trunk/drivers/hwmon/ultra45_env.c +++ /dev/null @@ -1,320 +0,0 @@ -/* ultra45_env.c: Driver for Ultra45 PIC16F747 environmental monitor. - * - * Copyright (C) 2008 David S. Miller - */ - -#include -#include -#include -#include -#include -#include -#include - -#define DRV_MODULE_VERSION "0.1" - -MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); -MODULE_DESCRIPTION("Ultra45 environmental monitor driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_MODULE_VERSION); - -/* PIC device registers */ -#define REG_CMD 0x00UL -#define REG_CMD_RESET 0x80 -#define REG_CMD_ESTAR 0x01 -#define REG_STAT 0x01UL -#define REG_STAT_FWVER 0xf0 -#define REG_STAT_TGOOD 0x08 -#define REG_STAT_STALE 0x04 -#define REG_STAT_BUSY 0x02 -#define REG_STAT_FAULT 0x01 -#define REG_DATA 0x40UL -#define REG_ADDR 0x41UL -#define REG_SIZE 0x42UL - -/* Registers accessed indirectly via REG_DATA/REG_ADDR */ -#define IREG_FAN0 0x00 -#define IREG_FAN1 0x01 -#define IREG_FAN2 0x02 -#define IREG_FAN3 0x03 -#define IREG_FAN4 0x04 -#define IREG_FAN5 0x05 -#define IREG_LCL_TEMP 0x06 -#define IREG_RMT1_TEMP 0x07 -#define IREG_RMT2_TEMP 0x08 -#define IREG_RMT3_TEMP 0x09 -#define IREG_LM95221_TEMP 0x0a -#define IREG_FIRE_TEMP 0x0b -#define IREG_LSI1064_TEMP 0x0c -#define IREG_FRONT_TEMP 0x0d -#define IREG_FAN_STAT 0x0e -#define IREG_VCORE0 0x0f -#define IREG_VCORE1 0x10 -#define IREG_VMEM0 0x11 -#define IREG_VMEM1 0x12 -#define IREG_PSU_TEMP 0x13 - -struct env { - void __iomem *regs; - spinlock_t lock; - - struct device *hwmon_dev; -}; - -static u8 env_read(struct env *p, u8 ireg) -{ - u8 ret; - - spin_lock(&p->lock); - writeb(ireg, p->regs + REG_ADDR); - ret = readb(p->regs + REG_DATA); - spin_unlock(&p->lock); - - return ret; -} - -static void env_write(struct env *p, u8 ireg, u8 val) -{ - spin_lock(&p->lock); - writeb(ireg, p->regs + REG_ADDR); - writeb(val, p->regs + REG_DATA); - spin_unlock(&p->lock); -} - -/* There seems to be a adr7462 providing these values, thus a lot - * of these calculations are borrowed from the adt7470 driver. - */ -#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x)) -#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM -#define FAN_PERIOD_INVALID (0xff << 8) -#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID) - -static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, char *buf) -{ - int fan_nr = to_sensor_dev_attr(attr)->index; - struct env *p = dev_get_drvdata(dev); - int rpm, period; - u8 val; - - val = env_read(p, IREG_FAN0 + fan_nr); - period = (int) val << 8; - if (FAN_DATA_VALID(period)) - rpm = FAN_PERIOD_TO_RPM(period); - else - rpm = 0; - - return sprintf(buf, "%d\n", rpm); -} - -static ssize_t set_fan_speed(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - int fan_nr = to_sensor_dev_attr(attr)->index; - int rpm = simple_strtol(buf, NULL, 10); - struct env *p = dev_get_drvdata(dev); - int period; - u8 val; - - if (!rpm) - return -EINVAL; - - period = FAN_RPM_TO_PERIOD(rpm); - val = period >> 8; - env_write(p, IREG_FAN0 + fan_nr, val); - - return count; -} - -static ssize_t show_fan_fault(struct device *dev, struct device_attribute *attr, char *buf) -{ - int fan_nr = to_sensor_dev_attr(attr)->index; - struct env *p = dev_get_drvdata(dev); - u8 val = env_read(p, IREG_FAN_STAT); - return sprintf(buf, "%d\n", (val & (1 << fan_nr)) ? 1 : 0); -} - -#define fan(index) \ -static SENSOR_DEVICE_ATTR(fan##index##_speed, S_IRUGO | S_IWUSR, \ - show_fan_speed, set_fan_speed, index); \ -static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, \ - show_fan_fault, NULL, index) - -fan(0); -fan(1); -fan(2); -fan(3); -fan(4); - -static SENSOR_DEVICE_ATTR(psu_fan_fault, S_IRUGO, show_fan_fault, NULL, 6); - -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) -{ - int temp_nr = to_sensor_dev_attr(attr)->index; - struct env *p = dev_get_drvdata(dev); - s8 val; - - val = env_read(p, IREG_LCL_TEMP + temp_nr); - return sprintf(buf, "%d\n", ((int) val) - 64); -} - -static SENSOR_DEVICE_ATTR(adt7462_local_temp, S_IRUGO, show_temp, NULL, 0); -static SENSOR_DEVICE_ATTR(cpu0_temp, S_IRUGO, show_temp, NULL, 1); -static SENSOR_DEVICE_ATTR(cpu1_temp, S_IRUGO, show_temp, NULL, 2); -static SENSOR_DEVICE_ATTR(motherboard_temp, S_IRUGO, show_temp, NULL, 3); -static SENSOR_DEVICE_ATTR(lm95221_local_temp, S_IRUGO, show_temp, NULL, 4); -static SENSOR_DEVICE_ATTR(fire_temp, S_IRUGO, show_temp, NULL, 5); -static SENSOR_DEVICE_ATTR(lsi1064_local_temp, S_IRUGO, show_temp, NULL, 6); -static SENSOR_DEVICE_ATTR(front_panel_temp, S_IRUGO, show_temp, NULL, 7); -static SENSOR_DEVICE_ATTR(psu_temp, S_IRUGO, show_temp, NULL, 13); - -static ssize_t show_stat_bit(struct device *dev, struct device_attribute *attr, char *buf) -{ - int index = to_sensor_dev_attr(attr)->index; - struct env *p = dev_get_drvdata(dev); - u8 val; - - val = readb(p->regs + REG_STAT); - return sprintf(buf, "%d\n", (val & (1 << index)) ? 1 : 0); -} - -static SENSOR_DEVICE_ATTR(fan_failure, S_IRUGO, show_stat_bit, NULL, 0); -static SENSOR_DEVICE_ATTR(env_bus_busy, S_IRUGO, show_stat_bit, NULL, 1); -static SENSOR_DEVICE_ATTR(env_data_stale, S_IRUGO, show_stat_bit, NULL, 2); -static SENSOR_DEVICE_ATTR(tpm_self_test_passed, S_IRUGO, show_stat_bit, NULL, 3); - -static ssize_t show_fwver(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct env *p = dev_get_drvdata(dev); - u8 val; - - val = readb(p->regs + REG_STAT); - return sprintf(buf, "%d\n", val >> 4); -} - -static SENSOR_DEVICE_ATTR(firmware_version, S_IRUGO, show_fwver, NULL, 0); - -static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "ultra45\n"); -} - -static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); - -static struct attribute *env_attributes[] = { - &sensor_dev_attr_fan0_speed.dev_attr.attr, - &sensor_dev_attr_fan0_fault.dev_attr.attr, - &sensor_dev_attr_fan1_speed.dev_attr.attr, - &sensor_dev_attr_fan1_fault.dev_attr.attr, - &sensor_dev_attr_fan2_speed.dev_attr.attr, - &sensor_dev_attr_fan2_fault.dev_attr.attr, - &sensor_dev_attr_fan3_speed.dev_attr.attr, - &sensor_dev_attr_fan3_fault.dev_attr.attr, - &sensor_dev_attr_fan4_speed.dev_attr.attr, - &sensor_dev_attr_fan4_fault.dev_attr.attr, - &sensor_dev_attr_psu_fan_fault.dev_attr.attr, - &sensor_dev_attr_adt7462_local_temp.dev_attr.attr, - &sensor_dev_attr_cpu0_temp.dev_attr.attr, - &sensor_dev_attr_cpu1_temp.dev_attr.attr, - &sensor_dev_attr_motherboard_temp.dev_attr.attr, - &sensor_dev_attr_lm95221_local_temp.dev_attr.attr, - &sensor_dev_attr_fire_temp.dev_attr.attr, - &sensor_dev_attr_lsi1064_local_temp.dev_attr.attr, - &sensor_dev_attr_front_panel_temp.dev_attr.attr, - &sensor_dev_attr_psu_temp.dev_attr.attr, - &sensor_dev_attr_fan_failure.dev_attr.attr, - &sensor_dev_attr_env_bus_busy.dev_attr.attr, - &sensor_dev_attr_env_data_stale.dev_attr.attr, - &sensor_dev_attr_tpm_self_test_passed.dev_attr.attr, - &sensor_dev_attr_firmware_version.dev_attr.attr, - &sensor_dev_attr_name.dev_attr.attr, - NULL, -}; - -static const struct attribute_group env_group = { - .attrs = env_attributes, -}; - -static int __devinit env_probe(struct of_device *op, - const struct of_device_id *match) -{ - struct env *p = kzalloc(sizeof(*p), GFP_KERNEL); - int err = -ENOMEM; - - if (!p) - goto out; - - spin_lock_init(&p->lock); - - p->regs = of_ioremap(&op->resource[0], 0, REG_SIZE, "pic16f747"); - if (!p->regs) - goto out_free; - - err = sysfs_create_group(&op->dev.kobj, &env_group); - if (err) - goto out_iounmap; - - p->hwmon_dev = hwmon_device_register(&op->dev); - if (IS_ERR(p->hwmon_dev)) { - err = PTR_ERR(p->hwmon_dev); - goto out_sysfs_remove_group; - } - - dev_set_drvdata(&op->dev, p); - err = 0; - -out: - return err; - -out_sysfs_remove_group: - sysfs_remove_group(&op->dev.kobj, &env_group); - -out_iounmap: - of_iounmap(&op->resource[0], p->regs, REG_SIZE); - -out_free: - kfree(p); - goto out; -} - -static int __devexit env_remove(struct of_device *op) -{ - struct env *p = dev_get_drvdata(&op->dev); - - if (p) { - sysfs_remove_group(&op->dev.kobj, &env_group); - hwmon_device_unregister(p->hwmon_dev); - of_iounmap(&op->resource[0], p->regs, REG_SIZE); - kfree(p); - } - - return 0; -} - -static const struct of_device_id env_match[] = { - { - .name = "env-monitor", - .compatible = "SUNW,ebus-pic16f747-env", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, env_match); - -static struct of_platform_driver env_driver = { - .name = "ultra45_env", - .match_table = env_match, - .probe = env_probe, - .remove = __devexit_p(env_remove), -}; - -static int __init env_init(void) -{ - return of_register_driver(&env_driver, &of_bus_type); -} - -static void __exit env_exit(void) -{ - of_unregister_driver(&env_driver); -} - -module_init(env_init); -module_exit(env_exit); diff --git a/trunk/drivers/input/misc/sparcspkr.c b/trunk/drivers/input/misc/sparcspkr.c index c4f42311fdec..d8765cc93d27 100644 --- a/trunk/drivers/input/misc/sparcspkr.c +++ b/trunk/drivers/input/misc/sparcspkr.c @@ -249,7 +249,7 @@ static int bbc_remove(struct of_device *op) return 0; } -static const struct of_device_id bbc_beep_match[] = { +static struct of_device_id bbc_beep_match[] = { { .name = "beep", .compatible = "SUNW,bbc-beep", @@ -328,7 +328,7 @@ static int grover_remove(struct of_device *op) return 0; } -static const struct of_device_id grover_beep_match[] = { +static struct of_device_id grover_beep_match[] = { { .name = "beep", .compatible = "SUNW,smbus-beep", diff --git a/trunk/drivers/input/serio/i8042-sparcio.h b/trunk/drivers/input/serio/i8042-sparcio.h index 5071af2c0604..692a79ec2a22 100644 --- a/trunk/drivers/input/serio/i8042-sparcio.h +++ b/trunk/drivers/input/serio/i8042-sparcio.h @@ -87,7 +87,7 @@ static int __devexit sparc_i8042_remove(struct of_device *op) return 0; } -static const struct of_device_id sparc_i8042_match[] = { +static struct of_device_id sparc_i8042_match[] = { { .name = "8042", }, diff --git a/trunk/drivers/leds/Kconfig b/trunk/drivers/leds/Kconfig index e3e40427e00e..5b14262af017 100644 --- a/trunk/drivers/leds/Kconfig +++ b/trunk/drivers/leds/Kconfig @@ -82,14 +82,6 @@ config LEDS_COBALT_RAQ help This option enables support for the Cobalt Raq series LEDs. -config LEDS_SUNFIRE - tristate "LED support for SunFire servers." - depends on LEDS_CLASS && SPARC64 - select LEDS_TRIGGERS - help - This option enables support for the Left, Middle, and Right - LEDs on the I/O and CPU boards of SunFire UltraSPARC servers. - config LEDS_HP6XX tristate "LED Support for the HP Jornada 6xx" depends on LEDS_CLASS && SH_HP6XX diff --git a/trunk/drivers/leds/Makefile b/trunk/drivers/leds/Makefile index eb186c351a1c..3a8e6a04363c 100644 --- a/trunk/drivers/leds/Makefile +++ b/trunk/drivers/leds/Makefile @@ -14,7 +14,6 @@ obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o obj-$(CONFIG_LEDS_H1940) += leds-h1940.o obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o -obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o diff --git a/trunk/drivers/leds/leds-sunfire.c b/trunk/drivers/leds/leds-sunfire.c deleted file mode 100644 index 6b008f0c3f62..000000000000 --- a/trunk/drivers/leds/leds-sunfire.c +++ /dev/null @@ -1,273 +0,0 @@ -/* leds-sunfire.c: SUNW,Ultra-Enterprise LED driver. - * - * Copyright (C) 2008 David S. Miller - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#define DRIVER_NAME "leds-sunfire" -#define PFX DRIVER_NAME ": " - -MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); -MODULE_DESCRIPTION("Sun Fire LED driver"); -MODULE_LICENSE("GPL"); - -struct sunfire_led { - struct led_classdev led_cdev; - void __iomem *reg; -}; -#define to_sunfire_led(d) container_of(d, struct sunfire_led, led_cdev) - -static void __clockboard_set(struct led_classdev *led_cdev, - enum led_brightness led_val, u8 bit) -{ - struct sunfire_led *p = to_sunfire_led(led_cdev); - u8 reg = upa_readb(p->reg); - - switch (bit) { - case CLOCK_CTRL_LLED: - if (led_val) - reg &= ~bit; - else - reg |= bit; - break; - - default: - if (led_val) - reg |= bit; - else - reg &= ~bit; - break; - } - upa_writeb(reg, p->reg); -} - -static void clockboard_left_set(struct led_classdev *led_cdev, - enum led_brightness led_val) -{ - __clockboard_set(led_cdev, led_val, CLOCK_CTRL_LLED); -} - -static void clockboard_middle_set(struct led_classdev *led_cdev, - enum led_brightness led_val) -{ - __clockboard_set(led_cdev, led_val, CLOCK_CTRL_MLED); -} - -static void clockboard_right_set(struct led_classdev *led_cdev, - enum led_brightness led_val) -{ - __clockboard_set(led_cdev, led_val, CLOCK_CTRL_RLED); -} - -static void __fhc_set(struct led_classdev *led_cdev, - enum led_brightness led_val, u32 bit) -{ - struct sunfire_led *p = to_sunfire_led(led_cdev); - u32 reg = upa_readl(p->reg); - - switch (bit) { - case FHC_CONTROL_LLED: - if (led_val) - reg &= ~bit; - else - reg |= bit; - break; - - default: - if (led_val) - reg |= bit; - else - reg &= ~bit; - break; - } - upa_writel(reg, p->reg); -} - -static void fhc_left_set(struct led_classdev *led_cdev, - enum led_brightness led_val) -{ - __fhc_set(led_cdev, led_val, FHC_CONTROL_LLED); -} - -static void fhc_middle_set(struct led_classdev *led_cdev, - enum led_brightness led_val) -{ - __fhc_set(led_cdev, led_val, FHC_CONTROL_MLED); -} - -static void fhc_right_set(struct led_classdev *led_cdev, - enum led_brightness led_val) -{ - __fhc_set(led_cdev, led_val, FHC_CONTROL_RLED); -} - -typedef void (*set_handler)(struct led_classdev *, enum led_brightness); -struct led_type { - const char *name; - set_handler handler; - const char *default_trigger; -}; - -#define NUM_LEDS_PER_BOARD 3 -struct sunfire_drvdata { - struct sunfire_led leds[NUM_LEDS_PER_BOARD]; -}; - -static int __devinit sunfire_led_generic_probe(struct platform_device *pdev, - struct led_type *types) -{ - struct sunfire_drvdata *p; - int i, err = -EINVAL; - - if (pdev->num_resources != 1) { - printk(KERN_ERR PFX "Wrong number of resources %d, should be 1\n", - pdev->num_resources); - goto out; - } - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) { - printk(KERN_ERR PFX "Could not allocate struct sunfire_drvdata\n"); - goto out; - } - - for (i = 0; i < NUM_LEDS_PER_BOARD; i++) { - struct led_classdev *lp = &p->leds[i].led_cdev; - - p->leds[i].reg = (void __iomem *) pdev->resource[0].start; - lp->name = types[i].name; - lp->brightness = LED_FULL; - lp->brightness_set = types[i].handler; - lp->default_trigger = types[i].default_trigger; - - err = led_classdev_register(&pdev->dev, lp); - if (err) { - printk(KERN_ERR PFX "Could not register %s LED\n", - lp->name); - goto out_unregister_led_cdevs; - } - } - - dev_set_drvdata(&pdev->dev, p); - - err = 0; -out: - return err; - -out_unregister_led_cdevs: - for (i--; i >= 0; i--) - led_classdev_unregister(&p->leds[i].led_cdev); - goto out; -} - -static int __devexit sunfire_led_generic_remove(struct platform_device *pdev) -{ - struct sunfire_drvdata *p = dev_get_drvdata(&pdev->dev); - int i; - - for (i = 0; i < NUM_LEDS_PER_BOARD; i++) - led_classdev_unregister(&p->leds[i].led_cdev); - - kfree(p); - - return 0; -} - -static struct led_type clockboard_led_types[NUM_LEDS_PER_BOARD] = { - { - .name = "clockboard-left", - .handler = clockboard_left_set, - }, - { - .name = "clockboard-middle", - .handler = clockboard_middle_set, - }, - { - .name = "clockboard-right", - .handler = clockboard_right_set, - .default_trigger= "heartbeat", - }, -}; - -static int __devinit sunfire_clockboard_led_probe(struct platform_device *pdev) -{ - return sunfire_led_generic_probe(pdev, clockboard_led_types); -} - -static struct led_type fhc_led_types[NUM_LEDS_PER_BOARD] = { - { - .name = "fhc-left", - .handler = fhc_left_set, - }, - { - .name = "fhc-middle", - .handler = fhc_middle_set, - }, - { - .name = "fhc-right", - .handler = fhc_right_set, - .default_trigger= "heartbeat", - }, -}; - -static int __devinit sunfire_fhc_led_probe(struct platform_device *pdev) -{ - return sunfire_led_generic_probe(pdev, fhc_led_types); -} - -MODULE_ALIAS("platform:sunfire-clockboard-leds"); -MODULE_ALIAS("platform:sunfire-fhc-leds"); - -static struct platform_driver sunfire_clockboard_led_driver = { - .probe = sunfire_clockboard_led_probe, - .remove = __devexit_p(sunfire_led_generic_remove), - .driver = { - .name = "sunfire-clockboard-leds", - .owner = THIS_MODULE, - }, -}; - -static struct platform_driver sunfire_fhc_led_driver = { - .probe = sunfire_fhc_led_probe, - .remove = __devexit_p(sunfire_led_generic_remove), - .driver = { - .name = "sunfire-fhc-leds", - .owner = THIS_MODULE, - }, -}; - -static int __init sunfire_leds_init(void) -{ - int err = platform_driver_register(&sunfire_clockboard_led_driver); - - if (err) { - printk(KERN_ERR PFX "Could not register clock board LED driver\n"); - return err; - } - - err = platform_driver_register(&sunfire_fhc_led_driver); - if (err) { - printk(KERN_ERR PFX "Could not register FHC LED driver\n"); - platform_driver_unregister(&sunfire_clockboard_led_driver); - } - - return err; -} - -static void __exit sunfire_leds_exit(void) -{ - platform_driver_unregister(&sunfire_clockboard_led_driver); - platform_driver_unregister(&sunfire_fhc_led_driver); -} - -module_init(sunfire_leds_init); -module_exit(sunfire_leds_exit); diff --git a/trunk/drivers/mtd/maps/sun_uflash.c b/trunk/drivers/mtd/maps/sun_uflash.c index fd7a1017399a..0d7c88396c88 100644 --- a/trunk/drivers/mtd/maps/sun_uflash.c +++ b/trunk/drivers/mtd/maps/sun_uflash.c @@ -1,10 +1,13 @@ -/* sun_uflash.c - Driver for user-programmable flash on - * Sun Microsystems SME boardsets. +/* + * + * sun_uflash - Driver implementation for user-programmable flash + * present on many Sun Microsystems SME boardsets. * * This driver does NOT provide access to the OBP-flash for * safety reasons-- use /drivers/sbus/char/flash.c instead. * * Copyright (c) 2001 Eric Brower (ebrower@usa.net) + * */ #include @@ -13,8 +16,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -23,65 +26,67 @@ #include #define UFLASH_OBPNAME "flashprom" -#define DRIVER_NAME "sun_uflash" -#define PFX DRIVER_NAME ": " +#define UFLASH_DEVNAME "userflash" #define UFLASH_WINDOW_SIZE 0x200000 #define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */ MODULE_AUTHOR("Eric Brower "); MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets"); -MODULE_SUPPORTED_DEVICE(DRIVER_NAME); +MODULE_SUPPORTED_DEVICE("userflash"); MODULE_LICENSE("GPL"); -MODULE_VERSION("2.1"); +MODULE_VERSION("2.0"); +static LIST_HEAD(device_list); struct uflash_dev { const char *name; /* device name */ struct map_info map; /* mtd map info */ struct mtd_info *mtd; /* mtd info */ }; + struct map_info uflash_map_templ = { .name = "SUNW,???-????", .size = UFLASH_WINDOW_SIZE, .bankwidth = UFLASH_BUSWIDTH, }; -int uflash_devinit(struct of_device *op, struct device_node *dp) +int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp) { struct uflash_dev *up; + struct resource *res; - if (op->resource[1].flags) { + res = &edev->resource[0]; + + if (edev->num_addrs != 1) { /* Non-CFI userflash device-- once I find one we * can work on supporting it. */ - printk(KERN_ERR PFX "Unsupported device at %s, 0x%llx\n", - dp->full_name, (unsigned long long)op->resource[0].start); + printk("%s: unsupported device at 0x%llx (%d regs): " \ + "email ebrower@usa.net\n", + dp->full_name, (unsigned long long)res->start, + edev->num_addrs); return -ENODEV; } up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL); - if (!up) { - printk(KERN_ERR PFX "Cannot allocate struct uflash_dev\n"); + if (!up) return -ENOMEM; - } /* copy defaults and tweak parameters */ memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ)); - - up->map.size = resource_size(&op->resource[0]); + up->map.size = (res->end - res->start) + 1UL; up->name = of_get_property(dp, "model", NULL); if (up->name && 0 < strlen(up->name)) up->map.name = (char *)up->name; - up->map.phys = op->resource[0].start; + up->map.phys = res->start; - up->map.virt = of_ioremap(&op->resource[0], 0, up->map.size, - DRIVER_NAME); + up->map.virt = ioremap_nocache(res->start, up->map.size); if (!up->map.virt) { - printk(KERN_ERR PFX "Failed to map device.\n"); + printk("%s: Failed to map device.\n", dp->full_name); kfree(up); return -EINVAL; @@ -92,7 +97,7 @@ int uflash_devinit(struct of_device *op, struct device_node *dp) /* MTD registration */ up->mtd = do_map_probe("cfi_probe", &up->map); if (!up->mtd) { - of_iounmap(&op->resource[0], up->map.virt, up->map.size); + iounmap(up->map.virt); kfree(up); return -ENXIO; @@ -102,34 +107,32 @@ int uflash_devinit(struct of_device *op, struct device_node *dp) add_mtd_device(up->mtd); - dev_set_drvdata(&op->dev, up); + dev_set_drvdata(&edev->ofdev.dev, up); return 0; } -static int __devinit uflash_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit uflash_probe(struct of_device *dev, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct linux_ebus_device *edev = to_ebus_device(&dev->dev); + struct device_node *dp = dev->node; - /* Flashprom must have the "user" property in order to - * be used by this driver. - */ - if (!of_find_property(dp, "user", NULL)) + if (of_find_property(dp, "user", NULL)) return -ENODEV; - return uflash_devinit(op, dp); + return uflash_devinit(edev, dp); } -static int __devexit uflash_remove(struct of_device *op) +static int __devexit uflash_remove(struct of_device *dev) { - struct uflash_dev *up = dev_get_drvdata(&op->dev); + struct uflash_dev *up = dev_get_drvdata(&dev->dev); if (up->mtd) { del_mtd_device(up->mtd); map_destroy(up->mtd); } if (up->map.virt) { - of_iounmap(&op->resource[0], up->map.virt, up->map.size); + iounmap(up->map.virt); up->map.virt = NULL; } @@ -138,7 +141,7 @@ static int __devexit uflash_remove(struct of_device *op) return 0; } -static const struct of_device_id uflash_match[] = { +static struct of_device_id uflash_match[] = { { .name = UFLASH_OBPNAME, }, @@ -148,7 +151,7 @@ static const struct of_device_id uflash_match[] = { MODULE_DEVICE_TABLE(of, uflash_match); static struct of_platform_driver uflash_driver = { - .name = DRIVER_NAME, + .name = UFLASH_DEVNAME, .match_table = uflash_match, .probe = uflash_probe, .remove = __devexit_p(uflash_remove), @@ -156,7 +159,7 @@ static struct of_platform_driver uflash_driver = { static int __init uflash_init(void) { - return of_register_driver(&uflash_driver, &of_bus_type); + return of_register_driver(&uflash_driver, &ebus_bus_type); } static void __exit uflash_exit(void) diff --git a/trunk/drivers/net/e1000/e1000_main.c b/trunk/drivers/net/e1000/e1000_main.c index fac82152e4c8..3bafaede7916 100644 --- a/trunk/drivers/net/e1000/e1000_main.c +++ b/trunk/drivers/net/e1000/e1000_main.c @@ -1047,11 +1047,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_LLTX; - netdev->vlan_features |= NETIF_F_TSO; - netdev->vlan_features |= NETIF_F_TSO6; - netdev->vlan_features |= NETIF_F_HW_CSUM; - netdev->vlan_features |= NETIF_F_SG; - adapter->en_mng_pt = e1000_enable_mng_pass_thru(hw); /* initialize eeprom parameters */ diff --git a/trunk/drivers/net/myri_sbus.c b/trunk/drivers/net/myri_sbus.c index 3ad7589d6a1c..06e682334c7e 100644 --- a/trunk/drivers/net/myri_sbus.c +++ b/trunk/drivers/net/myri_sbus.c @@ -1,6 +1,6 @@ /* myri_sbus.c: MyriCOM MyriNET SBUS card driver. * - * Copyright (C) 1996, 1999, 2006, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net) */ static char version[] = @@ -22,9 +22,6 @@ static char version[] = #include #include #include -#include -#include -#include #include #include @@ -36,6 +33,7 @@ static char version[] = #include #include #include +#include #include #include #include @@ -245,8 +243,7 @@ static void myri_clean_rings(struct myri_eth *mp) u32 dma_addr; dma_addr = sbus_readl(&rxd->myri_scatters[0].addr); - dma_unmap_single(&mp->myri_op->dev, dma_addr, - RX_ALLOC_SIZE, DMA_FROM_DEVICE); + sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); dev_kfree_skb(mp->rx_skbs[i]); mp->rx_skbs[i] = NULL; } @@ -262,9 +259,7 @@ static void myri_clean_rings(struct myri_eth *mp) u32 dma_addr; dma_addr = sbus_readl(&txd->myri_gathers[0].addr); - dma_unmap_single(&mp->myri_op->dev, dma_addr, - (skb->len + 3) & ~3, - DMA_TO_DEVICE); + sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3, SBUS_DMA_TODEVICE); dev_kfree_skb(mp->tx_skbs[i]); mp->tx_skbs[i] = NULL; } @@ -293,9 +288,7 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq) skb->dev = dev; skb_put(skb, RX_ALLOC_SIZE); - dma_addr = dma_map_single(&mp->myri_op->dev, - skb->data, RX_ALLOC_SIZE, - DMA_FROM_DEVICE); + dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); sbus_writel(dma_addr, &rxd[i].myri_scatters[0].addr); sbus_writel(RX_ALLOC_SIZE, &rxd[i].myri_scatters[0].len); sbus_writel(i, &rxd[i].ctx); @@ -351,8 +344,7 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev) DTX(("SKB[%d] ", entry)); dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr); - dma_unmap_single(&mp->myri_op->dev, dma_addr, - skb->len, DMA_TO_DEVICE); + sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE); dev_kfree_skb(skb); mp->tx_skbs[entry] = NULL; dev->stats.tx_packets++; @@ -431,9 +423,9 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) /* Check for errors. */ DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum)); - dma_sync_single_for_cpu(&mp->myri_op->dev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, DMA_FROM_DEVICE); + sbus_dma_sync_single_for_cpu(mp->myri_sdev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) { DRX(("ERROR[")); dev->stats.rx_errors++; @@ -450,10 +442,10 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) drops++; DRX(("DROP ")); dev->stats.rx_dropped++; - dma_sync_single_for_device(&mp->myri_op->dev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, - DMA_FROM_DEVICE); + sbus_dma_sync_single_for_device(mp->myri_sdev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, + SBUS_DMA_FROMDEVICE); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); sbus_writel(1, &rxd->num_sg); @@ -472,17 +464,17 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) DRX(("skb_alloc(FAILED) ")); goto drop_it; } - dma_unmap_single(&mp->myri_op->dev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, - DMA_FROM_DEVICE); + sbus_unmap_single(mp->myri_sdev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, + SBUS_DMA_FROMDEVICE); mp->rx_skbs[index] = new_skb; new_skb->dev = dev; skb_put(new_skb, RX_ALLOC_SIZE); - dma_addr = dma_map_single(&mp->myri_op->dev, - new_skb->data, - RX_ALLOC_SIZE, - DMA_FROM_DEVICE); + dma_addr = sbus_map_single(mp->myri_sdev, + new_skb->data, + RX_ALLOC_SIZE, + SBUS_DMA_FROMDEVICE); sbus_writel(dma_addr, &rxd->myri_scatters[0].addr); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); @@ -508,10 +500,10 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) /* Reuse original ring buffer. */ DRX(("reuse ")); - dma_sync_single_for_device(&mp->myri_op->dev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, - DMA_FROM_DEVICE); + sbus_dma_sync_single_for_device(mp->myri_sdev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, + SBUS_DMA_FROMDEVICE); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); sbus_writel(1, &rxd->num_sg); @@ -660,8 +652,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) sbus_writew((skb->data[4] << 8) | skb->data[5], &txd->addr[3]); } - dma_addr = dma_map_single(&mp->myri_op->dev, skb->data, - len, DMA_TO_DEVICE); + dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len, SBUS_DMA_TODEVICE); sbus_writel(dma_addr, &txd->myri_gathers[0].addr); sbus_writel(len, &txd->myri_gathers[0].len); sbus_writel(1, &txd->num_sg); @@ -900,30 +891,30 @@ static const struct header_ops myri_header_ops = { .cache_update = myri_header_cache_update, }; -static int __devinit myri_sbus_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit myri_ether_init(struct sbus_dev *sdev) { - struct device_node *dp = op->node; + static int num; static unsigned version_printed; struct net_device *dev; - DECLARE_MAC_BUF(mac); struct myri_eth *mp; - const void *prop; - static int num; - int i, len; + unsigned char prop_buf[32]; + int i; + DECLARE_MAC_BUF(mac); - DET(("myri_ether_init(%p,%d):\n", op, num)); + DET(("myri_ether_init(%p,%d):\n", sdev, num)); dev = alloc_etherdev(sizeof(struct myri_eth)); + if (!dev) return -ENOMEM; if (version_printed++ == 0) printk(version); - SET_NETDEV_DEV(dev, &op->dev); + SET_NETDEV_DEV(dev, &sdev->ofdev.dev); - mp = netdev_priv(dev); + mp = (struct myri_eth *) dev->priv; spin_lock_init(&mp->irq_lock); - mp->myri_op = op; + mp->myri_sdev = sdev; /* Clean out skb arrays. */ for (i = 0; i < (RX_RING_SIZE + 1); i++) @@ -933,44 +924,55 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic mp->tx_skbs[i] = NULL; /* First check for EEPROM information. */ - prop = of_get_property(dp, "myrinet-eeprom-info", &len); - - if (prop) - memcpy(&mp->eeprom, prop, sizeof(struct myri_eeprom)); - if (!prop) { + i = prom_getproperty(sdev->prom_node, "myrinet-eeprom-info", + (char *)&mp->eeprom, sizeof(struct myri_eeprom)); + DET(("prom_getprop(myrinet-eeprom-info) returns %d\n", i)); + if (i == 0 || i == -1) { /* No eeprom property, must cook up the values ourselves. */ DET(("No EEPROM: ")); mp->eeprom.bus_type = BUS_TYPE_SBUS; - mp->eeprom.cpuvers = - of_getintprop_default(dp, "cpu_version", 0); - mp->eeprom.cval = - of_getintprop_default(dp, "clock_value", 0); - mp->eeprom.ramsz = of_getintprop_default(dp, "sram_size", 0); - if (!mp->eeprom.cpuvers) + mp->eeprom.cpuvers = prom_getintdefault(sdev->prom_node,"cpu_version",0); + mp->eeprom.cval = prom_getintdefault(sdev->prom_node,"clock_value",0); + mp->eeprom.ramsz = prom_getintdefault(sdev->prom_node,"sram_size",0); + DET(("cpuvers[%d] cval[%d] ramsz[%d]\n", mp->eeprom.cpuvers, + mp->eeprom.cval, mp->eeprom.ramsz)); + if (mp->eeprom.cpuvers == 0) { + DET(("EEPROM: cpuvers was zero, setting to %04x\n",CPUVERS_2_3)); mp->eeprom.cpuvers = CPUVERS_2_3; - if (mp->eeprom.cpuvers < CPUVERS_3_0) + } + if (mp->eeprom.cpuvers < CPUVERS_3_0) { + DET(("EEPROM: cpuvers < CPUVERS_3_0, clockval set to zero.\n")); mp->eeprom.cval = 0; - if (!mp->eeprom.ramsz) + } + if (mp->eeprom.ramsz == 0) { + DET(("EEPROM: ramsz == 0, setting to 128k\n")); mp->eeprom.ramsz = (128 * 1024); - - prop = of_get_property(dp, "myrinet-board-id", &len); - if (prop) - memcpy(&mp->eeprom.id[0], prop, 6); + } + i = prom_getproperty(sdev->prom_node, "myrinet-board-id", + &prop_buf[0], 10); + DET(("EEPROM: prom_getprop(myrinet-board-id) returns %d\n", i)); + if ((i != 0) && (i != -1)) + memcpy(&mp->eeprom.id[0], &prop_buf[0], 6); else set_boardid_from_idprom(mp, num); - - prop = of_get_property(dp, "fpga_version", &len); - if (prop) - memcpy(&mp->eeprom.fvers[0], prop, 32); - else + i = prom_getproperty(sdev->prom_node, "fpga_version", + &mp->eeprom.fvers[0], 32); + DET(("EEPROM: prom_getprop(fpga_version) returns %d\n", i)); + if (i == 0 || i == -1) memset(&mp->eeprom.fvers[0], 0, 32); if (mp->eeprom.cpuvers == CPUVERS_4_1) { - if (mp->eeprom.ramsz == (128 * 1024)) + DET(("EEPROM: cpuvers CPUVERS_4_1, ")); + if (mp->eeprom.ramsz == (128 * 1024)) { + DET(("ramsize 128k, setting to 256k, ")); mp->eeprom.ramsz = (256 * 1024); - if ((mp->eeprom.cval == 0x40414041) || - (mp->eeprom.cval == 0x90449044)) + } + if ((mp->eeprom.cval==0x40414041)||(mp->eeprom.cval==0x90449044)){ + DET(("changing cval from %08x to %08x ", + mp->eeprom.cval, 0x50e450e4)); mp->eeprom.cval = 0x50e450e4; + } + DET(("\n")); } } #ifdef DEBUG_DETECT @@ -989,8 +991,8 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic * XXX only a valid version for PCI cards? Ask feldy... */ DET(("Mapping regs for cpuvers < CPUVERS_4_0\n")); - mp->regs = of_ioremap(&op->resource[0], 0, - mp->reg_size, "MyriCOM Regs"); + mp->regs = sbus_ioremap(&sdev->resource[0], 0, + mp->reg_size, "MyriCOM Regs"); if (!mp->regs) { printk("MyriCOM: Cannot map MyriCOM registers.\n"); goto err; @@ -999,12 +1001,13 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic mp->lregs = mp->lanai + (0x10000 * 2); } else { DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n")); - mp->cregs = of_ioremap(&op->resource[0], 0, - PAGE_SIZE, "MyriCOM Control Regs"); - mp->lregs = of_ioremap(&op->resource[0], (256 * 1024), + mp->cregs = sbus_ioremap(&sdev->resource[0], 0, + PAGE_SIZE, "MyriCOM Control Regs"); + mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024), PAGE_SIZE, "MyriCOM LANAI Regs"); - mp->lanai = of_ioremap(&op->resource[0], (512 * 1024), - mp->eeprom.ramsz, "MyriCOM SRAM"); + mp->lanai = + sbus_ioremap(&sdev->resource[0], (512 * 1024), + mp->eeprom.ramsz, "MyriCOM SRAM"); } DET(("Registers mapped: cregs[%p] lregs[%p] lanai[%p]\n", mp->cregs, mp->lregs, mp->lanai)); @@ -1036,15 +1039,16 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic myri_reset_on(mp->cregs); /* Get the supported DVMA burst sizes from our SBUS. */ - mp->myri_bursts = of_getintprop_default(dp->parent, - "burst-sizes", 0x00); - if (!sbus_can_burst64()) + mp->myri_bursts = prom_getintdefault(mp->myri_sdev->bus->prom_node, + "burst-sizes", 0x00); + + if (!sbus_can_burst64(sdev)) mp->myri_bursts &= ~(DMA_BURST64); DET(("MYRI bursts %02x\n", mp->myri_bursts)); /* Encode SBUS interrupt level in second control register. */ - i = of_getintprop_default(dp, "interrupts", 0); + i = prom_getint(sdev->prom_node, "interrupts"); if (i == 0) i = 4; DET(("prom_getint(interrupts)==%d, irqlvl set to %04x\n", @@ -1059,7 +1063,7 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic dev->tx_timeout = &myri_tx_timeout; dev->watchdog_timeo = 5*HZ; dev->set_multicast_list = &myri_set_multicast; - dev->irq = op->irqs[0]; + dev->irq = sdev->irqs[0]; /* Register interrupt handler now. */ DET(("Requesting MYRIcom IRQ line.\n")); @@ -1084,7 +1088,7 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic goto err_free_irq; } - dev_set_drvdata(&op->dev, mp); + dev_set_drvdata(&sdev->ofdev.dev, mp); num++; @@ -1101,9 +1105,17 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic return -ENODEV; } -static int __devexit myri_sbus_remove(struct of_device *op) + +static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + + return myri_ether_init(sdev); +} + +static int __devexit myri_sbus_remove(struct of_device *dev) { - struct myri_eth *mp = dev_get_drvdata(&op->dev); + struct myri_eth *mp = dev_get_drvdata(&dev->dev); struct net_device *net_dev = mp->dev; unregister_netdev(net_dev); @@ -1111,21 +1123,21 @@ static int __devexit myri_sbus_remove(struct of_device *op) free_irq(net_dev->irq, net_dev); if (mp->eeprom.cpuvers < CPUVERS_4_0) { - of_iounmap(&op->resource[0], mp->regs, mp->reg_size); + sbus_iounmap(mp->regs, mp->reg_size); } else { - of_iounmap(&op->resource[0], mp->cregs, PAGE_SIZE); - of_iounmap(&op->resource[0], mp->lregs, (256 * 1024)); - of_iounmap(&op->resource[0], mp->lanai, (512 * 1024)); + sbus_iounmap(mp->cregs, PAGE_SIZE); + sbus_iounmap(mp->lregs, (256 * 1024)); + sbus_iounmap(mp->lanai, (512 * 1024)); } free_netdev(net_dev); - dev_set_drvdata(&op->dev, NULL); + dev_set_drvdata(&dev->dev, NULL); return 0; } -static const struct of_device_id myri_sbus_match[] = { +static struct of_device_id myri_sbus_match[] = { { .name = "MYRICOM,mlanai", }, @@ -1146,7 +1158,7 @@ static struct of_platform_driver myri_sbus_driver = { static int __init myri_sbus_init(void) { - return of_register_driver(&myri_sbus_driver, &of_bus_type); + return of_register_driver(&myri_sbus_driver, &sbus_bus_type); } static void __exit myri_sbus_exit(void) diff --git a/trunk/drivers/net/myri_sbus.h b/trunk/drivers/net/myri_sbus.h index ff363e95d9cf..5d93fcc95d55 100644 --- a/trunk/drivers/net/myri_sbus.h +++ b/trunk/drivers/net/myri_sbus.h @@ -288,7 +288,7 @@ struct myri_eth { struct myri_eeprom eeprom; /* Local copy of EEPROM. */ unsigned int reg_size; /* Size of register space. */ unsigned int shmem_base; /* Offset to shared ram. */ - struct of_device *myri_op; /* Our OF device struct. */ + struct sbus_dev *myri_sdev; /* Our SBUS device struct. */ }; /* We use this to acquire receive skb's that we can DMA directly into. */ diff --git a/trunk/drivers/net/niu.c b/trunk/drivers/net/niu.c index ebc812702903..e3be81eba8a4 100644 --- a/trunk/drivers/net/niu.c +++ b/trunk/drivers/net/niu.c @@ -9130,7 +9130,7 @@ static int __devexit niu_of_remove(struct of_device *op) return 0; } -static const struct of_device_id niu_match[] = { +static struct of_device_id niu_match[] = { { .name = "network", .compatible = "SUNW,niusl", diff --git a/trunk/drivers/net/smc911x.c b/trunk/drivers/net/smc911x.c index 3d19d00e8eec..02cc064c2c8b 100644 --- a/trunk/drivers/net/smc911x.c +++ b/trunk/drivers/net/smc911x.c @@ -722,9 +722,6 @@ static void smc911x_phy_detect(struct net_device *dev) break; } } - if (phyaddr < 32) - /* Found an external PHY */ - break; } default: /* Internal media only */ diff --git a/trunk/drivers/net/sunbmac.c b/trunk/drivers/net/sunbmac.c index 018d0fca9422..31e7384e312a 100644 --- a/trunk/drivers/net/sunbmac.c +++ b/trunk/drivers/net/sunbmac.c @@ -1,6 +1,7 @@ -/* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. +/* $Id: sunbmac.c,v 1.30 2002/01/15 06:48:55 davem Exp $ + * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * - * Copyright (C) 1997, 1998, 1999, 2003, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 1997, 1998, 1999, 2003 David S. Miller (davem@redhat.com) */ #include @@ -22,9 +23,6 @@ #include #include #include -#include -#include -#include #include #include @@ -34,14 +32,15 @@ #include #include #include +#include #include #include "sunbmac.h" #define DRV_NAME "sunbmac" -#define DRV_VERSION "2.1" -#define DRV_RELDATE "August 26, 2008" -#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)" +#define DRV_VERSION "2.0" +#define DRV_RELDATE "11/24/03" +#define DRV_AUTHOR "David S. Miller (davem@redhat.com)" static char version[] = DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; @@ -97,8 +96,8 @@ static int qec_global_reset(void __iomem *gregs) static void qec_init(struct bigmac *bp) { - struct of_device *qec_op = bp->qec_op; void __iomem *gregs = bp->gregs; + struct sbus_dev *qec_sdev = bp->qec_sdev; u8 bsizes = bp->bigmac_bursts; u32 regval; @@ -113,13 +112,13 @@ static void qec_init(struct bigmac *bp) sbus_writel(GLOB_PSIZE_2048, gregs + GLOB_PSIZE); /* All of memsize is given to bigmac. */ - sbus_writel(resource_size(&qec_op->resource[1]), + sbus_writel(qec_sdev->reg_addrs[1].reg_size, gregs + GLOB_MSIZE); /* Half to the transmitter, half to the receiver. */ - sbus_writel(resource_size(&qec_op->resource[1]) >> 1, + sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1, gregs + GLOB_TSIZE); - sbus_writel(resource_size(&qec_op->resource[1]) >> 1, + sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1, gregs + GLOB_RSIZE); } @@ -240,10 +239,9 @@ static void bigmac_init_rings(struct bigmac *bp, int from_irq) skb_reserve(skb, 34); bb->be_rxd[i].rx_addr = - dma_map_single(&bp->bigmac_op->dev, - skb->data, - RX_BUF_ALLOC_SIZE - 34, - DMA_FROM_DEVICE); + sbus_map_single(bp->bigmac_sdev, skb->data, + RX_BUF_ALLOC_SIZE - 34, + SBUS_DMA_FROMDEVICE); bb->be_rxd[i].rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); } @@ -778,9 +776,9 @@ static void bigmac_tx(struct bigmac *bp) skb = bp->tx_skbs[elem]; bp->enet_stats.tx_packets++; bp->enet_stats.tx_bytes += skb->len; - dma_unmap_single(&bp->bigmac_op->dev, - this->tx_addr, skb->len, - DMA_TO_DEVICE); + sbus_unmap_single(bp->bigmac_sdev, + this->tx_addr, skb->len, + SBUS_DMA_TODEVICE); DTX(("skb(%p) ", skb)); bp->tx_skbs[elem] = NULL; @@ -833,19 +831,18 @@ static void bigmac_rx(struct bigmac *bp) drops++; goto drop_it; } - dma_unmap_single(&bp->bigmac_op->dev, - this->rx_addr, - RX_BUF_ALLOC_SIZE - 34, - DMA_FROM_DEVICE); + sbus_unmap_single(bp->bigmac_sdev, + this->rx_addr, + RX_BUF_ALLOC_SIZE - 34, + SBUS_DMA_FROMDEVICE); bp->rx_skbs[elem] = new_skb; new_skb->dev = bp->dev; skb_put(new_skb, ETH_FRAME_LEN); skb_reserve(new_skb, 34); - this->rx_addr = - dma_map_single(&bp->bigmac_op->dev, - new_skb->data, - RX_BUF_ALLOC_SIZE - 34, - DMA_FROM_DEVICE); + this->rx_addr = sbus_map_single(bp->bigmac_sdev, + new_skb->data, + RX_BUF_ALLOC_SIZE - 34, + SBUS_DMA_FROMDEVICE); this->rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); @@ -860,13 +857,13 @@ static void bigmac_rx(struct bigmac *bp) } skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - dma_sync_single_for_cpu(&bp->bigmac_op->dev, - this->rx_addr, len, - DMA_FROM_DEVICE); + sbus_dma_sync_single_for_cpu(bp->bigmac_sdev, + this->rx_addr, len, + SBUS_DMA_FROMDEVICE); skb_copy_to_linear_data(copy_skb, (unsigned char *)skb->data, len); - dma_sync_single_for_device(&bp->bigmac_op->dev, - this->rx_addr, len, - DMA_FROM_DEVICE); + sbus_dma_sync_single_for_device(bp->bigmac_sdev, + this->rx_addr, len, + SBUS_DMA_FROMDEVICE); /* Reuse original ring buffer. */ this->rx_flags = @@ -962,8 +959,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 mapping; len = skb->len; - mapping = dma_map_single(&bp->bigmac_op->dev, skb->data, - len, DMA_TO_DEVICE); + mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len, SBUS_DMA_TODEVICE); /* Avoid a race... */ spin_lock_irq(&bp->lock); @@ -1055,8 +1051,12 @@ static void bigmac_set_multicast(struct net_device *dev) /* Ethtool support... */ static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { + struct bigmac *bp = dev->priv; + strcpy(info->driver, "sunbmac"); strcpy(info->version, "2.0"); + sprintf(info->bus_info, "SBUS:%d", + bp->qec_sdev->slot); } static u32 bigmac_get_link(struct net_device *dev) @@ -1075,15 +1075,14 @@ static const struct ethtool_ops bigmac_ethtool_ops = { .get_link = bigmac_get_link, }; -static int __devinit bigmac_ether_init(struct of_device *op, - struct of_device *qec_op) +static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) { - static int version_printed; struct net_device *dev; - u8 bsizes, bsizes_more; - DECLARE_MAC_BUF(mac); + static int version_printed; struct bigmac *bp; + u8 bsizes, bsizes_more; int i; + DECLARE_MAC_BUF(mac); /* Get a new device struct for this interface. */ dev = alloc_etherdev(sizeof(struct bigmac)); @@ -1093,21 +1092,32 @@ static int __devinit bigmac_ether_init(struct of_device *op, if (version_printed++ == 0) printk(KERN_INFO "%s", version); + dev->base_addr = (long) qec_sdev; for (i = 0; i < 6; i++) dev->dev_addr[i] = idprom->id_ethaddr[i]; /* Setup softc, with backpointers to QEC and BigMAC SBUS device structs. */ - bp = netdev_priv(dev); - bp->qec_op = qec_op; - bp->bigmac_op = op; + bp = dev->priv; + bp->qec_sdev = qec_sdev; + bp->bigmac_sdev = qec_sdev->child; - SET_NETDEV_DEV(dev, &op->dev); + SET_NETDEV_DEV(dev, &bp->bigmac_sdev->ofdev.dev); spin_lock_init(&bp->lock); + /* Verify the registers we expect, are actually there. */ + if ((bp->bigmac_sdev->num_registers != 3) || + (bp->qec_sdev->num_registers != 2)) { + printk(KERN_ERR "BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n", + bp->qec_sdev->num_registers, + bp->bigmac_sdev->num_registers); + printk(KERN_ERR "BIGMAC: Would you like that for here or to go?\n"); + goto fail_and_cleanup; + } + /* Map in QEC global control registers. */ - bp->gregs = of_ioremap(&qec_op->resource[0], 0, - GLOB_REG_SIZE, "BigMAC QEC GLobal Regs"); + bp->gregs = sbus_ioremap(&bp->qec_sdev->resource[0], 0, + GLOB_REG_SIZE, "BigMAC QEC GLobal Regs"); if (!bp->gregs) { printk(KERN_ERR "BIGMAC: Cannot map QEC global registers.\n"); goto fail_and_cleanup; @@ -1124,8 +1134,13 @@ static int __devinit bigmac_ether_init(struct of_device *op, goto fail_and_cleanup; /* Get supported SBUS burst sizes. */ - bsizes = of_getintprop_default(qec_op->node, "burst-sizes", 0xff); - bsizes_more = of_getintprop_default(qec_op->node, "burst-sizes", 0xff); + bsizes = prom_getintdefault(bp->qec_sdev->prom_node, + "burst-sizes", + 0xff); + + bsizes_more = prom_getintdefault(bp->qec_sdev->bus->prom_node, + "burst-sizes", + 0xff); bsizes &= 0xff; if (bsizes_more != 0xff) @@ -1139,16 +1154,16 @@ static int __devinit bigmac_ether_init(struct of_device *op, qec_init(bp); /* Map in the BigMAC channel registers. */ - bp->creg = of_ioremap(&op->resource[0], 0, - CREG_REG_SIZE, "BigMAC QEC Channel Regs"); + bp->creg = sbus_ioremap(&bp->bigmac_sdev->resource[0], 0, + CREG_REG_SIZE, "BigMAC QEC Channel Regs"); if (!bp->creg) { printk(KERN_ERR "BIGMAC: Cannot map QEC channel registers.\n"); goto fail_and_cleanup; } /* Map in the BigMAC control registers. */ - bp->bregs = of_ioremap(&op->resource[1], 0, - BMAC_REG_SIZE, "BigMAC Primary Regs"); + bp->bregs = sbus_ioremap(&bp->bigmac_sdev->resource[1], 0, + BMAC_REG_SIZE, "BigMAC Primary Regs"); if (!bp->bregs) { printk(KERN_ERR "BIGMAC: Cannot map BigMAC primary registers.\n"); goto fail_and_cleanup; @@ -1157,8 +1172,8 @@ static int __devinit bigmac_ether_init(struct of_device *op, /* Map in the BigMAC transceiver registers, this is how you poke at * the BigMAC's PHY. */ - bp->tregs = of_ioremap(&op->resource[2], 0, - TCVR_REG_SIZE, "BigMAC Transceiver Regs"); + bp->tregs = sbus_ioremap(&bp->bigmac_sdev->resource[2], 0, + TCVR_REG_SIZE, "BigMAC Transceiver Regs"); if (!bp->tregs) { printk(KERN_ERR "BIGMAC: Cannot map BigMAC transceiver registers.\n"); goto fail_and_cleanup; @@ -1168,17 +1183,17 @@ static int __devinit bigmac_ether_init(struct of_device *op, bigmac_stop(bp); /* Allocate transmit/receive descriptor DVMA block. */ - bp->bmac_block = dma_alloc_coherent(&bp->bigmac_op->dev, - PAGE_SIZE, - &bp->bblock_dvma, GFP_ATOMIC); + bp->bmac_block = sbus_alloc_consistent(bp->bigmac_sdev, + PAGE_SIZE, + &bp->bblock_dvma); if (bp->bmac_block == NULL || bp->bblock_dvma == 0) { printk(KERN_ERR "BIGMAC: Cannot allocate consistent DMA.\n"); goto fail_and_cleanup; } /* Get the board revision of this BigMAC. */ - bp->board_rev = of_getintprop_default(bp->bigmac_op->node, - "board-version", 1); + bp->board_rev = prom_getintdefault(bp->bigmac_sdev->prom_node, + "board-version", 1); /* Init auto-negotiation timer state. */ init_timer(&bp->bigmac_timer); @@ -1202,7 +1217,7 @@ static int __devinit bigmac_ether_init(struct of_device *op, dev->watchdog_timeo = 5*HZ; /* Finish net device registration. */ - dev->irq = bp->bigmac_op->irqs[0]; + dev->irq = bp->bigmac_sdev->irqs[0]; dev->dma = 0; if (register_netdev(dev)) { @@ -1210,7 +1225,7 @@ static int __devinit bigmac_ether_init(struct of_device *op, goto fail_and_cleanup; } - dev_set_drvdata(&bp->bigmac_op->dev, bp); + dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp); printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n", dev->name, print_mac(mac, dev->dev_addr)); @@ -1221,67 +1236,66 @@ static int __devinit bigmac_ether_init(struct of_device *op, /* Something went wrong, undo whatever we did so far. */ /* Free register mappings if any. */ if (bp->gregs) - of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE); + sbus_iounmap(bp->gregs, GLOB_REG_SIZE); if (bp->creg) - of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE); + sbus_iounmap(bp->creg, CREG_REG_SIZE); if (bp->bregs) - of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE); + sbus_iounmap(bp->bregs, BMAC_REG_SIZE); if (bp->tregs) - of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE); + sbus_iounmap(bp->tregs, TCVR_REG_SIZE); if (bp->bmac_block) - dma_free_coherent(&bp->bigmac_op->dev, - PAGE_SIZE, - bp->bmac_block, - bp->bblock_dvma); + sbus_free_consistent(bp->bigmac_sdev, + PAGE_SIZE, + bp->bmac_block, + bp->bblock_dvma); /* This also frees the co-located 'dev->priv' */ free_netdev(dev); return -ENODEV; } -/* QEC can be the parent of either QuadEthernet or a BigMAC. We want - * the latter. +/* QEC can be the parent of either QuadEthernet or + * a BigMAC. We want the latter. */ -static int __devinit bigmac_sbus_probe(struct of_device *op, - const struct of_device_id *match) +static int __devinit bigmac_sbus_probe(struct of_device *dev, const struct of_device_id *match) { - struct device *parent = op->dev.parent; - struct of_device *qec_op; + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + struct device_node *dp = dev->node; - qec_op = to_of_device(parent); + if (!strcmp(dp->name, "be")) + sdev = sdev->parent; - return bigmac_ether_init(op, qec_op); + return bigmac_ether_init(sdev); } -static int __devexit bigmac_sbus_remove(struct of_device *op) +static int __devexit bigmac_sbus_remove(struct of_device *dev) { - struct bigmac *bp = dev_get_drvdata(&op->dev); - struct device *parent = op->dev.parent; + struct bigmac *bp = dev_get_drvdata(&dev->dev); struct net_device *net_dev = bp->dev; - struct of_device *qec_op; - - qec_op = to_of_device(parent); unregister_netdev(net_dev); - of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE); - of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE); - of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE); - of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE); - dma_free_coherent(&op->dev, - PAGE_SIZE, - bp->bmac_block, - bp->bblock_dvma); + sbus_iounmap(bp->gregs, GLOB_REG_SIZE); + sbus_iounmap(bp->creg, CREG_REG_SIZE); + sbus_iounmap(bp->bregs, BMAC_REG_SIZE); + sbus_iounmap(bp->tregs, TCVR_REG_SIZE); + sbus_free_consistent(bp->bigmac_sdev, + PAGE_SIZE, + bp->bmac_block, + bp->bblock_dvma); free_netdev(net_dev); - dev_set_drvdata(&op->dev, NULL); + dev_set_drvdata(&dev->dev, NULL); return 0; } -static const struct of_device_id bigmac_sbus_match[] = { +static struct of_device_id bigmac_sbus_match[] = { + { + .name = "qec", + }, { .name = "be", }, @@ -1299,7 +1313,7 @@ static struct of_platform_driver bigmac_sbus_driver = { static int __init bigmac_init(void) { - return of_register_driver(&bigmac_sbus_driver, &of_bus_type); + return of_register_driver(&bigmac_sbus_driver, &sbus_bus_type); } static void __exit bigmac_exit(void) diff --git a/trunk/drivers/net/sunbmac.h b/trunk/drivers/net/sunbmac.h index 8840bc0b840b..b563d3c2993e 100644 --- a/trunk/drivers/net/sunbmac.h +++ b/trunk/drivers/net/sunbmac.h @@ -329,8 +329,8 @@ struct bigmac { unsigned int timer_ticks; struct net_device_stats enet_stats; - struct of_device *qec_op; - struct of_device *bigmac_op; + struct sbus_dev *qec_sdev; + struct sbus_dev *bigmac_sdev; struct net_device *dev; }; diff --git a/trunk/drivers/net/sunhme.c b/trunk/drivers/net/sunhme.c index f1ebeb5f65b2..b79d5f018f79 100644 --- a/trunk/drivers/net/sunhme.c +++ b/trunk/drivers/net/sunhme.c @@ -3,7 +3,7 @@ * "Happy Meal Ethernet" found on SunSwift SBUS cards. * * Copyright (C) 1996, 1998, 1999, 2002, 2003, - * 2006, 2008 David S. Miller (davem@davemloft.net) + 2006 David S. Miller (davem@davemloft.net) * * Changes : * 2000/11/11 Willy Tarreau @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -42,9 +41,8 @@ #include #ifdef CONFIG_SPARC -#include -#include #include +#include #include #include #include @@ -62,8 +60,8 @@ #include "sunhme.h" #define DRV_NAME "sunhme" -#define DRV_VERSION "3.10" -#define DRV_RELDATE "August 26, 2008" +#define DRV_VERSION "3.00" +#define DRV_RELDATE "June 23, 2006" #define DRV_AUTHOR "David S. Miller (davem@davemloft.net)" static char version[] = @@ -253,13 +251,13 @@ static u32 pci_hme_read_desc32(hme32 *p) #define hme_read_desc32(__hp, __p) \ ((__hp)->read_desc32(__p)) #define hme_dma_map(__hp, __ptr, __size, __dir) \ - ((__hp)->dma_map((__hp)->dma_dev, (__ptr), (__size), (__dir))) + ((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir))) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ - ((__hp)->dma_unmap((__hp)->dma_dev, (__addr), (__size), (__dir))) + ((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir))) #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ - ((__hp)->dma_sync_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))) + ((__hp)->dma_sync_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))) #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ - ((__hp)->dma_sync_for_device((__hp)->dma_dev, (__addr), (__size), (__dir))) + ((__hp)->dma_sync_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))) #else #ifdef CONFIG_SBUS /* SBUS only compilation */ @@ -279,13 +277,13 @@ do { (__txd)->tx_addr = (__force hme32)(u32)(__addr); \ } while(0) #define hme_read_desc32(__hp, __p) ((__force u32)(hme32)*(__p)) #define hme_dma_map(__hp, __ptr, __size, __dir) \ - dma_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir)) + sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ - dma_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir)) + sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir)) #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ - dma_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir)) + sbus_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)) #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ - dma_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir)) + sbus_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)) #else /* PCI only compilation */ #define hme_write32(__hp, __reg, __val) \ @@ -307,17 +305,36 @@ static inline u32 hme_read_desc32(struct happy_meal *hp, hme32 *p) return le32_to_cpup((__le32 *)p); } #define hme_dma_map(__hp, __ptr, __size, __dir) \ - pci_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir)) + pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ - pci_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir)) + pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir)) #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ - pci_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir)) + pci_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)) #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ - pci_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir)) + pci_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)) #endif #endif +#ifdef SBUS_DMA_BIDIRECTIONAL +# define DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL +#else +# define DMA_BIDIRECTIONAL 0 +#endif + +#ifdef SBUS_DMA_FROMDEVICE +# define DMA_FROMDEVICE SBUS_DMA_FROMDEVICE +#else +# define DMA_TODEVICE 1 +#endif + +#ifdef SBUS_DMA_TODEVICE +# define DMA_TODEVICE SBUS_DMA_TODEVICE +#else +# define DMA_FROMDEVICE 2 +#endif + + /* Oh yes, the MIF BitBang is mighty fun to program. BitBucket is more like it. */ static void BB_PUT_BIT(struct happy_meal *hp, void __iomem *tregs, int bit) { @@ -1207,8 +1224,7 @@ static void happy_meal_clean_rings(struct happy_meal *hp) rxd = &hp->happy_block->happy_meal_rxd[i]; dma_addr = hme_read_desc32(hp, &rxd->rx_addr); - dma_unmap_single(hp->dma_dev, dma_addr, - RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE); + hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE); dev_kfree_skb_any(skb); hp->rx_skbs[i] = NULL; } @@ -1226,10 +1242,10 @@ static void happy_meal_clean_rings(struct happy_meal *hp) for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { txd = &hp->happy_block->happy_meal_txd[i]; dma_addr = hme_read_desc32(hp, &txd->tx_addr); - dma_unmap_single(hp->dma_dev, dma_addr, - (hme_read_desc32(hp, &txd->tx_flags) - & TXFLAG_SIZE), - DMA_TO_DEVICE); + hme_dma_unmap(hp, dma_addr, + (hme_read_desc32(hp, &txd->tx_flags) + & TXFLAG_SIZE), + DMA_TODEVICE); if (frag != skb_shinfo(skb)->nr_frags) i++; @@ -1271,8 +1287,7 @@ static void happy_meal_init_rings(struct happy_meal *hp) skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET + 4)); hme_write_rxd(hp, &hb->happy_meal_rxd[i], (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)), - dma_map_single(hp->dma_dev, skb->data, RX_BUF_ALLOC_SIZE, - DMA_FROM_DEVICE)); + hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE)); skb_reserve(skb, RX_OFFSET); } @@ -1578,7 +1593,7 @@ static int happy_meal_init(struct happy_meal *hp) if ((hp->happy_bursts & DMA_BURST64) && ((hp->happy_flags & HFLAG_PCI) != 0 #ifdef CONFIG_SBUS - || sbus_can_burst64() + || sbus_can_burst64(hp->happy_dev) #endif || 0)) { u32 gcfg = GREG_CFG_BURST64; @@ -1588,13 +1603,11 @@ static int happy_meal_init(struct happy_meal *hp) * do not. -DaveM */ #ifdef CONFIG_SBUS - if ((hp->happy_flags & HFLAG_PCI) == 0) { - struct of_device *op = hp->happy_dev; - if (sbus_can_dma_64bit()) { - sbus_set_sbus64(&op->dev, - hp->happy_bursts); - gcfg |= GREG_CFG_64BIT; - } + if ((hp->happy_flags & HFLAG_PCI) == 0 && + sbus_can_dma_64bit(hp->happy_dev)) { + sbus_set_sbus64(hp->happy_dev, + hp->happy_bursts); + gcfg |= GREG_CFG_64BIT; } #endif @@ -1953,7 +1966,7 @@ static void happy_meal_tx(struct happy_meal *hp) dma_len = hme_read_desc32(hp, &this->tx_flags); dma_len &= TXFLAG_SIZE; - dma_unmap_single(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE); + hme_dma_unmap(hp, dma_addr, dma_len, DMA_TODEVICE); elem = NEXT_TX(elem); this = &txbase[elem]; @@ -2031,14 +2044,13 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) drops++; goto drop_it; } - dma_unmap_single(hp->dma_dev, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE); + hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE); hp->rx_skbs[elem] = new_skb; new_skb->dev = dev; skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET + 4)); hme_write_rxd(hp, this, (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), - dma_map_single(hp->dma_dev, new_skb->data, RX_BUF_ALLOC_SIZE, - DMA_FROM_DEVICE)); + hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE)); skb_reserve(new_skb, RX_OFFSET); /* Trim the original skb for the netif. */ @@ -2053,9 +2065,10 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - dma_sync_single_for_cpu(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE); + hme_dma_sync_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE); skb_copy_from_linear_data(skb, copy_skb->data, len); - dma_sync_single_for_device(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE); + hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE); + /* Reuse original ring buffer. */ hme_write_rxd(hp, this, (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), @@ -2287,7 +2300,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 mapping, len; len = skb->len; - mapping = dma_map_single(hp->dma_dev, skb->data, len, DMA_TO_DEVICE); + mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE); tx_flags |= (TXFLAG_SOP | TXFLAG_EOP); hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], (tx_flags | (len & TXFLAG_SIZE)), @@ -2301,8 +2314,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) * Otherwise we could race with the device. */ first_len = skb_headlen(skb); - first_mapping = dma_map_single(hp->dma_dev, skb->data, first_len, - DMA_TO_DEVICE); + first_mapping = hme_dma_map(hp, skb->data, first_len, DMA_TODEVICE); entry = NEXT_TX(entry); for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { @@ -2310,9 +2322,10 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 len, mapping, this_txflags; len = this_frag->size; - mapping = dma_map_page(hp->dma_dev, this_frag->page, - this_frag->page_offset, len, - DMA_TO_DEVICE); + mapping = hme_dma_map(hp, + ((void *) page_address(this_frag->page) + + this_frag->page_offset), + len, DMA_TODEVICE); this_txflags = tx_flags; if (frag == skb_shinfo(skb)->nr_frags - 1) this_txflags |= TXFLAG_EOP; @@ -2480,12 +2493,9 @@ static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info } #ifdef CONFIG_SBUS else { - const struct linux_prom_registers *regs; - struct of_device *op = hp->happy_dev; - regs = of_get_property(op->node, "regs", NULL); - if (regs) - sprintf(info->bus_info, "SBUS:%d", - regs->which_io); + struct sbus_dev *sdev = hp->happy_dev; + sprintf(info->bus_info, "SBUS:%d", + sdev->slot); } #endif } @@ -2511,21 +2521,63 @@ static const struct ethtool_ops hme_ethtool_ops = { static int hme_version_printed; #ifdef CONFIG_SBUS +void __devinit quattro_get_ranges(struct quattro *qp) +{ + struct sbus_dev *sdev = qp->quattro_dev; + int err; + + err = prom_getproperty(sdev->prom_node, + "ranges", + (char *)&qp->ranges[0], + sizeof(qp->ranges)); + if (err == 0 || err == -1) { + qp->nranges = 0; + return; + } + qp->nranges = (err / sizeof(struct linux_prom_ranges)); +} + +static void __devinit quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp) +{ + struct sbus_dev *sdev = hp->happy_dev; + int rng; + + for (rng = 0; rng < qp->nranges; rng++) { + struct linux_prom_ranges *rngp = &qp->ranges[rng]; + int reg; + + for (reg = 0; reg < 5; reg++) { + if (sdev->reg_addrs[reg].which_io == + rngp->ot_child_space) + break; + } + if (reg == 5) + continue; + + sdev->reg_addrs[reg].which_io = rngp->ot_parent_space; + sdev->reg_addrs[reg].phys_addr += rngp->ot_parent_base; + } +} + /* Given a happy meal sbus device, find it's quattro parent. * If none exist, allocate and return a new one. * * Return NULL on failure. */ -static struct quattro * __devinit quattro_sbus_find(struct of_device *child) +static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev) { - struct device *parent = child->dev.parent; - struct of_device *op; + struct sbus_dev *sdev; struct quattro *qp; + int i; - op = to_of_device(parent); - qp = dev_get_drvdata(&op->dev); - if (qp) - return qp; + for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { + for (i = 0, sdev = qp->quattro_dev; + (sdev != NULL) && (i < 4); + sdev = sdev->next, i++) { + if (sdev == goal_sdev) + return qp; + } + } qp = kmalloc(sizeof(struct quattro), GFP_KERNEL); if (qp != NULL) { @@ -2534,11 +2586,10 @@ static struct quattro * __devinit quattro_sbus_find(struct of_device *child) for (i = 0; i < 4; i++) qp->happy_meals[i] = NULL; - qp->quattro_dev = child; + qp->quattro_dev = goal_sdev; qp->next = qfe_sbus_list; qfe_sbus_list = qp; - - dev_set_drvdata(&op->dev, qp); + quattro_get_ranges(qp); } return qp; } @@ -2551,10 +2602,10 @@ static void __init quattro_sbus_register_irqs(void) struct quattro *qp; for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { - struct of_device *op = qp->quattro_dev; + struct sbus_dev *sdev = qp->quattro_dev; int err; - err = request_irq(op->irqs[0], + err = request_irq(sdev->irqs[0], quattro_sbus_interrupt, IRQF_SHARED, "Quattro", qp); @@ -2570,9 +2621,9 @@ static void quattro_sbus_free_irqs(void) struct quattro *qp; for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { - struct of_device *op = qp->quattro_dev; + struct sbus_dev *sdev = qp->quattro_dev; - free_irq(op->irqs[0], qp); + free_irq(sdev->irqs[0], qp); } } #endif /* CONFIG_SBUS */ @@ -2609,9 +2660,9 @@ static struct quattro * __devinit quattro_pci_find(struct pci_dev *pdev) #endif /* CONFIG_PCI */ #ifdef CONFIG_SBUS -static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) +static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe) { - struct device_node *dp = op->node, *sbus_dp; + struct device_node *dp = sdev->ofdev.node; struct quattro *qp = NULL; struct happy_meal *hp; struct net_device *dev; @@ -2620,7 +2671,7 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) DECLARE_MAC_BUF(mac); if (is_qfe) { - qp = quattro_sbus_find(op); + qp = quattro_sbus_find(sdev); if (qp == NULL) goto err_out; for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) @@ -2634,7 +2685,7 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) dev = alloc_etherdev(sizeof(struct happy_meal)); if (!dev) goto err_out; - SET_NETDEV_DEV(dev, &op->dev); + SET_NETDEV_DEV(dev, &sdev->ofdev.dev); if (hme_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -2662,50 +2713,56 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) memcpy(dev->dev_addr, idprom->id_ethaddr, 6); } - hp = netdev_priv(dev); + hp = dev->priv; - hp->happy_dev = op; - hp->dma_dev = &op->dev; + hp->happy_dev = sdev; spin_lock_init(&hp->happy_lock); err = -ENODEV; + if (sdev->num_registers != 5) { + printk(KERN_ERR "happymeal: Device needs 5 regs, has %d.\n", + sdev->num_registers); + goto err_out_free_netdev; + } + if (qp != NULL) { hp->qfe_parent = qp; hp->qfe_ent = qfe_slot; qp->happy_meals[qfe_slot] = dev; + quattro_apply_ranges(qp, hp); } - hp->gregs = of_ioremap(&op->resource[0], 0, - GREG_REG_SIZE, "HME Global Regs"); + hp->gregs = sbus_ioremap(&sdev->resource[0], 0, + GREG_REG_SIZE, "HME Global Regs"); if (!hp->gregs) { printk(KERN_ERR "happymeal: Cannot map global registers.\n"); goto err_out_free_netdev; } - hp->etxregs = of_ioremap(&op->resource[1], 0, - ETX_REG_SIZE, "HME TX Regs"); + hp->etxregs = sbus_ioremap(&sdev->resource[1], 0, + ETX_REG_SIZE, "HME TX Regs"); if (!hp->etxregs) { printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n"); goto err_out_iounmap; } - hp->erxregs = of_ioremap(&op->resource[2], 0, - ERX_REG_SIZE, "HME RX Regs"); + hp->erxregs = sbus_ioremap(&sdev->resource[2], 0, + ERX_REG_SIZE, "HME RX Regs"); if (!hp->erxregs) { printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n"); goto err_out_iounmap; } - hp->bigmacregs = of_ioremap(&op->resource[3], 0, - BMAC_REG_SIZE, "HME BIGMAC Regs"); + hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0, + BMAC_REG_SIZE, "HME BIGMAC Regs"); if (!hp->bigmacregs) { printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n"); goto err_out_iounmap; } - hp->tcvregs = of_ioremap(&op->resource[4], 0, - TCVR_REG_SIZE, "HME Tranceiver Regs"); + hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0, + TCVR_REG_SIZE, "HME Tranceiver Regs"); if (!hp->tcvregs) { printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n"); goto err_out_iounmap; @@ -2724,18 +2781,13 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) if (qp != NULL) hp->happy_flags |= HFLAG_QUATTRO; - sbus_dp = to_of_device(op->dev.parent)->node; - if (is_qfe) - sbus_dp = to_of_device(op->dev.parent->parent)->node; - /* Get the supported DVMA burst sizes from our Happy SBUS. */ - hp->happy_bursts = of_getintprop_default(sbus_dp, + hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node, "burst-sizes", 0x00); - hp->happy_block = dma_alloc_coherent(hp->dma_dev, - PAGE_SIZE, - &hp->hblock_dvma, - GFP_ATOMIC); + hp->happy_block = sbus_alloc_consistent(hp->happy_dev, + PAGE_SIZE, + &hp->hblock_dvma); err = -ENOMEM; if (!hp->happy_block) { printk(KERN_ERR "happymeal: Cannot allocate descriptors.\n"); @@ -2764,13 +2816,19 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) /* Happy Meal can do it all... */ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; - dev->irq = op->irqs[0]; + dev->irq = sdev->irqs[0]; #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) - /* Hook up SBUS register/descriptor accessors. */ + /* Hook up PCI register/dma accessors. */ hp->read_desc32 = sbus_hme_read_desc32; hp->write_txd = sbus_hme_write_txd; hp->write_rxd = sbus_hme_write_rxd; + hp->dma_map = (u32 (*)(void *, void *, long, int))sbus_map_single; + hp->dma_unmap = (void (*)(void *, u32, long, int))sbus_unmap_single; + hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int)) + sbus_dma_sync_single_for_cpu; + hp->dma_sync_for_device = (void (*)(void *, u32, long, int)) + sbus_dma_sync_single_for_device; hp->read32 = sbus_hme_read32; hp->write32 = sbus_hme_write32; #endif @@ -2785,10 +2843,10 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) if (register_netdev(hp->dev)) { printk(KERN_ERR "happymeal: Cannot register net device, " "aborting.\n"); - goto err_out_free_coherent; + goto err_out_free_consistent; } - dev_set_drvdata(&op->dev, hp); + dev_set_drvdata(&sdev->ofdev.dev, hp); if (qfe_slot != -1) printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ", @@ -2801,23 +2859,23 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) return 0; -err_out_free_coherent: - dma_free_coherent(hp->dma_dev, - PAGE_SIZE, - hp->happy_block, - hp->hblock_dvma); +err_out_free_consistent: + sbus_free_consistent(hp->happy_dev, + PAGE_SIZE, + hp->happy_block, + hp->hblock_dvma); err_out_iounmap: if (hp->gregs) - of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE); + sbus_iounmap(hp->gregs, GREG_REG_SIZE); if (hp->etxregs) - of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE); + sbus_iounmap(hp->etxregs, ETX_REG_SIZE); if (hp->erxregs) - of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE); + sbus_iounmap(hp->erxregs, ERX_REG_SIZE); if (hp->bigmacregs) - of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE); + sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE); if (hp->tcvregs) - of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE); + sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE); err_out_free_netdev: free_netdev(dev); @@ -2977,7 +3035,6 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, memset(hp, 0, sizeof(*hp)); hp->happy_dev = pdev; - hp->dma_dev = &pdev->dev; spin_lock_init(&hp->happy_lock); @@ -3064,7 +3121,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, #endif hp->happy_block = (struct hmeal_init_block *) - dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &hp->hblock_dvma, GFP_KERNEL); + pci_alloc_consistent(pdev, PAGE_SIZE, &hp->hblock_dvma); err = -ENODEV; if (!hp->happy_block) { @@ -3094,10 +3151,16 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) - /* Hook up PCI register/descriptor accessors. */ + /* Hook up PCI register/dma accessors. */ hp->read_desc32 = pci_hme_read_desc32; hp->write_txd = pci_hme_write_txd; hp->write_rxd = pci_hme_write_rxd; + hp->dma_map = (u32 (*)(void *, void *, long, int))pci_map_single; + hp->dma_unmap = (void (*)(void *, u32, long, int))pci_unmap_single; + hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int)) + pci_dma_sync_single_for_cpu; + hp->dma_sync_for_device = (void (*)(void *, u32, long, int)) + pci_dma_sync_single_for_device; hp->read32 = pci_hme_read32; hp->write32 = pci_hme_write32; #endif @@ -3168,8 +3231,10 @@ static void __devexit happy_meal_pci_remove(struct pci_dev *pdev) unregister_netdev(net_dev); - dma_free_coherent(hp->dma_dev, PAGE_SIZE, - hp->happy_block, hp->hblock_dvma); + pci_free_consistent(hp->happy_dev, + PAGE_SIZE, + hp->happy_block, + hp->hblock_dvma); iounmap(hp->gregs); pci_release_regions(hp->happy_dev); @@ -3214,45 +3279,46 @@ static void happy_meal_pci_exit(void) #endif #ifdef CONFIG_SBUS -static int __devinit hme_sbus_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + struct device_node *dp = dev->node; const char *model = of_get_property(dp, "model", NULL); int is_qfe = (match->data != NULL); if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe")) is_qfe = 1; - return happy_meal_sbus_probe_one(op, is_qfe); + return happy_meal_sbus_probe_one(sdev, is_qfe); } -static int __devexit hme_sbus_remove(struct of_device *op) +static int __devexit hme_sbus_remove(struct of_device *dev) { - struct happy_meal *hp = dev_get_drvdata(&op->dev); + struct happy_meal *hp = dev_get_drvdata(&dev->dev); struct net_device *net_dev = hp->dev; unregister_netdev(net_dev); /* XXX qfe parent interrupt... */ - of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE); - of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE); - of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE); - of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE); - of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE); - dma_free_coherent(hp->dma_dev, - PAGE_SIZE, - hp->happy_block, - hp->hblock_dvma); + sbus_iounmap(hp->gregs, GREG_REG_SIZE); + sbus_iounmap(hp->etxregs, ETX_REG_SIZE); + sbus_iounmap(hp->erxregs, ERX_REG_SIZE); + sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE); + sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE); + sbus_free_consistent(hp->happy_dev, + PAGE_SIZE, + hp->happy_block, + hp->hblock_dvma); free_netdev(net_dev); - dev_set_drvdata(&op->dev, NULL); + dev_set_drvdata(&dev->dev, NULL); return 0; } -static const struct of_device_id hme_sbus_match[] = { +static struct of_device_id hme_sbus_match[] = { { .name = "SUNW,hme", }, @@ -3280,7 +3346,7 @@ static int __init happy_meal_sbus_init(void) { int err; - err = of_register_driver(&hme_sbus_driver, &of_bus_type); + err = of_register_driver(&hme_sbus_driver, &sbus_bus_type); if (!err) quattro_sbus_register_irqs(); diff --git a/trunk/drivers/net/sunhme.h b/trunk/drivers/net/sunhme.h index efd2ca0fcad3..4da5539fac7b 100644 --- a/trunk/drivers/net/sunhme.h +++ b/trunk/drivers/net/sunhme.h @@ -405,11 +405,14 @@ struct happy_meal { u32 (*read_desc32)(hme32 *); void (*write_txd)(struct happy_meal_txd *, u32, u32); void (*write_rxd)(struct happy_meal_rxd *, u32, u32); + u32 (*dma_map)(void *, void *, long, int); + void (*dma_unmap)(void *, u32, long, int); + void (*dma_sync_for_cpu)(void *, u32, long, int); + void (*dma_sync_for_device)(void *, u32, long, int); #endif - /* This is either an of_device or a pci_dev. */ + /* This is either a sbus_dev or a pci_dev. */ void *happy_dev; - struct device *dma_dev; spinlock_t happy_lock; diff --git a/trunk/drivers/net/sunlance.c b/trunk/drivers/net/sunlance.c index 704301a5a7ff..4e994f87469e 100644 --- a/trunk/drivers/net/sunlance.c +++ b/trunk/drivers/net/sunlance.c @@ -91,9 +91,6 @@ static char lancestr[] = "LANCE"; #include #include #include -#include -#include -#include #include #include @@ -101,6 +98,7 @@ static char lancestr[] = "LANCE"; #include #include /* Used by the checksum routines */ #include +#include #include #include /* For tpe-link-test? setting */ #include @@ -250,7 +248,7 @@ struct lance_private { int rx_new, tx_new; int rx_old, tx_old; - struct of_device *ledma; /* If set this points to ledma */ + struct sbus_dma *ledma; /* If set this points to ledma */ char tpe; /* cable-selection is TPE */ char auto_select; /* cable-selection by carrier */ char burst_sizes; /* ledma SBus burst sizes */ @@ -265,8 +263,7 @@ struct lance_private { char *name; dma_addr_t init_block_dvma; struct net_device *dev; /* Backpointer */ - struct of_device *op; - struct of_device *lebuffer; + struct sbus_dev *sdev; struct timer_list multicast_timer; }; @@ -1275,29 +1272,27 @@ static void lance_set_multicast_retry(unsigned long _opaque) static void lance_free_hwresources(struct lance_private *lp) { if (lp->lregs) - of_iounmap(&lp->op->resource[0], lp->lregs, LANCE_REG_SIZE); - if (lp->dregs) { - struct of_device *ledma = lp->ledma; - - of_iounmap(&ledma->resource[0], lp->dregs, - resource_size(&ledma->resource[0])); - } + sbus_iounmap(lp->lregs, LANCE_REG_SIZE); if (lp->init_block_iomem) { - of_iounmap(&lp->lebuffer->resource[0], lp->init_block_iomem, - sizeof(struct lance_init_block)); + sbus_iounmap(lp->init_block_iomem, + sizeof(struct lance_init_block)); } else if (lp->init_block_mem) { - dma_free_coherent(&lp->op->dev, - sizeof(struct lance_init_block), - lp->init_block_mem, - lp->init_block_dvma); + sbus_free_consistent(lp->sdev, + sizeof(struct lance_init_block), + lp->init_block_mem, + lp->init_block_dvma); } } /* Ethtool support... */ static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { + struct lance_private *lp = netdev_priv(dev); + strcpy(info->driver, "sunlance"); strcpy(info->version, "2.02"); + sprintf(info->bus_info, "SBUS:%d", + lp->sdev->slot); } static u32 sparc_lance_get_link(struct net_device *dev) @@ -1313,16 +1308,16 @@ static const struct ethtool_ops sparc_lance_ethtool_ops = { .get_link = sparc_lance_get_link, }; -static int __devinit sparc_lance_probe_one(struct of_device *op, - struct of_device *ledma, - struct of_device *lebuffer) +static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, + struct sbus_dma *ledma, + struct sbus_dev *lebuffer) { - struct device_node *dp = op->node; static unsigned version_printed; - struct lance_private *lp; + struct device_node *dp = sdev->ofdev.node; struct net_device *dev; - DECLARE_MAC_BUF(mac); + struct lance_private *lp; int i; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct lance_private) + 8); if (!dev) @@ -1343,27 +1338,14 @@ static int __devinit sparc_lance_probe_one(struct of_device *op, dev->dev_addr[i] = idprom->id_ethaddr[i]; /* Get the IO region */ - lp->lregs = of_ioremap(&op->resource[0], 0, - LANCE_REG_SIZE, lancestr); + lp->lregs = sbus_ioremap(&sdev->resource[0], 0, + LANCE_REG_SIZE, lancestr); if (!lp->lregs) { printk(KERN_ERR "SunLance: Cannot map registers.\n"); goto fail; } - lp->ledma = ledma; - if (lp->ledma) { - lp->dregs = of_ioremap(&ledma->resource[0], 0, - resource_size(&ledma->resource[0]), - "ledma"); - if (!lp->dregs) { - printk(KERN_ERR "SunLance: Cannot map " - "ledma registers.\n"); - goto fail; - } - } - - lp->op = op; - lp->lebuffer = lebuffer; + lp->sdev = sdev; if (lebuffer) { /* sanity check */ if (lebuffer->resource[0].start & 7) { @@ -1371,8 +1353,8 @@ static int __devinit sparc_lance_probe_one(struct of_device *op, goto fail; } lp->init_block_iomem = - of_ioremap(&lebuffer->resource[0], 0, - sizeof(struct lance_init_block), "lebuffer"); + sbus_ioremap(&lebuffer->resource[0], 0, + sizeof(struct lance_init_block), "lebuffer"); if (!lp->init_block_iomem) { printk(KERN_ERR "SunLance: Cannot map PIO buffer.\n"); goto fail; @@ -1384,10 +1366,9 @@ static int __devinit sparc_lance_probe_one(struct of_device *op, lp->tx = lance_tx_pio; } else { lp->init_block_mem = - dma_alloc_coherent(&op->dev, - sizeof(struct lance_init_block), - &lp->init_block_dvma, GFP_ATOMIC); - if (!lp->init_block_mem) { + sbus_alloc_consistent(sdev, sizeof(struct lance_init_block), + &lp->init_block_dvma); + if (!lp->init_block_mem || lp->init_block_dvma == 0) { printk(KERN_ERR "SunLance: Cannot allocate consistent DMA memory.\n"); goto fail; } @@ -1402,13 +1383,13 @@ static int __devinit sparc_lance_probe_one(struct of_device *op, LE_C3_BCON)); lp->name = lancestr; + lp->ledma = ledma; lp->burst_sizes = 0; if (lp->ledma) { - struct device_node *ledma_dp = ledma->node; - struct device_node *sbus_dp; - unsigned int sbmask; + struct device_node *ledma_dp = ledma->sdev->ofdev.node; const char *prop; + unsigned int sbmask; u32 csr; /* Find burst-size property for ledma */ @@ -1416,8 +1397,7 @@ static int __devinit sparc_lance_probe_one(struct of_device *op, "burst-sizes", 0); /* ledma may be capable of fast bursts, but sbus may not. */ - sbus_dp = ledma_dp->parent; - sbmask = of_getintprop_default(sbus_dp, "burst-sizes", + sbmask = of_getintprop_default(ledma_dp, "burst-sizes", DMA_BURSTBITS); lp->burst_sizes &= sbmask; @@ -1455,6 +1435,8 @@ static int __devinit sparc_lance_probe_one(struct of_device *op, lp->tpe = 1; } + lp->dregs = ledma->regs; + /* Reset ledma */ csr = sbus_readl(lp->dregs + DMA_CSR); sbus_writel(csr | DMA_RST_ENET, lp->dregs + DMA_CSR); @@ -1464,7 +1446,7 @@ static int __devinit sparc_lance_probe_one(struct of_device *op, lp->dregs = NULL; lp->dev = dev; - SET_NETDEV_DEV(dev, &op->dev); + SET_NETDEV_DEV(dev, &sdev->ofdev.dev); dev->open = &lance_open; dev->stop = &lance_close; dev->hard_start_xmit = &lance_start_xmit; @@ -1473,7 +1455,9 @@ static int __devinit sparc_lance_probe_one(struct of_device *op, dev->set_multicast_list = &lance_set_multicast; dev->ethtool_ops = &sparc_lance_ethtool_ops; - dev->irq = op->irqs[0]; + dev->irq = sdev->irqs[0]; + + dev->dma = 0; /* We cannot sleep if the chip is busy during a * multicast list update event, because such events @@ -1489,7 +1473,7 @@ static int __devinit sparc_lance_probe_one(struct of_device *op, goto fail; } - dev_set_drvdata(&op->dev, lp); + dev_set_drvdata(&sdev->ofdev.dev, lp); printk(KERN_INFO "%s: LANCE %s\n", dev->name, print_mac(mac, dev->dev_addr)); @@ -1502,25 +1486,80 @@ static int __devinit sparc_lance_probe_one(struct of_device *op, return -ENODEV; } -static int __devinit sunlance_sbus_probe(struct of_device *op, const struct of_device_id *match) +/* On 4m, find the associated dma for the lance chip */ +static struct sbus_dma * __devinit find_ledma(struct sbus_dev *sdev) +{ + struct sbus_dma *p; + + for_each_dvma(p) { + if (p->sdev == sdev) + return p; + } + return NULL; +} + +#ifdef CONFIG_SUN4 + +#include +#include + +/* Find all the lance cards on the system and initialize them */ +static struct sbus_dev sun4_sdev; +static int __devinit sparc_lance_init(void) +{ + if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) || + (idprom->id_machtype == (SM_SUN4|SM_4_470))) { + memset(&sun4_sdev, 0, sizeof(struct sbus_dev)); + sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr; + sun4_sdev.irqs[0] = 6; + return sparc_lance_probe_one(&sun4_sdev, NULL, NULL); + } + return -ENODEV; +} + +static int __exit sunlance_sun4_remove(void) { - struct of_device *parent = to_of_device(op->dev.parent); - struct device_node *parent_dp = parent->node; + struct lance_private *lp = dev_get_drvdata(&sun4_sdev.ofdev.dev); + struct net_device *net_dev = lp->dev; + + unregister_netdev(net_dev); + + lance_free_hwresources(lp); + + free_netdev(net_dev); + + dev_set_drvdata(&sun4_sdev.ofdev.dev, NULL); + + return 0; +} + +#else /* !CONFIG_SUN4 */ + +static int __devinit sunlance_sbus_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct sbus_dev *sdev = to_sbus_device(&dev->dev); int err; - if (!strcmp(parent_dp->name, "ledma")) { - err = sparc_lance_probe_one(op, parent, NULL); - } else if (!strcmp(parent_dp->name, "lebuffer")) { - err = sparc_lance_probe_one(op, NULL, parent); + if (sdev->parent) { + struct of_device *parent = &sdev->parent->ofdev; + + if (!strcmp(parent->node->name, "ledma")) { + struct sbus_dma *ledma = find_ledma(to_sbus_device(&parent->dev)); + + err = sparc_lance_probe_one(sdev, ledma, NULL); + } else if (!strcmp(parent->node->name, "lebuffer")) { + err = sparc_lance_probe_one(sdev, NULL, to_sbus_device(&parent->dev)); + } else + err = sparc_lance_probe_one(sdev, NULL, NULL); } else - err = sparc_lance_probe_one(op, NULL, NULL); + err = sparc_lance_probe_one(sdev, NULL, NULL); return err; } -static int __devexit sunlance_sbus_remove(struct of_device *op) +static int __devexit sunlance_sbus_remove(struct of_device *dev) { - struct lance_private *lp = dev_get_drvdata(&op->dev); + struct lance_private *lp = dev_get_drvdata(&dev->dev); struct net_device *net_dev = lp->dev; unregister_netdev(net_dev); @@ -1529,12 +1568,12 @@ static int __devexit sunlance_sbus_remove(struct of_device *op) free_netdev(net_dev); - dev_set_drvdata(&op->dev, NULL); + dev_set_drvdata(&dev->dev, NULL); return 0; } -static const struct of_device_id sunlance_sbus_match[] = { +static struct of_device_id sunlance_sbus_match[] = { { .name = "le", }, @@ -1554,12 +1593,17 @@ static struct of_platform_driver sunlance_sbus_driver = { /* Find all the lance cards on the system and initialize them */ static int __init sparc_lance_init(void) { - return of_register_driver(&sunlance_sbus_driver, &of_bus_type); + return of_register_driver(&sunlance_sbus_driver, &sbus_bus_type); } +#endif /* !CONFIG_SUN4 */ static void __exit sparc_lance_exit(void) { +#ifdef CONFIG_SUN4 + sunlance_sun4_remove(); +#else of_unregister_driver(&sunlance_sbus_driver); +#endif } module_init(sparc_lance_init); diff --git a/trunk/drivers/net/sunqe.c b/trunk/drivers/net/sunqe.c index f63644744ff9..e811331d4608 100644 --- a/trunk/drivers/net/sunqe.c +++ b/trunk/drivers/net/sunqe.c @@ -3,7 +3,7 @@ * controller out there can be most efficiently programmed * if you make it look like a LANCE. * - * Copyright (C) 1996, 1999, 2003, 2006, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996, 1999, 2003, 2006 David S. Miller (davem@davemloft.net) */ #include @@ -24,15 +24,13 @@ #include #include #include -#include -#include -#include #include #include #include #include #include +#include #include #include #include @@ -42,8 +40,8 @@ #include "sunqe.h" #define DRV_NAME "sunqe" -#define DRV_VERSION "4.1" -#define DRV_RELDATE "August 27, 2008" +#define DRV_VERSION "4.0" +#define DRV_RELDATE "June 23, 2006" #define DRV_AUTHOR "David S. Miller (davem@davemloft.net)" static char version[] = @@ -692,18 +690,12 @@ static void qe_set_multicast(struct net_device *dev) /* Ethtool support... */ static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - const struct linux_prom_registers *regs; struct sunqe *qep = dev->priv; - struct of_device *op; strcpy(info->driver, "sunqe"); strcpy(info->version, "3.0"); - - op = qep->op; - regs = of_get_property(op->node, "reg", NULL); - if (regs) - sprintf(info->bus_info, "SBUS:%d", regs->which_io); - + sprintf(info->bus_info, "SBUS:%d", + qep->qe_sdev->slot); } static u32 qe_get_link(struct net_device *dev) @@ -725,11 +717,11 @@ static const struct ethtool_ops qe_ethtool_ops = { }; /* This is only called once at boot time for each card probed. */ -static void qec_init_once(struct sunqec *qecp, struct of_device *op) +static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev) { u8 bsizes = qecp->qec_bursts; - if (sbus_can_burst64() && (bsizes & DMA_BURST64)) { + if (sbus_can_burst64(qsdev) && (bsizes & DMA_BURST64)) { sbus_writel(GLOB_CTRL_B64, qecp->gregs + GLOB_CTRL); } else if (bsizes & DMA_BURST32) { sbus_writel(GLOB_CTRL_B32, qecp->gregs + GLOB_CTRL); @@ -743,15 +735,15 @@ static void qec_init_once(struct sunqec *qecp, struct of_device *op) sbus_writel(GLOB_PSIZE_2048, qecp->gregs + GLOB_PSIZE); /* Set the local memsize register, divided up to one piece per QE channel. */ - sbus_writel((resource_size(&op->resource[1]) >> 2), + sbus_writel((qsdev->reg_addrs[1].reg_size >> 2), qecp->gregs + GLOB_MSIZE); /* Divide up the local QEC memory amongst the 4 QE receiver and * transmitter FIFOs. Basically it is (total / 2 / num_channels). */ - sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1, + sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1, qecp->gregs + GLOB_TSIZE); - sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1, + sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1, qecp->gregs + GLOB_RSIZE); } @@ -775,21 +767,24 @@ static u8 __devinit qec_get_burst(struct device_node *dp) return bsizes; } -static struct sunqec * __devinit get_qec(struct of_device *child) +static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev) { - struct of_device *op = to_of_device(child->dev.parent); + struct sbus_dev *qec_sdev = child_sdev->parent; struct sunqec *qecp; - qecp = dev_get_drvdata(&op->dev); + for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) { + if (qecp->qec_sdev == qec_sdev) + break; + } if (!qecp) { qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL); if (qecp) { u32 ctrl; - qecp->op = op; - qecp->gregs = of_ioremap(&op->resource[0], 0, - GLOB_REG_SIZE, - "QEC Global Registers"); + qecp->qec_sdev = qec_sdev; + qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0, + GLOB_REG_SIZE, + "QEC Global Registers"); if (!qecp->gregs) goto fail; @@ -804,18 +799,16 @@ static struct sunqec * __devinit get_qec(struct of_device *child) if (qec_global_reset(qecp->gregs)) goto fail; - qecp->qec_bursts = qec_get_burst(op->node); + qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node); - qec_init_once(qecp, op); + qec_init_once(qecp, qec_sdev); - if (request_irq(op->irqs[0], &qec_interrupt, + if (request_irq(qec_sdev->irqs[0], &qec_interrupt, IRQF_SHARED, "qec", (void *) qecp)) { printk(KERN_ERR "qec: Can't register irq.\n"); goto fail; } - dev_set_drvdata(&op->dev, qecp); - qecp->next_module = root_qec_dev; root_qec_dev = qecp; } @@ -825,17 +818,17 @@ static struct sunqec * __devinit get_qec(struct of_device *child) fail: if (qecp->gregs) - of_iounmap(&op->resource[0], qecp->gregs, GLOB_REG_SIZE); + sbus_iounmap(qecp->gregs, GLOB_REG_SIZE); kfree(qecp); return NULL; } -static int __devinit qec_ether_init(struct of_device *op) +static int __devinit qec_ether_init(struct sbus_dev *sdev) { static unsigned version_printed; struct net_device *dev; - struct sunqec *qecp; struct sunqe *qe; + struct sunqec *qecp; int i, res; if (version_printed++ == 0) @@ -849,42 +842,49 @@ static int __devinit qec_ether_init(struct of_device *op) qe = netdev_priv(dev); - res = -ENODEV; - - i = of_getintprop_default(op->node, "channel#", -1); - if (i == -1) - goto fail; + i = of_getintprop_default(sdev->ofdev.node, "channel#", -1); + if (i == -1) { + struct sbus_dev *td = sdev->parent->child; + i = 0; + while (td != sdev) { + td = td->next; + i++; + } + } qe->channel = i; spin_lock_init(&qe->lock); - qecp = get_qec(op); + res = -ENODEV; + qecp = get_qec(sdev); if (!qecp) goto fail; qecp->qes[qe->channel] = qe; qe->dev = dev; qe->parent = qecp; - qe->op = op; + qe->qe_sdev = sdev; res = -ENOMEM; - qe->qcregs = of_ioremap(&op->resource[0], 0, - CREG_REG_SIZE, "QEC Channel Registers"); + qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0, + CREG_REG_SIZE, "QEC Channel Registers"); if (!qe->qcregs) { printk(KERN_ERR "qe: Cannot map channel registers.\n"); goto fail; } - qe->mregs = of_ioremap(&op->resource[1], 0, - MREGS_REG_SIZE, "QE MACE Registers"); + qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0, + MREGS_REG_SIZE, "QE MACE Registers"); if (!qe->mregs) { printk(KERN_ERR "qe: Cannot map MACE registers.\n"); goto fail; } - qe->qe_block = dma_alloc_coherent(&op->dev, PAGE_SIZE, - &qe->qblock_dvma, GFP_ATOMIC); - qe->buffers = dma_alloc_coherent(&op->dev, sizeof(struct sunqe_buffers), - &qe->buffers_dvma, GFP_ATOMIC); + qe->qe_block = sbus_alloc_consistent(qe->qe_sdev, + PAGE_SIZE, + &qe->qblock_dvma); + qe->buffers = sbus_alloc_consistent(qe->qe_sdev, + sizeof(struct sunqe_buffers), + &qe->buffers_dvma); if (qe->qe_block == NULL || qe->qblock_dvma == 0 || qe->buffers == NULL || qe->buffers_dvma == 0) goto fail; @@ -892,7 +892,7 @@ static int __devinit qec_ether_init(struct of_device *op) /* Stop this QE. */ qe_stop(qe); - SET_NETDEV_DEV(dev, &op->dev); + SET_NETDEV_DEV(dev, &sdev->ofdev.dev); dev->open = qe_open; dev->stop = qe_close; @@ -900,7 +900,7 @@ static int __devinit qec_ether_init(struct of_device *op) dev->set_multicast_list = qe_set_multicast; dev->tx_timeout = qe_tx_timeout; dev->watchdog_timeo = 5*HZ; - dev->irq = op->irqs[0]; + dev->irq = sdev->irqs[0]; dev->dma = 0; dev->ethtool_ops = &qe_ethtool_ops; @@ -908,7 +908,7 @@ static int __devinit qec_ether_init(struct of_device *op) if (res) goto fail; - dev_set_drvdata(&op->dev, qe); + dev_set_drvdata(&sdev->ofdev.dev, qe); printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel); for (i = 0; i < 6; i++) @@ -922,50 +922,58 @@ static int __devinit qec_ether_init(struct of_device *op) fail: if (qe->qcregs) - of_iounmap(&op->resource[0], qe->qcregs, CREG_REG_SIZE); + sbus_iounmap(qe->qcregs, CREG_REG_SIZE); if (qe->mregs) - of_iounmap(&op->resource[1], qe->mregs, MREGS_REG_SIZE); + sbus_iounmap(qe->mregs, MREGS_REG_SIZE); if (qe->qe_block) - dma_free_coherent(&op->dev, PAGE_SIZE, - qe->qe_block, qe->qblock_dvma); + sbus_free_consistent(qe->qe_sdev, + PAGE_SIZE, + qe->qe_block, + qe->qblock_dvma); if (qe->buffers) - dma_free_coherent(&op->dev, - sizeof(struct sunqe_buffers), - qe->buffers, - qe->buffers_dvma); + sbus_free_consistent(qe->qe_sdev, + sizeof(struct sunqe_buffers), + qe->buffers, + qe->buffers_dvma); free_netdev(dev); return res; } -static int __devinit qec_sbus_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match) { - return qec_ether_init(op); + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + + return qec_ether_init(sdev); } -static int __devexit qec_sbus_remove(struct of_device *op) +static int __devexit qec_sbus_remove(struct of_device *dev) { - struct sunqe *qp = dev_get_drvdata(&op->dev); + struct sunqe *qp = dev_get_drvdata(&dev->dev); struct net_device *net_dev = qp->dev; unregister_netdev(net_dev); - of_iounmap(&op->resource[0], qp->qcregs, CREG_REG_SIZE); - of_iounmap(&op->resource[1], qp->mregs, MREGS_REG_SIZE); - dma_free_coherent(&op->dev, PAGE_SIZE, - qp->qe_block, qp->qblock_dvma); - dma_free_coherent(&op->dev, sizeof(struct sunqe_buffers), - qp->buffers, qp->buffers_dvma); + sbus_iounmap(qp->qcregs, CREG_REG_SIZE); + sbus_iounmap(qp->mregs, MREGS_REG_SIZE); + sbus_free_consistent(qp->qe_sdev, + PAGE_SIZE, + qp->qe_block, + qp->qblock_dvma); + sbus_free_consistent(qp->qe_sdev, + sizeof(struct sunqe_buffers), + qp->buffers, + qp->buffers_dvma); free_netdev(net_dev); - dev_set_drvdata(&op->dev, NULL); + dev_set_drvdata(&dev->dev, NULL); return 0; } -static const struct of_device_id qec_sbus_match[] = { +static struct of_device_id qec_sbus_match[] = { { .name = "qe", }, @@ -983,7 +991,7 @@ static struct of_platform_driver qec_sbus_driver = { static int __init qec_init(void) { - return of_register_driver(&qec_sbus_driver, &of_bus_type); + return of_register_driver(&qec_sbus_driver, &sbus_bus_type); } static void __exit qec_exit(void) @@ -992,11 +1000,11 @@ static void __exit qec_exit(void) while (root_qec_dev) { struct sunqec *next = root_qec_dev->next_module; - struct of_device *op = root_qec_dev->op; - free_irq(op->irqs[0], (void *) root_qec_dev); - of_iounmap(&op->resource[0], root_qec_dev->gregs, - GLOB_REG_SIZE); + free_irq(root_qec_dev->qec_sdev->irqs[0], + (void *) root_qec_dev); + sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE); + kfree(root_qec_dev); root_qec_dev = next; diff --git a/trunk/drivers/net/sunqe.h b/trunk/drivers/net/sunqe.h index 5813a7b2faa5..347c8ddc1592 100644 --- a/trunk/drivers/net/sunqe.h +++ b/trunk/drivers/net/sunqe.h @@ -314,7 +314,7 @@ struct sunqec { void __iomem *gregs; /* QEC Global Registers */ struct sunqe *qes[4]; /* Each child MACE */ unsigned int qec_bursts; /* Support burst sizes */ - struct of_device *op; /* QEC's OF device */ + struct sbus_dev *qec_sdev; /* QEC's SBUS device */ struct sunqec *next_module; /* List of all QECs in system */ }; @@ -342,7 +342,7 @@ struct sunqe { __u32 buffers_dvma; /* DVMA visible address. */ struct sunqec *parent; u8 mconfig; /* Base MACE mconfig value */ - struct of_device *op; /* QE's OF device struct */ + struct sbus_dev *qe_sdev; /* QE's SBUS device struct */ struct net_device *dev; /* QE's netdevice struct */ int channel; /* Who am I? */ }; diff --git a/trunk/drivers/net/sunvnet.c b/trunk/drivers/net/sunvnet.c index a720065553df..6415ce15c2ef 100644 --- a/trunk/drivers/net/sunvnet.c +++ b/trunk/drivers/net/sunvnet.c @@ -1,6 +1,6 @@ /* sunvnet.c: Sun LDOM Virtual Network Driver. * - * Copyright (C) 2007, 2008 David S. Miller + * Copyright (C) 2007 David S. Miller */ #include @@ -1260,7 +1260,7 @@ static int vnet_port_remove(struct vio_dev *vdev) return 0; } -static const struct vio_device_id vnet_port_match[] = { +static struct vio_device_id vnet_port_match[] = { { .type = "vnet-port", }, diff --git a/trunk/drivers/parport/parport_sunbpp.c b/trunk/drivers/parport/parport_sunbpp.c index 065f229580d5..9d595aa91e46 100644 --- a/trunk/drivers/parport/parport_sunbpp.c +++ b/trunk/drivers/parport/parport_sunbpp.c @@ -26,8 +26,6 @@ #include #include #include -#include -#include #include @@ -36,6 +34,7 @@ #include #include /* OpenProm Library */ +#include #include /* BPP uses LSI 64854 for DMA */ #include #include @@ -286,37 +285,38 @@ static struct parport_operations parport_sunbpp_ops = .owner = THIS_MODULE, }; -static int __devinit bpp_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit init_one_port(struct sbus_dev *sdev) { + struct parport *p; + /* at least in theory there may be a "we don't dma" case */ struct parport_operations *ops; - struct bpp_regs __iomem *regs; + void __iomem *base; int irq, dma, err = 0, size; + struct bpp_regs __iomem *regs; unsigned char value_tcr; - void __iomem *base; - struct parport *p; - irq = op->irqs[0]; - base = of_ioremap(&op->resource[0], 0, - resource_size(&op->resource[0]), - "sunbpp"); + irq = sdev->irqs[0]; + base = sbus_ioremap(&sdev->resource[0], 0, + sdev->reg_addrs[0].reg_size, + "sunbpp"); if (!base) return -ENODEV; - size = resource_size(&op->resource[0]); + size = sdev->reg_addrs[0].reg_size; dma = PARPORT_DMA_NONE; ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL); if (!ops) goto out_unmap; - memcpy (ops, &parport_sunbpp_ops, sizeof(struct parport_operations)); + memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations)); dprintk(("register_port\n")); if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) goto out_free_ops; p->size = size; - p->dev = &op->dev; + p->dev = &sdev->ofdev.dev; if ((err = request_irq(p->irq, parport_irq_handler, IRQF_SHARED, p->name, p)) != 0) { @@ -333,7 +333,7 @@ static int __devinit bpp_probe(struct of_device *op, const struct of_device_id * printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base); - dev_set_drvdata(&op->dev, p); + dev_set_drvdata(&sdev->ofdev.dev, p); parport_announce_port(p); @@ -346,14 +346,21 @@ static int __devinit bpp_probe(struct of_device *op, const struct of_device_id * kfree(ops); out_unmap: - of_iounmap(&op->resource[0], base, size); + sbus_iounmap(base, size); return err; } -static int __devexit bpp_remove(struct of_device *op) +static int __devinit bpp_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + + return init_one_port(sdev); +} + +static int __devexit bpp_remove(struct of_device *dev) { - struct parport *p = dev_get_drvdata(&op->dev); + struct parport *p = dev_get_drvdata(&dev->dev); struct parport_operations *ops = p->ops; parport_remove_port(p); @@ -363,16 +370,16 @@ static int __devexit bpp_remove(struct of_device *op) free_irq(p->irq, p); } - of_iounmap(&op->resource[0], (void __iomem *) p->base, p->size); + sbus_iounmap((void __iomem *) p->base, p->size); parport_put_port(p); kfree(ops); - dev_set_drvdata(&op->dev, NULL); + dev_set_drvdata(&dev->dev, NULL); return 0; } -static const struct of_device_id bpp_match[] = { +static struct of_device_id bpp_match[] = { { .name = "SUNW,bpp", }, @@ -390,7 +397,7 @@ static struct of_platform_driver bpp_sbus_driver = { static int __init parport_sunbpp_init(void) { - return of_register_driver(&bpp_sbus_driver, &of_bus_type); + return of_register_driver(&bpp_sbus_driver, &sbus_bus_type); } static void __exit parport_sunbpp_exit(void) diff --git a/trunk/drivers/rtc/Kconfig b/trunk/drivers/rtc/Kconfig index b57fba5c6d02..9a9755c92fad 100644 --- a/trunk/drivers/rtc/Kconfig +++ b/trunk/drivers/rtc/Kconfig @@ -329,7 +329,7 @@ comment "Platform RTC drivers" config RTC_DRV_CMOS tristate "PC-style 'CMOS'" - depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS || SPARC64 + depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS default y if X86 help Say "yes" here to get direct support for the real time clock @@ -406,26 +406,14 @@ config RTC_DRV_M48T86 will be called rtc-m48t86. config RTC_DRV_M48T59 - tristate "ST M48T59/M48T08/M48T02" + tristate "ST M48T59" help If you say Y here you will get support for the - ST M48T59 RTC chip and compatible ST M48T08 and M48T02. - - These chips are usually found in Sun SPARC and UltraSPARC - workstations. + ST M48T59 RTC chip. This driver can also be built as a module, if so, the module will be called "rtc-m48t59". -config RTC_DRV_BQ4802 - tristate "TI BQ4802" - help - If you say Y here you will get support for the TI - BQ4802 RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-bq4802. - config RTC_DRV_V3020 tristate "EM Microelectronic V3020" help @@ -595,18 +583,4 @@ config RTC_DRV_PPC the RTC. This exposes that functionality through the generic RTC class. -config RTC_DRV_SUN4V - bool "SUN4V Hypervisor RTC" - depends on SPARC64 - help - If you say Y here you will get support for the Hypervisor - based RTC on SUN4V systems. - -config RTC_DRV_STARFIRE - bool "Starfire RTC" - depends on SPARC64 - help - If you say Y here you will get support for the RTC found on - Starfire systems. - endif # RTC_CLASS diff --git a/trunk/drivers/rtc/Makefile b/trunk/drivers/rtc/Makefile index 10f41f85c38a..18622ef84cab 100644 --- a/trunk/drivers/rtc/Makefile +++ b/trunk/drivers/rtc/Makefile @@ -38,9 +38,6 @@ obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o -obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o -obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o -obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o diff --git a/trunk/drivers/rtc/rtc-bq4802.c b/trunk/drivers/rtc/rtc-bq4802.c deleted file mode 100644 index 189a018bdf34..000000000000 --- a/trunk/drivers/rtc/rtc-bq4802.c +++ /dev/null @@ -1,230 +0,0 @@ -/* rtc-bq4802.c: TI BQ4802 RTC driver. - * - * Copyright (C) 2008 David S. Miller - */ - -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("David S. Miller "); -MODULE_DESCRIPTION("TI BQ4802 RTC driver"); -MODULE_LICENSE("GPL"); - -struct bq4802 { - void __iomem *regs; - unsigned long ioport; - struct rtc_device *rtc; - spinlock_t lock; - struct resource *r; - u8 (*read)(struct bq4802 *, int); - void (*write)(struct bq4802 *, int, u8); -}; - -static u8 bq4802_read_io(struct bq4802 *p, int off) -{ - return inb(p->ioport + off); -} - -static void bq4802_write_io(struct bq4802 *p, int off, u8 val) -{ - outb(val, p->ioport + off); -} - -static u8 bq4802_read_mem(struct bq4802 *p, int off) -{ - return readb(p->regs + off); -} - -static void bq4802_write_mem(struct bq4802 *p, int off, u8 val) -{ - writeb(val, p->regs + off); -} - -static int bq4802_read_time(struct device *dev, struct rtc_time *tm) -{ - struct platform_device *pdev = to_platform_device(dev); - struct bq4802 *p = platform_get_drvdata(pdev); - unsigned long flags; - unsigned int century; - u8 val; - - spin_lock_irqsave(&p->lock, flags); - - val = p->read(p, 0x0e); - p->write(p, 0xe, val | 0x08); - - tm->tm_sec = p->read(p, 0x00); - tm->tm_min = p->read(p, 0x02); - tm->tm_hour = p->read(p, 0x04); - tm->tm_mday = p->read(p, 0x06); - tm->tm_mon = p->read(p, 0x09); - tm->tm_year = p->read(p, 0x0a); - tm->tm_wday = p->read(p, 0x08); - century = p->read(p, 0x0f); - - p->write(p, 0x0e, val); - - spin_unlock_irqrestore(&p->lock, flags); - - BCD_TO_BIN(tm->tm_sec); - BCD_TO_BIN(tm->tm_min); - BCD_TO_BIN(tm->tm_hour); - BCD_TO_BIN(tm->tm_mday); - BCD_TO_BIN(tm->tm_mon); - BCD_TO_BIN(tm->tm_year); - BCD_TO_BIN(tm->tm_wday); - BCD_TO_BIN(century); - - tm->tm_year += (century * 100); - tm->tm_year -= 1900; - - tm->tm_mon--; - - return 0; -} - -static int bq4802_set_time(struct device *dev, struct rtc_time *tm) -{ - struct platform_device *pdev = to_platform_device(dev); - struct bq4802 *p = platform_get_drvdata(pdev); - u8 sec, min, hrs, day, mon, yrs, century, val; - unsigned long flags; - unsigned int year; - - year = tm->tm_year + 1900; - century = year / 100; - yrs = year % 100; - - mon = tm->tm_mon + 1; /* tm_mon starts at zero */ - day = tm->tm_mday; - hrs = tm->tm_hour; - min = tm->tm_min; - sec = tm->tm_sec; - - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(yrs); - BIN_TO_BCD(century); - - spin_lock_irqsave(&p->lock, flags); - - val = p->read(p, 0x0e); - p->write(p, 0x0e, val | 0x08); - - p->write(p, 0x00, sec); - p->write(p, 0x02, min); - p->write(p, 0x04, hrs); - p->write(p, 0x06, day); - p->write(p, 0x09, mon); - p->write(p, 0x0a, yrs); - p->write(p, 0x0f, century); - - p->write(p, 0x0e, val); - - spin_unlock_irqrestore(&p->lock, flags); - - return 0; -} - -static const struct rtc_class_ops bq4802_ops = { - .read_time = bq4802_read_time, - .set_time = bq4802_set_time, -}; - -static int __devinit bq4802_probe(struct platform_device *pdev) -{ - struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL); - int err = -ENOMEM; - - if (!p) - goto out; - - spin_lock_init(&p->lock); - - p->r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!p->r) { - p->r = platform_get_resource(pdev, IORESOURCE_IO, 0); - err = -EINVAL; - if (!p->r) - goto out_free; - } - if (p->r->flags & IORESOURCE_IO) { - p->ioport = p->r->start; - p->read = bq4802_read_io; - p->write = bq4802_write_io; - } else if (p->r->flags & IORESOURCE_MEM) { - p->regs = ioremap(p->r->start, resource_size(p->r)); - p->read = bq4802_read_mem; - p->write = bq4802_write_mem; - } else { - err = -EINVAL; - goto out_free; - } - - p->rtc = rtc_device_register("bq4802", &pdev->dev, - &bq4802_ops, THIS_MODULE); - if (IS_ERR(p->rtc)) { - err = PTR_ERR(p->rtc); - goto out_iounmap; - } - - platform_set_drvdata(pdev, p); - err = 0; -out: - return err; - -out_iounmap: - if (p->r->flags & IORESOURCE_MEM) - iounmap(p->regs); -out_free: - kfree(p); - goto out; -} - -static int __devexit bq4802_remove(struct platform_device *pdev) -{ - struct bq4802 *p = platform_get_drvdata(pdev); - - rtc_device_unregister(p->rtc); - if (p->r->flags & IORESOURCE_MEM) - iounmap(p->regs); - - platform_set_drvdata(pdev, NULL); - - kfree(p); - - return 0; -} - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:rtc-bq4802"); - -static struct platform_driver bq4802_driver = { - .driver = { - .name = "rtc-bq4802", - .owner = THIS_MODULE, - }, - .probe = bq4802_probe, - .remove = __devexit_p(bq4802_remove), -}; - -static int __init bq4802_init(void) -{ - return platform_driver_register(&bq4802_driver); -} - -static void __exit bq4802_exit(void) -{ - platform_driver_unregister(&bq4802_driver); -} - -module_init(bq4802_init); -module_exit(bq4802_exit); diff --git a/trunk/drivers/rtc/rtc-cmos.c b/trunk/drivers/rtc/rtc-cmos.c index b23af0c2a869..b184367637d0 100644 --- a/trunk/drivers/rtc/rtc-cmos.c +++ b/trunk/drivers/rtc/rtc-cmos.c @@ -636,7 +636,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) */ #if defined(CONFIG_ATARI) address_space = 64; -#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__sparc__) +#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) address_space = 128; #else #warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes. @@ -699,8 +699,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) /* FIXME teach the alarm code how to handle binary mode; * doesn't know 12-hour mode either. */ - if (is_valid_irq(rtc_irq) && - (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))) { + if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) { dev_dbg(dev, "only 24-hr BCD mode supported\n"); retval = -ENXIO; goto cleanup1; diff --git a/trunk/drivers/rtc/rtc-m48t59.c b/trunk/drivers/rtc/rtc-m48t59.c index ce4eff6a8d51..013e6c103b9c 100644 --- a/trunk/drivers/rtc/rtc-m48t59.c +++ b/trunk/drivers/rtc/rtc-m48t59.c @@ -24,9 +24,8 @@ #define NO_IRQ (-1) #endif -#define M48T59_READ(reg) (pdata->read_byte(dev, pdata->offset + reg)) -#define M48T59_WRITE(val, reg) \ - (pdata->write_byte(dev, pdata->offset + reg, val)) +#define M48T59_READ(reg) pdata->read_byte(dev, reg) +#define M48T59_WRITE(val, reg) pdata->write_byte(dev, reg, val) #define M48T59_SET_BITS(mask, reg) \ M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg)) @@ -35,6 +34,7 @@ struct m48t59_private { void __iomem *ioaddr; + unsigned int size; /* iomem size */ int irq; struct rtc_device *rtc; spinlock_t lock; /* serialize the NVRAM and RTC access */ @@ -82,8 +82,7 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_mday = BCD2BIN(M48T59_READ(M48T59_MDAY)); val = M48T59_READ(M48T59_WDAY); - if ((pdata->type == M48T59RTC_TYPE_M48T59) && - (val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) { + if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) { dev_dbg(dev, "Century bit is enabled\n"); tm->tm_year += 100; /* one century */ } @@ -127,7 +126,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) M48T59_WRITE((BIN2BCD(tm->tm_mon + 1) & 0x1F), M48T59_MONTH); M48T59_WRITE(BIN2BCD(tm->tm_year % 100), M48T59_YEAR); - if (pdata->type == M48T59RTC_TYPE_M48T59 && (tm->tm_year / 100)) + if (tm->tm_year/100) val = (M48T59_WDAY_CEB | M48T59_WDAY_CB); val |= (BIN2BCD(tm->tm_wday) & 0x07); M48T59_WRITE(val, M48T59_WDAY); @@ -311,11 +310,6 @@ static const struct rtc_class_ops m48t59_rtc_ops = { .proc = m48t59_rtc_proc, }; -static const struct rtc_class_ops m48t02_rtc_ops = { - .read_time = m48t59_rtc_read_time, - .set_time = m48t59_rtc_set_time, -}; - static ssize_t m48t59_nvram_read(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t size) @@ -327,7 +321,7 @@ static ssize_t m48t59_nvram_read(struct kobject *kobj, ssize_t cnt = 0; unsigned long flags; - for (; size > 0 && pos < pdata->offset; cnt++, size--) { + for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) { spin_lock_irqsave(&m48t59->lock, flags); *buf++ = M48T59_READ(cnt); spin_unlock_irqrestore(&m48t59->lock, flags); @@ -347,7 +341,7 @@ static ssize_t m48t59_nvram_write(struct kobject *kobj, ssize_t cnt = 0; unsigned long flags; - for (; size > 0 && pos < pdata->offset; cnt++, size--) { + for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) { spin_lock_irqsave(&m48t59->lock, flags); M48T59_WRITE(*buf++, cnt); spin_unlock_irqrestore(&m48t59->lock, flags); @@ -364,6 +358,7 @@ static struct bin_attribute m48t59_nvram_attr = { }, .read = m48t59_nvram_read, .write = m48t59_nvram_write, + .size = M48T59_NVRAM_SIZE, }; static int __devinit m48t59_rtc_probe(struct platform_device *pdev) @@ -372,8 +367,6 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) struct m48t59_private *m48t59 = NULL; struct resource *res; int ret = -ENOMEM; - char *name; - const struct rtc_class_ops *ops; /* This chip could be memory-mapped or I/O-mapped */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -398,8 +391,6 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) /* Ensure we only kmalloc platform data once */ pdev->dev.platform_data = pdata; } - if (!pdata->type) - pdata->type = M48T59RTC_TYPE_M48T59; /* Try to use the generic memory read/write ops */ if (!pdata->write_byte) @@ -412,14 +403,10 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) if (!m48t59) return -ENOMEM; - m48t59->ioaddr = pdata->ioaddr; - - if (!m48t59->ioaddr) { - /* ioaddr not mapped externally */ - m48t59->ioaddr = ioremap(res->start, res->end - res->start + 1); - if (!m48t59->ioaddr) - goto out; - } + m48t59->size = res->end - res->start + 1; + m48t59->ioaddr = ioremap(res->start, m48t59->size); + if (!m48t59->ioaddr) + goto out; /* Try to get irq number. We also can work in * the mode without IRQ. @@ -434,36 +421,14 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) if (ret) goto out; } - switch (pdata->type) { - case M48T59RTC_TYPE_M48T59: - name = "m48t59"; - ops = &m48t59_rtc_ops; - pdata->offset = 0x1ff0; - break; - case M48T59RTC_TYPE_M48T02: - name = "m48t02"; - ops = &m48t02_rtc_ops; - pdata->offset = 0x7f0; - break; - case M48T59RTC_TYPE_M48T08: - name = "m48t08"; - ops = &m48t02_rtc_ops; - pdata->offset = 0x1ff0; - break; - default: - dev_err(&pdev->dev, "Unknown RTC type\n"); - ret = -ENODEV; - goto out; - } - m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE); + m48t59->rtc = rtc_device_register("m48t59", &pdev->dev, + &m48t59_rtc_ops, THIS_MODULE); if (IS_ERR(m48t59->rtc)) { ret = PTR_ERR(m48t59->rtc); goto out; } - m48t59_nvram_attr.size = pdata->offset; - ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); if (ret) goto out; @@ -487,12 +452,11 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) static int __devexit m48t59_rtc_remove(struct platform_device *pdev) { struct m48t59_private *m48t59 = platform_get_drvdata(pdev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); if (!IS_ERR(m48t59->rtc)) rtc_device_unregister(m48t59->rtc); - if (m48t59->ioaddr && !pdata->ioaddr) + if (m48t59->ioaddr) iounmap(m48t59->ioaddr); if (m48t59->irq != NO_IRQ) free_irq(m48t59->irq, &pdev->dev); @@ -527,5 +491,5 @@ module_init(m48t59_rtc_init); module_exit(m48t59_rtc_exit); MODULE_AUTHOR("Mark Zhan "); -MODULE_DESCRIPTION("M48T59/M48T02/M48T08 RTC driver"); +MODULE_DESCRIPTION("M48T59 RTC driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/rtc/rtc-starfire.c b/trunk/drivers/rtc/rtc-starfire.c deleted file mode 100644 index 7ccb0dd700af..000000000000 --- a/trunk/drivers/rtc/rtc-starfire.c +++ /dev/null @@ -1,120 +0,0 @@ -/* rtc-starfire.c: Starfire platform RTC driver. - * - * Copyright (C) 2008 David S. Miller - */ - -#include -#include -#include -#include -#include -#include - -#include - -MODULE_AUTHOR("David S. Miller "); -MODULE_DESCRIPTION("Starfire RTC driver"); -MODULE_LICENSE("GPL"); - -struct starfire_rtc { - struct rtc_device *rtc; - spinlock_t lock; -}; - -static u32 starfire_get_time(void) -{ - static char obp_gettod[32]; - static u32 unix_tod; - - sprintf(obp_gettod, "h# %08x unix-gettod", - (unsigned int) (long) &unix_tod); - prom_feval(obp_gettod); - - return unix_tod; -} - -static int starfire_read_time(struct device *dev, struct rtc_time *tm) -{ - struct starfire_rtc *p = dev_get_drvdata(dev); - unsigned long flags, secs; - - spin_lock_irqsave(&p->lock, flags); - secs = starfire_get_time(); - spin_unlock_irqrestore(&p->lock, flags); - - rtc_time_to_tm(secs, tm); - - return 0; -} - -static int starfire_set_time(struct device *dev, struct rtc_time *tm) -{ - unsigned long secs; - int err; - - err = rtc_tm_to_time(tm, &secs); - if (err) - return err; - - /* Do nothing, time is set using the service processor - * console on this platform. - */ - return 0; -} - -static const struct rtc_class_ops starfire_rtc_ops = { - .read_time = starfire_read_time, - .set_time = starfire_set_time, -}; - -static int __devinit starfire_rtc_probe(struct platform_device *pdev) -{ - struct starfire_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL); - - if (!p) - return -ENOMEM; - - spin_lock_init(&p->lock); - - p->rtc = rtc_device_register("starfire", &pdev->dev, - &starfire_rtc_ops, THIS_MODULE); - if (IS_ERR(p->rtc)) { - int err = PTR_ERR(p->rtc); - kfree(p); - return err; - } - platform_set_drvdata(pdev, p); - return 0; -} - -static int __devexit starfire_rtc_remove(struct platform_device *pdev) -{ - struct starfire_rtc *p = platform_get_drvdata(pdev); - - rtc_device_unregister(p->rtc); - kfree(p); - - return 0; -} - -static struct platform_driver starfire_rtc_driver = { - .driver = { - .name = "rtc-starfire", - .owner = THIS_MODULE, - }, - .probe = starfire_rtc_probe, - .remove = __devexit_p(starfire_rtc_remove), -}; - -static int __init starfire_rtc_init(void) -{ - return platform_driver_register(&starfire_rtc_driver); -} - -static void __exit starfire_rtc_exit(void) -{ - platform_driver_unregister(&starfire_rtc_driver); -} - -module_init(starfire_rtc_init); -module_exit(starfire_rtc_exit); diff --git a/trunk/drivers/rtc/rtc-sun4v.c b/trunk/drivers/rtc/rtc-sun4v.c deleted file mode 100644 index 2012ccbb4a53..000000000000 --- a/trunk/drivers/rtc/rtc-sun4v.c +++ /dev/null @@ -1,153 +0,0 @@ -/* rtc-sun4c.c: Hypervisor based RTC for SUN4V systems. - * - * Copyright (C) 2008 David S. Miller - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -MODULE_AUTHOR("David S. Miller "); -MODULE_DESCRIPTION("SUN4V RTC driver"); -MODULE_LICENSE("GPL"); - -struct sun4v_rtc { - struct rtc_device *rtc; - spinlock_t lock; -}; - -static unsigned long hypervisor_get_time(void) -{ - unsigned long ret, time; - int retries = 10000; - -retry: - ret = sun4v_tod_get(&time); - if (ret == HV_EOK) - return time; - if (ret == HV_EWOULDBLOCK) { - if (--retries > 0) { - udelay(100); - goto retry; - } - printk(KERN_WARNING "SUN4V: tod_get() timed out.\n"); - return 0; - } - printk(KERN_WARNING "SUN4V: tod_get() not supported.\n"); - return 0; -} - -static int sun4v_read_time(struct device *dev, struct rtc_time *tm) -{ - struct sun4v_rtc *p = dev_get_drvdata(dev); - unsigned long flags, secs; - - spin_lock_irqsave(&p->lock, flags); - secs = hypervisor_get_time(); - spin_unlock_irqrestore(&p->lock, flags); - - rtc_time_to_tm(secs, tm); - - return 0; -} - -static int hypervisor_set_time(unsigned long secs) -{ - unsigned long ret; - int retries = 10000; - -retry: - ret = sun4v_tod_set(secs); - if (ret == HV_EOK) - return 0; - if (ret == HV_EWOULDBLOCK) { - if (--retries > 0) { - udelay(100); - goto retry; - } - printk(KERN_WARNING "SUN4V: tod_set() timed out.\n"); - return -EAGAIN; - } - printk(KERN_WARNING "SUN4V: tod_set() not supported.\n"); - return -EOPNOTSUPP; -} - -static int sun4v_set_time(struct device *dev, struct rtc_time *tm) -{ - struct sun4v_rtc *p = dev_get_drvdata(dev); - unsigned long flags, secs; - int err; - - err = rtc_tm_to_time(tm, &secs); - if (err) - return err; - - spin_lock_irqsave(&p->lock, flags); - err = hypervisor_set_time(secs); - spin_unlock_irqrestore(&p->lock, flags); - - return err; -} - -static const struct rtc_class_ops sun4v_rtc_ops = { - .read_time = sun4v_read_time, - .set_time = sun4v_set_time, -}; - -static int __devinit sun4v_rtc_probe(struct platform_device *pdev) -{ - struct sun4v_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL); - - if (!p) - return -ENOMEM; - - spin_lock_init(&p->lock); - - p->rtc = rtc_device_register("sun4v", &pdev->dev, - &sun4v_rtc_ops, THIS_MODULE); - if (IS_ERR(p->rtc)) { - int err = PTR_ERR(p->rtc); - kfree(p); - return err; - } - platform_set_drvdata(pdev, p); - return 0; -} - -static int __devexit sun4v_rtc_remove(struct platform_device *pdev) -{ - struct sun4v_rtc *p = platform_get_drvdata(pdev); - - rtc_device_unregister(p->rtc); - kfree(p); - - return 0; -} - -static struct platform_driver sun4v_rtc_driver = { - .driver = { - .name = "rtc-sun4v", - .owner = THIS_MODULE, - }, - .probe = sun4v_rtc_probe, - .remove = __devexit_p(sun4v_rtc_remove), -}; - -static int __init sun4v_rtc_init(void) -{ - return platform_driver_register(&sun4v_rtc_driver); -} - -static void __exit sun4v_rtc_exit(void) -{ - platform_driver_unregister(&sun4v_rtc_driver); -} - -module_init(sun4v_rtc_init); -module_exit(sun4v_rtc_exit); diff --git a/trunk/drivers/sbus/Makefile b/trunk/drivers/sbus/Makefile index e94dc25805f9..7b1d24d95308 100644 --- a/trunk/drivers/sbus/Makefile +++ b/trunk/drivers/sbus/Makefile @@ -2,4 +2,8 @@ # Makefile for the linux kernel. # +ifneq ($(ARCH),m68k) +obj-y := sbus.o dvma.o +endif + obj-$(CONFIG_SBUSCHAR) += char/ diff --git a/trunk/drivers/sbus/char/Kconfig b/trunk/drivers/sbus/char/Kconfig index 73cde85d04d8..400c65bfb8c7 100644 --- a/trunk/drivers/sbus/char/Kconfig +++ b/trunk/drivers/sbus/char/Kconfig @@ -13,6 +13,16 @@ config SUN_OPENPROMIO If unsure, say Y. +config SUN_MOSTEK_RTC + tristate "Mostek real time clock support" + depends on SPARC32 + help + The Mostek RTC chip is used on all known Sun computers except + some JavaStations. For a JavaStation you need to say Y both here + and to "Enhanced Real Time Clock Support". + + Say Y here unless you are building a special purpose kernel. + config OBP_FLASH tristate "OBP Flash Device support" depends on SPARC64 @@ -20,9 +30,26 @@ config OBP_FLASH The OpenBoot PROM on Ultra systems is flashable. If you want to be able to upgrade the OBP firmware, say Y here. +config SUN_BPP + tristate "Bidirectional parallel port support (OBSOLETE)" + depends on EXPERIMENTAL + help + Say Y here to support Sun's obsolete variant of IEEE1284 + bidirectional parallel port protocol as /dev/bppX. Can be built on + x86 machines. + +config SUN_VIDEOPIX + tristate "Videopix Frame Grabber (EXPERIMENTAL)" + depends on EXPERIMENTAL && (BROKEN || !64BIT) + help + Say Y here to support the Videopix Frame Grabber from Sun + Microsystems, commonly found on SPARCstations. This card, which is + based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and + SVIDEO signals. + config TADPOLE_TS102_UCTRL tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on EXPERIMENTAL && SPARC32 help Say Y here to directly support the TS102 Microcontroller interface on the Tadpole Sparcbook 3. This device handles power-management diff --git a/trunk/drivers/sbus/char/Makefile b/trunk/drivers/sbus/char/Makefile index 78b6183c9866..7ab060e9a5fe 100644 --- a/trunk/drivers/sbus/char/Makefile +++ b/trunk/drivers/sbus/char/Makefile @@ -7,12 +7,18 @@ # Rewritten to use lists instead of if-statements. # +vfc-objs := vfc_dev.o vfc_i2c.o bbc-objs := bbc_i2c.o bbc_envctrl.o obj-$(CONFIG_ENVCTRL) += envctrl.o obj-$(CONFIG_DISPLAY7SEG) += display7seg.o +obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwatchdog.o +obj-$(CONFIG_WATCHDOG_RIO) += riowatchdog.o obj-$(CONFIG_OBP_FLASH) += flash.o obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o +obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o +obj-$(CONFIG_SUN_BPP) += bpp.o +obj-$(CONFIG_SUN_VIDEOPIX) += vfc.o obj-$(CONFIG_TADPOLE_TS102_UCTRL) += uctrl.o obj-$(CONFIG_SUN_JSFLASH) += jsflash.o obj-$(CONFIG_BBC_I2C) += bbc.o diff --git a/trunk/drivers/sbus/char/bbc_envctrl.c b/trunk/drivers/sbus/char/bbc_envctrl.c index 15dab96d05e3..0bde26989a23 100644 --- a/trunk/drivers/sbus/char/bbc_envctrl.c +++ b/trunk/drivers/sbus/char/bbc_envctrl.c @@ -1,15 +1,15 @@ -/* bbc_envctrl.c: UltraSPARC-III environment control driver. +/* $Id: bbc_envctrl.c,v 1.4 2001/04/06 16:48:08 davem Exp $ + * bbc_envctrl.c: UltraSPARC-III environment control driver. * - * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 2001 David S. Miller (davem@redhat.com) */ #include #include #include #include -#include -#include #include +#include #include "bbc_i2c.h" #include "max1617.h" @@ -75,8 +75,43 @@ static struct temp_limits amb_temp_limits[2] = { { 65, 55, 40, 5, -5, -10 }, }; -static LIST_HEAD(all_temps); -static LIST_HEAD(all_fans); +enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX }; + +struct bbc_cpu_temperature { + struct bbc_cpu_temperature *next; + + struct bbc_i2c_client *client; + int index; + + /* Current readings, and history. */ + s8 curr_cpu_temp; + s8 curr_amb_temp; + s8 prev_cpu_temp; + s8 prev_amb_temp; + s8 avg_cpu_temp; + s8 avg_amb_temp; + + int sample_tick; + + enum fan_action fan_todo[2]; +#define FAN_AMBIENT 0 +#define FAN_CPU 1 +}; + +struct bbc_cpu_temperature *all_bbc_temps; + +struct bbc_fan_control { + struct bbc_fan_control *next; + + struct bbc_i2c_client *client; + int index; + + int psupply_fan_on; + int cpu_fan_speed; + int system_fan_speed; +}; + +struct bbc_fan_control *all_bbc_fans; #define CPU_FAN_REG 0xf0 #define SYS_FAN_REG 0xf2 @@ -295,7 +330,7 @@ static enum fan_action prioritize_fan_action(int which_fan) * recommend we do, and perform that action on all the * fans. */ - list_for_each_entry(tp, &all_temps, glob_list) { + for (tp = all_bbc_temps; tp; tp = tp->next) { if (tp->fan_todo[which_fan] == FAN_FULLBLAST) { decision = FAN_FULLBLAST; break; @@ -404,7 +439,7 @@ static void fans_full_blast(void) /* Since we will not be monitoring things anymore, put * the fans on full blast. */ - list_for_each_entry(fp, &all_fans, glob_list) { + for (fp = all_bbc_fans; fp; fp = fp->next) { fp->cpu_fan_speed = FAN_SPEED_MAX; fp->system_fan_speed = FAN_SPEED_MAX; fp->psupply_fan_on = 1; @@ -428,11 +463,11 @@ static int kenvctrld(void *__unused) if (kthread_should_stop()) break; - list_for_each_entry(tp, &all_temps, glob_list) { + for (tp = all_bbc_temps; tp; tp = tp->next) { get_current_temps(tp); analyze_temps(tp, &last_warning_jiffies); } - list_for_each_entry(fp, &all_fans, glob_list) + for (fp = all_bbc_fans; fp; fp = fp->next) maybe_new_fan_speeds(fp); } printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n"); @@ -442,8 +477,7 @@ static int kenvctrld(void *__unused) return 0; } -static void attach_one_temp(struct bbc_i2c_bus *bp, struct of_device *op, - int temp_idx) +static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx) { struct bbc_cpu_temperature *tp; @@ -451,17 +485,20 @@ static void attach_one_temp(struct bbc_i2c_bus *bp, struct of_device *op, if (!tp) return; - tp->client = bbc_i2c_attach(bp, op); + tp->client = bbc_i2c_attach(echild); if (!tp->client) { kfree(tp); return; } - tp->index = temp_idx; - - list_add(&tp->glob_list, &all_temps); - list_add(&tp->bp_list, &bp->temps); + { + struct bbc_cpu_temperature **tpp = &all_bbc_temps; + while (*tpp) + tpp = &((*tpp)->next); + tp->next = NULL; + *tpp = tp; + } /* Tell it to convert once every 5 seconds, clear all cfg * bits. @@ -487,8 +524,7 @@ static void attach_one_temp(struct bbc_i2c_bus *bp, struct of_device *op, tp->fan_todo[FAN_CPU] = FAN_SAME; } -static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op, - int fan_idx) +static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) { struct bbc_fan_control *fp; @@ -496,7 +532,7 @@ static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op, if (!fp) return; - fp->client = bbc_i2c_attach(bp, op); + fp->client = bbc_i2c_attach(echild); if (!fp->client) { kfree(fp); return; @@ -504,8 +540,13 @@ static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op, fp->index = fan_idx; - list_add(&fp->glob_list, &all_fans); - list_add(&fp->bp_list, &bp->fans); + { + struct bbc_fan_control **fpp = &all_bbc_fans; + while (*fpp) + fpp = &((*fpp)->next); + fp->next = NULL; + *fpp = fp; + } /* The i2c device controlling the fans is write-only. * So the only way to keep track of the current power @@ -522,18 +563,18 @@ static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op, set_fan_speeds(fp); } -int bbc_envctrl_init(struct bbc_i2c_bus *bp) +int bbc_envctrl_init(void) { - struct of_device *op; + struct linux_ebus_child *echild; int temp_index = 0; int fan_index = 0; int devidx = 0; - while ((op = bbc_i2c_getdev(bp, devidx++)) != NULL) { - if (!strcmp(op->node->name, "temperature")) - attach_one_temp(bp, op, temp_index++); - if (!strcmp(op->node->name, "fan-control")) - attach_one_fan(bp, op, fan_index++); + while ((echild = bbc_i2c_getdev(devidx++)) != NULL) { + if (!strcmp(echild->prom_node->name, "temperature")) + attach_one_temp(echild, temp_index++); + if (!strcmp(echild->prom_node->name, "fan-control")) + attach_one_fan(echild, fan_index++); } if (temp_index != 0 && fan_index != 0) { kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld"); @@ -556,22 +597,26 @@ static void destroy_one_fan(struct bbc_fan_control *fp) kfree(fp); } -void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp) +void bbc_envctrl_cleanup(void) { - struct bbc_cpu_temperature *tp, *tpos; - struct bbc_fan_control *fp, *fpos; + struct bbc_cpu_temperature *tp; + struct bbc_fan_control *fp; kthread_stop(kenvctrld_task); - list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) { - list_del(&tp->bp_list); - list_del(&tp->glob_list); + tp = all_bbc_temps; + while (tp != NULL) { + struct bbc_cpu_temperature *next = tp->next; destroy_one_temp(tp); + tp = next; } + all_bbc_temps = NULL; - list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) { - list_del(&fp->bp_list); - list_del(&fp->glob_list); + fp = all_bbc_fans; + while (fp != NULL) { + struct bbc_fan_control *next = fp->next; destroy_one_fan(fp); + fp = next; } + all_bbc_fans = NULL; } diff --git a/trunk/drivers/sbus/char/bbc_i2c.c b/trunk/drivers/sbus/char/bbc_i2c.c index f08e169ba1b5..ac8ef2ce07fb 100644 --- a/trunk/drivers/sbus/char/bbc_i2c.c +++ b/trunk/drivers/sbus/char/bbc_i2c.c @@ -1,7 +1,8 @@ -/* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III +/* $Id: bbc_i2c.c,v 1.2 2001/04/02 09:59:08 davem Exp $ + * bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III * platforms. * - * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 2001 David S. Miller (davem@redhat.com) */ #include @@ -13,8 +14,9 @@ #include #include #include -#include -#include +#include +#include +#include #include #include @@ -51,12 +53,54 @@ * The second controller also connects to the smartcard reader, if present. */ -static void set_device_claimage(struct bbc_i2c_bus *bp, struct of_device *op, int val) +#define NUM_CHILDREN 8 +struct bbc_i2c_bus { + struct bbc_i2c_bus *next; + int index; + spinlock_t lock; + void __iomem *i2c_bussel_reg; + void __iomem *i2c_control_regs; + unsigned char own, clock; + + wait_queue_head_t wq; + volatile int waiting; + + struct linux_ebus_device *bus_edev; + struct { + struct linux_ebus_child *device; + int client_claimed; + } devs[NUM_CHILDREN]; +}; + +static struct bbc_i2c_bus *all_bbc_i2c; + +struct bbc_i2c_client { + struct bbc_i2c_bus *bp; + struct linux_ebus_child *echild; + int bus; + int address; +}; + +static int find_device(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild) { int i; for (i = 0; i < NUM_CHILDREN; i++) { - if (bp->devs[i].device == op) { + if (bp->devs[i].device == echild) { + if (bp->devs[i].client_claimed) + return 0; + return 1; + } + } + return 0; +} + +static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild, int val) +{ + int i; + + for (i = 0; i < NUM_CHILDREN; i++) { + if (bp->devs[i].device == echild) { bp->devs[i].client_claimed = val; return; } @@ -66,47 +110,61 @@ static void set_device_claimage(struct bbc_i2c_bus *bp, struct of_device *op, in #define claim_device(BP,ECHILD) set_device_claimage(BP,ECHILD,1) #define release_device(BP,ECHILD) set_device_claimage(BP,ECHILD,0) -struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index) +static struct bbc_i2c_bus *find_bus_for_device(struct linux_ebus_child *echild) { - struct of_device *op = NULL; - int curidx = 0, i; + struct bbc_i2c_bus *bp = all_bbc_i2c; - for (i = 0; i < NUM_CHILDREN; i++) { - if (!(op = bp->devs[i].device)) + while (bp != NULL) { + if (find_device(bp, echild) != 0) break; - if (curidx == index) - goto out; - op = NULL; - curidx++; + bp = bp->next; } + return bp; +} + +struct linux_ebus_child *bbc_i2c_getdev(int index) +{ + struct bbc_i2c_bus *bp = all_bbc_i2c; + struct linux_ebus_child *echild = NULL; + int curidx = 0; + + while (bp != NULL) { + struct bbc_i2c_bus *next = bp->next; + int i; + + for (i = 0; i < NUM_CHILDREN; i++) { + if (!(echild = bp->devs[i].device)) + break; + if (curidx == index) + goto out; + echild = NULL; + curidx++; + } + bp = next; + } out: if (curidx == index) - return op; + return echild; return NULL; } -struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *op) +struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild) { + struct bbc_i2c_bus *bp = find_bus_for_device(echild); struct bbc_i2c_client *client; - const u32 *reg; + if (!bp) + return NULL; client = kzalloc(sizeof(*client), GFP_KERNEL); if (!client) return NULL; client->bp = bp; - client->op = op; - - reg = of_get_property(op->node, "reg", NULL); - if (!reg) { - kfree(client); - return NULL; - } + client->echild = echild; + client->bus = echild->resource[0].start; + client->address = echild->resource[1].start; - client->bus = reg[0]; - client->address = reg[1]; - - claim_device(bp, op); + claim_device(bp, echild); return client; } @@ -114,9 +172,9 @@ struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device * void bbc_i2c_detach(struct bbc_i2c_client *client) { struct bbc_i2c_bus *bp = client->bp; - struct of_device *op = client->op; + struct linux_ebus_child *echild = client->echild; - release_device(bp, op); + release_device(bp, echild); kfree(client); } @@ -297,43 +355,44 @@ static void __init reset_one_i2c(struct bbc_i2c_bus *bp) writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0); } -static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int index) +static int __init attach_one_i2c(struct linux_ebus_device *edev, int index) { struct bbc_i2c_bus *bp; - struct device_node *dp; + struct linux_ebus_child *echild; int entry; bp = kzalloc(sizeof(*bp), GFP_KERNEL); if (!bp) - return NULL; + return -ENOMEM; - bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs"); + bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2); if (!bp->i2c_control_regs) goto fail; - bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel"); - if (!bp->i2c_bussel_reg) - goto fail; + if (edev->num_addrs == 2) { + bp->i2c_bussel_reg = ioremap(edev->resource[1].start, 0x1); + if (!bp->i2c_bussel_reg) + goto fail; + } bp->waiting = 0; init_waitqueue_head(&bp->wq); - if (request_irq(op->irqs[0], bbc_i2c_interrupt, + if (request_irq(edev->irqs[0], bbc_i2c_interrupt, IRQF_SHARED, "bbc_i2c", bp)) goto fail; bp->index = index; - bp->op = op; + bp->bus_edev = edev; spin_lock_init(&bp->lock); + bp->next = all_bbc_i2c; + all_bbc_i2c = bp; entry = 0; - for (dp = op->node->child; - dp && entry < 8; - dp = dp->sibling, entry++) { - struct of_device *child_op; - - child_op = of_find_device_by_node(dp); - bp->devs[entry].device = child_op; + for (echild = edev->children; + echild && entry < 8; + echild = echild->next, entry++) { + bp->devs[entry].device = echild; bp->devs[entry].client_claimed = 0; } @@ -347,90 +406,86 @@ static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int inde reset_one_i2c(bp); - return bp; + return 0; fail: if (bp->i2c_bussel_reg) - of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1); + iounmap(bp->i2c_bussel_reg); if (bp->i2c_control_regs) - of_iounmap(&op->resource[0], bp->i2c_control_regs, 2); + iounmap(bp->i2c_control_regs); kfree(bp); - return NULL; + return -EINVAL; } -extern int bbc_envctrl_init(struct bbc_i2c_bus *bp); -extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp); +static int __init bbc_present(void) +{ + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; -static int __devinit bbc_i2c_probe(struct of_device *op, - const struct of_device_id *match) + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_node->name, "bbc")) + return 1; + } + } + return 0; +} + +extern int bbc_envctrl_init(void); +extern void bbc_envctrl_cleanup(void); +static void bbc_i2c_cleanup(void); + +static int __init bbc_i2c_init(void) { - struct bbc_i2c_bus *bp; + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; int err, index = 0; - bp = attach_one_i2c(op, index); - if (!bp) - return -EINVAL; + if ((tlb_type != cheetah && tlb_type != cheetah_plus) || + !bbc_present()) + return -ENODEV; - err = bbc_envctrl_init(bp); - if (err) { - free_irq(op->irqs[0], bp); - if (bp->i2c_bussel_reg) - of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); - if (bp->i2c_control_regs) - of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); - kfree(bp); - } else { - dev_set_drvdata(&op->dev, bp); + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_node->name, "i2c")) { + if (!attach_one_i2c(edev, index)) + index++; + } + } } + if (!index) + return -ENODEV; + + err = bbc_envctrl_init(); + if (err) + bbc_i2c_cleanup(); return err; } -static int __devexit bbc_i2c_remove(struct of_device *op) +static void bbc_i2c_cleanup(void) { - struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev); - - bbc_envctrl_cleanup(bp); - - free_irq(op->irqs[0], bp); + struct bbc_i2c_bus *bp = all_bbc_i2c; - if (bp->i2c_bussel_reg) - of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); - if (bp->i2c_control_regs) - of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); + bbc_envctrl_cleanup(); - kfree(bp); + while (bp != NULL) { + struct bbc_i2c_bus *next = bp->next; - return 0; -} + free_irq(bp->bus_edev->irqs[0], bp); -static const struct of_device_id bbc_i2c_match[] = { - { - .name = "i2c", - .compatible = "SUNW,bbc-i2c", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, bbc_i2c_match); - -static struct of_platform_driver bbc_i2c_driver = { - .name = "bbc_i2c", - .match_table = bbc_i2c_match, - .probe = bbc_i2c_probe, - .remove = __devexit_p(bbc_i2c_remove), -}; + if (bp->i2c_bussel_reg) + iounmap(bp->i2c_bussel_reg); + if (bp->i2c_control_regs) + iounmap(bp->i2c_control_regs); -static int __init bbc_i2c_init(void) -{ - return of_register_driver(&bbc_i2c_driver, &of_bus_type); -} + kfree(bp); -static void __exit bbc_i2c_exit(void) -{ - of_unregister_driver(&bbc_i2c_driver); + bp = next; + } + all_bbc_i2c = NULL; } module_init(bbc_i2c_init); -module_exit(bbc_i2c_exit); - +module_exit(bbc_i2c_cleanup); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/sbus/char/bbc_i2c.h b/trunk/drivers/sbus/char/bbc_i2c.h index 83c4811b7b5e..fb01bd17704b 100644 --- a/trunk/drivers/sbus/char/bbc_i2c.h +++ b/trunk/drivers/sbus/char/bbc_i2c.h @@ -1,79 +1,14 @@ +/* $Id: bbc_i2c.h,v 1.2 2001/04/02 09:59:25 davem Exp $ */ #ifndef _BBC_I2C_H #define _BBC_I2C_H -#include -#include -#include +#include -struct bbc_i2c_client { - struct bbc_i2c_bus *bp; - struct of_device *op; - int bus; - int address; -}; - -enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX }; - -struct bbc_cpu_temperature { - struct list_head bp_list; - struct list_head glob_list; - - struct bbc_i2c_client *client; - int index; - - /* Current readings, and history. */ - s8 curr_cpu_temp; - s8 curr_amb_temp; - s8 prev_cpu_temp; - s8 prev_amb_temp; - s8 avg_cpu_temp; - s8 avg_amb_temp; - - int sample_tick; - - enum fan_action fan_todo[2]; -#define FAN_AMBIENT 0 -#define FAN_CPU 1 -}; - -struct bbc_fan_control { - struct list_head bp_list; - struct list_head glob_list; - - struct bbc_i2c_client *client; - int index; - - int psupply_fan_on; - int cpu_fan_speed; - int system_fan_speed; -}; - -#define NUM_CHILDREN 8 - -struct bbc_i2c_bus { - struct bbc_i2c_bus *next; - int index; - spinlock_t lock; - void __iomem *i2c_bussel_reg; - void __iomem *i2c_control_regs; - unsigned char own, clock; - - wait_queue_head_t wq; - volatile int waiting; - - struct list_head temps; - struct list_head fans; - - struct of_device *op; - struct { - struct of_device *device; - int client_claimed; - } devs[NUM_CHILDREN]; -}; +struct bbc_i2c_client; /* Probing and attachment. */ -extern struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *, int); -extern struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *); +extern struct linux_ebus_child *bbc_i2c_getdev(int); +extern struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *); extern void bbc_i2c_detach(struct bbc_i2c_client *); /* Register read/write. NOTE: Blocking! */ diff --git a/trunk/drivers/sbus/char/bpp.c b/trunk/drivers/sbus/char/bpp.c new file mode 100644 index 000000000000..bba21e053a1b --- /dev/null +++ b/trunk/drivers/sbus/char/bpp.c @@ -0,0 +1,1055 @@ +/* + * drivers/sbus/char/bpp.c + * + * Copyright (c) 1995 Picture Elements + * Stephen Williams (steve@icarus.com) + * Gus Baldauf (gbaldauf@ix.netcom.com) + * + * Linux/SPARC port by Peter Zaitcev. + * Integration into SPARC tree by Tom Dyas. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(__i386__) +# include +#endif + +#if defined(__sparc__) +# include +# include /* udelay() */ + +# include /* OpenProm Library */ +# include +#endif + +#include + +#define BPP_PROBE_CODE 0x55 +#define BPP_DELAY 100 + +static const unsigned BPP_MAJOR = LP_MAJOR; +static const char *bpp_dev_name = "bpp"; + +/* When switching from compatibility to a mode where I can read, try + the following mode first. */ + +/* const unsigned char DEFAULT_ECP = 0x10; */ +static const unsigned char DEFAULT_ECP = 0x30; +static const unsigned char DEFAULT_NIBBLE = 0x00; + +/* + * These are 1284 time constraints, in units of jiffies. + */ + +static const unsigned long TIME_PSetup = 1; +static const unsigned long TIME_PResponse = 6; +static const unsigned long TIME_IDLE_LIMIT = 2000; + +/* + * One instance per supported subdevice... + */ +# define BPP_NO 3 + +enum IEEE_Mode { COMPATIBILITY, NIBBLE, ECP, ECP_RLE, EPP }; + +struct inst { + unsigned present : 1; /* True if the hardware exists */ + unsigned enhanced : 1; /* True if the hardware in "enhanced" */ + unsigned opened : 1; /* True if the device is opened already */ + unsigned run_flag : 1; /* True if waiting for a repeate byte */ + + unsigned char direction; /* 0 --> out, 0x20 --> IN */ + unsigned char pp_state; /* State of host controlled pins. */ + enum IEEE_Mode mode; + + unsigned char run_length; + unsigned char repeat_byte; +}; + +static struct inst instances[BPP_NO]; + +#if defined(__i386__) + +static const unsigned short base_addrs[BPP_NO] = { 0x278, 0x378, 0x3bc }; + +/* + * These are for data access. + * Control lines accesses are hidden in set_bits() and get_bits(). + * The exception is the probe procedure, which is system-dependent. + */ +#define bpp_outb_p(data, base) outb_p((data), (base)) +#define bpp_inb(base) inb(base) +#define bpp_inb_p(base) inb_p(base) + +/* + * This method takes the pin values mask and sets the hardware pins to + * the requested value: 1 == high voltage, 0 == low voltage. This + * burries the annoying PC bit inversion and preserves the direction + * flag. + */ +static void set_pins(unsigned short pins, unsigned minor) +{ + unsigned char bits = instances[minor].direction; /* == 0x20 */ + + if (! (pins & BPP_PP_nStrobe)) bits |= 1; + if (! (pins & BPP_PP_nAutoFd)) bits |= 2; + if ( pins & BPP_PP_nInit) bits |= 4; + if (! (pins & BPP_PP_nSelectIn)) bits |= 8; + + instances[minor].pp_state = bits; + + outb_p(bits, base_addrs[minor]+2); +} + +static unsigned short get_pins(unsigned minor) +{ + unsigned short bits = 0; + + unsigned value = instances[minor].pp_state; + if (! (value & 0x01)) bits |= BPP_PP_nStrobe; + if (! (value & 0x02)) bits |= BPP_PP_nAutoFd; + if (value & 0x04) bits |= BPP_PP_nInit; + if (! (value & 0x08)) bits |= BPP_PP_nSelectIn; + + value = inb_p(base_addrs[minor]+1); + if (value & 0x08) bits |= BPP_GP_nFault; + if (value & 0x10) bits |= BPP_GP_Select; + if (value & 0x20) bits |= BPP_GP_PError; + if (value & 0x40) bits |= BPP_GP_nAck; + if (! (value & 0x80)) bits |= BPP_GP_Busy; + + return bits; +} + +#endif /* __i386__ */ + +#if defined(__sparc__) + +/* + * Register block + */ + /* DMA registers */ +#define BPP_CSR 0x00 +#define BPP_ADDR 0x04 +#define BPP_BCNT 0x08 +#define BPP_TST_CSR 0x0C + /* Parallel Port registers */ +#define BPP_HCR 0x10 +#define BPP_OCR 0x12 +#define BPP_DR 0x14 +#define BPP_TCR 0x15 +#define BPP_OR 0x16 +#define BPP_IR 0x17 +#define BPP_ICR 0x18 +#define BPP_SIZE 0x1A + +/* BPP_CSR. Bits of type RW1 are cleared with writing '1'. */ +#define P_DEV_ID_MASK 0xf0000000 /* R */ +#define P_DEV_ID_ZEBRA 0x40000000 +#define P_DEV_ID_L64854 0xa0000000 /* == NCR 89C100+89C105. Pity. */ +#define P_NA_LOADED 0x08000000 /* R NA wirtten but was not used */ +#define P_A_LOADED 0x04000000 /* R */ +#define P_DMA_ON 0x02000000 /* R DMA is not disabled */ +#define P_EN_NEXT 0x01000000 /* RW */ +#define P_TCI_DIS 0x00800000 /* RW TCI forbidden from interrupts */ +#define P_DIAG 0x00100000 /* RW Disables draining and resetting + of P-FIFO on loading of P_ADDR*/ +#define P_BURST_SIZE 0x000c0000 /* RW SBus burst size */ +#define P_BURST_8 0x00000000 +#define P_BURST_4 0x00040000 +#define P_BURST_1 0x00080000 /* "No burst" write */ +#define P_TC 0x00004000 /* RW1 Term Count, can be cleared when + P_EN_NEXT=1 */ +#define P_EN_CNT 0x00002000 /* RW */ +#define P_EN_DMA 0x00000200 /* RW */ +#define P_WRITE 0x00000100 /* R DMA dir, 1=to ram, 0=to port */ +#define P_RESET 0x00000080 /* RW */ +#define P_SLAVE_ERR 0x00000040 /* RW1 Access size error */ +#define P_INVALIDATE 0x00000020 /* W Drop P-FIFO */ +#define P_INT_EN 0x00000010 /* RW OK to P_INT_PEND||P_ERR_PEND */ +#define P_DRAINING 0x0000000c /* R P-FIFO is draining to memory */ +#define P_ERR_PEND 0x00000002 /* R */ +#define P_INT_PEND 0x00000001 /* R */ + +/* BPP_HCR. Time is in increments of SBus clock. */ +#define P_HCR_TEST 0x8000 /* Allows buried counters to be read */ +#define P_HCR_DSW 0x7f00 /* Data strobe width (in ticks) */ +#define P_HCR_DDS 0x007f /* Data setup before strobe (in ticks) */ + +/* BPP_OCR. */ +#define P_OCR_MEM_CLR 0x8000 +#define P_OCR_DATA_SRC 0x4000 /* ) */ +#define P_OCR_DS_DSEL 0x2000 /* ) Bidirectional */ +#define P_OCR_BUSY_DSEL 0x1000 /* ) selects */ +#define P_OCR_ACK_DSEL 0x0800 /* ) */ +#define P_OCR_EN_DIAG 0x0400 +#define P_OCR_BUSY_OP 0x0200 /* Busy operation */ +#define P_OCR_ACK_OP 0x0100 /* Ack operation */ +#define P_OCR_SRST 0x0080 /* Reset state machines. Not selfcleaning. */ +#define P_OCR_IDLE 0x0008 /* PP data transfer state machine is idle */ +#define P_OCR_V_ILCK 0x0002 /* Versatec faded. Zebra only. */ +#define P_OCR_EN_VER 0x0001 /* Enable Versatec (0 - enable). Zebra only. */ + +/* BPP_TCR */ +#define P_TCR_DIR 0x08 +#define P_TCR_BUSY 0x04 +#define P_TCR_ACK 0x02 +#define P_TCR_DS 0x01 /* Strobe */ + +/* BPP_OR */ +#define P_OR_V3 0x20 /* ) */ +#define P_OR_V2 0x10 /* ) on Zebra only */ +#define P_OR_V1 0x08 /* ) */ +#define P_OR_INIT 0x04 +#define P_OR_AFXN 0x02 /* Auto Feed */ +#define P_OR_SLCT_IN 0x01 + +/* BPP_IR */ +#define P_IR_PE 0x04 +#define P_IR_SLCT 0x02 +#define P_IR_ERR 0x01 + +/* BPP_ICR */ +#define P_DS_IRQ 0x8000 /* RW1 */ +#define P_ACK_IRQ 0x4000 /* RW1 */ +#define P_BUSY_IRQ 0x2000 /* RW1 */ +#define P_PE_IRQ 0x1000 /* RW1 */ +#define P_SLCT_IRQ 0x0800 /* RW1 */ +#define P_ERR_IRQ 0x0400 /* RW1 */ +#define P_DS_IRQ_EN 0x0200 /* RW Always on rising edge */ +#define P_ACK_IRQ_EN 0x0100 /* RW Always on rising edge */ +#define P_BUSY_IRP 0x0080 /* RW 1= rising edge */ +#define P_BUSY_IRQ_EN 0x0040 /* RW */ +#define P_PE_IRP 0x0020 /* RW 1= rising edge */ +#define P_PE_IRQ_EN 0x0010 /* RW */ +#define P_SLCT_IRP 0x0008 /* RW 1= rising edge */ +#define P_SLCT_IRQ_EN 0x0004 /* RW */ +#define P_ERR_IRP 0x0002 /* RW1 1= rising edge */ +#define P_ERR_IRQ_EN 0x0001 /* RW */ + +static void __iomem *base_addrs[BPP_NO]; + +#define bpp_outb_p(data, base) sbus_writeb(data, (base) + BPP_DR) +#define bpp_inb_p(base) sbus_readb((base) + BPP_DR) +#define bpp_inb(base) sbus_readb((base) + BPP_DR) + +static void set_pins(unsigned short pins, unsigned minor) +{ + void __iomem *base = base_addrs[minor]; + unsigned char bits_tcr = 0, bits_or = 0; + + if (instances[minor].direction & 0x20) bits_tcr |= P_TCR_DIR; + if ( pins & BPP_PP_nStrobe) bits_tcr |= P_TCR_DS; + + if ( pins & BPP_PP_nAutoFd) bits_or |= P_OR_AFXN; + if (! (pins & BPP_PP_nInit)) bits_or |= P_OR_INIT; + if (! (pins & BPP_PP_nSelectIn)) bits_or |= P_OR_SLCT_IN; + + sbus_writeb(bits_or, base + BPP_OR); + sbus_writeb(bits_tcr, base + BPP_TCR); +} + +/* + * i386 people read output pins from a software image. + * We may get them back from hardware. + * Again, inversion of pins must he buried here. + */ +static unsigned short get_pins(unsigned minor) +{ + void __iomem *base = base_addrs[minor]; + unsigned short bits = 0; + unsigned value_tcr = sbus_readb(base + BPP_TCR); + unsigned value_ir = sbus_readb(base + BPP_IR); + unsigned value_or = sbus_readb(base + BPP_OR); + + if (value_tcr & P_TCR_DS) bits |= BPP_PP_nStrobe; + if (value_or & P_OR_AFXN) bits |= BPP_PP_nAutoFd; + if (! (value_or & P_OR_INIT)) bits |= BPP_PP_nInit; + if (! (value_or & P_OR_SLCT_IN)) bits |= BPP_PP_nSelectIn; + + if (value_ir & P_IR_ERR) bits |= BPP_GP_nFault; + if (! (value_ir & P_IR_SLCT)) bits |= BPP_GP_Select; + if (! (value_ir & P_IR_PE)) bits |= BPP_GP_PError; + if (! (value_tcr & P_TCR_ACK)) bits |= BPP_GP_nAck; + if (value_tcr & P_TCR_BUSY) bits |= BPP_GP_Busy; + + return bits; +} + +#endif /* __sparc__ */ + +static void snooze(unsigned long snooze_time, unsigned minor) +{ + schedule_timeout_uninterruptible(snooze_time + 1); +} + +static int wait_for(unsigned short set, unsigned short clr, + unsigned long delay, unsigned minor) +{ + unsigned short pins = get_pins(minor); + + unsigned long extime = 0; + + /* + * Try a real fast scan for the first jiffy, in case the device + * responds real good. The first while loop guesses an expire + * time accounting for possible wraparound of jiffies. + */ + while (time_after_eq(jiffies, extime)) extime = jiffies + 1; + while ( (time_before(jiffies, extime)) + && (((pins & set) != set) || ((pins & clr) != 0)) ) { + pins = get_pins(minor); + } + + delay -= 1; + + /* + * If my delay expired or the pins are still not where I want + * them, then resort to using the timer and greatly reduce my + * sample rate. If the peripheral is going to be slow, this will + * give the CPU up to some more worthy process. + */ + while ( delay && (((pins & set) != set) || ((pins & clr) != 0)) ) { + + snooze(1, minor); + pins = get_pins(minor); + delay -= 1; + } + + if (delay == 0) return -1; + else return pins; +} + +/* + * Return ZERO(0) If the negotiation succeeds, an errno otherwise. An + * errno means something broke, and I do not yet know how to fix it. + */ +static int negotiate(unsigned char mode, unsigned minor) +{ + int rc; + unsigned short pins = get_pins(minor); + if (pins & BPP_PP_nSelectIn) return -EIO; + + + /* Event 0: Write the mode to the data lines */ + bpp_outb_p(mode, base_addrs[minor]); + + snooze(TIME_PSetup, minor); + + /* Event 1: Strobe the mode code into the peripheral */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nInit, minor); + + /* Wait for Event 2: Peripheral responds as a 1284 device. */ + rc = wait_for(BPP_GP_PError|BPP_GP_Select|BPP_GP_nFault, + BPP_GP_nAck, + TIME_PResponse, + minor); + + if (rc == -1) return -ETIMEDOUT; + + /* Event 3: latch extensibility request */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nInit, minor); + + /* ... quick nap while peripheral ponders the byte i'm sending...*/ + snooze(1, minor); + + /* Event 4: restore strobe, to ACK peripheral's response. */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); + + /* Wait for Event 6: Peripheral latches response bits */ + rc = wait_for(BPP_GP_nAck, 0, TIME_PSetup+TIME_PResponse, minor); + if (rc == -1) return -EIO; + + /* A 1284 device cannot refuse nibble mode */ + if (mode == DEFAULT_NIBBLE) return 0; + + if (pins & BPP_GP_Select) return 0; + + return -EPROTONOSUPPORT; +} + +static int terminate(unsigned minor) +{ + int rc; + + /* Event 22: Request termination of 1284 mode */ + set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); + + /* Wait for Events 23 and 24: ACK termination request. */ + rc = wait_for(BPP_GP_Busy|BPP_GP_nFault, + BPP_GP_nAck, + TIME_PSetup+TIME_PResponse, + minor); + + instances[minor].direction = 0; + instances[minor].mode = COMPATIBILITY; + + if (rc == -1) { + return -EIO; + } + + /* Event 25: Handshake by lowering nAutoFd */ + set_pins(BPP_PP_nStrobe|BPP_PP_nInit, minor); + + /* Event 26: Peripheral wiggles lines... */ + + /* Event 27: Peripheral sets nAck HIGH to ack handshake */ + rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); + if (rc == -1) { + set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); + return -EIO; + } + + /* Event 28: Finish phase by raising nAutoFd */ + set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); + + return 0; +} + +static DEFINE_SPINLOCK(bpp_open_lock); + +/* + * Allow only one process to open the device at a time. + */ +static int bpp_open(struct inode *inode, struct file *f) +{ + unsigned minor = iminor(inode); + int ret; + + lock_kernel(); + spin_lock(&bpp_open_lock); + ret = 0; + if (minor >= BPP_NO) { + ret = -ENODEV; + } else { + if (! instances[minor].present) { + ret = -ENODEV; + } else { + if (instances[minor].opened) + ret = -EBUSY; + else + instances[minor].opened = 1; + } + } + spin_unlock(&bpp_open_lock); + unlock_kernel(); + + return ret; +} + +/* + * When the process closes the device, this method is called to clean + * up and reset the hardware. Always leave the device in compatibility + * mode as this is a reasonable place to clean up from messes made by + * ioctls, or other mayhem. + */ +static int bpp_release(struct inode *inode, struct file *f) +{ + unsigned minor = iminor(inode); + + spin_lock(&bpp_open_lock); + instances[minor].opened = 0; + + if (instances[minor].mode != COMPATIBILITY) + terminate(minor); + + spin_unlock(&bpp_open_lock); + + return 0; +} + +static long read_nibble(unsigned minor, char __user *c, unsigned long cnt) +{ + unsigned long remaining = cnt; + long rc; + + while (remaining > 0) { + unsigned char byte = 0; + int pins; + + /* Event 7: request nibble */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor); + + /* Wait for event 9: Peripher strobes first nibble */ + pins = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor); + if (pins == -1) return -ETIMEDOUT; + + /* Event 10: I handshake nibble */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor); + if (pins & BPP_GP_nFault) byte |= 0x01; + if (pins & BPP_GP_Select) byte |= 0x02; + if (pins & BPP_GP_PError) byte |= 0x04; + if (pins & BPP_GP_Busy) byte |= 0x08; + + /* Wait for event 11: Peripheral handshakes nibble */ + rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); + + /* Event 7: request nibble */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor); + + /* Wait for event 9: Peripher strobes first nibble */ + pins = wait_for(0, BPP_GP_nAck, TIME_PResponse, minor); + if (rc == -1) return -ETIMEDOUT; + + /* Event 10: I handshake nibble */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor); + if (pins & BPP_GP_nFault) byte |= 0x10; + if (pins & BPP_GP_Select) byte |= 0x20; + if (pins & BPP_GP_PError) byte |= 0x40; + if (pins & BPP_GP_Busy) byte |= 0x80; + + if (put_user(byte, c)) + return -EFAULT; + c += 1; + remaining -= 1; + + /* Wait for event 11: Peripheral handshakes nibble */ + rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); + if (rc == -1) return -EIO; + } + + return cnt - remaining; +} + +static long read_ecp(unsigned minor, char __user *c, unsigned long cnt) +{ + unsigned long remaining; + long rc; + + /* Turn ECP mode from forward to reverse if needed. */ + if (! instances[minor].direction) { + unsigned short pins = get_pins(minor); + + /* Event 38: Turn the bus around */ + instances[minor].direction = 0x20; + pins &= ~BPP_PP_nAutoFd; + set_pins(pins, minor); + + /* Event 39: Set pins for reverse mode. */ + snooze(TIME_PSetup, minor); + set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor); + + /* Wait for event 40: Peripheral ready to be strobed */ + rc = wait_for(0, BPP_GP_PError, TIME_PResponse, minor); + if (rc == -1) return -ETIMEDOUT; + } + + remaining = cnt; + + while (remaining > 0) { + + /* If there is a run length for a repeated byte, repeat */ + /* that byte a few times. */ + if (instances[minor].run_length && !instances[minor].run_flag) { + + char buffer[128]; + unsigned idx; + unsigned repeat = remaining < instances[minor].run_length + ? remaining + : instances[minor].run_length; + + for (idx = 0 ; idx < repeat ; idx += 1) + buffer[idx] = instances[minor].repeat_byte; + + if (copy_to_user(c, buffer, repeat)) + return -EFAULT; + remaining -= repeat; + c += repeat; + instances[minor].run_length -= repeat; + } + + if (remaining == 0) break; + + + /* Wait for Event 43: Data active on the bus. */ + rc = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor); + if (rc == -1) break; + + if (rc & BPP_GP_Busy) { + /* OK, this is data. read it in. */ + unsigned char byte = bpp_inb(base_addrs[minor]); + if (put_user(byte, c)) + return -EFAULT; + c += 1; + remaining -= 1; + + if (instances[minor].run_flag) { + instances[minor].repeat_byte = byte; + instances[minor].run_flag = 0; + } + + } else { + unsigned char byte = bpp_inb(base_addrs[minor]); + if (byte & 0x80) { + printk("bpp%d: " + "Ignoring ECP channel %u from device.\n", + minor, byte & 0x7f); + } else { + instances[minor].run_length = byte; + instances[minor].run_flag = 1; + } + } + + /* Event 44: I got it. */ + set_pins(BPP_PP_nStrobe|BPP_PP_nAutoFd|BPP_PP_nSelectIn, minor); + + /* Wait for event 45: peripheral handshake */ + rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); + if (rc == -1) return -ETIMEDOUT; + + /* Event 46: Finish handshake */ + set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor); + + } + + + return cnt - remaining; +} + +static ssize_t bpp_read(struct file *f, char __user *c, size_t cnt, loff_t * ppos) +{ + long rc; + unsigned minor = iminor(f->f_path.dentry->d_inode); + if (minor >= BPP_NO) return -ENODEV; + if (!instances[minor].present) return -ENODEV; + + switch (instances[minor].mode) { + + default: + if (instances[minor].mode != COMPATIBILITY) + terminate(minor); + + if (instances[minor].enhanced) { + /* For now, do all reads with ECP-RLE mode */ + unsigned short pins; + + rc = negotiate(DEFAULT_ECP, minor); + if (rc < 0) break; + + instances[minor].mode = ECP_RLE; + + /* Event 30: set nAutoFd low to setup for ECP mode */ + pins = get_pins(minor); + pins &= ~BPP_PP_nAutoFd; + set_pins(pins, minor); + + /* Wait for Event 31: peripheral ready */ + rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor); + if (rc == -1) return -ETIMEDOUT; + + rc = read_ecp(minor, c, cnt); + + } else { + rc = negotiate(DEFAULT_NIBBLE, minor); + if (rc < 0) break; + + instances[minor].mode = NIBBLE; + + rc = read_nibble(minor, c, cnt); + } + break; + + case NIBBLE: + rc = read_nibble(minor, c, cnt); + break; + + case ECP: + case ECP_RLE: + rc = read_ecp(minor, c, cnt); + break; + + } + + + return rc; +} + +/* + * Compatibility mode handshaking is a matter of writing data, + * strobing it, and waiting for the printer to stop being busy. + */ +static long write_compat(unsigned minor, const char __user *c, unsigned long cnt) +{ + long rc; + unsigned short pins = get_pins(minor); + + unsigned long remaining = cnt; + + + while (remaining > 0) { + unsigned char byte; + + if (get_user(byte, c)) + return -EFAULT; + c += 1; + + rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor); + if (rc == -1) return -ETIMEDOUT; + + bpp_outb_p(byte, base_addrs[minor]); + remaining -= 1; + /* snooze(1, minor); */ + + pins &= ~BPP_PP_nStrobe; + set_pins(pins, minor); + + rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor); + + pins |= BPP_PP_nStrobe; + set_pins(pins, minor); + } + + return cnt - remaining; +} + +/* + * Write data using ECP mode. Watch out that the port may be set up + * for reading. If so, turn the port around. + */ +static long write_ecp(unsigned minor, const char __user *c, unsigned long cnt) +{ + unsigned short pins = get_pins(minor); + unsigned long remaining = cnt; + + if (instances[minor].direction) { + int rc; + + /* Event 47 Request bus be turned around */ + pins |= BPP_PP_nInit; + set_pins(pins, minor); + + /* Wait for Event 49: Peripheral relinquished bus */ + rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor); + + pins |= BPP_PP_nAutoFd; + instances[minor].direction = 0; + set_pins(pins, minor); + } + + while (remaining > 0) { + unsigned char byte; + int rc; + + if (get_user(byte, c)) + return -EFAULT; + + rc = wait_for(0, BPP_GP_Busy, TIME_PResponse, minor); + if (rc == -1) return -ETIMEDOUT; + + c += 1; + + bpp_outb_p(byte, base_addrs[minor]); + + pins &= ~BPP_PP_nStrobe; + set_pins(pins, minor); + + pins |= BPP_PP_nStrobe; + rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor); + if (rc == -1) return -EIO; + + set_pins(pins, minor); + } + + return cnt - remaining; +} + +/* + * Write to the peripheral. Be sensitive of the current mode. If I'm + * in a mode that can be turned around (ECP) then just do + * that. Otherwise, terminate and do my writing in compat mode. This + * is the safest course as any device can handle it. + */ +static ssize_t bpp_write(struct file *f, const char __user *c, size_t cnt, loff_t * ppos) +{ + long errno = 0; + unsigned minor = iminor(f->f_path.dentry->d_inode); + if (minor >= BPP_NO) return -ENODEV; + if (!instances[minor].present) return -ENODEV; + + switch (instances[minor].mode) { + + case ECP: + case ECP_RLE: + errno = write_ecp(minor, c, cnt); + break; + case COMPATIBILITY: + errno = write_compat(minor, c, cnt); + break; + default: + terminate(minor); + errno = write_compat(minor, c, cnt); + } + + return errno; +} + +static int bpp_ioctl(struct inode *inode, struct file *f, unsigned int cmd, + unsigned long arg) +{ + int errno = 0; + + unsigned minor = iminor(inode); + if (minor >= BPP_NO) return -ENODEV; + if (!instances[minor].present) return -ENODEV; + + + switch (cmd) { + + case BPP_PUT_PINS: + set_pins(arg, minor); + break; + + case BPP_GET_PINS: + errno = get_pins(minor); + break; + + case BPP_PUT_DATA: + bpp_outb_p(arg, base_addrs[minor]); + break; + + case BPP_GET_DATA: + errno = bpp_inb_p(base_addrs[minor]); + break; + + case BPP_SET_INPUT: + if (arg) + if (instances[minor].enhanced) { + unsigned short bits = get_pins(minor); + instances[minor].direction = 0x20; + set_pins(bits, minor); + } else { + errno = -ENOTTY; + } + else { + unsigned short bits = get_pins(minor); + instances[minor].direction = 0x00; + set_pins(bits, minor); + } + break; + + default: + errno = -EINVAL; + } + + return errno; +} + +static const struct file_operations bpp_fops = { + .owner = THIS_MODULE, + .read = bpp_read, + .write = bpp_write, + .ioctl = bpp_ioctl, + .open = bpp_open, + .release = bpp_release, +}; + +#if defined(__i386__) + +#define collectLptPorts() {} + +static void probeLptPort(unsigned idx) +{ + unsigned int testvalue; + const unsigned short lpAddr = base_addrs[idx]; + + instances[idx].present = 0; + instances[idx].enhanced = 0; + instances[idx].direction = 0; + instances[idx].mode = COMPATIBILITY; + instances[idx].run_length = 0; + instances[idx].run_flag = 0; + if (!request_region(lpAddr,3, bpp_dev_name)) return; + + /* + * First, make sure the instance exists. Do this by writing to + * the data latch and reading the value back. If the port *is* + * present, test to see if it supports extended-mode + * operation. This will be required for IEEE1284 reverse + * transfers. + */ + + outb_p(BPP_PROBE_CODE, lpAddr); + for (testvalue=0; testvalueresource[0], 0, BPP_SIZE, "bpp"); +} + +static int collectLptPorts(void) +{ + struct sbus_bus *bus; + struct sbus_dev *dev; + int count; + + count = 0; + for_all_sbusdev(dev, bus) { + if (strcmp(dev->prom_name, "SUNW,bpp") == 0) { + if (count >= BPP_NO) { + printk(KERN_NOTICE + "bpp: More than %d bpp ports," + " rest is ignored\n", BPP_NO); + return count; + } + base_addrs[count] = map_bpp(dev, count); + count++; + } + } + return count; +} + +static void probeLptPort(unsigned idx) +{ + void __iomem *rp = base_addrs[idx]; + __u32 csr; + char *brand; + + instances[idx].present = 0; + instances[idx].enhanced = 0; + instances[idx].direction = 0; + instances[idx].mode = COMPATIBILITY; + instances[idx].run_length = 0; + instances[idx].run_flag = 0; + + if (!rp) return; + + instances[idx].present = 1; + instances[idx].enhanced = 1; /* Sure */ + + csr = sbus_readl(rp + BPP_CSR); + if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) { + udelay(20); + csr = sbus_readl(rp + BPP_CSR); + if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) { + printk("bpp%d: DRAINING still active (0x%08x)\n", idx, csr); + } + } + printk("bpp%d: reset with 0x%08x ..", idx, csr); + sbus_writel((csr | P_RESET) & ~P_INT_EN, rp + BPP_CSR); + udelay(500); + sbus_writel(sbus_readl(rp + BPP_CSR) & ~P_RESET, rp + BPP_CSR); + csr = sbus_readl(rp + BPP_CSR); + printk(" done with csr=0x%08x ocr=0x%04x\n", + csr, sbus_readw(rp + BPP_OCR)); + + switch (csr & P_DEV_ID_MASK) { + case P_DEV_ID_ZEBRA: + brand = "Zebra"; + break; + case P_DEV_ID_L64854: + brand = "DMA2"; + break; + default: + brand = "Unknown"; + } + printk("bpp%d: %s at %p\n", idx, brand, rp); + + /* + * Leave the port in compat idle mode. + */ + set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx); + + return; +} + +static inline void freeLptPort(int idx) +{ + sbus_iounmap(base_addrs[idx], BPP_SIZE); +} + +#endif + +static int __init bpp_init(void) +{ + int rc; + unsigned idx; + + rc = collectLptPorts(); + if (rc == 0) + return -ENODEV; + + rc = register_chrdev(BPP_MAJOR, bpp_dev_name, &bpp_fops); + if (rc < 0) + return rc; + + for (idx = 0; idx < BPP_NO; idx++) { + instances[idx].opened = 0; + probeLptPort(idx); + } + + return 0; +} + +static void __exit bpp_cleanup(void) +{ + unsigned idx; + + unregister_chrdev(BPP_MAJOR, bpp_dev_name); + + for (idx = 0; idx < BPP_NO; idx++) { + if (instances[idx].present) + freeLptPort(idx); + } +} + +module_init(bpp_init); +module_exit(bpp_cleanup); + +MODULE_LICENSE("GPL"); + diff --git a/trunk/drivers/sbus/char/cpwatchdog.c b/trunk/drivers/sbus/char/cpwatchdog.c new file mode 100644 index 000000000000..23abfdfb44f1 --- /dev/null +++ b/trunk/drivers/sbus/char/cpwatchdog.c @@ -0,0 +1,858 @@ +/* cpwatchdog.c - driver implementation for hardware watchdog + * timers found on Sun Microsystems CP1400 and CP1500 boards. + * + * This device supports both the generic Linux watchdog + * interface and Solaris-compatible ioctls as best it is + * able. + * + * NOTE: CP1400 systems appear to have a defective intr_mask + * register on the PLD, preventing the disabling of + * timer interrupts. We use a timer to periodically + * reset 'stopped' watchdogs on affected platforms. + * + * Copyright (c) 2000 Eric Brower (ebrower@usa.net) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define WD_OBPNAME "watchdog" +#define WD_BADMODEL "SUNW,501-5336" +#define WD_BTIMEOUT (jiffies + (HZ * 1000)) +#define WD_BLIMIT 0xFFFF + +#define WD0_DEVNAME "watchdog0" +#define WD1_DEVNAME "watchdog1" +#define WD2_DEVNAME "watchdog2" + +#define WD0_MINOR 212 +#define WD1_MINOR 213 +#define WD2_MINOR 214 + + +/* Internal driver definitions + */ +#define WD0_ID 0 /* Watchdog0 */ +#define WD1_ID 1 /* Watchdog1 */ +#define WD2_ID 2 /* Watchdog2 */ +#define WD_NUMDEVS 3 /* Device contains 3 timers */ + +#define WD_INTR_OFF 0 /* Interrupt disable value */ +#define WD_INTR_ON 1 /* Interrupt enable value */ + +#define WD_STAT_INIT 0x01 /* Watchdog timer is initialized */ +#define WD_STAT_BSTOP 0x02 /* Watchdog timer is brokenstopped */ +#define WD_STAT_SVCD 0x04 /* Watchdog interrupt occurred */ + +/* Register value definitions + */ +#define WD0_INTR_MASK 0x01 /* Watchdog device interrupt masks */ +#define WD1_INTR_MASK 0x02 +#define WD2_INTR_MASK 0x04 + +#define WD_S_RUNNING 0x01 /* Watchdog device status running */ +#define WD_S_EXPIRED 0x02 /* Watchdog device status expired */ + +/* Sun uses Altera PLD EPF8820ATC144-4 + * providing three hardware watchdogs: + * + * 1) RIC - sends an interrupt when triggered + * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU + * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board + * + *** Timer register block definition (struct wd_timer_regblk) + * + * dcntr and limit registers (halfword access): + * ------------------- + * | 15 | ...| 1 | 0 | + * ------------------- + * |- counter val -| + * ------------------- + * dcntr - Current 16-bit downcounter value. + * When downcounter reaches '0' watchdog expires. + * Reading this register resets downcounter with 'limit' value. + * limit - 16-bit countdown value in 1/10th second increments. + * Writing this register begins countdown with input value. + * Reading from this register does not affect counter. + * NOTES: After watchdog reset, dcntr and limit contain '1' + * + * status register (byte access): + * --------------------------- + * | 7 | ... | 2 | 1 | 0 | + * --------------+------------ + * |- UNUSED -| EXP | RUN | + * --------------------------- + * status- Bit 0 - Watchdog is running + * Bit 1 - Watchdog has expired + * + *** PLD register block definition (struct wd_pld_regblk) + * + * intr_mask register (byte access): + * --------------------------------- + * | 7 | ... | 3 | 2 | 1 | 0 | + * +-------------+------------------ + * |- UNUSED -| WD3 | WD2 | WD1 | + * --------------------------------- + * WD3 - 1 == Interrupt disabled for watchdog 3 + * WD2 - 1 == Interrupt disabled for watchdog 2 + * WD1 - 1 == Interrupt disabled for watchdog 1 + * + * pld_status register (byte access): + * UNKNOWN, MAGICAL MYSTERY REGISTER + * + */ +#define WD_TIMER_REGSZ 16 +#define WD0_OFF 0 +#define WD1_OFF (WD_TIMER_REGSZ * 1) +#define WD2_OFF (WD_TIMER_REGSZ * 2) +#define PLD_OFF (WD_TIMER_REGSZ * 3) + +#define WD_DCNTR 0x00 +#define WD_LIMIT 0x04 +#define WD_STATUS 0x08 + +#define PLD_IMASK (PLD_OFF + 0x00) +#define PLD_STATUS (PLD_OFF + 0x04) + +/* Individual timer structure + */ +struct wd_timer { + __u16 timeout; + __u8 intr_mask; + unsigned char runstatus; + void __iomem *regs; +}; + +/* Device structure + */ +struct wd_device { + int irq; + spinlock_t lock; + unsigned char isbaddoggie; /* defective PLD */ + unsigned char opt_enable; + unsigned char opt_reboot; + unsigned short opt_timeout; + unsigned char initialized; + struct wd_timer watchdog[WD_NUMDEVS]; + void __iomem *regs; +}; + +static struct wd_device wd_dev = { + 0, __SPIN_LOCK_UNLOCKED(wd_dev.lock), 0, 0, 0, 0, +}; + +static struct timer_list wd_timer; + +static int wd0_timeout = 0; +static int wd1_timeout = 0; +static int wd2_timeout = 0; + +#ifdef MODULE +module_param (wd0_timeout, int, 0); +MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs"); +module_param (wd1_timeout, int, 0); +MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs"); +module_param (wd2_timeout, int, 0); +MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs"); + +MODULE_AUTHOR + ("Eric Brower "); +MODULE_DESCRIPTION + ("Hardware watchdog driver for Sun Microsystems CP1400/1500"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE + ("watchdog"); +#endif /* ifdef MODULE */ + +/* Forward declarations of internal methods + */ +#ifdef WD_DEBUG +static void wd_dumpregs(void); +#endif +static irqreturn_t wd_interrupt(int irq, void *dev_id); +static void wd_toggleintr(struct wd_timer* pTimer, int enable); +static void wd_pingtimer(struct wd_timer* pTimer); +static void wd_starttimer(struct wd_timer* pTimer); +static void wd_resetbrokentimer(struct wd_timer* pTimer); +static void wd_stoptimer(struct wd_timer* pTimer); +static void wd_brokentimer(unsigned long data); +static int wd_getstatus(struct wd_timer* pTimer); + +/* PLD expects words to be written in LSB format, + * so we must flip all words prior to writing them to regs + */ +static inline unsigned short flip_word(unsigned short word) +{ + return ((word & 0xff) << 8) | ((word >> 8) & 0xff); +} + +#define wd_writew(val, addr) (writew(flip_word(val), addr)) +#define wd_readw(addr) (flip_word(readw(addr))) +#define wd_writeb(val, addr) (writeb(val, addr)) +#define wd_readb(addr) (readb(addr)) + + +/* CP1400s seem to have broken PLD implementations-- + * the interrupt_mask register cannot be written, so + * no timer interrupts can be masked within the PLD. + */ +static inline int wd_isbroken(void) +{ + /* we could test this by read/write/read/restore + * on the interrupt mask register only if OBP + * 'watchdog-enable?' == FALSE, but it seems + * ubiquitous on CP1400s + */ + char val[32]; + prom_getproperty(prom_root_node, "model", val, sizeof(val)); + return((!strcmp(val, WD_BADMODEL)) ? 1 : 0); +} + +/* Retrieve watchdog-enable? option from OBP + * Returns 0 if false, 1 if true + */ +static inline int wd_opt_enable(void) +{ + int opt_node; + + opt_node = prom_getchild(prom_root_node); + opt_node = prom_searchsiblings(opt_node, "options"); + return((-1 == prom_getint(opt_node, "watchdog-enable?")) ? 0 : 1); +} + +/* Retrieve watchdog-reboot? option from OBP + * Returns 0 if false, 1 if true + */ +static inline int wd_opt_reboot(void) +{ + int opt_node; + + opt_node = prom_getchild(prom_root_node); + opt_node = prom_searchsiblings(opt_node, "options"); + return((-1 == prom_getint(opt_node, "watchdog-reboot?")) ? 0 : 1); +} + +/* Retrieve watchdog-timeout option from OBP + * Returns OBP value, or 0 if not located + */ +static inline int wd_opt_timeout(void) +{ + int opt_node; + char value[32]; + char *p = value; + + opt_node = prom_getchild(prom_root_node); + opt_node = prom_searchsiblings(opt_node, "options"); + opt_node = prom_getproperty(opt_node, + "watchdog-timeout", + value, + sizeof(value)); + if(-1 != opt_node) { + /* atoi implementation */ + for(opt_node = 0; /* nop */; p++) { + if(*p >= '0' && *p <= '9') { + opt_node = (10*opt_node)+(*p-'0'); + } + else { + break; + } + } + } + return((-1 == opt_node) ? (0) : (opt_node)); +} + +static int wd_open(struct inode *inode, struct file *f) +{ + lock_kernel(); + switch(iminor(inode)) + { + case WD0_MINOR: + f->private_data = &wd_dev.watchdog[WD0_ID]; + break; + case WD1_MINOR: + f->private_data = &wd_dev.watchdog[WD1_ID]; + break; + case WD2_MINOR: + f->private_data = &wd_dev.watchdog[WD2_ID]; + break; + default: + unlock_kernel(); + return(-ENODEV); + } + + /* Register IRQ on first open of device */ + if(0 == wd_dev.initialized) + { + if (request_irq(wd_dev.irq, + &wd_interrupt, + IRQF_SHARED, + WD_OBPNAME, + (void *)wd_dev.regs)) { + printk("%s: Cannot register IRQ %d\n", + WD_OBPNAME, wd_dev.irq); + unlock_kernel(); + return(-EBUSY); + } + wd_dev.initialized = 1; + } + + unlock_kernel(); + return(nonseekable_open(inode, f)); +} + +static int wd_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static int wd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int setopt = 0; + struct wd_timer* pTimer = (struct wd_timer*)file->private_data; + void __user *argp = (void __user *)arg; + struct watchdog_info info = { + 0, + 0, + "Altera EPF8820ATC144-4" + }; + + if(NULL == pTimer) { + return(-EINVAL); + } + + switch(cmd) + { + /* Generic Linux IOCTLs */ + case WDIOC_GETSUPPORT: + if(copy_to_user(argp, &info, sizeof(struct watchdog_info))) { + return(-EFAULT); + } + break; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + if (put_user(0, (int __user *)argp)) + return -EFAULT; + break; + case WDIOC_KEEPALIVE: + wd_pingtimer(pTimer); + break; + case WDIOC_SETOPTIONS: + if(copy_from_user(&setopt, argp, sizeof(unsigned int))) { + return -EFAULT; + } + if(setopt & WDIOS_DISABLECARD) { + if(wd_dev.opt_enable) { + printk( + "%s: cannot disable watchdog in ENABLED mode\n", + WD_OBPNAME); + return(-EINVAL); + } + wd_stoptimer(pTimer); + } + else if(setopt & WDIOS_ENABLECARD) { + wd_starttimer(pTimer); + } + else { + return(-EINVAL); + } + break; + /* Solaris-compatible IOCTLs */ + case WIOCGSTAT: + setopt = wd_getstatus(pTimer); + if(copy_to_user(argp, &setopt, sizeof(unsigned int))) { + return(-EFAULT); + } + break; + case WIOCSTART: + wd_starttimer(pTimer); + break; + case WIOCSTOP: + if(wd_dev.opt_enable) { + printk("%s: cannot disable watchdog in ENABLED mode\n", + WD_OBPNAME); + return(-EINVAL); + } + wd_stoptimer(pTimer); + break; + default: + return(-EINVAL); + } + return(0); +} + +static long wd_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int rval = -ENOIOCTLCMD; + + switch (cmd) { + /* solaris ioctls are specific to this driver */ + case WIOCSTART: + case WIOCSTOP: + case WIOCGSTAT: + lock_kernel(); + rval = wd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); + unlock_kernel(); + break; + /* everything else is handled by the generic compat layer */ + default: + break; + } + + return rval; +} + +static ssize_t wd_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + struct wd_timer* pTimer = (struct wd_timer*)file->private_data; + + if(NULL == pTimer) { + return(-EINVAL); + } + + if (count) { + wd_pingtimer(pTimer); + return 1; + } + return 0; +} + +static ssize_t wd_read(struct file * file, char __user *buffer, + size_t count, loff_t *ppos) +{ +#ifdef WD_DEBUG + wd_dumpregs(); + return(0); +#else + return(-EINVAL); +#endif /* ifdef WD_DEBUG */ +} + +static irqreturn_t wd_interrupt(int irq, void *dev_id) +{ + /* Only WD0 will interrupt-- others are NMI and we won't + * see them here.... + */ + spin_lock_irq(&wd_dev.lock); + if((unsigned long)wd_dev.regs == (unsigned long)dev_id) + { + wd_stoptimer(&wd_dev.watchdog[WD0_ID]); + wd_dev.watchdog[WD0_ID].runstatus |= WD_STAT_SVCD; + } + spin_unlock_irq(&wd_dev.lock); + return IRQ_HANDLED; +} + +static const struct file_operations wd_fops = { + .owner = THIS_MODULE, + .ioctl = wd_ioctl, + .compat_ioctl = wd_compat_ioctl, + .open = wd_open, + .write = wd_write, + .read = wd_read, + .release = wd_release, +}; + +static struct miscdevice wd0_miscdev = { WD0_MINOR, WD0_DEVNAME, &wd_fops }; +static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops }; +static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops }; + +#ifdef WD_DEBUG +static void wd_dumpregs(void) +{ + /* Reading from downcounters initiates watchdog countdown-- + * Example is included below for illustration purposes. + */ + int i; + printk("%s: dumping register values\n", WD_OBPNAME); + for(i = WD0_ID; i < WD_NUMDEVS; ++i) { + /* printk("\t%s%i: dcntr at 0x%lx: 0x%x\n", + * WD_OBPNAME, + * i, + * (unsigned long)(&wd_dev.watchdog[i].regs->dcntr), + * readw(&wd_dev.watchdog[i].regs->dcntr)); + */ + printk("\t%s%i: limit at 0x%lx: 0x%x\n", + WD_OBPNAME, + i, + (unsigned long)(&wd_dev.watchdog[i].regs->limit), + readw(&wd_dev.watchdog[i].regs->limit)); + printk("\t%s%i: status at 0x%lx: 0x%x\n", + WD_OBPNAME, + i, + (unsigned long)(&wd_dev.watchdog[i].regs->status), + readb(&wd_dev.watchdog[i].regs->status)); + printk("\t%s%i: driver status: 0x%x\n", + WD_OBPNAME, + i, + wd_getstatus(&wd_dev.watchdog[i])); + } + printk("\tintr_mask at %p: 0x%x\n", + wd_dev.regs + PLD_IMASK, + readb(wd_dev.regs + PLD_IMASK)); + printk("\tpld_status at %p: 0x%x\n", + wd_dev.regs + PLD_STATUS, + readb(wd_dev.regs + PLD_STATUS)); +} +#endif + +/* Enable or disable watchdog interrupts + * Because of the CP1400 defect this should only be + * called during initialzation or by wd_[start|stop]timer() + * + * pTimer - pointer to timer device, or NULL to indicate all timers + * enable - non-zero to enable interrupts, zero to disable + */ +static void wd_toggleintr(struct wd_timer* pTimer, int enable) +{ + unsigned char curregs = wd_readb(wd_dev.regs + PLD_IMASK); + unsigned char setregs = + (NULL == pTimer) ? + (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : + (pTimer->intr_mask); + + (WD_INTR_ON == enable) ? + (curregs &= ~setregs): + (curregs |= setregs); + + wd_writeb(curregs, wd_dev.regs + PLD_IMASK); + return; +} + +/* Reset countdown timer with 'limit' value and continue countdown. + * This will not start a stopped timer. + * + * pTimer - pointer to timer device + */ +static void wd_pingtimer(struct wd_timer* pTimer) +{ + if (wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { + wd_readw(pTimer->regs + WD_DCNTR); + } +} + +/* Stop a running watchdog timer-- the timer actually keeps + * running, but the interrupt is masked so that no action is + * taken upon expiration. + * + * pTimer - pointer to timer device + */ +static void wd_stoptimer(struct wd_timer* pTimer) +{ + if(wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { + wd_toggleintr(pTimer, WD_INTR_OFF); + + if(wd_dev.isbaddoggie) { + pTimer->runstatus |= WD_STAT_BSTOP; + wd_brokentimer((unsigned long)&wd_dev); + } + } +} + +/* Start a watchdog timer with the specified limit value + * If the watchdog is running, it will be restarted with + * the provided limit value. + * + * This function will enable interrupts on the specified + * watchdog. + * + * pTimer - pointer to timer device + * limit - limit (countdown) value in 1/10th seconds + */ +static void wd_starttimer(struct wd_timer* pTimer) +{ + if(wd_dev.isbaddoggie) { + pTimer->runstatus &= ~WD_STAT_BSTOP; + } + pTimer->runstatus &= ~WD_STAT_SVCD; + + wd_writew(pTimer->timeout, pTimer->regs + WD_LIMIT); + wd_toggleintr(pTimer, WD_INTR_ON); +} + +/* Restarts timer with maximum limit value and + * does not unset 'brokenstop' value. + */ +static void wd_resetbrokentimer(struct wd_timer* pTimer) +{ + wd_toggleintr(pTimer, WD_INTR_ON); + wd_writew(WD_BLIMIT, pTimer->regs + WD_LIMIT); +} + +/* Timer device initialization helper. + * Returns 0 on success, other on failure + */ +static int wd_inittimer(int whichdog) +{ + struct miscdevice *whichmisc; + void __iomem *whichregs; + char whichident[8]; + int whichmask; + __u16 whichlimit; + + switch(whichdog) + { + case WD0_ID: + whichmisc = &wd0_miscdev; + strcpy(whichident, "RIC"); + whichregs = wd_dev.regs + WD0_OFF; + whichmask = WD0_INTR_MASK; + whichlimit= (0 == wd0_timeout) ? + (wd_dev.opt_timeout): + (wd0_timeout); + break; + case WD1_ID: + whichmisc = &wd1_miscdev; + strcpy(whichident, "XIR"); + whichregs = wd_dev.regs + WD1_OFF; + whichmask = WD1_INTR_MASK; + whichlimit= (0 == wd1_timeout) ? + (wd_dev.opt_timeout): + (wd1_timeout); + break; + case WD2_ID: + whichmisc = &wd2_miscdev; + strcpy(whichident, "POR"); + whichregs = wd_dev.regs + WD2_OFF; + whichmask = WD2_INTR_MASK; + whichlimit= (0 == wd2_timeout) ? + (wd_dev.opt_timeout): + (wd2_timeout); + break; + default: + printk("%s: %s: invalid watchdog id: %i\n", + WD_OBPNAME, __func__, whichdog); + return(1); + } + if(0 != misc_register(whichmisc)) + { + return(1); + } + wd_dev.watchdog[whichdog].regs = whichregs; + wd_dev.watchdog[whichdog].timeout = whichlimit; + wd_dev.watchdog[whichdog].intr_mask = whichmask; + wd_dev.watchdog[whichdog].runstatus &= ~WD_STAT_BSTOP; + wd_dev.watchdog[whichdog].runstatus |= WD_STAT_INIT; + + printk("%s%i: %s hardware watchdog [%01i.%i sec] %s\n", + WD_OBPNAME, + whichdog, + whichident, + wd_dev.watchdog[whichdog].timeout / 10, + wd_dev.watchdog[whichdog].timeout % 10, + (0 != wd_dev.opt_enable) ? "in ENABLED mode" : ""); + return(0); +} + +/* Timer method called to reset stopped watchdogs-- + * because of the PLD bug on CP1400, we cannot mask + * interrupts within the PLD so me must continually + * reset the timers ad infinitum. + */ +static void wd_brokentimer(unsigned long data) +{ + struct wd_device* pDev = (struct wd_device*)data; + int id, tripped = 0; + + /* kill a running timer instance, in case we + * were called directly instead of by kernel timer + */ + if(timer_pending(&wd_timer)) { + del_timer(&wd_timer); + } + + for(id = WD0_ID; id < WD_NUMDEVS; ++id) { + if(pDev->watchdog[id].runstatus & WD_STAT_BSTOP) { + ++tripped; + wd_resetbrokentimer(&pDev->watchdog[id]); + } + } + + if(tripped) { + /* there is at least one timer brokenstopped-- reschedule */ + init_timer(&wd_timer); + wd_timer.expires = WD_BTIMEOUT; + add_timer(&wd_timer); + } +} + +static int wd_getstatus(struct wd_timer* pTimer) +{ + unsigned char stat = wd_readb(pTimer->regs + WD_STATUS); + unsigned char intr = wd_readb(wd_dev.regs + PLD_IMASK); + unsigned char ret = WD_STOPPED; + + /* determine STOPPED */ + if(0 == stat ) { + return(ret); + } + /* determine EXPIRED vs FREERUN vs RUNNING */ + else if(WD_S_EXPIRED & stat) { + ret = WD_EXPIRED; + } + else if(WD_S_RUNNING & stat) { + if(intr & pTimer->intr_mask) { + ret = WD_FREERUN; + } + else { + /* Fudge WD_EXPIRED status for defective CP1400-- + * IF timer is running + * AND brokenstop is set + * AND an interrupt has been serviced + * we are WD_EXPIRED. + * + * IF timer is running + * AND brokenstop is set + * AND no interrupt has been serviced + * we are WD_FREERUN. + */ + if(wd_dev.isbaddoggie && (pTimer->runstatus & WD_STAT_BSTOP)) { + if(pTimer->runstatus & WD_STAT_SVCD) { + ret = WD_EXPIRED; + } + else { + /* we could as well pretend we are expired */ + ret = WD_FREERUN; + } + } + else { + ret = WD_RUNNING; + } + } + } + + /* determine SERVICED */ + if(pTimer->runstatus & WD_STAT_SVCD) { + ret |= WD_SERVICED; + } + + return(ret); +} + +static int __init wd_init(void) +{ + int id; + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->ofdev.node->name, WD_OBPNAME)) + goto ebus_done; + } + } + +ebus_done: + if(!edev) { + printk("%s: unable to locate device\n", WD_OBPNAME); + return -ENODEV; + } + + wd_dev.regs = + ioremap(edev->resource[0].start, 4 * WD_TIMER_REGSZ); /* ? */ + + if(NULL == wd_dev.regs) { + printk("%s: unable to map registers\n", WD_OBPNAME); + return(-ENODEV); + } + + /* initialize device structure from OBP parameters */ + wd_dev.irq = edev->irqs[0]; + wd_dev.opt_enable = wd_opt_enable(); + wd_dev.opt_reboot = wd_opt_reboot(); + wd_dev.opt_timeout = wd_opt_timeout(); + wd_dev.isbaddoggie = wd_isbroken(); + + /* disable all interrupts unless watchdog-enabled? == true */ + if(! wd_dev.opt_enable) { + wd_toggleintr(NULL, WD_INTR_OFF); + } + + /* register miscellaneous devices */ + for(id = WD0_ID; id < WD_NUMDEVS; ++id) { + if(0 != wd_inittimer(id)) { + printk("%s%i: unable to initialize\n", WD_OBPNAME, id); + } + } + + /* warn about possible defective PLD */ + if(wd_dev.isbaddoggie) { + init_timer(&wd_timer); + wd_timer.function = wd_brokentimer; + wd_timer.data = (unsigned long)&wd_dev; + wd_timer.expires = WD_BTIMEOUT; + + printk("%s: PLD defect workaround enabled for model %s\n", + WD_OBPNAME, WD_BADMODEL); + } + return(0); +} + +static void __exit wd_cleanup(void) +{ + int id; + + /* if 'watchdog-enable?' == TRUE, timers are not stopped + * when module is unloaded. All brokenstopped timers will + * also now eventually trip. + */ + for(id = WD0_ID; id < WD_NUMDEVS; ++id) { + if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs + WD_STATUS)) { + if(wd_dev.opt_enable) { + printk(KERN_WARNING "%s%i: timer not stopped at release\n", + WD_OBPNAME, id); + } + else { + wd_stoptimer(&wd_dev.watchdog[id]); + if(wd_dev.watchdog[id].runstatus & WD_STAT_BSTOP) { + wd_resetbrokentimer(&wd_dev.watchdog[id]); + printk(KERN_WARNING + "%s%i: defect workaround disabled at release, "\ + "timer expires in ~%01i sec\n", + WD_OBPNAME, id, + wd_readw(wd_dev.watchdog[id].regs + WD_LIMIT) / 10); + } + } + } + } + + if(wd_dev.isbaddoggie && timer_pending(&wd_timer)) { + del_timer(&wd_timer); + } + if(0 != (wd_dev.watchdog[WD0_ID].runstatus & WD_STAT_INIT)) { + misc_deregister(&wd0_miscdev); + } + if(0 != (wd_dev.watchdog[WD1_ID].runstatus & WD_STAT_INIT)) { + misc_deregister(&wd1_miscdev); + } + if(0 != (wd_dev.watchdog[WD2_ID].runstatus & WD_STAT_INIT)) { + misc_deregister(&wd2_miscdev); + } + if(0 != wd_dev.initialized) { + free_irq(wd_dev.irq, (void *)wd_dev.regs); + } + iounmap(wd_dev.regs); +} + +module_init(wd_init); +module_exit(wd_cleanup); diff --git a/trunk/drivers/sbus/char/display7seg.c b/trunk/drivers/sbus/char/display7seg.c index 2550af4ae432..d8f5c0ca236d 100644 --- a/trunk/drivers/sbus/char/display7seg.c +++ b/trunk/drivers/sbus/char/display7seg.c @@ -1,7 +1,10 @@ -/* display7seg.c - Driver implementation for the 7-segment display - * present on Sun Microsystems CP1400 and CP1500 +/* $Id: display7seg.c,v 1.6 2002/01/08 16:00:16 davem Exp $ + * + * display7seg - Driver implementation for the 7-segment display + * present on Sun Microsystems CP1400 and CP1500 * * Copyright (c) 2000 Eric Brower (ebrower@usa.net) + * */ #include @@ -13,20 +16,22 @@ #include #include /* request_region */ #include -#include -#include #include +#include /* EBus device */ +#include /* OpenProm Library */ #include /* put_/get_user */ #include #include #define D7S_MINOR 193 -#define DRIVER_NAME "d7s" -#define PFX DRIVER_NAME ": " +#define D7S_OBPNAME "display7seg" +#define D7S_DEVNAME "d7s" static int sol_compat = 0; /* Solaris compatibility mode */ +#ifdef MODULE + /* Solaris compatibility flag - * The Solaris implementation omits support for several * documented driver features (ref Sun doc 806-0180-03). @@ -41,20 +46,20 @@ static int sol_compat = 0; /* Solaris compatibility mode */ * If you wish the device to operate as under Solaris, * omitting above features, set this parameter to non-zero. */ -module_param(sol_compat, int, 0); -MODULE_PARM_DESC(sol_compat, - "Disables documented functionality omitted from Solaris driver"); - -MODULE_AUTHOR("Eric Brower "); -MODULE_DESCRIPTION("7-Segment Display driver for Sun Microsystems CP1400/1500"); +module_param + (sol_compat, int, 0); +MODULE_PARM_DESC + (sol_compat, + "Disables documented functionality omitted from Solaris driver"); + +MODULE_AUTHOR + ("Eric Brower "); +MODULE_DESCRIPTION + ("7-Segment Display driver for Sun Microsystems CP1400/1500"); MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("d7s"); - -struct d7s { - void __iomem *regs; - bool flipped; -}; -struct d7s *d7s_device; +MODULE_SUPPORTED_DEVICE + ("d7s"); +#endif /* ifdef MODULE */ /* * Register block address- see header for details @@ -67,6 +72,22 @@ struct d7s *d7s_device; * FLIP - Inverts display for upside-down mounted board * bits 0-4 - 7-segment display contents */ +static void __iomem* d7s_regs; + +static inline void d7s_free(void) +{ + iounmap(d7s_regs); +} + +static inline int d7s_obpflipped(void) +{ + int opt_node; + + opt_node = prom_getchild(prom_root_node); + opt_node = prom_searchsiblings(opt_node, "options"); + return ((-1 != prom_getintdefault(opt_node, "d7s-flipped?", -1)) ? 0 : 1); +} + static atomic_t d7s_users = ATOMIC_INIT(0); static int d7s_open(struct inode *inode, struct file *f) @@ -85,15 +106,12 @@ static int d7s_release(struct inode *inode, struct file *f) * are not operating in solaris-compat mode */ if (atomic_dec_and_test(&d7s_users) && !sol_compat) { - struct d7s *p = d7s_device; - u8 regval = 0; - - regval = readb(p->regs); - if (p->flipped) - regval |= D7S_FLIP; - else - regval &= ~D7S_FLIP; - writeb(regval, p->regs); + int regval = 0; + + regval = readb(d7s_regs); + (0 == d7s_obpflipped()) ? + writeb(regval |= D7S_FLIP, d7s_regs): + writeb(regval &= ~D7S_FLIP, d7s_regs); } return 0; @@ -101,10 +119,9 @@ static int d7s_release(struct inode *inode, struct file *f) static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct d7s *p = d7s_device; - u8 regs = readb(p->regs); + __u8 regs = readb(d7s_regs); + __u8 ireg = 0; int error = 0; - u8 ireg = 0; if (D7S_MINOR != iminor(file->f_path.dentry->d_inode)) return -ENODEV; @@ -112,20 +129,18 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg) lock_kernel(); switch (cmd) { case D7SIOCWR: - /* assign device register values we mask-out D7S_FLIP - * if in sol_compat mode + /* assign device register values + * we mask-out D7S_FLIP if in sol_compat mode */ if (get_user(ireg, (int __user *) arg)) { error = -EFAULT; break; } - if (sol_compat) { - if (regs & D7S_FLIP) - ireg |= D7S_FLIP; - else - ireg &= ~D7S_FLIP; + if (0 != sol_compat) { + (regs & D7S_FLIP) ? + (ireg |= D7S_FLIP) : (ireg &= ~D7S_FLIP); } - writeb(ireg, p->regs); + writeb(ireg, d7s_regs); break; case D7SIOCRD: @@ -143,11 +158,9 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case D7SIOCTM: /* toggle device mode-- flip display orientation */ - if (regs & D7S_FLIP) - regs &= ~D7S_FLIP; - else - regs |= D7S_FLIP; - writeb(regs, p->regs); + (regs & D7S_FLIP) ? + (regs &= ~D7S_FLIP) : (regs |= D7S_FLIP); + writeb(regs, d7s_regs); break; }; unlock_kernel(); @@ -163,123 +176,69 @@ static const struct file_operations d7s_fops = { .release = d7s_release, }; -static struct miscdevice d7s_miscdev = { - .minor = D7S_MINOR, - .name = DRIVER_NAME, - .fops = &d7s_fops -}; +static struct miscdevice d7s_miscdev = { D7S_MINOR, D7S_DEVNAME, &d7s_fops }; -static int __devinit d7s_probe(struct of_device *op, - const struct of_device_id *match) +static int __init d7s_init(void) { - struct device_node *opts; - int err = -EINVAL; - struct d7s *p; - u8 regs; - - if (d7s_device) - goto out; - - p = kzalloc(sizeof(*p), GFP_KERNEL); - err = -ENOMEM; - if (!p) - goto out; - - p->regs = of_ioremap(&op->resource[0], 0, sizeof(u8), "d7s"); - if (!p->regs) { - printk(KERN_ERR PFX "Cannot map chip registers\n"); - goto out_free; + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + int iTmp = 0, regs = 0; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_node->name, D7S_OBPNAME)) + goto ebus_done; + } } - err = misc_register(&d7s_miscdev); - if (err) { - printk(KERN_ERR PFX "Unable to acquire miscdevice minor %i\n", - D7S_MINOR); - goto out_iounmap; +ebus_done: + if(!edev) { + printk("%s: unable to locate device\n", D7S_DEVNAME); + return -ENODEV; } - /* OBP option "d7s-flipped?" is honored as default for the - * device, and reset default when detached - */ - regs = readb(p->regs); - opts = of_find_node_by_path("/options"); - if (opts && - of_get_property(opts, "d7s-flipped?", NULL)) - p->flipped = true; - - if (p->flipped) - regs |= D7S_FLIP; - else - regs &= ~D7S_FLIP; - - writeb(regs, p->regs); - - printk(KERN_INFO PFX "7-Segment Display%s at [%s:0x%lx] %s\n", - op->node->full_name, - (regs & D7S_FLIP) ? " (FLIPPED)" : "", - op->resource[0].start, - sol_compat ? "in sol_compat mode" : ""); - - dev_set_drvdata(&op->dev, p); - d7s_device = p; - err = 0; - -out: - return err; - -out_iounmap: - of_iounmap(&op->resource[0], p->regs, sizeof(u8)); - -out_free: - kfree(p); - goto out; -} + d7s_regs = ioremap(edev->resource[0].start, sizeof(__u8)); -static int __devexit d7s_remove(struct of_device *op) -{ - struct d7s *p = dev_get_drvdata(&op->dev); - u8 regs = readb(p->regs); - - /* Honor OBP d7s-flipped? unless operating in solaris-compat mode */ - if (sol_compat) { - if (p->flipped) - regs |= D7S_FLIP; - else - regs &= ~D7S_FLIP; - writeb(regs, p->regs); + iTmp = misc_register(&d7s_miscdev); + if (0 != iTmp) { + printk("%s: unable to acquire miscdevice minor %i\n", + D7S_DEVNAME, D7S_MINOR); + iounmap(d7s_regs); + return iTmp; } - misc_deregister(&d7s_miscdev); - of_iounmap(&op->resource[0], p->regs, sizeof(u8)); - kfree(p); + /* OBP option "d7s-flipped?" is honored as default + * for the device, and reset default when detached + */ + regs = readb(d7s_regs); + iTmp = d7s_obpflipped(); + (0 == iTmp) ? + writeb(regs |= D7S_FLIP, d7s_regs): + writeb(regs &= ~D7S_FLIP, d7s_regs); + + printk("%s: 7-Segment Display%s at 0x%lx %s\n", + D7S_DEVNAME, + (0 == iTmp) ? (" (FLIPPED)") : (""), + edev->resource[0].start, + (0 != sol_compat) ? ("in sol_compat mode") : ("")); return 0; } -static const struct of_device_id d7s_match[] = { - { - .name = "display7seg", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, d7s_match); - -static struct of_platform_driver d7s_driver = { - .name = DRIVER_NAME, - .match_table = d7s_match, - .probe = d7s_probe, - .remove = __devexit_p(d7s_remove), -}; - -static int __init d7s_init(void) +static void __exit d7s_cleanup(void) { - return of_register_driver(&d7s_driver, &of_bus_type); -} + int regs = readb(d7s_regs); -static void __exit d7s_exit(void) -{ - of_unregister_driver(&d7s_driver); + /* Honor OBP d7s-flipped? unless operating in solaris-compat mode */ + if (0 == sol_compat) { + (0 == d7s_obpflipped()) ? + writeb(regs |= D7S_FLIP, d7s_regs): + writeb(regs &= ~D7S_FLIP, d7s_regs); + } + + misc_deregister(&d7s_miscdev); + d7s_free(); } module_init(d7s_init); -module_exit(d7s_exit); +module_exit(d7s_cleanup); diff --git a/trunk/drivers/sbus/char/envctrl.c b/trunk/drivers/sbus/char/envctrl.c index 58e583b61e60..a408402426f8 100644 --- a/trunk/drivers/sbus/char/envctrl.c +++ b/trunk/drivers/sbus/char/envctrl.c @@ -1,4 +1,5 @@ -/* envctrl.c: Temperature and Fan monitoring on Machines providing it. +/* $Id: envctrl.c,v 1.25 2002/01/15 09:01:26 davem Exp $ + * envctrl.c: Temperature and Fan monitoring on Machines providing it. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 2000 Vinh Truong (vinh.truong@eng.sun.com) @@ -27,16 +28,12 @@ #include #include #include -#include -#include +#include #include #include #include -#define DRIVER_NAME "envctrl" -#define PFX DRIVER_NAME ": " - #define ENVCTRL_MINOR 162 #define PCF8584_ADDRESS 0x55 @@ -196,7 +193,7 @@ static void envtrl_i2c_test_pin(void) } if (limit <= 0) - printk(KERN_INFO PFX "Pin status will not clear.\n"); + printk(KERN_INFO "envctrl: Pin status will not clear.\n"); } /* Function Description: Test busy bit. @@ -214,7 +211,7 @@ static void envctrl_i2c_test_bb(void) } if (limit <= 0) - printk(KERN_INFO PFX "Busy bit will not clear.\n"); + printk(KERN_INFO "envctrl: Busy bit will not clear.\n"); } /* Function Description: Send the address for a read access. @@ -861,10 +858,11 @@ static void envctrl_init_voltage_status(struct i2c_child_t *pchild) /* Function Description: Initialize i2c child device. * Return: None. */ -static void envctrl_init_i2c_child(struct device_node *dp, +static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, struct i2c_child_t *pchild) { int len, i, tbls_size = 0; + struct device_node *dp = edev_child->prom_node; const void *pval; /* Get device address. */ @@ -884,12 +882,12 @@ static void envctrl_init_i2c_child(struct device_node *dp, pchild->tables = kmalloc(tbls_size, GFP_KERNEL); if (pchild->tables == NULL){ - printk(KERN_ERR PFX "Failed to allocate table.\n"); + printk("envctrl: Failed to allocate table.\n"); return; } pval = of_get_property(dp, "tables", &len); if (!pval || len <= 0) { - printk(KERN_ERR PFX "Failed to get table.\n"); + printk("envctrl: Failed to get table.\n"); return; } memcpy(pchild->tables, pval, len); @@ -995,14 +993,14 @@ static int kenvctrld(void *__unused) struct i2c_child_t *cputemp; if (NULL == (cputemp = envctrl_get_i2c_child(ENVCTRL_CPUTEMP_MON))) { - printk(KERN_ERR PFX - "kenvctrld unable to monitor CPU temp-- exiting\n"); + printk(KERN_ERR + "envctrl: kenvctrld unable to monitor CPU temp-- exiting\n"); return -ENODEV; } poll_interval = 5000; /* TODO env_mon_interval */ - printk(KERN_INFO PFX "%s starting...\n", current->comm); + printk(KERN_INFO "envctrl: %s starting...\n", current->comm); for (;;) { msleep_interruptible(poll_interval); @@ -1024,35 +1022,54 @@ static int kenvctrld(void *__unused) } } } - printk(KERN_INFO PFX "%s exiting...\n", current->comm); + printk(KERN_INFO "envctrl: %s exiting...\n", current->comm); return 0; } -static int __devinit envctrl_probe(struct of_device *op, - const struct of_device_id *match) +static int __init envctrl_init(void) { - struct device_node *dp; - int index, err; - - if (i2c) - return -EINVAL; + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + struct linux_ebus_child *edev_child = NULL; + int err, i = 0; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_node->name, "bbc")) { + /* If we find a boot-bus controller node, + * then this envctrl driver is not for us. + */ + return -ENODEV; + } + } + } - i2c = of_ioremap(&op->resource[0], 0, 0x2, DRIVER_NAME); - if (!i2c) - return -ENOMEM; - - index = 0; - dp = op->node->child; - while (dp) { - if (!strcmp(dp->name, "gpio")) { - i2c_childlist[index].i2ctype = I2C_GPIO; - envctrl_init_i2c_child(dp, &(i2c_childlist[index++])); - } else if (!strcmp(dp->name, "adc")) { - i2c_childlist[index].i2ctype = I2C_ADC; - envctrl_init_i2c_child(dp, &(i2c_childlist[index++])); + /* Traverse through ebus and ebus device list for i2c device and + * adc and gpio nodes. + */ + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_node->name, "i2c")) { + i2c = ioremap(edev->resource[0].start, 0x2); + for_each_edevchild(edev, edev_child) { + if (!strcmp("gpio", edev_child->prom_node->name)) { + i2c_childlist[i].i2ctype = I2C_GPIO; + envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); + } + if (!strcmp("adc", edev_child->prom_node->name)) { + i2c_childlist[i].i2ctype = I2C_ADC; + envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); + } + } + goto done; + } } + } - dp = dp->sibling; +done: + if (!edev) { + printk("envctrl: I2C device not found.\n"); + return -ENODEV; } /* Set device address. */ @@ -1070,7 +1087,7 @@ static int __devinit envctrl_probe(struct of_device *op, /* Register the device as a minor miscellaneous device. */ err = misc_register(&envctrl_dev); if (err) { - printk(KERN_ERR PFX "Unable to get misc minor %d\n", + printk("envctrl: Unable to get misc minor %d\n", envctrl_dev.minor); goto out_iounmap; } @@ -1079,12 +1096,12 @@ static int __devinit envctrl_probe(struct of_device *op, * a next child device, so we decrement before reverse-traversal of * child devices. */ - printk(KERN_INFO PFX "Initialized "); - for (--index; index >= 0; --index) { + printk("envctrl: initialized "); + for (--i; i >= 0; --i) { printk("[%s 0x%lx]%s", - (I2C_ADC == i2c_childlist[index].i2ctype) ? "adc" : - ((I2C_GPIO == i2c_childlist[index].i2ctype) ? "gpio" : "unknown"), - i2c_childlist[index].addr, (0 == index) ? "\n" : " "); + (I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") : + ((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")), + i2c_childlist[i].addr, (0 == i) ? ("\n") : (" ")); } kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld"); @@ -1098,54 +1115,26 @@ static int __devinit envctrl_probe(struct of_device *op, out_deregister: misc_deregister(&envctrl_dev); out_iounmap: - of_iounmap(&op->resource[0], i2c, 0x2); - for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++) - kfree(i2c_childlist[index].tables); + iounmap(i2c); + for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) + kfree(i2c_childlist[i].tables); return err; } -static int __devexit envctrl_remove(struct of_device *op) +static void __exit envctrl_cleanup(void) { - int index; + int i; kthread_stop(kenvctrld_task); - of_iounmap(&op->resource[0], i2c, 0x2); + iounmap(i2c); misc_deregister(&envctrl_dev); - for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++) - kfree(i2c_childlist[index].tables); - - return 0; -} - -static const struct of_device_id envctrl_match[] = { - { - .name = "i2c", - .compatible = "i2cpcf,8584", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, envctrl_match); - -static struct of_platform_driver envctrl_driver = { - .name = DRIVER_NAME, - .match_table = envctrl_match, - .probe = envctrl_probe, - .remove = __devexit_p(envctrl_remove), -}; - -static int __init envctrl_init(void) -{ - return of_register_driver(&envctrl_driver, &of_bus_type); -} - -static void __exit envctrl_exit(void) -{ - of_unregister_driver(&envctrl_driver); + for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) + kfree(i2c_childlist[i].tables); } module_init(envctrl_init); -module_exit(envctrl_exit); +module_exit(envctrl_cleanup); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/sbus/char/flash.c b/trunk/drivers/sbus/char/flash.c index 41083472ff4f..7d95e151513a 100644 --- a/trunk/drivers/sbus/char/flash.c +++ b/trunk/drivers/sbus/char/flash.c @@ -1,4 +1,5 @@ -/* flash.c: Allow mmap access to the OBP Flash, for OBP updates. +/* $Id: flash.c,v 1.25 2001/12/21 04:56:16 davem Exp $ + * flash.c: Allow mmap access to the OBP Flash, for OBP updates. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) */ @@ -14,13 +15,13 @@ #include #include #include -#include -#include #include #include #include #include +#include +#include #include static DEFINE_SPINLOCK(flash_lock); @@ -160,68 +161,97 @@ static const struct file_operations flash_fops = { static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops }; -static int __devinit flash_probe(struct of_device *op, - const struct of_device_id *match) +static int __init flash_init(void) { - struct device_node *dp = op->node; - struct device_node *parent; + struct sbus_bus *sbus; + struct sbus_dev *sdev = NULL; +#ifdef CONFIG_PCI + struct linux_ebus *ebus; + struct linux_ebus_device *edev = NULL; + struct linux_prom_registers regs[2]; + int len, nregs; +#endif + int err; + + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "flashprom")) { + if (sdev->reg_addrs[0].phys_addr == sdev->reg_addrs[1].phys_addr) { + flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) | + (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL); + flash.read_size = sdev->reg_addrs[0].reg_size; + flash.write_base = flash.read_base; + flash.write_size = flash.read_size; + } else { + flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) | + (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL); + flash.read_size = sdev->reg_addrs[0].reg_size; + flash.write_base = ((unsigned long)sdev->reg_addrs[1].phys_addr) | + (((unsigned long)sdev->reg_addrs[1].which_io)<<32UL); + flash.write_size = sdev->reg_addrs[1].reg_size; + } + flash.busy = 0; + break; + } + } + if (!sdev) { +#ifdef CONFIG_PCI + const struct linux_prom_registers *ebus_regs; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_node->name, "flashprom")) + goto ebus_done; + } + } + ebus_done: + if (!edev) + return -ENODEV; + + ebus_regs = of_get_property(edev->prom_node, "reg", &len); + if (!ebus_regs || (len % sizeof(regs[0])) != 0) { + printk("flash: Strange reg property size %d\n", len); + return -ENODEV; + } - parent = dp->parent; + nregs = len / sizeof(ebus_regs[0]); - if (strcmp(parent->name, "sbus") && - strcmp(parent->name, "sbi") && - strcmp(parent->name, "ebus")) - return -ENODEV; + flash.read_base = edev->resource[0].start; + flash.read_size = ebus_regs[0].reg_size; - flash.read_base = op->resource[0].start; - flash.read_size = resource_size(&op->resource[0]); - if (op->resource[1].flags) { - flash.write_base = op->resource[1].start; - flash.write_size = resource_size(&op->resource[1]); - } else { - flash.write_base = op->resource[0].start; - flash.write_size = resource_size(&op->resource[0]); + if (nregs == 1) { + flash.write_base = edev->resource[0].start; + flash.write_size = ebus_regs[0].reg_size; + } else if (nregs == 2) { + flash.write_base = edev->resource[1].start; + flash.write_size = ebus_regs[1].reg_size; + } else { + printk("flash: Strange number of regs %d\n", nregs); + return -ENODEV; + } + + flash.busy = 0; + +#else + return -ENODEV; +#endif } - flash.busy = 0; - printk(KERN_INFO "%s: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n", - op->node->full_name, + printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n", flash.read_base, flash.read_size, flash.write_base, flash.write_size); - return misc_register(&flash_dev); -} - -static int __devexit flash_remove(struct of_device *op) -{ - misc_deregister(&flash_dev); + err = misc_register(&flash_dev); + if (err) { + printk(KERN_ERR "flash: unable to get misc minor\n"); + return err; + } return 0; } -static const struct of_device_id flash_match[] = { - { - .name = "flashprom", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, flash_match); - -static struct of_platform_driver flash_driver = { - .name = "flash", - .match_table = flash_match, - .probe = flash_probe, - .remove = __devexit_p(flash_remove), -}; - -static int __init flash_init(void) -{ - return of_register_driver(&flash_driver, &of_bus_type); -} - static void __exit flash_cleanup(void) { - of_unregister_driver(&flash_driver); + misc_deregister(&flash_dev); } module_init(flash_init); diff --git a/trunk/drivers/watchdog/riowd.c b/trunk/drivers/sbus/char/riowatchdog.c similarity index 51% rename from trunk/drivers/watchdog/riowd.c rename to trunk/drivers/sbus/char/riowatchdog.c index 09cb1833ea27..88c0fc6395e1 100644 --- a/trunk/drivers/watchdog/riowd.c +++ b/trunk/drivers/sbus/char/riowatchdog.c @@ -1,6 +1,7 @@ -/* riowd.c - driver for hw watchdog inside Super I/O of RIO +/* $Id: riowatchdog.c,v 1.3.2.2 2002/01/23 18:48:02 davem Exp $ + * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO * - * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 2001 David S. Miller (davem@redhat.com) */ #include @@ -11,13 +12,14 @@ #include #include #include -#include -#include -#include #include +#include +#include +#include #include +#include /* RIO uses the NatSemi Super I/O power management logical device * as its' watchdog. @@ -43,35 +45,74 @@ * The watchdog device generates no interrupts. */ -MODULE_AUTHOR("David S. Miller "); +MODULE_AUTHOR("David S. Miller "); MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO"); MODULE_SUPPORTED_DEVICE("watchdog"); MODULE_LICENSE("GPL"); -#define DRIVER_NAME "riowd" -#define PFX DRIVER_NAME ": " +#define RIOWD_NAME "pmc" +#define RIOWD_MINOR 215 -struct riowd { - void __iomem *regs; - spinlock_t lock; -}; - -static struct riowd *riowd_device; +static DEFINE_SPINLOCK(riowd_lock); +static void __iomem *bbc_regs; +static void __iomem *riowd_regs; #define WDTO_INDEX 0x05 static int riowd_timeout = 1; /* in minutes */ module_param(riowd_timeout, int, 0); MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes"); -static void riowd_writereg(struct riowd *p, u8 val, int index) +#if 0 /* Currently unused. */ +static u8 riowd_readreg(int index) { unsigned long flags; + u8 ret; - spin_lock_irqsave(&p->lock, flags); - writeb(index, p->regs + 0); - writeb(val, p->regs + 1); - spin_unlock_irqrestore(&p->lock, flags); + spin_lock_irqsave(&riowd_lock, flags); + writeb(index, riowd_regs + 0); + ret = readb(riowd_regs + 1); + spin_unlock_irqrestore(&riowd_lock, flags); + + return ret; +} +#endif + +static void riowd_writereg(u8 val, int index) +{ + unsigned long flags; + + spin_lock_irqsave(&riowd_lock, flags); + writeb(index, riowd_regs + 0); + writeb(val, riowd_regs + 1); + spin_unlock_irqrestore(&riowd_lock, flags); +} + +static void riowd_pingtimer(void) +{ + riowd_writereg(riowd_timeout, WDTO_INDEX); +} + +static void riowd_stoptimer(void) +{ + u8 val; + + riowd_writereg(0, WDTO_INDEX); + + val = readb(bbc_regs + BBC_WDACTION); + val &= ~BBC_WDACTION_RST; + writeb(val, bbc_regs + BBC_WDACTION); +} + +static void riowd_starttimer(void) +{ + u8 val; + + riowd_writereg(riowd_timeout, WDTO_INDEX); + + val = readb(bbc_regs + BBC_WDACTION); + val |= BBC_WDACTION_RST; + writeb(val, bbc_regs + BBC_WDACTION); } static int riowd_open(struct inode *inode, struct file *filp) @@ -90,12 +131,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { static struct watchdog_info info = { - .options = WDIOF_SETTIMEOUT, - .firmware_version = 1, - .identity = DRIVER_NAME, + WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317" }; void __user *argp = (void __user *)arg; - struct riowd *p = riowd_device; unsigned int options; int new_margin; @@ -112,7 +150,7 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, break; case WDIOC_KEEPALIVE: - riowd_writereg(p, riowd_timeout, WDTO_INDEX); + riowd_pingtimer(); break; case WDIOC_SETOPTIONS: @@ -120,9 +158,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, return -EFAULT; if (options & WDIOS_DISABLECARD) - riowd_writereg(p, 0, WDTO_INDEX); + riowd_stoptimer(); else if (options & WDIOS_ENABLECARD) - riowd_writereg(p, riowd_timeout, WDTO_INDEX); + riowd_starttimer(); else return -EINVAL; @@ -132,9 +170,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, if (get_user(new_margin, (int __user *)argp)) return -EFAULT; if ((new_margin < 60) || (new_margin > (255 * 60))) - return -EINVAL; + return -EINVAL; riowd_timeout = (new_margin + 59) / 60; - riowd_writereg(p, riowd_timeout, WDTO_INDEX); + riowd_pingtimer(); /* Fall */ case WDIOC_GETTIMEOUT: @@ -149,10 +187,8 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct riowd *p = riowd_device; - if (count) { - riowd_writereg(p, riowd_timeout, WDTO_INDEX); + riowd_pingtimer(); return 1; } @@ -161,99 +197,99 @@ static ssize_t riowd_write(struct file *file, const char __user *buf, size_t cou static const struct file_operations riowd_fops = { .owner = THIS_MODULE, - .llseek = no_llseek, .ioctl = riowd_ioctl, .open = riowd_open, .write = riowd_write, .release = riowd_release, }; -static struct miscdevice riowd_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &riowd_fops -}; +static struct miscdevice riowd_miscdev = { RIOWD_MINOR, RIOWD_NAME, &riowd_fops }; -static int __devinit riowd_probe(struct of_device *op, - const struct of_device_id *match) +static int __init riowd_bbc_init(void) { - struct riowd *p; - int err = -EINVAL; - - if (riowd_device) - goto out; + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + u8 val; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->ofdev.node->name, "bbc")) + goto found_bbc; + } + } - err = -ENOMEM; - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - goto out; +found_bbc: + if (!edev) + return -ENODEV; + bbc_regs = ioremap(edev->resource[0].start, BBC_REGS_SIZE); + if (!bbc_regs) + return -ENODEV; - spin_lock_init(&p->lock); + /* Turn it off. */ + val = readb(bbc_regs + BBC_WDACTION); + val &= ~BBC_WDACTION_RST; + writeb(val, bbc_regs + BBC_WDACTION); - p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME); - if (!p->regs) { - printk(KERN_ERR PFX "Cannot map registers.\n"); - goto out_free; - } + return 0; +} - err = misc_register(&riowd_miscdev); - if (err) { - printk(KERN_ERR PFX "Cannot register watchdog misc device.\n"); - goto out_iounmap; +static int __init riowd_init(void) +{ + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->ofdev.node->name, RIOWD_NAME)) + goto ebus_done; + } } - printk(KERN_INFO PFX "Hardware watchdog [%i minutes], " - "regs at %p\n", riowd_timeout, p->regs); +ebus_done: + if (!edev) + goto fail; - dev_set_drvdata(&op->dev, p); - riowd_device = p; - err = 0; - -out_iounmap: - of_iounmap(&op->resource[0], p->regs, 2); - -out_free: - kfree(p); + riowd_regs = ioremap(edev->resource[0].start, 2); + if (riowd_regs == NULL) { + printk(KERN_ERR "pmc: Cannot map registers.\n"); + return -ENODEV; + } -out: - return err; -} + if (riowd_bbc_init()) { + printk(KERN_ERR "pmc: Failure initializing BBC config.\n"); + goto fail; + } -static int __devexit riowd_remove(struct of_device *op) -{ - struct riowd *p = dev_get_drvdata(&op->dev); + if (misc_register(&riowd_miscdev)) { + printk(KERN_ERR "pmc: Cannot register watchdog misc device.\n"); + goto fail; + } - misc_deregister(&riowd_miscdev); - of_iounmap(&op->resource[0], p->regs, 2); - kfree(p); + printk(KERN_INFO "pmc: Hardware watchdog [%i minutes], " + "regs at %p\n", riowd_timeout, riowd_regs); return 0; -} - -static const struct of_device_id riowd_match[] = { - { - .name = "pmc", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, riowd_match); - -static struct of_platform_driver riowd_driver = { - .name = DRIVER_NAME, - .match_table = riowd_match, - .probe = riowd_probe, - .remove = __devexit_p(riowd_remove), -}; -static int __init riowd_init(void) -{ - return of_register_driver(&riowd_driver, &of_bus_type); +fail: + if (riowd_regs) { + iounmap(riowd_regs); + riowd_regs = NULL; + } + if (bbc_regs) { + iounmap(bbc_regs); + bbc_regs = NULL; + } + return -ENODEV; } -static void __exit riowd_exit(void) +static void __exit riowd_cleanup(void) { - of_unregister_driver(&riowd_driver); + misc_deregister(&riowd_miscdev); + iounmap(riowd_regs); + riowd_regs = NULL; + iounmap(bbc_regs); + bbc_regs = NULL; } module_init(riowd_init); -module_exit(riowd_exit); +module_exit(riowd_cleanup); diff --git a/trunk/drivers/sbus/char/rtc.c b/trunk/drivers/sbus/char/rtc.c new file mode 100644 index 000000000000..b0429917154d --- /dev/null +++ b/trunk/drivers/sbus/char/rtc.c @@ -0,0 +1,275 @@ +/* $Id: rtc.c,v 1.28 2001/10/08 22:19:51 davem Exp $ + * + * Linux/SPARC Real Time Clock Driver + * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) + * + * This is a little driver that lets a user-level program access + * the SPARC Mostek real time clock chip. It is no use unless you + * use the modified clock utility. + * + * Get the modified clock utility from: + * ftp://vger.kernel.org/pub/linux/Sparc/userland/clock.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int rtc_busy = 0; + +/* This is the structure layout used by drivers/char/rtc.c, we + * support that driver's ioctls so that things are less messy in + * userspace. + */ +struct rtc_time_generic { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; +#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */ +#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */ +#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ +#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */ +#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */ +#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */ +#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */ +#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */ +#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time_generic) /* Read RTC time */ +#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time_generic) /* Set RTC time */ +#define RTC_ALM_SET _IOW('p', 0x07, struct rtc_time) /* Set alarm time */ +#define RTC_ALM_READ _IOR('p', 0x08, struct rtc_time) /* Read alarm time */ +#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ +#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ +#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ +#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ +#define RTC_WKALM_SET _IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/ +#define RTC_WKALM_RD _IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/ +#define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */ +#define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */ + +/* Retrieve the current date and time from the real time clock. */ +static void get_rtc_time(struct rtc_time *t) +{ + void __iomem *regs = mstk48t02_regs; + u8 tmp; + + spin_lock_irq(&mostek_lock); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_READ; + mostek_write(regs + MOSTEK_CREG, tmp); + + t->sec = MSTK_REG_SEC(regs); + t->min = MSTK_REG_MIN(regs); + t->hour = MSTK_REG_HOUR(regs); + t->dow = MSTK_REG_DOW(regs); + t->dom = MSTK_REG_DOM(regs); + t->month = MSTK_REG_MONTH(regs); + t->year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) ); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_READ; + mostek_write(regs + MOSTEK_CREG, tmp); + + spin_unlock_irq(&mostek_lock); +} + +/* Set the current date and time inthe real time clock. */ +void set_rtc_time(struct rtc_time *t) +{ + void __iomem *regs = mstk48t02_regs; + u8 tmp; + + spin_lock_irq(&mostek_lock); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + + MSTK_SET_REG_SEC(regs,t->sec); + MSTK_SET_REG_MIN(regs,t->min); + MSTK_SET_REG_HOUR(regs,t->hour); + MSTK_SET_REG_DOW(regs,t->dow); + MSTK_SET_REG_DOM(regs,t->dom); + MSTK_SET_REG_MONTH(regs,t->month); + MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + + spin_unlock_irq(&mostek_lock); +} + +static int put_rtc_time_generic(void __user *argp, struct rtc_time *tm) +{ + struct rtc_time_generic __user *utm = argp; + + if (__put_user(tm->sec, &utm->tm_sec) || + __put_user(tm->min, &utm->tm_min) || + __put_user(tm->hour, &utm->tm_hour) || + __put_user(tm->dom, &utm->tm_mday) || + __put_user(tm->month, &utm->tm_mon) || + __put_user(tm->year, &utm->tm_year) || + __put_user(tm->dow, &utm->tm_wday) || + __put_user(0, &utm->tm_yday) || + __put_user(0, &utm->tm_isdst)) + return -EFAULT; + + return 0; +} + +static int get_rtc_time_generic(struct rtc_time *tm, void __user *argp) +{ + struct rtc_time_generic __user *utm = argp; + + if (__get_user(tm->sec, &utm->tm_sec) || + __get_user(tm->min, &utm->tm_min) || + __get_user(tm->hour, &utm->tm_hour) || + __get_user(tm->dom, &utm->tm_mday) || + __get_user(tm->month, &utm->tm_mon) || + __get_user(tm->year, &utm->tm_year) || + __get_user(tm->dow, &utm->tm_wday)) + return -EFAULT; + + return 0; +} + +static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct rtc_time rtc_tm; + void __user *argp = (void __user *)arg; + + switch (cmd) { + /* No interrupt support, return an error + * compatible with drivers/char/rtc.c + */ + case RTC_AIE_OFF: + case RTC_AIE_ON: + case RTC_PIE_OFF: + case RTC_PIE_ON: + case RTC_UIE_OFF: + case RTC_UIE_ON: + case RTC_IRQP_READ: + case RTC_IRQP_SET: + case RTC_EPOCH_SET: + case RTC_EPOCH_READ: + return -EINVAL; + + case RTCGET: + case RTC_RD_TIME: + memset(&rtc_tm, 0, sizeof(struct rtc_time)); + get_rtc_time(&rtc_tm); + + if (cmd == RTCGET) { + if (copy_to_user(argp, &rtc_tm, + sizeof(struct rtc_time))) + return -EFAULT; + } else if (put_rtc_time_generic(argp, &rtc_tm)) + return -EFAULT; + + return 0; + + + case RTCSET: + case RTC_SET_TIME: + if (!capable(CAP_SYS_TIME)) + return -EPERM; + + if (cmd == RTCSET) { + if (copy_from_user(&rtc_tm, argp, + sizeof(struct rtc_time))) + return -EFAULT; + } else if (get_rtc_time_generic(&rtc_tm, argp)) + return -EFAULT; + + set_rtc_time(&rtc_tm); + + return 0; + + default: + return -EINVAL; + } +} + +static int rtc_open(struct inode *inode, struct file *file) +{ + int ret; + + lock_kernel(); + spin_lock_irq(&mostek_lock); + if (rtc_busy) { + ret = -EBUSY; + } else { + rtc_busy = 1; + ret = 0; + } + spin_unlock_irq(&mostek_lock); + unlock_kernel(); + + return ret; +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + rtc_busy = 0; + + return 0; +} + +static const struct file_operations rtc_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .ioctl = rtc_ioctl, + .open = rtc_open, + .release = rtc_release, +}; + +static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops }; + +static int __init rtc_sun_init(void) +{ + int error; + + /* It is possible we are being driven by some other RTC chip + * and thus another RTC driver is handling things. + */ + if (!mstk48t02_regs) + return -ENODEV; + + error = misc_register(&rtc_dev); + if (error) { + printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n"); + return error; + } + printk("rtc_sun_init: Registered Mostek RTC driver.\n"); + + return 0; +} + +static void __exit rtc_sun_cleanup(void) +{ + misc_deregister(&rtc_dev); +} + +module_init(rtc_sun_init); +module_exit(rtc_sun_cleanup); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/sbus/char/uctrl.c b/trunk/drivers/sbus/char/uctrl.c index 27993c37775d..777637594acd 100644 --- a/trunk/drivers/sbus/char/uctrl.c +++ b/trunk/drivers/sbus/char/uctrl.c @@ -1,7 +1,7 @@ -/* uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3 +/* $Id: uctrl.c,v 1.12 2001/10/08 22:19:51 davem Exp $ + * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3 * * Copyright 1999 Derrick J Brashear (shadow@dementia.org) - * Copyright 2008 David S. Miller (davem@davemloft.net) */ #include @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include @@ -23,6 +21,7 @@ #include #include #include +#include #define UCTRL_MINOR 174 @@ -34,26 +33,26 @@ #endif struct uctrl_regs { - u32 uctrl_intr; - u32 uctrl_data; - u32 uctrl_stat; - u32 uctrl_xxx[5]; + volatile u32 uctrl_intr; + volatile u32 uctrl_data; + volatile u32 uctrl_stat; + volatile u32 uctrl_xxx[5]; }; struct ts102_regs { - u32 card_a_intr; - u32 card_a_stat; - u32 card_a_ctrl; - u32 card_a_xxx; - u32 card_b_intr; - u32 card_b_stat; - u32 card_b_ctrl; - u32 card_b_xxx; - u32 uctrl_intr; - u32 uctrl_data; - u32 uctrl_stat; - u32 uctrl_xxx; - u32 ts102_xxx[4]; + volatile u32 card_a_intr; + volatile u32 card_a_stat; + volatile u32 card_a_ctrl; + volatile u32 card_a_xxx; + volatile u32 card_b_intr; + volatile u32 card_b_stat; + volatile u32 card_b_ctrl; + volatile u32 card_b_xxx; + volatile u32 uctrl_intr; + volatile u32 uctrl_data; + volatile u32 uctrl_stat; + volatile u32 uctrl_xxx; + volatile u32 ts102_xxx[4]; }; /* Bits for uctrl_intr register */ @@ -187,15 +186,17 @@ enum uctrl_opcode { POWER_RESTART=0x83, }; -static struct uctrl_driver { - struct uctrl_regs __iomem *regs; +struct uctrl_driver { + struct uctrl_regs *regs; int irq; int pending; struct uctrl_status status; -} *global_driver; +}; + +static struct uctrl_driver drv; -static void uctrl_get_event_status(struct uctrl_driver *); -static void uctrl_get_external_status(struct uctrl_driver *); +static void uctrl_get_event_status(void); +static void uctrl_get_external_status(void); static int uctrl_ioctl(struct inode *inode, struct file *file, @@ -212,14 +213,16 @@ static int uctrl_open(struct inode *inode, struct file *file) { lock_kernel(); - uctrl_get_event_status(global_driver); - uctrl_get_external_status(global_driver); + uctrl_get_event_status(); + uctrl_get_external_status(); unlock_kernel(); return 0; } static irqreturn_t uctrl_interrupt(int irq, void *dev_id) { + struct uctrl_driver *driver = (struct uctrl_driver *)dev_id; + printk("in uctrl_interrupt\n"); return IRQ_HANDLED; } @@ -241,11 +244,11 @@ static struct miscdevice uctrl_dev = { { \ unsigned int i; \ for (i = 0; i < 10000; i++) { \ - if (UCTRL_STAT_TXNF_STA & sbus_readl(&driver->regs->uctrl_stat)) \ + if (UCTRL_STAT_TXNF_STA & driver->regs->uctrl_stat) \ break; \ } \ dprintk(("write data 0x%02x\n", value)); \ - sbus_writel(value, &driver->regs->uctrl_data); \ + driver->regs->uctrl_data = value; \ } /* Wait for something to read, read it, then clear the bit */ @@ -254,23 +257,24 @@ static struct miscdevice uctrl_dev = { unsigned int i; \ value = 0; \ for (i = 0; i < 10000; i++) { \ - if ((UCTRL_STAT_RXNE_STA & sbus_readl(&driver->regs->uctrl_stat)) == 0) \ + if ((UCTRL_STAT_RXNE_STA & driver->regs->uctrl_stat) == 0) \ break; \ udelay(1); \ } \ - value = sbus_readl(&driver->regs->uctrl_data); \ + value = driver->regs->uctrl_data; \ dprintk(("read data 0x%02x\n", value)); \ - sbus_writel(UCTRL_STAT_RXNE_STA, &driver->regs->uctrl_stat); \ + driver->regs->uctrl_stat = UCTRL_STAT_RXNE_STA; \ } -static void uctrl_do_txn(struct uctrl_driver *driver, struct uctrl_txn *txn) +static void uctrl_do_txn(struct uctrl_txn *txn) { + struct uctrl_driver *driver = &drv; int stat, incnt, outcnt, bytecnt, intr; u32 byte; - stat = sbus_readl(&driver->regs->uctrl_stat); - intr = sbus_readl(&driver->regs->uctrl_intr); - sbus_writel(stat, &driver->regs->uctrl_stat); + stat = driver->regs->uctrl_stat; + intr = driver->regs->uctrl_intr; + driver->regs->uctrl_stat = stat; dprintk(("interrupt stat 0x%x int 0x%x\n", stat, intr)); @@ -301,8 +305,9 @@ static void uctrl_do_txn(struct uctrl_driver *driver, struct uctrl_txn *txn) } } -static void uctrl_get_event_status(struct uctrl_driver *driver) +static void uctrl_get_event_status(void) { + struct uctrl_driver *driver = &drv; struct uctrl_txn txn; u8 outbits[2]; @@ -312,7 +317,7 @@ static void uctrl_get_event_status(struct uctrl_driver *driver) txn.inbuf = NULL; txn.outbuf = outbits; - uctrl_do_txn(driver, &txn); + uctrl_do_txn(&txn); dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff))); driver->status.event_status = @@ -320,8 +325,9 @@ static void uctrl_get_event_status(struct uctrl_driver *driver) dprintk(("ev is %x\n", driver->status.event_status)); } -static void uctrl_get_external_status(struct uctrl_driver *driver) +static void uctrl_get_external_status(void) { + struct uctrl_driver *driver = &drv; struct uctrl_txn txn; u8 outbits[2]; int i, v; @@ -332,7 +338,7 @@ static void uctrl_get_external_status(struct uctrl_driver *driver) txn.inbuf = NULL; txn.outbuf = outbits; - uctrl_do_txn(driver, &txn); + uctrl_do_txn(&txn); dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff))); driver->status.external_status = @@ -348,101 +354,71 @@ static void uctrl_get_external_status(struct uctrl_driver *driver) } -static int __devinit uctrl_probe(struct of_device *op, - const struct of_device_id *match) +static int __init ts102_uctrl_init(void) { - struct uctrl_driver *p; - int err = -ENOMEM; - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) { - printk(KERN_ERR "uctrl: Unable to allocate device struct.\n"); - goto out; - } - - p->regs = of_ioremap(&op->resource[0], 0, - resource_size(&op->resource[0]), - "uctrl"); - if (!p->regs) { - printk(KERN_ERR "uctrl: Unable to map registers.\n"); - goto out_free; - } + struct uctrl_driver *driver = &drv; + int len; + struct linux_prom_irqs tmp_irq[2]; + unsigned int vaddr[2] = { 0, 0 }; + int tmpnode, uctrlnode = prom_getchild(prom_root_node); + int err; - p->irq = op->irqs[0]; - err = request_irq(p->irq, uctrl_interrupt, 0, "uctrl", p); - if (err) { - printk(KERN_ERR "uctrl: Unable to register irq.\n"); - goto out_iounmap; - } + tmpnode = prom_searchsiblings(uctrlnode, "obio"); - err = misc_register(&uctrl_dev); - if (err) { - printk(KERN_ERR "uctrl: Unable to register misc device.\n"); - goto out_free_irq; - } + if (tmpnode) + uctrlnode = prom_getchild(tmpnode); - sbus_writel(UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK, &p->regs->uctrl_intr); - printk(KERN_INFO "%s: uctrl regs[0x%p] (irq %d)\n", - op->node->full_name, p->regs, p->irq); - uctrl_get_event_status(p); - uctrl_get_external_status(p); + uctrlnode = prom_searchsiblings(uctrlnode, "uctrl"); - dev_set_drvdata(&op->dev, p); - global_driver = p; + if (!uctrlnode) + return -ENODEV; -out: - return err; + /* the prom mapped it for us */ + len = prom_getproperty(uctrlnode, "address", (void *) vaddr, + sizeof(vaddr)); + driver->regs = (struct uctrl_regs *)vaddr[0]; -out_free_irq: - free_irq(p->irq, p); + len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq, + sizeof(tmp_irq)); -out_iounmap: - of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0])); + /* Flush device */ + READUCTLDATA(len); -out_free: - kfree(p); - goto out; -} + if(!driver->irq) + driver->irq = tmp_irq[0].pri; -static int __devexit uctrl_remove(struct of_device *op) -{ - struct uctrl_driver *p = dev_get_drvdata(&op->dev); - - if (p) { - misc_deregister(&uctrl_dev); - free_irq(p->irq, p); - of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0])); - kfree(p); + err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver); + if (err) { + printk("%s: unable to register irq %d\n", + __func__, driver->irq); + return err; } - return 0; -} - -static const struct of_device_id uctrl_match[] = { - { - .name = "uctrl", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, uctrl_match); - -static struct of_platform_driver uctrl_driver = { - .name = "uctrl", - .match_table = uctrl_match, - .probe = uctrl_probe, - .remove = __devexit_p(uctrl_remove), -}; + if (misc_register(&uctrl_dev)) { + printk("%s: unable to get misc minor %d\n", + __func__, uctrl_dev.minor); + free_irq(driver->irq, driver); + return -ENODEV; + } -static int __init uctrl_init(void) -{ - return of_register_driver(&uctrl_driver, &of_bus_type); + driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK; + printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq); + uctrl_get_event_status(); + uctrl_get_external_status(); + return 0; } -static void __exit uctrl_exit(void) +static void __exit ts102_uctrl_cleanup(void) { - of_unregister_driver(&uctrl_driver); + struct uctrl_driver *driver = &drv; + + misc_deregister(&uctrl_dev); + if (driver->irq) + free_irq(driver->irq, driver); + if (driver->regs) + driver->regs = NULL; } -module_init(uctrl_init); -module_exit(uctrl_exit); +module_init(ts102_uctrl_init); +module_exit(ts102_uctrl_cleanup); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/sbus/char/vfc.h b/trunk/drivers/sbus/char/vfc.h new file mode 100644 index 000000000000..a5240c52aa0b --- /dev/null +++ b/trunk/drivers/sbus/char/vfc.h @@ -0,0 +1,171 @@ +#ifndef _LINUX_VFC_H_ +#define _LINUX_VFC_H_ + +/* + * The control register for the vfc is at offset 0x4000 + * The first field ram bank is located at offset 0x5000 + * The second field ram bank is at offset 0x7000 + * i2c_reg address the Phillips PCF8584(see notes in vfc_i2c.c) + * data and transmit register. + * i2c_s1 controls register s1 of the PCF8584 + * i2c_write seems to be similar to i2c_write but I am not + * quite sure why sun uses it + * + * I am also not sure whether or not you can read the fram bank as a + * whole or whether you must read each word individually from offset + * 0x5000 as soon as I figure it out I will update this file */ + +struct vfc_regs { + char pad1[0x4000]; + unsigned int control; /* Offset 0x4000 */ + char pad2[0xffb]; /* from offset 0x4004 to 0x5000 */ + unsigned int fram_bank1; /* Offset 0x5000 */ + char pad3[0xffb]; /* from offset 0x5004 to 0x6000 */ + unsigned int i2c_reg; /* Offset 0x6000 */ + unsigned int i2c_magic2; /* Offset 0x6004 */ + unsigned int i2c_s1; /* Offset 0x6008 */ + unsigned int i2c_write; /* Offset 0x600c */ + char pad4[0xff0]; /* from offset 0x6010 to 0x7000 */ + unsigned int fram_bank2; /* Offset 0x7000 */ + char pad5[0x1000]; +}; + +#define VFC_SAA9051_NR (13) +#define VFC_SAA9051_ADDR (0x8a) + /* The saa9051 returns the following for its status + * bit 0 - 0 + * bit 1 - SECAM color detected (1=found,0=not found) + * bit 2 - COLOR detected (1=found,0=not found) + * bit 3 - 0 + * bit 4 - Field frequency bit (1=60Hz (NTSC), 0=50Hz (PAL)) + * bit 5 - 1 + * bit 6 - horizontal frequency lock (1=transmitter found, + * 0=no transmitter) + * bit 7 - Power on reset bit (1=reset,0=at least one successful + * read of the status byte) + */ + +#define VFC_SAA9051_PONRES (0x80) +#define VFC_SAA9051_HLOCK (0x40) +#define VFC_SAA9051_FD (0x10) +#define VFC_SAA9051_CD (0x04) +#define VFC_SAA9051_CS (0x02) + + +/* The various saa9051 sub addresses */ + +#define VFC_SAA9051_IDEL (0) +#define VFC_SAA9051_HSY_START (1) +#define VFC_SAA9051_HSY_STOP (2) +#define VFC_SAA9051_HC_START (3) +#define VFC_SAA9051_HC_STOP (4) +#define VFC_SAA9051_HS_START (5) +#define VFC_SAA9051_HORIZ_PEAK (6) +#define VFC_SAA9051_HUE (7) +#define VFC_SAA9051_C1 (8) +#define VFC_SAA9051_C2 (9) +#define VFC_SAA9051_C3 (0xa) +#define VFC_SAA9051_SECAM_DELAY (0xb) + + +/* Bit settings for saa9051 sub address 0x06 */ + +#define VFC_SAA9051_AP1 (0x01) +#define VFC_SAA9051_AP2 (0x02) +#define VFC_SAA9051_COR1 (0x04) +#define VFC_SAA9051_COR2 (0x08) +#define VFC_SAA9051_BP1 (0x10) +#define VFC_SAA9051_BP2 (0x20) +#define VFC_SAA9051_PF (0x40) +#define VFC_SAA9051_BY (0x80) + + +/* Bit settings for saa9051 sub address 0x08 */ + +#define VFC_SAA9051_CCFR0 (0x01) +#define VFC_SAA9051_CCFR1 (0x02) +#define VFC_SAA9051_YPN (0x04) +#define VFC_SAA9051_ALT (0x08) +#define VFC_SAA9051_CO (0x10) +#define VFC_SAA9051_VTR (0x20) +#define VFC_SAA9051_FS (0x40) +#define VFC_SAA9051_HPLL (0x80) + + +/* Bit settings for saa9051 sub address 9 */ + +#define VFC_SAA9051_SS0 (0x01) +#define VFC_SAA9051_SS1 (0x02) +#define VFC_SAA9051_AFCC (0x04) +#define VFC_SAA9051_CI (0x08) +#define VFC_SAA9051_SA9D4 (0x10) /* Don't care bit */ +#define VFC_SAA9051_OEC (0x20) +#define VFC_SAA9051_OEY (0x40) +#define VFC_SAA9051_VNL (0x80) + + +/* Bit settings for saa9051 sub address 0x0A */ + +#define VFC_SAA9051_YDL0 (0x01) +#define VFC_SAA9051_YDL1 (0x02) +#define VFC_SAA9051_YDL2 (0x04) +#define VFC_SAA9051_SS2 (0x08) +#define VFC_SAA9051_SS3 (0x10) +#define VFC_SAA9051_YC (0x20) +#define VFC_SAA9051_CT (0x40) +#define VFC_SAA9051_SYC (0x80) + + +#define VFC_SAA9051_SA(a,b) ((a)->saa9051_state_array[(b)+1]) +#define vfc_update_saa9051(a) (vfc_i2c_sendbuf((a),VFC_SAA9051_ADDR,\ + (a)->saa9051_state_array,\ + VFC_SAA9051_NR)) + + +struct vfc_dev { + volatile struct vfc_regs __iomem *regs; + struct vfc_regs *phys_regs; + unsigned int control_reg; + struct mutex device_lock_mtx; + int instance; + int busy; + unsigned long which_io; + unsigned char saa9051_state_array[VFC_SAA9051_NR]; +}; + +void captstat_reset(struct vfc_dev *); +void memptr_reset(struct vfc_dev *); + +int vfc_pcf8584_init(struct vfc_dev *); +void vfc_i2c_delay_no_busy(struct vfc_dev *, unsigned long); +void vfc_i2c_delay(struct vfc_dev *); +int vfc_i2c_sendbuf(struct vfc_dev *, unsigned char, char *, int) ; +int vfc_i2c_recvbuf(struct vfc_dev *, unsigned char, char *, int) ; +int vfc_i2c_reset_bus(struct vfc_dev *); +int vfc_init_i2c_bus(struct vfc_dev *); + +#define VFC_CONTROL_DIAGMODE 0x10000000 +#define VFC_CONTROL_MEMPTR 0x20000000 +#define VFC_CONTROL_CAPTURE 0x02000000 +#define VFC_CONTROL_CAPTRESET 0x04000000 + +#define VFC_STATUS_CAPTURE 0x08000000 + +#ifdef VFC_IOCTL_DEBUG +#define VFC_IOCTL_DEBUG_PRINTK(a) printk a +#else +#define VFC_IOCTL_DEBUG_PRINTK(a) +#endif + +#ifdef VFC_I2C_DEBUG +#define VFC_I2C_DEBUG_PRINTK(a) printk a +#else +#define VFC_I2C_DEBUG_PRINTK(a) +#endif + +#endif /* _LINUX_VFC_H_ */ + + + + + diff --git a/trunk/drivers/sbus/char/vfc_dev.c b/trunk/drivers/sbus/char/vfc_dev.c new file mode 100644 index 000000000000..25181bb7d627 --- /dev/null +++ b/trunk/drivers/sbus/char/vfc_dev.c @@ -0,0 +1,736 @@ +/* + * drivers/sbus/char/vfc_dev.c + * + * Driver for the Videopix Frame Grabber. + * + * In order to use the VFC you need to program the video controller + * chip. This chip is the Phillips SAA9051. You need to call their + * documentation ordering line to get the docs. + * + * There is very little documentation on the VFC itself. There is + * some useful info that can be found in the manuals that come with + * the card. I will hopefully write some better docs at a later date. + * + * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu) + * */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define VFC_MAJOR (60) + +#if 0 +#define VFC_IOCTL_DEBUG +#endif + +#include "vfc.h" +#include + +static const struct file_operations vfc_fops; +static struct vfc_dev **vfc_dev_lst; +static char vfcstr[]="vfc"; +static unsigned char saa9051_init_array[VFC_SAA9051_NR] = { + 0x00, 0x64, 0x72, 0x52, + 0x36, 0x18, 0xff, 0x20, + 0xfc, 0x77, 0xe3, 0x50, + 0x3e +}; + +static void vfc_lock_device(struct vfc_dev *dev) +{ + mutex_lock(&dev->device_lock_mtx); +} + +static void vfc_unlock_device(struct vfc_dev *dev) +{ + mutex_unlock(&dev->device_lock_mtx); +} + + +static void vfc_captstat_reset(struct vfc_dev *dev) +{ + dev->control_reg |= VFC_CONTROL_CAPTRESET; + sbus_writel(dev->control_reg, &dev->regs->control); + dev->control_reg &= ~VFC_CONTROL_CAPTRESET; + sbus_writel(dev->control_reg, &dev->regs->control); + dev->control_reg |= VFC_CONTROL_CAPTRESET; + sbus_writel(dev->control_reg, &dev->regs->control); +} + +static void vfc_memptr_reset(struct vfc_dev *dev) +{ + dev->control_reg |= VFC_CONTROL_MEMPTR; + sbus_writel(dev->control_reg, &dev->regs->control); + dev->control_reg &= ~VFC_CONTROL_MEMPTR; + sbus_writel(dev->control_reg, &dev->regs->control); + dev->control_reg |= VFC_CONTROL_MEMPTR; + sbus_writel(dev->control_reg, &dev->regs->control); +} + +static int vfc_csr_init(struct vfc_dev *dev) +{ + dev->control_reg = 0x80000000; + sbus_writel(dev->control_reg, &dev->regs->control); + udelay(200); + dev->control_reg &= ~0x80000000; + sbus_writel(dev->control_reg, &dev->regs->control); + udelay(100); + sbus_writel(0x0f000000, &dev->regs->i2c_magic2); + + vfc_memptr_reset(dev); + + dev->control_reg &= ~VFC_CONTROL_DIAGMODE; + dev->control_reg &= ~VFC_CONTROL_CAPTURE; + dev->control_reg |= 0x40000000; + sbus_writel(dev->control_reg, &dev->regs->control); + + vfc_captstat_reset(dev); + + return 0; +} + +static int vfc_saa9051_init(struct vfc_dev *dev) +{ + int i; + + for (i = 0; i < VFC_SAA9051_NR; i++) + dev->saa9051_state_array[i] = saa9051_init_array[i]; + + vfc_i2c_sendbuf(dev,VFC_SAA9051_ADDR, + dev->saa9051_state_array, VFC_SAA9051_NR); + return 0; +} + +static int init_vfc_hw(struct vfc_dev *dev) +{ + vfc_lock_device(dev); + vfc_csr_init(dev); + + vfc_pcf8584_init(dev); + vfc_init_i2c_bus(dev); /* hopefully this doesn't undo the magic + sun code above*/ + vfc_saa9051_init(dev); + vfc_unlock_device(dev); + return 0; +} + +static int init_vfc_devstruct(struct vfc_dev *dev, int instance) +{ + dev->instance=instance; + mutex_init(&dev->device_lock_mtx); + dev->control_reg=0; + dev->busy=0; + return 0; +} + +static int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, + int instance) +{ + if(dev == NULL) { + printk(KERN_ERR "VFC: Bogus pointer passed\n"); + return -ENOMEM; + } + printk("Initializing vfc%d\n",instance); + dev->regs = NULL; + dev->regs = (volatile struct vfc_regs __iomem *) + sbus_ioremap(&sdev->resource[0], 0, + sizeof(struct vfc_regs), vfcstr); + dev->which_io = sdev->reg_addrs[0].which_io; + dev->phys_regs = (struct vfc_regs *) sdev->reg_addrs[0].phys_addr; + if (dev->regs == NULL) + return -EIO; + + printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n", + instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs); + + if (init_vfc_devstruct(dev, instance)) + return -EINVAL; + if (init_vfc_hw(dev)) + return -EIO; + return 0; +} + + +static struct vfc_dev *vfc_get_dev_ptr(int instance) +{ + return vfc_dev_lst[instance]; +} + +static DEFINE_SPINLOCK(vfc_dev_lock); + +static int vfc_open(struct inode *inode, struct file *file) +{ + struct vfc_dev *dev; + + lock_kernel(); + spin_lock(&vfc_dev_lock); + dev = vfc_get_dev_ptr(iminor(inode)); + if (dev == NULL) { + spin_unlock(&vfc_dev_lock); + unlock_kernel(); + return -ENODEV; + } + if (dev->busy) { + spin_unlock(&vfc_dev_lock); + unlock_kernel(); + return -EBUSY; + } + + dev->busy = 1; + spin_unlock(&vfc_dev_lock); + + vfc_lock_device(dev); + + vfc_csr_init(dev); + vfc_pcf8584_init(dev); + vfc_init_i2c_bus(dev); + vfc_saa9051_init(dev); + vfc_memptr_reset(dev); + vfc_captstat_reset(dev); + + vfc_unlock_device(dev); + unlock_kernel(); + return 0; +} + +static int vfc_release(struct inode *inode,struct file *file) +{ + struct vfc_dev *dev; + + spin_lock(&vfc_dev_lock); + dev = vfc_get_dev_ptr(iminor(inode)); + if (!dev || !dev->busy) { + spin_unlock(&vfc_dev_lock); + return -EINVAL; + } + dev->busy = 0; + spin_unlock(&vfc_dev_lock); + return 0; +} + +static int vfc_debug(struct vfc_dev *dev, int cmd, void __user *argp) +{ + struct vfc_debug_inout inout; + unsigned char *buffer; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + switch(cmd) { + case VFC_I2C_SEND: + if(copy_from_user(&inout, argp, sizeof(inout))) + return -EFAULT; + + buffer = kmalloc(inout.len, GFP_KERNEL); + if (buffer == NULL) + return -ENOMEM; + + if(copy_from_user(buffer, inout.buffer, inout.len)) { + kfree(buffer); + return -EFAULT; + } + + + vfc_lock_device(dev); + inout.ret= + vfc_i2c_sendbuf(dev,inout.addr & 0xff, + buffer,inout.len); + + if (copy_to_user(argp,&inout,sizeof(inout))) { + vfc_unlock_device(dev); + kfree(buffer); + return -EFAULT; + } + vfc_unlock_device(dev); + + break; + case VFC_I2C_RECV: + if (copy_from_user(&inout, argp, sizeof(inout))) + return -EFAULT; + + buffer = kzalloc(inout.len, GFP_KERNEL); + if (buffer == NULL) + return -ENOMEM; + + vfc_lock_device(dev); + inout.ret= + vfc_i2c_recvbuf(dev,inout.addr & 0xff + ,buffer,inout.len); + vfc_unlock_device(dev); + + if (copy_to_user(inout.buffer, buffer, inout.len)) { + kfree(buffer); + return -EFAULT; + } + if (copy_to_user(argp,&inout,sizeof(inout))) { + kfree(buffer); + return -EFAULT; + } + kfree(buffer); + break; + default: + return -EINVAL; + }; + + return 0; +} + +static int vfc_capture_start(struct vfc_dev *dev) +{ + vfc_captstat_reset(dev); + dev->control_reg = sbus_readl(&dev->regs->control); + if((dev->control_reg & VFC_STATUS_CAPTURE)) { + printk(KERN_ERR "vfc%d: vfc capture status not reset\n", + dev->instance); + return -EIO; + } + + vfc_lock_device(dev); + dev->control_reg &= ~VFC_CONTROL_CAPTURE; + sbus_writel(dev->control_reg, &dev->regs->control); + dev->control_reg |= VFC_CONTROL_CAPTURE; + sbus_writel(dev->control_reg, &dev->regs->control); + dev->control_reg &= ~VFC_CONTROL_CAPTURE; + sbus_writel(dev->control_reg, &dev->regs->control); + vfc_unlock_device(dev); + + return 0; +} + +static int vfc_capture_poll(struct vfc_dev *dev) +{ + int timeout = 1000; + + while (!timeout--) { + if (sbus_readl(&dev->regs->control) & VFC_STATUS_CAPTURE) + break; + vfc_i2c_delay_no_busy(dev, 100); + } + if(!timeout) { + printk(KERN_WARNING "vfc%d: capture timed out\n", + dev->instance); + return -ETIMEDOUT; + } + return 0; +} + + + +static int vfc_set_control_ioctl(struct inode *inode, struct file *file, + struct vfc_dev *dev, unsigned long arg) +{ + int setcmd, ret = 0; + + if (copy_from_user(&setcmd,(void __user *)arg,sizeof(unsigned int))) + return -EFAULT; + + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n", + dev->instance,setcmd)); + + switch(setcmd) { + case MEMPRST: + vfc_lock_device(dev); + vfc_memptr_reset(dev); + vfc_unlock_device(dev); + ret=0; + break; + case CAPTRCMD: + vfc_capture_start(dev); + vfc_capture_poll(dev); + break; + case DIAGMODE: + if(capable(CAP_SYS_ADMIN)) { + vfc_lock_device(dev); + dev->control_reg |= VFC_CONTROL_DIAGMODE; + sbus_writel(dev->control_reg, &dev->regs->control); + vfc_unlock_device(dev); + ret = 0; + } else { + ret = -EPERM; + } + break; + case NORMMODE: + vfc_lock_device(dev); + dev->control_reg &= ~VFC_CONTROL_DIAGMODE; + sbus_writel(dev->control_reg, &dev->regs->control); + vfc_unlock_device(dev); + ret = 0; + break; + case CAPTRSTR: + vfc_capture_start(dev); + ret = 0; + break; + case CAPTRWAIT: + vfc_capture_poll(dev); + ret = 0; + break; + default: + ret = -EINVAL; + break; + }; + + return ret; +} + + +static int vfc_port_change_ioctl(struct inode *inode, struct file *file, + struct vfc_dev *dev, unsigned long arg) +{ + int ret = 0; + int cmd; + + if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) { + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " + "vfc_port_change_ioctl\n", + dev->instance)); + return -EFAULT; + } + + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n", + dev->instance, cmd)); + + switch(cmd) { + case 1: + case 2: + VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x72; + VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x52; + VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0x36; + VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0x18; + VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BP2; + VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_CT | VFC_SAA9051_SS3; + VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0x3e; + break; + case 3: + VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x3a; + VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x17; + VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0xfa; + VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0xde; + VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = + VFC_SAA9051_BY | VFC_SAA9051_PF | VFC_SAA9051_BP2; + VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_YC; + VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0; + VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &= + ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1); + break; + default: + ret = -EINVAL; + return ret; + break; + } + + switch(cmd) { + case 1: + VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= + (VFC_SAA9051_SS0 | VFC_SAA9051_SS1); + break; + case 2: + VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &= + ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1); + VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0; + break; + case 3: + break; + default: + ret = -EINVAL; + return ret; + break; + } + VFC_SAA9051_SA(dev,VFC_SAA9051_C3) &= ~(VFC_SAA9051_SS2); + ret=vfc_update_saa9051(dev); + udelay(500); + VFC_SAA9051_SA(dev,VFC_SAA9051_C3) |= (VFC_SAA9051_SS2); + ret=vfc_update_saa9051(dev); + return ret; +} + +static int vfc_set_video_ioctl(struct inode *inode, struct file *file, + struct vfc_dev *dev, unsigned long arg) +{ + int ret = 0; + int cmd; + + if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) { + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " + "vfc_set_video_ioctl\n", + dev->instance)); + return ret; + } + + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n", + dev->instance, cmd)); + switch(cmd) { + case STD_NTSC: + VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~VFC_SAA9051_ALT; + VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_YPN | + VFC_SAA9051_CCFR0 | VFC_SAA9051_CCFR1 | VFC_SAA9051_FS; + ret = vfc_update_saa9051(dev); + break; + case STD_PAL: + VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_YPN | + VFC_SAA9051_CCFR1 | + VFC_SAA9051_CCFR0 | + VFC_SAA9051_FS); + VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_ALT; + ret = vfc_update_saa9051(dev); + break; + + case COLOR_ON: + VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_CO; + VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) &= + ~(VFC_SAA9051_BY | VFC_SAA9051_PF); + ret = vfc_update_saa9051(dev); + break; + case MONO: + VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_CO); + VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) |= + (VFC_SAA9051_BY | VFC_SAA9051_PF); + ret = vfc_update_saa9051(dev); + break; + default: + ret = -EINVAL; + break; + }; + + return ret; +} + +static int vfc_get_video_ioctl(struct inode *inode, struct file *file, + struct vfc_dev *dev, unsigned long arg) +{ + int ret = 0; + unsigned int status = NO_LOCK; + unsigned char buf[1]; + + if(vfc_i2c_recvbuf(dev, VFC_SAA9051_ADDR, buf, 1)) { + printk(KERN_ERR "vfc%d: Unable to get status\n", + dev->instance); + return -EIO; + } + + if(buf[0] & VFC_SAA9051_HLOCK) { + status = NO_LOCK; + } else if(buf[0] & VFC_SAA9051_FD) { + if(buf[0] & VFC_SAA9051_CD) + status = NTSC_COLOR; + else + status = NTSC_NOCOLOR; + } else { + if(buf[0] & VFC_SAA9051_CD) + status = PAL_COLOR; + else + status = PAL_NOCOLOR; + } + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; " + "buf[0]=%x\n", dev->instance, status, buf[0])); + + if (copy_to_user((void __user *)arg,&status,sizeof(unsigned int))) { + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " + "vfc_get_video_ioctl\n", + dev->instance)); + return ret; + } + return ret; +} + +static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + unsigned int tmp; + struct vfc_dev *dev; + void __user *argp = (void __user *)arg; + + dev = vfc_get_dev_ptr(iminor(inode)); + if(dev == NULL) + return -ENODEV; + + switch(cmd & 0x0000ffff) { + case VFCGCTRL: +#if 0 + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n", dev->instance)); +#endif + tmp = sbus_readl(&dev->regs->control); + if(copy_to_user(argp, &tmp, sizeof(unsigned int))) { + ret = -EFAULT; + break; + } + ret = 0; + break; + case VFCSCTRL: + ret = vfc_set_control_ioctl(inode, file, dev, arg); + break; + case VFCGVID: + ret = vfc_get_video_ioctl(inode, file, dev, arg); + break; + case VFCSVID: + ret = vfc_set_video_ioctl(inode, file, dev, arg); + break; + case VFCHUE: + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n", dev->instance)); + if(copy_from_user(&tmp,argp,sizeof(unsigned int))) { + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer " + "to IOCTL(VFCHUE)", dev->instance)); + ret = -EFAULT; + } else { + VFC_SAA9051_SA(dev,VFC_SAA9051_HUE) = tmp; + vfc_update_saa9051(dev); + ret = 0; + } + break; + case VFCPORTCHG: + ret = vfc_port_change_ioctl(inode, file, dev, arg); + break; + case VFCRDINFO: + ret = -EINVAL; + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n", dev->instance)); + break; + default: + ret = vfc_debug(vfc_get_dev_ptr(iminor(inode)), cmd, argp); + break; + }; + + return ret; +} + +static int vfc_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned int map_size, ret, map_offset; + struct vfc_dev *dev; + + dev = vfc_get_dev_ptr(iminor(file->f_path.dentry->d_inode)); + if(dev == NULL) + return -ENODEV; + + map_size = vma->vm_end - vma->vm_start; + if(map_size > sizeof(struct vfc_regs)) + map_size = sizeof(struct vfc_regs); + + vma->vm_flags |= + (VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE); + map_offset = (unsigned int) (long)dev->phys_regs; + ret = io_remap_pfn_range(vma, vma->vm_start, + MK_IOSPACE_PFN(dev->which_io, + map_offset >> PAGE_SHIFT), + map_size, vma->vm_page_prot); + + if(ret) + return -EAGAIN; + + return 0; +} + + +static const struct file_operations vfc_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .ioctl = vfc_ioctl, + .mmap = vfc_mmap, + .open = vfc_open, + .release = vfc_release, +}; + +static int vfc_probe(void) +{ + struct sbus_bus *sbus; + struct sbus_dev *sdev = NULL; + int ret; + int instance = 0, cards = 0; + + for_all_sbusdev(sdev, sbus) { + if (strcmp(sdev->prom_name, "vfc") == 0) { + cards++; + continue; + } + } + + if (!cards) + return -ENODEV; + + vfc_dev_lst = kcalloc(cards + 1, sizeof(struct vfc_dev*), GFP_KERNEL); + if (vfc_dev_lst == NULL) + return -ENOMEM; + vfc_dev_lst[cards] = NULL; + + ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops); + if(ret) { + printk(KERN_ERR "Unable to get major number %d\n", VFC_MAJOR); + kfree(vfc_dev_lst); + return -EIO; + } + instance = 0; + for_all_sbusdev(sdev, sbus) { + if (strcmp(sdev->prom_name, "vfc") == 0) { + vfc_dev_lst[instance]=(struct vfc_dev *) + kmalloc(sizeof(struct vfc_dev), GFP_KERNEL); + if (vfc_dev_lst[instance] == NULL) + return -ENOMEM; + ret = init_vfc_device(sdev, + vfc_dev_lst[instance], + instance); + if(ret) { + printk(KERN_ERR "Unable to initialize" + " vfc%d device\n", + instance); + } else { + } + + instance++; + continue; + } + } + + return 0; +} + +#ifdef MODULE +int init_module(void) +#else +int vfc_init(void) +#endif +{ + return vfc_probe(); +} + +#ifdef MODULE +static void deinit_vfc_device(struct vfc_dev *dev) +{ + if(dev == NULL) + return; + sbus_iounmap(dev->regs, sizeof(struct vfc_regs)); + kfree(dev); +} + +void cleanup_module(void) +{ + struct vfc_dev **devp; + + unregister_chrdev(VFC_MAJOR,vfcstr); + + for (devp = vfc_dev_lst; *devp; devp++) + deinit_vfc_device(*devp); + + kfree(vfc_dev_lst); + return; +} +#endif + +MODULE_LICENSE("GPL"); + diff --git a/trunk/drivers/sbus/char/vfc_i2c.c b/trunk/drivers/sbus/char/vfc_i2c.c new file mode 100644 index 000000000000..32b986e0ed78 --- /dev/null +++ b/trunk/drivers/sbus/char/vfc_i2c.c @@ -0,0 +1,335 @@ +/* + * drivers/sbus/char/vfc_i2c.c + * + * Driver for the Videopix Frame Grabber. + * + * Functions that support the Phillips i2c(I squared C) bus on the vfc + * Documentation for the Phillips I2C bus can be found on the + * phillips home page + * + * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu) + * + */ + +/* NOTE: It seems to me that the documentation regarding the +pcd8584t/pcf8584 does not show the correct way to address the i2c bus. +Based on the information on the I2C bus itself and the remainder of +the Phillips docs the following algorithms appear to be correct. I am +fairly certain that the flowcharts in the phillips docs are wrong. */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define VFC_I2C_DEBUG +#endif + +#include "vfc.h" +#include "vfc_i2c.h" + +#define WRITE_S1(__val) \ + sbus_writel(__val, &dev->regs->i2c_s1) +#define WRITE_REG(__val) \ + sbus_writel(__val, &dev->regs->i2c_reg) + +#define VFC_I2C_READ (0x1) +#define VFC_I2C_WRITE (0x0) + +/****** + The i2c bus controller chip on the VFC is a pcd8584t, but + phillips claims it doesn't exist. As far as I can tell it is + identical to the PCF8584 so I treat it like it is the pcf8584. + + NOTE: The pcf8584 only cares + about the msb of the word you feed it +*****/ + +int vfc_pcf8584_init(struct vfc_dev *dev) +{ + /* This will also choose register S0_OWN so we can set it. */ + WRITE_S1(RESET); + + /* The pcf8584 shifts this value left one bit and uses + * it as its i2c bus address. + */ + WRITE_REG(0x55000000); + + /* This will set the i2c bus at the same speed sun uses, + * and set another magic bit. + */ + WRITE_S1(SELECT(S2)); + WRITE_REG(0x14000000); + + /* Enable the serial port, idle the i2c bus and set + * the data reg to s0. + */ + WRITE_S1(CLEAR_I2C_BUS); + udelay(100); + return 0; +} + +void vfc_i2c_delay_no_busy(struct vfc_dev *dev, unsigned long usecs) +{ + schedule_timeout_uninterruptible(usecs_to_jiffies(usecs)); +} + +void inline vfc_i2c_delay(struct vfc_dev *dev) +{ + vfc_i2c_delay_no_busy(dev, 100); +} + +int vfc_init_i2c_bus(struct vfc_dev *dev) +{ + WRITE_S1(ENABLE_SERIAL | SELECT(S0) | ACK); + vfc_i2c_reset_bus(dev); + return 0; +} + +int vfc_i2c_reset_bus(struct vfc_dev *dev) +{ + VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n", + dev->instance)); + if(dev == NULL) + return -EINVAL; + if(dev->regs == NULL) + return -EINVAL; + WRITE_S1(SEND_I2C_STOP); + WRITE_S1(SEND_I2C_STOP | ACK); + vfc_i2c_delay(dev); + WRITE_S1(CLEAR_I2C_BUS); + VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n", + dev->instance, + sbus_readl(&dev->regs->i2c_s1))); + return 0; +} + +static int vfc_i2c_wait_for_bus(struct vfc_dev *dev) +{ + int timeout = 1000; + + while(!(sbus_readl(&dev->regs->i2c_s1) & BB)) { + if(!(timeout--)) + return -ETIMEDOUT; + vfc_i2c_delay(dev); + } + return 0; +} + +static int vfc_i2c_wait_for_pin(struct vfc_dev *dev, int ack) +{ + int timeout = 1000; + int s1; + + while ((s1 = sbus_readl(&dev->regs->i2c_s1)) & PIN) { + if (!(timeout--)) + return -ETIMEDOUT; + vfc_i2c_delay(dev); + } + if (ack == VFC_I2C_ACK_CHECK) { + if(s1 & LRB) + return -EIO; + } + return 0; +} + +#define SHIFT(a) ((a) << 24) +static int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr, + char mode) +{ + int ret, raddr; +#if 1 + WRITE_S1(SEND_I2C_STOP | ACK); + WRITE_S1(SELECT(S0) | ENABLE_SERIAL); + vfc_i2c_delay(dev); +#endif + + switch(mode) { + case VFC_I2C_READ: + raddr = SHIFT(((unsigned int)addr | 0x1)); + WRITE_REG(raddr); + VFC_I2C_DEBUG_PRINTK(("vfc%d: receiving from i2c addr 0x%x\n", + dev->instance, addr | 0x1)); + break; + case VFC_I2C_WRITE: + raddr = SHIFT((unsigned int)addr & ~0x1); + WRITE_REG(raddr); + VFC_I2C_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n", + dev->instance, addr & ~0x1)); + break; + default: + return -EINVAL; + }; + + WRITE_S1(SEND_I2C_START); + vfc_i2c_delay(dev); + ret = vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK); /* We wait + for the + i2c send + to finish + here but + Sun + doesn't, + hmm */ + if (ret) { + printk(KERN_ERR "vfc%d: VFC xmit addr timed out or no ack\n", + dev->instance); + return ret; + } else if (mode == VFC_I2C_READ) { + if ((ret = sbus_readl(&dev->regs->i2c_reg) & 0xff000000) != raddr) { + printk(KERN_WARNING + "vfc%d: returned slave address " + "mismatch(%x,%x)\n", + dev->instance, raddr, ret); + } + } + return 0; +} + +static int vfc_i2c_xmit_byte(struct vfc_dev *dev,unsigned char *byte) +{ + int ret; + u32 val = SHIFT((unsigned int)*byte); + + WRITE_REG(val); + + ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_ACK_CHECK); + switch(ret) { + case -ETIMEDOUT: + printk(KERN_ERR "vfc%d: VFC xmit byte timed out or no ack\n", + dev->instance); + break; + case -EIO: + ret = XMIT_LAST_BYTE; + break; + default: + break; + }; + + return ret; +} + +static int vfc_i2c_recv_byte(struct vfc_dev *dev, unsigned char *byte, + int last) +{ + int ret; + + if (last) { + WRITE_REG(NEGATIVE_ACK); + VFC_I2C_DEBUG_PRINTK(("vfc%d: sending negative ack\n", + dev->instance)); + } else { + WRITE_S1(ACK); + } + + ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_NO_ACK_CHECK); + if(ret) { + printk(KERN_ERR "vfc%d: " + "VFC recv byte timed out\n", + dev->instance); + } + *byte = (sbus_readl(&dev->regs->i2c_reg)) >> 24; + return ret; +} + +int vfc_i2c_recvbuf(struct vfc_dev *dev, unsigned char addr, + char *buf, int count) +{ + int ret, last; + + if(!(count && buf && dev && dev->regs) ) + return -EINVAL; + + if ((ret = vfc_i2c_wait_for_bus(dev))) { + printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance); + return ret; + } + + if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_READ))) { + WRITE_S1(SEND_I2C_STOP); + vfc_i2c_delay(dev); + return ret; + } + + last = 0; + while (count--) { + if (!count) + last = 1; + if ((ret = vfc_i2c_recv_byte(dev, buf, last))) { + printk(KERN_ERR "vfc%d: " + "VFC error while receiving byte\n", + dev->instance); + WRITE_S1(SEND_I2C_STOP); + ret = -EINVAL; + } + buf++; + } + WRITE_S1(SEND_I2C_STOP | ACK); + vfc_i2c_delay(dev); + return ret; +} + +int vfc_i2c_sendbuf(struct vfc_dev *dev, unsigned char addr, + char *buf, int count) +{ + int ret; + + if (!(buf && dev && dev->regs)) + return -EINVAL; + + if ((ret = vfc_i2c_wait_for_bus(dev))) { + printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance); + return ret; + } + + if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_WRITE))) { + WRITE_S1(SEND_I2C_STOP); + vfc_i2c_delay(dev); + return ret; + } + + while(count--) { + ret = vfc_i2c_xmit_byte(dev, buf); + switch(ret) { + case XMIT_LAST_BYTE: + VFC_I2C_DEBUG_PRINTK(("vfc%d: " + "Receiver ended transmission with " + " %d bytes remaining\n", + dev->instance, count)); + ret = 0; + goto done; + break; + case 0: + break; + default: + printk(KERN_ERR "vfc%d: " + "VFC error while sending byte\n", dev->instance); + break; + }; + + buf++; + } +done: + WRITE_S1(SEND_I2C_STOP | ACK); + vfc_i2c_delay(dev); + return ret; +} + + + + + + + + + diff --git a/trunk/drivers/sbus/char/vfc_i2c.h b/trunk/drivers/sbus/char/vfc_i2c.h new file mode 100644 index 000000000000..a2e6973209d5 --- /dev/null +++ b/trunk/drivers/sbus/char/vfc_i2c.h @@ -0,0 +1,44 @@ +#ifndef _LINUX_VFC_I2C_H_ +#define _LINUX_VFC_I2C_H_ + +/* control bits */ +#define PIN (0x80000000) +#define ESO (0x40000000) +#define ES1 (0x20000000) +#define ES2 (0x10000000) +#define ENI (0x08000000) +#define STA (0x04000000) +#define STO (0x02000000) +#define ACK (0x01000000) + +/* status bits */ +#define STS (0x20000000) +#define BER (0x10000000) +#define LRB (0x08000000) +#define AAS (0x04000000) +#define LAB (0x02000000) +#define BB (0x01000000) + +#define SEND_I2C_START (PIN | ESO | STA) +#define SEND_I2C_STOP (PIN | ESO | STO) +#define CLEAR_I2C_BUS (PIN | ESO | ACK) +#define NEGATIVE_ACK ((ESO) & ~ACK) + +#define SELECT(a) (a) +#define S0 (PIN | ESO | ES1) +#define S0_OWN (PIN) +#define S2 (PIN | ES1) +#define S3 (PIN | ES2) + +#define ENABLE_SERIAL (PIN | ESO) +#define DISABLE_SERIAL (PIN) +#define RESET (PIN) + +#define XMIT_LAST_BYTE (1) +#define VFC_I2C_ACK_CHECK (1) +#define VFC_I2C_NO_ACK_CHECK (0) + +#endif /* _LINUX_VFC_I2C_H_ */ + + + diff --git a/trunk/drivers/sbus/dvma.c b/trunk/drivers/sbus/dvma.c new file mode 100644 index 000000000000..ab0d2de3324c --- /dev/null +++ b/trunk/drivers/sbus/dvma.c @@ -0,0 +1,136 @@ +/* dvma.c: Routines that are used to access DMA on the Sparc SBus. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct sbus_dma *dma_chain; + +static void __init init_one_dvma(struct sbus_dma *dma, int num_dma) +{ + printk("dma%d: ", num_dma); + + dma->next = NULL; + dma->running = 0; /* No transfers going on as of yet */ + dma->allocated = 0; /* No one has allocated us yet */ + switch(sbus_readl(dma->regs + DMA_CSR)&DMA_DEVICE_ID) { + case DMA_VERS0: + dma->revision = dvmarev0; + printk("Revision 0 "); + break; + case DMA_ESCV1: + dma->revision = dvmaesc1; + printk("ESC Revision 1 "); + break; + case DMA_VERS1: + dma->revision = dvmarev1; + printk("Revision 1 "); + break; + case DMA_VERS2: + dma->revision = dvmarev2; + printk("Revision 2 "); + break; + case DMA_VERHME: + dma->revision = dvmahme; + printk("HME DVMA gate array "); + break; + case DMA_VERSPLUS: + dma->revision = dvmarevplus; + printk("Revision 1 PLUS "); + break; + default: + printk("unknown dma version %08x", + sbus_readl(dma->regs + DMA_CSR) & DMA_DEVICE_ID); + dma->allocated = 1; + break; + } + printk("\n"); +} + +/* Probe this SBus DMA module(s) */ +void __init dvma_init(struct sbus_bus *sbus) +{ + struct sbus_dev *this_dev; + struct sbus_dma *dma; + struct sbus_dma *dchain; + static int num_dma = 0; + + for_each_sbusdev(this_dev, sbus) { + char *name = this_dev->prom_name; + int hme = 0; + + if(!strcmp(name, "SUNW,fas")) + hme = 1; + else if(strcmp(name, "dma") && + strcmp(name, "ledma") && + strcmp(name, "espdma")) + continue; + + /* Found one... */ + dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC); + + dma->sdev = this_dev; + + /* Put at end of dma chain */ + dchain = dma_chain; + if(dchain) { + while(dchain->next) + dchain = dchain->next; + dchain->next = dma; + } else { + /* We're the first in line */ + dma_chain = dma; + } + + dma->regs = sbus_ioremap(&dma->sdev->resource[0], 0, + dma->sdev->resource[0].end - dma->sdev->resource[0].start + 1, + "dma"); + + dma->node = dma->sdev->prom_node; + + init_one_dvma(dma, num_dma++); + } +} + +#ifdef CONFIG_SUN4 + +#include + +void __init sun4_dvma_init(void) +{ + struct sbus_dma *dma; + struct resource r; + + if(sun4_dma_physaddr) { + dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC); + + /* No SBUS */ + dma->sdev = NULL; + + /* Only one DMA device */ + dma_chain = dma; + + memset(&r, 0, sizeof(r)); + r.start = sun4_dma_physaddr; + dma->regs = sbus_ioremap(&r, 0, PAGE_SIZE, "dma"); + + /* No prom node */ + dma->node = 0x0; + + init_one_dvma(dma, 0); + } else { + dma_chain = NULL; + } +} + +#endif diff --git a/trunk/drivers/sbus/sbus.c b/trunk/drivers/sbus/sbus.c new file mode 100644 index 000000000000..9c129248466c --- /dev/null +++ b/trunk/drivers/sbus/sbus.c @@ -0,0 +1,316 @@ +/* sbus.c: SBus support routines. + * + * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net) + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static ssize_t +show_sbusobppath_attr(struct device * dev, struct device_attribute * attr, char * buf) +{ + struct sbus_dev *sbus; + + sbus = to_sbus_device(dev); + + return snprintf (buf, PAGE_SIZE, "%s\n", sbus->ofdev.node->full_name); +} + +static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, NULL); + +struct sbus_bus *sbus_root; + +static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev) +{ + struct dev_archdata *sd; + unsigned long base; + const void *pval; + int len, err; + + sdev->prom_node = dp->node; + strcpy(sdev->prom_name, dp->name); + + pval = of_get_property(dp, "reg", &len); + sdev->num_registers = 0; + if (pval) { + memcpy(sdev->reg_addrs, pval, len); + + sdev->num_registers = + len / sizeof(struct linux_prom_registers); + + base = (unsigned long) sdev->reg_addrs[0].phys_addr; + + /* Compute the slot number. */ + if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) + sdev->slot = sbus_dev_slot(base); + else + sdev->slot = sdev->reg_addrs[0].which_io; + } + + pval = of_get_property(dp, "ranges", &len); + sdev->num_device_ranges = 0; + if (pval) { + memcpy(sdev->device_ranges, pval, len); + sdev->num_device_ranges = + len / sizeof(struct linux_prom_ranges); + } + + sbus_fill_device_irq(sdev); + + sd = &sdev->ofdev.dev.archdata; + sd->prom_node = dp; + sd->op = &sdev->ofdev; + + sdev->ofdev.node = dp; + if (sdev->parent) + sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev; + else + sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev; + sdev->ofdev.dev.bus = &sbus_bus_type; + dev_set_name(&sdev->ofdev.dev, "sbus[%08x]", dp->node); + + if (of_device_register(&sdev->ofdev) != 0) + printk(KERN_DEBUG "sbus: device registration error for %s!\n", + dp->path_component_name); + + /* WE HAVE BEEN INVADED BY ALIENS! */ + err = sysfs_create_file(&sdev->ofdev.dev.kobj, &dev_attr_obppath.attr); +} + +static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus) +{ + const void *pval; + int len; + + pval = of_get_property(dp, "ranges", &len); + sbus->num_sbus_ranges = 0; + if (pval) { + memcpy(sbus->sbus_ranges, pval, len); + sbus->num_sbus_ranges = + len / sizeof(struct linux_prom_ranges); + + sbus_arch_bus_ranges_init(dp->parent, sbus); + } +} + +static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges, + int num_ranges, + struct linux_prom_registers *regs, + int num_regs) +{ + if (num_ranges) { + int regnum; + + for (regnum = 0; regnum < num_regs; regnum++) { + int rngnum; + + for (rngnum = 0; rngnum < num_ranges; rngnum++) { + if (regs[regnum].which_io == ranges[rngnum].ot_child_space) + break; + } + if (rngnum == num_ranges) { + /* We used to flag this as an error. Actually + * some devices do not report the regs as we expect. + * For example, see SUNW,pln device. In that case + * the reg property is in a format internal to that + * node, ie. it is not in the SBUS register space + * per se. -DaveM + */ + return; + } + regs[regnum].which_io = ranges[rngnum].ot_parent_space; + regs[regnum].phys_addr -= ranges[rngnum].ot_child_base; + regs[regnum].phys_addr += ranges[rngnum].ot_parent_base; + } + } +} + +static void __init __fixup_regs_sdev(struct sbus_dev *sdev) +{ + if (sdev->num_registers != 0) { + struct sbus_dev *parent = sdev->parent; + int i; + + while (parent != NULL) { + __apply_ranges_to_regs(parent->device_ranges, + parent->num_device_ranges, + sdev->reg_addrs, + sdev->num_registers); + + parent = parent->parent; + } + + __apply_ranges_to_regs(sdev->bus->sbus_ranges, + sdev->bus->num_sbus_ranges, + sdev->reg_addrs, + sdev->num_registers); + + for (i = 0; i < sdev->num_registers; i++) { + struct resource *res = &sdev->resource[i]; + + res->start = sdev->reg_addrs[i].phys_addr; + res->end = (res->start + + (unsigned long)sdev->reg_addrs[i].reg_size - 1UL); + res->flags = IORESOURCE_IO | + (sdev->reg_addrs[i].which_io & 0xff); + } + } +} + +static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev) +{ + struct sbus_dev *sdev; + + for (sdev = first_sdev; sdev; sdev = sdev->next) { + if (sdev->child) + sbus_fixup_all_regs(sdev->child); + __fixup_regs_sdev(sdev); + } +} + +/* We preserve the "probe order" of these bus and device lists to give + * the same ordering as the old code. + */ +static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root) +{ + while (*root) + root = &(*root)->next; + *root = sbus; + sbus->next = NULL; +} + +static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root) +{ + while (*root) + root = &(*root)->next; + *root = sdev; + sdev->next = NULL; +} + +static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus) +{ + dp = dp->child; + while (dp) { + struct sbus_dev *sdev; + + sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC); + if (sdev) { + sdev_insert(sdev, &parent->child); + + sdev->bus = sbus; + sdev->parent = parent; + sdev->ofdev.dev.archdata.iommu = + sbus->ofdev.dev.archdata.iommu; + sdev->ofdev.dev.archdata.stc = + sbus->ofdev.dev.archdata.stc; + + fill_sbus_device(dp, sdev); + + walk_children(dp, sdev, sbus); + } + dp = dp->sibling; + } +} + +static void __init build_one_sbus(struct device_node *dp, int num_sbus) +{ + struct sbus_bus *sbus; + unsigned int sbus_clock; + struct device_node *dev_dp; + + sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC); + if (!sbus) + return; + + sbus_insert(sbus, &sbus_root); + sbus->prom_node = dp->node; + + sbus_setup_iommu(sbus, dp); + + printk("sbus%d: ", num_sbus); + + sbus_clock = of_getintprop_default(dp, "clock-frequency", + (25*1000*1000)); + sbus->clock_freq = sbus_clock; + + printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000), + (int) (((sbus_clock/1000)%1000 != 0) ? + (((sbus_clock/1000)%1000) + 1000) : 0)); + + strcpy(sbus->prom_name, dp->name); + + sbus_setup_arch_props(sbus, dp); + + sbus_bus_ranges_init(dp, sbus); + + sbus->ofdev.node = dp; + sbus->ofdev.dev.parent = NULL; + sbus->ofdev.dev.bus = &sbus_bus_type; + dev_set_name(&sbus->ofdev.dev, "sbus%d", num_sbus); + + if (of_device_register(&sbus->ofdev) != 0) + printk(KERN_DEBUG "sbus: device registration error for %s!\n", + dev_name(&sbus->ofdev.dev)); + + dev_dp = dp->child; + while (dev_dp) { + struct sbus_dev *sdev; + + sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC); + if (sdev) { + sdev_insert(sdev, &sbus->devices); + + sdev->bus = sbus; + sdev->parent = NULL; + sdev->ofdev.dev.archdata.iommu = + sbus->ofdev.dev.archdata.iommu; + sdev->ofdev.dev.archdata.stc = + sbus->ofdev.dev.archdata.stc; + + fill_sbus_device(dev_dp, sdev); + + walk_children(dev_dp, sdev, sbus); + } + dev_dp = dev_dp->sibling; + } + + sbus_fixup_all_regs(sbus->devices); + + dvma_init(sbus); +} + +static int __init sbus_init(void) +{ + struct device_node *dp; + const char *sbus_name = "sbus"; + int num_sbus = 0; + + if (sbus_arch_preinit()) + return 0; + + if (sparc_cpu_model == sun4d) + sbus_name = "sbi"; + + for_each_node_by_name(dp, sbus_name) { + build_one_sbus(dp, num_sbus); + num_sbus++; + + } + + sbus_arch_postinit(); + + return 0; +} + +subsys_initcall(sbus_init); diff --git a/trunk/drivers/scsi/esp_scsi.h b/trunk/drivers/scsi/esp_scsi.h index 28e22acf87ea..bb43a1388188 100644 --- a/trunk/drivers/scsi/esp_scsi.h +++ b/trunk/drivers/scsi/esp_scsi.h @@ -521,8 +521,7 @@ struct esp { struct completion *eh_reset; - void *dma; - int dmarev; + struct sbus_dma *dma; }; /* A front-end driver for the ESP chip should do the following in diff --git a/trunk/drivers/scsi/qlogicpti.c b/trunk/drivers/scsi/qlogicpti.c index 69d6ad862b60..905350896725 100644 --- a/trunk/drivers/scsi/qlogicpti.c +++ b/trunk/drivers/scsi/qlogicpti.c @@ -1,6 +1,6 @@ /* qlogicpti.c: Performance Technologies QlogicISP sbus card driver. * - * Copyright (C) 1996, 2006, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net) * * A lot of this driver was directly stolen from Erik H. Moe's PCI * Qlogic ISP driver. Mucho kudos to him for this code. @@ -25,14 +25,12 @@ #include #include #include -#include -#include -#include #include #include "qlogicpti.h" +#include #include #include #include @@ -159,7 +157,7 @@ static inline void set_sbus_cfg1(struct qlogicpti *qpti) * is a nop and the chip ends up using the smallest burst * size. -DaveM */ - if (sbus_can_burst64() && (bursts & DMA_BURST64)) { + if (sbus_can_burst64(qpti->sdev) && (bursts & DMA_BURST64)) { val = (SBUS_CFG1_BENAB | SBUS_CFG1_B64); } else #endif @@ -686,19 +684,19 @@ static void __devexit qpti_chain_del(struct qlogicpti *qpti) static int __devinit qpti_map_regs(struct qlogicpti *qpti) { - struct of_device *op = qpti->op; + struct sbus_dev *sdev = qpti->sdev; - qpti->qregs = of_ioremap(&op->resource[0], 0, - resource_size(&op->resource[0]), - "PTI Qlogic/ISP"); + qpti->qregs = sbus_ioremap(&sdev->resource[0], 0, + sdev->reg_addrs[0].reg_size, + "PTI Qlogic/ISP"); if (!qpti->qregs) { printk("PTI: Qlogic/ISP registers are unmappable\n"); return -1; } if (qpti->is_pti) { - qpti->sreg = of_ioremap(&op->resource[0], (16 * 4096), - sizeof(unsigned char), - "PTI Qlogic/ISP statreg"); + qpti->sreg = sbus_ioremap(&sdev->resource[0], (16 * 4096), + sizeof(unsigned char), + "PTI Qlogic/ISP statreg"); if (!qpti->sreg) { printk("PTI: Qlogic/ISP status register is unmappable\n"); return -1; @@ -709,9 +707,9 @@ static int __devinit qpti_map_regs(struct qlogicpti *qpti) static int __devinit qpti_register_irq(struct qlogicpti *qpti) { - struct of_device *op = qpti->op; + struct sbus_dev *sdev = qpti->sdev; - qpti->qhost->irq = qpti->irq = op->irqs[0]; + qpti->qhost->irq = qpti->irq = sdev->irqs[0]; /* We used to try various overly-clever things to * reduce the interrupt processing overhead on @@ -734,19 +732,17 @@ static int __devinit qpti_register_irq(struct qlogicpti *qpti) static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti) { - struct of_device *op = qpti->op; - struct device_node *dp; - - dp = op->node; - - qpti->scsi_id = of_getintprop_default(dp, "initiator-id", -1); + qpti->scsi_id = prom_getintdefault(qpti->prom_node, + "initiator-id", + -1); if (qpti->scsi_id == -1) - qpti->scsi_id = of_getintprop_default(dp, "scsi-initiator-id", - -1); + qpti->scsi_id = prom_getintdefault(qpti->prom_node, + "scsi-initiator-id", + -1); if (qpti->scsi_id == -1) qpti->scsi_id = - of_getintprop_default(dp->parent, - "scsi-initiator-id", 7); + prom_getintdefault(qpti->sdev->bus->prom_node, + "scsi-initiator-id", 7); qpti->qhost->this_id = qpti->scsi_id; qpti->qhost->max_sectors = 64; @@ -755,11 +751,12 @@ static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti) static void qpti_get_bursts(struct qlogicpti *qpti) { - struct of_device *op = qpti->op; + struct sbus_dev *sdev = qpti->sdev; u8 bursts, bmask; - bursts = of_getintprop_default(op->node, "burst-sizes", 0xff); - bmask = of_getintprop_default(op->node->parent, "burst-sizes", 0xff); + bursts = prom_getintdefault(qpti->prom_node, "burst-sizes", 0xff); + bmask = prom_getintdefault(sdev->bus->prom_node, + "burst-sizes", 0xff); if (bmask != 0xff) bursts &= bmask; if (bursts == 0xff || @@ -788,25 +785,25 @@ static void qpti_get_clock(struct qlogicpti *qpti) */ static int __devinit qpti_map_queues(struct qlogicpti *qpti) { - struct of_device *op = qpti->op; + struct sbus_dev *sdev = qpti->sdev; #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) - qpti->res_cpu = dma_alloc_coherent(&op->dev, - QSIZE(RES_QUEUE_LEN), - &qpti->res_dvma, GFP_ATOMIC); + qpti->res_cpu = sbus_alloc_consistent(sdev, + QSIZE(RES_QUEUE_LEN), + &qpti->res_dvma); if (qpti->res_cpu == NULL || qpti->res_dvma == 0) { printk("QPTI: Cannot map response queue.\n"); return -1; } - qpti->req_cpu = dma_alloc_coherent(&op->dev, - QSIZE(QLOGICPTI_REQ_QUEUE_LEN), - &qpti->req_dvma, GFP_ATOMIC); + qpti->req_cpu = sbus_alloc_consistent(sdev, + QSIZE(QLOGICPTI_REQ_QUEUE_LEN), + &qpti->req_dvma); if (qpti->req_cpu == NULL || qpti->req_dvma == 0) { - dma_free_coherent(&op->dev, QSIZE(RES_QUEUE_LEN), - qpti->res_cpu, qpti->res_dvma); + sbus_free_consistent(sdev, QSIZE(RES_QUEUE_LEN), + qpti->res_cpu, qpti->res_dvma); printk("QPTI: Cannot map request queue.\n"); return -1; } @@ -878,9 +875,8 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd, int sg_count; sg = scsi_sglist(Cmnd); - sg_count = dma_map_sg(&qpti->op->dev, sg, - scsi_sg_count(Cmnd), - Cmnd->sc_data_direction); + sg_count = sbus_map_sg(qpti->sdev, sg, scsi_sg_count(Cmnd), + Cmnd->sc_data_direction); ds = cmd->dataseg; cmd->segment_cnt = sg_count; @@ -1156,9 +1152,9 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti) Cmnd->result = DID_ERROR << 16; if (scsi_bufflen(Cmnd)) - dma_unmap_sg(&qpti->op->dev, - scsi_sglist(Cmnd), scsi_sg_count(Cmnd), - Cmnd->sc_data_direction); + sbus_unmap_sg(qpti->sdev, + scsi_sglist(Cmnd), scsi_sg_count(Cmnd), + Cmnd->sc_data_direction); qpti->cmd_count[Cmnd->device->id]--; sbus_writew(out_ptr, qpti->qregs + MBOX5); @@ -1272,32 +1268,34 @@ static struct scsi_host_template qpti_template = { .use_clustering = ENABLE_CLUSTERING, }; -static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match) { + static int nqptis; + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + struct device_node *dp = dev->node; struct scsi_host_template *tpnt = match->data; - struct device_node *dp = op->node; struct Scsi_Host *host; struct qlogicpti *qpti; - static int nqptis; const char *fcode; /* Sometimes Antares cards come up not completely * setup, and we get a report of a zero IRQ. */ - if (op->irqs[0] == 0) + if (sdev->irqs[0] == 0) return -ENODEV; host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti)); if (!host) return -ENOMEM; - qpti = shost_priv(host); + qpti = (struct qlogicpti *) host->hostdata; host->max_id = MAX_TARGETS; qpti->qhost = host; - qpti->op = op; + qpti->sdev = sdev; qpti->qpti_id = nqptis; - strcpy(qpti->prom_name, op->node->name); + qpti->prom_node = sdev->prom_node; + strcpy(qpti->prom_name, sdev->ofdev.node->name); qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp"); if (qpti_map_regs(qpti) < 0) @@ -1343,12 +1341,12 @@ static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_devic (qpti->ultra ? "Ultra" : "Fast"), (qpti->differential ? "differential" : "single ended")); - if (scsi_add_host(host, &op->dev)) { + if (scsi_add_host(host, &dev->dev)) { printk("qlogicpti%d: Failed scsi_add_host\n", qpti->qpti_id); goto fail_unmap_queues; } - dev_set_drvdata(&op->dev, qpti); + dev_set_drvdata(&sdev->ofdev.dev, qpti); qpti_chain_add(qpti); @@ -1359,20 +1357,19 @@ static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_devic fail_unmap_queues: #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) - dma_free_coherent(&op->dev, - QSIZE(RES_QUEUE_LEN), - qpti->res_cpu, qpti->res_dvma); - dma_free_coherent(&op->dev, - QSIZE(QLOGICPTI_REQ_QUEUE_LEN), - qpti->req_cpu, qpti->req_dvma); + sbus_free_consistent(qpti->sdev, + QSIZE(RES_QUEUE_LEN), + qpti->res_cpu, qpti->res_dvma); + sbus_free_consistent(qpti->sdev, + QSIZE(QLOGICPTI_REQ_QUEUE_LEN), + qpti->req_cpu, qpti->req_dvma); #undef QSIZE fail_unmap_regs: - of_iounmap(&op->resource[0], qpti->qregs, - resource_size(&op->resource[0])); + sbus_iounmap(qpti->qregs, + qpti->sdev->reg_addrs[0].reg_size); if (qpti->is_pti) - of_iounmap(&op->resource[0], qpti->sreg, - sizeof(unsigned char)); + sbus_iounmap(qpti->sreg, sizeof(unsigned char)); fail_free_irq: free_irq(qpti->irq, qpti); @@ -1383,9 +1380,9 @@ static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_devic return -ENODEV; } -static int __devexit qpti_sbus_remove(struct of_device *op) +static int __devexit qpti_sbus_remove(struct of_device *dev) { - struct qlogicpti *qpti = dev_get_drvdata(&op->dev); + struct qlogicpti *qpti = dev_get_drvdata(&dev->dev); qpti_chain_del(qpti); @@ -1398,25 +1395,24 @@ static int __devexit qpti_sbus_remove(struct of_device *op) free_irq(qpti->irq, qpti); #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) - dma_free_coherent(&op->dev, - QSIZE(RES_QUEUE_LEN), - qpti->res_cpu, qpti->res_dvma); - dma_free_coherent(&op->dev, - QSIZE(QLOGICPTI_REQ_QUEUE_LEN), - qpti->req_cpu, qpti->req_dvma); + sbus_free_consistent(qpti->sdev, + QSIZE(RES_QUEUE_LEN), + qpti->res_cpu, qpti->res_dvma); + sbus_free_consistent(qpti->sdev, + QSIZE(QLOGICPTI_REQ_QUEUE_LEN), + qpti->req_cpu, qpti->req_dvma); #undef QSIZE - of_iounmap(&op->resource[0], qpti->qregs, - resource_size(&op->resource[0])); + sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size); if (qpti->is_pti) - of_iounmap(&op->resource[0], qpti->sreg, sizeof(unsigned char)); + sbus_iounmap(qpti->sreg, sizeof(unsigned char)); scsi_host_put(qpti->qhost); return 0; } -static const struct of_device_id qpti_match[] = { +static struct of_device_id qpti_match[] = { { .name = "ptisp", .data = &qpti_template, @@ -1446,7 +1442,7 @@ static struct of_platform_driver qpti_sbus_driver = { static int __init qpti_init(void) { - return of_register_driver(&qpti_sbus_driver, &of_bus_type); + return of_register_driver(&qpti_sbus_driver, &sbus_bus_type); } static void __exit qpti_exit(void) @@ -1457,7 +1453,7 @@ static void __exit qpti_exit(void) MODULE_DESCRIPTION("QlogicISP SBUS driver"); MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); MODULE_LICENSE("GPL"); -MODULE_VERSION("2.1"); +MODULE_VERSION("2.0"); module_init(qpti_init); module_exit(qpti_exit); diff --git a/trunk/drivers/scsi/qlogicpti.h b/trunk/drivers/scsi/qlogicpti.h index 9c053bbaa877..ef6da2df584b 100644 --- a/trunk/drivers/scsi/qlogicpti.h +++ b/trunk/drivers/scsi/qlogicpti.h @@ -342,7 +342,7 @@ struct qlogicpti { u_int req_in_ptr; /* index of next request slot */ u_int res_out_ptr; /* index of next result slot */ long send_marker; /* must we send a marker? */ - struct of_device *op; + struct sbus_dev *sdev; unsigned long __pad; int cmd_count[MAX_TARGETS]; diff --git a/trunk/drivers/scsi/sun_esp.c b/trunk/drivers/scsi/sun_esp.c index 3d73aad4bc82..f9cf70151366 100644 --- a/trunk/drivers/scsi/sun_esp.c +++ b/trunk/drivers/scsi/sun_esp.c @@ -1,6 +1,6 @@ /* sun_esp.c: ESP front-end for Sparc SBUS systems. * - * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 2007 David S. Miller (davem@davemloft.net) */ #include @@ -9,89 +9,79 @@ #include #include #include -#include -#include -#include #include #include #include +#include + #include #include "esp_scsi.h" #define DRV_MODULE_NAME "sun_esp" #define PFX DRV_MODULE_NAME ": " -#define DRV_VERSION "1.100" -#define DRV_MODULE_RELDATE "August 27, 2008" +#define DRV_VERSION "1.000" +#define DRV_MODULE_RELDATE "April 19, 2007" #define dma_read32(REG) \ sbus_readl(esp->dma_regs + (REG)) #define dma_write32(VAL, REG) \ sbus_writel((VAL), esp->dma_regs + (REG)) -/* DVMA chip revisions */ -enum dvma_rev { - dvmarev0, - dvmaesc1, - dvmarev1, - dvmarev2, - dvmarev3, - dvmarevplus, - dvmahme -}; - -static int __devinit esp_sbus_setup_dma(struct esp *esp, - struct of_device *dma_of) +static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sdev) { - esp->dma = dma_of; + struct sbus_dev *sdev = esp->dev; + struct sbus_dma *dma; - esp->dma_regs = of_ioremap(&dma_of->resource[0], 0, - resource_size(&dma_of->resource[0]), - "espdma"); - if (!esp->dma_regs) - return -ENOMEM; + if (dma_sdev != NULL) { + for_each_dvma(dma) { + if (dma->sdev == dma_sdev) + break; + } + } else { + for_each_dvma(dma) { + if (dma->sdev == NULL) + break; - switch (dma_read32(DMA_CSR) & DMA_DEVICE_ID) { - case DMA_VERS0: - esp->dmarev = dvmarev0; - break; - case DMA_ESCV1: - esp->dmarev = dvmaesc1; - break; - case DMA_VERS1: - esp->dmarev = dvmarev1; - break; - case DMA_VERS2: - esp->dmarev = dvmarev2; - break; - case DMA_VERHME: - esp->dmarev = dvmahme; - break; - case DMA_VERSPLUS: - esp->dmarev = dvmarevplus; - break; + /* If bus + slot are the same and it has the + * correct OBP name, it's ours. + */ + if (sdev->bus == dma->sdev->bus && + sdev->slot == dma->sdev->slot && + (!strcmp(dma->sdev->prom_name, "dma") || + !strcmp(dma->sdev->prom_name, "espdma"))) + break; + } } + if (dma == NULL) { + printk(KERN_ERR PFX "[%s] Cannot find dma.\n", + sdev->ofdev.node->full_name); + return -ENODEV; + } + esp->dma = dma; + esp->dma_regs = dma->regs; + return 0; } static int __devinit esp_sbus_map_regs(struct esp *esp, int hme) { - struct of_device *op = esp->dev; + struct sbus_dev *sdev = esp->dev; struct resource *res; /* On HME, two reg sets exist, first is DVMA, * second is ESP registers. */ if (hme) - res = &op->resource[1]; + res = &sdev->resource[1]; else - res = &op->resource[0]; + res = &sdev->resource[0]; - esp->regs = of_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP"); + esp->regs = sbus_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP"); if (!esp->regs) return -ENOMEM; @@ -100,11 +90,10 @@ static int __devinit esp_sbus_map_regs(struct esp *esp, int hme) static int __devinit esp_sbus_map_command_block(struct esp *esp) { - struct of_device *op = esp->dev; + struct sbus_dev *sdev = esp->dev; - esp->command_block = dma_alloc_coherent(&op->dev, 16, - &esp->command_block_dma, - GFP_ATOMIC); + esp->command_block = sbus_alloc_consistent(sdev, 16, + &esp->command_block_dma); if (!esp->command_block) return -ENOMEM; return 0; @@ -113,18 +102,17 @@ static int __devinit esp_sbus_map_command_block(struct esp *esp) static int __devinit esp_sbus_register_irq(struct esp *esp) { struct Scsi_Host *host = esp->host; - struct of_device *op = esp->dev; + struct sbus_dev *sdev = esp->dev; - host->irq = op->irqs[0]; + host->irq = sdev->irqs[0]; return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); } -static void __devinit esp_get_scsi_id(struct esp *esp, struct of_device *espdma) +static void __devinit esp_get_scsi_id(struct esp *esp) { - struct of_device *op = esp->dev; - struct device_node *dp; + struct sbus_dev *sdev = esp->dev; + struct device_node *dp = sdev->ofdev.node; - dp = op->node; esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff); if (esp->scsi_id != 0xff) goto done; @@ -133,7 +121,13 @@ static void __devinit esp_get_scsi_id(struct esp *esp, struct of_device *espdma) if (esp->scsi_id != 0xff) goto done; - esp->scsi_id = of_getintprop_default(espdma->node, + if (!sdev->bus) { + /* SUN4 */ + esp->scsi_id = 7; + goto done; + } + + esp->scsi_id = of_getintprop_default(sdev->bus->ofdev.node, "scsi-initiator-id", 7); done: @@ -143,10 +137,9 @@ static void __devinit esp_get_scsi_id(struct esp *esp, struct of_device *espdma) static void __devinit esp_get_differential(struct esp *esp) { - struct of_device *op = esp->dev; - struct device_node *dp; + struct sbus_dev *sdev = esp->dev; + struct device_node *dp = sdev->ofdev.node; - dp = op->node; if (of_find_property(dp, "differential", NULL)) esp->flags |= ESP_FLAG_DIFFERENTIAL; else @@ -155,36 +148,43 @@ static void __devinit esp_get_differential(struct esp *esp) static void __devinit esp_get_clock_params(struct esp *esp) { - struct of_device *op = esp->dev; - struct device_node *bus_dp, *dp; + struct sbus_dev *sdev = esp->dev; + struct device_node *dp = sdev->ofdev.node; + struct device_node *bus_dp; int fmhz; - dp = op->node; - bus_dp = dp->parent; + bus_dp = NULL; + if (sdev != NULL && sdev->bus != NULL) + bus_dp = sdev->bus->ofdev.node; fmhz = of_getintprop_default(dp, "clock-frequency", 0); if (fmhz == 0) - fmhz = of_getintprop_default(bus_dp, "clock-frequency", 0); + fmhz = (!bus_dp) ? 0 : + of_getintprop_default(bus_dp, "clock-frequency", 0); esp->cfreq = fmhz; } -static void __devinit esp_get_bursts(struct esp *esp, struct of_device *dma_of) +static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma) { - struct device_node *dma_dp = dma_of->node; - struct of_device *op = esp->dev; - struct device_node *dp; - u8 bursts, val; + struct sbus_dev *sdev = esp->dev; + struct device_node *dp = sdev->ofdev.node; + u8 bursts; - dp = op->node; bursts = of_getintprop_default(dp, "burst-sizes", 0xff); - val = of_getintprop_default(dma_dp, "burst-sizes", 0xff); - if (val != 0xff) - bursts &= val; + if (dma) { + struct device_node *dma_dp = dma->ofdev.node; + u8 val = of_getintprop_default(dma_dp, "burst-sizes", 0xff); + if (val != 0xff) + bursts &= val; + } - val = of_getintprop_default(dma_dp->parent, "burst-sizes", 0xff); - if (val != 0xff) - bursts &= val; + if (sdev->bus) { + u8 val = of_getintprop_default(sdev->bus->ofdev.node, + "burst-sizes", 0xff); + if (val != 0xff) + bursts &= val; + } if (bursts == 0xff || (bursts & DMA_BURST16) == 0 || @@ -194,9 +194,9 @@ static void __devinit esp_get_bursts(struct esp *esp, struct of_device *dma_of) esp->bursts = bursts; } -static void __devinit esp_sbus_get_props(struct esp *esp, struct of_device *espdma) +static void __devinit esp_sbus_get_props(struct esp *esp, struct sbus_dev *espdma) { - esp_get_scsi_id(esp, espdma); + esp_get_scsi_id(esp); esp_get_differential(esp); esp_get_clock_params(esp); esp_get_bursts(esp, espdma); @@ -215,33 +215,25 @@ static u8 sbus_esp_read8(struct esp *esp, unsigned long reg) static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf, size_t sz, int dir) { - struct of_device *op = esp->dev; - - return dma_map_single(&op->dev, buf, sz, dir); + return sbus_map_single(esp->dev, buf, sz, dir); } static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg, int num_sg, int dir) { - struct of_device *op = esp->dev; - - return dma_map_sg(&op->dev, sg, num_sg, dir); + return sbus_map_sg(esp->dev, sg, num_sg, dir); } static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr, size_t sz, int dir) { - struct of_device *op = esp->dev; - - dma_unmap_single(&op->dev, addr, sz, dir); + sbus_unmap_single(esp->dev, addr, sz, dir); } static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, int num_sg, int dir) { - struct of_device *op = esp->dev; - - dma_unmap_sg(&op->dev, sg, num_sg, dir); + sbus_unmap_sg(esp->dev, sg, num_sg, dir); } static int sbus_esp_irq_pending(struct esp *esp) @@ -255,26 +247,24 @@ static void sbus_esp_reset_dma(struct esp *esp) { int can_do_burst16, can_do_burst32, can_do_burst64; int can_do_sbus64, lim; - struct of_device *op; u32 val; can_do_burst16 = (esp->bursts & DMA_BURST16) != 0; can_do_burst32 = (esp->bursts & DMA_BURST32) != 0; can_do_burst64 = 0; can_do_sbus64 = 0; - op = esp->dev; - if (sbus_can_dma_64bit()) + if (sbus_can_dma_64bit(esp->dev)) can_do_sbus64 = 1; - if (sbus_can_burst64()) + if (sbus_can_burst64(esp->sdev)) can_do_burst64 = (esp->bursts & DMA_BURST64) != 0; /* Put the DVMA into a known state. */ - if (esp->dmarev != dvmahme) { + if (esp->dma->revision != dvmahme) { val = dma_read32(DMA_CSR); dma_write32(val | DMA_RST_SCSI, DMA_CSR); dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); } - switch (esp->dmarev) { + switch (esp->dma->revision) { case dvmahme: dma_write32(DMA_RESET_FAS366, DMA_CSR); dma_write32(DMA_RST_SCSI, DMA_CSR); @@ -292,7 +282,7 @@ static void sbus_esp_reset_dma(struct esp *esp) if (can_do_sbus64) { esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64; - sbus_set_sbus64(&op->dev, esp->bursts); + sbus_set_sbus64(esp->dev, esp->bursts); } lim = 1000; @@ -356,14 +346,14 @@ static void sbus_esp_dma_drain(struct esp *esp) u32 csr; int lim; - if (esp->dmarev == dvmahme) + if (esp->dma->revision == dvmahme) return; csr = dma_read32(DMA_CSR); if (!(csr & DMA_FIFO_ISDRAIN)) return; - if (esp->dmarev != dvmarev3 && esp->dmarev != dvmaesc1) + if (esp->dma->revision != dvmarev3 && esp->dma->revision != dvmaesc1) dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR); lim = 1000; @@ -379,7 +369,7 @@ static void sbus_esp_dma_drain(struct esp *esp) static void sbus_esp_dma_invalidate(struct esp *esp) { - if (esp->dmarev == dvmahme) { + if (esp->dma->revision == dvmahme) { dma_write32(DMA_RST_SCSI, DMA_CSR); esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | @@ -450,7 +440,7 @@ static void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, else csr &= ~DMA_ST_WRITE; dma_write32(csr, DMA_CSR); - if (esp->dmarev == dvmaesc1) { + if (esp->dma->revision == dvmaesc1) { u32 end = PAGE_ALIGN(addr + dma_count + 16U); dma_write32(end - addr, DMA_COUNT); } @@ -486,8 +476,10 @@ static const struct esp_driver_ops sbus_esp_ops = { .dma_error = sbus_esp_dma_error, }; -static int __devinit esp_sbus_probe_one(struct of_device *op, - struct of_device *espdma, +static int __devinit esp_sbus_probe_one(struct device *dev, + struct sbus_dev *esp_dev, + struct sbus_dev *espdma, + struct sbus_bus *sbus, int hme) { struct scsi_host_template *tpnt = &scsi_esp_template; @@ -505,13 +497,13 @@ static int __devinit esp_sbus_probe_one(struct of_device *op, esp = shost_priv(host); esp->host = host; - esp->dev = op; + esp->dev = esp_dev; esp->ops = &sbus_esp_ops; if (hme) esp->flags |= ESP_FLAG_WIDE_CAPABLE; - err = esp_sbus_setup_dma(esp, espdma); + err = esp_sbus_find_dma(esp, espdma); if (err < 0) goto fail_unlink; @@ -533,15 +525,15 @@ static int __devinit esp_sbus_probe_one(struct of_device *op, * come up with the reset bit set, so make sure that * is clear first. */ - if (esp->dmarev == dvmaesc1) { + if (esp->dma->revision == dvmaesc1) { u32 val = dma_read32(DMA_CSR); dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); } - dev_set_drvdata(&op->dev, esp); + dev_set_drvdata(&esp_dev->ofdev.dev, esp); - err = scsi_esp_register(esp, &op->dev); + err = scsi_esp_register(esp, dev); if (err) goto fail_free_irq; @@ -550,46 +542,41 @@ static int __devinit esp_sbus_probe_one(struct of_device *op, fail_free_irq: free_irq(host->irq, esp); fail_unmap_command_block: - dma_free_coherent(&op->dev, 16, - esp->command_block, - esp->command_block_dma); + sbus_free_consistent(esp->dev, 16, + esp->command_block, + esp->command_block_dma); fail_unmap_regs: - of_iounmap(&op->resource[(hme ? 1 : 0)], esp->regs, SBUS_ESP_REG_SIZE); + sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE); fail_unlink: scsi_host_put(host); fail: return err; } -static int __devinit esp_sbus_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match) { - struct device_node *dma_node = NULL; - struct device_node *dp = op->node; - struct of_device *dma_of = NULL; + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + struct device_node *dp = dev->node; + struct sbus_dev *dma_sdev = NULL; int hme = 0; if (dp->parent && (!strcmp(dp->parent->name, "espdma") || !strcmp(dp->parent->name, "dma"))) - dma_node = dp->parent; + dma_sdev = sdev->parent; else if (!strcmp(dp->name, "SUNW,fas")) { - dma_node = op->node; + dma_sdev = sdev; hme = 1; } - if (dma_node) - dma_of = of_find_device_by_node(dma_node); - if (!dma_of) - return -ENODEV; - return esp_sbus_probe_one(op, dma_of, hme); + return esp_sbus_probe_one(&dev->dev, sdev, dma_sdev, + sdev->bus, hme); } -static int __devexit esp_sbus_remove(struct of_device *op) +static int __devexit esp_sbus_remove(struct of_device *dev) { - struct esp *esp = dev_get_drvdata(&op->dev); - struct of_device *dma_of = esp->dma; + struct esp *esp = dev_get_drvdata(&dev->dev); unsigned int irq = esp->host->irq; - bool is_hme; u32 val; scsi_esp_unregister(esp); @@ -599,25 +586,17 @@ static int __devexit esp_sbus_remove(struct of_device *op) dma_write32(val & ~DMA_INT_ENAB, DMA_CSR); free_irq(irq, esp); - - is_hme = (esp->dmarev == dvmahme); - - dma_free_coherent(&op->dev, 16, - esp->command_block, - esp->command_block_dma); - of_iounmap(&op->resource[(is_hme ? 1 : 0)], esp->regs, - SBUS_ESP_REG_SIZE); - of_iounmap(&dma_of->resource[0], esp->dma_regs, - resource_size(&dma_of->resource[0])); + sbus_free_consistent(esp->dev, 16, + esp->command_block, + esp->command_block_dma); + sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE); scsi_host_put(esp->host); - dev_set_drvdata(&op->dev, NULL); - return 0; } -static const struct of_device_id esp_match[] = { +static struct of_device_id esp_match[] = { { .name = "SUNW,esp", }, @@ -640,7 +619,7 @@ static struct of_platform_driver esp_sbus_driver = { static int __init sunesp_init(void) { - return of_register_driver(&esp_sbus_driver, &of_bus_type); + return of_register_driver(&esp_sbus_driver, &sbus_bus_type); } static void __exit sunesp_exit(void) diff --git a/trunk/drivers/serial/sunhv.c b/trunk/drivers/serial/sunhv.c index a94a2ab4b571..e41766d08035 100644 --- a/trunk/drivers/serial/sunhv.c +++ b/trunk/drivers/serial/sunhv.c @@ -616,7 +616,7 @@ static int __devexit hv_remove(struct of_device *dev) return 0; } -static const struct of_device_id hv_match[] = { +static struct of_device_id hv_match[] = { { .name = "console", .compatible = "qcn", diff --git a/trunk/drivers/serial/sunsab.c b/trunk/drivers/serial/sunsab.c index 0355efe115d9..29b4458abf74 100644 --- a/trunk/drivers/serial/sunsab.c +++ b/trunk/drivers/serial/sunsab.c @@ -1078,7 +1078,7 @@ static int __devexit sab_remove(struct of_device *op) return 0; } -static const struct of_device_id sab_match[] = { +static struct of_device_id sab_match[] = { { .name = "se", }, diff --git a/trunk/drivers/serial/sunsu.c b/trunk/drivers/serial/sunsu.c index a4dc79b1d7ab..a378464f9292 100644 --- a/trunk/drivers/serial/sunsu.c +++ b/trunk/drivers/serial/sunsu.c @@ -1506,7 +1506,7 @@ static int __devexit su_remove(struct of_device *op) return 0; } -static const struct of_device_id su_match[] = { +static struct of_device_id su_match[] = { { .name = "su", }, diff --git a/trunk/drivers/serial/sunzilog.c b/trunk/drivers/serial/sunzilog.c index 45a299f35617..3cb4c8aee13f 100644 --- a/trunk/drivers/serial/sunzilog.c +++ b/trunk/drivers/serial/sunzilog.c @@ -1480,7 +1480,7 @@ static int __devexit zs_remove(struct of_device *op) return 0; } -static const struct of_device_id zs_match[] = { +static struct of_device_id zs_match[] = { { .name = "zs", }, diff --git a/trunk/drivers/video/bw2.c b/trunk/drivers/video/bw2.c index 1e35ba6f18e0..e721644bad74 100644 --- a/trunk/drivers/video/bw2.c +++ b/trunk/drivers/video/bw2.c @@ -372,7 +372,7 @@ static int __devexit bw2_remove(struct of_device *op) return 0; } -static const struct of_device_id bw2_match[] = { +static struct of_device_id bw2_match[] = { { .name = "bwtwo", }, diff --git a/trunk/drivers/video/cg14.c b/trunk/drivers/video/cg14.c index a2d1882791a5..b17e74671779 100644 --- a/trunk/drivers/video/cg14.c +++ b/trunk/drivers/video/cg14.c @@ -589,7 +589,7 @@ static int __devexit cg14_remove(struct of_device *op) return 0; } -static const struct of_device_id cg14_match[] = { +static struct of_device_id cg14_match[] = { { .name = "cgfourteen", }, diff --git a/trunk/drivers/video/cg3.c b/trunk/drivers/video/cg3.c index 99f87fb61d05..3aa7b6cb0268 100644 --- a/trunk/drivers/video/cg3.c +++ b/trunk/drivers/video/cg3.c @@ -456,7 +456,7 @@ static int __devexit cg3_remove(struct of_device *op) return 0; } -static const struct of_device_id cg3_match[] = { +static struct of_device_id cg3_match[] = { { .name = "cgthree", }, diff --git a/trunk/drivers/video/cg6.c b/trunk/drivers/video/cg6.c index 940ec04f0f1b..2f64bb3bd254 100644 --- a/trunk/drivers/video/cg6.c +++ b/trunk/drivers/video/cg6.c @@ -34,11 +34,10 @@ static int cg6_blank(int, struct fb_info *); static void cg6_imageblit(struct fb_info *, const struct fb_image *); static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *); -static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area); static int cg6_sync(struct fb_info *); static int cg6_mmap(struct fb_info *, struct vm_area_struct *); static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long); -static int cg6_pan_display(struct fb_var_screeninfo *, struct fb_info *); +static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area); /* * Frame buffer operations @@ -48,7 +47,6 @@ static struct fb_ops cg6_ops = { .owner = THIS_MODULE, .fb_setcolreg = cg6_setcolreg, .fb_blank = cg6_blank, - .fb_pan_display = cg6_pan_display, .fb_fillrect = cg6_fillrect, .fb_copyarea = cg6_copyarea, .fb_imageblit = cg6_imageblit, @@ -163,7 +161,6 @@ static struct fb_ops cg6_ops = { #define CG6_THC_MISC_INT_ENAB (1 << 5) #define CG6_THC_MISC_INT (1 << 4) #define CG6_THC_MISC_INIT 0x9f -#define CG6_THC_CURSOFF ((65536-32) | ((65536-32) << 16)) /* The contents are unknown */ struct cg6_tec { @@ -283,33 +280,6 @@ static int cg6_sync(struct fb_info *info) return 0; } -static void cg6_switch_from_graph(struct cg6_par *par) -{ - struct cg6_thc __iomem *thc = par->thc; - unsigned long flags; - - spin_lock_irqsave(&par->lock, flags); - - /* Hide the cursor. */ - sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy); - - spin_unlock_irqrestore(&par->lock, flags); -} - -static int cg6_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) -{ - struct cg6_par *par = (struct cg6_par *)info->par; - - /* We just use this to catch switches out of - * graphics mode. - */ - cg6_switch_from_graph(par); - - if (var->xoffset || var->yoffset || var->vmode) - return -EINVAL; - return 0; -} - /** * cg6_fillrect - Draws a rectangle on the screen. * @@ -673,13 +643,9 @@ static void __devinit cg6_chip_init(struct fb_info *info) struct cg6_par *par = (struct cg6_par *)info->par; struct cg6_tec __iomem *tec = par->tec; struct cg6_fbc __iomem *fbc = par->fbc; - struct cg6_thc __iomem *thc = par->thc; u32 rev, conf, mode; int i; - /* Hide the cursor. */ - sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy); - /* Turn off stuff in the Transform Engine. */ sbus_writel(0, &tec->tec_matrix); sbus_writel(0, &tec->tec_clip); @@ -848,7 +814,7 @@ static int __devexit cg6_remove(struct of_device *op) return 0; } -static const struct of_device_id cg6_match[] = { +static struct of_device_id cg6_match[] = { { .name = "cgsix", }, diff --git a/trunk/drivers/video/ffb.c b/trunk/drivers/video/ffb.c index 9dbb9646081f..7992b13ee68f 100644 --- a/trunk/drivers/video/ffb.c +++ b/trunk/drivers/video/ffb.c @@ -1042,7 +1042,7 @@ static int __devexit ffb_remove(struct of_device *op) return 0; } -static const struct of_device_id ffb_match[] = { +static struct of_device_id ffb_match[] = { { .name = "SUNW,ffb", }, diff --git a/trunk/drivers/video/leo.c b/trunk/drivers/video/leo.c index 7c7e8c2da9d9..13fea61d6ae4 100644 --- a/trunk/drivers/video/leo.c +++ b/trunk/drivers/video/leo.c @@ -33,7 +33,6 @@ static int leo_blank(int, struct fb_info *); static int leo_mmap(struct fb_info *, struct vm_area_struct *); static int leo_ioctl(struct fb_info *, unsigned int, unsigned long); -static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *); /* * Frame buffer operations @@ -43,7 +42,6 @@ static struct fb_ops leo_ops = { .owner = THIS_MODULE, .fb_setcolreg = leo_setcolreg, .fb_blank = leo_blank, - .fb_pan_display = leo_pan_display, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, @@ -208,60 +206,6 @@ static void leo_wait(struct leo_lx_krn __iomem *lx_krn) return; } -static void leo_switch_from_graph(struct fb_info *info) -{ - struct leo_par *par = (struct leo_par *) info->par; - struct leo_ld_ss0 __iomem *ss = par->ld_ss0; - struct leo_cursor __iomem *cursor = par->cursor; - unsigned long flags; - u32 val; - - spin_lock_irqsave(&par->lock, flags); - - par->extent = ((info->var.xres - 1) | - ((info->var.yres - 1) << 16)); - - sbus_writel(0xffffffff, &ss->wid); - sbus_writel(0xffff, &ss->wmask); - sbus_writel(0, &ss->vclipmin); - sbus_writel(par->extent, &ss->vclipmax); - sbus_writel(0, &ss->fg); - sbus_writel(0xff000000, &ss->planemask); - sbus_writel(0x310850, &ss->rop); - sbus_writel(0, &ss->widclip); - sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11), - &par->lc_ss0_usr->extent); - sbus_writel(4, &par->lc_ss0_usr->addrspace); - sbus_writel(0x80000000, &par->lc_ss0_usr->fill); - sbus_writel(0, &par->lc_ss0_usr->fontt); - do { - val = sbus_readl(&par->lc_ss0_usr->csr); - } while (val & 0x20000000); - - /* setup screen buffer for cfb_* functions */ - sbus_writel(1, &ss->wid); - sbus_writel(0x00ffffff, &ss->planemask); - sbus_writel(0x310b90, &ss->rop); - sbus_writel(0, &par->lc_ss0_usr->addrspace); - - /* hide cursor */ - sbus_writel(sbus_readl(&cursor->cur_misc) & ~LEO_CUR_ENABLE, &cursor->cur_misc); - - spin_unlock_irqrestore(&par->lock, flags); -} - -static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) -{ - /* We just use this to catch switches out of - * graphics mode. - */ - leo_switch_from_graph(info); - - if (var->xoffset || var->yoffset || var->vmode) - return -EINVAL; - return 0; -} - /** * leo_setcolreg - Optional function. Sets a color register. * @regno: boolean, 0 copy local, 1 get_user() function @@ -510,6 +454,44 @@ static void leo_init_wids(struct fb_info *info) leo_wid_put(info, &wl); } +static void leo_switch_from_graph(struct fb_info *info) +{ + struct leo_par *par = (struct leo_par *) info->par; + struct leo_ld_ss0 __iomem *ss = par->ld_ss0; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&par->lock, flags); + + par->extent = ((info->var.xres - 1) | + ((info->var.yres - 1) << 16)); + + sbus_writel(0xffffffff, &ss->wid); + sbus_writel(0xffff, &ss->wmask); + sbus_writel(0, &ss->vclipmin); + sbus_writel(par->extent, &ss->vclipmax); + sbus_writel(0, &ss->fg); + sbus_writel(0xff000000, &ss->planemask); + sbus_writel(0x310850, &ss->rop); + sbus_writel(0, &ss->widclip); + sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11), + &par->lc_ss0_usr->extent); + sbus_writel(4, &par->lc_ss0_usr->addrspace); + sbus_writel(0x80000000, &par->lc_ss0_usr->fill); + sbus_writel(0, &par->lc_ss0_usr->fontt); + do { + val = sbus_readl(&par->lc_ss0_usr->csr); + } while (val & 0x20000000); + + /* setup screen buffer for cfb_* functions */ + sbus_writel(1, &ss->wid); + sbus_writel(0x00ffffff, &ss->planemask); + sbus_writel(0x310b90, &ss->rop); + sbus_writel(0, &par->lc_ss0_usr->addrspace); + + spin_unlock_irqrestore(&par->lock, flags); +} + static void leo_init_hw(struct fb_info *info) { struct leo_par *par = (struct leo_par *) info->par; @@ -659,7 +641,7 @@ static int __devexit leo_remove(struct of_device *op) return 0; } -static const struct of_device_id leo_match[] = { +static struct of_device_id leo_match[] = { { .name = "SUNW,leo", }, diff --git a/trunk/drivers/video/p9100.c b/trunk/drivers/video/p9100.c index 7000f2cd5854..9e903454ffc1 100644 --- a/trunk/drivers/video/p9100.c +++ b/trunk/drivers/video/p9100.c @@ -349,7 +349,7 @@ static int __devexit p9100_remove(struct of_device *op) return 0; } -static const struct of_device_id p9100_match[] = { +static struct of_device_id p9100_match[] = { { .name = "p9100", }, diff --git a/trunk/drivers/video/tcx.c b/trunk/drivers/video/tcx.c index 643afbfe8277..2a03f78bbb0d 100644 --- a/trunk/drivers/video/tcx.c +++ b/trunk/drivers/video/tcx.c @@ -505,7 +505,7 @@ static int __devexit tcx_remove(struct of_device *op) return 0; } -static const struct of_device_id tcx_match[] = { +static struct of_device_id tcx_match[] = { { .name = "SUNW,tcx", }, diff --git a/trunk/drivers/watchdog/Makefile b/trunk/drivers/watchdog/Makefile index 6702d2ef0434..e0ef123fbdea 100644 --- a/trunk/drivers/watchdog/Makefile +++ b/trunk/drivers/watchdog/Makefile @@ -123,9 +123,6 @@ obj-$(CONFIG_SH_WDT) += shwdt.o # SPARC64 Architecture -obj-$(CONFIG_WATCHDOG_RIO) += riowd.o -obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o - # XTENSA Architecture # Architecture Independant diff --git a/trunk/drivers/watchdog/cpwd.c b/trunk/drivers/watchdog/cpwd.c deleted file mode 100644 index 084dfe9cecfb..000000000000 --- a/trunk/drivers/watchdog/cpwd.c +++ /dev/null @@ -1,695 +0,0 @@ -/* cpwd.c - driver implementation for hardware watchdog - * timers found on Sun Microsystems CP1400 and CP1500 boards. - * - * This device supports both the generic Linux watchdog - * interface and Solaris-compatible ioctls as best it is - * able. - * - * NOTE: CP1400 systems appear to have a defective intr_mask - * register on the PLD, preventing the disabling of - * timer interrupts. We use a timer to periodically - * reset 'stopped' watchdogs on affected platforms. - * - * Copyright (c) 2000 Eric Brower (ebrower@usa.net) - * Copyright (C) 2008 David S. Miller - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#define DRIVER_NAME "cpwd" -#define PFX DRIVER_NAME ": " - -#define WD_OBPNAME "watchdog" -#define WD_BADMODEL "SUNW,501-5336" -#define WD_BTIMEOUT (jiffies + (HZ * 1000)) -#define WD_BLIMIT 0xFFFF - -#define WD0_MINOR 212 -#define WD1_MINOR 213 -#define WD2_MINOR 214 - -/* Internal driver definitions. */ -#define WD0_ID 0 -#define WD1_ID 1 -#define WD2_ID 2 -#define WD_NUMDEVS 3 - -#define WD_INTR_OFF 0 -#define WD_INTR_ON 1 - -#define WD_STAT_INIT 0x01 /* Watchdog timer is initialized */ -#define WD_STAT_BSTOP 0x02 /* Watchdog timer is brokenstopped */ -#define WD_STAT_SVCD 0x04 /* Watchdog interrupt occurred */ - -/* Register value definitions - */ -#define WD0_INTR_MASK 0x01 /* Watchdog device interrupt masks */ -#define WD1_INTR_MASK 0x02 -#define WD2_INTR_MASK 0x04 - -#define WD_S_RUNNING 0x01 /* Watchdog device status running */ -#define WD_S_EXPIRED 0x02 /* Watchdog device status expired */ - -struct cpwd { - void __iomem *regs; - spinlock_t lock; - - unsigned int irq; - - unsigned long timeout; - bool enabled; - bool reboot; - bool broken; - bool initialized; - - struct { - struct miscdevice misc; - void __iomem *regs; - u8 intr_mask; - u8 runstatus; - u16 timeout; - } devs[WD_NUMDEVS]; -}; - -static struct cpwd *cpwd_device; - -/* Sun uses Altera PLD EPF8820ATC144-4 - * providing three hardware watchdogs: - * - * 1) RIC - sends an interrupt when triggered - * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU - * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board - * - *** Timer register block definition (struct wd_timer_regblk) - * - * dcntr and limit registers (halfword access): - * ------------------- - * | 15 | ...| 1 | 0 | - * ------------------- - * |- counter val -| - * ------------------- - * dcntr - Current 16-bit downcounter value. - * When downcounter reaches '0' watchdog expires. - * Reading this register resets downcounter with 'limit' value. - * limit - 16-bit countdown value in 1/10th second increments. - * Writing this register begins countdown with input value. - * Reading from this register does not affect counter. - * NOTES: After watchdog reset, dcntr and limit contain '1' - * - * status register (byte access): - * --------------------------- - * | 7 | ... | 2 | 1 | 0 | - * --------------+------------ - * |- UNUSED -| EXP | RUN | - * --------------------------- - * status- Bit 0 - Watchdog is running - * Bit 1 - Watchdog has expired - * - *** PLD register block definition (struct wd_pld_regblk) - * - * intr_mask register (byte access): - * --------------------------------- - * | 7 | ... | 3 | 2 | 1 | 0 | - * +-------------+------------------ - * |- UNUSED -| WD3 | WD2 | WD1 | - * --------------------------------- - * WD3 - 1 == Interrupt disabled for watchdog 3 - * WD2 - 1 == Interrupt disabled for watchdog 2 - * WD1 - 1 == Interrupt disabled for watchdog 1 - * - * pld_status register (byte access): - * UNKNOWN, MAGICAL MYSTERY REGISTER - * - */ -#define WD_TIMER_REGSZ 16 -#define WD0_OFF 0 -#define WD1_OFF (WD_TIMER_REGSZ * 1) -#define WD2_OFF (WD_TIMER_REGSZ * 2) -#define PLD_OFF (WD_TIMER_REGSZ * 3) - -#define WD_DCNTR 0x00 -#define WD_LIMIT 0x04 -#define WD_STATUS 0x08 - -#define PLD_IMASK (PLD_OFF + 0x00) -#define PLD_STATUS (PLD_OFF + 0x04) - -static struct timer_list cpwd_timer; - -static int wd0_timeout = 0; -static int wd1_timeout = 0; -static int wd2_timeout = 0; - -module_param (wd0_timeout, int, 0); -MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs"); -module_param (wd1_timeout, int, 0); -MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs"); -module_param (wd2_timeout, int, 0); -MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs"); - -MODULE_AUTHOR("Eric Brower "); -MODULE_DESCRIPTION("Hardware watchdog driver for Sun Microsystems CP1400/1500"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("watchdog"); - -static void cpwd_writew(u16 val, void __iomem *addr) -{ - writew(cpu_to_le16(val), addr); -} -static u16 cpwd_readw(void __iomem *addr) -{ - u16 val = readw(addr); - - return le16_to_cpu(val); -} - -static void cpwd_writeb(u8 val, void __iomem *addr) -{ - writeb(val, addr); -} - -static u8 cpwd_readb(void __iomem *addr) -{ - return readb(addr); -} - -/* Enable or disable watchdog interrupts - * Because of the CP1400 defect this should only be - * called during initialzation or by wd_[start|stop]timer() - * - * index - sub-device index, or -1 for 'all' - * enable - non-zero to enable interrupts, zero to disable - */ -static void cpwd_toggleintr(struct cpwd *p, int index, int enable) -{ - unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK); - unsigned char setregs = - (index == -1) ? - (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : - (p->devs[index].intr_mask); - - if (enable == WD_INTR_ON) - curregs &= ~setregs; - else - curregs |= setregs; - - cpwd_writeb(curregs, p->regs + PLD_IMASK); -} - -/* Restarts timer with maximum limit value and - * does not unset 'brokenstop' value. - */ -static void cpwd_resetbrokentimer(struct cpwd *p, int index) -{ - cpwd_toggleintr(p, index, WD_INTR_ON); - cpwd_writew(WD_BLIMIT, p->devs[index].regs + WD_LIMIT); -} - -/* Timer method called to reset stopped watchdogs-- - * because of the PLD bug on CP1400, we cannot mask - * interrupts within the PLD so me must continually - * reset the timers ad infinitum. - */ -static void cpwd_brokentimer(unsigned long data) -{ - struct cpwd *p = (struct cpwd *) data; - int id, tripped = 0; - - /* kill a running timer instance, in case we - * were called directly instead of by kernel timer - */ - if (timer_pending(&cpwd_timer)) - del_timer(&cpwd_timer); - - for (id = 0; id < WD_NUMDEVS; id++) { - if (p->devs[id].runstatus & WD_STAT_BSTOP) { - ++tripped; - cpwd_resetbrokentimer(p, id); - } - } - - if (tripped) { - /* there is at least one timer brokenstopped-- reschedule */ - cpwd_timer.expires = WD_BTIMEOUT; - add_timer(&cpwd_timer); - } -} - -/* Reset countdown timer with 'limit' value and continue countdown. - * This will not start a stopped timer. - */ -static void cpwd_pingtimer(struct cpwd *p, int index) -{ - if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) - cpwd_readw(p->devs[index].regs + WD_DCNTR); -} - -/* Stop a running watchdog timer-- the timer actually keeps - * running, but the interrupt is masked so that no action is - * taken upon expiration. - */ -static void cpwd_stoptimer(struct cpwd *p, int index) -{ - if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) { - cpwd_toggleintr(p, index, WD_INTR_OFF); - - if (p->broken) { - p->devs[index].runstatus |= WD_STAT_BSTOP; - cpwd_brokentimer((unsigned long) p); - } - } -} - -/* Start a watchdog timer with the specified limit value - * If the watchdog is running, it will be restarted with - * the provided limit value. - * - * This function will enable interrupts on the specified - * watchdog. - */ -static void cpwd_starttimer(struct cpwd *p, int index) -{ - if (p->broken) - p->devs[index].runstatus &= ~WD_STAT_BSTOP; - - p->devs[index].runstatus &= ~WD_STAT_SVCD; - - cpwd_writew(p->devs[index].timeout, p->devs[index].regs + WD_LIMIT); - cpwd_toggleintr(p, index, WD_INTR_ON); -} - -static int cpwd_getstatus(struct cpwd *p, int index) -{ - unsigned char stat = cpwd_readb(p->devs[index].regs + WD_STATUS); - unsigned char intr = cpwd_readb(p->devs[index].regs + PLD_IMASK); - unsigned char ret = WD_STOPPED; - - /* determine STOPPED */ - if (!stat) - return ret; - - /* determine EXPIRED vs FREERUN vs RUNNING */ - else if (WD_S_EXPIRED & stat) { - ret = WD_EXPIRED; - } else if(WD_S_RUNNING & stat) { - if (intr & p->devs[index].intr_mask) { - ret = WD_FREERUN; - } else { - /* Fudge WD_EXPIRED status for defective CP1400-- - * IF timer is running - * AND brokenstop is set - * AND an interrupt has been serviced - * we are WD_EXPIRED. - * - * IF timer is running - * AND brokenstop is set - * AND no interrupt has been serviced - * we are WD_FREERUN. - */ - if (p->broken && - (p->devs[index].runstatus & WD_STAT_BSTOP)) { - if (p->devs[index].runstatus & WD_STAT_SVCD) { - ret = WD_EXPIRED; - } else { - /* we could as well pretend we are expired */ - ret = WD_FREERUN; - } - } else { - ret = WD_RUNNING; - } - } - } - - /* determine SERVICED */ - if (p->devs[index].runstatus & WD_STAT_SVCD) - ret |= WD_SERVICED; - - return(ret); -} - -static irqreturn_t cpwd_interrupt(int irq, void *dev_id) -{ - struct cpwd *p = dev_id; - - /* Only WD0 will interrupt-- others are NMI and we won't - * see them here.... - */ - spin_lock_irq(&p->lock); - - cpwd_stoptimer(p, WD0_ID); - p->devs[WD0_ID].runstatus |= WD_STAT_SVCD; - - spin_unlock_irq(&p->lock); - - return IRQ_HANDLED; -} - -static int cpwd_open(struct inode *inode, struct file *f) -{ - struct cpwd *p = cpwd_device; - - lock_kernel(); - switch(iminor(inode)) { - case WD0_MINOR: - case WD1_MINOR: - case WD2_MINOR: - break; - - default: - unlock_kernel(); - return -ENODEV; - } - - /* Register IRQ on first open of device */ - if (!p->initialized) { - if (request_irq(p->irq, &cpwd_interrupt, - IRQF_SHARED, DRIVER_NAME, p)) { - printk(KERN_ERR PFX "Cannot register IRQ %d\n", - p->irq); - unlock_kernel(); - return -EBUSY; - } - p->initialized = true; - } - - unlock_kernel(); - - return nonseekable_open(inode, f); -} - -static int cpwd_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static int cpwd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - static struct watchdog_info info = { - .options = WDIOF_SETTIMEOUT, - .firmware_version = 1, - .identity = DRIVER_NAME, - }; - void __user *argp = (void __user *)arg; - int index = iminor(inode) - WD0_MINOR; - struct cpwd *p = cpwd_device; - int setopt = 0; - - switch (cmd) { - /* Generic Linux IOCTLs */ - case WDIOC_GETSUPPORT: - if (copy_to_user(argp, &info, sizeof(struct watchdog_info))) - return -EFAULT; - break; - - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - if (put_user(0, (int __user *)argp)) - return -EFAULT; - break; - - case WDIOC_KEEPALIVE: - cpwd_pingtimer(p, index); - break; - - case WDIOC_SETOPTIONS: - if (copy_from_user(&setopt, argp, sizeof(unsigned int))) - return -EFAULT; - - if (setopt & WDIOS_DISABLECARD) { - if (p->enabled) - return -EINVAL; - cpwd_stoptimer(p, index); - } else if (setopt & WDIOS_ENABLECARD) { - cpwd_starttimer(p, index); - } else { - return -EINVAL; - } - break; - - /* Solaris-compatible IOCTLs */ - case WIOCGSTAT: - setopt = cpwd_getstatus(p, index); - if (copy_to_user(argp, &setopt, sizeof(unsigned int))) - return -EFAULT; - break; - - case WIOCSTART: - cpwd_starttimer(p, index); - break; - - case WIOCSTOP: - if (p->enabled) - return(-EINVAL); - - cpwd_stoptimer(p, index); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static long cpwd_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int rval = -ENOIOCTLCMD; - - switch (cmd) { - /* solaris ioctls are specific to this driver */ - case WIOCSTART: - case WIOCSTOP: - case WIOCGSTAT: - lock_kernel(); - rval = cpwd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); - unlock_kernel(); - break; - - /* everything else is handled by the generic compat layer */ - default: - break; - } - - return rval; -} - -static ssize_t cpwd_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct inode *inode = file->f_path.dentry->d_inode; - struct cpwd *p = cpwd_device; - int index = iminor(inode); - - if (count) { - cpwd_pingtimer(p, index); - return 1; - } - - return 0; -} - -static ssize_t cpwd_read(struct file * file, char __user *buffer, - size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static const struct file_operations cpwd_fops = { - .owner = THIS_MODULE, - .ioctl = cpwd_ioctl, - .compat_ioctl = cpwd_compat_ioctl, - .open = cpwd_open, - .write = cpwd_write, - .read = cpwd_read, - .release = cpwd_release, -}; - -static int __devinit cpwd_probe(struct of_device *op, - const struct of_device_id *match) -{ - struct device_node *options; - const char *str_prop; - const void *prop_val; - int i, err = -EINVAL; - struct cpwd *p; - - if (cpwd_device) - return -EINVAL; - - p = kzalloc(sizeof(*p), GFP_KERNEL); - err = -ENOMEM; - if (!p) { - printk(KERN_ERR PFX "Unable to allocate struct cpwd.\n"); - goto out; - } - - p->irq = op->irqs[0]; - - spin_lock_init(&p->lock); - - p->regs = of_ioremap(&op->resource[0], 0, - 4 * WD_TIMER_REGSZ, DRIVER_NAME); - if (!p->regs) { - printk(KERN_ERR PFX "Unable to map registers.\n"); - goto out_free; - } - - options = of_find_node_by_path("/options"); - err = -ENODEV; - if (!options) { - printk(KERN_ERR PFX "Unable to find /options node.\n"); - goto out_iounmap; - } - - prop_val = of_get_property(options, "watchdog-enable?", NULL); - p->enabled = (prop_val ? true : false); - - prop_val = of_get_property(options, "watchdog-reboot?", NULL); - p->reboot = (prop_val ? true : false); - - str_prop = of_get_property(options, "watchdog-timeout", NULL); - if (str_prop) - p->timeout = simple_strtoul(str_prop, NULL, 10); - - /* CP1400s seem to have broken PLD implementations-- the - * interrupt_mask register cannot be written, so no timer - * interrupts can be masked within the PLD. - */ - str_prop = of_get_property(op->node, "model", NULL); - p->broken = (str_prop && !strcmp(str_prop, WD_BADMODEL)); - - if (!p->enabled) - cpwd_toggleintr(p, -1, WD_INTR_OFF); - - for (i = 0; i < WD_NUMDEVS; i++) { - static const char *cpwd_names[] = { "RIC", "XIR", "POR" }; - static int *parms[] = { &wd0_timeout, - &wd1_timeout, - &wd2_timeout }; - struct miscdevice *mp = &p->devs[i].misc; - - mp->minor = WD0_MINOR + i; - mp->name = cpwd_names[i]; - mp->fops = &cpwd_fops; - - p->devs[i].regs = p->regs + (i * WD_TIMER_REGSZ); - p->devs[i].intr_mask = (WD0_INTR_MASK << i); - p->devs[i].runstatus &= ~WD_STAT_BSTOP; - p->devs[i].runstatus |= WD_STAT_INIT; - p->devs[i].timeout = p->timeout; - if (*parms[i]) - p->devs[i].timeout = *parms[i]; - - err = misc_register(&p->devs[i].misc); - if (err) { - printk(KERN_ERR "Could not register misc device for " - "dev %d\n", i); - goto out_unregister; - } - } - - if (p->broken) { - init_timer(&cpwd_timer); - cpwd_timer.function = cpwd_brokentimer; - cpwd_timer.data = (unsigned long) p; - cpwd_timer.expires = WD_BTIMEOUT; - - printk(KERN_INFO PFX "PLD defect workaround enabled for " - "model " WD_BADMODEL ".\n"); - } - - dev_set_drvdata(&op->dev, p); - cpwd_device = p; - err = 0; - -out: - return err; - -out_unregister: - for (i--; i >= 0; i--) - misc_deregister(&p->devs[i].misc); - -out_iounmap: - of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ); - -out_free: - kfree(p); - goto out; -} - -static int __devexit cpwd_remove(struct of_device *op) -{ - struct cpwd *p = dev_get_drvdata(&op->dev); - int i; - - for (i = 0; i < 4; i++) { - misc_deregister(&p->devs[i].misc); - - if (!p->enabled) { - cpwd_stoptimer(p, i); - if (p->devs[i].runstatus & WD_STAT_BSTOP) - cpwd_resetbrokentimer(p, i); - } - } - - if (p->broken) - del_timer_sync(&cpwd_timer); - - if (p->initialized) - free_irq(p->irq, p); - - of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ); - kfree(p); - - cpwd_device = NULL; - - return 0; -} - -static const struct of_device_id cpwd_match[] = { - { - .name = "watchdog", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, cpwd_match); - -static struct of_platform_driver cpwd_driver = { - .name = DRIVER_NAME, - .match_table = cpwd_match, - .probe = cpwd_probe, - .remove = __devexit_p(cpwd_remove), -}; - -static int __init cpwd_init(void) -{ - return of_register_driver(&cpwd_driver, &of_bus_type); -} - -static void __exit cpwd_exit(void) -{ - of_unregister_driver(&cpwd_driver); -} - -module_init(cpwd_init); -module_exit(cpwd_exit); diff --git a/trunk/fs/ioctl.c b/trunk/fs/ioctl.c index d152856c371b..33a6b7ecb8b8 100644 --- a/trunk/fs/ioctl.c +++ b/trunk/fs/ioctl.c @@ -226,8 +226,6 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) return error; } -#ifdef CONFIG_BLOCK - #define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits) #define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits); @@ -344,8 +342,6 @@ int generic_block_fiemap(struct inode *inode, } EXPORT_SYMBOL(generic_block_fiemap); -#endif /* CONFIG_BLOCK */ - static int file_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { diff --git a/trunk/include/linux/key.h b/trunk/include/linux/key.h index 1b70e35a71e3..c45c962d1cc5 100644 --- a/trunk/include/linux/key.h +++ b/trunk/include/linux/key.h @@ -299,7 +299,6 @@ extern void key_init(void); #define key_validate(k) 0 #define key_serial(k) 0 #define key_get(k) ({ NULL; }) -#define key_revoke(k) do { } while(0) #define key_put(k) do { } while(0) #define key_ref_put(k) do { } while(0) #define make_key_ref(k, p) ({ NULL; }) diff --git a/trunk/include/linux/rtc/m48t59.h b/trunk/include/linux/rtc/m48t59.h index 6fc961459b4a..e8c7c21ceb1f 100644 --- a/trunk/include/linux/rtc/m48t59.h +++ b/trunk/include/linux/rtc/m48t59.h @@ -18,47 +18,40 @@ /* * M48T59 Register Offset */ -#define M48T59_YEAR 0xf -#define M48T59_MONTH 0xe -#define M48T59_MDAY 0xd /* Day of Month */ -#define M48T59_WDAY 0xc /* Day of Week */ +#define M48T59_YEAR 0x1fff +#define M48T59_MONTH 0x1ffe +#define M48T59_MDAY 0x1ffd /* Day of Month */ +#define M48T59_WDAY 0x1ffc /* Day of Week */ #define M48T59_WDAY_CB 0x20 /* Century Bit */ #define M48T59_WDAY_CEB 0x10 /* Century Enable Bit */ -#define M48T59_HOUR 0xb -#define M48T59_MIN 0xa -#define M48T59_SEC 0x9 -#define M48T59_CNTL 0x8 +#define M48T59_HOUR 0x1ffb +#define M48T59_MIN 0x1ffa +#define M48T59_SEC 0x1ff9 +#define M48T59_CNTL 0x1ff8 #define M48T59_CNTL_READ 0x40 #define M48T59_CNTL_WRITE 0x80 -#define M48T59_WATCHDOG 0x7 -#define M48T59_INTR 0x6 +#define M48T59_WATCHDOG 0x1ff7 +#define M48T59_INTR 0x1ff6 #define M48T59_INTR_AFE 0x80 /* Alarm Interrupt Enable */ #define M48T59_INTR_ABE 0x20 -#define M48T59_ALARM_DATE 0x5 -#define M48T59_ALARM_HOUR 0x4 -#define M48T59_ALARM_MIN 0x3 -#define M48T59_ALARM_SEC 0x2 -#define M48T59_UNUSED 0x1 -#define M48T59_FLAGS 0x0 +#define M48T59_ALARM_DATE 0x1ff5 +#define M48T59_ALARM_HOUR 0x1ff4 +#define M48T59_ALARM_MIN 0x1ff3 +#define M48T59_ALARM_SEC 0x1ff2 +#define M48T59_UNUSED 0x1ff1 +#define M48T59_FLAGS 0x1ff0 #define M48T59_FLAGS_WDT 0x80 /* watchdog timer expired */ #define M48T59_FLAGS_AF 0x40 /* alarm */ #define M48T59_FLAGS_BF 0x10 /* low battery */ -#define M48T59RTC_TYPE_M48T59 0 /* to keep compatibility */ -#define M48T59RTC_TYPE_M48T02 1 -#define M48T59RTC_TYPE_M48T08 2 +#define M48T59_NVRAM_SIZE 0x1ff0 struct m48t59_plat_data { - /* The method to access M48T59 registers */ + /* The method to access M48T59 registers, + * NOTE: The 'ofs' should be 0x00~0x1fff + */ void (*write_byte)(struct device *dev, u32 ofs, u8 val); unsigned char (*read_byte)(struct device *dev, u32 ofs); - - int type; /* RTC model */ - - /* ioaddr mapped externally */ - void __iomem *ioaddr; - /* offset to RTC registers, automatically set according to the type */ - unsigned int offset; }; #endif /* _LINUX_RTC_M48T59_H_ */ diff --git a/trunk/include/sound/core.h b/trunk/include/sound/core.h index 35424a971b7a..e5eec5f73502 100644 --- a/trunk/include/sound/core.h +++ b/trunk/include/sound/core.h @@ -43,6 +43,9 @@ #ifdef CONFIG_PCI struct pci_dev; #endif +#ifdef CONFIG_SBUS +struct sbus_dev; +#endif /* device allocation stuff */ diff --git a/trunk/include/sound/memalloc.h b/trunk/include/sound/memalloc.h index 7ccce94a5255..d787a6b4a101 100644 --- a/trunk/include/sound/memalloc.h +++ b/trunk/include/sound/memalloc.h @@ -37,6 +37,7 @@ struct snd_dma_device { #ifndef snd_dma_pci_data #define snd_dma_pci_data(pci) (&(pci)->dev) #define snd_dma_isa_data() NULL +#define snd_dma_sbus_data(sbus) ((struct device *)(sbus)) #define snd_dma_continuous_data(x) ((struct device *)(unsigned long)(x)) #endif @@ -48,6 +49,7 @@ struct snd_dma_device { #define SNDRV_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */ #define SNDRV_DMA_TYPE_DEV 2 /* generic device continuous */ #define SNDRV_DMA_TYPE_DEV_SG 3 /* generic device SG-buffer */ +#define SNDRV_DMA_TYPE_SBUS 4 /* SBUS continuous */ /* * info for buffer allocation diff --git a/trunk/kernel/sysctl.c b/trunk/kernel/sysctl.c index 1bf369bd4423..50ec0886fa3d 100644 --- a/trunk/kernel/sysctl.c +++ b/trunk/kernel/sysctl.c @@ -118,8 +118,10 @@ extern char modprobe_path[]; extern int sg_big_buff; #endif -#ifdef CONFIG_SPARC -#include +#ifdef __sparc__ +extern char reboot_command []; +extern int stop_a_enabled; +extern int scons_pwroff; #endif #ifdef __hppa__ @@ -413,7 +415,7 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = &proc_dointvec, }, -#ifdef CONFIG_SPARC +#ifdef __sparc__ { .ctl_name = KERN_SPARC_REBOOT, .procname = "reboot-cmd", diff --git a/trunk/net/ipv4/ip_gre.c b/trunk/net/ipv4/ip_gre.c index 85c487b8572b..05ebce2881ef 100644 --- a/trunk/net/ipv4/ip_gre.c +++ b/trunk/net/ipv4/ip_gre.c @@ -1345,7 +1345,7 @@ static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[]) static void ipgre_netlink_parms(struct nlattr *data[], struct ip_tunnel_parm *parms) { - memset(parms, 0, sizeof(*parms)); + memset(parms, 0, sizeof(parms)); parms->iph.protocol = IPPROTO_GRE; diff --git a/trunk/net/netfilter/ipvs/Kconfig b/trunk/net/netfilter/ipvs/Kconfig index 05048e403266..de6004de80bc 100644 --- a/trunk/net/netfilter/ipvs/Kconfig +++ b/trunk/net/netfilter/ipvs/Kconfig @@ -2,8 +2,8 @@ # IP Virtual Server configuration # menuconfig IP_VS - tristate "IP virtual server support" - depends on NET && INET && NETFILTER + tristate "IP virtual server support (EXPERIMENTAL)" + depends on NETFILTER ---help--- IP Virtual Server support will let you build a high-performance virtual server based on cluster of two or more real servers. This diff --git a/trunk/sound/core/memalloc.c b/trunk/sound/core/memalloc.c index 1b3534d67686..a7b46ec72f32 100644 --- a/trunk/sound/core/memalloc.c +++ b/trunk/sound/core/memalloc.c @@ -33,6 +33,9 @@ #include #include #include +#ifdef CONFIG_SBUS +#include +#endif MODULE_AUTHOR("Takashi Iwai , Jaroslav Kysela "); @@ -159,6 +162,39 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, } #endif /* CONFIG_HAS_DMA */ +#ifdef CONFIG_SBUS + +static void *snd_malloc_sbus_pages(struct device *dev, size_t size, + dma_addr_t *dma_addr) +{ + struct sbus_dev *sdev = (struct sbus_dev *)dev; + int pg; + void *res; + + if (WARN_ON(!dma_addr)) + return NULL; + pg = get_order(size); + res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr); + if (res != NULL) + inc_snd_pages(pg); + return res; +} + +static void snd_free_sbus_pages(struct device *dev, size_t size, + void *ptr, dma_addr_t dma_addr) +{ + struct sbus_dev *sdev = (struct sbus_dev *)dev; + int pg; + + if (ptr == NULL) + return; + pg = get_order(size); + dec_snd_pages(pg); + sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr); +} + +#endif /* CONFIG_SBUS */ + /* * * ALSA generic memory management @@ -195,6 +231,11 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->area = snd_malloc_pages(size, (unsigned long)device); dmab->addr = 0; break; +#ifdef CONFIG_SBUS + case SNDRV_DMA_TYPE_SBUS: + dmab->area = snd_malloc_sbus_pages(device, size, &dmab->addr); + break; +#endif #ifdef CONFIG_HAS_DMA case SNDRV_DMA_TYPE_DEV: dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); @@ -265,6 +306,11 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) case SNDRV_DMA_TYPE_CONTINUOUS: snd_free_pages(dmab->area, dmab->bytes); break; +#ifdef CONFIG_SBUS + case SNDRV_DMA_TYPE_SBUS: + snd_free_sbus_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); + break; +#endif #ifdef CONFIG_HAS_DMA case SNDRV_DMA_TYPE_DEV: snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); @@ -373,7 +419,7 @@ static int snd_mem_proc_read(struct seq_file *seq, void *offset) long pages = snd_allocated_pages >> (PAGE_SHIFT-12); struct snd_mem_list *mem; int devno; - static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG" }; + static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" }; mutex_lock(&list_mutex); seq_printf(seq, "pages : %li bytes (%li pages per %likB)\n", diff --git a/trunk/sound/sparc/amd7930.c b/trunk/sound/sparc/amd7930.c index f87933e48812..49acee0c4840 100644 --- a/trunk/sound/sparc/amd7930.c +++ b/trunk/sound/sparc/amd7930.c @@ -1,6 +1,6 @@ /* * Driver for AMD7930 sound chips found on Sparcs. - * Copyright (C) 2002, 2008 David S. Miller + * Copyright (C) 2002 David S. Miller * * Based entirely upon drivers/sbus/audio/amd7930.c which is: * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -35,8 +35,6 @@ #include #include #include -#include -#include #include #include @@ -46,6 +44,7 @@ #include #include +#include #include static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ @@ -336,8 +335,8 @@ struct snd_amd7930 { int pgain; int mgain; - struct of_device *op; unsigned int irq; + unsigned int regs_size; struct snd_amd7930 *next; }; @@ -906,16 +905,13 @@ static int __devinit snd_amd7930_mixer(struct snd_amd7930 *amd) static int snd_amd7930_free(struct snd_amd7930 *amd) { - struct of_device *op = amd->op; - amd7930_idle(amd); if (amd->irq) free_irq(amd->irq, amd); if (amd->regs) - of_iounmap(&op->resource[0], amd->regs, - resource_size(&op->resource[0])); + sbus_iounmap(amd->regs, amd->regs_size); kfree(amd); @@ -934,12 +930,13 @@ static struct snd_device_ops snd_amd7930_dev_ops = { }; static int __devinit snd_amd7930_create(struct snd_card *card, - struct of_device *op, + struct resource *rp, + unsigned int reg_size, int irq, int dev, struct snd_amd7930 **ramd) { - struct snd_amd7930 *amd; unsigned long flags; + struct snd_amd7930 *amd; int err; *ramd = NULL; @@ -949,10 +946,9 @@ static int __devinit snd_amd7930_create(struct snd_card *card, spin_lock_init(&amd->lock); amd->card = card; - amd->op = op; + amd->regs_size = reg_size; - amd->regs = of_ioremap(&op->resource[0], 0, - resource_size(&op->resource[0]), "amd7930"); + amd->regs = sbus_ioremap(rp, 0, amd->regs_size, "amd7930"); if (!amd->regs) { snd_printk("amd7930-%d: Unable to map chip registers.\n", dev); return -EIO; @@ -1001,15 +997,12 @@ static int __devinit snd_amd7930_create(struct snd_card *card, return 0; } -static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit amd7930_attach_common(struct resource *rp, int irq) { - struct resource *rp = &op->resource[0]; static int dev_num; struct snd_card *card; struct snd_amd7930 *amd; - int err, irq; - - irq = op->irqs[0]; + int err; if (dev_num >= SNDRV_CARDS) return -ENODEV; @@ -1030,7 +1023,8 @@ static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_de (unsigned long long)rp->start, irq); - if ((err = snd_amd7930_create(card, op, + if ((err = snd_amd7930_create(card, rp, + (rp->end - rp->start) + 1, irq, dev_num, &amd)) < 0) goto out_err; @@ -1055,7 +1049,43 @@ static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_de return err; } -static const struct of_device_id amd7930_match[] = { +static int __devinit amd7930_obio_attach(struct device_node *dp) +{ + const struct linux_prom_registers *regs; + const struct linux_prom_irqs *irqp; + struct resource res, *rp; + int len; + + irqp = of_get_property(dp, "intr", &len); + if (!irqp) { + snd_printk("%s: Firmware node lacks IRQ property.\n", + dp->full_name); + return -ENODEV; + } + + regs = of_get_property(dp, "reg", &len); + if (!regs) { + snd_printk("%s: Firmware node lacks register property.\n", + dp->full_name); + return -ENODEV; + } + + rp = &res; + rp->start = regs->phys_addr; + rp->end = rp->start + regs->reg_size - 1; + rp->flags = IORESOURCE_IO | (regs->which_io & 0xff); + + return amd7930_attach_common(rp, irqp->pri); +} + +static int __devinit amd7930_sbus_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + + return amd7930_attach_common(&sdev->resource[0], sdev->irqs[0]); +} + +static struct of_device_id amd7930_match[] = { { .name = "audio", }, @@ -1070,7 +1100,20 @@ static struct of_platform_driver amd7930_sbus_driver = { static int __init amd7930_init(void) { - return of_register_driver(&amd7930_sbus_driver, &of_bus_type); + struct device_node *dp; + + /* Try to find the sun4c "audio" node first. */ + dp = of_find_node_by_path("/"); + dp = dp->child; + while (dp) { + if (!strcmp(dp->name, "audio")) + amd7930_obio_attach(dp); + + dp = dp->sibling; + } + + /* Probe each SBUS for amd7930 chips. */ + return of_register_driver(&amd7930_sbus_driver, &sbus_bus_type); } static void __exit amd7930_exit(void) diff --git a/trunk/sound/sparc/cs4231.c b/trunk/sound/sparc/cs4231.c index d44bf98e965e..791d2fb821d1 100644 --- a/trunk/sound/sparc/cs4231.c +++ b/trunk/sound/sparc/cs4231.c @@ -1,6 +1,6 @@ /* * Driver for CS4231 sound chips found on Sparcs. - * Copyright (C) 2002, 2008 David S. Miller + * Copyright (C) 2002 David S. Miller * * Based entirely upon drivers/sbus/audio/cs4231.c which is: * Copyright (C) 1996, 1997, 1998 Derrick J Brashear (shadow@andrew.cmu.edu) @@ -17,8 +17,7 @@ #include #include #include -#include -#include + #include #include @@ -30,12 +29,13 @@ #ifdef CONFIG_SBUS #define SBUS_SUPPORT +#include #endif #if defined(CONFIG_PCI) && defined(CONFIG_SPARC64) #define EBUS_SUPPORT #include -#include +#include #endif static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ @@ -70,6 +70,8 @@ struct cs4231_dma_control { int (*request)(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len); unsigned int (*address)(struct cs4231_dma_control *dma_cont); + void (*preallocate)(struct snd_cs4231 *chip, + struct snd_pcm *pcm); #ifdef EBUS_SUPPORT struct ebus_dma_info ebus_info; #endif @@ -112,12 +114,21 @@ struct snd_cs4231 { struct mutex mce_mutex; /* mutex for mce register */ struct mutex open_mutex; /* mutex for ALSA open/close */ - struct of_device *op; + union { +#ifdef SBUS_SUPPORT + struct sbus_dev *sdev; +#endif +#ifdef EBUS_SUPPORT + struct pci_dev *pdev; +#endif + } dev_u; unsigned int irq[2]; unsigned int regs_size; struct snd_cs4231 *next; }; +static struct snd_cs4231 *cs4231_list; + /* Eventually we can use sound/isa/cs423x/cs4231_lib.c directly, but for * now.... -DaveM */ @@ -256,19 +267,27 @@ static unsigned char snd_cs4231_original_image[32] = static u8 __cs4231_readb(struct snd_cs4231 *cp, void __iomem *reg_addr) { +#ifdef EBUS_SUPPORT if (cp->flags & CS4231_FLAG_EBUS) return readb(reg_addr); else +#endif +#ifdef SBUS_SUPPORT return sbus_readb(reg_addr); +#endif } static void __cs4231_writeb(struct snd_cs4231 *cp, u8 val, void __iomem *reg_addr) { +#ifdef EBUS_SUPPORT if (cp->flags & CS4231_FLAG_EBUS) return writeb(val, reg_addr); else +#endif +#ifdef SBUS_SUPPORT return sbus_writeb(val, reg_addr); +#endif } /* @@ -1239,9 +1258,7 @@ static int __init snd_cs4231_pcm(struct snd_card *card) pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; strcpy(pcm->name, "CS4231"); - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - &chip->op->dev, - 64 * 1024, 128 * 1024); + chip->p_dma.preallocate(chip, pcm); chip->pcm = pcm; @@ -1610,7 +1627,8 @@ static int __init cs4231_attach_finish(struct snd_card *card) if (err < 0) goto out_err; - dev_set_drvdata(&chip->op->dev, chip); + chip->next = cs4231_list; + cs4231_list = chip; dev++; return 0; @@ -1765,19 +1783,24 @@ static unsigned int sbus_dma_addr(struct cs4231_dma_control *dma_cont) return sbus_readl(base->regs + base->dir + APCVA); } +static void sbus_dma_preallocate(struct snd_cs4231 *chip, struct snd_pcm *pcm) +{ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS, + snd_dma_sbus_data(chip->dev_u.sdev), + 64 * 1024, 128 * 1024); +} + /* * Init and exit routines */ static int snd_cs4231_sbus_free(struct snd_cs4231 *chip) { - struct of_device *op = chip->op; - if (chip->irq[0]) free_irq(chip->irq[0], chip); if (chip->port) - of_iounmap(&op->resource[0], chip->port, chip->regs_size); + sbus_iounmap(chip->port, chip->regs_size); return 0; } @@ -1794,7 +1817,7 @@ static struct snd_device_ops snd_cs4231_sbus_dev_ops = { }; static int __init snd_cs4231_sbus_create(struct snd_card *card, - struct of_device *op, + struct sbus_dev *sdev, int dev) { struct snd_cs4231 *chip = card->private_data; @@ -1805,13 +1828,13 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card, spin_lock_init(&chip->p_dma.sbus_info.lock); mutex_init(&chip->mce_mutex); mutex_init(&chip->open_mutex); - chip->op = op; - chip->regs_size = resource_size(&op->resource[0]); + chip->dev_u.sdev = sdev; + chip->regs_size = sdev->reg_addrs[0].reg_size; memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); - chip->port = of_ioremap(&op->resource[0], 0, - chip->regs_size, "cs4231"); + chip->port = sbus_ioremap(&sdev->resource[0], 0, + chip->regs_size, "cs4231"); if (!chip->port) { snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev); return -EIO; @@ -1826,20 +1849,22 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card, chip->p_dma.enable = sbus_dma_enable; chip->p_dma.request = sbus_dma_request; chip->p_dma.address = sbus_dma_addr; + chip->p_dma.preallocate = sbus_dma_preallocate; chip->c_dma.prepare = sbus_dma_prepare; chip->c_dma.enable = sbus_dma_enable; chip->c_dma.request = sbus_dma_request; chip->c_dma.address = sbus_dma_addr; + chip->c_dma.preallocate = sbus_dma_preallocate; - if (request_irq(op->irqs[0], snd_cs4231_sbus_interrupt, + if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt, IRQF_SHARED, "cs4231", chip)) { snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d\n", - dev, op->irqs[0]); + dev, sdev->irqs[0]); snd_cs4231_sbus_free(chip); return -EBUSY; } - chip->irq[0] = op->irqs[0]; + chip->irq[0] = sdev->irqs[0]; if (snd_cs4231_probe(chip) < 0) { snd_cs4231_sbus_free(chip); @@ -1856,9 +1881,9 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card, return 0; } -static int __devinit cs4231_sbus_probe(struct of_device *op, const struct of_device_id *match) +static int __init cs4231_sbus_attach(struct sbus_dev *sdev) { - struct resource *rp = &op->resource[0]; + struct resource *rp = &sdev->resource[0]; struct snd_card *card; int err; @@ -1870,9 +1895,9 @@ static int __devinit cs4231_sbus_probe(struct of_device *op, const struct of_dev card->shortname, rp->flags & 0xffL, (unsigned long long)rp->start, - op->irqs[0]); + sdev->irqs[0]); - err = snd_cs4231_sbus_create(card, op, dev); + err = snd_cs4231_sbus_create(card, sdev, dev); if (err < 0) { snd_card_free(card); return err; @@ -1925,25 +1950,30 @@ static unsigned int _ebus_dma_addr(struct cs4231_dma_control *dma_cont) return ebus_dma_addr(&dma_cont->ebus_info); } +static void _ebus_dma_preallocate(struct snd_cs4231 *chip, struct snd_pcm *pcm) +{ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->dev_u.pdev), + 64*1024, 128*1024); +} + /* * Init and exit routines */ static int snd_cs4231_ebus_free(struct snd_cs4231 *chip) { - struct of_device *op = chip->op; - if (chip->c_dma.ebus_info.regs) { ebus_dma_unregister(&chip->c_dma.ebus_info); - of_iounmap(&op->resource[2], chip->c_dma.ebus_info.regs, 0x10); + iounmap(chip->c_dma.ebus_info.regs); } if (chip->p_dma.ebus_info.regs) { ebus_dma_unregister(&chip->p_dma.ebus_info); - of_iounmap(&op->resource[1], chip->p_dma.ebus_info.regs, 0x10); + iounmap(chip->p_dma.ebus_info.regs); } if (chip->port) - of_iounmap(&op->resource[0], chip->port, 0x10); + iounmap(chip->port); return 0; } @@ -1960,7 +1990,7 @@ static struct snd_device_ops snd_cs4231_ebus_dev_ops = { }; static int __init snd_cs4231_ebus_create(struct snd_card *card, - struct of_device *op, + struct linux_ebus_device *edev, int dev) { struct snd_cs4231 *chip = card->private_data; @@ -1972,35 +2002,35 @@ static int __init snd_cs4231_ebus_create(struct snd_card *card, mutex_init(&chip->mce_mutex); mutex_init(&chip->open_mutex); chip->flags |= CS4231_FLAG_EBUS; - chip->op = op; + chip->dev_u.pdev = edev->bus->self; memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); strcpy(chip->c_dma.ebus_info.name, "cs4231(capture)"); chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback; chip->c_dma.ebus_info.client_cookie = chip; - chip->c_dma.ebus_info.irq = op->irqs[0]; + chip->c_dma.ebus_info.irq = edev->irqs[0]; strcpy(chip->p_dma.ebus_info.name, "cs4231(play)"); chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback; chip->p_dma.ebus_info.client_cookie = chip; - chip->p_dma.ebus_info.irq = op->irqs[1]; + chip->p_dma.ebus_info.irq = edev->irqs[1]; chip->p_dma.prepare = _ebus_dma_prepare; chip->p_dma.enable = _ebus_dma_enable; chip->p_dma.request = _ebus_dma_request; chip->p_dma.address = _ebus_dma_addr; + chip->p_dma.preallocate = _ebus_dma_preallocate; chip->c_dma.prepare = _ebus_dma_prepare; chip->c_dma.enable = _ebus_dma_enable; chip->c_dma.request = _ebus_dma_request; chip->c_dma.address = _ebus_dma_addr; + chip->c_dma.preallocate = _ebus_dma_preallocate; - chip->port = of_ioremap(&op->resource[0], 0, 0x10, "cs4231"); - chip->p_dma.ebus_info.regs = - of_ioremap(&op->resource[1], 0, 0x10, "cs4231_pdma"); - chip->c_dma.ebus_info.regs = - of_ioremap(&op->resource[2], 0, 0x10, "cs4231_cdma"); + chip->port = ioremap(edev->resource[0].start, 0x10); + chip->p_dma.ebus_info.regs = ioremap(edev->resource[1].start, 0x10); + chip->c_dma.ebus_info.regs = ioremap(edev->resource[2].start, 0x10); if (!chip->port || !chip->p_dma.ebus_info.regs || !chip->c_dma.ebus_info.regs) { snd_cs4231_ebus_free(chip); @@ -2048,7 +2078,7 @@ static int __init snd_cs4231_ebus_create(struct snd_card *card, return 0; } -static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_device_id *match) +static int __init cs4231_ebus_attach(struct linux_ebus_device *edev) { struct snd_card *card; int err; @@ -2059,10 +2089,10 @@ static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_dev sprintf(card->longname, "%s at 0x%lx, irq %d", card->shortname, - op->resource[0].start, - op->irqs[0]); + edev->resource[0].start, + edev->irqs[0]); - err = snd_cs4231_ebus_create(card, op, dev); + err = snd_cs4231_ebus_create(card, edev, dev); if (err < 0) { snd_card_free(card); return err; @@ -2072,57 +2102,68 @@ static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_dev } #endif -static int __devinit cs4231_probe(struct of_device *op, const struct of_device_id *match) +static int __init cs4231_init(void) { +#ifdef SBUS_SUPPORT + struct sbus_bus *sbus; + struct sbus_dev *sdev; +#endif #ifdef EBUS_SUPPORT - if (!strcmp(op->node->parent->name, "ebus")) - return cs4231_ebus_probe(op, match); + struct linux_ebus *ebus; + struct linux_ebus_device *edev; #endif + int found; + + found = 0; + #ifdef SBUS_SUPPORT - if (!strcmp(op->node->parent->name, "sbus") || - !strcmp(op->node->parent->name, "sbi")) - return cs4231_sbus_probe(op, match); + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "SUNW,CS4231")) { + if (cs4231_sbus_attach(sdev) == 0) + found++; + } + } #endif - return -ENODEV; -} +#ifdef EBUS_SUPPORT + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + int match = 0; + + if (!strcmp(edev->prom_node->name, "SUNW,CS4231")) { + match = 1; + } else if (!strcmp(edev->prom_node->name, "audio")) { + const char *compat; + + compat = of_get_property(edev->prom_node, + "compatible", NULL); + if (compat && !strcmp(compat, "SUNW,CS4231")) + match = 1; + } -static int __devexit cs4231_remove(struct of_device *op) -{ - struct snd_cs4231 *chip = dev_get_drvdata(&op->dev); + if (match && + cs4231_ebus_attach(edev) == 0) + found++; + } + } +#endif - snd_card_free(chip->card); - return 0; + return (found > 0) ? 0 : -EIO; } -static const struct of_device_id cs4231_match[] = { - { - .name = "SUNW,CS4231", - }, - { - .name = "audio", - .compatible = "SUNW,CS4231", - }, - {}, -}; +static void __exit cs4231_exit(void) +{ + struct snd_cs4231 *p = cs4231_list; -MODULE_DEVICE_TABLE(of, cs4231_match); + while (p != NULL) { + struct snd_cs4231 *next = p->next; -static struct of_platform_driver cs4231_driver = { - .name = "audio", - .match_table = cs4231_match, - .probe = cs4231_probe, - .remove = __devexit_p(cs4231_remove), -}; + snd_card_free(p->card); -static int __init cs4231_init(void) -{ - return of_register_driver(&cs4231_driver, &of_bus_type); -} + p = next; + } -static void __exit cs4231_exit(void) -{ - of_unregister_driver(&cs4231_driver); + cs4231_list = NULL; } module_init(cs4231_init); diff --git a/trunk/sound/sparc/dbri.c b/trunk/sound/sparc/dbri.c index c257ad8bdfbc..c534a2a849fa 100644 --- a/trunk/sound/sparc/dbri.c +++ b/trunk/sound/sparc/dbri.c @@ -57,7 +57,6 @@ #include #include #include -#include #include #include @@ -67,7 +66,7 @@ #include #include -#include +#include #include MODULE_AUTHOR("Rudolf Koenig, Brent Baccala and Martin Habets"); @@ -298,7 +297,7 @@ struct dbri_streaminfo { /* This structure holds the information for both chips (DBRI & CS4215) */ struct snd_dbri { int regs_size, irq; /* Needed for unload */ - struct of_device *op; /* OF device info */ + struct sbus_dev *sdev; /* SBUS device info */ spinlock_t lock; struct dbri_dma *dma; /* Pointer to our DMA block */ @@ -2094,15 +2093,14 @@ static int snd_dbri_hw_params(struct snd_pcm_substream *substream, */ if (info->dvma_buffer == 0) { if (DBRI_STREAMNO(substream) == DBRI_PLAY) - direction = DMA_TO_DEVICE; + direction = SBUS_DMA_TODEVICE; else - direction = DMA_FROM_DEVICE; + direction = SBUS_DMA_FROMDEVICE; - info->dvma_buffer = - dma_map_single(&dbri->op->dev, - runtime->dma_area, - params_buffer_bytes(hw_params), - direction); + info->dvma_buffer = sbus_map_single(dbri->sdev, + runtime->dma_area, + params_buffer_bytes(hw_params), + direction); } direction = params_buffer_bytes(hw_params); @@ -2123,12 +2121,12 @@ static int snd_dbri_hw_free(struct snd_pcm_substream *substream) */ if (info->dvma_buffer) { if (DBRI_STREAMNO(substream) == DBRI_PLAY) - direction = DMA_TO_DEVICE; + direction = SBUS_DMA_TODEVICE; else - direction = DMA_FROM_DEVICE; + direction = SBUS_DMA_FROMDEVICE; - dma_unmap_single(&dbri->op->dev, info->dvma_buffer, - substream->runtime->buffer_size, direction); + sbus_unmap_single(dbri->sdev, info->dvma_buffer, + substream->runtime->buffer_size, direction); info->dvma_buffer = 0; } if (info->pipe != -1) { @@ -2521,32 +2519,31 @@ static void __devinit snd_dbri_proc(struct snd_card *card) static void snd_dbri_free(struct snd_dbri *dbri); static int __devinit snd_dbri_create(struct snd_card *card, - struct of_device *op, - int irq, int dev) + struct sbus_dev *sdev, + int irq, int dev) { struct snd_dbri *dbri = card->private_data; int err; spin_lock_init(&dbri->lock); - dbri->op = op; + dbri->sdev = sdev; dbri->irq = irq; - dbri->dma = dma_alloc_coherent(&op->dev, - sizeof(struct dbri_dma), - &dbri->dma_dvma, GFP_ATOMIC); + dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma), + &dbri->dma_dvma); memset((void *)dbri->dma, 0, sizeof(struct dbri_dma)); dprintk(D_GEN, "DMA Cmd Block 0x%p (0x%08x)\n", dbri->dma, dbri->dma_dvma); /* Map the registers into memory. */ - dbri->regs_size = resource_size(&op->resource[0]); - dbri->regs = of_ioremap(&op->resource[0], 0, - dbri->regs_size, "DBRI Registers"); + dbri->regs_size = sdev->reg_addrs[0].reg_size; + dbri->regs = sbus_ioremap(&sdev->resource[0], 0, + dbri->regs_size, "DBRI Registers"); if (!dbri->regs) { printk(KERN_ERR "DBRI: could not allocate registers\n"); - dma_free_coherent(&op->dev, sizeof(struct dbri_dma), - (void *)dbri->dma, dbri->dma_dvma); + sbus_free_consistent(sdev, sizeof(struct dbri_dma), + (void *)dbri->dma, dbri->dma_dvma); return -EIO; } @@ -2554,9 +2551,9 @@ static int __devinit snd_dbri_create(struct snd_card *card, "DBRI audio", dbri); if (err) { printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq); - of_iounmap(&op->resource[0], dbri->regs, dbri->regs_size); - dma_free_coherent(&op->dev, sizeof(struct dbri_dma), - (void *)dbri->dma, dbri->dma_dvma); + sbus_iounmap(dbri->regs, dbri->regs_size); + sbus_free_consistent(sdev, sizeof(struct dbri_dma), + (void *)dbri->dma, dbri->dma_dvma); return err; } @@ -2580,23 +2577,27 @@ static void snd_dbri_free(struct snd_dbri *dbri) free_irq(dbri->irq, dbri); if (dbri->regs) - of_iounmap(&dbri->op->resource[0], dbri->regs, dbri->regs_size); + sbus_iounmap(dbri->regs, dbri->regs_size); if (dbri->dma) - dma_free_coherent(&dbri->op->dev, - sizeof(struct dbri_dma), - (void *)dbri->dma, dbri->dma_dvma); + sbus_free_consistent(dbri->sdev, sizeof(struct dbri_dma), + (void *)dbri->dma, dbri->dma_dvma); } -static int __devinit dbri_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit dbri_probe(struct of_device *of_dev, + const struct of_device_id *match) { + struct sbus_dev *sdev = to_sbus_device(&of_dev->dev); struct snd_dbri *dbri; + int irq; struct resource *rp; struct snd_card *card; static int dev = 0; - int irq; int err; + dprintk(D_GEN, "DBRI: Found %s in SBUS slot %d\n", + sdev->prom_name, sdev->slot); + if (dev >= SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { @@ -2604,7 +2605,7 @@ static int __devinit dbri_probe(struct of_device *op, const struct of_device_id return -ENOENT; } - irq = op->irqs[0]; + irq = sdev->irqs[0]; if (irq <= 0) { printk(KERN_ERR "DBRI-%d: No IRQ.\n", dev); return -ENODEV; @@ -2617,12 +2618,12 @@ static int __devinit dbri_probe(struct of_device *op, const struct of_device_id strcpy(card->driver, "DBRI"); strcpy(card->shortname, "Sun DBRI"); - rp = &op->resource[0]; + rp = &sdev->resource[0]; sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d", card->shortname, rp->flags & 0xffL, (unsigned long long)rp->start, irq); - err = snd_dbri_create(card, op, irq, dev); + err = snd_dbri_create(card, sdev, irq, dev); if (err < 0) { snd_card_free(card); return err; @@ -2639,7 +2640,7 @@ static int __devinit dbri_probe(struct of_device *op, const struct of_device_id /* /proc file handling */ snd_dbri_proc(card); - dev_set_drvdata(&op->dev, card); + dev_set_drvdata(&of_dev->dev, card); err = snd_card_register(card); if (err < 0) @@ -2647,7 +2648,7 @@ static int __devinit dbri_probe(struct of_device *op, const struct of_device_id printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n", dev, dbri->regs, - dbri->irq, op->node->name[9], dbri->mm.version); + dbri->irq, sdev->prom_name[9], dbri->mm.version); dev++; return 0; @@ -2658,19 +2659,19 @@ static int __devinit dbri_probe(struct of_device *op, const struct of_device_id return err; } -static int __devexit dbri_remove(struct of_device *op) +static int __devexit dbri_remove(struct of_device *dev) { - struct snd_card *card = dev_get_drvdata(&op->dev); + struct snd_card *card = dev_get_drvdata(&dev->dev); snd_dbri_free(card->private_data); snd_card_free(card); - dev_set_drvdata(&op->dev, NULL); + dev_set_drvdata(&dev->dev, NULL); return 0; } -static const struct of_device_id dbri_match[] = { +static struct of_device_id dbri_match[] = { { .name = "SUNW,DBRIe", }, @@ -2692,7 +2693,7 @@ static struct of_platform_driver dbri_sbus_driver = { /* Probe for the dbri chip and then attach the driver. */ static int __init dbri_init(void) { - return of_register_driver(&dbri_sbus_driver, &of_bus_type); + return of_register_driver(&dbri_sbus_driver, &sbus_bus_type); } static void __exit dbri_exit(void)