Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
ext4: fix kconfig typo and extra whitespace
ext4: fix build failure without procfs
ext4: add an option to control error handling on file data
jbd2: don't dirty original metadata buffer on abort
ext4: add checks for errors from jbd2
jbd2: fix error handling for checkpoint io
jbd2: abort when failed to log metadata buffers
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 25efbaf..2443f5b 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -658,11 +658,12 @@
earlyprintk= [X86-32,X86-64,SH,BLACKFIN]
earlyprintk=vga
earlyprintk=serial[,ttySn[,baudrate]]
+ earlyprintk=dbgp
Append ",keep" to not disable it when the real console
takes over.
- Only vga or serial at a time, not both.
+ Only vga or serial or usb debug port at a time.
Currently only ttyS0 and ttyS1 are supported.
@@ -1231,6 +1232,29 @@
or
memmap=0x10000$0x18690000
+ memory_corruption_check=0/1 [X86]
+ Some BIOSes seem to corrupt the first 64k of
+ memory when doing things like suspend/resume.
+ Setting this option will scan the memory
+ looking for corruption. Enabling this will
+ both detect corruption and prevent the kernel
+ from using the memory being corrupted.
+ However, its intended as a diagnostic tool; if
+ repeatable BIOS-originated corruption always
+ affects the same memory, you can use memmap=
+ to prevent the kernel from using that memory.
+
+ memory_corruption_check_size=size [X86]
+ By default it checks for corruption in the low
+ 64k, making this memory unavailable for normal
+ use. Use this parameter to scan for
+ corruption in more or less memory.
+
+ memory_corruption_check_period=seconds [X86]
+ By default it checks for corruption every 60
+ seconds. Use this parameter to check at some
+ other rate. 0 disables periodic checking.
+
memtest= [KNL,X86] Enable memtest
Format: <integer>
range: 0,4 : pattern number
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
index b54cb50..87a7c07a 100644
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
@@ -5073,8 +5073,7 @@
with <constant>SNDRV_DMA_TYPE_CONTINUOUS</constant> type and the
<function>snd_dma_continuous_data(GFP_KERNEL)</function> device pointer,
where <constant>GFP_KERNEL</constant> is the kernel allocation flag to
- use. For the SBUS, <constant>SNDRV_DMA_TYPE_SBUS</constant> and
- <function>snd_dma_sbus_data(sbus_dev)</function> are used instead.
+ use.
For the PCI scatter-gather buffers, use
<constant>SNDRV_DMA_TYPE_DEV_SG</constant> with
<function>snd_dma_pci_data(pci)</function>
diff --git a/Documentation/sparc/sbus_drivers.txt b/Documentation/sparc/sbus_drivers.txt
deleted file mode 100644
index eb1e28a..0000000
--- a/Documentation/sparc/sbus_drivers.txt
+++ /dev/null
@@ -1,309 +0,0 @@
-
- Writing SBUS Drivers
-
- David S. Miller (davem@redhat.com)
-
- The SBUS driver interfaces of the Linux kernel have been
-revamped completely for 2.4.x for several reasons. Foremost were
-performance and complexity concerns. This document details these
-new interfaces and how they are used to write an SBUS device driver.
-
- SBUS drivers need to include <asm/sbus.h> to get access
-to functions and structures described here.
-
- Probing and Detection
-
- Each SBUS device inside the machine is described by a
-structure called "struct sbus_dev". Likewise, each SBUS bus
-found in the system is described by a "struct sbus_bus". For
-each SBUS bus, the devices underneath are hung in a tree-like
-fashion off of the bus structure.
-
- The SBUS device structure contains enough information
-for you to implement your device probing algorithm and obtain
-the bits necessary to run your device. The most commonly
-used members of this structure, and their typical usage,
-will be detailed below.
-
- Here is a piece of skeleton code for performing a device
-probe in an SBUS driver under Linux:
-
- static int __devinit mydevice_probe_one(struct sbus_dev *sdev)
- {
- struct mysdevice *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
-
- if (!mp)
- return -ENODEV;
-
- ...
- dev_set_drvdata(&sdev->ofdev.dev, mp);
- return 0;
- ...
- }
-
- static int __devinit mydevice_probe(struct of_device *dev,
- const struct of_device_id *match)
- {
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
- return mydevice_probe_one(sdev);
- }
-
- static int __devexit mydevice_remove(struct of_device *dev)
- {
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- struct mydevice *mp = dev_get_drvdata(&dev->dev);
-
- return mydevice_remove_one(sdev, mp);
- }
-
- static struct of_device_id mydevice_match[] = {
- {
- .name = "mydevice",
- },
- {},
- };
-
- MODULE_DEVICE_TABLE(of, mydevice_match);
-
- static struct of_platform_driver mydevice_driver = {
- .match_table = mydevice_match,
- .probe = mydevice_probe,
- .remove = __devexit_p(mydevice_remove),
- .driver = {
- .name = "mydevice",
- },
- };
-
- static int __init mydevice_init(void)
- {
- return of_register_driver(&mydevice_driver, &sbus_bus_type);
- }
-
- static void __exit mydevice_exit(void)
- {
- of_unregister_driver(&mydevice_driver);
- }
-
- module_init(mydevice_init);
- module_exit(mydevice_exit);
-
- The mydevice_match table is a series of entries which
-describes what SBUS devices your driver is meant for. In the
-simplest case you specify a string for the 'name' field. Every
-SBUS device with a 'name' property matching your string will
-be passed one-by-one to your .probe method.
-
- You should store away your device private state structure
-pointer in the drvdata area so that you can retrieve it later on
-in your .remove method.
-
- Any memory allocated, registers mapped, IRQs registered,
-etc. must be undone by your .remove method so that all resources
-of your device are released by the time it returns.
-
- You should _NOT_ use the for_each_sbus(), for_each_sbusdev(),
-and for_all_sbusdev() interfaces. They are deprecated, will be
-removed, and no new driver should reference them ever.
-
- Mapping and Accessing I/O Registers
-
- Each SBUS device structure contains an array of descriptors
-which describe each register set. We abuse struct resource for that.
-They each correspond to the "reg" properties provided by the OBP firmware.
-
- Before you can access your device's registers you must map
-them. And later if you wish to shutdown your driver (for module
-unload or similar) you must unmap them. You must treat them as
-a resource, which you allocate (map) before using and free up
-(unmap) when you are done with it.
-
- The mapping information is stored in an opaque value
-typed as an "unsigned long". This is the type of the return value
-of the mapping interface, and the arguments to the unmapping
-interface. Let's say you want to map the first set of registers.
-Perhaps part of your driver software state structure looks like:
-
- struct mydevice {
- unsigned long control_regs;
- ...
- struct sbus_dev *sdev;
- ...
- };
-
- At initialization time you then use the sbus_ioremap
-interface to map in your registers, like so:
-
- static void init_one_mydevice(struct sbus_dev *sdev)
- {
- struct mydevice *mp;
- ...
-
- mp->control_regs = sbus_ioremap(&sdev->resource[0], 0,
- CONTROL_REGS_SIZE, "mydevice regs");
- if (!mp->control_regs) {
- /* Failure, cleanup and return. */
- }
- }
-
- Second argument to sbus_ioremap is an offset for
-cranky devices with broken OBP PROM. The sbus_ioremap uses only
-a start address and flags from the resource structure.
-Therefore it is possible to use the same resource to map
-several sets of registers or even to fabricate a resource
-structure if driver gets physical address from some private place.
-This practice is discouraged though. Use whatever OBP PROM
-provided to you.
-
- And here is how you might unmap these registers later at
-driver shutdown or module unload time, using the sbus_iounmap
-interface:
-
- static void mydevice_unmap_regs(struct mydevice *mp)
- {
- sbus_iounmap(mp->control_regs, CONTROL_REGS_SIZE);
- }
-
- Finally, to actually access your registers there are 6
-interface routines at your disposal. Accesses are byte (8 bit),
-word (16 bit), or longword (32 bit) sized. Here they are:
-
- u8 sbus_readb(unsigned long reg) /* read byte */
- u16 sbus_readw(unsigned long reg) /* read word */
- u32 sbus_readl(unsigned long reg) /* read longword */
- void sbus_writeb(u8 value, unsigned long reg) /* write byte */
- void sbus_writew(u16 value, unsigned long reg) /* write word */
- void sbus_writel(u32 value, unsigned long reg) /* write longword */
-
- So, let's say your device has a control register of some sort
-at offset zero. The following might implement resetting your device:
-
- #define CONTROL 0x00UL
-
- #define CONTROL_RESET 0x00000001 /* Reset hardware */
-
- static void mydevice_reset(struct mydevice *mp)
- {
- sbus_writel(CONTROL_RESET, mp->regs + CONTROL);
- }
-
- Or perhaps there is a data port register at an offset of
-16 bytes which allows you to read bytes from a fifo in the device:
-
- #define DATA 0x10UL
-
- static u8 mydevice_get_byte(struct mydevice *mp)
- {
- return sbus_readb(mp->regs + DATA);
- }
-
- It's pretty straightforward, and clueful readers may have
-noticed that these interfaces mimick the PCI interfaces of the
-Linux kernel. This was not by accident.
-
- WARNING:
-
- DO NOT try to treat these opaque register mapping
- values as a memory mapped pointer to some structure
- which you can dereference.
-
- It may be memory mapped, it may not be. In fact it
- could be a physical address, or it could be the time
- of day xor'd with 0xdeadbeef. :-)
-
- Whatever it is, it's an implementation detail. The
- interface was done this way to shield the driver
- author from such complexities.
-
- Doing DVMA
-
- SBUS devices can perform DMA transactions in a way similar
-to PCI but dissimilar to ISA, e.g. DMA masters supply address.
-In contrast to PCI, however, that address (a bus address) is
-translated by IOMMU before a memory access is performed and therefore
-it is virtual. Sun calls this procedure DVMA.
-
- Linux supports two styles of using SBUS DVMA: "consistent memory"
-and "streaming DVMA". CPU view of consistent memory chunk is, well,
-consistent with a view of a device. Think of it as an uncached memory.
-Typically this way of doing DVMA is not very fast and drivers use it
-mostly for control blocks or queues. On some CPUs we cannot flush or
-invalidate individual pages or cache lines and doing explicit flushing
-over ever little byte in every control block would be wasteful.
-
-Streaming DVMA is a preferred way to transfer large amounts of data.
-This process works in the following way:
-1. a CPU stops accessing a certain part of memory,
- flushes its caches covering that memory;
-2. a device does DVMA accesses, then posts an interrupt;
-3. CPU invalidates its caches and starts to access the memory.
-
-A single streaming DVMA operation can touch several discontiguous
-regions of a virtual bus address space. This is called a scatter-gather
-DVMA.
-
-[TBD: Why do not we neither Solaris attempt to map disjoint pages
-into a single virtual chunk with the help of IOMMU, so that non SG
-DVMA masters would do SG? It'd be very helpful for RAID.]
-
- In order to perform a consistent DVMA a driver does something
-like the following:
-
- char *mem; /* Address in the CPU space */
- u32 busa; /* Address in the SBus space */
-
- mem = (char *) sbus_alloc_consistent(sdev, MYMEMSIZE, &busa);
-
- Then mem is used when CPU accesses this memory and u32
-is fed to the device so that it can do DVMA. This is typically
-done with an sbus_writel() into some device register.
-
- Do not forget to free the DVMA resources once you are done:
-
- sbus_free_consistent(sdev, MYMEMSIZE, mem, busa);
-
- Streaming DVMA is more interesting. First you allocate some
-memory suitable for it or pin down some user pages. Then it all works
-like this:
-
- char *mem = argumen1;
- unsigned int size = argument2;
- u32 busa; /* Address in the SBus space */
-
- *mem = 1; /* CPU can access */
- busa = sbus_map_single(sdev, mem, size);
- if (busa == 0) .......
-
- /* Tell the device to use busa here */
- /* CPU cannot access the memory without sbus_dma_sync_single() */
-
- sbus_unmap_single(sdev, busa, size);
- if (*mem == 0) .... /* CPU can access again */
-
- It is possible to retain mappings and ask the device to
-access data again and again without calling sbus_unmap_single.
-However, CPU caches must be invalidated with sbus_dma_sync_single
-before such access.
-
-[TBD but what about writeback caches here... do we have any?]
-
- There is an equivalent set of functions doing the same thing
-only with several memory segments at once for devices capable of
-scatter-gather transfers. Use the Source, Luke.
-
- Examples
-
- drivers/net/sunhme.c
- This is a complicated driver which illustrates many concepts
-discussed above and plus it handles both PCI and SBUS boards.
-
- drivers/scsi/esp.c
- Check it out for scatter-gather DVMA.
-
- drivers/sbus/char/bpp.c
- A non-DVMA device.
-
- drivers/net/sunlance.c
- Lance driver abuses consistent mappings for data transfer.
-It is a nifty trick which we do not particularly recommend...
-Just check it out and know that it's legal.
diff --git a/MAINTAINERS b/MAINTAINERS
index 587f418..8bf72d3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -390,6 +390,11 @@
T: git://git.kernel.org/pub/scm/linux/kernel/git/joro/linux-2.6-iommu.git
S: Supported
+AMD MICROCODE UPDATE SUPPORT
+P: Peter Oruba
+M: peter.oruba@amd.com
+S: Supported
+
AMS (Apple Motion Sensor) DRIVER
P: Stelian Pop
M: stelian@popies.net
diff --git a/arch/arm/mach-orion5x/include/mach/orion5x.h b/arch/arm/mach-orion5x/include/mach/orion5x.h
index e67c843..9f5ce1c 100644
--- a/arch/arm/mach-orion5x/include/mach/orion5x.h
+++ b/arch/arm/mach-orion5x/include/mach/orion5x.h
@@ -157,9 +157,11 @@
#define CPU_CONF ORION5X_BRIDGE_REG(0x100)
#define CPU_CTRL ORION5X_BRIDGE_REG(0x104)
#define CPU_RESET_MASK ORION5X_BRIDGE_REG(0x108)
+#define WDT_RESET 0x0002
#define CPU_SOFT_RESET ORION5X_BRIDGE_REG(0x10c)
#define POWER_MNG_CTRL_REG ORION5X_BRIDGE_REG(0x11C)
#define BRIDGE_CAUSE ORION5X_BRIDGE_REG(0x110)
+#define WDT_INT_REQ 0x0008
#define BRIDGE_MASK ORION5X_BRIDGE_REG(0x114)
#define BRIDGE_INT_TIMER0 0x0002
#define BRIDGE_INT_TIMER1 0x0004
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index a716ecd..97187fa 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -441,16 +441,8 @@
#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
-#ifdef CONFIG_ARCH_OMAP24XX
-#define OMAP_WDT_BASE 0x48022000
-#else
-#define OMAP_WDT_BASE 0xfffeb000
-#endif
-
static struct resource wdt_resources[] = {
{
- .start = OMAP_WDT_BASE,
- .end = OMAP_WDT_BASE + 0x4f,
.flags = IORESOURCE_MEM,
},
};
@@ -464,6 +456,19 @@
static void omap_init_wdt(void)
{
+ if (cpu_is_omap16xx())
+ wdt_resources[0].start = 0xfffeb000;
+ else if (cpu_is_omap2420())
+ wdt_resources[0].start = 0x48022000; /* WDT2 */
+ else if (cpu_is_omap2430())
+ wdt_resources[0].start = 0x49016000; /* WDT2 */
+ else if (cpu_is_omap343x())
+ wdt_resources[0].start = 0x48314000; /* WDT2 */
+ else
+ return;
+
+ wdt_resources[0].end = wdt_resources[0].start + 0x4f;
+
(void) platform_device_register(&omap_wdt_device);
}
#else
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index b8286f1ce..6c54580 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -9,6 +9,7 @@
*/
#include <linux/clk.h>
#include <linux/etherdevice.h>
+#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
@@ -53,8 +54,11 @@
};
static struct mci_platform_data __initdata mci0_data = {
- .detect_pin = GPIO_PIN_PC(25),
- .wp_pin = GPIO_PIN_PE(0),
+ .slot[0] = {
+ .bus_width = 4,
+ .detect_pin = GPIO_PIN_PC(25),
+ .wp_pin = GPIO_PIN_PE(0),
+ },
};
/*
@@ -190,7 +194,7 @@
* PB28/EXTINT3 doesn't; it should be SMBALERT# (for PMBus),
* but it's not available off-board.
*/
- at32_select_periph(GPIO_PIN_PB(28), 0, AT32_GPIOF_PULLUP);
+ at32_select_periph(GPIO_PIOB_BASE, 1 << 28, 0, AT32_GPIOF_PULLUP);
at32_select_gpio(i2c_gpio_data.sda_pin,
AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
at32_select_gpio(i2c_gpio_data.scl_pin,
@@ -204,6 +208,15 @@
static int __init atngw100_arch_init(void)
{
+ /* PB30 is the otherwise unused jumper on the mainboard, with an
+ * external pullup; the jumper grounds it. Use it however you
+ * like, including letting U-Boot or Linux tweak boot sequences.
+ */
+ at32_select_gpio(GPIO_PIN_PB(30), 0);
+ gpio_request(GPIO_PIN_PB(30), "j15");
+ gpio_direction_input(GPIO_PIN_PB(30));
+ gpio_export(GPIO_PIN_PB(30), false);
+
/* set_irq_type() after the arch_initcall for EIC has run, and
* before the I2C subsystem could try using this IRQ.
*/
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index dfc3443..29e5b51 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -232,7 +232,7 @@
goto err_set_clk;
}
- at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+ at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
at73c213_data.dac_clk = gclk;
err_set_clk:
@@ -264,16 +264,20 @@
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+static struct mci_platform_data __initdata mci0_data = {
+ .slot[0] = {
+ .bus_width = 4,
+
/* MMC card detect requires MACB0 *NOT* be used */
#ifdef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
-static struct mci_platform_data __initdata mci0_data = {
- .detect_pin = GPIO_PIN_PC(14), /* gpio30/sdcd */
- .wp_pin = GPIO_PIN_PC(15), /* gpio31/sdwp */
-};
-#define MCI_PDATA &mci0_data
+ .detect_pin = GPIO_PIN_PC(14), /* gpio30/sdcd */
+ .wp_pin = GPIO_PIN_PC(15), /* gpio31/sdwp */
#else
-#define MCI_PDATA NULL
+ .detect_pin = -ENODEV,
+ .wp_pin = -ENODEV,
#endif /* SW6 for sd{cd,wp} routing */
+ },
+};
#endif /* SW2 for MMC signal routing */
@@ -326,13 +330,14 @@
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
#endif
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
- at32_add_device_mci(0, MCI_PDATA);
+ at32_add_device_mci(0, &mci0_data);
#endif
#ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
set_hw_addr(at32_add_device_eth(1, ð_data[1]));
#else
at32_add_device_lcdc(0, &atstk1000_lcdc_data,
- fbmem_start, fbmem_size, 0);
+ fbmem_start, fbmem_size,
+ ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL);
#endif
at32_add_device_usba(0, NULL);
#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
diff --git a/arch/avr32/boards/atstk1000/atstk1003.c b/arch/avr32/boards/atstk1000/atstk1003.c
index 0cf6641..be089d7f 100644
--- a/arch/avr32/boards/atstk1000/atstk1003.c
+++ b/arch/avr32/boards/atstk1000/atstk1003.c
@@ -19,6 +19,7 @@
#include <linux/spi/spi.h>
#include <asm/setup.h>
+#include <asm/atmel-mci.h>
#include <mach/at32ap700x.h>
#include <mach/board.h>
@@ -66,6 +67,16 @@
} };
#endif
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+static struct mci_platform_data __initdata mci0_data = {
+ .slot[0] = {
+ .bus_width = 4,
+ .detect_pin = -ENODEV,
+ .wp_pin = -ENODEV,
+ },
+};
+#endif
+
#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
static void __init atstk1003_setup_extdac(void)
{
@@ -84,7 +95,7 @@
goto err_set_clk;
}
- at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+ at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
at73c213_data.dac_clk = gclk;
err_set_clk:
@@ -154,7 +165,7 @@
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
#endif
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
- at32_add_device_mci(0, NULL);
+ at32_add_device_mci(0, &mci0_data);
#endif
at32_add_device_usba(0, NULL);
#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
diff --git a/arch/avr32/boards/atstk1000/atstk1004.c b/arch/avr32/boards/atstk1000/atstk1004.c
index 50a5273..248ef23 100644
--- a/arch/avr32/boards/atstk1000/atstk1004.c
+++ b/arch/avr32/boards/atstk1000/atstk1004.c
@@ -21,6 +21,7 @@
#include <video/atmel_lcdc.h>
#include <asm/setup.h>
+#include <asm/atmel-mci.h>
#include <mach/at32ap700x.h>
#include <mach/board.h>
@@ -71,6 +72,16 @@
} };
#endif
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+static struct mci_platform_data __initdata mci0_data = {
+ .slot[0] = {
+ .bus_width = 4,
+ .detect_pin = -ENODEV,
+ .wp_pin = -ENODEV,
+ },
+};
+#endif
+
#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
static void __init atstk1004_setup_extdac(void)
{
@@ -89,7 +100,7 @@
goto err_set_clk;
}
- at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+ at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
at73c213_data.dac_clk = gclk;
err_set_clk:
@@ -137,10 +148,11 @@
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
#endif
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
- at32_add_device_mci(0, NULL);
+ at32_add_device_mci(0, &mci0_data);
#endif
at32_add_device_lcdc(0, &atstk1000_lcdc_data,
- fbmem_start, fbmem_size, 0);
+ fbmem_start, fbmem_size,
+ ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL);
at32_add_device_usba(0, NULL);
#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
at32_add_device_ssc(0, ATMEL_SSC_TX);
diff --git a/arch/avr32/include/asm/atmel-mci.h b/arch/avr32/include/asm/atmel-mci.h
index c2ea6e1..59f3fad 100644
--- a/arch/avr32/include/asm/atmel-mci.h
+++ b/arch/avr32/include/asm/atmel-mci.h
@@ -1,9 +1,39 @@
#ifndef __ASM_AVR32_ATMEL_MCI_H
#define __ASM_AVR32_ATMEL_MCI_H
-struct mci_platform_data {
+#define ATMEL_MCI_MAX_NR_SLOTS 2
+
+struct dma_slave;
+
+/**
+ * struct mci_slot_pdata - board-specific per-slot configuration
+ * @bus_width: Number of data lines wired up the slot
+ * @detect_pin: GPIO pin wired to the card detect switch
+ * @wp_pin: GPIO pin wired to the write protect sensor
+ *
+ * If a given slot is not present on the board, @bus_width should be
+ * set to 0. The other fields are ignored in this case.
+ *
+ * Any pins that aren't available should be set to a negative value.
+ *
+ * Note that support for multiple slots is experimental -- some cards
+ * might get upset if we don't get the clock management exactly right.
+ * But in most cases, it should work just fine.
+ */
+struct mci_slot_pdata {
+ unsigned int bus_width;
int detect_pin;
int wp_pin;
};
+/**
+ * struct mci_platform_data - board-specific MMC/SDcard configuration
+ * @dma_slave: DMA slave interface to use in data transfers, or NULL.
+ * @slot: Per-slot configuration data.
+ */
+struct mci_platform_data {
+ struct dma_slave *dma_slave;
+ struct mci_slot_pdata slot[ATMEL_MCI_MAX_NR_SLOTS];
+};
+
#endif /* __ASM_AVR32_ATMEL_MCI_H */
diff --git a/arch/avr32/include/asm/byteorder.h b/arch/avr32/include/asm/byteorder.h
index d77b48b..8e3af02 100644
--- a/arch/avr32/include/asm/byteorder.h
+++ b/arch/avr32/include/asm/byteorder.h
@@ -7,6 +7,9 @@
#include <asm/types.h>
#include <linux/compiler.h>
+#define __BIG_ENDIAN
+#define __SWAB_64_THRU_32__
+
#ifdef __CHECKER__
extern unsigned long __builtin_bswap_32(unsigned long x);
extern unsigned short __builtin_bswap_16(unsigned short x);
@@ -17,15 +20,18 @@
* the result.
*/
#if !(__GNUC__ == 4 && __GNUC_MINOR__ < 2)
-#define __arch__swab32(x) __builtin_bswap_32(x)
-#define __arch__swab16(x) __builtin_bswap_16(x)
+static inline __attribute_const__ __u16 __arch_swab16(__u16 val)
+{
+ return __builtin_bswap_16(val);
+}
+#define __arch_swab16 __arch_swab16
+
+static inline __attribute_const__ __u32 __arch_swab32(__u32 val)
+{
+ return __builtin_bswap_32(val);
+}
+#define __arch_swab32 __arch_swab32
#endif
-#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
-# define __BYTEORDER_HAS_U64__
-# define __SWAB_64_THRU_32__
-#endif
-
-#include <linux/byteorder/big_endian.h>
-
+#include <linux/byteorder.h>
#endif /* __ASM_AVR32_BYTEORDER_H */
diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h
index a520f77..22c97ef 100644
--- a/arch/avr32/include/asm/io.h
+++ b/arch/avr32/include/asm/io.h
@@ -160,6 +160,14 @@
#define readw_relaxed readw
#define readl_relaxed readl
+#define readb_be __raw_readb
+#define readw_be __raw_readw
+#define readl_be __raw_readl
+
+#define writeb_be __raw_writeb
+#define writew_be __raw_writew
+#define writel_be __raw_writel
+
#define __BUILD_MEMORY_STRING(bwl, type) \
static inline void writes##bwl(volatile void __iomem *addr, \
const void *data, unsigned int count) \
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 2c08ac9..134d530 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/fs.h>
+#include <linux/pm.h>
#include <linux/ptrace.h>
#include <linux/reboot.h>
#include <linux/tick.h>
@@ -20,7 +21,7 @@
#include <mach/pm.h>
-void (*pm_power_off)(void) = NULL;
+void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
/*
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index d8e623c..5c70839 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -283,6 +283,25 @@
}
early_param("fbmem", early_parse_fbmem);
+/*
+ * Pick out the memory size. We look for mem=size@start,
+ * where start and size are "size[KkMmGg]"
+ */
+static int __init early_mem(char *p)
+{
+ resource_size_t size, start;
+
+ start = system_ram->start;
+ size = memparse(p, &p);
+ if (*p == '@')
+ start = memparse(p + 1, &p);
+
+ system_ram->start = start;
+ system_ram->end = system_ram->start + size - 1;
+ return 0;
+}
+early_param("mem", early_mem);
+
static int __init parse_tag_core(struct tag *tag)
{
if (tag->hdr.size > 2) {
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index e01dbe4..813b684 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -82,8 +82,9 @@
.num_resources = ARRAY_SIZE(_name##_id##_resource), \
}
-#define select_peripheral(pin, periph, flags) \
- at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
+#define select_peripheral(port, pin_mask, periph, flags) \
+ at32_select_periph(GPIO_##port##_BASE, pin_mask, \
+ GPIO_##periph, flags)
#define DEV_CLK(_name, devname, bus, _index) \
static struct clk devname##_##_name = { \
@@ -871,6 +872,7 @@
struct platform_device *__init at32_add_device_psif(unsigned int id)
{
struct platform_device *pdev;
+ u32 pin_mask;
if (!(id == 0 || id == 1))
return NULL;
@@ -881,20 +883,22 @@
switch (id) {
case 0:
+ pin_mask = (1 << 8) | (1 << 9); /* CLOCK & DATA */
+
if (platform_device_add_resources(pdev, atmel_psif0_resource,
ARRAY_SIZE(atmel_psif0_resource)))
goto err_add_resources;
atmel_psif0_pclk.dev = &pdev->dev;
- select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */
- select_peripheral(PA(9), PERIPH_A, 0); /* DATA */
+ select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
break;
case 1:
+ pin_mask = (1 << 11) | (1 << 12); /* CLOCK & DATA */
+
if (platform_device_add_resources(pdev, atmel_psif1_resource,
ARRAY_SIZE(atmel_psif1_resource)))
goto err_add_resources;
atmel_psif1_pclk.dev = &pdev->dev;
- select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */
- select_peripheral(PB(12), PERIPH_A, 0); /* DATA */
+ select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
break;
default:
return NULL;
@@ -958,26 +962,30 @@
static inline void configure_usart0_pins(void)
{
- select_peripheral(PA(8), PERIPH_B, 0); /* RXD */
- select_peripheral(PA(9), PERIPH_B, 0); /* TXD */
+ u32 pin_mask = (1 << 8) | (1 << 9); /* RXD & TXD */
+
+ select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
}
static inline void configure_usart1_pins(void)
{
- select_peripheral(PA(17), PERIPH_A, 0); /* RXD */
- select_peripheral(PA(18), PERIPH_A, 0); /* TXD */
+ u32 pin_mask = (1 << 17) | (1 << 18); /* RXD & TXD */
+
+ select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
}
static inline void configure_usart2_pins(void)
{
- select_peripheral(PB(26), PERIPH_B, 0); /* RXD */
- select_peripheral(PB(27), PERIPH_B, 0); /* TXD */
+ u32 pin_mask = (1 << 26) | (1 << 27); /* RXD & TXD */
+
+ select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
}
static inline void configure_usart3_pins(void)
{
- select_peripheral(PB(18), PERIPH_B, 0); /* RXD */
- select_peripheral(PB(17), PERIPH_B, 0); /* TXD */
+ u32 pin_mask = (1 << 18) | (1 << 17); /* RXD & TXD */
+
+ select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
}
static struct platform_device *__initdata at32_usarts[4];
@@ -1057,59 +1065,69 @@
at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
{
struct platform_device *pdev;
+ u32 pin_mask;
switch (id) {
case 0:
pdev = &macb0_device;
- select_peripheral(PC(3), PERIPH_A, 0); /* TXD0 */
- select_peripheral(PC(4), PERIPH_A, 0); /* TXD1 */
- select_peripheral(PC(7), PERIPH_A, 0); /* TXEN */
- select_peripheral(PC(8), PERIPH_A, 0); /* TXCK */
- select_peripheral(PC(9), PERIPH_A, 0); /* RXD0 */
- select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
- select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
- select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
- select_peripheral(PC(16), PERIPH_A, 0); /* MDC */
- select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
+ pin_mask = (1 << 3); /* TXD0 */
+ pin_mask |= (1 << 4); /* TXD1 */
+ pin_mask |= (1 << 7); /* TXEN */
+ pin_mask |= (1 << 8); /* TXCK */
+ pin_mask |= (1 << 9); /* RXD0 */
+ pin_mask |= (1 << 10); /* RXD1 */
+ pin_mask |= (1 << 13); /* RXER */
+ pin_mask |= (1 << 15); /* RXDV */
+ pin_mask |= (1 << 16); /* MDC */
+ pin_mask |= (1 << 17); /* MDIO */
if (!data->is_rmii) {
- select_peripheral(PC(0), PERIPH_A, 0); /* COL */
- select_peripheral(PC(1), PERIPH_A, 0); /* CRS */
- select_peripheral(PC(2), PERIPH_A, 0); /* TXER */
- select_peripheral(PC(5), PERIPH_A, 0); /* TXD2 */
- select_peripheral(PC(6), PERIPH_A, 0); /* TXD3 */
- select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
- select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
- select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
- select_peripheral(PC(18), PERIPH_A, 0); /* SPD */
+ pin_mask |= (1 << 0); /* COL */
+ pin_mask |= (1 << 1); /* CRS */
+ pin_mask |= (1 << 2); /* TXER */
+ pin_mask |= (1 << 5); /* TXD2 */
+ pin_mask |= (1 << 6); /* TXD3 */
+ pin_mask |= (1 << 11); /* RXD2 */
+ pin_mask |= (1 << 12); /* RXD3 */
+ pin_mask |= (1 << 14); /* RXCK */
+ pin_mask |= (1 << 18); /* SPD */
}
+
+ select_peripheral(PIOC, pin_mask, PERIPH_A, 0);
+
break;
case 1:
pdev = &macb1_device;
- select_peripheral(PD(13), PERIPH_B, 0); /* TXD0 */
- select_peripheral(PD(14), PERIPH_B, 0); /* TXD1 */
- select_peripheral(PD(11), PERIPH_B, 0); /* TXEN */
- select_peripheral(PD(12), PERIPH_B, 0); /* TXCK */
- select_peripheral(PD(10), PERIPH_B, 0); /* RXD0 */
- select_peripheral(PD(6), PERIPH_B, 0); /* RXD1 */
- select_peripheral(PD(5), PERIPH_B, 0); /* RXER */
- select_peripheral(PD(4), PERIPH_B, 0); /* RXDV */
- select_peripheral(PD(3), PERIPH_B, 0); /* MDC */
- select_peripheral(PD(2), PERIPH_B, 0); /* MDIO */
+ pin_mask = (1 << 13); /* TXD0 */
+ pin_mask |= (1 << 14); /* TXD1 */
+ pin_mask |= (1 << 11); /* TXEN */
+ pin_mask |= (1 << 12); /* TXCK */
+ pin_mask |= (1 << 10); /* RXD0 */
+ pin_mask |= (1 << 6); /* RXD1 */
+ pin_mask |= (1 << 5); /* RXER */
+ pin_mask |= (1 << 4); /* RXDV */
+ pin_mask |= (1 << 3); /* MDC */
+ pin_mask |= (1 << 2); /* MDIO */
+
+ if (!data->is_rmii)
+ pin_mask |= (1 << 15); /* SPD */
+
+ select_peripheral(PIOD, pin_mask, PERIPH_B, 0);
if (!data->is_rmii) {
- select_peripheral(PC(19), PERIPH_B, 0); /* COL */
- select_peripheral(PC(23), PERIPH_B, 0); /* CRS */
- select_peripheral(PC(26), PERIPH_B, 0); /* TXER */
- select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */
- select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */
- select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */
- select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */
- select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */
- select_peripheral(PD(15), PERIPH_B, 0); /* SPD */
+ pin_mask = (1 << 19); /* COL */
+ pin_mask |= (1 << 23); /* CRS */
+ pin_mask |= (1 << 26); /* TXER */
+ pin_mask |= (1 << 27); /* TXD2 */
+ pin_mask |= (1 << 28); /* TXD3 */
+ pin_mask |= (1 << 29); /* RXD2 */
+ pin_mask |= (1 << 30); /* RXD3 */
+ pin_mask |= (1 << 24); /* RXCK */
+
+ select_peripheral(PIOC, pin_mask, PERIPH_B, 0);
}
break;
@@ -1177,23 +1195,28 @@
{ GPIO_PIN_PB(2), GPIO_PIN_PB(3),
GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
struct platform_device *pdev;
+ u32 pin_mask;
switch (id) {
case 0:
pdev = &atmel_spi0_device;
+ pin_mask = (1 << 1) | (1 << 2); /* MOSI & SCK */
+
/* pullup MISO so a level is always defined */
- select_peripheral(PA(0), PERIPH_A, AT32_GPIOF_PULLUP);
- select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */
- select_peripheral(PA(2), PERIPH_A, 0); /* SCK */
+ select_peripheral(PIOA, (1 << 0), PERIPH_A, AT32_GPIOF_PULLUP);
+ select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
at32_spi_setup_slaves(0, b, n, spi0_pins);
break;
case 1:
pdev = &atmel_spi1_device;
+ pin_mask = (1 << 1) | (1 << 5); /* MOSI */
+
/* pullup MISO so a level is always defined */
- select_peripheral(PB(0), PERIPH_B, AT32_GPIOF_PULLUP);
- select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */
- select_peripheral(PB(5), PERIPH_B, 0); /* SCK */
+ select_peripheral(PIOB, (1 << 0), PERIPH_B, AT32_GPIOF_PULLUP);
+ select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
+
at32_spi_setup_slaves(1, b, n, spi1_pins);
break;
@@ -1226,6 +1249,7 @@
unsigned int n)
{
struct platform_device *pdev;
+ u32 pin_mask;
if (id != 0)
return NULL;
@@ -1238,8 +1262,9 @@
ARRAY_SIZE(atmel_twi0_resource)))
goto err_add_resources;
- select_peripheral(PA(6), PERIPH_A, 0); /* SDA */
- select_peripheral(PA(7), PERIPH_A, 0); /* SDL */
+ pin_mask = (1 << 6) | (1 << 7); /* SDA & SDL */
+
+ select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
atmel_twi0_pclk.dev = &pdev->dev;
@@ -1272,10 +1297,16 @@
struct platform_device *__init
at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
{
- struct mci_platform_data _data;
struct platform_device *pdev;
+ struct dw_dma_slave *dws;
+ u32 pioa_mask;
+ u32 piob_mask;
- if (id != 0)
+ if (id != 0 || !data)
+ return NULL;
+
+ /* Must have at least one usable slot */
+ if (!data->slot[0].bus_width && !data->slot[1].bus_width)
return NULL;
pdev = platform_device_alloc("atmel_mci", id);
@@ -1286,28 +1317,80 @@
ARRAY_SIZE(atmel_mci0_resource)))
goto fail;
- if (!data) {
- data = &_data;
- memset(data, -1, sizeof(struct mci_platform_data));
- data->detect_pin = GPIO_PIN_NONE;
- data->wp_pin = GPIO_PIN_NONE;
- }
+ if (data->dma_slave)
+ dws = kmemdup(to_dw_dma_slave(data->dma_slave),
+ sizeof(struct dw_dma_slave), GFP_KERNEL);
+ else
+ dws = kzalloc(sizeof(struct dw_dma_slave), GFP_KERNEL);
+
+ dws->slave.dev = &pdev->dev;
+ dws->slave.dma_dev = &dw_dmac0_device.dev;
+ dws->slave.reg_width = DMA_SLAVE_WIDTH_32BIT;
+ dws->cfg_hi = (DWC_CFGH_SRC_PER(0)
+ | DWC_CFGH_DST_PER(1));
+ dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL
+ | DWC_CFGL_HS_SRC_POL);
+
+ data->dma_slave = &dws->slave;
if (platform_device_add_data(pdev, data,
sizeof(struct mci_platform_data)))
goto fail;
- select_peripheral(PA(10), PERIPH_A, 0); /* CLK */
- select_peripheral(PA(11), PERIPH_A, 0); /* CMD */
- select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
- select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
- select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
- select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
+ /* CLK line is common to both slots */
+ pioa_mask = 1 << 10;
- if (gpio_is_valid(data->detect_pin))
- at32_select_gpio(data->detect_pin, 0);
- if (gpio_is_valid(data->wp_pin))
- at32_select_gpio(data->wp_pin, 0);
+ switch (data->slot[0].bus_width) {
+ case 4:
+ pioa_mask |= 1 << 13; /* DATA1 */
+ pioa_mask |= 1 << 14; /* DATA2 */
+ pioa_mask |= 1 << 15; /* DATA3 */
+ /* fall through */
+ case 1:
+ pioa_mask |= 1 << 11; /* CMD */
+ pioa_mask |= 1 << 12; /* DATA0 */
+
+ if (gpio_is_valid(data->slot[0].detect_pin))
+ at32_select_gpio(data->slot[0].detect_pin, 0);
+ if (gpio_is_valid(data->slot[0].wp_pin))
+ at32_select_gpio(data->slot[0].wp_pin, 0);
+ break;
+ case 0:
+ /* Slot is unused */
+ break;
+ default:
+ goto fail;
+ }
+
+ select_peripheral(PIOA, pioa_mask, PERIPH_A, 0);
+ piob_mask = 0;
+
+ switch (data->slot[1].bus_width) {
+ case 4:
+ piob_mask |= 1 << 8; /* DATA1 */
+ piob_mask |= 1 << 9; /* DATA2 */
+ piob_mask |= 1 << 10; /* DATA3 */
+ /* fall through */
+ case 1:
+ piob_mask |= 1 << 6; /* CMD */
+ piob_mask |= 1 << 7; /* DATA0 */
+ select_peripheral(PIOB, piob_mask, PERIPH_B, 0);
+
+ if (gpio_is_valid(data->slot[1].detect_pin))
+ at32_select_gpio(data->slot[1].detect_pin, 0);
+ if (gpio_is_valid(data->slot[1].wp_pin))
+ at32_select_gpio(data->slot[1].wp_pin, 0);
+ break;
+ case 0:
+ /* Slot is unused */
+ break;
+ default:
+ if (!data->slot[0].bus_width)
+ goto fail;
+
+ data->slot[1].bus_width = 0;
+ break;
+ }
atmel_mci0_pclk.dev = &pdev->dev;
@@ -1353,13 +1436,14 @@
struct platform_device *__init
at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
unsigned long fbmem_start, unsigned long fbmem_len,
- unsigned int pin_config)
+ u64 pin_mask)
{
struct platform_device *pdev;
struct atmel_lcdfb_info *info;
struct fb_monspecs *monspecs;
struct fb_videomode *modedb;
unsigned int modedb_size;
+ u32 portc_mask, portd_mask, porte_mask;
/*
* Do a deep copy of the fb data, monspecs and modedb. Make
@@ -1381,76 +1465,21 @@
case 0:
pdev = &atmel_lcdfb0_device;
- switch (pin_config) {
- case 0:
- select_peripheral(PC(19), PERIPH_A, 0); /* CC */
- select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */
- select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */
- select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */
- select_peripheral(PC(23), PERIPH_A, 0); /* DVAL */
- select_peripheral(PC(24), PERIPH_A, 0); /* MODE */
- select_peripheral(PC(25), PERIPH_A, 0); /* PWR */
- select_peripheral(PC(26), PERIPH_A, 0); /* DATA0 */
- select_peripheral(PC(27), PERIPH_A, 0); /* DATA1 */
- select_peripheral(PC(28), PERIPH_A, 0); /* DATA2 */
- select_peripheral(PC(29), PERIPH_A, 0); /* DATA3 */
- select_peripheral(PC(30), PERIPH_A, 0); /* DATA4 */
- select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */
- select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */
- select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */
- select_peripheral(PD(2), PERIPH_A, 0); /* DATA8 */
- select_peripheral(PD(3), PERIPH_A, 0); /* DATA9 */
- select_peripheral(PD(4), PERIPH_A, 0); /* DATA10 */
- select_peripheral(PD(5), PERIPH_A, 0); /* DATA11 */
- select_peripheral(PD(6), PERIPH_A, 0); /* DATA12 */
- select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */
- select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */
- select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */
- select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
- select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
- select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
- select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
- select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
- select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
- select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
- select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
- break;
- case 1:
- select_peripheral(PE(0), PERIPH_B, 0); /* CC */
- select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */
- select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */
- select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */
- select_peripheral(PE(1), PERIPH_B, 0); /* DVAL */
- select_peripheral(PE(2), PERIPH_B, 0); /* MODE */
- select_peripheral(PC(25), PERIPH_A, 0); /* PWR */
- select_peripheral(PE(3), PERIPH_B, 0); /* DATA0 */
- select_peripheral(PE(4), PERIPH_B, 0); /* DATA1 */
- select_peripheral(PE(5), PERIPH_B, 0); /* DATA2 */
- select_peripheral(PE(6), PERIPH_B, 0); /* DATA3 */
- select_peripheral(PE(7), PERIPH_B, 0); /* DATA4 */
- select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */
- select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */
- select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */
- select_peripheral(PE(8), PERIPH_B, 0); /* DATA8 */
- select_peripheral(PE(9), PERIPH_B, 0); /* DATA9 */
- select_peripheral(PE(10), PERIPH_B, 0); /* DATA10 */
- select_peripheral(PE(11), PERIPH_B, 0); /* DATA11 */
- select_peripheral(PE(12), PERIPH_B, 0); /* DATA12 */
- select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */
- select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */
- select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */
- select_peripheral(PE(13), PERIPH_B, 0); /* DATA16 */
- select_peripheral(PE(14), PERIPH_B, 0); /* DATA17 */
- select_peripheral(PE(15), PERIPH_B, 0); /* DATA18 */
- select_peripheral(PE(16), PERIPH_B, 0); /* DATA19 */
- select_peripheral(PE(17), PERIPH_B, 0); /* DATA20 */
- select_peripheral(PE(18), PERIPH_B, 0); /* DATA21 */
- select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
- select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
- break;
- default:
- goto err_invalid_id;
- }
+ if (pin_mask == 0ULL)
+ /* Default to "full" lcdc control signals and 24bit */
+ pin_mask = ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL;
+
+ /* LCDC on port C */
+ portc_mask = (pin_mask & 0xfff80000) >> 19;
+ select_peripheral(PIOC, portc_mask, PERIPH_A, 0);
+
+ /* LCDC on port D */
+ portd_mask = pin_mask & 0x0003ffff;
+ select_peripheral(PIOD, portd_mask, PERIPH_A, 0);
+
+ /* LCDC on port E */
+ porte_mask = (pin_mask >> 32) & 0x0007ffff;
+ select_peripheral(PIOE, porte_mask, PERIPH_B, 0);
clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
@@ -1499,6 +1528,7 @@
struct platform_device *__init at32_add_device_pwm(u32 mask)
{
struct platform_device *pdev;
+ u32 pin_mask;
if (!mask)
return NULL;
@@ -1514,14 +1544,21 @@
if (platform_device_add_data(pdev, &mask, sizeof(mask)))
goto out_free_pdev;
+ pin_mask = 0;
if (mask & (1 << 0))
- select_peripheral(PA(28), PERIPH_A, 0);
+ pin_mask |= (1 << 28);
if (mask & (1 << 1))
- select_peripheral(PA(29), PERIPH_A, 0);
+ pin_mask |= (1 << 29);
+ if (pin_mask > 0)
+ select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
+ pin_mask = 0;
if (mask & (1 << 2))
- select_peripheral(PA(21), PERIPH_B, 0);
+ pin_mask |= (1 << 21);
if (mask & (1 << 3))
- select_peripheral(PA(22), PERIPH_B, 0);
+ pin_mask |= (1 << 22);
+ if (pin_mask > 0)
+ select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
atmel_pwm0_mck.dev = &pdev->dev;
@@ -1562,52 +1599,65 @@
at32_add_device_ssc(unsigned int id, unsigned int flags)
{
struct platform_device *pdev;
+ u32 pin_mask = 0;
switch (id) {
case 0:
pdev = &ssc0_device;
if (flags & ATMEL_SSC_RF)
- select_peripheral(PA(21), PERIPH_A, 0); /* RF */
+ pin_mask |= (1 << 21); /* RF */
if (flags & ATMEL_SSC_RK)
- select_peripheral(PA(22), PERIPH_A, 0); /* RK */
+ pin_mask |= (1 << 22); /* RK */
if (flags & ATMEL_SSC_TK)
- select_peripheral(PA(23), PERIPH_A, 0); /* TK */
+ pin_mask |= (1 << 23); /* TK */
if (flags & ATMEL_SSC_TF)
- select_peripheral(PA(24), PERIPH_A, 0); /* TF */
+ pin_mask |= (1 << 24); /* TF */
if (flags & ATMEL_SSC_TD)
- select_peripheral(PA(25), PERIPH_A, 0); /* TD */
+ pin_mask |= (1 << 25); /* TD */
if (flags & ATMEL_SSC_RD)
- select_peripheral(PA(26), PERIPH_A, 0); /* RD */
+ pin_mask |= (1 << 26); /* RD */
+
+ if (pin_mask > 0)
+ select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
break;
case 1:
pdev = &ssc1_device;
if (flags & ATMEL_SSC_RF)
- select_peripheral(PA(0), PERIPH_B, 0); /* RF */
+ pin_mask |= (1 << 0); /* RF */
if (flags & ATMEL_SSC_RK)
- select_peripheral(PA(1), PERIPH_B, 0); /* RK */
+ pin_mask |= (1 << 1); /* RK */
if (flags & ATMEL_SSC_TK)
- select_peripheral(PA(2), PERIPH_B, 0); /* TK */
+ pin_mask |= (1 << 2); /* TK */
if (flags & ATMEL_SSC_TF)
- select_peripheral(PA(3), PERIPH_B, 0); /* TF */
+ pin_mask |= (1 << 3); /* TF */
if (flags & ATMEL_SSC_TD)
- select_peripheral(PA(4), PERIPH_B, 0); /* TD */
+ pin_mask |= (1 << 4); /* TD */
if (flags & ATMEL_SSC_RD)
- select_peripheral(PA(5), PERIPH_B, 0); /* RD */
+ pin_mask |= (1 << 5); /* RD */
+
+ if (pin_mask > 0)
+ select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
+
break;
case 2:
pdev = &ssc2_device;
if (flags & ATMEL_SSC_TD)
- select_peripheral(PB(13), PERIPH_A, 0); /* TD */
+ pin_mask |= (1 << 13); /* TD */
if (flags & ATMEL_SSC_RD)
- select_peripheral(PB(14), PERIPH_A, 0); /* RD */
+ pin_mask |= (1 << 14); /* RD */
if (flags & ATMEL_SSC_TK)
- select_peripheral(PB(15), PERIPH_A, 0); /* TK */
+ pin_mask |= (1 << 15); /* TK */
if (flags & ATMEL_SSC_TF)
- select_peripheral(PB(16), PERIPH_A, 0); /* TF */
+ pin_mask |= (1 << 16); /* TF */
if (flags & ATMEL_SSC_RF)
- select_peripheral(PB(17), PERIPH_A, 0); /* RF */
+ pin_mask |= (1 << 17); /* RF */
if (flags & ATMEL_SSC_RK)
- select_peripheral(PB(18), PERIPH_A, 0); /* RK */
+ pin_mask |= (1 << 18); /* RK */
+
+ if (pin_mask > 0)
+ select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
+
break;
default:
return NULL;
@@ -1745,14 +1795,15 @@
unsigned int cs, unsigned int extint)
{
static unsigned int extint_pin_map[4] __initdata = {
- GPIO_PIN_PB(25),
- GPIO_PIN_PB(26),
- GPIO_PIN_PB(27),
- GPIO_PIN_PB(28),
+ (1 << 25),
+ (1 << 26),
+ (1 << 27),
+ (1 << 28),
};
static bool common_pins_initialized __initdata = false;
unsigned int extint_pin;
int ret;
+ u32 pin_mask;
if (extint >= ARRAY_SIZE(extint_pin_map))
return -EINVAL;
@@ -1766,7 +1817,8 @@
if (ret)
return ret;
- select_peripheral(PE(21), PERIPH_A, 0); /* NCS4 -> OE_N */
+ /* NCS4 -> OE_N */
+ select_peripheral(PIOE, (1 << 21), PERIPH_A, 0);
hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF0_ENABLE);
break;
case 5:
@@ -1776,7 +1828,8 @@
if (ret)
return ret;
- select_peripheral(PE(22), PERIPH_A, 0); /* NCS5 -> OE_N */
+ /* NCS5 -> OE_N */
+ select_peripheral(PIOE, (1 << 22), PERIPH_A, 0);
hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF1_ENABLE);
break;
default:
@@ -1784,14 +1837,17 @@
}
if (!common_pins_initialized) {
- select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1 -> CS0_N */
- select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2 -> CS1_N */
- select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW -> DIR */
- select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT <- IORDY */
+ pin_mask = (1 << 19); /* CFCE1 -> CS0_N */
+ pin_mask |= (1 << 20); /* CFCE2 -> CS1_N */
+ pin_mask |= (1 << 23); /* CFRNW -> DIR */
+ pin_mask |= (1 << 24); /* NWAIT <- IORDY */
+
+ select_peripheral(PIOE, pin_mask, PERIPH_A, 0);
+
common_pins_initialized = true;
}
- at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+ select_peripheral(PIOB, extint_pin, PERIPH_A, AT32_GPIOF_DEGLITCH);
pdev->resource[1].start = EIM_IRQ_BASE + extint;
pdev->resource[1].end = pdev->resource[1].start;
@@ -1930,6 +1986,7 @@
{
struct platform_device *pdev;
struct ac97c_platform_data _data;
+ u32 pin_mask;
if (id != 0)
return NULL;
@@ -1956,10 +2013,10 @@
sizeof(struct ac97c_platform_data)))
goto fail;
- select_peripheral(PB(20), PERIPH_B, 0); /* SDO */
- select_peripheral(PB(21), PERIPH_B, 0); /* SYNC */
- select_peripheral(PB(22), PERIPH_B, 0); /* SCLK */
- select_peripheral(PB(23), PERIPH_B, 0); /* SDI */
+ pin_mask = (1 << 20) | (1 << 21); /* SDO & SYNC */
+ pin_mask |= (1 << 22) | (1 << 23); /* SCLK & SDI */
+
+ select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
/* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */
if (data->reset_pin != GPIO_PIN_NONE)
@@ -2001,6 +2058,7 @@
struct platform_device *__init at32_add_device_abdac(unsigned int id)
{
struct platform_device *pdev;
+ u32 pin_mask;
if (id != 0)
return NULL;
@@ -2013,10 +2071,10 @@
ARRAY_SIZE(abdac0_resource)))
goto err_add_resources;
- select_peripheral(PB(20), PERIPH_A, 0); /* DATA1 */
- select_peripheral(PB(21), PERIPH_A, 0); /* DATA0 */
- select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1 */
- select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0 */
+ pin_mask = (1 << 20) | (1 << 22); /* DATA1 & DATAN1 */
+ pin_mask |= (1 << 21) | (1 << 23); /* DATA0 & DATAN0 */
+
+ select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
abdac0_pclk.dev = &pdev->dev;
abdac0_sample_clk.dev = &pdev->dev;
@@ -2073,7 +2131,7 @@
.index = 4,
};
-struct clk *at32_clock_list[] = {
+static __initdata struct clk *init_clocks[] = {
&osc32k,
&osc0,
&osc1,
@@ -2137,7 +2195,6 @@
&gclk3,
&gclk4,
};
-unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
void __init setup_platform(void)
{
@@ -2168,14 +2225,19 @@
genclk_init_parent(&abdac0_sample_clk);
/*
- * Turn on all clocks that have at least one user already, and
- * turn off everything else. We only do this for module
- * clocks, and even though it isn't particularly pretty to
- * check the address of the mode function, it should do the
- * trick...
+ * Build initial dynamic clock list by registering all clocks
+ * from the array.
+ * At the same time, turn on all clocks that have at least one
+ * user already, and turn off everything else. We only do this
+ * for module clocks, and even though it isn't particularly
+ * pretty to check the address of the mode function, it should
+ * do the trick...
*/
- for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
- struct clk *clk = at32_clock_list[i];
+ for (i = 0; i < ARRAY_SIZE(init_clocks); i++) {
+ struct clk *clk = init_clocks[i];
+
+ /* first, register clock */
+ at32_clk_register(clk);
if (clk->users == 0)
continue;
diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c
index 6c27dda..138a00a 100644
--- a/arch/avr32/mach-at32ap/clock.c
+++ b/arch/avr32/mach-at32ap/clock.c
@@ -15,24 +15,40 @@
#include <linux/err.h>
#include <linux/device.h>
#include <linux/string.h>
+#include <linux/list.h>
#include <mach/chip.h>
#include "clock.h"
+/* at32 clock list */
+static LIST_HEAD(at32_clock_list);
+
static DEFINE_SPINLOCK(clk_lock);
+static DEFINE_SPINLOCK(clk_list_lock);
+
+void at32_clk_register(struct clk *clk)
+{
+ spin_lock(&clk_list_lock);
+ /* add the new item to the end of the list */
+ list_add_tail(&clk->list, &at32_clock_list);
+ spin_unlock(&clk_list_lock);
+}
struct clk *clk_get(struct device *dev, const char *id)
{
- int i;
+ struct clk *clk;
- for (i = 0; i < at32_nr_clocks; i++) {
- struct clk *clk = at32_clock_list[i];
+ spin_lock(&clk_list_lock);
- if (clk->dev == dev && strcmp(id, clk->name) == 0)
+ list_for_each_entry(clk, &at32_clock_list, list) {
+ if (clk->dev == dev && strcmp(id, clk->name) == 0) {
+ spin_unlock(&clk_list_lock);
return clk;
+ }
}
+ spin_unlock(&clk_list_lock);
return ERR_PTR(-ENOENT);
}
EXPORT_SYMBOL(clk_get);
@@ -203,8 +219,8 @@
/* cost of this scan is small, but not linear... */
r->nest = nest + NEST_DELTA;
- for (i = 3; i < at32_nr_clocks; i++) {
- clk = at32_clock_list[i];
+
+ list_for_each_entry(clk, &at32_clock_list, list) {
if (clk->parent == parent)
dump_clock(clk, r);
}
@@ -215,6 +231,7 @@
{
struct clkinf r;
int i;
+ struct clk *clk;
/* show all the power manager registers */
seq_printf(s, "MCCTRL = %8x\n", pm_readl(MCCTRL));
@@ -234,14 +251,25 @@
seq_printf(s, "\n");
- /* show clock tree as derived from the three oscillators
- * we "know" are at the head of the list
- */
r.s = s;
r.nest = 0;
- dump_clock(at32_clock_list[0], &r);
- dump_clock(at32_clock_list[1], &r);
- dump_clock(at32_clock_list[2], &r);
+ /* protected from changes on the list while dumping */
+ spin_lock(&clk_list_lock);
+
+ /* show clock tree as derived from the three oscillators */
+ clk = clk_get(NULL, "osc32k");
+ dump_clock(clk, &r);
+ clk_put(clk);
+
+ clk = clk_get(NULL, "osc0");
+ dump_clock(clk, &r);
+ clk_put(clk);
+
+ clk = clk_get(NULL, "osc1");
+ dump_clock(clk, &r);
+ clk_put(clk);
+
+ spin_unlock(&clk_list_lock);
return 0;
}
diff --git a/arch/avr32/mach-at32ap/clock.h b/arch/avr32/mach-at32ap/clock.h
index bb8e1f2..623bf0e 100644
--- a/arch/avr32/mach-at32ap/clock.h
+++ b/arch/avr32/mach-at32ap/clock.h
@@ -12,8 +12,13 @@
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
+#include <linux/list.h>
+
+
+void at32_clk_register(struct clk *clk);
struct clk {
+ struct list_head list; /* linking element */
const char *name; /* Clock name/function */
struct device *dev; /* Device the clock is used by */
struct clk *parent; /* Parent clock, if any */
@@ -25,6 +30,3 @@
u16 users; /* Enabled if non-zero */
u16 index; /* Sibling index */
};
-
-extern struct clk *at32_clock_list[];
-extern unsigned int at32_nr_clocks;
diff --git a/arch/avr32/mach-at32ap/include/mach/at32ap700x.h b/arch/avr32/mach-at32ap/include/mach/at32ap700x.h
index 1e9852d..a77d372 100644
--- a/arch/avr32/mach-at32ap/include/mach/at32ap700x.h
+++ b/arch/avr32/mach-at32ap/include/mach/at32ap700x.h
@@ -83,4 +83,132 @@
#define HMATRIX_BASE 0xfff00800
#define SDRAMC_BASE 0xfff03800
+/* LCDC on port C */
+#define ATMEL_LCDC_PC_CC (1ULL << 19)
+#define ATMEL_LCDC_PC_HSYNC (1ULL << 20)
+#define ATMEL_LCDC_PC_PCLK (1ULL << 21)
+#define ATMEL_LCDC_PC_VSYNC (1ULL << 22)
+#define ATMEL_LCDC_PC_DVAL (1ULL << 23)
+#define ATMEL_LCDC_PC_MODE (1ULL << 24)
+#define ATMEL_LCDC_PC_PWR (1ULL << 25)
+#define ATMEL_LCDC_PC_DATA0 (1ULL << 26)
+#define ATMEL_LCDC_PC_DATA1 (1ULL << 27)
+#define ATMEL_LCDC_PC_DATA2 (1ULL << 28)
+#define ATMEL_LCDC_PC_DATA3 (1ULL << 29)
+#define ATMEL_LCDC_PC_DATA4 (1ULL << 30)
+#define ATMEL_LCDC_PC_DATA5 (1ULL << 31)
+
+/* LCDC on port D */
+#define ATMEL_LCDC_PD_DATA6 (1ULL << 0)
+#define ATMEL_LCDC_PD_DATA7 (1ULL << 1)
+#define ATMEL_LCDC_PD_DATA8 (1ULL << 2)
+#define ATMEL_LCDC_PD_DATA9 (1ULL << 3)
+#define ATMEL_LCDC_PD_DATA10 (1ULL << 4)
+#define ATMEL_LCDC_PD_DATA11 (1ULL << 5)
+#define ATMEL_LCDC_PD_DATA12 (1ULL << 6)
+#define ATMEL_LCDC_PD_DATA13 (1ULL << 7)
+#define ATMEL_LCDC_PD_DATA14 (1ULL << 8)
+#define ATMEL_LCDC_PD_DATA15 (1ULL << 9)
+#define ATMEL_LCDC_PD_DATA16 (1ULL << 10)
+#define ATMEL_LCDC_PD_DATA17 (1ULL << 11)
+#define ATMEL_LCDC_PD_DATA18 (1ULL << 12)
+#define ATMEL_LCDC_PD_DATA19 (1ULL << 13)
+#define ATMEL_LCDC_PD_DATA20 (1ULL << 14)
+#define ATMEL_LCDC_PD_DATA21 (1ULL << 15)
+#define ATMEL_LCDC_PD_DATA22 (1ULL << 16)
+#define ATMEL_LCDC_PD_DATA23 (1ULL << 17)
+
+/* LCDC on port E */
+#define ATMEL_LCDC_PE_CC (1ULL << (32 + 0))
+#define ATMEL_LCDC_PE_DVAL (1ULL << (32 + 1))
+#define ATMEL_LCDC_PE_MODE (1ULL << (32 + 2))
+#define ATMEL_LCDC_PE_DATA0 (1ULL << (32 + 3))
+#define ATMEL_LCDC_PE_DATA1 (1ULL << (32 + 4))
+#define ATMEL_LCDC_PE_DATA2 (1ULL << (32 + 5))
+#define ATMEL_LCDC_PE_DATA3 (1ULL << (32 + 6))
+#define ATMEL_LCDC_PE_DATA4 (1ULL << (32 + 7))
+#define ATMEL_LCDC_PE_DATA8 (1ULL << (32 + 8))
+#define ATMEL_LCDC_PE_DATA9 (1ULL << (32 + 9))
+#define ATMEL_LCDC_PE_DATA10 (1ULL << (32 + 10))
+#define ATMEL_LCDC_PE_DATA11 (1ULL << (32 + 11))
+#define ATMEL_LCDC_PE_DATA12 (1ULL << (32 + 12))
+#define ATMEL_LCDC_PE_DATA16 (1ULL << (32 + 13))
+#define ATMEL_LCDC_PE_DATA17 (1ULL << (32 + 14))
+#define ATMEL_LCDC_PE_DATA18 (1ULL << (32 + 15))
+#define ATMEL_LCDC_PE_DATA19 (1ULL << (32 + 16))
+#define ATMEL_LCDC_PE_DATA20 (1ULL << (32 + 17))
+#define ATMEL_LCDC_PE_DATA21 (1ULL << (32 + 18))
+
+
+#define ATMEL_LCDC(PORT, PIN) (ATMEL_LCDC_##PORT##_##PIN)
+
+
+#define ATMEL_LCDC_PRI_24B_DATA ( \
+ ATMEL_LCDC(PC, DATA0) | ATMEL_LCDC(PC, DATA1) | \
+ ATMEL_LCDC(PC, DATA2) | ATMEL_LCDC(PC, DATA3) | \
+ ATMEL_LCDC(PC, DATA4) | ATMEL_LCDC(PC, DATA5) | \
+ ATMEL_LCDC(PD, DATA6) | ATMEL_LCDC(PD, DATA7) | \
+ ATMEL_LCDC(PD, DATA8) | ATMEL_LCDC(PD, DATA9) | \
+ ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) | \
+ ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA13) | \
+ ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) | \
+ ATMEL_LCDC(PD, DATA16) | ATMEL_LCDC(PD, DATA17) | \
+ ATMEL_LCDC(PD, DATA18) | ATMEL_LCDC(PD, DATA19) | \
+ ATMEL_LCDC(PD, DATA20) | ATMEL_LCDC(PD, DATA21) | \
+ ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23))
+
+#define ATMEL_LCDC_ALT_24B_DATA ( \
+ ATMEL_LCDC(PE, DATA0) | ATMEL_LCDC(PE, DATA1) | \
+ ATMEL_LCDC(PE, DATA2) | ATMEL_LCDC(PE, DATA3) | \
+ ATMEL_LCDC(PE, DATA4) | ATMEL_LCDC(PC, DATA5) | \
+ ATMEL_LCDC(PD, DATA6) | ATMEL_LCDC(PD, DATA7) | \
+ ATMEL_LCDC(PE, DATA8) | ATMEL_LCDC(PE, DATA9) | \
+ ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) | \
+ ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PD, DATA13) | \
+ ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) | \
+ ATMEL_LCDC(PE, DATA16) | ATMEL_LCDC(PE, DATA17) | \
+ ATMEL_LCDC(PE, DATA18) | ATMEL_LCDC(PE, DATA19) | \
+ ATMEL_LCDC(PE, DATA20) | ATMEL_LCDC(PE, DATA21) | \
+ ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23))
+
+#define ATMEL_LCDC_PRI_15B_DATA ( \
+ ATMEL_LCDC(PC, DATA0) | ATMEL_LCDC(PC, DATA1) | \
+ ATMEL_LCDC(PC, DATA2) | ATMEL_LCDC(PC, DATA3) | \
+ ATMEL_LCDC(PC, DATA4) | ATMEL_LCDC(PC, DATA5) | \
+ ATMEL_LCDC(PD, DATA8) | ATMEL_LCDC(PD, DATA9) | \
+ ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) | \
+ ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA16) | \
+ ATMEL_LCDC(PD, DATA17) | ATMEL_LCDC(PD, DATA18) | \
+ ATMEL_LCDC(PD, DATA19) | ATMEL_LCDC(PD, DATA20))
+
+#define ATMEL_LCDC_ALT_15B_DATA ( \
+ ATMEL_LCDC(PE, DATA0) | ATMEL_LCDC(PE, DATA1) | \
+ ATMEL_LCDC(PE, DATA2) | ATMEL_LCDC(PE, DATA3) | \
+ ATMEL_LCDC(PE, DATA4) | ATMEL_LCDC(PC, DATA5) | \
+ ATMEL_LCDC(PE, DATA8) | ATMEL_LCDC(PE, DATA9) | \
+ ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) | \
+ ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PE, DATA16) | \
+ ATMEL_LCDC(PE, DATA17) | ATMEL_LCDC(PE, DATA18) | \
+ ATMEL_LCDC(PE, DATA19) | ATMEL_LCDC(PE, DATA20))
+
+#define ATMEL_LCDC_PRI_CONTROL ( \
+ ATMEL_LCDC(PC, CC) | ATMEL_LCDC(PC, DVAL) | \
+ ATMEL_LCDC(PC, MODE) | ATMEL_LCDC(PC, PWR))
+
+#define ATMEL_LCDC_ALT_CONTROL ( \
+ ATMEL_LCDC(PE, CC) | ATMEL_LCDC(PE, DVAL) | \
+ ATMEL_LCDC(PE, MODE) | ATMEL_LCDC(PC, PWR))
+
+#define ATMEL_LCDC_CONTROL ( \
+ ATMEL_LCDC(PC, HSYNC) | ATMEL_LCDC(PC, VSYNC) | \
+ ATMEL_LCDC(PC, PCLK))
+
+#define ATMEL_LCDC_PRI_24BIT (ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_24B_DATA)
+
+#define ATMEL_LCDC_ALT_24BIT (ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_24B_DATA)
+
+#define ATMEL_LCDC_PRI_15BIT (ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_15B_DATA)
+
+#define ATMEL_LCDC_ALT_15BIT (ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_15B_DATA)
+
#endif /* __ASM_ARCH_AT32AP700X_H__ */
diff --git a/arch/avr32/mach-at32ap/include/mach/board.h b/arch/avr32/mach-at32ap/include/mach/board.h
index e60e907..c48386d 100644
--- a/arch/avr32/mach-at32ap/include/mach/board.h
+++ b/arch/avr32/mach-at32ap/include/mach/board.h
@@ -43,7 +43,7 @@
struct platform_device *
at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
unsigned long fbmem_start, unsigned long fbmem_len,
- unsigned int pin_config);
+ u64 pin_mask);
struct usba_platform_data;
struct platform_device *
diff --git a/arch/avr32/mach-at32ap/include/mach/io.h b/arch/avr32/mach-at32ap/include/mach/io.h
index 4ec6abc..22ea79b 100644
--- a/arch/avr32/mach-at32ap/include/mach/io.h
+++ b/arch/avr32/mach-at32ap/include/mach/io.h
@@ -1,8 +1,7 @@
#ifndef __ASM_AVR32_ARCH_AT32AP_IO_H
#define __ASM_AVR32_ARCH_AT32AP_IO_H
-/* For "bizarre" halfword swapping */
-#include <linux/byteorder/swabb.h>
+#include <linux/swab.h>
#if defined(CONFIG_AP700X_32_BIT_SMC)
# define __swizzle_addr_b(addr) (addr ^ 3UL)
diff --git a/arch/avr32/mach-at32ap/include/mach/portmux.h b/arch/avr32/mach-at32ap/include/mach/portmux.h
index b1abe6b..21c7937 100644
--- a/arch/avr32/mach-at32ap/include/mach/portmux.h
+++ b/arch/avr32/mach-at32ap/include/mach/portmux.h
@@ -21,9 +21,10 @@
#define AT32_GPIOF_DEGLITCH 0x00000008 /* (IN) Filter glitches */
#define AT32_GPIOF_MULTIDRV 0x00000010 /* Enable multidriver option */
-void at32_select_periph(unsigned int pin, unsigned int periph,
- unsigned long flags);
+void at32_select_periph(unsigned int port, unsigned int pin,
+ unsigned int periph, unsigned long flags);
void at32_select_gpio(unsigned int pin, unsigned long flags);
+void at32_deselect_pin(unsigned int pin);
void at32_reserve_pin(unsigned int pin);
#endif /* __ASM_ARCH_PORTMUX_H__ */
diff --git a/arch/avr32/mach-at32ap/pdc.c b/arch/avr32/mach-at32ap/pdc.c
index 1040bda..61ab15a 100644
--- a/arch/avr32/mach-at32ap/pdc.c
+++ b/arch/avr32/mach-at32ap/pdc.c
@@ -35,7 +35,6 @@
}
static struct platform_driver pdc_driver = {
- .probe = pdc_probe,
.driver = {
.name = "pdc",
},
@@ -43,6 +42,6 @@
static int __init pdc_init(void)
{
- return platform_driver_register(&pdc_driver);
+ return platform_driver_probe(&pdc_driver, pdc_probe);
}
arch_initcall(pdc_init);
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index 405ee6b..ed81a8b 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -50,35 +50,48 @@
}
/* Pin multiplexing API */
+static DEFINE_SPINLOCK(pio_lock);
-void __init at32_select_periph(unsigned int pin, unsigned int periph,
- unsigned long flags)
+void __init at32_select_periph(unsigned int port, u32 pin_mask,
+ unsigned int periph, unsigned long flags)
{
struct pio_device *pio;
- unsigned int pin_index = pin & 0x1f;
- u32 mask = 1 << pin_index;
- pio = gpio_to_pio(pin);
+ /* assign and verify pio */
+ pio = gpio_to_pio(port);
if (unlikely(!pio)) {
- printk("pio: invalid pin %u\n", pin);
+ printk(KERN_WARNING "pio: invalid port %u\n", port);
goto fail;
}
- if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask)
- || gpiochip_is_requested(&pio->chip, pin_index))) {
- printk("%s: pin %u is busy\n", pio->name, pin_index);
+ /* Test if any of the requested pins is already muxed */
+ spin_lock(&pio_lock);
+ if (unlikely(pio->pinmux_mask & pin_mask)) {
+ printk(KERN_WARNING "%s: pin(s) busy (requested 0x%x, busy 0x%x)\n",
+ pio->name, pin_mask, pio->pinmux_mask & pin_mask);
+ spin_unlock(&pio_lock);
goto fail;
}
- pio_writel(pio, PUER, mask);
+ pio->pinmux_mask |= pin_mask;
+
+ /* enable pull ups */
+ pio_writel(pio, PUER, pin_mask);
+
+ /* select either peripheral A or B */
if (periph)
- pio_writel(pio, BSR, mask);
+ pio_writel(pio, BSR, pin_mask);
else
- pio_writel(pio, ASR, mask);
+ pio_writel(pio, ASR, pin_mask);
- pio_writel(pio, PDR, mask);
+ /* enable peripheral control */
+ pio_writel(pio, PDR, pin_mask);
+
+ /* Disable pull ups if not requested. */
if (!(flags & AT32_GPIOF_PULLUP))
- pio_writel(pio, PUDR, mask);
+ pio_writel(pio, PUDR, pin_mask);
+
+ spin_unlock(&pio_lock);
return;
@@ -134,6 +147,25 @@
dump_stack();
}
+/*
+ * Undo a previous pin reservation. Will not affect the hardware
+ * configuration.
+ */
+void at32_deselect_pin(unsigned int pin)
+{
+ struct pio_device *pio;
+ unsigned int pin_index = pin & 0x1f;
+
+ pio = gpio_to_pio(pin);
+ if (unlikely(!pio)) {
+ printk("pio: invalid pin %u\n", pin);
+ dump_stack();
+ return;
+ }
+
+ clear_bit(pin_index, &pio->pinmux_mask);
+}
+
/* Reserve a pin, preventing anyone else from changing its configuration. */
void __init at32_reserve_pin(unsigned int pin)
{
@@ -382,7 +414,6 @@
}
static struct platform_driver pio_driver = {
- .probe = pio_probe,
.driver = {
.name = "pio",
},
@@ -390,7 +421,7 @@
static int __init pio_init(void)
{
- return platform_driver_register(&pio_driver);
+ return platform_driver_probe(&pio_driver, pio_probe);
}
postcore_initcall(pio_init);
diff --git a/arch/avr32/oprofile/Makefile b/arch/avr32/oprofile/Makefile
index 1fe81c3..e0eb520 100644
--- a/arch/avr32/oprofile/Makefile
+++ b/arch/avr32/oprofile/Makefile
@@ -5,4 +5,4 @@
event_buffer.o oprofile_files.o \
oprofilefs.o oprofile_stats.o \
timer_int.o)
-oprofile-y += op_model_avr32.o
+oprofile-y += op_model_avr32.o backtrace.o
diff --git a/arch/avr32/oprofile/backtrace.c b/arch/avr32/oprofile/backtrace.c
new file mode 100644
index 0000000..75d9ad6
--- /dev/null
+++ b/arch/avr32/oprofile/backtrace.c
@@ -0,0 +1,81 @@
+/*
+ * AVR32 specific backtracing code for oprofile
+ *
+ * Copyright 2008 Weinmann GmbH
+ *
+ * Author: Nikolaus Voss <n.voss@weinmann.de>
+ *
+ * Based on i386 oprofile backtrace code by John Levon and David Smith
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/oprofile.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+
+/* The first two words of each frame on the stack look like this if we have
+ * frame pointers */
+struct frame_head {
+ unsigned long lr;
+ struct frame_head *fp;
+};
+
+/* copied from arch/avr32/kernel/process.c */
+static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
+{
+ return (p > (unsigned long)tinfo)
+ && (p < (unsigned long)tinfo + THREAD_SIZE - 3);
+}
+
+/* copied from arch/x86/oprofile/backtrace.c */
+static struct frame_head *dump_user_backtrace(struct frame_head *head)
+{
+ struct frame_head bufhead[2];
+
+ /* Also check accessibility of one struct frame_head beyond */
+ if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
+ return NULL;
+ if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
+ return NULL;
+
+ oprofile_add_trace(bufhead[0].lr);
+
+ /* frame pointers should strictly progress back up the stack
+ * (towards higher addresses) */
+ if (bufhead[0].fp <= head)
+ return NULL;
+
+ return bufhead[0].fp;
+}
+
+void avr32_backtrace(struct pt_regs * const regs, unsigned int depth)
+{
+ /* Get first frame pointer */
+ struct frame_head *head = (struct frame_head *)(regs->r7);
+
+ if (!user_mode(regs)) {
+#ifdef CONFIG_FRAME_POINTER
+ /*
+ * Traverse the kernel stack from frame to frame up to
+ * "depth" steps.
+ */
+ while (depth-- && valid_stack_ptr(task_thread_info(current),
+ (unsigned long)head)) {
+ oprofile_add_trace(head->lr);
+ if (head->fp <= head)
+ break;
+ head = head->fp;
+ }
+#endif
+ } else {
+ /* Assume we have frame pointers in user mode process */
+ while (depth-- && head)
+ head = dump_user_backtrace(head);
+ }
+}
+
+
diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c
index df42325..a3e9b3c 100644
--- a/arch/avr32/oprofile/op_model_avr32.c
+++ b/arch/avr32/oprofile/op_model_avr32.c
@@ -22,6 +22,8 @@
#define AVR32_PERFCTR_IRQ_GROUP 0
#define AVR32_PERFCTR_IRQ_LINE 1
+void avr32_backtrace(struct pt_regs * const regs, unsigned int depth);
+
enum { PCCNT, PCNT0, PCNT1, NR_counter };
struct avr32_perf_counter {
@@ -223,6 +225,8 @@
memcpy(ops, &avr32_perf_counter_ops,
sizeof(struct oprofile_operations));
+ ops->backtrace = avr32_backtrace;
+
printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");
return 0;
diff --git a/arch/ia64/include/asm/siginfo.h b/arch/ia64/include/asm/siginfo.h
index 9294e4b..118d429 100644
--- a/arch/ia64/include/asm/siginfo.h
+++ b/arch/ia64/include/asm/siginfo.h
@@ -113,11 +113,6 @@
#undef NSIGSEGV
#define NSIGSEGV 3
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */
-#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */
#undef NSIGTRAP
#define NSIGTRAP 4
diff --git a/arch/powerpc/include/asm/siginfo.h b/arch/powerpc/include/asm/siginfo.h
index 12f1bce..49495b0 100644
--- a/arch/powerpc/include/asm/siginfo.h
+++ b/arch/powerpc/include/asm/siginfo.h
@@ -15,11 +15,6 @@
#include <asm-generic/siginfo.h>
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */
-#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */
#undef NSIGTRAP
#define NSIGTRAP 4
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index a214002..97671da 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -20,6 +20,11 @@
bool
default y
+config GENERIC_GPIO
+ bool
+ help
+ Generic GPIO API support
+
config ARCH_NO_VIRT_TO_BUS
def_bool y
@@ -69,6 +74,9 @@
select HAVE_OPROFILE
select HAVE_ARCH_KGDB if !SMP
select HAVE_ARCH_TRACEHOOK
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select RTC_CLASS
+ select RTC_DRV_M48T59
# Identify this as a Sparc32 build
config SPARC32
@@ -204,17 +212,6 @@
Enable power management and CPU standby features on supported
SPARC platforms.
-config SUN4
- bool "Support for SUN4 machines (disables SUN4[CDM] support)"
- depends on !SMP
- default n
- help
- Say Y here if, and only if, your machine is a sun4. Note that
- a kernel compiled with this option will run only on sun4.
- (And the current version will probably work only on sun4/330.)
-
-if !SUN4
-
config PCI
bool "Support for PCI and PS/2 keyboard/mouse"
help
@@ -227,11 +224,6 @@
source "drivers/pci/Kconfig"
-endif
-
-config NO_DMA
- def_bool !PCI
-
config SUN_OPENPROMFS
tristate "Openprom tree appears in /proc/openprom"
help
@@ -263,9 +255,7 @@
source "drivers/Kconfig"
-if !SUN4
source "drivers/sbus/char/Kconfig"
-endif
# This one must be before the filesystem configs. -DaveM
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index a5f0ce7..2ba7183 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -22,7 +22,6 @@
header-y += apc.h
header-y += asi.h
-header-y += bpp.h
header-y += display7seg.h
header-y += envctrl.h
header-y += fbio.h
@@ -41,5 +40,4 @@
header-y += traps.h
header-y += uctx.h
header-y += utrap.h
-header-y += vfc_ioctls.h
header-y += watchdog.h
diff --git a/arch/sparc/include/asm/asmmacro.h b/arch/sparc/include/asm/asmmacro.h
index a619a4d..a995bf8 100644
--- a/arch/sparc/include/asm/asmmacro.h
+++ b/arch/sparc/include/asm/asmmacro.h
@@ -34,12 +34,7 @@
/* sun4 probably wants half word accesses to ASI_SEGMAP, while sun4c+
likes byte accesses. These are to avoid ifdef mania. */
-#ifdef CONFIG_SUN4
-#define lduXa lduha
-#define stXa stha
-#else
#define lduXa lduba
#define stXa stba
-#endif
#endif /* !(_SPARC_ASMMACRO_H) */
diff --git a/arch/sparc/include/asm/bpp.h b/arch/sparc/include/asm/bpp.h
deleted file mode 100644
index 31f515e..0000000
--- a/arch/sparc/include/asm/bpp.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef _SPARC_BPP_H
-#define _SPARC_BPP_H
-
-/*
- * Copyright (c) 1995 Picture Elements
- * Stephen Williams
- * Gus Baldauf
- *
- * Linux/SPARC port by Peter Zaitcev.
- * Integration into SPARC tree by Tom Dyas.
- */
-
-#include <linux/ioctl.h>
-
-/*
- * This is a driver that supports IEEE Std 1284-1994 communications
- * with compliant or compatible devices. It will use whatever features
- * the device supports, prefering those that are typically faster.
- *
- * When the device is opened, it is left in COMPATIBILITY mode, and
- * writes work like any printer device. The driver only attempt to
- * negotiate 1284 modes when needed so that plugs can be pulled,
- * switch boxes switched, etc., without disrupting things. It will
- * also leave the device in compatibility mode when closed.
- */
-
-
-
-/*
- * This driver also supplies ioctls to manually manipulate the
- * pins. This is great for testing devices, or writing code to deal
- * with bizzarro-mode of the ACME Special TurboThingy Plus.
- *
- * NOTE: These ioctl currently do not interact well with
- * read/write. Caveat emptor.
- *
- * PUT_PINS allows us to assign the sense of all the pins, including
- * the data pins if being driven by the host. The GET_PINS returns the
- * pins that the peripheral drives, including data if appropriate.
- */
-
-# define BPP_PUT_PINS _IOW('B', 1, int)
-# define BPP_GET_PINS _IOR('B', 2, char) /* that's bogus - should've been _IO */
-# define BPP_PUT_DATA _IOW('B', 3, int)
-# define BPP_GET_DATA _IOR('B', 4, char) /* ditto */
-
-/*
- * Set the data bus to input mode. Disengage the data bin driver and
- * be prepared to read values from the peripheral. If the arg is 0,
- * then revert the bus to output mode.
- */
-# define BPP_SET_INPUT _IOW('B', 5, int)
-
-/*
- * These bits apply to the PUT operation...
- */
-# define BPP_PP_nStrobe 0x0001
-# define BPP_PP_nAutoFd 0x0002
-# define BPP_PP_nInit 0x0004
-# define BPP_PP_nSelectIn 0x0008
-
-/*
- * These apply to the GET operation, which also reads the current value
- * of the previously put values. A bit mask of these will be returned
- * as a bit mask in the return code of the ioctl().
- */
-# define BPP_GP_nAck 0x0100
-# define BPP_GP_Busy 0x0200
-# define BPP_GP_PError 0x0400
-# define BPP_GP_Select 0x0800
-# define BPP_GP_nFault 0x1000
-
-#endif
diff --git a/arch/sparc/include/asm/bugs.h b/arch/sparc/include/asm/bugs.h
index e179bc1..61d86bb 100644
--- a/arch/sparc/include/asm/bugs.h
+++ b/arch/sparc/include/asm/bugs.h
@@ -7,10 +7,6 @@
#include <asm/cpudata.h>
#endif
-#ifdef CONFIG_SPARC64
-#include <asm/sstate.h>
-#endif
-
extern unsigned long loops_per_jiffy;
static void __init check_bugs(void)
@@ -18,7 +14,4 @@
#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/arch/sparc/include/asm/cpudata_64.h b/arch/sparc/include/asm/cpudata_64.h
index 532975e..7da7c13 100644
--- a/arch/sparc/include/asm/cpudata_64.h
+++ b/arch/sparc/include/asm/cpudata_64.h
@@ -86,7 +86,6 @@
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/arch/sparc/include/asm/dma-mapping_32.h b/arch/sparc/include/asm/dma-mapping_32.h
index f3a641e..8a57ea0 100644
--- a/arch/sparc/include/asm/dma-mapping_32.h
+++ b/arch/sparc/include/asm/dma-mapping_32.h
@@ -1,11 +1,60 @@
#ifndef _ASM_SPARC_DMA_MAPPING_H
#define _ASM_SPARC_DMA_MAPPING_H
+#include <linux/types.h>
-#ifdef CONFIG_PCI
-#include <asm-generic/dma-mapping.h>
-#else
-#include <asm-generic/dma-mapping-broken.h>
-#endif /* PCI */
+struct device;
+struct scatterlist;
+struct page;
+
+#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
+
+extern int dma_supported(struct device *dev, u64 mask);
+extern int dma_set_mask(struct device *dev, u64 dma_mask);
+extern void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag);
+extern void dma_free_coherent(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle);
+extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+ size_t size,
+ enum dma_data_direction direction);
+extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+ size_t size,
+ enum dma_data_direction direction);
+extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction);
+extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+ size_t size, enum dma_data_direction direction);
+extern int dma_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction);
+extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction);
+extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ size_t size,
+ enum dma_data_direction direction);
+extern void dma_sync_single_for_device(struct device *dev,
+ dma_addr_t dma_handle,
+ size_t size,
+ enum dma_data_direction direction);
+extern void dma_sync_single_range_for_cpu(struct device *dev,
+ dma_addr_t dma_handle,
+ unsigned long offset,
+ size_t size,
+ enum dma_data_direction direction);
+extern void dma_sync_single_range_for_device(struct device *dev,
+ dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction);
+extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction direction);
+extern void dma_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction);
+extern int dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
+extern int dma_get_cache_alignment(void);
+
+#define dma_alloc_noncoherent dma_alloc_coherent
+#define dma_free_noncoherent dma_free_coherent
#endif /* _ASM_SPARC_DMA_MAPPING_H */
diff --git a/arch/sparc/include/asm/dma.h b/arch/sparc/include/asm/dma.h
index aa1d90a..b554927 100644
--- a/arch/sparc/include/asm/dma.h
+++ b/arch/sparc/include/asm/dma.h
@@ -1,8 +1,139 @@
-#ifndef ___ASM_SPARC_DMA_H
-#define ___ASM_SPARC_DMA_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/dma_64.h>
+#ifndef _ASM_SPARC_DMA_H
+#define _ASM_SPARC_DMA_H
+
+/* These are irrelevant for Sparc DMA, but we leave it in so that
+ * things can compile.
+ */
+#define MAX_DMA_CHANNELS 8
+#define DMA_MODE_READ 1
+#define DMA_MODE_WRITE 2
+#define MAX_DMA_ADDRESS (~0UL)
+
+/* Useful constants */
+#define SIZE_16MB (16*1024*1024)
+#define SIZE_64K (64*1024)
+
+/* SBUS DMA controller reg offsets */
+#define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */
+#define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */
+#define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */
+#define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */
+
+/* Fields in the cond_reg register */
+/* First, the version identification bits */
+#define DMA_DEVICE_ID 0xf0000000 /* Device identification bits */
+#define DMA_VERS0 0x00000000 /* Sunray DMA version */
+#define DMA_ESCV1 0x40000000 /* DMA ESC Version 1 */
+#define DMA_VERS1 0x80000000 /* DMA rev 1 */
+#define DMA_VERS2 0xa0000000 /* DMA rev 2 */
+#define DMA_VERHME 0xb0000000 /* DMA hme gate array */
+#define DMA_VERSPLUS 0x90000000 /* DMA rev 1 PLUS */
+
+#define DMA_HNDL_INTR 0x00000001 /* An IRQ needs to be handled */
+#define DMA_HNDL_ERROR 0x00000002 /* We need to take an error */
+#define DMA_FIFO_ISDRAIN 0x0000000c /* The DMA FIFO is draining */
+#define DMA_INT_ENAB 0x00000010 /* Turn on interrupts */
+#define DMA_FIFO_INV 0x00000020 /* Invalidate the FIFO */
+#define DMA_ACC_SZ_ERR 0x00000040 /* The access size was bad */
+#define DMA_FIFO_STDRAIN 0x00000040 /* DMA_VERS1 Drain the FIFO */
+#define DMA_RST_SCSI 0x00000080 /* Reset the SCSI controller */
+#define DMA_RST_ENET DMA_RST_SCSI /* Reset the ENET controller */
+#define DMA_ST_WRITE 0x00000100 /* write from device to memory */
+#define DMA_ENABLE 0x00000200 /* Fire up DMA, handle requests */
+#define DMA_PEND_READ 0x00000400 /* DMA_VERS1/0/PLUS Pending Read */
+#define DMA_ESC_BURST 0x00000800 /* 1=16byte 0=32byte */
+#define DMA_READ_AHEAD 0x00001800 /* DMA read ahead partial longword */
+#define DMA_DSBL_RD_DRN 0x00001000 /* No EC drain on slave reads */
+#define DMA_BCNT_ENAB 0x00002000 /* If on, use the byte counter */
+#define DMA_TERM_CNTR 0x00004000 /* Terminal counter */
+#define DMA_SCSI_SBUS64 0x00008000 /* HME: Enable 64-bit SBUS mode. */
+#define DMA_CSR_DISAB 0x00010000 /* No FIFO drains during csr */
+#define DMA_SCSI_DISAB 0x00020000 /* No FIFO drains during reg */
+#define DMA_DSBL_WR_INV 0x00020000 /* No EC inval. on slave writes */
+#define DMA_ADD_ENABLE 0x00040000 /* Special ESC DVMA optimization */
+#define DMA_E_BURSTS 0x000c0000 /* ENET: SBUS r/w burst mask */
+#define DMA_E_BURST32 0x00040000 /* ENET: SBUS 32 byte r/w burst */
+#define DMA_E_BURST16 0x00000000 /* ENET: SBUS 16 byte r/w burst */
+#define DMA_BRST_SZ 0x000c0000 /* SCSI: SBUS r/w burst size */
+#define DMA_BRST64 0x000c0000 /* SCSI: 64byte bursts (HME on UltraSparc only) */
+#define DMA_BRST32 0x00040000 /* SCSI: 32byte bursts */
+#define DMA_BRST16 0x00000000 /* SCSI: 16byte bursts */
+#define DMA_BRST0 0x00080000 /* SCSI: no bursts (non-HME gate arrays) */
+#define DMA_ADDR_DISAB 0x00100000 /* No FIFO drains during addr */
+#define DMA_2CLKS 0x00200000 /* Each transfer = 2 clock ticks */
+#define DMA_3CLKS 0x00400000 /* Each transfer = 3 clock ticks */
+#define DMA_EN_ENETAUI DMA_3CLKS /* Put lance into AUI-cable mode */
+#define DMA_CNTR_DISAB 0x00800000 /* No IRQ when DMA_TERM_CNTR set */
+#define DMA_AUTO_NADDR 0x01000000 /* Use "auto nxt addr" feature */
+#define DMA_SCSI_ON 0x02000000 /* Enable SCSI dma */
+#define DMA_PARITY_OFF 0x02000000 /* HME: disable parity checking */
+#define DMA_LOADED_ADDR 0x04000000 /* Address has been loaded */
+#define DMA_LOADED_NADDR 0x08000000 /* Next address has been loaded */
+#define DMA_RESET_FAS366 0x08000000 /* HME: Assert RESET to FAS366 */
+
+/* Values describing the burst-size property from the PROM */
+#define DMA_BURST1 0x01
+#define DMA_BURST2 0x02
+#define DMA_BURST4 0x04
+#define DMA_BURST8 0x08
+#define DMA_BURST16 0x10
+#define DMA_BURST32 0x20
+#define DMA_BURST64 0x40
+#define DMA_BURSTBITS 0x7f
+
+/* From PCI */
+
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
#else
-#include <asm/dma_32.h>
+#define isa_dma_bridge_buggy (0)
#endif
+
+#ifdef CONFIG_SPARC32
+
+/* Routines for data transfer buffers. */
+BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
+BTFIXUPDEF_CALL(void, mmu_unlockarea, char *, unsigned long)
+
+#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len)
+#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len)
+
+struct page;
+struct device;
+struct scatterlist;
+
+/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */
+BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, struct device *, char *, unsigned long)
+BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct device *, struct scatterlist *, int)
+BTFIXUPDEF_CALL(void, mmu_release_scsi_one, struct device *, __u32, unsigned long)
+BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct device *, struct scatterlist *, int)
+
+#define mmu_get_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_get_scsi_one)(dev,vaddr,len)
+#define mmu_get_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_get_scsi_sgl)(dev,sg,sz)
+#define mmu_release_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_release_scsi_one)(dev,vaddr,len)
+#define mmu_release_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_release_scsi_sgl)(dev,sg,sz)
+
+/*
+ * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep.
+ *
+ * The mmu_map_dma_area establishes two mappings in one go.
+ * These mappings point to pages normally mapped at 'va' (linear address).
+ * First mapping is for CPU visible address at 'a', uncached.
+ * This is an alias, but it works because it is an uncached mapping.
+ * Second mapping is for device visible address, or "bus" address.
+ * The bus address is returned at '*pba'.
+ *
+ * These functions seem distinct, but are hard to split. On sun4c,
+ * at least for now, 'a' is equal to bus address, and retured in *pba.
+ * On sun4m, page attributes depend on the CPU type, so we have to
+ * know if we are mapping RAM or I/O, so it has to be an additional argument
+ * to a separate mapping function for CPU visible mappings.
+ */
+BTFIXUPDEF_CALL(int, mmu_map_dma_area, struct device *, dma_addr_t *, unsigned long, unsigned long, int len)
+BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, struct device *, unsigned long busa, int len)
+
+#define mmu_map_dma_area(dev,pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(dev,pba,va,a,len)
+#define mmu_unmap_dma_area(dev,ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(dev,ba,len)
#endif
+
+#endif /* !(_ASM_SPARC_DMA_H) */
diff --git a/arch/sparc/include/asm/dma_32.h b/arch/sparc/include/asm/dma_32.h
deleted file mode 100644
index cf7189c..0000000
--- a/arch/sparc/include/asm/dma_32.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/* include/asm/dma.h
- *
- * Copyright 1995 (C) David S. Miller (davem@davemloft.net)
- */
-
-#ifndef _ASM_SPARC_DMA_H
-#define _ASM_SPARC_DMA_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-
-#include <asm/vac-ops.h> /* for invalidate's, etc. */
-#include <asm/sbus.h>
-#include <asm/delay.h>
-#include <asm/oplib.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <linux/spinlock.h>
-
-struct page;
-extern spinlock_t dma_spin_lock;
-
-static inline unsigned long claim_dma_lock(void)
-{
- unsigned long flags;
- spin_lock_irqsave(&dma_spin_lock, flags);
- return flags;
-}
-
-static inline void release_dma_lock(unsigned long flags)
-{
- spin_unlock_irqrestore(&dma_spin_lock, flags);
-}
-
-/* These are irrelevant for Sparc DMA, but we leave it in so that
- * things can compile.
- */
-#define MAX_DMA_CHANNELS 8
-#define MAX_DMA_ADDRESS (~0UL)
-#define DMA_MODE_READ 1
-#define DMA_MODE_WRITE 2
-
-/* Useful constants */
-#define SIZE_16MB (16*1024*1024)
-#define SIZE_64K (64*1024)
-
-/* SBUS DMA controller reg offsets */
-#define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */
-#define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */
-#define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */
-#define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */
-
-/* DVMA chip revisions */
-enum dvma_rev {
- dvmarev0,
- dvmaesc1,
- dvmarev1,
- dvmarev2,
- dvmarev3,
- dvmarevplus,
- dvmahme
-};
-
-#define DMA_HASCOUNT(rev) ((rev)==dvmaesc1)
-
-/* Linux DMA information structure, filled during probe. */
-struct sbus_dma {
- struct sbus_dma *next;
- struct sbus_dev *sdev;
- void __iomem *regs;
-
- /* Status, misc info */
- int node; /* Prom node for this DMA device */
- int running; /* Are we doing DMA now? */
- int allocated; /* Are we "owned" by anyone yet? */
-
- /* Transfer information. */
- unsigned long addr; /* Start address of current transfer */
- int nbytes; /* Size of current transfer */
- int realbytes; /* For splitting up large transfers, etc. */
-
- /* DMA revision */
- enum dvma_rev revision;
-};
-
-extern struct sbus_dma *dma_chain;
-
-/* Broken hardware... */
-#ifdef CONFIG_SUN4
-/* Have to sort this out. Does rev0 work fine on sun4[cmd] without isbroken?
- * Or is rev0 present only on sun4 boxes? -jj */
-#define DMA_ISBROKEN(dma) ((dma)->revision == dvmarev0 || (dma)->revision == dvmarev1)
-#else
-#define DMA_ISBROKEN(dma) ((dma)->revision == dvmarev1)
-#endif
-#define DMA_ISESC1(dma) ((dma)->revision == dvmaesc1)
-
-/* Main routines in dma.c */
-extern void dvma_init(struct sbus_bus *);
-
-/* Fields in the cond_reg register */
-/* First, the version identification bits */
-#define DMA_DEVICE_ID 0xf0000000 /* Device identification bits */
-#define DMA_VERS0 0x00000000 /* Sunray DMA version */
-#define DMA_ESCV1 0x40000000 /* DMA ESC Version 1 */
-#define DMA_VERS1 0x80000000 /* DMA rev 1 */
-#define DMA_VERS2 0xa0000000 /* DMA rev 2 */
-#define DMA_VERHME 0xb0000000 /* DMA hme gate array */
-#define DMA_VERSPLUS 0x90000000 /* DMA rev 1 PLUS */
-
-#define DMA_HNDL_INTR 0x00000001 /* An IRQ needs to be handled */
-#define DMA_HNDL_ERROR 0x00000002 /* We need to take an error */
-#define DMA_FIFO_ISDRAIN 0x0000000c /* The DMA FIFO is draining */
-#define DMA_INT_ENAB 0x00000010 /* Turn on interrupts */
-#define DMA_FIFO_INV 0x00000020 /* Invalidate the FIFO */
-#define DMA_ACC_SZ_ERR 0x00000040 /* The access size was bad */
-#define DMA_FIFO_STDRAIN 0x00000040 /* DMA_VERS1 Drain the FIFO */
-#define DMA_RST_SCSI 0x00000080 /* Reset the SCSI controller */
-#define DMA_RST_ENET DMA_RST_SCSI /* Reset the ENET controller */
-#define DMA_RST_BPP DMA_RST_SCSI /* Reset the BPP controller */
-#define DMA_ST_WRITE 0x00000100 /* write from device to memory */
-#define DMA_ENABLE 0x00000200 /* Fire up DMA, handle requests */
-#define DMA_PEND_READ 0x00000400 /* DMA_VERS1/0/PLUS Pending Read */
-#define DMA_ESC_BURST 0x00000800 /* 1=16byte 0=32byte */
-#define DMA_READ_AHEAD 0x00001800 /* DMA read ahead partial longword */
-#define DMA_DSBL_RD_DRN 0x00001000 /* No EC drain on slave reads */
-#define DMA_BCNT_ENAB 0x00002000 /* If on, use the byte counter */
-#define DMA_TERM_CNTR 0x00004000 /* Terminal counter */
-#define DMA_SCSI_SBUS64 0x00008000 /* HME: Enable 64-bit SBUS mode. */
-#define DMA_CSR_DISAB 0x00010000 /* No FIFO drains during csr */
-#define DMA_SCSI_DISAB 0x00020000 /* No FIFO drains during reg */
-#define DMA_DSBL_WR_INV 0x00020000 /* No EC inval. on slave writes */
-#define DMA_ADD_ENABLE 0x00040000 /* Special ESC DVMA optimization */
-#define DMA_E_BURSTS 0x000c0000 /* ENET: SBUS r/w burst mask */
-#define DMA_E_BURST32 0x00040000 /* ENET: SBUS 32 byte r/w burst */
-#define DMA_E_BURST16 0x00000000 /* ENET: SBUS 16 byte r/w burst */
-#define DMA_BRST_SZ 0x000c0000 /* SCSI: SBUS r/w burst size */
-#define DMA_BRST64 0x00080000 /* SCSI: 64byte bursts (HME on UltraSparc only) */
-#define DMA_BRST32 0x00040000 /* SCSI/BPP: 32byte bursts */
-#define DMA_BRST16 0x00000000 /* SCSI/BPP: 16byte bursts */
-#define DMA_BRST0 0x00080000 /* SCSI: no bursts (non-HME gate arrays) */
-#define DMA_ADDR_DISAB 0x00100000 /* No FIFO drains during addr */
-#define DMA_2CLKS 0x00200000 /* Each transfer = 2 clock ticks */
-#define DMA_3CLKS 0x00400000 /* Each transfer = 3 clock ticks */
-#define DMA_EN_ENETAUI DMA_3CLKS /* Put lance into AUI-cable mode */
-#define DMA_CNTR_DISAB 0x00800000 /* No IRQ when DMA_TERM_CNTR set */
-#define DMA_AUTO_NADDR 0x01000000 /* Use "auto nxt addr" feature */
-#define DMA_SCSI_ON 0x02000000 /* Enable SCSI dma */
-#define DMA_BPP_ON DMA_SCSI_ON /* Enable BPP dma */
-#define DMA_PARITY_OFF 0x02000000 /* HME: disable parity checking */
-#define DMA_LOADED_ADDR 0x04000000 /* Address has been loaded */
-#define DMA_LOADED_NADDR 0x08000000 /* Next address has been loaded */
-#define DMA_RESET_FAS366 0x08000000 /* HME: Assert RESET to FAS366 */
-
-/* Values describing the burst-size property from the PROM */
-#define DMA_BURST1 0x01
-#define DMA_BURST2 0x02
-#define DMA_BURST4 0x04
-#define DMA_BURST8 0x08
-#define DMA_BURST16 0x10
-#define DMA_BURST32 0x20
-#define DMA_BURST64 0x40
-#define DMA_BURSTBITS 0x7f
-
-/* Determine highest possible final transfer address given a base */
-#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
-
-/* Yes, I hack a lot of elisp in my spare time... */
-#define DMA_ERROR_P(regs) ((((regs)->cond_reg) & DMA_HNDL_ERROR))
-#define DMA_IRQ_P(regs) ((((regs)->cond_reg) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)))
-#define DMA_WRITE_P(regs) ((((regs)->cond_reg) & DMA_ST_WRITE))
-#define DMA_OFF(regs) ((((regs)->cond_reg) &= (~DMA_ENABLE)))
-#define DMA_INTSOFF(regs) ((((regs)->cond_reg) &= (~DMA_INT_ENAB)))
-#define DMA_INTSON(regs) ((((regs)->cond_reg) |= (DMA_INT_ENAB)))
-#define DMA_PUNTFIFO(regs) ((((regs)->cond_reg) |= DMA_FIFO_INV))
-#define DMA_SETSTART(regs, addr) ((((regs)->st_addr) = (char *) addr))
-#define DMA_BEGINDMA_W(regs) \
- ((((regs)->cond_reg |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB))))
-#define DMA_BEGINDMA_R(regs) \
- ((((regs)->cond_reg |= ((DMA_ENABLE|DMA_INT_ENAB)&(~DMA_ST_WRITE)))))
-
-/* For certain DMA chips, we need to disable ints upon irq entry
- * and turn them back on when we are done. So in any ESP interrupt
- * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
- * when leaving the handler. You have been warned...
- */
-#define DMA_IRQ_ENTRY(dma, dregs) do { \
- if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
- } while (0)
-
-#define DMA_IRQ_EXIT(dma, dregs) do { \
- if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
- } while(0)
-
-#if 0 /* P3 this stuff is inline in ledma.c:init_restart_ledma() */
-/* Pause until counter runs out or BIT isn't set in the DMA condition
- * register.
- */
-static inline void sparc_dma_pause(struct sparc_dma_registers *regs,
- unsigned long bit)
-{
- int ctr = 50000; /* Let's find some bugs ;) */
-
- /* Busy wait until the bit is not set any more */
- while((regs->cond_reg&bit) && (ctr>0)) {
- ctr--;
- __delay(5);
- }
-
- /* Check for bogus outcome. */
- if(!ctr)
- panic("DMA timeout");
-}
-
-/* Reset the friggin' thing... */
-#define DMA_RESET(dma) do { \
- struct sparc_dma_registers *regs = dma->regs; \
- /* Let the current FIFO drain itself */ \
- sparc_dma_pause(regs, (DMA_FIFO_ISDRAIN)); \
- /* Reset the logic */ \
- regs->cond_reg |= (DMA_RST_SCSI); /* assert */ \
- __delay(400); /* let the bits set ;) */ \
- regs->cond_reg &= ~(DMA_RST_SCSI); /* de-assert */ \
- sparc_dma_enable_interrupts(regs); /* Re-enable interrupts */ \
- /* Enable FAST transfers if available */ \
- if(dma->revision>dvmarev1) regs->cond_reg |= DMA_3CLKS; \
- dma->running = 0; \
-} while(0)
-#endif
-
-#define for_each_dvma(dma) \
- for((dma) = dma_chain; (dma); (dma) = (dma)->next)
-
-extern int get_dma_list(char *);
-extern int request_dma(unsigned int, __const__ char *);
-extern void free_dma(unsigned int);
-
-/* From PCI */
-
-#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
-#else
-#define isa_dma_bridge_buggy (0)
-#endif
-
-/* Routines for data transfer buffers. */
-BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
-BTFIXUPDEF_CALL(void, mmu_unlockarea, char *, unsigned long)
-
-#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len)
-#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len)
-
-/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */
-BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, char *, unsigned long, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void, mmu_release_scsi_one, __u32, unsigned long, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus)
-
-#define mmu_get_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_get_scsi_one)(vaddr,len,sbus)
-#define mmu_get_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_get_scsi_sgl)(sg,sz,sbus)
-#define mmu_release_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_release_scsi_one)(vaddr,len,sbus)
-#define mmu_release_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_release_scsi_sgl)(sg,sz,sbus)
-
-/*
- * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep.
- *
- * The mmu_map_dma_area establishes two mappings in one go.
- * These mappings point to pages normally mapped at 'va' (linear address).
- * First mapping is for CPU visible address at 'a', uncached.
- * This is an alias, but it works because it is an uncached mapping.
- * Second mapping is for device visible address, or "bus" address.
- * The bus address is returned at '*pba'.
- *
- * These functions seem distinct, but are hard to split. On sun4c,
- * at least for now, 'a' is equal to bus address, and retured in *pba.
- * On sun4m, page attributes depend on the CPU type, so we have to
- * know if we are mapping RAM or I/O, so it has to be an additional argument
- * to a separate mapping function for CPU visible mappings.
- */
-BTFIXUPDEF_CALL(int, mmu_map_dma_area, dma_addr_t *, unsigned long, unsigned long, int len)
-BTFIXUPDEF_CALL(struct page *, mmu_translate_dvma, unsigned long busa)
-BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, unsigned long busa, int len)
-
-#define mmu_map_dma_area(pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(pba,va,a,len)
-#define mmu_unmap_dma_area(ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(ba,len)
-#define mmu_translate_dvma(ba) BTFIXUP_CALL(mmu_translate_dvma)(ba)
-
-#endif /* !(_ASM_SPARC_DMA_H) */
diff --git a/arch/sparc/include/asm/dma_64.h b/arch/sparc/include/asm/dma_64.h
deleted file mode 100644
index 46a8aec..0000000
--- a/arch/sparc/include/asm/dma_64.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * include/asm/dma.h
- *
- * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _ASM_SPARC64_DMA_H
-#define _ASM_SPARC64_DMA_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-
-#include <asm/sbus.h>
-#include <asm/delay.h>
-#include <asm/oplib.h>
-
-/* These are irrelevant for Sparc DMA, but we leave it in so that
- * things can compile.
- */
-#define MAX_DMA_CHANNELS 8
-#define DMA_MODE_READ 1
-#define DMA_MODE_WRITE 2
-#define MAX_DMA_ADDRESS (~0UL)
-
-/* Useful constants */
-#define SIZE_16MB (16*1024*1024)
-#define SIZE_64K (64*1024)
-
-/* SBUS DMA controller reg offsets */
-#define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */
-#define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */
-#define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */
-#define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */
-
-/* DVMA chip revisions */
-enum dvma_rev {
- dvmarev0,
- dvmaesc1,
- dvmarev1,
- dvmarev2,
- dvmarev3,
- dvmarevplus,
- dvmahme
-};
-
-#define DMA_HASCOUNT(rev) ((rev)==dvmaesc1)
-
-/* Linux DMA information structure, filled during probe. */
-struct sbus_dma {
- struct sbus_dma *next;
- struct sbus_dev *sdev;
- void __iomem *regs;
-
- /* Status, misc info */
- int node; /* Prom node for this DMA device */
- int running; /* Are we doing DMA now? */
- int allocated; /* Are we "owned" by anyone yet? */
-
- /* Transfer information. */
- u32 addr; /* Start address of current transfer */
- int nbytes; /* Size of current transfer */
- int realbytes; /* For splitting up large transfers, etc. */
-
- /* DMA revision */
- enum dvma_rev revision;
-};
-
-extern struct sbus_dma *dma_chain;
-
-/* Broken hardware... */
-#define DMA_ISBROKEN(dma) ((dma)->revision == dvmarev1)
-#define DMA_ISESC1(dma) ((dma)->revision == dvmaesc1)
-
-/* Main routines in dma.c */
-extern void dvma_init(struct sbus_bus *);
-
-/* Fields in the cond_reg register */
-/* First, the version identification bits */
-#define DMA_DEVICE_ID 0xf0000000 /* Device identification bits */
-#define DMA_VERS0 0x00000000 /* Sunray DMA version */
-#define DMA_ESCV1 0x40000000 /* DMA ESC Version 1 */
-#define DMA_VERS1 0x80000000 /* DMA rev 1 */
-#define DMA_VERS2 0xa0000000 /* DMA rev 2 */
-#define DMA_VERHME 0xb0000000 /* DMA hme gate array */
-#define DMA_VERSPLUS 0x90000000 /* DMA rev 1 PLUS */
-
-#define DMA_HNDL_INTR 0x00000001 /* An IRQ needs to be handled */
-#define DMA_HNDL_ERROR 0x00000002 /* We need to take an error */
-#define DMA_FIFO_ISDRAIN 0x0000000c /* The DMA FIFO is draining */
-#define DMA_INT_ENAB 0x00000010 /* Turn on interrupts */
-#define DMA_FIFO_INV 0x00000020 /* Invalidate the FIFO */
-#define DMA_ACC_SZ_ERR 0x00000040 /* The access size was bad */
-#define DMA_FIFO_STDRAIN 0x00000040 /* DMA_VERS1 Drain the FIFO */
-#define DMA_RST_SCSI 0x00000080 /* Reset the SCSI controller */
-#define DMA_RST_ENET DMA_RST_SCSI /* Reset the ENET controller */
-#define DMA_ST_WRITE 0x00000100 /* write from device to memory */
-#define DMA_ENABLE 0x00000200 /* Fire up DMA, handle requests */
-#define DMA_PEND_READ 0x00000400 /* DMA_VERS1/0/PLUS Pending Read */
-#define DMA_ESC_BURST 0x00000800 /* 1=16byte 0=32byte */
-#define DMA_READ_AHEAD 0x00001800 /* DMA read ahead partial longword */
-#define DMA_DSBL_RD_DRN 0x00001000 /* No EC drain on slave reads */
-#define DMA_BCNT_ENAB 0x00002000 /* If on, use the byte counter */
-#define DMA_TERM_CNTR 0x00004000 /* Terminal counter */
-#define DMA_SCSI_SBUS64 0x00008000 /* HME: Enable 64-bit SBUS mode. */
-#define DMA_CSR_DISAB 0x00010000 /* No FIFO drains during csr */
-#define DMA_SCSI_DISAB 0x00020000 /* No FIFO drains during reg */
-#define DMA_DSBL_WR_INV 0x00020000 /* No EC inval. on slave writes */
-#define DMA_ADD_ENABLE 0x00040000 /* Special ESC DVMA optimization */
-#define DMA_E_BURSTS 0x000c0000 /* ENET: SBUS r/w burst mask */
-#define DMA_E_BURST32 0x00040000 /* ENET: SBUS 32 byte r/w burst */
-#define DMA_E_BURST16 0x00000000 /* ENET: SBUS 16 byte r/w burst */
-#define DMA_BRST_SZ 0x000c0000 /* SCSI: SBUS r/w burst size */
-#define DMA_BRST64 0x000c0000 /* SCSI: 64byte bursts (HME on UltraSparc only) */
-#define DMA_BRST32 0x00040000 /* SCSI: 32byte bursts */
-#define DMA_BRST16 0x00000000 /* SCSI: 16byte bursts */
-#define DMA_BRST0 0x00080000 /* SCSI: no bursts (non-HME gate arrays) */
-#define DMA_ADDR_DISAB 0x00100000 /* No FIFO drains during addr */
-#define DMA_2CLKS 0x00200000 /* Each transfer = 2 clock ticks */
-#define DMA_3CLKS 0x00400000 /* Each transfer = 3 clock ticks */
-#define DMA_EN_ENETAUI DMA_3CLKS /* Put lance into AUI-cable mode */
-#define DMA_CNTR_DISAB 0x00800000 /* No IRQ when DMA_TERM_CNTR set */
-#define DMA_AUTO_NADDR 0x01000000 /* Use "auto nxt addr" feature */
-#define DMA_SCSI_ON 0x02000000 /* Enable SCSI dma */
-#define DMA_PARITY_OFF 0x02000000 /* HME: disable parity checking */
-#define DMA_LOADED_ADDR 0x04000000 /* Address has been loaded */
-#define DMA_LOADED_NADDR 0x08000000 /* Next address has been loaded */
-#define DMA_RESET_FAS366 0x08000000 /* HME: Assert RESET to FAS366 */
-
-/* Values describing the burst-size property from the PROM */
-#define DMA_BURST1 0x01
-#define DMA_BURST2 0x02
-#define DMA_BURST4 0x04
-#define DMA_BURST8 0x08
-#define DMA_BURST16 0x10
-#define DMA_BURST32 0x20
-#define DMA_BURST64 0x40
-#define DMA_BURSTBITS 0x7f
-
-/* Determine highest possible final transfer address given a base */
-#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
-
-/* Yes, I hack a lot of elisp in my spare time... */
-#define DMA_ERROR_P(regs) ((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR))
-#define DMA_IRQ_P(regs) ((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
-#define DMA_WRITE_P(regs) ((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE))
-#define DMA_OFF(__regs) \
-do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
- tmp &= ~DMA_ENABLE; \
- sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_INTSOFF(__regs) \
-do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
- tmp &= ~DMA_INT_ENAB; \
- sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_INTSON(__regs) \
-do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
- tmp |= DMA_INT_ENAB; \
- sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_PUNTFIFO(__regs) \
-do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
- tmp |= DMA_FIFO_INV; \
- sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_SETSTART(__regs, __addr) \
- sbus_writel((u32)(__addr), (__regs) + DMA_ADDR);
-#define DMA_BEGINDMA_W(__regs) \
-do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
- tmp |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB); \
- sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_BEGINDMA_R(__regs) \
-do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
- tmp |= (DMA_ENABLE|DMA_INT_ENAB); \
- tmp &= ~DMA_ST_WRITE; \
- sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-
-/* For certain DMA chips, we need to disable ints upon irq entry
- * and turn them back on when we are done. So in any ESP interrupt
- * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
- * when leaving the handler. You have been warned...
- */
-#define DMA_IRQ_ENTRY(dma, dregs) do { \
- if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
- } while (0)
-
-#define DMA_IRQ_EXIT(dma, dregs) do { \
- if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
- } while(0)
-
-#define for_each_dvma(dma) \
- for((dma) = dma_chain; (dma); (dma) = (dma)->next)
-
-/* From PCI */
-
-#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
-#else
-#define isa_dma_bridge_buggy (0)
-#endif
-
-#endif /* !(_ASM_SPARC64_DMA_H) */
diff --git a/arch/sparc/include/asm/ebus.h b/arch/sparc/include/asm/ebus.h
deleted file mode 100644
index 83a6d16..0000000
--- a/arch/sparc/include/asm/ebus.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_EBUS_H
-#define ___ASM_SPARC_EBUS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/ebus_64.h>
-#else
-#include <asm/ebus_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/ebus_32.h b/arch/sparc/include/asm/ebus_32.h
deleted file mode 100644
index f91f0b2..0000000
--- a/arch/sparc/include/asm/ebus_32.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * ebus.h: PCI to Ebus pseudo driver software state.
- *
- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- *
- * Adopted for sparc by V. Roganov and G. Raiko.
- */
-
-#ifndef __SPARC_EBUS_H
-#define __SPARC_EBUS_H
-
-#ifndef _LINUX_IOPORT_H
-#include <linux/ioport.h>
-#endif
-#include <linux/of_device.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-
-struct linux_ebus_child {
- struct linux_ebus_child *next;
- struct linux_ebus_device *parent;
- struct linux_ebus *bus;
- struct device_node *prom_node;
- struct resource resource[PROMREG_MAX];
- int num_addrs;
- unsigned int irqs[PROMINTR_MAX];
- int num_irqs;
-};
-
-struct linux_ebus_device {
- struct of_device ofdev;
- struct linux_ebus_device *next;
- struct linux_ebus_child *children;
- struct linux_ebus *bus;
- struct device_node *prom_node;
- struct resource resource[PROMREG_MAX];
- int num_addrs;
- unsigned int irqs[PROMINTR_MAX];
- int num_irqs;
-};
-#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
-
-struct linux_ebus {
- struct of_device ofdev;
- struct linux_ebus *next;
- struct linux_ebus_device *devices;
- struct linux_pbm_info *parent;
- struct pci_dev *self;
- struct device_node *prom_node;
-};
-#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
-
-struct linux_ebus_dma {
- unsigned int dcsr;
- unsigned int dacr;
- unsigned int dbcr;
-};
-
-#define EBUS_DCSR_INT_PEND 0x00000001
-#define EBUS_DCSR_ERR_PEND 0x00000002
-#define EBUS_DCSR_DRAIN 0x00000004
-#define EBUS_DCSR_INT_EN 0x00000010
-#define EBUS_DCSR_RESET 0x00000080
-#define EBUS_DCSR_WRITE 0x00000100
-#define EBUS_DCSR_EN_DMA 0x00000200
-#define EBUS_DCSR_CYC_PEND 0x00000400
-#define EBUS_DCSR_DIAG_RD_DONE 0x00000800
-#define EBUS_DCSR_DIAG_WR_DONE 0x00001000
-#define EBUS_DCSR_EN_CNT 0x00002000
-#define EBUS_DCSR_TC 0x00004000
-#define EBUS_DCSR_DIS_CSR_DRN 0x00010000
-#define EBUS_DCSR_BURST_SZ_MASK 0x000c0000
-#define EBUS_DCSR_BURST_SZ_1 0x00080000
-#define EBUS_DCSR_BURST_SZ_4 0x00000000
-#define EBUS_DCSR_BURST_SZ_8 0x00040000
-#define EBUS_DCSR_BURST_SZ_16 0x000c0000
-#define EBUS_DCSR_DIAG_EN 0x00100000
-#define EBUS_DCSR_DIS_ERR_PEND 0x00400000
-#define EBUS_DCSR_TCI_DIS 0x00800000
-#define EBUS_DCSR_EN_NEXT 0x01000000
-#define EBUS_DCSR_DMA_ON 0x02000000
-#define EBUS_DCSR_A_LOADED 0x04000000
-#define EBUS_DCSR_NA_LOADED 0x08000000
-#define EBUS_DCSR_DEV_ID_MASK 0xf0000000
-
-extern struct linux_ebus *ebus_chain;
-
-extern void ebus_init(void);
-
-#define for_each_ebus(bus) \
- for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
-
-#define for_each_ebusdev(dev, bus) \
- for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
-
-#define for_each_edevchild(dev, child) \
- for((child) = (dev)->children; (child); (child) = (child)->next)
-
-#endif /* !(__SPARC_EBUS_H) */
diff --git a/arch/sparc/include/asm/ebus_64.h b/arch/sparc/include/asm/ebus_64.h
deleted file mode 100644
index 14c6a11..0000000
--- a/arch/sparc/include/asm/ebus_64.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * ebus.h: PCI to Ebus pseudo driver software state.
- *
- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
- */
-
-#ifndef __SPARC64_EBUS_H
-#define __SPARC64_EBUS_H
-
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-
-struct linux_ebus_child {
- struct linux_ebus_child *next;
- struct linux_ebus_device *parent;
- struct linux_ebus *bus;
- struct device_node *prom_node;
- struct resource resource[PROMREG_MAX];
- int num_addrs;
- unsigned int irqs[PROMINTR_MAX];
- int num_irqs;
-};
-
-struct linux_ebus_device {
- struct of_device ofdev;
- struct linux_ebus_device *next;
- struct linux_ebus_child *children;
- struct linux_ebus *bus;
- struct device_node *prom_node;
- struct resource resource[PROMREG_MAX];
- int num_addrs;
- unsigned int irqs[PROMINTR_MAX];
- int num_irqs;
-};
-#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
-
-struct linux_ebus {
- struct of_device ofdev;
- struct linux_ebus *next;
- struct linux_ebus_device *devices;
- struct pci_dev *self;
- int index;
- int is_rio;
- struct device_node *prom_node;
-};
-#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
-
-struct ebus_dma_info {
- spinlock_t lock;
- void __iomem *regs;
-
- unsigned int flags;
-#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER 0x00000001
-#define EBUS_DMA_FLAG_TCI_DISABLE 0x00000002
-
- /* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
- * set.
- */
- void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
- void *client_cookie;
- unsigned int irq;
-#define EBUS_DMA_EVENT_ERROR 1
-#define EBUS_DMA_EVENT_DMA 2
-#define EBUS_DMA_EVENT_DEVICE 4
-
- unsigned char name[64];
-};
-
-extern int ebus_dma_register(struct ebus_dma_info *p);
-extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
-extern void ebus_dma_unregister(struct ebus_dma_info *p);
-extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
- size_t len);
-extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
-extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
-extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
-extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
-
-extern struct linux_ebus *ebus_chain;
-
-extern void ebus_init(void);
-
-#define for_each_ebus(bus) \
- for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
-
-#define for_each_ebusdev(dev, bus) \
- for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
-
-#define for_each_edevchild(dev, child) \
- for((child) = (dev)->children; (child); (child) = (child)->next)
-
-#endif /* !(__SPARC64_EBUS_H) */
diff --git a/arch/sparc/include/asm/ebus_dma.h b/arch/sparc/include/asm/ebus_dma.h
new file mode 100644
index 0000000..f07a5b5
--- /dev/null
+++ b/arch/sparc/include/asm/ebus_dma.h
@@ -0,0 +1,35 @@
+#ifndef __ASM_SPARC_EBUS_DMA_H
+#define __ASM_SPARC_EBUS_DMA_H
+
+struct ebus_dma_info {
+ spinlock_t lock;
+ void __iomem *regs;
+
+ unsigned int flags;
+#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER 0x00000001
+#define EBUS_DMA_FLAG_TCI_DISABLE 0x00000002
+
+ /* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
+ * set.
+ */
+ void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
+ void *client_cookie;
+ unsigned int irq;
+#define EBUS_DMA_EVENT_ERROR 1
+#define EBUS_DMA_EVENT_DMA 2
+#define EBUS_DMA_EVENT_DEVICE 4
+
+ unsigned char name[64];
+};
+
+extern int ebus_dma_register(struct ebus_dma_info *p);
+extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
+extern void ebus_dma_unregister(struct ebus_dma_info *p);
+extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
+ size_t len);
+extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
+extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
+extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
+extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
+
+#endif /* __ASM_SPARC_EBUS_DMA_H */
diff --git a/arch/sparc/include/asm/elf_32.h b/arch/sparc/include/asm/elf_32.h
index d043f80..b7ab605 100644
--- a/arch/sparc/include/asm/elf_32.h
+++ b/arch/sparc/include/asm/elf_32.h
@@ -105,11 +105,8 @@
#define ELF_DATA ELFDATA2MSB
#define USE_ELF_CORE_DUMP
-#ifndef CONFIG_SUN4
+
#define ELF_EXEC_PAGESIZE 4096
-#else
-#define ELF_EXEC_PAGESIZE 8192
-#endif
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
@@ -126,7 +123,7 @@
/* Sun4c has none of the capabilities, most sun4m's have them all.
* XXX This is gross, set some global variable at boot time. -DaveM
*/
-#define ELF_HWCAP ((ARCH_SUN4C_SUN4) ? 0 : \
+#define ELF_HWCAP ((ARCH_SUN4C) ? 0 : \
(HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
HWCAP_SPARC_SWAP | \
((srmmu_modtype != Cypress && \
diff --git a/arch/sparc/include/asm/fhc.h b/arch/sparc/include/asm/fhc.h
index 788cbc4..57f1b30 100644
--- a/arch/sparc/include/asm/fhc.h
+++ b/arch/sparc/include/asm/fhc.h
@@ -1,5 +1,4 @@
-/*
- * fhc.h: Structures for central/fhc pseudo driver on Sunfire/Starfire/Wildfire.
+/* fhc.h: FHC and Clock board register definitions.
*
* Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com)
*/
@@ -7,14 +6,6 @@
#ifndef _SPARC64_FHC_H
#define _SPARC64_FHC_H
-#include <linux/timer.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/upa.h>
-
-struct linux_fhc;
-
/* Clock board register offsets. */
#define CLOCK_CTRL 0x00UL /* Main control */
#define CLOCK_STAT1 0x10UL /* Status one */
@@ -29,21 +20,7 @@
#define CLOCK_CTRL_MLED 0x02 /* Mid LED, 1 == on */
#define CLOCK_CTRL_RLED 0x01 /* RIght LED, 1 == on */
-struct linux_central {
- struct linux_fhc *child;
- unsigned long cfreg;
- unsigned long clkregs;
- unsigned long clkver;
- int slots;
- struct device_node *prom_node;
-
- struct linux_prom_ranges central_ranges[PROMREG_MAX];
- int num_central_ranges;
-};
-
/* Firehose controller register offsets */
-struct fhc_regs {
- unsigned long pregs; /* FHC internal regs */
#define FHC_PREGS_ID 0x00UL /* FHC ID */
#define FHC_ID_VERS 0xf0000000 /* Version of this FHC */
#define FHC_ID_PARTID 0x0ffff000 /* Part ID code (0x0f9f == FHC) */
@@ -90,32 +67,14 @@
#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/arch/sparc/include/asm/floppy_32.h b/arch/sparc/include/asm/floppy_32.h
index ae3f00b..c792830 100644
--- a/arch/sparc/include/asm/floppy_32.h
+++ b/arch/sparc/include/asm/floppy_32.h
@@ -6,6 +6,9 @@
#ifndef __ASM_SPARC_FLOPPY_H
#define __ASM_SPARC_FLOPPY_H
+#include <linux/of.h>
+#include <linux/of_device.h>
+
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -343,7 +346,7 @@
r.flags = fd_regs[0].which_io;
r.start = fd_regs[0].phys_addr;
sun_fdc = (struct sun_flpy_controller *)
- sbus_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
+ of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
/* Last minute sanity check... */
if(sun_fdc->status_82072 == 0xff) {
@@ -385,4 +388,15 @@
#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/arch/sparc/include/asm/floppy_64.h b/arch/sparc/include/asm/floppy_64.h
index c39db10..36439d6 100644
--- a/arch/sparc/include/asm/floppy_64.h
+++ b/arch/sparc/include/asm/floppy_64.h
@@ -1,6 +1,6 @@
/* floppy.h: Sparc specific parts of the Floppy driver.
*
- * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*
* Ultra/PCI support added: Sep 1997 Eddie C. Dost (ecd@skynet.be)
@@ -9,18 +9,11 @@
#ifndef __ASM_SPARC64_FLOPPY_H
#define __ASM_SPARC64_FLOPPY_H
-#include <linux/init.h>
-#include <linux/pci.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/idprom.h>
-#include <asm/oplib.h>
#include <asm/auxio.h>
-#include <asm/sbus.h>
-#include <asm/irq.h>
-
/*
* Define this to enable exchanging drive 0 and 1 if only drive 1 is
@@ -50,7 +43,7 @@
/* You'll only ever find one controller on an Ultra anyways. */
static struct sun_flpy_controller *sun_fdc = (struct sun_flpy_controller *)-1;
unsigned long fdc_status;
-static struct sbus_dev *floppy_sdev = NULL;
+static struct of_device *floppy_op = NULL;
struct sun_floppy_ops {
unsigned char (*fd_inb) (unsigned long port);
@@ -291,12 +284,11 @@
return 0;
}
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
#include <asm/ns87303.h>
static struct ebus_dma_info sun_pci_fd_ebus_dma;
-static struct pci_dev *sun_pci_ebus_dev;
+static struct device *sun_floppy_dev;
static int sun_pci_broken_drive = -1;
struct sun_pci_dma_op {
@@ -377,7 +369,7 @@
sun_pci_dma_pending.addr = -1U;
sun_pci_dma_current.addr =
- pci_map_single(sun_pci_ebus_dev,
+ dma_map_single(sun_floppy_dev,
sun_pci_dma_current.buf,
sun_pci_dma_current.len,
sun_pci_dma_current.direction);
@@ -394,7 +386,7 @@
{
ebus_dma_enable(&sun_pci_fd_ebus_dma, 0);
if (sun_pci_dma_current.addr != -1U)
- pci_unmap_single(sun_pci_ebus_dev,
+ dma_unmap_single(sun_floppy_dev,
sun_pci_dma_current.addr,
sun_pci_dma_current.len,
sun_pci_dma_current.direction);
@@ -404,9 +396,9 @@
static void sun_pci_fd_set_dma_mode(int mode)
{
if (mode == DMA_MODE_WRITE)
- sun_pci_dma_pending.direction = PCI_DMA_TODEVICE;
+ sun_pci_dma_pending.direction = DMA_TO_DEVICE;
else
- sun_pci_dma_pending.direction = PCI_DMA_FROMDEVICE;
+ sun_pci_dma_pending.direction = DMA_FROM_DEVICE;
ebus_dma_prepare(&sun_pci_fd_ebus_dma, mode != DMA_MODE_WRITE);
}
@@ -538,80 +530,84 @@
#undef MSR
#undef DOR
-#endif /* CONFIG_PCI */
-
-#ifdef CONFIG_PCI
-static int __init ebus_fdthree_p(struct linux_ebus_device *edev)
+static int __init ebus_fdthree_p(struct device_node *dp)
{
- if (!strcmp(edev->prom_node->name, "fdthree"))
+ if (!strcmp(dp->name, "fdthree"))
return 1;
- if (!strcmp(edev->prom_node->name, "floppy")) {
+ if (!strcmp(dp->name, "floppy")) {
const char *compat;
- compat = of_get_property(edev->prom_node,
- "compatible", NULL);
+ compat = of_get_property(dp, "compatible", NULL);
if (compat && !strcmp(compat, "fdthree"))
return 1;
}
return 0;
}
-#endif
static unsigned long __init sun_floppy_init(void)
{
- char state[128];
- struct sbus_bus *bus;
- struct sbus_dev *sdev = NULL;
static int initialized = 0;
+ struct device_node *dp;
+ struct of_device *op;
+ const char *prop;
+ char state[128];
if (initialized)
return sun_floppy_types[0];
initialized = 1;
- for_all_sbusdev (sdev, bus) {
- if (!strcmp(sdev->prom_name, "SUNW,fdtwo"))
+ op = NULL;
+
+ for_each_node_by_name(dp, "SUNW,fdtwo") {
+ if (strcmp(dp->parent->name, "sbus"))
+ continue;
+ op = of_find_device_by_node(dp);
+ if (op)
break;
}
- if(sdev) {
- floppy_sdev = sdev;
- FLOPPY_IRQ = sdev->irqs[0];
+ if (op) {
+ floppy_op = op;
+ FLOPPY_IRQ = op->irqs[0];
} else {
-#ifdef CONFIG_PCI
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev = NULL;
- unsigned long config = 0;
+ struct device_node *ebus_dp;
void __iomem *auxio_reg;
const char *state_prop;
+ unsigned long config;
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (ebus_fdthree_p(edev))
- goto ebus_done;
+ dp = NULL;
+ for_each_node_by_name(ebus_dp, "ebus") {
+ for (dp = ebus_dp->child; dp; dp = dp->sibling) {
+ if (ebus_fdthree_p(dp))
+ goto found_fdthree;
}
}
- ebus_done:
- if (!edev)
+ found_fdthree:
+ if (!dp)
return 0;
- state_prop = of_get_property(edev->prom_node, "status", NULL);
+ op = of_find_device_by_node(dp);
+ if (!op)
+ return 0;
+
+ state_prop = of_get_property(op->node, "status", NULL);
if (state_prop && !strncmp(state_prop, "disabled", 8))
return 0;
- FLOPPY_IRQ = edev->irqs[0];
+ FLOPPY_IRQ = op->irqs[0];
/* Make sure the high density bit is set, some systems
* (most notably Ultra5/Ultra10) come up with it clear.
*/
- auxio_reg = (void __iomem *) edev->resource[2].start;
+ auxio_reg = (void __iomem *) op->resource[2].start;
writel(readl(auxio_reg)|0x2, auxio_reg);
- sun_pci_ebus_dev = ebus->self;
+ sun_floppy_dev = &op->dev;
spin_lock_init(&sun_pci_fd_ebus_dma.lock);
/* XXX ioremap */
sun_pci_fd_ebus_dma.regs = (void __iomem *)
- edev->resource[1].start;
+ op->resource[1].start;
if (!sun_pci_fd_ebus_dma.regs)
return 0;
@@ -625,7 +621,7 @@
return 0;
/* XXX ioremap */
- sun_fdc = (struct sun_flpy_controller *)edev->resource[0].start;
+ sun_fdc = (struct sun_flpy_controller *) op->resource[0].start;
sun_fdops.fd_inb = sun_pci_fd_inb;
sun_fdops.fd_outb = sun_pci_fd_outb;
@@ -662,12 +658,15 @@
/*
* Find NS87303 SuperIO config registers (through ecpp).
*/
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_node->name, "ecpp")) {
- config = edev->resource[1].start;
- goto config_done;
- }
+ config = 0;
+ for (dp = ebus_dp->child; dp; dp = dp->sibling) {
+ if (!strcmp(dp->name, "ecpp")) {
+ struct of_device *ecpp_op;
+
+ ecpp_op = of_find_device_by_node(dp);
+ if (ecpp_op)
+ config = ecpp_op->resource[1].start;
+ goto config_done;
}
}
config_done:
@@ -716,26 +715,23 @@
#endif /* PCI_FDC_SWAP_DRIVES */
return sun_floppy_types[0];
-#else
- return 0;
-#endif
}
- prom_getproperty(sdev->prom_node, "status", state, sizeof(state));
- if(!strncmp(state, "disabled", 8))
+ prop = of_get_property(op->node, "status", NULL);
+ if (prop && !strncmp(state, "disabled", 8))
return 0;
/*
- * We cannot do sbus_ioremap here: it does request_region,
+ * We cannot do of_ioremap here: it does request_region,
* which the generic floppy driver tries to do once again.
* But we must use the sdev resource values as they have
* had parent ranges applied.
*/
sun_fdc = (struct sun_flpy_controller *)
- (sdev->resource[0].start +
- ((sdev->resource[0].flags & 0x1ffUL) << 32UL));
+ (op->resource[0].start +
+ ((op->resource[0].flags & 0x1ffUL) << 32UL));
/* Last minute sanity check... */
- if(sbus_readb(&sun_fdc->status1_82077) == 0xff) {
+ if (sbus_readb(&sun_fdc->status1_82077) == 0xff) {
sun_fdc = (struct sun_flpy_controller *)-1;
return 0;
}
diff --git a/arch/sparc/include/asm/gpio.h b/arch/sparc/include/asm/gpio.h
new file mode 100644
index 0000000..a0e3ac0
--- /dev/null
+++ b/arch/sparc/include/asm/gpio.h
@@ -0,0 +1,36 @@
+#ifndef __ASM_SPARC_GPIO_H
+#define __ASM_SPARC_GPIO_H
+
+#include <linux/errno.h>
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_GPIOLIB
+
+static inline int gpio_get_value(unsigned int gpio)
+{
+ return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+ __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+ return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+ return -ENOSYS;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+ return -EINVAL;
+}
+
+#endif /* CONFIG_GPIOLIB */
+
+#endif /* __ASM_SPARC_GPIO_H */
diff --git a/arch/sparc/include/asm/io-unit.h b/arch/sparc/include/asm/io-unit.h
index 96823b4..01ab2f6 100644
--- a/arch/sparc/include/asm/io-unit.h
+++ b/arch/sparc/include/asm/io-unit.h
@@ -55,8 +55,4 @@
#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/arch/sparc/include/asm/io_32.h b/arch/sparc/include/asm/io_32.h
index 10d7da4..93fe21e 100644
--- a/arch/sparc/include/asm/io_32.h
+++ b/arch/sparc/include/asm/io_32.h
@@ -293,14 +293,6 @@
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
* hardware pops up.
@@ -308,6 +300,17 @@
#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/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h
index 0bff078..4aee21d 100644
--- a/arch/sparc/include/asm/io_64.h
+++ b/arch/sparc/include/asm/io_64.h
@@ -482,18 +482,16 @@
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
-/* Similarly for SBUS. */
-#define sbus_ioremap(__res, __offset, __size, __name) \
-({ unsigned long __ret; \
- __ret = (__res)->start + (((__res)->flags & 0x1ffUL) << 32UL); \
- __ret += (unsigned long) (__offset); \
- if (! request_region((__ret), (__size), (__name))) \
- __ret = 0UL; \
- (void __iomem *) __ret; \
-})
-
-#define sbus_iounmap(__addr, __size) \
- release_region((unsigned long)(__addr), (__size))
+static inline int sbus_can_dma_64bit(void)
+{
+ return 1;
+}
+static inline int sbus_can_burst64(void)
+{
+ return 1;
+}
+struct device;
+extern void sbus_set_sbus64(struct device *, int);
/*
* Convert a physical pointer to a virtual kernel pointer for /dev/mem
diff --git a/arch/sparc/include/asm/iommu_64.h b/arch/sparc/include/asm/iommu_64.h
index d7b9afc..caf798b 100644
--- a/arch/sparc/include/asm/iommu_64.h
+++ b/arch/sparc/include/asm/iommu_64.h
@@ -48,6 +48,9 @@
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/arch/sparc/include/asm/irq_64.h b/arch/sparc/include/asm/irq_64.h
index e3dd930..71673ec 100644
--- a/arch/sparc/include/asm/irq_64.h
+++ b/arch/sparc/include/asm/irq_64.h
@@ -56,7 +56,6 @@
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/arch/sparc/include/asm/mc146818rtc_64.h b/arch/sparc/include/asm/mc146818rtc_64.h
index e9c0fcc..7238d17 100644
--- a/arch/sparc/include/asm/mc146818rtc_64.h
+++ b/arch/sparc/include/asm/mc146818rtc_64.h
@@ -7,12 +7,8 @@
#include <asm/io.h>
#ifndef RTC_PORT
-#ifdef CONFIG_PCI
-extern unsigned long ds1287_regs;
-#else
-#define ds1287_regs (0UL)
-#endif
-#define RTC_PORT(x) (ds1287_regs + (x))
+extern unsigned long cmos_regs;
+#define RTC_PORT(x) (cmos_regs + (x))
#define RTC_ALWAYS_BCD 0
#endif
@@ -29,6 +25,4 @@
outb_p((val),RTC_PORT(1)); \
})
-#define RTC_IRQ 8
-
#endif /* __ASM_SPARC64_MC146818RTC_H */
diff --git a/arch/sparc/include/asm/memctrl.h b/arch/sparc/include/asm/memctrl.h
new file mode 100644
index 0000000..4065c56
--- /dev/null
+++ b/arch/sparc/include/asm/memctrl.h
@@ -0,0 +1,9 @@
+#ifndef _SPARC_MEMCTRL_H
+#define _SPARC_MEMCTRL_H
+
+typedef int (*dimm_printer_t)(int synd_code, unsigned long paddr, char *buf, int buflen);
+
+int register_dimm_printer(dimm_printer_t func);
+void unregister_dimm_printer(dimm_printer_t func);
+
+#endif /* _SPARC_MEMCTRL_H */
diff --git a/arch/sparc/include/asm/mostek.h b/arch/sparc/include/asm/mostek.h
deleted file mode 100644
index 433be3e..0000000
--- a/arch/sparc/include/asm/mostek.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_MOSTEK_H
-#define ___ASM_SPARC_MOSTEK_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/mostek_64.h>
-#else
-#include <asm/mostek_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/mostek_32.h b/arch/sparc/include/asm/mostek_32.h
deleted file mode 100644
index a99590c..0000000
--- a/arch/sparc/include/asm/mostek_32.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * mostek.h: Describes the various Mostek time of day clock registers.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- * Added intersil code 05/25/98 Chris Davis (cdavis@cois.on.ca)
- */
-
-#ifndef _SPARC_MOSTEK_H
-#define _SPARC_MOSTEK_H
-
-#include <asm/idprom.h>
-#include <asm/io.h>
-
-/* M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ)
- *
- * Data
- * Address Function
- * Bit 7 Bit 6 Bit 5 Bit 4Bit 3 Bit 2 Bit 1 Bit 0
- * 7ff - - - - - - - - Year 00-99
- * 7fe 0 0 0 - - - - - Month 01-12
- * 7fd 0 0 - - - - - - Date 01-31
- * 7fc 0 FT 0 0 0 - - - Day 01-07
- * 7fb KS 0 - - - - - - Hours 00-23
- * 7fa 0 - - - - - - - Minutes 00-59
- * 7f9 ST - - - - - - - Seconds 00-59
- * 7f8 W R S - - - - - Control
- *
- * * ST is STOP BIT
- * * W is WRITE BIT
- * * R is READ BIT
- * * S is SIGN BIT
- * * FT is FREQ TEST BIT
- * * KS is KICK START BIT
- */
-
-/* The Mostek 48t02 real time clock and NVRAM chip. The registers
- * other than the control register are in binary coded decimal. Some
- * control bits also live outside the control register.
- */
-#define mostek_read(_addr) readb(_addr)
-#define mostek_write(_addr,_val) writeb(_val, _addr)
-#define MOSTEK_EEPROM 0x0000UL
-#define MOSTEK_IDPROM 0x07d8UL
-#define MOSTEK_CREG 0x07f8UL
-#define MOSTEK_SEC 0x07f9UL
-#define MOSTEK_MIN 0x07faUL
-#define MOSTEK_HOUR 0x07fbUL
-#define MOSTEK_DOW 0x07fcUL
-#define MOSTEK_DOM 0x07fdUL
-#define MOSTEK_MONTH 0x07feUL
-#define MOSTEK_YEAR 0x07ffUL
-
-struct mostek48t02 {
- volatile char eeprom[2008]; /* This is the eeprom, don't touch! */
- struct idprom idprom; /* The idprom lives here. */
- volatile unsigned char creg; /* Control register */
- volatile unsigned char sec; /* Seconds (0-59) */
- volatile unsigned char min; /* Minutes (0-59) */
- volatile unsigned char hour; /* Hour (0-23) */
- volatile unsigned char dow; /* Day of the week (1-7) */
- volatile unsigned char dom; /* Day of the month (1-31) */
- volatile unsigned char month; /* Month of year (1-12) */
- volatile unsigned char year; /* Year (0-99) */
-};
-
-extern spinlock_t mostek_lock;
-extern void __iomem *mstk48t02_regs;
-
-/* Control register values. */
-#define MSTK_CREG_WRITE 0x80 /* Must set this before placing values. */
-#define MSTK_CREG_READ 0x40 /* Stop updates to allow a clean read. */
-#define MSTK_CREG_SIGN 0x20 /* Slow/speed clock in calibration mode. */
-
-/* Control bits that live in the other registers. */
-#define MSTK_STOP 0x80 /* Stop the clock oscillator. (sec) */
-#define MSTK_KICK_START 0x80 /* Kick start the clock chip. (hour) */
-#define MSTK_FREQ_TEST 0x40 /* Frequency test mode. (day) */
-
-#define MSTK_YEAR_ZERO 1968 /* If year reg has zero, it is 1968. */
-#define MSTK_CVT_YEAR(yr) ((yr) + MSTK_YEAR_ZERO)
-
-/* Masks that define how much space each value takes up. */
-#define MSTK_SEC_MASK 0x7f
-#define MSTK_MIN_MASK 0x7f
-#define MSTK_HOUR_MASK 0x3f
-#define MSTK_DOW_MASK 0x07
-#define MSTK_DOM_MASK 0x3f
-#define MSTK_MONTH_MASK 0x1f
-#define MSTK_YEAR_MASK 0xffU
-
-/* Binary coded decimal conversion macros. */
-#define MSTK_REGVAL_TO_DECIMAL(x) (((x) & 0x0F) + 0x0A * ((x) >> 0x04))
-#define MSTK_DECIMAL_TO_REGVAL(x) ((((x) / 0x0A) << 0x04) + ((x) % 0x0A))
-
-/* Generic register set and get macros for internal use. */
-#define MSTK_GET(regs,var,mask) (MSTK_REGVAL_TO_DECIMAL(((struct mostek48t02 *)regs)->var & MSTK_ ## mask ## _MASK))
-#define MSTK_SET(regs,var,value,mask) do { ((struct mostek48t02 *)regs)->var &= ~(MSTK_ ## mask ## _MASK); ((struct mostek48t02 *)regs)->var |= MSTK_DECIMAL_TO_REGVAL(value) & (MSTK_ ## mask ## _MASK); } while (0)
-
-/* Macros to make register access easier on our fingers. These give you
- * the decimal value of the register requested if applicable. You pass
- * the a pointer to a 'struct mostek48t02'.
- */
-#define MSTK_REG_CREG(regs) (((struct mostek48t02 *)regs)->creg)
-#define MSTK_REG_SEC(regs) MSTK_GET(regs,sec,SEC)
-#define MSTK_REG_MIN(regs) MSTK_GET(regs,min,MIN)
-#define MSTK_REG_HOUR(regs) MSTK_GET(regs,hour,HOUR)
-#define MSTK_REG_DOW(regs) MSTK_GET(regs,dow,DOW)
-#define MSTK_REG_DOM(regs) MSTK_GET(regs,dom,DOM)
-#define MSTK_REG_MONTH(regs) MSTK_GET(regs,month,MONTH)
-#define MSTK_REG_YEAR(regs) MSTK_GET(regs,year,YEAR)
-
-#define MSTK_SET_REG_SEC(regs,value) MSTK_SET(regs,sec,value,SEC)
-#define MSTK_SET_REG_MIN(regs,value) MSTK_SET(regs,min,value,MIN)
-#define MSTK_SET_REG_HOUR(regs,value) MSTK_SET(regs,hour,value,HOUR)
-#define MSTK_SET_REG_DOW(regs,value) MSTK_SET(regs,dow,value,DOW)
-#define MSTK_SET_REG_DOM(regs,value) MSTK_SET(regs,dom,value,DOM)
-#define MSTK_SET_REG_MONTH(regs,value) MSTK_SET(regs,month,value,MONTH)
-#define MSTK_SET_REG_YEAR(regs,value) MSTK_SET(regs,year,value,YEAR)
-
-
-/* The Mostek 48t08 clock chip. Found on Sun4m's I think. It has the
- * same (basically) layout of the 48t02 chip except for the extra
- * NVRAM on board (8 KB against the 48t02's 2 KB).
- */
-struct mostek48t08 {
- char offset[6*1024]; /* Magic things may be here, who knows? */
- struct mostek48t02 regs; /* Here is what we are interested in. */
-};
-
-#ifdef CONFIG_SUN4
-enum sparc_clock_type { MSTK48T02, MSTK48T08, \
-INTERSIL, MSTK_INVALID };
-#else
-enum sparc_clock_type { MSTK48T02, MSTK48T08, \
-MSTK_INVALID };
-#endif
-
-#ifdef CONFIG_SUN4
-/* intersil on a sun 4/260 code data from harris doc */
-struct intersil_dt {
- volatile unsigned char int_csec;
- volatile unsigned char int_hour;
- volatile unsigned char int_min;
- volatile unsigned char int_sec;
- volatile unsigned char int_month;
- volatile unsigned char int_day;
- volatile unsigned char int_year;
- volatile unsigned char int_dow;
-};
-
-struct intersil {
- struct intersil_dt clk;
- struct intersil_dt cmp;
- volatile unsigned char int_intr_reg;
- volatile unsigned char int_cmd_reg;
-};
-
-#define INTERSIL_STOP 0x0
-#define INTERSIL_START 0x8
-#define INTERSIL_INTR_DISABLE 0x0
-#define INTERSIL_INTR_ENABLE 0x10
-#define INTERSIL_32K 0x0
-#define INTERSIL_NORMAL 0x0
-#define INTERSIL_24H 0x4
-#define INTERSIL_INT_100HZ 0x2
-
-/* end of intersil info */
-#endif
-
-#endif /* !(_SPARC_MOSTEK_H) */
diff --git a/arch/sparc/include/asm/mostek_64.h b/arch/sparc/include/asm/mostek_64.h
deleted file mode 100644
index c5652de..0000000
--- a/arch/sparc/include/asm/mostek_64.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/* mostek.h: Describes the various Mostek time of day clock registers.
- *
- * Copyright (C) 1995 David S. Miller (davem@davemloft.net)
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- */
-
-#ifndef _SPARC64_MOSTEK_H
-#define _SPARC64_MOSTEK_H
-
-#include <asm/idprom.h>
-
-/* M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ)
- *
- * Data
- * Address Function
- * Bit 7 Bit 6 Bit 5 Bit 4Bit 3 Bit 2 Bit 1 Bit 0
- * 7ff - - - - - - - - Year 00-99
- * 7fe 0 0 0 - - - - - Month 01-12
- * 7fd 0 0 - - - - - - Date 01-31
- * 7fc 0 FT 0 0 0 - - - Day 01-07
- * 7fb KS 0 - - - - - - Hours 00-23
- * 7fa 0 - - - - - - - Minutes 00-59
- * 7f9 ST - - - - - - - Seconds 00-59
- * 7f8 W R S - - - - - Control
- *
- * * ST is STOP BIT
- * * W is WRITE BIT
- * * R is READ BIT
- * * S is SIGN BIT
- * * FT is FREQ TEST BIT
- * * KS is KICK START BIT
- */
-
-/* The Mostek 48t02 real time clock and NVRAM chip. The registers
- * other than the control register are in binary coded decimal. Some
- * control bits also live outside the control register.
- *
- * We now deal with physical addresses for I/O to the chip. -DaveM
- */
-static inline u8 mostek_read(void __iomem *addr)
-{
- u8 ret;
-
- __asm__ __volatile__("lduba [%1] %2, %0"
- : "=r" (ret)
- : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
- return ret;
-}
-
-static inline void mostek_write(void __iomem *addr, u8 val)
-{
- __asm__ __volatile__("stba %0, [%1] %2"
- : /* no outputs */
- : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
-}
-
-#define MOSTEK_EEPROM 0x0000UL
-#define MOSTEK_IDPROM 0x07d8UL
-#define MOSTEK_CREG 0x07f8UL
-#define MOSTEK_SEC 0x07f9UL
-#define MOSTEK_MIN 0x07faUL
-#define MOSTEK_HOUR 0x07fbUL
-#define MOSTEK_DOW 0x07fcUL
-#define MOSTEK_DOM 0x07fdUL
-#define MOSTEK_MONTH 0x07feUL
-#define MOSTEK_YEAR 0x07ffUL
-
-extern spinlock_t mostek_lock;
-extern void __iomem *mstk48t02_regs;
-
-/* Control register values. */
-#define MSTK_CREG_WRITE 0x80 /* Must set this before placing values. */
-#define MSTK_CREG_READ 0x40 /* Stop updates to allow a clean read. */
-#define MSTK_CREG_SIGN 0x20 /* Slow/speed clock in calibration mode. */
-
-/* Control bits that live in the other registers. */
-#define MSTK_STOP 0x80 /* Stop the clock oscillator. (sec) */
-#define MSTK_KICK_START 0x80 /* Kick start the clock chip. (hour) */
-#define MSTK_FREQ_TEST 0x40 /* Frequency test mode. (day) */
-
-#define MSTK_YEAR_ZERO 1968 /* If year reg has zero, it is 1968. */
-#define MSTK_CVT_YEAR(yr) ((yr) + MSTK_YEAR_ZERO)
-
-/* Masks that define how much space each value takes up. */
-#define MSTK_SEC_MASK 0x7f
-#define MSTK_MIN_MASK 0x7f
-#define MSTK_HOUR_MASK 0x3f
-#define MSTK_DOW_MASK 0x07
-#define MSTK_DOM_MASK 0x3f
-#define MSTK_MONTH_MASK 0x1f
-#define MSTK_YEAR_MASK 0xffU
-
-/* Binary coded decimal conversion macros. */
-#define MSTK_REGVAL_TO_DECIMAL(x) (((x) & 0x0F) + 0x0A * ((x) >> 0x04))
-#define MSTK_DECIMAL_TO_REGVAL(x) ((((x) / 0x0A) << 0x04) + ((x) % 0x0A))
-
-/* Generic register set and get macros for internal use. */
-#define MSTK_GET(regs,name) \
- (MSTK_REGVAL_TO_DECIMAL(mostek_read(regs + MOSTEK_ ## name) & MSTK_ ## name ## _MASK))
-#define MSTK_SET(regs,name,value) \
-do { u8 __val = mostek_read(regs + MOSTEK_ ## name); \
- __val &= ~(MSTK_ ## name ## _MASK); \
- __val |= (MSTK_DECIMAL_TO_REGVAL(value) & \
- (MSTK_ ## name ## _MASK)); \
- mostek_write(regs + MOSTEK_ ## name, __val); \
-} while(0)
-
-/* Macros to make register access easier on our fingers. These give you
- * the decimal value of the register requested if applicable. You pass
- * the a pointer to a 'struct mostek48t02'.
- */
-#define MSTK_REG_CREG(regs) (mostek_read((regs) + MOSTEK_CREG))
-#define MSTK_REG_SEC(regs) MSTK_GET(regs,SEC)
-#define MSTK_REG_MIN(regs) MSTK_GET(regs,MIN)
-#define MSTK_REG_HOUR(regs) MSTK_GET(regs,HOUR)
-#define MSTK_REG_DOW(regs) MSTK_GET(regs,DOW)
-#define MSTK_REG_DOM(regs) MSTK_GET(regs,DOM)
-#define MSTK_REG_MONTH(regs) MSTK_GET(regs,MONTH)
-#define MSTK_REG_YEAR(regs) MSTK_GET(regs,YEAR)
-
-#define MSTK_SET_REG_SEC(regs,value) MSTK_SET(regs,SEC,value)
-#define MSTK_SET_REG_MIN(regs,value) MSTK_SET(regs,MIN,value)
-#define MSTK_SET_REG_HOUR(regs,value) MSTK_SET(regs,HOUR,value)
-#define MSTK_SET_REG_DOW(regs,value) MSTK_SET(regs,DOW,value)
-#define MSTK_SET_REG_DOM(regs,value) MSTK_SET(regs,DOM,value)
-#define MSTK_SET_REG_MONTH(regs,value) MSTK_SET(regs,MONTH,value)
-#define MSTK_SET_REG_YEAR(regs,value) MSTK_SET(regs,YEAR,value)
-
-
-/* The Mostek 48t08 clock chip. Found on Sun4m's I think. It has the
- * same (basically) layout of the 48t02 chip except for the extra
- * NVRAM on board (8 KB against the 48t02's 2 KB).
- */
-#define MOSTEK_48T08_OFFSET 0x0000UL /* Lower NVRAM portions */
-#define MOSTEK_48T08_48T02 0x1800UL /* Offset to 48T02 chip */
-
-/* SUN5 systems usually have 48t59 model clock chipsets. But we keep the older
- * clock chip definitions around just in case.
- */
-#define MOSTEK_48T59_OFFSET 0x0000UL /* Lower NVRAM portions */
-#define MOSTEK_48T59_48T02 0x1800UL /* Offset to 48T02 chip */
-
-#endif /* !(_SPARC64_MOSTEK_H) */
diff --git a/arch/sparc/include/asm/obio.h b/arch/sparc/include/asm/obio.h
index 1a7544c..4ade0c8 100644
--- a/arch/sparc/include/asm/obio.h
+++ b/arch/sparc/include/asm/obio.h
@@ -155,17 +155,6 @@
"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/arch/sparc/include/asm/of_device.h b/arch/sparc/include/asm/of_device.h
index bba777a..a5d9811 100644
--- a/arch/sparc/include/asm/of_device.h
+++ b/arch/sparc/include/asm/of_device.h
@@ -30,6 +30,8 @@
extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
+extern void of_propagate_archdata(struct of_device *bus);
+
/* This is just here during the transition */
#include <linux/of_platform.h>
diff --git a/arch/sparc/include/asm/of_platform.h b/arch/sparc/include/asm/of_platform.h
index 2348ab9..90da990 100644
--- a/arch/sparc/include/asm/of_platform.h
+++ b/arch/sparc/include/asm/of_platform.h
@@ -13,9 +13,6 @@
*
*/
-extern struct bus_type ebus_bus_type;
-extern struct bus_type sbus_bus_type;
-
#define of_bus_type of_platform_bus_type /* for compatibility */
#endif
diff --git a/arch/sparc/include/asm/oplib_32.h b/arch/sparc/include/asm/oplib_32.h
index b2631da..699da05 100644
--- a/arch/sparc/include/asm/oplib_32.h
+++ b/arch/sparc/include/asm/oplib_32.h
@@ -21,7 +21,6 @@
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/arch/sparc/include/asm/page_32.h b/arch/sparc/include/asm/page_32.h
index cf5fb70..d1806ed 100644
--- a/arch/sparc/include/asm/page_32.h
+++ b/arch/sparc/include/asm/page_32.h
@@ -8,11 +8,8 @@
#ifndef _SPARC_PAGE_H
#define _SPARC_PAGE_H
-#ifdef CONFIG_SUN4
-#define PAGE_SHIFT 13
-#else
#define PAGE_SHIFT 12
-#endif
+
#ifndef __ASSEMBLY__
/* I have my suspicions... -DaveM */
#define PAGE_SIZE (1UL << PAGE_SHIFT)
diff --git a/arch/sparc/include/asm/page_64.h b/arch/sparc/include/asm/page_64.h
index b579b91..4274ed1 100644
--- a/arch/sparc/include/asm/page_64.h
+++ b/arch/sparc/include/asm/page_64.h
@@ -38,6 +38,8 @@
#ifndef __ASSEMBLY__
+#define WANT_PAGE_VIRTUAL
+
extern void _clear_page(void *page);
#define clear_page(X) _clear_page((void *)(X))
struct page;
diff --git a/arch/sparc/include/asm/parport.h b/arch/sparc/include/asm/parport.h
index d983062..dff3f02 100644
--- a/arch/sparc/include/asm/parport.h
+++ b/arch/sparc/include/asm/parport.h
@@ -8,7 +8,7 @@
#include <linux/of_device.h>
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
#include <asm/ns87303.h>
#include <asm/prom.h>
@@ -215,7 +215,7 @@
return 0;
}
-static struct of_device_id ecpp_match[] = {
+static const struct of_device_id ecpp_match[] = {
{
.name = "ecpp",
},
diff --git a/arch/sparc/include/asm/pci_32.h b/arch/sparc/include/asm/pci_32.h
index 0ee949d..b41c4c1 100644
--- a/arch/sparc/include/asm/pci_32.h
+++ b/arch/sparc/include/asm/pci_32.h
@@ -3,6 +3,8 @@
#ifdef __KERNEL__
+#include <linux/dma-mapping.h>
+
/* Can be used to override the logic in pci_scan_bus for skipping
* already-configured bus numbers - to be used for buggy BIOSes
* or architectures with incomplete PCI setup by the loader.
diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h
index 08237fd..e0cabe7 100644
--- a/arch/sparc/include/asm/pgtable_32.h
+++ b/arch/sparc/include/asm/pgtable_32.h
@@ -14,11 +14,7 @@
#include <linux/spinlock.h>
#include <linux/swap.h>
#include <asm/types.h>
-#ifdef CONFIG_SUN4
-#include <asm/pgtsun4.h>
-#else
#include <asm/pgtsun4c.h>
-#endif
#include <asm/pgtsrmmu.h>
#include <asm/vac-ops.h>
#include <asm/oplib.h>
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index bb9ec2c..b049abf 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -770,6 +770,8 @@
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/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h
index fd55522..900d447 100644
--- a/arch/sparc/include/asm/prom.h
+++ b/arch/sparc/include/asm/prom.h
@@ -18,6 +18,7 @@
*/
#include <linux/types.h>
#include <linux/proc_fs.h>
+#include <linux/mutex.h>
#include <asm/atomic.h>
#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 2
@@ -73,6 +74,7 @@
extern struct device_node *of_find_node_by_cpuid(int cpuid);
extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
+extern struct mutex of_set_property_mutex;
extern int of_getintprop_default(struct device_node *np,
const char *name,
int def);
@@ -94,6 +96,16 @@
{
}
+/* 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/arch/sparc/include/asm/ptrace_64.h b/arch/sparc/include/asm/ptrace_64.h
index 06e4914..3d3e9c1 100644
--- a/arch/sparc/include/asm/ptrace_64.h
+++ b/arch/sparc/include/asm/ptrace_64.h
@@ -113,6 +113,8 @@
#ifdef __KERNEL__
+#include <linux/threads.h>
+
static inline int pt_regs_trap_type(struct pt_regs *regs)
{
return regs->magic & 0x1ff;
@@ -138,6 +140,7 @@
struct 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/arch/sparc/include/asm/reboot.h b/arch/sparc/include/asm/reboot.h
deleted file mode 100644
index 3f3f43f..0000000
--- a/arch/sparc/include/asm/reboot.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SPARC64_REBOOT_H
-#define _SPARC64_REBOOT_H
-
-extern void machine_alt_power_off(void);
-
-#endif /* _SPARC64_REBOOT_H */
diff --git a/arch/sparc/include/asm/rtc.h b/arch/sparc/include/asm/rtc.h
deleted file mode 100644
index f9ecb1f..0000000
--- a/arch/sparc/include/asm/rtc.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * rtc.h: Definitions for access to the Mostek real time clock
- *
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- */
-
-#ifndef _RTC_H
-#define _RTC_H
-
-#include <linux/ioctl.h>
-
-struct rtc_time
-{
- int sec; /* Seconds (0-59) */
- int min; /* Minutes (0-59) */
- int hour; /* Hour (0-23) */
- int dow; /* Day of the week (1-7) */
- int dom; /* Day of the month (1-31) */
- int month; /* Month of year (1-12) */
- int year; /* Year (0-99) */
-};
-
-#define RTCGET _IOR('p', 20, struct rtc_time)
-#define RTCSET _IOW('p', 21, struct rtc_time)
-
-#endif
diff --git a/arch/sparc/include/asm/sbus.h b/arch/sparc/include/asm/sbus.h
deleted file mode 100644
index f82481a..0000000
--- a/arch/sparc/include/asm/sbus.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_SBUS_H
-#define ___ASM_SPARC_SBUS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/sbus_64.h>
-#else
-#include <asm/sbus_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/sbus_32.h b/arch/sparc/include/asm/sbus_32.h
deleted file mode 100644
index a7b4fa2..0000000
--- a/arch/sparc/include/asm/sbus_32.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * sbus.h: Defines for the Sun SBus.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _SPARC_SBUS_H
-#define _SPARC_SBUS_H
-
-#include <linux/dma-mapping.h>
-#include <linux/ioport.h>
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/scatterlist.h>
-
-/* We scan which devices are on the SBus using the PROM node device
- * tree. SBus devices are described in two different ways. You can
- * either get an absolute address at which to access the device, or
- * you can get a SBus 'slot' number and an offset within that slot.
- */
-
-/* The base address at which to calculate device OBIO addresses. */
-#define SUN_SBUS_BVADDR 0xf8000000
-#define SBUS_OFF_MASK 0x01ffffff
-
-/* These routines are used to calculate device address from slot
- * numbers + offsets, and vice versa.
- */
-
-static inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
-{
- return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<25)+(offset));
-}
-
-static inline int sbus_dev_slot(unsigned long dev_addr)
-{
- return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>25);
-}
-
-struct sbus_bus;
-
-/* Linux SBUS device tables */
-struct sbus_dev {
- struct of_device ofdev;
- struct sbus_bus *bus;
- struct sbus_dev *next;
- struct sbus_dev *child;
- struct sbus_dev *parent;
- int prom_node;
- char prom_name[64];
- int slot;
-
- struct resource resource[PROMREG_MAX];
-
- struct linux_prom_registers reg_addrs[PROMREG_MAX];
- int num_registers;
-
- struct linux_prom_ranges device_ranges[PROMREG_MAX];
- int num_device_ranges;
-
- unsigned int irqs[4];
- int num_irqs;
-};
-#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
-
-/* This struct describes the SBus(s) found on this machine. */
-struct sbus_bus {
- struct of_device ofdev;
- struct sbus_dev *devices; /* Link to devices on this SBus */
- struct sbus_bus *next; /* next SBus, if more than one SBus */
- int prom_node; /* PROM device tree node for this SBus */
- char prom_name[64]; /* Usually "sbus" or "sbi" */
- int clock_freq;
-
- struct linux_prom_ranges sbus_ranges[PROMREG_MAX];
- int num_sbus_ranges;
-
- int devid;
- int board;
-};
-#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
-
-extern struct sbus_bus *sbus_root;
-
-static inline int
-sbus_is_slave(struct sbus_dev *dev)
-{
- /* XXX Have to write this for sun4c's */
- return 0;
-}
-
-/* Device probing routines could find these handy */
-#define for_each_sbus(bus) \
- for((bus) = sbus_root; (bus); (bus)=(bus)->next)
-
-#define for_each_sbusdev(device, bus) \
- for((device) = (bus)->devices; (device); (device)=(device)->next)
-
-#define for_all_sbusdev(device, bus) \
- for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
- for ((device) = (bus)->devices; (device); (device) = (device)->next)
-
-/* Driver DVMA interfaces. */
-#define sbus_can_dma_64bit(sdev) (0) /* actually, sparc_cpu_model==sun4d */
-#define sbus_can_burst64(sdev) (0) /* actually, sparc_cpu_model==sun4d */
-extern void sbus_set_sbus64(struct sbus_dev *, int);
-extern void sbus_fill_device_irq(struct sbus_dev *);
-
-/* These yield IOMMU mappings in consistent mode. */
-extern void *sbus_alloc_consistent(struct sbus_dev *, long, u32 *dma_addrp);
-extern void sbus_free_consistent(struct sbus_dev *, long, void *, u32);
-void prom_adjust_ranges(struct linux_prom_ranges *, int,
- struct linux_prom_ranges *, int);
-
-#define SBUS_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL
-#define SBUS_DMA_TODEVICE DMA_TO_DEVICE
-#define SBUS_DMA_FROMDEVICE DMA_FROM_DEVICE
-#define SBUS_DMA_NONE DMA_NONE
-
-/* All the rest use streaming mode mappings. */
-extern dma_addr_t sbus_map_single(struct sbus_dev *, void *, size_t, int);
-extern void sbus_unmap_single(struct sbus_dev *, dma_addr_t, size_t, int);
-extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int, int);
-extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int);
-
-/* Finally, allow explicit synchronization of streamable mappings. */
-extern void sbus_dma_sync_single_for_cpu(struct sbus_dev *, dma_addr_t, size_t, int);
-#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
-extern void sbus_dma_sync_single_for_device(struct sbus_dev *, dma_addr_t, size_t, int);
-extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, int, int);
-#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
-extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int);
-
-/* Eric Brower (ebrower@usa.net)
- * Translate SBus interrupt levels to ino values--
- * this is used when converting sbus "interrupts" OBP
- * node values to "intr" node values, and is platform
- * dependent. If only we could call OBP with
- * "sbus-intr>cpu (sbint -- ino)" from kernel...
- * See .../drivers/sbus/sbus.c for details.
- */
-BTFIXUPDEF_CALL(unsigned int, sbint_to_irq, struct sbus_dev *sdev, unsigned int)
-#define sbint_to_irq(sdev, sbint) BTFIXUP_CALL(sbint_to_irq)(sdev, sbint)
-
-extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
-extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
-extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
-extern int sbus_arch_preinit(void);
-extern void sbus_arch_postinit(void);
-
-#endif /* !(_SPARC_SBUS_H) */
diff --git a/arch/sparc/include/asm/sbus_64.h b/arch/sparc/include/asm/sbus_64.h
deleted file mode 100644
index b606c14..0000000
--- a/arch/sparc/include/asm/sbus_64.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/* sbus.h: Defines for the Sun SBus.
- *
- * Copyright (C) 1996, 1999, 2007 David S. Miller (davem@davemloft.net)
- */
-
-#ifndef _SPARC64_SBUS_H
-#define _SPARC64_SBUS_H
-
-#include <linux/dma-mapping.h>
-#include <linux/ioport.h>
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/iommu.h>
-#include <asm/scatterlist.h>
-
-/* We scan which devices are on the SBus using the PROM node device
- * tree. SBus devices are described in two different ways. You can
- * either get an absolute address at which to access the device, or
- * you can get a SBus 'slot' number and an offset within that slot.
- */
-
-/* The base address at which to calculate device OBIO addresses. */
-#define SUN_SBUS_BVADDR 0x00000000
-#define SBUS_OFF_MASK 0x0fffffff
-
-/* These routines are used to calculate device address from slot
- * numbers + offsets, and vice versa.
- */
-
-static inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
-{
- return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<28)+(offset));
-}
-
-static inline int sbus_dev_slot(unsigned long dev_addr)
-{
- return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>28);
-}
-
-struct sbus_bus;
-
-/* Linux SBUS device tables */
-struct sbus_dev {
- struct of_device ofdev;
- struct sbus_bus *bus;
- struct sbus_dev *next;
- struct sbus_dev *child;
- struct sbus_dev *parent;
- int prom_node;
- char prom_name[64];
- int slot;
-
- struct resource resource[PROMREG_MAX];
-
- struct linux_prom_registers reg_addrs[PROMREG_MAX];
- int num_registers;
-
- struct linux_prom_ranges device_ranges[PROMREG_MAX];
- int num_device_ranges;
-
- unsigned int irqs[4];
- int num_irqs;
-};
-#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
-
-/* This struct describes the SBus(s) found on this machine. */
-struct sbus_bus {
- struct of_device ofdev;
- struct sbus_dev *devices; /* Tree of SBUS devices */
- struct sbus_bus *next; /* Next SBUS in system */
- int prom_node; /* OBP node of SBUS */
- char prom_name[64]; /* Usually "sbus" or "sbi" */
- int clock_freq;
-
- struct linux_prom_ranges sbus_ranges[PROMREG_MAX];
- int num_sbus_ranges;
-
- int portid;
-};
-#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
-
-extern struct sbus_bus *sbus_root;
-
-/* Device probing routines could find these handy */
-#define for_each_sbus(bus) \
- for((bus) = sbus_root; (bus); (bus)=(bus)->next)
-
-#define for_each_sbusdev(device, bus) \
- for((device) = (bus)->devices; (device); (device)=(device)->next)
-
-#define for_all_sbusdev(device, bus) \
- for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
- for ((device) = (bus)->devices; (device); (device) = (device)->next)
-
-/* Driver DVMA interfaces. */
-#define sbus_can_dma_64bit(sdev) (1)
-#define sbus_can_burst64(sdev) (1)
-extern void sbus_set_sbus64(struct sbus_dev *, int);
-extern void sbus_fill_device_irq(struct sbus_dev *);
-
-static inline void *sbus_alloc_consistent(struct sbus_dev *sdev , size_t size,
- dma_addr_t *dma_handle)
-{
- return dma_alloc_coherent(&sdev->ofdev.dev, size,
- dma_handle, GFP_ATOMIC);
-}
-
-static inline void sbus_free_consistent(struct sbus_dev *sdev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
- return dma_free_coherent(&sdev->ofdev.dev, size, vaddr, dma_handle);
-}
-
-#define SBUS_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL
-#define SBUS_DMA_TODEVICE DMA_TO_DEVICE
-#define SBUS_DMA_FROMDEVICE DMA_FROM_DEVICE
-#define SBUS_DMA_NONE DMA_NONE
-
-/* All the rest use streaming mode mappings. */
-static inline dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr,
- size_t size, int direction)
-{
- return dma_map_single(&sdev->ofdev.dev, ptr, size,
- (enum dma_data_direction) direction);
-}
-
-static inline void sbus_unmap_single(struct sbus_dev *sdev,
- dma_addr_t dma_addr, size_t size,
- int direction)
-{
- dma_unmap_single(&sdev->ofdev.dev, dma_addr, size,
- (enum dma_data_direction) direction);
-}
-
-static inline int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg,
- int nents, int direction)
-{
- return dma_map_sg(&sdev->ofdev.dev, sg, nents,
- (enum dma_data_direction) direction);
-}
-
-static inline void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg,
- int nents, int direction)
-{
- dma_unmap_sg(&sdev->ofdev.dev, sg, nents,
- (enum dma_data_direction) direction);
-}
-
-/* Finally, allow explicit synchronization of streamable mappings. */
-static inline void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev,
- dma_addr_t dma_handle,
- size_t size, int direction)
-{
- dma_sync_single_for_cpu(&sdev->ofdev.dev, dma_handle, size,
- (enum dma_data_direction) direction);
-}
-#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
-
-static inline void sbus_dma_sync_single_for_device(struct sbus_dev *sdev,
- dma_addr_t dma_handle,
- size_t size, int direction)
-{
- /* No flushing needed to sync cpu writes to the device. */
-}
-
-static inline void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev,
- struct scatterlist *sg,
- int nents, int direction)
-{
- dma_sync_sg_for_cpu(&sdev->ofdev.dev, sg, nents,
- (enum dma_data_direction) direction);
-}
-#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
-
-static inline void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev,
- struct scatterlist *sg,
- int nents, int direction)
-{
- /* No flushing needed to sync cpu writes to the device. */
-}
-
-extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
-extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
-extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
-extern int sbus_arch_preinit(void);
-extern void sbus_arch_postinit(void);
-
-#endif /* !(_SPARC64_SBUS_H) */
diff --git a/arch/sparc/include/asm/spinlock_32.h b/arch/sparc/include/asm/spinlock_32.h
index de2249b..bf2d532 100644
--- a/arch/sparc/include/asm/spinlock_32.h
+++ b/arch/sparc/include/asm/spinlock_32.h
@@ -6,8 +6,6 @@
#ifndef __SPARC_SPINLOCK_H
#define __SPARC_SPINLOCK_H
-#include <linux/threads.h> /* For NR_CPUS */
-
#ifndef __ASSEMBLY__
#include <asm/psr.h>
diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h
index 0006fe9..120cfe4 100644
--- a/arch/sparc/include/asm/spinlock_64.h
+++ b/arch/sparc/include/asm/spinlock_64.h
@@ -6,8 +6,6 @@
#ifndef __SPARC64_SPINLOCK_H
#define __SPARC64_SPINLOCK_H
-#include <linux/threads.h> /* For NR_CPUS */
-
#ifndef __ASSEMBLY__
/* To get debugging spinlocks which detect and catch
diff --git a/arch/sparc/include/asm/sstate.h b/arch/sparc/include/asm/sstate.h
deleted file mode 100644
index a7c35db..0000000
--- a/arch/sparc/include/asm/sstate.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef _SPARC64_SSTATE_H
-#define _SPARC64_SSTATE_H
-
-extern void sstate_booting(void);
-extern void sstate_running(void);
-extern void sstate_halt(void);
-extern void sstate_poweroff(void);
-extern void sstate_panic(void);
-extern void sstate_reboot(void);
-
-extern void sun4v_sstate_init(void);
-
-#endif /* _SPARC64_SSTATE_H */
diff --git a/arch/sparc/include/asm/starfire.h b/arch/sparc/include/asm/starfire.h
index 07bafd3..d56ce60a 100644
--- a/arch/sparc/include/asm/starfire.h
+++ b/arch/sparc/include/asm/starfire.h
@@ -12,7 +12,6 @@
extern int this_is_starfire;
extern void check_if_starfire(void);
-extern void starfire_cpu_setup(void);
extern int starfire_hard_smp_processor_id(void);
extern void starfire_hookup(int);
extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid);
diff --git a/arch/sparc/include/asm/sun4paddr.h b/arch/sparc/include/asm/sun4paddr.h
deleted file mode 100644
index d52985f..0000000
--- a/arch/sparc/include/asm/sun4paddr.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * sun4paddr.h: Various physical addresses on sun4 machines
- *
- * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
- * Copyright (C) 1998 Chris Davis (cdavis@cois.on.ca)
- *
- * Now supports more sun4's
- */
-
-#ifndef _SPARC_SUN4PADDR_H
-#define _SPARC_SUN4PADDR_H
-
-#define SUN4_IE_PHYSADDR 0xf5000000
-#define SUN4_UNUSED_PHYSADDR 0
-
-/* these work for me */
-#define SUN4_200_MEMREG_PHYSADDR 0xf4000000
-#define SUN4_200_CLOCK_PHYSADDR 0xf3000000
-#define SUN4_200_BWTWO_PHYSADDR 0xfd000000
-#define SUN4_200_ETH_PHYSADDR 0xf6000000
-#define SUN4_200_SI_PHYSADDR 0xff200000
-
-/* these were here before */
-#define SUN4_300_MEMREG_PHYSADDR 0xf4000000
-#define SUN4_300_CLOCK_PHYSADDR 0xf2000000
-#define SUN4_300_TIMER_PHYSADDR 0xef000000
-#define SUN4_300_ETH_PHYSADDR 0xf9000000
-#define SUN4_300_BWTWO_PHYSADDR 0xfb400000
-#define SUN4_300_DMA_PHYSADDR 0xfa001000
-#define SUN4_300_ESP_PHYSADDR 0xfa000000
-
-/* Are these right? */
-#define SUN4_400_MEMREG_PHYSADDR 0xf4000000
-#define SUN4_400_CLOCK_PHYSADDR 0xf2000000
-#define SUN4_400_TIMER_PHYSADDR 0xef000000
-#define SUN4_400_ETH_PHYSADDR 0xf9000000
-#define SUN4_400_BWTWO_PHYSADDR 0xfb400000
-#define SUN4_400_DMA_PHYSADDR 0xfa001000
-#define SUN4_400_ESP_PHYSADDR 0xfa000000
-
-/*
- these are the actual values set and used in the code. Unused items set
- to SUN_UNUSED_PHYSADDR
- */
-
-extern int sun4_memreg_physaddr; /* memory register (ecc?) */
-extern int sun4_clock_physaddr; /* system clock */
-extern int sun4_timer_physaddr; /* timer, where applicable */
-extern int sun4_eth_physaddr; /* onboard ethernet (ie/le) */
-extern int sun4_si_physaddr; /* sun3 scsi adapter */
-extern int sun4_bwtwo_physaddr; /* onboard bw2 */
-extern int sun4_dma_physaddr; /* scsi dma */
-extern int sun4_esp_physaddr; /* esp scsi */
-extern int sun4_ie_physaddr; /* interrupt enable */
-
-#endif /* !(_SPARC_SUN4PADDR_H) */
diff --git a/arch/sparc/include/asm/sun4prom.h b/arch/sparc/include/asm/sun4prom.h
deleted file mode 100644
index 9c8b4cb..0000000
--- a/arch/sparc/include/asm/sun4prom.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * sun4prom.h -- interface to sun4 PROM monitor. We don't use most of this,
- * so most of these are just placeholders.
- */
-
-#ifndef _SUN4PROM_H_
-#define _SUN4PROM_H_
-
-/*
- * Although this looks similar to an romvec for a OpenProm machine, it is
- * actually closer to what was used in the Sun2 and Sun3.
- *
- * V2 entries exist only in version 2 PROMs and later, V3 in version 3 and later.
- *
- * Many of the function prototypes are guesses. Some are certainly wrong.
- * Use with care.
- */
-
-typedef struct {
- char *initSP; /* Initial system stack ptr */
- void (*startmon)(void); /* Initial PC for hardware */
- int *diagberr; /* Bus err handler for diags */
- struct linux_arguments_v0 **bootParam; /* Info for bootstrapped pgm */
- unsigned int *memorysize; /* Usable memory in bytes */
- unsigned char (*getchar)(void); /* Get char from input device */
- void (*putchar)(char); /* Put char to output device */
- int (*mayget)(void); /* Maybe get char, or -1 */
- int (*mayput)(int); /* Maybe put char, or -1 */
- unsigned char *echo; /* Should getchar echo? */
- unsigned char *insource; /* Input source selector */
- unsigned char *outsink; /* Output sink selector */
- int (*getkey)(void); /* Get next key if one exists */
- void (*initgetkey)(void); /* Initialize get key */
- unsigned int *translation; /* Kbd translation selector */
- unsigned char *keybid; /* Keyboard ID byte */
- int *screen_x; /* V2: Screen x pos (r/o) */
- int *screen_y; /* V2: Screen y pos (r/o) */
- struct keybuf *keybuf; /* Up/down keycode buffer */
- char *monid; /* Monitor version ID */
- void (*fbwritechar)(char); /* Write a character to FB */
- int *fbAddr; /* Address of frame buffer */
- char **font; /* Font table for FB */
- void (*fbwritestr)(char *); /* Write string to FB */
- void (*reboot)(char *); /* e.g. reboot("sd()vmlinux") */
- unsigned char *linebuf; /* The line input buffer */
- unsigned char **lineptr; /* Cur pointer into linebuf */
- int *linesize; /* length of line in linebuf */
- void (*getline)(char *); /* Get line from user */
- unsigned char (*getnextchar)(void); /* Get next char from linebuf */
- unsigned char (*peeknextchar)(void); /* Peek at next char */
- int *fbthere; /* =1 if frame buffer there */
- int (*getnum)(void); /* Grab hex num from line */
- int (*printf)(char *, ...); /* See prom_printf() instead */
- void (*printhex)(int); /* Format N digits in hex */
- unsigned char *leds; /* RAM copy of LED register */
- void (*setLEDs)(unsigned char *); /* Sets LED's and RAM copy */
- void (*NMIaddr)(void *); /* Addr for level 7 vector */
- void (*abortentry)(void); /* Entry for keyboard abort */
- int *nmiclock; /* Counts up in msec */
- int *FBtype; /* Frame buffer type */
- unsigned int romvecversion; /* Version number for this romvec */
- struct globram *globram; /* monitor global variables ??? */
- void * kbdaddr; /* Addr of keyboard in use */
- int *keyrinit; /* ms before kbd repeat */
- unsigned char *keyrtick; /* ms between repetitions */
- unsigned int *memoryavail; /* V1: Main mem usable size */
- long *resetaddr; /* where to jump on a reset */
- long *resetmap; /* pgmap entry for resetaddr */
- void (*exittomon)(void); /* Exit from user program */
- unsigned char **memorybitmap; /* V1: &{0 or &bits} */
- void (*setcxsegmap)(int ctxt, char *va, int pmeg); /* Set seg in any context */
- void (**vector_cmd)(void *); /* V2: Handler for 'v' cmd */
- unsigned long *expectedtrapsig; /* V3: Location of the expected trap signal */
- unsigned long *trapvectorbasetable; /* V3: Address of the trap vector table */
- int unused1;
- int unused2;
- int unused3;
- int unused4;
-} linux_sun4_romvec;
-
-extern linux_sun4_romvec *sun4_romvec;
-
-#endif /* _SUN4PROM_H_ */
diff --git a/arch/sparc/include/asm/system_32.h b/arch/sparc/include/asm/system_32.h
index b4b0244..8623fc4 100644
--- a/arch/sparc/include/asm/system_32.h
+++ b/arch/sparc/include/asm/system_32.h
@@ -34,13 +34,7 @@
extern enum sparc_cpu sparc_cpu_model;
-#ifndef CONFIG_SUN4
-#define ARCH_SUN4C_SUN4 (sparc_cpu_model==sun4c)
-#define ARCH_SUN4 0
-#else
-#define ARCH_SUN4C_SUN4 1
-#define ARCH_SUN4 1
-#endif
+#define ARCH_SUN4C (sparc_cpu_model==sun4c)
#define SUN4M_NCPUS 4 /* Architectural limit of sun4m. */
@@ -55,6 +49,7 @@
extern 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/arch/sparc/include/asm/system_64.h b/arch/sparc/include/asm/system_64.h
index db9e742..8759f2a 100644
--- a/arch/sparc/include/asm/system_64.h
+++ b/arch/sparc/include/asm/system_64.h
@@ -26,9 +26,8 @@
#define sparc_cpu_model sun4u
-/* This cannot ever be a sun4c nor sun4 :) That's just history. */
-#define ARCH_SUN4C_SUN4 0
-#define ARCH_SUN4 0
+/* This cannot ever be a sun4c :) That's just history. */
+#define ARCH_SUN4C 0
extern char reboot_command[];
@@ -118,6 +117,7 @@
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/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h
index cbb892d..29899fd 100644
--- a/arch/sparc/include/asm/thread_info_32.h
+++ b/arch/sparc/include/asm/thread_info_32.h
@@ -80,11 +80,7 @@
/*
* 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/arch/sparc/include/asm/timer_32.h b/arch/sparc/include/asm/timer_32.h
index 361e538..2ec030e 100644
--- a/arch/sparc/include/asm/timer_32.h
+++ b/arch/sparc/include/asm/timer_32.h
@@ -9,96 +9,9 @@
#define _SPARC_TIMER_H
#include <asm/system.h> /* For SUN4M_NCPUS */
-#include <asm/sun4paddr.h>
#include <asm/btfixup.h>
-/* Timer structures. The interrupt timer has two properties which
- * are the counter (which is handled in do_timer in sched.c) and the limit.
- * This limit is where the timer's counter 'wraps' around. Oddly enough,
- * the sun4c timer when it hits the limit wraps back to 1 and not zero
- * thus when calculating the value at which it will fire a microsecond you
- * must adjust by one. Thanks SUN for designing such great hardware ;(
- */
-
-/* Note that I am only going to use the timer that interrupts at
- * Sparc IRQ 10. There is another one available that can fire at
- * IRQ 14. Currently it is left untouched, we keep the PROM's limit
- * register value and let the prom take these interrupts. This allows
- * L1-A to work.
- */
-
-struct sun4c_timer_info {
- __volatile__ unsigned int cur_count10;
- __volatile__ unsigned int timer_limit10;
- __volatile__ unsigned int cur_count14;
- __volatile__ unsigned int timer_limit14;
-};
-
-#define SUN4C_TIMER_PHYSADDR 0xf3000000
-#ifdef CONFIG_SUN4
-#define SUN_TIMER_PHYSADDR SUN4_300_TIMER_PHYSADDR
-#else
-#define SUN_TIMER_PHYSADDR SUN4C_TIMER_PHYSADDR
-#endif
-
-/* A sun4m has two blocks of registers which are probably of the same
- * structure. LSI Logic's L64851 is told to _decrement_ from the limit
- * value. Aurora behaves similarly but its limit value is compacted in
- * other fashion (it's wider). Documented fields are defined here.
- */
-
-/* As with the interrupt register, we have two classes of timer registers
- * which are per-cpu and master. Per-cpu timers only hit that cpu and are
- * only level 14 ticks, master timer hits all cpus and is level 10.
- */
-
-#define SUN4M_PRM_CNT_L 0x80000000
-#define SUN4M_PRM_CNT_LVALUE 0x7FFFFC00
-
-struct sun4m_timer_percpu_info {
- __volatile__ unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */
- __volatile__ unsigned int l14_cur_count;
-
- /* This register appears to be write only and/or inaccessible
- * on Uni-Processor sun4m machines.
- */
- __volatile__ unsigned int l14_limit_noclear; /* Data access error is here */
-
- __volatile__ unsigned int cntrl; /* =1 after POST on Aurora */
- __volatile__ unsigned char space[PAGE_SIZE - 16];
-};
-
-struct sun4m_timer_regs {
- struct sun4m_timer_percpu_info cpu_timers[SUN4M_NCPUS];
- volatile unsigned int l10_timer_limit;
- volatile unsigned int l10_cur_count;
-
- /* Again, this appears to be write only and/or inaccessible
- * on uni-processor sun4m machines.
- */
- volatile unsigned int l10_limit_noclear;
-
- /* This register too, it must be magic. */
- volatile unsigned int foobar;
-
- volatile unsigned int cfg; /* equals zero at boot time... */
-};
-
-#define SUN4D_PRM_CNT_L 0x80000000
-#define SUN4D_PRM_CNT_LVALUE 0x7FFFFC00
-
-struct sun4d_timer_regs {
- volatile unsigned int l10_timer_limit;
- volatile unsigned int l10_cur_countx;
- volatile unsigned int l10_limit_noclear;
- volatile unsigned int ctrl;
- volatile unsigned int l10_cur_count;
-};
-
-extern struct sun4d_timer_regs *sun4d_timers;
-
extern __volatile__ unsigned int *master_l10_counter;
-extern __volatile__ unsigned int *master_l10_limit;
/* FIXME: Make do_[gs]ettimeofday btfixup calls */
BTFIXUPDEF_CALL(int, bus_do_settimeofday, struct timespec *tv)
diff --git a/arch/sparc/include/asm/vac-ops.h b/arch/sparc/include/asm/vac-ops.h
index d105276..a63e88e 100644
--- a/arch/sparc/include/asm/vac-ops.h
+++ b/arch/sparc/include/asm/vac-ops.h
@@ -76,11 +76,7 @@
* cacheable bit in the pte's of all such pages.
*/
-#ifdef CONFIG_SUN4
-#define S4CVAC_BADBITS 0x0001e000
-#else
#define S4CVAC_BADBITS 0x0000f000
-#endif
/* The following is true if vaddr1 and vaddr2 would cause
* a 'bad alias'.
@@ -94,10 +90,7 @@
*/
struct sun4c_vac_props {
unsigned int num_bytes; /* Size of the cache */
- unsigned int num_lines; /* Number of cache lines */
unsigned int do_hwflushes; /* Hardware flushing available? */
- enum { VAC_NONE, VAC_WRITE_THROUGH,
- VAC_WRITE_BACK } type; /* What type of VAC? */
unsigned int linesize; /* Size of each line in bytes */
unsigned int log2lsize; /* log2(linesize) */
unsigned int on; /* VAC is enabled */
diff --git a/arch/sparc/include/asm/vfc_ioctls.h b/arch/sparc/include/asm/vfc_ioctls.h
deleted file mode 100644
index af8b690..0000000
--- a/arch/sparc/include/asm/vfc_ioctls.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (c) 1996 by Manish Vachharajani */
-
-#ifndef _LINUX_VFC_IOCTLS_H_
-#define _LINUX_VFC_IOCTLS_H_
-
- /* IOCTLs */
-#define VFC_IOCTL(a) (('j' << 8) | a)
-#define VFCGCTRL (VFC_IOCTL (0)) /* get vfc attributes */
-#define VFCSCTRL (VFC_IOCTL (1)) /* set vfc attributes */
-#define VFCGVID (VFC_IOCTL (2)) /* get video decoder attributes */
-#define VFCSVID (VFC_IOCTL (3)) /* set video decoder attributes */
-#define VFCHUE (VFC_IOCTL (4)) /* set hue */
-#define VFCPORTCHG (VFC_IOCTL (5)) /* change port */
-#define VFCRDINFO (VFC_IOCTL (6)) /* read info */
-
- /* Options for setting the vfc attributes and status */
-#define MEMPRST 0x1 /* reset FIFO ptr. */
-#define CAPTRCMD 0x2 /* start capture and wait */
-#define DIAGMODE 0x3 /* diag mode */
-#define NORMMODE 0x4 /* normal mode */
-#define CAPTRSTR 0x5 /* start capture */
-#define CAPTRWAIT 0x6 /* wait for capture to finish */
-
-
- /* Options for the decoder */
-#define STD_NTSC 0x1 /* NTSC mode */
-#define STD_PAL 0x2 /* PAL mode */
-#define COLOR_ON 0x3 /* force color ON */
-#define MONO 0x4 /* force color OFF */
-
- /* Values returned by ioctl 2 */
-
-#define NO_LOCK 1
-#define NTSC_COLOR 2
-#define NTSC_NOCOLOR 3
-#define PAL_COLOR 4
-#define PAL_NOCOLOR 5
-
-/* Not too sure what this does yet */
- /* Options for setting Field number */
-#define ODD_FIELD 0x1
-#define EVEN_FIELD 0x0
-#define ACTIVE_ONLY 0x2
-#define NON_ACTIVE 0x0
-
-/* Debug options */
-#define VFC_I2C_SEND 0
-#define VFC_I2C_RECV 1
-
-struct vfc_debug_inout
-{
- unsigned long addr;
- unsigned long ret;
- unsigned long len;
- unsigned char __user *buffer;
-};
-
-#endif /* _LINUX_VFC_IOCTLS_H_ */
diff --git a/arch/sparc/include/asm/visasm.h b/arch/sparc/include/asm/visasm.h
index de797b9..39ca301 100644
--- a/arch/sparc/include/asm/visasm.h
+++ b/arch/sparc/include/asm/visasm.h
@@ -57,6 +57,7 @@
" " : : "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/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 6e03a2a..2d65820 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -13,15 +13,13 @@
time.o windows.o cpu.o devices.o \
tadpole.o tick14.o ptrace.o \
unaligned.o una_asm.o muldiv.o \
- prom.o of_device.o devres.o
+ prom.o of_device.o devres.o dma.o
devres-y = ../../../kernel/irq/devres.o
obj-$(CONFIG_PCI) += pcic.o
-obj-$(CONFIG_SUN4) += sun4setup.o
obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
obj-$(CONFIG_SUN_AUXIO) += auxio.o
-obj-$(CONFIG_PCI) += ebus.o
obj-$(CONFIG_SUN_PM) += apc.o pmc.o
obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o
obj-$(CONFIG_SPARC_LED) += led.o
diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c
index 5267d48..4dd1ba7 100644
--- a/arch/sparc/kernel/apc.c
+++ b/arch/sparc/kernel/apc.c
@@ -12,9 +12,10 @@
#include <linux/miscdevice.h>
#include <linux/smp_lock.h>
#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/sbus.h>
#include <asm/oplib.h>
#include <asm/uaccess.h>
#include <asm/auxio.h>
@@ -29,11 +30,10 @@
#define APC_OBPNAME "power-management"
#define APC_DEVNAME "apc"
-volatile static u8 __iomem *regs;
-static int apc_regsize;
+static u8 __iomem *regs;
static int apc_no_idle __initdata = 0;
-#define apc_readb(offs) (sbus_readb(regs+offs))
+#define apc_readb(offs) (sbus_readb(regs+offs))
#define apc_writeb(val, offs) (sbus_writeb(val, regs+offs))
/* Specify "apc=noidle" on the kernel command line to
@@ -69,9 +69,9 @@
#endif
}
-static inline void apc_free(void)
+static inline void apc_free(struct of_device *op)
{
- sbus_iounmap(regs, apc_regsize);
+ of_iounmap(&op->resource[0], regs, resource_size(&op->resource[0]));
}
static int apc_open(struct inode *inode, struct file *f)
@@ -153,52 +153,56 @@
static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
-static int __init apc_probe(void)
+static int __devinit apc_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct sbus_bus *sbus = NULL;
- struct sbus_dev *sdev = NULL;
- int iTmp = 0;
+ int err;
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, APC_OBPNAME)) {
- goto sbus_done;
- }
- }
- }
-
-sbus_done:
- if (!sdev) {
- return -ENODEV;
- }
-
- apc_regsize = sdev->reg_addrs[0].reg_size;
- regs = sbus_ioremap(&sdev->resource[0], 0,
- apc_regsize, APC_OBPNAME);
- if(!regs) {
+ regs = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]), APC_OBPNAME);
+ if (!regs) {
printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME);
return -ENODEV;
}
- iTmp = misc_register(&apc_miscdev);
- if (iTmp != 0) {
+ err = misc_register(&apc_miscdev);
+ if (err) {
printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME);
- apc_free();
+ apc_free(op);
return -ENODEV;
}
/* Assign power management IDLE handler */
- if(!apc_no_idle)
+ if (!apc_no_idle)
pm_idle = apc_swift_idle;
printk(KERN_INFO "%s: power management initialized%s\n",
- APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
+ APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
+
return 0;
}
+static struct of_device_id __initdata apc_match[] = {
+ {
+ .name = APC_OBPNAME,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, apc_match);
+
+static struct of_platform_driver apc_driver = {
+ .name = "apc",
+ .match_table = apc_match,
+ .probe = apc_probe,
+};
+
+static int __init apc_init(void)
+{
+ return of_register_driver(&apc_driver, &of_bus_type);
+}
+
/* This driver is not critical to the boot process
* and is easiest to ioremap when SBus is already
* initialized, so we install ourselves thusly:
*/
-__initcall(apc_probe);
-
+__initcall(apc_init);
diff --git a/arch/sparc/kernel/auxio.c b/arch/sparc/kernel/auxio.c
index baf4ed3..09c8572 100644
--- a/arch/sparc/kernel/auxio.c
+++ b/arch/sparc/kernel/auxio.c
@@ -6,6 +6,8 @@
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/oplib.h>
#include <asm/io.h>
#include <asm/auxio.h>
@@ -59,7 +61,7 @@
r.flags = auxregs[0].which_io & 0xF;
r.start = auxregs[0].phys_addr;
r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1;
- auxio_register = sbus_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
+ auxio_register = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
/* Fix the address on sun4m and sun4c. */
if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 ||
sparc_cpu_model == sun4c)
@@ -128,7 +130,7 @@
r.flags = regs.which_io & 0xF;
r.start = regs.phys_addr;
r.end = regs.phys_addr + regs.reg_size - 1;
- auxio_power_register = (unsigned char *) sbus_ioremap(&r, 0,
+ auxio_power_register = (unsigned char *) of_ioremap(&r, 0,
regs.reg_size, "auxpower");
/* Display a quick message on the console. */
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
index b240b88..ad656b0 100644
--- a/arch/sparc/kernel/devices.c
+++ b/arch/sparc/kernel/devices.c
@@ -143,7 +143,7 @@
#endif
clock_stop_probe();
- if (ARCH_SUN4C_SUN4)
+ if (ARCH_SUN4C)
sun4c_probe_memerr_reg();
return;
diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c
new file mode 100644
index 0000000..ebc8403
--- /dev/null
+++ b/arch/sparc/kernel/dma.c
@@ -0,0 +1,227 @@
+/* dma.c: PCI and SBUS DMA accessors for 32-bit sparc.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/mm.h>
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+
+#include "dma.h"
+
+int dma_supported(struct device *dev, u64 mask)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_dma_supported(to_pci_dev(dev), mask);
+#endif
+ return 0;
+}
+EXPORT_SYMBOL(dma_supported);
+
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
+#endif
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(dma_set_mask);
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
+#endif
+ return sbus_alloc_consistent(dev, size, dma_handle);
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+void dma_free_coherent(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_free_consistent(to_pci_dev(dev), size,
+ cpu_addr, dma_handle);
+ return;
+ }
+#endif
+ sbus_free_consistent(dev, size, cpu_addr, dma_handle);
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+ size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_map_single(to_pci_dev(dev), cpu_addr,
+ size, (int)direction);
+#endif
+ return sbus_map_single(dev, cpu_addr, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_map_single);
+
+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+ size_t size,
+ enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_unmap_single(to_pci_dev(dev), dma_addr,
+ size, (int)direction);
+ return;
+ }
+#endif
+ sbus_unmap_single(dev, dma_addr, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_single);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_map_page(to_pci_dev(dev), page, offset,
+ size, (int)direction);
+#endif
+ return sbus_map_single(dev, page_address(page) + offset,
+ size, (int)direction);
+}
+EXPORT_SYMBOL(dma_map_page);
+
+void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+ size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_unmap_page(to_pci_dev(dev), dma_address,
+ size, (int)direction);
+ return;
+ }
+#endif
+ sbus_unmap_single(dev, dma_address, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_page);
+
+int dma_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
+#endif
+ return sbus_map_sg(dev, sg, nents, direction);
+}
+EXPORT_SYMBOL(dma_map_sg);
+
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_unmap_sg(to_pci_dev(dev), sg, nents, (int)direction);
+ return;
+ }
+#endif
+ sbus_unmap_sg(dev, sg, nents, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_sg);
+
+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle,
+ size, (int)direction);
+ return;
+ }
+#endif
+ sbus_dma_sync_single_for_cpu(dev, dma_handle, size, (int) direction);
+}
+EXPORT_SYMBOL(dma_sync_single_for_cpu);
+
+void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle,
+ size, (int)direction);
+ return;
+ }
+#endif
+ sbus_dma_sync_single_for_device(dev, dma_handle, size, (int) direction);
+}
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_single_range_for_cpu(struct device *dev,
+ dma_addr_t dma_handle,
+ unsigned long offset,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
+
+void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_device);
+
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg,
+ nelems, (int)direction);
+ return;
+ }
+#endif
+ BUG();
+}
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+void dma_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_dma_sync_sg_for_device(to_pci_dev(dev), sg,
+ nelems, (int)direction);
+ return;
+ }
+#endif
+ BUG();
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+ return (dma_addr == DMA_ERROR_CODE);
+}
+EXPORT_SYMBOL(dma_mapping_error);
+
+int dma_get_cache_alignment(void)
+{
+ return 32;
+}
+EXPORT_SYMBOL(dma_get_cache_alignment);
diff --git a/arch/sparc/kernel/dma.h b/arch/sparc/kernel/dma.h
new file mode 100644
index 0000000..f8d8951
--- /dev/null
+++ b/arch/sparc/kernel/dma.h
@@ -0,0 +1,14 @@
+void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp);
+void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba);
+dma_addr_t sbus_map_single(struct device *dev, void *va,
+ size_t len, int direction);
+void sbus_unmap_single(struct device *dev, dma_addr_t ba,
+ size_t n, int direction);
+int sbus_map_sg(struct device *dev, struct scatterlist *sg,
+ int n, int direction);
+void sbus_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int n, int direction);
+void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba,
+ size_t size, int direction);
+void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba,
+ size_t size, int direction);
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
deleted file mode 100644
index 9729423..0000000
--- a/arch/sparc/kernel/ebus.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * ebus.c: PCI to EBus bridge device.
- *
- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- *
- * Adopted for sparc by V. Roganov and G. Raiko.
- * Fixes for different platforms by Pete Zaitcev.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/pbm.h>
-#include <asm/ebus.h>
-#include <asm/io.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-
-struct linux_ebus *ebus_chain = NULL;
-
-/* We are together with pcic.c under CONFIG_PCI. */
-extern unsigned int pcic_pin_to_irq(unsigned int, const char *name);
-
-/*
- * IRQ Blacklist
- * Here we list PROMs and systems that are known to supply crap as IRQ numbers.
- */
-struct ebus_device_irq {
- char *name;
- unsigned int pin;
-};
-
-struct ebus_system_entry {
- char *esname;
- struct ebus_device_irq *ipt;
-};
-
-static struct ebus_device_irq je1_1[] = {
- { "8042", 3 },
- { "SUNW,CS4231", 0 },
- { "parallel", 0 },
- { "se", 2 },
- { NULL, 0 }
-};
-
-/*
- * Gleb's JE1 supplied reasonable pin numbers, but mine did not (OBP 2.32).
- * Blacklist the sucker... Note that Gleb's system will work.
- */
-static struct ebus_system_entry ebus_blacklist[] = {
- { "SUNW,JavaEngine1", je1_1 },
- { NULL, NULL }
-};
-
-static struct ebus_device_irq *ebus_blackp = NULL;
-
-/*
- */
-static inline unsigned long ebus_alloc(size_t size)
-{
- return (unsigned long)kmalloc(size, GFP_ATOMIC);
-}
-
-/*
- */
-static int __init ebus_blacklist_irq(const char *name)
-{
- struct ebus_device_irq *dp;
-
- if ((dp = ebus_blackp) != NULL) {
- for (; dp->name != NULL; dp++) {
- if (strcmp(name, dp->name) == 0) {
- return pcic_pin_to_irq(dp->pin, name);
- }
- }
- }
- return 0;
-}
-
-static void __init fill_ebus_child(struct device_node *dp,
- struct linux_ebus_child *dev)
-{
- const int *regs;
- const int *irqs;
- int i, len;
-
- dev->prom_node = dp;
- regs = of_get_property(dp, "reg", &len);
- if (!regs)
- len = 0;
- dev->num_addrs = len / sizeof(regs[0]);
-
- for (i = 0; i < dev->num_addrs; i++) {
- if (regs[i] >= dev->parent->num_addrs) {
- prom_printf("UGH: property for %s was %d, need < %d\n",
- dev->prom_node->name, len,
- dev->parent->num_addrs);
- panic(__func__);
- }
-
- /* XXX resource */
- dev->resource[i].start =
- dev->parent->resource[regs[i]].start;
- }
-
- for (i = 0; i < PROMINTR_MAX; i++)
- dev->irqs[i] = PCI_IRQ_NONE;
-
- if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
- dev->num_irqs = 1;
- } else {
- irqs = of_get_property(dp, "interrupts", &len);
- if (!irqs) {
- dev->num_irqs = 0;
- dev->irqs[0] = 0;
- if (dev->parent->num_irqs != 0) {
- dev->num_irqs = 1;
- dev->irqs[0] = dev->parent->irqs[0];
- }
- } else {
- dev->num_irqs = len / sizeof(irqs[0]);
- if (irqs[0] == 0 || irqs[0] >= 8) {
- /*
- * XXX Zero is a valid pin number...
- * This works as long as Ebus is not wired
- * to INTA#.
- */
- printk("EBUS: %s got bad irq %d from PROM\n",
- dev->prom_node->name, irqs[0]);
- dev->num_irqs = 0;
- dev->irqs[0] = 0;
- } else {
- dev->irqs[0] =
- pcic_pin_to_irq(irqs[0],
- dev->prom_node->name);
- }
- }
- }
-}
-
-static void __init fill_ebus_device(struct device_node *dp,
- struct linux_ebus_device *dev)
-{
- const struct linux_prom_registers *regs;
- struct linux_ebus_child *child;
- struct dev_archdata *sd;
- const int *irqs;
- int i, n, len;
- unsigned long baseaddr;
-
- dev->prom_node = dp;
-
- regs = of_get_property(dp, "reg", &len);
- if (!regs)
- len = 0;
- if (len % sizeof(struct linux_prom_registers)) {
- prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
- dev->prom_node->name, len,
- (int)sizeof(struct linux_prom_registers));
- panic(__func__);
- }
- dev->num_addrs = len / sizeof(struct linux_prom_registers);
-
- for (i = 0; i < dev->num_addrs; i++) {
- /*
- * XXX Collect JE-1 PROM
- *
- * Example - JS-E with 3.11:
- * /ebus
- * regs
- * 0x00000000, 0x0, 0x00000000, 0x0, 0x00000000,
- * 0x82000010, 0x0, 0xf0000000, 0x0, 0x01000000,
- * 0x82000014, 0x0, 0x38800000, 0x0, 0x00800000,
- * ranges
- * 0x00, 0x00000000, 0x02000010, 0x0, 0x0, 0x01000000,
- * 0x01, 0x01000000, 0x02000014, 0x0, 0x0, 0x00800000,
- * /ebus/8042
- * regs
- * 0x00000001, 0x00300060, 0x00000008,
- * 0x00000001, 0x00300060, 0x00000008,
- */
- n = regs[i].which_io;
- if (n >= 4) {
- /* XXX This is copied from old JE-1 by Gleb. */
- n = (regs[i].which_io - 0x10) >> 2;
- } else {
- ;
- }
-
-/*
- * XXX Now as we have regions, why don't we make an on-demand allocation...
- */
- dev->resource[i].start = 0;
- if ((baseaddr = dev->bus->self->resource[n].start +
- regs[i].phys_addr) != 0) {
- /* dev->resource[i].name = dev->prom_name; */
- if ((baseaddr = (unsigned long) ioremap(baseaddr,
- regs[i].reg_size)) == 0) {
- panic("ebus: unable to remap dev %s",
- dev->prom_node->name);
- }
- }
- dev->resource[i].start = baseaddr; /* XXX Unaligned */
- }
-
- for (i = 0; i < PROMINTR_MAX; i++)
- dev->irqs[i] = PCI_IRQ_NONE;
-
- if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
- dev->num_irqs = 1;
- } else {
- irqs = of_get_property(dp, "interrupts", &len);
- if (!irqs) {
- dev->num_irqs = 0;
- if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
- dev->num_irqs = 1;
-/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
- }
- } else {
- dev->num_irqs = 1; /* dev->num_irqs = len / sizeof(irqs[0]); */
- if (irqs[0] == 0 || irqs[0] >= 8) {
- /* See above for the parent. XXX */
- printk("EBUS: %s got bad irq %d from PROM\n",
- dev->prom_node->name, irqs[0]);
- dev->num_irqs = 0;
- dev->irqs[0] = 0;
- } else {
- dev->irqs[0] =
- pcic_pin_to_irq(irqs[0],
- dev->prom_node->name);
- }
- }
- }
-
- sd = &dev->ofdev.dev.archdata;
- sd->prom_node = dp;
- sd->op = &dev->ofdev;
- sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;
-
- dev->ofdev.node = dp;
- dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
- dev->ofdev.dev.bus = &ebus_bus_type;
- sprintf(dev->ofdev.dev.bus_id, "ebus[%08x]", dp->node);
-
- /* Register with core */
- if (of_device_register(&dev->ofdev) != 0)
- printk(KERN_DEBUG "ebus: device registration error for %s!\n",
- dp->path_component_name);
-
- if ((dp = dp->child) != NULL) {
- dev->children = (struct linux_ebus_child *)
- ebus_alloc(sizeof(struct linux_ebus_child));
-
- child = dev->children;
- child->next = NULL;
- child->parent = dev;
- child->bus = dev->bus;
- fill_ebus_child(dp, child);
-
- while ((dp = dp->sibling) != NULL) {
- child->next = (struct linux_ebus_child *)
- ebus_alloc(sizeof(struct linux_ebus_child));
-
- child = child->next;
- child->next = NULL;
- child->parent = dev;
- child->bus = dev->bus;
- fill_ebus_child(dp, child);
- }
- }
-}
-
-void __init ebus_init(void)
-{
- const struct linux_prom_pci_registers *regs;
- struct linux_pbm_info *pbm;
- struct linux_ebus_device *dev;
- struct linux_ebus *ebus;
- struct ebus_system_entry *sp;
- struct pci_dev *pdev;
- struct pcidev_cookie *cookie;
- struct device_node *dp;
- struct resource *p;
- unsigned short pci_command;
- int len, reg, nreg;
- int num_ebus = 0;
-
- dp = of_find_node_by_path("/");
- for (sp = ebus_blacklist; sp->esname != NULL; sp++) {
- if (strcmp(dp->name, sp->esname) == 0) {
- ebus_blackp = sp->ipt;
- break;
- }
- }
-
- pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, NULL);
- if (!pdev)
- return;
-
- cookie = pdev->sysdata;
- dp = cookie->prom_node;
-
- ebus_chain = ebus = (struct linux_ebus *)
- ebus_alloc(sizeof(struct linux_ebus));
- ebus->next = NULL;
-
- while (dp) {
- struct device_node *nd;
-
- ebus->prom_node = dp;
- ebus->self = pdev;
- ebus->parent = pbm = cookie->pbm;
-
- /* Enable BUS Master. */
- pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
- pci_command |= PCI_COMMAND_MASTER;
- pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-
- regs = of_get_property(dp, "reg", &len);
- if (!regs) {
- prom_printf("%s: can't find reg property\n",
- __func__);
- prom_halt();
- }
- nreg = len / sizeof(struct linux_prom_pci_registers);
-
- p = &ebus->self->resource[0];
- for (reg = 0; reg < nreg; reg++) {
- if (!(regs[reg].which_io & 0x03000000))
- continue;
-
- (p++)->start = regs[reg].phys_lo;
- }
-
- ebus->ofdev.node = dp;
- ebus->ofdev.dev.parent = &pdev->dev;
- ebus->ofdev.dev.bus = &ebus_bus_type;
- sprintf(ebus->ofdev.dev.bus_id, "ebus%d", num_ebus);
-
- /* Register with core */
- if (of_device_register(&ebus->ofdev) != 0)
- printk(KERN_DEBUG "ebus: device registration error for %s!\n",
- dp->path_component_name);
-
-
- nd = dp->child;
- if (!nd)
- goto next_ebus;
-
- ebus->devices = (struct linux_ebus_device *)
- ebus_alloc(sizeof(struct linux_ebus_device));
-
- dev = ebus->devices;
- dev->next = NULL;
- dev->children = NULL;
- dev->bus = ebus;
- fill_ebus_device(nd, dev);
-
- while ((nd = nd->sibling) != NULL) {
- dev->next = (struct linux_ebus_device *)
- ebus_alloc(sizeof(struct linux_ebus_device));
-
- dev = dev->next;
- dev->next = NULL;
- dev->children = NULL;
- dev->bus = ebus;
- fill_ebus_device(nd, dev);
- }
-
- next_ebus:
- pdev = pci_get_device(PCI_VENDOR_ID_SUN,
- PCI_DEVICE_ID_SUN_EBUS, pdev);
- if (!pdev)
- break;
-
- cookie = pdev->sysdata;
- dp = cookie->prom_node;
-
- ebus->next = (struct linux_ebus *)
- ebus_alloc(sizeof(struct linux_ebus));
- ebus = ebus->next;
- ebus->next = NULL;
- ++num_ebus;
- }
- if (pdev)
- pci_dev_put(pdev);
-}
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index e8cdf71..faf9ccd 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -20,11 +20,7 @@
#include <asm/memreg.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#ifdef CONFIG_SUN4
-#include <asm/pgtsun4.h>
-#else
#include <asm/pgtsun4c.h>
-#endif
#include <asm/winmacro.h>
#include <asm/signal.h>
#include <asm/obio.h>
@@ -276,17 +272,18 @@
*/
maybe_smp4m_msg:
GET_PROCESSOR4M_ID(o3)
- set sun4m_interrupts, %l5
- ld [%l5], %o5
+ sethi %hi(sun4m_irq_percpu), %l5
+ sll %o3, 2, %o3
+ or %l5, %lo(sun4m_irq_percpu), %o5
sethi %hi(0x40000000), %o2
- sll %o3, 12, %o3
ld [%o5 + %o3], %o1
- andcc %o1, %o2, %g0
+ ld [%o1 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending
+ andcc %o3, %o2, %g0
be,a smp4m_ticker
cmp %l7, 14
- st %o2, [%o5 + 0x4]
+ st %o2, [%o1 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x40000000
WRITE_PAUSE
- ld [%o5], %g0
+ ld [%o1 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending
WRITE_PAUSE
or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr
@@ -304,16 +301,16 @@
SAVE_ALL
sethi %hi(0x80000000), %o2
GET_PROCESSOR4M_ID(o0)
- set sun4m_interrupts, %l5
- ld [%l5], %o5
- sll %o0, 12, %o0
- add %o5, %o0, %o5
- ld [%o5], %o3
+ sethi %hi(sun4m_irq_percpu), %l5
+ or %l5, %lo(sun4m_irq_percpu), %o5
+ sll %o0, 2, %o0
+ ld [%o5 + %o0], %o5
+ ld [%o5 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending
andcc %o3, %o2, %g0
be 1f ! Must be an NMI async memory error
- st %o2, [%o5 + 4]
+ st %o2, [%o5 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x80000000
WRITE_PAUSE
- ld [%o5], %g0
+ ld [%o5 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending
WRITE_PAUSE
or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr
@@ -327,12 +324,11 @@
1:
/* NMI async memory error handling. */
sethi %hi(0x80000000), %l4
- sethi %hi(0x4000), %o3
- sub %o5, %o0, %o5
- add %o5, %o3, %l5
- st %l4, [%l5 + 0xc]
+ sethi %hi(sun4m_irq_global), %o5
+ ld [%o5 + %lo(sun4m_irq_global)], %l5
+ st %l4, [%l5 + 0x0c] ! sun4m_irq_global->mask_set=0x80000000
WRITE_PAUSE
- ld [%l5], %g0
+ ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
WRITE_PAUSE
or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr
@@ -341,9 +337,9 @@
WRITE_PAUSE
call sun4m_nmi
nop
- st %l4, [%l5 + 0x8]
+ st %l4, [%l5 + 0x08] ! sun4m_irq_global->mask_clear=0x80000000
WRITE_PAUSE
- ld [%l5], %g0
+ ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
WRITE_PAUSE
RESTORE_ALL
@@ -775,11 +771,7 @@
* Ugly, but we cant use hardware flushing on the sun4 and we'd require
* two instructions (Anton)
*/
-#ifdef CONFIG_SUN4
-vac_hwflush_patch1_on: nop
-#else
vac_hwflush_patch1_on: addcc %l7, -PAGE_SIZE, %l7
-#endif
vac_hwflush_patch2_on: sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG
@@ -798,42 +790,10 @@
! %l7 = 1 for textfault
! We want error in %l5, vaddr in %l6
sun4c_fault:
-#ifdef CONFIG_SUN4
- sethi %hi(sun4c_memerr_reg), %l4
- ld [%l4+%lo(sun4c_memerr_reg)], %l4 ! memerr ctrl reg addr
- ld [%l4], %l6 ! memerr ctrl reg
- ld [%l4 + 4], %l5 ! memerr vaddr reg
- andcc %l6, 0x80, %g0 ! check for error type
- st %g0, [%l4 + 4] ! clear the error
- be 0f ! normal error
- sethi %hi(AC_BUS_ERROR), %l4 ! bus err reg addr
-
- call prom_halt ! something weird happened
- ! what exactly did happen?
- ! what should we do here?
-
-0: or %l4, %lo(AC_BUS_ERROR), %l4 ! bus err reg addr
- lduba [%l4] ASI_CONTROL, %l6 ! bus err reg
-
- cmp %l7, 1 ! text fault?
- be 1f ! yes
- nop
-
- ld [%l1], %l4 ! load instruction that caused fault
- srl %l4, 21, %l4
- andcc %l4, 1, %g0 ! store instruction?
-
- be 1f ! no
- sethi %hi(SUN4C_SYNC_BADWRITE), %l4 ! yep
- ! %lo(SUN4C_SYNC_BADWRITE) = 0
- or %l4, %l6, %l6 ! set write bit to emulate sun4c
-1:
-#else
sethi %hi(AC_SYNC_ERR), %l4
add %l4, 0x4, %l6 ! AC_SYNC_VA in %l6
lda [%l6] ASI_CONTROL, %l5 ! Address
lda [%l4] ASI_CONTROL, %l6 ! Error, retained for a bit
-#endif
andn %l5, 0xfff, %l5 ! Encode all info into l7
srl %l6, 14, %l4
@@ -880,12 +840,7 @@
or %l4, %lo(swapper_pg_dir), %l4
sll %l6, 2, %l6
ld [%l4 + %l6], %l4
-#ifdef CONFIG_SUN4
- sethi %hi(PAGE_MASK), %l6
- andcc %l4, %l6, %g0
-#else
andcc %l4, PAGE_MASK, %g0
-#endif
be sun4c_fault_fromuser
lduXa [%l5] ASI_SEGMAP, %l4
@@ -937,11 +892,7 @@
ld [%l6 + 0x08], %l3 ! tmp = entry->vaddr
! Flush segment from the cache.
-#ifdef CONFIG_SUN4
- sethi %hi((128 * 1024)), %l7
-#else
sethi %hi((64 * 1024)), %l7
-#endif
9:
vac_hwflush_patch1:
vac_linesize_patch:
@@ -1029,12 +980,7 @@
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/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index 50d9a16..2d325fd 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -63,15 +63,9 @@
.align 4
-#ifndef CONFIG_SUN4
sun4_notsup:
- .asciz "Sparc-Linux sun4 needs a specially compiled kernel, turn CONFIG_SUN4 on.\n\n"
+ .asciz "Sparc-Linux sun4 support does no longer exist.\n\n"
.align 4
-#else
-sun4cdm_notsup:
- .asciz "Kernel compiled with CONFIG_SUN4 cannot run on SUN4C/SUN4M/SUN4D\nTurn CONFIG_SUN4 off.\n\n"
- .align 4
-#endif
sun4e_notsup:
.asciz "Sparc-Linux sun4e support does not exist\n\n"
@@ -780,15 +774,6 @@
nop
found_version:
-#ifdef CONFIG_SUN4
-/* For people who try sun4 kernels, even if Configure.help advises them. */
- ld [%g7 + 0x68], %o1
- set sun4cdm_notsup, %o0
- call %o1
- nop
- b halt_me
- nop
-#endif
/* Get the machine type via the mysterious romvec node operations. */
add %g7, 0x1c, %l1
@@ -1150,15 +1135,6 @@
nop
sun4_init:
-#ifdef CONFIG_SUN4
-/* There, happy now Adrian? */
- set cputypval, %o2 ! Let everyone know we
- set ' ', %o0 ! are a "sun4 " architecture
- stb %o0, [%o2 + 0x4]
-
- b got_prop
- nop
-#else
sethi %hi(SUN4_PROM_VECTOR+0x84), %o1
ld [%o1 + %lo(SUN4_PROM_VECTOR+0x84)], %o1
set sun4_notsup, %o0
@@ -1170,7 +1146,7 @@
nop
1: ba 1b ! Cannot exit into KMON
nop
-#endif
+
no_sun4e_here:
ld [%g7 + 0x68], %o1
set sun4e_notsup, %o0
diff --git a/arch/sparc/kernel/idprom.c b/arch/sparc/kernel/idprom.c
index fc511f3..223a658 100644
--- a/arch/sparc/kernel/idprom.c
+++ b/arch/sparc/kernel/idprom.c
@@ -12,10 +12,6 @@
#include <asm/oplib.h>
#include <asm/idprom.h>
#include <asm/machines.h> /* Fun with Sun released architectures. */
-#ifdef CONFIG_SUN4
-#include <asm/sun4paddr.h>
-extern void sun4setup(void);
-#endif
struct idprom *idprom;
static struct idprom idprom_buffer;
@@ -101,7 +97,4 @@
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/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 2a8a847..4f025b3 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -42,10 +42,13 @@
#include <asm/vaddrs.h>
#include <asm/oplib.h>
#include <asm/prom.h>
-#include <asm/sbus.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/dma.h>
+#include <asm/iommu.h>
+#include <asm/io-unit.h>
+
+#include "dma.h"
#define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */
@@ -139,15 +142,6 @@
}
}
-/*
- */
-void __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)
{
@@ -164,13 +158,6 @@
EXPORT_SYMBOL(of_iounmap);
/*
- */
-void sbus_iounmap(volatile void __iomem *addr, unsigned long size)
-{
- iounmap(addr);
-}
-
-/*
* Meat of mapping
*/
static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys,
@@ -246,63 +233,19 @@
#ifdef CONFIG_SBUS
-void sbus_set_sbus64(struct sbus_dev *sdev, int x)
+void sbus_set_sbus64(struct device *dev, int x)
{
printk("sbus_set_sbus64: unsupported\n");
}
-extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
-void __init sbus_fill_device_irq(struct sbus_dev *sdev)
-{
- struct linux_prom_irqs irqs[PROMINTR_MAX];
- int len;
-
- len = prom_getproperty(sdev->prom_node, "intr",
- (char *)irqs, sizeof(irqs));
- if (len != -1) {
- sdev->num_irqs = len / 8;
- if (sdev->num_irqs == 0) {
- sdev->irqs[0] = 0;
- } else if (sparc_cpu_model == sun4d) {
- for (len = 0; len < sdev->num_irqs; len++)
- sdev->irqs[len] =
- sun4d_build_irq(sdev, irqs[len].pri);
- } else {
- for (len = 0; len < sdev->num_irqs; len++)
- sdev->irqs[len] = irqs[len].pri;
- }
- } else {
- int interrupts[PROMINTR_MAX];
-
- /* No "intr" node found-- check for "interrupts" node.
- * This node contains SBus interrupt levels, not IPLs
- * as in "intr", and no vector values. We convert
- * SBus interrupt levels to PILs (platform specific).
- */
- len = prom_getproperty(sdev->prom_node, "interrupts",
- (char *)interrupts, sizeof(interrupts));
- if (len == -1) {
- sdev->irqs[0] = 0;
- sdev->num_irqs = 0;
- } else {
- sdev->num_irqs = len / sizeof(int);
- for (len = 0; len < sdev->num_irqs; len++) {
- sdev->irqs[len] =
- sbint_to_irq(sdev, interrupts[len]);
- }
- }
- }
-}
-
/*
* Allocate a chunk of memory suitable for DMA.
* Typically devices use them for control blocks.
* CPU may access them without any explicit flushing.
- *
- * XXX Some clever people know that sdev is not used and supply NULL. Watch.
*/
-void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
+void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp)
{
+ struct of_device *op = to_of_device(dev);
unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
unsigned long va;
struct resource *res;
@@ -336,13 +279,10 @@
* XXX That's where sdev would be used. Currently we load
* all iommu tables with the same translations.
*/
- if (mmu_map_dma_area(dma_addrp, va, res->start, len_total) != 0)
+ if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0)
goto err_noiommu;
- /* Set the resource name, if known. */
- if (sdev) {
- res->name = sdev->prom_name;
- }
+ res->name = op->node->name;
return (void *)(unsigned long)res->start;
@@ -356,7 +296,7 @@
return NULL;
}
-void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
+void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba)
{
struct resource *res;
struct page *pgv;
@@ -383,8 +323,8 @@
kfree(res);
/* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */
- pgv = mmu_translate_dvma(ba);
- mmu_unmap_dma_area(ba, n);
+ pgv = virt_to_page(p);
+ mmu_unmap_dma_area(dev, ba, n);
__free_pages(pgv, get_order(n));
}
@@ -394,7 +334,7 @@
* CPU view of this memory may be inconsistent with
* a device view and explicit flushing is necessary.
*/
-dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction)
+dma_addr_t sbus_map_single(struct device *dev, void *va, size_t len, int direction)
{
/* XXX why are some lengths signed, others unsigned? */
if (len <= 0) {
@@ -404,17 +344,17 @@
if (len > 256*1024) { /* __get_free_pages() limit */
return 0;
}
- return mmu_get_scsi_one(va, len, sdev->bus);
+ return mmu_get_scsi_one(dev, va, len);
}
-void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t ba, size_t n, int direction)
+void sbus_unmap_single(struct device *dev, dma_addr_t ba, size_t n, int direction)
{
- mmu_release_scsi_one(ba, n, sdev->bus);
+ mmu_release_scsi_one(dev, ba, n);
}
-int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
{
- mmu_get_scsi_sgl(sg, n, sdev->bus);
+ mmu_get_scsi_sgl(dev, sg, n);
/*
* XXX sparc64 can return a partial length here. sun4c should do this
@@ -423,145 +363,28 @@
return n;
}
-void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
{
- mmu_release_scsi_sgl(sg, n, sdev->bus);
+ mmu_release_scsi_sgl(dev, sg, n);
}
-/*
- */
-void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
+void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba, size_t size, int direction)
{
-#if 0
- unsigned long va;
- struct resource *res;
-
- /* We do not need the resource, just print a message if invalid. */
- res = _sparc_find_resource(&_sparc_dvma, ba);
- if (res == NULL)
- panic("sbus_dma_sync_single: 0x%x\n", ba);
-
- va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */
- /*
- * XXX This bogosity will be fixed with the iommu rewrite coming soon
- * to a kernel near you. - Anton
- */
- /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */
-#endif
}
-void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
+void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba, size_t size, int direction)
{
-#if 0
- unsigned long va;
- struct resource *res;
-
- /* We do not need the resource, just print a message if invalid. */
- res = _sparc_find_resource(&_sparc_dvma, ba);
- if (res == NULL)
- panic("sbus_dma_sync_single: 0x%x\n", ba);
-
- va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */
- /*
- * XXX This bogosity will be fixed with the iommu rewrite coming soon
- * to a kernel near you. - Anton
- */
- /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */
-#endif
}
-void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
-{
- printk("sbus_dma_sync_sg_for_cpu: not implemented yet\n");
-}
-
-void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
-{
- printk("sbus_dma_sync_sg_for_device: not implemented yet\n");
-}
-
-/* Support code for sbus_init(). */
-/*
- * XXX This functions appears to be a distorted version of
- * prom_sbus_ranges_init(), with all sun4d stuff cut away.
- * Ask DaveM what is going on here, how is sun4d supposed to work... XXX
- */
-/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
-void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
-{
- int parent_node = pn->node;
-
- if (sparc_cpu_model == sun4d) {
- struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
- int num_iounit_ranges, len;
-
- len = prom_getproperty(parent_node, "ranges",
- (char *) iounit_ranges,
- sizeof (iounit_ranges));
- if (len != -1) {
- num_iounit_ranges =
- (len / sizeof(struct linux_prom_ranges));
- prom_adjust_ranges(sbus->sbus_ranges,
- sbus->num_sbus_ranges,
- iounit_ranges, num_iounit_ranges);
- }
- }
-}
-
-void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
-{
-#ifndef CONFIG_SUN4
- struct device_node *parent = dp->parent;
-
- if (sparc_cpu_model != sun4d &&
- parent != NULL &&
- !strcmp(parent->name, "iommu")) {
- extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
-
- iommu_init(parent->node, sbus);
- }
-
- if (sparc_cpu_model == sun4d) {
- extern void iounit_init(int sbi_node, int iounit_node,
- struct sbus_bus *sbus);
-
- iounit_init(dp->node, parent->node, sbus);
- }
-#endif
-}
-
-void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
-{
- if (sparc_cpu_model == sun4d) {
- struct device_node *parent = dp->parent;
-
- sbus->devid = of_getintprop_default(parent, "device-id", 0);
- sbus->board = of_getintprop_default(parent, "board#", 0);
- }
-}
-
-int __init sbus_arch_preinit(void)
+static int __init sparc_register_ioport(void)
{
register_proc_sparc_ioport();
-#ifdef CONFIG_SUN4
- {
- extern void sun4_dvma_init(void);
- sun4_dvma_init();
- }
- return 1;
-#else
return 0;
-#endif
}
-void __init sbus_arch_postinit(void)
-{
- if (sparc_cpu_model == sun4d) {
- extern void sun4d_init_sbi_irq(void);
- sun4d_init_sbi_irq();
- }
-}
+arch_initcall(sparc_register_ioport);
+
#endif /* CONFIG_SBUS */
#ifdef CONFIG_PCI
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
index 32ef3eb..db75138 100644
--- a/arch/sparc/kernel/irq.h
+++ b/arch/sparc/kernel/irq.h
@@ -13,7 +13,6 @@
BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
BTFIXUPDEF_CALL(void, clear_clock_irq, void)
-BTFIXUPDEF_CALL(void, clear_profile_irq, int)
BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
static inline void __disable_irq(unsigned int irq)
@@ -41,11 +40,6 @@
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/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index f58c537..0837bd52e 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -29,15 +29,38 @@
}
EXPORT_SYMBOL(of_find_device_by_node);
-#ifdef CONFIG_PCI
-struct bus_type ebus_bus_type;
-EXPORT_SYMBOL(ebus_bus_type);
-#endif
+unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+{
+ struct of_device *op = of_find_device_by_node(node);
-#ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type;
-EXPORT_SYMBOL(sbus_bus_type);
-#endif
+ if (!op || index >= op->num_irqs)
+ return 0;
+
+ return op->irqs[index];
+}
+EXPORT_SYMBOL(irq_of_parse_and_map);
+
+/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
+ * BUS and propagate to all child of_device objects.
+ */
+void of_propagate_archdata(struct of_device *bus)
+{
+ struct dev_archdata *bus_sd = &bus->dev.archdata;
+ struct device_node *bus_dp = bus->node;
+ struct device_node *dp;
+
+ for (dp = bus_dp->child; dp; dp = dp->sibling) {
+ struct of_device *op = of_find_device_by_node(dp);
+
+ op->dev.archdata.iommu = bus_sd->iommu;
+ op->dev.archdata.stc = bus_sd->stc;
+ op->dev.archdata.host_controller = bus_sd->host_controller;
+ op->dev.archdata.numa_node = bus_sd->numa_node;
+
+ if (dp->child)
+ of_propagate_archdata(op);
+ }
+}
struct bus_type of_platform_bus_type;
EXPORT_SYMBOL(of_platform_bus_type);
@@ -327,6 +350,27 @@
return 1;
}
+static int __init use_1to1_mapping(struct device_node *pp)
+{
+ /* If we have a ranges property in the parent, use it. */
+ if (of_find_property(pp, "ranges", NULL) != NULL)
+ return 0;
+
+ /* Some SBUS devices use intermediate nodes to express
+ * hierarchy within the device itself. These aren't
+ * real bus nodes, and don't have a 'ranges' property.
+ * But, we should still pass the translation work up
+ * to the SBUS itself.
+ */
+ if (!strcmp(pp->name, "dma") ||
+ !strcmp(pp->name, "espdma") ||
+ !strcmp(pp->name, "ledma") ||
+ !strcmp(pp->name, "lebuffer"))
+ return 0;
+
+ return 1;
+}
+
static int of_resource_verbose;
static void __init build_device_resources(struct of_device *op,
@@ -373,10 +417,7 @@
flags = bus->get_flags(reg, 0);
- /* If the immediate parent has no ranges property to apply,
- * just use a 1<->1 mapping.
- */
- if (of_find_property(pp, "ranges", NULL) == NULL) {
+ if (use_1to1_mapping(pp)) {
result = of_read_addr(addr, na);
goto build_res;
}
@@ -565,15 +606,6 @@
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/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index a6a6f98..462584e 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -17,8 +17,6 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
-#include <asm/ebus.h>
-#include <asm/sbus.h> /* for sanity check... */
#include <asm/swift.h> /* for cache flushing. */
#include <asm/io.h>
@@ -430,7 +428,6 @@
pcic_pbm_scan_bus(pcic);
- ebus_init();
return 0;
}
@@ -493,10 +490,6 @@
* do ioremap() before accessing PC-style I/O,
* we supply virtual, ready to access address.
*
- * Ebus devices do not come here even if
- * CheerIO makes a similar conversion.
- * See ebus.c for details.
- *
* Note that request_region()
* works for these devices.
*
@@ -677,7 +670,7 @@
}
/*
- * pcic_pin_to_irq() is exported to ebus.c.
+ * pcic_pin_to_irq() is exported to bus probing code
*/
unsigned int
pcic_pin_to_irq(unsigned int pin, const char *name)
@@ -904,11 +897,6 @@
local_irq_restore(flags);
}
-static void pcic_clear_profile_irq(int cpu)
-{
- printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
-}
-
static void pcic_load_profile_irq(int cpu, unsigned int limit)
{
printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
@@ -934,7 +922,6 @@
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/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c
index 7eca887..2afcfab 100644
--- a/arch/sparc/kernel/pmc.c
+++ b/arch/sparc/kernel/pmc.c
@@ -8,11 +8,11 @@
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/miscdevice.h>
#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/sbus.h>
#include <asm/oplib.h>
#include <asm/uaccess.h>
#include <asm/auxio.h>
@@ -23,17 +23,15 @@
* #define PMC_NO_IDLE
*/
-#define PMC_MINOR MISC_DYNAMIC_MINOR
#define PMC_OBPNAME "SUNW,pmc"
#define PMC_DEVNAME "pmc"
#define PMC_IDLE_REG 0x00
#define PMC_IDLE_ON 0x01
-volatile static u8 __iomem *regs;
-static int pmc_regsize;
+static u8 __iomem *regs;
-#define pmc_readb(offs) (sbus_readb(regs+offs))
+#define pmc_readb(offs) (sbus_readb(regs+offs))
#define pmc_writeb(val, offs) (sbus_writeb(val, regs+offs))
/*
@@ -53,31 +51,11 @@
#endif
}
-static inline void pmc_free(void)
+static int __devinit pmc_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- sbus_iounmap(regs, pmc_regsize);
-}
-
-static int __init pmc_probe(void)
-{
- struct sbus_bus *sbus = NULL;
- struct sbus_dev *sdev = NULL;
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, PMC_OBPNAME)) {
- goto sbus_done;
- }
- }
- }
-
-sbus_done:
- if (!sdev) {
- return -ENODEV;
- }
-
- pmc_regsize = sdev->reg_addrs[0].reg_size;
- regs = sbus_ioremap(&sdev->resource[0], 0,
- pmc_regsize, PMC_OBPNAME);
+ regs = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]), PMC_OBPNAME);
if (!regs) {
printk(KERN_ERR "%s: unable to map registers\n", PMC_DEVNAME);
return -ENODEV;
@@ -92,8 +70,27 @@
return 0;
}
+static struct of_device_id __initdata pmc_match[] = {
+ {
+ .name = PMC_OBPNAME,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pmc_match);
+
+static struct of_platform_driver pmc_driver = {
+ .name = "pmc",
+ .match_table = pmc_match,
+ .probe = pmc_probe,
+};
+
+static int __init pmc_init(void)
+{
+ return of_register_driver(&pmc_driver, &of_bus_type);
+}
+
/* This driver is not critical to the boot process
* and is easiest to ioremap when SBus is already
* initialized, so we install ourselves thusly:
*/
-__initcall(pmc_probe);
+__initcall(pmc_init);
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 4bb4309..e8c43ff 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -75,7 +75,7 @@
{
/* endless idle loop with no priority at all */
for (;;) {
- if (ARCH_SUN4C_SUN4) {
+ if (ARCH_SUN4C) {
static int count = HZ;
static unsigned long last_jiffies;
static unsigned long last_faults;
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
index cd4fb79..eee5efc 100644
--- a/arch/sparc/kernel/prom.c
+++ b/arch/sparc/kernel/prom.c
@@ -54,6 +54,9 @@
}
EXPORT_SYMBOL(of_getintprop_default);
+DEFINE_MUTEX(of_set_property_mutex);
+EXPORT_SYMBOL(of_set_property_mutex);
+
int of_set_property(struct device_node *dp, const char *name, void *val, int len)
{
struct property **prevp;
@@ -77,7 +80,10 @@
void *old_val = prop->value;
int ret;
+ mutex_lock(&of_set_property_mutex);
ret = prom_setprop(dp->node, (char *) name, val, len);
+ mutex_unlock(&of_set_property_mutex);
+
err = -EINVAL;
if (ret >= 0) {
prop->value = new_val;
@@ -436,7 +442,6 @@
switch (prom_vers) {
case PROM_V0:
- case PROM_SUN4:
skip = 0;
switch (*romvec->pv_stdout) {
case PROMDEV_SCREEN:
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 9e451b2..24fe307 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -213,23 +213,25 @@
/* Initialize PROM console and command line. */
*cmdline_p = prom_getbootargs();
strcpy(boot_command_line, *cmdline_p);
+ parse_early_param();
/* Set sparc_cpu_model */
sparc_cpu_model = sun_unknown;
- if(!strcmp(&cputypval,"sun4 ")) { sparc_cpu_model=sun4; }
- if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; }
- if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; }
- if(!strcmp(&cputypval,"sun4s")) { sparc_cpu_model=sun4m; } /* CP-1200 with PROM 2.30 -E */
- if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
- if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
- if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
+ if (!strcmp(&cputypval,"sun4 "))
+ sparc_cpu_model = sun4;
+ if (!strcmp(&cputypval,"sun4c"))
+ sparc_cpu_model = sun4c;
+ if (!strcmp(&cputypval,"sun4m"))
+ sparc_cpu_model = sun4m;
+ if (!strcmp(&cputypval,"sun4s"))
+ sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */
+ if (!strcmp(&cputypval,"sun4d"))
+ sparc_cpu_model = sun4d;
+ if (!strcmp(&cputypval,"sun4e"))
+ sparc_cpu_model = sun4e;
+ if (!strcmp(&cputypval,"sun4u"))
+ sparc_cpu_model = sun4u;
-#ifdef CONFIG_SUN4
- if (sparc_cpu_model != sun4) {
- prom_printf("This kernel is for Sun4 architecture only.\n");
- prom_halt();
- }
-#endif
printk("ARCH: ");
switch(sparc_cpu_model) {
case sun4:
@@ -263,7 +265,7 @@
boot_flags_init(*cmdline_p);
idprom_init();
- if (ARCH_SUN4C_SUN4)
+ if (ARCH_SUN4C)
sun4c_probe_vac();
load_mmu();
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index b23cea5..b0dfff8 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -38,17 +38,12 @@
#include <asm/idprom.h>
#include <asm/head.h>
#include <asm/smp.h>
-#include <asm/mostek.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>
#include <asm/checksum.h>
#ifdef CONFIG_SBUS
-#include <asm/sbus.h>
#include <asm/dma.h>
#endif
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
-#endif
#include <asm/io-unit.h>
#include <asm/bug.h>
@@ -127,16 +122,11 @@
EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(__ndelay);
EXPORT_SYMBOL(rtc_lock);
-EXPORT_SYMBOL(mostek_lock);
-EXPORT_SYMBOL(mstk48t02_regs);
#ifdef CONFIG_SUN_AUXIO
EXPORT_SYMBOL(set_auxio);
EXPORT_SYMBOL(get_auxio);
#endif
EXPORT_SYMBOL(io_remap_pfn_range);
- /* P3: iounit_xxx may be needed, sun4d users */
-/* EXPORT_SYMBOL(iounit_map_dma_init); */
-/* EXPORT_SYMBOL(iounit_map_dma_page); */
#ifndef CONFIG_SMP
EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32));
@@ -153,24 +143,9 @@
EXPORT_SYMBOL(BTFIXUP_CALL(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/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
index 340fc39..5dc8a57 100644
--- a/arch/sparc/kernel/sun4c_irq.c
+++ b/arch/sparc/kernel/sun4c_irq.c
@@ -18,6 +18,8 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include "irq.h"
#include <asm/ptrace.h>
@@ -31,15 +33,8 @@
#include <asm/traps.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/sun4paddr.h>
#include <asm/idprom.h>
#include <asm/machines.h>
-#include <asm/sbus.h>
-
-#if 0
-static struct resource sun4c_timer_eb = { "sun4c_timer" };
-static struct resource sun4c_intr_eb = { "sun4c_intr" };
-#endif
/*
* Bit field defines for the interrupt registers on various
@@ -64,19 +59,7 @@
*
* so don't go making it static, like I tried. sigh.
*/
-unsigned char *interrupt_enable = NULL;
-
-static int sun4c_pil_map[] = { 0, 1, 2, 3, 5, 7, 8, 9 };
-
-static unsigned int sun4c_sbint_to_irq(struct sbus_dev *sdev,
- unsigned int sbint)
-{
- if (sbint >= sizeof(sun4c_pil_map)) {
- printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
- BUG();
- }
- return sun4c_pil_map[sbint];
-}
+unsigned char __iomem *interrupt_enable = NULL;
static void sun4c_disable_irq(unsigned int irq_nr)
{
@@ -85,7 +68,7 @@
local_irq_save(flags);
irq_nr &= (NR_IRQS - 1);
- current_mask = *interrupt_enable;
+ current_mask = sbus_readb(interrupt_enable);
switch(irq_nr) {
case 1:
new_mask = ((current_mask) & (~(SUN4C_INT_E1)));
@@ -103,7 +86,7 @@
local_irq_restore(flags);
return;
}
- *interrupt_enable = new_mask;
+ sbus_writeb(new_mask, interrupt_enable);
local_irq_restore(flags);
}
@@ -114,7 +97,7 @@
local_irq_save(flags);
irq_nr &= (NR_IRQS - 1);
- current_mask = *interrupt_enable;
+ current_mask = sbus_readb(interrupt_enable);
switch(irq_nr) {
case 1:
new_mask = ((current_mask) | SUN4C_INT_E1);
@@ -132,37 +115,22 @@
local_irq_restore(flags);
return;
}
- *interrupt_enable = new_mask;
+ sbus_writeb(new_mask, interrupt_enable);
local_irq_restore(flags);
}
-#define TIMER_IRQ 10 /* Also at level 14, but we ignore that one. */
-#define PROFILE_IRQ 14 /* Level14 ticker.. used by OBP for polling */
+struct sun4c_timer_info {
+ u32 l10_count;
+ u32 l10_limit;
+ u32 l14_count;
+ u32 l14_limit;
+};
-volatile struct sun4c_timer_info *sun4c_timers;
-
-#ifdef CONFIG_SUN4
-/* This is an ugly hack to work around the
- current timer code, and make it work with
- the sun4/260 intersil
- */
-volatile struct sun4c_timer_info sun4_timer;
-#endif
+static struct sun4c_timer_info __iomem *sun4c_timers;
static void sun4c_clear_clock_irq(void)
{
- volatile unsigned int clear_intr;
-#ifdef CONFIG_SUN4
- if (idprom->id_machtype == (SM_SUN4 | SM_4_260))
- clear_intr = sun4_timer.timer_limit10;
- else
-#endif
- clear_intr = sun4c_timers->timer_limit10;
-}
-
-static void sun4c_clear_profile_irq(int cpu)
-{
- /* Errm.. not sure how to do this.. */
+ sbus_readl(&sun4c_timers->l10_limit);
}
static void sun4c_load_profile_irq(int cpu, unsigned int limit)
@@ -172,41 +140,48 @@
static void __init sun4c_init_timers(irq_handler_t counter_fn)
{
- int irq;
+ const struct linux_prom_irqs *irq;
+ struct device_node *dp;
+ const u32 *addr;
+ int err;
- /* Map the Timer chip, this is implemented in hardware inside
- * the cache chip on the sun4c.
- */
-#ifdef CONFIG_SUN4
- if (idprom->id_machtype == (SM_SUN4 | SM_4_260))
- sun4c_timers = &sun4_timer;
- else
-#endif
- sun4c_timers = ioremap(SUN_TIMER_PHYSADDR,
- sizeof(struct sun4c_timer_info));
+ dp = of_find_node_by_name(NULL, "counter-timer");
+ if (!dp) {
+ prom_printf("sun4c_init_timers: Unable to find counter-timer\n");
+ prom_halt();
+ }
+
+ addr = of_get_property(dp, "address", NULL);
+ if (!addr) {
+ prom_printf("sun4c_init_timers: No address property\n");
+ prom_halt();
+ }
+
+ sun4c_timers = (void __iomem *) (unsigned long) addr[0];
+
+ irq = of_get_property(dp, "intr", NULL);
+ if (!irq) {
+ prom_printf("sun4c_init_timers: No intr property\n");
+ prom_halt();
+ }
/* Have the level 10 timer tick at 100HZ. We don't touch the
* level 14 timer limit since we are letting the prom handle
* them until we have a real console driver so L1-A works.
*/
- sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10);
- master_l10_counter = &sun4c_timers->cur_count10;
- master_l10_limit = &sun4c_timers->timer_limit10;
+ sbus_writel((((1000000/HZ) + 1) << 10), &sun4c_timers->l10_limit);
- irq = request_irq(TIMER_IRQ,
- counter_fn,
+ master_l10_counter = &sun4c_timers->l10_count;
+
+ err = request_irq(irq[0].pri, counter_fn,
(IRQF_DISABLED | SA_STATIC_ALLOC),
"timer", NULL);
- if (irq) {
- prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
+ if (err) {
+ prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err);
prom_halt();
}
-#if 0
- /* This does not work on 4/330 */
- sun4c_enable_irq(10);
-#endif
- claim_ticker14(NULL, PROFILE_IRQ, 0);
+ sun4c_disable_irq(irq[1].pri);
}
#ifdef CONFIG_SMP
@@ -215,41 +190,28 @@
void __init sun4c_init_IRQ(void)
{
- struct linux_prom_registers int_regs[2];
- int ie_node;
+ struct device_node *dp;
+ const u32 *addr;
- if (ARCH_SUN4) {
- interrupt_enable = (char *)
- ioremap(sun4_ie_physaddr, PAGE_SIZE);
- } else {
- struct resource phyres;
-
- ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
- "interrupt-enable");
- if(ie_node == 0)
- panic("Cannot find /interrupt-enable node");
-
- /* Depending on the "address" property is bad news... */
- interrupt_enable = NULL;
- if (prom_getproperty(ie_node, "reg", (char *) int_regs,
- sizeof(int_regs)) != -1) {
- memset(&phyres, 0, sizeof(struct resource));
- phyres.flags = int_regs[0].which_io;
- phyres.start = int_regs[0].phys_addr;
- interrupt_enable = (char *) sbus_ioremap(&phyres, 0,
- int_regs[0].reg_size, "sun4c_intr");
- }
+ dp = of_find_node_by_name(NULL, "interrupt-enable");
+ if (!dp) {
+ prom_printf("sun4c_init_IRQ: Unable to find interrupt-enable\n");
+ prom_halt();
}
- if (!interrupt_enable)
- panic("Cannot map interrupt_enable");
- BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM);
+ addr = of_get_property(dp, "address", NULL);
+ if (!addr) {
+ prom_printf("sun4c_init_IRQ: No address property\n");
+ prom_halt();
+ }
+
+ interrupt_enable = (void __iomem *) (unsigned long) addr[0];
+
BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP);
BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
sparc_init_timers = sun4c_init_timers;
#ifdef CONFIG_SMP
@@ -257,6 +219,6 @@
BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP);
#endif
- *interrupt_enable = (SUN4C_INT_ENABLE);
+ sbus_writeb(SUN4C_INT_ENABLE, interrupt_enable);
/* Cannot enable interrupts until OBP ticker is disabled. */
}
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 1290b59..d3cb76c 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -19,6 +19,8 @@
#include <linux/smp.h>
#include <linux/spinlock.h>
#include <linux/seq_file.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
@@ -34,7 +36,6 @@
#include <asm/io.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
-#include <asm/sbus.h>
#include <asm/sbi.h>
#include <asm/cacheflush.h>
#include <asm/irq_regs.h>
@@ -44,16 +45,22 @@
/* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
/* #define DISTRIBUTE_IRQS */
-struct sun4d_timer_regs *sun4d_timers;
+struct sun4d_timer_regs {
+ u32 l10_timer_limit;
+ u32 l10_cur_countx;
+ u32 l10_limit_noclear;
+ u32 ctrl;
+ u32 l10_cur_count;
+};
+
+static struct sun4d_timer_regs __iomem *sun4d_timers;
+
#define TIMER_IRQ 10
#define MAX_STATIC_ALLOC 4
extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
extern int static_irq_count;
-unsigned char cpu_leds[32];
-#ifdef CONFIG_SMP
static unsigned char sbus_tid[32];
-#endif
static struct irqaction *irq_action[NR_IRQS];
extern spinlock_t irq_action_lock;
@@ -72,9 +79,9 @@
};
static int nsbi;
-#ifdef CONFIG_SMP
+
+/* Exported for sun4d_smp.c */
DEFINE_SPINLOCK(sun4d_imsk_lock);
-#endif
int show_sun4d_interrupts(struct seq_file *p, void *v)
{
@@ -257,26 +264,6 @@
set_irq_regs(old_regs);
}
-unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq)
-{
- int sbusl = pil_to_sbus[irq];
-
- if (sbusl)
- return ((sdev->bus->board + 1) << 5) + (sbusl << 2) + sdev->slot;
- else
- return irq;
-}
-
-static unsigned int sun4d_sbint_to_irq(struct sbus_dev *sdev,
- unsigned int sbint)
-{
- if (sbint >= sizeof(sbus_to_pil)) {
- printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
- BUG();
- }
- return sun4d_build_irq(sdev, sbus_to_pil[sbint]);
-}
-
int sun4d_request_irq(unsigned int irq,
irq_handler_t handler,
unsigned long irqflags, const char * devname, void *dev_id)
@@ -360,36 +347,28 @@
static void sun4d_disable_irq(unsigned int irq)
{
-#ifdef CONFIG_SMP
int tid = sbus_tid[(irq >> 5) - 1];
unsigned long flags;
-#endif
- if (irq < NR_IRQS) return;
-#ifdef CONFIG_SMP
+ if (irq < NR_IRQS)
+ return;
+
spin_lock_irqsave(&sun4d_imsk_lock, flags);
cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-#else
- cc_set_imsk(cc_get_imsk() | (1 << sbus_to_pil[(irq >> 2) & 7]));
-#endif
}
static void sun4d_enable_irq(unsigned int irq)
{
-#ifdef CONFIG_SMP
int tid = sbus_tid[(irq >> 5) - 1];
unsigned long flags;
-#endif
- if (irq < NR_IRQS) return;
-#ifdef CONFIG_SMP
+ if (irq < NR_IRQS)
+ return;
+
spin_lock_irqsave(&sun4d_imsk_lock, flags);
cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-#else
- cc_set_imsk(cc_get_imsk() & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
-#endif
}
#ifdef CONFIG_SMP
@@ -409,47 +388,55 @@
/* Setup IRQ distribution scheme. */
void __init sun4d_distribute_irqs(void)
{
+ struct device_node *dp;
+
#ifdef DISTRIBUTE_IRQS
- struct sbus_bus *sbus;
- unsigned long sbus_serving_map;
+ cpumask_t sbus_serving_map;
sbus_serving_map = cpu_present_map;
- for_each_sbus(sbus) {
- if ((sbus->board * 2) == boot_cpu_id && (cpu_present_map & (1 << (sbus->board * 2 + 1))))
- sbus_tid[sbus->board] = (sbus->board * 2 + 1);
- else if (cpu_present_map & (1 << (sbus->board * 2)))
- sbus_tid[sbus->board] = (sbus->board * 2);
- else if (cpu_present_map & (1 << (sbus->board * 2 + 1)))
- sbus_tid[sbus->board] = (sbus->board * 2 + 1);
+ for_each_node_by_name(dp, "sbi") {
+ int board = of_getintprop_default(dp, "board#", 0);
+
+ if ((board * 2) == boot_cpu_id && cpu_isset(board * 2 + 1, cpu_present_map))
+ sbus_tid[board] = (board * 2 + 1);
+ else if (cpu_isset(board * 2, cpu_present_map))
+ sbus_tid[board] = (board * 2);
+ else if (cpu_isset(board * 2 + 1, cpu_present_map))
+ sbus_tid[board] = (board * 2 + 1);
else
- sbus_tid[sbus->board] = 0xff;
- if (sbus_tid[sbus->board] != 0xff)
- sbus_serving_map &= ~(1 << sbus_tid[sbus->board]);
+ sbus_tid[board] = 0xff;
+ if (sbus_tid[board] != 0xff)
+ cpu_clear(sbus_tid[board], sbus_serving_map);
}
- for_each_sbus(sbus)
- if (sbus_tid[sbus->board] == 0xff) {
+ for_each_node_by_name(dp, "sbi") {
+ int board = of_getintprop_default(dp, "board#", 0);
+ if (sbus_tid[board] == 0xff) {
int i = 31;
- if (!sbus_serving_map)
+ if (cpus_empty(sbus_serving_map))
sbus_serving_map = cpu_present_map;
- while (!(sbus_serving_map & (1 << i)))
+ while (cpu_isset(i, sbus_serving_map))
i--;
- sbus_tid[sbus->board] = i;
- sbus_serving_map &= ~(1 << i);
+ sbus_tid[board] = i;
+ cpu_clear(i, sbus_serving_map);
}
- for_each_sbus(sbus) {
- printk("sbus%d IRQs directed to CPU%d\n", sbus->board, sbus_tid[sbus->board]);
- set_sbi_tid(sbus->devid, sbus_tid[sbus->board] << 3);
+ }
+ for_each_node_by_name(dp, "sbi") {
+ int devid = of_getintprop_default(dp, "device-id", 0);
+ int board = of_getintprop_default(dp, "board#", 0);
+ printk("sbus%d IRQs directed to CPU%d\n", board, sbus_tid[board]);
+ set_sbi_tid(devid, sbus_tid[board] << 3);
}
#else
- struct sbus_bus *sbus;
int cpuid = cpu_logical_map(1);
if (cpuid == -1)
cpuid = cpu_logical_map(0);
- for_each_sbus(sbus) {
- sbus_tid[sbus->board] = cpuid;
- set_sbi_tid(sbus->devid, cpuid << 3);
+ for_each_node_by_name(dp, "sbi") {
+ int devid = of_getintprop_default(dp, "device-id", 0);
+ int board = of_getintprop_default(dp, "board#", 0);
+ sbus_tid[board] = cpuid;
+ set_sbi_tid(devid, cpuid << 3);
}
printk("All sbus IRQs directed to CPU%d\n", cpuid);
#endif
@@ -458,13 +445,7 @@
static void sun4d_clear_clock_irq(void)
{
- volatile unsigned int clear_intr;
- clear_intr = sun4d_timers->l10_timer_limit;
-}
-
-static void sun4d_clear_profile_irq(int cpu)
-{
- bw_get_prof_limit(cpu);
+ sbus_readl(&sun4d_timers->l10_timer_limit);
}
static void sun4d_load_profile_irq(int cpu, unsigned int limit)
@@ -472,98 +453,121 @@
bw_set_prof_limit(cpu, limit);
}
-static void __init sun4d_init_timers(irq_handler_t counter_fn)
+static void __init sun4d_load_profile_irqs(void)
{
- int irq;
- int cpu;
- struct resource r;
- int mid;
+ int cpu = 0, mid;
- /* Map the User Timer registers. */
- memset(&r, 0, sizeof(r));
-#ifdef CONFIG_SMP
- r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT;
-#else
- r.start = CSR_BASE(0)+BW_TIMER_LIMIT;
-#endif
- r.flags = 0xf;
- sun4d_timers = (struct sun4d_timer_regs *) sbus_ioremap(&r, 0,
- PAGE_SIZE, "user timer");
-
- sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
- master_l10_counter = &sun4d_timers->l10_cur_count;
- master_l10_limit = &sun4d_timers->l10_timer_limit;
-
- irq = request_irq(TIMER_IRQ,
- counter_fn,
- (IRQF_DISABLED | SA_STATIC_ALLOC),
- "timer", NULL);
- if (irq) {
- prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
- prom_halt();
- }
-
- /* Enable user timer free run for CPU 0 in BW */
- /* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
-
- cpu = 0;
while (!cpu_find_by_instance(cpu, NULL, &mid)) {
sun4d_load_profile_irq(mid >> 3, 0);
cpu++;
}
-
+}
+
+static void __init sun4d_fixup_trap_table(void)
+{
#ifdef CONFIG_SMP
- {
- unsigned long flags;
- extern unsigned long lvl14_save[4];
- struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
- extern unsigned int real_irq_entry[], smp4d_ticker[];
- extern unsigned int patchme_maybe_smp_msg[];
+ unsigned long flags;
+ extern unsigned long lvl14_save[4];
+ struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
+ extern unsigned int real_irq_entry[], smp4d_ticker[];
+ extern unsigned int patchme_maybe_smp_msg[];
- /* Adjust so that we jump directly to smp4d_ticker */
- lvl14_save[2] += smp4d_ticker - real_irq_entry;
+ /* Adjust so that we jump directly to smp4d_ticker */
+ lvl14_save[2] += smp4d_ticker - real_irq_entry;
- /* For SMP we use the level 14 ticker, however the bootup code
- * has copied the firmware's level 14 vector into the boot cpu's
- * trap table, we must fix this now or we get squashed.
- */
- local_irq_save(flags);
- patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
- trap_table->inst_one = lvl14_save[0];
- trap_table->inst_two = lvl14_save[1];
- trap_table->inst_three = lvl14_save[2];
- trap_table->inst_four = lvl14_save[3];
- local_flush_cache_all();
- local_irq_restore(flags);
- }
+ /* For SMP we use the level 14 ticker, however the bootup code
+ * has copied the firmware's level 14 vector into the boot cpu's
+ * trap table, we must fix this now or we get squashed.
+ */
+ local_irq_save(flags);
+ patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
+ trap_table->inst_one = lvl14_save[0];
+ trap_table->inst_two = lvl14_save[1];
+ trap_table->inst_three = lvl14_save[2];
+ trap_table->inst_four = lvl14_save[3];
+ local_flush_cache_all();
+ local_irq_restore(flags);
#endif
}
+static void __init sun4d_init_timers(irq_handler_t counter_fn)
+{
+ struct device_node *dp;
+ struct resource res;
+ const u32 *reg;
+ int err;
+
+ dp = of_find_node_by_name(NULL, "cpu-unit");
+ if (!dp) {
+ prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
+ prom_halt();
+ }
+
+ /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
+ * registers via any cpu's mapping. The first 'reg' property is the
+ * bootbus.
+ */
+ reg = of_get_property(dp, "reg", NULL);
+ if (!reg) {
+ prom_printf("sun4d_init_timers: No reg property\n");
+ prom_halt();
+ }
+
+ res.start = reg[1];
+ res.end = reg[2] - 1;
+ res.flags = reg[0] & 0xff;
+ sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
+ sizeof(struct sun4d_timer_regs), "user timer");
+ if (!sun4d_timers) {
+ prom_printf("sun4d_init_timers: Can't map timer regs\n");
+ prom_halt();
+ }
+
+ sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
+
+ master_l10_counter = &sun4d_timers->l10_cur_count;
+
+ err = request_irq(TIMER_IRQ, counter_fn,
+ (IRQF_DISABLED | SA_STATIC_ALLOC),
+ "timer", NULL);
+ if (err) {
+ prom_printf("sun4d_init_timers: request_irq() failed with %d\n", err);
+ prom_halt();
+ }
+ sun4d_load_profile_irqs();
+ sun4d_fixup_trap_table();
+}
+
void __init sun4d_init_sbi_irq(void)
{
- struct sbus_bus *sbus;
- unsigned mask;
+ struct device_node *dp;
+ int target_cpu = 0;
+
+#ifdef CONFIG_SMP
+ target_cpu = boot_cpu_id;
+#endif
nsbi = 0;
- for_each_sbus(sbus)
+ for_each_node_by_name(dp, "sbi")
nsbi++;
sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
if (!sbus_actions) {
prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n");
prom_halt();
}
- for_each_sbus(sbus) {
-#ifdef CONFIG_SMP
- extern unsigned char boot_cpu_id;
-
- set_sbi_tid(sbus->devid, boot_cpu_id << 3);
- sbus_tid[sbus->board] = boot_cpu_id;
-#endif
+ for_each_node_by_name(dp, "sbi") {
+ int devid = of_getintprop_default(dp, "device-id", 0);
+ int board = of_getintprop_default(dp, "board#", 0);
+ unsigned int mask;
+
+ set_sbi_tid(devid, target_cpu << 3);
+ sbus_tid[board] = target_cpu;
+
/* Get rid of pending irqs from PROM */
- mask = acquire_sbi(sbus->devid, 0xffffffff);
+ mask = acquire_sbi(devid, 0xffffffff);
if (mask) {
- printk ("Clearing pending IRQs %08x on SBI %d\n", mask, sbus->board);
- release_sbi(sbus->devid, mask);
+ printk ("Clearing pending IRQs %08x on SBI %d\n", mask, board);
+ release_sbi(devid, mask);
}
}
}
@@ -572,11 +576,9 @@
{
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/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 446767e..ce3d45d 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -30,7 +30,6 @@
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
-#include <asm/sbus.h>
#include <asm/sbi.h>
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
@@ -72,6 +71,17 @@
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/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index 94e02de..f103171 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -20,6 +20,8 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/ioport.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
@@ -35,59 +37,27 @@
#include <asm/smp.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/sbus.h>
#include <asm/cacheflush.h>
#include "irq.h"
-/* On the sun4m, just like the timers, we have both per-cpu and master
- * interrupt registers.
- */
-
-/* These registers are used for sending/receiving irqs from/to
- * different cpu's.
- */
-struct sun4m_intreg_percpu {
- unsigned int tbt; /* Interrupts still pending for this cpu. */
-
- /* These next two registers are WRITE-ONLY and are only
- * "on bit" sensitive, "off bits" written have NO affect.
- */
- unsigned int clear; /* Clear this cpus irqs here. */
- unsigned int set; /* Set this cpus irqs here. */
- unsigned char space[PAGE_SIZE - 12];
+struct sun4m_irq_percpu {
+ u32 pending;
+ u32 clear;
+ u32 set;
};
-/*
- * djhr
- * Actually the clear and set fields in this struct are misleading..
- * according to the SLAVIO manual (and the same applies for the SEC)
- * the clear field clears bits in the mask which will ENABLE that IRQ
- * the set field sets bits in the mask to DISABLE the IRQ.
- *
- * Also the undirected_xx address in the SLAVIO is defined as
- * RESERVED and write only..
- *
- * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
- * sun4m machines, for MP the layout makes more sense.
- */
-struct sun4m_intregs {
- struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
- unsigned int tbt; /* IRQ's that are still pending. */
- unsigned int irqs; /* Master IRQ bits. */
-
- /* Again, like the above, two these registers are WRITE-ONLY. */
- unsigned int clear; /* Clear master IRQ's by setting bits here. */
- unsigned int set; /* Set master IRQ's by setting bits here. */
-
- /* This register is both READ and WRITE. */
- unsigned int undirected_target; /* Which cpu gets undirected irqs. */
+struct sun4m_irq_global {
+ u32 pending;
+ u32 mask;
+ u32 mask_clear;
+ u32 mask_set;
+ u32 interrupt_target;
};
-static unsigned long dummy;
-
-struct sun4m_intregs *sun4m_interrupts;
-unsigned long *irq_rcvreg = &dummy;
+/* Code in entry.S needs to get at these register mappings. */
+struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
+struct sun4m_irq_global __iomem *sun4m_irq_global;
/* Dave Redman (djhr@tadpole.co.uk)
* The sun4m interrupt registers.
@@ -101,8 +71,9 @@
#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */
#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */
-#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */
-#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */
+#define SUN4M_INT_M2S_WRITE_ERR 0x20000000 /* write buffer error */
+#define SUN4M_INT_ECC_ERR 0x10000000 /* ecc memory error */
+#define SUN4M_INT_VME_ERR 0x08000000 /* vme async error */
#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */
#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */
#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */
@@ -113,75 +84,126 @@
#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */
#define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */
#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */
+#define SUN4M_INT_VMEBITS 0x0000007F /* vme int bits */
+
+#define SUN4M_INT_ERROR (SUN4M_INT_MODULE_ERR | \
+ SUN4M_INT_M2S_WRITE_ERR | \
+ SUN4M_INT_ECC_ERR | \
+ SUN4M_INT_VME_ERR)
#define SUN4M_INT_SBUS(x) (1 << (x+7))
#define SUN4M_INT_VME(x) (1 << (x))
-/* These tables only apply for interrupts greater than 15..
- *
- * any intr value below 0x10 is considered to be a soft-int
- * this may be useful or it may not.. but that's how I've done it.
- * and it won't clash with what OBP is telling us about devices.
+/* Interrupt levels used by OBP */
+#define OBP_INT_LEVEL_SOFT 0x10
+#define OBP_INT_LEVEL_ONBOARD 0x20
+#define OBP_INT_LEVEL_SBUS 0x30
+#define OBP_INT_LEVEL_VME 0x40
+
+/* Interrupt level assignment on sun4m:
*
- * take an encoded intr value and lookup if it's valid
- * then get the mask bits that match from irq_mask
+ * level source
+ * ------------------------------------------------------------
+ * 1 softint-1
+ * 2 softint-2, VME/SBUS level 1
+ * 3 softint-3, VME/SBUS level 2
+ * 4 softint-4, onboard SCSI
+ * 5 softint-5, VME/SBUS level 3
+ * 6 softint-6, onboard ETHERNET
+ * 7 softint-7, VME/SBUS level 4
+ * 8 softint-8, onboard VIDEO
+ * 9 softint-9, VME/SBUS level 5, Module Interrupt
+ * 10 softint-10, system counter/timer
+ * 11 softint-11, VME/SBUS level 6, Floppy
+ * 12 softint-12, Keyboard/Mouse, Serial
+ * 13 softint-13, VME/SBUS level 7, ISDN Audio
+ * 14 softint-14, per-processor counter/timer
+ * 15 softint-15, Asynchronous Errors (broadcast)
*
- * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee.
+ * Each interrupt source is masked distinctly in the sun4m interrupt
+ * registers. The PIL level alone is therefore ambiguous, since multiple
+ * interrupt sources map to a single PIL.
+ *
+ * This ambiguity is resolved in the 'intr' property for device nodes
+ * in the OF device tree. Each 'intr' property entry is composed of
+ * two 32-bit words. The first word is the IRQ priority value, which
+ * is what we're intersted in. The second word is the IRQ vector, which
+ * is unused.
+ *
+ * The low 4 bits of the IRQ priority indicate the PIL, and the upper
+ * 4 bits indicate onboard vs. SBUS leveled vs. VME leveled. 0x20
+ * means onboard, 0x30 means SBUS leveled, and 0x40 means VME leveled.
+ *
+ * For example, an 'intr' IRQ priority value of 0x24 is onboard SCSI
+ * whereas a value of 0x33 is SBUS level 2. Here are some sample
+ * 'intr' property IRQ priority values from ss4, ss5, ss10, ss20, and
+ * Tadpole S3 GX systems.
+ *
+ * esp: 0x24 onboard ESP SCSI
+ * le: 0x26 onboard Lance ETHERNET
+ * p9100: 0x32 SBUS level 1 P9100 video
+ * bpp: 0x33 SBUS level 2 BPP parallel port device
+ * DBRI: 0x39 SBUS level 5 DBRI ISDN audio
+ * SUNW,leo: 0x39 SBUS level 5 LEO video
+ * pcmcia: 0x3b SBUS level 6 PCMCIA controller
+ * uctrl: 0x3b SBUS level 6 UCTRL device
+ * modem: 0x3d SBUS level 7 MODEM
+ * zs: 0x2c onboard keyboard/mouse/serial
+ * floppy: 0x2b onboard Floppy
+ * power: 0x22 onboard power device (XXX unknown mask bit XXX)
*/
-static unsigned char irq_xlate[32] = {
- /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */
- 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7,
- 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0
+
+static unsigned long irq_mask[0x50] = {
+ /* SMP */
+ 0, SUN4M_SOFT_INT(1),
+ SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
+ SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
+ SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
+ SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
+ SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+ SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+ SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+ /* soft */
+ 0, SUN4M_SOFT_INT(1),
+ SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
+ SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
+ SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
+ SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
+ SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+ SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+ SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+ /* onboard */
+ 0, 0, 0, 0,
+ SUN4M_INT_SCSI, 0, SUN4M_INT_ETHERNET, 0,
+ SUN4M_INT_VIDEO, SUN4M_INT_MODULE,
+ SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY,
+ (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),
+ SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR,
+ /* sbus */
+ 0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1),
+ 0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3),
+ 0, SUN4M_INT_SBUS(4), 0, SUN4M_INT_SBUS(5),
+ 0, SUN4M_INT_SBUS(6), 0, 0,
+ /* vme */
+ 0, 0, SUN4M_INT_VME(0), SUN4M_INT_VME(1),
+ 0, SUN4M_INT_VME(2), 0, SUN4M_INT_VME(3),
+ 0, SUN4M_INT_VME(4), 0, SUN4M_INT_VME(5),
+ 0, SUN4M_INT_VME(6), 0, 0
};
-static unsigned long irq_mask[] = {
- 0, /* illegal index */
- SUN4M_INT_SCSI, /* 1 irq 4 */
- SUN4M_INT_ETHERNET, /* 2 irq 6 */
- SUN4M_INT_VIDEO, /* 3 irq 8 */
- SUN4M_INT_REALTIME, /* 4 irq 10 */
- SUN4M_INT_FLOPPY, /* 5 irq 11 */
- (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), /* 6 irq 12 */
- SUN4M_INT_MODULE_ERR, /* 7 irq 15 */
- SUN4M_INT_SBUS(0), /* 8 irq 2 */
- SUN4M_INT_SBUS(1), /* 9 irq 3 */
- SUN4M_INT_SBUS(2), /* 10 irq 5 */
- SUN4M_INT_SBUS(3), /* 11 irq 7 */
- SUN4M_INT_SBUS(4), /* 12 irq 9 */
- SUN4M_INT_SBUS(5), /* 13 irq 11 */
- SUN4M_INT_SBUS(6) /* 14 irq 13 */
-};
-
-static int sun4m_pil_map[] = { 0, 2, 3, 5, 7, 9, 11, 13 };
-
-static unsigned int sun4m_sbint_to_irq(struct sbus_dev *sdev,
- unsigned int sbint)
-{
- if (sbint >= sizeof(sun4m_pil_map)) {
- printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
- BUG();
- }
- return sun4m_pil_map[sbint] | 0x30;
-}
-
static unsigned long sun4m_get_irqmask(unsigned int irq)
{
unsigned long mask;
- if (irq > 0x20) {
- /* OBIO/SBUS interrupts */
- irq &= 0x1f;
- mask = irq_mask[irq_xlate[irq]];
- if (!mask)
- printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq);
- } else {
- /* Soft Interrupts will come here.
- * Currently there is no way to trigger them but I'm sure
- * something could be cooked up.
- */
- irq &= 0xf;
- mask = SUN4M_SOFT_INT(irq);
- }
+ if (irq < 0x50)
+ mask = irq_mask[irq];
+ else
+ mask = 0;
+
+ if (!mask)
+ printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n",
+ irq);
+
return mask;
}
@@ -193,9 +215,9 @@
mask = sun4m_get_irqmask(irq_nr);
local_irq_save(flags);
if (irq_nr > 15)
- sun4m_interrupts->set = mask;
+ sbus_writel(mask, &sun4m_irq_global->mask_set);
else
- sun4m_interrupts->cpu_intregs[cpu].set = mask;
+ sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
local_irq_restore(flags);
}
@@ -212,13 +234,13 @@
mask = sun4m_get_irqmask(irq_nr);
local_irq_save(flags);
if (irq_nr > 15)
- sun4m_interrupts->clear = mask;
+ sbus_writel(mask, &sun4m_irq_global->mask_clear);
else
- sun4m_interrupts->cpu_intregs[cpu].clear = mask;
+ sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
local_irq_restore(flags);
} else {
local_irq_save(flags);
- sun4m_interrupts->clear = SUN4M_INT_FLOPPY;
+ sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
local_irq_restore(flags);
}
}
@@ -236,10 +258,10 @@
/*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
/*10*/ SUN4M_INT_REALTIME,
/*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
-/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
-/*13*/ SUN4M_INT_AUDIO,
+/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
+/*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO,
/*14*/ SUN4M_INT_E14,
-/*15*/ 0x00000000
+/*15*/ SUN4M_INT_ERROR
};
/* We assume the caller has disabled local interrupts when these are called,
@@ -247,126 +269,141 @@
*/
static void sun4m_disable_pil_irq(unsigned int pil)
{
- sun4m_interrupts->set = cpu_pil_to_imask[pil];
+ sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set);
}
static void sun4m_enable_pil_irq(unsigned int pil)
{
- sun4m_interrupts->clear = cpu_pil_to_imask[pil];
+ sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear);
}
#ifdef CONFIG_SMP
static void sun4m_send_ipi(int cpu, int level)
{
- unsigned long mask;
-
- mask = sun4m_get_irqmask(level);
- sun4m_interrupts->cpu_intregs[cpu].set = mask;
+ unsigned long mask = sun4m_get_irqmask(level);
+ sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
}
static void sun4m_clear_ipi(int cpu, int level)
{
- unsigned long mask;
-
- mask = sun4m_get_irqmask(level);
- sun4m_interrupts->cpu_intregs[cpu].clear = mask;
+ unsigned long mask = sun4m_get_irqmask(level);
+ sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
}
static void sun4m_set_udt(int cpu)
{
- sun4m_interrupts->undirected_target = cpu;
+ sbus_writel(cpu, &sun4m_irq_global->interrupt_target);
}
#endif
-#define OBIO_INTR 0x20
-#define TIMER_IRQ (OBIO_INTR | 10)
-#define PROFILE_IRQ (OBIO_INTR | 14)
+struct sun4m_timer_percpu {
+ u32 l14_limit;
+ u32 l14_count;
+ u32 l14_limit_noclear;
+ u32 user_timer_start_stop;
+};
-static struct sun4m_timer_regs *sun4m_timers;
+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)
+
unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
static void sun4m_clear_clock_irq(void)
{
- volatile unsigned int clear_intr;
- clear_intr = sun4m_timers->l10_timer_limit;
+ sbus_readl(&timers_global->l10_limit);
}
-static void sun4m_clear_profile_irq(int cpu)
+void sun4m_nmi(struct pt_regs *regs)
{
- volatile unsigned int clear;
-
- clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit;
+ unsigned long afsr, afar, si;
+
+ printk(KERN_ERR "Aieee: sun4m NMI received!\n");
+ /* XXX HyperSparc hack XXX */
+ __asm__ __volatile__("mov 0x500, %%g1\n\t"
+ "lda [%%g1] 0x4, %0\n\t"
+ "mov 0x600, %%g1\n\t"
+ "lda [%%g1] 0x4, %1\n\t" :
+ "=r" (afsr), "=r" (afar));
+ printk(KERN_ERR "afsr=%08lx afar=%08lx\n", afsr, afar);
+ si = sbus_readl(&sun4m_irq_global->pending);
+ printk(KERN_ERR "si=%08lx\n", si);
+ if (si & SUN4M_INT_MODULE_ERR)
+ printk(KERN_ERR "Module async error\n");
+ if (si & SUN4M_INT_M2S_WRITE_ERR)
+ printk(KERN_ERR "MBus/SBus async error\n");
+ if (si & SUN4M_INT_ECC_ERR)
+ printk(KERN_ERR "ECC memory error\n");
+ if (si & SUN4M_INT_VME_ERR)
+ printk(KERN_ERR "VME async error\n");
+ printk(KERN_ERR "you lose buddy boy...\n");
+ show_regs(regs);
+ prom_halt();
+}
+
+/* Exported for sun4m_smp.c */
+void sun4m_clear_profile_irq(int cpu)
+{
+ sbus_readl(&timers_percpu[cpu]->l14_limit);
}
static void sun4m_load_profile_irq(int cpu, unsigned int limit)
{
- sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit;
+ sbus_writel(limit, &timers_percpu[cpu]->l14_limit);
}
static void __init sun4m_init_timers(irq_handler_t counter_fn)
{
- int reg_count, irq, cpu;
- struct linux_prom_registers cnt_regs[PROMREG_MAX];
- int obio_node, cnt_node;
- struct resource r;
+ struct device_node *dp = of_find_node_by_name(NULL, "counter");
+ int i, err, len, num_cpu_timers;
+ const u32 *addr;
- cnt_node = 0;
- if((obio_node =
- prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
- (obio_node = prom_getchild (obio_node)) == 0 ||
- (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
- prom_printf("Cannot find /obio/counter node\n");
- prom_halt();
- }
- reg_count = prom_getproperty(cnt_node, "reg",
- (void *) cnt_regs, sizeof(cnt_regs));
- reg_count = (reg_count/sizeof(struct linux_prom_registers));
-
- /* Apply the obio ranges to the timer registers. */
- prom_apply_obio_ranges(cnt_regs, reg_count);
-
- cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr;
- cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size;
- cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io;
- for(obio_node = 1; obio_node < 4; obio_node++) {
- cnt_regs[obio_node].phys_addr =
- cnt_regs[obio_node-1].phys_addr + PAGE_SIZE;
- cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
- cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;
+ if (!dp) {
+ printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n");
+ return;
}
- memset((char*)&r, 0, sizeof(struct resource));
- /* Map the per-cpu Counter registers. */
- r.flags = cnt_regs[0].which_io;
- r.start = cnt_regs[0].phys_addr;
- sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0,
- PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt");
- /* Map the system Counter register. */
- /* XXX Here we expect consequent calls to yeld adjusent maps. */
- r.flags = cnt_regs[4].which_io;
- r.start = cnt_regs[4].phys_addr;
- sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt");
-
- sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
- master_l10_counter = &sun4m_timers->l10_cur_count;
- master_l10_limit = &sun4m_timers->l10_timer_limit;
-
- irq = request_irq(TIMER_IRQ,
- counter_fn,
- (IRQF_DISABLED | SA_STATIC_ALLOC),
- "timer", NULL);
- if (irq) {
- prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
- prom_halt();
+ addr = of_get_property(dp, "address", &len);
+ if (!addr) {
+ printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n");
+ return;
}
-
- if (!cpu_find_by_instance(1, NULL, NULL)) {
- for(cpu = 0; cpu < 4; cpu++)
- sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0;
- sun4m_interrupts->set = SUN4M_INT_E14;
- } else {
- sun4m_timers->cpu_timers[0].l14_timer_limit = 0;
+
+ num_cpu_timers = (len / sizeof(u32)) - 1;
+ for (i = 0; i < num_cpu_timers; i++) {
+ timers_percpu[i] = (void __iomem *)
+ (unsigned long) addr[i];
}
+ timers_global = (void __iomem *)
+ (unsigned long) addr[num_cpu_timers];
+
+ sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit);
+
+ master_l10_counter = &timers_global->l10_count;
+
+ err = request_irq(TIMER_IRQ, counter_fn,
+ (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
+ if (err) {
+ printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n",
+ err);
+ return;
+ }
+
+ for (i = 0; i < num_cpu_timers; i++)
+ sbus_writel(0, &timers_percpu[i]->l14_limit);
+ if (num_cpu_timers == 4)
+ sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set);
+
#ifdef CONFIG_SMP
{
unsigned long flags;
@@ -390,70 +427,43 @@
void __init sun4m_init_IRQ(void)
{
- int ie_node,i;
- struct linux_prom_registers int_regs[PROMREG_MAX];
- int num_regs;
- struct resource r;
- int mid;
-
+ struct device_node *dp = of_find_node_by_name(NULL, "interrupt");
+ int len, i, mid, num_cpu_iregs;
+ const u32 *addr;
+
+ if (!dp) {
+ printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n");
+ return;
+ }
+
+ addr = of_get_property(dp, "address", &len);
+ if (!addr) {
+ printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
+ return;
+ }
+
+ num_cpu_iregs = (len / sizeof(u32)) - 1;
+ for (i = 0; i < num_cpu_iregs; i++) {
+ sun4m_irq_percpu[i] = (void __iomem *)
+ (unsigned long) addr[i];
+ }
+ sun4m_irq_global = (void __iomem *)
+ (unsigned long) addr[num_cpu_iregs];
+
local_irq_disable();
- if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
- (ie_node = prom_getchild (ie_node)) == 0 ||
- (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
- prom_printf("Cannot find /obio/interrupt node\n");
- prom_halt();
- }
- num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
- sizeof(int_regs));
- num_regs = (num_regs/sizeof(struct linux_prom_registers));
-
- /* Apply the obio ranges to these registers. */
- prom_apply_obio_ranges(int_regs, num_regs);
-
- int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
- int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
- int_regs[4].which_io = int_regs[num_regs-1].which_io;
- for(ie_node = 1; ie_node < 4; ie_node++) {
- int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
- int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
- int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
- }
- memset((char *)&r, 0, sizeof(struct resource));
- /* Map the interrupt registers for all possible cpus. */
- r.flags = int_regs[0].which_io;
- r.start = int_regs[0].phys_addr;
- sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0,
- PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu");
-
- /* Map the system interrupt control registers. */
- r.flags = int_regs[4].which_io;
- r.start = int_regs[4].phys_addr;
- sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
-
- sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
+ sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set);
for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
- sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff;
+ sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
- if (!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);
+ if (num_cpu_iregs == 4)
+ sbus_writel(0, &sun4m_irq_global->interrupt_target);
+
BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
sparc_init_timers = sun4m_init_timers;
#ifdef CONFIG_SMP
@@ -461,5 +471,6 @@
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/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 9964890..0c564ba 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -315,6 +315,8 @@
ccall_info.processors_out[i] = 1;
}
+extern void sun4m_clear_profile_irq(int cpu);
+
void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
{
struct pt_regs *old_regs;
@@ -322,7 +324,7 @@
old_regs = set_irq_regs(regs);
- clear_profile_irq(cpu);
+ sun4m_clear_profile_irq(cpu);
profile_tick(CPU_PROFILING);
diff --git a/arch/sparc/kernel/sun4setup.c b/arch/sparc/kernel/sun4setup.c
deleted file mode 100644
index 229a52f..0000000
--- a/arch/sparc/kernel/sun4setup.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* sun4setup.c: Setup the hardware address of various items in the sun4
- * architecture. Called from idprom_init
- *
- * Copyright (C) 1998 Chris G. Davis (cdavis@cois.on.ca)
- */
-
-#include <asm/page.h>
-#include <asm/oplib.h>
-#include <asm/idprom.h>
-#include <asm/sun4paddr.h>
-#include <asm/machines.h>
-
-int sun4_memreg_physaddr;
-int sun4_ie_physaddr;
-int sun4_clock_physaddr;
-int sun4_timer_physaddr;
-int sun4_eth_physaddr;
-int sun4_si_physaddr;
-int sun4_bwtwo_physaddr;
-int sun4_zs0_physaddr;
-int sun4_zs1_physaddr;
-int sun4_dma_physaddr;
-int sun4_esp_physaddr;
-int sun4_ie_physaddr;
-
-void __init sun4setup(void)
-{
- printk("Sun4 Hardware Setup v1.0 18/May/98 Chris Davis (cdavis@cois.on.ca). ");
- /*
- setup standard sun4 info
- */
- sun4_ie_physaddr=SUN4_IE_PHYSADDR;
-
- /*
- setup model specific info
- */
- switch(idprom->id_machtype) {
- case (SM_SUN4 | SM_4_260 ):
- printk("Setup for a SUN4/260\n");
- sun4_memreg_physaddr=SUN4_200_MEMREG_PHYSADDR;
- sun4_clock_physaddr=SUN4_200_CLOCK_PHYSADDR;
- sun4_timer_physaddr=SUN4_UNUSED_PHYSADDR;
- sun4_eth_physaddr=SUN4_200_ETH_PHYSADDR;
- sun4_si_physaddr=SUN4_200_SI_PHYSADDR;
- sun4_bwtwo_physaddr=SUN4_200_BWTWO_PHYSADDR;
- sun4_dma_physaddr=SUN4_UNUSED_PHYSADDR;
- sun4_esp_physaddr=SUN4_UNUSED_PHYSADDR;
- break;
- case (SM_SUN4 | SM_4_330 ):
- printk("Setup for a SUN4/330\n");
- sun4_memreg_physaddr=SUN4_300_MEMREG_PHYSADDR;
- sun4_clock_physaddr=SUN4_300_CLOCK_PHYSADDR;
- sun4_timer_physaddr=SUN4_300_TIMER_PHYSADDR;
- sun4_eth_physaddr=SUN4_300_ETH_PHYSADDR;
- sun4_si_physaddr=SUN4_UNUSED_PHYSADDR;
- sun4_bwtwo_physaddr=SUN4_300_BWTWO_PHYSADDR;
- sun4_dma_physaddr=SUN4_300_DMA_PHYSADDR;
- sun4_esp_physaddr=SUN4_300_ESP_PHYSADDR;
- break;
- case (SM_SUN4 | SM_4_470 ):
- printk("Setup for a SUN4/470\n");
- sun4_memreg_physaddr=SUN4_400_MEMREG_PHYSADDR;
- sun4_clock_physaddr=SUN4_400_CLOCK_PHYSADDR;
- sun4_timer_physaddr=SUN4_400_TIMER_PHYSADDR;
- sun4_eth_physaddr=SUN4_400_ETH_PHYSADDR;
- sun4_si_physaddr=SUN4_UNUSED_PHYSADDR;
- sun4_bwtwo_physaddr=SUN4_400_BWTWO_PHYSADDR;
- sun4_dma_physaddr=SUN4_400_DMA_PHYSADDR;
- sun4_esp_physaddr=SUN4_400_ESP_PHYSADDR;
- break;
- default:
- ;
- }
-}
-
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index 4d73421..03035c8 100644
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -53,7 +53,7 @@
/* See asm-sparc/uaccess.h */
if (len > TASK_SIZE - PAGE_SIZE)
return -ENOMEM;
- if (ARCH_SUN4C_SUN4 && len > 0x20000000)
+ if (ARCH_SUN4C && len > 0x20000000)
return -ENOMEM;
if (!addr)
addr = TASK_UNMAPPED_BASE;
@@ -65,7 +65,7 @@
for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
/* At this point: (!vmm || addr < vmm->vm_end). */
- if (ARCH_SUN4C_SUN4 && addr < 0xe0000000 && 0x20000000 - len < addr) {
+ if (ARCH_SUN4C && addr < 0xe0000000 && 0x20000000 - len < addr) {
addr = PAGE_OFFSET;
vmm = find_vma(current->mm, PAGE_OFFSET);
}
@@ -81,7 +81,7 @@
asmlinkage unsigned long sparc_brk(unsigned long brk)
{
- if(ARCH_SUN4C_SUN4) {
+ if(ARCH_SUN4C) {
if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000))
return current->mm->brk;
}
@@ -221,7 +221,7 @@
int sparc_mmap_check(unsigned long addr, unsigned long len)
{
- if (ARCH_SUN4C_SUN4 &&
+ if (ARCH_SUN4C &&
(len > 0x20000000 ||
(addr < 0xe0000000 && addr + len > 0x20000000)))
return -EINVAL;
diff --git a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c
index 707bfda..138bbf5 100644
--- a/arch/sparc/kernel/tick14.c
+++ b/arch/sparc/kernel/tick14.c
@@ -1,31 +1,12 @@
/* tick14.c
- * linux/arch/sparc/kernel/tick14.c
*
* Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
*
* This file handles the Sparc specific level14 ticker
* This is really useful for profiling OBP uses it for keyboard
* aborts and other stuff.
- *
- *
*/
-#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/timex.h>
-#include <linux/interrupt.h>
-
-#include <asm/oplib.h>
-#include <asm/timer.h>
-#include <asm/mostek.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-
-#include "irq.h"
extern unsigned long lvl14_save[5];
static unsigned long *linux_lvl14 = NULL;
@@ -56,31 +37,3 @@
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/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 0762f5d..62c1d94 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -23,22 +23,24 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/rtc/m48t59.h>
#include <linux/timex.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/profile.h>
+#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <asm/oplib.h>
#include <asm/timer.h>
-#include <asm/mostek.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/idprom.h>
#include <asm/machines.h>
-#include <asm/sun4paddr.h>
#include <asm/page.h>
#include <asm/pcic.h>
#include <asm/irq_regs.h>
@@ -46,34 +48,9 @@
#include "irq.h"
DEFINE_SPINLOCK(rtc_lock);
-static enum sparc_clock_type sp_clock_typ;
-DEFINE_SPINLOCK(mostek_lock);
-void __iomem *mstk48t02_regs = NULL;
-static struct mostek48t08 __iomem *mstk48t08_regs = NULL;
static int set_rtc_mmss(unsigned long);
static int sbus_do_settimeofday(struct timespec *tv);
-#ifdef CONFIG_SUN4
-struct intersil *intersil_clock;
-#define intersil_cmd(intersil_reg, intsil_cmd) intersil_reg->int_cmd_reg = \
- (intsil_cmd)
-
-#define intersil_intr(intersil_reg, intsil_cmd) intersil_reg->int_intr_reg = \
- (intsil_cmd)
-
-#define intersil_start(intersil_reg) intersil_cmd(intersil_reg, \
- ( INTERSIL_START | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
- INTERSIL_INTR_ENABLE))
-
-#define intersil_stop(intersil_reg) intersil_cmd(intersil_reg, \
- ( INTERSIL_STOP | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
- INTERSIL_INTR_ENABLE))
-
-#define intersil_read_intr(intersil_reg, towhere) towhere = \
- intersil_reg->int_intr_reg
-
-#endif
-
unsigned long profile_pc(struct pt_regs *regs)
{
extern char __copy_user_begin[], __copy_user_end[];
@@ -96,7 +73,6 @@
EXPORT_SYMBOL(profile_pc);
__volatile__ unsigned int *master_l10_counter;
-__volatile__ unsigned int *master_l10_limit;
/*
* timer_interrupt() needs to keep up the real-time clock,
@@ -116,15 +92,7 @@
/* Protect counter clear so that do_gettimeoffset works */
write_seqlock(&xtime_lock);
-#ifdef CONFIG_SUN4
- if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
- (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
- int temp;
- intersil_read_intr(intersil_clock, temp);
- /* re-enable the irq */
- enable_pil_irq(10);
- }
-#endif
+
clear_clock_irq();
do_timer(1);
@@ -147,157 +115,56 @@
return IRQ_HANDLED;
}
-/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
-static void __devinit kick_start_clock(void)
+static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
{
- struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
- unsigned char sec;
- int i, count;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ void __iomem *regs = pdata->ioaddr;
+ unsigned char val = readb(regs + ofs);
- prom_printf("CLOCK: Clock was stopped. Kick start ");
-
- spin_lock_irq(&mostek_lock);
-
- /* Turn on the kick start bit to start the oscillator. */
- regs->creg |= MSTK_CREG_WRITE;
- regs->sec &= ~MSTK_STOP;
- regs->hour |= MSTK_KICK_START;
- regs->creg &= ~MSTK_CREG_WRITE;
-
- spin_unlock_irq(&mostek_lock);
-
- /* Delay to allow the clock oscillator to start. */
- sec = MSTK_REG_SEC(regs);
- for (i = 0; i < 3; i++) {
- while (sec == MSTK_REG_SEC(regs))
- for (count = 0; count < 100000; count++)
- /* nothing */ ;
- prom_printf(".");
- sec = regs->sec;
+ /* the year 0 is 1968 */
+ if (ofs == pdata->offset + M48T59_YEAR) {
+ val += 0x68;
+ if ((val & 0xf) > 9)
+ val += 6;
}
- prom_printf("\n");
+ return val;
+}
- spin_lock_irq(&mostek_lock);
+static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ void __iomem *regs = pdata->ioaddr;
- /* Turn off kick start and set a "valid" time and date. */
- regs->creg |= MSTK_CREG_WRITE;
- regs->hour &= ~MSTK_KICK_START;
- MSTK_SET_REG_SEC(regs,0);
- MSTK_SET_REG_MIN(regs,0);
- MSTK_SET_REG_HOUR(regs,0);
- MSTK_SET_REG_DOW(regs,5);
- MSTK_SET_REG_DOM(regs,1);
- MSTK_SET_REG_MONTH(regs,8);
- MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
- regs->creg &= ~MSTK_CREG_WRITE;
-
- spin_unlock_irq(&mostek_lock);
-
- /* Ensure the kick start bit is off. If it isn't, turn it off. */
- while (regs->hour & MSTK_KICK_START) {
- prom_printf("CLOCK: Kick start still on!\n");
-
- spin_lock_irq(&mostek_lock);
- regs->creg |= MSTK_CREG_WRITE;
- regs->hour &= ~MSTK_KICK_START;
- regs->creg &= ~MSTK_CREG_WRITE;
- spin_unlock_irq(&mostek_lock);
+ if (ofs == pdata->offset + M48T59_YEAR) {
+ if (val < 0x68)
+ val += 0x32;
+ else
+ val -= 0x68;
+ if ((val & 0xf) > 9)
+ val += 6;
+ if ((val & 0xf0) > 0x9A)
+ val += 0x60;
}
-
- prom_printf("CLOCK: Kick start procedure successful.\n");
+ writeb(val, regs + ofs);
}
-/* Return nonzero if the clock chip battery is low. */
-static inline int has_low_battery(void)
-{
- struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
- unsigned char data1, data2;
+static struct m48t59_plat_data m48t59_data = {
+ .read_byte = mostek_read_byte,
+ .write_byte = mostek_write_byte,
+};
- spin_lock_irq(&mostek_lock);
- data1 = regs->eeprom[0]; /* Read some data. */
- regs->eeprom[0] = ~data1; /* Write back the complement. */
- data2 = regs->eeprom[0]; /* Read back the complement. */
- regs->eeprom[0] = data1; /* Restore the original value. */
- spin_unlock_irq(&mostek_lock);
+/* resource is set at runtime */
+static struct platform_device m48t59_rtc = {
+ .name = "rtc-m48t59",
+ .id = 0,
+ .num_resources = 1,
+ .dev = {
+ .platform_data = &m48t59_data,
+ },
+};
- return (data1 == data2); /* Was the write blocked? */
-}
-
-static void __devinit mostek_set_system_time(void)
-{
- unsigned int year, mon, day, hour, min, sec;
- struct mostek48t02 *mregs;
-
- mregs = (struct mostek48t02 *)mstk48t02_regs;
- if(!mregs) {
- prom_printf("Something wrong, clock regs not mapped yet.\n");
- prom_halt();
- }
- spin_lock_irq(&mostek_lock);
- mregs->creg |= MSTK_CREG_READ;
- sec = MSTK_REG_SEC(mregs);
- min = MSTK_REG_MIN(mregs);
- hour = MSTK_REG_HOUR(mregs);
- day = MSTK_REG_DOM(mregs);
- mon = MSTK_REG_MONTH(mregs);
- year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
- xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
- mregs->creg &= ~MSTK_CREG_READ;
- spin_unlock_irq(&mostek_lock);
-}
-
-/* Probe for the real time clock chip on Sun4 */
-static inline void sun4_clock_probe(void)
-{
-#ifdef CONFIG_SUN4
- int temp;
- struct resource r;
-
- memset(&r, 0, sizeof(r));
- if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) {
- sp_clock_typ = MSTK48T02;
- r.start = sun4_clock_physaddr;
- mstk48t02_regs = sbus_ioremap(&r, 0,
- sizeof(struct mostek48t02), NULL);
- mstk48t08_regs = NULL; /* To catch weirdness */
- intersil_clock = NULL; /* just in case */
-
- /* Kick start the clock if it is completely stopped. */
- if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
- kick_start_clock();
- } else if( idprom->id_machtype == (SM_SUN4 | SM_4_260)) {
- /* intersil setup code */
- printk("Clock: INTERSIL at %8x ",sun4_clock_physaddr);
- sp_clock_typ = INTERSIL;
- r.start = sun4_clock_physaddr;
- intersil_clock = (struct intersil *)
- sbus_ioremap(&r, 0, sizeof(*intersil_clock), "intersil");
- mstk48t02_regs = 0; /* just be sure */
- mstk48t08_regs = NULL; /* ditto */
- /* initialise the clock */
-
- intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
-
- intersil_start(intersil_clock);
-
- intersil_read_intr(intersil_clock, temp);
- while (!(temp & 0x80))
- intersil_read_intr(intersil_clock, temp);
-
- intersil_read_intr(intersil_clock, temp);
- while (!(temp & 0x80))
- intersil_read_intr(intersil_clock, temp);
-
- intersil_stop(intersil_clock);
-
- }
-#endif
-}
-
-#ifndef CONFIG_SUN4
static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->node;
@@ -306,38 +173,26 @@
if (!model)
return -ENODEV;
+ m48t59_rtc.resource = &op->resource[0];
if (!strcmp(model, "mk48t02")) {
- sp_clock_typ = MSTK48T02;
-
/* Map the clock register io area read-only */
- mstk48t02_regs = of_ioremap(&op->resource[0], 0,
- sizeof(struct mostek48t02),
- "mk48t02");
- mstk48t08_regs = NULL; /* To catch weirdness */
+ m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
+ 2048, "rtc-m48t59");
+ m48t59_data.type = M48T59RTC_TYPE_M48T02;
} else if (!strcmp(model, "mk48t08")) {
- sp_clock_typ = MSTK48T08;
- mstk48t08_regs = of_ioremap(&op->resource[0], 0,
- sizeof(struct mostek48t08),
- "mk48t08");
-
- mstk48t02_regs = &mstk48t08_regs->regs;
+ m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
+ 8192, "rtc-m48t59");
+ m48t59_data.type = M48T59RTC_TYPE_M48T08;
} else
return -ENODEV;
- /* Report a low battery voltage condition. */
- if (has_low_battery())
- printk(KERN_CRIT "NVRAM: Low battery voltage!\n");
-
- /* Kick start the clock if it is completely stopped. */
- if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
- kick_start_clock();
-
- mostek_set_system_time();
+ if (platform_device_register(&m48t59_rtc) < 0)
+ printk(KERN_ERR "Registering RTC device failed\n");
return 0;
}
-static struct of_device_id clock_match[] = {
+static struct of_device_id __initdata clock_match[] = {
{
.name = "eeprom",
},
@@ -348,7 +203,7 @@
.match_table = clock_match,
.probe = clock_probe,
.driver = {
- .name = "clock",
+ .name = "rtc",
},
};
@@ -364,7 +219,6 @@
* need to see the clock registers.
*/
fs_initcall(clock_init);
-#endif /* !CONFIG_SUN4 */
static void __init sbus_time_init(void)
{
@@ -372,51 +226,8 @@
BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
btfixup();
- if (ARCH_SUN4)
- sun4_clock_probe();
-
sparc_init_timers(timer_interrupt);
-#ifdef CONFIG_SUN4
- if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {
- mostek_set_system_time();
- } else if(idprom->id_machtype == (SM_SUN4 | SM_4_260) ) {
- /* initialise the intersil on sun4 */
- unsigned int year, mon, day, hour, min, sec;
- int temp;
- struct intersil *iregs;
-
- iregs=intersil_clock;
- if(!iregs) {
- prom_printf("Something wrong, clock regs not mapped yet.\n");
- prom_halt();
- }
-
- intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
- disable_pil_irq(10);
- intersil_stop(iregs);
- intersil_read_intr(intersil_clock, temp);
-
- temp = iregs->clk.int_csec;
-
- sec = iregs->clk.int_sec;
- min = iregs->clk.int_min;
- hour = iregs->clk.int_hour;
- day = iregs->clk.int_day;
- mon = iregs->clk.int_month;
- year = MSTK_CVT_YEAR(iregs->clk.int_year);
-
- enable_pil_irq(10);
- intersil_start(iregs);
-
- xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
- printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec);
- }
-#endif
-
/* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
local_irq_enable();
}
@@ -522,80 +333,15 @@
return 0;
}
-/*
- * BUG: This routine does not handle hour overflow properly; it just
- * sets the minutes. Usually you won't notice until after reboot!
- */
-static int set_rtc_mmss(unsigned long nowtime)
+static int set_rtc_mmss(unsigned long secs)
{
- int real_seconds, real_minutes, mostek_minutes;
- struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
- unsigned long flags;
-#ifdef CONFIG_SUN4
- struct intersil *iregs = intersil_clock;
- int temp;
-#endif
+ struct rtc_device *rtc = rtc_class_open("rtc0");
+ int err = -1;
- /* Not having a register set can lead to trouble. */
- if (!regs) {
-#ifdef CONFIG_SUN4
- if(!iregs)
- return -1;
- else {
- temp = iregs->clk.int_csec;
-
- mostek_minutes = iregs->clk.int_min;
-
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
-
- if (abs(real_minutes - mostek_minutes) < 30) {
- intersil_stop(iregs);
- iregs->clk.int_sec=real_seconds;
- iregs->clk.int_min=real_minutes;
- intersil_start(iregs);
- } else {
- printk(KERN_WARNING
- "set_rtc_mmss: can't update from %d to %d\n",
- mostek_minutes, real_minutes);
- return -1;
- }
-
- return 0;
- }
-#endif
+ if (rtc) {
+ err = rtc_set_mmss(rtc, secs);
+ rtc_class_close(rtc);
}
- spin_lock_irqsave(&mostek_lock, flags);
- /* Read the current RTC minutes. */
- regs->creg |= MSTK_CREG_READ;
- mostek_minutes = MSTK_REG_MIN(regs);
- regs->creg &= ~MSTK_CREG_READ;
-
- /*
- * since we're only adjusting minutes and seconds,
- * don't interfere with hour overflow. This avoids
- * messing with unknown time zones but requires your
- * RTC not to be off by more than 15 minutes
- */
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
-
- if (abs(real_minutes - mostek_minutes) < 30) {
- regs->creg |= MSTK_CREG_WRITE;
- MSTK_SET_REG_SEC(regs,real_seconds);
- MSTK_SET_REG_MIN(regs,real_minutes);
- regs->creg &= ~MSTK_CREG_WRITE;
- spin_unlock_irqrestore(&mostek_lock, flags);
- return 0;
- } else {
- spin_unlock_irqrestore(&mostek_lock, flags);
- return -1;
- }
+ return err;
}
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
index 5d45d5f..2b7d506 100644
--- a/arch/sparc/kernel/traps.c
+++ b/arch/sparc/kernel/traps.c
@@ -43,23 +43,6 @@
{
}
-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/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index 109c8b2..ea88955 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -3,13 +3,8 @@
EXTRA_AFLAGS := -ansi
-obj-y := fault.o init.o loadmmu.o generic.o extable.o btfixup.o
-
-ifeq ($(CONFIG_SUN4),y)
-obj-y += nosrmmu.o
-else
-obj-y += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
-endif
+obj-y := fault.o init.o loadmmu.o generic.o extable.o btfixup.o \
+ srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
ifdef CONFIG_HIGHMEM
obj-y += highmem.o
diff --git a/arch/sparc/mm/btfixup.c b/arch/sparc/mm/btfixup.c
index a312d12..5175ac2 100644
--- a/arch/sparc/mm/btfixup.c
+++ b/arch/sparc/mm/btfixup.c
@@ -20,11 +20,7 @@
extern char *srmmu_name;
static char version[] __initdata = "Boot time fixup v1.6. 4/Mar/98 Jakub Jelinek (jj@ultra.linux.cz). Patching kernel for ";
-#ifdef CONFIG_SUN4
-static char str_sun4c[] __initdata = "sun4\n";
-#else
static char str_sun4c[] __initdata = "sun4c\n";
-#endif
static char str_srmmu[] __initdata = "srmmu[%s]/";
static char str_iommu[] __initdata = "iommu\n";
static char str_iounit[] __initdata = "io-unit\n";
@@ -86,7 +82,7 @@
if (!visited) {
visited++;
printk(version);
- if (ARCH_SUN4C_SUN4)
+ if (ARCH_SUN4C)
printk(str_sun4c);
else {
printk(str_srmmu, srmmu_name);
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index 3604c2e..a507e11 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -191,7 +191,7 @@
* only copy the information from the master page table,
* nothing more.
*/
- if (!ARCH_SUN4C_SUN4 && address >= TASK_SIZE)
+ if (!ARCH_SUN4C && address >= TASK_SIZE)
goto vmalloc_fault;
info.si_code = SEGV_MAPERR;
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index e103f1b..677c1e1 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -23,6 +23,7 @@
#include <linux/highmem.h>
#include <linux/bootmem.h>
#include <linux/pagemap.h>
+#include <linux/poison.h>
#include <asm/system.h>
#include <asm/vac-ops.h>
@@ -480,6 +481,7 @@
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
struct page *p;
+ memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
p = virt_to_page(addr);
ClearPageReserved(p);
@@ -488,20 +490,26 @@
totalram_pages++;
num_physpages++;
}
- printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+ printk(KERN_INFO "Freeing unused kernel memory: %dk freed\n",
+ (&__init_end - &__init_begin) >> 10);
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
if (start < end)
- printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+ printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
+ (end - start) >> 10);
for (; start < end; start += PAGE_SIZE) {
- struct page *p = virt_to_page(start);
+ struct page *p;
+
+ memset((void *)start, POISON_FREE_INITMEM, PAGE_SIZE);
+ p = virt_to_page(start);
ClearPageReserved(p);
init_page_count(p);
__free_page(p);
+ totalram_pages++;
num_physpages++;
}
}
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c
index f167835..daadf5f 100644
--- a/arch/sparc/mm/io-unit.c
+++ b/arch/sparc/mm/io-unit.c
@@ -12,10 +12,11 @@
#include <linux/highmem.h> /* pte_offset_map => kmap_atomic */
#include <linux/bitops.h>
#include <linux/scatterlist.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
-#include <asm/sbus.h>
#include <asm/io.h>
#include <asm/io-unit.h>
#include <asm/mxcc.h>
@@ -34,13 +35,10 @@
#define IOPERM (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
#define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
-void __init
-iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
+static void __init iounit_iommu_init(struct of_device *op)
{
- iopte_t *xpt, *xptend;
struct iounit_struct *iounit;
- struct linux_prom_registers iommu_promregs[PROMREG_MAX];
- struct resource r;
+ iopte_t *xpt, *xptend;
iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
if (!iounit) {
@@ -55,18 +53,13 @@
iounit->rotor[1] = IOUNIT_BMAP2_START;
iounit->rotor[2] = IOUNIT_BMAPM_START;
- xpt = NULL;
- if(prom_getproperty(sbi_node, "reg", (void *) iommu_promregs,
- sizeof(iommu_promregs)) != -1) {
- prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3);
- memset(&r, 0, sizeof(r));
- r.flags = iommu_promregs[2].which_io;
- r.start = iommu_promregs[2].phys_addr;
- xpt = (iopte_t *) sbus_ioremap(&r, 0, PAGE_SIZE * 16, "XPT");
+ xpt = of_ioremap(&op->resource[2], 0, PAGE_SIZE * 16, "XPT");
+ if (!xpt) {
+ prom_printf("SUN4D: Cannot map External Page Table.");
+ prom_halt();
}
- if(!xpt) panic("Cannot map External Page Table.");
- sbus->ofdev.dev.archdata.iommu = iounit;
+ op->dev.archdata.iommu = iounit;
iounit->page_table = xpt;
spin_lock_init(&iounit->lock);
@@ -75,6 +68,25 @@
iopte_val(*xpt++) = 0;
}
+static int __init iounit_init(void)
+{
+ extern void sun4d_init_sbi_irq(void);
+ struct device_node *dp;
+
+ for_each_node_by_name(dp, "sbi") {
+ struct of_device *op = of_find_device_by_node(dp);
+
+ iounit_iommu_init(op);
+ of_propagate_archdata(op);
+ }
+
+ sun4d_init_sbi_irq();
+
+ return 0;
+}
+
+subsys_initcall(iounit_init);
+
/* One has to hold iounit->lock to call this */
static unsigned long iounit_get_area(struct iounit_struct *iounit, unsigned long vaddr, int size)
{
@@ -124,10 +136,10 @@
return vaddr;
}
-static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iounit_get_scsi_one(struct device *dev, char *vaddr, unsigned long len)
{
+ struct iounit_struct *iounit = dev->archdata.iommu;
unsigned long ret, flags;
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
spin_lock_irqsave(&iounit->lock, flags);
ret = iounit_get_area(iounit, (unsigned long)vaddr, len);
@@ -135,10 +147,10 @@
return ret;
}
-static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iounit_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
{
+ struct iounit_struct *iounit = dev->archdata.iommu;
unsigned long flags;
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
/* FIXME: Cache some resolved pages - often several sg entries are to the same page */
spin_lock_irqsave(&iounit->lock, flags);
@@ -151,10 +163,10 @@
spin_unlock_irqrestore(&iounit->lock, flags);
}
-static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
+static void iounit_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len)
{
+ struct iounit_struct *iounit = dev->archdata.iommu;
unsigned long flags;
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
spin_lock_irqsave(&iounit->lock, flags);
len = ((vaddr & ~PAGE_MASK) + len + (PAGE_SIZE-1)) >> PAGE_SHIFT;
@@ -165,11 +177,11 @@
spin_unlock_irqrestore(&iounit->lock, flags);
}
-static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iounit_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
{
+ struct iounit_struct *iounit = dev->archdata.iommu;
unsigned long flags;
unsigned long vaddr, len;
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
spin_lock_irqsave(&iounit->lock, flags);
while (sz != 0) {
@@ -185,12 +197,12 @@
}
#ifdef CONFIG_SBUS
-static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, int len)
+static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, __u32 addr, int len)
{
+ struct iounit_struct *iounit = dev->archdata.iommu;
unsigned long page, end;
pgprot_t dvma_prot;
iopte_t *iopte;
- struct sbus_bus *sbus;
*pba = addr;
@@ -212,12 +224,8 @@
i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
- for_each_sbus(sbus) {
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-
- iopte = (iopte_t *)(iounit->page_table + i);
- *iopte = MKIOPTE(__pa(page));
- }
+ iopte = (iopte_t *)(iounit->page_table + i);
+ *iopte = MKIOPTE(__pa(page));
}
addr += PAGE_SIZE;
va += PAGE_SIZE;
@@ -228,23 +236,10 @@
return 0;
}
-static void iounit_unmap_dma_area(unsigned long addr, int len)
+static void iounit_unmap_dma_area(struct device *dev, unsigned long addr, int len)
{
/* XXX Somebody please fill this in */
}
-
-/* XXX We do not pass sbus device here, bad. */
-static struct page *iounit_translate_dvma(unsigned long addr)
-{
- struct sbus_bus *sbus = sbus_root; /* They are all the same */
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
- int i;
- iopte_t *iopte;
-
- i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
- iopte = (iopte_t *)(iounit->page_table + i);
- return pfn_to_page(iopte_val(*iopte) >> (PAGE_SHIFT-4)); /* XXX sun4d guru, help */
-}
#endif
static char *iounit_lockarea(char *vaddr, unsigned long len)
@@ -271,54 +266,5 @@
#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/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c
index 4b93427..e7a499e 100644
--- a/arch/sparc/mm/iommu.c
+++ b/arch/sparc/mm/iommu.c
@@ -13,10 +13,11 @@
#include <linux/slab.h>
#include <linux/highmem.h> /* pte_offset_map => kmap_atomic */
#include <linux/scatterlist.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
-#include <asm/sbus.h>
#include <asm/io.h>
#include <asm/mxcc.h>
#include <asm/mbus.h>
@@ -55,30 +56,21 @@
#define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID)
#define MKIOPTE(pfn, perm) (((((pfn)<<8) & IOPTE_PAGE) | (perm)) & ~IOPTE_WAZ)
-void __init
-iommu_init(int iommund, struct sbus_bus *sbus)
+static void __init sbus_iommu_init(struct of_device *op)
{
- unsigned int impl, vers;
- unsigned long tmp;
struct iommu_struct *iommu;
- struct linux_prom_registers iommu_promregs[PROMREG_MAX];
- struct resource r;
+ unsigned int impl, vers;
unsigned long *bitmap;
+ unsigned long tmp;
iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
if (!iommu) {
prom_printf("Unable to allocate iommu structure\n");
prom_halt();
}
- iommu->regs = NULL;
- if (prom_getproperty(iommund, "reg", (void *) iommu_promregs,
- sizeof(iommu_promregs)) != -1) {
- memset(&r, 0, sizeof(r));
- r.flags = iommu_promregs[0].which_io;
- r.start = iommu_promregs[0].phys_addr;
- iommu->regs = (struct iommu_regs *)
- sbus_ioremap(&r, 0, PAGE_SIZE * 3, "iommu_regs");
- }
+
+ iommu->regs = of_ioremap(&op->resource[0], 0, PAGE_SIZE * 3,
+ "iommu_regs");
if (!iommu->regs) {
prom_printf("Cannot map IOMMU registers\n");
prom_halt();
@@ -128,13 +120,29 @@
else
iommu->usemap.num_colors = 1;
- printk("IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n",
- impl, vers, iommu->page_table,
- (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES);
+ printk(KERN_INFO "IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n",
+ impl, vers, iommu->page_table,
+ (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES);
- sbus->ofdev.dev.archdata.iommu = iommu;
+ op->dev.archdata.iommu = iommu;
}
+static int __init iommu_init(void)
+{
+ struct device_node *dp;
+
+ for_each_node_by_name(dp, "iommu") {
+ struct of_device *op = of_find_device_by_node(dp);
+
+ sbus_iommu_init(op);
+ of_propagate_archdata(op);
+ }
+
+ return 0;
+}
+
+subsys_initcall(iommu_init);
+
/* This begs to be btfixup-ed by srmmu. */
/* Flush the iotlb entries to ram. */
/* This could be better if we didn't have to flush whole pages. */
@@ -164,9 +172,9 @@
}
}
-static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus)
+static u32 iommu_get_one(struct device *dev, struct page *page, int npages)
{
- struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct iommu_struct *iommu = dev->archdata.iommu;
int ioptex;
iopte_t *iopte, *iopte0;
unsigned int busa, busa0;
@@ -194,8 +202,7 @@
return busa0;
}
-static u32 iommu_get_scsi_one(char *vaddr, unsigned int len,
- struct sbus_bus *sbus)
+static u32 iommu_get_scsi_one(struct device *dev, char *vaddr, unsigned int len)
{
unsigned long off;
int npages;
@@ -205,22 +212,22 @@
off = (unsigned long)vaddr & ~PAGE_MASK;
npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT;
page = virt_to_page((unsigned long)vaddr & PAGE_MASK);
- busa = iommu_get_one(page, npages, sbus);
+ busa = iommu_get_one(dev, page, npages);
return busa + off;
}
-static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_noflush(struct device *dev, char *vaddr, unsigned long len)
{
- return iommu_get_scsi_one(vaddr, len, sbus);
+ return iommu_get_scsi_one(dev, vaddr, len);
}
-static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_gflush(struct device *dev, char *vaddr, unsigned long len)
{
flush_page_for_dma(0);
- return iommu_get_scsi_one(vaddr, len, sbus);
+ return iommu_get_scsi_one(dev, vaddr, len);
}
-static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_pflush(struct device *dev, char *vaddr, unsigned long len)
{
unsigned long page = ((unsigned long) vaddr) & PAGE_MASK;
@@ -228,23 +235,23 @@
flush_page_for_dma(page);
page += PAGE_SIZE;
}
- return iommu_get_scsi_one(vaddr, len, sbus);
+ return iommu_get_scsi_one(dev, vaddr, len);
}
-static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_noflush(struct device *dev, struct scatterlist *sg, int sz)
{
int n;
while (sz != 0) {
--sz;
n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
- sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+ sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
sg->dvma_length = (__u32) sg->length;
sg = sg_next(sg);
}
}
-static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_gflush(struct device *dev, struct scatterlist *sg, int sz)
{
int n;
@@ -252,13 +259,13 @@
while (sz != 0) {
--sz;
n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
- sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+ sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
sg->dvma_length = (__u32) sg->length;
sg = sg_next(sg);
}
}
-static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_pflush(struct device *dev, struct scatterlist *sg, int sz)
{
unsigned long page, oldpage = 0;
int n, i;
@@ -283,15 +290,15 @@
}
}
- sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+ sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
sg->dvma_length = (__u32) sg->length;
sg = sg_next(sg);
}
}
-static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus)
+static void iommu_release_one(struct device *dev, u32 busa, int npages)
{
- struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct iommu_struct *iommu = dev->archdata.iommu;
int ioptex;
int i;
@@ -305,17 +312,17 @@
bit_map_clear(&iommu->usemap, ioptex, npages);
}
-static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
+static void iommu_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len)
{
unsigned long off;
int npages;
off = vaddr & ~PAGE_MASK;
npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT;
- iommu_release_one(vaddr & PAGE_MASK, npages, sbus);
+ iommu_release_one(dev, vaddr & PAGE_MASK, npages);
}
-static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
{
int n;
@@ -323,18 +330,18 @@
--sz;
n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
- iommu_release_one(sg->dvma_address & PAGE_MASK, n, sbus);
+ iommu_release_one(dev, sg->dvma_address & PAGE_MASK, n);
sg->dvma_address = 0x21212121;
sg = sg_next(sg);
}
}
#ifdef CONFIG_SBUS
-static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
- unsigned long addr, int len)
+static int iommu_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va,
+ unsigned long addr, int len)
{
+ struct iommu_struct *iommu = dev->archdata.iommu;
unsigned long page, end;
- struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
iopte_t *iopte = iommu->page_table;
iopte_t *first;
int ioptex;
@@ -397,9 +404,9 @@
return 0;
}
-static void iommu_unmap_dma_area(unsigned long busa, int len)
+static void iommu_unmap_dma_area(struct device *dev, unsigned long busa, int len)
{
- struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
+ struct iommu_struct *iommu = dev->archdata.iommu;
iopte_t *iopte = iommu->page_table;
unsigned long end;
int ioptex = (busa - iommu->start) >> PAGE_SHIFT;
@@ -417,15 +424,6 @@
iommu_invalidate(iommu->regs);
bit_map_clear(&iommu->usemap, ioptex, len >> PAGE_SHIFT);
}
-
-static struct page *iommu_translate_dvma(unsigned long busa)
-{
- struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
- iopte_t *iopte = iommu->page_table;
-
- iopte += ((busa - iommu->start) >> PAGE_SHIFT);
- return pfn_to_page((iopte_val(*iopte) & IOPTE_PAGE) >> (PAGE_SHIFT-4));
-}
#endif
static char *iommu_lockarea(char *vaddr, unsigned long len)
@@ -461,7 +459,6 @@
#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/arch/sparc/mm/nosrmmu.c b/arch/sparc/mm/nosrmmu.c
deleted file mode 100644
index 3701f70..0000000
--- a/arch/sparc/mm/nosrmmu.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * nosrmmu.c: This file is a bunch of dummies for sun4 compiles,
- * so that it does not need srmmu and avoid ifdefs.
- *
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <asm/mbus.h>
-#include <asm/sbus.h>
-
-static char shouldnothappen[] __initdata = "SUN4 kernel can only run on SUN4\n";
-
-enum mbus_module srmmu_modtype;
-void *srmmu_nocache_pool;
-
-int vac_cache_size = 0;
-
-static void __init should_not_happen(void)
-{
- prom_printf(shouldnothappen);
- prom_halt();
-}
-
-void __init srmmu_frob_mem_map(unsigned long start_mem)
-{
- should_not_happen();
-}
-
-unsigned long __init srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
-{
- should_not_happen();
- return 0;
-}
-
-void __init ld_mmu_srmmu(void)
-{
- should_not_happen();
-}
-
-void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly)
-{
-}
-
-void srmmu_unmapioaddr(unsigned long virt_addr)
-{
-}
-
-__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
-{
- return 0;
-}
-
-__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
-{
- return 0;
-}
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index ee30462..6a5d7ca 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -31,7 +31,6 @@
#include <asm/mbus.h>
#include <asm/cache.h>
#include <asm/oplib.h>
-#include <asm/sbus.h>
#include <asm/asi.h>
#include <asm/msi.h>
#include <asm/mmu_context.h>
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index d1782f6..fe65aee 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -31,7 +31,6 @@
#include <asm/oplib.h>
#include <asm/openprom.h>
#include <asm/mmu_context.h>
-#include <asm/sun4paddr.h>
#include <asm/highmem.h>
#include <asm/btfixup.h>
#include <asm/cacheflush.h>
@@ -52,15 +51,11 @@
extern unsigned long page_kernel;
-#ifdef CONFIG_SUN4
-#define SUN4C_VAC_SIZE sun4c_vacinfo.num_bytes
-#else
/* That's it, we prom_halt() on sun4c if the cache size is something other than 65536.
* So let's save some cycles and just use that everywhere except for that bootup
* sanity check.
*/
#define SUN4C_VAC_SIZE 65536
-#endif
#define SUN4C_KERNEL_BUCKETS 32
@@ -285,75 +280,32 @@
{
sun4c_disable_vac();
- if (ARCH_SUN4) {
- switch (idprom->id_machtype) {
-
- case (SM_SUN4|SM_4_110):
- sun4c_vacinfo.type = VAC_NONE;
- sun4c_vacinfo.num_bytes = 0;
- sun4c_vacinfo.linesize = 0;
- sun4c_vacinfo.do_hwflushes = 0;
- prom_printf("No VAC. Get some bucks and buy a real computer.");
- prom_halt();
- break;
-
- case (SM_SUN4|SM_4_260):
- sun4c_vacinfo.type = VAC_WRITE_BACK;
- sun4c_vacinfo.num_bytes = 128 * 1024;
- sun4c_vacinfo.linesize = 16;
- sun4c_vacinfo.do_hwflushes = 0;
- break;
-
- case (SM_SUN4|SM_4_330):
- sun4c_vacinfo.type = VAC_WRITE_THROUGH;
- sun4c_vacinfo.num_bytes = 128 * 1024;
- sun4c_vacinfo.linesize = 16;
- sun4c_vacinfo.do_hwflushes = 0;
- break;
-
- case (SM_SUN4|SM_4_470):
- sun4c_vacinfo.type = VAC_WRITE_BACK;
- sun4c_vacinfo.num_bytes = 128 * 1024;
- sun4c_vacinfo.linesize = 32;
- sun4c_vacinfo.do_hwflushes = 0;
- break;
-
- default:
- prom_printf("Cannot initialize VAC - weird sun4 model idprom->id_machtype = %d", idprom->id_machtype);
- prom_halt();
- };
+ if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+ (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+ /* PROM on SS1 lacks this info, to be super safe we
+ * hard code it here since this arch is cast in stone.
+ */
+ sun4c_vacinfo.num_bytes = 65536;
+ sun4c_vacinfo.linesize = 16;
} else {
- sun4c_vacinfo.type = VAC_WRITE_THROUGH;
+ sun4c_vacinfo.num_bytes =
+ prom_getintdefault(prom_root_node, "vac-size", 65536);
+ sun4c_vacinfo.linesize =
+ prom_getintdefault(prom_root_node, "vac-linesize", 16);
+ }
+ sun4c_vacinfo.do_hwflushes =
+ prom_getintdefault(prom_root_node, "vac-hwflush", 0);
- if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
- /* PROM on SS1 lacks this info, to be super safe we
- * hard code it here since this arch is cast in stone.
- */
- sun4c_vacinfo.num_bytes = 65536;
- sun4c_vacinfo.linesize = 16;
- } else {
- sun4c_vacinfo.num_bytes =
- prom_getintdefault(prom_root_node, "vac-size", 65536);
- sun4c_vacinfo.linesize =
- prom_getintdefault(prom_root_node, "vac-linesize", 16);
- }
+ if (sun4c_vacinfo.do_hwflushes == 0)
sun4c_vacinfo.do_hwflushes =
- prom_getintdefault(prom_root_node, "vac-hwflush", 0);
+ prom_getintdefault(prom_root_node, "vac_hwflush", 0);
- if (sun4c_vacinfo.do_hwflushes == 0)
- sun4c_vacinfo.do_hwflushes =
- prom_getintdefault(prom_root_node, "vac_hwflush", 0);
-
- if (sun4c_vacinfo.num_bytes != 65536) {
- prom_printf("WEIRD Sun4C VAC cache size, "
- "tell sparclinux@vger.kernel.org");
- prom_halt();
- }
+ if (sun4c_vacinfo.num_bytes != 65536) {
+ prom_printf("WEIRD Sun4C VAC cache size, "
+ "tell sparclinux@vger.kernel.org");
+ prom_halt();
}
- sun4c_vacinfo.num_lines =
- (sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
switch (sun4c_vacinfo.linesize) {
case 16:
sun4c_vacinfo.log2lsize = 4;
@@ -447,49 +399,18 @@
static void __init sun4c_probe_mmu(void)
{
- if (ARCH_SUN4) {
- switch (idprom->id_machtype) {
- case (SM_SUN4|SM_4_110):
- prom_printf("No support for 4100 yet\n");
- prom_halt();
- num_segmaps = 256;
- num_contexts = 8;
- break;
-
- case (SM_SUN4|SM_4_260):
- /* should be 512 segmaps. when it get fixed */
- num_segmaps = 256;
- num_contexts = 16;
- break;
-
- case (SM_SUN4|SM_4_330):
- num_segmaps = 256;
- num_contexts = 16;
- break;
-
- case (SM_SUN4|SM_4_470):
- /* should be 1024 segmaps. when it get fixed */
- num_segmaps = 256;
- num_contexts = 64;
- break;
- default:
- prom_printf("Invalid SUN4 model\n");
- prom_halt();
- };
+ if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+ (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+ /* Hardcode these just to be safe, PROM on SS1 does
+ * not have this info available in the root node.
+ */
+ num_segmaps = 128;
+ num_contexts = 8;
} else {
- if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
- /* Hardcode these just to be safe, PROM on SS1 does
- * not have this info available in the root node.
- */
- num_segmaps = 128;
- num_contexts = 8;
- } else {
- num_segmaps =
- prom_getintdefault(prom_root_node, "mmu-npmg", 128);
- num_contexts =
- prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
- }
+ num_segmaps =
+ prom_getintdefault(prom_root_node, "mmu-npmg", 128);
+ num_contexts =
+ prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
}
patch_kernel_fault_handler();
}
@@ -501,18 +422,14 @@
int node;
struct linux_prom_registers regs[1];
- if (ARCH_SUN4) {
- sun4c_memerr_reg = ioremap(sun4_memreg_physaddr, PAGE_SIZE);
- } else {
- node = prom_getchild(prom_root_node);
- node = prom_searchsiblings(prom_root_node, "memory-error");
- if (!node)
- return;
- if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0)
- return;
- /* hmm I think regs[0].which_io is zero here anyways */
- sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
- }
+ node = prom_getchild(prom_root_node);
+ node = prom_searchsiblings(prom_root_node, "memory-error");
+ if (!node)
+ return;
+ if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0)
+ return;
+ /* hmm I think regs[0].which_io is zero here anyways */
+ sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
}
static inline void sun4c_init_ss2_cache_bug(void)
@@ -521,7 +438,6 @@
if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
(idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
- (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
(idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
/* Whee.. */
printk("SS2 cache bug detected, uncaching trap table page\n");
@@ -532,8 +448,8 @@
}
/* Addr is always aligned on a page boundary for us already. */
-static int sun4c_map_dma_area(dma_addr_t *pba, unsigned long va,
- unsigned long addr, int len)
+static int sun4c_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va,
+ unsigned long addr, int len)
{
unsigned long page, end;
@@ -555,14 +471,7 @@
return 0;
}
-static struct page *sun4c_translate_dvma(unsigned long busa)
-{
- /* Fortunately for us, bus_addr == uncached_virt in sun4c. */
- unsigned long pte = sun4c_get_pte(busa);
- return pfn_to_page(pte & SUN4C_PFN_MASK);
-}
-
-static void sun4c_unmap_dma_area(unsigned long busa, int len)
+static void sun4c_unmap_dma_area(struct device *dev, unsigned long busa, int len)
{
/* Fortunately for us, bus_addr == uncached_virt in sun4c. */
/* XXX Implement this */
@@ -624,11 +533,7 @@
{
unsigned long vaddr;
unsigned char pseg, ctx;
-#ifdef CONFIG_SUN4
- /* sun4/110 and 260 have no kadb. */
- if ((idprom->id_machtype != (SM_SUN4 | SM_4_260)) &&
- (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
-#endif
+
for (vaddr = KADB_DEBUGGER_BEGVM;
vaddr < LINUX_OPPROM_ENDVM;
vaddr += SUN4C_REAL_PGDIR_SIZE) {
@@ -640,9 +545,7 @@
fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
}
}
-#ifdef CONFIG_SUN4
- }
-#endif
+
for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
pseg = sun4c_get_segmap(vaddr);
mmu_entry_pool[pseg].locked = 1;
@@ -1048,14 +951,10 @@
* so we must flush the cache to guarantee consistency.
*/
sun4c_flush_page(pages);
-#ifndef CONFIG_SUN4
sun4c_flush_page(pages + PAGE_SIZE);
-#endif
sun4c_put_pte(addr, BUCKET_PTE(pages));
-#ifndef CONFIG_SUN4
sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
-#endif
#ifdef CONFIG_DEBUG_STACK_USAGE
memset((void *)addr, 0, PAGE_SIZE << THREAD_INFO_ORDER);
@@ -1072,13 +971,11 @@
/* We are deleting a mapping, so the flush here is mandatory. */
sun4c_flush_page(tiaddr);
-#ifndef CONFIG_SUN4
sun4c_flush_page(tiaddr + PAGE_SIZE);
-#endif
+
sun4c_put_pte(tiaddr, 0);
-#ifndef CONFIG_SUN4
sun4c_put_pte(tiaddr + PAGE_SIZE, 0);
-#endif
+
sun4c_bucket[entry] = BUCKET_EMPTY;
if (entry < sun4c_lowbucket_avail)
sun4c_lowbucket_avail = entry;
@@ -1211,7 +1108,7 @@
* by implication and fool the page locking code above
* if passed to by mistake.
*/
-static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct sbus_bus *sbus)
+static __u32 sun4c_get_scsi_one(struct device *dev, char *bufptr, unsigned long len)
{
unsigned long page;
@@ -1223,7 +1120,7 @@
return (__u32)sun4c_lockarea(bufptr, len);
}
-static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void sun4c_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
{
while (sz != 0) {
--sz;
@@ -1233,14 +1130,14 @@
}
}
-static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct sbus_bus *sbus)
+static void sun4c_release_scsi_one(struct device *dev, __u32 bufptr, unsigned long len)
{
if (bufptr < sun4c_iobuffer_start)
return; /* On kernel stack or similar, see above */
sun4c_unlockarea((char *)bufptr, len);
}
-static void sun4c_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void sun4c_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
{
while (sz != 0) {
--sz;
@@ -2263,7 +2160,6 @@
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/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile
index 7f5eacf..8f7e185 100644
--- a/arch/sparc/prom/Makefile
+++ b/arch/sparc/prom/Makefile
@@ -4,5 +4,3 @@
lib-y := bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \
palloc.o ranges.o segment.o console.o printf.o tree.o
-
-lib-$(CONFIG_SUN4) += sun4prom.o
diff --git a/arch/sparc/prom/bootstr.c b/arch/sparc/prom/bootstr.c
index 5a35c76..916831d 100644
--- a/arch/sparc/prom/bootstr.c
+++ b/arch/sparc/prom/bootstr.c
@@ -6,15 +6,12 @@
#include <linux/string.h>
#include <asm/oplib.h>
-#include <asm/sun4prom.h>
#include <linux/init.h>
#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)
{
@@ -28,7 +25,6 @@
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/arch/sparc/prom/console.c b/arch/sparc/prom/console.c
index 790057a..b3075d7 100644
--- a/arch/sparc/prom/console.c
+++ b/arch/sparc/prom/console.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/openprom.h>
-#include <asm/sun4prom.h>
#include <asm/oplib.h>
#include <asm/system.h>
#include <linux/string.h>
@@ -30,7 +29,6 @@
spin_lock_irqsave(&prom_lock, flags);
switch(prom_vers) {
case PROM_V0:
- case PROM_SUN4:
i = (*(romvec->pv_nbgetchar))();
break;
case PROM_V2:
@@ -63,7 +61,6 @@
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/arch/sparc/prom/init.c b/arch/sparc/prom/init.c
index 729f870..873217c 100644
--- a/arch/sparc/prom/init.c
+++ b/arch/sparc/prom/init.c
@@ -11,12 +11,10 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
-#include <asm/sun4prom.h>
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;
@@ -34,10 +32,6 @@
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) {
@@ -50,9 +44,6 @@
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);
@@ -76,11 +67,8 @@
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/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c
index 947f047..fac7899 100644
--- a/arch/sparc/prom/memory.c
+++ b/arch/sparc/prom/memory.c
@@ -10,7 +10,6 @@
#include <linux/init.h>
#include <asm/openprom.h>
-#include <asm/sun4prom.h>
#include <asm/oplib.h>
#include <asm/page.h>
@@ -46,15 +45,6 @@
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;
@@ -81,10 +71,6 @@
num_ents = prom_meminit_v2();
break;
- case PROM_SUN4:
- num_ents = prom_meminit_sun4();
- break;
-
default:
break;
}
diff --git a/arch/sparc/prom/ranges.c b/arch/sparc/prom/ranges.c
index f9b7def..64579a3 100644
--- a/arch/sparc/prom/ranges.c
+++ b/arch/sparc/prom/ranges.c
@@ -9,7 +9,6 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/types.h>
-#include <asm/sbus.h>
#include <asm/system.h>
struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
diff --git a/arch/sparc/prom/sun4prom.c b/arch/sparc/prom/sun4prom.c
deleted file mode 100644
index 00390a2..0000000
--- a/arch/sparc/prom/sun4prom.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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 <linux/kernel.h>
-#include <linux/string.h>
-#include <asm/oplib.h>
-#include <asm/idprom.h>
-#include <asm/machines.h>
-#include <asm/sun4prom.h>
-#include <asm/asi.h>
-#include <asm/contregs.h>
-#include <linux/init.h>
-
-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/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 36b4b7a..5446e2a 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -18,6 +18,13 @@
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
@@ -31,6 +38,11 @@
bool
default y
+config GENERIC_GPIO
+ bool
+ help
+ Generic GPIO API support
+
config 64BIT
def_bool y
@@ -185,6 +197,17 @@
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/arch/sparc64/Makefile b/arch/sparc64/Makefile
index b785a39..c7214ab 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -7,7 +7,7 @@
# Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
#
-CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -m64
+CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -D__arch64__ -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/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 418b578..c0b8009 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -7,16 +7,16 @@
extra-y := head.o init_task.o vmlinux.lds
-obj-y := process.o setup.o cpu.o idprom.o \
+obj-y := process.o setup.o cpu.o idprom.o reboot.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 pci.o starfire.o \
- power.o sbus.o sparc64_ksyms.o chmc.o \
+ unaligned.o central.o starfire.o \
+ power.o sbus.o sparc64_ksyms.o ebus.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) += ebus.o pci_common.o \
+obj-$(CONFIG_PCI) += pci.o pci_common.o psycho_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,6 +25,7 @@
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/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index dd5c7bf..858beda 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -109,7 +109,7 @@
}
}
-static struct of_device_id auxio_match[] = {
+static struct of_device_id __initdata auxio_match[] = {
{
.name = "auxio",
},
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
index f2e87d0..05f1c91 100644
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -1,461 +1,268 @@
/* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
*
- * Copyright (C) 1997, 1999 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1997, 1999, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/bootmem.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
-#include <asm/page.h>
#include <asm/fhc.h>
-#include <asm/starfire.h>
+#include <asm/upa.h>
-static struct linux_central *central_bus = NULL;
-static struct linux_fhc *fhc_list = NULL;
+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;
+};
-#define IS_CENTRAL_FHC(__fhc) ((__fhc) == central_bus->child)
+struct fhc {
+ void __iomem *pregs;
+ bool central;
+ bool jtag_master;
+ int board_num;
+ struct resource leds_resource;
+ struct platform_device leds_pdev;
+};
-static void central_probe_failure(int line)
+static int __devinit clock_board_calc_nslots(struct clock_board *p)
{
- prom_printf("CENTRAL: Critical device probe failure at central.c:%d\n",
- line);
- prom_halt();
-}
+ u8 reg = upa_readb(p->clock_regs + CLOCK_STAT1) & 0xc0;
-static void central_ranges_init(struct linux_central *central)
-{
- 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));
- }
-}
-
-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));
- }
-}
-
-/* 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;
- }
-}
-
-/* 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);
-}
-
-static void * __init central_alloc_bootmem(unsigned long size)
-{
- void *ret;
-
- ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
- if (ret != NULL)
- memset(ret, 0, size);
-
- return ret;
-}
-
-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);
- }
-}
-
-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__);
-
- pr = of_get_property(dp, "reg", &nregs);
- if (!pr)
- central_probe_failure(__LINE__);
-
- memcpy(cregs, pr, nregs);
- nregs /= sizeof(struct linux_prom_registers);
-
- 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]);
-
- if (nregs == 2)
- central->clkver = 0UL;
- else
- central->clkver = prom_reg_to_paddr(&cregs[2]);
-
- tmp = upa_readb(central->clkregs + CLOCK_STAT1);
- tmp &= 0xc0;
- switch(tmp) {
+ switch (reg) {
case 0x40:
- nslots = 16;
- break;
+ return 16;
+
case 0xc0:
- nslots = 8;
- break;
+ return 8;
+
case 0x80:
- if (central->clkver != 0UL &&
- upa_readb(central->clkver) != 0) {
- if ((upa_readb(central->clkver) & 0x80) != 0)
- nslots = 4;
+ reg = 0;
+ if (p->clock_ver_reg)
+ reg = upa_readb(p->clock_ver_reg);
+ if (reg) {
+ if (reg & 0x80)
+ return 4;
else
- nslots = 5;
- break;
+ return 5;
}
+ /* Fallthrough */
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));
+ return 4;
+ }
}
-static void ZAP(unsigned long iclr, unsigned long imap)
+static int __devinit clock_board_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- u32 imap_tmp;
+ struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ int err = -ENOMEM;
- upa_writel(0, iclr);
- upa_readl(iclr);
- imap_tmp = upa_readl(imap);
- imap_tmp &= ~(0x80000000);
- upa_writel(imap_tmp, imap);
- upa_readl(imap);
-}
-
-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 (!p) {
+ printk(KERN_ERR "clock_board: Cannot allocate struct clock_board\n");
+ goto out;
}
-}
-
-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;
+ 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;
}
- /* 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;
+ 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;
}
- if (!fp)
- central_probe_failure(__LINE__);
- fhc->prom_node = fp;
- fhc_ranges_init(fhc);
+ 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;
+ }
+ }
- /* Now, map in FHC register set. */
- pr = of_get_property(fp, "reg", NULL);
- if (!pr)
- central_probe_failure(__LINE__);
- memcpy(fpregs, pr, sizeof(fpregs));
+ p->num_slots = clock_board_calc_nslots(p);
- 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]);
+ p->leds_resource.start = (unsigned long)
+ (p->clock_regs + CLOCK_CTRL);
+ p->leds_resource.end = p->leds_resource.end;
+ p->leds_resource.name = "leds";
- /* 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));
+ 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;
- fhc->jtag_master = 0;
+ 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;
+ }
- /* Attach the clock board registers for CENTRAL. */
- probe_clock_board(central_bus, fhc, fp);
+ printk(KERN_INFO "clock_board: Detected %d slot Enterprise system.\n",
+ p->num_slots);
- 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));
+ err = 0;
+out:
+ return err;
- probe_other_fhcs();
+out_unmap_clock_ver_reg:
+ if (p->clock_ver_reg)
+ of_iounmap(&op->resource[2], p->clock_ver_reg,
+ resource_size(&op->resource[2]));
- init_all_fhc_hw();
+out_unmap_clock_regs:
+ of_iounmap(&op->resource[1], p->clock_regs,
+ resource_size(&op->resource[1]));
+
+out_unmap_clock_freq_regs:
+ of_iounmap(&op->resource[0], p->clock_freq_regs,
+ resource_size(&op->resource[0]));
+
+out_free:
+ kfree(p);
+ goto out;
}
-static inline void fhc_ledblink(struct linux_fhc *fhc, int on)
+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)
{
- u32 tmp;
+ struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ int err = -ENOMEM;
+ u32 reg;
- tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+ if (!p) {
+ printk(KERN_ERR "fhc: Cannot allocate struct fhc\n");
+ goto out;
+ }
- /* 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);
+ if (!strcmp(op->node->parent->name, "central"))
+ p->central = true;
- upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
- upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+ 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;
+ }
+
+ 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;
+ }
+ }
+ reg = upa_readl(p->pregs + FHC_PREGS_CTRL);
+
+ if (!p->central)
+ reg |= FHC_CONTROL_IXIST;
+
+ reg &= ~(FHC_CONTROL_AOFF |
+ FHC_CONTROL_BOFF |
+ FHC_CONTROL_SLINE);
+
+ upa_writel(reg, p->pregs + FHC_PREGS_CTRL);
+ upa_readl(p->pregs + FHC_PREGS_CTRL);
+
+ 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)" : "")));
+
+ err = 0;
+
+out:
+ return err;
+
+out_unmap_pregs:
+ of_iounmap(&op->resource[0], p->pregs, resource_size(&op->resource[0]));
+
+out_free:
+ kfree(p);
+ goto out;
}
-static inline void central_ledblink(struct linux_central *central, int on)
+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)
{
- u8 tmp;
-
- tmp = upa_readb(central->clkregs + CLOCK_CTRL);
-
- /* NOTE: reverse logic on this bit */
- if (on)
- tmp &= ~(CLOCK_CTRL_RLED);
- else
- tmp |= CLOCK_CTRL_RLED;
-
- upa_writeb(tmp, central->clkregs + CLOCK_CTRL);
- upa_readb(central->clkregs + CLOCK_CTRL);
+ (void) of_register_driver(&fhc_driver, &of_platform_bus_type);
+ (void) of_register_driver(&clock_board_driver, &of_platform_bus_type);
+ return 0;
}
-static struct timer_list sftimer;
-static int led_state;
-
-static void sunfire_timer(unsigned long __ignored)
-{
- 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);
-}
-
-/* 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);
-}
+subsys_initcall(sunfire_init);
diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c
index 6d4f02e..967b048 100644
--- a/arch/sparc64/kernel/chmc.c
+++ b/arch/sparc64/kernel/chmc.c
@@ -1,6 +1,6 @@
-/* memctrlr.c: Driver for UltraSPARC-III memory controller.
+/* chmc.c: Driver for UltraSPARC-III memory controller.
*
- * Copyright (C) 2001, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2001, 2007, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -13,45 +13,64 @@
#include <linux/smp.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/spitfire.h>
#include <asm/chmctrl.h>
#include <asm/cpudata.h>
#include <asm/oplib.h>
#include <asm/prom.h>
+#include <asm/head.h>
#include <asm/io.h>
+#include <asm/memctrl.h>
+
+#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 DIMMS_PER_MC (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
+#define CHMC_DIMMS_PER_MC (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
/* OBP memory-layout property format. */
-struct obp_map {
+struct chmc_obp_map {
unsigned char dimm_map[144];
unsigned char pin_map[576];
};
#define DIMM_LABEL_SZ 8
-struct obp_mem_layout {
+struct chmc_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[DIMMS_PER_MC][DIMM_LABEL_SZ];
+ char dimm_labels[CHMC_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 obp_map map[2];
+ struct chmc_obp_map map[2];
};
#define CHMCTRL_NBANKS 4
-struct bank_info {
- struct mctrl_info *mp;
+struct chmc_bank_info {
+ struct chmc *p;
int bank_id;
u64 raw_reg;
@@ -65,28 +84,406 @@
unsigned long size;
};
-struct mctrl_info {
- struct list_head list;
- int portid;
+struct chmc {
+ struct list_head list;
+ int portid;
- struct obp_mem_layout layout_prop;
- int layout_size;
+ struct chmc_obp_mem_layout layout_prop;
+ int layout_size;
- void __iomem *regs;
+ void __iomem *regs;
- u64 timing_control1;
- u64 timing_control2;
- u64 timing_control3;
- u64 timing_control4;
- u64 memaddr_control;
+ u64 timing_control1;
+ u64 timing_control2;
+ u64 timing_control3;
+ u64 timing_control4;
+ u64 memaddr_control;
- struct bank_info logical_banks[CHMCTRL_NBANKS];
+ 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;
+};
+
+struct jbusmc_dimm_group {
+ struct jbusmc *controller;
+ int index;
+ u64 base_addr;
+ u64 size;
+};
+
+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;
+};
+
+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 bank_match(struct bank_info *bp, unsigned long phys_addr)
+static int chmc_bank_match(struct chmc_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;
@@ -118,25 +515,18 @@
}
/* Given PHYS_ADDR, search memory controller banks for a match. */
-static struct bank_info *find_bank(unsigned long phys_addr)
+static struct chmc_bank_info *chmc_find_bank(unsigned long phys_addr)
{
- struct list_head *mctrl_head = &mctrl_list;
- struct list_head *mctrl_entry = mctrl_head->next;
+ struct chmc *p;
- for (;;) {
- struct mctrl_info *mp =
- list_entry(mctrl_entry, struct mctrl_info, list);
+ list_for_each_entry(p, &mctrl_list, 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 bank_info *bp;
+ struct chmc_bank_info *bp;
- bp = &mp->logical_banks[bank_no];
- if (bank_match(bp, phys_addr))
+ bp = &p->logical_banks[bank_no];
+ if (chmc_bank_match(bp, phys_addr))
return bp;
}
}
@@ -145,17 +535,15 @@
}
/* This is the main purpose of this driver. */
-#define SYNDROME_MIN -1
-#define SYNDROME_MAX 144
-int chmc_getunumber(int syndrome_code,
- unsigned long phys_addr,
- char *buf, int buflen)
+static int chmc_print_dimm(int syndrome_code,
+ unsigned long phys_addr,
+ char *buf, int buflen)
{
- struct bank_info *bp;
- struct obp_mem_layout *prop;
+ struct chmc_bank_info *bp;
+ struct chmc_obp_mem_layout *prop;
int bank_in_controller, first_dimm;
- bp = find_bank(phys_addr);
+ bp = chmc_find_bank(phys_addr);
if (bp == NULL ||
syndrome_code < SYNDROME_MIN ||
syndrome_code > SYNDROME_MAX) {
@@ -166,60 +554,18 @@
return 0;
}
- prop = &bp->mp->layout_prop;
+ prop = &bp->p->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) {
- struct obp_map *map;
- int qword, where_in_line, where, map_index, map_offset;
- unsigned int map_val;
+ char *dimm_str;
+ int 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]);
+ 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;
@@ -240,7 +586,7 @@
* the code is executing, you must use special ASI load/store else
* you go through the global mapping.
*/
-static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
+static u64 chmc_read_mcreg(struct chmc *p, unsigned long offset)
{
unsigned long ret, this_cpu;
@@ -248,14 +594,14 @@
this_cpu = real_hard_smp_processor_id();
- if (mp->portid == this_cpu) {
+ if (p->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" (mp->regs + offset),
+ : "r" (p->regs + offset),
"i" (ASI_PHYS_BYPASS_EC_E));
}
@@ -265,178 +611,253 @@
}
#if 0 /* currently unused */
-static void write_mcreg(struct mctrl_info *mp, unsigned long offset, u64 val)
+static void chmc_write_mcreg(struct chmc *p, unsigned long offset, u64 val)
{
- if (mp->portid == smp_processor_id()) {
+ if (p->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" (mp->regs + offset),
+ "r" (p->regs + offset),
"i" (ASI_PHYS_BYPASS_EC_E));
}
}
#endif
-static void interpret_one_decode_reg(struct mctrl_info *mp, int which_bank, u64 val)
+static void chmc_interpret_one_decode_reg(struct chmc *p, int which_bank, u64 val)
{
- struct bank_info *p = &mp->logical_banks[which_bank];
+ struct chmc_bank_info *bp = &p->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;
+ 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;
- p->base = (p->um);
- p->base &= ~(p->uk);
- p->base <<= PA_UPPER_BITS_SHIFT;
+ bp->base = (bp->um);
+ bp->base &= ~(bp->uk);
+ bp->base <<= PA_UPPER_BITS_SHIFT;
- switch(p->lk) {
+ switch(bp->lk) {
case 0xf:
default:
- p->interleave = 1;
+ bp->interleave = 1;
break;
case 0xe:
- p->interleave = 2;
+ bp->interleave = 2;
break;
case 0xc:
- p->interleave = 4;
+ bp->interleave = 4;
break;
case 0x8:
- p->interleave = 8;
+ bp->interleave = 8;
break;
case 0x0:
- p->interleave = 16;
+ bp->interleave = 16;
break;
};
/* UK[10] is reserved, and UK[11] is not set for the SDRAM
* bank size definition.
*/
- p->size = (((unsigned long)p->uk &
- ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
- p->size /= p->interleave;
+ bp->size = (((unsigned long)bp->uk &
+ ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
+ bp->size /= bp->interleave;
}
-static void fetch_decode_regs(struct mctrl_info *mp)
+static void chmc_fetch_decode_regs(struct chmc *p)
{
- if (mp->layout_size == 0)
+ if (p->layout_size == 0)
return;
- 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));
+ 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));
}
-static int init_one_mctrl(struct device_node *dp)
+static int __devinit chmc_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
- int portid = of_getintprop_default(dp, "portid", -1);
- const struct linux_prom64_registers *regs;
+ struct device_node *dp = op->node;
+ unsigned long ver;
const void *pval;
- int len;
+ int len, portid;
+ struct chmc *p;
+ int err;
- if (!mp)
- return -1;
+ err = -ENODEV;
+ __asm__ ("rdpr %%ver, %0" : "=r" (ver));
+ if ((ver >> 32UL) == __JALAPENO_ID ||
+ (ver >> 32UL) == __SERRANO_ID)
+ goto out;
+
+ portid = of_getintprop_default(dp, "portid", -1);
if (portid == -1)
- goto fail;
+ goto out;
- mp->portid = portid;
pval = of_get_property(dp, "memory-layout", &len);
- mp->layout_size = len;
+ if (pval && len > sizeof(p->layout_prop)) {
+ printk(KERN_ERR PFX "Unexpected memory-layout property "
+ "size %d.\n", len);
+ goto out;
+ }
+
+ err = -ENOMEM;
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ printk(KERN_ERR PFX "Could not allocate struct chmc.\n");
+ goto out;
+ }
+
+ p->portid = portid;
+ p->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);
+ 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;
}
- regs = of_get_property(dp, "reg", NULL);
- if (!regs || regs->reg_size != 0x48)
- goto fail;
-
- mp->regs = ioremap(regs->phys_addr, regs->reg_size);
- if (mp->regs == NULL)
- goto fail;
-
- 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);
+ 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);
}
- fetch_decode_regs(mp);
+ chmc_fetch_decode_regs(p);
- list_add(&mp->list, &mctrl_list);
+ mc_list_add(&p->list);
- /* Report the device. */
- printk(KERN_INFO "%s: US3 memory controller at %p [%s]\n",
+ printk(KERN_INFO PFX "UltraSPARC-III memory controller at %s [%s]\n",
dp->full_name,
- mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE"));
+ (p->layout_size ? "ACTIVE" : "INACTIVE"));
- return 0;
+ dev_set_drvdata(&op->dev, p);
-fail:
- if (mp) {
- if (mp->regs != NULL)
- iounmap(mp->regs);
- kfree(mp);
- }
- return -1;
+ err = 0;
+
+out:
+ return err;
+
+out_free:
+ kfree(p);
+ goto out;
}
-static int __init chmc_init(void)
+static int __devinit us3mc_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct device_node *dp;
+ 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;
+}
- /* This driver is only for cheetah platforms. */
- if (tlb_type != cheetah && tlb_type != cheetah_plus)
+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;
+}
+
+static int __init us3mc_init(void)
+{
+ unsigned long ver;
+ int ret;
+
+ if (!us3mc_platform())
return -ENODEV;
- for_each_node_by_name(dp, "memory-controller")
- init_one_mctrl(dp);
+ __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, "mc-us3")
- init_one_mctrl(dp);
+ ret = register_dimm_printer(us3mc_dimm_printer);
- return 0;
+ if (!ret) {
+ ret = of_register_driver(&us3mc_driver, &of_bus_type);
+ if (ret)
+ unregister_dimm_printer(us3mc_dimm_printer);
+ }
+ return ret;
}
-static void __exit chmc_cleanup(void)
+static void __exit us3mc_cleanup(void)
{
- 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);
+ if (us3mc_platform()) {
+ unregister_dimm_printer(us3mc_dimm_printer);
+ of_unregister_driver(&us3mc_driver);
}
}
-module_init(chmc_init);
-module_exit(chmc_cleanup);
+module_init(us3mc_init);
+module_exit(us3mc_cleanup);
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index 0097c08..0c9ac83 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/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 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@@ -19,53 +19,86 @@
DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
-struct cpu_iu_info {
- short manuf;
- short impl;
- char* cpu_name; /* should be enough I hope... */
+struct cpu_chip_info {
+ unsigned short manuf;
+ unsigned short impl;
+ const char *cpu_name;
+ const char *fp_name;
};
-struct cpu_fp_info {
- short manuf;
- short impl;
- char fpu_vers;
- char* fp_name;
+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",
+ },
};
-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 NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips)
-#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)"},
-};
-
-#define NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips)
-
-char *sparc_cpu_type;
-char *sparc_fpu_type;
+const char *sparc_cpu_type;
+const char *sparc_fpu_type;
static void __init sun4v_cpu_probe(void)
{
@@ -89,68 +122,45 @@
}
}
-void __init cpu_probe(void)
+static const struct cpu_chip_info * __init find_cpu_chip(unsigned short manuf,
+ unsigned short impl)
{
- unsigned long ver, fpu_vers, manuf, impl, fprs;
int i;
-
+
+ for (i = 0; i < ARRAY_SIZE(cpu_chips); i++) {
+ const struct cpu_chip_info *p = &cpu_chips[i];
+
+ if (p->manuf == manuf && p->impl == impl)
+ return p;
+ }
+ return NULL;
+}
+
+static int __init cpu_type_probe(void)
+{
if (tlb_type == hypervisor) {
sun4v_cpu_probe();
- return;
- }
-
- fprs = fprs_read();
- fprs_write(FPRS_FEF);
- __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]"
- : "=&r" (ver)
- : "r" (&fpu_vers));
- fprs_write(fprs);
+ } else {
+ unsigned long ver, manuf, impl;
+ const struct cpu_chip_info *p;
- manuf = ((ver >> 48) & 0xffff);
- impl = ((ver >> 32) & 0xffff);
+ __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+
+ 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;
- }
+ 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";
}
}
-
- 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";
- }
-
- 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;
- }
- }
- }
-
- if (i == NSPARCFPU) {
- printk("DEBUG: manuf[%lx] impl[%lx] fsr.vers[%lx]\n",
- manuf, impl, fpu_vers);
- sparc_fpu_type = "Unknown FPU";
- }
+ return 0;
}
+
+arch_initcall(cpu_type_probe);
diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c
index d0fa5aa..f52e053 100644
--- a/arch/sparc64/kernel/ds.c
+++ b/arch/sparc64/kernel/ds.c
@@ -1,6 +1,6 @@
/* ds.c: Domain Services driver for Logical Domains
*
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/kernel.h>
@@ -1217,7 +1217,7 @@
return 0;
}
-static struct vio_device_id ds_match[] = {
+static struct vio_device_id __initdata ds_match[] = {
{
.type = "domain-services-port",
},
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 60d36d1..77dbf6d 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -1,5 +1,4 @@
-/*
- * ebus.c: PCI to EBus bridge device.
+/* ebus.c: EBUS DMA library code.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -9,24 +8,12 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/of_device.h>
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-#include <asm/irq.h>
+#include <asm/ebus_dma.h>
#include <asm/io.h>
-/* EBUS dma library. */
-
#define EBDMA_CSR 0x00UL /* Control/Status */
#define EBDMA_ADDR 0x04UL /* DMA Address */
#define EBDMA_COUNT 0x08UL /* DMA Count */
@@ -268,283 +255,3 @@
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/arch/sparc64/kernel/entry.h b/arch/sparc64/kernel/entry.h
index fc294a2..34d7ab5 100644
--- a/arch/sparc64/kernel/entry.h
+++ b/arch/sparc64/kernel/entry.h
@@ -5,8 +5,8 @@
#include <linux/types.h>
#include <linux/init.h>
-extern char *sparc_cpu_type;
-extern char *sparc_fpu_type;
+extern const char *sparc_cpu_type;
+extern const char *sparc_fpu_type;
extern void __init per_cpu_patch(void);
extern void __init sun4v_patch(void);
@@ -22,7 +22,8 @@
unsigned long orig_i0,
unsigned long thread_info_flags);
-extern asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p);
+extern asmlinkage int syscall_trace_enter(struct pt_regs *regs);
+extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
extern void bad_trap_tl1(struct pt_regs *regs, long lvl);
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index c9afef0..353226f 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -10,6 +10,7 @@
#include <linux/errno.h>
#include <linux/threads.h>
#include <linux/init.h>
+#include <linux/linkage.h>
#include <asm/thread_info.h>
#include <asm/asi.h>
#include <asm/pstate.h>
diff --git a/arch/sparc64/kernel/hvapi.c b/arch/sparc64/kernel/hvapi.c
index 691760b..1d272c3 100644
--- a/arch/sparc64/kernel/hvapi.c
+++ b/arch/sparc64/kernel/hvapi.c
@@ -9,7 +9,6 @@
#include <asm/hypervisor.h>
#include <asm/oplib.h>
-#include <asm/sstate.h>
/* If the hypervisor indicates that the API setting
* calls are unsupported, by returning HV_EBADTRAP or
@@ -184,8 +183,6 @@
if (sun4v_hvapi_register(group, major, &minor))
goto bad;
- sun4v_sstate_init();
-
return;
bad:
diff --git a/arch/sparc64/kernel/hvcalls.S b/arch/sparc64/kernel/hvcalls.S
index a2810f3..e066269 100644
--- a/arch/sparc64/kernel/hvcalls.S
+++ b/arch/sparc64/kernel/hvcalls.S
@@ -3,89 +3,75 @@
*
* returns %o0: sysino
*/
- .globl sun4v_devino_to_sysino
- .type sun4v_devino_to_sysino,#function
-sun4v_devino_to_sysino:
+ENTRY(sun4v_devino_to_sysino)
mov HV_FAST_INTR_DEVINO2SYSINO, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
- .size sun4v_devino_to_sysino, .-sun4v_devino_to_sysino
+ENDPROC(sun4v_devino_to_sysino)
/* %o0: sysino
*
* returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED})
*/
- .globl sun4v_intr_getenabled
- .type sun4v_intr_getenabled,#function
-sun4v_intr_getenabled:
+ENTRY(sun4v_intr_getenabled)
mov HV_FAST_INTR_GETENABLED, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
- .size sun4v_intr_getenabled, .-sun4v_intr_getenabled
+ENDPROC(sun4v_intr_getenabled)
/* %o0: sysino
* %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED})
*/
- .globl sun4v_intr_setenabled
- .type sun4v_intr_setenabled,#function
-sun4v_intr_setenabled:
+ENTRY(sun4v_intr_setenabled)
mov HV_FAST_INTR_SETENABLED, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_intr_setenabled, .-sun4v_intr_setenabled
+ENDPROC(sun4v_intr_setenabled)
/* %o0: sysino
*
* returns %o0: intr_state (HV_INTR_STATE_*)
*/
- .globl sun4v_intr_getstate
- .type sun4v_intr_getstate,#function
-sun4v_intr_getstate:
+ENTRY(sun4v_intr_getstate)
mov HV_FAST_INTR_GETSTATE, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
- .size sun4v_intr_getstate, .-sun4v_intr_getstate
+ENDPROC(sun4v_intr_getstate)
/* %o0: sysino
* %o1: intr_state (HV_INTR_STATE_*)
*/
- .globl sun4v_intr_setstate
- .type sun4v_intr_setstate,#function
-sun4v_intr_setstate:
+ENTRY(sun4v_intr_setstate)
mov HV_FAST_INTR_SETSTATE, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_intr_setstate, .-sun4v_intr_setstate
+ENDPROC(sun4v_intr_setstate)
/* %o0: sysino
*
* returns %o0: cpuid
*/
- .globl sun4v_intr_gettarget
- .type sun4v_intr_gettarget,#function
-sun4v_intr_gettarget:
+ENTRY(sun4v_intr_gettarget)
mov HV_FAST_INTR_GETTARGET, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
- .size sun4v_intr_gettarget, .-sun4v_intr_gettarget
+ENDPROC(sun4v_intr_gettarget)
/* %o0: sysino
* %o1: cpuid
*/
- .globl sun4v_intr_settarget
- .type sun4v_intr_settarget,#function
-sun4v_intr_settarget:
+ENTRY(sun4v_intr_settarget)
mov HV_FAST_INTR_SETTARGET, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_intr_settarget, .-sun4v_intr_settarget
+ENDPROC(sun4v_intr_settarget)
/* %o0: cpuid
* %o1: pc
@@ -94,37 +80,31 @@
*
* returns %o0: status
*/
- .globl sun4v_cpu_start
- .type sun4v_cpu_start,#function
-sun4v_cpu_start:
+ENTRY(sun4v_cpu_start)
mov HV_FAST_CPU_START, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_cpu_start, .-sun4v_cpu_start
+ENDPROC(sun4v_cpu_start)
/* %o0: cpuid
*
* returns %o0: status
*/
- .globl sun4v_cpu_stop
- .type sun4v_cpu_stop,#function
-sun4v_cpu_stop:
+ENTRY(sun4v_cpu_stop)
mov HV_FAST_CPU_STOP, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_cpu_stop, .-sun4v_cpu_stop
+ENDPROC(sun4v_cpu_stop)
/* returns %o0: status */
- .globl sun4v_cpu_yield
- .type sun4v_cpu_yield, #function
-sun4v_cpu_yield:
+ENTRY(sun4v_cpu_yield)
mov HV_FAST_CPU_YIELD, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_cpu_yield, .-sun4v_cpu_yield
+ENDPROC(sun4v_cpu_yield)
/* %o0: type
* %o1: queue paddr
@@ -132,14 +112,12 @@
*
* returns %o0: status
*/
- .globl sun4v_cpu_qconf
- .type sun4v_cpu_qconf,#function
-sun4v_cpu_qconf:
+ENTRY(sun4v_cpu_qconf)
mov HV_FAST_CPU_QCONF, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_cpu_qconf, .-sun4v_cpu_qconf
+ENDPROC(sun4v_cpu_qconf)
/* %o0: num cpus in cpu list
* %o1: cpu list paddr
@@ -147,23 +125,19 @@
*
* returns %o0: status
*/
- .globl sun4v_cpu_mondo_send
- .type sun4v_cpu_mondo_send,#function
-sun4v_cpu_mondo_send:
+ENTRY(sun4v_cpu_mondo_send)
mov HV_FAST_CPU_MONDO_SEND, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_cpu_mondo_send, .-sun4v_cpu_mondo_send
+ENDPROC(sun4v_cpu_mondo_send)
/* %o0: CPU ID
*
* returns %o0: -status if status non-zero, else
* %o0: cpu state as HV_CPU_STATE_*
*/
- .globl sun4v_cpu_state
- .type sun4v_cpu_state,#function
-sun4v_cpu_state:
+ENTRY(sun4v_cpu_state)
mov HV_FAST_CPU_STATE, %o5
ta HV_FAST_TRAP
brnz,pn %o0, 1f
@@ -171,7 +145,7 @@
mov %o1, %o0
1: retl
nop
- .size sun4v_cpu_state, .-sun4v_cpu_state
+ENDPROC(sun4v_cpu_state)
/* %o0: virtual address
* %o1: must be zero
@@ -180,28 +154,24 @@
*
* returns %o0: status
*/
- .globl sun4v_mmu_map_perm_addr
- .type sun4v_mmu_map_perm_addr,#function
-sun4v_mmu_map_perm_addr:
+ENTRY(sun4v_mmu_map_perm_addr)
mov HV_FAST_MMU_MAP_PERM_ADDR, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_mmu_map_perm_addr, .-sun4v_mmu_map_perm_addr
+ENDPROC(sun4v_mmu_map_perm_addr)
/* %o0: number of TSB descriptions
* %o1: TSB descriptions real address
*
* returns %o0: status
*/
- .globl sun4v_mmu_tsb_ctx0
- .type sun4v_mmu_tsb_ctx0,#function
-sun4v_mmu_tsb_ctx0:
+ENTRY(sun4v_mmu_tsb_ctx0)
mov HV_FAST_MMU_TSB_CTX0, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_mmu_tsb_ctx0, .-sun4v_mmu_tsb_ctx0
+ENDPROC(sun4v_mmu_tsb_ctx0)
/* %o0: API group number
* %o1: pointer to unsigned long major number storage
@@ -209,9 +179,7 @@
*
* returns %o0: status
*/
- .globl sun4v_get_version
- .type sun4v_get_version,#function
-sun4v_get_version:
+ENTRY(sun4v_get_version)
mov HV_CORE_GET_VER, %o5
mov %o1, %o3
mov %o2, %o4
@@ -219,7 +187,7 @@
stx %o1, [%o3]
retl
stx %o2, [%o4]
- .size sun4v_get_version, .-sun4v_get_version
+ENDPROC(sun4v_get_version)
/* %o0: API group number
* %o1: desired major number
@@ -228,51 +196,43 @@
*
* returns %o0: status
*/
- .globl sun4v_set_version
- .type sun4v_set_version,#function
-sun4v_set_version:
+ENTRY(sun4v_set_version)
mov HV_CORE_SET_VER, %o5
mov %o3, %o4
ta HV_CORE_TRAP
retl
stx %o1, [%o4]
- .size sun4v_set_version, .-sun4v_set_version
+ENDPROC(sun4v_set_version)
/* %o0: pointer to unsigned long time
*
* returns %o0: status
*/
- .globl sun4v_tod_get
- .type sun4v_tod_get,#function
-sun4v_tod_get:
+ENTRY(sun4v_tod_get)
mov %o0, %o4
mov HV_FAST_TOD_GET, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_tod_get, .-sun4v_tod_get
+ENDPROC(sun4v_tod_get)
/* %o0: time
*
* returns %o0: status
*/
- .globl sun4v_tod_set
- .type sun4v_tod_set,#function
-sun4v_tod_set:
+ENTRY(sun4v_tod_set)
mov HV_FAST_TOD_SET, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_tod_set, .-sun4v_tod_set
+ENDPROC(sun4v_tod_set)
/* %o0: pointer to unsigned long status
*
* returns %o0: signed character
*/
- .globl sun4v_con_getchar
- .type sun4v_con_getchar,#function
-sun4v_con_getchar:
+ENTRY(sun4v_con_getchar)
mov %o0, %o4
mov HV_FAST_CONS_GETCHAR, %o5
clr %o0
@@ -281,20 +241,18 @@
stx %o0, [%o4]
retl
sra %o1, 0, %o0
- .size sun4v_con_getchar, .-sun4v_con_getchar
+ENDPROC(sun4v_con_getchar)
/* %o0: signed long character
*
* returns %o0: status
*/
- .globl sun4v_con_putchar
- .type sun4v_con_putchar,#function
-sun4v_con_putchar:
+ENTRY(sun4v_con_putchar)
mov HV_FAST_CONS_PUTCHAR, %o5
ta HV_FAST_TRAP
retl
sra %o0, 0, %o0
- .size sun4v_con_putchar, .-sun4v_con_putchar
+ENDPROC(sun4v_con_putchar)
/* %o0: buffer real address
* %o1: buffer size
@@ -302,9 +260,7 @@
*
* returns %o0: status
*/
- .globl sun4v_con_read
- .type sun4v_con_read,#function
-sun4v_con_read:
+ENTRY(sun4v_con_read)
mov %o2, %o4
mov HV_FAST_CONS_READ, %o5
ta HV_FAST_TRAP
@@ -318,7 +274,7 @@
stx %o1, [%o4]
1: retl
nop
- .size sun4v_con_read, .-sun4v_con_read
+ENDPROC(sun4v_con_read)
/* %o0: buffer real address
* %o1: buffer size
@@ -326,43 +282,37 @@
*
* returns %o0: status
*/
- .globl sun4v_con_write
- .type sun4v_con_write,#function
-sun4v_con_write:
+ENTRY(sun4v_con_write)
mov %o2, %o4
mov HV_FAST_CONS_WRITE, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_con_write, .-sun4v_con_write
+ENDPROC(sun4v_con_write)
/* %o0: soft state
* %o1: address of description string
*
* returns %o0: status
*/
- .globl sun4v_mach_set_soft_state
- .type sun4v_mach_set_soft_state,#function
-sun4v_mach_set_soft_state:
+ENTRY(sun4v_mach_set_soft_state)
mov HV_FAST_MACH_SET_SOFT_STATE, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_mach_set_soft_state, .-sun4v_mach_set_soft_state
+ENDPROC(sun4v_mach_set_soft_state)
/* %o0: exit code
*
* Does not return.
*/
- .globl sun4v_mach_exit
- .type sun4v_mach_exit,#function
-sun4v_mach_exit:
+ENTRY(sun4v_mach_exit)
mov HV_FAST_MACH_EXIT, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_mach_exit, .-sun4v_mach_exit
+ENDPROC(sun4v_mach_exit)
/* %o0: buffer real address
* %o1: buffer length
@@ -370,44 +320,38 @@
*
* returns %o0: status
*/
- .globl sun4v_mach_desc
- .type sun4v_mach_desc,#function
-sun4v_mach_desc:
+ENTRY(sun4v_mach_desc)
mov %o2, %o4
mov HV_FAST_MACH_DESC, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_mach_desc, .-sun4v_mach_desc
+ENDPROC(sun4v_mach_desc)
/* %o0: new timeout in milliseconds
* %o1: pointer to unsigned long orig_timeout
*
* returns %o0: status
*/
- .globl sun4v_mach_set_watchdog
- .type sun4v_mach_set_watchdog,#function
-sun4v_mach_set_watchdog:
+ENTRY(sun4v_mach_set_watchdog)
mov %o1, %o4
mov HV_FAST_MACH_SET_WATCHDOG, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_mach_set_watchdog, .-sun4v_mach_set_watchdog
+ENDPROC(sun4v_mach_set_watchdog)
/* No inputs and does not return. */
- .globl sun4v_mach_sir
- .type sun4v_mach_sir,#function
-sun4v_mach_sir:
+ENTRY(sun4v_mach_sir)
mov %o1, %o4
mov HV_FAST_MACH_SIR, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_mach_sir, .-sun4v_mach_sir
+ENDPROC(sun4v_mach_sir)
/* %o0: channel
* %o1: ra
@@ -415,14 +359,12 @@
*
* returns %o0: status
*/
- .globl sun4v_ldc_tx_qconf
- .type sun4v_ldc_tx_qconf,#function
-sun4v_ldc_tx_qconf:
+ENTRY(sun4v_ldc_tx_qconf)
mov HV_FAST_LDC_TX_QCONF, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_tx_qconf, .-sun4v_ldc_tx_qconf
+ENDPROC(sun4v_ldc_tx_qconf)
/* %o0: channel
* %o1: pointer to unsigned long ra
@@ -430,9 +372,7 @@
*
* returns %o0: status
*/
- .globl sun4v_ldc_tx_qinfo
- .type sun4v_ldc_tx_qinfo,#function
-sun4v_ldc_tx_qinfo:
+ENTRY(sun4v_ldc_tx_qinfo)
mov %o1, %g1
mov %o2, %g2
mov HV_FAST_LDC_TX_QINFO, %o5
@@ -441,7 +381,7 @@
stx %o2, [%g2]
retl
nop
- .size sun4v_ldc_tx_qinfo, .-sun4v_ldc_tx_qinfo
+ENDPROC(sun4v_ldc_tx_qinfo)
/* %o0: channel
* %o1: pointer to unsigned long head_off
@@ -450,9 +390,7 @@
*
* returns %o0: status
*/
- .globl sun4v_ldc_tx_get_state
- .type sun4v_ldc_tx_get_state,#function
-sun4v_ldc_tx_get_state:
+ENTRY(sun4v_ldc_tx_get_state)
mov %o1, %g1
mov %o2, %g2
mov %o3, %g3
@@ -463,21 +401,19 @@
stx %o3, [%g3]
retl
nop
- .size sun4v_ldc_tx_get_state, .-sun4v_ldc_tx_get_state
+ENDPROC(sun4v_ldc_tx_get_state)
/* %o0: channel
* %o1: tail_off
*
* returns %o0: status
*/
- .globl sun4v_ldc_tx_set_qtail
- .type sun4v_ldc_tx_set_qtail,#function
-sun4v_ldc_tx_set_qtail:
+ENTRY(sun4v_ldc_tx_set_qtail)
mov HV_FAST_LDC_TX_SET_QTAIL, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_tx_set_qtail, .-sun4v_ldc_tx_set_qtail
+ENDPROC(sun4v_ldc_tx_set_qtail)
/* %o0: channel
* %o1: ra
@@ -485,14 +421,12 @@
*
* returns %o0: status
*/
- .globl sun4v_ldc_rx_qconf
- .type sun4v_ldc_rx_qconf,#function
-sun4v_ldc_rx_qconf:
+ENTRY(sun4v_ldc_rx_qconf)
mov HV_FAST_LDC_RX_QCONF, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_rx_qconf, .-sun4v_ldc_rx_qconf
+ENDPROC(sun4v_ldc_rx_qconf)
/* %o0: channel
* %o1: pointer to unsigned long ra
@@ -500,9 +434,7 @@
*
* returns %o0: status
*/
- .globl sun4v_ldc_rx_qinfo
- .type sun4v_ldc_rx_qinfo,#function
-sun4v_ldc_rx_qinfo:
+ENTRY(sun4v_ldc_rx_qinfo)
mov %o1, %g1
mov %o2, %g2
mov HV_FAST_LDC_RX_QINFO, %o5
@@ -511,7 +443,7 @@
stx %o2, [%g2]
retl
nop
- .size sun4v_ldc_rx_qinfo, .-sun4v_ldc_rx_qinfo
+ENDPROC(sun4v_ldc_rx_qinfo)
/* %o0: channel
* %o1: pointer to unsigned long head_off
@@ -520,9 +452,7 @@
*
* returns %o0: status
*/
- .globl sun4v_ldc_rx_get_state
- .type sun4v_ldc_rx_get_state,#function
-sun4v_ldc_rx_get_state:
+ENTRY(sun4v_ldc_rx_get_state)
mov %o1, %g1
mov %o2, %g2
mov %o3, %g3
@@ -533,21 +463,19 @@
stx %o3, [%g3]
retl
nop
- .size sun4v_ldc_rx_get_state, .-sun4v_ldc_rx_get_state
+ENDPROC(sun4v_ldc_rx_get_state)
/* %o0: channel
* %o1: head_off
*
* returns %o0: status
*/
- .globl sun4v_ldc_rx_set_qhead
- .type sun4v_ldc_rx_set_qhead,#function
-sun4v_ldc_rx_set_qhead:
+ENTRY(sun4v_ldc_rx_set_qhead)
mov HV_FAST_LDC_RX_SET_QHEAD, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_rx_set_qhead, .-sun4v_ldc_rx_set_qhead
+ENDPROC(sun4v_ldc_rx_set_qhead)
/* %o0: channel
* %o1: ra
@@ -555,14 +483,12 @@
*
* returns %o0: status
*/
- .globl sun4v_ldc_set_map_table
- .type sun4v_ldc_set_map_table,#function
-sun4v_ldc_set_map_table:
+ENTRY(sun4v_ldc_set_map_table)
mov HV_FAST_LDC_SET_MAP_TABLE, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_set_map_table, .-sun4v_ldc_set_map_table
+ENDPROC(sun4v_ldc_set_map_table)
/* %o0: channel
* %o1: pointer to unsigned long ra
@@ -570,9 +496,7 @@
*
* returns %o0: status
*/
- .globl sun4v_ldc_get_map_table
- .type sun4v_ldc_get_map_table,#function
-sun4v_ldc_get_map_table:
+ENTRY(sun4v_ldc_get_map_table)
mov %o1, %g1
mov %o2, %g2
mov HV_FAST_LDC_GET_MAP_TABLE, %o5
@@ -581,7 +505,7 @@
stx %o2, [%g2]
retl
nop
- .size sun4v_ldc_get_map_table, .-sun4v_ldc_get_map_table
+ENDPROC(sun4v_ldc_get_map_table)
/* %o0: channel
* %o1: dir_code
@@ -592,16 +516,14 @@
*
* returns %o0: status
*/
- .globl sun4v_ldc_copy
- .type sun4v_ldc_copy,#function
-sun4v_ldc_copy:
+ENTRY(sun4v_ldc_copy)
mov %o5, %g1
mov HV_FAST_LDC_COPY, %o5
ta HV_FAST_TRAP
stx %o1, [%g1]
retl
nop
- .size sun4v_ldc_copy, .-sun4v_ldc_copy
+ENDPROC(sun4v_ldc_copy)
/* %o0: channel
* %o1: cookie
@@ -610,9 +532,7 @@
*
* returns %o0: status
*/
- .globl sun4v_ldc_mapin
- .type sun4v_ldc_mapin,#function
-sun4v_ldc_mapin:
+ENTRY(sun4v_ldc_mapin)
mov %o2, %g1
mov %o3, %g2
mov HV_FAST_LDC_MAPIN, %o5
@@ -621,20 +541,18 @@
stx %o2, [%g2]
retl
nop
- .size sun4v_ldc_mapin, .-sun4v_ldc_mapin
+ENDPROC(sun4v_ldc_mapin)
/* %o0: ra
*
* returns %o0: status
*/
- .globl sun4v_ldc_unmap
- .type sun4v_ldc_unmap,#function
-sun4v_ldc_unmap:
+ENTRY(sun4v_ldc_unmap)
mov HV_FAST_LDC_UNMAP, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_unmap, .-sun4v_ldc_unmap
+ENDPROC(sun4v_ldc_unmap)
/* %o0: channel
* %o1: cookie
@@ -642,14 +560,12 @@
*
* returns %o0: status
*/
- .globl sun4v_ldc_revoke
- .type sun4v_ldc_revoke,#function
-sun4v_ldc_revoke:
+ENTRY(sun4v_ldc_revoke)
mov HV_FAST_LDC_REVOKE, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_revoke, .-sun4v_ldc_revoke
+ENDPROC(sun4v_ldc_revoke)
/* %o0: device handle
* %o1: device INO
@@ -657,16 +573,14 @@
*
* returns %o0: status
*/
- .globl sun4v_vintr_get_cookie
- .type sun4v_vintr_get_cookie,#function
-sun4v_vintr_get_cookie:
+ENTRY(sun4v_vintr_get_cookie)
mov %o2, %g1
mov HV_FAST_VINTR_GET_COOKIE, %o5
ta HV_FAST_TRAP
stx %o1, [%g1]
retl
nop
- .size sun4v_vintr_get_cookie, .-sun4v_vintr_get_cookie
+ENDPROC(sun4v_vintr_get_cookie)
/* %o0: device handle
* %o1: device INO
@@ -674,14 +588,12 @@
*
* returns %o0: status
*/
- .globl sun4v_vintr_set_cookie
- .type sun4v_vintr_set_cookie,#function
-sun4v_vintr_set_cookie:
+ENTRY(sun4v_vintr_set_cookie)
mov HV_FAST_VINTR_SET_COOKIE, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_vintr_set_cookie, .-sun4v_vintr_set_cookie
+ENDPROC(sun4v_vintr_set_cookie)
/* %o0: device handle
* %o1: device INO
@@ -689,16 +601,14 @@
*
* returns %o0: status
*/
- .globl sun4v_vintr_get_valid
- .type sun4v_vintr_get_valid,#function
-sun4v_vintr_get_valid:
+ENTRY(sun4v_vintr_get_valid)
mov %o2, %g1
mov HV_FAST_VINTR_GET_VALID, %o5
ta HV_FAST_TRAP
stx %o1, [%g1]
retl
nop
- .size sun4v_vintr_get_valid, .-sun4v_vintr_get_valid
+ENDPROC(sun4v_vintr_get_valid)
/* %o0: device handle
* %o1: device INO
@@ -706,14 +616,12 @@
*
* returns %o0: status
*/
- .globl sun4v_vintr_set_valid
- .type sun4v_vintr_set_valid,#function
-sun4v_vintr_set_valid:
+ENTRY(sun4v_vintr_set_valid)
mov HV_FAST_VINTR_SET_VALID, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_vintr_set_valid, .-sun4v_vintr_set_valid
+ENDPROC(sun4v_vintr_set_valid)
/* %o0: device handle
* %o1: device INO
@@ -721,16 +629,14 @@
*
* returns %o0: status
*/
- .globl sun4v_vintr_get_state
- .type sun4v_vintr_get_state,#function
-sun4v_vintr_get_state:
+ENTRY(sun4v_vintr_get_state)
mov %o2, %g1
mov HV_FAST_VINTR_GET_STATE, %o5
ta HV_FAST_TRAP
stx %o1, [%g1]
retl
nop
- .size sun4v_vintr_get_state, .-sun4v_vintr_get_state
+ENDPROC(sun4v_vintr_get_state)
/* %o0: device handle
* %o1: device INO
@@ -738,14 +644,12 @@
*
* returns %o0: status
*/
- .globl sun4v_vintr_set_state
- .type sun4v_vintr_set_state,#function
-sun4v_vintr_set_state:
+ENTRY(sun4v_vintr_set_state)
mov HV_FAST_VINTR_SET_STATE, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_vintr_set_state, .-sun4v_vintr_set_state
+ENDPROC(sun4v_vintr_set_state)
/* %o0: device handle
* %o1: device INO
@@ -753,16 +657,14 @@
*
* returns %o0: status
*/
- .globl sun4v_vintr_get_target
- .type sun4v_vintr_get_target,#function
-sun4v_vintr_get_target:
+ENTRY(sun4v_vintr_get_target)
mov %o2, %g1
mov HV_FAST_VINTR_GET_TARGET, %o5
ta HV_FAST_TRAP
stx %o1, [%g1]
retl
nop
- .size sun4v_vintr_get_target, .-sun4v_vintr_get_target
+ENDPROC(sun4v_vintr_get_target)
/* %o0: device handle
* %o1: device INO
@@ -770,14 +672,12 @@
*
* returns %o0: status
*/
- .globl sun4v_vintr_set_target
- .type sun4v_vintr_set_target,#function
-sun4v_vintr_set_target:
+ENTRY(sun4v_vintr_set_target)
mov HV_FAST_VINTR_SET_TARGET, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_vintr_set_target, .-sun4v_vintr_set_target
+ENDPROC(sun4v_vintr_set_target)
/* %o0: NCS sub-function
* %o1: sub-function arg real-address
@@ -785,18 +685,14 @@
*
* returns %o0: status
*/
- .globl sun4v_ncs_request
- .type sun4v_ncs_request,#function
-sun4v_ncs_request:
+ENTRY(sun4v_ncs_request)
mov HV_FAST_NCS_REQUEST, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ncs_request, .-sun4v_ncs_request
+ENDPROC(sun4v_ncs_request)
- .globl sun4v_svc_send
- .type sun4v_svc_send,#function
-sun4v_svc_send:
+ENTRY(sun4v_svc_send)
save %sp, -192, %sp
mov %i0, %o0
mov %i1, %o1
@@ -806,11 +702,9 @@
stx %o1, [%i3]
ret
restore
- .size sun4v_svc_send, .-sun4v_svc_send
+ENDPROC(sun4v_svc_send)
- .globl sun4v_svc_recv
- .type sun4v_svc_recv,#function
-sun4v_svc_recv:
+ENTRY(sun4v_svc_recv)
save %sp, -192, %sp
mov %i0, %o0
mov %i1, %o1
@@ -820,62 +714,50 @@
stx %o1, [%i3]
ret
restore
- .size sun4v_svc_recv, .-sun4v_svc_recv
+ENDPROC(sun4v_svc_recv)
- .globl sun4v_svc_getstatus
- .type sun4v_svc_getstatus,#function
-sun4v_svc_getstatus:
+ENTRY(sun4v_svc_getstatus)
mov HV_FAST_SVC_GETSTATUS, %o5
mov %o1, %o4
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_svc_getstatus, .-sun4v_svc_getstatus
+ENDPROC(sun4v_svc_getstatus)
- .globl sun4v_svc_setstatus
- .type sun4v_svc_setstatus,#function
-sun4v_svc_setstatus:
+ENTRY(sun4v_svc_setstatus)
mov HV_FAST_SVC_SETSTATUS, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_svc_setstatus, .-sun4v_svc_setstatus
+ENDPROC(sun4v_svc_setstatus)
- .globl sun4v_svc_clrstatus
- .type sun4v_svc_clrstatus,#function
-sun4v_svc_clrstatus:
+ENTRY(sun4v_svc_clrstatus)
mov HV_FAST_SVC_CLRSTATUS, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus
+ENDPROC(sun4v_svc_clrstatus)
- .globl sun4v_mmustat_conf
- .type sun4v_mmustat_conf,#function
-sun4v_mmustat_conf:
+ENTRY(sun4v_mmustat_conf)
mov %o1, %o4
mov HV_FAST_MMUSTAT_CONF, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_mmustat_conf, .-sun4v_mmustat_conf
+ENDPROC(sun4v_mmustat_conf)
- .globl sun4v_mmustat_info
- .type sun4v_mmustat_info,#function
-sun4v_mmustat_info:
+ENTRY(sun4v_mmustat_info)
mov %o0, %o4
mov HV_FAST_MMUSTAT_INFO, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_mmustat_info, .-sun4v_mmustat_info
+ENDPROC(sun4v_mmustat_info)
- .globl sun4v_mmu_demap_all
- .type sun4v_mmu_demap_all,#function
-sun4v_mmu_demap_all:
+ENTRY(sun4v_mmu_demap_all)
clr %o0
clr %o1
mov HV_MMU_ALL, %o2
@@ -883,4 +765,4 @@
ta HV_FAST_TRAP
retl
nop
- .size sun4v_mmu_demap_all, .-sun4v_mmu_demap_all
+ENDPROC(sun4v_mmu_demap_all)
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 7495bc7..52fc836 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -29,7 +29,6 @@
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/sbus.h>
#include <asm/iommu.h>
#include <asm/upa.h>
#include <asm/oplib.h>
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 100ebd5..0f616ae 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -55,15 +55,38 @@
}
EXPORT_SYMBOL(of_find_device_by_node);
-#ifdef CONFIG_PCI
-struct bus_type ebus_bus_type;
-EXPORT_SYMBOL(ebus_bus_type);
-#endif
+unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+{
+ struct of_device *op = of_find_device_by_node(node);
-#ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type;
-EXPORT_SYMBOL(sbus_bus_type);
-#endif
+ if (!op || index >= op->num_irqs)
+ return 0;
+
+ return op->irqs[index];
+}
+EXPORT_SYMBOL(irq_of_parse_and_map);
+
+/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
+ * BUS and propagate to all child of_device objects.
+ */
+void of_propagate_archdata(struct of_device *bus)
+{
+ struct dev_archdata *bus_sd = &bus->dev.archdata;
+ struct device_node *bus_dp = bus->node;
+ struct device_node *dp;
+
+ for (dp = bus_dp->child; dp; dp = dp->sibling) {
+ struct of_device *op = of_find_device_by_node(dp);
+
+ op->dev.archdata.iommu = bus_sd->iommu;
+ op->dev.archdata.stc = bus_sd->stc;
+ op->dev.archdata.host_controller = bus_sd->host_controller;
+ op->dev.archdata.numa_node = bus_sd->numa_node;
+
+ if (dp->child)
+ of_propagate_archdata(op);
+ }
+}
struct bus_type of_platform_bus_type;
EXPORT_SYMBOL(of_platform_bus_type);
@@ -378,8 +401,7 @@
int na, int ns, int pna)
{
const u32 *ranges;
- unsigned int rlen;
- int rone;
+ int rone, rlen;
ranges = of_get_property(parent, "ranges", &rlen);
if (ranges == NULL || rlen == 0) {
@@ -421,8 +443,17 @@
/* 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"))
+ if (!strcmp(pp->name, "dma") ||
+ !strcmp(pp->name, "espdma") ||
+ !strcmp(pp->name, "ledma") ||
+ !strcmp(pp->name, "lebuffer"))
return 0;
/* Similarly for all PCI bridges, if we get this far
@@ -844,15 +875,6 @@
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/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 80dad76..242ac1c 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -18,32 +18,17 @@
#include <linux/msi.h>
#include <linux/irq.h>
#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
-#include <asm/ebus.h>
#include <asm/prom.h>
#include <asm/apb.h>
#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;
@@ -179,97 +164,6 @@
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)
@@ -348,11 +242,12 @@
}
}
-struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
- struct device_node *node,
- struct pci_bus *bus, int devfn)
+static 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;
@@ -366,14 +261,17 @@
sd->stc = &pbm->stc;
sd->host_controller = pbm;
sd->prom_node = node;
- sd->op = of_find_device_by_node(node);
+ sd->op = op = of_find_device_by_node(node);
sd->numa_node = pbm->numa_node;
- sd = &sd->op->dev.archdata;
+ 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 = "";
@@ -775,15 +673,15 @@
pci_bus_register_of_sysfs(child_bus);
}
-struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
+struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
+ struct device *parent)
{
- struct device_node *node = pbm->prom_node;
+ struct device_node *node = pbm->op->node;
struct pci_bus *bus;
printk("PCI: Scanning PBM %s\n", node->full_name);
- /* XXX parent device? XXX */
- bus = pci_create_bus(NULL, pbm->pci_first_busno, pbm->pci_ops, pbm);
+ bus = pci_create_bus(parent, pbm->pci_first_busno, pbm->pci_ops, pbm);
if (!bus) {
printk(KERN_ERR "Failed to create bus for %s\n",
node->full_name);
@@ -802,32 +700,6 @@
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;
@@ -1105,14 +977,14 @@
EXPORT_SYMBOL(pcibus_to_node);
#endif
-/* Return the domain nuber for this pci bus */
+/* Return the domain number for this pci bus */
int pci_domain_nr(struct pci_bus *pbus)
{
struct pci_pbm_info *pbm = pbus->sysdata;
int ret;
- if (pbm == NULL || pbm->parent == NULL) {
+ if (!pbm) {
ret = -ENXIO;
} else {
ret = pbm->index;
@@ -1126,7 +998,7 @@
int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
{
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
- int virt_irq;
+ unsigned int virt_irq;
if (!pbm->setup_msi_irq)
return -EINVAL;
@@ -1140,10 +1012,8 @@
struct pci_dev *pdev = entry->dev;
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
- if (!pbm->teardown_msi_irq)
- return;
-
- return pbm->teardown_msi_irq(virt_irq, pdev);
+ if (pbm->teardown_msi_irq)
+ pbm->teardown_msi_irq(virt_irq, pdev);
}
#endif /* !(CONFIG_PCI_MSI) */
@@ -1215,5 +1085,3 @@
*start = rp->start - offset;
*end = rp->end - offset;
}
-
-#endif /* !(CONFIG_PCI) */
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 09a5ec2..23b8808 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -314,12 +314,12 @@
void pci_get_pbm_props(struct pci_pbm_info *pbm)
{
- const u32 *val = of_get_property(pbm->prom_node, "bus-range", NULL);
+ const u32 *val = of_get_property(pbm->op->node, "bus-range", NULL);
pbm->pci_first_busno = val[0];
pbm->pci_last_busno = val[1];
- val = of_get_property(pbm->prom_node, "ino-bitmap", NULL);
+ val = of_get_property(pbm->op->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_iommu_region(struct pci_pbm_info *pbm)
{
- const u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL);
+ const u32 *vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
if (vdma) {
struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL);
@@ -389,7 +389,7 @@
int num_pbm_ranges;
saw_mem = saw_io = 0;
- pbm_ranges = of_get_property(pbm->prom_node, "ranges", &i);
+ pbm_ranges = of_get_property(pbm->op->node, "ranges", &i);
if (!pbm_ranges) {
prom_printf("PCI: Fatal error, missing PBM ranges property "
" for %s\n",
diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c
index d23bb6f..9462b68 100644
--- a/arch/sparc64/kernel/pci_fire.c
+++ b/arch/sparc64/kernel/pci_fire.c
@@ -8,34 +8,16 @@
#include <linux/init.h>
#include <linux/msi.h>
#include <linux/irq.h>
+#include <linux/of_device.h>
-#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/irq.h>
+#include <asm/upa.h>
#include "pci_impl.h"
-#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 DRIVER_NAME "fire"
+#define PFX DRIVER_NAME ": "
#define FIRE_IOMMU_CONTROL 0x40000UL
#define FIRE_IOMMU_TSBBASE 0x40008UL
@@ -69,21 +51,21 @@
/*
* Invalidate TLB Entries.
*/
- fire_write(iommu->iommu_flushinv, ~(u64)0);
+ upa_writeq(~(u64)0, iommu->iommu_flushinv);
err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
pbm->numa_node);
if (err)
return err;
- fire_write(iommu->iommu_tsbbase, __pa(iommu->page_table) | 0x7UL);
+ upa_writeq(__pa(iommu->page_table) | 0x7UL, iommu->iommu_tsbbase);
- control = fire_read(iommu->iommu_control);
+ control = upa_readq(iommu->iommu_control);
control |= (0x00000400 /* TSB cache snoop enable */ |
0x00000300 /* Cache mode */ |
0x00000002 /* Bypass enable */ |
0x00000001 /* Translation enable */);
- fire_write(iommu->iommu_control, control);
+ upa_writeq(control, iommu->iommu_control);
return 0;
}
@@ -165,7 +147,7 @@
static int pci_fire_get_head(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long *head)
{
- *head = fire_read(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
+ *head = upa_readq(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
return 0;
}
@@ -191,8 +173,7 @@
*msi = msi_num = ((ep->word0 & MSIQ_WORD0_DATA0) >>
MSIQ_WORD0_DATA0_SHIFT);
- fire_write(pbm->pbm_regs + MSI_CLEAR(msi_num),
- MSI_CLEAR_EQWR_N);
+ upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi_num));
/* Clear the entry. */
ep->word0 &= ~MSIQ_WORD0_FMT_TYPE;
@@ -208,7 +189,7 @@
static int pci_fire_set_head(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long head)
{
- fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid), head);
+ upa_writeq(head, pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
return 0;
}
@@ -217,17 +198,16 @@
{
u64 val;
- val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+ val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
val &= ~(MSI_MAP_EQNUM);
val |= msiqid;
- fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+ upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
- fire_write(pbm->pbm_regs + MSI_CLEAR(msi),
- MSI_CLEAR_EQWR_N);
+ upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi));
- val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+ val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
val |= MSI_MAP_VALID;
- fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+ upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
return 0;
}
@@ -237,12 +217,12 @@
unsigned long msiqid;
u64 val;
- val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+ val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
msiqid = (val & MSI_MAP_EQNUM);
val &= ~MSI_MAP_VALID;
- fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+ upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
return 0;
}
@@ -261,22 +241,19 @@
memset((char *)pages, 0, PAGE_SIZE << order);
pbm->msi_queues = (void *) pages;
- fire_write(pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG,
- (EVENT_QUEUE_BASE_ADDR_ALL_ONES |
- __pa(pbm->msi_queues)));
+ 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 + IMONDO_DATA0,
- pbm->portid << 6);
- fire_write(pbm->pbm_regs + IMONDO_DATA1, 0);
+ upa_writeq(pbm->portid << 6, pbm->pbm_regs + IMONDO_DATA0);
+ upa_writeq(0, pbm->pbm_regs + IMONDO_DATA1);
- fire_write(pbm->pbm_regs + MSI_32BIT_ADDR,
- pbm->msi32_start);
- fire_write(pbm->pbm_regs + MSI_64BIT_ADDR,
- pbm->msi64_start);
+ upa_writeq(pbm->msi32_start, pbm->pbm_regs + MSI_32BIT_ADDR);
+ upa_writeq(pbm->msi64_start, pbm->pbm_regs + MSI_64BIT_ADDR);
for (i = 0; i < pbm->msiq_num; i++) {
- fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(i), 0);
- fire_write(pbm->pbm_regs + EVENT_QUEUE_TAIL(i), 0);
+ upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_HEAD(i));
+ upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_TAIL(i));
}
return 0;
@@ -310,9 +287,9 @@
/* XXX iterate amongst the 4 IRQ controllers XXX */
int_ctrlr = (1UL << 6);
- val = fire_read(imap_reg);
+ val = upa_readq(imap_reg);
val |= (1UL << 63) | int_ctrlr;
- fire_write(imap_reg, val);
+ upa_writeq(val, imap_reg);
fixup = ((pbm->portid << 6) | devino) - int_ctrlr;
@@ -320,9 +297,8 @@
if (!virt_irq)
return -ENOMEM;
- fire_write(pbm->pbm_regs +
- EVENT_QUEUE_CONTROL_SET(msiqid),
- EVENT_QUEUE_CONTROL_SET_EN);
+ upa_writeq(EVENT_QUEUE_CONTROL_SET_EN,
+ pbm->pbm_regs + EVENT_QUEUE_CONTROL_SET(msiqid));
return virt_irq;
}
@@ -390,77 +366,65 @@
{
u64 val;
- fire_write(pbm->controller_regs + FIRE_PARITY_CONTROL,
- FIRE_PARITY_ENAB);
+ upa_writeq(FIRE_PARITY_ENAB,
+ pbm->controller_regs + FIRE_PARITY_CONTROL);
- fire_write(pbm->controller_regs + FIRE_FATAL_RESET_CTL,
- (FIRE_FATAL_RESET_SPARE |
+ upa_writeq((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));
+ FIRE_FATAL_RESET_JR),
+ pbm->controller_regs + FIRE_FATAL_RESET_CTL);
- fire_write(pbm->controller_regs + FIRE_CORE_INTR_ENABLE, ~(u64)0);
+ upa_writeq(~(u64)0, pbm->controller_regs + FIRE_CORE_INTR_ENABLE);
- val = fire_read(pbm->pbm_regs + FIRE_TLU_CTRL);
+ val = upa_readq(pbm->pbm_regs + FIRE_TLU_CTRL);
val |= (FIRE_TLU_CTRL_TIM |
FIRE_TLU_CTRL_QDET |
FIRE_TLU_CTRL_CFG);
- 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);
+ 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);
- 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);
+ 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);
- 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);
+ 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);
- fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0);
+ upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_PEC_IENAB);
}
-static int __init pci_fire_pbm_init(struct pci_controller_info *p,
- struct device_node *dp, u32 portid)
+static int __init pci_fire_pbm_init(struct pci_pbm_info *pbm,
+ struct of_device *op, u32 portid)
{
const struct linux_prom64_registers *regs;
- struct pci_pbm_info *pbm;
+ struct device_node *dp = op->node;
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->parent = p;
- pbm->prom_node = dp;
+ pbm->op = op;
pbm->name = dp->full_name;
regs = of_get_property(dp, "reg", NULL);
@@ -481,53 +445,77 @@
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)
+static int __devinit fire_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- if (x == (y ^ 1))
- return 1;
- return 0;
-}
-
-void __init fire_pci_init(struct device_node *dp, const char *model_name)
-{
- struct pci_controller_info *p;
- u32 portid = of_getintprop_default(dp, "portid", 0xff);
- struct iommu *iommu;
+ struct device_node *dp = op->node;
struct pci_pbm_info *pbm;
+ struct iommu *iommu;
+ u32 portid;
+ int 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;
- }
+ portid = of_getintprop_default(dp, "portid", 0xff);
+
+ err = -ENOMEM;
+ pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+ if (!pbm) {
+ printk(KERN_ERR PFX "Cannot allocate pci_pbminfo.\n");
+ goto out_err;
}
- p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
- if (!p)
- goto fatal_memory_error;
+ iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+ if (!iommu) {
+ printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+ goto out_free_controller;
+ }
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ pbm->iommu = iommu;
- p->pbm_A.iommu = iommu;
+ err = pci_fire_pbm_init(pbm, op, portid);
+ if (err)
+ goto out_free_iommu;
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ dev_set_drvdata(&op->dev, pbm);
- p->pbm_B.iommu = iommu;
+ return 0;
- if (pci_fire_pbm_init(p, dp, portid))
- goto fatal_memory_error;
+out_free_iommu:
+ kfree(pbm->iommu);
+
+out_free_controller:
+ kfree(pbm);
- return;
-
-fatal_memory_error:
- prom_printf("PCI_FIRE: Fatal memory allocation error.\n");
- prom_halt();
+out_err:
+ return err;
}
+
+static struct of_device_id __initdata fire_match[] = {
+ {
+ .name = "pci",
+ .compatible = "pciex108e,80f0",
+ },
+ {},
+};
+
+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);
+}
+
+subsys_initcall(fire_init);
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index c385d12..0318682 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -10,6 +10,7 @@
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <linux/msi.h>
+#include <linux/of_device.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/iommu.h>
@@ -56,15 +57,11 @@
};
#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;
@@ -94,7 +91,7 @@
char *name;
/* OBP specific information. */
- struct device_node *prom_node;
+ struct of_device *op;
u64 ino_bitmap;
/* PBM I/O and Memory space resources. */
@@ -107,6 +104,10 @@
/* 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;
@@ -146,25 +147,19 @@
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);
+extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
+ struct device *parent);
extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
/* Error reporting support. */
@@ -183,4 +178,8 @@
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/arch/sparc64/kernel/pci_msi.c b/arch/sparc64/kernel/pci_msi.c
index 60c71e3..2e680f3 100644
--- a/arch/sparc64/kernel/pci_msi.c
+++ b/arch/sparc64/kernel/pci_msi.c
@@ -323,7 +323,7 @@
const u32 *val;
int len;
- val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
+ val = of_get_property(pbm->op->node, "#msi-eqs", &len);
if (!val || len != 4)
goto no_msi;
pbm->msiq_num = *val;
@@ -346,16 +346,16 @@
u32 msi64_len;
} *arng;
- val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
+ val = of_get_property(pbm->op->node, "msi-eq-size", &len);
if (!val || len != 4)
goto no_msi;
pbm->msiq_ent_count = *val;
- mqp = of_get_property(pbm->prom_node,
+ mqp = of_get_property(pbm->op->node,
"msi-eq-to-devino", &len);
if (!mqp)
- mqp = of_get_property(pbm->prom_node,
+ mqp = of_get_property(pbm->op->node,
"msi-eq-devino", &len);
if (!mqp || len != sizeof(struct msiq_prop))
goto no_msi;
@@ -363,27 +363,27 @@
pbm->msiq_first = mqp->first_msiq;
pbm->msiq_first_devino = mqp->first_devino;
- val = of_get_property(pbm->prom_node, "#msi", &len);
+ val = of_get_property(pbm->op->node, "#msi", &len);
if (!val || len != 4)
goto no_msi;
pbm->msi_num = *val;
- mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
+ mrng = of_get_property(pbm->op->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->prom_node, "msi-data-mask", &len);
+ val = of_get_property(pbm->op->node, "msi-data-mask", &len);
if (!val || len != 4)
goto no_msi;
pbm->msi_data_mask = *val;
- val = of_get_property(pbm->prom_node, "msix-data-width", &len);
+ val = of_get_property(pbm->op->node, "msix-data-width", &len);
if (!val || len != 4)
goto no_msi;
pbm->msix_data_width = *val;
- arng = of_get_property(pbm->prom_node, "msi-address-ranges",
+ arng = of_get_property(pbm->op->node, "msi-address-ranges",
&len);
if (!arng || len != sizeof(struct addr_range_prop))
goto no_msi;
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index f85b6be..dfb3ec8 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -17,29 +17,14 @@
#include <asm/irq.h>
#include <asm/starfire.h>
#include <asm/prom.h>
-#include <asm/oplib.h>
+#include <asm/upa.h>
#include "pci_impl.h"
#include "iommu_common.h"
+#include "psycho_common.h"
-/* 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")
+#define DRIVER_NAME "psycho"
+#define PFX DRIVER_NAME ": "
/* Misc. PSYCHO PCI controller register offsets and definitions. */
#define PSYCHO_CONTROL 0x0010UL
@@ -67,37 +52,7 @@
#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
@@ -122,129 +77,10 @@
#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.
@@ -271,122 +107,7 @@
#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
@@ -410,15 +131,14 @@
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 = psycho_read(afar_reg);
- afsr = psycho_read(afsr_reg);
+ afar = upa_readq(afar_reg);
+ afsr = upa_readq(afsr_reg);
/* Clear the primary/secondary error status bits. */
error_bits = afsr &
@@ -426,7 +146,7 @@
PSYCHO_UEAFSR_SPIO | PSYCHO_UEAFSR_SDRD | PSYCHO_UEAFSR_SDWR);
if (!error_bits)
return IRQ_NONE;
- psycho_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: Uncorrectable Error, primary error type[%s]\n",
@@ -463,8 +183,9 @@
printk("]\n");
/* Interrogate both IOMMUs for error status. */
- psycho_check_iommu_error(&p->pbm_A, afsr, afar, UE_ERR);
- psycho_check_iommu_error(&p->pbm_B, afsr, afar, UE_ERR);
+ psycho_check_iommu_error(pbm, afsr, afar, UE_ERR);
+ if (pbm->sibling)
+ psycho_check_iommu_error(pbm->sibling, afsr, afar, UE_ERR);
return IRQ_HANDLED;
}
@@ -495,8 +216,8 @@
int reported;
/* Latch error status. */
- afar = psycho_read(afar_reg);
- afsr = psycho_read(afsr_reg);
+ afar = upa_readq(afar_reg);
+ afsr = upa_readq(afsr_reg);
/* Clear primary/secondary error status bits. */
error_bits = afsr &
@@ -504,7 +225,7 @@
PSYCHO_CEAFSR_SPIO | PSYCHO_CEAFSR_SDRD | PSYCHO_CEAFSR_SDWR);
if (!error_bits)
return IRQ_NONE;
- psycho_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: Correctable Error, primary error type[%s]\n",
@@ -554,164 +275,9 @@
*/
#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 */
@@ -719,7 +285,7 @@
#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->prom_node);
+ struct of_device *op = of_find_device_by_node(pbm->op->node);
unsigned long base = pbm->controller_regs;
u64 tmp;
int err;
@@ -762,27 +328,26 @@
"err=%d\n", pbm->name, err);
/* Enable UE and CE interrupts for controller. */
- psycho_write(base + PSYCHO_ECC_CTRL,
- (PSYCHO_ECCCTRL_EE |
- PSYCHO_ECCCTRL_UE |
- PSYCHO_ECCCTRL_CE));
+ upa_writeq((PSYCHO_ECCCTRL_EE |
+ PSYCHO_ECCCTRL_UE |
+ PSYCHO_ECCCTRL_CE), base + PSYCHO_ECC_CTRL);
/* Enable PCI Error interrupts and clear error
* bits for each PBM.
*/
- tmp = psycho_read(base + PSYCHO_PCIA_CTRL);
+ tmp = upa_readq(base + PSYCHO_PCIA_CTRL);
tmp |= (PSYCHO_PCICTRL_SERR |
PSYCHO_PCICTRL_SBH_ERR |
PSYCHO_PCICTRL_EEN);
tmp &= ~(PSYCHO_PCICTRL_SBH_INT);
- psycho_write(base + PSYCHO_PCIA_CTRL, tmp);
+ upa_writeq(tmp, base + PSYCHO_PCIA_CTRL);
- tmp = psycho_read(base + PSYCHO_PCIB_CTRL);
+ tmp = upa_readq(base + PSYCHO_PCIB_CTRL);
tmp |= (PSYCHO_PCICTRL_SERR |
PSYCHO_PCICTRL_SBH_ERR |
PSYCHO_PCICTRL_EEN);
tmp &= ~(PSYCHO_PCICTRL_SBH_INT);
- psycho_write(base + PSYCHO_PCIB_CTRL, tmp);
+ upa_writeq(tmp, base + PSYCHO_PCIB_CTRL);
}
/* PSYCHO boot time probing and initialization. */
@@ -803,11 +368,12 @@
pci_config_write8(addr, 64);
}
-static void __init psycho_scan_bus(struct pci_pbm_info *pbm)
+static void __init psycho_scan_bus(struct pci_pbm_info *pbm,
+ struct device *parent)
{
pbm_config_busmastering(pbm);
pbm->is_66mhz_capable = 0;
- pbm->pci_bus = pci_scan_one_pbm(pbm);
+ pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
/* After the PCI bus scan is complete, we can register
* the error interrupt handlers.
@@ -815,61 +381,6 @@
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
@@ -886,28 +397,28 @@
{
u64 tmp;
- psycho_write(pbm->controller_regs + PSYCHO_IRQ_RETRY, 5);
+ upa_writeq(5, pbm->controller_regs + PSYCHO_IRQ_RETRY);
/* Enable arbiter for all PCI slots. */
- tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_CTRL);
+ tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_CTRL);
tmp |= PSYCHO_PCICTRL_AEN;
- psycho_write(pbm->controller_regs + PSYCHO_PCIA_CTRL, tmp);
+ upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_CTRL);
- tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_CTRL);
+ tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_CTRL);
tmp |= PSYCHO_PCICTRL_AEN;
- psycho_write(pbm->controller_regs + PSYCHO_PCIB_CTRL, tmp);
+ upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_CTRL);
/* Disable DMA write / PIO read synchronization on
* both PCI bus segments.
* [ U2P Erratum 1243770, STP2223BGA data sheet ]
*/
- tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_DIAG);
+ tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_DIAG);
tmp |= PSYCHO_PCIDIAG_DDWSYNC;
- psycho_write(pbm->controller_regs + PSYCHO_PCIA_DIAG, tmp);
+ upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_DIAG);
- tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_DIAG);
+ tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_DIAG);
tmp |= PSYCHO_PCIDIAG_DDWSYNC;
- psycho_write(pbm->controller_regs + PSYCHO_PCIB_DIAG, tmp);
+ upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_DIAG);
}
static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
@@ -920,10 +431,16 @@
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;
@@ -946,7 +463,7 @@
*/
#undef PSYCHO_STRBUF_RERUN_ENABLE
#undef PSYCHO_STRBUF_RERUN_DISABLE
- control = psycho_read(pbm->stc.strbuf_control);
+ control = upa_readq(pbm->stc.strbuf_control);
control |= PSYCHO_STRBUF_CTRL_ENAB;
control &= ~(PSYCHO_STRBUF_CTRL_LENAB | PSYCHO_STRBUF_CTRL_LPTR);
#ifdef PSYCHO_STRBUF_RERUN_ENABLE
@@ -956,7 +473,7 @@
control |= PSYCHO_STRBUF_CTRL_RRDIS;
#endif
#endif
- psycho_write(pbm->stc.strbuf_control, control);
+ upa_writeq(control, pbm->stc.strbuf_control);
pbm->stc.strbuf_enabled = 1;
}
@@ -968,111 +485,134 @@
#define PSYCHO_MEMSPACE_B 0x180000000UL
#define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL
-static void __init psycho_pbm_init(struct pci_controller_info *p,
- struct device_node *dp, int is_pbm_a)
+static void __init psycho_pbm_init(struct pci_pbm_info *pbm,
+ struct of_device *op, int is_pbm_a)
{
- struct property *prop;
+ 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)
+{
struct pci_pbm_info *pbm;
- 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 = psycho_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_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->parent = p;
- pbm->prom_node = dp;
- pbm->name = dp->full_name;
-
- printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n",
- pbm->name,
- pbm->chip_version, pbm->chip_revision);
-
- pci_determine_mem_io_space(pbm);
-
- pci_get_pbm_props(pbm);
-
- psycho_pbm_strbuf_init(pbm, is_pbm_a);
+ for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+ if (pbm->portid == upa_portid)
+ return pbm;
+ }
+ return NULL;
}
#define PSYCHO_CONFIGSPACE 0x001000000UL
-void __init psycho_init(struct device_node *dp, char *model_name)
+static int __devinit psycho_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct linux_prom64_registers *pr_regs;
- struct pci_controller_info *p;
+ const struct linux_prom64_registers *pr_regs;
+ struct device_node *dp = op->node;
struct pci_pbm_info *pbm;
struct iommu *iommu;
- struct property *prop;
+ int is_pbm_a, err;
u32 upa_portid;
- int is_pbm_a;
- upa_portid = 0xff;
- prop = of_find_property(dp, "upa-portid", NULL);
- if (prop)
- upa_portid = *(u32 *) prop->value;
+ upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
- for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
- struct pci_controller_info *p = pbm->parent;
+ err = -ENOMEM;
+ pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+ if (!pbm) {
+ printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+ goto out_err;
+ }
- 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;
+ 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;
}
}
- 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;
+ pbm->iommu = iommu;
+ pbm->portid = upa_portid;
- p->pbm_A.iommu = p->pbm_B.iommu = iommu;
-
- p->pbm_A.portid = upa_portid;
- p->pbm_B.portid = upa_portid;
-
- prop = of_find_property(dp, "reg", NULL);
- pr_regs = prop->value;
-
- p->pbm_A.controller_regs = pr_regs[2].phys_addr;
- p->pbm_B.controller_regs = pr_regs[2].phys_addr;
-
- p->pbm_A.config_space = p->pbm_B.config_space =
- (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
-
- psycho_controller_hwinit(&p->pbm_A);
-
- if (psycho_iommu_init(&p->pbm_A))
- goto fatal_memory_error;
+ 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;
+ }
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
- psycho_pbm_init(p, dp, is_pbm_a);
- return;
-fatal_memory_error:
- prom_printf("PSYCHO: Fatal memory allocation error.\n");
- prom_halt();
+ pbm->controller_regs = pr_regs[2].phys_addr;
+ pbm->config_space = (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
+
+ 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_controller_hwinit(pbm);
+ if (!pbm->sibling) {
+ err = psycho_iommu_init(pbm, 128, 0xc0000000,
+ 0xffffffff, PSYCHO_CONTROL);
+ if (err)
+ goto out_free_iommu;
+
+ /* If necessary, hook us up for starfire IRQ translations. */
+ if (this_is_starfire)
+ starfire_hookup(pbm->portid);
+ }
+
+ psycho_pbm_init(pbm, op, is_pbm_a);
+
+ pbm->next = pci_pbm_root;
+ pci_pbm_root = pbm;
+
+ if (pbm->sibling)
+ pbm->sibling->sibling = pbm;
+
+ dev_set_drvdata(&op->dev, pbm);
+
+ return 0;
+
+out_free_iommu:
+ if (!pbm->sibling)
+ kfree(pbm->iommu);
+
+out_free_controller:
+ kfree(pbm);
+
+out_err:
+ return err;
}
+
+static struct of_device_id __initdata psycho_match[] = {
+ {
+ .name = "pci",
+ .compatible = "pci108e,8000",
+ },
+ {},
+};
+
+static struct of_platform_driver psycho_driver = {
+ .name = DRIVER_NAME,
+ .match_table = psycho_match,
+ .probe = psycho_probe,
+};
+
+static int __init psycho_init(void)
+{
+ return of_register_driver(&psycho_driver, &of_bus_type);
+}
+
+subsys_initcall(psycho_init);
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index ade5184..713257b 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -16,31 +16,15 @@
#include <asm/apb.h>
#include <asm/iommu.h>
#include <asm/irq.h>
-#include <asm/smp.h>
-#include <asm/oplib.h>
#include <asm/prom.h>
+#include <asm/upa.h>
#include "pci_impl.h"
#include "iommu_common.h"
+#include "psycho_common.h"
-/* 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")
+#define DRIVER_NAME "sabre"
+#define PFX DRIVER_NAME ": "
/* SABRE PCI controller register offsets and definitions. */
#define SABRE_UE_AFSR 0x0030UL
@@ -208,95 +192,6 @@
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;
@@ -306,8 +201,8 @@
int reported;
/* Latch uncorrectable error status. */
- afar = sabre_read(afar_reg);
- afsr = sabre_read(afsr_reg);
+ afar = upa_readq(afar_reg);
+ afsr = upa_readq(afsr_reg);
/* Clear the primary/secondary error status bits. */
error_bits = afsr &
@@ -316,7 +211,7 @@
SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE);
if (!error_bits)
return IRQ_NONE;
- sabre_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: Uncorrectable Error, primary error type[%s%s]\n",
@@ -352,7 +247,7 @@
printk("]\n");
/* Interrogate IOMMU for error status. */
- sabre_check_iommu_error(pbm, afsr, afar);
+ psycho_check_iommu_error(pbm, afsr, afar, UE_ERR);
return IRQ_HANDLED;
}
@@ -366,8 +261,8 @@
int reported;
/* Latch error status. */
- afar = sabre_read(afar_reg);
- afsr = sabre_read(afsr_reg);
+ afar = upa_readq(afar_reg);
+ afsr = upa_readq(afsr_reg);
/* Clear primary/secondary error status bits. */
error_bits = afsr &
@@ -375,7 +270,7 @@
SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR);
if (!error_bits)
return IRQ_NONE;
- sabre_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: Correctable Error, primary error type[%s]\n",
@@ -413,136 +308,9 @@
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->prom_node;
+ struct device_node *dp = pbm->op->node;
struct of_device *op;
unsigned long base = pbm->controller_regs;
u64 tmp;
@@ -568,33 +336,34 @@
* registering the handler so that we don't get spurious
* interrupts.
*/
- sabre_write(base + SABRE_UE_AFSR,
- (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
- SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
- SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE));
+ upa_writeq((SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
+ SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
+ SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE),
+ base + SABRE_UE_AFSR);
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);
- sabre_write(base + SABRE_CE_AFSR,
- (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
- SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR));
+ upa_writeq((SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
+ SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR),
+ base + SABRE_CE_AFSR);
+
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], sabre_pcierr_intr, 0,
+ err = request_irq(op->irqs[0], psycho_pcierr_intr, 0,
"SABRE_PCIERR", pbm);
if (err)
printk(KERN_WARNING "%s: Couldn't register PCIERR, err=%d.\n",
pbm->name, err);
- tmp = sabre_read(base + SABRE_PCICTRL);
+ tmp = upa_readq(base + SABRE_PCICTRL);
tmp |= SABRE_PCICTRL_ERREN;
- sabre_write(base + SABRE_PCICTRL, tmp);
+ upa_writeq(tmp, base + SABRE_PCICTRL);
}
static void apb_init(struct pci_bus *sabre_bus)
@@ -633,7 +402,8 @@
}
}
-static void __init sabre_scan_bus(struct pci_pbm_info *pbm)
+static void __init sabre_scan_bus(struct pci_pbm_info *pbm,
+ struct device *parent)
{
static int once;
@@ -656,12 +426,12 @@
* to live at bus 0.
*/
if (once != 0) {
- prom_printf("SABRE: Multiple controllers unsupported.\n");
- prom_halt();
+ printk(KERN_ERR PFX "Multiple controllers unsupported.\n");
+ return;
}
once++;
- pbm->pci_bus = pci_scan_one_pbm(pbm);
+ pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
if (!pbm->pci_bus)
return;
@@ -672,133 +442,58 @@
sabre_register_error_handlers(pbm);
}
-static int sabre_iommu_init(struct pci_pbm_info *pbm,
- int tsbsize, unsigned long dvma_offset,
- u32 dma_mask)
+static void __init sabre_pbm_init(struct pci_pbm_info *pbm,
+ struct of_device *op)
{
- 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;
+ 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);
}
-static void __init sabre_pbm_init(struct pci_controller_info *p,
- struct pci_pbm_info *pbm, struct device_node *dp)
-{
- 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);
-}
-
-void __init sabre_init(struct device_node *dp, char *model_name)
+static int __devinit sabre_probe(struct of_device *op,
+ const struct of_device_id *match)
{
const struct linux_prom64_registers *pr_regs;
- struct pci_controller_info *p;
+ struct device_node *dp = op->node;
struct pci_pbm_info *pbm;
- struct iommu *iommu;
- int tsbsize;
- const u32 *vdma;
u32 upa_portid, dma_mask;
+ struct iommu *iommu;
+ int tsbsize, err;
+ const u32 *vdma;
u64 clear_irq;
- 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;
+ 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(dp, "cpu") {
- if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe"))
- hummingbird_p = 1;
- }
+ /* 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;
}
}
- p = kzalloc(sizeof(*p), GFP_ATOMIC);
- if (!p)
- goto fatal_memory_error;
+ 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_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
- pbm = &p->pbm_A;
+ iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+ if (!iommu) {
+ printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+ goto out_free_controller;
+ }
+
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;
/*
@@ -806,6 +501,11 @@
*/
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.
@@ -816,22 +516,25 @@
/* PCI first */
for (clear_irq = SABRE_ICLR_A_SLOT0; clear_irq < SABRE_ICLR_B_SLOT0 + 0x80; clear_irq += 8)
- sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
+ upa_writeq(0x0UL, pbm->controller_regs + clear_irq);
/* Then OBIO */
for (clear_irq = SABRE_ICLR_SCSI; clear_irq < SABRE_ICLR_SCSI + 0x80; clear_irq += 8)
- sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
+ upa_writeq(0x0UL, pbm->controller_regs + clear_irq);
/* Error interrupts are enabled later after the bus scan. */
- sabre_write(pbm->controller_regs + SABRE_PCICTRL,
- (SABRE_PCICTRL_MRLEN | SABRE_PCICTRL_SERR |
- SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
+ upa_writeq((SABRE_PCICTRL_MRLEN | SABRE_PCICTRL_SERR |
+ SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN),
+ pbm->controller_regs + SABRE_PCICTRL);
/* 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]) {
@@ -849,20 +552,58 @@
tsbsize = 128;
break;
default:
- prom_printf("SABRE: strange virtual-dma size.\n");
- prom_halt();
+ printk(KERN_ERR PFX "Strange virtual-dma size.\n");
+ goto out_free_iommu;
}
- if (sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask))
- goto fatal_memory_error;
+ err = psycho_iommu_init(pbm, tsbsize, vdma[0], dma_mask, SABRE_WRSYNC);
+ if (err)
+ goto out_free_iommu;
/*
* Look for APB underneath.
*/
- sabre_pbm_init(p, pbm, dp);
- return;
+ sabre_pbm_init(pbm, op);
-fatal_memory_error:
- prom_printf("SABRE: Fatal memory allocation error.\n");
- prom_halt();
+ 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);
+}
+
+subsys_initcall(sabre_init);
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 9248c67..45d9dba 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/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 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2001, 2002, 2003, 2007, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@@ -13,32 +13,15 @@
#include <asm/iommu.h>
#include <asm/irq.h>
-#include <asm/upa.h>
#include <asm/pstate.h>
#include <asm/prom.h>
-#include <asm/oplib.h>
+#include <asm/upa.h>
#include "pci_impl.h"
#include "iommu_common.h"
-/* 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")
+#define DRIVER_NAME "schizo"
+#define PFX DRIVER_NAME ": "
/* This is a convention that at least Excalibur and Merlin
* follow. I suppose the SCHIZO used in Starcat and friends
@@ -163,25 +146,25 @@
* invalidating it before it has a chance to reach
* main memory.
*/
- control = schizo_read(strbuf->strbuf_control);
- schizo_write(strbuf->strbuf_control,
- (control | SCHIZO_STRBUF_CTRL_DENAB));
+ control = upa_readq(strbuf->strbuf_control);
+ upa_writeq((control | SCHIZO_STRBUF_CTRL_DENAB),
+ strbuf->strbuf_control);
for (i = 0; i < 128; i++) {
unsigned long val;
- val = schizo_read(err_base + (i * 8UL));
- schizo_write(err_base + (i * 8UL), 0UL);
+ 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] = 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);
+ 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. */
- schizo_write(strbuf->strbuf_control, control);
+ upa_writeq(control, strbuf->strbuf_control);
for (i = 0; i < 16; i++) {
int j, saw_error, first, last;
@@ -258,14 +241,14 @@
int i;
spin_lock_irqsave(&iommu->lock, flags);
- control = schizo_read(iommu->iommu_control);
+ control = upa_readq(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;
- schizo_write(iommu->iommu_control, control);
+ upa_writeq(control, iommu->iommu_control);
switch((control & SCHIZO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
case 0:
@@ -295,24 +278,24 @@
* get as much diagnostic information to the
* console as we can.
*/
- schizo_write(iommu->iommu_control,
- control | SCHIZO_IOMMU_CTRL_DENAB);
+ upa_writeq(control | SCHIZO_IOMMU_CTRL_DENAB,
+ iommu->iommu_control);
base = pbm->pbm_regs;
for (i = 0; i < 16; i++) {
iommu_tag[i] =
- schizo_read(base + SCHIZO_IOMMU_TAG + (i * 8UL));
+ upa_readq(base + SCHIZO_IOMMU_TAG + (i * 8UL));
iommu_data[i] =
- schizo_read(base + SCHIZO_IOMMU_DATA + (i * 8UL));
+ upa_readq(base + SCHIZO_IOMMU_DATA + (i * 8UL));
/* Now clear out the entry. */
- schizo_write(base + SCHIZO_IOMMU_TAG + (i * 8UL), 0);
- schizo_write(base + SCHIZO_IOMMU_DATA + (i * 8UL), 0);
+ upa_writeq(0, base + SCHIZO_IOMMU_TAG + (i * 8UL));
+ upa_writeq(0, base + SCHIZO_IOMMU_DATA + (i * 8UL));
}
/* Leave diagnostic mode. */
- schizo_write(iommu->iommu_control, control);
+ upa_writeq(control, iommu->iommu_control);
for (i = 0; i < 16; i++) {
unsigned long tag, data;
@@ -357,11 +340,12 @@
spin_unlock_irqrestore(&iommu->lock, flags);
}
-static void schizo_check_iommu_error(struct pci_controller_info *p,
+static void schizo_check_iommu_error(struct pci_pbm_info *pbm,
enum schizo_error_type type)
{
- schizo_check_iommu_error_pbm(&p->pbm_A, type);
- schizo_check_iommu_error_pbm(&p->pbm_B, type);
+ schizo_check_iommu_error_pbm(pbm, type);
+ if (pbm->sibling)
+ schizo_check_iommu_error_pbm(pbm->sibling, type);
}
/* Uncorrectable ECC error status gathering. */
@@ -386,14 +370,13 @@
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 = schizo_read(afar_reg);
+ afar = upa_readq(afar_reg);
/* If either of the error pending bits are set in the
* AFSR, the error status is being actively updated by
@@ -401,7 +384,7 @@
*/
limit = 1000;
do {
- afsr = schizo_read(afsr_reg);
+ afsr = upa_readq(afsr_reg);
} while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
/* Clear the primary/secondary error status bits. */
@@ -410,7 +393,7 @@
SCHIZO_UEAFSR_SPIO | SCHIZO_UEAFSR_SDMA);
if (!error_bits)
return IRQ_NONE;
- schizo_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: Uncorrectable Error, primary error type[%s]\n",
@@ -449,7 +432,7 @@
printk("]\n");
/* Interrogate IOMMU for error status. */
- schizo_check_iommu_error(p, UE_ERR);
+ schizo_check_iommu_error(pbm, UE_ERR);
return IRQ_HANDLED;
}
@@ -481,7 +464,7 @@
int reported, limit;
/* Latch error status. */
- afar = schizo_read(afar_reg);
+ afar = upa_readq(afar_reg);
/* If either of the error pending bits are set in the
* AFSR, the error status is being actively updated by
@@ -489,7 +472,7 @@
*/
limit = 1000;
do {
- afsr = schizo_read(afsr_reg);
+ afsr = upa_readq(afsr_reg);
} while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
/* Clear primary/secondary error status bits. */
@@ -498,7 +481,7 @@
SCHIZO_CEAFSR_SPIO | SCHIZO_CEAFSR_SDMA);
if (!error_bits)
return IRQ_NONE;
- schizo_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: Correctable Error, primary error type[%s]\n",
@@ -600,7 +583,7 @@
u16 stat;
csr_reg = pbm->pbm_regs + SCHIZO_PCI_CTRL;
- csr = schizo_read(csr_reg);
+ csr = upa_readq(csr_reg);
csr_error_bits =
csr & (SCHIZO_PCICTRL_BUS_UNUS |
SCHIZO_PCICTRL_TTO_ERR |
@@ -610,7 +593,7 @@
SCHIZO_PCICTRL_SERR);
if (csr_error_bits) {
/* Clear the errors. */
- schizo_write(csr_reg, csr);
+ upa_writeq(csr, csr_reg);
/* Log 'em. */
if (csr_error_bits & SCHIZO_PCICTRL_BUS_UNUS)
@@ -650,7 +633,6 @@
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;
@@ -661,8 +643,8 @@
afar_reg = base + SCHIZO_PCI_AFAR;
/* Latch error status. */
- afar = schizo_read(afar_reg);
- afsr = schizo_read(afsr_reg);
+ afar = upa_readq(afar_reg);
+ afsr = upa_readq(afsr_reg);
/* Clear primary/secondary error status bits. */
error_bits = afsr &
@@ -674,7 +656,7 @@
SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS);
if (!error_bits)
return schizo_pcierr_intr_other(pbm);
- schizo_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: PCI Error, primary error type[%s]\n",
@@ -744,7 +726,7 @@
* 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(p, PCI_ERR);
+ schizo_check_iommu_error(pbm, PCI_ERR);
pci_scan_for_target_abort(pbm, pbm->pci_bus);
}
if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
@@ -805,12 +787,11 @@
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 = schizo_read(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
- schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG,
- errlog & ~(SAFARI_ERRLOG_ERROUT));
+ errlog = upa_readq(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
+ upa_writeq(errlog & ~(SAFARI_ERRLOG_ERROUT),
+ pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
if (!(errlog & BUS_ERROR_UNMAP)) {
printk("%s: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
@@ -821,7 +802,7 @@
printk("%s: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
pbm->name);
- schizo_check_iommu_error(p, SAFARI_ERR);
+ schizo_check_iommu_error(pbm, SAFARI_ERR);
return IRQ_HANDLED;
}
@@ -863,7 +844,7 @@
*/
static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct of_device *op = of_find_device_by_node(pbm->prom_node);
+ struct of_device *op = of_find_device_by_node(pbm->op->node);
u64 tmp, err_mask, err_no_mask;
int err;
@@ -910,10 +891,9 @@
}
/* Enable UE and CE interrupts for controller. */
- schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
- (SCHIZO_ECCCTRL_EE |
- SCHIZO_ECCCTRL_UE |
- SCHIZO_ECCCTRL_CE));
+ upa_writeq((SCHIZO_ECCCTRL_EE |
+ SCHIZO_ECCCTRL_UE |
+ SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL);
/* Enable PCI Error interrupts and clear error
* bits.
@@ -926,10 +906,10 @@
err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
- tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+ tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
tmp |= err_mask;
tmp &= ~err_no_mask;
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+ upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
@@ -938,7 +918,7 @@
SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
SCHIZO_PCIAFSR_STTO);
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR, err_mask);
+ upa_writeq(err_mask, pbm->pbm_regs + SCHIZO_PCI_AFSR);
err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR |
BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD |
@@ -950,16 +930,16 @@
BUS_ERROR_APERR | BUS_ERROR_UNMAP |
BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT);
- schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
- (SCHIZO_SAFERRCTRL_EN | err_mask));
+ upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask),
+ pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL);
- schizo_write(pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL,
- (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
+ upa_writeq((SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)),
+ pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL);
}
static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct of_device *op = of_find_device_by_node(pbm->prom_node);
+ struct of_device *op = of_find_device_by_node(pbm->op->node);
u64 tmp, err_mask, err_no_mask;
int err;
@@ -1006,10 +986,9 @@
}
/* Enable UE and CE interrupts for controller. */
- schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
- (SCHIZO_ECCCTRL_EE |
- SCHIZO_ECCCTRL_UE |
- SCHIZO_ECCCTRL_CE));
+ upa_writeq((SCHIZO_ECCCTRL_EE |
+ SCHIZO_ECCCTRL_UE |
+ SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL);
err_mask = (SCHIZO_PCICTRL_BUS_UNUS |
SCHIZO_PCICTRL_ESLCK |
@@ -1025,18 +1004,18 @@
/* Enable PCI Error interrupts and clear error
* bits for each PBM.
*/
- tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+ tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
tmp |= err_mask;
tmp &= ~err_no_mask;
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+ upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
- 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));
+ 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);
/* Make all Safari error conditions fatal except unmapped
* errors which we make generate interrupts.
@@ -1063,8 +1042,8 @@
BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB);
#endif
- schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
- (SCHIZO_SAFERRCTRL_EN | err_mask));
+ upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask),
+ pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL);
}
static void pbm_config_busmastering(struct pci_pbm_info *pbm)
@@ -1084,14 +1063,15 @@
pci_config_write8(addr, 64);
}
-static void __init schizo_scan_bus(struct pci_pbm_info *pbm)
+static void __devinit schizo_scan_bus(struct pci_pbm_info *pbm,
+ struct device *parent)
{
pbm_config_busmastering(pbm);
pbm->is_66mhz_capable =
- (of_find_property(pbm->prom_node, "66mhz-capable", NULL)
+ (of_find_property(pbm->op->node, "66mhz-capable", NULL)
!= NULL);
- pbm->pci_bus = pci_scan_one_pbm(pbm);
+ pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
tomatillo_register_error_handlers(pbm);
@@ -1133,12 +1113,12 @@
* streaming buffer and leave the rerun-disable
* setting however OBP set it.
*/
- control = schizo_read(pbm->stc.strbuf_control);
+ control = upa_readq(pbm->stc.strbuf_control);
control &= ~(SCHIZO_STRBUF_CTRL_LPTR |
SCHIZO_STRBUF_CTRL_LENAB |
SCHIZO_STRBUF_CTRL_DENAB);
control |= SCHIZO_STRBUF_CTRL_ENAB;
- schizo_write(pbm->stc.strbuf_control, control);
+ upa_writeq(control, pbm->stc.strbuf_control);
pbm->stc.strbuf_enabled = 1;
}
@@ -1150,24 +1130,17 @@
static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
{
- struct iommu *iommu = pbm->iommu;
+ static const u32 vdma_default[] = { 0xc0000000, 0x40000000 };
unsigned long i, tagbase, database;
- struct property *prop;
- u32 vdma[2], dma_mask;
+ struct iommu *iommu = pbm->iommu;
int tsbsize, err;
+ const u32 *vdma;
+ u32 dma_mask;
u64 control;
- 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;
- }
+ vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+ if (!vdma)
+ vdma = vdma_default;
dma_mask = vdma[0];
switch (vdma[1]) {
@@ -1187,9 +1160,9 @@
break;
default:
- prom_printf("SCHIZO: strange virtual-dma size.\n");
- prom_halt();
- };
+ printk(KERN_ERR PFX "Strange virtual-dma size.\n");
+ return -EINVAL;
+ }
/* Register addresses, SCHIZO has iommu ctx flushing. */
iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
@@ -1206,15 +1179,15 @@
/*
* Invalidate TLB Entries.
*/
- control = schizo_read(iommu->iommu_control);
+ control = upa_readq(iommu->iommu_control);
control |= SCHIZO_IOMMU_CTRL_DENAB;
- schizo_write(iommu->iommu_control, control);
+ upa_writeq(control, iommu->iommu_control);
tagbase = SCHIZO_IOMMU_TAG, database = SCHIZO_IOMMU_DATA;
- for(i = 0; i < 16; i++) {
- schizo_write(pbm->pbm_regs + tagbase + (i * 8UL), 0);
- schizo_write(pbm->pbm_regs + database + (i * 8UL), 0);
+ for (i = 0; i < 16; i++) {
+ upa_writeq(0, pbm->pbm_regs + tagbase + (i * 8UL));
+ upa_writeq(0, pbm->pbm_regs + database + (i * 8UL));
}
/* Leave diag mode enabled for full-flushing done
@@ -1222,12 +1195,14 @@
*/
err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
pbm->numa_node);
- if (err)
+ if (err) {
+ printk(KERN_ERR PFX "iommu_table_init() fails with %d\n", err);
return err;
+ }
- schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table));
+ upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);
- control = schizo_read(iommu->iommu_control);
+ control = upa_readq(iommu->iommu_control);
control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ);
switch (tsbsize) {
case 64:
@@ -1236,10 +1211,10 @@
case 128:
control |= SCHIZO_IOMMU_TSBSZ_128K;
break;
- };
+ }
control |= SCHIZO_IOMMU_CTRL_ENAB;
- schizo_write(iommu->iommu_control, control);
+ upa_writeq(control, iommu->iommu_control);
return 0;
}
@@ -1280,12 +1255,11 @@
static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
{
- struct property *prop;
u64 tmp;
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5);
+ upa_writeq(5, pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY);
- tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+ tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
/* Enable arbiter for all PCI slots. */
tmp |= 0xff;
@@ -1294,8 +1268,7 @@
pbm->chip_version >= 0x2)
tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
- prop = of_find_property(pbm->prom_node, "no-bus-parking", NULL);
- if (!prop)
+ if (!of_find_property(pbm->op->node, "no-bus-parking", NULL))
tmp |= SCHIZO_PCICTRL_PARK;
else
tmp &= ~SCHIZO_PCICTRL_PARK;
@@ -1311,13 +1284,13 @@
SCHIZO_PCICTRL_RDO_PREF |
SCHIZO_PCICTRL_RDL_PREF);
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+ upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
- tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_DIAG);
+ tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_DIAG);
tmp &= ~(SCHIZO_PCIDIAG_D_RTRYARB |
SCHIZO_PCIDIAG_D_RETRY |
SCHIZO_PCIDIAG_D_INTSYNC);
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_DIAG, tmp);
+ upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_DIAG);
if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
/* Clear prefetch lengths to workaround a bug in
@@ -1329,17 +1302,16 @@
TOMATILLO_IOC_RDONE_CPENAB |
TOMATILLO_IOC_RDLINE_CPENAB);
- schizo_write(pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR,
- tmp);
+ upa_writeq(tmp, pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR);
}
}
-static int __init schizo_pbm_init(struct pci_controller_info *p,
- struct device_node *dp, u32 portid,
- int chip_type)
+static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm,
+ struct of_device *op, u32 portid,
+ int chip_type)
{
const struct linux_prom64_registers *regs;
- struct pci_pbm_info *pbm;
+ struct device_node *dp = op->node;
const char *chipset_name;
int is_pbm_a, err;
@@ -1372,25 +1344,19 @@
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->parent = p;
- pbm->prom_node = dp;
+ pbm->op = op;
pbm->chip_type = chip_type;
pbm->chip_version = of_getintprop_default(dp, "version#", 0);
@@ -1420,6 +1386,8 @@
schizo_pbm_strbuf_init(pbm);
+ schizo_scan_bus(pbm, &op->dev);
+
return 0;
}
@@ -1433,62 +1401,104 @@
return (x == y);
}
-static void __init __schizo_init(struct device_node *dp, char *model_name,
- int chip_type)
+static struct pci_pbm_info * __devinit schizo_find_sibling(u32 portid,
+ int chip_type)
{
- struct pci_controller_info *p;
+ 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_pbm_info *pbm;
struct iommu *iommu;
u32 portid;
+ int err;
portid = of_getintprop_default(dp, "portid", 0xff);
- 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;
- }
+ err = -ENOMEM;
+ pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+ if (!pbm) {
+ printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+ goto out_err;
}
- p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
- if (!p)
- goto fatal_memory_error;
+ pbm->sibling = schizo_find_sibling(portid, chip_type);
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+ if (!iommu) {
+ printk(KERN_ERR PFX "Cannot allocate PBM A iommu.\n");
+ goto out_free_pbm;
+ }
- p->pbm_A.iommu = iommu;
+ pbm->iommu = iommu;
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ if (schizo_pbm_init(pbm, op, portid, chip_type))
+ goto out_free_iommu;
- p->pbm_B.iommu = iommu;
+ if (pbm->sibling)
+ pbm->sibling->sibling = pbm;
- if (schizo_pbm_init(p, dp, portid, chip_type))
- goto fatal_memory_error;
+ dev_set_drvdata(&op->dev, pbm);
- return;
+ return 0;
-fatal_memory_error:
- prom_printf("SCHIZO: Fatal memory allocation error.\n");
- prom_halt();
+out_free_iommu:
+ kfree(pbm->iommu);
+
+out_free_pbm:
+ kfree(pbm);
+
+out_err:
+ return err;
}
-void __init schizo_init(struct device_node *dp, char *model_name)
+static int __devinit schizo_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO);
+ return __schizo_init(op, (unsigned long) match->data);
}
-void __init schizo_plus_init(struct device_node *dp, char *model_name)
+/* 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)
{
- __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
+ return of_register_driver(&schizo_driver, &of_bus_type);
}
-void __init tomatillo_init(struct device_node *dp, char *model_name)
-{
- __schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO);
-}
+subsys_initcall(schizo_init);
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index a104c80..e86c73e 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -13,12 +13,10 @@
#include <linux/irq.h>
#include <linux/msi.h>
#include <linux/log2.h>
+#include <linux/of_device.h>
#include <asm/iommu.h>
#include <asm/irq.h>
-#include <asm/upa.h>
-#include <asm/pstate.h>
-#include <asm/oplib.h>
#include <asm/hypervisor.h>
#include <asm/prom.h>
@@ -27,6 +25,9 @@
#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;
@@ -41,6 +42,7 @@
};
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)
@@ -542,15 +544,16 @@
.sync_sg_for_cpu = dma_4v_sync_sg_for_cpu,
};
-static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
+static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm,
+ struct device *parent)
{
struct property *prop;
struct device_node *dp;
- dp = pbm->prom_node;
+ dp = pbm->op->node;
prop = of_find_property(dp, "66mhz-capable", NULL);
pbm->is_66mhz_capable = (prop != NULL);
- pbm->pci_bus = pci_scan_one_pbm(pbm);
+ pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
/* XXX register error interrupt handlers XXX */
}
@@ -583,29 +586,22 @@
return cnt;
}
-static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
+static int __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 vdma[2], dma_mask, dma_offset;
+ u32 dma_mask, dma_offset;
+ const u32 *vdma;
- 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;
- }
+ vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+ if (!vdma)
+ vdma = vdma_default;
if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) {
- prom_printf("PCI-SUN4V: strange virtual-dma[%08x:%08x].\n",
- vdma[0], vdma[1]);
- prom_halt();
+ printk(KERN_ERR PFX "Strange virtual-dma[%08x:%08x].\n",
+ vdma[0], vdma[1]);
+ return -EINVAL;
};
dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL);
@@ -625,8 +621,8 @@
sz = (sz + 7UL) & ~7UL;
iommu->arena.map = kzalloc(sz, GFP_KERNEL);
if (!iommu->arena.map) {
- prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
- prom_halt();
+ printk(KERN_ERR PFX "Error, kmalloc(arena.map) failed.\n");
+ return -ENOMEM;
}
iommu->arena.limit = num_tsb_entries;
@@ -634,6 +630,8 @@
if (sz)
printk("%s: Imported %lu TSB entries from OBP\n",
pbm->name, sz);
+
+ return 0;
}
#ifdef CONFIG_PCI_MSI
@@ -890,29 +888,20 @@
}
#endif /* !(CONFIG_PCI_MSI) */
-static void __init pci_sun4v_pbm_init(struct pci_controller_info *p,
- struct device_node *dp, u32 devhandle)
+static int __init pci_sun4v_pbm_init(struct pci_pbm_info *pbm,
+ struct of_device *op, u32 devhandle)
{
- 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;
+ struct device_node *dp = op->node;
+ int err;
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->parent = p;
- pbm->prom_node = dp;
+ pbm->op = op;
pbm->devhandle = devhandle;
@@ -924,82 +913,120 @@
pci_determine_mem_io_space(pbm);
pci_get_pbm_props(pbm);
- pci_sun4v_iommu_init(pbm);
+
+ err = pci_sun4v_iommu_init(pbm);
+ if (err)
+ return err;
+
pci_sun4v_msi_init(pbm);
+
+ pci_sun4v_scan_bus(pbm, &op->dev);
+
+ pbm->next = pci_pbm_root;
+ pci_pbm_root = pbm;
+
+ return 0;
}
-void __init sun4v_pci_init(struct device_node *dp, char *model_name)
+static int __devinit pci_sun4v_probe(struct of_device *op,
+ const struct of_device_id *match)
{
+ 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;
+ int i, err;
+
+ dp = op->node;
if (!hvapi_negotiated++) {
- int err = sun4v_hvapi_register(HV_GRP_PCI,
- vpci_major,
- &vpci_minor);
+ err = sun4v_hvapi_register(HV_GRP_PCI,
+ vpci_major,
+ &vpci_minor);
if (err) {
- prom_printf("SUN4V_PCI: Could not register hvapi, "
- "err=%d\n", err);
- prom_halt();
+ printk(KERN_ERR PFX "Could not register hvapi, "
+ "err=%d\n", err);
+ return err;
}
- printk("SUN4V_PCI: Registered hvapi major[%lu] minor[%lu]\n",
+ printk(KERN_INFO PFX "Registered hvapi major[%lu] minor[%lu]\n",
vpci_major, vpci_minor);
dma_ops = &sun4v_dma_ops;
}
- prop = of_find_property(dp, "reg", NULL);
- if (!prop) {
- prom_printf("SUN4V_PCI: Could not find config registers\n");
- prom_halt();
+ regs = of_get_property(dp, "reg", NULL);
+ err = -ENODEV;
+ if (!regs) {
+ printk(KERN_ERR PFX "Could not find config registers\n");
+ goto out_err;
}
- regs = prop->value;
-
devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
- for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
- if (pbm->devhandle == (devhandle ^ 0x40)) {
- pci_sun4v_pbm_init(pbm->parent, dp, devhandle);
- return;
+ err = -ENOMEM;
+ if (!iommu_batch_initialized) {
+ for_each_possible_cpu(i) {
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+
+ if (!page)
+ goto out_err;
+
+ per_cpu(iommu_batch, i).pglist = (u64 *) page;
}
+ iommu_batch_initialized = 1;
}
- for_each_possible_cpu(i) {
- unsigned long page = get_zeroed_page(GFP_ATOMIC);
-
- if (!page)
- goto fatal_memory_error;
-
- per_cpu(iommu_batch, i).pglist = (u64 *) page;
+ pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+ if (!pbm) {
+ printk(KERN_ERR PFX "Could not allocate pci_pbm_info\n");
+ goto out_err;
}
- p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
- if (!p)
- goto fatal_memory_error;
+ iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+ if (!iommu) {
+ printk(KERN_ERR PFX "Could not allocate pbm iommu\n");
+ goto out_free_controller;
+ }
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ pbm->iommu = iommu;
- p->pbm_A.iommu = iommu;
+ err = pci_sun4v_pbm_init(pbm, op, devhandle);
+ if (err)
+ goto out_free_iommu;
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ dev_set_drvdata(&op->dev, pbm);
- p->pbm_B.iommu = iommu;
+ return 0;
- pci_sun4v_pbm_init(p, dp, devhandle);
- return;
+out_free_iommu:
+ kfree(pbm->iommu);
-fatal_memory_error:
- prom_printf("SUN4V_PCI: Fatal memory allocation error.\n");
- prom_halt();
+out_free_controller:
+ kfree(pbm);
+
+out_err:
+ return err;
}
+
+static struct of_device_id __initdata pci_sun4v_match[] = {
+ {
+ .name = "pci",
+ .compatible = "SUNW,sun4v-pci",
+ },
+ {},
+};
+
+static struct of_platform_driver pci_sun4v_driver = {
+ .name = DRIVER_NAME,
+ .match_table = pci_sun4v_match,
+ .probe = pci_sun4v_probe,
+};
+
+static int __init pci_sun4v_init(void)
+{
+ return of_register_driver(&pci_sun4v_driver, &of_bus_type);
+}
+
+subsys_initcall(pci_sun4v_init);
diff --git a/arch/sparc64/kernel/pci_sun4v_asm.S b/arch/sparc64/kernel/pci_sun4v_asm.S
index ecb81f3..e606d46 100644
--- a/arch/sparc64/kernel/pci_sun4v_asm.S
+++ b/arch/sparc64/kernel/pci_sun4v_asm.S
@@ -1,8 +1,9 @@
/* pci_sun4v_asm: Hypervisor calls for PCI support.
*
- * Copyright (C) 2006 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2006, 2008 David S. Miller <davem@davemloft.net>
*/
+#include <linux/linkage.h>
#include <asm/hypervisor.h>
/* %o0: devhandle
@@ -14,8 +15,7 @@
* returns %o0: -status if status was non-zero, else
* %o0: num pages mapped
*/
- .globl pci_sun4v_iommu_map
-pci_sun4v_iommu_map:
+ENTRY(pci_sun4v_iommu_map)
mov %o5, %g1
mov HV_FAST_PCI_IOMMU_MAP, %o5
ta HV_FAST_TRAP
@@ -24,6 +24,7 @@
mov %o1, %o0
1: retl
nop
+ENDPROC(pci_sun4v_iommu_map)
/* %o0: devhandle
* %o1: tsbid
@@ -31,12 +32,12 @@
*
* returns %o0: num ttes demapped
*/
- .globl pci_sun4v_iommu_demap
-pci_sun4v_iommu_demap:
+ENTRY(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
@@ -45,8 +46,7 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_iommu_getmap
-pci_sun4v_iommu_getmap:
+ENTRY(pci_sun4v_iommu_getmap)
mov %o2, %o4
mov HV_FAST_PCI_IOMMU_GETMAP, %o5
ta HV_FAST_TRAP
@@ -54,6 +54,7 @@
stx %o2, [%o3]
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_iommu_getmap)
/* %o0: devhandle
* %o1: pci_device
@@ -65,14 +66,14 @@
* If there is an error, the data will be returned
* as all 1's.
*/
- .globl pci_sun4v_config_get
-pci_sun4v_config_get:
+ENTRY(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
@@ -85,14 +86,14 @@
* status will be zero if the operation completed
* successfully, else -1 if not
*/
- .globl pci_sun4v_config_put
-pci_sun4v_config_put:
+ENTRY(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
@@ -104,12 +105,12 @@
* status will be zero if the operation completed
* successfully, else -1 if not
*/
- .globl pci_sun4v_msiq_conf
-pci_sun4v_msiq_conf:
+ENTRY(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
@@ -118,8 +119,7 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_info
-pci_sun4v_msiq_info:
+ENTRY(pci_sun4v_msiq_info)
mov %o2, %o4
mov HV_FAST_PCI_MSIQ_INFO, %o5
ta HV_FAST_TRAP
@@ -127,6 +127,7 @@
stx %o2, [%o3]
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msiq_info)
/* %o0: devhandle
* %o1: msiqid
@@ -134,13 +135,13 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_getvalid
-pci_sun4v_msiq_getvalid:
+ENTRY(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
@@ -148,12 +149,12 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_setvalid
-pci_sun4v_msiq_setvalid:
+ENTRY(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
@@ -161,13 +162,13 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_getstate
-pci_sun4v_msiq_getstate:
+ENTRY(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
@@ -175,12 +176,12 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_setstate
-pci_sun4v_msiq_setstate:
+ENTRY(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
@@ -188,13 +189,13 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_gethead
-pci_sun4v_msiq_gethead:
+ENTRY(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
@@ -202,12 +203,12 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_sethead
-pci_sun4v_msiq_sethead:
+ENTRY(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
@@ -215,13 +216,13 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_gettail
-pci_sun4v_msiq_gettail:
+ENTRY(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
@@ -229,13 +230,13 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msi_getvalid
-pci_sun4v_msi_getvalid:
+ENTRY(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
@@ -243,12 +244,12 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msi_setvalid
-pci_sun4v_msi_setvalid:
+ENTRY(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
@@ -256,13 +257,13 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msi_getmsiq
-pci_sun4v_msi_getmsiq:
+ENTRY(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
@@ -271,12 +272,12 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msi_setmsiq
-pci_sun4v_msi_setmsiq:
+ENTRY(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
@@ -284,13 +285,13 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msi_getstate
-pci_sun4v_msi_getstate:
+ENTRY(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
@@ -298,12 +299,12 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msi_setstate
-pci_sun4v_msi_setstate:
+ENTRY(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
@@ -311,13 +312,13 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msg_getmsiq
-pci_sun4v_msg_getmsiq:
+ENTRY(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
@@ -325,12 +326,12 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msg_setmsiq
-pci_sun4v_msg_setmsiq:
+ENTRY(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
@@ -338,13 +339,13 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msg_getvalid
-pci_sun4v_msg_getvalid:
+ENTRY(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
@@ -352,10 +353,10 @@
*
* returns %o0: status
*/
- .globl pci_sun4v_msg_setvalid
-pci_sun4v_msg_setvalid:
+ENTRY(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/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index 3bb987a..076cad7 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -1,34 +1,17 @@
/* power.c: Power management driver.
*
- * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1999, 2007, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/pm.h>
-#include <linux/syscalls.h>
#include <linux/reboot.h>
#include <linux/of_device.h>
-#include <asm/system.h>
-#include <asm/auxio.h>
#include <asm/prom.h>
#include <asm/io.h>
-#include <asm/sstate.h>
-#include <asm/reboot.h>
-
-#include <linux/unistd.h>
-
-/*
- * sysctl - toggle power-off restriction for serial console
- * systems in machine_power_off()
- */
-int scons_pwroff = 1;
static void __iomem *power_reg;
@@ -40,31 +23,6 @@
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)
@@ -85,8 +43,6 @@
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)
@@ -96,7 +52,7 @@
return 0;
}
-static struct of_device_id power_match[] = {
+static struct of_device_id __initdata power_match[] = {
{
.name = "power",
},
@@ -111,8 +67,9 @@
},
};
-void __init power_init(void)
+static int __init power_init(void)
{
- of_register_driver(&power_driver, &of_platform_bus_type);
- return;
+ return of_register_driver(&power_driver, &of_platform_bus_type);
}
+
+device_initcall(power_init);
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 15f4178..d5e2ace 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -22,7 +22,6 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
-#include <linux/reboot.h>
#include <linux/delay.h>
#include <linux/compat.h>
#include <linux/tick.h>
@@ -31,7 +30,6 @@
#include <linux/elfcore.h>
#include <linux/sysrq.h>
-#include <asm/oplib.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/page.h>
@@ -46,8 +44,6 @@
#include <asm/mmu_context.h>
#include <asm/unistd.h>
#include <asm/hypervisor.h>
-#include <asm/sstate.h>
-#include <asm/reboot.h>
#include <asm/syscalls.h>
#include <asm/irq_regs.h>
#include <asm/smp.h>
@@ -115,35 +111,6 @@
}
}
-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)
{
@@ -248,7 +215,6 @@
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 *)
@@ -304,7 +270,6 @@
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/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 7151513..dbba82f 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -38,7 +38,7 @@
{
struct device_node *np;
- for (np = allnodes; np != 0; np = np->allnext)
+ for (np = allnodes; np; np = np->allnext)
if (np->node == handle)
break;
@@ -59,6 +59,9 @@
}
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;
@@ -82,7 +85,10 @@
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;
@@ -945,22 +951,30 @@
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))
- return t->init(dp);
+ if (!strcmp(model, t->name)) {
+ t->init(dp);
+ return;
+ }
}
}
#endif
#ifdef CONFIG_SBUS
if (!strcmp(dp->name, "sbus") ||
- !strcmp(dp->name, "sbi"))
- return sbus_irq_trans_init(dp);
+ !strcmp(dp->name, "sbi")) {
+ sbus_irq_trans_init(dp);
+ return;
+ }
#endif
if (!strcmp(dp->name, "fhc") &&
- !strcmp(dp->parent->name, "central"))
- return central_irq_trans_init(dp);
+ !strcmp(dp->parent->name, "central")) {
+ central_irq_trans_init(dp);
+ return;
+ }
if (!strcmp(dp->name, "virtual-devices") ||
- !strcmp(dp->name, "niu"))
- return sun4v_vdev_irq_trans_init(dp);
+ !strcmp(dp->name, "niu")) {
+ sun4v_vdev_irq_trans_init(dp);
+ return;
+ }
}
static int is_root_node(const struct device_node *dp)
@@ -1231,32 +1245,49 @@
if (parent != NULL) {
if (!strcmp(parent->type, "pci") ||
- !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);
+ !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;
+ }
if (!strcmp(parent->name, "usb") ||
- !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);
-
+ !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;
+ }
/* "isa" is handled with platform naming */
}
/* Use platform naming convention. */
- if (tlb_type == hypervisor)
- return sun4v_path_component(dp, tmp_buf);
- else
- return sun4u_path_component(dp, tmp_buf);
+ if (tlb_type == hypervisor) {
+ sun4v_path_component(dp, tmp_buf);
+ return;
+ } else {
+ sun4u_path_component(dp, tmp_buf);
+ }
}
static char * __init build_path_component(struct device_node *dp)
diff --git a/arch/sparc64/kernel/psycho_common.c b/arch/sparc64/kernel/psycho_common.c
new file mode 100644
index 0000000..7909964
--- /dev/null
+++ b/arch/sparc64/kernel/psycho_common.c
@@ -0,0 +1,470 @@
+/* psycho_common.c: Code common to PSYCHO and derivative PCI controllers.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+
+#include <asm/upa.h>
+
+#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_PAGE_SHIFT);
+ }
+}
+
+#define PSYCHO_IOMMU_CTRL_XLTESTAT 0x0000000006000000UL
+#define PSYCHO_IOMMU_CTRL_XLTEERR 0x0000000001000000UL
+
+void psycho_check_iommu_error(struct pci_pbm_info *pbm,
+ unsigned long afsr,
+ unsigned long afar,
+ enum psycho_error_type type)
+{
+ u64 control, iommu_tag[16], iommu_data[16];
+ struct iommu *iommu = pbm->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/arch/sparc64/kernel/psycho_common.h b/arch/sparc64/kernel/psycho_common.h
new file mode 100644
index 0000000..092c278
--- /dev/null
+++ b/arch/sparc64/kernel/psycho_common.h
@@ -0,0 +1,48 @@
+#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/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 10306e4..f43adbc 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -1050,31 +1050,17 @@
return ret;
}
-asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
+asmlinkage int syscall_trace_enter(struct pt_regs *regs)
{
int ret = 0;
/* do the secure computing check first */
secure_computing(regs->u_regs[UREG_G1]);
- if (unlikely(current->audit_context) && syscall_exit_p) {
- unsigned long tstate = regs->tstate;
- int result = AUDITSC_SUCCESS;
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+ ret = tracehook_report_syscall_entry(regs);
- 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) && !syscall_exit_p && !ret)
+ if (unlikely(current->audit_context) && !ret)
audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
AUDIT_ARCH_SPARC :
AUDIT_ARCH_SPARC64),
@@ -1086,3 +1072,19 @@
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/arch/sparc64/kernel/reboot.c b/arch/sparc64/kernel/reboot.c
new file mode 100644
index 0000000..ef89d3d
--- /dev/null
+++ b/arch/sparc64/kernel/reboot.c
@@ -0,0 +1,53 @@
+/* reboot.c: reboot/shutdown/halt/poweroff handling
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+
+#include <asm/system.h>
+#include <asm/oplib.h>
+#include <asm/prom.h>
+
+/* 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/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index e33a8a6..2ead310 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -11,15 +11,17 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/page.h>
-#include <asm/sbus.h>
#include <asm/io.h>
#include <asm/upa.h>
#include <asm/cache.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/prom.h>
+#include <asm/oplib.h>
#include <asm/starfire.h>
#include "iommu_common.h"
@@ -52,13 +54,23 @@
#define STRBUF_TAG_VALID 0x02UL
/* Enable 64-bit DVMA mode for the given device. */
-void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
+void sbus_set_sbus64(struct device *dev, int bursts)
{
- struct iommu *iommu = sdev->ofdev.dev.archdata.iommu;
- int slot = sdev->slot;
+ struct iommu *iommu = dev->archdata.iommu;
+ struct of_device *op = to_of_device(dev);
+ const struct linux_prom_registers *regs;
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:
@@ -191,10 +203,9 @@
return imap + diff;
}
-unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
+static unsigned int sbus_build_irq(struct of_device *op, unsigned int ino)
{
- struct sbus_bus *sbus = (struct sbus_bus *)buscookie;
- struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct iommu *iommu = op->dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned long imap, iclr;
int sbus_level = 0;
@@ -255,12 +266,12 @@
#define SYSIO_UEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */
static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
{
- struct sbus_bus *sbus = dev_id;
- struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct of_device *op = dev_id;
+ struct iommu *iommu = op->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;
+ int reported, portid;
afsr_reg = reg_base + SYSIO_UE_AFSR;
afar_reg = reg_base + SYSIO_UE_AFAR;
@@ -275,9 +286,11 @@
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",
- sbus->portid,
+ portid,
(((error_bits & SYSIO_UEAFSR_PPIO) ?
"PIO" :
((error_bits & SYSIO_UEAFSR_PDRD) ?
@@ -285,12 +298,12 @@
((error_bits & SYSIO_UEAFSR_PDWR) ?
"DVMA Write" : "???")))));
printk("SYSIO[%x]: DOFF[%lx] SIZE[%lx] MID[%lx]\n",
- sbus->portid,
+ portid,
(afsr & SYSIO_UEAFSR_DOFF) >> 45UL,
(afsr & SYSIO_UEAFSR_SIZE) >> 42UL,
(afsr & SYSIO_UEAFSR_MID) >> 37UL);
- printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
- printk("SYSIO[%x]: Secondary UE errors [", sbus->portid);
+ printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
+ printk("SYSIO[%x]: Secondary UE errors [", portid);
reported = 0;
if (afsr & SYSIO_UEAFSR_SPIO) {
reported++;
@@ -327,12 +340,12 @@
#define SYSIO_CEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */
static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
{
- struct sbus_bus *sbus = dev_id;
- struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct of_device *op = dev_id;
+ struct iommu *iommu = op->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;
+ int reported, portid;
afsr_reg = reg_base + SYSIO_CE_AFSR;
afar_reg = reg_base + SYSIO_CE_AFAR;
@@ -347,8 +360,10 @@
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",
- sbus->portid,
+ portid,
(((error_bits & SYSIO_CEAFSR_PPIO) ?
"PIO" :
((error_bits & SYSIO_CEAFSR_PDRD) ?
@@ -360,14 +375,14 @@
* XXX UDB CE trap handler does... -DaveM
*/
printk("SYSIO[%x]: DOFF[%lx] ECC Syndrome[%lx] Size[%lx] MID[%lx]\n",
- sbus->portid,
+ 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", sbus->portid, afar);
+ printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
- printk("SYSIO[%x]: Secondary CE errors [", sbus->portid);
+ printk("SYSIO[%x]: Secondary CE errors [", portid);
reported = 0;
if (afsr & SYSIO_CEAFSR_SPIO) {
reported++;
@@ -404,11 +419,11 @@
#define SYSIO_SBAFSR_RESV3 0x0000001fffffffffUL /* Reserved */
static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
{
- struct sbus_bus *sbus = dev_id;
- struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct of_device *op = dev_id;
+ struct iommu *iommu = op->dev.archdata.iommu;
unsigned long afsr_reg, afar_reg, reg_base;
unsigned long afsr, afar, error_bits;
- int reported;
+ int reported, portid;
reg_base = iommu->write_complete_reg - 0x2000UL;
afsr_reg = reg_base + SYSIO_SBUS_AFSR;
@@ -423,9 +438,11 @@
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",
- sbus->portid,
+ portid,
(((error_bits & SYSIO_SBAFSR_PLE) ?
"Late PIO Error" :
((error_bits & SYSIO_SBAFSR_PTO) ?
@@ -434,11 +451,11 @@
"Error Ack" : "???")))),
(afsr & SYSIO_SBAFSR_RD) ? 1 : 0);
printk("SYSIO[%x]: size[%lx] MID[%lx]\n",
- sbus->portid,
+ portid,
(afsr & SYSIO_SBAFSR_SIZE) >> 42UL,
(afsr & SYSIO_SBAFSR_MID) >> 37UL);
- printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
- printk("SYSIO[%x]: Secondary SBUS errors [", sbus->portid);
+ printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
+ printk("SYSIO[%x]: Secondary SBUS errors [", portid);
reported = 0;
if (afsr & SYSIO_SBAFSR_SLE) {
reported++;
@@ -470,34 +487,37 @@
#define SYSIO_CE_INO 0x35
#define SYSIO_SBUSERR_INO 0x36
-static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
+static void __init sysio_register_error_handlers(struct of_device *op)
{
- struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct iommu *iommu = op->dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned int irq;
u64 control;
+ int portid;
- irq = sbus_build_irq(sbus, SYSIO_UE_INO);
+ portid = of_getintprop_default(op->node, "portid", -1);
+
+ irq = sbus_build_irq(op, SYSIO_UE_INO);
if (request_irq(irq, sysio_ue_handler, 0,
- "SYSIO_UE", sbus) < 0) {
+ "SYSIO_UE", op) < 0) {
prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n",
- sbus->portid);
+ portid);
prom_halt();
}
- irq = sbus_build_irq(sbus, SYSIO_CE_INO);
+ irq = sbus_build_irq(op, SYSIO_CE_INO);
if (request_irq(irq, sysio_ce_handler, 0,
- "SYSIO_CE", sbus) < 0) {
+ "SYSIO_CE", op) < 0) {
prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n",
- sbus->portid);
+ portid);
prom_halt();
}
- irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO);
+ irq = sbus_build_irq(op, SYSIO_SBUSERR_INO);
if (request_irq(irq, sysio_sbus_error_handler, 0,
- "SYSIO_SBERR", sbus) < 0) {
+ "SYSIO_SBERR", op) < 0) {
prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n",
- sbus->portid);
+ portid);
prom_halt();
}
@@ -513,19 +533,15 @@
}
/* Boot time initialization. */
-static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
+static void __init sbus_iommu_init(struct of_device *op)
{
const struct linux_prom64_registers *pr;
- struct device_node *dp;
+ struct device_node *dp = op->node;
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) {
@@ -542,9 +558,9 @@
if (!strbuf)
goto fatal_memory_error;
- sbus->ofdev.dev.archdata.iommu = iommu;
- sbus->ofdev.dev.archdata.stc = strbuf;
- sbus->ofdev.dev.archdata.numa_node = -1;
+ op->dev.archdata.iommu = iommu;
+ op->dev.archdata.stc = strbuf;
+ op->dev.archdata.numa_node = -1;
reg_base = regs + SYSIO_IOMMUREG_BASE;
iommu->iommu_control = reg_base + IOMMU_CONTROL;
@@ -572,8 +588,9 @@
*/
iommu->write_complete_reg = regs + 0x2000UL;
- printk("SYSIO: UPA portID %x, at %016lx\n",
- sbus->portid, regs);
+ portid = of_getintprop_default(op->node, "portid", -1);
+ printk(KERN_INFO "SYSIO: UPA portID %x, at %016lx\n",
+ 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))
@@ -631,56 +648,27 @@
/* Now some Xfire specific grot... */
if (this_is_starfire)
- starfire_hookup(sbus->portid);
+ starfire_hookup(portid);
- sysio_register_error_handlers(sbus);
+ sysio_register_error_handlers(op);
return;
fatal_memory_error:
prom_printf("sbus_iommu_init: Fatal memory allocation error.\n");
}
-void sbus_fill_device_irq(struct sbus_dev *sdev)
+static int __init sbus_init(void)
{
- struct device_node *dp = of_find_node_by_phandle(sdev->prom_node);
- const struct linux_prom_irqs *irqs;
+ struct device_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;
+ for_each_node_by_name(dp, "sbus") {
+ struct of_device *op = of_find_device_by_node(dp);
- sdev->num_irqs = 1;
- if (pri < 0x20)
- pri += sdev->slot * 8;
-
- sdev->irqs[0] = sbus_build_irq(sdev->bus, pri);
+ sbus_iommu_init(op);
+ of_propagate_archdata(op);
}
-}
-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;
}
-void __init sbus_arch_postinit(void)
-{
- extern void firetruck_init(void);
-
- firetruck_init();
-}
+subsys_initcall(sbus_init);
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 0804f71..30bba8b 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -36,7 +36,6 @@
#include <asm/elf.h>
#include <asm/head.h>
#include <asm/smp.h>
-#include <asm/mostek.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>
#include <asm/checksum.h>
@@ -44,12 +43,8 @@
#include <asm/pgalloc.h>
#include <asm/cacheflush.h>
#ifdef CONFIG_SBUS
-#include <asm/sbus.h>
#include <asm/dma.h>
#endif
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
-#endif
#include <asm/ns87303.h>
#include <asm/timer.h>
#include <asm/cpudata.h>
@@ -68,7 +63,6 @@
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 *);
@@ -154,26 +148,12 @@
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);
@@ -182,7 +162,6 @@
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);
@@ -300,3 +279,5 @@
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/arch/sparc64/kernel/sstate.c b/arch/sparc64/kernel/sstate.c
index 5b6e75b..8cdbe59 100644
--- a/arch/sparc64/kernel/sstate.c
+++ b/arch/sparc64/kernel/sstate.c
@@ -1,14 +1,15 @@
/* sstate.c: System soft state support.
*
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/kernel.h>
#include <linux/notifier.h>
+#include <linux/reboot.h>
#include <linux/init.h>
#include <asm/hypervisor.h>
-#include <asm/sstate.h>
+#include <asm/spitfire.h>
#include <asm/oplib.h>
#include <asm/head.h>
#include <asm/io.h>
@@ -50,30 +51,33 @@
static const char panicing_msg[32] __attribute__((aligned(32))) =
"Linux panicing";
-void sstate_booting(void)
+static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused)
{
- do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg);
+ const char *msg;
+
+ switch (type) {
+ case SYS_DOWN:
+ default:
+ msg = rebooting_msg;
+ break;
+
+ case SYS_HALT:
+ msg = halting_msg;
+ break;
+
+ case SYS_POWER_OFF:
+ msg = poweroff_msg;
+ break;
+ }
+
+ do_set_sstate(HV_SOFT_STATE_TRANSITION, msg);
+
+ return NOTIFY_OK;
}
-void sstate_running(void)
-{
- do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg);
-}
-
-void sstate_halt(void)
-{
- do_set_sstate(HV_SOFT_STATE_TRANSITION, halting_msg);
-}
-
-void sstate_poweroff(void)
-{
- do_set_sstate(HV_SOFT_STATE_TRANSITION, poweroff_msg);
-}
-
-void sstate_reboot(void)
-{
- do_set_sstate(HV_SOFT_STATE_TRANSITION, rebooting_msg);
-}
+static struct notifier_block sstate_reboot_notifier = {
+ .notifier_call = sstate_reboot_call,
+};
static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr)
{
@@ -87,18 +91,37 @@
.priority = INT_MAX,
};
-void __init sun4v_sstate_init(void)
+static int __init 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;
+ return 0;
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/arch/sparc64/kernel/starfire.c b/arch/sparc64/kernel/starfire.c
index 7461581..060d0f3 100644
--- a/arch/sparc64/kernel/starfire.c
+++ b/arch/sparc64/kernel/starfire.c
@@ -28,11 +28,6 @@
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/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 3d11853..3320c9d 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -575,14 +575,6 @@
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/arch/sparc64/kernel/syscalls.S b/arch/sparc64/kernel/syscalls.S
index a2f2427..7a6786a 100644
--- a/arch/sparc64/kernel/syscalls.S
+++ b/arch/sparc64/kernel/syscalls.S
@@ -65,9 +65,8 @@
andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
be,pt %icc, rtrap
nop
- add %sp, PTREGS_OFF, %o0
- call syscall_trace
- mov 1, %o1
+ call syscall_trace_leave
+ add %sp, PTREGS_OFF, %o0
ba,pt %xcc, rtrap
nop
@@ -159,9 +158,8 @@
or %l7, %lo(sys_ni_syscall), %l7
linux_syscall_trace32:
- add %sp, PTREGS_OFF, %o0
- call syscall_trace
- clr %o1
+ call syscall_trace_enter
+ add %sp, PTREGS_OFF, %o0
brnz,pn %o0, 3f
mov -ENOSYS, %o0
srl %i0, 0, %o0
@@ -172,9 +170,8 @@
srl %i3, 0, %o3
linux_syscall_trace:
- add %sp, PTREGS_OFF, %o0
- call syscall_trace
- clr %o1
+ call syscall_trace_enter
+ add %sp, PTREGS_OFF, %o0
brnz,pn %o0, 3f
mov -ENOSYS, %o0
mov %i0, %o0
@@ -275,9 +272,8 @@
b,pt %xcc, rtrap
stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
linux_syscall_trace2:
- add %sp, PTREGS_OFF, %o0
- call syscall_trace
- mov 1, %o1
+ call syscall_trace_leave
+ add %sp, PTREGS_OFF, %o0
stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
ba,pt %xcc, rtrap
stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 0fdbf3b..5daee4b 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -23,7 +23,7 @@
/*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, sys32_pause
+/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys_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/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index cc16fdc..80d71a5 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -30,13 +30,14 @@
#include <linux/percpu.h>
#include <linux/miscdevice.h>
#include <linux/rtc.h>
+#include <linux/rtc/m48t59.h>
#include <linux/kernel_stat.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <asm/oplib.h>
-#include <asm/mostek.h>
#include <asm/timer.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -50,18 +51,7 @@
#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)
@@ -405,313 +395,167 @@
int update_persistent_clock(struct timespec now)
{
- return set_rtc_mmss(now.tv_sec);
-}
+ struct rtc_device *rtc = rtc_class_open("rtc0");
+ int err = -1;
-/* 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);
+ if (rtc) {
+ err = rtc_set_mmss(rtc, now.tv_sec);
+ rtc_class_close(rtc);
}
- prom_printf("CLOCK: Kick start procedure successful.\n");
+ return err;
}
-/* Return nonzero if the clock chip battery is low. */
-static int __init has_low_battery(void)
+unsigned long cmos_regs;
+EXPORT_SYMBOL(cmos_regs);
+
+static struct resource rtc_cmos_resource;
+
+static struct platform_device rtc_cmos_device = {
+ .name = "rtc_cmos",
+ .id = -1,
+ .resource = &rtc_cmos_resource,
+ .num_resources = 1,
+};
+
+static int __devinit rtc_probe(struct of_device *op, const struct of_device_id *match)
{
- void __iomem *regs = mstk48t02_regs;
- u8 data1, data2;
+ struct resource *r;
- spin_lock_irq(&mostek_lock);
+ printk(KERN_INFO "%s: RTC regs at 0x%lx\n",
+ op->node->full_name, op->resource[0].start);
- 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. */
-
- spin_unlock_irq(&mostek_lock);
-
- return (data1 == data2); /* Was the write blocked? */
-}
-
-static void __init mostek_set_system_time(void __iomem *mregs)
-{
- unsigned int year, mon, day, hour, min, sec;
- u8 tmp;
-
- spin_lock_irq(&mostek_lock);
-
- /* Traditional Mostek chip. */
- tmp = mostek_read(mregs + MOSTEK_CREG);
- tmp |= MSTK_CREG_READ;
- mostek_write(mregs + MOSTEK_CREG, tmp);
-
- 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);
-
- tmp = mostek_read(mregs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_READ;
- mostek_write(mregs + MOSTEK_CREG, tmp);
-
- spin_unlock_irq(&mostek_lock);
-}
-
-/* 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
-
- if (!mregs && !dregs && !bregs) {
- prom_printf("Something wrong, clock regs not mapped yet.\n");
- prom_halt();
- }
-
- if (mregs) {
- mostek_set_system_time(mregs);
- return;
- }
-
- if (bregs) {
- unsigned char val = readb(bregs + 0x0e);
- unsigned int century;
-
- /* BQ4802 RTC chip. */
-
- writeb(val | 0x08, bregs + 0x0e);
-
- 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);
-
- 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;
- }
-
- 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)
-{
- 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_set_time(u32 val)
-{
- /* Do nothing, time is set using the service processor
- * console on this platform.
+ /* 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.
*/
- return 0;
+
+ 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;
+
+ cmos_regs = op->resource[0].start;
+ return platform_device_register(&rtc_cmos_device);
}
-static u32 hypervisor_get_time(void)
-{
- unsigned long ret, time;
- int retries = 10000;
+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",
+ },
+ {},
+};
-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;
+static struct of_platform_driver rtc_driver = {
+ .match_table = rtc_match,
+ .probe = rtc_probe,
+ .driver = {
+ .name = "rtc",
+ },
+};
+
+static struct platform_device rtc_bq4802_device = {
+ .name = "rtc-bq4802",
+ .id = -1,
+ .num_resources = 1,
+};
+
+static int __devinit bq4802_probe(struct of_device *op, const struct of_device_id *match)
+{
+
+ printk(KERN_INFO "%s: BQ4802 regs at 0x%lx\n",
+ op->node->full_name, op->resource[0].start);
+
+ rtc_bq4802_device.resource = &op->resource[0];
+ return platform_device_register(&rtc_bq4802_device);
+}
+
+static struct of_device_id __initdata bq4802_match[] = {
+ {
+ .name = "rtc",
+ .compatible = "bq4802",
+ },
+};
+
+static struct of_platform_driver bq4802_driver = {
+ .match_table = bq4802_match,
+ .probe = bq4802_probe,
+ .driver = {
+ .name = "bq4802",
+ },
+};
+
+static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ void __iomem *regs;
+ unsigned char val;
+
+ regs = (void __iomem *) pdev->resource[0].start;
+ val = readb(regs + ofs);
+
+ /* the year 0 is 1968 */
+ if (ofs == pdata->offset + M48T59_YEAR) {
+ val += 0x68;
+ if ((val & 0xf) > 9)
+ val += 6;
}
- printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
- return 0;
+ return val;
}
-static int hypervisor_set_time(u32 secs)
+static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
{
- 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 __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 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;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
void __iomem *regs;
- if (!model)
- model = compat;
+ 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;
+ }
+ writeb(val, regs + ofs);
+}
- if (!model || !clock_model_matches(model))
- return -ENODEV;
+static struct m48t59_plat_data m48t59_data = {
+ .read_byte = mostek_read_byte,
+ .write_byte = mostek_write_byte,
+};
+
+static struct platform_device m48t59_rtc = {
+ .name = "rtc-m48t59",
+ .id = 0,
+ .num_resources = 1,
+ .dev = {
+ .platform_data = &m48t59_data,
+ },
+};
+
+static int __devinit mostek_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct device_node *dp = op->node;
/* On an Enterprise system there can be multiple mostek clocks.
* We should only match the one that is on the central FHC bus.
@@ -720,88 +564,51 @@
strcmp(dp->parent->parent->name, "central") != 0)
return -ENODEV;
- size = (op->resource[0].end - op->resource[0].start) + 1;
- regs = of_ioremap(&op->resource[0], 0, size, "clock");
- if (!regs)
- return -ENOMEM;
+ printk(KERN_INFO "%s: Mostek regs at 0x%lx\n",
+ dp->full_name, op->resource[0].start);
-#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);
-
- return 0;
+ m48t59_rtc.resource = &op->resource[0];
+ return platform_device_register(&m48t59_rtc);
}
-static struct of_device_id clock_match[] = {
+static struct of_device_id __initdata mostek_match[] = {
{
.name = "eeprom",
},
- {
- .name = "rtc",
- },
{},
};
-static struct of_platform_driver clock_driver = {
- .match_table = clock_match,
- .probe = clock_probe,
+static struct of_platform_driver mostek_driver = {
+ .match_table = mostek_match,
+ .probe = mostek_probe,
.driver = {
- .name = "clock",
+ .name = "mostek",
},
};
+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) {
- 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;
- }
+ if (this_is_starfire)
+ return platform_device_register(&rtc_starfire_device);
- return of_register_driver(&clock_driver, &of_platform_bus_type);
+ 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);
+
+ return 0;
}
/* Must be after subsys_initcall() so that busses are probed. Must
@@ -814,7 +621,7 @@
static unsigned long sparc64_init_timers(void)
{
struct device_node *dp;
- unsigned long clock;
+ unsigned long freq;
dp = of_find_node_by_path("/");
if (tlb_type == spitfire) {
@@ -827,17 +634,17 @@
if (manuf == 0x17 && impl == 0x13) {
/* Hummingbird, aka Ultra-IIe */
tick_ops = &hbtick_operations;
- clock = of_getintprop_default(dp, "stick-frequency", 0);
+ freq = of_getintprop_default(dp, "stick-frequency", 0);
} else {
tick_ops = &tick_operations;
- clock = local_cpu_data().clock_tick;
+ freq = local_cpu_data().clock_tick;
}
} else {
tick_ops = &stick_operations;
- clock = of_getintprop_default(dp, "stick-frequency", 0);
+ freq = of_getintprop_default(dp, "stick-frequency", 0);
}
- return clock;
+ return freq;
}
struct freq_table {
@@ -1029,16 +836,16 @@
void __init time_init(void)
{
- unsigned long clock = sparc64_init_timers();
+ unsigned long freq = sparc64_init_timers();
- tb_ticks_per_usec = clock / USEC_PER_SEC;
+ tb_ticks_per_usec = freq / USEC_PER_SEC;
timer_ticks_per_nsec_quotient =
- clocksource_hz2mult(clock, SPARC64_NSEC_PER_CYC_SHIFT);
+ clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT);
clocksource_tick.name = tick_ops->name;
clocksource_tick.mult =
- clocksource_hz2mult(clock,
+ clocksource_hz2mult(freq,
clocksource_tick.shift);
clocksource_tick.read = tick_ops->get_tick;
@@ -1049,7 +856,7 @@
sparc64_clockevent.name = tick_ops->name;
- setup_clockevent_multiplier(clock);
+ setup_clockevent_multiplier(freq);
sparc64_clockevent.max_delta_ns =
clockevent_delta2ns(0x7fffffffffffffffUL, &sparc64_clockevent);
@@ -1070,672 +877,8 @@
>> 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/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index c824df1..81ccd22 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -38,6 +38,7 @@
#include <asm/timer.h>
#include <asm/head.h>
#include <asm/prom.h>
+#include <asm/memctrl.h>
#include "entry.h"
#include "kstack.h"
@@ -129,6 +130,56 @@
}
#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;
@@ -291,10 +342,7 @@
}
#ifdef CONFIG_PCI
-/* This is really pathetic... */
-extern volatile int pci_poke_in_progress;
-extern volatile int pci_poke_cpu;
-extern volatile int pci_poke_faulted;
+#include "pci_impl.h"
#endif
/* When access exceptions happen, we must do this. */
@@ -376,8 +424,7 @@
if (udbl & bit) {
scode = ecc_syndrome_table[udbl & 0xff];
- if (prom_getunumber(scode, afar,
- memmod_str, sizeof(memmod_str)) == -1)
+ if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0)
p = syndrome_unknown;
else
p = memmod_str;
@@ -388,8 +435,7 @@
if (udbh & bit) {
scode = ecc_syndrome_table[udbh & 0xff];
- if (prom_getunumber(scode, afar,
- memmod_str, sizeof(memmod_str)) == -1)
+ if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0)
p = syndrome_unknown;
else
p = memmod_str;
@@ -1062,8 +1108,6 @@
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)
{
@@ -1105,7 +1149,7 @@
syndrome = (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT;
syndrome = cheetah_ecc_syntab[syndrome];
- ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
+ ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum));
if (ret != -1)
printk("%s" "ERROR(%d): AFAR E-syndrome [%s]\n",
(recoverable ? KERN_WARNING : KERN_CRIT),
@@ -1116,7 +1160,7 @@
syndrome = (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT;
syndrome = cheetah_mtag_syntab[syndrome];
- ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
+ ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum));
if (ret != -1)
printk("%s" "ERROR(%d): AFAR M-syndrome [%s]\n",
(recoverable ? KERN_WARNING : KERN_CRIT),
@@ -2224,7 +2268,6 @@
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/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index a490077..92b1f8e 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -152,7 +152,7 @@
static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH,
show_pciobppath_attr, NULL);
-struct device_node *cdev_node;
+static struct device_node *cdev_node;
static struct vio_dev *root_vdev;
static u64 cdev_cfg_handle;
@@ -371,9 +371,9 @@
.node_name = "domain-services-port",
};
-const char *channel_devices_node = "channel-devices";
-const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
-const char *cfg_handle_prop = "cfg-handle";
+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";
static int __init vio_init(void)
{
diff --git a/arch/sparc64/kernel/visemul.c b/arch/sparc64/kernel/visemul.c
index c3fd647..9e05cb5 100644
--- a/arch/sparc64/kernel/visemul.c
+++ b/arch/sparc64/kernel/visemul.c
@@ -243,7 +243,7 @@
struct edge_tab {
u16 left, right;
};
-struct edge_tab edge8_tab[8] = {
+static struct edge_tab edge8_tab[8] = {
{ 0xff, 0x80 },
{ 0x7f, 0xc0 },
{ 0x3f, 0xe0 },
@@ -253,7 +253,7 @@
{ 0x03, 0xfe },
{ 0x01, 0xff },
};
-struct edge_tab edge8_tab_l[8] = {
+static struct edge_tab edge8_tab_l[8] = {
{ 0xff, 0x01 },
{ 0xfe, 0x03 },
{ 0xfc, 0x07 },
@@ -263,23 +263,23 @@
{ 0xc0, 0x7f },
{ 0x80, 0xff },
};
-struct edge_tab edge16_tab[4] = {
+static struct edge_tab edge16_tab[4] = {
{ 0xf, 0x8 },
{ 0x7, 0xc },
{ 0x3, 0xe },
{ 0x1, 0xf },
};
-struct edge_tab edge16_tab_l[4] = {
+static struct edge_tab edge16_tab_l[4] = {
{ 0xf, 0x1 },
{ 0xe, 0x3 },
{ 0xc, 0x7 },
{ 0x8, 0xf },
};
-struct edge_tab edge32_tab[2] = {
+static struct edge_tab edge32_tab[2] = {
{ 0x3, 0x2 },
{ 0x1, 0x3 },
};
-struct edge_tab edge32_tab_l[2] = {
+static struct edge_tab edge32_tab_l[2] = {
{ 0x3, 0x1 },
{ 0x2, 0x3 },
};
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index ea7d7ae..a9e474b 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -51,43 +51,6 @@
}
#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/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index a41df7b..3c10daf 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -46,15 +46,11 @@
#include <asm/tsb.h>
#include <asm/hypervisor.h>
#include <asm/prom.h>
-#include <asm/sstate.h>
#include <asm/mdesc.h>
#include <asm/cpudata.h>
#include <asm/irq.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)
+#include "init.h"
unsigned long kern_linear_pte_xor[2] __read_mostly;
@@ -416,17 +412,9 @@
#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
@@ -938,6 +926,10 @@
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;
@@ -1206,8 +1198,44 @@
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;
}
@@ -1633,8 +1661,6 @@
/* paging_init() sets up the page tables */
-extern void central_probe(void);
-
static unsigned long last_valid_pfn;
pgd_t swapper_pg_dir[2048];
@@ -1679,8 +1705,6 @@
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
@@ -1803,9 +1827,6 @@
}
printk("Booting Linux...\n");
-
- central_probe();
- cpu_probe();
}
int __init page_in_phys_avail(unsigned long paddr)
@@ -2032,7 +2053,6 @@
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;
@@ -2045,14 +2065,6 @@
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)
@@ -2136,7 +2148,6 @@
_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;
@@ -2147,10 +2158,10 @@
#ifdef CONFIG_DEBUG_PAGEALLOC
kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4U) ^
- 0xfffff80000000000;
+ 0xfffff80000000000UL;
#else
kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^
- 0xfffff80000000000;
+ 0xfffff80000000000UL;
#endif
kern_linear_pte_xor[0] |= (_PAGE_CP_4U | _PAGE_CV_4U |
_PAGE_P_4U | _PAGE_W_4U);
@@ -2188,7 +2199,6 @@
__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;
@@ -2196,20 +2206,20 @@
#ifdef CONFIG_DEBUG_PAGEALLOC
kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^
- 0xfffff80000000000;
+ 0xfffff80000000000UL;
#else
kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^
- 0xfffff80000000000;
+ 0xfffff80000000000UL;
#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) ^
- 0xfffff80000000000;
+ 0xfffff80000000000UL;
#else
kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZ256MB_4V) ^
- 0xfffff80000000000;
+ 0xfffff80000000000UL;
#endif
kern_linear_pte_xor[1] |= (_PAGE_CP_4V | _PAGE_CV_4V |
_PAGE_P_4V | _PAGE_W_4V);
diff --git a/arch/sparc64/mm/init.h b/arch/sparc64/mm/init.h
new file mode 100644
index 0000000..1606387
--- /dev/null
+++ b/arch/sparc64/mm/init.h
@@ -0,0 +1,49 @@
+#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/arch/sparc64/mm/tlb.c b/arch/sparc64/mm/tlb.c
index ae24919..d8f21e2 100644
--- a/arch/sparc64/mm/tlb.c
+++ b/arch/sparc64/mm/tlb.c
@@ -19,7 +19,7 @@
/* Heavily inspired by the ppc64 code. */
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers) = { 0, };
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
void flush_tlb_pending(void)
{
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 44d4f21..fc8351f 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -778,23 +778,45 @@
Say N otherwise.
config MICROCODE
- tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support"
+ tristate "/dev/cpu/microcode - microcode support"
select FW_LOADER
---help---
If you say Y here, you will be able to update the microcode on
- Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II,
- Pentium III, Pentium 4, Xeon etc. You will obviously need the
- actual microcode binary data itself which is not shipped with the
- Linux kernel.
+ certain Intel and AMD processors. The Intel support is for the
+ IA32 family, e.g. Pentium Pro, Pentium II, Pentium III,
+ Pentium 4, Xeon etc. The AMD support is for family 0x10 and
+ 0x11 processors, e.g. Opteron, Phenom and Turion 64 Ultra.
+ You will obviously need the actual microcode binary data itself
+ which is not shipped with the Linux kernel.
- For latest news and information on obtaining all the required
- ingredients for this driver, check:
- <http://www.urbanmyth.org/microcode/>.
+ This option selects the general module only, you need to select
+ at least one vendor specific module as well.
To compile this driver as a module, choose M here: the
module will be called microcode.
-config MICROCODE_OLD_INTERFACE
+config MICROCODE_INTEL
+ bool "Intel microcode patch loading support"
+ depends on MICROCODE
+ default MICROCODE
+ select FW_LOADER
+ --help---
+ This options enables microcode patch loading support for Intel
+ processors.
+
+ For latest news and information on obtaining all the required
+ Intel ingredients for this driver, check:
+ <http://www.urbanmyth.org/microcode/>.
+
+config MICROCODE_AMD
+ bool "AMD microcode patch loading support"
+ depends on MICROCODE
+ select FW_LOADER
+ --help---
+ If you select this option, microcode patch loading support for AMD
+ processors will be enabled.
+
+ config MICROCODE_OLD_INTERFACE
def_bool y
depends on MICROCODE
@@ -1061,6 +1083,56 @@
low memory. Setting this option will put user-space page table
entries in high memory.
+config X86_CHECK_BIOS_CORRUPTION
+ bool "Check for low memory corruption"
+ help
+ Periodically check for memory corruption in low memory, which
+ is suspected to be caused by BIOS. Even when enabled in the
+ configuration, it is disabled at runtime. Enable it by
+ setting "memory_corruption_check=1" on the kernel command
+ line. By default it scans the low 64k of memory every 60
+ seconds; see the memory_corruption_check_size and
+ memory_corruption_check_period parameters in
+ Documentation/kernel-parameters.txt to adjust this.
+
+ When enabled with the default parameters, this option has
+ almost no overhead, as it reserves a relatively small amount
+ of memory and scans it infrequently. It both detects corruption
+ and prevents it from affecting the running system.
+
+ It is, however, intended as a diagnostic tool; if repeatable
+ BIOS-originated corruption always affects the same memory,
+ you can use memmap= to prevent the kernel from using that
+ memory.
+
+config X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
+ bool "Set the default setting of memory_corruption_check"
+ depends on X86_CHECK_BIOS_CORRUPTION
+ default y
+ help
+ Set whether the default state of memory_corruption_check is
+ on or off.
+
+config X86_RESERVE_LOW_64K
+ bool "Reserve low 64K of RAM on AMI/Phoenix BIOSen"
+ default y
+ help
+ Reserve the first 64K of physical RAM on BIOSes that are known
+ to potentially corrupt that memory range. A numbers of BIOSes are
+ known to utilize this area during suspend/resume, so it must not
+ be used by the kernel.
+
+ Set this to N if you are absolutely sure that you trust the BIOS
+ to get all its memory reservations and usages right.
+
+ If you have doubts about the BIOS (e.g. suspend/resume does not
+ work or there's kernel crashes after certain hardware hotplug
+ events) and it's not AMI or Phoenix, then you might want to enable
+ X86_CHECK_BIOS_CORRUPTION=y to allow the kernel to check typical
+ corruption patterns.
+
+ Say Y if unsure.
+
config MATH_EMULATION
bool
prompt "Math emulation" if X86_32
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index f8843c3..c5f1013 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -420,7 +420,6 @@
depends on !(MK6 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386)
menuconfig PROCESSOR_SELECT
- default y
bool "Supported processor vendors" if EMBEDDED
help
This lets you choose what x86 vendor support code your kernel
@@ -430,48 +429,97 @@
default y
bool "Support Intel processors" if PROCESSOR_SELECT
help
- This enables extended support for Intel processors
+ This enables detection, tunings and quirks for Intel processors
+
+ You need this enabled if you want your kernel to run on an
+ Intel CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on an Intel
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config CPU_SUP_CYRIX_32
default y
bool "Support Cyrix processors" if PROCESSOR_SELECT
depends on !64BIT
help
- This enables extended support for Cyrix processors
+ This enables detection, tunings and quirks for Cyrix processors
+
+ You need this enabled if you want your kernel to run on a
+ Cyrix CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on a Cyrix
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config CPU_SUP_AMD
default y
bool "Support AMD processors" if PROCESSOR_SELECT
help
- This enables extended support for AMD processors
+ This enables detection, tunings and quirks for AMD processors
+
+ You need this enabled if you want your kernel to run on an
+ AMD CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on an AMD
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config CPU_SUP_CENTAUR_32
default y
bool "Support Centaur processors" if PROCESSOR_SELECT
depends on !64BIT
help
- This enables extended support for Centaur processors
+ This enables detection, tunings and quirks for Centaur processors
+
+ You need this enabled if you want your kernel to run on a
+ Centaur CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on a Centaur
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config CPU_SUP_CENTAUR_64
default y
bool "Support Centaur processors" if PROCESSOR_SELECT
depends on 64BIT
help
- This enables extended support for Centaur processors
+ This enables detection, tunings and quirks for Centaur processors
+
+ You need this enabled if you want your kernel to run on a
+ Centaur CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on a Centaur
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config CPU_SUP_TRANSMETA_32
default y
bool "Support Transmeta processors" if PROCESSOR_SELECT
depends on !64BIT
help
- This enables extended support for Transmeta processors
+ This enables detection, tunings and quirks for Transmeta processors
+
+ You need this enabled if you want your kernel to run on a
+ Transmeta CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on a Transmeta
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config CPU_SUP_UMC_32
default y
bool "Support UMC processors" if PROCESSOR_SELECT
depends on !64BIT
help
- This enables extended support for UMC processors
+ This enables detection, tunings and quirks for UMC processors
+
+ You need this enabled if you want your kernel to run on a
+ UMC CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on a UMC
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config X86_DS
bool "Debug Store support"
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 092f019..2a3dfbd 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -43,6 +43,19 @@
with klogd/syslogd or the X server. You should normally N here,
unless you want to debug such a crash.
+config EARLY_PRINTK_DBGP
+ bool "Early printk via EHCI debug port"
+ default n
+ depends on EARLY_PRINTK && PCI
+ help
+ Write kernel log output directly into the EHCI debug port.
+
+ This is useful for kernel debugging when your machine crashes very
+ early before the console code is initialized. For normal operation
+ it is not recommended because it looks ugly and doesn't cooperate
+ with klogd/syslogd or the X server. You should normally N here,
+ unless you want to debug such a crash. You need usb debug device.
+
config DEBUG_STACKOVERFLOW
bool "Check for stack overflows"
depends on DEBUG_KERNEL
diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu
index e372b58..b72b4f75 100644
--- a/arch/x86/Makefile_32.cpu
+++ b/arch/x86/Makefile_32.cpu
@@ -45,3 +45,8 @@
# cpu entries
cflags-$(CONFIG_X86_GENERIC) += $(call tune,generic,$(call tune,i686))
+# Bug fix for binutils: this option is required in order to keep
+# binutils from generating NOPL instructions against our will.
+ifneq ($(CONFIG_X86_P6_NOP),y)
+cflags-y += $(call cc-option,-Wa$(comma)-mtune=generic32,)
+endif
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 7ee102f..cd48c72 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -72,9 +72,7 @@
KBUILD_CFLAGS += $(call cc-option,-m32)
KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
-$(obj)/zImage: IMAGE_OFFSET := 0x1000
$(obj)/zImage: asflags-y := $(SVGA_MODE) $(RAMDISK)
-$(obj)/bzImage: IMAGE_OFFSET := 0x100000
$(obj)/bzImage: ccflags-y := -D__BIG_KERNEL__
$(obj)/bzImage: asflags-y := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
$(obj)/bzImage: BUILDFLAGS := -b
@@ -117,7 +115,7 @@
$(call if_changed,objcopy)
$(obj)/compressed/vmlinux: FORCE
- $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
+ $(Q)$(MAKE) $(build)=$(obj)/compressed $@
# Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
FDARGS =
@@ -181,6 +179,7 @@
mkisofs -J -r -o $(obj)/image.iso -b isolinux.bin -c boot.cat \
-no-emul-boot -boot-load-size 4 -boot-info-table \
$(obj)/isoimage
+ isohybrid $(obj)/image.iso 2>/dev/null || true
rm -rf $(obj)/isoimage
zlilo: $(BOOTIMAGE)
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 92fdd35..1771c80 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -27,9 +27,8 @@
$(call if_changed,objcopy)
-ifeq ($(CONFIG_X86_32),y)
-targets += vmlinux.bin.all vmlinux.relocs
-hostprogs-y := relocs
+targets += vmlinux.bin.all vmlinux.relocs relocs
+hostprogs-$(CONFIG_X86_32) += relocs
quiet_cmd_relocs = RELOCS $@
cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $<
@@ -43,6 +42,8 @@
$(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE
$(call if_changed,relocbin)
+ifeq ($(CONFIG_X86_32),y)
+
ifdef CONFIG_RELOCATABLE
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE
$(call if_changed,gzip)
@@ -59,6 +60,5 @@
LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T
endif
-
$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
$(call if_changed,ld)
diff --git a/arch/x86/boot/edd.c b/arch/x86/boot/edd.c
index d93cbc6..1aae8f3 100644
--- a/arch/x86/boot/edd.c
+++ b/arch/x86/boot/edd.c
@@ -41,6 +41,7 @@
char *mbrbuf_ptr, *mbrbuf_end;
u32 buf_base, mbr_base;
extern char _end[];
+ u16 mbr_magic;
sector_size = ei->params.bytes_per_sector;
if (!sector_size)
@@ -58,11 +59,15 @@
if (mbrbuf_end > (char *)(size_t)boot_params.hdr.heap_end_ptr)
return -1;
+ memset(mbrbuf_ptr, 0, sector_size);
if (read_mbr(devno, mbrbuf_ptr))
return -1;
*mbrsig = *(u32 *)&mbrbuf_ptr[EDD_MBR_SIG_OFFSET];
- return 0;
+ mbr_magic = *(u16 *)&mbrbuf_ptr[510];
+
+ /* check for valid MBR magic */
+ return mbr_magic == 0xAA55 ? 0 : -1;
}
static int get_edd_info(u8 devno, struct edd_info *ei)
diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c
index 401ad99..1e6fe02 100644
--- a/arch/x86/boot/video-vesa.c
+++ b/arch/x86/boot/video-vesa.c
@@ -224,7 +224,7 @@
static void vesa_store_mode_params_graphics(void)
{
/* Tell the kernel we're in VESA graphics mode */
- boot_params.screen_info.orig_video_isVGA = 0x23;
+ boot_params.screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
/* Mode parameters */
boot_params.screen_info.vesa_attributes = vminfo.mode_attr;
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index ef9a520..ca226ca 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -1535,7 +1535,6 @@
CONFIG_VGA_CONSOLE=y
CONFIG_VGACON_SOFT_SCROLLBACK=y
CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
-CONFIG_VIDEO_SELECT=y
CONFIG_DUMMY_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE is not set
CONFIG_LOGO=y
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index e620ea6..2c4b1c7 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -1505,7 +1505,6 @@
CONFIG_VGA_CONSOLE=y
CONFIG_VGACON_SOFT_SCROLLBACK=y
CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
-CONFIG_VIDEO_SELECT=y
CONFIG_DUMMY_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE is not set
CONFIG_LOGO=y
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 8d64c1b..4bc02b2 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -351,31 +351,28 @@
savesegment(es, tmp);
err |= __put_user(tmp, (unsigned int __user *)&sc->es);
- err |= __put_user((u32)regs->di, &sc->di);
- err |= __put_user((u32)regs->si, &sc->si);
- err |= __put_user((u32)regs->bp, &sc->bp);
- err |= __put_user((u32)regs->sp, &sc->sp);
- err |= __put_user((u32)regs->bx, &sc->bx);
- err |= __put_user((u32)regs->dx, &sc->dx);
- err |= __put_user((u32)regs->cx, &sc->cx);
- err |= __put_user((u32)regs->ax, &sc->ax);
- err |= __put_user((u32)regs->cs, &sc->cs);
- err |= __put_user((u32)regs->ss, &sc->ss);
+ err |= __put_user(regs->di, &sc->di);
+ err |= __put_user(regs->si, &sc->si);
+ err |= __put_user(regs->bp, &sc->bp);
+ err |= __put_user(regs->sp, &sc->sp);
+ err |= __put_user(regs->bx, &sc->bx);
+ err |= __put_user(regs->dx, &sc->dx);
+ err |= __put_user(regs->cx, &sc->cx);
+ err |= __put_user(regs->ax, &sc->ax);
+ err |= __put_user(regs->cs, &sc->cs);
+ err |= __put_user(regs->ss, &sc->ss);
err |= __put_user(current->thread.trap_no, &sc->trapno);
err |= __put_user(current->thread.error_code, &sc->err);
- err |= __put_user((u32)regs->ip, &sc->ip);
- err |= __put_user((u32)regs->flags, &sc->flags);
- err |= __put_user((u32)regs->sp, &sc->sp_at_signal);
+ err |= __put_user(regs->ip, &sc->ip);
+ err |= __put_user(regs->flags, &sc->flags);
+ err |= __put_user(regs->sp, &sc->sp_at_signal);
tmp = save_i387_xstate_ia32(fpstate);
if (tmp < 0)
err = -EFAULT;
- else {
- clear_used_math();
- stts();
+ else
err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
&sc->fpstate);
- }
/* non-iBCS2 extensions.. */
err |= __put_user(mask, &sc->oldmask);
@@ -444,21 +441,18 @@
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return -EFAULT;
- err |= __put_user(sig, &frame->sig);
- if (err)
- goto give_sigsegv;
+ if (__put_user(sig, &frame->sig))
+ return -EFAULT;
- err |= ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
- if (err)
- goto give_sigsegv;
+ if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
+ return -EFAULT;
if (_COMPAT_NSIG_WORDS > 1) {
- err |= __copy_to_user(frame->extramask, &set->sig[1],
- sizeof(frame->extramask));
- if (err)
- goto give_sigsegv;
+ if (__copy_to_user(frame->extramask, &set->sig[1],
+ sizeof(frame->extramask)))
+ return -EFAULT;
}
if (ka->sa.sa_flags & SA_RESTORER) {
@@ -479,7 +473,7 @@
*/
err |= __copy_to_user(frame->retcode, &code, 8);
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up registers for signal handler */
regs->sp = (unsigned long) frame;
@@ -502,10 +496,6 @@
#endif
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -533,14 +523,14 @@
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return -EFAULT;
err |= __put_user(sig, &frame->sig);
err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo);
err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc);
err |= copy_siginfo_to_user32(&frame->info, info);
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Create the ucontext. */
if (cpu_has_xsave)
@@ -556,7 +546,7 @@
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
- goto give_sigsegv;
+ return -EFAULT;
if (ka->sa.sa_flags & SA_RESTORER)
restorer = ka->sa.sa_restorer;
@@ -571,7 +561,7 @@
*/
err |= __copy_to_user(frame->retcode, &code, 8);
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up registers for signal handler */
regs->sp = (unsigned long) frame;
@@ -599,8 +589,4 @@
#endif
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index c9be69f..5098585 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -10,7 +10,7 @@
# Do not profile debug and lowlevel utilities
CFLAGS_REMOVE_tsc.o = -pg
CFLAGS_REMOVE_rtc.o = -pg
-CFLAGS_REMOVE_paravirt.o = -pg
+CFLAGS_REMOVE_paravirt-spinlocks.o = -pg
endif
#
@@ -51,7 +51,6 @@
obj-$(CONFIG_MCA) += mca_32.o
obj-$(CONFIG_X86_MSR) += msr.o
obj-$(CONFIG_X86_CPUID) += cpuid.o
-obj-$(CONFIG_MICROCODE) += microcode.o
obj-$(CONFIG_PCI) += early-quirks.o
apm-y := apm_32.o
obj-$(CONFIG_APM) += apm.o
@@ -90,7 +89,7 @@
obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o
obj-$(CONFIG_KVM_GUEST) += kvm.o
obj-$(CONFIG_KVM_CLOCK) += kvmclock.o
-obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch_$(BITS).o
+obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch_$(BITS).o paravirt-spinlocks.o
obj-$(CONFIG_PARAVIRT_CLOCK) += pvclock.o
obj-$(CONFIG_PCSPKR_PLATFORM) += pcspeaker.o
@@ -100,6 +99,11 @@
obj-$(CONFIG_OLPC) += olpc.o
+microcode-y := microcode_core.o
+microcode-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o
+microcode-$(CONFIG_MICROCODE_AMD) += microcode_amd.o
+obj-$(CONFIG_MICROCODE) += microcode.o
+
###
# 64 bit specific files
ifeq ($(CONFIG_X86_64),y)
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index c2ac1b4..eb875cd 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -1418,8 +1418,16 @@
*/
static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
{
- pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n", d->ident);
- acpi_skip_timer_override = 1;
+ /*
+ * The ati_ixp4x0_rev() early PCI quirk should have set
+ * the acpi_skip_timer_override flag already:
+ */
+ if (!acpi_skip_timer_override) {
+ WARN(1, KERN_ERR "ati_ixp4x0 quirk not complete.\n");
+ pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n",
+ d->ident);
+ acpi_skip_timer_override = 1;
+ }
return 0;
}
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c
index 148fcfe..4cd8083 100644
--- a/arch/x86/kernel/amd_iommu_init.c
+++ b/arch/x86/kernel/amd_iommu_init.c
@@ -723,9 +723,7 @@
init_iommu_from_acpi(iommu, h);
init_iommu_devices(iommu);
- pci_enable_device(iommu->dev);
-
- return 0;
+ return pci_enable_device(iommu->dev);
}
/*
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 7581b62..fb789dd 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1121,16 +1121,5 @@
xsave_init();
}
-#ifdef CONFIG_HOTPLUG_CPU
-void __cpuinit cpu_uninit(void)
-{
- int cpu = raw_smp_processor_id();
- cpu_clear(cpu, cpu_initialized);
-
- /* lazy TLB state */
- per_cpu(cpu_tlbstate, cpu).state = 0;
- per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
-}
-#endif
#endif
diff --git a/arch/x86/kernel/doublefault_32.c b/arch/x86/kernel/doublefault_32.c
index a47798b..395acb1 100644
--- a/arch/x86/kernel/doublefault_32.c
+++ b/arch/x86/kernel/doublefault_32.c
@@ -66,6 +66,6 @@
.ds = __USER_DS,
.fs = __KERNEL_PERCPU,
- .__cr3 = __pa(swapper_pg_dir)
+ .__cr3 = __phys_addr_const((unsigned long)swapper_pg_dir)
}
};
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index 24bb5fa..733c4f8 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -95,6 +95,52 @@
}
+static u32 ati_ixp4x0_rev(int num, int slot, int func)
+{
+ u32 d;
+ u8 b;
+
+ b = read_pci_config_byte(num, slot, func, 0xac);
+ b &= ~(1<<5);
+ write_pci_config_byte(num, slot, func, 0xac, b);
+
+ d = read_pci_config(num, slot, func, 0x70);
+ d |= 1<<8;
+ write_pci_config(num, slot, func, 0x70, d);
+
+ d = read_pci_config(num, slot, func, 0x8);
+ d &= 0xff;
+ return d;
+}
+
+static void __init ati_bugs(int num, int slot, int func)
+{
+#if defined(CONFIG_ACPI) && defined (CONFIG_X86_IO_APIC)
+ u32 d;
+ u8 b;
+
+ if (acpi_use_timer_override)
+ return;
+
+ d = ati_ixp4x0_rev(num, slot, func);
+ if (d < 0x82)
+ acpi_skip_timer_override = 1;
+ else {
+ /* check for IRQ0 interrupt swap */
+ outb(0x72, 0xcd6); b = inb(0xcd7);
+ if (!(b & 0x2))
+ acpi_skip_timer_override = 1;
+ }
+
+ if (acpi_skip_timer_override) {
+ printk(KERN_INFO "SB4X0 revision 0x%x\n", d);
+ printk(KERN_INFO "Ignoring ACPI timer override.\n");
+ printk(KERN_INFO "If you got timer trouble "
+ "try acpi_use_timer_override\n");
+ }
+#endif
+}
+
#ifdef CONFIG_DMAR
static void __init intel_g33_dmar(int num, int slot, int func)
{
@@ -128,6 +174,8 @@
PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, via_bugs },
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB,
PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config },
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
+ PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs },
#ifdef CONFIG_DMAR
{ PCI_VENDOR_ID_INTEL, 0x29c0,
PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, intel_g33_dmar },
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index ff9e735..34ad997 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -3,11 +3,19 @@
#include <linux/init.h>
#include <linux/string.h>
#include <linux/screen_info.h>
+#include <linux/usb/ch9.h>
+#include <linux/pci_regs.h>
+#include <linux/pci_ids.h>
+#include <linux/errno.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/fcntl.h>
#include <asm/setup.h>
#include <xen/hvc-console.h>
+#include <asm/pci-direct.h>
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
+#include <linux/usb/ehci_def.h>
/* Simple VGA output */
#define VGABASE (__ISA_IO_base + 0xb8000)
@@ -78,6 +86,7 @@
static int early_serial_putc(unsigned char ch)
{
unsigned timeout = 0xffff;
+
while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
cpu_relax();
outb(ch, early_serial_base + TXR);
@@ -111,7 +120,7 @@
if (!strncmp(s, "0x", 2)) {
early_serial_base = simple_strtoul(s, &e, 16);
} else {
- static int bases[] = { 0x3f8, 0x2f8 };
+ static const int __initconst bases[] = { 0x3f8, 0x2f8 };
if (!strncmp(s, "ttyS", 4))
s += 4;
@@ -151,6 +160,721 @@
.index = -1,
};
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+
+static struct ehci_caps __iomem *ehci_caps;
+static struct ehci_regs __iomem *ehci_regs;
+static struct ehci_dbg_port __iomem *ehci_debug;
+static unsigned int dbgp_endpoint_out;
+
+struct ehci_dev {
+ u32 bus;
+ u32 slot;
+ u32 func;
+};
+
+static struct ehci_dev ehci_dev;
+
+#define USB_DEBUG_DEVNUM 127
+
+#define DBGP_DATA_TOGGLE 0x8800
+
+static inline u32 dbgp_pid_update(u32 x, u32 tok)
+{
+ return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff);
+}
+
+static inline u32 dbgp_len_update(u32 x, u32 len)
+{
+ return (x & ~0x0f) | (len & 0x0f);
+}
+
+/*
+ * USB Packet IDs (PIDs)
+ */
+
+/* token */
+#define USB_PID_OUT 0xe1
+#define USB_PID_IN 0x69
+#define USB_PID_SOF 0xa5
+#define USB_PID_SETUP 0x2d
+/* handshake */
+#define USB_PID_ACK 0xd2
+#define USB_PID_NAK 0x5a
+#define USB_PID_STALL 0x1e
+#define USB_PID_NYET 0x96
+/* data */
+#define USB_PID_DATA0 0xc3
+#define USB_PID_DATA1 0x4b
+#define USB_PID_DATA2 0x87
+#define USB_PID_MDATA 0x0f
+/* Special */
+#define USB_PID_PREAMBLE 0x3c
+#define USB_PID_ERR 0x3c
+#define USB_PID_SPLIT 0x78
+#define USB_PID_PING 0xb4
+#define USB_PID_UNDEF_0 0xf0
+
+#define USB_PID_DATA_TOGGLE 0x88
+#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE)
+
+#define PCI_CAP_ID_EHCI_DEBUG 0xa
+
+#define HUB_ROOT_RESET_TIME 50 /* times are in msec */
+#define HUB_SHORT_RESET_TIME 10
+#define HUB_LONG_RESET_TIME 200
+#define HUB_RESET_TIMEOUT 500
+
+#define DBGP_MAX_PACKET 8
+
+static int dbgp_wait_until_complete(void)
+{
+ u32 ctrl;
+ int loop = 0x100000;
+
+ do {
+ ctrl = readl(&ehci_debug->control);
+ /* Stop when the transaction is finished */
+ if (ctrl & DBGP_DONE)
+ break;
+ } while (--loop > 0);
+
+ if (!loop)
+ return -1;
+
+ /*
+ * Now that we have observed the completed transaction,
+ * clear the done bit.
+ */
+ writel(ctrl | DBGP_DONE, &ehci_debug->control);
+ return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl);
+}
+
+static void dbgp_mdelay(int ms)
+{
+ int i;
+
+ while (ms--) {
+ for (i = 0; i < 1000; i++)
+ outb(0x1, 0x80);
+ }
+}
+
+static void dbgp_breath(void)
+{
+ /* Sleep to give the debug port a chance to breathe */
+}
+
+static int dbgp_wait_until_done(unsigned ctrl)
+{
+ u32 pids, lpid;
+ int ret;
+ int loop = 3;
+
+retry:
+ writel(ctrl | DBGP_GO, &ehci_debug->control);
+ ret = dbgp_wait_until_complete();
+ pids = readl(&ehci_debug->pids);
+ lpid = DBGP_PID_GET(pids);
+
+ if (ret < 0)
+ return ret;
+
+ /*
+ * If the port is getting full or it has dropped data
+ * start pacing ourselves, not necessary but it's friendly.
+ */
+ if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET))
+ dbgp_breath();
+
+ /* If I get a NACK reissue the transmission */
+ if (lpid == USB_PID_NAK) {
+ if (--loop > 0)
+ goto retry;
+ }
+
+ return ret;
+}
+
+static void dbgp_set_data(const void *buf, int size)
+{
+ const unsigned char *bytes = buf;
+ u32 lo, hi;
+ int i;
+
+ lo = hi = 0;
+ for (i = 0; i < 4 && i < size; i++)
+ lo |= bytes[i] << (8*i);
+ for (; i < 8 && i < size; i++)
+ hi |= bytes[i] << (8*(i - 4));
+ writel(lo, &ehci_debug->data03);
+ writel(hi, &ehci_debug->data47);
+}
+
+static void dbgp_get_data(void *buf, int size)
+{
+ unsigned char *bytes = buf;
+ u32 lo, hi;
+ int i;
+
+ lo = readl(&ehci_debug->data03);
+ hi = readl(&ehci_debug->data47);
+ for (i = 0; i < 4 && i < size; i++)
+ bytes[i] = (lo >> (8*i)) & 0xff;
+ for (; i < 8 && i < size; i++)
+ bytes[i] = (hi >> (8*(i - 4))) & 0xff;
+}
+
+static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
+ const char *bytes, int size)
+{
+ u32 pids, addr, ctrl;
+ int ret;
+
+ if (size > DBGP_MAX_PACKET)
+ return -1;
+
+ addr = DBGP_EPADDR(devnum, endpoint);
+
+ pids = readl(&ehci_debug->pids);
+ pids = dbgp_pid_update(pids, USB_PID_OUT);
+
+ ctrl = readl(&ehci_debug->control);
+ ctrl = dbgp_len_update(ctrl, size);
+ ctrl |= DBGP_OUT;
+ ctrl |= DBGP_GO;
+
+ dbgp_set_data(bytes, size);
+ writel(addr, &ehci_debug->address);
+ writel(pids, &ehci_debug->pids);
+
+ ret = dbgp_wait_until_done(ctrl);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
+ int size)
+{
+ u32 pids, addr, ctrl;
+ int ret;
+
+ if (size > DBGP_MAX_PACKET)
+ return -1;
+
+ addr = DBGP_EPADDR(devnum, endpoint);
+
+ pids = readl(&ehci_debug->pids);
+ pids = dbgp_pid_update(pids, USB_PID_IN);
+
+ ctrl = readl(&ehci_debug->control);
+ ctrl = dbgp_len_update(ctrl, size);
+ ctrl &= ~DBGP_OUT;
+ ctrl |= DBGP_GO;
+
+ writel(addr, &ehci_debug->address);
+ writel(pids, &ehci_debug->pids);
+ ret = dbgp_wait_until_done(ctrl);
+ if (ret < 0)
+ return ret;
+
+ if (size > ret)
+ size = ret;
+ dbgp_get_data(data, size);
+ return ret;
+}
+
+static int dbgp_control_msg(unsigned devnum, int requesttype, int request,
+ int value, int index, void *data, int size)
+{
+ u32 pids, addr, ctrl;
+ struct usb_ctrlrequest req;
+ int read;
+ int ret;
+
+ read = (requesttype & USB_DIR_IN) != 0;
+ if (size > (read ? DBGP_MAX_PACKET:0))
+ return -1;
+
+ /* Compute the control message */
+ req.bRequestType = requesttype;
+ req.bRequest = request;
+ req.wValue = cpu_to_le16(value);
+ req.wIndex = cpu_to_le16(index);
+ req.wLength = cpu_to_le16(size);
+
+ pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP);
+ addr = DBGP_EPADDR(devnum, 0);
+
+ ctrl = readl(&ehci_debug->control);
+ ctrl = dbgp_len_update(ctrl, sizeof(req));
+ ctrl |= DBGP_OUT;
+ ctrl |= DBGP_GO;
+
+ /* Send the setup message */
+ dbgp_set_data(&req, sizeof(req));
+ writel(addr, &ehci_debug->address);
+ writel(pids, &ehci_debug->pids);
+ ret = dbgp_wait_until_done(ctrl);
+ if (ret < 0)
+ return ret;
+
+ /* Read the result */
+ return dbgp_bulk_read(devnum, 0, data, size);
+}
+
+
+/* Find a PCI capability */
+static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap)
+{
+ u8 pos;
+ int bytes;
+
+ if (!(read_pci_config_16(num, slot, func, PCI_STATUS) &
+ PCI_STATUS_CAP_LIST))
+ return 0;
+
+ pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST);
+ for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
+ u8 id;
+
+ pos &= ~3;
+ id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID);
+ if (id == 0xff)
+ break;
+ if (id == cap)
+ return pos;
+
+ pos = read_pci_config_byte(num, slot, func,
+ pos+PCI_CAP_LIST_NEXT);
+ }
+ return 0;
+}
+
+static u32 __init __find_dbgp(u32 bus, u32 slot, u32 func)
+{
+ u32 class;
+
+ class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION);
+ if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI)
+ return 0;
+
+ return find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG);
+}
+
+static u32 __init find_dbgp(int ehci_num, u32 *rbus, u32 *rslot, u32 *rfunc)
+{
+ u32 bus, slot, func;
+
+ for (bus = 0; bus < 256; bus++) {
+ for (slot = 0; slot < 32; slot++) {
+ for (func = 0; func < 8; func++) {
+ unsigned cap;
+
+ cap = __find_dbgp(bus, slot, func);
+
+ if (!cap)
+ continue;
+ if (ehci_num-- != 0)
+ continue;
+ *rbus = bus;
+ *rslot = slot;
+ *rfunc = func;
+ return cap;
+ }
+ }
+ }
+ return 0;
+}
+
+static int ehci_reset_port(int port)
+{
+ u32 portsc;
+ u32 delay_time, delay;
+ int loop;
+
+ /* Reset the usb debug port */
+ portsc = readl(&ehci_regs->port_status[port - 1]);
+ portsc &= ~PORT_PE;
+ portsc |= PORT_RESET;
+ writel(portsc, &ehci_regs->port_status[port - 1]);
+
+ delay = HUB_ROOT_RESET_TIME;
+ for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT;
+ delay_time += delay) {
+ dbgp_mdelay(delay);
+
+ portsc = readl(&ehci_regs->port_status[port - 1]);
+ if (portsc & PORT_RESET) {
+ /* force reset to complete */
+ loop = 2;
+ writel(portsc & ~(PORT_RWC_BITS | PORT_RESET),
+ &ehci_regs->port_status[port - 1]);
+ do {
+ portsc = readl(&ehci_regs->port_status[port-1]);
+ } while ((portsc & PORT_RESET) && (--loop > 0));
+ }
+
+ /* Device went away? */
+ if (!(portsc & PORT_CONNECT))
+ return -ENOTCONN;
+
+ /* bomb out completely if something weird happend */
+ if ((portsc & PORT_CSC))
+ return -EINVAL;
+
+ /* If we've finished resetting, then break out of the loop */
+ if (!(portsc & PORT_RESET) && (portsc & PORT_PE))
+ return 0;
+ }
+ return -EBUSY;
+}
+
+static int ehci_wait_for_port(int port)
+{
+ u32 status;
+ int ret, reps;
+
+ for (reps = 0; reps < 3; reps++) {
+ dbgp_mdelay(100);
+ status = readl(&ehci_regs->status);
+ if (status & STS_PCD) {
+ ret = ehci_reset_port(port);
+ if (ret == 0)
+ return 0;
+ }
+ }
+ return -ENOTCONN;
+}
+
+#ifdef DBGP_DEBUG
+# define dbgp_printk early_printk
+#else
+static inline void dbgp_printk(const char *fmt, ...) { }
+#endif
+
+typedef void (*set_debug_port_t)(int port);
+
+static void default_set_debug_port(int port)
+{
+}
+
+static set_debug_port_t set_debug_port = default_set_debug_port;
+
+static void nvidia_set_debug_port(int port)
+{
+ u32 dword;
+ dword = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
+ 0x74);
+ dword &= ~(0x0f<<12);
+ dword |= ((port & 0x0f)<<12);
+ write_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, 0x74,
+ dword);
+ dbgp_printk("set debug port to %d\n", port);
+}
+
+static void __init detect_set_debug_port(void)
+{
+ u32 vendorid;
+
+ vendorid = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
+ 0x00);
+
+ if ((vendorid & 0xffff) == 0x10de) {
+ dbgp_printk("using nvidia set_debug_port\n");
+ set_debug_port = nvidia_set_debug_port;
+ }
+}
+
+static int __init ehci_setup(void)
+{
+ struct usb_debug_descriptor dbgp_desc;
+ u32 cmd, ctrl, status, portsc, hcs_params;
+ u32 debug_port, new_debug_port = 0, n_ports;
+ u32 devnum;
+ int ret, i;
+ int loop;
+ int port_map_tried;
+ int playtimes = 3;
+
+try_next_time:
+ port_map_tried = 0;
+
+try_next_port:
+
+ hcs_params = readl(&ehci_caps->hcs_params);
+ debug_port = HCS_DEBUG_PORT(hcs_params);
+ n_ports = HCS_N_PORTS(hcs_params);
+
+ dbgp_printk("debug_port: %d\n", debug_port);
+ dbgp_printk("n_ports: %d\n", n_ports);
+
+ for (i = 1; i <= n_ports; i++) {
+ portsc = readl(&ehci_regs->port_status[i-1]);
+ dbgp_printk("portstatus%d: %08x\n", i, portsc);
+ }
+
+ if (port_map_tried && (new_debug_port != debug_port)) {
+ if (--playtimes) {
+ set_debug_port(new_debug_port);
+ goto try_next_time;
+ }
+ return -1;
+ }
+
+ loop = 10;
+ /* Reset the EHCI controller */
+ cmd = readl(&ehci_regs->command);
+ cmd |= CMD_RESET;
+ writel(cmd, &ehci_regs->command);
+ do {
+ cmd = readl(&ehci_regs->command);
+ } while ((cmd & CMD_RESET) && (--loop > 0));
+
+ if (!loop) {
+ dbgp_printk("can not reset ehci\n");
+ return -1;
+ }
+ dbgp_printk("ehci reset done\n");
+
+ /* Claim ownership, but do not enable yet */
+ ctrl = readl(&ehci_debug->control);
+ ctrl |= DBGP_OWNER;
+ ctrl &= ~(DBGP_ENABLED | DBGP_INUSE);
+ writel(ctrl, &ehci_debug->control);
+
+ /* Start the ehci running */
+ cmd = readl(&ehci_regs->command);
+ cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET);
+ cmd |= CMD_RUN;
+ writel(cmd, &ehci_regs->command);
+
+ /* Ensure everything is routed to the EHCI */
+ writel(FLAG_CF, &ehci_regs->configured_flag);
+
+ /* Wait until the controller is no longer halted */
+ loop = 10;
+ do {
+ status = readl(&ehci_regs->status);
+ } while ((status & STS_HALT) && (--loop > 0));
+
+ if (!loop) {
+ dbgp_printk("ehci can be started\n");
+ return -1;
+ }
+ dbgp_printk("ehci started\n");
+
+ /* Wait for a device to show up in the debug port */
+ ret = ehci_wait_for_port(debug_port);
+ if (ret < 0) {
+ dbgp_printk("No device found in debug port\n");
+ goto next_debug_port;
+ }
+ dbgp_printk("ehci wait for port done\n");
+
+ /* Enable the debug port */
+ ctrl = readl(&ehci_debug->control);
+ ctrl |= DBGP_CLAIM;
+ writel(ctrl, &ehci_debug->control);
+ ctrl = readl(&ehci_debug->control);
+ if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) {
+ dbgp_printk("No device in debug port\n");
+ writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control);
+ goto err;
+ }
+ dbgp_printk("debug ported enabled\n");
+
+ /* Completely transfer the debug device to the debug controller */
+ portsc = readl(&ehci_regs->port_status[debug_port - 1]);
+ portsc &= ~PORT_PE;
+ writel(portsc, &ehci_regs->port_status[debug_port - 1]);
+
+ dbgp_mdelay(100);
+
+ /* Find the debug device and make it device number 127 */
+ for (devnum = 0; devnum <= 127; devnum++) {
+ ret = dbgp_control_msg(devnum,
+ USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0,
+ &dbgp_desc, sizeof(dbgp_desc));
+ if (ret > 0)
+ break;
+ }
+ if (devnum > 127) {
+ dbgp_printk("Could not find attached debug device\n");
+ goto err;
+ }
+ if (ret < 0) {
+ dbgp_printk("Attached device is not a debug device\n");
+ goto err;
+ }
+ dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint;
+
+ /* Move the device to 127 if it isn't already there */
+ if (devnum != USB_DEBUG_DEVNUM) {
+ ret = dbgp_control_msg(devnum,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0);
+ if (ret < 0) {
+ dbgp_printk("Could not move attached device to %d\n",
+ USB_DEBUG_DEVNUM);
+ goto err;
+ }
+ devnum = USB_DEBUG_DEVNUM;
+ dbgp_printk("debug device renamed to 127\n");
+ }
+
+ /* Enable the debug interface */
+ ret = dbgp_control_msg(USB_DEBUG_DEVNUM,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0);
+ if (ret < 0) {
+ dbgp_printk(" Could not enable the debug device\n");
+ goto err;
+ }
+ dbgp_printk("debug interface enabled\n");
+
+ /* Perform a small write to get the even/odd data state in sync
+ */
+ ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ", 1);
+ if (ret < 0) {
+ dbgp_printk("dbgp_bulk_write failed: %d\n", ret);
+ goto err;
+ }
+ dbgp_printk("small write doned\n");
+
+ return 0;
+err:
+ /* Things didn't work so remove my claim */
+ ctrl = readl(&ehci_debug->control);
+ ctrl &= ~(DBGP_CLAIM | DBGP_OUT);
+ writel(ctrl, &ehci_debug->control);
+ return -1;
+
+next_debug_port:
+ port_map_tried |= (1<<(debug_port - 1));
+ new_debug_port = ((debug_port-1+1)%n_ports) + 1;
+ if (port_map_tried != ((1<<n_ports) - 1)) {
+ set_debug_port(new_debug_port);
+ goto try_next_port;
+ }
+ if (--playtimes) {
+ set_debug_port(new_debug_port);
+ goto try_next_time;
+ }
+
+ return -1;
+}
+
+static int __init early_dbgp_init(char *s)
+{
+ u32 debug_port, bar, offset;
+ u32 bus, slot, func, cap;
+ void __iomem *ehci_bar;
+ u32 dbgp_num;
+ u32 bar_val;
+ char *e;
+ int ret;
+ u8 byte;
+
+ if (!early_pci_allowed())
+ return -1;
+
+ dbgp_num = 0;
+ if (*s)
+ dbgp_num = simple_strtoul(s, &e, 10);
+ dbgp_printk("dbgp_num: %d\n", dbgp_num);
+
+ cap = find_dbgp(dbgp_num, &bus, &slot, &func);
+ if (!cap)
+ return -1;
+
+ dbgp_printk("Found EHCI debug port on %02x:%02x.%1x\n", bus, slot,
+ func);
+
+ debug_port = read_pci_config(bus, slot, func, cap);
+ bar = (debug_port >> 29) & 0x7;
+ bar = (bar * 4) + 0xc;
+ offset = (debug_port >> 16) & 0xfff;
+ dbgp_printk("bar: %02x offset: %03x\n", bar, offset);
+ if (bar != PCI_BASE_ADDRESS_0) {
+ dbgp_printk("only debug ports on bar 1 handled.\n");
+
+ return -1;
+ }
+
+ bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
+ dbgp_printk("bar_val: %02x offset: %03x\n", bar_val, offset);
+ if (bar_val & ~PCI_BASE_ADDRESS_MEM_MASK) {
+ dbgp_printk("only simple 32bit mmio bars supported\n");
+
+ return -1;
+ }
+
+ /* double check if the mem space is enabled */
+ byte = read_pci_config_byte(bus, slot, func, 0x04);
+ if (!(byte & 0x2)) {
+ byte |= 0x02;
+ write_pci_config_byte(bus, slot, func, 0x04, byte);
+ dbgp_printk("mmio for ehci enabled\n");
+ }
+
+ /*
+ * FIXME I don't have the bar size so just guess PAGE_SIZE is more
+ * than enough. 1K is the biggest I have seen.
+ */
+ set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK);
+ ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE);
+ ehci_bar += bar_val & ~PAGE_MASK;
+ dbgp_printk("ehci_bar: %p\n", ehci_bar);
+
+ ehci_caps = ehci_bar;
+ ehci_regs = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase));
+ ehci_debug = ehci_bar + offset;
+ ehci_dev.bus = bus;
+ ehci_dev.slot = slot;
+ ehci_dev.func = func;
+
+ detect_set_debug_port();
+
+ ret = ehci_setup();
+ if (ret < 0) {
+ dbgp_printk("ehci_setup failed\n");
+ ehci_debug = NULL;
+
+ return -1;
+ }
+
+ return 0;
+}
+
+static void early_dbgp_write(struct console *con, const char *str, u32 n)
+{
+ int chunk, ret;
+
+ if (!ehci_debug)
+ return;
+ while (n > 0) {
+ chunk = n;
+ if (chunk > DBGP_MAX_PACKET)
+ chunk = DBGP_MAX_PACKET;
+ ret = dbgp_bulk_write(USB_DEBUG_DEVNUM,
+ dbgp_endpoint_out, str, chunk);
+ str += chunk;
+ n -= chunk;
+ }
+}
+
+static struct console early_dbgp_console = {
+ .name = "earlydbg",
+ .write = early_dbgp_write,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+#endif
+
/* Console interface to a host file on AMD's SimNow! */
static int simnow_fd;
@@ -165,6 +889,7 @@
static noinline long simnow(long cmd, long a, long b, long c)
{
long ret;
+
asm volatile("cpuid" :
"=a" (ret) :
"b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2));
@@ -174,6 +899,7 @@
static void __init simnow_init(char *str)
{
char *fn = "klog";
+
if (*str == '=')
fn = ++str;
/* error ignored */
@@ -194,7 +920,7 @@
/* Direct interface for emergencies */
static struct console *early_console = &early_vga_console;
-static int early_console_initialized;
+static int __initdata early_console_initialized;
asmlinkage void early_printk(const char *fmt, ...)
{
@@ -208,10 +934,11 @@
va_end(ap);
}
-static int __initdata keep_early;
static int __init setup_early_printk(char *buf)
{
+ int keep_early;
+
if (!buf)
return 0;
@@ -219,8 +946,7 @@
return 0;
early_console_initialized = 1;
- if (strstr(buf, "keep"))
- keep_early = 1;
+ keep_early = (strstr(buf, "keep") != NULL);
if (!strncmp(buf, "serial", 6)) {
early_serial_init(buf + 6);
@@ -238,6 +964,17 @@
simnow_init(buf + 6);
early_console = &simnow_console;
keep_early = 1;
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+ } else if (!strncmp(buf, "dbgp", 4)) {
+ if (early_dbgp_init(buf+4) < 0)
+ return 0;
+ early_console = &early_dbgp_console;
+ /*
+ * usb subsys will reset ehci controller, so don't keep
+ * that early console
+ */
+ keep_early = 0;
+#endif
#ifdef CONFIG_HVC_XEN
} else if (!strncmp(buf, "xen", 3)) {
early_console = &xenboot_console;
@@ -251,4 +988,5 @@
register_console(early_console);
return 0;
}
+
early_param("earlyprintk", setup_early_printk);
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 45723f1..1f20608 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -468,9 +468,23 @@
static int save_i387_xsave(void __user *buf)
{
+ struct task_struct *tsk = current;
struct _fpstate_ia32 __user *fx = buf;
int err = 0;
+ /*
+ * For legacy compatible, we always set FP/SSE bits in the bit
+ * vector while saving the state to the user context.
+ * This will enable us capturing any changes(during sigreturn) to
+ * the FP/SSE bits by the legacy applications which don't touch
+ * xstate_bv in the xsave header.
+ *
+ * xsave aware applications can change the xstate_bv in the xsave
+ * header as well as change any contents in the memory layout.
+ * xrestore as part of sigreturn will capture all the changes.
+ */
+ tsk->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
+
if (save_i387_fxsave(fx) < 0)
return -1;
diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c
index a1bec29..02063ae 100644
--- a/arch/x86/kernel/io_apic_64.c
+++ b/arch/x86/kernel/io_apic_64.c
@@ -1281,8 +1281,8 @@
printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
icr = apic_icr_read();
- printk(KERN_DEBUG "... APIC ICR: %08x\n", icr);
- printk(KERN_DEBUG "... APIC ICR2: %08x\n", icr >> 32);
+ printk(KERN_DEBUG "... APIC ICR: %08x\n", (u32)icr);
+ printk(KERN_DEBUG "... APIC ICR2: %08x\n", (u32)(icr >> 32));
v = apic_read(APIC_LVTT);
printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
index 0ed5f93..eee32b4 100644
--- a/arch/x86/kernel/ldt.c
+++ b/arch/x86/kernel/ldt.c
@@ -52,6 +52,8 @@
memset(newldt + oldsize * LDT_ENTRY_SIZE, 0,
(mincount - oldsize) * LDT_ENTRY_SIZE);
+ paravirt_alloc_ldt(newldt, mincount);
+
#ifdef CONFIG_X86_64
/* CHECKME: Do we really need this ? */
wmb();
@@ -74,6 +76,7 @@
#endif
}
if (oldsize) {
+ paravirt_free_ldt(oldldt, oldsize);
if (oldsize * LDT_ENTRY_SIZE > PAGE_SIZE)
vfree(oldldt);
else
@@ -85,10 +88,13 @@
static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
{
int err = alloc_ldt(new, old->size, 0);
+ int i;
if (err < 0)
return err;
- memcpy(new->ldt, old->ldt, old->size * LDT_ENTRY_SIZE);
+
+ for(i = 0; i < old->size; i++)
+ write_ldt_entry(new->ldt, i, old->ldt + i * LDT_ENTRY_SIZE);
return 0;
}
@@ -125,6 +131,7 @@
if (mm == current->active_mm)
clear_LDT();
#endif
+ paravirt_free_ldt(mm->context.ldt, mm->context.size);
if (mm->context.size * LDT_ENTRY_SIZE > PAGE_SIZE)
vfree(mm->context.ldt);
else
diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c
deleted file mode 100644
index 652fa5c..0000000
--- a/arch/x86/kernel/microcode.c
+++ /dev/null
@@ -1,853 +0,0 @@
-/*
- * Intel CPU Microcode Update Driver for Linux
- *
- * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
- * 2006 Shaohua Li <shaohua.li@intel.com>
- *
- * This driver allows to upgrade microcode on Intel processors
- * belonging to IA-32 family - PentiumPro, Pentium II,
- * Pentium III, Xeon, Pentium 4, etc.
- *
- * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
- * Software Developer's Manual
- * Order Number 253668 or free download from:
- *
- * http://developer.intel.com/design/pentium4/manuals/253668.htm
- *
- * For more information, go to http://www.urbanmyth.org/microcode
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * 1.0 16 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Initial release.
- * 1.01 18 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Added read() support + cleanups.
- * 1.02 21 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Added 'device trimming' support. open(O_WRONLY) zeroes
- * and frees the saved copy of applied microcode.
- * 1.03 29 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Made to use devfs (/dev/cpu/microcode) + cleanups.
- * 1.04 06 Jun 2000, Simon Trimmer <simon@veritas.com>
- * Added misc device support (now uses both devfs and misc).
- * Added MICROCODE_IOCFREE ioctl to clear memory.
- * 1.05 09 Jun 2000, Simon Trimmer <simon@veritas.com>
- * Messages for error cases (non Intel & no suitable microcode).
- * 1.06 03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
- * Removed ->release(). Removed exclusive open and status bitmap.
- * Added microcode_rwsem to serialize read()/write()/ioctl().
- * Removed global kernel lock usage.
- * 1.07 07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
- * Write 0 to 0x8B msr and then cpuid before reading revision,
- * so that it works even if there were no update done by the
- * BIOS. Otherwise, reading from 0x8B gives junk (which happened
- * to be 0 on my machine which is why it worked even when I
- * disabled update by the BIOS)
- * Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
- * 1.08 11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
- * Tigran Aivazian <tigran@veritas.com>
- * Intel Pentium 4 processor support and bugfixes.
- * 1.09 30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
- * Bugfix for HT (Hyper-Threading) enabled processors
- * whereby processor resources are shared by all logical processors
- * in a single CPU package.
- * 1.10 28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
- * Tigran Aivazian <tigran@veritas.com>,
- * Serialize updates as required on HT processors due to speculative
- * nature of implementation.
- * 1.11 22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
- * Fix the panic when writing zero-length microcode chunk.
- * 1.12 29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
- * Jun Nakajima <jun.nakajima@intel.com>
- * Support for the microcode updates in the new format.
- * 1.13 10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
- * Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
- * because we no longer hold a copy of applied microcode
- * in kernel memory.
- * 1.14 25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
- * Fix sigmatch() macro to handle old CPUs with pf == 0.
- * Thanks to Stuart Swales for pointing out this bug.
- */
-
-//#define DEBUG /* pr_debug */
-#include <linux/capability.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/cpumask.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/miscdevice.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/mutex.h>
-#include <linux/cpu.h>
-#include <linux/firmware.h>
-#include <linux/platform_device.h>
-
-#include <asm/msr.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-
-MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
-MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
-MODULE_LICENSE("GPL");
-
-#define MICROCODE_VERSION "1.14a"
-
-#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */
-#define MC_HEADER_SIZE (sizeof (microcode_header_t)) /* 48 bytes */
-#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */
-#define EXT_HEADER_SIZE (sizeof (struct extended_sigtable)) /* 20 bytes */
-#define EXT_SIGNATURE_SIZE (sizeof (struct extended_signature)) /* 12 bytes */
-#define DWSIZE (sizeof (u32))
-#define get_totalsize(mc) \
- (((microcode_t *)mc)->hdr.totalsize ? \
- ((microcode_t *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE)
-#define get_datasize(mc) \
- (((microcode_t *)mc)->hdr.datasize ? \
- ((microcode_t *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
-
-#define sigmatch(s1, s2, p1, p2) \
- (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
-
-#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
-
-/* serialize access to the physical write to MSR 0x79 */
-static DEFINE_SPINLOCK(microcode_update_lock);
-
-/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
-static DEFINE_MUTEX(microcode_mutex);
-
-static struct ucode_cpu_info {
- int valid;
- unsigned int sig;
- unsigned int pf;
- unsigned int rev;
- microcode_t *mc;
-} ucode_cpu_info[NR_CPUS];
-
-static void collect_cpu_info(int cpu_num)
-{
- struct cpuinfo_x86 *c = &cpu_data(cpu_num);
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
- unsigned int val[2];
-
- /* We should bind the task to the CPU */
- BUG_ON(raw_smp_processor_id() != cpu_num);
- uci->pf = uci->rev = 0;
- uci->mc = NULL;
- uci->valid = 1;
-
- if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
- cpu_has(c, X86_FEATURE_IA64)) {
- printk(KERN_ERR "microcode: CPU%d not a capable Intel "
- "processor\n", cpu_num);
- uci->valid = 0;
- return;
- }
-
- uci->sig = cpuid_eax(0x00000001);
-
- if ((c->x86_model >= 5) || (c->x86 > 6)) {
- /* get processor flags from MSR 0x17 */
- rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
- uci->pf = 1 << ((val[1] >> 18) & 7);
- }
-
- wrmsr(MSR_IA32_UCODE_REV, 0, 0);
- /* see notes above for revision 1.07. Apparent chip bug */
- sync_core();
- /* get the current revision from MSR 0x8B */
- rdmsr(MSR_IA32_UCODE_REV, val[0], uci->rev);
- pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
- uci->sig, uci->pf, uci->rev);
-}
-
-static inline int microcode_update_match(int cpu_num,
- microcode_header_t *mc_header, int sig, int pf)
-{
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-
- if (!sigmatch(sig, uci->sig, pf, uci->pf)
- || mc_header->rev <= uci->rev)
- return 0;
- return 1;
-}
-
-static int microcode_sanity_check(void *mc)
-{
- microcode_header_t *mc_header = mc;
- struct extended_sigtable *ext_header = NULL;
- struct extended_signature *ext_sig;
- unsigned long total_size, data_size, ext_table_size;
- int sum, orig_sum, ext_sigcount = 0, i;
-
- total_size = get_totalsize(mc_header);
- data_size = get_datasize(mc_header);
- if (data_size + MC_HEADER_SIZE > total_size) {
- printk(KERN_ERR "microcode: error! "
- "Bad data size in microcode data file\n");
- return -EINVAL;
- }
-
- if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
- printk(KERN_ERR "microcode: error! "
- "Unknown microcode update format\n");
- return -EINVAL;
- }
- ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
- if (ext_table_size) {
- if ((ext_table_size < EXT_HEADER_SIZE)
- || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
- printk(KERN_ERR "microcode: error! "
- "Small exttable size in microcode data file\n");
- return -EINVAL;
- }
- ext_header = mc + MC_HEADER_SIZE + data_size;
- if (ext_table_size != exttable_size(ext_header)) {
- printk(KERN_ERR "microcode: error! "
- "Bad exttable size in microcode data file\n");
- return -EFAULT;
- }
- ext_sigcount = ext_header->count;
- }
-
- /* check extended table checksum */
- if (ext_table_size) {
- int ext_table_sum = 0;
- int *ext_tablep = (int *)ext_header;
-
- i = ext_table_size / DWSIZE;
- while (i--)
- ext_table_sum += ext_tablep[i];
- if (ext_table_sum) {
- printk(KERN_WARNING "microcode: aborting, "
- "bad extended signature table checksum\n");
- return -EINVAL;
- }
- }
-
- /* calculate the checksum */
- orig_sum = 0;
- i = (MC_HEADER_SIZE + data_size) / DWSIZE;
- while (i--)
- orig_sum += ((int *)mc)[i];
- if (orig_sum) {
- printk(KERN_ERR "microcode: aborting, bad checksum\n");
- return -EINVAL;
- }
- if (!ext_table_size)
- return 0;
- /* check extended signature checksum */
- for (i = 0; i < ext_sigcount; i++) {
- ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
- EXT_SIGNATURE_SIZE * i;
- sum = orig_sum
- - (mc_header->sig + mc_header->pf + mc_header->cksum)
- + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
- if (sum) {
- printk(KERN_ERR "microcode: aborting, bad checksum\n");
- return -EINVAL;
- }
- }
- return 0;
-}
-
-/*
- * return 0 - no update found
- * return 1 - found update
- * return < 0 - error
- */
-static int get_maching_microcode(void *mc, int cpu)
-{
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
- microcode_header_t *mc_header = mc;
- struct extended_sigtable *ext_header;
- unsigned long total_size = get_totalsize(mc_header);
- int ext_sigcount, i;
- struct extended_signature *ext_sig;
- void *new_mc;
-
- if (microcode_update_match(cpu, mc_header,
- mc_header->sig, mc_header->pf))
- goto find;
-
- if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
- return 0;
-
- ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
- ext_sigcount = ext_header->count;
- ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
- for (i = 0; i < ext_sigcount; i++) {
- if (microcode_update_match(cpu, mc_header,
- ext_sig->sig, ext_sig->pf))
- goto find;
- ext_sig++;
- }
- return 0;
-find:
- pr_debug("microcode: CPU%d found a matching microcode update with"
- " version 0x%x (current=0x%x)\n", cpu, mc_header->rev,uci->rev);
- new_mc = vmalloc(total_size);
- if (!new_mc) {
- printk(KERN_ERR "microcode: error! Can not allocate memory\n");
- return -ENOMEM;
- }
-
- /* free previous update file */
- vfree(uci->mc);
-
- memcpy(new_mc, mc, total_size);
- uci->mc = new_mc;
- return 1;
-}
-
-static void apply_microcode(int cpu)
-{
- unsigned long flags;
- unsigned int val[2];
- int cpu_num = raw_smp_processor_id();
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-
- /* We should bind the task to the CPU */
- BUG_ON(cpu_num != cpu);
-
- if (uci->mc == NULL)
- return;
-
- /* serialize access to the physical write to MSR 0x79 */
- spin_lock_irqsave(µcode_update_lock, flags);
-
- /* write microcode via MSR 0x79 */
- wrmsr(MSR_IA32_UCODE_WRITE,
- (unsigned long) uci->mc->bits,
- (unsigned long) uci->mc->bits >> 16 >> 16);
- wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-
- /* see notes above for revision 1.07. Apparent chip bug */
- sync_core();
-
- /* get the current revision from MSR 0x8B */
- rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
-
- spin_unlock_irqrestore(µcode_update_lock, flags);
- if (val[1] != uci->mc->hdr.rev) {
- printk(KERN_ERR "microcode: CPU%d update from revision "
- "0x%x to 0x%x failed\n", cpu_num, uci->rev, val[1]);
- return;
- }
- printk(KERN_INFO "microcode: CPU%d updated from revision "
- "0x%x to 0x%x, date = %08x \n",
- cpu_num, uci->rev, val[1], uci->mc->hdr.date);
- uci->rev = val[1];
-}
-
-#ifdef CONFIG_MICROCODE_OLD_INTERFACE
-static void __user *user_buffer; /* user area microcode data buffer */
-static unsigned int user_buffer_size; /* it's size */
-
-static long get_next_ucode(void **mc, long offset)
-{
- microcode_header_t mc_header;
- unsigned long total_size;
-
- /* No more data */
- if (offset >= user_buffer_size)
- return 0;
- if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) {
- printk(KERN_ERR "microcode: error! Can not read user data\n");
- return -EFAULT;
- }
- total_size = get_totalsize(&mc_header);
- if (offset + total_size > user_buffer_size) {
- printk(KERN_ERR "microcode: error! Bad total size in microcode "
- "data file\n");
- return -EINVAL;
- }
- *mc = vmalloc(total_size);
- if (!*mc)
- return -ENOMEM;
- if (copy_from_user(*mc, user_buffer + offset, total_size)) {
- printk(KERN_ERR "microcode: error! Can not read user data\n");
- vfree(*mc);
- return -EFAULT;
- }
- return offset + total_size;
-}
-
-static int do_microcode_update (void)
-{
- long cursor = 0;
- int error = 0;
- void *new_mc = NULL;
- int cpu;
- cpumask_t old;
-
- old = current->cpus_allowed;
-
- while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
- error = microcode_sanity_check(new_mc);
- if (error)
- goto out;
- /*
- * It's possible the data file has multiple matching ucode,
- * lets keep searching till the latest version
- */
- for_each_online_cpu(cpu) {
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
- if (!uci->valid)
- continue;
- set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
- error = get_maching_microcode(new_mc, cpu);
- if (error < 0)
- goto out;
- if (error == 1)
- apply_microcode(cpu);
- }
- vfree(new_mc);
- }
-out:
- if (cursor > 0)
- vfree(new_mc);
- if (cursor < 0)
- error = cursor;
- set_cpus_allowed_ptr(current, &old);
- return error;
-}
-
-static int microcode_open (struct inode *unused1, struct file *unused2)
-{
- cycle_kernel_lock();
- return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
-}
-
-static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
-{
- ssize_t ret;
-
- if ((len >> PAGE_SHIFT) > num_physpages) {
- printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
- return -EINVAL;
- }
-
- get_online_cpus();
- mutex_lock(µcode_mutex);
-
- user_buffer = (void __user *) buf;
- user_buffer_size = (int) len;
-
- ret = do_microcode_update();
- if (!ret)
- ret = (ssize_t)len;
-
- mutex_unlock(µcode_mutex);
- put_online_cpus();
-
- return ret;
-}
-
-static const struct file_operations microcode_fops = {
- .owner = THIS_MODULE,
- .write = microcode_write,
- .open = microcode_open,
-};
-
-static struct miscdevice microcode_dev = {
- .minor = MICROCODE_MINOR,
- .name = "microcode",
- .fops = µcode_fops,
-};
-
-static int __init microcode_dev_init (void)
-{
- int error;
-
- error = misc_register(µcode_dev);
- if (error) {
- printk(KERN_ERR
- "microcode: can't misc_register on minor=%d\n",
- MICROCODE_MINOR);
- return error;
- }
-
- return 0;
-}
-
-static void microcode_dev_exit (void)
-{
- misc_deregister(µcode_dev);
-}
-
-MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
-#else
-#define microcode_dev_init() 0
-#define microcode_dev_exit() do { } while(0)
-#endif
-
-static long get_next_ucode_from_buffer(void **mc, const u8 *buf,
- unsigned long size, long offset)
-{
- microcode_header_t *mc_header;
- unsigned long total_size;
-
- /* No more data */
- if (offset >= size)
- return 0;
- mc_header = (microcode_header_t *)(buf + offset);
- total_size = get_totalsize(mc_header);
-
- if (offset + total_size > size) {
- printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
- return -EINVAL;
- }
-
- *mc = vmalloc(total_size);
- if (!*mc) {
- printk(KERN_ERR "microcode: error! Can not allocate memory\n");
- return -ENOMEM;
- }
- memcpy(*mc, buf + offset, total_size);
- return offset + total_size;
-}
-
-/* fake device for request_firmware */
-static struct platform_device *microcode_pdev;
-
-static int cpu_request_microcode(int cpu)
-{
- char name[30];
- struct cpuinfo_x86 *c = &cpu_data(cpu);
- const struct firmware *firmware;
- const u8 *buf;
- unsigned long size;
- long offset = 0;
- int error;
- void *mc;
-
- /* We should bind the task to the CPU */
- BUG_ON(cpu != raw_smp_processor_id());
- sprintf(name,"intel-ucode/%02x-%02x-%02x",
- c->x86, c->x86_model, c->x86_mask);
- error = request_firmware(&firmware, name, µcode_pdev->dev);
- if (error) {
- pr_debug("microcode: data file %s load failed\n", name);
- return error;
- }
- buf = firmware->data;
- size = firmware->size;
- while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset))
- > 0) {
- error = microcode_sanity_check(mc);
- if (error)
- break;
- error = get_maching_microcode(mc, cpu);
- if (error < 0)
- break;
- /*
- * It's possible the data file has multiple matching ucode,
- * lets keep searching till the latest version
- */
- if (error == 1) {
- apply_microcode(cpu);
- error = 0;
- }
- vfree(mc);
- }
- if (offset > 0)
- vfree(mc);
- if (offset < 0)
- error = offset;
- release_firmware(firmware);
-
- return error;
-}
-
-static int apply_microcode_check_cpu(int cpu)
-{
- struct cpuinfo_x86 *c = &cpu_data(cpu);
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
- cpumask_t old;
- unsigned int val[2];
- int err = 0;
-
- /* Check if the microcode is available */
- if (!uci->mc)
- return 0;
-
- old = current->cpus_allowed;
- set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-
- /* Check if the microcode we have in memory matches the CPU */
- if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
- cpu_has(c, X86_FEATURE_IA64) || uci->sig != cpuid_eax(0x00000001))
- err = -EINVAL;
-
- if (!err && ((c->x86_model >= 5) || (c->x86 > 6))) {
- /* get processor flags from MSR 0x17 */
- rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
- if (uci->pf != (1 << ((val[1] >> 18) & 7)))
- err = -EINVAL;
- }
-
- if (!err) {
- wrmsr(MSR_IA32_UCODE_REV, 0, 0);
- /* see notes above for revision 1.07. Apparent chip bug */
- sync_core();
- /* get the current revision from MSR 0x8B */
- rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
- if (uci->rev != val[1])
- err = -EINVAL;
- }
-
- if (!err)
- apply_microcode(cpu);
- else
- printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:"
- " sig=0x%x, pf=0x%x, rev=0x%x\n",
- cpu, uci->sig, uci->pf, uci->rev);
-
- set_cpus_allowed_ptr(current, &old);
- return err;
-}
-
-static void microcode_init_cpu(int cpu, int resume)
-{
- cpumask_t old;
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
- old = current->cpus_allowed;
-
- set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
- mutex_lock(µcode_mutex);
- collect_cpu_info(cpu);
- if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
- cpu_request_microcode(cpu);
- mutex_unlock(µcode_mutex);
- set_cpus_allowed_ptr(current, &old);
-}
-
-static void microcode_fini_cpu(int cpu)
-{
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
- mutex_lock(µcode_mutex);
- uci->valid = 0;
- vfree(uci->mc);
- uci->mc = NULL;
- mutex_unlock(µcode_mutex);
-}
-
-static ssize_t reload_store(struct sys_device *dev,
- struct sysdev_attribute *attr,
- const char *buf, size_t sz)
-{
- struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
- char *end;
- unsigned long val = simple_strtoul(buf, &end, 0);
- int err = 0;
- int cpu = dev->id;
-
- if (end == buf)
- return -EINVAL;
- if (val == 1) {
- cpumask_t old = current->cpus_allowed;
-
- get_online_cpus();
- set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-
- mutex_lock(µcode_mutex);
- if (uci->valid)
- err = cpu_request_microcode(cpu);
- mutex_unlock(µcode_mutex);
- put_online_cpus();
- set_cpus_allowed_ptr(current, &old);
- }
- if (err)
- return err;
- return sz;
-}
-
-static ssize_t version_show(struct sys_device *dev,
- struct sysdev_attribute *attr, char *buf)
-{
- struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
-
- return sprintf(buf, "0x%x\n", uci->rev);
-}
-
-static ssize_t pf_show(struct sys_device *dev,
- struct sysdev_attribute *attr, char *buf)
-{
- struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
-
- return sprintf(buf, "0x%x\n", uci->pf);
-}
-
-static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
-static SYSDEV_ATTR(version, 0400, version_show, NULL);
-static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
-
-static struct attribute *mc_default_attrs[] = {
- &attr_reload.attr,
- &attr_version.attr,
- &attr_processor_flags.attr,
- NULL
-};
-
-static struct attribute_group mc_attr_group = {
- .attrs = mc_default_attrs,
- .name = "microcode",
-};
-
-static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
-{
- int err, cpu = sys_dev->id;
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
- if (!cpu_online(cpu))
- return 0;
-
- pr_debug("microcode: CPU%d added\n", cpu);
- memset(uci, 0, sizeof(*uci));
-
- err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
- if (err)
- return err;
-
- microcode_init_cpu(cpu, resume);
-
- return 0;
-}
-
-static int mc_sysdev_add(struct sys_device *sys_dev)
-{
- return __mc_sysdev_add(sys_dev, 0);
-}
-
-static int mc_sysdev_remove(struct sys_device *sys_dev)
-{
- int cpu = sys_dev->id;
-
- if (!cpu_online(cpu))
- return 0;
-
- pr_debug("microcode: CPU%d removed\n", cpu);
- microcode_fini_cpu(cpu);
- sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
- return 0;
-}
-
-static int mc_sysdev_resume(struct sys_device *dev)
-{
- int cpu = dev->id;
-
- if (!cpu_online(cpu))
- return 0;
- pr_debug("microcode: CPU%d resumed\n", cpu);
- /* only CPU 0 will apply ucode here */
- apply_microcode(0);
- return 0;
-}
-
-static struct sysdev_driver mc_sysdev_driver = {
- .add = mc_sysdev_add,
- .remove = mc_sysdev_remove,
- .resume = mc_sysdev_resume,
-};
-
-static __cpuinit int
-mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
-{
- unsigned int cpu = (unsigned long)hcpu;
- struct sys_device *sys_dev;
-
- sys_dev = get_cpu_sysdev(cpu);
- switch (action) {
- case CPU_UP_CANCELED_FROZEN:
- /* The CPU refused to come up during a system resume */
- microcode_fini_cpu(cpu);
- break;
- case CPU_ONLINE:
- case CPU_DOWN_FAILED:
- mc_sysdev_add(sys_dev);
- break;
- case CPU_ONLINE_FROZEN:
- /* System-wide resume is in progress, try to apply microcode */
- if (apply_microcode_check_cpu(cpu)) {
- /* The application of microcode failed */
- microcode_fini_cpu(cpu);
- __mc_sysdev_add(sys_dev, 1);
- break;
- }
- case CPU_DOWN_FAILED_FROZEN:
- if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
- printk(KERN_ERR "microcode: Failed to create the sysfs "
- "group for CPU%d\n", cpu);
- break;
- case CPU_DOWN_PREPARE:
- mc_sysdev_remove(sys_dev);
- break;
- case CPU_DOWN_PREPARE_FROZEN:
- /* Suspend is in progress, only remove the interface */
- sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
- break;
- }
- return NOTIFY_OK;
-}
-
-static struct notifier_block __refdata mc_cpu_notifier = {
- .notifier_call = mc_cpu_callback,
-};
-
-static int __init microcode_init (void)
-{
- int error;
-
- printk(KERN_INFO
- "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n");
-
- error = microcode_dev_init();
- if (error)
- return error;
- microcode_pdev = platform_device_register_simple("microcode", -1,
- NULL, 0);
- if (IS_ERR(microcode_pdev)) {
- microcode_dev_exit();
- return PTR_ERR(microcode_pdev);
- }
-
- get_online_cpus();
- error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
- put_online_cpus();
- if (error) {
- microcode_dev_exit();
- platform_device_unregister(microcode_pdev);
- return error;
- }
-
- register_hotcpu_notifier(&mc_cpu_notifier);
- return 0;
-}
-
-static void __exit microcode_exit (void)
-{
- microcode_dev_exit();
-
- unregister_hotcpu_notifier(&mc_cpu_notifier);
-
- get_online_cpus();
- sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
- put_online_cpus();
-
- platform_device_unregister(microcode_pdev);
-}
-
-module_init(microcode_init)
-module_exit(microcode_exit)
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
new file mode 100644
index 0000000..7a1f8ee
--- /dev/null
+++ b/arch/x86/kernel/microcode_amd.c
@@ -0,0 +1,435 @@
+/*
+ * AMD CPU Microcode Update Driver for Linux
+ * Copyright (C) 2008 Advanced Micro Devices Inc.
+ *
+ * Author: Peter Oruba <peter.oruba@amd.com>
+ *
+ * Based on work by:
+ * Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ *
+ * This driver allows to upgrade microcode on AMD
+ * family 0x10 and 0x11 processors.
+ *
+ * Licensed unter the terms of the GNU General Public
+ * License version 2. See file COPYING for details.
+*/
+
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("AMD Microcode Update Driver");
+MODULE_AUTHOR("Peter Oruba <peter.oruba@amd.com>");
+MODULE_LICENSE("GPL v2");
+
+#define UCODE_MAGIC 0x00414d44
+#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
+#define UCODE_UCODE_TYPE 0x00000001
+
+struct equiv_cpu_entry {
+ unsigned int installed_cpu;
+ unsigned int fixed_errata_mask;
+ unsigned int fixed_errata_compare;
+ unsigned int equiv_cpu;
+};
+
+struct microcode_header_amd {
+ unsigned int data_code;
+ unsigned int patch_id;
+ unsigned char mc_patch_data_id[2];
+ unsigned char mc_patch_data_len;
+ unsigned char init_flag;
+ unsigned int mc_patch_data_checksum;
+ unsigned int nb_dev_id;
+ unsigned int sb_dev_id;
+ unsigned char processor_rev_id[2];
+ unsigned char nb_rev_id;
+ unsigned char sb_rev_id;
+ unsigned char bios_api_rev;
+ unsigned char reserved1[3];
+ unsigned int match_reg[8];
+};
+
+struct microcode_amd {
+ struct microcode_header_amd hdr;
+ unsigned int mpb[0];
+};
+
+#define UCODE_MAX_SIZE (2048)
+#define DEFAULT_UCODE_DATASIZE (896)
+#define MC_HEADER_SIZE (sizeof(struct microcode_header_amd))
+#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
+#define DWSIZE (sizeof(u32))
+/* For now we support a fixed ucode total size only */
+#define get_totalsize(mc) \
+ ((((struct microcode_amd *)mc)->hdr.mc_patch_data_len * 28) \
+ + MC_HEADER_SIZE)
+
+/* serialize access to the physical write */
+static DEFINE_SPINLOCK(microcode_update_lock);
+
+static struct equiv_cpu_entry *equiv_cpu_table;
+
+static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
+{
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+ memset(csig, 0, sizeof(*csig));
+
+ if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) {
+ printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n",
+ cpu);
+ return -1;
+ }
+
+ asm volatile("movl %1, %%ecx; rdmsr"
+ : "=a" (csig->rev)
+ : "i" (0x0000008B) : "ecx");
+
+ printk(KERN_INFO "microcode: collect_cpu_info_amd : patch_id=0x%x\n",
+ csig->rev);
+
+ return 0;
+}
+
+static int get_matching_microcode(int cpu, void *mc, int rev)
+{
+ struct microcode_header_amd *mc_header = mc;
+ struct pci_dev *nb_pci_dev, *sb_pci_dev;
+ unsigned int current_cpu_id;
+ unsigned int equiv_cpu_id = 0x00;
+ unsigned int i = 0;
+
+ BUG_ON(equiv_cpu_table == NULL);
+ current_cpu_id = cpuid_eax(0x00000001);
+
+ while (equiv_cpu_table[i].installed_cpu != 0) {
+ if (current_cpu_id == equiv_cpu_table[i].installed_cpu) {
+ equiv_cpu_id = equiv_cpu_table[i].equiv_cpu;
+ break;
+ }
+ i++;
+ }
+
+ if (!equiv_cpu_id) {
+ printk(KERN_ERR "microcode: CPU%d cpu_id "
+ "not found in equivalent cpu table \n", cpu);
+ return 0;
+ }
+
+ if ((mc_header->processor_rev_id[0]) != (equiv_cpu_id & 0xff)) {
+ printk(KERN_ERR
+ "microcode: CPU%d patch does not match "
+ "(patch is %x, cpu extended is %x) \n",
+ cpu, mc_header->processor_rev_id[0],
+ (equiv_cpu_id & 0xff));
+ return 0;
+ }
+
+ if ((mc_header->processor_rev_id[1]) != ((equiv_cpu_id >> 16) & 0xff)) {
+ printk(KERN_ERR "microcode: CPU%d patch does not match "
+ "(patch is %x, cpu base id is %x) \n",
+ cpu, mc_header->processor_rev_id[1],
+ ((equiv_cpu_id >> 16) & 0xff));
+
+ return 0;
+ }
+
+ /* ucode may be northbridge specific */
+ if (mc_header->nb_dev_id) {
+ nb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+ (mc_header->nb_dev_id & 0xff),
+ NULL);
+ if ((!nb_pci_dev) ||
+ (mc_header->nb_rev_id != nb_pci_dev->revision)) {
+ printk(KERN_ERR "microcode: CPU%d NB mismatch \n", cpu);
+ pci_dev_put(nb_pci_dev);
+ return 0;
+ }
+ pci_dev_put(nb_pci_dev);
+ }
+
+ /* ucode may be southbridge specific */
+ if (mc_header->sb_dev_id) {
+ sb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+ (mc_header->sb_dev_id & 0xff),
+ NULL);
+ if ((!sb_pci_dev) ||
+ (mc_header->sb_rev_id != sb_pci_dev->revision)) {
+ printk(KERN_ERR "microcode: CPU%d SB mismatch \n", cpu);
+ pci_dev_put(sb_pci_dev);
+ return 0;
+ }
+ pci_dev_put(sb_pci_dev);
+ }
+
+ if (mc_header->patch_id <= rev)
+ return 0;
+
+ return 1;
+}
+
+static void apply_microcode_amd(int cpu)
+{
+ unsigned long flags;
+ unsigned int eax, edx;
+ unsigned int rev;
+ int cpu_num = raw_smp_processor_id();
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+ struct microcode_amd *mc_amd = uci->mc;
+ unsigned long addr;
+
+ /* We should bind the task to the CPU */
+ BUG_ON(cpu_num != cpu);
+
+ if (mc_amd == NULL)
+ return;
+
+ spin_lock_irqsave(µcode_update_lock, flags);
+
+ addr = (unsigned long)&mc_amd->hdr.data_code;
+ edx = (unsigned int)(((unsigned long)upper_32_bits(addr)));
+ eax = (unsigned int)(((unsigned long)lower_32_bits(addr)));
+
+ asm volatile("movl %0, %%ecx; wrmsr" :
+ : "i" (0xc0010020), "a" (eax), "d" (edx) : "ecx");
+
+ /* get patch id after patching */
+ asm volatile("movl %1, %%ecx; rdmsr"
+ : "=a" (rev)
+ : "i" (0x0000008B) : "ecx");
+
+ spin_unlock_irqrestore(µcode_update_lock, flags);
+
+ /* check current patch id and patch's id for match */
+ if (rev != mc_amd->hdr.patch_id) {
+ printk(KERN_ERR "microcode: CPU%d update from revision "
+ "0x%x to 0x%x failed\n", cpu_num,
+ mc_amd->hdr.patch_id, rev);
+ return;
+ }
+
+ printk(KERN_INFO "microcode: CPU%d updated from revision "
+ "0x%x to 0x%x \n",
+ cpu_num, uci->cpu_sig.rev, mc_amd->hdr.patch_id);
+
+ uci->cpu_sig.rev = rev;
+}
+
+static void * get_next_ucode(u8 *buf, unsigned int size,
+ int (*get_ucode_data)(void *, const void *, size_t),
+ unsigned int *mc_size)
+{
+ unsigned int total_size;
+#define UCODE_CONTAINER_SECTION_HDR 8
+ u8 section_hdr[UCODE_CONTAINER_SECTION_HDR];
+ void *mc;
+
+ if (get_ucode_data(section_hdr, buf, UCODE_CONTAINER_SECTION_HDR))
+ return NULL;
+
+ if (section_hdr[0] != UCODE_UCODE_TYPE) {
+ printk(KERN_ERR "microcode: error! "
+ "Wrong microcode payload type field\n");
+ return NULL;
+ }
+
+ total_size = (unsigned long) (section_hdr[4] + (section_hdr[5] << 8));
+
+ printk(KERN_INFO "microcode: size %u, total_size %u\n",
+ size, total_size);
+
+ if (total_size > size || total_size > UCODE_MAX_SIZE) {
+ printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+ return NULL;
+ }
+
+ mc = vmalloc(UCODE_MAX_SIZE);
+ if (mc) {
+ memset(mc, 0, UCODE_MAX_SIZE);
+ if (get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR, total_size)) {
+ vfree(mc);
+ mc = NULL;
+ } else
+ *mc_size = total_size + UCODE_CONTAINER_SECTION_HDR;
+ }
+#undef UCODE_CONTAINER_SECTION_HDR
+ return mc;
+}
+
+
+static int install_equiv_cpu_table(u8 *buf,
+ int (*get_ucode_data)(void *, const void *, size_t))
+{
+#define UCODE_CONTAINER_HEADER_SIZE 12
+ u8 *container_hdr[UCODE_CONTAINER_HEADER_SIZE];
+ unsigned int *buf_pos = (unsigned int *)container_hdr;
+ unsigned long size;
+
+ if (get_ucode_data(&container_hdr, buf, UCODE_CONTAINER_HEADER_SIZE))
+ return 0;
+
+ size = buf_pos[2];
+
+ if (buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE || !size) {
+ printk(KERN_ERR "microcode: error! "
+ "Wrong microcode equivalnet cpu table\n");
+ return 0;
+ }
+
+ equiv_cpu_table = (struct equiv_cpu_entry *) vmalloc(size);
+ if (!equiv_cpu_table) {
+ printk(KERN_ERR "microcode: error, can't allocate memory for equiv CPU table\n");
+ return 0;
+ }
+
+ buf += UCODE_CONTAINER_HEADER_SIZE;
+ if (get_ucode_data(equiv_cpu_table, buf, size)) {
+ vfree(equiv_cpu_table);
+ return 0;
+ }
+
+ return size + UCODE_CONTAINER_HEADER_SIZE; /* add header length */
+#undef UCODE_CONTAINER_HEADER_SIZE
+}
+
+static void free_equiv_cpu_table(void)
+{
+ if (equiv_cpu_table) {
+ vfree(equiv_cpu_table);
+ equiv_cpu_table = NULL;
+ }
+}
+
+static int generic_load_microcode(int cpu, void *data, size_t size,
+ int (*get_ucode_data)(void *, const void *, size_t))
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ u8 *ucode_ptr = data, *new_mc = NULL, *mc;
+ int new_rev = uci->cpu_sig.rev;
+ unsigned int leftover;
+ unsigned long offset;
+
+ offset = install_equiv_cpu_table(ucode_ptr, get_ucode_data);
+ if (!offset) {
+ printk(KERN_ERR "microcode: installing equivalent cpu table failed\n");
+ return -EINVAL;
+ }
+
+ ucode_ptr += offset;
+ leftover = size - offset;
+
+ while (leftover) {
+ unsigned int uninitialized_var(mc_size);
+ struct microcode_header_amd *mc_header;
+
+ mc = get_next_ucode(ucode_ptr, leftover, get_ucode_data, &mc_size);
+ if (!mc)
+ break;
+
+ mc_header = (struct microcode_header_amd *)mc;
+ if (get_matching_microcode(cpu, mc, new_rev)) {
+ if (new_mc)
+ vfree(new_mc);
+ new_rev = mc_header->patch_id;
+ new_mc = mc;
+ } else
+ vfree(mc);
+
+ ucode_ptr += mc_size;
+ leftover -= mc_size;
+ }
+
+ if (new_mc) {
+ if (!leftover) {
+ if (uci->mc)
+ vfree(uci->mc);
+ uci->mc = new_mc;
+ pr_debug("microcode: CPU%d found a matching microcode update with"
+ " version 0x%x (current=0x%x)\n",
+ cpu, new_rev, uci->cpu_sig.rev);
+ } else
+ vfree(new_mc);
+ }
+
+ free_equiv_cpu_table();
+
+ return (int)leftover;
+}
+
+static int get_ucode_fw(void *to, const void *from, size_t n)
+{
+ memcpy(to, from, n);
+ return 0;
+}
+
+static int request_microcode_fw(int cpu, struct device *device)
+{
+ const char *fw_name = "amd-ucode/microcode_amd.bin";
+ const struct firmware *firmware;
+ int ret;
+
+ /* We should bind the task to the CPU */
+ BUG_ON(cpu != raw_smp_processor_id());
+
+ ret = request_firmware(&firmware, fw_name, device);
+ if (ret) {
+ printk(KERN_ERR "microcode: ucode data file %s load failed\n", fw_name);
+ return ret;
+ }
+
+ ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size,
+ &get_ucode_fw);
+
+ release_firmware(firmware);
+
+ return ret;
+}
+
+static int request_microcode_user(int cpu, const void __user *buf, size_t size)
+{
+ printk(KERN_WARNING "microcode: AMD microcode update via /dev/cpu/microcode"
+ "is not supported\n");
+ return -1;
+}
+
+static void microcode_fini_cpu_amd(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ vfree(uci->mc);
+ uci->mc = NULL;
+}
+
+static struct microcode_ops microcode_amd_ops = {
+ .request_microcode_user = request_microcode_user,
+ .request_microcode_fw = request_microcode_fw,
+ .collect_cpu_info = collect_cpu_info_amd,
+ .apply_microcode = apply_microcode_amd,
+ .microcode_fini_cpu = microcode_fini_cpu_amd,
+};
+
+struct microcode_ops * __init init_amd_microcode(void)
+{
+ return µcode_amd_ops;
+}
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
new file mode 100644
index 0000000..936d8d5
--- /dev/null
+++ b/arch/x86/kernel/microcode_core.c
@@ -0,0 +1,508 @@
+/*
+ * Intel CPU Microcode Update Driver for Linux
+ *
+ * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ * 2006 Shaohua Li <shaohua.li@intel.com>
+ *
+ * This driver allows to upgrade microcode on Intel processors
+ * belonging to IA-32 family - PentiumPro, Pentium II,
+ * Pentium III, Xeon, Pentium 4, etc.
+ *
+ * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
+ * Software Developer's Manual
+ * Order Number 253668 or free download from:
+ *
+ * http://developer.intel.com/design/pentium4/manuals/253668.htm
+ *
+ * For more information, go to http://www.urbanmyth.org/microcode
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 1.0 16 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Initial release.
+ * 1.01 18 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Added read() support + cleanups.
+ * 1.02 21 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Added 'device trimming' support. open(O_WRONLY) zeroes
+ * and frees the saved copy of applied microcode.
+ * 1.03 29 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Made to use devfs (/dev/cpu/microcode) + cleanups.
+ * 1.04 06 Jun 2000, Simon Trimmer <simon@veritas.com>
+ * Added misc device support (now uses both devfs and misc).
+ * Added MICROCODE_IOCFREE ioctl to clear memory.
+ * 1.05 09 Jun 2000, Simon Trimmer <simon@veritas.com>
+ * Messages for error cases (non Intel & no suitable microcode).
+ * 1.06 03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
+ * Removed ->release(). Removed exclusive open and status bitmap.
+ * Added microcode_rwsem to serialize read()/write()/ioctl().
+ * Removed global kernel lock usage.
+ * 1.07 07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
+ * Write 0 to 0x8B msr and then cpuid before reading revision,
+ * so that it works even if there were no update done by the
+ * BIOS. Otherwise, reading from 0x8B gives junk (which happened
+ * to be 0 on my machine which is why it worked even when I
+ * disabled update by the BIOS)
+ * Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
+ * 1.08 11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
+ * Tigran Aivazian <tigran@veritas.com>
+ * Intel Pentium 4 processor support and bugfixes.
+ * 1.09 30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
+ * Bugfix for HT (Hyper-Threading) enabled processors
+ * whereby processor resources are shared by all logical processors
+ * in a single CPU package.
+ * 1.10 28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
+ * Tigran Aivazian <tigran@veritas.com>,
+ * Serialize updates as required on HT processors due to
+ * speculative nature of implementation.
+ * 1.11 22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
+ * Fix the panic when writing zero-length microcode chunk.
+ * 1.12 29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
+ * Jun Nakajima <jun.nakajima@intel.com>
+ * Support for the microcode updates in the new format.
+ * 1.13 10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
+ * Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
+ * because we no longer hold a copy of applied microcode
+ * in kernel memory.
+ * 1.14 25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
+ * Fix sigmatch() macro to handle old CPUs with pf == 0.
+ * Thanks to Stuart Swales for pointing out this bug.
+ */
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("Microcode Update Driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
+MODULE_LICENSE("GPL");
+
+#define MICROCODE_VERSION "2.00"
+
+struct microcode_ops *microcode_ops;
+
+/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
+static DEFINE_MUTEX(microcode_mutex);
+
+struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
+EXPORT_SYMBOL_GPL(ucode_cpu_info);
+
+#ifdef CONFIG_MICROCODE_OLD_INTERFACE
+static int do_microcode_update(const void __user *buf, size_t size)
+{
+ cpumask_t old;
+ int error = 0;
+ int cpu;
+
+ old = current->cpus_allowed;
+
+ for_each_online_cpu(cpu) {
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ if (!uci->valid)
+ continue;
+
+ set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+ error = microcode_ops->request_microcode_user(cpu, buf, size);
+ if (error < 0)
+ goto out;
+ if (!error)
+ microcode_ops->apply_microcode(cpu);
+ }
+out:
+ set_cpus_allowed_ptr(current, &old);
+ return error;
+}
+
+static int microcode_open(struct inode *unused1, struct file *unused2)
+{
+ cycle_kernel_lock();
+ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
+static ssize_t microcode_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ ssize_t ret;
+
+ if ((len >> PAGE_SHIFT) > num_physpages) {
+ printk(KERN_ERR "microcode: too much data (max %ld pages)\n",
+ num_physpages);
+ return -EINVAL;
+ }
+
+ get_online_cpus();
+ mutex_lock(µcode_mutex);
+
+ ret = do_microcode_update(buf, len);
+ if (!ret)
+ ret = (ssize_t)len;
+
+ mutex_unlock(µcode_mutex);
+ put_online_cpus();
+
+ return ret;
+}
+
+static const struct file_operations microcode_fops = {
+ .owner = THIS_MODULE,
+ .write = microcode_write,
+ .open = microcode_open,
+};
+
+static struct miscdevice microcode_dev = {
+ .minor = MICROCODE_MINOR,
+ .name = "microcode",
+ .fops = µcode_fops,
+};
+
+static int __init microcode_dev_init(void)
+{
+ int error;
+
+ error = misc_register(µcode_dev);
+ if (error) {
+ printk(KERN_ERR
+ "microcode: can't misc_register on minor=%d\n",
+ MICROCODE_MINOR);
+ return error;
+ }
+
+ return 0;
+}
+
+static void microcode_dev_exit(void)
+{
+ misc_deregister(µcode_dev);
+}
+
+MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
+#else
+#define microcode_dev_init() 0
+#define microcode_dev_exit() do { } while (0)
+#endif
+
+/* fake device for request_firmware */
+struct platform_device *microcode_pdev;
+
+static ssize_t reload_store(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ const char *buf, size_t sz)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+ char *end;
+ unsigned long val = simple_strtoul(buf, &end, 0);
+ int err = 0;
+ int cpu = dev->id;
+
+ if (end == buf)
+ return -EINVAL;
+ if (val == 1) {
+ cpumask_t old = current->cpus_allowed;
+
+ get_online_cpus();
+ if (cpu_online(cpu)) {
+ set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+ mutex_lock(µcode_mutex);
+ if (uci->valid) {
+ err = microcode_ops->request_microcode_fw(cpu,
+ µcode_pdev->dev);
+ if (!err)
+ microcode_ops->apply_microcode(cpu);
+ }
+ mutex_unlock(µcode_mutex);
+ set_cpus_allowed_ptr(current, &old);
+ }
+ put_online_cpus();
+ }
+ if (err)
+ return err;
+ return sz;
+}
+
+static ssize_t version_show(struct sys_device *dev,
+ struct sysdev_attribute *attr, char *buf)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+
+ return sprintf(buf, "0x%x\n", uci->cpu_sig.rev);
+}
+
+static ssize_t pf_show(struct sys_device *dev,
+ struct sysdev_attribute *attr, char *buf)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+
+ return sprintf(buf, "0x%x\n", uci->cpu_sig.pf);
+}
+
+static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
+static SYSDEV_ATTR(version, 0400, version_show, NULL);
+static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
+
+static struct attribute *mc_default_attrs[] = {
+ &attr_reload.attr,
+ &attr_version.attr,
+ &attr_processor_flags.attr,
+ NULL
+};
+
+static struct attribute_group mc_attr_group = {
+ .attrs = mc_default_attrs,
+ .name = "microcode",
+};
+
+static void microcode_fini_cpu(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ mutex_lock(µcode_mutex);
+ microcode_ops->microcode_fini_cpu(cpu);
+ uci->valid = 0;
+ mutex_unlock(µcode_mutex);
+}
+
+static void collect_cpu_info(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ memset(uci, 0, sizeof(*uci));
+ if (!microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig))
+ uci->valid = 1;
+}
+
+static int microcode_resume_cpu(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ struct cpu_signature nsig;
+
+ pr_debug("microcode: CPU%d resumed\n", cpu);
+
+ if (!uci->mc)
+ return 1;
+
+ /*
+ * Let's verify that the 'cached' ucode does belong
+ * to this cpu (a bit of paranoia):
+ */
+ if (microcode_ops->collect_cpu_info(cpu, &nsig)) {
+ microcode_fini_cpu(cpu);
+ return -1;
+ }
+
+ if (memcmp(&nsig, &uci->cpu_sig, sizeof(nsig))) {
+ microcode_fini_cpu(cpu);
+ /* Should we look for a new ucode here? */
+ return 1;
+ }
+
+ return 0;
+}
+
+void microcode_update_cpu(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ int err = 0;
+
+ /*
+ * Check if the system resume is in progress (uci->valid != NULL),
+ * otherwise just request a firmware:
+ */
+ if (uci->valid) {
+ err = microcode_resume_cpu(cpu);
+ } else {
+ collect_cpu_info(cpu);
+ if (uci->valid && system_state == SYSTEM_RUNNING)
+ err = microcode_ops->request_microcode_fw(cpu,
+ µcode_pdev->dev);
+ }
+ if (!err)
+ microcode_ops->apply_microcode(cpu);
+}
+
+static void microcode_init_cpu(int cpu)
+{
+ cpumask_t old = current->cpus_allowed;
+
+ set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+ /* We should bind the task to the CPU */
+ BUG_ON(raw_smp_processor_id() != cpu);
+
+ mutex_lock(µcode_mutex);
+ microcode_update_cpu(cpu);
+ mutex_unlock(µcode_mutex);
+
+ set_cpus_allowed_ptr(current, &old);
+}
+
+static int mc_sysdev_add(struct sys_device *sys_dev)
+{
+ int err, cpu = sys_dev->id;
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ if (!cpu_online(cpu))
+ return 0;
+
+ pr_debug("microcode: CPU%d added\n", cpu);
+ memset(uci, 0, sizeof(*uci));
+
+ err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
+ if (err)
+ return err;
+
+ microcode_init_cpu(cpu);
+ return 0;
+}
+
+static int mc_sysdev_remove(struct sys_device *sys_dev)
+{
+ int cpu = sys_dev->id;
+
+ if (!cpu_online(cpu))
+ return 0;
+
+ pr_debug("microcode: CPU%d removed\n", cpu);
+ microcode_fini_cpu(cpu);
+ sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+ return 0;
+}
+
+static int mc_sysdev_resume(struct sys_device *dev)
+{
+ int cpu = dev->id;
+
+ if (!cpu_online(cpu))
+ return 0;
+
+ /* only CPU 0 will apply ucode here */
+ microcode_update_cpu(0);
+ return 0;
+}
+
+static struct sysdev_driver mc_sysdev_driver = {
+ .add = mc_sysdev_add,
+ .remove = mc_sysdev_remove,
+ .resume = mc_sysdev_resume,
+};
+
+static __cpuinit int
+mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ struct sys_device *sys_dev;
+
+ sys_dev = get_cpu_sysdev(cpu);
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ microcode_init_cpu(cpu);
+ case CPU_DOWN_FAILED:
+ case CPU_DOWN_FAILED_FROZEN:
+ pr_debug("microcode: CPU%d added\n", cpu);
+ if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
+ printk(KERN_ERR "microcode: Failed to create the sysfs "
+ "group for CPU%d\n", cpu);
+ break;
+ case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
+ /* Suspend is in progress, only remove the interface */
+ sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+ pr_debug("microcode: CPU%d removed\n", cpu);
+ break;
+ case CPU_DEAD:
+ case CPU_UP_CANCELED_FROZEN:
+ /* The CPU refused to come up during a system resume */
+ microcode_fini_cpu(cpu);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __refdata mc_cpu_notifier = {
+ .notifier_call = mc_cpu_callback,
+};
+
+static int __init microcode_init(void)
+{
+ struct cpuinfo_x86 *c = &cpu_data(0);
+ int error;
+
+ if (c->x86_vendor == X86_VENDOR_INTEL)
+ microcode_ops = init_intel_microcode();
+ else if (c->x86_vendor == X86_VENDOR_AMD)
+ microcode_ops = init_amd_microcode();
+
+ if (!microcode_ops) {
+ printk(KERN_ERR "microcode: no support for this CPU vendor\n");
+ return -ENODEV;
+ }
+
+ error = microcode_dev_init();
+ if (error)
+ return error;
+ microcode_pdev = platform_device_register_simple("microcode", -1,
+ NULL, 0);
+ if (IS_ERR(microcode_pdev)) {
+ microcode_dev_exit();
+ return PTR_ERR(microcode_pdev);
+ }
+
+ get_online_cpus();
+ error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
+ put_online_cpus();
+ if (error) {
+ microcode_dev_exit();
+ platform_device_unregister(microcode_pdev);
+ return error;
+ }
+
+ register_hotcpu_notifier(&mc_cpu_notifier);
+
+ printk(KERN_INFO
+ "Microcode Update Driver: v" MICROCODE_VERSION
+ " <tigran@aivazian.fsnet.co.uk>"
+ " <peter.oruba@amd.com>\n");
+
+ return 0;
+}
+
+static void __exit microcode_exit(void)
+{
+ microcode_dev_exit();
+
+ unregister_hotcpu_notifier(&mc_cpu_notifier);
+
+ get_online_cpus();
+ sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
+ put_online_cpus();
+
+ platform_device_unregister(microcode_pdev);
+
+ microcode_ops = NULL;
+
+ printk(KERN_INFO
+ "Microcode Update Driver: v" MICROCODE_VERSION " removed.\n");
+}
+
+module_init(microcode_init);
+module_exit(microcode_exit);
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
new file mode 100644
index 0000000..622dc4a
--- /dev/null
+++ b/arch/x86/kernel/microcode_intel.c
@@ -0,0 +1,480 @@
+/*
+ * Intel CPU Microcode Update Driver for Linux
+ *
+ * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ * 2006 Shaohua Li <shaohua.li@intel.com>
+ *
+ * This driver allows to upgrade microcode on Intel processors
+ * belonging to IA-32 family - PentiumPro, Pentium II,
+ * Pentium III, Xeon, Pentium 4, etc.
+ *
+ * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
+ * Software Developer's Manual
+ * Order Number 253668 or free download from:
+ *
+ * http://developer.intel.com/design/pentium4/manuals/253668.htm
+ *
+ * For more information, go to http://www.urbanmyth.org/microcode
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 1.0 16 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Initial release.
+ * 1.01 18 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Added read() support + cleanups.
+ * 1.02 21 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Added 'device trimming' support. open(O_WRONLY) zeroes
+ * and frees the saved copy of applied microcode.
+ * 1.03 29 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Made to use devfs (/dev/cpu/microcode) + cleanups.
+ * 1.04 06 Jun 2000, Simon Trimmer <simon@veritas.com>
+ * Added misc device support (now uses both devfs and misc).
+ * Added MICROCODE_IOCFREE ioctl to clear memory.
+ * 1.05 09 Jun 2000, Simon Trimmer <simon@veritas.com>
+ * Messages for error cases (non Intel & no suitable microcode).
+ * 1.06 03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
+ * Removed ->release(). Removed exclusive open and status bitmap.
+ * Added microcode_rwsem to serialize read()/write()/ioctl().
+ * Removed global kernel lock usage.
+ * 1.07 07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
+ * Write 0 to 0x8B msr and then cpuid before reading revision,
+ * so that it works even if there were no update done by the
+ * BIOS. Otherwise, reading from 0x8B gives junk (which happened
+ * to be 0 on my machine which is why it worked even when I
+ * disabled update by the BIOS)
+ * Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
+ * 1.08 11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
+ * Tigran Aivazian <tigran@veritas.com>
+ * Intel Pentium 4 processor support and bugfixes.
+ * 1.09 30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
+ * Bugfix for HT (Hyper-Threading) enabled processors
+ * whereby processor resources are shared by all logical processors
+ * in a single CPU package.
+ * 1.10 28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
+ * Tigran Aivazian <tigran@veritas.com>,
+ * Serialize updates as required on HT processors due to
+ * speculative nature of implementation.
+ * 1.11 22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
+ * Fix the panic when writing zero-length microcode chunk.
+ * 1.12 29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
+ * Jun Nakajima <jun.nakajima@intel.com>
+ * Support for the microcode updates in the new format.
+ * 1.13 10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
+ * Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
+ * because we no longer hold a copy of applied microcode
+ * in kernel memory.
+ * 1.14 25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
+ * Fix sigmatch() macro to handle old CPUs with pf == 0.
+ * Thanks to Stuart Swales for pointing out this bug.
+ */
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("Microcode Update Driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
+MODULE_LICENSE("GPL");
+
+struct microcode_header_intel {
+ unsigned int hdrver;
+ unsigned int rev;
+ unsigned int date;
+ unsigned int sig;
+ unsigned int cksum;
+ unsigned int ldrver;
+ unsigned int pf;
+ unsigned int datasize;
+ unsigned int totalsize;
+ unsigned int reserved[3];
+};
+
+struct microcode_intel {
+ struct microcode_header_intel hdr;
+ unsigned int bits[0];
+};
+
+/* microcode format is extended from prescott processors */
+struct extended_signature {
+ unsigned int sig;
+ unsigned int pf;
+ unsigned int cksum;
+};
+
+struct extended_sigtable {
+ unsigned int count;
+ unsigned int cksum;
+ unsigned int reserved[3];
+ struct extended_signature sigs[0];
+};
+
+#define DEFAULT_UCODE_DATASIZE (2000)
+#define MC_HEADER_SIZE (sizeof(struct microcode_header_intel))
+#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
+#define EXT_HEADER_SIZE (sizeof(struct extended_sigtable))
+#define EXT_SIGNATURE_SIZE (sizeof(struct extended_signature))
+#define DWSIZE (sizeof(u32))
+#define get_totalsize(mc) \
+ (((struct microcode_intel *)mc)->hdr.totalsize ? \
+ ((struct microcode_intel *)mc)->hdr.totalsize : \
+ DEFAULT_UCODE_TOTALSIZE)
+
+#define get_datasize(mc) \
+ (((struct microcode_intel *)mc)->hdr.datasize ? \
+ ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
+
+#define sigmatch(s1, s2, p1, p2) \
+ (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
+
+#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
+
+/* serialize access to the physical write to MSR 0x79 */
+static DEFINE_SPINLOCK(microcode_update_lock);
+
+static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
+{
+ struct cpuinfo_x86 *c = &cpu_data(cpu_num);
+ unsigned int val[2];
+
+ memset(csig, 0, sizeof(*csig));
+
+ if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
+ cpu_has(c, X86_FEATURE_IA64)) {
+ printk(KERN_ERR "microcode: CPU%d not a capable Intel "
+ "processor\n", cpu_num);
+ return -1;
+ }
+
+ csig->sig = cpuid_eax(0x00000001);
+
+ if ((c->x86_model >= 5) || (c->x86 > 6)) {
+ /* get processor flags from MSR 0x17 */
+ rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
+ csig->pf = 1 << ((val[1] >> 18) & 7);
+ }
+
+ wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+ /* see notes above for revision 1.07. Apparent chip bug */
+ sync_core();
+ /* get the current revision from MSR 0x8B */
+ rdmsr(MSR_IA32_UCODE_REV, val[0], csig->rev);
+ pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
+ csig->sig, csig->pf, csig->rev);
+
+ return 0;
+}
+
+static inline int update_match_cpu(struct cpu_signature *csig, int sig, int pf)
+{
+ return (!sigmatch(sig, csig->sig, pf, csig->pf)) ? 0 : 1;
+}
+
+static inline int
+update_match_revision(struct microcode_header_intel *mc_header, int rev)
+{
+ return (mc_header->rev <= rev) ? 0 : 1;
+}
+
+static int microcode_sanity_check(void *mc)
+{
+ struct microcode_header_intel *mc_header = mc;
+ struct extended_sigtable *ext_header = NULL;
+ struct extended_signature *ext_sig;
+ unsigned long total_size, data_size, ext_table_size;
+ int sum, orig_sum, ext_sigcount = 0, i;
+
+ total_size = get_totalsize(mc_header);
+ data_size = get_datasize(mc_header);
+ if (data_size + MC_HEADER_SIZE > total_size) {
+ printk(KERN_ERR "microcode: error! "
+ "Bad data size in microcode data file\n");
+ return -EINVAL;
+ }
+
+ if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
+ printk(KERN_ERR "microcode: error! "
+ "Unknown microcode update format\n");
+ return -EINVAL;
+ }
+ ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
+ if (ext_table_size) {
+ if ((ext_table_size < EXT_HEADER_SIZE)
+ || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
+ printk(KERN_ERR "microcode: error! "
+ "Small exttable size in microcode data file\n");
+ return -EINVAL;
+ }
+ ext_header = mc + MC_HEADER_SIZE + data_size;
+ if (ext_table_size != exttable_size(ext_header)) {
+ printk(KERN_ERR "microcode: error! "
+ "Bad exttable size in microcode data file\n");
+ return -EFAULT;
+ }
+ ext_sigcount = ext_header->count;
+ }
+
+ /* check extended table checksum */
+ if (ext_table_size) {
+ int ext_table_sum = 0;
+ int *ext_tablep = (int *)ext_header;
+
+ i = ext_table_size / DWSIZE;
+ while (i--)
+ ext_table_sum += ext_tablep[i];
+ if (ext_table_sum) {
+ printk(KERN_WARNING "microcode: aborting, "
+ "bad extended signature table checksum\n");
+ return -EINVAL;
+ }
+ }
+
+ /* calculate the checksum */
+ orig_sum = 0;
+ i = (MC_HEADER_SIZE + data_size) / DWSIZE;
+ while (i--)
+ orig_sum += ((int *)mc)[i];
+ if (orig_sum) {
+ printk(KERN_ERR "microcode: aborting, bad checksum\n");
+ return -EINVAL;
+ }
+ if (!ext_table_size)
+ return 0;
+ /* check extended signature checksum */
+ for (i = 0; i < ext_sigcount; i++) {
+ ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
+ EXT_SIGNATURE_SIZE * i;
+ sum = orig_sum
+ - (mc_header->sig + mc_header->pf + mc_header->cksum)
+ + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
+ if (sum) {
+ printk(KERN_ERR "microcode: aborting, bad checksum\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/*
+ * return 0 - no update found
+ * return 1 - found update
+ */
+static int
+get_matching_microcode(struct cpu_signature *cpu_sig, void *mc, int rev)
+{
+ struct microcode_header_intel *mc_header = mc;
+ struct extended_sigtable *ext_header;
+ unsigned long total_size = get_totalsize(mc_header);
+ int ext_sigcount, i;
+ struct extended_signature *ext_sig;
+
+ if (!update_match_revision(mc_header, rev))
+ return 0;
+
+ if (update_match_cpu(cpu_sig, mc_header->sig, mc_header->pf))
+ return 1;
+
+ /* Look for ext. headers: */
+ if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
+ return 0;
+
+ ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
+ ext_sigcount = ext_header->count;
+ ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
+
+ for (i = 0; i < ext_sigcount; i++) {
+ if (update_match_cpu(cpu_sig, ext_sig->sig, ext_sig->pf))
+ return 1;
+ ext_sig++;
+ }
+ return 0;
+}
+
+static void apply_microcode(int cpu)
+{
+ unsigned long flags;
+ unsigned int val[2];
+ int cpu_num = raw_smp_processor_id();
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ struct microcode_intel *mc_intel = uci->mc;
+
+ /* We should bind the task to the CPU */
+ BUG_ON(cpu_num != cpu);
+
+ if (mc_intel == NULL)
+ return;
+
+ /* serialize access to the physical write to MSR 0x79 */
+ spin_lock_irqsave(µcode_update_lock, flags);
+
+ /* write microcode via MSR 0x79 */
+ wrmsr(MSR_IA32_UCODE_WRITE,
+ (unsigned long) mc_intel->bits,
+ (unsigned long) mc_intel->bits >> 16 >> 16);
+ wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+
+ /* see notes above for revision 1.07. Apparent chip bug */
+ sync_core();
+
+ /* get the current revision from MSR 0x8B */
+ rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+
+ spin_unlock_irqrestore(µcode_update_lock, flags);
+ if (val[1] != mc_intel->hdr.rev) {
+ printk(KERN_ERR "microcode: CPU%d update from revision "
+ "0x%x to 0x%x failed\n", cpu_num, uci->cpu_sig.rev, val[1]);
+ return;
+ }
+ printk(KERN_INFO "microcode: CPU%d updated from revision "
+ "0x%x to 0x%x, date = %04x-%02x-%02x \n",
+ cpu_num, uci->cpu_sig.rev, val[1],
+ mc_intel->hdr.date & 0xffff,
+ mc_intel->hdr.date >> 24,
+ (mc_intel->hdr.date >> 16) & 0xff);
+ uci->cpu_sig.rev = val[1];
+}
+
+static int generic_load_microcode(int cpu, void *data, size_t size,
+ int (*get_ucode_data)(void *, const void *, size_t))
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ u8 *ucode_ptr = data, *new_mc = NULL, *mc;
+ int new_rev = uci->cpu_sig.rev;
+ unsigned int leftover = size;
+
+ while (leftover) {
+ struct microcode_header_intel mc_header;
+ unsigned int mc_size;
+
+ if (get_ucode_data(&mc_header, ucode_ptr, sizeof(mc_header)))
+ break;
+
+ mc_size = get_totalsize(&mc_header);
+ if (!mc_size || mc_size > leftover) {
+ printk(KERN_ERR "microcode: error!"
+ "Bad data in microcode data file\n");
+ break;
+ }
+
+ mc = vmalloc(mc_size);
+ if (!mc)
+ break;
+
+ if (get_ucode_data(mc, ucode_ptr, mc_size) ||
+ microcode_sanity_check(mc) < 0) {
+ vfree(mc);
+ break;
+ }
+
+ if (get_matching_microcode(&uci->cpu_sig, mc, new_rev)) {
+ if (new_mc)
+ vfree(new_mc);
+ new_rev = mc_header.rev;
+ new_mc = mc;
+ } else
+ vfree(mc);
+
+ ucode_ptr += mc_size;
+ leftover -= mc_size;
+ }
+
+ if (new_mc) {
+ if (!leftover) {
+ if (uci->mc)
+ vfree(uci->mc);
+ uci->mc = (struct microcode_intel *)new_mc;
+ pr_debug("microcode: CPU%d found a matching microcode update with"
+ " version 0x%x (current=0x%x)\n",
+ cpu, new_rev, uci->cpu_sig.rev);
+ } else
+ vfree(new_mc);
+ }
+
+ return (int)leftover;
+}
+
+static int get_ucode_fw(void *to, const void *from, size_t n)
+{
+ memcpy(to, from, n);
+ return 0;
+}
+
+static int request_microcode_fw(int cpu, struct device *device)
+{
+ char name[30];
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
+ const struct firmware *firmware;
+ int ret;
+
+ /* We should bind the task to the CPU */
+ BUG_ON(cpu != raw_smp_processor_id());
+ sprintf(name, "intel-ucode/%02x-%02x-%02x",
+ c->x86, c->x86_model, c->x86_mask);
+ ret = request_firmware(&firmware, name, device);
+ if (ret) {
+ pr_debug("microcode: data file %s load failed\n", name);
+ return ret;
+ }
+
+ ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size,
+ &get_ucode_fw);
+
+ release_firmware(firmware);
+
+ return ret;
+}
+
+static int get_ucode_user(void *to, const void *from, size_t n)
+{
+ return copy_from_user(to, from, n);
+}
+
+static int request_microcode_user(int cpu, const void __user *buf, size_t size)
+{
+ /* We should bind the task to the CPU */
+ BUG_ON(cpu != raw_smp_processor_id());
+
+ return generic_load_microcode(cpu, (void*)buf, size, &get_ucode_user);
+}
+
+static void microcode_fini_cpu(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ vfree(uci->mc);
+ uci->mc = NULL;
+}
+
+struct microcode_ops microcode_intel_ops = {
+ .request_microcode_user = request_microcode_user,
+ .request_microcode_fw = request_microcode_fw,
+ .collect_cpu_info = collect_cpu_info,
+ .apply_microcode = apply_microcode,
+ .microcode_fini_cpu = microcode_fini_cpu,
+};
+
+struct microcode_ops * __init init_intel_microcode(void)
+{
+ return µcode_intel_ops;
+}
+
diff --git a/arch/x86/kernel/paravirt-spinlocks.c b/arch/x86/kernel/paravirt-spinlocks.c
new file mode 100644
index 0000000..0e9f198
--- /dev/null
+++ b/arch/x86/kernel/paravirt-spinlocks.c
@@ -0,0 +1,37 @@
+/*
+ * Split spinlock implementation out into its own file, so it can be
+ * compiled in a FTRACE-compatible way.
+ */
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+#include <asm/paravirt.h>
+
+static void default_spin_lock_flags(struct raw_spinlock *lock, unsigned long flags)
+{
+ __raw_spin_lock(lock);
+}
+
+struct pv_lock_ops pv_lock_ops = {
+#ifdef CONFIG_SMP
+ .spin_is_locked = __ticket_spin_is_locked,
+ .spin_is_contended = __ticket_spin_is_contended,
+
+ .spin_lock = __ticket_spin_lock,
+ .spin_lock_flags = default_spin_lock_flags,
+ .spin_trylock = __ticket_spin_trylock,
+ .spin_unlock = __ticket_spin_unlock,
+#endif
+};
+EXPORT_SYMBOL(pv_lock_ops);
+
+void __init paravirt_use_bytelocks(void)
+{
+#ifdef CONFIG_SMP
+ pv_lock_ops.spin_is_locked = __byte_spin_is_locked;
+ pv_lock_ops.spin_is_contended = __byte_spin_is_contended;
+ pv_lock_ops.spin_lock = __byte_spin_lock;
+ pv_lock_ops.spin_trylock = __byte_spin_trylock;
+ pv_lock_ops.spin_unlock = __byte_spin_unlock;
+#endif
+}
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 6b0bb73..e4c8fb6 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -268,17 +268,6 @@
return __get_cpu_var(paravirt_lazy_mode);
}
-void __init paravirt_use_bytelocks(void)
-{
-#ifdef CONFIG_SMP
- pv_lock_ops.spin_is_locked = __byte_spin_is_locked;
- pv_lock_ops.spin_is_contended = __byte_spin_is_contended;
- pv_lock_ops.spin_lock = __byte_spin_lock;
- pv_lock_ops.spin_trylock = __byte_spin_trylock;
- pv_lock_ops.spin_unlock = __byte_spin_unlock;
-#endif
-}
-
struct pv_info pv_info = {
.name = "bare hardware",
.paravirt_enabled = 0,
@@ -349,6 +338,10 @@
.write_ldt_entry = native_write_ldt_entry,
.write_gdt_entry = native_write_gdt_entry,
.write_idt_entry = native_write_idt_entry,
+
+ .alloc_ldt = paravirt_nop,
+ .free_ldt = paravirt_nop,
+
.load_sp0 = native_load_sp0,
#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
@@ -460,18 +453,6 @@
.set_fixmap = native_set_fixmap,
};
-struct pv_lock_ops pv_lock_ops = {
-#ifdef CONFIG_SMP
- .spin_is_locked = __ticket_spin_is_locked,
- .spin_is_contended = __ticket_spin_is_contended,
-
- .spin_lock = __ticket_spin_lock,
- .spin_trylock = __ticket_spin_trylock,
- .spin_unlock = __ticket_spin_unlock,
-#endif
-};
-EXPORT_SYMBOL(pv_lock_ops);
-
EXPORT_SYMBOL_GPL(pv_time_ops);
EXPORT_SYMBOL (pv_cpu_ops);
EXPORT_SYMBOL (pv_mmu_ops);
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 205188d..922c140 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -76,47 +76,12 @@
return ((unsigned long *)tsk->thread.sp)[3];
}
-#ifdef CONFIG_HOTPLUG_CPU
-#include <asm/nmi.h>
-
-static void cpu_exit_clear(void)
-{
- int cpu = raw_smp_processor_id();
-
- idle_task_exit();
-
- cpu_uninit();
- irq_ctx_exit(cpu);
-
- cpu_clear(cpu, cpu_callout_map);
- cpu_clear(cpu, cpu_callin_map);
-
- numa_remove_cpu(cpu);
- c1e_remove_cpu(cpu);
-}
-
-/* We don't actually take CPU down, just spin without interrupts. */
-static inline void play_dead(void)
-{
- /* This must be done before dead CPU ack */
- cpu_exit_clear();
- mb();
- /* Ack it */
- __get_cpu_var(cpu_state) = CPU_DEAD;
-
- /*
- * With physical CPU hotplug, we should halt the cpu
- */
- local_irq_disable();
- /* mask all interrupts, flush any and all caches, and halt */
- wbinvd_halt();
-}
-#else
+#ifndef CONFIG_SMP
static inline void play_dead(void)
{
BUG();
}
-#endif /* CONFIG_HOTPLUG_CPU */
+#endif
/*
* The idle thread. There's no useful work to be
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 2a8ccb9..ca80394 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -86,30 +86,12 @@
__exit_idle();
}
-#ifdef CONFIG_HOTPLUG_CPU
-DECLARE_PER_CPU(int, cpu_state);
-
-#include <linux/nmi.h>
-/* We halt the CPU with physical CPU hotplug */
-static inline void play_dead(void)
-{
- idle_task_exit();
- c1e_remove_cpu(raw_smp_processor_id());
-
- mb();
- /* Ack it */
- __get_cpu_var(cpu_state) = CPU_DEAD;
-
- local_irq_disable();
- /* mask all interrupts, flush any and all caches, and halt */
- wbinvd_halt();
-}
-#else
+#ifndef CONFIG_SMP
static inline void play_dead(void)
{
BUG();
}
-#endif /* CONFIG_HOTPLUG_CPU */
+#endif
/*
* The idle thread. There's no useful work to be
@@ -754,12 +736,12 @@
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/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index e375b65..0a6d8c1 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -40,7 +40,9 @@
REGSET_GENERAL,
REGSET_FP,
REGSET_XFP,
+ REGSET_IOPERM64 = REGSET_XFP,
REGSET_TLS,
+ REGSET_IOPERM32,
};
/*
@@ -555,6 +557,29 @@
return 0;
}
+/*
+ * These access the current or another (stopped) task's io permission
+ * bitmap for debugging or core dump.
+ */
+static int ioperm_active(struct task_struct *target,
+ const struct user_regset *regset)
+{
+ return target->thread.io_bitmap_max / regset->size;
+}
+
+static int ioperm_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ if (!target->thread.io_bitmap_ptr)
+ return -ENXIO;
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ target->thread.io_bitmap_ptr,
+ 0, IO_BITMAP_BYTES);
+}
+
#ifdef CONFIG_X86_PTRACE_BTS
/*
* The configuration for a particular BTS hardware implementation.
@@ -1385,6 +1410,12 @@
.size = sizeof(long), .align = sizeof(long),
.active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set
},
+ [REGSET_IOPERM64] = {
+ .core_note_type = NT_386_IOPERM,
+ .n = IO_BITMAP_LONGS,
+ .size = sizeof(long), .align = sizeof(long),
+ .active = ioperm_active, .get = ioperm_get
+ },
};
static const struct user_regset_view user_x86_64_view = {
@@ -1431,6 +1462,12 @@
.active = regset_tls_active,
.get = regset_tls_get, .set = regset_tls_set
},
+ [REGSET_IOPERM32] = {
+ .core_note_type = NT_386_IOPERM,
+ .n = IO_BITMAP_BYTES / sizeof(u32),
+ .size = sizeof(u32), .align = sizeof(u32),
+ .active = ioperm_active, .get = ioperm_get
+ },
};
static const struct user_regset_view user_x86_32_view = {
@@ -1452,7 +1489,8 @@
#endif
}
-void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
+void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
+ int error_code, int si_code)
{
struct siginfo info;
@@ -1461,7 +1499,7 @@
memset(&info, 0, sizeof(info));
info.si_signo = SIGTRAP;
- info.si_code = TRAP_BRKPT;
+ info.si_code = si_code;
/* User-mode ip? */
info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL;
@@ -1548,5 +1586,5 @@
*/
if (test_thread_flag(TIF_SINGLESTEP) &&
tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL))
- send_sigtrap(current, regs, 0);
+ send_sigtrap(current, regs, 0, TRAP_BRKPT);
}
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 46c98ef..21b8e0a 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -582,6 +582,190 @@
struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;
/*
+ * Some BIOSes seem to corrupt the low 64k of memory during events
+ * like suspend/resume and unplugging an HDMI cable. Reserve all
+ * remaining free memory in that area and fill it with a distinct
+ * pattern.
+ */
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+#define MAX_SCAN_AREAS 8
+
+static int __read_mostly memory_corruption_check = -1;
+
+static unsigned __read_mostly corruption_check_size = 64*1024;
+static unsigned __read_mostly corruption_check_period = 60; /* seconds */
+
+static struct e820entry scan_areas[MAX_SCAN_AREAS];
+static int num_scan_areas;
+
+
+static int set_corruption_check(char *arg)
+{
+ char *end;
+
+ memory_corruption_check = simple_strtol(arg, &end, 10);
+
+ return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check", set_corruption_check);
+
+static int set_corruption_check_period(char *arg)
+{
+ char *end;
+
+ corruption_check_period = simple_strtoul(arg, &end, 10);
+
+ return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_period", set_corruption_check_period);
+
+static int set_corruption_check_size(char *arg)
+{
+ char *end;
+ unsigned size;
+
+ size = memparse(arg, &end);
+
+ if (*end == '\0')
+ corruption_check_size = size;
+
+ return (size == corruption_check_size) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_size", set_corruption_check_size);
+
+
+static void __init setup_bios_corruption_check(void)
+{
+ u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */
+
+ if (memory_corruption_check == -1) {
+ memory_corruption_check =
+#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
+ 1
+#else
+ 0
+#endif
+ ;
+ }
+
+ if (corruption_check_size == 0)
+ memory_corruption_check = 0;
+
+ if (!memory_corruption_check)
+ return;
+
+ corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
+
+ while(addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
+ u64 size;
+ addr = find_e820_area_size(addr, &size, PAGE_SIZE);
+
+ if (addr == 0)
+ break;
+
+ if ((addr + size) > corruption_check_size)
+ size = corruption_check_size - addr;
+
+ if (size == 0)
+ break;
+
+ e820_update_range(addr, size, E820_RAM, E820_RESERVED);
+ scan_areas[num_scan_areas].addr = addr;
+ scan_areas[num_scan_areas].size = size;
+ num_scan_areas++;
+
+ /* Assume we've already mapped this early memory */
+ memset(__va(addr), 0, size);
+
+ addr += size;
+ }
+
+ printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
+ num_scan_areas);
+ update_e820();
+}
+
+static struct timer_list periodic_check_timer;
+
+void check_for_bios_corruption(void)
+{
+ int i;
+ int corruption = 0;
+
+ if (!memory_corruption_check)
+ return;
+
+ for(i = 0; i < num_scan_areas; i++) {
+ unsigned long *addr = __va(scan_areas[i].addr);
+ unsigned long size = scan_areas[i].size;
+
+ for(; size; addr++, size -= sizeof(unsigned long)) {
+ if (!*addr)
+ continue;
+ printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n",
+ addr, __pa(addr), *addr);
+ corruption = 1;
+ *addr = 0;
+ }
+ }
+
+ WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n");
+}
+
+static void periodic_check_for_corruption(unsigned long data)
+{
+ check_for_bios_corruption();
+ mod_timer(&periodic_check_timer, round_jiffies(jiffies + corruption_check_period*HZ));
+}
+
+void start_periodic_check_for_corruption(void)
+{
+ if (!memory_corruption_check || corruption_check_period == 0)
+ return;
+
+ printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
+ corruption_check_period);
+
+ init_timer(&periodic_check_timer);
+ periodic_check_timer.function = &periodic_check_for_corruption;
+ periodic_check_for_corruption(0);
+}
+#endif
+
+static int __init dmi_low_memory_corruption(const struct dmi_system_id *d)
+{
+ printk(KERN_NOTICE
+ "%s detected: BIOS may corrupt low RAM, working it around.\n",
+ d->ident);
+
+ e820_update_range(0, 0x10000, E820_RAM, E820_RESERVED);
+ sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+
+ return 0;
+}
+
+/* List of systems that have known low memory corruption BIOS problems */
+static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
+#ifdef CONFIG_X86_RESERVE_LOW_64K
+ {
+ .callback = dmi_low_memory_corruption,
+ .ident = "AMI BIOS",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+ },
+ },
+ {
+ .callback = dmi_low_memory_corruption,
+ .ident = "Phoenix BIOS",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
+ },
+ },
+#endif
+ {}
+};
+
+/*
* Determine if we were loaded by an EFI loader. If so, then we have also been
* passed the efi memmap, systab, etc., so we should use these data structures
* for initialization. Note, the efi init code path is determined by the
@@ -715,6 +899,10 @@
finish_e820_parsing();
+ dmi_scan_machine();
+
+ dmi_check_system(bad_bios_dmi_table);
+
#ifdef CONFIG_X86_32
probe_roms();
#endif
@@ -771,6 +959,10 @@
high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
#endif
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+ setup_bios_corruption_check();
+#endif
+
/* max_pfn_mapped is updated here */
max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
max_pfn_mapped = max_low_pfn_mapped;
@@ -799,8 +991,6 @@
vsmp_init();
#endif
- dmi_scan_machine();
-
io_delay_init();
/*
@@ -903,3 +1093,5 @@
#endif
#endif
}
+
+
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index b21070e..d6dd057 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -27,6 +27,7 @@
#include <asm/uaccess.h>
#include <asm/i387.h>
#include <asm/vdso.h>
+#include <asm/syscall.h>
#include <asm/syscalls.h>
#include "sigframe.h"
@@ -112,6 +113,27 @@
return do_sigaltstack(uss, uoss, regs->sp);
}
+#define COPY(x) { \
+ err |= __get_user(regs->x, &sc->x); \
+}
+
+#define COPY_SEG(seg) { \
+ unsigned short tmp; \
+ err |= __get_user(tmp, &sc->seg); \
+ regs->seg = tmp; \
+}
+
+#define COPY_SEG_STRICT(seg) { \
+ unsigned short tmp; \
+ err |= __get_user(tmp, &sc->seg); \
+ regs->seg = tmp | 3; \
+}
+
+#define GET_SEG(seg) { \
+ unsigned short tmp; \
+ err |= __get_user(tmp, &sc->seg); \
+ loadsegment(seg, tmp); \
+}
/*
* Do a signal return; undo the signal stack.
@@ -120,28 +142,13 @@
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
unsigned long *pax)
{
+ void __user *buf;
+ unsigned int tmpflags;
unsigned int err = 0;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
-#define COPY(x) err |= __get_user(regs->x, &sc->x)
-
-#define COPY_SEG(seg) \
- { unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
- regs->seg = tmp; }
-
-#define COPY_SEG_STRICT(seg) \
- { unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
- regs->seg = tmp|3; }
-
-#define GET_SEG(seg) \
- { unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
- loadsegment(seg, tmp); }
-
GET_SEG(gs);
COPY_SEG(fs);
COPY_SEG(es);
@@ -151,21 +158,12 @@
COPY_SEG_STRICT(cs);
COPY_SEG_STRICT(ss);
- {
- unsigned int tmpflags;
+ err |= __get_user(tmpflags, &sc->flags);
+ regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
+ regs->orig_ax = -1; /* disable syscall checks */
- err |= __get_user(tmpflags, &sc->flags);
- regs->flags = (regs->flags & ~FIX_EFLAGS) |
- (tmpflags & FIX_EFLAGS);
- regs->orig_ax = -1; /* disable syscall checks */
- }
-
- {
- void __user *buf;
-
- err |= __get_user(buf, &sc->fpstate);
- err |= restore_i387_xstate(buf);
- }
+ err |= __get_user(buf, &sc->fpstate);
+ err |= restore_i387_xstate(buf);
err |= __get_user(*pax, &sc->ax);
return err;
@@ -214,9 +212,8 @@
return 0;
}
-asmlinkage int sys_rt_sigreturn(unsigned long __unused)
+static long do_rt_sigreturn(struct pt_regs *regs)
{
- struct pt_regs *regs = (struct pt_regs *)&__unused;
struct rt_sigframe __user *frame;
unsigned long ax;
sigset_t set;
@@ -242,10 +239,17 @@
return ax;
badframe:
- force_sig(SIGSEGV, current);
+ signal_fault(regs, frame, "rt_sigreturn");
return 0;
}
+asmlinkage int sys_rt_sigreturn(unsigned long __unused)
+{
+ struct pt_regs *regs = (struct pt_regs *)&__unused;
+
+ return do_rt_sigreturn(regs);
+}
+
/*
* Set up a signal frame.
*/
@@ -337,39 +341,29 @@
}
static int
-setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
- struct pt_regs *regs)
+__setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
+ struct pt_regs *regs)
{
struct sigframe __user *frame;
void __user *restorer;
int err = 0;
- int usig;
void __user *fpstate = NULL;
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return -EFAULT;
- usig = current_thread_info()->exec_domain
- && current_thread_info()->exec_domain->signal_invmap
- && sig < 32
- ? current_thread_info()->exec_domain->signal_invmap[sig]
- : sig;
+ if (__put_user(sig, &frame->sig))
+ return -EFAULT;
- err = __put_user(usig, &frame->sig);
- if (err)
- goto give_sigsegv;
-
- err = setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
- if (err)
- goto give_sigsegv;
+ if (setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
+ return -EFAULT;
if (_NSIG_WORDS > 1) {
- err = __copy_to_user(&frame->extramask, &set->sig[1],
- sizeof(frame->extramask));
- if (err)
- goto give_sigsegv;
+ if (__copy_to_user(&frame->extramask, &set->sig[1],
+ sizeof(frame->extramask)))
+ return -EFAULT;
}
if (current->mm->context.vdso)
@@ -394,7 +388,7 @@
err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up registers for signal handler */
regs->sp = (unsigned long)frame;
@@ -409,38 +403,27 @@
regs->cs = __USER_CS;
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs *regs)
+static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
void __user *restorer;
int err = 0;
- int usig;
void __user *fpstate = NULL;
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return -EFAULT;
- usig = current_thread_info()->exec_domain
- && current_thread_info()->exec_domain->signal_invmap
- && sig < 32
- ? current_thread_info()->exec_domain->signal_invmap[sig]
- : sig;
-
- err |= __put_user(usig, &frame->sig);
+ err |= __put_user(sig, &frame->sig);
err |= __put_user(&frame->info, &frame->pinfo);
err |= __put_user(&frame->uc, &frame->puc);
err |= copy_siginfo_to_user(&frame->info, info);
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Create the ucontext. */
if (cpu_has_xsave)
@@ -456,7 +439,7 @@
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up to return from userspace. */
restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
@@ -476,12 +459,12 @@
err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up registers for signal handler */
regs->sp = (unsigned long)frame;
regs->ip = (unsigned long)ka->sa.sa_handler;
- regs->ax = (unsigned long)usig;
+ regs->ax = (unsigned long)sig;
regs->dx = (unsigned long)&frame->info;
regs->cx = (unsigned long)&frame->uc;
@@ -491,15 +474,48 @@
regs->cs = __USER_CS;
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
/*
* OK, we're invoking a handler:
*/
+static int signr_convert(int sig)
+{
+ struct thread_info *info = current_thread_info();
+
+ if (info->exec_domain && info->exec_domain->signal_invmap && sig < 32)
+ return info->exec_domain->signal_invmap[sig];
+ return sig;
+}
+
+#define is_ia32 1
+#define ia32_setup_frame __setup_frame
+#define ia32_setup_rt_frame __setup_rt_frame
+
+static int
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
+{
+ int usig = signr_convert(sig);
+ int ret;
+
+ /* Set up the stack frame */
+ if (is_ia32) {
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
+ else
+ ret = ia32_setup_frame(usig, ka, set, regs);
+ } else
+ ret = __setup_rt_frame(sig, ka, info, set, regs);
+
+ if (ret) {
+ force_sigsegv(sig, current);
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
static int
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs *regs)
@@ -507,9 +523,9 @@
int ret;
/* Are we from a system call? */
- if ((long)regs->orig_ax >= 0) {
+ if (syscall_get_nr(current, regs) >= 0) {
/* If so, check system call restarting.. */
- switch (regs->ax) {
+ switch (syscall_get_error(current, regs)) {
case -ERESTART_RESTARTBLOCK:
case -ERESTARTNOHAND:
regs->ax = -EINTR;
@@ -536,15 +552,20 @@
likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
regs->flags &= ~X86_EFLAGS_TF;
- /* Set up the stack frame */
- if (ka->sa.sa_flags & SA_SIGINFO)
- ret = setup_rt_frame(sig, ka, info, oldset, regs);
- else
- ret = setup_frame(sig, ka, oldset, regs);
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
if (ret)
return ret;
+#ifdef CONFIG_X86_64
+ /*
+ * This has nothing to do with segment registers,
+ * despite the name. This magic affects uaccess.h
+ * macros' behavior. Reset it to the normal setting.
+ */
+ set_fs(USER_DS);
+#endif
+
/*
* Clear the direction flag as per the ABI for function entry.
*/
@@ -571,6 +592,7 @@
return 0;
}
+#define NR_restart_syscall __NR_restart_syscall
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -623,9 +645,9 @@
}
/* Did we come from a system call? */
- if ((long)regs->orig_ax >= 0) {
+ if (syscall_get_nr(current, regs) >= 0) {
/* Restart the system call - no handlers present */
- switch (regs->ax) {
+ switch (syscall_get_error(current, regs)) {
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
@@ -634,7 +656,7 @@
break;
case -ERESTART_RESTARTBLOCK:
- regs->ax = __NR_restart_syscall;
+ regs->ax = NR_restart_syscall;
regs->ip -= 2;
break;
}
@@ -657,6 +679,12 @@
void
do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
{
+#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
+ /* notify userspace of pending MCEs */
+ if (thread_info_flags & _TIF_MCE_NOTIFY)
+ mce_notify_user();
+#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
+
/* deal with pending signal delivery */
if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs);
@@ -666,5 +694,23 @@
tracehook_notify_resume(regs);
}
+#ifdef CONFIG_X86_32
clear_thread_flag(TIF_IRET);
+#endif /* CONFIG_X86_32 */
+}
+
+void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
+{
+ struct task_struct *me = current;
+
+ if (show_unhandled_signals && printk_ratelimit()) {
+ printk(KERN_INFO
+ "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
+ me->comm, me->pid, where, frame,
+ regs->ip, regs->sp, regs->orig_ax);
+ print_vma_addr(" in ", regs->ip);
+ printk(KERN_CONT "\n");
+ }
+
+ force_sig(SIGSEGV, me);
}
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
index 823a55b..a5c9627 100644
--- a/arch/x86/kernel/signal_64.c
+++ b/arch/x86/kernel/signal_64.c
@@ -52,6 +52,16 @@
return do_sigaltstack(uss, uoss, regs->sp);
}
+#define COPY(x) { \
+ err |= __get_user(regs->x, &sc->x); \
+}
+
+#define COPY_SEG_STRICT(seg) { \
+ unsigned short tmp; \
+ err |= __get_user(tmp, &sc->seg); \
+ regs->seg = tmp | 3; \
+}
+
/*
* Do a signal return; undo the signal stack.
*/
@@ -59,13 +69,13 @@
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
unsigned long *pax)
{
+ void __user *buf;
+ unsigned int tmpflags;
unsigned int err = 0;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
-#define COPY(x) (err |= __get_user(regs->x, &sc->x))
-
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
COPY(dx); COPY(cx); COPY(ip);
COPY(r8);
@@ -80,34 +90,24 @@
/* Kernel saves and restores only the CS segment register on signals,
* which is the bare minimum needed to allow mixed 32/64-bit code.
* App's signal handler can save/restore other segments if needed. */
- {
- unsigned cs;
- err |= __get_user(cs, &sc->cs);
- regs->cs = cs | 3; /* Force into user mode */
- }
+ COPY_SEG_STRICT(cs);
- {
- unsigned int tmpflags;
- err |= __get_user(tmpflags, &sc->flags);
- regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
- regs->orig_ax = -1; /* disable syscall checks */
- }
+ err |= __get_user(tmpflags, &sc->flags);
+ regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
+ regs->orig_ax = -1; /* disable syscall checks */
- {
- struct _fpstate __user *buf;
- err |= __get_user(buf, &sc->fpstate);
- err |= restore_i387_xstate(buf);
- }
+ err |= __get_user(buf, &sc->fpstate);
+ err |= restore_i387_xstate(buf);
err |= __get_user(*pax, &sc->ax);
return err;
}
-asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+static long do_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
- sigset_t set;
unsigned long ax;
+ sigset_t set;
frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -130,10 +130,15 @@
return ax;
badframe:
- signal_fault(regs, frame, "sigreturn");
+ signal_fault(regs, frame, "rt_sigreturn");
return 0;
}
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+{
+ return do_rt_sigreturn(regs);
+}
+
/*
* Set up a signal frame.
*/
@@ -195,8 +200,8 @@
return (void __user *)round_down(sp - size, 64);
}
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs *regs)
+static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
void __user *fp = NULL;
@@ -209,17 +214,16 @@
(unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
if (save_i387_xstate(fp) < 0)
- err |= -1;
+ return -EFAULT;
} else
frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return -EFAULT;
if (ka->sa.sa_flags & SA_SIGINFO) {
- err |= copy_siginfo_to_user(&frame->info, info);
- if (err)
- goto give_sigsegv;
+ if (copy_siginfo_to_user(&frame->info, info))
+ return -EFAULT;
}
/* Create the ucontext. */
@@ -247,11 +251,11 @@
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
} else {
/* could use a vstub here */
- goto give_sigsegv;
+ return -EFAULT;
}
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up registers for signal handler */
regs->di = sig;
@@ -271,15 +275,45 @@
regs->cs = __USER_CS;
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
/*
* OK, we're invoking a handler
*/
+static int signr_convert(int sig)
+{
+ return sig;
+}
+
+#ifdef CONFIG_IA32_EMULATION
+#define is_ia32 test_thread_flag(TIF_IA32)
+#else
+#define is_ia32 0
+#endif
+
+static int
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
+{
+ int usig = signr_convert(sig);
+ int ret;
+
+ /* Set up the stack frame */
+ if (is_ia32) {
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
+ else
+ ret = ia32_setup_frame(usig, ka, set, regs);
+ } else
+ ret = __setup_rt_frame(sig, ka, info, set, regs);
+
+ if (ret) {
+ force_sigsegv(sig, current);
+ return -EFAULT;
+ }
+
+ return ret;
+}
static int
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
@@ -317,51 +351,48 @@
likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
regs->flags &= ~X86_EFLAGS_TF;
-#ifdef CONFIG_IA32_EMULATION
- if (test_thread_flag(TIF_IA32)) {
- if (ka->sa.sa_flags & SA_SIGINFO)
- ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs);
- else
- ret = ia32_setup_frame(sig, ka, oldset, regs);
- } else
-#endif
ret = setup_rt_frame(sig, ka, info, oldset, regs);
- if (ret == 0) {
- /*
- * This has nothing to do with segment registers,
- * despite the name. This magic affects uaccess.h
- * macros' behavior. Reset it to the normal setting.
- */
- set_fs(USER_DS);
+ if (ret)
+ return ret;
- /*
- * Clear the direction flag as per the ABI for function entry.
- */
- regs->flags &= ~X86_EFLAGS_DF;
+#ifdef CONFIG_X86_64
+ /*
+ * This has nothing to do with segment registers,
+ * despite the name. This magic affects uaccess.h
+ * macros' behavior. Reset it to the normal setting.
+ */
+ set_fs(USER_DS);
+#endif
- /*
- * Clear TF when entering the signal handler, but
- * notify any tracer that was single-stepping it.
- * The tracer may want to single-step inside the
- * handler too.
- */
- regs->flags &= ~X86_EFLAGS_TF;
+ /*
+ * Clear the direction flag as per the ABI for function entry.
+ */
+ regs->flags &= ~X86_EFLAGS_DF;
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ /*
+ * Clear TF when entering the signal handler, but
+ * notify any tracer that was single-stepping it.
+ * The tracer may want to single-step inside the
+ * handler too.
+ */
+ regs->flags &= ~X86_EFLAGS_TF;
- tracehook_signal_handler(sig, info, ka, regs,
- test_thread_flag(TIF_SINGLESTEP));
- }
+ spin_lock_irq(¤t->sighand->siglock);
+ sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NODEFER))
+ sigaddset(¤t->blocked, sig);
+ recalc_sigpending();
+ spin_unlock_irq(¤t->sighand->siglock);
- return ret;
+ tracehook_signal_handler(sig, info, ka, regs,
+ test_thread_flag(TIF_SINGLESTEP));
+
+ return 0;
}
+#define NR_restart_syscall \
+ test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -391,7 +422,8 @@
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
- /* Re-enable any watchpoints before delivering the
+ /*
+ * Re-enable any watchpoints before delivering the
* signal to user space. The processor register will
* have been cleared if the watchpoint triggered
* inside the kernel.
@@ -399,7 +431,7 @@
if (current->thread.debugreg7)
set_debugreg(current->thread.debugreg7, 7);
- /* Whee! Actually deliver the signal. */
+ /* Whee! Actually deliver the signal. */
if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
/*
* A signal was successfully delivered; the saved
@@ -422,10 +454,9 @@
regs->ax = regs->orig_ax;
regs->ip -= 2;
break;
+
case -ERESTART_RESTARTBLOCK:
- regs->ax = test_thread_flag(TIF_IA32) ?
- __NR_ia32_restart_syscall :
- __NR_restart_syscall;
+ regs->ax = NR_restart_syscall;
regs->ip -= 2;
break;
}
@@ -441,14 +472,18 @@
}
}
-void do_notify_resume(struct pt_regs *regs, void *unused,
- __u32 thread_info_flags)
+/*
+ * notification of userspace execution resumption
+ * - triggered by the TIF_WORK_MASK flags
+ */
+void
+do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
{
-#ifdef CONFIG_X86_MCE
+#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
/* notify userspace of pending MCEs */
if (thread_info_flags & _TIF_MCE_NOTIFY)
mce_notify_user();
-#endif /* CONFIG_X86_MCE */
+#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
/* deal with pending signal delivery */
if (thread_info_flags & _TIF_SIGPENDING)
@@ -458,17 +493,23 @@
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
}
+
+#ifdef CONFIG_X86_32
+ clear_thread_flag(TIF_IRET);
+#endif /* CONFIG_X86_32 */
}
void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
{
struct task_struct *me = current;
+
if (show_unhandled_signals && printk_ratelimit()) {
- printk("%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
- me->comm, me->pid, where, frame, regs->ip,
- regs->sp, regs->orig_ax);
+ printk(KERN_INFO
+ "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
+ me->comm, me->pid, where, frame,
+ regs->ip, regs->sp, regs->orig_ax);
print_vma_addr(" in ", regs->ip);
- printk("\n");
+ printk(KERN_CONT "\n");
}
force_sig(SIGSEGV, me);
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index 361b7a4..18f9b19 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -214,12 +214,16 @@
struct smp_ops smp_ops = {
.smp_prepare_boot_cpu = native_smp_prepare_boot_cpu,
.smp_prepare_cpus = native_smp_prepare_cpus,
- .cpu_up = native_cpu_up,
.smp_cpus_done = native_smp_cpus_done,
.smp_send_stop = native_smp_send_stop,
.smp_send_reschedule = native_smp_send_reschedule,
+ .cpu_up = native_cpu_up,
+ .cpu_die = native_cpu_die,
+ .cpu_disable = native_cpu_disable,
+ .play_dead = native_play_dead,
+
.send_call_func_ipi = native_send_call_func_ipi,
.send_call_func_single_ipi = native_send_call_func_single_ipi,
};
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 9056f7e..76b6f50 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -52,6 +52,7 @@
#include <asm/desc.h>
#include <asm/nmi.h>
#include <asm/irq.h>
+#include <asm/idle.h>
#include <asm/smp.h>
#include <asm/trampoline.h>
#include <asm/cpu.h>
@@ -1344,7 +1345,29 @@
numa_remove_cpu(cpu);
}
-int __cpu_disable(void)
+void cpu_disable_common(void)
+{
+ int cpu = smp_processor_id();
+ /*
+ * HACK:
+ * Allow any queued timer interrupts to get serviced
+ * This is only a temporary solution until we cleanup
+ * fixup_irqs as we do for IA64.
+ */
+ local_irq_enable();
+ mdelay(1);
+
+ local_irq_disable();
+ remove_siblinginfo(cpu);
+
+ /* It's now safe to remove this processor from the online map */
+ lock_vector_lock();
+ remove_cpu_from_maps(cpu);
+ unlock_vector_lock();
+ fixup_irqs(cpu_online_map);
+}
+
+int native_cpu_disable(void)
{
int cpu = smp_processor_id();
@@ -1363,27 +1386,11 @@
stop_apic_nmi_watchdog(NULL);
clear_local_APIC();
- /*
- * HACK:
- * Allow any queued timer interrupts to get serviced
- * This is only a temporary solution until we cleanup
- * fixup_irqs as we do for IA64.
- */
- local_irq_enable();
- mdelay(1);
-
- local_irq_disable();
- remove_siblinginfo(cpu);
-
- /* It's now safe to remove this processor from the online map */
- lock_vector_lock();
- remove_cpu_from_maps(cpu);
- unlock_vector_lock();
- fixup_irqs(cpu_online_map);
+ cpu_disable_common();
return 0;
}
-void __cpu_die(unsigned int cpu)
+void native_cpu_die(unsigned int cpu)
{
/* We don't do anything here: idle task is faking death itself. */
unsigned int i;
@@ -1400,15 +1407,45 @@
}
printk(KERN_ERR "CPU %u didn't die...\n", cpu);
}
+
+void play_dead_common(void)
+{
+ idle_task_exit();
+ reset_lazy_tlbstate();
+ irq_ctx_exit(raw_smp_processor_id());
+ c1e_remove_cpu(raw_smp_processor_id());
+
+ mb();
+ /* Ack it */
+ __get_cpu_var(cpu_state) = CPU_DEAD;
+
+ /*
+ * With physical CPU hotplug, we should halt the cpu
+ */
+ local_irq_disable();
+}
+
+void native_play_dead(void)
+{
+ play_dead_common();
+ wbinvd_halt();
+}
+
#else /* ... !CONFIG_HOTPLUG_CPU */
-int __cpu_disable(void)
+int native_cpu_disable(void)
{
return -ENOSYS;
}
-void __cpu_die(unsigned int cpu)
+void native_cpu_die(unsigned int cpu)
{
/* We said "no" in __cpu_disable */
BUG();
}
+
+void native_play_dead(void)
+{
+ BUG();
+}
+
#endif
diff --git a/arch/x86/kernel/tlb_32.c b/arch/x86/kernel/tlb_32.c
index fec1ece..e00534b 100644
--- a/arch/x86/kernel/tlb_32.c
+++ b/arch/x86/kernel/tlb_32.c
@@ -241,3 +241,11 @@
on_each_cpu(do_flush_tlb_all, NULL, 1);
}
+void reset_lazy_tlbstate(void)
+{
+ int cpu = raw_smp_processor_id();
+
+ per_cpu(cpu_tlbstate, cpu).state = 0;
+ per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
+}
+
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c
index da5a596..0429c5d 100644
--- a/arch/x86/kernel/traps_32.c
+++ b/arch/x86/kernel/traps_32.c
@@ -891,6 +891,7 @@
{
struct task_struct *tsk = current;
unsigned int condition;
+ int si_code;
trace_hardirqs_fixup();
@@ -935,8 +936,9 @@
goto clear_TF_reenable;
}
+ si_code = get_si_code((unsigned long)condition);
/* Ok, finally something we can handle */
- send_sigtrap(tsk, regs, error_code);
+ send_sigtrap(tsk, regs, error_code, si_code);
/*
* Disable additional traps. They'll be re-enabled when
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c
index 2887a78..9c0ac0c 100644
--- a/arch/x86/kernel/traps_64.c
+++ b/arch/x86/kernel/traps_64.c
@@ -940,7 +940,7 @@
tsk->thread.error_code = error_code;
info.si_signo = SIGTRAP;
info.si_errno = 0;
- info.si_code = TRAP_BRKPT;
+ info.si_code = get_si_code(condition);
info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL;
force_sig_info(SIGTRAP, &info, tsk);
diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S
index 201e81a..46e0544 100644
--- a/arch/x86/kernel/vmlinux_64.lds.S
+++ b/arch/x86/kernel/vmlinux_64.lds.S
@@ -172,8 +172,8 @@
.x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
*(.x86_cpu_dev.init)
}
- SECURITY_INIT
__x86_cpu_dev_end = .;
+ SECURITY_INIT
. = ALIGN(8);
.parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) {
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index 07713d6..9abac8a 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -95,7 +95,9 @@
* Start with clearing the user buffer. This will present a
* clean context for the bytes not touched by the fxsave/xsave.
*/
- __clear_user(buf, sig_xstate_size);
+ err = __clear_user(buf, sig_xstate_size);
+ if (err)
+ return err;
if (task_thread_info(tsk)->status & TS_XSAVE)
err = xsave_user(buf);
@@ -114,6 +116,8 @@
if (task_thread_info(tsk)->status & TS_XSAVE) {
struct _fpstate __user *fx = buf;
+ struct _xstate __user *x = buf;
+ u64 xstate_bv;
err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
sizeof(struct _fpx_sw_bytes));
@@ -121,6 +125,31 @@
err |= __put_user(FP_XSTATE_MAGIC2,
(__u32 __user *) (buf + sig_xstate_size
- FP_XSTATE_MAGIC2_SIZE));
+
+ /*
+ * Read the xstate_bv which we copied (directly from the cpu or
+ * from the state in task struct) to the user buffers and
+ * set the FP/SSE bits.
+ */
+ err |= __get_user(xstate_bv, &x->xstate_hdr.xstate_bv);
+
+ /*
+ * For legacy compatible, we always set FP/SSE bits in the bit
+ * vector while saving the state to the user context. This will
+ * enable us capturing any changes(during sigreturn) to
+ * the FP/SSE bits by the legacy applications which don't touch
+ * xstate_bv in the xsave header.
+ *
+ * xsave aware apps can change the xstate_bv in the xsave
+ * header as well as change any contents in the memory layout.
+ * xrestore as part of sigreturn will capture all the changes.
+ */
+ xstate_bv |= XSTATE_FPSSE;
+
+ err |= __put_user(xstate_bv, &x->xstate_hdr.xstate_bv);
+
+ if (err)
+ return err;
}
return 1;
@@ -272,7 +301,7 @@
/*
* setup the xstate image representing the init state
*/
-void setup_xstate_init(void)
+static void __init setup_xstate_init(void)
{
init_xstate_buf = alloc_bootmem(xstate_size);
init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 8f92cac..a742d75 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -914,15 +914,15 @@
void vmalloc_sync_all(void)
{
-#ifdef CONFIG_X86_32
- unsigned long start = VMALLOC_START & PGDIR_MASK;
unsigned long address;
+#ifdef CONFIG_X86_32
if (SHARED_KERNEL_PMD)
return;
- BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK);
- for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) {
+ for (address = VMALLOC_START & PMD_MASK;
+ address >= TASK_SIZE && address < FIXADDR_TOP;
+ address += PMD_SIZE) {
unsigned long flags;
struct page *page;
@@ -935,10 +935,8 @@
spin_unlock_irqrestore(&pgd_lock, flags);
}
#else /* CONFIG_X86_64 */
- unsigned long start = VMALLOC_START & PGDIR_MASK;
- unsigned long address;
-
- for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) {
+ for (address = VMALLOC_START & PGDIR_MASK; address <= VMALLOC_END;
+ address += PGDIR_SIZE) {
const pgd_t *pgd_ref = pgd_offset_k(address);
unsigned long flags;
struct page *page;
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index c3789bb..bbe044d 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -31,6 +31,7 @@
#include <linux/cpumask.h>
#include <asm/asm.h>
+#include <asm/bios_ebda.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -969,6 +970,8 @@
int codesize, reservedpages, datasize, initsize;
int tmp;
+ start_periodic_check_for_corruption();
+
#ifdef CONFIG_FLATMEM
BUG_ON(!mem_map);
#endif
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 83e13f2..3e10054 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -31,6 +31,7 @@
#include <linux/nmi.h>
#include <asm/processor.h>
+#include <asm/bios_ebda.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -881,6 +882,8 @@
{
long codesize, reservedpages, datasize, initsize;
+ start_periodic_check_for_corruption();
+
pci_iommu_alloc();
/* clear_bss() already clear the empty_zero_page */
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 6ab3196..8cbeda1 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -24,19 +24,27 @@
#ifdef CONFIG_X86_64
-unsigned long __phys_addr(unsigned long x)
-{
- if (x >= __START_KERNEL_map)
- return x - __START_KERNEL_map + phys_base;
- return x - PAGE_OFFSET;
-}
-EXPORT_SYMBOL(__phys_addr);
-
static inline int phys_addr_valid(unsigned long addr)
{
return addr < (1UL << boot_cpu_data.x86_phys_bits);
}
+unsigned long __phys_addr(unsigned long x)
+{
+ if (x >= __START_KERNEL_map) {
+ x -= __START_KERNEL_map;
+ VIRTUAL_BUG_ON(x >= KERNEL_IMAGE_SIZE);
+ x += phys_base;
+ } else {
+ VIRTUAL_BUG_ON(x < PAGE_OFFSET);
+ x -= PAGE_OFFSET;
+ VIRTUAL_BUG_ON(system_state == SYSTEM_BOOTING ? x > MAXMEM :
+ !phys_addr_valid(x));
+ }
+ return x;
+}
+EXPORT_SYMBOL(__phys_addr);
+
#else
static inline int phys_addr_valid(unsigned long addr)
@@ -44,6 +52,17 @@
return 1;
}
+#ifdef CONFIG_DEBUG_VIRTUAL
+unsigned long __phys_addr(unsigned long x)
+{
+ /* VMALLOC_* aren't constants; not available at the boot time */
+ VIRTUAL_BUG_ON(x < PAGE_OFFSET || (system_state != SYSTEM_BOOTING &&
+ is_vmalloc_addr((void *)x)));
+ return x - PAGE_OFFSET;
+}
+EXPORT_SYMBOL(__phys_addr);
+#endif
+
#endif
int page_is_ram(unsigned long pagenr)
@@ -614,7 +633,7 @@
*/
offset = phys_addr & ~PAGE_MASK;
phys_addr &= PAGE_MASK;
- size = PAGE_ALIGN(last_addr) - phys_addr;
+ size = PAGE_ALIGN(last_addr + 1) - phys_addr;
/*
* Mappings have to fit in the FIX_BTMAP area.
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
index 3815e42..87b9ab1 100644
--- a/arch/x86/xen/Kconfig
+++ b/arch/x86/xen/Kconfig
@@ -26,5 +26,13 @@
config XEN_SAVE_RESTORE
bool
- depends on PM
- default y
\ No newline at end of file
+ depends on XEN && PM
+ default y
+
+config XEN_DEBUG_FS
+ bool "Enable Xen debug and tuning parameters in debugfs"
+ depends on XEN && DEBUG_FS
+ default n
+ help
+ Enable statistics output and various tuning options in debugfs.
+ Enabling this option may incur a significant performance overhead.
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
index 59c1e53..3139479 100644
--- a/arch/x86/xen/Makefile
+++ b/arch/x86/xen/Makefile
@@ -1,4 +1,12 @@
-obj-y := enlighten.o setup.o multicalls.o mmu.o \
+ifdef CONFIG_FTRACE
+# Do not profile debug and lowlevel utilities
+CFLAGS_REMOVE_spinlock.o = -pg
+CFLAGS_REMOVE_time.o = -pg
+CFLAGS_REMOVE_irq.o = -pg
+endif
+
+obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \
time.o xen-asm_$(BITS).o grant-table.o suspend.o
-obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_SMP) += smp.o spinlock.o
+obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o
\ No newline at end of file
diff --git a/arch/x86/xen/debugfs.c b/arch/x86/xen/debugfs.c
new file mode 100644
index 0000000..b53225d
--- /dev/null
+++ b/arch/x86/xen/debugfs.c
@@ -0,0 +1,123 @@
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+#include "debugfs.h"
+
+static struct dentry *d_xen_debug;
+
+struct dentry * __init xen_init_debugfs(void)
+{
+ if (!d_xen_debug) {
+ d_xen_debug = debugfs_create_dir("xen", NULL);
+
+ if (!d_xen_debug)
+ pr_warning("Could not create 'xen' debugfs directory\n");
+ }
+
+ return d_xen_debug;
+}
+
+struct array_data
+{
+ void *array;
+ unsigned elements;
+};
+
+static int u32_array_open(struct inode *inode, struct file *file)
+{
+ file->private_data = NULL;
+ return nonseekable_open(inode, file);
+}
+
+static size_t format_array(char *buf, size_t bufsize, const char *fmt,
+ u32 *array, unsigned array_size)
+{
+ size_t ret = 0;
+ unsigned i;
+
+ for(i = 0; i < array_size; i++) {
+ size_t len;
+
+ len = snprintf(buf, bufsize, fmt, array[i]);
+ len++; /* ' ' or '\n' */
+ ret += len;
+
+ if (buf) {
+ buf += len;
+ bufsize -= len;
+ buf[-1] = (i == array_size-1) ? '\n' : ' ';
+ }
+ }
+
+ ret++; /* \0 */
+ if (buf)
+ *buf = '\0';
+
+ return ret;
+}
+
+static char *format_array_alloc(const char *fmt, u32 *array, unsigned array_size)
+{
+ size_t len = format_array(NULL, 0, fmt, array, array_size);
+ char *ret;
+
+ ret = kmalloc(len, GFP_KERNEL);
+ if (ret == NULL)
+ return NULL;
+
+ format_array(ret, len, fmt, array, array_size);
+ return ret;
+}
+
+static ssize_t u32_array_read(struct file *file, char __user *buf, size_t len,
+ loff_t *ppos)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct array_data *data = inode->i_private;
+ size_t size;
+
+ if (*ppos == 0) {
+ if (file->private_data) {
+ kfree(file->private_data);
+ file->private_data = NULL;
+ }
+
+ file->private_data = format_array_alloc("%u", data->array, data->elements);
+ }
+
+ size = 0;
+ if (file->private_data)
+ size = strlen(file->private_data);
+
+ return simple_read_from_buffer(buf, len, ppos, file->private_data, size);
+}
+
+static int xen_array_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+
+ return 0;
+}
+
+static struct file_operations u32_array_fops = {
+ .owner = THIS_MODULE,
+ .open = u32_array_open,
+ .release= xen_array_release,
+ .read = u32_array_read,
+};
+
+struct dentry *xen_debugfs_create_u32_array(const char *name, mode_t mode,
+ struct dentry *parent,
+ u32 *array, unsigned elements)
+{
+ struct array_data *data = kmalloc(sizeof(*data), GFP_KERNEL);
+
+ if (data == NULL)
+ return NULL;
+
+ data->array = array;
+ data->elements = elements;
+
+ return debugfs_create_file(name, mode, parent, data, &u32_array_fops);
+}
diff --git a/arch/x86/xen/debugfs.h b/arch/x86/xen/debugfs.h
new file mode 100644
index 0000000..e281320
--- /dev/null
+++ b/arch/x86/xen/debugfs.h
@@ -0,0 +1,10 @@
+#ifndef _XEN_DEBUGFS_H
+#define _XEN_DEBUGFS_H
+
+struct dentry * __init xen_init_debugfs(void);
+
+struct dentry *xen_debugfs_create_u32_array(const char *name, mode_t mode,
+ struct dentry *parent,
+ u32 *array, unsigned elements);
+
+#endif /* _XEN_DEBUGFS_H */
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index a27d562..0013a72 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -30,7 +30,6 @@
#include <xen/interface/xen.h>
#include <xen/interface/physdev.h>
#include <xen/interface/vcpu.h>
-#include <xen/interface/sched.h>
#include <xen/features.h>
#include <xen/page.h>
#include <xen/hvc-console.h>
@@ -58,6 +57,9 @@
DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info);
+enum xen_domain_type xen_domain_type = XEN_NATIVE;
+EXPORT_SYMBOL_GPL(xen_domain_type);
+
/*
* Identity map, in addition to plain kernel map. This needs to be
* large enough to allocate page table pages to allocate the rest.
@@ -111,7 +113,14 @@
*
* 0: not available, 1: available
*/
-static int have_vcpu_info_placement = 1;
+static int have_vcpu_info_placement =
+#ifdef CONFIG_X86_32
+ 1
+#else
+ 0
+#endif
+ ;
+
static void xen_vcpu_setup(int cpu)
{
@@ -227,94 +236,6 @@
return HYPERVISOR_get_debugreg(reg);
}
-static unsigned long xen_save_fl(void)
-{
- struct vcpu_info *vcpu;
- unsigned long flags;
-
- vcpu = x86_read_percpu(xen_vcpu);
-
- /* flag has opposite sense of mask */
- flags = !vcpu->evtchn_upcall_mask;
-
- /* convert to IF type flag
- -0 -> 0x00000000
- -1 -> 0xffffffff
- */
- return (-flags) & X86_EFLAGS_IF;
-}
-
-static void xen_restore_fl(unsigned long flags)
-{
- struct vcpu_info *vcpu;
-
- /* convert from IF type flag */
- flags = !(flags & X86_EFLAGS_IF);
-
- /* There's a one instruction preempt window here. We need to
- make sure we're don't switch CPUs between getting the vcpu
- pointer and updating the mask. */
- preempt_disable();
- vcpu = x86_read_percpu(xen_vcpu);
- vcpu->evtchn_upcall_mask = flags;
- preempt_enable_no_resched();
-
- /* Doesn't matter if we get preempted here, because any
- pending event will get dealt with anyway. */
-
- if (flags == 0) {
- preempt_check_resched();
- barrier(); /* unmask then check (avoid races) */
- if (unlikely(vcpu->evtchn_upcall_pending))
- force_evtchn_callback();
- }
-}
-
-static void xen_irq_disable(void)
-{
- /* There's a one instruction preempt window here. We need to
- make sure we're don't switch CPUs between getting the vcpu
- pointer and updating the mask. */
- preempt_disable();
- x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
- preempt_enable_no_resched();
-}
-
-static void xen_irq_enable(void)
-{
- struct vcpu_info *vcpu;
-
- /* We don't need to worry about being preempted here, since
- either a) interrupts are disabled, so no preemption, or b)
- the caller is confused and is trying to re-enable interrupts
- on an indeterminate processor. */
-
- vcpu = x86_read_percpu(xen_vcpu);
- vcpu->evtchn_upcall_mask = 0;
-
- /* Doesn't matter if we get preempted here, because any
- pending event will get dealt with anyway. */
-
- barrier(); /* unmask then check (avoid races) */
- if (unlikely(vcpu->evtchn_upcall_pending))
- force_evtchn_callback();
-}
-
-static void xen_safe_halt(void)
-{
- /* Blocking includes an implicit local_irq_enable(). */
- if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
- BUG();
-}
-
-static void xen_halt(void)
-{
- if (irqs_disabled())
- HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
- else
- xen_safe_halt();
-}
-
static void xen_leave_lazy(void)
{
paravirt_leave_lazy(paravirt_get_lazy_mode());
@@ -326,6 +247,59 @@
return 0;
}
+/*
+ * Set the page permissions for a particular virtual address. If the
+ * address is a vmalloc mapping (or other non-linear mapping), then
+ * find the linear mapping of the page and also set its protections to
+ * match.
+ */
+static void set_aliased_prot(void *v, pgprot_t prot)
+{
+ int level;
+ pte_t *ptep;
+ pte_t pte;
+ unsigned long pfn;
+ struct page *page;
+
+ ptep = lookup_address((unsigned long)v, &level);
+ BUG_ON(ptep == NULL);
+
+ pfn = pte_pfn(*ptep);
+ page = pfn_to_page(pfn);
+
+ pte = pfn_pte(pfn, prot);
+
+ if (HYPERVISOR_update_va_mapping((unsigned long)v, pte, 0))
+ BUG();
+
+ if (!PageHighMem(page)) {
+ void *av = __va(PFN_PHYS(pfn));
+
+ if (av != v)
+ if (HYPERVISOR_update_va_mapping((unsigned long)av, pte, 0))
+ BUG();
+ } else
+ kmap_flush_unused();
+}
+
+static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries)
+{
+ const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE;
+ int i;
+
+ for(i = 0; i < entries; i += entries_per_page)
+ set_aliased_prot(ldt + i, PAGE_KERNEL_RO);
+}
+
+static void xen_free_ldt(struct desc_struct *ldt, unsigned entries)
+{
+ const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE;
+ int i;
+
+ for(i = 0; i < entries; i += entries_per_page)
+ set_aliased_prot(ldt + i, PAGE_KERNEL);
+}
+
static void xen_set_ldt(const void *addr, unsigned entries)
{
struct mmuext_op *op;
@@ -426,8 +400,7 @@
static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum,
const void *ptr)
{
- unsigned long lp = (unsigned long)&dt[entrynum];
- xmaddr_t mach_lp = virt_to_machine(lp);
+ xmaddr_t mach_lp = arbitrary_virt_to_machine(&dt[entrynum]);
u64 entry = *(u64 *)ptr;
preempt_disable();
@@ -560,7 +533,7 @@
}
static void xen_load_sp0(struct tss_struct *tss,
- struct thread_struct *thread)
+ struct thread_struct *thread)
{
struct multicall_space mcs = xen_mc_entry(0);
MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0);
@@ -835,6 +808,19 @@
ret = -EFAULT;
break;
#endif
+
+ case MSR_STAR:
+ case MSR_CSTAR:
+ case MSR_LSTAR:
+ case MSR_SYSCALL_MASK:
+ case MSR_IA32_SYSENTER_CS:
+ case MSR_IA32_SYSENTER_ESP:
+ case MSR_IA32_SYSENTER_EIP:
+ /* Fast syscall setup is all done in hypercalls, so
+ these are all ignored. Stub them out here to stop
+ Xen console noise. */
+ break;
+
default:
ret = native_write_msr_safe(msr, low, high);
}
@@ -878,8 +864,8 @@
SetPagePinned(page);
if (!PageHighMem(page)) {
- make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
- if (level == PT_PTE)
+ make_lowmem_page_readonly(__va(PFN_PHYS((unsigned long)pfn)));
+ if (level == PT_PTE && USE_SPLIT_PTLOCKS)
pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn);
} else
/* make sure there are no stray mappings of
@@ -947,7 +933,7 @@
if (PagePinned(page)) {
if (!PageHighMem(page)) {
- if (level == PT_PTE)
+ if (level == PT_PTE && USE_SPLIT_PTLOCKS)
pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
}
@@ -994,6 +980,7 @@
}
#endif
+#ifdef CONFIG_X86_32
static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
{
/* If there's an existing pte, then don't allow _PAGE_RW to be set */
@@ -1012,6 +999,7 @@
xen_set_pte(ptep, pte);
}
+#endif
static __init void xen_pagetable_setup_start(pgd_t *base)
{
@@ -1078,7 +1066,6 @@
/* xen_vcpu_setup managed to place the vcpu_info within the
percpu area for all cpus, so make use of it */
-#ifdef CONFIG_X86_32
if (have_vcpu_info_placement) {
printk(KERN_INFO "Xen: using vcpu_info placement\n");
@@ -1088,7 +1075,6 @@
pv_irq_ops.irq_enable = xen_irq_enable_direct;
pv_mmu_ops.read_cr2 = xen_read_cr2_direct;
}
-#endif
}
static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
@@ -1109,12 +1095,10 @@
goto patch_site
switch (type) {
-#ifdef CONFIG_X86_32
SITE(pv_irq_ops, irq_enable);
SITE(pv_irq_ops, irq_disable);
SITE(pv_irq_ops, save_fl);
SITE(pv_irq_ops, restore_fl);
-#endif /* CONFIG_X86_32 */
#undef SITE
patch_site:
@@ -1252,6 +1236,9 @@
.load_gs_index = xen_load_gs_index,
#endif
+ .alloc_ldt = xen_alloc_ldt,
+ .free_ldt = xen_free_ldt,
+
.store_gdt = native_store_gdt,
.store_idt = native_store_idt,
.store_tr = xen_store_tr,
@@ -1273,36 +1260,6 @@
},
};
-static void __init __xen_init_IRQ(void)
-{
-#ifdef CONFIG_X86_64
- int i;
-
- /* Create identity vector->irq map */
- for(i = 0; i < NR_VECTORS; i++) {
- int cpu;
-
- for_each_possible_cpu(cpu)
- per_cpu(vector_irq, cpu)[i] = i;
- }
-#endif /* CONFIG_X86_64 */
-
- xen_init_IRQ();
-}
-
-static const struct pv_irq_ops xen_irq_ops __initdata = {
- .init_IRQ = __xen_init_IRQ,
- .save_fl = xen_save_fl,
- .restore_fl = xen_restore_fl,
- .irq_disable = xen_irq_disable,
- .irq_enable = xen_irq_enable,
- .safe_halt = xen_safe_halt,
- .halt = xen_halt,
-#ifdef CONFIG_X86_64
- .adjust_exception_frame = xen_adjust_exception_frame,
-#endif
-};
-
static const struct pv_apic_ops xen_apic_ops __initdata = {
#ifdef CONFIG_X86_LOCAL_APIC
.setup_boot_clock = paravirt_nop,
@@ -1443,7 +1400,7 @@
if (HYPERVISOR_xen_version(XENVER_platform_parameters, &pp) == 0)
top = pp.virt_start;
- reserve_top_address(-top + 2 * PAGE_SIZE);
+ reserve_top_address(-top);
#endif /* CONFIG_X86_32 */
}
@@ -1477,48 +1434,11 @@
return __ka(m2p(maddr));
}
-#ifdef CONFIG_X86_64
-static void walk(pgd_t *pgd, unsigned long addr)
-{
- unsigned l4idx = pgd_index(addr);
- unsigned l3idx = pud_index(addr);
- unsigned l2idx = pmd_index(addr);
- unsigned l1idx = pte_index(addr);
- pgd_t l4;
- pud_t l3;
- pmd_t l2;
- pte_t l1;
-
- xen_raw_printk("walk %p, %lx -> %d %d %d %d\n",
- pgd, addr, l4idx, l3idx, l2idx, l1idx);
-
- l4 = pgd[l4idx];
- xen_raw_printk(" l4: %016lx\n", l4.pgd);
- xen_raw_printk(" %016lx\n", pgd_val(l4));
-
- l3 = ((pud_t *)(m2v(l4.pgd)))[l3idx];
- xen_raw_printk(" l3: %016lx\n", l3.pud);
- xen_raw_printk(" %016lx\n", pud_val(l3));
-
- l2 = ((pmd_t *)(m2v(l3.pud)))[l2idx];
- xen_raw_printk(" l2: %016lx\n", l2.pmd);
- xen_raw_printk(" %016lx\n", pmd_val(l2));
-
- l1 = ((pte_t *)(m2v(l2.pmd)))[l1idx];
- xen_raw_printk(" l1: %016lx\n", l1.pte);
- xen_raw_printk(" %016lx\n", pte_val(l1));
-}
-#endif
-
static void set_page_prot(void *addr, pgprot_t prot)
{
unsigned long pfn = __pa(addr) >> PAGE_SHIFT;
pte_t pte = pfn_pte(pfn, prot);
- xen_raw_printk("addr=%p pfn=%lx mfn=%lx prot=%016llx pte=%016llx\n",
- addr, pfn, get_phys_to_machine(pfn),
- pgprot_val(prot), pte.pte);
-
if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, 0))
BUG();
}
@@ -1694,6 +1614,8 @@
if (!xen_start_info)
return;
+ xen_domain_type = XEN_PV_DOMAIN;
+
BUG_ON(memcmp(xen_start_info->magic, "xen-3", 5) != 0);
xen_setup_features();
@@ -1703,10 +1625,11 @@
pv_init_ops = xen_init_ops;
pv_time_ops = xen_time_ops;
pv_cpu_ops = xen_cpu_ops;
- pv_irq_ops = xen_irq_ops;
pv_apic_ops = xen_apic_ops;
pv_mmu_ops = xen_mmu_ops;
+ xen_init_irq_ops();
+
#ifdef CONFIG_X86_LOCAL_APIC
/*
* set up the basic apic ops.
@@ -1737,7 +1660,7 @@
/* Prevent unwanted bits from being set in PTEs. */
__supported_pte_mask &= ~_PAGE_GLOBAL;
- if (!is_initial_xendomain())
+ if (!xen_initial_domain())
__supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
/* Don't do the full vcpu_info placement stuff until we have a
@@ -1772,7 +1695,7 @@
boot_params.hdr.ramdisk_size = xen_start_info->mod_len;
boot_params.hdr.cmd_line_ptr = __pa(xen_start_info->cmd_line);
- if (!is_initial_xendomain()) {
+ if (!xen_initial_domain()) {
add_preferred_console("xenboot", 0, NULL);
add_preferred_console("tty", 0, NULL);
add_preferred_console("hvc", 0, NULL);
@@ -1780,15 +1703,6 @@
xen_raw_console_write("about to get started...\n");
-#if 0
- xen_raw_printk("&boot_params=%p __pa(&boot_params)=%lx __va(__pa(&boot_params))=%lx\n",
- &boot_params, __pa_symbol(&boot_params),
- __va(__pa_symbol(&boot_params)));
-
- walk(pgd, &boot_params);
- walk(pgd, __va(__pa(&boot_params)));
-#endif
-
/* Start the world */
#ifdef CONFIG_X86_32
i386_start_kernel();
diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c
new file mode 100644
index 0000000..28b85ab
--- /dev/null
+++ b/arch/x86/xen/irq.c
@@ -0,0 +1,143 @@
+#include <linux/hardirq.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/sched.h>
+#include <xen/interface/vcpu.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#include "xen-ops.h"
+
+/*
+ * Force a proper event-channel callback from Xen after clearing the
+ * callback mask. We do this in a very simple manner, by making a call
+ * down into Xen. The pending flag will be checked by Xen on return.
+ */
+void xen_force_evtchn_callback(void)
+{
+ (void)HYPERVISOR_xen_version(0, NULL);
+}
+
+static void __init __xen_init_IRQ(void)
+{
+#ifdef CONFIG_X86_64
+ int i;
+
+ /* Create identity vector->irq map */
+ for(i = 0; i < NR_VECTORS; i++) {
+ int cpu;
+
+ for_each_possible_cpu(cpu)
+ per_cpu(vector_irq, cpu)[i] = i;
+ }
+#endif /* CONFIG_X86_64 */
+
+ xen_init_IRQ();
+}
+
+static unsigned long xen_save_fl(void)
+{
+ struct vcpu_info *vcpu;
+ unsigned long flags;
+
+ vcpu = x86_read_percpu(xen_vcpu);
+
+ /* flag has opposite sense of mask */
+ flags = !vcpu->evtchn_upcall_mask;
+
+ /* convert to IF type flag
+ -0 -> 0x00000000
+ -1 -> 0xffffffff
+ */
+ return (-flags) & X86_EFLAGS_IF;
+}
+
+static void xen_restore_fl(unsigned long flags)
+{
+ struct vcpu_info *vcpu;
+
+ /* convert from IF type flag */
+ flags = !(flags & X86_EFLAGS_IF);
+
+ /* There's a one instruction preempt window here. We need to
+ make sure we're don't switch CPUs between getting the vcpu
+ pointer and updating the mask. */
+ preempt_disable();
+ vcpu = x86_read_percpu(xen_vcpu);
+ vcpu->evtchn_upcall_mask = flags;
+ preempt_enable_no_resched();
+
+ /* Doesn't matter if we get preempted here, because any
+ pending event will get dealt with anyway. */
+
+ if (flags == 0) {
+ preempt_check_resched();
+ barrier(); /* unmask then check (avoid races) */
+ if (unlikely(vcpu->evtchn_upcall_pending))
+ xen_force_evtchn_callback();
+ }
+}
+
+static void xen_irq_disable(void)
+{
+ /* There's a one instruction preempt window here. We need to
+ make sure we're don't switch CPUs between getting the vcpu
+ pointer and updating the mask. */
+ preempt_disable();
+ x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
+ preempt_enable_no_resched();
+}
+
+static void xen_irq_enable(void)
+{
+ struct vcpu_info *vcpu;
+
+ /* We don't need to worry about being preempted here, since
+ either a) interrupts are disabled, so no preemption, or b)
+ the caller is confused and is trying to re-enable interrupts
+ on an indeterminate processor. */
+
+ vcpu = x86_read_percpu(xen_vcpu);
+ vcpu->evtchn_upcall_mask = 0;
+
+ /* Doesn't matter if we get preempted here, because any
+ pending event will get dealt with anyway. */
+
+ barrier(); /* unmask then check (avoid races) */
+ if (unlikely(vcpu->evtchn_upcall_pending))
+ xen_force_evtchn_callback();
+}
+
+static void xen_safe_halt(void)
+{
+ /* Blocking includes an implicit local_irq_enable(). */
+ if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
+ BUG();
+}
+
+static void xen_halt(void)
+{
+ if (irqs_disabled())
+ HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+ else
+ xen_safe_halt();
+}
+
+static const struct pv_irq_ops xen_irq_ops __initdata = {
+ .init_IRQ = __xen_init_IRQ,
+ .save_fl = xen_save_fl,
+ .restore_fl = xen_restore_fl,
+ .irq_disable = xen_irq_disable,
+ .irq_enable = xen_irq_enable,
+ .safe_halt = xen_safe_halt,
+ .halt = xen_halt,
+#ifdef CONFIG_X86_64
+ .adjust_exception_frame = xen_adjust_exception_frame,
+#endif
+};
+
+void __init xen_init_irq_ops()
+{
+ pv_irq_ops = xen_irq_ops;
+}
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index aa37469..ae173f6 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -40,6 +40,7 @@
*/
#include <linux/sched.h>
#include <linux/highmem.h>
+#include <linux/debugfs.h>
#include <linux/bug.h>
#include <asm/pgtable.h>
@@ -57,6 +58,61 @@
#include "multicalls.h"
#include "mmu.h"
+#include "debugfs.h"
+
+#define MMU_UPDATE_HISTO 30
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct {
+ u32 pgd_update;
+ u32 pgd_update_pinned;
+ u32 pgd_update_batched;
+
+ u32 pud_update;
+ u32 pud_update_pinned;
+ u32 pud_update_batched;
+
+ u32 pmd_update;
+ u32 pmd_update_pinned;
+ u32 pmd_update_batched;
+
+ u32 pte_update;
+ u32 pte_update_pinned;
+ u32 pte_update_batched;
+
+ u32 mmu_update;
+ u32 mmu_update_extended;
+ u32 mmu_update_histo[MMU_UPDATE_HISTO];
+
+ u32 prot_commit;
+ u32 prot_commit_batched;
+
+ u32 set_pte_at;
+ u32 set_pte_at_batched;
+ u32 set_pte_at_pinned;
+ u32 set_pte_at_current;
+ u32 set_pte_at_kernel;
+} mmu_stats;
+
+static u8 zero_stats;
+
+static inline void check_zero(void)
+{
+ if (unlikely(zero_stats)) {
+ memset(&mmu_stats, 0, sizeof(mmu_stats));
+ zero_stats = 0;
+ }
+}
+
+#define ADD_STATS(elem, val) \
+ do { check_zero(); mmu_stats.elem += (val); } while(0)
+
+#else /* !CONFIG_XEN_DEBUG_FS */
+
+#define ADD_STATS(elem, val) do { (void)(val); } while(0)
+
+#endif /* CONFIG_XEN_DEBUG_FS */
/*
* Just beyond the highest usermode address. STACK_TOP_MAX has a
@@ -229,25 +285,35 @@
}
-static bool page_pinned(void *ptr)
+static bool xen_page_pinned(void *ptr)
{
struct page *page = virt_to_page(ptr);
return PagePinned(page);
}
-static void extend_mmu_update(const struct mmu_update *update)
+static void xen_extend_mmu_update(const struct mmu_update *update)
{
struct multicall_space mcs;
struct mmu_update *u;
mcs = xen_mc_extend_args(__HYPERVISOR_mmu_update, sizeof(*u));
- if (mcs.mc != NULL)
+ if (mcs.mc != NULL) {
+ ADD_STATS(mmu_update_extended, 1);
+ ADD_STATS(mmu_update_histo[mcs.mc->args[1]], -1);
+
mcs.mc->args[1]++;
- else {
+
+ if (mcs.mc->args[1] < MMU_UPDATE_HISTO)
+ ADD_STATS(mmu_update_histo[mcs.mc->args[1]], 1);
+ else
+ ADD_STATS(mmu_update_histo[0], 1);
+ } else {
+ ADD_STATS(mmu_update, 1);
mcs = __xen_mc_entry(sizeof(*u));
MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_SELF);
+ ADD_STATS(mmu_update_histo[1], 1);
}
u = mcs.args;
@@ -265,7 +331,9 @@
/* ptr may be ioremapped for 64-bit pagetable setup */
u.ptr = arbitrary_virt_to_machine(ptr).maddr;
u.val = pmd_val_ma(val);
- extend_mmu_update(&u);
+ xen_extend_mmu_update(&u);
+
+ ADD_STATS(pmd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
xen_mc_issue(PARAVIRT_LAZY_MMU);
@@ -274,13 +342,17 @@
void xen_set_pmd(pmd_t *ptr, pmd_t val)
{
+ ADD_STATS(pmd_update, 1);
+
/* If page is not pinned, we can just update the entry
directly */
- if (!page_pinned(ptr)) {
+ if (!xen_page_pinned(ptr)) {
*ptr = val;
return;
}
+ ADD_STATS(pmd_update_pinned, 1);
+
xen_set_pmd_hyper(ptr, val);
}
@@ -300,12 +372,18 @@
if (mm == &init_mm)
preempt_disable();
+ ADD_STATS(set_pte_at, 1);
+// ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep));
+ ADD_STATS(set_pte_at_current, mm == current->mm);
+ ADD_STATS(set_pte_at_kernel, mm == &init_mm);
+
if (mm == current->mm || mm == &init_mm) {
if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
struct multicall_space mcs;
mcs = xen_mc_entry(0);
MULTI_update_va_mapping(mcs.mc, addr, pteval, 0);
+ ADD_STATS(set_pte_at_batched, 1);
xen_mc_issue(PARAVIRT_LAZY_MMU);
goto out;
} else
@@ -334,7 +412,10 @@
u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
u.val = pte_val_ma(pte);
- extend_mmu_update(&u);
+ xen_extend_mmu_update(&u);
+
+ ADD_STATS(prot_commit, 1);
+ ADD_STATS(prot_commit_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
xen_mc_issue(PARAVIRT_LAZY_MMU);
}
@@ -400,7 +481,9 @@
/* ptr may be ioremapped for 64-bit pagetable setup */
u.ptr = arbitrary_virt_to_machine(ptr).maddr;
u.val = pud_val_ma(val);
- extend_mmu_update(&u);
+ xen_extend_mmu_update(&u);
+
+ ADD_STATS(pud_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
xen_mc_issue(PARAVIRT_LAZY_MMU);
@@ -409,18 +492,26 @@
void xen_set_pud(pud_t *ptr, pud_t val)
{
+ ADD_STATS(pud_update, 1);
+
/* If page is not pinned, we can just update the entry
directly */
- if (!page_pinned(ptr)) {
+ if (!xen_page_pinned(ptr)) {
*ptr = val;
return;
}
+ ADD_STATS(pud_update_pinned, 1);
+
xen_set_pud_hyper(ptr, val);
}
void xen_set_pte(pte_t *ptep, pte_t pte)
{
+ ADD_STATS(pte_update, 1);
+// ADD_STATS(pte_update_pinned, xen_page_pinned(ptep));
+ ADD_STATS(pte_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
+
#ifdef CONFIG_X86_PAE
ptep->pte_high = pte.pte_high;
smp_wmb();
@@ -490,7 +581,7 @@
u.ptr = virt_to_machine(ptr).maddr;
u.val = pgd_val_ma(val);
- extend_mmu_update(&u);
+ xen_extend_mmu_update(&u);
}
/*
@@ -517,17 +608,22 @@
{
pgd_t *user_ptr = xen_get_user_pgd(ptr);
+ ADD_STATS(pgd_update, 1);
+
/* If page is not pinned, we can just update the entry
directly */
- if (!page_pinned(ptr)) {
+ if (!xen_page_pinned(ptr)) {
*ptr = val;
if (user_ptr) {
- WARN_ON(page_pinned(user_ptr));
+ WARN_ON(xen_page_pinned(user_ptr));
*user_ptr = val;
}
return;
}
+ ADD_STATS(pgd_update_pinned, 1);
+ ADD_STATS(pgd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
+
/* If it's pinned, then we can at least batch the kernel and
user updates together. */
xen_mc_batch();
@@ -555,9 +651,12 @@
* For 64-bit, we must skip the Xen hole in the middle of the address
* space, just after the big x86-64 virtual hole.
*/
-static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
- unsigned long limit)
+static int xen_pgd_walk(struct mm_struct *mm,
+ int (*func)(struct mm_struct *mm, struct page *,
+ enum pt_level),
+ unsigned long limit)
{
+ pgd_t *pgd = mm->pgd;
int flush = 0;
unsigned hole_low, hole_high;
unsigned pgdidx_limit, pudidx_limit, pmdidx_limit;
@@ -590,8 +689,6 @@
pmdidx_limit = 0;
#endif
- flush |= (*func)(virt_to_page(pgd), PT_PGD);
-
for (pgdidx = 0; pgdidx <= pgdidx_limit; pgdidx++) {
pud_t *pud;
@@ -604,7 +701,7 @@
pud = pud_offset(&pgd[pgdidx], 0);
if (PTRS_PER_PUD > 1) /* not folded */
- flush |= (*func)(virt_to_page(pud), PT_PUD);
+ flush |= (*func)(mm, virt_to_page(pud), PT_PUD);
for (pudidx = 0; pudidx < PTRS_PER_PUD; pudidx++) {
pmd_t *pmd;
@@ -619,7 +716,7 @@
pmd = pmd_offset(&pud[pudidx], 0);
if (PTRS_PER_PMD > 1) /* not folded */
- flush |= (*func)(virt_to_page(pmd), PT_PMD);
+ flush |= (*func)(mm, virt_to_page(pmd), PT_PMD);
for (pmdidx = 0; pmdidx < PTRS_PER_PMD; pmdidx++) {
struct page *pte;
@@ -633,28 +730,34 @@
continue;
pte = pmd_page(pmd[pmdidx]);
- flush |= (*func)(pte, PT_PTE);
+ flush |= (*func)(mm, pte, PT_PTE);
}
}
}
+
out:
+ /* Do the top level last, so that the callbacks can use it as
+ a cue to do final things like tlb flushes. */
+ flush |= (*func)(mm, virt_to_page(pgd), PT_PGD);
return flush;
}
-static spinlock_t *lock_pte(struct page *page)
+/* If we're using split pte locks, then take the page's lock and
+ return a pointer to it. Otherwise return NULL. */
+static spinlock_t *xen_pte_lock(struct page *page, struct mm_struct *mm)
{
spinlock_t *ptl = NULL;
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
ptl = __pte_lockptr(page);
- spin_lock(ptl);
+ spin_lock_nest_lock(ptl, &mm->page_table_lock);
#endif
return ptl;
}
-static void do_unlock(void *v)
+static void xen_pte_unlock(void *v)
{
spinlock_t *ptl = v;
spin_unlock(ptl);
@@ -672,7 +775,8 @@
MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
}
-static int pin_page(struct page *page, enum pt_level level)
+static int xen_pin_page(struct mm_struct *mm, struct page *page,
+ enum pt_level level)
{
unsigned pgfl = TestSetPagePinned(page);
int flush;
@@ -691,21 +795,40 @@
flush = 0;
+ /*
+ * We need to hold the pagetable lock between the time
+ * we make the pagetable RO and when we actually pin
+ * it. If we don't, then other users may come in and
+ * attempt to update the pagetable by writing it,
+ * which will fail because the memory is RO but not
+ * pinned, so Xen won't do the trap'n'emulate.
+ *
+ * If we're using split pte locks, we can't hold the
+ * entire pagetable's worth of locks during the
+ * traverse, because we may wrap the preempt count (8
+ * bits). The solution is to mark RO and pin each PTE
+ * page while holding the lock. This means the number
+ * of locks we end up holding is never more than a
+ * batch size (~32 entries, at present).
+ *
+ * If we're not using split pte locks, we needn't pin
+ * the PTE pages independently, because we're
+ * protected by the overall pagetable lock.
+ */
ptl = NULL;
if (level == PT_PTE)
- ptl = lock_pte(page);
+ ptl = xen_pte_lock(page, mm);
MULTI_update_va_mapping(mcs.mc, (unsigned long)pt,
pfn_pte(pfn, PAGE_KERNEL_RO),
level == PT_PGD ? UVMF_TLB_FLUSH : 0);
- if (level == PT_PTE)
+ if (ptl) {
xen_do_pin(MMUEXT_PIN_L1_TABLE, pfn);
- if (ptl) {
/* Queue a deferred unlock for when this batch
is completed. */
- xen_mc_callback(do_unlock, ptl);
+ xen_mc_callback(xen_pte_unlock, ptl);
}
}
@@ -715,11 +838,11 @@
/* This is called just after a mm has been created, but it has not
been used yet. We need to make sure that its pagetable is all
read-only, and can be pinned. */
-void xen_pgd_pin(pgd_t *pgd)
+static void __xen_pgd_pin(struct mm_struct *mm, pgd_t *pgd)
{
xen_mc_batch();
- if (pgd_walk(pgd, pin_page, USER_LIMIT)) {
+ if (xen_pgd_walk(mm, xen_pin_page, USER_LIMIT)) {
/* re-enable interrupts for kmap_flush_unused */
xen_mc_issue(0);
kmap_flush_unused();
@@ -733,25 +856,35 @@
xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(pgd)));
if (user_pgd) {
- pin_page(virt_to_page(user_pgd), PT_PGD);
+ xen_pin_page(mm, virt_to_page(user_pgd), PT_PGD);
xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(user_pgd)));
}
}
#else /* CONFIG_X86_32 */
#ifdef CONFIG_X86_PAE
/* Need to make sure unshared kernel PMD is pinnable */
- pin_page(virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])), PT_PMD);
+ xen_pin_page(mm, virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])),
+ PT_PMD);
#endif
xen_do_pin(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(pgd)));
#endif /* CONFIG_X86_64 */
xen_mc_issue(0);
}
+static void xen_pgd_pin(struct mm_struct *mm)
+{
+ __xen_pgd_pin(mm, mm->pgd);
+}
+
/*
* On save, we need to pin all pagetables to make sure they get their
* mfns turned into pfns. Search the list for any unpinned pgds and pin
* them (unpinned pgds are not currently in use, probably because the
* process is under construction or destruction).
+ *
+ * Expected to be called in stop_machine() ("equivalent to taking
+ * every spinlock in the system"), so the locking doesn't really
+ * matter all that much.
*/
void xen_mm_pin_all(void)
{
@@ -762,7 +895,7 @@
list_for_each_entry(page, &pgd_list, lru) {
if (!PagePinned(page)) {
- xen_pgd_pin((pgd_t *)page_address(page));
+ __xen_pgd_pin(&init_mm, (pgd_t *)page_address(page));
SetPageSavePinned(page);
}
}
@@ -775,7 +908,8 @@
* that's before we have page structures to store the bits. So do all
* the book-keeping now.
*/
-static __init int mark_pinned(struct page *page, enum pt_level level)
+static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page,
+ enum pt_level level)
{
SetPagePinned(page);
return 0;
@@ -783,10 +917,11 @@
void __init xen_mark_init_mm_pinned(void)
{
- pgd_walk(init_mm.pgd, mark_pinned, FIXADDR_TOP);
+ xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP);
}
-static int unpin_page(struct page *page, enum pt_level level)
+static int xen_unpin_page(struct mm_struct *mm, struct page *page,
+ enum pt_level level)
{
unsigned pgfl = TestClearPagePinned(page);
@@ -796,10 +931,18 @@
spinlock_t *ptl = NULL;
struct multicall_space mcs;
+ /*
+ * Do the converse to pin_page. If we're using split
+ * pte locks, we must be holding the lock for while
+ * the pte page is unpinned but still RO to prevent
+ * concurrent updates from seeing it in this
+ * partially-pinned state.
+ */
if (level == PT_PTE) {
- ptl = lock_pte(page);
+ ptl = xen_pte_lock(page, mm);
- xen_do_pin(MMUEXT_UNPIN_TABLE, pfn);
+ if (ptl)
+ xen_do_pin(MMUEXT_UNPIN_TABLE, pfn);
}
mcs = __xen_mc_entry(0);
@@ -810,7 +953,7 @@
if (ptl) {
/* unlock when batch completed */
- xen_mc_callback(do_unlock, ptl);
+ xen_mc_callback(xen_pte_unlock, ptl);
}
}
@@ -818,7 +961,7 @@
}
/* Release a pagetables pages back as normal RW */
-static void xen_pgd_unpin(pgd_t *pgd)
+static void __xen_pgd_unpin(struct mm_struct *mm, pgd_t *pgd)
{
xen_mc_batch();
@@ -830,21 +973,27 @@
if (user_pgd) {
xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(user_pgd)));
- unpin_page(virt_to_page(user_pgd), PT_PGD);
+ xen_unpin_page(mm, virt_to_page(user_pgd), PT_PGD);
}
}
#endif
#ifdef CONFIG_X86_PAE
/* Need to make sure unshared kernel PMD is unpinned */
- pin_page(virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])), PT_PMD);
+ xen_unpin_page(mm, virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])),
+ PT_PMD);
#endif
- pgd_walk(pgd, unpin_page, USER_LIMIT);
+ xen_pgd_walk(mm, xen_unpin_page, USER_LIMIT);
xen_mc_issue(0);
}
+static void xen_pgd_unpin(struct mm_struct *mm)
+{
+ __xen_pgd_unpin(mm, mm->pgd);
+}
+
/*
* On resume, undo any pinning done at save, so that the rest of the
* kernel doesn't see any unexpected pinned pagetables.
@@ -859,7 +1008,7 @@
list_for_each_entry(page, &pgd_list, lru) {
if (PageSavePinned(page)) {
BUG_ON(!PagePinned(page));
- xen_pgd_unpin((pgd_t *)page_address(page));
+ __xen_pgd_unpin(&init_mm, (pgd_t *)page_address(page));
ClearPageSavePinned(page);
}
}
@@ -870,14 +1019,14 @@
void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
{
spin_lock(&next->page_table_lock);
- xen_pgd_pin(next->pgd);
+ xen_pgd_pin(next);
spin_unlock(&next->page_table_lock);
}
void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
{
spin_lock(&mm->page_table_lock);
- xen_pgd_pin(mm->pgd);
+ xen_pgd_pin(mm);
spin_unlock(&mm->page_table_lock);
}
@@ -907,7 +1056,7 @@
}
}
-static void drop_mm_ref(struct mm_struct *mm)
+static void xen_drop_mm_ref(struct mm_struct *mm)
{
cpumask_t mask;
unsigned cpu;
@@ -937,7 +1086,7 @@
smp_call_function_mask(mask, drop_other_mm_ref, mm, 1);
}
#else
-static void drop_mm_ref(struct mm_struct *mm)
+static void xen_drop_mm_ref(struct mm_struct *mm)
{
if (current->active_mm == mm)
load_cr3(swapper_pg_dir);
@@ -961,14 +1110,77 @@
void xen_exit_mmap(struct mm_struct *mm)
{
get_cpu(); /* make sure we don't move around */
- drop_mm_ref(mm);
+ xen_drop_mm_ref(mm);
put_cpu();
spin_lock(&mm->page_table_lock);
/* pgd may not be pinned in the error exit path of execve */
- if (page_pinned(mm->pgd))
- xen_pgd_unpin(mm->pgd);
+ if (xen_page_pinned(mm->pgd))
+ xen_pgd_unpin(mm);
spin_unlock(&mm->page_table_lock);
}
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_mmu_debug;
+
+static int __init xen_mmu_debugfs(void)
+{
+ struct dentry *d_xen = xen_init_debugfs();
+
+ if (d_xen == NULL)
+ return -ENOMEM;
+
+ d_mmu_debug = debugfs_create_dir("mmu", d_xen);
+
+ debugfs_create_u8("zero_stats", 0644, d_mmu_debug, &zero_stats);
+
+ debugfs_create_u32("pgd_update", 0444, d_mmu_debug, &mmu_stats.pgd_update);
+ debugfs_create_u32("pgd_update_pinned", 0444, d_mmu_debug,
+ &mmu_stats.pgd_update_pinned);
+ debugfs_create_u32("pgd_update_batched", 0444, d_mmu_debug,
+ &mmu_stats.pgd_update_pinned);
+
+ debugfs_create_u32("pud_update", 0444, d_mmu_debug, &mmu_stats.pud_update);
+ debugfs_create_u32("pud_update_pinned", 0444, d_mmu_debug,
+ &mmu_stats.pud_update_pinned);
+ debugfs_create_u32("pud_update_batched", 0444, d_mmu_debug,
+ &mmu_stats.pud_update_pinned);
+
+ debugfs_create_u32("pmd_update", 0444, d_mmu_debug, &mmu_stats.pmd_update);
+ debugfs_create_u32("pmd_update_pinned", 0444, d_mmu_debug,
+ &mmu_stats.pmd_update_pinned);
+ debugfs_create_u32("pmd_update_batched", 0444, d_mmu_debug,
+ &mmu_stats.pmd_update_pinned);
+
+ debugfs_create_u32("pte_update", 0444, d_mmu_debug, &mmu_stats.pte_update);
+// debugfs_create_u32("pte_update_pinned", 0444, d_mmu_debug,
+// &mmu_stats.pte_update_pinned);
+ debugfs_create_u32("pte_update_batched", 0444, d_mmu_debug,
+ &mmu_stats.pte_update_pinned);
+
+ debugfs_create_u32("mmu_update", 0444, d_mmu_debug, &mmu_stats.mmu_update);
+ debugfs_create_u32("mmu_update_extended", 0444, d_mmu_debug,
+ &mmu_stats.mmu_update_extended);
+ xen_debugfs_create_u32_array("mmu_update_histo", 0444, d_mmu_debug,
+ mmu_stats.mmu_update_histo, 20);
+
+ debugfs_create_u32("set_pte_at", 0444, d_mmu_debug, &mmu_stats.set_pte_at);
+ debugfs_create_u32("set_pte_at_batched", 0444, d_mmu_debug,
+ &mmu_stats.set_pte_at_batched);
+ debugfs_create_u32("set_pte_at_current", 0444, d_mmu_debug,
+ &mmu_stats.set_pte_at_current);
+ debugfs_create_u32("set_pte_at_kernel", 0444, d_mmu_debug,
+ &mmu_stats.set_pte_at_kernel);
+
+ debugfs_create_u32("prot_commit", 0444, d_mmu_debug, &mmu_stats.prot_commit);
+ debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug,
+ &mmu_stats.prot_commit_batched);
+
+ return 0;
+}
+fs_initcall(xen_mmu_debugfs);
+
+#endif /* CONFIG_XEN_DEBUG_FS */
diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h
index 0f59bd0..98d7165 100644
--- a/arch/x86/xen/mmu.h
+++ b/arch/x86/xen/mmu.h
@@ -18,9 +18,6 @@
void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
void xen_exit_mmap(struct mm_struct *mm);
-void xen_pgd_pin(pgd_t *pgd);
-//void xen_pgd_unpin(pgd_t *pgd);
-
pteval_t xen_pte_val(pte_t);
pmdval_t xen_pmd_val(pmd_t);
pgdval_t xen_pgd_val(pgd_t);
diff --git a/arch/x86/xen/multicalls.c b/arch/x86/xen/multicalls.c
index 9efd1c6..8ea8a0d 100644
--- a/arch/x86/xen/multicalls.c
+++ b/arch/x86/xen/multicalls.c
@@ -21,16 +21,20 @@
*/
#include <linux/percpu.h>
#include <linux/hardirq.h>
+#include <linux/debugfs.h>
#include <asm/xen/hypercall.h>
#include "multicalls.h"
+#include "debugfs.h"
+
+#define MC_BATCH 32
#define MC_DEBUG 1
-#define MC_BATCH 32
#define MC_ARGS (MC_BATCH * 16)
+
struct mc_buffer {
struct multicall_entry entries[MC_BATCH];
#if MC_DEBUG
@@ -47,6 +51,76 @@
static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
+/* flush reasons 0- slots, 1- args, 2- callbacks */
+enum flush_reasons
+{
+ FL_SLOTS,
+ FL_ARGS,
+ FL_CALLBACKS,
+
+ FL_N_REASONS
+};
+
+#ifdef CONFIG_XEN_DEBUG_FS
+#define NHYPERCALLS 40 /* not really */
+
+static struct {
+ unsigned histo[MC_BATCH+1];
+
+ unsigned issued;
+ unsigned arg_total;
+ unsigned hypercalls;
+ unsigned histo_hypercalls[NHYPERCALLS];
+
+ unsigned flush[FL_N_REASONS];
+} mc_stats;
+
+static u8 zero_stats;
+
+static inline void check_zero(void)
+{
+ if (unlikely(zero_stats)) {
+ memset(&mc_stats, 0, sizeof(mc_stats));
+ zero_stats = 0;
+ }
+}
+
+static void mc_add_stats(const struct mc_buffer *mc)
+{
+ int i;
+
+ check_zero();
+
+ mc_stats.issued++;
+ mc_stats.hypercalls += mc->mcidx;
+ mc_stats.arg_total += mc->argidx;
+
+ mc_stats.histo[mc->mcidx]++;
+ for(i = 0; i < mc->mcidx; i++) {
+ unsigned op = mc->entries[i].op;
+ if (op < NHYPERCALLS)
+ mc_stats.histo_hypercalls[op]++;
+ }
+}
+
+static void mc_stats_flush(enum flush_reasons idx)
+{
+ check_zero();
+
+ mc_stats.flush[idx]++;
+}
+
+#else /* !CONFIG_XEN_DEBUG_FS */
+
+static inline void mc_add_stats(const struct mc_buffer *mc)
+{
+}
+
+static inline void mc_stats_flush(enum flush_reasons idx)
+{
+}
+#endif /* CONFIG_XEN_DEBUG_FS */
+
void xen_mc_flush(void)
{
struct mc_buffer *b = &__get_cpu_var(mc_buffer);
@@ -60,6 +134,8 @@
something in the middle */
local_irq_save(flags);
+ mc_add_stats(b);
+
if (b->mcidx) {
#if MC_DEBUG
memcpy(b->debug, b->entries,
@@ -115,6 +191,7 @@
if (b->mcidx == MC_BATCH ||
(argidx + args) > MC_ARGS) {
+ mc_stats_flush(b->mcidx == MC_BATCH ? FL_SLOTS : FL_ARGS);
xen_mc_flush();
argidx = roundup(b->argidx, sizeof(u64));
}
@@ -158,10 +235,44 @@
struct mc_buffer *b = &__get_cpu_var(mc_buffer);
struct callback *cb;
- if (b->cbidx == MC_BATCH)
+ if (b->cbidx == MC_BATCH) {
+ mc_stats_flush(FL_CALLBACKS);
xen_mc_flush();
+ }
cb = &b->callbacks[b->cbidx++];
cb->fn = fn;
cb->data = data;
}
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_mc_debug;
+
+static int __init xen_mc_debugfs(void)
+{
+ struct dentry *d_xen = xen_init_debugfs();
+
+ if (d_xen == NULL)
+ return -ENOMEM;
+
+ d_mc_debug = debugfs_create_dir("multicalls", d_xen);
+
+ debugfs_create_u8("zero_stats", 0644, d_mc_debug, &zero_stats);
+
+ debugfs_create_u32("batches", 0444, d_mc_debug, &mc_stats.issued);
+ debugfs_create_u32("hypercalls", 0444, d_mc_debug, &mc_stats.hypercalls);
+ debugfs_create_u32("arg_total", 0444, d_mc_debug, &mc_stats.arg_total);
+
+ xen_debugfs_create_u32_array("batch_histo", 0444, d_mc_debug,
+ mc_stats.histo, MC_BATCH);
+ xen_debugfs_create_u32_array("hypercall_histo", 0444, d_mc_debug,
+ mc_stats.histo_hypercalls, NHYPERCALLS);
+ xen_debugfs_create_u32_array("flush_reasons", 0444, d_mc_debug,
+ mc_stats.flush, FL_N_REASONS);
+
+ return 0;
+}
+fs_initcall(xen_mc_debugfs);
+
+#endif /* CONFIG_XEN_DEBUG_FS */
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index d8faf79..d77da61 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -11,11 +11,8 @@
* useful topology information for the kernel to make use of. As a
* result, all CPUs are treated as if they're single-core and
* single-threaded.
- *
- * This does not handle HOTPLUG_CPU yet.
*/
#include <linux/sched.h>
-#include <linux/kernel_stat.h>
#include <linux/err.h>
#include <linux/smp.h>
@@ -36,8 +33,6 @@
#include "xen-ops.h"
#include "mmu.h"
-static void __cpuinit xen_init_lock_cpu(int cpu);
-
cpumask_t xen_cpu_initialized_map;
static DEFINE_PER_CPU(int, resched_irq);
@@ -64,11 +59,12 @@
return IRQ_HANDLED;
}
-static __cpuinit void cpu_bringup_and_idle(void)
+static __cpuinit void cpu_bringup(void)
{
int cpu = smp_processor_id();
cpu_init();
+ touch_softlockup_watchdog();
preempt_disable();
xen_enable_sysenter();
@@ -89,6 +85,11 @@
local_irq_enable();
wmb(); /* make sure everything is out */
+}
+
+static __cpuinit void cpu_bringup_and_idle(void)
+{
+ cpu_bringup();
cpu_idle();
}
@@ -212,8 +213,6 @@
cpu_set(cpu, cpu_present_map);
}
-
- //init_xenbus_allowed_cpumask();
}
static __cpuinit int
@@ -281,12 +280,6 @@
struct task_struct *idle = idle_task(cpu);
int rc;
-#if 0
- rc = cpu_up_check(cpu);
- if (rc)
- return rc;
-#endif
-
#ifdef CONFIG_X86_64
/* Allocate node local memory for AP pdas */
WARN_ON(cpu == 0);
@@ -339,6 +332,60 @@
{
}
+#ifdef CONFIG_HOTPLUG_CPU
+static int xen_cpu_disable(void)
+{
+ unsigned int cpu = smp_processor_id();
+ if (cpu == 0)
+ return -EBUSY;
+
+ cpu_disable_common();
+
+ load_cr3(swapper_pg_dir);
+ return 0;
+}
+
+static void xen_cpu_die(unsigned int cpu)
+{
+ while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(HZ/10);
+ }
+ unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
+ unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
+ unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL);
+ unbind_from_irqhandler(per_cpu(callfuncsingle_irq, cpu), NULL);
+ xen_uninit_lock_cpu(cpu);
+ xen_teardown_timer(cpu);
+
+ if (num_online_cpus() == 1)
+ alternatives_smp_switch(0);
+}
+
+static void xen_play_dead(void)
+{
+ play_dead_common();
+ HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+ cpu_bringup();
+}
+
+#else /* !CONFIG_HOTPLUG_CPU */
+static int xen_cpu_disable(void)
+{
+ return -ENOSYS;
+}
+
+static void xen_cpu_die(unsigned int cpu)
+{
+ BUG();
+}
+
+static void xen_play_dead(void)
+{
+ BUG();
+}
+
+#endif
static void stop_self(void *v)
{
int cpu = smp_processor_id();
@@ -419,176 +466,16 @@
return IRQ_HANDLED;
}
-struct xen_spinlock {
- unsigned char lock; /* 0 -> free; 1 -> locked */
- unsigned short spinners; /* count of waiting cpus */
-};
-
-static int xen_spin_is_locked(struct raw_spinlock *lock)
-{
- struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
- return xl->lock != 0;
-}
-
-static int xen_spin_is_contended(struct raw_spinlock *lock)
-{
- struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
- /* Not strictly true; this is only the count of contended
- lock-takers entering the slow path. */
- return xl->spinners != 0;
-}
-
-static int xen_spin_trylock(struct raw_spinlock *lock)
-{
- struct xen_spinlock *xl = (struct xen_spinlock *)lock;
- u8 old = 1;
-
- asm("xchgb %b0,%1"
- : "+q" (old), "+m" (xl->lock) : : "memory");
-
- return old == 0;
-}
-
-static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
-static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);
-
-static inline void spinning_lock(struct xen_spinlock *xl)
-{
- __get_cpu_var(lock_spinners) = xl;
- wmb(); /* set lock of interest before count */
- asm(LOCK_PREFIX " incw %0"
- : "+m" (xl->spinners) : : "memory");
-}
-
-static inline void unspinning_lock(struct xen_spinlock *xl)
-{
- asm(LOCK_PREFIX " decw %0"
- : "+m" (xl->spinners) : : "memory");
- wmb(); /* decrement count before clearing lock */
- __get_cpu_var(lock_spinners) = NULL;
-}
-
-static noinline int xen_spin_lock_slow(struct raw_spinlock *lock)
-{
- struct xen_spinlock *xl = (struct xen_spinlock *)lock;
- int irq = __get_cpu_var(lock_kicker_irq);
- int ret;
-
- /* If kicker interrupts not initialized yet, just spin */
- if (irq == -1)
- return 0;
-
- /* announce we're spinning */
- spinning_lock(xl);
-
- /* clear pending */
- xen_clear_irq_pending(irq);
-
- /* check again make sure it didn't become free while
- we weren't looking */
- ret = xen_spin_trylock(lock);
- if (ret)
- goto out;
-
- /* block until irq becomes pending */
- xen_poll_irq(irq);
- kstat_this_cpu.irqs[irq]++;
-
-out:
- unspinning_lock(xl);
- return ret;
-}
-
-static void xen_spin_lock(struct raw_spinlock *lock)
-{
- struct xen_spinlock *xl = (struct xen_spinlock *)lock;
- int timeout;
- u8 oldval;
-
- do {
- timeout = 1 << 10;
-
- asm("1: xchgb %1,%0\n"
- " testb %1,%1\n"
- " jz 3f\n"
- "2: rep;nop\n"
- " cmpb $0,%0\n"
- " je 1b\n"
- " dec %2\n"
- " jnz 2b\n"
- "3:\n"
- : "+m" (xl->lock), "=q" (oldval), "+r" (timeout)
- : "1" (1)
- : "memory");
-
- } while (unlikely(oldval != 0 && !xen_spin_lock_slow(lock)));
-}
-
-static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
-{
- int cpu;
-
- for_each_online_cpu(cpu) {
- /* XXX should mix up next cpu selection */
- if (per_cpu(lock_spinners, cpu) == xl) {
- xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
- break;
- }
- }
-}
-
-static void xen_spin_unlock(struct raw_spinlock *lock)
-{
- struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
- smp_wmb(); /* make sure no writes get moved after unlock */
- xl->lock = 0; /* release lock */
-
- /* make sure unlock happens before kick */
- barrier();
-
- if (unlikely(xl->spinners))
- xen_spin_unlock_slow(xl);
-}
-
-static __cpuinit void xen_init_lock_cpu(int cpu)
-{
- int irq;
- const char *name;
-
- name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
- irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
- cpu,
- xen_reschedule_interrupt,
- IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
- name,
- NULL);
-
- if (irq >= 0) {
- disable_irq(irq); /* make sure it's never delivered */
- per_cpu(lock_kicker_irq, cpu) = irq;
- }
-
- printk("cpu %d spinlock event irq %d\n", cpu, irq);
-}
-
-static void __init xen_init_spinlocks(void)
-{
- pv_lock_ops.spin_is_locked = xen_spin_is_locked;
- pv_lock_ops.spin_is_contended = xen_spin_is_contended;
- pv_lock_ops.spin_lock = xen_spin_lock;
- pv_lock_ops.spin_trylock = xen_spin_trylock;
- pv_lock_ops.spin_unlock = xen_spin_unlock;
-}
-
static const struct smp_ops xen_smp_ops __initdata = {
.smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu,
.smp_prepare_cpus = xen_smp_prepare_cpus,
- .cpu_up = xen_cpu_up,
.smp_cpus_done = xen_smp_cpus_done,
+ .cpu_up = xen_cpu_up,
+ .cpu_die = xen_cpu_die,
+ .cpu_disable = xen_cpu_disable,
+ .play_dead = xen_play_dead,
+
.smp_send_stop = xen_smp_send_stop,
.smp_send_reschedule = xen_smp_send_reschedule,
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
new file mode 100644
index 0000000..dd71e3a
--- /dev/null
+++ b/arch/x86/xen/spinlock.c
@@ -0,0 +1,428 @@
+/*
+ * Split spinlock implementation out into its own file, so it can be
+ * compiled in a FTRACE-compatible way.
+ */
+#include <linux/kernel_stat.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/log2.h>
+
+#include <asm/paravirt.h>
+
+#include <xen/interface/xen.h>
+#include <xen/events.h>
+
+#include "xen-ops.h"
+#include "debugfs.h"
+
+#ifdef CONFIG_XEN_DEBUG_FS
+static struct xen_spinlock_stats
+{
+ u64 taken;
+ u32 taken_slow;
+ u32 taken_slow_nested;
+ u32 taken_slow_pickup;
+ u32 taken_slow_spurious;
+ u32 taken_slow_irqenable;
+
+ u64 released;
+ u32 released_slow;
+ u32 released_slow_kicked;
+
+#define HISTO_BUCKETS 30
+ u32 histo_spin_total[HISTO_BUCKETS+1];
+ u32 histo_spin_spinning[HISTO_BUCKETS+1];
+ u32 histo_spin_blocked[HISTO_BUCKETS+1];
+
+ u64 time_total;
+ u64 time_spinning;
+ u64 time_blocked;
+} spinlock_stats;
+
+static u8 zero_stats;
+
+static unsigned lock_timeout = 1 << 10;
+#define TIMEOUT lock_timeout
+
+static inline void check_zero(void)
+{
+ if (unlikely(zero_stats)) {
+ memset(&spinlock_stats, 0, sizeof(spinlock_stats));
+ zero_stats = 0;
+ }
+}
+
+#define ADD_STATS(elem, val) \
+ do { check_zero(); spinlock_stats.elem += (val); } while(0)
+
+static inline u64 spin_time_start(void)
+{
+ return xen_clocksource_read();
+}
+
+static void __spin_time_accum(u64 delta, u32 *array)
+{
+ unsigned index = ilog2(delta);
+
+ check_zero();
+
+ if (index < HISTO_BUCKETS)
+ array[index]++;
+ else
+ array[HISTO_BUCKETS]++;
+}
+
+static inline void spin_time_accum_spinning(u64 start)
+{
+ u32 delta = xen_clocksource_read() - start;
+
+ __spin_time_accum(delta, spinlock_stats.histo_spin_spinning);
+ spinlock_stats.time_spinning += delta;
+}
+
+static inline void spin_time_accum_total(u64 start)
+{
+ u32 delta = xen_clocksource_read() - start;
+
+ __spin_time_accum(delta, spinlock_stats.histo_spin_total);
+ spinlock_stats.time_total += delta;
+}
+
+static inline void spin_time_accum_blocked(u64 start)
+{
+ u32 delta = xen_clocksource_read() - start;
+
+ __spin_time_accum(delta, spinlock_stats.histo_spin_blocked);
+ spinlock_stats.time_blocked += delta;
+}
+#else /* !CONFIG_XEN_DEBUG_FS */
+#define TIMEOUT (1 << 10)
+#define ADD_STATS(elem, val) do { (void)(val); } while(0)
+
+static inline u64 spin_time_start(void)
+{
+ return 0;
+}
+
+static inline void spin_time_accum_total(u64 start)
+{
+}
+static inline void spin_time_accum_spinning(u64 start)
+{
+}
+static inline void spin_time_accum_blocked(u64 start)
+{
+}
+#endif /* CONFIG_XEN_DEBUG_FS */
+
+struct xen_spinlock {
+ unsigned char lock; /* 0 -> free; 1 -> locked */
+ unsigned short spinners; /* count of waiting cpus */
+};
+
+static int xen_spin_is_locked(struct raw_spinlock *lock)
+{
+ struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+ return xl->lock != 0;
+}
+
+static int xen_spin_is_contended(struct raw_spinlock *lock)
+{
+ struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+ /* Not strictly true; this is only the count of contended
+ lock-takers entering the slow path. */
+ return xl->spinners != 0;
+}
+
+static int xen_spin_trylock(struct raw_spinlock *lock)
+{
+ struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+ u8 old = 1;
+
+ asm("xchgb %b0,%1"
+ : "+q" (old), "+m" (xl->lock) : : "memory");
+
+ return old == 0;
+}
+
+static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
+static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);
+
+/*
+ * Mark a cpu as interested in a lock. Returns the CPU's previous
+ * lock of interest, in case we got preempted by an interrupt.
+ */
+static inline struct xen_spinlock *spinning_lock(struct xen_spinlock *xl)
+{
+ struct xen_spinlock *prev;
+
+ prev = __get_cpu_var(lock_spinners);
+ __get_cpu_var(lock_spinners) = xl;
+
+ wmb(); /* set lock of interest before count */
+
+ asm(LOCK_PREFIX " incw %0"
+ : "+m" (xl->spinners) : : "memory");
+
+ return prev;
+}
+
+/*
+ * Mark a cpu as no longer interested in a lock. Restores previous
+ * lock of interest (NULL for none).
+ */
+static inline void unspinning_lock(struct xen_spinlock *xl, struct xen_spinlock *prev)
+{
+ asm(LOCK_PREFIX " decw %0"
+ : "+m" (xl->spinners) : : "memory");
+ wmb(); /* decrement count before restoring lock */
+ __get_cpu_var(lock_spinners) = prev;
+}
+
+static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enable)
+{
+ struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+ struct xen_spinlock *prev;
+ int irq = __get_cpu_var(lock_kicker_irq);
+ int ret;
+ unsigned long flags;
+ u64 start;
+
+ /* If kicker interrupts not initialized yet, just spin */
+ if (irq == -1)
+ return 0;
+
+ start = spin_time_start();
+
+ /* announce we're spinning */
+ prev = spinning_lock(xl);
+
+ flags = __raw_local_save_flags();
+ if (irq_enable) {
+ ADD_STATS(taken_slow_irqenable, 1);
+ raw_local_irq_enable();
+ }
+
+ ADD_STATS(taken_slow, 1);
+ ADD_STATS(taken_slow_nested, prev != NULL);
+
+ do {
+ /* clear pending */
+ xen_clear_irq_pending(irq);
+
+ /* check again make sure it didn't become free while
+ we weren't looking */
+ ret = xen_spin_trylock(lock);
+ if (ret) {
+ ADD_STATS(taken_slow_pickup, 1);
+
+ /*
+ * If we interrupted another spinlock while it
+ * was blocking, make sure it doesn't block
+ * without rechecking the lock.
+ */
+ if (prev != NULL)
+ xen_set_irq_pending(irq);
+ goto out;
+ }
+
+ /*
+ * Block until irq becomes pending. If we're
+ * interrupted at this point (after the trylock but
+ * before entering the block), then the nested lock
+ * handler guarantees that the irq will be left
+ * pending if there's any chance the lock became free;
+ * xen_poll_irq() returns immediately if the irq is
+ * pending.
+ */
+ xen_poll_irq(irq);
+ ADD_STATS(taken_slow_spurious, !xen_test_irq_pending(irq));
+ } while (!xen_test_irq_pending(irq)); /* check for spurious wakeups */
+
+ kstat_this_cpu.irqs[irq]++;
+
+out:
+ raw_local_irq_restore(flags);
+ unspinning_lock(xl, prev);
+ spin_time_accum_blocked(start);
+
+ return ret;
+}
+
+static inline void __xen_spin_lock(struct raw_spinlock *lock, bool irq_enable)
+{
+ struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+ unsigned timeout;
+ u8 oldval;
+ u64 start_spin;
+
+ ADD_STATS(taken, 1);
+
+ start_spin = spin_time_start();
+
+ do {
+ u64 start_spin_fast = spin_time_start();
+
+ timeout = TIMEOUT;
+
+ asm("1: xchgb %1,%0\n"
+ " testb %1,%1\n"
+ " jz 3f\n"
+ "2: rep;nop\n"
+ " cmpb $0,%0\n"
+ " je 1b\n"
+ " dec %2\n"
+ " jnz 2b\n"
+ "3:\n"
+ : "+m" (xl->lock), "=q" (oldval), "+r" (timeout)
+ : "1" (1)
+ : "memory");
+
+ spin_time_accum_spinning(start_spin_fast);
+
+ } while (unlikely(oldval != 0 &&
+ (TIMEOUT == ~0 || !xen_spin_lock_slow(lock, irq_enable))));
+
+ spin_time_accum_total(start_spin);
+}
+
+static void xen_spin_lock(struct raw_spinlock *lock)
+{
+ __xen_spin_lock(lock, false);
+}
+
+static void xen_spin_lock_flags(struct raw_spinlock *lock, unsigned long flags)
+{
+ __xen_spin_lock(lock, !raw_irqs_disabled_flags(flags));
+}
+
+static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
+{
+ int cpu;
+
+ ADD_STATS(released_slow, 1);
+
+ for_each_online_cpu(cpu) {
+ /* XXX should mix up next cpu selection */
+ if (per_cpu(lock_spinners, cpu) == xl) {
+ ADD_STATS(released_slow_kicked, 1);
+ xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
+ break;
+ }
+ }
+}
+
+static void xen_spin_unlock(struct raw_spinlock *lock)
+{
+ struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+ ADD_STATS(released, 1);
+
+ smp_wmb(); /* make sure no writes get moved after unlock */
+ xl->lock = 0; /* release lock */
+
+ /* make sure unlock happens before kick */
+ barrier();
+
+ if (unlikely(xl->spinners))
+ xen_spin_unlock_slow(xl);
+}
+
+static irqreturn_t dummy_handler(int irq, void *dev_id)
+{
+ BUG();
+ return IRQ_HANDLED;
+}
+
+void __cpuinit xen_init_lock_cpu(int cpu)
+{
+ int irq;
+ const char *name;
+
+ name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
+ irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
+ cpu,
+ dummy_handler,
+ IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+ name,
+ NULL);
+
+ if (irq >= 0) {
+ disable_irq(irq); /* make sure it's never delivered */
+ per_cpu(lock_kicker_irq, cpu) = irq;
+ }
+
+ printk("cpu %d spinlock event irq %d\n", cpu, irq);
+}
+
+void xen_uninit_lock_cpu(int cpu)
+{
+ unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
+}
+
+void __init xen_init_spinlocks(void)
+{
+ pv_lock_ops.spin_is_locked = xen_spin_is_locked;
+ pv_lock_ops.spin_is_contended = xen_spin_is_contended;
+ pv_lock_ops.spin_lock = xen_spin_lock;
+ pv_lock_ops.spin_lock_flags = xen_spin_lock_flags;
+ pv_lock_ops.spin_trylock = xen_spin_trylock;
+ pv_lock_ops.spin_unlock = xen_spin_unlock;
+}
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_spin_debug;
+
+static int __init xen_spinlock_debugfs(void)
+{
+ struct dentry *d_xen = xen_init_debugfs();
+
+ if (d_xen == NULL)
+ return -ENOMEM;
+
+ d_spin_debug = debugfs_create_dir("spinlocks", d_xen);
+
+ debugfs_create_u8("zero_stats", 0644, d_spin_debug, &zero_stats);
+
+ debugfs_create_u32("timeout", 0644, d_spin_debug, &lock_timeout);
+
+ debugfs_create_u64("taken", 0444, d_spin_debug, &spinlock_stats.taken);
+ debugfs_create_u32("taken_slow", 0444, d_spin_debug,
+ &spinlock_stats.taken_slow);
+ debugfs_create_u32("taken_slow_nested", 0444, d_spin_debug,
+ &spinlock_stats.taken_slow_nested);
+ debugfs_create_u32("taken_slow_pickup", 0444, d_spin_debug,
+ &spinlock_stats.taken_slow_pickup);
+ debugfs_create_u32("taken_slow_spurious", 0444, d_spin_debug,
+ &spinlock_stats.taken_slow_spurious);
+ debugfs_create_u32("taken_slow_irqenable", 0444, d_spin_debug,
+ &spinlock_stats.taken_slow_irqenable);
+
+ debugfs_create_u64("released", 0444, d_spin_debug, &spinlock_stats.released);
+ debugfs_create_u32("released_slow", 0444, d_spin_debug,
+ &spinlock_stats.released_slow);
+ debugfs_create_u32("released_slow_kicked", 0444, d_spin_debug,
+ &spinlock_stats.released_slow_kicked);
+
+ debugfs_create_u64("time_spinning", 0444, d_spin_debug,
+ &spinlock_stats.time_spinning);
+ debugfs_create_u64("time_blocked", 0444, d_spin_debug,
+ &spinlock_stats.time_blocked);
+ debugfs_create_u64("time_total", 0444, d_spin_debug,
+ &spinlock_stats.time_total);
+
+ xen_debugfs_create_u32_array("histo_total", 0444, d_spin_debug,
+ spinlock_stats.histo_spin_total, HISTO_BUCKETS + 1);
+ xen_debugfs_create_u32_array("histo_spinning", 0444, d_spin_debug,
+ spinlock_stats.histo_spin_spinning, HISTO_BUCKETS + 1);
+ xen_debugfs_create_u32_array("histo_blocked", 0444, d_spin_debug,
+ spinlock_stats.histo_spin_blocked, HISTO_BUCKETS + 1);
+
+ return 0;
+}
+fs_initcall(xen_spinlock_debugfs);
+
+#endif /* CONFIG_XEN_DEBUG_FS */
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 685b774..004ba86 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -30,8 +30,6 @@
#define TIMER_SLOP 100000
#define NS_PER_TICK (1000000000LL / HZ)
-static cycle_t xen_clocksource_read(void);
-
/* runstate info updated by Xen */
static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
@@ -213,7 +211,7 @@
return xen_khz;
}
-static cycle_t xen_clocksource_read(void)
+cycle_t xen_clocksource_read(void)
{
struct pvclock_vcpu_time_info *src;
cycle_t ret;
@@ -452,6 +450,14 @@
setup_runstate_info(cpu);
}
+void xen_teardown_timer(int cpu)
+{
+ struct clock_event_device *evt;
+ BUG_ON(cpu == 0);
+ evt = &per_cpu(xen_clock_events, cpu);
+ unbind_from_irqhandler(evt->irq, NULL);
+}
+
void xen_setup_cpu_clockevents(void)
{
BUG_ON(preemptible());
diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S
index 2497a30..42786f5 100644
--- a/arch/x86/xen/xen-asm_32.S
+++ b/arch/x86/xen/xen-asm_32.S
@@ -298,7 +298,7 @@
push %eax
push %ecx
push %edx
- call force_evtchn_callback
+ call xen_force_evtchn_callback
pop %edx
pop %ecx
pop %eax
diff --git a/arch/x86/xen/xen-asm_64.S b/arch/x86/xen/xen-asm_64.S
index 7f58304..05794c5 100644
--- a/arch/x86/xen/xen-asm_64.S
+++ b/arch/x86/xen/xen-asm_64.S
@@ -26,8 +26,15 @@
/* Pseudo-flag used for virtual NMI, which we don't implement yet */
#define XEN_EFLAGS_NMI 0x80000000
-#if 0
-#include <asm/percpu.h>
+#if 1
+/*
+ x86-64 does not yet support direct access to percpu variables
+ via a segment override, so we just need to make sure this code
+ never gets used
+ */
+#define BUG ud2a
+#define PER_CPU_VAR(var, off) 0xdeadbeef
+#endif
/*
Enable events. This clears the event mask and tests the pending
@@ -35,6 +42,8 @@
events, then enter the hypervisor to get them handled.
*/
ENTRY(xen_irq_enable_direct)
+ BUG
+
/* Unmask events */
movb $0, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
@@ -58,6 +67,8 @@
non-zero.
*/
ENTRY(xen_irq_disable_direct)
+ BUG
+
movb $1, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
ENDPATCH(xen_irq_disable_direct)
ret
@@ -74,6 +85,8 @@
Xen and x86 use opposite senses (mask vs enable).
*/
ENTRY(xen_save_fl_direct)
+ BUG
+
testb $0xff, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
setz %ah
addb %ah,%ah
@@ -91,6 +104,8 @@
if so.
*/
ENTRY(xen_restore_fl_direct)
+ BUG
+
testb $X86_EFLAGS_IF>>8, %ah
setz PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
/* Preempt here doesn't matter because that will deal with
@@ -122,7 +137,7 @@
push %r9
push %r10
push %r11
- call force_evtchn_callback
+ call xen_force_evtchn_callback
pop %r11
pop %r10
pop %r9
@@ -133,7 +148,6 @@
pop %rcx
pop %rax
ret
-#endif
ENTRY(xen_adjust_exception_frame)
mov 8+0(%rsp),%rcx
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index dd3c231..d7422dc 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -2,6 +2,7 @@
#define XEN_OPS_H
#include <linux/init.h>
+#include <linux/clocksource.h>
#include <linux/irqreturn.h>
#include <xen/xen-ops.h>
@@ -31,7 +32,10 @@
void __init xen_build_dynamic_phys_to_machine(void);
+void xen_init_irq_ops(void);
void xen_setup_timer(int cpu);
+void xen_teardown_timer(int cpu);
+cycle_t xen_clocksource_read(void);
void xen_setup_cpu_clockevents(void);
unsigned long xen_tsc_khz(void);
void __init xen_time_init(void);
@@ -50,6 +54,10 @@
#ifdef CONFIG_SMP
void xen_smp_init(void);
+void __init xen_init_spinlocks(void);
+__cpuinit void xen_init_lock_cpu(int cpu);
+void xen_uninit_lock_cpu(int cpu);
+
extern cpumask_t xen_cpu_initialized_map;
#else
static inline void xen_smp_init(void) {}
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 8dd3336..3c578ef 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -369,7 +369,6 @@
DBG("RTC unavailable?\n");
return 0;
}
-/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */
-fs_initcall(acpi_rtc_init);
+module_init(acpi_rtc_init);
#endif
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index f17cd4b..78fbec8 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -7,7 +7,6 @@
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/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 73338d2..937c9c0 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -47,8 +47,9 @@
#include <asm/atomic.h>
#ifdef CONFIG_SBUS
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/idprom.h>
-#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/pgtable.h>
@@ -661,249 +662,189 @@
#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)
+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);
+ struct of_device *op = fore200e->bus_dev;
+ u32 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);
+ dma_addr = dma_map_single(&op->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);
- return dma_addr;
+ return dma_addr;
}
-
-static void
-fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int 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);
+ struct of_device *op = fore200e->bus_dev;
- sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, 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);
}
-
-static void
-fore200e_sba_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, int 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);
+ 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);
- sbus_dma_sync_single_for_cpu((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
+ dma_sync_single_for_cpu(&op->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)
{
- DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
+ struct of_device *op = fore200e->bus_dev;
- sbus_dma_sync_single_for_device((struct sbus_dev*)fore200e->bus_dev, 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);
}
-
-/* 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)
+/* 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)
{
- chunk->alloc_size = chunk->align_size = size * nbr;
+ struct of_device *op = fore200e->bus_dev;
- /* returned chunks are page-aligned */
- chunk->alloc_addr = sbus_alloc_consistent((struct sbus_dev*)fore200e->bus_dev,
- chunk->alloc_size,
- &chunk->dma_addr);
+ 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 = dma_alloc_coherent(&op->dev, chunk->alloc_size,
+ &chunk->dma_addr, GFP_ATOMIC);
- chunk->align_addr = chunk->alloc_addr;
+ if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
+ return -ENOMEM;
+
+ 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)
+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);
+ 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_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 sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
- unsigned int bursts;
+ struct of_device *op = fore200e->bus_dev;
+ unsigned int bursts;
- /* 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");
+ /* 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");
- 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);
-
- fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */
-
- /* get the supported DVMA burst sizes */
- bursts = prom_getintdefault(sbus_dev->bus->prom_node, "burst-sizes", 0x00);
-
- if (sbus_can_dma_64bit(sbus_dev))
- sbus_set_sbus64(sbus_dev, bursts);
-
- fore200e->state = FORE200E_STATE_MAP;
- return 0;
-}
-
-
-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)
-{
- fore200e->state = FORE200E_STATE_CONFIGURE;
- return 0;
-}
-
-
-static struct fore200e* __init
-fore200e_sba_detect(const struct fore200e_bus* bus, int index)
-{
- 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++;
- }
+ if (!fore200e->virt_base) {
+ printk(FORE200E "unable to map RAM of device %s\n", fore200e->name);
+ return -EFAULT;
}
- }
- return NULL;
+
+ DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
- 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->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */
- fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
- if (fore200e == NULL)
- return NULL;
+ /* get the supported DVMA burst sizes */
+ bursts = of_getintprop_default(op->node->parent, "burst-sizes", 0x00);
- fore200e->bus = bus;
- fore200e->bus_dev = sbus_dev;
- fore200e->irq = sbus_dev->irqs[ 0 ];
+ if (sbus_can_dma_64bit())
+ sbus_set_sbus64(&op->dev, bursts);
- fore200e->phys_base = (unsigned long)sbus_dev;
-
- sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
-
- return fore200e;
+ fore200e->state = FORE200E_STATE_MAP;
+ return 0;
}
-
-static int __init
-fore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom)
+static void fore200e_sba_unmap(struct fore200e *fore200e)
{
- struct sbus_dev* sbus_dev = (struct sbus_dev*) fore200e->bus_dev;
- int len;
+ struct of_device *op = fore200e->bus_dev;
- 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;
+ 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 int
-fore200e_sba_proc_read(struct fore200e* fore200e, char *page)
+static int __init fore200e_sba_configure(struct fore200e *fore200e)
{
- struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
+ fore200e->state = FORE200E_STATE_CONFIGURE;
+ return 0;
+}
- return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name);
+static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_data *prom)
+{
+ struct of_device *op = fore200e->bus_dev;
+ const u8 *prop;
+ int len;
+
+ prop = of_get_property(op->node, "madaddrlo2", &len);
+ if (!prop)
+ return -ENODEV;
+ memcpy(&prom->mac_addr[4], prop, 4);
+
+ prop = of_get_property(op->node, "madaddrhi4", &len);
+ if (!prop)
+ return -ENODEV;
+ memcpy(&prom->mac_addr[2], prop, 4);
+
+ prom->serial_number = of_getintprop_default(op->node, "serialnumber", 0);
+ prom->hw_revision = of_getintprop_default(op->node, "promversion", 0);
+
+ return 0;
+}
+
+static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page)
+{
+ struct of_device *op = fore200e->bus_dev;
+ const struct linux_prom_registers *regs;
+
+ 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);
}
#endif /* CONFIG_SBUS */
@@ -2572,7 +2513,7 @@
device = &((struct pci_dev *) fore200e->bus_dev)->dev;
#ifdef CONFIG_SBUS
else if (strcmp(fore200e->bus->model_name, "SBA-200E") == 0)
- device = &((struct sbus_dev *) fore200e->bus_dev)->ofdev.dev;
+ device = &((struct of_device *) fore200e->bus_dev)->dev;
#endif
else
return err;
@@ -2701,6 +2642,66 @@
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)
@@ -2784,66 +2785,39 @@
};
#endif
-
-static int __init
-fore200e_module_init(void)
+static int __init fore200e_module_init(void)
{
- const struct fore200e_bus* bus;
- struct fore200e* fore200e;
- int index;
+ int err;
- printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
+ printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
- /* 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
- if (!pci_register_driver(&fore200e_pca_driver))
- return 0;
+#ifdef CONFIG_SBUS
+ err = of_register_driver(&fore200e_sba_driver, &of_bus_type);
+ if (err)
+ return err;
#endif
- if (!list_empty(&fore200e_boards))
- return 0;
-
- return -ENODEV;
-}
-
-
-static void __exit
-fore200e_module_cleanup(void)
-{
- struct fore200e *fore200e, *next;
-
#ifdef CONFIG_PCI
- pci_unregister_driver(&fore200e_pca_driver);
+ err = pci_register_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");
+#ifdef CONFIG_SBUS
+ if (err)
+ of_unregister_driver(&fore200e_sba_driver);
+#endif
+
+ return err;
}
+static void __exit fore200e_module_cleanup(void)
+{
+#ifdef CONFIG_PCI
+ pci_unregister_driver(&fore200e_pca_driver);
+#endif
+#ifdef CONFIG_SBUS
+ of_unregister_driver(&fore200e_sba_driver);
+#endif
+}
static int
fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
@@ -3163,7 +3137,6 @@
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,
@@ -3185,7 +3158,6 @@
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/drivers/atm/fore200e.h b/drivers/atm/fore200e.h
index 5c6e7ad..7f97c09 100644
--- a/drivers/atm/fore200e.h
+++ b/drivers/atm/fore200e.h
@@ -778,9 +778,9 @@
/* SBA-200E registers */
typedef struct fore200e_sba_regs {
- 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 */
+ 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 */
} fore200e_sba_regs_t;
@@ -810,7 +810,6 @@
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/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index a8de037..953c0b8 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -1,6 +1,6 @@
/* sunvdc.c: Sun LDOM Virtual Disk Client.
*
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/module.h>
@@ -834,7 +834,7 @@
return 0;
}
-static struct vio_device_id vdc_port_match[] = {
+static const struct vio_device_id vdc_port_match[] = {
{
.type = "vdc-port",
},
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index bff602c..1a50ae7 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -1066,7 +1066,7 @@
static int __init xlblk_init(void)
{
- if (!is_running_on_xen())
+ if (!xen_domain())
return -ENODEV;
if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
index 6b70aa6..538ceea 100644
--- a/drivers/char/hvc_xen.c
+++ b/drivers/char/hvc_xen.c
@@ -108,8 +108,8 @@
{
struct hvc_struct *hp;
- if (!is_running_on_xen() ||
- is_initial_xendomain() ||
+ if (!xen_pv_domain() ||
+ xen_initial_domain() ||
!xen_start_info->console.domU.evtchn)
return -ENODEV;
@@ -142,7 +142,7 @@
static int xen_cons_init(void)
{
- if (!is_running_on_xen())
+ if (!xen_pv_domain())
return 0;
hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
index 5220f54..8859aea 100644
--- a/drivers/char/hw_random/n2-drv.c
+++ b/drivers/char/hw_random/n2-drv.c
@@ -736,7 +736,7 @@
return 0;
}
-static struct of_device_id n2rng_match[] = {
+static const struct of_device_id n2rng_match[] = {
{
.name = "random-number-generator",
.compatible = "SUNW,n2-rng",
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index f53d4d0..b47710c 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -88,12 +88,12 @@
#endif
#ifdef CONFIG_SPARC32
-#include <linux/pci.h>
-#include <linux/jiffies.h>
-#include <asm/ebus.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <asm/io.h>
static unsigned long rtc_port;
-static int rtc_irq = PCI_IRQ_NONE;
+static int rtc_irq;
#endif
#ifdef CONFIG_HPET_RTC_IRQ
@@ -973,8 +973,8 @@
char *guess = NULL;
#endif
#ifdef CONFIG_SPARC32
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev;
+ struct device_node *ebus_dp;
+ struct of_device *op;
#else
void *r;
#ifdef RTC_IRQ
@@ -983,12 +983,16 @@
#endif
#ifdef CONFIG_SPARC32
- 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;
+ 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;
+ }
}
}
}
@@ -997,7 +1001,7 @@
return -EIO;
found:
- if (rtc_irq == PCI_IRQ_NONE) {
+ if (!rtc_irq) {
rtc_has_irq = 0;
goto no_irq;
}
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 3309e86..ebacc0a 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -800,6 +800,13 @@
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/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 6babc80..042d5a7 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -41,6 +41,7 @@
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/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
new file mode 100644
index 0000000..68e90ab
--- /dev/null
+++ b/drivers/hwmon/ultra45_env.c
@@ -0,0 +1,320 @@
+/* ultra45_env.c: Driver for Ultra45 PIC16F747 environmental monitor.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/io.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#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/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index d8765cc..c4f4231 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -249,7 +249,7 @@
return 0;
}
-static struct of_device_id bbc_beep_match[] = {
+static const struct of_device_id bbc_beep_match[] = {
{
.name = "beep",
.compatible = "SUNW,bbc-beep",
@@ -328,7 +328,7 @@
return 0;
}
-static struct of_device_id grover_beep_match[] = {
+static const struct of_device_id grover_beep_match[] = {
{
.name = "beep",
.compatible = "SUNW,smbus-beep",
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
index 692a79e..5071af2 100644
--- a/drivers/input/serio/i8042-sparcio.h
+++ b/drivers/input/serio/i8042-sparcio.h
@@ -87,7 +87,7 @@
return 0;
}
-static struct of_device_id sparc_i8042_match[] = {
+static const struct of_device_id sparc_i8042_match[] = {
{
.name = "8042",
},
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c
index 9ce3b3b..3ab6362 100644
--- a/drivers/input/xen-kbdfront.c
+++ b/drivers/input/xen-kbdfront.c
@@ -335,11 +335,11 @@
static int __init xenkbd_init(void)
{
- if (!is_running_on_xen())
+ if (!xen_domain())
return -ENODEV;
/* Nothing to do if running in dom0. */
- if (is_initial_xendomain())
+ if (xen_initial_domain())
return -ENODEV;
return xenbus_register_frontend(&xenkbd);
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 5b14262..e3e4042 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -82,6 +82,14 @@
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/drivers/leds/Makefile b/drivers/leds/Makefile
index 3a8e6a0..eb186c3 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -14,6 +14,7 @@
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/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c
new file mode 100644
index 0000000..6b008f0
--- /dev/null
+++ b/drivers/leds/leds-sunfire.c
@@ -0,0 +1,273 @@
+/* leds-sunfire.c: SUNW,Ultra-Enterprise LED driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <asm/fhc.h>
+#include <asm/upa.h>
+
+#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/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index c0b41e8..f2eeb38 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -3,13 +3,14 @@
#
menuconfig MMC
- tristate "MMC/SD card support"
+ tristate "MMC/SD/SDIO card support"
depends on HAS_IOMEM
help
- MMC is the "multi-media card" bus protocol.
+ This selects MultiMediaCard, Secure Digital and Secure
+ Digital I/O support.
- If you want MMC support, you should say Y here and also
- to the specific driver for your MMC interface.
+ If you want MMC/SD/SDIO support, you should say Y here and
+ also to your specific host controller driver.
config MMC_DEBUG
bool "MMC debugging"
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index dd0f398..3f2a912 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -2,7 +2,7 @@
# MMC/SD card drivers
#
-comment "MMC/SD Card Drivers"
+comment "MMC/SD/SDIO Card Drivers"
config MMC_BLOCK
tristate "MMC block device driver"
@@ -34,7 +34,6 @@
config SDIO_UART
tristate "SDIO UART/GPS class support"
- depends on MMC
help
SDIO function driver for SDIO cards that implements the UART
class, as well as the GPS class which appears like a UART.
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index efacee0..24c97d3 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -58,7 +58,6 @@
struct mmc_queue queue;
unsigned int usage;
- unsigned int block_bits;
unsigned int read_only;
};
@@ -216,8 +215,7 @@
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
struct mmc_blk_request brq;
- int ret = 1, data_size, i;
- struct scatterlist *sg;
+ int ret = 1;
mmc_claim_host(card->host);
@@ -233,13 +231,11 @@
if (!mmc_card_blockaddr(card))
brq.cmd.arg <<= 9;
brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- brq.data.blksz = 1 << md->block_bits;
+ brq.data.blksz = 512;
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
- brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
- if (brq.data.blocks > card->host->max_blk_count)
- brq.data.blocks = card->host->max_blk_count;
+ brq.data.blocks = req->nr_sectors;
if (brq.data.blocks > 1) {
/* SPI multiblock writes terminate using a special
@@ -271,24 +267,6 @@
mmc_queue_bounce_pre(mq);
- /*
- * Adjust the sg list so it is the same size as the
- * request.
- */
- if (brq.data.blocks !=
- (req->nr_sectors >> (md->block_bits - 9))) {
- data_size = brq.data.blocks * brq.data.blksz;
- for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
- data_size -= sg->length;
- if (data_size <= 0) {
- sg->length += data_size;
- i++;
- break;
- }
- }
- brq.data.sg_len = i;
- }
-
mmc_wait_for_req(card->host, &brq.mrq);
mmc_queue_bounce_post(mq);
@@ -373,16 +351,11 @@
if (rq_data_dir(req) != READ) {
if (mmc_card_sd(card)) {
u32 blocks;
- unsigned int bytes;
blocks = mmc_sd_num_wr_blocks(card);
if (blocks != (u32)-1) {
- if (card->csd.write_partial)
- bytes = blocks << md->block_bits;
- else
- bytes = blocks << 9;
spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, 0, bytes);
+ ret = __blk_end_request(req, 0, blocks << 9);
spin_unlock_irq(&md->lock);
}
} else {
@@ -432,13 +405,6 @@
*/
md->read_only = mmc_blk_readonly(card);
- /*
- * Both SD and MMC specifications state (although a bit
- * unclearly in the MMC case) that a block size of 512
- * bytes must always be supported by the card.
- */
- md->block_bits = 9;
-
md->disk = alloc_disk(1 << MMC_SHIFT);
if (md->disk == NULL) {
ret = -ENOMEM;
@@ -476,7 +442,7 @@
sprintf(md->disk->disk_name, "mmcblk%d", devidx);
- blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
+ blk_queue_hardsect_size(md->queue.queue, 512);
if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
/*
@@ -514,7 +480,7 @@
mmc_claim_host(card->host);
cmd.opcode = MMC_SET_BLOCKLEN;
- cmd.arg = 1 << md->block_bits;
+ cmd.arg = 512;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
mmc_release_host(card->host);
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 3dee97e..406989e 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -31,7 +31,7 @@
/*
* We only like normal block requests.
*/
- if (!blk_fs_request(req) && !blk_pc_request(req)) {
+ if (!blk_fs_request(req)) {
blk_dump_rq_flags(req, "MMC bad request");
return BLKPREP_KILL;
}
@@ -131,6 +131,7 @@
mq->req = NULL;
blk_queue_prep_rq(mq->queue, mmc_prep_request);
+ blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL);
#ifdef CONFIG_MMC_BLOCK_BOUNCE
if (host->max_hw_segs == 1) {
@@ -142,12 +143,19 @@
bouncesz = host->max_req_size;
if (bouncesz > host->max_seg_size)
bouncesz = host->max_seg_size;
+ if (bouncesz > (host->max_blk_count * 512))
+ bouncesz = host->max_blk_count * 512;
- mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
- if (!mq->bounce_buf) {
- printk(KERN_WARNING "%s: unable to allocate "
- "bounce buffer\n", mmc_card_name(card));
- } else {
+ if (bouncesz > 512) {
+ mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+ if (!mq->bounce_buf) {
+ printk(KERN_WARNING "%s: unable to "
+ "allocate bounce buffer\n",
+ mmc_card_name(card));
+ }
+ }
+
+ if (mq->bounce_buf) {
blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
blk_queue_max_sectors(mq->queue, bouncesz / 512);
blk_queue_max_phys_segments(mq->queue, bouncesz / 512);
@@ -175,7 +183,8 @@
if (!mq->bounce_buf) {
blk_queue_bounce_limit(mq->queue, limit);
- blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
+ blk_queue_max_sectors(mq->queue,
+ min(host->max_blk_count, host->max_req_size / 512));
blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 64b05c6..9c50e6f 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -248,8 +248,12 @@
sg_init_one(&sg, data_buf, len);
- if (card)
- mmc_set_data_timeout(&data, card);
+ /*
+ * The spec states that CSR and CID accesses have a timeout
+ * of 64 clock cycles.
+ */
+ data.timeout_ns = 0;
+ data.timeout_clks = 64;
mmc_wait_for_req(host, &mrq);
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4eab79e..fb99ccf 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -165,6 +165,36 @@
}
/*
+ * Test if the card supports high-speed mode and, if so, switch to it.
+ */
+static int sdio_enable_hs(struct mmc_card *card)
+{
+ int ret;
+ u8 speed;
+
+ if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
+ return 0;
+
+ if (!card->cccr.high_speed)
+ return 0;
+
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
+ if (ret)
+ return ret;
+
+ speed |= SDIO_SPEED_EHS;
+
+ ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
+ if (ret)
+ return ret;
+
+ mmc_card_set_highspeed(card);
+ mmc_set_timing(card->host, MMC_TIMING_SD_HS);
+
+ return 0;
+}
+
+/*
* Host is being removed. Free up the current card.
*/
static void mmc_sdio_remove(struct mmc_host *host)
@@ -333,10 +363,26 @@
goto remove;
/*
- * No support for high-speed yet, so just set
- * the card's maximum speed.
+ * Switch to high-speed (if supported).
*/
- mmc_set_clock(host, card->cis.max_dtr);
+ err = sdio_enable_hs(card);
+ if (err)
+ goto remove;
+
+ /*
+ * Change to the card's maximum speed.
+ */
+ if (mmc_card_highspeed(card)) {
+ /*
+ * The SDIO specification doesn't mention how
+ * the CIS transfer speed register relates to
+ * high-speed, but it seems that 50 MHz is
+ * mandatory.
+ */
+ mmc_set_clock(host, 50000000);
+ } else {
+ mmc_set_clock(host, card->cis.max_dtr);
+ }
/*
* Switch to wider bus (if supported).
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index c292e12..bb192f9 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -5,6 +5,8 @@
* Created: June 18, 2007
* Copyright: MontaVista Software Inc.
*
+ * Copyright 2008 Pierre Ossman
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
@@ -107,11 +109,14 @@
/*
* Give other threads a chance to run in the presence of
- * errors. FIXME: determine if due to card removal and
- * possibly exit this thread if so.
+ * errors.
*/
- if (ret < 0)
- ssleep(1);
+ if (ret < 0) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!kthread_should_stop())
+ schedule_timeout(HZ);
+ set_current_state(TASK_RUNNING);
+ }
/*
* Adaptive polling frequency based on the assumption
@@ -154,7 +159,8 @@
if (!host->sdio_irqs++) {
atomic_set(&host->sdio_irq_thread_abort, 0);
host->sdio_irq_thread =
- kthread_run(sdio_irq_thread, host, "ksdiorqd");
+ kthread_run(sdio_irq_thread, host, "ksdioirqd/%s",
+ mmc_hostname(host));
if (IS_ERR(host->sdio_irq_thread)) {
int err = PTR_ERR(host->sdio_irq_thread);
host->sdio_irqs--;
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index ea8d7a3..dfa585f 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -2,7 +2,7 @@
# MMC/SD host controller drivers
#
-comment "MMC/SD Host Controller Drivers"
+comment "MMC/SD/SDIO Host Controller Drivers"
config MMC_ARMMMCI
tristate "ARM AMBA Multimedia Card Interface support"
@@ -114,6 +114,17 @@
If unsure, say N.
+config MMC_ATMELMCI_DMA
+ bool "Atmel MCI DMA support (EXPERIMENTAL)"
+ depends on MMC_ATMELMCI && DMA_ENGINE && EXPERIMENTAL
+ help
+ Say Y here to have the Atmel MCI driver use a DMA engine to
+ do data transfers and thus increase the throughput and
+ reduce the CPU utilization. Note that this is highly
+ experimental and may cause the driver to lock up.
+
+ If unsure, say N.
+
config MMC_IMX
tristate "Motorola i.MX Multimedia Card Interface support"
depends on ARCH_IMX
@@ -141,21 +152,22 @@
module will be called tifm_sd.
config MMC_SPI
- tristate "MMC/SD over SPI"
- depends on MMC && SPI_MASTER && !HIGHMEM && HAS_DMA
+ tristate "MMC/SD/SDIO over SPI"
+ depends on SPI_MASTER && !HIGHMEM && HAS_DMA
select CRC7
select CRC_ITU_T
help
- Some systems accss MMC/SD cards using a SPI controller instead of
- using a "native" MMC/SD controller. This has a disadvantage of
- being relatively high overhead, but a compensating advantage of
- working on many systems without dedicated MMC/SD controllers.
+ Some systems accss MMC/SD/SDIO cards using a SPI controller
+ instead of using a "native" MMC/SD/SDIO controller. This has a
+ disadvantage of being relatively high overhead, but a compensating
+ advantage of working on many systems without dedicated MMC/SD/SDIO
+ controllers.
If unsure, or if your system has no SPI master driver, say N.
config MMC_S3C
tristate "Samsung S3C SD/MMC Card Interface support"
- depends on ARCH_S3C2410 && MMC
+ depends on ARCH_S3C2410
help
This selects a driver for the MCI interface found in
Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
@@ -166,7 +178,7 @@
config MMC_SDRICOH_CS
tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)"
- depends on EXPERIMENTAL && MMC && PCI && PCMCIA
+ depends on EXPERIMENTAL && PCI && PCMCIA
help
Say Y here if your Notebook reports a Ricoh Bay1Controller PCMCIA
card whenever you insert a MMC or SD card into the card slot.
diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h
index 26bd80e..b58364e 100644
--- a/drivers/mmc/host/atmel-mci-regs.h
+++ b/drivers/mmc/host/atmel-mci-regs.h
@@ -25,8 +25,10 @@
#define MCI_SDCR 0x000c /* SD Card / SDIO */
# define MCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */
# define MCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */
-# define MCI_SDCBUS_1BIT ( 0 << 7) /* 1-bit data bus */
-# define MCI_SDCBUS_4BIT ( 1 << 7) /* 4-bit data bus */
+# define MCI_SDCSEL_MASK ( 3 << 0)
+# define MCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */
+# define MCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */
+# define MCI_SDCBUS_MASK ( 3 << 6)
#define MCI_ARGR 0x0010 /* Command Argument */
#define MCI_CMDR 0x0014 /* Command */
# define MCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 0000896..7a3f243 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -11,6 +11,8 @@
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/init.h>
@@ -33,64 +35,178 @@
#include "atmel-mci-regs.h"
#define ATMCI_DATA_ERROR_FLAGS (MCI_DCRCE | MCI_DTOE | MCI_OVRE | MCI_UNRE)
+#define ATMCI_DMA_THRESHOLD 16
enum {
EVENT_CMD_COMPLETE = 0,
- EVENT_DATA_ERROR,
- EVENT_DATA_COMPLETE,
- EVENT_STOP_SENT,
- EVENT_STOP_COMPLETE,
EVENT_XFER_COMPLETE,
+ EVENT_DATA_COMPLETE,
+ EVENT_DATA_ERROR,
};
+enum atmel_mci_state {
+ STATE_IDLE = 0,
+ STATE_SENDING_CMD,
+ STATE_SENDING_DATA,
+ STATE_DATA_BUSY,
+ STATE_SENDING_STOP,
+ STATE_DATA_ERROR,
+};
+
+struct atmel_mci_dma {
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+ struct dma_client client;
+ struct dma_chan *chan;
+ struct dma_async_tx_descriptor *data_desc;
+#endif
+};
+
+/**
+ * struct atmel_mci - MMC controller state shared between all slots
+ * @lock: Spinlock protecting the queue and associated data.
+ * @regs: Pointer to MMIO registers.
+ * @sg: Scatterlist entry currently being processed by PIO code, if any.
+ * @pio_offset: Offset into the current scatterlist entry.
+ * @cur_slot: The slot which is currently using the controller.
+ * @mrq: The request currently being processed on @cur_slot,
+ * or NULL if the controller is idle.
+ * @cmd: The command currently being sent to the card, or NULL.
+ * @data: The data currently being transferred, or NULL if no data
+ * transfer is in progress.
+ * @dma: DMA client state.
+ * @data_chan: DMA channel being used for the current data transfer.
+ * @cmd_status: Snapshot of SR taken upon completion of the current
+ * command. Only valid when EVENT_CMD_COMPLETE is pending.
+ * @data_status: Snapshot of SR taken upon completion of the current
+ * data transfer. Only valid when EVENT_DATA_COMPLETE or
+ * EVENT_DATA_ERROR is pending.
+ * @stop_cmdr: Value to be loaded into CMDR when the stop command is
+ * to be sent.
+ * @tasklet: Tasklet running the request state machine.
+ * @pending_events: Bitmask of events flagged by the interrupt handler
+ * to be processed by the tasklet.
+ * @completed_events: Bitmask of events which the state machine has
+ * processed.
+ * @state: Tasklet state.
+ * @queue: List of slots waiting for access to the controller.
+ * @need_clock_update: Update the clock rate before the next request.
+ * @need_reset: Reset controller before next request.
+ * @mode_reg: Value of the MR register.
+ * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
+ * rate and timeout calculations.
+ * @mapbase: Physical address of the MMIO registers.
+ * @mck: The peripheral bus clock hooked up to the MMC controller.
+ * @pdev: Platform device associated with the MMC controller.
+ * @slot: Slots sharing this MMC controller.
+ *
+ * Locking
+ * =======
+ *
+ * @lock is a softirq-safe spinlock protecting @queue as well as
+ * @cur_slot, @mrq and @state. These must always be updated
+ * at the same time while holding @lock.
+ *
+ * @lock also protects mode_reg and need_clock_update since these are
+ * used to synchronize mode register updates with the queue
+ * processing.
+ *
+ * The @mrq field of struct atmel_mci_slot is also protected by @lock,
+ * and must always be written at the same time as the slot is added to
+ * @queue.
+ *
+ * @pending_events and @completed_events are accessed using atomic bit
+ * operations, so they don't need any locking.
+ *
+ * None of the fields touched by the interrupt handler need any
+ * locking. However, ordering is important: Before EVENT_DATA_ERROR or
+ * EVENT_DATA_COMPLETE is set in @pending_events, all data-related
+ * interrupts must be disabled and @data_status updated with a
+ * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the
+ * CMDRDY interupt must be disabled and @cmd_status updated with a
+ * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the
+ * bytes_xfered field of @data must be written. This is ensured by
+ * using barriers.
+ */
struct atmel_mci {
- struct mmc_host *mmc;
+ spinlock_t lock;
void __iomem *regs;
struct scatterlist *sg;
unsigned int pio_offset;
+ struct atmel_mci_slot *cur_slot;
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
+ struct atmel_mci_dma dma;
+ struct dma_chan *data_chan;
+
u32 cmd_status;
u32 data_status;
- u32 stop_status;
u32 stop_cmdr;
- u32 mode_reg;
- u32 sdc_reg;
-
struct tasklet_struct tasklet;
unsigned long pending_events;
unsigned long completed_events;
+ enum atmel_mci_state state;
+ struct list_head queue;
- int present;
- int detect_pin;
- int wp_pin;
-
- /* For detect pin debouncing */
- struct timer_list detect_timer;
-
+ bool need_clock_update;
+ bool need_reset;
+ u32 mode_reg;
unsigned long bus_hz;
unsigned long mapbase;
struct clk *mck;
struct platform_device *pdev;
+
+ struct atmel_mci_slot *slot[ATMEL_MCI_MAX_NR_SLOTS];
};
-#define atmci_is_completed(host, event) \
- test_bit(event, &host->completed_events)
+/**
+ * struct atmel_mci_slot - MMC slot state
+ * @mmc: The mmc_host representing this slot.
+ * @host: The MMC controller this slot is using.
+ * @sdc_reg: Value of SDCR to be written before using this slot.
+ * @mrq: mmc_request currently being processed or waiting to be
+ * processed, or NULL when the slot is idle.
+ * @queue_node: List node for placing this node in the @queue list of
+ * &struct atmel_mci.
+ * @clock: Clock rate configured by set_ios(). Protected by host->lock.
+ * @flags: Random state bits associated with the slot.
+ * @detect_pin: GPIO pin used for card detection, or negative if not
+ * available.
+ * @wp_pin: GPIO pin used for card write protect sending, or negative
+ * if not available.
+ * @detect_timer: Timer used for debouncing @detect_pin interrupts.
+ */
+struct atmel_mci_slot {
+ struct mmc_host *mmc;
+ struct atmel_mci *host;
+
+ u32 sdc_reg;
+
+ struct mmc_request *mrq;
+ struct list_head queue_node;
+
+ unsigned int clock;
+ unsigned long flags;
+#define ATMCI_CARD_PRESENT 0
+#define ATMCI_CARD_NEED_INIT 1
+#define ATMCI_SHUTDOWN 2
+
+ int detect_pin;
+ int wp_pin;
+
+ struct timer_list detect_timer;
+};
+
#define atmci_test_and_clear_pending(host, event) \
test_and_clear_bit(event, &host->pending_events)
-#define atmci_test_and_set_completed(host, event) \
- test_and_set_bit(event, &host->completed_events)
#define atmci_set_completed(host, event) \
set_bit(event, &host->completed_events)
#define atmci_set_pending(host, event) \
set_bit(event, &host->pending_events)
-#define atmci_clear_pending(host, event) \
- clear_bit(event, &host->pending_events)
/*
* The debugfs stuff below is mostly optimized away when
@@ -98,14 +214,15 @@
*/
static int atmci_req_show(struct seq_file *s, void *v)
{
- struct atmel_mci *host = s->private;
- struct mmc_request *mrq = host->mrq;
+ struct atmel_mci_slot *slot = s->private;
+ struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_command *stop;
struct mmc_data *data;
/* Make sure we get a consistent snapshot */
- spin_lock_irq(&host->mmc->lock);
+ spin_lock_bh(&slot->host->lock);
+ mrq = slot->mrq;
if (mrq) {
cmd = mrq->cmd;
@@ -130,7 +247,7 @@
stop->resp[2], stop->error);
}
- spin_unlock_irq(&host->mmc->lock);
+ spin_unlock_bh(&slot->host->lock);
return 0;
}
@@ -193,12 +310,16 @@
if (!buf)
return -ENOMEM;
- /* Grab a more or less consistent snapshot */
- spin_lock_irq(&host->mmc->lock);
+ /*
+ * Grab a more or less consistent snapshot. Note that we're
+ * not disabling interrupts, so IMR and SR may not be
+ * consistent.
+ */
+ spin_lock_bh(&host->lock);
clk_enable(host->mck);
memcpy_fromio(buf, host->regs, MCI_REGS_SIZE);
clk_disable(host->mck);
- spin_unlock_irq(&host->mmc->lock);
+ spin_unlock_bh(&host->lock);
seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
buf[MCI_MR / 4],
@@ -236,13 +357,13 @@
.release = single_release,
};
-static void atmci_init_debugfs(struct atmel_mci *host)
+static void atmci_init_debugfs(struct atmel_mci_slot *slot)
{
- struct mmc_host *mmc;
- struct dentry *root;
- struct dentry *node;
+ struct mmc_host *mmc = slot->mmc;
+ struct atmel_mci *host = slot->host;
+ struct dentry *root;
+ struct dentry *node;
- mmc = host->mmc;
root = mmc->debugfs_root;
if (!root)
return;
@@ -254,7 +375,11 @@
if (!node)
goto err;
- node = debugfs_create_file("req", S_IRUSR, root, host, &atmci_req_fops);
+ node = debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
+ if (!node)
+ goto err;
+
+ node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
if (!node)
goto err;
@@ -271,25 +396,7 @@
return;
err:
- dev_err(&host->pdev->dev,
- "failed to initialize debugfs for controller\n");
-}
-
-static void atmci_enable(struct atmel_mci *host)
-{
- clk_enable(host->mck);
- mci_writel(host, CR, MCI_CR_MCIEN);
- mci_writel(host, MR, host->mode_reg);
- mci_writel(host, SDCR, host->sdc_reg);
-}
-
-static void atmci_disable(struct atmel_mci *host)
-{
- mci_writel(host, CR, MCI_CR_SWRST);
-
- /* Stall until write is complete, then disable the bus clock */
- mci_readl(host, SR);
- clk_disable(host->mck);
+ dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
}
static inline unsigned int ns_to_clocks(struct atmel_mci *host,
@@ -299,7 +406,7 @@
}
static void atmci_set_timeout(struct atmel_mci *host,
- struct mmc_data *data)
+ struct atmel_mci_slot *slot, struct mmc_data *data)
{
static unsigned dtomul_to_shift[] = {
0, 4, 7, 8, 10, 12, 16, 20
@@ -322,7 +429,7 @@
dtocyc = 15;
}
- dev_vdbg(&host->mmc->class_dev, "setting timeout to %u cycles\n",
+ dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n",
dtocyc << dtomul_to_shift[dtomul]);
mci_writel(host, DTOR, (MCI_DTOMUL(dtomul) | MCI_DTOCYC(dtocyc)));
}
@@ -375,15 +482,12 @@
}
static void atmci_start_command(struct atmel_mci *host,
- struct mmc_command *cmd,
- u32 cmd_flags)
+ struct mmc_command *cmd, u32 cmd_flags)
{
- /* Must read host->cmd after testing event flags */
- smp_rmb();
WARN_ON(host->cmd);
host->cmd = cmd;
- dev_vdbg(&host->mmc->class_dev,
+ dev_vdbg(&host->pdev->dev,
"start command: ARGR=0x%08x CMDR=0x%08x\n",
cmd->arg, cmd_flags);
@@ -391,34 +495,157 @@
mci_writel(host, CMDR, cmd_flags);
}
-static void send_stop_cmd(struct mmc_host *mmc, struct mmc_data *data)
+static void send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
{
- struct atmel_mci *host = mmc_priv(mmc);
-
atmci_start_command(host, data->stop, host->stop_cmdr);
mci_writel(host, IER, MCI_CMDRDY);
}
-static void atmci_request_end(struct mmc_host *mmc, struct mmc_request *mrq)
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+static void atmci_dma_cleanup(struct atmel_mci *host)
{
- struct atmel_mci *host = mmc_priv(mmc);
+ struct mmc_data *data = host->data;
- WARN_ON(host->cmd || host->data);
- host->mrq = NULL;
-
- atmci_disable(host);
-
- mmc_request_done(mmc, mrq);
+ dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
+ ((data->flags & MMC_DATA_WRITE)
+ ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
}
+static void atmci_stop_dma(struct atmel_mci *host)
+{
+ struct dma_chan *chan = host->data_chan;
+
+ if (chan) {
+ chan->device->device_terminate_all(chan);
+ atmci_dma_cleanup(host);
+ } else {
+ /* Data transfer was stopped by the interrupt handler */
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ mci_writel(host, IER, MCI_NOTBUSY);
+ }
+}
+
+/* This function is called by the DMA driver from tasklet context. */
+static void atmci_dma_complete(void *arg)
+{
+ struct atmel_mci *host = arg;
+ struct mmc_data *data = host->data;
+
+ dev_vdbg(&host->pdev->dev, "DMA complete\n");
+
+ atmci_dma_cleanup(host);
+
+ /*
+ * If the card was removed, data will be NULL. No point trying
+ * to send the stop command or waiting for NBUSY in this case.
+ */
+ if (data) {
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ tasklet_schedule(&host->tasklet);
+
+ /*
+ * Regardless of what the documentation says, we have
+ * to wait for NOTBUSY even after block read
+ * operations.
+ *
+ * When the DMA transfer is complete, the controller
+ * may still be reading the CRC from the card, i.e.
+ * the data transfer is still in progress and we
+ * haven't seen all the potential error bits yet.
+ *
+ * The interrupt handler will schedule a different
+ * tasklet to finish things up when the data transfer
+ * is completely done.
+ *
+ * We may not complete the mmc request here anyway
+ * because the mmc layer may call back and cause us to
+ * violate the "don't submit new operations from the
+ * completion callback" rule of the dma engine
+ * framework.
+ */
+ mci_writel(host, IER, MCI_NOTBUSY);
+ }
+}
+
+static int
+atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+{
+ struct dma_chan *chan;
+ struct dma_async_tx_descriptor *desc;
+ struct scatterlist *sg;
+ unsigned int i;
+ enum dma_data_direction direction;
+
+ /*
+ * We don't do DMA on "complex" transfers, i.e. with
+ * non-word-aligned buffers or lengths. Also, we don't bother
+ * with all the DMA setup overhead for short transfers.
+ */
+ if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD)
+ return -EINVAL;
+ if (data->blksz & 3)
+ return -EINVAL;
+
+ for_each_sg(data->sg, sg, data->sg_len, i) {
+ if (sg->offset & 3 || sg->length & 3)
+ return -EINVAL;
+ }
+
+ /* If we don't have a channel, we can't do DMA */
+ chan = host->dma.chan;
+ if (chan) {
+ dma_chan_get(chan);
+ host->data_chan = chan;
+ }
+
+ if (!chan)
+ return -ENODEV;
+
+ if (data->flags & MMC_DATA_READ)
+ direction = DMA_FROM_DEVICE;
+ else
+ direction = DMA_TO_DEVICE;
+
+ desc = chan->device->device_prep_slave_sg(chan,
+ data->sg, data->sg_len, direction,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc)
+ return -ENOMEM;
+
+ host->dma.data_desc = desc;
+ desc->callback = atmci_dma_complete;
+ desc->callback_param = host;
+ desc->tx_submit(desc);
+
+ /* Go! */
+ chan->device->device_issue_pending(chan);
+
+ return 0;
+}
+
+#else /* CONFIG_MMC_ATMELMCI_DMA */
+
+static int atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+{
+ return -ENOSYS;
+}
+
+static void atmci_stop_dma(struct atmel_mci *host)
+{
+ /* Data transfer was stopped by the interrupt handler */
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ mci_writel(host, IER, MCI_NOTBUSY);
+}
+
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
+
/*
* Returns a mask of interrupt flags to be enabled after the whole
* request has been prepared.
*/
-static u32 atmci_submit_data(struct mmc_host *mmc, struct mmc_data *data)
+static u32 atmci_submit_data(struct atmel_mci *host, struct mmc_data *data)
{
- struct atmel_mci *host = mmc_priv(mmc);
- u32 iflags;
+ u32 iflags;
data->error = -EINPROGRESS;
@@ -426,77 +653,89 @@
host->sg = NULL;
host->data = data;
- dev_vdbg(&mmc->class_dev, "BLKR=0x%08x\n",
- MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz));
-
iflags = ATMCI_DATA_ERROR_FLAGS;
- host->sg = data->sg;
- host->pio_offset = 0;
- if (data->flags & MMC_DATA_READ)
- iflags |= MCI_RXRDY;
- else
- iflags |= MCI_TXRDY;
+ if (atmci_submit_data_dma(host, data)) {
+ host->data_chan = NULL;
+
+ /*
+ * Errata: MMC data write operation with less than 12
+ * bytes is impossible.
+ *
+ * Errata: MCI Transmit Data Register (TDR) FIFO
+ * corruption when length is not multiple of 4.
+ */
+ if (data->blocks * data->blksz < 12
+ || (data->blocks * data->blksz) & 3)
+ host->need_reset = true;
+
+ host->sg = data->sg;
+ host->pio_offset = 0;
+ if (data->flags & MMC_DATA_READ)
+ iflags |= MCI_RXRDY;
+ else
+ iflags |= MCI_TXRDY;
+ }
return iflags;
}
-static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+static void atmci_start_request(struct atmel_mci *host,
+ struct atmel_mci_slot *slot)
{
- struct atmel_mci *host = mmc_priv(mmc);
- struct mmc_data *data;
+ struct mmc_request *mrq;
struct mmc_command *cmd;
+ struct mmc_data *data;
u32 iflags;
- u32 cmdflags = 0;
+ u32 cmdflags;
+
+ mrq = slot->mrq;
+ host->cur_slot = slot;
+ host->mrq = mrq;
+
+ host->pending_events = 0;
+ host->completed_events = 0;
+ host->data_status = 0;
+
+ if (host->need_reset) {
+ mci_writel(host, CR, MCI_CR_SWRST);
+ mci_writel(host, CR, MCI_CR_MCIEN);
+ mci_writel(host, MR, host->mode_reg);
+ host->need_reset = false;
+ }
+ mci_writel(host, SDCR, slot->sdc_reg);
iflags = mci_readl(host, IMR);
if (iflags)
- dev_warn(&mmc->class_dev, "WARNING: IMR=0x%08x\n",
- mci_readl(host, IMR));
+ dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
+ iflags);
- WARN_ON(host->mrq != NULL);
-
- /*
- * We may "know" the card is gone even though there's still an
- * electrical connection. If so, we really need to communicate
- * this to the MMC core since there won't be any more
- * interrupts as the card is completely removed. Otherwise,
- * the MMC core might believe the card is still there even
- * though the card was just removed very slowly.
- */
- if (!host->present) {
- mrq->cmd->error = -ENOMEDIUM;
- mmc_request_done(mmc, mrq);
- return;
+ if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) {
+ /* Send init sequence (74 clock cycles) */
+ mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT);
+ while (!(mci_readl(host, SR) & MCI_CMDRDY))
+ cpu_relax();
}
-
- host->mrq = mrq;
- host->pending_events = 0;
- host->completed_events = 0;
-
- atmci_enable(host);
-
- /* We don't support multiple blocks of weird lengths. */
data = mrq->data;
if (data) {
- if (data->blocks > 1 && data->blksz & 3)
- goto fail;
- atmci_set_timeout(host, data);
+ atmci_set_timeout(host, slot, data);
/* Must set block count/size before sending command */
mci_writel(host, BLKR, MCI_BCNT(data->blocks)
| MCI_BLKLEN(data->blksz));
+ dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n",
+ MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz));
}
iflags = MCI_CMDRDY;
cmd = mrq->cmd;
- cmdflags = atmci_prepare_command(mmc, cmd);
+ cmdflags = atmci_prepare_command(slot->mmc, cmd);
atmci_start_command(host, cmd, cmdflags);
if (data)
- iflags |= atmci_submit_data(mmc, data);
+ iflags |= atmci_submit_data(host, data);
if (mrq->stop) {
- host->stop_cmdr = atmci_prepare_command(mmc, mrq->stop);
+ host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop);
host->stop_cmdr |= MCI_CMDR_STOP_XFER;
if (!(data->flags & MMC_DATA_WRITE))
host->stop_cmdr |= MCI_CMDR_TRDIR_READ;
@@ -513,59 +752,156 @@
* prepared yet.)
*/
mci_writel(host, IER, iflags);
+}
- return;
+static void atmci_queue_request(struct atmel_mci *host,
+ struct atmel_mci_slot *slot, struct mmc_request *mrq)
+{
+ dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
+ host->state);
-fail:
- atmci_disable(host);
- host->mrq = NULL;
- mrq->cmd->error = -EINVAL;
- mmc_request_done(mmc, mrq);
+ spin_lock_bh(&host->lock);
+ slot->mrq = mrq;
+ if (host->state == STATE_IDLE) {
+ host->state = STATE_SENDING_CMD;
+ atmci_start_request(host, slot);
+ } else {
+ list_add_tail(&slot->queue_node, &host->queue);
+ }
+ spin_unlock_bh(&host->lock);
+}
+
+static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct atmel_mci_slot *slot = mmc_priv(mmc);
+ struct atmel_mci *host = slot->host;
+ struct mmc_data *data;
+
+ WARN_ON(slot->mrq);
+
+ /*
+ * We may "know" the card is gone even though there's still an
+ * electrical connection. If so, we really need to communicate
+ * this to the MMC core since there won't be any more
+ * interrupts as the card is completely removed. Otherwise,
+ * the MMC core might believe the card is still there even
+ * though the card was just removed very slowly.
+ */
+ if (!test_bit(ATMCI_CARD_PRESENT, &slot->flags)) {
+ mrq->cmd->error = -ENOMEDIUM;
+ mmc_request_done(mmc, mrq);
+ return;
+ }
+
+ /* We don't support multiple blocks of weird lengths. */
+ data = mrq->data;
+ if (data && data->blocks > 1 && data->blksz & 3) {
+ mrq->cmd->error = -EINVAL;
+ mmc_request_done(mmc, mrq);
+ }
+
+ atmci_queue_request(host, slot, mrq);
}
static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
- struct atmel_mci *host = mmc_priv(mmc);
+ struct atmel_mci_slot *slot = mmc_priv(mmc);
+ struct atmel_mci *host = slot->host;
+ unsigned int i;
+
+ slot->sdc_reg &= ~MCI_SDCBUS_MASK;
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_1:
+ slot->sdc_reg |= MCI_SDCBUS_1BIT;
+ break;
+ case MMC_BUS_WIDTH_4:
+ slot->sdc_reg = MCI_SDCBUS_4BIT;
+ break;
+ }
if (ios->clock) {
+ unsigned int clock_min = ~0U;
u32 clkdiv;
- /* Set clock rate */
- clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * ios->clock) - 1;
+ spin_lock_bh(&host->lock);
+ if (!host->mode_reg) {
+ clk_enable(host->mck);
+ mci_writel(host, CR, MCI_CR_SWRST);
+ mci_writel(host, CR, MCI_CR_MCIEN);
+ }
+
+ /*
+ * Use mirror of ios->clock to prevent race with mmc
+ * core ios update when finding the minimum.
+ */
+ slot->clock = ios->clock;
+ for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+ if (host->slot[i] && host->slot[i]->clock
+ && host->slot[i]->clock < clock_min)
+ clock_min = host->slot[i]->clock;
+ }
+
+ /* Calculate clock divider */
+ clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1;
if (clkdiv > 255) {
dev_warn(&mmc->class_dev,
"clock %u too slow; using %lu\n",
- ios->clock, host->bus_hz / (2 * 256));
+ clock_min, host->bus_hz / (2 * 256));
clkdiv = 255;
}
+ /*
+ * WRPROOF and RDPROOF prevent overruns/underruns by
+ * stopping the clock when the FIFO is full/empty.
+ * This state is not expected to last for long.
+ */
host->mode_reg = MCI_MR_CLKDIV(clkdiv) | MCI_MR_WRPROOF
| MCI_MR_RDPROOF;
- }
- switch (ios->bus_width) {
- case MMC_BUS_WIDTH_1:
- host->sdc_reg = 0;
- break;
- case MMC_BUS_WIDTH_4:
- host->sdc_reg = MCI_SDCBUS_4BIT;
- break;
+ if (list_empty(&host->queue))
+ mci_writel(host, MR, host->mode_reg);
+ else
+ host->need_clock_update = true;
+
+ spin_unlock_bh(&host->lock);
+ } else {
+ bool any_slot_active = false;
+
+ spin_lock_bh(&host->lock);
+ slot->clock = 0;
+ for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+ if (host->slot[i] && host->slot[i]->clock) {
+ any_slot_active = true;
+ break;
+ }
+ }
+ if (!any_slot_active) {
+ mci_writel(host, CR, MCI_CR_MCIDIS);
+ if (host->mode_reg) {
+ mci_readl(host, MR);
+ clk_disable(host->mck);
+ }
+ host->mode_reg = 0;
+ }
+ spin_unlock_bh(&host->lock);
}
switch (ios->power_mode) {
- case MMC_POWER_ON:
- /* Send init sequence (74 clock cycles) */
- atmci_enable(host);
- mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT);
- while (!(mci_readl(host, SR) & MCI_CMDRDY))
- cpu_relax();
- atmci_disable(host);
+ case MMC_POWER_UP:
+ set_bit(ATMCI_CARD_NEED_INIT, &slot->flags);
break;
default:
/*
* TODO: None of the currently available AVR32-based
* boards allow MMC power to be turned off. Implement
* power control when this can be tested properly.
+ *
+ * We also need to hook this into the clock management
+ * somehow so that newly inserted cards aren't
+ * subjected to a fast clock before we have a chance
+ * to figure out what the maximum rate is. Currently,
+ * there's no way to avoid this, and there never will
+ * be for boards that don't support power control.
*/
break;
}
@@ -573,31 +909,82 @@
static int atmci_get_ro(struct mmc_host *mmc)
{
- int read_only = 0;
- struct atmel_mci *host = mmc_priv(mmc);
+ int read_only = -ENOSYS;
+ struct atmel_mci_slot *slot = mmc_priv(mmc);
- if (gpio_is_valid(host->wp_pin)) {
- read_only = gpio_get_value(host->wp_pin);
+ if (gpio_is_valid(slot->wp_pin)) {
+ read_only = gpio_get_value(slot->wp_pin);
dev_dbg(&mmc->class_dev, "card is %s\n",
read_only ? "read-only" : "read-write");
- } else {
- dev_dbg(&mmc->class_dev,
- "no pin for checking read-only switch."
- " Assuming write-enable.\n");
}
return read_only;
}
-static struct mmc_host_ops atmci_ops = {
+static int atmci_get_cd(struct mmc_host *mmc)
+{
+ int present = -ENOSYS;
+ struct atmel_mci_slot *slot = mmc_priv(mmc);
+
+ if (gpio_is_valid(slot->detect_pin)) {
+ present = !gpio_get_value(slot->detect_pin);
+ dev_dbg(&mmc->class_dev, "card is %spresent\n",
+ present ? "" : "not ");
+ }
+
+ return present;
+}
+
+static const struct mmc_host_ops atmci_ops = {
.request = atmci_request,
.set_ios = atmci_set_ios,
.get_ro = atmci_get_ro,
+ .get_cd = atmci_get_cd,
};
-static void atmci_command_complete(struct atmel_mci *host,
- struct mmc_command *cmd, u32 status)
+/* Called with host->lock held */
+static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
+ __releases(&host->lock)
+ __acquires(&host->lock)
{
+ struct atmel_mci_slot *slot = NULL;
+ struct mmc_host *prev_mmc = host->cur_slot->mmc;
+
+ WARN_ON(host->cmd || host->data);
+
+ /*
+ * Update the MMC clock rate if necessary. This may be
+ * necessary if set_ios() is called when a different slot is
+ * busy transfering data.
+ */
+ if (host->need_clock_update)
+ mci_writel(host, MR, host->mode_reg);
+
+ host->cur_slot->mrq = NULL;
+ host->mrq = NULL;
+ if (!list_empty(&host->queue)) {
+ slot = list_entry(host->queue.next,
+ struct atmel_mci_slot, queue_node);
+ list_del(&slot->queue_node);
+ dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
+ mmc_hostname(slot->mmc));
+ host->state = STATE_SENDING_CMD;
+ atmci_start_request(host, slot);
+ } else {
+ dev_vdbg(&host->pdev->dev, "list empty\n");
+ host->state = STATE_IDLE;
+ }
+
+ spin_unlock(&host->lock);
+ mmc_request_done(prev_mmc, mrq);
+ spin_lock(&host->lock);
+}
+
+static void atmci_command_complete(struct atmel_mci *host,
+ struct mmc_command *cmd)
+{
+ u32 status = host->cmd_status;
+
/* Read the response from the card (up to 16 bytes) */
cmd->resp[0] = mci_readl(host, RSPR);
cmd->resp[1] = mci_readl(host, RSPR);
@@ -614,11 +1001,12 @@
cmd->error = 0;
if (cmd->error) {
- dev_dbg(&host->mmc->class_dev,
+ dev_dbg(&host->pdev->dev,
"command error: status=0x%08x\n", status);
if (cmd->data) {
host->data = NULL;
+ atmci_stop_dma(host);
mci_writel(host, IDR, MCI_NOTBUSY
| MCI_TXRDY | MCI_RXRDY
| ATMCI_DATA_ERROR_FLAGS);
@@ -628,146 +1016,222 @@
static void atmci_detect_change(unsigned long data)
{
- struct atmel_mci *host = (struct atmel_mci *)data;
- struct mmc_request *mrq = host->mrq;
- int present;
+ struct atmel_mci_slot *slot = (struct atmel_mci_slot *)data;
+ bool present;
+ bool present_old;
/*
- * atmci_remove() sets detect_pin to -1 before freeing the
- * interrupt. We must not re-enable the interrupt if it has
- * been freed.
+ * atmci_cleanup_slot() sets the ATMCI_SHUTDOWN flag before
+ * freeing the interrupt. We must not re-enable the interrupt
+ * if it has been freed, and if we're shutting down, it
+ * doesn't really matter whether the card is present or not.
*/
smp_rmb();
- if (!gpio_is_valid(host->detect_pin))
+ if (test_bit(ATMCI_SHUTDOWN, &slot->flags))
return;
- enable_irq(gpio_to_irq(host->detect_pin));
- present = !gpio_get_value(host->detect_pin);
+ enable_irq(gpio_to_irq(slot->detect_pin));
+ present = !gpio_get_value(slot->detect_pin);
+ present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags);
- dev_vdbg(&host->pdev->dev, "detect change: %d (was %d)\n",
- present, host->present);
+ dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n",
+ present, present_old);
- if (present != host->present) {
- dev_dbg(&host->mmc->class_dev, "card %s\n",
+ if (present != present_old) {
+ struct atmel_mci *host = slot->host;
+ struct mmc_request *mrq;
+
+ dev_dbg(&slot->mmc->class_dev, "card %s\n",
present ? "inserted" : "removed");
- host->present = present;
- /* Reset controller if card is gone */
- if (!present) {
- mci_writel(host, CR, MCI_CR_SWRST);
- mci_writel(host, IDR, ~0UL);
- mci_writel(host, CR, MCI_CR_MCIEN);
- }
+ spin_lock(&host->lock);
+
+ if (!present)
+ clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
+ else
+ set_bit(ATMCI_CARD_PRESENT, &slot->flags);
/* Clean up queue if present */
+ mrq = slot->mrq;
if (mrq) {
- /*
- * Reset controller to terminate any ongoing
- * commands or data transfers.
- */
- mci_writel(host, CR, MCI_CR_SWRST);
+ if (mrq == host->mrq) {
+ /*
+ * Reset controller to terminate any ongoing
+ * commands or data transfers.
+ */
+ mci_writel(host, CR, MCI_CR_SWRST);
+ mci_writel(host, CR, MCI_CR_MCIEN);
+ mci_writel(host, MR, host->mode_reg);
- if (!atmci_is_completed(host, EVENT_CMD_COMPLETE))
- mrq->cmd->error = -ENOMEDIUM;
-
- if (mrq->data && !atmci_is_completed(host,
- EVENT_DATA_COMPLETE)) {
host->data = NULL;
- mrq->data->error = -ENOMEDIUM;
+ host->cmd = NULL;
+
+ switch (host->state) {
+ case STATE_IDLE:
+ break;
+ case STATE_SENDING_CMD:
+ mrq->cmd->error = -ENOMEDIUM;
+ if (!mrq->data)
+ break;
+ /* fall through */
+ case STATE_SENDING_DATA:
+ mrq->data->error = -ENOMEDIUM;
+ atmci_stop_dma(host);
+ break;
+ case STATE_DATA_BUSY:
+ case STATE_DATA_ERROR:
+ if (mrq->data->error == -EINPROGRESS)
+ mrq->data->error = -ENOMEDIUM;
+ if (!mrq->stop)
+ break;
+ /* fall through */
+ case STATE_SENDING_STOP:
+ mrq->stop->error = -ENOMEDIUM;
+ break;
+ }
+
+ atmci_request_end(host, mrq);
+ } else {
+ list_del(&slot->queue_node);
+ mrq->cmd->error = -ENOMEDIUM;
+ if (mrq->data)
+ mrq->data->error = -ENOMEDIUM;
+ if (mrq->stop)
+ mrq->stop->error = -ENOMEDIUM;
+
+ spin_unlock(&host->lock);
+ mmc_request_done(slot->mmc, mrq);
+ spin_lock(&host->lock);
}
- if (mrq->stop && !atmci_is_completed(host,
- EVENT_STOP_COMPLETE))
- mrq->stop->error = -ENOMEDIUM;
-
- host->cmd = NULL;
- atmci_request_end(host->mmc, mrq);
}
+ spin_unlock(&host->lock);
- mmc_detect_change(host->mmc, 0);
+ mmc_detect_change(slot->mmc, 0);
}
}
static void atmci_tasklet_func(unsigned long priv)
{
- struct mmc_host *mmc = (struct mmc_host *)priv;
- struct atmel_mci *host = mmc_priv(mmc);
+ struct atmel_mci *host = (struct atmel_mci *)priv;
struct mmc_request *mrq = host->mrq;
struct mmc_data *data = host->data;
+ struct mmc_command *cmd = host->cmd;
+ enum atmel_mci_state state = host->state;
+ enum atmel_mci_state prev_state;
+ u32 status;
- dev_vdbg(&mmc->class_dev,
- "tasklet: pending/completed/mask %lx/%lx/%x\n",
- host->pending_events, host->completed_events,
+ spin_lock(&host->lock);
+
+ state = host->state;
+
+ dev_vdbg(&host->pdev->dev,
+ "tasklet: state %u pending/completed/mask %lx/%lx/%x\n",
+ state, host->pending_events, host->completed_events,
mci_readl(host, IMR));
- if (atmci_test_and_clear_pending(host, EVENT_CMD_COMPLETE)) {
- /*
- * host->cmd must be set to NULL before the interrupt
- * handler sees EVENT_CMD_COMPLETE
- */
- host->cmd = NULL;
- smp_wmb();
- atmci_set_completed(host, EVENT_CMD_COMPLETE);
- atmci_command_complete(host, mrq->cmd, host->cmd_status);
+ do {
+ prev_state = state;
- if (!mrq->cmd->error && mrq->stop
- && atmci_is_completed(host, EVENT_XFER_COMPLETE)
- && !atmci_test_and_set_completed(host,
- EVENT_STOP_SENT))
- send_stop_cmd(host->mmc, mrq->data);
- }
- if (atmci_test_and_clear_pending(host, EVENT_STOP_COMPLETE)) {
- /*
- * host->cmd must be set to NULL before the interrupt
- * handler sees EVENT_STOP_COMPLETE
- */
- host->cmd = NULL;
- smp_wmb();
- atmci_set_completed(host, EVENT_STOP_COMPLETE);
- atmci_command_complete(host, mrq->stop, host->stop_status);
- }
- if (atmci_test_and_clear_pending(host, EVENT_DATA_ERROR)) {
- u32 status = host->data_status;
+ switch (state) {
+ case STATE_IDLE:
+ break;
- dev_vdbg(&mmc->class_dev, "data error: status=%08x\n", status);
+ case STATE_SENDING_CMD:
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_CMD_COMPLETE))
+ break;
- atmci_set_completed(host, EVENT_DATA_ERROR);
- atmci_set_completed(host, EVENT_DATA_COMPLETE);
+ host->cmd = NULL;
+ atmci_set_completed(host, EVENT_CMD_COMPLETE);
+ atmci_command_complete(host, mrq->cmd);
+ if (!mrq->data || cmd->error) {
+ atmci_request_end(host, host->mrq);
+ goto unlock;
+ }
- if (status & MCI_DTOE) {
- dev_dbg(&mmc->class_dev,
- "data timeout error\n");
- data->error = -ETIMEDOUT;
- } else if (status & MCI_DCRCE) {
- dev_dbg(&mmc->class_dev, "data CRC error\n");
- data->error = -EILSEQ;
- } else {
- dev_dbg(&mmc->class_dev,
- "data FIFO error (status=%08x)\n",
- status);
- data->error = -EIO;
+ prev_state = state = STATE_SENDING_DATA;
+ /* fall through */
+
+ case STATE_SENDING_DATA:
+ if (atmci_test_and_clear_pending(host,
+ EVENT_DATA_ERROR)) {
+ atmci_stop_dma(host);
+ if (data->stop)
+ send_stop_cmd(host, data);
+ state = STATE_DATA_ERROR;
+ break;
+ }
+
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_XFER_COMPLETE))
+ break;
+
+ atmci_set_completed(host, EVENT_XFER_COMPLETE);
+ prev_state = state = STATE_DATA_BUSY;
+ /* fall through */
+
+ case STATE_DATA_BUSY:
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_DATA_COMPLETE))
+ break;
+
+ host->data = NULL;
+ atmci_set_completed(host, EVENT_DATA_COMPLETE);
+ status = host->data_status;
+ if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) {
+ if (status & MCI_DTOE) {
+ dev_dbg(&host->pdev->dev,
+ "data timeout error\n");
+ data->error = -ETIMEDOUT;
+ } else if (status & MCI_DCRCE) {
+ dev_dbg(&host->pdev->dev,
+ "data CRC error\n");
+ data->error = -EILSEQ;
+ } else {
+ dev_dbg(&host->pdev->dev,
+ "data FIFO error (status=%08x)\n",
+ status);
+ data->error = -EIO;
+ }
+ } else {
+ data->bytes_xfered = data->blocks * data->blksz;
+ data->error = 0;
+ }
+
+ if (!data->stop) {
+ atmci_request_end(host, host->mrq);
+ goto unlock;
+ }
+
+ prev_state = state = STATE_SENDING_STOP;
+ if (!data->error)
+ send_stop_cmd(host, data);
+ /* fall through */
+
+ case STATE_SENDING_STOP:
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_CMD_COMPLETE))
+ break;
+
+ host->cmd = NULL;
+ atmci_command_complete(host, mrq->stop);
+ atmci_request_end(host, host->mrq);
+ goto unlock;
+
+ case STATE_DATA_ERROR:
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_XFER_COMPLETE))
+ break;
+
+ state = STATE_DATA_BUSY;
+ break;
}
+ } while (state != prev_state);
- if (host->present && data->stop
- && atmci_is_completed(host, EVENT_CMD_COMPLETE)
- && !atmci_test_and_set_completed(
- host, EVENT_STOP_SENT))
- send_stop_cmd(host->mmc, data);
+ host->state = state;
- host->data = NULL;
- }
- if (atmci_test_and_clear_pending(host, EVENT_DATA_COMPLETE)) {
- atmci_set_completed(host, EVENT_DATA_COMPLETE);
-
- if (!atmci_is_completed(host, EVENT_DATA_ERROR)) {
- data->bytes_xfered = data->blocks * data->blksz;
- data->error = 0;
- }
-
- host->data = NULL;
- }
-
- if (host->mrq && !host->cmd && !host->data)
- atmci_request_end(mmc, host->mrq);
+unlock:
+ spin_unlock(&host->lock);
}
static void atmci_read_data_pio(struct atmel_mci *host)
@@ -789,6 +1253,7 @@
nbytes += 4;
if (offset == sg->length) {
+ flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg);
if (!sg)
goto done;
@@ -817,9 +1282,11 @@
mci_writel(host, IDR, (MCI_NOTBUSY | MCI_RXRDY
| ATMCI_DATA_ERROR_FLAGS));
host->data_status = status;
+ data->bytes_xfered += nbytes;
+ smp_wmb();
atmci_set_pending(host, EVENT_DATA_ERROR);
tasklet_schedule(&host->tasklet);
- break;
+ return;
}
} while (status & MCI_RXRDY);
@@ -832,10 +1299,8 @@
mci_writel(host, IDR, MCI_RXRDY);
mci_writel(host, IER, MCI_NOTBUSY);
data->bytes_xfered += nbytes;
- atmci_set_completed(host, EVENT_XFER_COMPLETE);
- if (data->stop && atmci_is_completed(host, EVENT_CMD_COMPLETE)
- && !atmci_test_and_set_completed(host, EVENT_STOP_SENT))
- send_stop_cmd(host->mmc, data);
+ smp_wmb();
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
}
static void atmci_write_data_pio(struct atmel_mci *host)
@@ -888,9 +1353,11 @@
mci_writel(host, IDR, (MCI_NOTBUSY | MCI_TXRDY
| ATMCI_DATA_ERROR_FLAGS));
host->data_status = status;
+ data->bytes_xfered += nbytes;
+ smp_wmb();
atmci_set_pending(host, EVENT_DATA_ERROR);
tasklet_schedule(&host->tasklet);
- break;
+ return;
}
} while (status & MCI_TXRDY);
@@ -903,38 +1370,26 @@
mci_writel(host, IDR, MCI_TXRDY);
mci_writel(host, IER, MCI_NOTBUSY);
data->bytes_xfered += nbytes;
- atmci_set_completed(host, EVENT_XFER_COMPLETE);
- if (data->stop && atmci_is_completed(host, EVENT_CMD_COMPLETE)
- && !atmci_test_and_set_completed(host, EVENT_STOP_SENT))
- send_stop_cmd(host->mmc, data);
+ smp_wmb();
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
}
-static void atmci_cmd_interrupt(struct mmc_host *mmc, u32 status)
+static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
{
- struct atmel_mci *host = mmc_priv(mmc);
-
mci_writel(host, IDR, MCI_CMDRDY);
- if (atmci_is_completed(host, EVENT_STOP_SENT)) {
- host->stop_status = status;
- atmci_set_pending(host, EVENT_STOP_COMPLETE);
- } else {
- host->cmd_status = status;
- atmci_set_pending(host, EVENT_CMD_COMPLETE);
- }
-
+ host->cmd_status = status;
+ smp_wmb();
+ atmci_set_pending(host, EVENT_CMD_COMPLETE);
tasklet_schedule(&host->tasklet);
}
static irqreturn_t atmci_interrupt(int irq, void *dev_id)
{
- struct mmc_host *mmc = dev_id;
- struct atmel_mci *host = mmc_priv(mmc);
+ struct atmel_mci *host = dev_id;
u32 status, mask, pending;
unsigned int pass_count = 0;
- spin_lock(&mmc->lock);
-
do {
status = mci_readl(host, SR);
mask = mci_readl(host, IMR);
@@ -946,13 +1401,18 @@
mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS
| MCI_RXRDY | MCI_TXRDY);
pending &= mci_readl(host, IMR);
+
host->data_status = status;
+ smp_wmb();
atmci_set_pending(host, EVENT_DATA_ERROR);
tasklet_schedule(&host->tasklet);
}
if (pending & MCI_NOTBUSY) {
- mci_writel(host, IDR, (MCI_NOTBUSY
- | ATMCI_DATA_ERROR_FLAGS));
+ mci_writel(host, IDR,
+ ATMCI_DATA_ERROR_FLAGS | MCI_NOTBUSY);
+ if (!host->data_status)
+ host->data_status = status;
+ smp_wmb();
atmci_set_pending(host, EVENT_DATA_COMPLETE);
tasklet_schedule(&host->tasklet);
}
@@ -962,18 +1422,15 @@
atmci_write_data_pio(host);
if (pending & MCI_CMDRDY)
- atmci_cmd_interrupt(mmc, status);
+ atmci_cmd_interrupt(host, status);
} while (pass_count++ < 5);
- spin_unlock(&mmc->lock);
-
return pass_count ? IRQ_HANDLED : IRQ_NONE;
}
static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
{
- struct mmc_host *mmc = dev_id;
- struct atmel_mci *host = mmc_priv(mmc);
+ struct atmel_mci_slot *slot = dev_id;
/*
* Disable interrupts until the pin has stabilized and check
@@ -981,19 +1438,176 @@
* middle of the timer routine when this interrupt triggers.
*/
disable_irq_nosync(irq);
- mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
+ mod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20));
return IRQ_HANDLED;
}
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+
+static inline struct atmel_mci *
+dma_client_to_atmel_mci(struct dma_client *client)
+{
+ return container_of(client, struct atmel_mci, dma.client);
+}
+
+static enum dma_state_client atmci_dma_event(struct dma_client *client,
+ struct dma_chan *chan, enum dma_state state)
+{
+ struct atmel_mci *host;
+ enum dma_state_client ret = DMA_NAK;
+
+ host = dma_client_to_atmel_mci(client);
+
+ switch (state) {
+ case DMA_RESOURCE_AVAILABLE:
+ spin_lock_bh(&host->lock);
+ if (!host->dma.chan) {
+ host->dma.chan = chan;
+ ret = DMA_ACK;
+ }
+ spin_unlock_bh(&host->lock);
+
+ if (ret == DMA_ACK)
+ dev_info(&host->pdev->dev,
+ "Using %s for DMA transfers\n",
+ chan->dev.bus_id);
+ break;
+
+ case DMA_RESOURCE_REMOVED:
+ spin_lock_bh(&host->lock);
+ if (host->dma.chan == chan) {
+ host->dma.chan = NULL;
+ ret = DMA_ACK;
+ }
+ spin_unlock_bh(&host->lock);
+
+ if (ret == DMA_ACK)
+ dev_info(&host->pdev->dev,
+ "Lost %s, falling back to PIO\n",
+ chan->dev.bus_id);
+ break;
+
+ default:
+ break;
+ }
+
+
+ return ret;
+}
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
+
+static int __init atmci_init_slot(struct atmel_mci *host,
+ struct mci_slot_pdata *slot_data, unsigned int id,
+ u32 sdc_reg)
+{
+ struct mmc_host *mmc;
+ struct atmel_mci_slot *slot;
+
+ mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev);
+ if (!mmc)
+ return -ENOMEM;
+
+ slot = mmc_priv(mmc);
+ slot->mmc = mmc;
+ slot->host = host;
+ slot->detect_pin = slot_data->detect_pin;
+ slot->wp_pin = slot_data->wp_pin;
+ slot->sdc_reg = sdc_reg;
+
+ mmc->ops = &atmci_ops;
+ mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
+ mmc->f_max = host->bus_hz / 2;
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+ if (slot_data->bus_width >= 4)
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+ mmc->max_hw_segs = 64;
+ mmc->max_phys_segs = 64;
+ mmc->max_req_size = 32768 * 512;
+ mmc->max_blk_size = 32768;
+ mmc->max_blk_count = 512;
+
+ /* Assume card is present initially */
+ set_bit(ATMCI_CARD_PRESENT, &slot->flags);
+ if (gpio_is_valid(slot->detect_pin)) {
+ if (gpio_request(slot->detect_pin, "mmc_detect")) {
+ dev_dbg(&mmc->class_dev, "no detect pin available\n");
+ slot->detect_pin = -EBUSY;
+ } else if (gpio_get_value(slot->detect_pin)) {
+ clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
+ }
+ }
+
+ if (!gpio_is_valid(slot->detect_pin))
+ mmc->caps |= MMC_CAP_NEEDS_POLL;
+
+ if (gpio_is_valid(slot->wp_pin)) {
+ if (gpio_request(slot->wp_pin, "mmc_wp")) {
+ dev_dbg(&mmc->class_dev, "no WP pin available\n");
+ slot->wp_pin = -EBUSY;
+ }
+ }
+
+ host->slot[id] = slot;
+ mmc_add_host(mmc);
+
+ if (gpio_is_valid(slot->detect_pin)) {
+ int ret;
+
+ setup_timer(&slot->detect_timer, atmci_detect_change,
+ (unsigned long)slot);
+
+ ret = request_irq(gpio_to_irq(slot->detect_pin),
+ atmci_detect_interrupt,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "mmc-detect", slot);
+ if (ret) {
+ dev_dbg(&mmc->class_dev,
+ "could not request IRQ %d for detect pin\n",
+ gpio_to_irq(slot->detect_pin));
+ gpio_free(slot->detect_pin);
+ slot->detect_pin = -EBUSY;
+ }
+ }
+
+ atmci_init_debugfs(slot);
+
+ return 0;
+}
+
+static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
+ unsigned int id)
+{
+ /* Debugfs stuff is cleaned up by mmc core */
+
+ set_bit(ATMCI_SHUTDOWN, &slot->flags);
+ smp_wmb();
+
+ mmc_remove_host(slot->mmc);
+
+ if (gpio_is_valid(slot->detect_pin)) {
+ int pin = slot->detect_pin;
+
+ free_irq(gpio_to_irq(pin), slot);
+ del_timer_sync(&slot->detect_timer);
+ gpio_free(pin);
+ }
+ if (gpio_is_valid(slot->wp_pin))
+ gpio_free(slot->wp_pin);
+
+ slot->host->slot[id] = NULL;
+ mmc_free_host(slot->mmc);
+}
+
static int __init atmci_probe(struct platform_device *pdev)
{
struct mci_platform_data *pdata;
- struct atmel_mci *host;
- struct mmc_host *mmc;
- struct resource *regs;
- int irq;
- int ret;
+ struct atmel_mci *host;
+ struct resource *regs;
+ unsigned int nr_slots;
+ int irq;
+ int ret;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
@@ -1005,15 +1619,13 @@
if (irq < 0)
return irq;
- mmc = mmc_alloc_host(sizeof(struct atmel_mci), &pdev->dev);
- if (!mmc)
+ host = kzalloc(sizeof(struct atmel_mci), GFP_KERNEL);
+ if (!host)
return -ENOMEM;
- host = mmc_priv(mmc);
host->pdev = pdev;
- host->mmc = mmc;
- host->detect_pin = pdata->detect_pin;
- host->wp_pin = pdata->wp_pin;
+ spin_lock_init(&host->lock);
+ INIT_LIST_HEAD(&host->queue);
host->mck = clk_get(&pdev->dev, "mci_clk");
if (IS_ERR(host->mck)) {
@@ -1033,122 +1645,102 @@
host->mapbase = regs->start;
- mmc->ops = &atmci_ops;
- mmc->f_min = (host->bus_hz + 511) / 512;
- mmc->f_max = host->bus_hz / 2;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps |= MMC_CAP_4_BIT_DATA;
+ tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
- mmc->max_hw_segs = 64;
- mmc->max_phys_segs = 64;
- mmc->max_req_size = 32768 * 512;
- mmc->max_blk_size = 32768;
- mmc->max_blk_count = 512;
-
- tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)mmc);
-
- ret = request_irq(irq, atmci_interrupt, 0, pdev->dev.bus_id, mmc);
+ ret = request_irq(irq, atmci_interrupt, 0, pdev->dev.bus_id, host);
if (ret)
goto err_request_irq;
- /* Assume card is present if we don't have a detect pin */
- host->present = 1;
- if (gpio_is_valid(host->detect_pin)) {
- if (gpio_request(host->detect_pin, "mmc_detect")) {
- dev_dbg(&mmc->class_dev, "no detect pin available\n");
- host->detect_pin = -1;
- } else {
- host->present = !gpio_get_value(host->detect_pin);
- }
- }
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+ if (pdata->dma_slave) {
+ struct dma_slave *slave = pdata->dma_slave;
- if (!gpio_is_valid(host->detect_pin))
- mmc->caps |= MMC_CAP_NEEDS_POLL;
+ slave->tx_reg = regs->start + MCI_TDR;
+ slave->rx_reg = regs->start + MCI_RDR;
- if (gpio_is_valid(host->wp_pin)) {
- if (gpio_request(host->wp_pin, "mmc_wp")) {
- dev_dbg(&mmc->class_dev, "no WP pin available\n");
- host->wp_pin = -1;
- }
+ /* Try to grab a DMA channel */
+ host->dma.client.event_callback = atmci_dma_event;
+ dma_cap_set(DMA_SLAVE, host->dma.client.cap_mask);
+ host->dma.client.slave = slave;
+
+ dma_async_client_register(&host->dma.client);
+ dma_async_client_chan_request(&host->dma.client);
+ } else {
+ dev_notice(&pdev->dev, "DMA not available, using PIO\n");
}
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
platform_set_drvdata(pdev, host);
- mmc_add_host(mmc);
-
- if (gpio_is_valid(host->detect_pin)) {
- setup_timer(&host->detect_timer, atmci_detect_change,
- (unsigned long)host);
-
- ret = request_irq(gpio_to_irq(host->detect_pin),
- atmci_detect_interrupt,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "mmc-detect", mmc);
- if (ret) {
- dev_dbg(&mmc->class_dev,
- "could not request IRQ %d for detect pin\n",
- gpio_to_irq(host->detect_pin));
- gpio_free(host->detect_pin);
- host->detect_pin = -1;
- }
+ /* We need at least one slot to succeed */
+ nr_slots = 0;
+ ret = -ENODEV;
+ if (pdata->slot[0].bus_width) {
+ ret = atmci_init_slot(host, &pdata->slot[0],
+ MCI_SDCSEL_SLOT_A, 0);
+ if (!ret)
+ nr_slots++;
+ }
+ if (pdata->slot[1].bus_width) {
+ ret = atmci_init_slot(host, &pdata->slot[1],
+ MCI_SDCSEL_SLOT_B, 1);
+ if (!ret)
+ nr_slots++;
}
- dev_info(&mmc->class_dev,
- "Atmel MCI controller at 0x%08lx irq %d\n",
- host->mapbase, irq);
+ if (!nr_slots)
+ goto err_init_slot;
- atmci_init_debugfs(host);
+ dev_info(&pdev->dev,
+ "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
+ host->mapbase, irq, nr_slots);
return 0;
+err_init_slot:
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+ if (pdata->dma_slave)
+ dma_async_client_unregister(&host->dma.client);
+#endif
+ free_irq(irq, host);
err_request_irq:
iounmap(host->regs);
err_ioremap:
clk_put(host->mck);
err_clk_get:
- mmc_free_host(mmc);
+ kfree(host);
return ret;
}
static int __exit atmci_remove(struct platform_device *pdev)
{
- struct atmel_mci *host = platform_get_drvdata(pdev);
+ struct atmel_mci *host = platform_get_drvdata(pdev);
+ unsigned int i;
platform_set_drvdata(pdev, NULL);
- if (host) {
- /* Debugfs stuff is cleaned up by mmc core */
-
- if (gpio_is_valid(host->detect_pin)) {
- int pin = host->detect_pin;
-
- /* Make sure the timer doesn't enable the interrupt */
- host->detect_pin = -1;
- smp_wmb();
-
- free_irq(gpio_to_irq(pin), host->mmc);
- del_timer_sync(&host->detect_timer);
- gpio_free(pin);
- }
-
- mmc_remove_host(host->mmc);
-
- clk_enable(host->mck);
- mci_writel(host, IDR, ~0UL);
- mci_writel(host, CR, MCI_CR_MCIDIS);
- mci_readl(host, SR);
- clk_disable(host->mck);
-
- if (gpio_is_valid(host->wp_pin))
- gpio_free(host->wp_pin);
-
- free_irq(platform_get_irq(pdev, 0), host->mmc);
- iounmap(host->regs);
-
- clk_put(host->mck);
-
- mmc_free_host(host->mmc);
+ for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+ if (host->slot[i])
+ atmci_cleanup_slot(host->slot[i], i);
}
+
+ clk_enable(host->mck);
+ mci_writel(host, IDR, ~0UL);
+ mci_writel(host, CR, MCI_CR_MCIDIS);
+ mci_readl(host, SR);
+ clk_disable(host->mck);
+
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+ if (host->dma.client.slave)
+ dma_async_client_unregister(&host->dma.client);
+#endif
+
+ free_irq(platform_get_irq(pdev, 0), host);
+ iounmap(host->regs);
+
+ clk_put(host->mck);
+ kfree(host);
+
return 0;
}
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 7503b81..07faf54 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -95,8 +95,6 @@
* reads which takes nowhere near that long. Older cards may be able to use
* shorter timeouts ... but why bother?
*/
-#define readblock_timeout ktime_set(0, 100 * 1000 * 1000)
-#define writeblock_timeout ktime_set(0, 250 * 1000 * 1000)
#define r1b_timeout ktime_set(3, 0)
@@ -220,9 +218,9 @@
return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);
}
-static int mmc_spi_readtoken(struct mmc_spi_host *host)
+static int mmc_spi_readtoken(struct mmc_spi_host *host, ktime_t timeout)
{
- return mmc_spi_skip(host, readblock_timeout, 1, 0xff);
+ return mmc_spi_skip(host, timeout, 1, 0xff);
}
@@ -605,7 +603,8 @@
* Return negative errno, else success.
*/
static int
-mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
+mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
+ ktime_t timeout)
{
struct spi_device *spi = host->spi;
int status, i;
@@ -673,7 +672,7 @@
if (scratch->status[i] != 0)
return 0;
}
- return mmc_spi_wait_unbusy(host, writeblock_timeout);
+ return mmc_spi_wait_unbusy(host, timeout);
}
/*
@@ -693,7 +692,8 @@
* STOP_TRANSMISSION command.
*/
static int
-mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
+mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
+ ktime_t timeout)
{
struct spi_device *spi = host->spi;
int status;
@@ -707,7 +707,7 @@
return status;
status = scratch->status[0];
if (status == 0xff || status == 0)
- status = mmc_spi_readtoken(host);
+ status = mmc_spi_readtoken(host, timeout);
if (status == SPI_TOKEN_SINGLE) {
if (host->dma_dev) {
@@ -778,6 +778,8 @@
struct scatterlist *sg;
unsigned n_sg;
int multiple = (data->blocks > 1);
+ u32 clock_rate;
+ ktime_t timeout;
if (data->flags & MMC_DATA_READ)
direction = DMA_FROM_DEVICE;
@@ -786,6 +788,14 @@
mmc_spi_setup_data_message(host, multiple, direction);
t = &host->t;
+ if (t->speed_hz)
+ clock_rate = t->speed_hz;
+ else
+ clock_rate = spi->max_speed_hz;
+
+ timeout = ktime_add_ns(ktime_set(0, 0), data->timeout_ns +
+ data->timeout_clks * 1000000 / clock_rate);
+
/* Handle scatterlist segments one at a time, with synch for
* each 512-byte block
*/
@@ -832,9 +842,9 @@
t->len);
if (direction == DMA_TO_DEVICE)
- status = mmc_spi_writeblock(host, t);
+ status = mmc_spi_writeblock(host, t, timeout);
else
- status = mmc_spi_readblock(host, t);
+ status = mmc_spi_readblock(host, t, timeout);
if (status < 0)
break;
@@ -917,7 +927,7 @@
if (scratch->status[tmp] != 0)
return;
}
- tmp = mmc_spi_wait_unbusy(host, writeblock_timeout);
+ tmp = mmc_spi_wait_unbusy(host, timeout);
if (tmp < 0 && !data->error)
data->error = tmp;
}
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index fcb14c2..0a84f10 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -144,7 +144,8 @@
SDHCI_QUIRK_32BIT_DMA_SIZE |
SDHCI_QUIRK_32BIT_ADMA_SIZE |
SDHCI_QUIRK_RESET_AFTER_REQUEST |
- SDHCI_QUIRK_BROKEN_SMALL_PIO;
+ SDHCI_QUIRK_BROKEN_SMALL_PIO |
+ SDHCI_QUIRK_FORCE_HIGHSPEED;
}
/*
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index e3a8133..30f64b1 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -177,7 +177,7 @@
{
unsigned long flags;
size_t blksize, len, chunk;
- u32 scratch;
+ u32 uninitialized_var(scratch);
u8 *buf;
DBG("PIO reading\n");
@@ -1154,7 +1154,7 @@
spin_unlock_irqrestore(&host->lock, flags);
- mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+ mmc_detect_change(host->mmc, msecs_to_jiffies(200));
}
static void sdhci_tasklet_finish(unsigned long param)
@@ -1266,9 +1266,31 @@
SDHCI_INT_INDEX))
host->cmd->error = -EILSEQ;
- if (host->cmd->error)
+ if (host->cmd->error) {
tasklet_schedule(&host->finish_tasklet);
- else if (intmask & SDHCI_INT_RESPONSE)
+ return;
+ }
+
+ /*
+ * The host can send and interrupt when the busy state has
+ * ended, allowing us to wait without wasting CPU cycles.
+ * Unfortunately this is overloaded on the "data complete"
+ * interrupt, so we need to take some care when handling
+ * it.
+ *
+ * Note: The 1.0 specification is a bit ambiguous about this
+ * feature so there might be some problems with older
+ * controllers.
+ */
+ if (host->cmd->flags & MMC_RSP_BUSY) {
+ if (host->cmd->data)
+ DBG("Cannot wait for busy signal when also "
+ "doing a data transfer");
+ else
+ return;
+ }
+
+ if (intmask & SDHCI_INT_RESPONSE)
sdhci_finish_command(host);
}
@@ -1278,11 +1300,16 @@
if (!host->data) {
/*
- * A data end interrupt is sent together with the response
- * for the stop command.
+ * The "data complete" interrupt is also used to
+ * indicate that a busy state has ended. See comment
+ * above in sdhci_cmd_irq().
*/
- if (intmask & SDHCI_INT_DATA_END)
- return;
+ if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
+ if (intmask & SDHCI_INT_DATA_END) {
+ sdhci_finish_command(host);
+ return;
+ }
+ }
printk(KERN_ERR "%s: Got data interrupt 0x%08x even "
"though no data operation was in progress.\n",
@@ -1604,7 +1631,8 @@
mmc->f_max = host->max_clk;
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
- if (caps & SDHCI_CAN_DO_HISPD)
+ if ((caps & SDHCI_CAN_DO_HISPD) ||
+ (host->quirks & SDHCI_QUIRK_FORCE_HIGHSPEED))
mmc->caps |= MMC_CAP_SD_HIGHSPEED;
mmc->ocr_avail = 0;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 197d4a0..31f4b15 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -208,6 +208,8 @@
#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12)
/* Controller has an issue with buffer bits for small transfers */
#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13)
+/* Controller supports high speed but doesn't have the caps bit set */
+#define SDHCI_QUIRK_FORCE_HIGHSPEED (1<<14)
int irq; /* Device IRQ */
void __iomem * ioaddr; /* Mapped address */
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c
index 0d7c883..fd7a101 100644
--- a/drivers/mtd/maps/sun_uflash.c
+++ b/drivers/mtd/maps/sun_uflash.c
@@ -1,13 +1,10 @@
-/*
- *
- * sun_uflash - Driver implementation for user-programmable flash
- * present on many Sun Microsystems SME boardsets.
+/* sun_uflash.c - Driver for user-programmable flash on
+ * Sun Microsystems SME boardsets.
*
* This driver does NOT provide access to the OBP-flash for
* safety reasons-- use <linux>/drivers/sbus/char/flash.c instead.
*
* Copyright (c) 2001 Eric Brower (ebrower@usa.net)
- *
*/
#include <linux/kernel.h>
@@ -16,8 +13,8 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/ioport.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/prom.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -26,67 +23,65 @@
#include <linux/mtd/map.h>
#define UFLASH_OBPNAME "flashprom"
-#define UFLASH_DEVNAME "userflash"
+#define DRIVER_NAME "sun_uflash"
+#define PFX DRIVER_NAME ": "
#define UFLASH_WINDOW_SIZE 0x200000
#define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */
MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets");
-MODULE_SUPPORTED_DEVICE("userflash");
+MODULE_SUPPORTED_DEVICE(DRIVER_NAME);
MODULE_LICENSE("GPL");
-MODULE_VERSION("2.0");
+MODULE_VERSION("2.1");
-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 linux_ebus_device *edev, struct device_node *dp)
+int uflash_devinit(struct of_device *op, struct device_node *dp)
{
struct uflash_dev *up;
- struct resource *res;
- res = &edev->resource[0];
-
- if (edev->num_addrs != 1) {
+ if (op->resource[1].flags) {
/* Non-CFI userflash device-- once I find one we
* can work on supporting it.
*/
- 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);
+ printk(KERN_ERR PFX "Unsupported device at %s, 0x%llx\n",
+ dp->full_name, (unsigned long long)op->resource[0].start);
return -ENODEV;
}
up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL);
- if (!up)
+ if (!up) {
+ printk(KERN_ERR PFX "Cannot allocate struct uflash_dev\n");
return -ENOMEM;
+ }
/* copy defaults and tweak parameters */
memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ));
- up->map.size = (res->end - res->start) + 1UL;
+
+ up->map.size = resource_size(&op->resource[0]);
up->name = of_get_property(dp, "model", NULL);
if (up->name && 0 < strlen(up->name))
up->map.name = (char *)up->name;
- up->map.phys = res->start;
+ up->map.phys = op->resource[0].start;
- up->map.virt = ioremap_nocache(res->start, up->map.size);
+ up->map.virt = of_ioremap(&op->resource[0], 0, up->map.size,
+ DRIVER_NAME);
if (!up->map.virt) {
- printk("%s: Failed to map device.\n", dp->full_name);
+ printk(KERN_ERR PFX "Failed to map device.\n");
kfree(up);
return -EINVAL;
@@ -97,7 +92,7 @@
/* MTD registration */
up->mtd = do_map_probe("cfi_probe", &up->map);
if (!up->mtd) {
- iounmap(up->map.virt);
+ of_iounmap(&op->resource[0], up->map.virt, up->map.size);
kfree(up);
return -ENXIO;
@@ -107,32 +102,34 @@
add_mtd_device(up->mtd);
- dev_set_drvdata(&edev->ofdev.dev, up);
+ dev_set_drvdata(&op->dev, up);
return 0;
}
-static int __devinit uflash_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit uflash_probe(struct of_device *op, const struct of_device_id *match)
{
- struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
- struct device_node *dp = dev->node;
+ struct device_node *dp = op->node;
- if (of_find_property(dp, "user", NULL))
+ /* Flashprom must have the "user" property in order to
+ * be used by this driver.
+ */
+ if (!of_find_property(dp, "user", NULL))
return -ENODEV;
- return uflash_devinit(edev, dp);
+ return uflash_devinit(op, dp);
}
-static int __devexit uflash_remove(struct of_device *dev)
+static int __devexit uflash_remove(struct of_device *op)
{
- struct uflash_dev *up = dev_get_drvdata(&dev->dev);
+ struct uflash_dev *up = dev_get_drvdata(&op->dev);
if (up->mtd) {
del_mtd_device(up->mtd);
map_destroy(up->mtd);
}
if (up->map.virt) {
- iounmap(up->map.virt);
+ of_iounmap(&op->resource[0], up->map.virt, up->map.size);
up->map.virt = NULL;
}
@@ -141,7 +138,7 @@
return 0;
}
-static struct of_device_id uflash_match[] = {
+static const struct of_device_id uflash_match[] = {
{
.name = UFLASH_OBPNAME,
},
@@ -151,7 +148,7 @@
MODULE_DEVICE_TABLE(of, uflash_match);
static struct of_platform_driver uflash_driver = {
- .name = UFLASH_DEVNAME,
+ .name = DRIVER_NAME,
.match_table = uflash_match,
.probe = uflash_probe,
.remove = __devexit_p(uflash_remove),
@@ -159,7 +156,7 @@
static int __init uflash_init(void)
{
- return of_register_driver(&uflash_driver, &ebus_bus_type);
+ return of_register_driver(&uflash_driver, &of_bus_type);
}
static void __exit uflash_exit(void)
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 3bafaed..fac8215 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1047,6 +1047,11 @@
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/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 06e6823..3ad7589 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -1,6 +1,6 @@
/* myri_sbus.c: MyriCOM MyriNET SBUS card driver.
*
- * Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 1999, 2006, 2008 David S. Miller (davem@davemloft.net)
*/
static char version[] =
@@ -22,6 +22,9 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <net/dst.h>
#include <net/arp.h>
@@ -33,7 +36,6 @@
#include <asm/dma.h>
#include <asm/byteorder.h>
#include <asm/idprom.h>
-#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/auxio.h>
@@ -243,7 +245,8 @@
u32 dma_addr;
dma_addr = sbus_readl(&rxd->myri_scatters[0].addr);
- sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+ dma_unmap_single(&mp->myri_op->dev, dma_addr,
+ RX_ALLOC_SIZE, DMA_FROM_DEVICE);
dev_kfree_skb(mp->rx_skbs[i]);
mp->rx_skbs[i] = NULL;
}
@@ -259,7 +262,9 @@
u32 dma_addr;
dma_addr = sbus_readl(&txd->myri_gathers[0].addr);
- sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3, SBUS_DMA_TODEVICE);
+ dma_unmap_single(&mp->myri_op->dev, dma_addr,
+ (skb->len + 3) & ~3,
+ DMA_TO_DEVICE);
dev_kfree_skb(mp->tx_skbs[i]);
mp->tx_skbs[i] = NULL;
}
@@ -288,7 +293,9 @@
skb->dev = dev;
skb_put(skb, RX_ALLOC_SIZE);
- dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+ dma_addr = dma_map_single(&mp->myri_op->dev,
+ skb->data, RX_ALLOC_SIZE,
+ DMA_FROM_DEVICE);
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);
@@ -344,7 +351,8 @@
DTX(("SKB[%d] ", entry));
dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr);
- sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE);
+ dma_unmap_single(&mp->myri_op->dev, dma_addr,
+ skb->len, DMA_TO_DEVICE);
dev_kfree_skb(skb);
mp->tx_skbs[entry] = NULL;
dev->stats.tx_packets++;
@@ -423,9 +431,9 @@
/* Check for errors. */
DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum));
- sbus_dma_sync_single_for_cpu(mp->myri_sdev,
- sbus_readl(&rxd->myri_scatters[0].addr),
- RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+ dma_sync_single_for_cpu(&mp->myri_op->dev,
+ sbus_readl(&rxd->myri_scatters[0].addr),
+ RX_ALLOC_SIZE, DMA_FROM_DEVICE);
if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) {
DRX(("ERROR["));
dev->stats.rx_errors++;
@@ -442,10 +450,10 @@
drops++;
DRX(("DROP "));
dev->stats.rx_dropped++;
- sbus_dma_sync_single_for_device(mp->myri_sdev,
- sbus_readl(&rxd->myri_scatters[0].addr),
- RX_ALLOC_SIZE,
- SBUS_DMA_FROMDEVICE);
+ dma_sync_single_for_device(&mp->myri_op->dev,
+ sbus_readl(&rxd->myri_scatters[0].addr),
+ RX_ALLOC_SIZE,
+ DMA_FROM_DEVICE);
sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
sbus_writel(index, &rxd->ctx);
sbus_writel(1, &rxd->num_sg);
@@ -464,17 +472,17 @@
DRX(("skb_alloc(FAILED) "));
goto drop_it;
}
- sbus_unmap_single(mp->myri_sdev,
- sbus_readl(&rxd->myri_scatters[0].addr),
- RX_ALLOC_SIZE,
- SBUS_DMA_FROMDEVICE);
+ dma_unmap_single(&mp->myri_op->dev,
+ sbus_readl(&rxd->myri_scatters[0].addr),
+ RX_ALLOC_SIZE,
+ DMA_FROM_DEVICE);
mp->rx_skbs[index] = new_skb;
new_skb->dev = dev;
skb_put(new_skb, RX_ALLOC_SIZE);
- dma_addr = sbus_map_single(mp->myri_sdev,
- new_skb->data,
- RX_ALLOC_SIZE,
- SBUS_DMA_FROMDEVICE);
+ dma_addr = dma_map_single(&mp->myri_op->dev,
+ new_skb->data,
+ RX_ALLOC_SIZE,
+ DMA_FROM_DEVICE);
sbus_writel(dma_addr, &rxd->myri_scatters[0].addr);
sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
sbus_writel(index, &rxd->ctx);
@@ -500,10 +508,10 @@
/* Reuse original ring buffer. */
DRX(("reuse "));
- sbus_dma_sync_single_for_device(mp->myri_sdev,
- sbus_readl(&rxd->myri_scatters[0].addr),
- RX_ALLOC_SIZE,
- SBUS_DMA_FROMDEVICE);
+ dma_sync_single_for_device(&mp->myri_op->dev,
+ sbus_readl(&rxd->myri_scatters[0].addr),
+ RX_ALLOC_SIZE,
+ DMA_FROM_DEVICE);
sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
sbus_writel(index, &rxd->ctx);
sbus_writel(1, &rxd->num_sg);
@@ -652,7 +660,8 @@
sbus_writew((skb->data[4] << 8) | skb->data[5], &txd->addr[3]);
}
- dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len, SBUS_DMA_TODEVICE);
+ dma_addr = dma_map_single(&mp->myri_op->dev, skb->data,
+ len, DMA_TO_DEVICE);
sbus_writel(dma_addr, &txd->myri_gathers[0].addr);
sbus_writel(len, &txd->myri_gathers[0].len);
sbus_writel(1, &txd->num_sg);
@@ -891,30 +900,30 @@
.cache_update = myri_header_cache_update,
};
-static int __devinit myri_ether_init(struct sbus_dev *sdev)
+static int __devinit myri_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
- static int num;
+ struct device_node *dp = op->node;
static unsigned version_printed;
struct net_device *dev;
- struct myri_eth *mp;
- unsigned char prop_buf[32];
- int i;
DECLARE_MAC_BUF(mac);
+ struct myri_eth *mp;
+ const void *prop;
+ static int num;
+ int i, len;
- DET(("myri_ether_init(%p,%d):\n", sdev, num));
+ DET(("myri_ether_init(%p,%d):\n", op, num));
dev = alloc_etherdev(sizeof(struct myri_eth));
-
if (!dev)
return -ENOMEM;
if (version_printed++ == 0)
printk(version);
- SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+ SET_NETDEV_DEV(dev, &op->dev);
- mp = (struct myri_eth *) dev->priv;
+ mp = netdev_priv(dev);
spin_lock_init(&mp->irq_lock);
- mp->myri_sdev = sdev;
+ mp->myri_op = op;
/* Clean out skb arrays. */
for (i = 0; i < (RX_RING_SIZE + 1); i++)
@@ -924,55 +933,44 @@
mp->tx_skbs[i] = NULL;
/* First check for EEPROM information. */
- 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) {
+ prop = of_get_property(dp, "myrinet-eeprom-info", &len);
+
+ if (prop)
+ memcpy(&mp->eeprom, prop, sizeof(struct myri_eeprom));
+ if (!prop) {
/* No eeprom property, must cook up the values ourselves. */
DET(("No EEPROM: "));
mp->eeprom.bus_type = BUS_TYPE_SBUS;
- 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 =
+ 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 = CPUVERS_2_3;
- }
- if (mp->eeprom.cpuvers < CPUVERS_3_0) {
- DET(("EEPROM: cpuvers < CPUVERS_3_0, clockval set to zero.\n"));
+ if (mp->eeprom.cpuvers < CPUVERS_3_0)
mp->eeprom.cval = 0;
- }
- if (mp->eeprom.ramsz == 0) {
- DET(("EEPROM: ramsz == 0, setting to 128k\n"));
+ if (!mp->eeprom.ramsz)
mp->eeprom.ramsz = (128 * 1024);
- }
- 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);
+
+ prop = of_get_property(dp, "myrinet-board-id", &len);
+ if (prop)
+ memcpy(&mp->eeprom.id[0], prop, 6);
else
set_boardid_from_idprom(mp, num);
- 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)
+
+ prop = of_get_property(dp, "fpga_version", &len);
+ if (prop)
+ memcpy(&mp->eeprom.fvers[0], prop, 32);
+ else
memset(&mp->eeprom.fvers[0], 0, 32);
if (mp->eeprom.cpuvers == CPUVERS_4_1) {
- DET(("EEPROM: cpuvers CPUVERS_4_1, "));
- if (mp->eeprom.ramsz == (128 * 1024)) {
- DET(("ramsize 128k, setting to 256k, "));
+ if (mp->eeprom.ramsz == (128 * 1024))
mp->eeprom.ramsz = (256 * 1024);
- }
- if ((mp->eeprom.cval==0x40414041)||(mp->eeprom.cval==0x90449044)){
- DET(("changing cval from %08x to %08x ",
- mp->eeprom.cval, 0x50e450e4));
+ if ((mp->eeprom.cval == 0x40414041) ||
+ (mp->eeprom.cval == 0x90449044))
mp->eeprom.cval = 0x50e450e4;
- }
- DET(("\n"));
}
}
#ifdef DEBUG_DETECT
@@ -991,8 +989,8 @@
* XXX only a valid version for PCI cards? Ask feldy...
*/
DET(("Mapping regs for cpuvers < CPUVERS_4_0\n"));
- mp->regs = sbus_ioremap(&sdev->resource[0], 0,
- mp->reg_size, "MyriCOM Regs");
+ mp->regs = of_ioremap(&op->resource[0], 0,
+ mp->reg_size, "MyriCOM Regs");
if (!mp->regs) {
printk("MyriCOM: Cannot map MyriCOM registers.\n");
goto err;
@@ -1001,13 +999,12 @@
mp->lregs = mp->lanai + (0x10000 * 2);
} else {
DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n"));
- mp->cregs = sbus_ioremap(&sdev->resource[0], 0,
- PAGE_SIZE, "MyriCOM Control Regs");
- mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024),
+ mp->cregs = of_ioremap(&op->resource[0], 0,
+ PAGE_SIZE, "MyriCOM Control Regs");
+ mp->lregs = of_ioremap(&op->resource[0], (256 * 1024),
PAGE_SIZE, "MyriCOM LANAI Regs");
- mp->lanai =
- sbus_ioremap(&sdev->resource[0], (512 * 1024),
- mp->eeprom.ramsz, "MyriCOM SRAM");
+ mp->lanai = of_ioremap(&op->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));
@@ -1039,16 +1036,15 @@
myri_reset_on(mp->cregs);
/* Get the supported DVMA burst sizes from our SBUS. */
- mp->myri_bursts = prom_getintdefault(mp->myri_sdev->bus->prom_node,
- "burst-sizes", 0x00);
-
- if (!sbus_can_burst64(sdev))
+ mp->myri_bursts = of_getintprop_default(dp->parent,
+ "burst-sizes", 0x00);
+ if (!sbus_can_burst64())
mp->myri_bursts &= ~(DMA_BURST64);
DET(("MYRI bursts %02x\n", mp->myri_bursts));
/* Encode SBUS interrupt level in second control register. */
- i = prom_getint(sdev->prom_node, "interrupts");
+ i = of_getintprop_default(dp, "interrupts", 0);
if (i == 0)
i = 4;
DET(("prom_getint(interrupts)==%d, irqlvl set to %04x\n",
@@ -1063,7 +1059,7 @@
dev->tx_timeout = &myri_tx_timeout;
dev->watchdog_timeo = 5*HZ;
dev->set_multicast_list = &myri_set_multicast;
- dev->irq = sdev->irqs[0];
+ dev->irq = op->irqs[0];
/* Register interrupt handler now. */
DET(("Requesting MYRIcom IRQ line.\n"));
@@ -1088,7 +1084,7 @@
goto err_free_irq;
}
- dev_set_drvdata(&sdev->ofdev.dev, mp);
+ dev_set_drvdata(&op->dev, mp);
num++;
@@ -1105,17 +1101,9 @@
return -ENODEV;
}
-
-static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devexit myri_sbus_remove(struct of_device *op)
{
- 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(&dev->dev);
+ struct myri_eth *mp = dev_get_drvdata(&op->dev);
struct net_device *net_dev = mp->dev;
unregister_netdev(net_dev);
@@ -1123,21 +1111,21 @@
free_irq(net_dev->irq, net_dev);
if (mp->eeprom.cpuvers < CPUVERS_4_0) {
- sbus_iounmap(mp->regs, mp->reg_size);
+ of_iounmap(&op->resource[0], mp->regs, mp->reg_size);
} else {
- sbus_iounmap(mp->cregs, PAGE_SIZE);
- sbus_iounmap(mp->lregs, (256 * 1024));
- sbus_iounmap(mp->lanai, (512 * 1024));
+ 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));
}
free_netdev(net_dev);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id myri_sbus_match[] = {
+static const struct of_device_id myri_sbus_match[] = {
{
.name = "MYRICOM,mlanai",
},
@@ -1158,7 +1146,7 @@
static int __init myri_sbus_init(void)
{
- return of_register_driver(&myri_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&myri_sbus_driver, &of_bus_type);
}
static void __exit myri_sbus_exit(void)
diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h
index 5d93fcc..ff363e9 100644
--- a/drivers/net/myri_sbus.h
+++ b/drivers/net/myri_sbus.h
@@ -288,7 +288,7 @@
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 sbus_dev *myri_sdev; /* Our SBUS device struct. */
+ struct of_device *myri_op; /* Our OF device struct. */
};
/* We use this to acquire receive skb's that we can DMA directly into. */
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index e3be81e..ebc8127 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -9130,7 +9130,7 @@
return 0;
}
-static struct of_device_id niu_match[] = {
+static const struct of_device_id niu_match[] = {
{
.name = "network",
.compatible = "SUNW,niusl",
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 02cc064..3d19d00 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -722,6 +722,9 @@
break;
}
}
+ if (phyaddr < 32)
+ /* Found an external PHY */
+ break;
}
default:
/* Internal media only */
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 31e7384..018d0fc 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -1,7 +1,6 @@
-/* $Id: sunbmac.c,v 1.30 2002/01/15 06:48:55 davem Exp $
- * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
+/* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
*
- * Copyright (C) 1997, 1998, 1999, 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1997, 1998, 1999, 2003, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -23,6 +22,9 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/auxio.h>
#include <asm/byteorder.h>
@@ -32,15 +34,14 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/pgtable.h>
-#include <asm/sbus.h>
#include <asm/system.h>
#include "sunbmac.h"
#define DRV_NAME "sunbmac"
-#define DRV_VERSION "2.0"
-#define DRV_RELDATE "11/24/03"
-#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
+#define DRV_VERSION "2.1"
+#define DRV_RELDATE "August 26, 2008"
+#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
@@ -96,8 +97,8 @@
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;
@@ -112,13 +113,13 @@
sbus_writel(GLOB_PSIZE_2048, gregs + GLOB_PSIZE);
/* All of memsize is given to bigmac. */
- sbus_writel(qec_sdev->reg_addrs[1].reg_size,
+ sbus_writel(resource_size(&qec_op->resource[1]),
gregs + GLOB_MSIZE);
/* Half to the transmitter, half to the receiver. */
- sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1,
+ sbus_writel(resource_size(&qec_op->resource[1]) >> 1,
gregs + GLOB_TSIZE);
- sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1,
+ sbus_writel(resource_size(&qec_op->resource[1]) >> 1,
gregs + GLOB_RSIZE);
}
@@ -239,9 +240,10 @@
skb_reserve(skb, 34);
bb->be_rxd[i].rx_addr =
- sbus_map_single(bp->bigmac_sdev, skb->data,
- RX_BUF_ALLOC_SIZE - 34,
- SBUS_DMA_FROMDEVICE);
+ dma_map_single(&bp->bigmac_op->dev,
+ skb->data,
+ RX_BUF_ALLOC_SIZE - 34,
+ DMA_FROM_DEVICE);
bb->be_rxd[i].rx_flags =
(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
}
@@ -776,9 +778,9 @@
skb = bp->tx_skbs[elem];
bp->enet_stats.tx_packets++;
bp->enet_stats.tx_bytes += skb->len;
- sbus_unmap_single(bp->bigmac_sdev,
- this->tx_addr, skb->len,
- SBUS_DMA_TODEVICE);
+ dma_unmap_single(&bp->bigmac_op->dev,
+ this->tx_addr, skb->len,
+ DMA_TO_DEVICE);
DTX(("skb(%p) ", skb));
bp->tx_skbs[elem] = NULL;
@@ -831,18 +833,19 @@
drops++;
goto drop_it;
}
- sbus_unmap_single(bp->bigmac_sdev,
- this->rx_addr,
- RX_BUF_ALLOC_SIZE - 34,
- SBUS_DMA_FROMDEVICE);
+ dma_unmap_single(&bp->bigmac_op->dev,
+ this->rx_addr,
+ RX_BUF_ALLOC_SIZE - 34,
+ DMA_FROM_DEVICE);
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 = sbus_map_single(bp->bigmac_sdev,
- new_skb->data,
- RX_BUF_ALLOC_SIZE - 34,
- SBUS_DMA_FROMDEVICE);
+ this->rx_addr =
+ dma_map_single(&bp->bigmac_op->dev,
+ new_skb->data,
+ RX_BUF_ALLOC_SIZE - 34,
+ DMA_FROM_DEVICE);
this->rx_flags =
(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
@@ -857,13 +860,13 @@
}
skb_reserve(copy_skb, 2);
skb_put(copy_skb, len);
- sbus_dma_sync_single_for_cpu(bp->bigmac_sdev,
- this->rx_addr, len,
- SBUS_DMA_FROMDEVICE);
+ dma_sync_single_for_cpu(&bp->bigmac_op->dev,
+ this->rx_addr, len,
+ DMA_FROM_DEVICE);
skb_copy_to_linear_data(copy_skb, (unsigned char *)skb->data, len);
- sbus_dma_sync_single_for_device(bp->bigmac_sdev,
- this->rx_addr, len,
- SBUS_DMA_FROMDEVICE);
+ dma_sync_single_for_device(&bp->bigmac_op->dev,
+ this->rx_addr, len,
+ DMA_FROM_DEVICE);
/* Reuse original ring buffer. */
this->rx_flags =
@@ -959,7 +962,8 @@
u32 mapping;
len = skb->len;
- mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len, SBUS_DMA_TODEVICE);
+ mapping = dma_map_single(&bp->bigmac_op->dev, skb->data,
+ len, DMA_TO_DEVICE);
/* Avoid a race... */
spin_lock_irq(&bp->lock);
@@ -1051,12 +1055,8 @@
/* 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,14 +1075,15 @@
.get_link = bigmac_get_link,
};
-static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
+static int __devinit bigmac_ether_init(struct of_device *op,
+ struct of_device *qec_op)
{
- struct net_device *dev;
static int version_printed;
- struct bigmac *bp;
+ struct net_device *dev;
u8 bsizes, bsizes_more;
- int i;
DECLARE_MAC_BUF(mac);
+ struct bigmac *bp;
+ int i;
/* Get a new device struct for this interface. */
dev = alloc_etherdev(sizeof(struct bigmac));
@@ -1092,32 +1093,21 @@
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 = dev->priv;
- bp->qec_sdev = qec_sdev;
- bp->bigmac_sdev = qec_sdev->child;
+ bp = netdev_priv(dev);
+ bp->qec_op = qec_op;
+ bp->bigmac_op = op;
- SET_NETDEV_DEV(dev, &bp->bigmac_sdev->ofdev.dev);
+ SET_NETDEV_DEV(dev, &op->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 = sbus_ioremap(&bp->qec_sdev->resource[0], 0,
- GLOB_REG_SIZE, "BigMAC QEC GLobal Regs");
+ bp->gregs = of_ioremap(&qec_op->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;
@@ -1134,13 +1124,8 @@
goto fail_and_cleanup;
/* Get supported SBUS burst sizes. */
- 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 = of_getintprop_default(qec_op->node, "burst-sizes", 0xff);
+ bsizes_more = of_getintprop_default(qec_op->node, "burst-sizes", 0xff);
bsizes &= 0xff;
if (bsizes_more != 0xff)
@@ -1154,16 +1139,16 @@
qec_init(bp);
/* Map in the BigMAC channel registers. */
- bp->creg = sbus_ioremap(&bp->bigmac_sdev->resource[0], 0,
- CREG_REG_SIZE, "BigMAC QEC Channel Regs");
+ bp->creg = of_ioremap(&op->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 = sbus_ioremap(&bp->bigmac_sdev->resource[1], 0,
- BMAC_REG_SIZE, "BigMAC Primary Regs");
+ bp->bregs = of_ioremap(&op->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;
@@ -1172,8 +1157,8 @@
/* Map in the BigMAC transceiver registers, this is how you poke at
* the BigMAC's PHY.
*/
- bp->tregs = sbus_ioremap(&bp->bigmac_sdev->resource[2], 0,
- TCVR_REG_SIZE, "BigMAC Transceiver Regs");
+ bp->tregs = of_ioremap(&op->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;
@@ -1183,17 +1168,17 @@
bigmac_stop(bp);
/* Allocate transmit/receive descriptor DVMA block. */
- bp->bmac_block = sbus_alloc_consistent(bp->bigmac_sdev,
- PAGE_SIZE,
- &bp->bblock_dvma);
+ bp->bmac_block = dma_alloc_coherent(&bp->bigmac_op->dev,
+ PAGE_SIZE,
+ &bp->bblock_dvma, GFP_ATOMIC);
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 = prom_getintdefault(bp->bigmac_sdev->prom_node,
- "board-version", 1);
+ bp->board_rev = of_getintprop_default(bp->bigmac_op->node,
+ "board-version", 1);
/* Init auto-negotiation timer state. */
init_timer(&bp->bigmac_timer);
@@ -1217,7 +1202,7 @@
dev->watchdog_timeo = 5*HZ;
/* Finish net device registration. */
- dev->irq = bp->bigmac_sdev->irqs[0];
+ dev->irq = bp->bigmac_op->irqs[0];
dev->dma = 0;
if (register_netdev(dev)) {
@@ -1225,7 +1210,7 @@
goto fail_and_cleanup;
}
- dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp);
+ dev_set_drvdata(&bp->bigmac_op->dev, bp);
printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n",
dev->name, print_mac(mac, dev->dev_addr));
@@ -1236,66 +1221,67 @@
/* Something went wrong, undo whatever we did so far. */
/* Free register mappings if any. */
if (bp->gregs)
- sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
+ of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE);
if (bp->creg)
- sbus_iounmap(bp->creg, CREG_REG_SIZE);
+ of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE);
if (bp->bregs)
- sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
+ of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE);
if (bp->tregs)
- sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
+ of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE);
if (bp->bmac_block)
- sbus_free_consistent(bp->bigmac_sdev,
- PAGE_SIZE,
- bp->bmac_block,
- bp->bblock_dvma);
+ dma_free_coherent(&bp->bigmac_op->dev,
+ 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 *dev, const struct of_device_id *match)
+static int __devinit bigmac_sbus_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- struct device_node *dp = dev->node;
+ struct device *parent = op->dev.parent;
+ struct of_device *qec_op;
- if (!strcmp(dp->name, "be"))
- sdev = sdev->parent;
+ qec_op = to_of_device(parent);
- return bigmac_ether_init(sdev);
+ return bigmac_ether_init(op, qec_op);
}
-static int __devexit bigmac_sbus_remove(struct of_device *dev)
+static int __devexit bigmac_sbus_remove(struct of_device *op)
{
- struct bigmac *bp = dev_get_drvdata(&dev->dev);
+ struct bigmac *bp = dev_get_drvdata(&op->dev);
+ struct device *parent = op->dev.parent;
struct net_device *net_dev = bp->dev;
+ struct of_device *qec_op;
+
+ qec_op = to_of_device(parent);
unregister_netdev(net_dev);
- 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);
+ 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);
free_netdev(net_dev);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id bigmac_sbus_match[] = {
- {
- .name = "qec",
- },
+static const struct of_device_id bigmac_sbus_match[] = {
{
.name = "be",
},
@@ -1313,7 +1299,7 @@
static int __init bigmac_init(void)
{
- return of_register_driver(&bigmac_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&bigmac_sbus_driver, &of_bus_type);
}
static void __exit bigmac_exit(void)
diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h
index b563d3c..8840bc0 100644
--- a/drivers/net/sunbmac.h
+++ b/drivers/net/sunbmac.h
@@ -329,8 +329,8 @@
unsigned int timer_ticks;
struct net_device_stats enet_stats;
- struct sbus_dev *qec_sdev;
- struct sbus_dev *bigmac_sdev;
+ struct of_device *qec_op;
+ struct of_device *bigmac_op;
struct net_device *dev;
};
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index b79d5f0..f1ebeb5 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -3,7 +3,7 @@
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
*
* Copyright (C) 1996, 1998, 1999, 2002, 2003,
- 2006 David S. Miller (davem@davemloft.net)
+ * 2006, 2008 David S. Miller (davem@davemloft.net)
*
* Changes :
* 2000/11/11 Willy Tarreau <willy AT meta-x.org>
@@ -34,6 +34,7 @@
#include <linux/skbuff.h>
#include <linux/mm.h>
#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -41,8 +42,9 @@
#include <asm/byteorder.h>
#ifdef CONFIG_SPARC
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/idprom.h>
-#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/prom.h>
@@ -60,8 +62,8 @@
#include "sunhme.h"
#define DRV_NAME "sunhme"
-#define DRV_VERSION "3.00"
-#define DRV_RELDATE "June 23, 2006"
+#define DRV_VERSION "3.10"
+#define DRV_RELDATE "August 26, 2008"
#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
@@ -251,13 +253,13 @@
#define hme_read_desc32(__hp, __p) \
((__hp)->read_desc32(__p))
#define hme_dma_map(__hp, __ptr, __size, __dir) \
- ((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir)))
+ ((__hp)->dma_map((__hp)->dma_dev, (__ptr), (__size), (__dir)))
#define hme_dma_unmap(__hp, __addr, __size, __dir) \
- ((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir)))
+ ((__hp)->dma_unmap((__hp)->dma_dev, (__addr), (__size), (__dir)))
#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
- ((__hp)->dma_sync_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)))
+ ((__hp)->dma_sync_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir)))
#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
- ((__hp)->dma_sync_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)))
+ ((__hp)->dma_sync_for_device((__hp)->dma_dev, (__addr), (__size), (__dir)))
#else
#ifdef CONFIG_SBUS
/* SBUS only compilation */
@@ -277,13 +279,13 @@
} while(0)
#define hme_read_desc32(__hp, __p) ((__force u32)(hme32)*(__p))
#define hme_dma_map(__hp, __ptr, __size, __dir) \
- sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
+ dma_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir))
#define hme_dma_unmap(__hp, __addr, __size, __dir) \
- sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+ dma_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir))
#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
- sbus_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))
+ dma_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))
#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
- sbus_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))
+ dma_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir))
#else
/* PCI only compilation */
#define hme_write32(__hp, __reg, __val) \
@@ -305,36 +307,17 @@
return le32_to_cpup((__le32 *)p);
}
#define hme_dma_map(__hp, __ptr, __size, __dir) \
- pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
+ pci_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir))
#define hme_dma_unmap(__hp, __addr, __size, __dir) \
- pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+ pci_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir))
#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
- pci_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))
+ pci_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))
#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
- pci_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))
+ pci_dma_sync_single_for_device((__hp)->dma_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)
{
@@ -1224,7 +1207,8 @@
rxd = &hp->happy_block->happy_meal_rxd[i];
dma_addr = hme_read_desc32(hp, &rxd->rx_addr);
- hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
+ dma_unmap_single(hp->dma_dev, dma_addr,
+ RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
hp->rx_skbs[i] = NULL;
}
@@ -1242,10 +1226,10 @@
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);
- hme_dma_unmap(hp, dma_addr,
- (hme_read_desc32(hp, &txd->tx_flags)
- & TXFLAG_SIZE),
- DMA_TODEVICE);
+ dma_unmap_single(hp->dma_dev, dma_addr,
+ (hme_read_desc32(hp, &txd->tx_flags)
+ & TXFLAG_SIZE),
+ DMA_TO_DEVICE);
if (frag != skb_shinfo(skb)->nr_frags)
i++;
@@ -1287,7 +1271,8 @@
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)),
- hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
+ dma_map_single(hp->dma_dev, skb->data, RX_BUF_ALLOC_SIZE,
+ DMA_FROM_DEVICE));
skb_reserve(skb, RX_OFFSET);
}
@@ -1593,7 +1578,7 @@
if ((hp->happy_bursts & DMA_BURST64) &&
((hp->happy_flags & HFLAG_PCI) != 0
#ifdef CONFIG_SBUS
- || sbus_can_burst64(hp->happy_dev)
+ || sbus_can_burst64()
#endif
|| 0)) {
u32 gcfg = GREG_CFG_BURST64;
@@ -1603,11 +1588,13 @@
* do not. -DaveM
*/
#ifdef CONFIG_SBUS
- 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;
+ 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;
+ }
}
#endif
@@ -1966,7 +1953,7 @@
dma_len = hme_read_desc32(hp, &this->tx_flags);
dma_len &= TXFLAG_SIZE;
- hme_dma_unmap(hp, dma_addr, dma_len, DMA_TODEVICE);
+ dma_unmap_single(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE);
elem = NEXT_TX(elem);
this = &txbase[elem];
@@ -2044,13 +2031,14 @@
drops++;
goto drop_it;
}
- hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
+ dma_unmap_single(hp->dma_dev, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE);
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)),
- hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
+ dma_map_single(hp->dma_dev, new_skb->data, RX_BUF_ALLOC_SIZE,
+ DMA_FROM_DEVICE));
skb_reserve(new_skb, RX_OFFSET);
/* Trim the original skb for the netif. */
@@ -2065,10 +2053,9 @@
skb_reserve(copy_skb, 2);
skb_put(copy_skb, len);
- hme_dma_sync_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE);
+ dma_sync_single_for_cpu(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE);
skb_copy_from_linear_data(skb, copy_skb->data, len);
- hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE);
-
+ dma_sync_single_for_device(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE);
/* Reuse original ring buffer. */
hme_write_rxd(hp, this,
(RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
@@ -2300,7 +2287,7 @@
u32 mapping, len;
len = skb->len;
- mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE);
+ mapping = dma_map_single(hp->dma_dev, skb->data, len, DMA_TO_DEVICE);
tx_flags |= (TXFLAG_SOP | TXFLAG_EOP);
hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry],
(tx_flags | (len & TXFLAG_SIZE)),
@@ -2314,7 +2301,8 @@
* Otherwise we could race with the device.
*/
first_len = skb_headlen(skb);
- first_mapping = hme_dma_map(hp, skb->data, first_len, DMA_TODEVICE);
+ first_mapping = dma_map_single(hp->dma_dev, skb->data, first_len,
+ DMA_TO_DEVICE);
entry = NEXT_TX(entry);
for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
@@ -2322,10 +2310,9 @@
u32 len, mapping, this_txflags;
len = this_frag->size;
- mapping = hme_dma_map(hp,
- ((void *) page_address(this_frag->page) +
- this_frag->page_offset),
- len, DMA_TODEVICE);
+ mapping = dma_map_page(hp->dma_dev, this_frag->page,
+ this_frag->page_offset, len,
+ DMA_TO_DEVICE);
this_txflags = tx_flags;
if (frag == skb_shinfo(skb)->nr_frags - 1)
this_txflags |= TXFLAG_EOP;
@@ -2493,9 +2480,12 @@
}
#ifdef CONFIG_SBUS
else {
- struct sbus_dev *sdev = hp->happy_dev;
- sprintf(info->bus_info, "SBUS:%d",
- sdev->slot);
+ 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);
}
#endif
}
@@ -2521,63 +2511,21 @@
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 sbus_dev *goal_sdev)
+static struct quattro * __devinit quattro_sbus_find(struct of_device *child)
{
- struct sbus_dev *sdev;
+ struct device *parent = child->dev.parent;
+ struct of_device *op;
struct quattro *qp;
- int i;
- 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;
- }
- }
+ op = to_of_device(parent);
+ qp = dev_get_drvdata(&op->dev);
+ if (qp)
+ return qp;
qp = kmalloc(sizeof(struct quattro), GFP_KERNEL);
if (qp != NULL) {
@@ -2586,10 +2534,11 @@
for (i = 0; i < 4; i++)
qp->happy_meals[i] = NULL;
- qp->quattro_dev = goal_sdev;
+ qp->quattro_dev = child;
qp->next = qfe_sbus_list;
qfe_sbus_list = qp;
- quattro_get_ranges(qp);
+
+ dev_set_drvdata(&op->dev, qp);
}
return qp;
}
@@ -2602,10 +2551,10 @@
struct quattro *qp;
for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
- struct sbus_dev *sdev = qp->quattro_dev;
+ struct of_device *op = qp->quattro_dev;
int err;
- err = request_irq(sdev->irqs[0],
+ err = request_irq(op->irqs[0],
quattro_sbus_interrupt,
IRQF_SHARED, "Quattro",
qp);
@@ -2621,9 +2570,9 @@
struct quattro *qp;
for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
- struct sbus_dev *sdev = qp->quattro_dev;
+ struct of_device *op = qp->quattro_dev;
- free_irq(sdev->irqs[0], qp);
+ free_irq(op->irqs[0], qp);
}
}
#endif /* CONFIG_SBUS */
@@ -2660,9 +2609,9 @@
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
-static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe)
+static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe)
{
- struct device_node *dp = sdev->ofdev.node;
+ struct device_node *dp = op->node, *sbus_dp;
struct quattro *qp = NULL;
struct happy_meal *hp;
struct net_device *dev;
@@ -2671,7 +2620,7 @@
DECLARE_MAC_BUF(mac);
if (is_qfe) {
- qp = quattro_sbus_find(sdev);
+ qp = quattro_sbus_find(op);
if (qp == NULL)
goto err_out;
for (qfe_slot = 0; qfe_slot < 4; qfe_slot++)
@@ -2685,7 +2634,7 @@
dev = alloc_etherdev(sizeof(struct happy_meal));
if (!dev)
goto err_out;
- SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+ SET_NETDEV_DEV(dev, &op->dev);
if (hme_version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -2713,56 +2662,50 @@
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
- hp = dev->priv;
+ hp = netdev_priv(dev);
- hp->happy_dev = sdev;
+ hp->happy_dev = op;
+ hp->dma_dev = &op->dev;
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 = sbus_ioremap(&sdev->resource[0], 0,
- GREG_REG_SIZE, "HME Global Regs");
+ hp->gregs = of_ioremap(&op->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 = sbus_ioremap(&sdev->resource[1], 0,
- ETX_REG_SIZE, "HME TX Regs");
+ hp->etxregs = of_ioremap(&op->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 = sbus_ioremap(&sdev->resource[2], 0,
- ERX_REG_SIZE, "HME RX Regs");
+ hp->erxregs = of_ioremap(&op->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 = sbus_ioremap(&sdev->resource[3], 0,
- BMAC_REG_SIZE, "HME BIGMAC Regs");
+ hp->bigmacregs = of_ioremap(&op->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 = sbus_ioremap(&sdev->resource[4], 0,
- TCVR_REG_SIZE, "HME Tranceiver Regs");
+ hp->tcvregs = of_ioremap(&op->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;
@@ -2781,13 +2724,18 @@
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(sdev->bus->ofdev.node,
+ hp->happy_bursts = of_getintprop_default(sbus_dp,
"burst-sizes", 0x00);
- hp->happy_block = sbus_alloc_consistent(hp->happy_dev,
- PAGE_SIZE,
- &hp->hblock_dvma);
+ hp->happy_block = dma_alloc_coherent(hp->dma_dev,
+ PAGE_SIZE,
+ &hp->hblock_dvma,
+ GFP_ATOMIC);
err = -ENOMEM;
if (!hp->happy_block) {
printk(KERN_ERR "happymeal: Cannot allocate descriptors.\n");
@@ -2816,19 +2764,13 @@
/* Happy Meal can do it all... */
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
- dev->irq = sdev->irqs[0];
+ dev->irq = op->irqs[0];
#if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
- /* Hook up PCI register/dma accessors. */
+ /* Hook up SBUS register/descriptor 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
@@ -2843,10 +2785,10 @@
if (register_netdev(hp->dev)) {
printk(KERN_ERR "happymeal: Cannot register net device, "
"aborting.\n");
- goto err_out_free_consistent;
+ goto err_out_free_coherent;
}
- dev_set_drvdata(&sdev->ofdev.dev, hp);
+ dev_set_drvdata(&op->dev, hp);
if (qfe_slot != -1)
printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
@@ -2859,23 +2801,23 @@
return 0;
-err_out_free_consistent:
- sbus_free_consistent(hp->happy_dev,
- PAGE_SIZE,
- hp->happy_block,
- hp->hblock_dvma);
+err_out_free_coherent:
+ dma_free_coherent(hp->dma_dev,
+ PAGE_SIZE,
+ hp->happy_block,
+ hp->hblock_dvma);
err_out_iounmap:
if (hp->gregs)
- sbus_iounmap(hp->gregs, GREG_REG_SIZE);
+ of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE);
if (hp->etxregs)
- sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
+ of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE);
if (hp->erxregs)
- sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
+ of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE);
if (hp->bigmacregs)
- sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
+ of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE);
if (hp->tcvregs)
- sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
+ of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE);
err_out_free_netdev:
free_netdev(dev);
@@ -3035,6 +2977,7 @@
memset(hp, 0, sizeof(*hp));
hp->happy_dev = pdev;
+ hp->dma_dev = &pdev->dev;
spin_lock_init(&hp->happy_lock);
@@ -3121,7 +3064,7 @@
#endif
hp->happy_block = (struct hmeal_init_block *)
- pci_alloc_consistent(pdev, PAGE_SIZE, &hp->hblock_dvma);
+ dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &hp->hblock_dvma, GFP_KERNEL);
err = -ENODEV;
if (!hp->happy_block) {
@@ -3151,16 +3094,10 @@
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
#if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
- /* Hook up PCI register/dma accessors. */
+ /* Hook up PCI register/descriptor 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
@@ -3231,10 +3168,8 @@
unregister_netdev(net_dev);
- pci_free_consistent(hp->happy_dev,
- PAGE_SIZE,
- hp->happy_block,
- hp->hblock_dvma);
+ dma_free_coherent(hp->dma_dev, PAGE_SIZE,
+ hp->happy_block, hp->hblock_dvma);
iounmap(hp->gregs);
pci_release_regions(hp->happy_dev);
@@ -3279,46 +3214,45 @@
#endif
#ifdef CONFIG_SBUS
-static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit hme_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- struct device_node *dp = dev->node;
+ struct device_node *dp = op->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(sdev, is_qfe);
+ return happy_meal_sbus_probe_one(op, is_qfe);
}
-static int __devexit hme_sbus_remove(struct of_device *dev)
+static int __devexit hme_sbus_remove(struct of_device *op)
{
- struct happy_meal *hp = dev_get_drvdata(&dev->dev);
+ struct happy_meal *hp = dev_get_drvdata(&op->dev);
struct net_device *net_dev = hp->dev;
unregister_netdev(net_dev);
/* XXX qfe parent interrupt... */
- 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);
+ 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);
free_netdev(net_dev);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id hme_sbus_match[] = {
+static const struct of_device_id hme_sbus_match[] = {
{
.name = "SUNW,hme",
},
@@ -3346,7 +3280,7 @@
{
int err;
- err = of_register_driver(&hme_sbus_driver, &sbus_bus_type);
+ err = of_register_driver(&hme_sbus_driver, &of_bus_type);
if (!err)
quattro_sbus_register_irqs();
diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h
index 4da5539..efd2ca0 100644
--- a/drivers/net/sunhme.h
+++ b/drivers/net/sunhme.h
@@ -405,14 +405,11 @@
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 a sbus_dev or a pci_dev. */
+ /* This is either an of_device or a pci_dev. */
void *happy_dev;
+ struct device *dma_dev;
spinlock_t happy_lock;
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 4e994f8..704301a 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -91,6 +91,9 @@
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -98,7 +101,6 @@
#include <asm/pgtable.h>
#include <asm/byteorder.h> /* Used by the checksum routines */
#include <asm/idprom.h>
-#include <asm/sbus.h>
#include <asm/prom.h>
#include <asm/auxio.h> /* For tpe-link-test? setting */
#include <asm/irq.h>
@@ -248,7 +250,7 @@
int rx_new, tx_new;
int rx_old, tx_old;
- struct sbus_dma *ledma; /* If set this points to ledma */
+ struct of_device *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 */
@@ -263,7 +265,8 @@
char *name;
dma_addr_t init_block_dvma;
struct net_device *dev; /* Backpointer */
- struct sbus_dev *sdev;
+ struct of_device *op;
+ struct of_device *lebuffer;
struct timer_list multicast_timer;
};
@@ -1272,27 +1275,29 @@
static void lance_free_hwresources(struct lance_private *lp)
{
if (lp->lregs)
- sbus_iounmap(lp->lregs, LANCE_REG_SIZE);
+ 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]));
+ }
if (lp->init_block_iomem) {
- sbus_iounmap(lp->init_block_iomem,
- sizeof(struct lance_init_block));
+ of_iounmap(&lp->lebuffer->resource[0], lp->init_block_iomem,
+ sizeof(struct lance_init_block));
} else if (lp->init_block_mem) {
- sbus_free_consistent(lp->sdev,
- sizeof(struct lance_init_block),
- lp->init_block_mem,
- lp->init_block_dvma);
+ dma_free_coherent(&lp->op->dev,
+ 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)
@@ -1308,16 +1313,16 @@
.get_link = sparc_lance_get_link,
};
-static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
- struct sbus_dma *ledma,
- struct sbus_dev *lebuffer)
+static int __devinit sparc_lance_probe_one(struct of_device *op,
+ struct of_device *ledma,
+ struct of_device *lebuffer)
{
+ struct device_node *dp = op->node;
static unsigned version_printed;
- struct device_node *dp = sdev->ofdev.node;
- struct net_device *dev;
struct lance_private *lp;
- int i;
+ struct net_device *dev;
DECLARE_MAC_BUF(mac);
+ int i;
dev = alloc_etherdev(sizeof(struct lance_private) + 8);
if (!dev)
@@ -1338,14 +1343,27 @@
dev->dev_addr[i] = idprom->id_ethaddr[i];
/* Get the IO region */
- lp->lregs = sbus_ioremap(&sdev->resource[0], 0,
- LANCE_REG_SIZE, lancestr);
+ lp->lregs = of_ioremap(&op->resource[0], 0,
+ LANCE_REG_SIZE, lancestr);
if (!lp->lregs) {
printk(KERN_ERR "SunLance: Cannot map registers.\n");
goto fail;
}
- lp->sdev = sdev;
+ 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;
if (lebuffer) {
/* sanity check */
if (lebuffer->resource[0].start & 7) {
@@ -1353,8 +1371,8 @@
goto fail;
}
lp->init_block_iomem =
- sbus_ioremap(&lebuffer->resource[0], 0,
- sizeof(struct lance_init_block), "lebuffer");
+ of_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;
@@ -1366,9 +1384,10 @@
lp->tx = lance_tx_pio;
} else {
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) {
+ dma_alloc_coherent(&op->dev,
+ sizeof(struct lance_init_block),
+ &lp->init_block_dvma, GFP_ATOMIC);
+ if (!lp->init_block_mem) {
printk(KERN_ERR "SunLance: Cannot allocate consistent DMA memory.\n");
goto fail;
}
@@ -1383,13 +1402,13 @@
LE_C3_BCON));
lp->name = lancestr;
- lp->ledma = ledma;
lp->burst_sizes = 0;
if (lp->ledma) {
- struct device_node *ledma_dp = ledma->sdev->ofdev.node;
- const char *prop;
+ struct device_node *ledma_dp = ledma->node;
+ struct device_node *sbus_dp;
unsigned int sbmask;
+ const char *prop;
u32 csr;
/* Find burst-size property for ledma */
@@ -1397,7 +1416,8 @@
"burst-sizes", 0);
/* ledma may be capable of fast bursts, but sbus may not. */
- sbmask = of_getintprop_default(ledma_dp, "burst-sizes",
+ sbus_dp = ledma_dp->parent;
+ sbmask = of_getintprop_default(sbus_dp, "burst-sizes",
DMA_BURSTBITS);
lp->burst_sizes &= sbmask;
@@ -1435,8 +1455,6 @@
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);
@@ -1446,7 +1464,7 @@
lp->dregs = NULL;
lp->dev = dev;
- SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+ SET_NETDEV_DEV(dev, &op->dev);
dev->open = &lance_open;
dev->stop = &lance_close;
dev->hard_start_xmit = &lance_start_xmit;
@@ -1455,9 +1473,7 @@
dev->set_multicast_list = &lance_set_multicast;
dev->ethtool_ops = &sparc_lance_ethtool_ops;
- dev->irq = sdev->irqs[0];
-
- dev->dma = 0;
+ dev->irq = op->irqs[0];
/* We cannot sleep if the chip is busy during a
* multicast list update event, because such events
@@ -1473,7 +1489,7 @@
goto fail;
}
- dev_set_drvdata(&sdev->ofdev.dev, lp);
+ dev_set_drvdata(&op->dev, lp);
printk(KERN_INFO "%s: LANCE %s\n",
dev->name, print_mac(mac, dev->dev_addr));
@@ -1486,80 +1502,25 @@
return -ENODEV;
}
-/* On 4m, find the associated dma for the lance chip */
-static struct sbus_dma * __devinit find_ledma(struct sbus_dev *sdev)
+static int __devinit sunlance_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
- struct sbus_dma *p;
-
- for_each_dvma(p) {
- if (p->sdev == sdev)
- return p;
- }
- return NULL;
-}
-
-#ifdef CONFIG_SUN4
-
-#include <asm/sun4paddr.h>
-#include <asm/machines.h>
-
-/* 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 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);
+ struct of_device *parent = to_of_device(op->dev.parent);
+ struct device_node *parent_dp = parent->node;
int err;
- 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);
+ 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);
} else
- err = sparc_lance_probe_one(sdev, NULL, NULL);
+ err = sparc_lance_probe_one(op, NULL, NULL);
return err;
}
-static int __devexit sunlance_sbus_remove(struct of_device *dev)
+static int __devexit sunlance_sbus_remove(struct of_device *op)
{
- struct lance_private *lp = dev_get_drvdata(&dev->dev);
+ struct lance_private *lp = dev_get_drvdata(&op->dev);
struct net_device *net_dev = lp->dev;
unregister_netdev(net_dev);
@@ -1568,12 +1529,12 @@
free_netdev(net_dev);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id sunlance_sbus_match[] = {
+static const struct of_device_id sunlance_sbus_match[] = {
{
.name = "le",
},
@@ -1593,17 +1554,12 @@
/* 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, &sbus_bus_type);
+ return of_register_driver(&sunlance_sbus_driver, &of_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/drivers/net/sunqe.c b/drivers/net/sunqe.c
index e811331..f636447 100644
--- a/drivers/net/sunqe.c
+++ b/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 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 1999, 2003, 2006, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -24,13 +24,15 @@
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
#include <asm/idprom.h>
-#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/auxio.h>
@@ -40,8 +42,8 @@
#include "sunqe.h"
#define DRV_NAME "sunqe"
-#define DRV_VERSION "4.0"
-#define DRV_RELDATE "June 23, 2006"
+#define DRV_VERSION "4.1"
+#define DRV_RELDATE "August 27, 2008"
#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
@@ -690,12 +692,18 @@
/* 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");
- sprintf(info->bus_info, "SBUS:%d",
- qep->qe_sdev->slot);
+
+ op = qep->op;
+ regs = of_get_property(op->node, "reg", NULL);
+ if (regs)
+ sprintf(info->bus_info, "SBUS:%d", regs->which_io);
+
}
static u32 qe_get_link(struct net_device *dev)
@@ -717,11 +725,11 @@
};
/* This is only called once at boot time for each card probed. */
-static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
+static void qec_init_once(struct sunqec *qecp, struct of_device *op)
{
u8 bsizes = qecp->qec_bursts;
- if (sbus_can_burst64(qsdev) && (bsizes & DMA_BURST64)) {
+ if (sbus_can_burst64() && (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);
@@ -735,15 +743,15 @@
sbus_writel(GLOB_PSIZE_2048, qecp->gregs + GLOB_PSIZE);
/* Set the local memsize register, divided up to one piece per QE channel. */
- sbus_writel((qsdev->reg_addrs[1].reg_size >> 2),
+ sbus_writel((resource_size(&op->resource[1]) >> 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((qsdev->reg_addrs[1].reg_size >> 2) >> 1,
+ sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1,
qecp->gregs + GLOB_TSIZE);
- sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1,
+ sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1,
qecp->gregs + GLOB_RSIZE);
}
@@ -767,24 +775,21 @@
return bsizes;
}
-static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev)
+static struct sunqec * __devinit get_qec(struct of_device *child)
{
- struct sbus_dev *qec_sdev = child_sdev->parent;
+ struct of_device *op = to_of_device(child->dev.parent);
struct sunqec *qecp;
- for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) {
- if (qecp->qec_sdev == qec_sdev)
- break;
- }
+ qecp = dev_get_drvdata(&op->dev);
if (!qecp) {
qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL);
if (qecp) {
u32 ctrl;
- qecp->qec_sdev = qec_sdev;
- qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0,
- GLOB_REG_SIZE,
- "QEC Global Registers");
+ qecp->op = op;
+ qecp->gregs = of_ioremap(&op->resource[0], 0,
+ GLOB_REG_SIZE,
+ "QEC Global Registers");
if (!qecp->gregs)
goto fail;
@@ -799,16 +804,18 @@
if (qec_global_reset(qecp->gregs))
goto fail;
- qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node);
+ qecp->qec_bursts = qec_get_burst(op->node);
- qec_init_once(qecp, qec_sdev);
+ qec_init_once(qecp, op);
- if (request_irq(qec_sdev->irqs[0], &qec_interrupt,
+ if (request_irq(op->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;
}
@@ -818,17 +825,17 @@
fail:
if (qecp->gregs)
- sbus_iounmap(qecp->gregs, GLOB_REG_SIZE);
+ of_iounmap(&op->resource[0], qecp->gregs, GLOB_REG_SIZE);
kfree(qecp);
return NULL;
}
-static int __devinit qec_ether_init(struct sbus_dev *sdev)
+static int __devinit qec_ether_init(struct of_device *op)
{
static unsigned version_printed;
struct net_device *dev;
- struct sunqe *qe;
struct sunqec *qecp;
+ struct sunqe *qe;
int i, res;
if (version_printed++ == 0)
@@ -842,49 +849,42 @@
qe = netdev_priv(dev);
- 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++;
- }
- }
+ res = -ENODEV;
+
+ i = of_getintprop_default(op->node, "channel#", -1);
+ if (i == -1)
+ goto fail;
qe->channel = i;
spin_lock_init(&qe->lock);
- res = -ENODEV;
- qecp = get_qec(sdev);
+ qecp = get_qec(op);
if (!qecp)
goto fail;
qecp->qes[qe->channel] = qe;
qe->dev = dev;
qe->parent = qecp;
- qe->qe_sdev = sdev;
+ qe->op = op;
res = -ENOMEM;
- qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0,
- CREG_REG_SIZE, "QEC Channel Registers");
+ qe->qcregs = of_ioremap(&op->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 = sbus_ioremap(&qe->qe_sdev->resource[1], 0,
- MREGS_REG_SIZE, "QE MACE Registers");
+ qe->mregs = of_ioremap(&op->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 = 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);
+ 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);
if (qe->qe_block == NULL || qe->qblock_dvma == 0 ||
qe->buffers == NULL || qe->buffers_dvma == 0)
goto fail;
@@ -892,7 +892,7 @@
/* Stop this QE. */
qe_stop(qe);
- SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+ SET_NETDEV_DEV(dev, &op->dev);
dev->open = qe_open;
dev->stop = qe_close;
@@ -900,7 +900,7 @@
dev->set_multicast_list = qe_set_multicast;
dev->tx_timeout = qe_tx_timeout;
dev->watchdog_timeo = 5*HZ;
- dev->irq = sdev->irqs[0];
+ dev->irq = op->irqs[0];
dev->dma = 0;
dev->ethtool_ops = &qe_ethtool_ops;
@@ -908,7 +908,7 @@
if (res)
goto fail;
- dev_set_drvdata(&sdev->ofdev.dev, qe);
+ dev_set_drvdata(&op->dev, qe);
printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel);
for (i = 0; i < 6; i++)
@@ -922,58 +922,50 @@
fail:
if (qe->qcregs)
- sbus_iounmap(qe->qcregs, CREG_REG_SIZE);
+ of_iounmap(&op->resource[0], qe->qcregs, CREG_REG_SIZE);
if (qe->mregs)
- sbus_iounmap(qe->mregs, MREGS_REG_SIZE);
+ of_iounmap(&op->resource[1], qe->mregs, MREGS_REG_SIZE);
if (qe->qe_block)
- sbus_free_consistent(qe->qe_sdev,
- PAGE_SIZE,
- qe->qe_block,
- qe->qblock_dvma);
+ dma_free_coherent(&op->dev, PAGE_SIZE,
+ qe->qe_block, qe->qblock_dvma);
if (qe->buffers)
- sbus_free_consistent(qe->qe_sdev,
- sizeof(struct sunqe_buffers),
- qe->buffers,
- qe->buffers_dvma);
+ dma_free_coherent(&op->dev,
+ sizeof(struct sunqe_buffers),
+ qe->buffers,
+ qe->buffers_dvma);
free_netdev(dev);
return res;
}
-static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit qec_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
- return qec_ether_init(sdev);
+ return qec_ether_init(op);
}
-static int __devexit qec_sbus_remove(struct of_device *dev)
+static int __devexit qec_sbus_remove(struct of_device *op)
{
- struct sunqe *qp = dev_get_drvdata(&dev->dev);
+ struct sunqe *qp = dev_get_drvdata(&op->dev);
struct net_device *net_dev = qp->dev;
unregister_netdev(net_dev);
- 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);
+ 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);
free_netdev(net_dev);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id qec_sbus_match[] = {
+static const struct of_device_id qec_sbus_match[] = {
{
.name = "qe",
},
@@ -991,7 +983,7 @@
static int __init qec_init(void)
{
- return of_register_driver(&qec_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&qec_sbus_driver, &of_bus_type);
}
static void __exit qec_exit(void)
@@ -1000,11 +992,11 @@
while (root_qec_dev) {
struct sunqec *next = root_qec_dev->next_module;
+ struct of_device *op = root_qec_dev->op;
- free_irq(root_qec_dev->qec_sdev->irqs[0],
- (void *) root_qec_dev);
- sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE);
-
+ free_irq(op->irqs[0], (void *) root_qec_dev);
+ of_iounmap(&op->resource[0], root_qec_dev->gregs,
+ GLOB_REG_SIZE);
kfree(root_qec_dev);
root_qec_dev = next;
diff --git a/drivers/net/sunqe.h b/drivers/net/sunqe.h
index 347c8dd..5813a7b 100644
--- a/drivers/net/sunqe.h
+++ b/drivers/net/sunqe.h
@@ -314,7 +314,7 @@
void __iomem *gregs; /* QEC Global Registers */
struct sunqe *qes[4]; /* Each child MACE */
unsigned int qec_bursts; /* Support burst sizes */
- struct sbus_dev *qec_sdev; /* QEC's SBUS device */
+ struct of_device *op; /* QEC's OF device */
struct sunqec *next_module; /* List of all QECs in system */
};
@@ -342,7 +342,7 @@
__u32 buffers_dvma; /* DVMA visible address. */
struct sunqec *parent;
u8 mconfig; /* Base MACE mconfig value */
- struct sbus_dev *qe_sdev; /* QE's SBUS device struct */
+ struct of_device *op; /* QE's OF device struct */
struct net_device *dev; /* QE's netdevice struct */
int channel; /* Who am I? */
};
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index 6415ce1..a720065 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -1,6 +1,6 @@
/* sunvnet.c: Sun LDOM Virtual Network Driver.
*
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/module.h>
@@ -1260,7 +1260,7 @@
return 0;
}
-static struct vio_device_id vnet_port_match[] = {
+static const struct vio_device_id vnet_port_match[] = {
{
.type = "vnet-port",
},
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index c749bdb..3c3dd40 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1794,10 +1794,10 @@
static int __init netif_init(void)
{
- if (!is_running_on_xen())
+ if (!xen_domain())
return -ENODEV;
- if (is_initial_xendomain())
+ if (xen_initial_domain())
return 0;
printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");
@@ -1809,7 +1809,7 @@
static void __exit netif_exit(void)
{
- if (is_initial_xendomain())
+ if (xen_initial_domain())
return;
xenbus_unregister_driver(&netfront);
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 9d595aa..065f229 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -26,6 +26,8 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/parport.h>
@@ -34,7 +36,6 @@
#include <asm/io.h>
#include <asm/oplib.h> /* OpenProm Library */
-#include <asm/sbus.h>
#include <asm/dma.h> /* BPP uses LSI 64854 for DMA */
#include <asm/irq.h>
#include <asm/sunbpp.h>
@@ -285,38 +286,37 @@
.owner = THIS_MODULE,
};
-static int __devinit init_one_port(struct sbus_dev *sdev)
+static int __devinit bpp_probe(struct of_device *op, const struct of_device_id *match)
{
- struct parport *p;
- /* at least in theory there may be a "we don't dma" case */
struct parport_operations *ops;
- void __iomem *base;
- int irq, dma, err = 0, size;
struct bpp_regs __iomem *regs;
+ int irq, dma, err = 0, size;
unsigned char value_tcr;
+ void __iomem *base;
+ struct parport *p;
- irq = sdev->irqs[0];
- base = sbus_ioremap(&sdev->resource[0], 0,
- sdev->reg_addrs[0].reg_size,
- "sunbpp");
+ irq = op->irqs[0];
+ base = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]),
+ "sunbpp");
if (!base)
return -ENODEV;
- size = sdev->reg_addrs[0].reg_size;
+ size = resource_size(&op->resource[0]);
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 = &sdev->ofdev.dev;
+ p->dev = &op->dev;
if ((err = request_irq(p->irq, parport_irq_handler,
IRQF_SHARED, p->name, p)) != 0) {
@@ -333,7 +333,7 @@
printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base);
- dev_set_drvdata(&sdev->ofdev.dev, p);
+ dev_set_drvdata(&op->dev, p);
parport_announce_port(p);
@@ -346,21 +346,14 @@
kfree(ops);
out_unmap:
- sbus_iounmap(base, size);
+ of_iounmap(&op->resource[0], base, size);
return err;
}
-static int __devinit bpp_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devexit bpp_remove(struct of_device *op)
{
- 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(&dev->dev);
+ struct parport *p = dev_get_drvdata(&op->dev);
struct parport_operations *ops = p->ops;
parport_remove_port(p);
@@ -370,16 +363,16 @@
free_irq(p->irq, p);
}
- sbus_iounmap((void __iomem *) p->base, p->size);
+ of_iounmap(&op->resource[0], (void __iomem *) p->base, p->size);
parport_put_port(p);
kfree(ops);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id bpp_match[] = {
+static const struct of_device_id bpp_match[] = {
{
.name = "SUNW,bpp",
},
@@ -397,7 +390,7 @@
static int __init parport_sunbpp_init(void)
{
- return of_register_driver(&bpp_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&bpp_sbus_driver, &of_bus_type);
}
static void __exit parport_sunbpp_exit(void)
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 1982f8b..63bb579 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -58,7 +58,7 @@
config BATTERY_WM97XX
bool "WM97xx generic battery driver"
- depends on TOUCHSCREEN_WM97XX
+ depends on TOUCHSCREEN_WM97XX=y
help
Say Y to enable support for battery measured by WM97xx aux port.
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 9a9755c..b57fba5 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -329,7 +329,7 @@
config RTC_DRV_CMOS
tristate "PC-style 'CMOS'"
- depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS
+ depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS || SPARC64
default y if X86
help
Say "yes" here to get direct support for the real time clock
@@ -406,14 +406,26 @@
will be called rtc-m48t86.
config RTC_DRV_M48T59
- tristate "ST M48T59"
+ tristate "ST M48T59/M48T08/M48T02"
help
If you say Y here you will get support for the
- ST M48T59 RTC chip.
+ ST M48T59 RTC chip and compatible ST M48T08 and M48T02.
+
+ These chips are usually found in Sun SPARC and UltraSPARC
+ workstations.
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
@@ -583,4 +595,18 @@
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/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 18622ef..10f41f8 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -38,6 +38,9 @@
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/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c
new file mode 100644
index 0000000..189a018
--- /dev/null
+++ b/drivers/rtc/rtc-bq4802.c
@@ -0,0 +1,230 @@
+/* rtc-bq4802.c: TI BQ4802 RTC driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+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/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index b184367..b23af0c 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -636,7 +636,7 @@
*/
#if defined(CONFIG_ATARI)
address_space = 64;
-#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__sparc__)
address_space = 128;
#else
#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
@@ -699,7 +699,8 @@
/* FIXME teach the alarm code how to handle binary mode;
* <asm-generic/rtc.h> doesn't know 12-hour mode either.
*/
- if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) {
+ if (is_valid_irq(rtc_irq) &&
+ (!(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/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index 013e6c1..ce4eff6 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -24,8 +24,9 @@
#define NO_IRQ (-1)
#endif
-#define M48T59_READ(reg) pdata->read_byte(dev, reg)
-#define M48T59_WRITE(val, reg) pdata->write_byte(dev, reg, val)
+#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_SET_BITS(mask, reg) \
M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg))
@@ -34,7 +35,6 @@
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,7 +82,8 @@
tm->tm_mday = BCD2BIN(M48T59_READ(M48T59_MDAY));
val = M48T59_READ(M48T59_WDAY);
- if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
+ if ((pdata->type == M48T59RTC_TYPE_M48T59) &&
+ (val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
dev_dbg(dev, "Century bit is enabled\n");
tm->tm_year += 100; /* one century */
}
@@ -126,7 +127,7 @@
M48T59_WRITE((BIN2BCD(tm->tm_mon + 1) & 0x1F), M48T59_MONTH);
M48T59_WRITE(BIN2BCD(tm->tm_year % 100), M48T59_YEAR);
- if (tm->tm_year/100)
+ if (pdata->type == M48T59RTC_TYPE_M48T59 && (tm->tm_year / 100))
val = (M48T59_WDAY_CEB | M48T59_WDAY_CB);
val |= (BIN2BCD(tm->tm_wday) & 0x07);
M48T59_WRITE(val, M48T59_WDAY);
@@ -310,6 +311,11 @@
.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)
@@ -321,7 +327,7 @@
ssize_t cnt = 0;
unsigned long flags;
- for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
+ for (; size > 0 && pos < pdata->offset; cnt++, size--) {
spin_lock_irqsave(&m48t59->lock, flags);
*buf++ = M48T59_READ(cnt);
spin_unlock_irqrestore(&m48t59->lock, flags);
@@ -341,7 +347,7 @@
ssize_t cnt = 0;
unsigned long flags;
- for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
+ for (; size > 0 && pos < pdata->offset; cnt++, size--) {
spin_lock_irqsave(&m48t59->lock, flags);
M48T59_WRITE(*buf++, cnt);
spin_unlock_irqrestore(&m48t59->lock, flags);
@@ -358,7 +364,6 @@
},
.read = m48t59_nvram_read,
.write = m48t59_nvram_write,
- .size = M48T59_NVRAM_SIZE,
};
static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
@@ -367,6 +372,8 @@
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);
@@ -391,6 +398,8 @@
/* 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)
@@ -403,10 +412,14 @@
if (!m48t59)
return -ENOMEM;
- m48t59->size = res->end - res->start + 1;
- m48t59->ioaddr = ioremap(res->start, m48t59->size);
- if (!m48t59->ioaddr)
- goto out;
+ 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;
+ }
/* Try to get irq number. We also can work in
* the mode without IRQ.
@@ -421,14 +434,36 @@
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("m48t59", &pdev->dev,
- &m48t59_rtc_ops, THIS_MODULE);
+ m48t59->rtc = rtc_device_register(name, &pdev->dev, 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;
@@ -452,11 +487,12 @@
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)
+ if (m48t59->ioaddr && !pdata->ioaddr)
iounmap(m48t59->ioaddr);
if (m48t59->irq != NO_IRQ)
free_irq(m48t59->irq, &pdev->dev);
@@ -491,5 +527,5 @@
module_exit(m48t59_rtc_exit);
MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>");
-MODULE_DESCRIPTION("M48T59 RTC driver");
+MODULE_DESCRIPTION("M48T59/M48T02/M48T08 RTC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c
new file mode 100644
index 0000000..7ccb0dd
--- /dev/null
+++ b/drivers/rtc/rtc-starfire.c
@@ -0,0 +1,120 @@
+/* rtc-starfire.c: Starfire platform RTC driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+#include <asm/oplib.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+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/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c
new file mode 100644
index 0000000..2012ccb
--- /dev/null
+++ b/drivers/rtc/rtc-sun4v.c
@@ -0,0 +1,153 @@
+/* rtc-sun4c.c: Hypervisor based RTC for SUN4V systems.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+#include <asm/hypervisor.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+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/drivers/sbus/Makefile b/drivers/sbus/Makefile
index 7b1d24d9..e94dc25 100644
--- a/drivers/sbus/Makefile
+++ b/drivers/sbus/Makefile
@@ -2,8 +2,4 @@
# Makefile for the linux kernel.
#
-ifneq ($(ARCH),m68k)
-obj-y := sbus.o dvma.o
-endif
-
obj-$(CONFIG_SBUSCHAR) += char/
diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig
index 400c65b..73cde85 100644
--- a/drivers/sbus/char/Kconfig
+++ b/drivers/sbus/char/Kconfig
@@ -13,16 +13,6 @@
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
@@ -30,26 +20,9 @@
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 && SPARC32
+ depends on EXPERIMENTAL
help
Say Y here to directly support the TS102 Microcontroller interface
on the Tadpole Sparcbook 3. This device handles power-management
diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile
index 7ab060e..78b6183 100644
--- a/drivers/sbus/char/Makefile
+++ b/drivers/sbus/char/Makefile
@@ -7,18 +7,12 @@
# 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/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
index 0bde269..15dab96 100644
--- a/drivers/sbus/char/bbc_envctrl.c
+++ b/drivers/sbus/char/bbc_envctrl.c
@@ -1,15 +1,15 @@
-/* $Id: bbc_envctrl.c,v 1.4 2001/04/06 16:48:08 davem Exp $
- * bbc_envctrl.c: UltraSPARC-III environment control driver.
+/* bbc_envctrl.c: UltraSPARC-III environment control driver.
*
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/kmod.h>
#include <linux/reboot.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/oplib.h>
-#include <asm/ebus.h>
#include "bbc_i2c.h"
#include "max1617.h"
@@ -75,43 +75,8 @@
{ 65, 55, 40, 5, -5, -10 },
};
-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;
+static LIST_HEAD(all_temps);
+static LIST_HEAD(all_fans);
#define CPU_FAN_REG 0xf0
#define SYS_FAN_REG 0xf2
@@ -330,7 +295,7 @@
* recommend we do, and perform that action on all the
* fans.
*/
- for (tp = all_bbc_temps; tp; tp = tp->next) {
+ list_for_each_entry(tp, &all_temps, glob_list) {
if (tp->fan_todo[which_fan] == FAN_FULLBLAST) {
decision = FAN_FULLBLAST;
break;
@@ -439,7 +404,7 @@
/* Since we will not be monitoring things anymore, put
* the fans on full blast.
*/
- for (fp = all_bbc_fans; fp; fp = fp->next) {
+ list_for_each_entry(fp, &all_fans, glob_list) {
fp->cpu_fan_speed = FAN_SPEED_MAX;
fp->system_fan_speed = FAN_SPEED_MAX;
fp->psupply_fan_on = 1;
@@ -463,11 +428,11 @@
if (kthread_should_stop())
break;
- for (tp = all_bbc_temps; tp; tp = tp->next) {
+ list_for_each_entry(tp, &all_temps, glob_list) {
get_current_temps(tp);
analyze_temps(tp, &last_warning_jiffies);
}
- for (fp = all_bbc_fans; fp; fp = fp->next)
+ list_for_each_entry(fp, &all_fans, glob_list)
maybe_new_fan_speeds(fp);
}
printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n");
@@ -477,7 +442,8 @@
return 0;
}
-static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
+static void attach_one_temp(struct bbc_i2c_bus *bp, struct of_device *op,
+ int temp_idx)
{
struct bbc_cpu_temperature *tp;
@@ -485,20 +451,17 @@
if (!tp)
return;
- tp->client = bbc_i2c_attach(echild);
+ tp->client = bbc_i2c_attach(bp, op);
if (!tp->client) {
kfree(tp);
return;
}
+
tp->index = temp_idx;
- {
- struct bbc_cpu_temperature **tpp = &all_bbc_temps;
- while (*tpp)
- tpp = &((*tpp)->next);
- tp->next = NULL;
- *tpp = tp;
- }
+
+ list_add(&tp->glob_list, &all_temps);
+ list_add(&tp->bp_list, &bp->temps);
/* Tell it to convert once every 5 seconds, clear all cfg
* bits.
@@ -524,7 +487,8 @@
tp->fan_todo[FAN_CPU] = FAN_SAME;
}
-static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
+static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op,
+ int fan_idx)
{
struct bbc_fan_control *fp;
@@ -532,7 +496,7 @@
if (!fp)
return;
- fp->client = bbc_i2c_attach(echild);
+ fp->client = bbc_i2c_attach(bp, op);
if (!fp->client) {
kfree(fp);
return;
@@ -540,13 +504,8 @@
fp->index = fan_idx;
- {
- struct bbc_fan_control **fpp = &all_bbc_fans;
- while (*fpp)
- fpp = &((*fpp)->next);
- fp->next = NULL;
- *fpp = fp;
- }
+ list_add(&fp->glob_list, &all_fans);
+ list_add(&fp->bp_list, &bp->fans);
/* The i2c device controlling the fans is write-only.
* So the only way to keep track of the current power
@@ -563,18 +522,18 @@
set_fan_speeds(fp);
}
-int bbc_envctrl_init(void)
+int bbc_envctrl_init(struct bbc_i2c_bus *bp)
{
- struct linux_ebus_child *echild;
+ struct of_device *op;
int temp_index = 0;
int fan_index = 0;
int devidx = 0;
- 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++);
+ 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++);
}
if (temp_index != 0 && fan_index != 0) {
kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
@@ -597,26 +556,22 @@
kfree(fp);
}
-void bbc_envctrl_cleanup(void)
+void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp)
{
- struct bbc_cpu_temperature *tp;
- struct bbc_fan_control *fp;
+ struct bbc_cpu_temperature *tp, *tpos;
+ struct bbc_fan_control *fp, *fpos;
kthread_stop(kenvctrld_task);
- tp = all_bbc_temps;
- while (tp != NULL) {
- struct bbc_cpu_temperature *next = tp->next;
+ list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) {
+ list_del(&tp->bp_list);
+ list_del(&tp->glob_list);
destroy_one_temp(tp);
- tp = next;
}
- all_bbc_temps = NULL;
- fp = all_bbc_fans;
- while (fp != NULL) {
- struct bbc_fan_control *next = fp->next;
+ list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) {
+ list_del(&fp->bp_list);
+ list_del(&fp->glob_list);
destroy_one_fan(fp);
- fp = next;
}
- all_bbc_fans = NULL;
}
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index ac8ef2c..f08e169 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -1,8 +1,7 @@
-/* $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
+/* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III
* platforms.
*
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -14,9 +13,8 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <asm/oplib.h>
-#include <asm/ebus.h>
-#include <asm/spitfire.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/bbc.h>
#include <asm/io.h>
@@ -53,54 +51,12 @@
* The second controller also connects to the smartcard reader, if present.
*/
-#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)
+static void set_device_claimage(struct bbc_i2c_bus *bp, struct of_device *op, int val)
{
int i;
for (i = 0; i < NUM_CHILDREN; i++) {
- 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) {
+ if (bp->devs[i].device == op) {
bp->devs[i].client_claimed = val;
return;
}
@@ -110,61 +66,47 @@
#define claim_device(BP,ECHILD) set_device_claimage(BP,ECHILD,1)
#define release_device(BP,ECHILD) set_device_claimage(BP,ECHILD,0)
-static struct bbc_i2c_bus *find_bus_for_device(struct linux_ebus_child *echild)
+struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index)
{
- struct bbc_i2c_bus *bp = all_bbc_i2c;
+ struct of_device *op = NULL;
+ int curidx = 0, i;
- while (bp != NULL) {
- if (find_device(bp, echild) != 0)
+ for (i = 0; i < NUM_CHILDREN; i++) {
+ if (!(op = bp->devs[i].device))
break;
- bp = bp->next;
+ if (curidx == index)
+ goto out;
+ op = NULL;
+ curidx++;
}
- 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 echild;
+ return op;
return NULL;
}
-struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild)
+struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *op)
{
- 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->echild = echild;
- client->bus = echild->resource[0].start;
- client->address = echild->resource[1].start;
+ client->op = op;
- claim_device(bp, echild);
+ reg = of_get_property(op->node, "reg", NULL);
+ if (!reg) {
+ kfree(client);
+ return NULL;
+ }
+
+ client->bus = reg[0];
+ client->address = reg[1];
+
+ claim_device(bp, op);
return client;
}
@@ -172,9 +114,9 @@
void bbc_i2c_detach(struct bbc_i2c_client *client)
{
struct bbc_i2c_bus *bp = client->bp;
- struct linux_ebus_child *echild = client->echild;
+ struct of_device *op = client->op;
- release_device(bp, echild);
+ release_device(bp, op);
kfree(client);
}
@@ -355,44 +297,43 @@
writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0);
}
-static int __init attach_one_i2c(struct linux_ebus_device *edev, int index)
+static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int index)
{
struct bbc_i2c_bus *bp;
- struct linux_ebus_child *echild;
+ struct device_node *dp;
int entry;
bp = kzalloc(sizeof(*bp), GFP_KERNEL);
if (!bp)
- return -ENOMEM;
+ return NULL;
- bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2);
+ bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs");
if (!bp->i2c_control_regs)
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->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel");
+ if (!bp->i2c_bussel_reg)
+ goto fail;
bp->waiting = 0;
init_waitqueue_head(&bp->wq);
- if (request_irq(edev->irqs[0], bbc_i2c_interrupt,
+ if (request_irq(op->irqs[0], bbc_i2c_interrupt,
IRQF_SHARED, "bbc_i2c", bp))
goto fail;
bp->index = index;
- bp->bus_edev = edev;
+ bp->op = op;
spin_lock_init(&bp->lock);
- bp->next = all_bbc_i2c;
- all_bbc_i2c = bp;
entry = 0;
- for (echild = edev->children;
- echild && entry < 8;
- echild = echild->next, entry++) {
- bp->devs[entry].device = echild;
+ 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;
bp->devs[entry].client_claimed = 0;
}
@@ -406,86 +347,90 @@
reset_one_i2c(bp);
- return 0;
+ return bp;
fail:
if (bp->i2c_bussel_reg)
- iounmap(bp->i2c_bussel_reg);
+ of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1);
if (bp->i2c_control_regs)
- iounmap(bp->i2c_control_regs);
+ of_iounmap(&op->resource[0], bp->i2c_control_regs, 2);
kfree(bp);
- return -EINVAL;
+ return NULL;
}
-static int __init bbc_present(void)
+extern int bbc_envctrl_init(struct bbc_i2c_bus *bp);
+extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp);
+
+static int __devinit bbc_i2c_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct linux_ebus *ebus = NULL;
- struct linux_ebus_device *edev = NULL;
-
- 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 linux_ebus *ebus = NULL;
- struct linux_ebus_device *edev = NULL;
+ struct bbc_i2c_bus *bp;
int err, index = 0;
- if ((tlb_type != cheetah && tlb_type != cheetah_plus) ||
- !bbc_present())
- return -ENODEV;
+ bp = attach_one_i2c(op, index);
+ if (!bp)
+ return -EINVAL;
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_node->name, "i2c")) {
- if (!attach_one_i2c(edev, index))
- index++;
- }
- }
+ 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);
}
- if (!index)
- return -ENODEV;
-
- err = bbc_envctrl_init();
- if (err)
- bbc_i2c_cleanup();
return err;
}
-static void bbc_i2c_cleanup(void)
+static int __devexit bbc_i2c_remove(struct of_device *op)
{
- struct bbc_i2c_bus *bp = all_bbc_i2c;
+ struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev);
- bbc_envctrl_cleanup();
+ bbc_envctrl_cleanup(bp);
- while (bp != NULL) {
- struct bbc_i2c_bus *next = bp->next;
+ free_irq(op->irqs[0], bp);
- free_irq(bp->bus_edev->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);
- if (bp->i2c_bussel_reg)
- iounmap(bp->i2c_bussel_reg);
- if (bp->i2c_control_regs)
- iounmap(bp->i2c_control_regs);
+ kfree(bp);
- kfree(bp);
+ return 0;
+}
- bp = next;
- }
- all_bbc_i2c = NULL;
+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),
+};
+
+static int __init bbc_i2c_init(void)
+{
+ return of_register_driver(&bbc_i2c_driver, &of_bus_type);
+}
+
+static void __exit bbc_i2c_exit(void)
+{
+ of_unregister_driver(&bbc_i2c_driver);
}
module_init(bbc_i2c_init);
-module_exit(bbc_i2c_cleanup);
+module_exit(bbc_i2c_exit);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/bbc_i2c.h b/drivers/sbus/char/bbc_i2c.h
index fb01bd1..83c4811 100644
--- a/drivers/sbus/char/bbc_i2c.h
+++ b/drivers/sbus/char/bbc_i2c.h
@@ -1,14 +1,79 @@
-/* $Id: bbc_i2c.h,v 1.2 2001/04/02 09:59:25 davem Exp $ */
#ifndef _BBC_I2C_H
#define _BBC_I2C_H
-#include <asm/ebus.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/list.h>
-struct bbc_i2c_client;
+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];
+};
/* Probing and attachment. */
-extern struct linux_ebus_child *bbc_i2c_getdev(int);
-extern struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *);
+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 void bbc_i2c_detach(struct bbc_i2c_client *);
/* Register read/write. NOTE: Blocking! */
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
deleted file mode 100644
index bba21e05..0000000
--- a/drivers/sbus/char/bpp.c
+++ /dev/null
@@ -1,1055 +0,0 @@
-/*
- * 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 <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/major.h>
-#include <linux/smp_lock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#if defined(__i386__)
-# include <asm/system.h>
-#endif
-
-#if defined(__sparc__)
-# include <linux/init.h>
-# include <linux/delay.h> /* udelay() */
-
-# include <asm/oplib.h> /* OpenProm Library */
-# include <asm/sbus.h>
-#endif
-
-#include <asm/bpp.h>
-
-#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; testvalue<BPP_DELAY; testvalue++)
- ;
- testvalue = inb_p(lpAddr);
- if (testvalue == BPP_PROBE_CODE) {
- unsigned save;
- instances[idx].present = 1;
-
- save = inb_p(lpAddr+2);
- for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
- ;
- outb_p(save|0x20, lpAddr+2);
- for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
- ;
- outb_p(~BPP_PROBE_CODE, lpAddr);
- for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
- ;
- testvalue = inb_p(lpAddr);
- if ((testvalue&0xff) == (0xff&~BPP_PROBE_CODE))
- instances[idx].enhanced = 0;
- else
- instances[idx].enhanced = 1;
- outb_p(save, lpAddr+2);
- }
- else {
- release_region(lpAddr,3);
- }
- /*
- * Leave the port in compat idle mode.
- */
- set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx);
-
- printk("bpp%d: Port at 0x%03x: Enhanced mode %s\n", idx, base_addrs[idx],
- instances[idx].enhanced? "SUPPORTED" : "UNAVAILABLE");
-}
-
-static inline void freeLptPort(int idx)
-{
- release_region(base_addrs[idx], 3);
-}
-
-#endif
-
-#if defined(__sparc__)
-
-static void __iomem *map_bpp(struct sbus_dev *dev, int idx)
-{
- return sbus_ioremap(&dev->resource[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/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
deleted file mode 100644
index 23abfdf..0000000
--- a/drivers/sbus/char/cpwatchdog.c
+++ /dev/null
@@ -1,858 +0,0 @@
-/* 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 <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/major.h>
-#include <linux/init.h>
-#include <linux/miscdevice.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/smp_lock.h>
-#include <linux/io.h>
-#include <asm/irq.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
-#include <asm/uaccess.h>
-
-#include <asm/watchdog.h>
-
-#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 <ebrower@usa.net>");
-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/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index d8f5c0c..2550af4 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -1,10 +1,7 @@
-/* $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
+/* display7seg.c - Driver implementation for the 7-segment display
+ * present on Sun Microsystems CP1400 and CP1500
*
* Copyright (c) 2000 Eric Brower (ebrower@usa.net)
- *
*/
#include <linux/kernel.h>
@@ -16,22 +13,20 @@
#include <linux/miscdevice.h>
#include <linux/ioport.h> /* request_region */
#include <linux/smp_lock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/atomic.h>
-#include <asm/ebus.h> /* EBus device */
-#include <asm/oplib.h> /* OpenProm Library */
#include <asm/uaccess.h> /* put_/get_user */
#include <asm/io.h>
#include <asm/display7seg.h>
#define D7S_MINOR 193
-#define D7S_OBPNAME "display7seg"
-#define D7S_DEVNAME "d7s"
+#define DRIVER_NAME "d7s"
+#define PFX DRIVER_NAME ": "
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).
@@ -46,20 +41,20 @@
* 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_param(sol_compat, int, 0);
+MODULE_PARM_DESC(sol_compat,
+ "Disables documented functionality omitted from Solaris driver");
-MODULE_AUTHOR
- ("Eric Brower <ebrower@usa.net>");
-MODULE_DESCRIPTION
- ("7-Segment Display driver for Sun Microsystems CP1400/1500");
+MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
+MODULE_DESCRIPTION("7-Segment Display driver for Sun Microsystems CP1400/1500");
MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE
- ("d7s");
-#endif /* ifdef MODULE */
+MODULE_SUPPORTED_DEVICE("d7s");
+
+struct d7s {
+ void __iomem *regs;
+ bool flipped;
+};
+struct d7s *d7s_device;
/*
* Register block address- see header for details
@@ -72,22 +67,6 @@
* 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)
@@ -106,12 +85,15 @@
* are not operating in solaris-compat mode
*/
if (atomic_dec_and_test(&d7s_users) && !sol_compat) {
- int regval = 0;
+ struct d7s *p = d7s_device;
+ u8 regval = 0;
- regval = readb(d7s_regs);
- (0 == d7s_obpflipped()) ?
- writeb(regval |= D7S_FLIP, d7s_regs):
- writeb(regval &= ~D7S_FLIP, d7s_regs);
+ regval = readb(p->regs);
+ if (p->flipped)
+ regval |= D7S_FLIP;
+ else
+ regval &= ~D7S_FLIP;
+ writeb(regval, p->regs);
}
return 0;
@@ -119,9 +101,10 @@
static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- __u8 regs = readb(d7s_regs);
- __u8 ireg = 0;
+ struct d7s *p = d7s_device;
+ u8 regs = readb(p->regs);
int error = 0;
+ u8 ireg = 0;
if (D7S_MINOR != iminor(file->f_path.dentry->d_inode))
return -ENODEV;
@@ -129,18 +112,20 @@
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 (0 != sol_compat) {
- (regs & D7S_FLIP) ?
- (ireg |= D7S_FLIP) : (ireg &= ~D7S_FLIP);
+ if (sol_compat) {
+ if (regs & D7S_FLIP)
+ ireg |= D7S_FLIP;
+ else
+ ireg &= ~D7S_FLIP;
}
- writeb(ireg, d7s_regs);
+ writeb(ireg, p->regs);
break;
case D7SIOCRD:
@@ -158,9 +143,11 @@
case D7SIOCTM:
/* toggle device mode-- flip display orientation */
- (regs & D7S_FLIP) ?
- (regs &= ~D7S_FLIP) : (regs |= D7S_FLIP);
- writeb(regs, d7s_regs);
+ if (regs & D7S_FLIP)
+ regs &= ~D7S_FLIP;
+ else
+ regs |= D7S_FLIP;
+ writeb(regs, p->regs);
break;
};
unlock_kernel();
@@ -176,69 +163,123 @@
.release = d7s_release,
};
-static struct miscdevice d7s_miscdev = { D7S_MINOR, D7S_DEVNAME, &d7s_fops };
+static struct miscdevice d7s_miscdev = {
+ .minor = D7S_MINOR,
+ .name = DRIVER_NAME,
+ .fops = &d7s_fops
+};
-static int __init d7s_init(void)
+static int __devinit d7s_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct linux_ebus *ebus = NULL;
- struct linux_ebus_device *edev = NULL;
- int iTmp = 0, regs = 0;
+ struct device_node *opts;
+ int err = -EINVAL;
+ struct d7s *p;
+ u8 regs;
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_node->name, D7S_OBPNAME))
- goto ebus_done;
- }
+ 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;
}
-ebus_done:
- if(!edev) {
- printk("%s: unable to locate device\n", D7S_DEVNAME);
- return -ENODEV;
+ err = misc_register(&d7s_miscdev);
+ if (err) {
+ printk(KERN_ERR PFX "Unable to acquire miscdevice minor %i\n",
+ D7S_MINOR);
+ goto out_iounmap;
}
- d7s_regs = ioremap(edev->resource[0].start, sizeof(__u8));
-
- 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;
- }
-
- /* OBP option "d7s-flipped?" is honored as default
- * for the device, and reset default when detached
+ /* 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);
+ regs = readb(p->regs);
+ opts = of_find_node_by_path("/options");
+ if (opts &&
+ of_get_property(opts, "d7s-flipped?", NULL))
+ p->flipped = true;
- 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") : (""));
+ 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;
+}
+
+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);
+ }
+
+ misc_deregister(&d7s_miscdev);
+ of_iounmap(&op->resource[0], p->regs, sizeof(u8));
+ kfree(p);
return 0;
}
-static void __exit d7s_cleanup(void)
+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)
{
- int regs = readb(d7s_regs);
+ return of_register_driver(&d7s_driver, &of_bus_type);
+}
- /* 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();
+static void __exit d7s_exit(void)
+{
+ of_unregister_driver(&d7s_driver);
}
module_init(d7s_init);
-module_exit(d7s_cleanup);
+module_exit(d7s_exit);
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index a408402..58e583b 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -1,5 +1,4 @@
-/* $Id: envctrl.c,v 1.25 2002/01/15 09:01:26 davem Exp $
- * envctrl.c: Temperature and Fan monitoring on Machines providing it.
+/* 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)
@@ -28,12 +27,16 @@
#include <linux/kmod.h>
#include <linux/reboot.h>
#include <linux/smp_lock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
-#include <asm/ebus.h>
#include <asm/uaccess.h>
#include <asm/envctrl.h>
#include <asm/io.h>
+#define DRIVER_NAME "envctrl"
+#define PFX DRIVER_NAME ": "
+
#define ENVCTRL_MINOR 162
#define PCF8584_ADDRESS 0x55
@@ -193,7 +196,7 @@
}
if (limit <= 0)
- printk(KERN_INFO "envctrl: Pin status will not clear.\n");
+ printk(KERN_INFO PFX "Pin status will not clear.\n");
}
/* Function Description: Test busy bit.
@@ -211,7 +214,7 @@
}
if (limit <= 0)
- printk(KERN_INFO "envctrl: Busy bit will not clear.\n");
+ printk(KERN_INFO PFX "Busy bit will not clear.\n");
}
/* Function Description: Send the address for a read access.
@@ -858,11 +861,10 @@
/* Function Description: Initialize i2c child device.
* Return: None.
*/
-static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
+static void envctrl_init_i2c_child(struct device_node *dp,
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. */
@@ -882,12 +884,12 @@
pchild->tables = kmalloc(tbls_size, GFP_KERNEL);
if (pchild->tables == NULL){
- printk("envctrl: Failed to allocate table.\n");
+ printk(KERN_ERR PFX "Failed to allocate table.\n");
return;
}
pval = of_get_property(dp, "tables", &len);
if (!pval || len <= 0) {
- printk("envctrl: Failed to get table.\n");
+ printk(KERN_ERR PFX "Failed to get table.\n");
return;
}
memcpy(pchild->tables, pval, len);
@@ -993,14 +995,14 @@
struct i2c_child_t *cputemp;
if (NULL == (cputemp = envctrl_get_i2c_child(ENVCTRL_CPUTEMP_MON))) {
- printk(KERN_ERR
- "envctrl: kenvctrld unable to monitor CPU temp-- exiting\n");
+ printk(KERN_ERR PFX
+ "kenvctrld unable to monitor CPU temp-- exiting\n");
return -ENODEV;
}
poll_interval = 5000; /* TODO env_mon_interval */
- printk(KERN_INFO "envctrl: %s starting...\n", current->comm);
+ printk(KERN_INFO PFX "%s starting...\n", current->comm);
for (;;) {
msleep_interruptible(poll_interval);
@@ -1022,54 +1024,35 @@
}
}
}
- printk(KERN_INFO "envctrl: %s exiting...\n", current->comm);
+ printk(KERN_INFO PFX "%s exiting...\n", current->comm);
return 0;
}
-static int __init envctrl_init(void)
+static int __devinit envctrl_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct linux_ebus *ebus = NULL;
- struct linux_ebus_device *edev = NULL;
- struct linux_ebus_child *edev_child = NULL;
- int err, i = 0;
+ struct device_node *dp;
+ int index, err;
- 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;
- }
+ if (i2c)
+ return -EINVAL;
+
+ 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;
- }
- }
- }
-
-done:
- if (!edev) {
- printk("envctrl: I2C device not found.\n");
- return -ENODEV;
+ dp = dp->sibling;
}
/* Set device address. */
@@ -1087,7 +1070,7 @@
/* Register the device as a minor miscellaneous device. */
err = misc_register(&envctrl_dev);
if (err) {
- printk("envctrl: Unable to get misc minor %d\n",
+ printk(KERN_ERR PFX "Unable to get misc minor %d\n",
envctrl_dev.minor);
goto out_iounmap;
}
@@ -1096,12 +1079,12 @@
* a next child device, so we decrement before reverse-traversal of
* child devices.
*/
- printk("envctrl: initialized ");
- for (--i; i >= 0; --i) {
+ printk(KERN_INFO PFX "Initialized ");
+ for (--index; index >= 0; --index) {
printk("[%s 0x%lx]%s",
- (I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") :
- ((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")),
- i2c_childlist[i].addr, (0 == i) ? ("\n") : (" "));
+ (I2C_ADC == i2c_childlist[index].i2ctype) ? "adc" :
+ ((I2C_GPIO == i2c_childlist[index].i2ctype) ? "gpio" : "unknown"),
+ i2c_childlist[index].addr, (0 == index) ? "\n" : " ");
}
kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
@@ -1115,26 +1098,54 @@
out_deregister:
misc_deregister(&envctrl_dev);
out_iounmap:
- iounmap(i2c);
- for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++)
- kfree(i2c_childlist[i].tables);
+ of_iounmap(&op->resource[0], i2c, 0x2);
+ for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++)
+ kfree(i2c_childlist[index].tables);
return err;
}
-static void __exit envctrl_cleanup(void)
+static int __devexit envctrl_remove(struct of_device *op)
{
- int i;
+ int index;
kthread_stop(kenvctrld_task);
- iounmap(i2c);
+ of_iounmap(&op->resource[0], i2c, 0x2);
misc_deregister(&envctrl_dev);
- for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++)
- kfree(i2c_childlist[i].tables);
+ 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);
}
module_init(envctrl_init);
-module_exit(envctrl_cleanup);
+module_exit(envctrl_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index 7d95e15..4108347 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -1,5 +1,4 @@
-/* $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.
+/* flash.c: Allow mmap access to the OBP Flash, for OBP updates.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*/
@@ -15,13 +14,13 @@
#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/ebus.h>
#include <asm/upa.h>
static DEFINE_SPINLOCK(flash_lock);
@@ -161,97 +160,68 @@
static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops };
-static int __init flash_init(void)
+static int __devinit flash_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- 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;
+ struct device_node *dp = op->node;
+ struct device_node *parent;
- 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;
+ parent = dp->parent;
- 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;
- }
-
- nregs = len / sizeof(ebus_regs[0]);
-
- flash.read_base = edev->resource[0].start;
- flash.read_size = ebus_regs[0].reg_size;
-
- 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
+ if (strcmp(parent->name, "sbus") &&
+ strcmp(parent->name, "sbi") &&
+ strcmp(parent->name, "ebus"))
return -ENODEV;
-#endif
- }
- printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n",
+ 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]);
+ }
+ flash.busy = 0;
+
+ printk(KERN_INFO "%s: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n",
+ op->node->full_name,
flash.read_base, flash.read_size,
flash.write_base, flash.write_size);
- err = misc_register(&flash_dev);
- if (err) {
- printk(KERN_ERR "flash: unable to get misc minor\n");
- return err;
- }
+ return misc_register(&flash_dev);
+}
+
+static int __devexit flash_remove(struct of_device *op)
+{
+ misc_deregister(&flash_dev);
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)
{
- misc_deregister(&flash_dev);
+ of_unregister_driver(&flash_driver);
}
module_init(flash_init);
diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/sbus/char/riowatchdog.c
deleted file mode 100644
index 88c0fc6..0000000
--- a/drivers/sbus/char/riowatchdog.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/* $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 David S. Miller (davem@redhat.com)
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
-
-#include <asm/io.h>
-#include <asm/ebus.h>
-#include <asm/bbc.h>
-#include <asm/oplib.h>
-#include <asm/uaccess.h>
-
-#include <asm/watchdog.h>
-
-/* RIO uses the NatSemi Super I/O power management logical device
- * as its' watchdog.
- *
- * When the watchdog triggers, it asserts a line to the BBC (Boot Bus
- * Controller) of the machine. The BBC can only be configured to
- * trigger a power-on reset when the signal is asserted. The BBC
- * can be configured to ignore the signal entirely as well.
- *
- * The only Super I/O device register we care about is at index
- * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255).
- * If set to zero, this disables the watchdog. When set, the system
- * must periodically (before watchdog expires) clear (set to zero) and
- * re-set the watchdog else it will trigger.
- *
- * There are two other indexed watchdog registers inside this Super I/O
- * logical device, but they are unused. The first, at index 0x06 is
- * the watchdog control and can be used to make the watchdog timer re-set
- * when the PS/2 mouse or serial lines show activity. The second, at
- * index 0x07 is merely a sampling of the line from the watchdog to the
- * BBC.
- *
- * The watchdog device generates no interrupts.
- */
-
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
-MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
-MODULE_SUPPORTED_DEVICE("watchdog");
-MODULE_LICENSE("GPL");
-
-#define RIOWD_NAME "pmc"
-#define RIOWD_MINOR 215
-
-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");
-
-#if 0 /* Currently unused. */
-static u8 riowd_readreg(int index)
-{
- unsigned long flags;
- u8 ret;
-
- 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)
-{
- cycle_kernel_lock();
- nonseekable_open(inode, filp);
- return 0;
-}
-
-static int riowd_release(struct inode *inode, struct file *filp)
-{
- return 0;
-}
-
-static int riowd_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- static struct watchdog_info info = {
- WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317"
- };
- void __user *argp = (void __user *)arg;
- unsigned int options;
- int new_margin;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- break;
-
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- if (put_user(0, (int __user *)argp))
- return -EFAULT;
- break;
-
- case WDIOC_KEEPALIVE:
- riowd_pingtimer();
- break;
-
- case WDIOC_SETOPTIONS:
- if (copy_from_user(&options, argp, sizeof(options)))
- return -EFAULT;
-
- if (options & WDIOS_DISABLECARD)
- riowd_stoptimer();
- else if (options & WDIOS_ENABLECARD)
- riowd_starttimer();
- else
- return -EINVAL;
-
- break;
-
- case WDIOC_SETTIMEOUT:
- if (get_user(new_margin, (int __user *)argp))
- return -EFAULT;
- if ((new_margin < 60) || (new_margin > (255 * 60)))
- return -EINVAL;
- riowd_timeout = (new_margin + 59) / 60;
- riowd_pingtimer();
- /* Fall */
-
- case WDIOC_GETTIMEOUT:
- return put_user(riowd_timeout * 60, (int __user *)argp);
-
- default:
- return -EINVAL;
- };
-
- return 0;
-}
-
-static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
-{
- if (count) {
- riowd_pingtimer();
- return 1;
- }
-
- return 0;
-}
-
-static const struct file_operations riowd_fops = {
- .owner = THIS_MODULE,
- .ioctl = riowd_ioctl,
- .open = riowd_open,
- .write = riowd_write,
- .release = riowd_release,
-};
-
-static struct miscdevice riowd_miscdev = { RIOWD_MINOR, RIOWD_NAME, &riowd_fops };
-
-static int __init riowd_bbc_init(void)
-{
- 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;
- }
- }
-
-found_bbc:
- if (!edev)
- return -ENODEV;
- bbc_regs = ioremap(edev->resource[0].start, BBC_REGS_SIZE);
- if (!bbc_regs)
- return -ENODEV;
-
- /* Turn it off. */
- val = readb(bbc_regs + BBC_WDACTION);
- val &= ~BBC_WDACTION_RST;
- writeb(val, bbc_regs + BBC_WDACTION);
-
- return 0;
-}
-
-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;
- }
- }
-
-ebus_done:
- if (!edev)
- goto fail;
-
- riowd_regs = ioremap(edev->resource[0].start, 2);
- if (riowd_regs == NULL) {
- printk(KERN_ERR "pmc: Cannot map registers.\n");
- return -ENODEV;
- }
-
- if (riowd_bbc_init()) {
- printk(KERN_ERR "pmc: Failure initializing BBC config.\n");
- goto fail;
- }
-
- if (misc_register(&riowd_miscdev)) {
- printk(KERN_ERR "pmc: Cannot register watchdog misc device.\n");
- goto fail;
- }
-
- printk(KERN_INFO "pmc: Hardware watchdog [%i minutes], "
- "regs at %p\n", riowd_timeout, riowd_regs);
-
- return 0;
-
-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_cleanup(void)
-{
- misc_deregister(&riowd_miscdev);
- iounmap(riowd_regs);
- riowd_regs = NULL;
- iounmap(bbc_regs);
- bbc_regs = NULL;
-}
-
-module_init(riowd_init);
-module_exit(riowd_cleanup);
diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c
deleted file mode 100644
index b042991..0000000
--- a/drivers/sbus/char/rtc.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/* $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 <linux/module.h>
-#include <linux/smp_lock.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/mostek.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/rtc.h>
-
-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/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 7776375..27993c3 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -1,7 +1,7 @@
-/* $Id: uctrl.c,v 1.12 2001/10/08 22:19:51 davem Exp $
- * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
+/* 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 <linux/module.h>
@@ -14,6 +14,8 @@
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
@@ -21,7 +23,6 @@
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/pgtable.h>
-#include <asm/sbus.h>
#define UCTRL_MINOR 174
@@ -33,26 +34,26 @@
#endif
struct uctrl_regs {
- volatile u32 uctrl_intr;
- volatile u32 uctrl_data;
- volatile u32 uctrl_stat;
- volatile u32 uctrl_xxx[5];
+ u32 uctrl_intr;
+ u32 uctrl_data;
+ u32 uctrl_stat;
+ u32 uctrl_xxx[5];
};
struct ts102_regs {
- 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];
+ 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];
};
/* Bits for uctrl_intr register */
@@ -186,17 +187,15 @@
POWER_RESTART=0x83,
};
-struct uctrl_driver {
- struct uctrl_regs *regs;
+static struct uctrl_driver {
+ struct uctrl_regs __iomem *regs;
int irq;
int pending;
struct uctrl_status status;
-};
+} *global_driver;
-static struct uctrl_driver drv;
-
-static void uctrl_get_event_status(void);
-static void uctrl_get_external_status(void);
+static void uctrl_get_event_status(struct uctrl_driver *);
+static void uctrl_get_external_status(struct uctrl_driver *);
static int
uctrl_ioctl(struct inode *inode, struct file *file,
@@ -213,16 +212,14 @@
uctrl_open(struct inode *inode, struct file *file)
{
lock_kernel();
- uctrl_get_event_status();
- uctrl_get_external_status();
+ uctrl_get_event_status(global_driver);
+ uctrl_get_external_status(global_driver);
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;
}
@@ -244,11 +241,11 @@
{ \
unsigned int i; \
for (i = 0; i < 10000; i++) { \
- if (UCTRL_STAT_TXNF_STA & driver->regs->uctrl_stat) \
+ if (UCTRL_STAT_TXNF_STA & sbus_readl(&driver->regs->uctrl_stat)) \
break; \
} \
dprintk(("write data 0x%02x\n", value)); \
- driver->regs->uctrl_data = value; \
+ sbus_writel(value, &driver->regs->uctrl_data); \
}
/* Wait for something to read, read it, then clear the bit */
@@ -257,24 +254,23 @@
unsigned int i; \
value = 0; \
for (i = 0; i < 10000; i++) { \
- if ((UCTRL_STAT_RXNE_STA & driver->regs->uctrl_stat) == 0) \
+ if ((UCTRL_STAT_RXNE_STA & sbus_readl(&driver->regs->uctrl_stat)) == 0) \
break; \
udelay(1); \
} \
- value = driver->regs->uctrl_data; \
+ value = sbus_readl(&driver->regs->uctrl_data); \
dprintk(("read data 0x%02x\n", value)); \
- driver->regs->uctrl_stat = UCTRL_STAT_RXNE_STA; \
+ sbus_writel(UCTRL_STAT_RXNE_STA, &driver->regs->uctrl_stat); \
}
-static void uctrl_do_txn(struct uctrl_txn *txn)
+static void uctrl_do_txn(struct uctrl_driver *driver, struct uctrl_txn *txn)
{
- struct uctrl_driver *driver = &drv;
int stat, incnt, outcnt, bytecnt, intr;
u32 byte;
- stat = driver->regs->uctrl_stat;
- intr = driver->regs->uctrl_intr;
- driver->regs->uctrl_stat = stat;
+ stat = sbus_readl(&driver->regs->uctrl_stat);
+ intr = sbus_readl(&driver->regs->uctrl_intr);
+ sbus_writel(stat, &driver->regs->uctrl_stat);
dprintk(("interrupt stat 0x%x int 0x%x\n", stat, intr));
@@ -305,9 +301,8 @@
}
}
-static void uctrl_get_event_status(void)
+static void uctrl_get_event_status(struct uctrl_driver *driver)
{
- struct uctrl_driver *driver = &drv;
struct uctrl_txn txn;
u8 outbits[2];
@@ -317,7 +312,7 @@
txn.inbuf = NULL;
txn.outbuf = outbits;
- uctrl_do_txn(&txn);
+ uctrl_do_txn(driver, &txn);
dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
driver->status.event_status =
@@ -325,9 +320,8 @@
dprintk(("ev is %x\n", driver->status.event_status));
}
-static void uctrl_get_external_status(void)
+static void uctrl_get_external_status(struct uctrl_driver *driver)
{
- struct uctrl_driver *driver = &drv;
struct uctrl_txn txn;
u8 outbits[2];
int i, v;
@@ -338,7 +332,7 @@
txn.inbuf = NULL;
txn.outbuf = outbits;
- uctrl_do_txn(&txn);
+ uctrl_do_txn(driver, &txn);
dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
driver->status.external_status =
@@ -354,71 +348,101 @@
}
-static int __init ts102_uctrl_init(void)
+static int __devinit uctrl_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- 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;
+ struct uctrl_driver *p;
+ int err = -ENOMEM;
- tmpnode = prom_searchsiblings(uctrlnode, "obio");
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ printk(KERN_ERR "uctrl: Unable to allocate device struct.\n");
+ goto out;
+ }
- if (tmpnode)
- uctrlnode = prom_getchild(tmpnode);
+ 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;
+ }
- uctrlnode = prom_searchsiblings(uctrlnode, "uctrl");
-
- if (!uctrlnode)
- return -ENODEV;
-
- /* the prom mapped it for us */
- len = prom_getproperty(uctrlnode, "address", (void *) vaddr,
- sizeof(vaddr));
- driver->regs = (struct uctrl_regs *)vaddr[0];
-
- len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq,
- sizeof(tmp_irq));
-
- /* Flush device */
- READUCTLDATA(len);
-
- if(!driver->irq)
- driver->irq = tmp_irq[0].pri;
-
- err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
+ p->irq = op->irqs[0];
+ err = request_irq(p->irq, uctrl_interrupt, 0, "uctrl", p);
if (err) {
- printk("%s: unable to register irq %d\n",
- __func__, driver->irq);
- return err;
+ printk(KERN_ERR "uctrl: Unable to register irq.\n");
+ goto out_iounmap;
}
- 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;
+ err = misc_register(&uctrl_dev);
+ if (err) {
+ printk(KERN_ERR "uctrl: Unable to register misc device.\n");
+ goto out_free_irq;
}
- 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;
+ 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);
+
+ dev_set_drvdata(&op->dev, p);
+ global_driver = p;
+
+out:
+ return err;
+
+out_free_irq:
+ free_irq(p->irq, p);
+
+out_iounmap:
+ of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
+
+out_free:
+ kfree(p);
+ goto out;
}
-static void __exit ts102_uctrl_cleanup(void)
+static int __devexit uctrl_remove(struct of_device *op)
{
- struct uctrl_driver *driver = &drv;
+ struct uctrl_driver *p = dev_get_drvdata(&op->dev);
- misc_deregister(&uctrl_dev);
- if (driver->irq)
- free_irq(driver->irq, driver);
- if (driver->regs)
- driver->regs = NULL;
+ 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);
+ }
+ return 0;
}
-module_init(ts102_uctrl_init);
-module_exit(ts102_uctrl_cleanup);
+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),
+};
+
+
+static int __init uctrl_init(void)
+{
+ return of_register_driver(&uctrl_driver, &of_bus_type);
+}
+
+static void __exit uctrl_exit(void)
+{
+ of_unregister_driver(&uctrl_driver);
+}
+
+module_init(uctrl_init);
+module_exit(uctrl_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h
deleted file mode 100644
index a5240c5..0000000
--- a/drivers/sbus/char/vfc.h
+++ /dev/null
@@ -1,171 +0,0 @@
-#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/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
deleted file mode 100644
index 25181bb..0000000
--- a/drivers/sbus/char/vfc_dev.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * 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 <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/sbus.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#define VFC_MAJOR (60)
-
-#if 0
-#define VFC_IOCTL_DEBUG
-#endif
-
-#include "vfc.h"
-#include <asm/vfc_ioctls.h>
-
-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/drivers/sbus/char/vfc_i2c.c b/drivers/sbus/char/vfc_i2c.c
deleted file mode 100644
index 32b986e..0000000
--- a/drivers/sbus/char/vfc_i2c.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * 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 <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/sbus.h>
-
-#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/drivers/sbus/char/vfc_i2c.h b/drivers/sbus/char/vfc_i2c.h
deleted file mode 100644
index a2e6973..0000000
--- a/drivers/sbus/char/vfc_i2c.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#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/drivers/sbus/dvma.c b/drivers/sbus/dvma.c
deleted file mode 100644
index ab0d2de..0000000
--- a/drivers/sbus/dvma.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/* dvma.c: Routines that are used to access DMA on the Sparc SBus.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/sbus.h>
-
-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 <asm/sun4paddr.h>
-
-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/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
deleted file mode 100644
index 9c12924..0000000
--- a/drivers/sbus/sbus.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/* sbus.c: SBus support routines.
- *
- * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net)
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/of_device.h>
-
-#include <asm/system.h>
-#include <asm/sbus.h>
-#include <asm/dma.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-#include <asm/irq.h>
-
-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/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
index bb43a13..28e22ac 100644
--- a/drivers/scsi/esp_scsi.h
+++ b/drivers/scsi/esp_scsi.h
@@ -521,7 +521,8 @@
struct completion *eh_reset;
- struct sbus_dma *dma;
+ void *dma;
+ int dmarev;
};
/* A front-end driver for the ESP chip should do the following in
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 9053508..69d6ad8 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -1,6 +1,6 @@
/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
*
- * Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2006, 2008 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,12 +25,14 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/jiffies.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/byteorder.h>
#include "qlogicpti.h"
-#include <asm/sbus.h>
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/ptrace.h>
@@ -157,7 +159,7 @@
* is a nop and the chip ends up using the smallest burst
* size. -DaveM
*/
- if (sbus_can_burst64(qpti->sdev) && (bursts & DMA_BURST64)) {
+ if (sbus_can_burst64() && (bursts & DMA_BURST64)) {
val = (SBUS_CFG1_BENAB | SBUS_CFG1_B64);
} else
#endif
@@ -684,19 +686,19 @@
static int __devinit qpti_map_regs(struct qlogicpti *qpti)
{
- struct sbus_dev *sdev = qpti->sdev;
+ struct of_device *op = qpti->op;
- qpti->qregs = sbus_ioremap(&sdev->resource[0], 0,
- sdev->reg_addrs[0].reg_size,
- "PTI Qlogic/ISP");
+ qpti->qregs = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]),
+ "PTI Qlogic/ISP");
if (!qpti->qregs) {
printk("PTI: Qlogic/ISP registers are unmappable\n");
return -1;
}
if (qpti->is_pti) {
- qpti->sreg = sbus_ioremap(&sdev->resource[0], (16 * 4096),
- sizeof(unsigned char),
- "PTI Qlogic/ISP statreg");
+ qpti->sreg = of_ioremap(&op->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;
@@ -707,9 +709,9 @@
static int __devinit qpti_register_irq(struct qlogicpti *qpti)
{
- struct sbus_dev *sdev = qpti->sdev;
+ struct of_device *op = qpti->op;
- qpti->qhost->irq = qpti->irq = sdev->irqs[0];
+ qpti->qhost->irq = qpti->irq = op->irqs[0];
/* We used to try various overly-clever things to
* reduce the interrupt processing overhead on
@@ -732,17 +734,19 @@
static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti)
{
- qpti->scsi_id = prom_getintdefault(qpti->prom_node,
- "initiator-id",
- -1);
+ struct of_device *op = qpti->op;
+ struct device_node *dp;
+
+ dp = op->node;
+
+ qpti->scsi_id = of_getintprop_default(dp, "initiator-id", -1);
if (qpti->scsi_id == -1)
- qpti->scsi_id = prom_getintdefault(qpti->prom_node,
- "scsi-initiator-id",
- -1);
+ qpti->scsi_id = of_getintprop_default(dp, "scsi-initiator-id",
+ -1);
if (qpti->scsi_id == -1)
qpti->scsi_id =
- prom_getintdefault(qpti->sdev->bus->prom_node,
- "scsi-initiator-id", 7);
+ of_getintprop_default(dp->parent,
+ "scsi-initiator-id", 7);
qpti->qhost->this_id = qpti->scsi_id;
qpti->qhost->max_sectors = 64;
@@ -751,12 +755,11 @@
static void qpti_get_bursts(struct qlogicpti *qpti)
{
- struct sbus_dev *sdev = qpti->sdev;
+ struct of_device *op = qpti->op;
u8 bursts, bmask;
- bursts = prom_getintdefault(qpti->prom_node, "burst-sizes", 0xff);
- bmask = prom_getintdefault(sdev->bus->prom_node,
- "burst-sizes", 0xff);
+ bursts = of_getintprop_default(op->node, "burst-sizes", 0xff);
+ bmask = of_getintprop_default(op->node->parent, "burst-sizes", 0xff);
if (bmask != 0xff)
bursts &= bmask;
if (bursts == 0xff ||
@@ -785,25 +788,25 @@
*/
static int __devinit qpti_map_queues(struct qlogicpti *qpti)
{
- struct sbus_dev *sdev = qpti->sdev;
+ struct of_device *op = qpti->op;
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
- qpti->res_cpu = sbus_alloc_consistent(sdev,
- QSIZE(RES_QUEUE_LEN),
- &qpti->res_dvma);
+ qpti->res_cpu = dma_alloc_coherent(&op->dev,
+ QSIZE(RES_QUEUE_LEN),
+ &qpti->res_dvma, GFP_ATOMIC);
if (qpti->res_cpu == NULL ||
qpti->res_dvma == 0) {
printk("QPTI: Cannot map response queue.\n");
return -1;
}
- qpti->req_cpu = sbus_alloc_consistent(sdev,
- QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
- &qpti->req_dvma);
+ qpti->req_cpu = dma_alloc_coherent(&op->dev,
+ QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+ &qpti->req_dvma, GFP_ATOMIC);
if (qpti->req_cpu == NULL ||
qpti->req_dvma == 0) {
- sbus_free_consistent(sdev, QSIZE(RES_QUEUE_LEN),
- qpti->res_cpu, qpti->res_dvma);
+ dma_free_coherent(&op->dev, QSIZE(RES_QUEUE_LEN),
+ qpti->res_cpu, qpti->res_dvma);
printk("QPTI: Cannot map request queue.\n");
return -1;
}
@@ -875,8 +878,9 @@
int sg_count;
sg = scsi_sglist(Cmnd);
- sg_count = sbus_map_sg(qpti->sdev, sg, scsi_sg_count(Cmnd),
- Cmnd->sc_data_direction);
+ sg_count = dma_map_sg(&qpti->op->dev, sg,
+ scsi_sg_count(Cmnd),
+ Cmnd->sc_data_direction);
ds = cmd->dataseg;
cmd->segment_cnt = sg_count;
@@ -1152,9 +1156,9 @@
Cmnd->result = DID_ERROR << 16;
if (scsi_bufflen(Cmnd))
- sbus_unmap_sg(qpti->sdev,
- scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
- Cmnd->sc_data_direction);
+ dma_unmap_sg(&qpti->op->dev,
+ scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
+ Cmnd->sc_data_direction);
qpti->cmd_count[Cmnd->device->id]--;
sbus_writew(out_ptr, qpti->qregs + MBOX5);
@@ -1268,34 +1272,32 @@
.use_clustering = ENABLE_CLUSTERING,
};
-static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit qpti_sbus_probe(struct of_device *op, 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 (sdev->irqs[0] == 0)
+ if (op->irqs[0] == 0)
return -ENODEV;
host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti));
if (!host)
return -ENOMEM;
- qpti = (struct qlogicpti *) host->hostdata;
+ qpti = shost_priv(host);
host->max_id = MAX_TARGETS;
qpti->qhost = host;
- qpti->sdev = sdev;
+ qpti->op = op;
qpti->qpti_id = nqptis;
- qpti->prom_node = sdev->prom_node;
- strcpy(qpti->prom_name, sdev->ofdev.node->name);
+ strcpy(qpti->prom_name, op->node->name);
qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp");
if (qpti_map_regs(qpti) < 0)
@@ -1341,12 +1343,12 @@
(qpti->ultra ? "Ultra" : "Fast"),
(qpti->differential ? "differential" : "single ended"));
- if (scsi_add_host(host, &dev->dev)) {
+ if (scsi_add_host(host, &op->dev)) {
printk("qlogicpti%d: Failed scsi_add_host\n", qpti->qpti_id);
goto fail_unmap_queues;
}
- dev_set_drvdata(&sdev->ofdev.dev, qpti);
+ dev_set_drvdata(&op->dev, qpti);
qpti_chain_add(qpti);
@@ -1357,19 +1359,20 @@
fail_unmap_queues:
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
- 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);
+ 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);
#undef QSIZE
fail_unmap_regs:
- sbus_iounmap(qpti->qregs,
- qpti->sdev->reg_addrs[0].reg_size);
+ of_iounmap(&op->resource[0], qpti->qregs,
+ resource_size(&op->resource[0]));
if (qpti->is_pti)
- sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+ of_iounmap(&op->resource[0], qpti->sreg,
+ sizeof(unsigned char));
fail_free_irq:
free_irq(qpti->irq, qpti);
@@ -1380,9 +1383,9 @@
return -ENODEV;
}
-static int __devexit qpti_sbus_remove(struct of_device *dev)
+static int __devexit qpti_sbus_remove(struct of_device *op)
{
- struct qlogicpti *qpti = dev_get_drvdata(&dev->dev);
+ struct qlogicpti *qpti = dev_get_drvdata(&op->dev);
qpti_chain_del(qpti);
@@ -1395,24 +1398,25 @@
free_irq(qpti->irq, qpti);
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
- 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);
+ 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);
#undef QSIZE
- sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
+ of_iounmap(&op->resource[0], qpti->qregs,
+ resource_size(&op->resource[0]));
if (qpti->is_pti)
- sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+ of_iounmap(&op->resource[0], qpti->sreg, sizeof(unsigned char));
scsi_host_put(qpti->qhost);
return 0;
}
-static struct of_device_id qpti_match[] = {
+static const struct of_device_id qpti_match[] = {
{
.name = "ptisp",
.data = &qpti_template,
@@ -1442,7 +1446,7 @@
static int __init qpti_init(void)
{
- return of_register_driver(&qpti_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&qpti_sbus_driver, &of_bus_type);
}
static void __exit qpti_exit(void)
@@ -1453,7 +1457,7 @@
MODULE_DESCRIPTION("QlogicISP SBUS driver");
MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL");
-MODULE_VERSION("2.0");
+MODULE_VERSION("2.1");
module_init(qpti_init);
module_exit(qpti_exit);
diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h
index ef6da2d..9c053bb 100644
--- a/drivers/scsi/qlogicpti.h
+++ b/drivers/scsi/qlogicpti.h
@@ -342,7 +342,7 @@
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 sbus_dev *sdev;
+ struct of_device *op;
unsigned long __pad;
int cmd_count[MAX_TARGETS];
diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c
index f9cf701..3d73aad 100644
--- a/drivers/scsi/sun_esp.c
+++ b/drivers/scsi/sun_esp.c
@@ -1,6 +1,6 @@
/* sun_esp.c: ESP front-end for Sparc SBUS systems.
*
- * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@@ -9,79 +9,89 @@
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/dma.h>
-#include <asm/sbus.h>
-
#include <scsi/scsi_host.h>
#include "esp_scsi.h"
#define DRV_MODULE_NAME "sun_esp"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_VERSION "1.000"
-#define DRV_MODULE_RELDATE "April 19, 2007"
+#define DRV_VERSION "1.100"
+#define DRV_MODULE_RELDATE "August 27, 2008"
#define dma_read32(REG) \
sbus_readl(esp->dma_regs + (REG))
#define dma_write32(VAL, REG) \
sbus_writel((VAL), esp->dma_regs + (REG))
-static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sdev)
+/* 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)
{
- struct sbus_dev *sdev = esp->dev;
- struct sbus_dma *dma;
+ esp->dma = dma_of;
- if (dma_sdev != NULL) {
- for_each_dvma(dma) {
- if (dma->sdev == dma_sdev)
- break;
- }
- } else {
- for_each_dvma(dma) {
- if (dma->sdev == NULL)
- break;
+ esp->dma_regs = of_ioremap(&dma_of->resource[0], 0,
+ resource_size(&dma_of->resource[0]),
+ "espdma");
+ if (!esp->dma_regs)
+ return -ENOMEM;
- /* 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;
- }
+ 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 (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 sbus_dev *sdev = esp->dev;
+ struct of_device *op = esp->dev;
struct resource *res;
/* On HME, two reg sets exist, first is DVMA,
* second is ESP registers.
*/
if (hme)
- res = &sdev->resource[1];
+ res = &op->resource[1];
else
- res = &sdev->resource[0];
+ res = &op->resource[0];
- esp->regs = sbus_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");
+ esp->regs = of_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");
if (!esp->regs)
return -ENOMEM;
@@ -90,10 +100,11 @@
static int __devinit esp_sbus_map_command_block(struct esp *esp)
{
- struct sbus_dev *sdev = esp->dev;
+ struct of_device *op = esp->dev;
- esp->command_block = sbus_alloc_consistent(sdev, 16,
- &esp->command_block_dma);
+ esp->command_block = dma_alloc_coherent(&op->dev, 16,
+ &esp->command_block_dma,
+ GFP_ATOMIC);
if (!esp->command_block)
return -ENOMEM;
return 0;
@@ -102,17 +113,18 @@
static int __devinit esp_sbus_register_irq(struct esp *esp)
{
struct Scsi_Host *host = esp->host;
- struct sbus_dev *sdev = esp->dev;
+ struct of_device *op = esp->dev;
- host->irq = sdev->irqs[0];
+ host->irq = op->irqs[0];
return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);
}
-static void __devinit esp_get_scsi_id(struct esp *esp)
+static void __devinit esp_get_scsi_id(struct esp *esp, struct of_device *espdma)
{
- struct sbus_dev *sdev = esp->dev;
- struct device_node *dp = sdev->ofdev.node;
+ struct of_device *op = esp->dev;
+ struct device_node *dp;
+ dp = op->node;
esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff);
if (esp->scsi_id != 0xff)
goto done;
@@ -121,13 +133,7 @@
if (esp->scsi_id != 0xff)
goto done;
- if (!sdev->bus) {
- /* SUN4 */
- esp->scsi_id = 7;
- goto done;
- }
-
- esp->scsi_id = of_getintprop_default(sdev->bus->ofdev.node,
+ esp->scsi_id = of_getintprop_default(espdma->node,
"scsi-initiator-id", 7);
done:
@@ -137,9 +143,10 @@
static void __devinit esp_get_differential(struct esp *esp)
{
- struct sbus_dev *sdev = esp->dev;
- struct device_node *dp = sdev->ofdev.node;
+ struct of_device *op = esp->dev;
+ struct device_node *dp;
+ dp = op->node;
if (of_find_property(dp, "differential", NULL))
esp->flags |= ESP_FLAG_DIFFERENTIAL;
else
@@ -148,43 +155,36 @@
static void __devinit esp_get_clock_params(struct esp *esp)
{
- struct sbus_dev *sdev = esp->dev;
- struct device_node *dp = sdev->ofdev.node;
- struct device_node *bus_dp;
+ struct of_device *op = esp->dev;
+ struct device_node *bus_dp, *dp;
int fmhz;
- bus_dp = NULL;
- if (sdev != NULL && sdev->bus != NULL)
- bus_dp = sdev->bus->ofdev.node;
+ dp = op->node;
+ bus_dp = dp->parent;
fmhz = of_getintprop_default(dp, "clock-frequency", 0);
if (fmhz == 0)
- fmhz = (!bus_dp) ? 0 :
- of_getintprop_default(bus_dp, "clock-frequency", 0);
+ fmhz = of_getintprop_default(bus_dp, "clock-frequency", 0);
esp->cfreq = fmhz;
}
-static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
+static void __devinit esp_get_bursts(struct esp *esp, struct of_device *dma_of)
{
- struct sbus_dev *sdev = esp->dev;
- struct device_node *dp = sdev->ofdev.node;
- u8 bursts;
+ struct device_node *dma_dp = dma_of->node;
+ struct of_device *op = esp->dev;
+ struct device_node *dp;
+ u8 bursts, val;
+ dp = op->node;
bursts = of_getintprop_default(dp, "burst-sizes", 0xff);
- 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, "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;
- }
+ val = of_getintprop_default(dma_dp->parent, "burst-sizes", 0xff);
+ if (val != 0xff)
+ bursts &= val;
if (bursts == 0xff ||
(bursts & DMA_BURST16) == 0 ||
@@ -194,9 +194,9 @@
esp->bursts = bursts;
}
-static void __devinit esp_sbus_get_props(struct esp *esp, struct sbus_dev *espdma)
+static void __devinit esp_sbus_get_props(struct esp *esp, struct of_device *espdma)
{
- esp_get_scsi_id(esp);
+ esp_get_scsi_id(esp, espdma);
esp_get_differential(esp);
esp_get_clock_params(esp);
esp_get_bursts(esp, espdma);
@@ -215,25 +215,33 @@
static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf,
size_t sz, int dir)
{
- return sbus_map_single(esp->dev, buf, sz, dir);
+ struct of_device *op = esp->dev;
+
+ return dma_map_single(&op->dev, buf, sz, dir);
}
static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg,
int num_sg, int dir)
{
- return sbus_map_sg(esp->dev, sg, num_sg, dir);
+ struct of_device *op = esp->dev;
+
+ return dma_map_sg(&op->dev, sg, num_sg, dir);
}
static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr,
size_t sz, int dir)
{
- sbus_unmap_single(esp->dev, addr, sz, dir);
+ struct of_device *op = esp->dev;
+
+ dma_unmap_single(&op->dev, addr, sz, dir);
}
static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
int num_sg, int dir)
{
- sbus_unmap_sg(esp->dev, sg, num_sg, dir);
+ struct of_device *op = esp->dev;
+
+ dma_unmap_sg(&op->dev, sg, num_sg, dir);
}
static int sbus_esp_irq_pending(struct esp *esp)
@@ -247,24 +255,26 @@
{
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;
- if (sbus_can_dma_64bit(esp->dev))
+ op = esp->dev;
+ if (sbus_can_dma_64bit())
can_do_sbus64 = 1;
- if (sbus_can_burst64(esp->sdev))
+ if (sbus_can_burst64())
can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;
/* Put the DVMA into a known state. */
- if (esp->dma->revision != dvmahme) {
+ if (esp->dmarev != dvmahme) {
val = dma_read32(DMA_CSR);
dma_write32(val | DMA_RST_SCSI, DMA_CSR);
dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
}
- switch (esp->dma->revision) {
+ switch (esp->dmarev) {
case dvmahme:
dma_write32(DMA_RESET_FAS366, DMA_CSR);
dma_write32(DMA_RST_SCSI, DMA_CSR);
@@ -282,7 +292,7 @@
if (can_do_sbus64) {
esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
- sbus_set_sbus64(esp->dev, esp->bursts);
+ sbus_set_sbus64(&op->dev, esp->bursts);
}
lim = 1000;
@@ -346,14 +356,14 @@
u32 csr;
int lim;
- if (esp->dma->revision == dvmahme)
+ if (esp->dmarev == dvmahme)
return;
csr = dma_read32(DMA_CSR);
if (!(csr & DMA_FIFO_ISDRAIN))
return;
- if (esp->dma->revision != dvmarev3 && esp->dma->revision != dvmaesc1)
+ if (esp->dmarev != dvmarev3 && esp->dmarev != dvmaesc1)
dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);
lim = 1000;
@@ -369,7 +379,7 @@
static void sbus_esp_dma_invalidate(struct esp *esp)
{
- if (esp->dma->revision == dvmahme) {
+ if (esp->dmarev == dvmahme) {
dma_write32(DMA_RST_SCSI, DMA_CSR);
esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
@@ -440,7 +450,7 @@
else
csr &= ~DMA_ST_WRITE;
dma_write32(csr, DMA_CSR);
- if (esp->dma->revision == dvmaesc1) {
+ if (esp->dmarev == dvmaesc1) {
u32 end = PAGE_ALIGN(addr + dma_count + 16U);
dma_write32(end - addr, DMA_COUNT);
}
@@ -476,10 +486,8 @@
.dma_error = sbus_esp_dma_error,
};
-static int __devinit esp_sbus_probe_one(struct device *dev,
- struct sbus_dev *esp_dev,
- struct sbus_dev *espdma,
- struct sbus_bus *sbus,
+static int __devinit esp_sbus_probe_one(struct of_device *op,
+ struct of_device *espdma,
int hme)
{
struct scsi_host_template *tpnt = &scsi_esp_template;
@@ -497,13 +505,13 @@
esp = shost_priv(host);
esp->host = host;
- esp->dev = esp_dev;
+ esp->dev = op;
esp->ops = &sbus_esp_ops;
if (hme)
esp->flags |= ESP_FLAG_WIDE_CAPABLE;
- err = esp_sbus_find_dma(esp, espdma);
+ err = esp_sbus_setup_dma(esp, espdma);
if (err < 0)
goto fail_unlink;
@@ -525,15 +533,15 @@
* come up with the reset bit set, so make sure that
* is clear first.
*/
- if (esp->dma->revision == dvmaesc1) {
+ if (esp->dmarev == dvmaesc1) {
u32 val = dma_read32(DMA_CSR);
dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
}
- dev_set_drvdata(&esp_dev->ofdev.dev, esp);
+ dev_set_drvdata(&op->dev, esp);
- err = scsi_esp_register(esp, dev);
+ err = scsi_esp_register(esp, &op->dev);
if (err)
goto fail_free_irq;
@@ -542,41 +550,46 @@
fail_free_irq:
free_irq(host->irq, esp);
fail_unmap_command_block:
- sbus_free_consistent(esp->dev, 16,
- esp->command_block,
- esp->command_block_dma);
+ dma_free_coherent(&op->dev, 16,
+ esp->command_block,
+ esp->command_block_dma);
fail_unmap_regs:
- sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+ of_iounmap(&op->resource[(hme ? 1 : 0)], esp->regs, SBUS_ESP_REG_SIZE);
fail_unlink:
scsi_host_put(host);
fail:
return err;
}
-static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit esp_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- struct device_node *dp = dev->node;
- struct sbus_dev *dma_sdev = NULL;
+ struct device_node *dma_node = NULL;
+ struct device_node *dp = op->node;
+ struct of_device *dma_of = NULL;
int hme = 0;
if (dp->parent &&
(!strcmp(dp->parent->name, "espdma") ||
!strcmp(dp->parent->name, "dma")))
- dma_sdev = sdev->parent;
+ dma_node = dp->parent;
else if (!strcmp(dp->name, "SUNW,fas")) {
- dma_sdev = sdev;
+ dma_node = op->node;
hme = 1;
}
+ if (dma_node)
+ dma_of = of_find_device_by_node(dma_node);
+ if (!dma_of)
+ return -ENODEV;
- return esp_sbus_probe_one(&dev->dev, sdev, dma_sdev,
- sdev->bus, hme);
+ return esp_sbus_probe_one(op, dma_of, hme);
}
-static int __devexit esp_sbus_remove(struct of_device *dev)
+static int __devexit esp_sbus_remove(struct of_device *op)
{
- struct esp *esp = dev_get_drvdata(&dev->dev);
+ struct esp *esp = dev_get_drvdata(&op->dev);
+ struct of_device *dma_of = esp->dma;
unsigned int irq = esp->host->irq;
+ bool is_hme;
u32 val;
scsi_esp_unregister(esp);
@@ -586,17 +599,25 @@
dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);
free_irq(irq, esp);
- sbus_free_consistent(esp->dev, 16,
- esp->command_block,
- esp->command_block_dma);
- sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+
+ 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]));
scsi_host_put(esp->host);
+ dev_set_drvdata(&op->dev, NULL);
+
return 0;
}
-static struct of_device_id esp_match[] = {
+static const struct of_device_id esp_match[] = {
{
.name = "SUNW,esp",
},
@@ -619,7 +640,7 @@
static int __init sunesp_init(void)
{
- return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&esp_sbus_driver, &of_bus_type);
}
static void __exit sunesp_exit(void)
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index e41766d..a94a2ab 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -616,7 +616,7 @@
return 0;
}
-static struct of_device_id hv_match[] = {
+static const struct of_device_id hv_match[] = {
{
.name = "console",
.compatible = "qcn",
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 29b4458..0355efe 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -1078,7 +1078,7 @@
return 0;
}
-static struct of_device_id sab_match[] = {
+static const struct of_device_id sab_match[] = {
{
.name = "se",
},
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index a378464..a4dc79b1 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1506,7 +1506,7 @@
return 0;
}
-static struct of_device_id su_match[] = {
+static const struct of_device_id su_match[] = {
{
.name = "su",
},
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 3cb4c8a..45a299f 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1480,7 +1480,7 @@
return 0;
}
-static struct of_device_id zs_match[] = {
+static const struct of_device_id zs_match[] = {
{
.name = "zs",
},
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 5799298..b697a13 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -210,143 +210,7 @@
/*-------------------------------------------------------------------------*/
-/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
-
-/* Section 2.2 Host Controller Capability Registers */
-struct ehci_caps {
- /* these fields are specified as 8 and 16 bit registers,
- * but some hosts can't perform 8 or 16 bit PCI accesses.
- */
- u32 hc_capbase;
-#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
-#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
- u32 hcs_params; /* HCSPARAMS - offset 0x4 */
-#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */
-#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
-#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
-#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
-#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
-#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
-#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
-
- u32 hcc_params; /* HCCPARAMS - offset 0x8 */
-#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */
-#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
-#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
-#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
-#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
-#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */
- u8 portroute [8]; /* nibbles for routing - offset 0xC */
-} __attribute__ ((packed));
-
-
-/* Section 2.3 Host Controller Operational Registers */
-struct ehci_regs {
-
- /* USBCMD: offset 0x00 */
- u32 command;
-/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
-#define CMD_PARK (1<<11) /* enable "park" on async qh */
-#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
-#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
-#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
-#define CMD_ASE (1<<5) /* async schedule enable */
-#define CMD_PSE (1<<4) /* periodic schedule enable */
-/* 3:2 is periodic frame list size */
-#define CMD_RESET (1<<1) /* reset HC not bus */
-#define CMD_RUN (1<<0) /* start/stop HC */
-
- /* USBSTS: offset 0x04 */
- u32 status;
-#define STS_ASS (1<<15) /* Async Schedule Status */
-#define STS_PSS (1<<14) /* Periodic Schedule Status */
-#define STS_RECL (1<<13) /* Reclamation */
-#define STS_HALT (1<<12) /* Not running (any reason) */
-/* some bits reserved */
- /* these STS_* flags are also intr_enable bits (USBINTR) */
-#define STS_IAA (1<<5) /* Interrupted on async advance */
-#define STS_FATAL (1<<4) /* such as some PCI access errors */
-#define STS_FLR (1<<3) /* frame list rolled over */
-#define STS_PCD (1<<2) /* port change detect */
-#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
-#define STS_INT (1<<0) /* "normal" completion (short, ...) */
-
- /* USBINTR: offset 0x08 */
- u32 intr_enable;
-
- /* FRINDEX: offset 0x0C */
- u32 frame_index; /* current microframe number */
- /* CTRLDSSEGMENT: offset 0x10 */
- u32 segment; /* address bits 63:32 if needed */
- /* PERIODICLISTBASE: offset 0x14 */
- u32 frame_list; /* points to periodic list */
- /* ASYNCLISTADDR: offset 0x18 */
- u32 async_next; /* address of next async queue head */
-
- u32 reserved [9];
-
- /* CONFIGFLAG: offset 0x40 */
- u32 configured_flag;
-#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
-
- /* PORTSC: offset 0x44 */
- u32 port_status [0]; /* up to N_PORTS */
-/* 31:23 reserved */
-#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
-#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
-#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */
-/* 19:16 for port testing */
-#define PORT_LED_OFF (0<<14)
-#define PORT_LED_AMBER (1<<14)
-#define PORT_LED_GREEN (2<<14)
-#define PORT_LED_MASK (3<<14)
-#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
-#define PORT_POWER (1<<12) /* true: has power (see PPC) */
-#define PORT_USB11(x) (((x)&(3<<10))==(1<<10)) /* USB 1.1 device */
-/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
-/* 9 reserved */
-#define PORT_RESET (1<<8) /* reset port */
-#define PORT_SUSPEND (1<<7) /* suspend port */
-#define PORT_RESUME (1<<6) /* resume it */
-#define PORT_OCC (1<<5) /* over current change */
-#define PORT_OC (1<<4) /* over current active */
-#define PORT_PEC (1<<3) /* port enable change */
-#define PORT_PE (1<<2) /* port enable */
-#define PORT_CSC (1<<1) /* connect status change */
-#define PORT_CONNECT (1<<0) /* device connected */
-#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
-} __attribute__ ((packed));
-
-#define USBMODE 0x68 /* USB Device mode */
-#define USBMODE_SDIS (1<<3) /* Stream disable */
-#define USBMODE_BE (1<<2) /* BE/LE endianness select */
-#define USBMODE_CM_HC (3<<0) /* host controller mode */
-#define USBMODE_CM_IDLE (0<<0) /* idle state */
-
-/* Appendix C, Debug port ... intended for use with special "debug devices"
- * that can help if there's no serial console. (nonstandard enumeration.)
- */
-struct ehci_dbg_port {
- u32 control;
-#define DBGP_OWNER (1<<30)
-#define DBGP_ENABLED (1<<28)
-#define DBGP_DONE (1<<16)
-#define DBGP_INUSE (1<<10)
-#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
-# define DBGP_ERR_BAD 1
-# define DBGP_ERR_SIGNAL 2
-#define DBGP_ERROR (1<<6)
-#define DBGP_GO (1<<5)
-#define DBGP_OUT (1<<4)
-#define DBGP_LEN(x) (((x)>>0)&0x0f)
- u32 pids;
-#define DBGP_PID_GET(x) (((x)>>16)&0xff)
-#define DBGP_PID_SET(data,tok) (((data)<<8)|(tok))
- u32 data03;
- u32 data47;
- u32 address;
-#define DBGP_EPADDR(dev,ep) (((dev)<<8)|(ep))
-} __attribute__ ((packed));
+#include <linux/usb/ehci_def.h>
/*-------------------------------------------------------------------------*/
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d85a74c..f79c204 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -673,7 +673,6 @@
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
- select VIDEO_SELECT
help
This is the frame buffer device driver for generic VESA 2.0
compliant graphic cards. The older VESA 1.2 cards are not supported.
@@ -1578,7 +1577,6 @@
tristate "Cyberblade/i1 support"
depends on FB && PCI && X86_32 && !64BIT
select FB_CFB_IMAGEBLIT
- select VIDEO_SELECT
---help---
This driver is supposed to support the Trident Cyberblade/i1
graphics core integrated in the VIA VT8601A North Bridge,
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index e721644..1e35ba6 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -372,7 +372,7 @@
return 0;
}
-static struct of_device_id bw2_match[] = {
+static const struct of_device_id bw2_match[] = {
{
.name = "bwtwo",
},
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index b17e746..a2d1882 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -589,7 +589,7 @@
return 0;
}
-static struct of_device_id cg14_match[] = {
+static const struct of_device_id cg14_match[] = {
{
.name = "cgfourteen",
},
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index 3aa7b6c..99f87fb 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -456,7 +456,7 @@
return 0;
}
-static struct of_device_id cg3_match[] = {
+static const struct of_device_id cg3_match[] = {
{
.name = "cgthree",
},
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index 2f64bb3..940ec04 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -34,10 +34,11 @@
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 void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+static int cg6_pan_display(struct fb_var_screeninfo *, struct fb_info *);
/*
* Frame buffer operations
@@ -47,6 +48,7 @@
.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,
@@ -161,6 +163,7 @@
#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 {
@@ -280,6 +283,33 @@
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.
*
@@ -643,9 +673,13 @@
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);
@@ -814,7 +848,7 @@
return 0;
}
-static struct of_device_id cg6_match[] = {
+static const struct of_device_id cg6_match[] = {
{
.name = "cgsix",
},
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 06f87b0..2f50a80 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -43,22 +43,6 @@
buffer. Each 64KB will give you approximately 16 80x25
screenfuls of scrollback buffer
-config VIDEO_SELECT
- bool "Video mode selection support"
- depends on X86 && VGA_CONSOLE
- ---help---
- This enables support for text mode selection on kernel startup. If
- you want to take advantage of some high-resolution text mode your
- card's BIOS offers, but the traditional Linux utilities like
- SVGATextMode don't, you can say Y here and set the mode using the
- "vga=" option from your boot loader (lilo or loadlin) or set
- "vga=ask" which brings up a video mode menu on kernel startup. (Try
- "man bootparam" or see the documentation of your boot loader about
- how to pass options to the kernel.)
-
- Read the file <file:Documentation/svga.txt> for more information
- about the Video mode selection support. If unsure, say N.
-
config MDA_CONSOLE
depends on !M68K && !PARISC && ISA
tristate "MDA text console (dual-headed) (EXPERIMENTAL)"
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 7992b13..9dbb964 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -1042,7 +1042,7 @@
return 0;
}
-static struct of_device_id ffb_match[] = {
+static const struct of_device_id ffb_match[] = {
{
.name = "SUNW,ffb",
},
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index 13fea61..7c7e8c2 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -33,6 +33,7 @@
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
@@ -42,6 +43,7 @@
.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,
@@ -206,6 +208,60 @@
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
@@ -454,44 +510,6 @@
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;
@@ -641,7 +659,7 @@
return 0;
}
-static struct of_device_id leo_match[] = {
+static const struct of_device_id leo_match[] = {
{
.name = "SUNW,leo",
},
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index 9e90345..7000f2c 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -349,7 +349,7 @@
return 0;
}
-static struct of_device_id p9100_match[] = {
+static const struct of_device_id p9100_match[] = {
{
.name = "p9100",
},
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index 2a03f78..643afbfe 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -505,7 +505,7 @@
return 0;
}
-static struct of_device_id tcx_match[] = {
+static const struct of_device_id tcx_match[] = {
{
.name = "SUNW,tcx",
},
diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
index 47ed39b..a463b3d 100644
--- a/drivers/video/xen-fbfront.c
+++ b/drivers/video/xen-fbfront.c
@@ -680,11 +680,11 @@
static int __init xenfb_init(void)
{
- if (!is_running_on_xen())
+ if (!xen_domain())
return -ENODEV;
/* Nothing to do if running in dom0. */
- if (is_initial_xendomain())
+ if (xen_initial_domain())
return -ENODEV;
return xenbus_register_frontend(&xenfb);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index c510367..1a22fe7 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -66,6 +66,13 @@
Watchdog timer embedded into AT91RM9200 chips. This will reboot your
system when the timeout is reached.
+config AT91SAM9X_WATCHDOG
+ tristate "AT91SAM9X watchdog"
+ depends on WATCHDOG && (ARCH_AT91SAM9260 || ARCH_AT91SAM9261)
+ help
+ Watchdog timer embedded into AT91SAM9X chips. This will reboot your
+ system when the timeout is reached.
+
config 21285_WATCHDOG
tristate "DC21285 watchdog"
depends on FOOTBRIDGE
@@ -217,6 +224,15 @@
NOTE: once enabled, this timer cannot be disabled.
Say N if you are unsure.
+config ORION5X_WATCHDOG
+ tristate "Orion5x watchdog"
+ depends on ARCH_ORION5X
+ help
+ Say Y here if to include support for the watchdog timer
+ in the Orion5x ARM SoCs.
+ To compile this driver as a module, choose M here: the
+ module will be called orion5x_wdt.
+
# ARM26 Architecture
# AVR32 Architecture
@@ -416,6 +432,18 @@
To compile this driver as a module, choose M here: the
module will be called it8712f_wdt.
+config IT87_WDT
+ tristate "IT87 Watchdog Timer"
+ depends on X86 && EXPERIMENTAL
+ ---help---
+ This is the driver for the hardware watchdog on the ITE IT8716,
+ IT8718, IT8726, IT8712(Version J,K) Super I/O chips. This watchdog
+ simply watches your kernel to make sure it doesn't freeze, and if
+ it does, it reboots your computer after a certain amount of time.
+
+ To compile this driver as a module, choose M here: the module will
+ be called it87_wdt.
+
config HP_WATCHDOG
tristate "HP Proliant iLO 2 Hardware Watchdog Timer"
depends on X86
@@ -573,6 +601,21 @@
Most people will say N.
+config W83697UG_WDT
+ tristate "W83697UG/W83697UF Watchdog Timer"
+ depends on X86
+ ---help---
+ This is the driver for the hardware watchdog on the W83697UG/UF
+ chipset as used in MSI Fuzzy CX700 VIA motherboards (and likely others).
+ This watchdog simply watches your kernel to make sure it doesn't
+ freeze, and if it does, it reboots your computer after a certain
+ amount of time.
+
+ To compile this driver as a module, choose M here: the
+ module will be called w83697ug_wdt.
+
+ Most people will say N.
+
config W83877F_WDT
tristate "W83877F (EMACS) Watchdog Timer"
depends on X86
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index e0ef123..e352bbb 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -26,6 +26,7 @@
# ARM Architecture
obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
+obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
@@ -39,6 +40,7 @@
obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
+obj-$(CONFIG_ORION5X_WATCHDOG) += orion5x_wdt.o
# ARM26 Architecture
@@ -71,6 +73,7 @@
obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o
endif
obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
+obj-$(CONFIG_IT87_WDT) += it87_wdt.o
obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
@@ -83,6 +86,7 @@
obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o
+obj-$(CONFIG_W83697UG_WDT) += w83697ug_wdt.o
obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
obj-$(CONFIG_MACHZ_WDT) += machzwd.o
@@ -123,6 +127,9 @@
# SPARC64 Architecture
+obj-$(CONFIG_WATCHDOG_RIO) += riowd.o
+obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o
+
# XTENSA Architecture
# Architecture Independant
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
new file mode 100644
index 0000000..b4babfc
--- /dev/null
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -0,0 +1,328 @@
+/*
+ * Watchdog driver for Atmel AT91SAM9x processors.
+ *
+ * Copyright (C) 2008 Renaud CERRATO r.cerrato@til-technologies.fr
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * The Watchdog Timer Mode Register can be only written to once. If the
+ * timeout need to be set from Linux, be sure that the bootstrap or the
+ * bootloader doesn't write to this register.
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/bitops.h>
+#include <linux/uaccess.h>
+
+#include <asm/arch/at91_wdt.h>
+
+#define DRV_NAME "AT91SAM9 Watchdog"
+
+/* AT91SAM9 watchdog runs a 12bit counter @ 256Hz,
+ * use this to convert a watchdog
+ * value from/to milliseconds.
+ */
+#define ms_to_ticks(t) (((t << 8) / 1000) - 1)
+#define ticks_to_ms(t) (((t + 1) * 1000) >> 8)
+
+/* Hardware timeout in seconds */
+#define WDT_HW_TIMEOUT 2
+
+/* Timer heartbeat (500ms) */
+#define WDT_TIMEOUT (HZ/2)
+
+/* User land timeout */
+#define WDT_HEARTBEAT 15
+static int heartbeat = WDT_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
+ "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
+ "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static void at91_ping(unsigned long data);
+
+static struct {
+ unsigned long next_heartbeat; /* the next_heartbeat for the timer */
+ unsigned long open;
+ char expect_close;
+ struct timer_list timer; /* The timer that pings the watchdog */
+} at91wdt_private;
+
+/* ......................................................................... */
+
+
+/*
+ * Reload the watchdog timer. (ie, pat the watchdog)
+ */
+static inline void at91_wdt_reset(void)
+{
+ at91_sys_write(AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT);
+}
+
+/*
+ * Timer tick
+ */
+static void at91_ping(unsigned long data)
+{
+ if (time_before(jiffies, at91wdt_private.next_heartbeat) ||
+ (!nowayout && !at91wdt_private.open)) {
+ at91_wdt_reset();
+ mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+ } else
+ printk(KERN_CRIT DRV_NAME": I will reset your machine !\n");
+}
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int at91_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(0, &at91wdt_private.open))
+ return -EBUSY;
+
+ at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+ mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+
+ return nonseekable_open(inode, file);
+}
+
+/*
+ * Close the watchdog device.
+ */
+static int at91_wdt_close(struct inode *inode, struct file *file)
+{
+ clear_bit(0, &at91wdt_private.open);
+
+ /* stop internal ping */
+ if (!at91wdt_private.expect_close)
+ del_timer(&at91wdt_private.timer);
+
+ at91wdt_private.expect_close = 0;
+ return 0;
+}
+
+/*
+ * Set the watchdog time interval in 1/256Hz (write-once)
+ * Counter is 12 bit.
+ */
+static int at91_wdt_settimeout(unsigned int timeout)
+{
+ unsigned int reg;
+ unsigned int mr;
+
+ /* Check if disabled */
+ mr = at91_sys_read(AT91_WDT_MR);
+ if (mr & AT91_WDT_WDDIS) {
+ printk(KERN_ERR DRV_NAME": sorry, watchdog is disabled\n");
+ return -EIO;
+ }
+
+ /*
+ * All counting occurs at SLOW_CLOCK / 128 = 256 Hz
+ *
+ * Since WDV is a 12-bit counter, the maximum period is
+ * 4096 / 256 = 16 seconds.
+ */
+ reg = AT91_WDT_WDRSTEN /* causes watchdog reset */
+ /* | AT91_WDT_WDRPROC causes processor reset only */
+ | AT91_WDT_WDDBGHLT /* disabled in debug mode */
+ | AT91_WDT_WDD /* restart at any time */
+ | (timeout & AT91_WDT_WDV); /* timer value */
+ at91_sys_write(AT91_WDT_MR, reg);
+
+ return 0;
+}
+
+static const struct watchdog_info at91_wdt_info = {
+ .identity = DRV_NAME,
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+};
+
+/*
+ * Handle commands from user-space.
+ */
+static long at91_wdt_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int new_value;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &at91_wdt_info,
+ sizeof(at91_wdt_info)) ? -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+
+ case WDIOC_KEEPALIVE:
+ at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+ return 0;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_value, p))
+ return -EFAULT;
+
+ heartbeat = new_value;
+ at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+
+ return put_user(new_value, p); /* return current value */
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(heartbeat, p);
+ }
+ return -ENOTTY;
+}
+
+/*
+ * Pat the watchdog whenever device is written to.
+ */
+static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len,
+ loff_t *ppos)
+{
+ if (!len)
+ return 0;
+
+ /* Scan for magic character */
+ if (!nowayout) {
+ size_t i;
+
+ at91wdt_private.expect_close = 0;
+
+ for (i = 0; i < len; i++) {
+ char c;
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V') {
+ at91wdt_private.expect_close = 42;
+ break;
+ }
+ }
+ }
+
+ at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+
+ return len;
+}
+
+/* ......................................................................... */
+
+static const struct file_operations at91wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .unlocked_ioctl = at91_wdt_ioctl,
+ .open = at91_wdt_open,
+ .release = at91_wdt_close,
+ .write = at91_wdt_write,
+};
+
+static struct miscdevice at91wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &at91wdt_fops,
+};
+
+static int __init at91wdt_probe(struct platform_device *pdev)
+{
+ int res;
+
+ if (at91wdt_miscdev.parent)
+ return -EBUSY;
+ at91wdt_miscdev.parent = &pdev->dev;
+
+ /* Set watchdog */
+ res = at91_wdt_settimeout(ms_to_ticks(WDT_HW_TIMEOUT * 1000));
+ if (res)
+ return res;
+
+ res = misc_register(&at91wdt_miscdev);
+ if (res)
+ return res;
+
+ at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+ setup_timer(&at91wdt_private.timer, at91_ping, 0);
+ mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+
+ printk(KERN_INFO DRV_NAME " enabled (heartbeat=%d sec, nowayout=%d)\n",
+ heartbeat, nowayout);
+
+ return 0;
+}
+
+static int __exit at91wdt_remove(struct platform_device *pdev)
+{
+ int res;
+
+ res = misc_deregister(&at91wdt_miscdev);
+ if (!res)
+ at91wdt_miscdev.parent = NULL;
+
+ return res;
+}
+
+#ifdef CONFIG_PM
+
+static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+ return 0;
+}
+
+static int at91wdt_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+#else
+#define at91wdt_suspend NULL
+#define at91wdt_resume NULL
+#endif
+
+static struct platform_driver at91wdt_driver = {
+ .remove = __exit_p(at91wdt_remove),
+ .suspend = at91wdt_suspend,
+ .resume = at91wdt_resume,
+ .driver = {
+ .name = "at91_wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init at91sam_wdt_init(void)
+{
+ return platform_driver_probe(&at91wdt_driver, at91wdt_probe);
+}
+
+static void __exit at91sam_wdt_exit(void)
+{
+ platform_driver_unregister(&at91wdt_driver);
+}
+
+module_init(at91sam_wdt_init);
+module_exit(at91sam_wdt_exit);
+
+MODULE_AUTHOR("Renaud CERRATO <r.cerrato@til-technologies.fr>");
+MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
new file mode 100644
index 0000000..084dfe9
--- /dev/null
+++ b/drivers/watchdog/cpwd.c
@@ -0,0 +1,695 @@
+/* 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 <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/smp_lock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include <asm/watchdog.h>
+
+#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 <ebrower@usa.net>");
+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/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
new file mode 100644
index 0000000..afb8af3
--- /dev/null
+++ b/drivers/watchdog/it87_wdt.c
@@ -0,0 +1,725 @@
+/*
+ * Watchdog Timer Driver
+ * for ITE IT87xx Environment Control - Low Pin Count Input / Output
+ *
+ * (c) Copyright 2007 Oliver Schuster <olivers137@aol.com>
+ *
+ * Based on softdog.c by Alan Cox,
+ * 83977f_wdt.c by Jose Goncalves,
+ * it87.c by Chris Gauthron, Jean Delvare
+ *
+ * Data-sheets: Publicly available at the ITE website
+ * http://www.ite.com.tw/
+ *
+ * Support of the watchdog timers, which are available on
+ * IT8716, IT8718, IT8726 and IT8712 (J,K version).
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+
+#define WATCHDOG_VERSION "1.12"
+#define WATCHDOG_NAME "IT87 WDT"
+#define PFX WATCHDOG_NAME ": "
+#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
+#define WD_MAGIC 'V'
+
+/* Defaults for Module Parameter */
+#define DEFAULT_NOGAMEPORT 0
+#define DEFAULT_EXCLUSIVE 1
+#define DEFAULT_TIMEOUT 60
+#define DEFAULT_TESTMODE 0
+#define DEFAULT_NOWAYOUT WATCHDOG_NOWAYOUT
+
+/* IO Ports */
+#define REG 0x2e
+#define VAL 0x2f
+
+/* Logical device Numbers LDN */
+#define GPIO 0x07
+#define GAMEPORT 0x09
+#define CIR 0x0a
+
+/* Configuration Registers and Functions */
+#define LDNREG 0x07
+#define CHIPID 0x20
+#define CHIPREV 0x22
+#define ACTREG 0x30
+#define BASEREG 0x60
+
+/* Chip Id numbers */
+#define NO_DEV_ID 0xffff
+#define IT8705_ID 0x8705
+#define IT8712_ID 0x8712
+#define IT8716_ID 0x8716
+#define IT8718_ID 0x8718
+#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */
+
+/* GPIO Configuration Registers LDN=0x07 */
+#define WDTCTRL 0x71
+#define WDTCFG 0x72
+#define WDTVALLSB 0x73
+#define WDTVALMSB 0x74
+
+/* GPIO Bits WDTCTRL */
+#define WDT_CIRINT 0x80
+#define WDT_MOUSEINT 0x40
+#define WDT_KYBINT 0x20
+#define WDT_GAMEPORT 0x10 /* not it8718 */
+#define WDT_FORCE 0x02
+#define WDT_ZERO 0x01
+
+/* GPIO Bits WDTCFG */
+#define WDT_TOV1 0x80
+#define WDT_KRST 0x40
+#define WDT_TOVE 0x20
+#define WDT_PWROK 0x10
+#define WDT_INT_MASK 0x0f
+
+/* CIR Configuration Register LDN=0x0a */
+#define CIR_ILS 0x70
+
+/* The default Base address is not always available, we use this */
+#define CIR_BASE 0x0208
+
+/* CIR Controller */
+#define CIR_DR(b) (b)
+#define CIR_IER(b) (b + 1)
+#define CIR_RCR(b) (b + 2)
+#define CIR_TCR1(b) (b + 3)
+#define CIR_TCR2(b) (b + 4)
+#define CIR_TSR(b) (b + 5)
+#define CIR_RSR(b) (b + 6)
+#define CIR_BDLR(b) (b + 5)
+#define CIR_BDHR(b) (b + 6)
+#define CIR_IIR(b) (b + 7)
+
+/* Default Base address of Game port */
+#define GP_BASE_DEFAULT 0x0201
+
+/* wdt_status */
+#define WDTS_TIMER_RUN 0
+#define WDTS_DEV_OPEN 1
+#define WDTS_KEEPALIVE 2
+#define WDTS_LOCKED 3
+#define WDTS_USE_GP 4
+#define WDTS_EXPECTED 5
+
+static unsigned int base, gpact, ciract;
+static unsigned long wdt_status;
+static DEFINE_SPINLOCK(spinlock);
+
+static int nogameport = DEFAULT_NOGAMEPORT;
+static int exclusive = DEFAULT_EXCLUSIVE;
+static int timeout = DEFAULT_TIMEOUT;
+static int testmode = DEFAULT_TESTMODE;
+static int nowayout = DEFAULT_NOWAYOUT;
+
+module_param(nogameport, int, 0);
+MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
+ __MODULE_STRING(DEFAULT_NOGAMEPORT));
+module_param(exclusive, int, 0);
+MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default="
+ __MODULE_STRING(DEFAULT_EXCLUSIVE));
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default="
+ __MODULE_STRING(DEFAULT_TIMEOUT));
+module_param(testmode, int, 0);
+MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default="
+ __MODULE_STRING(DEFAULT_TESTMODE));
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT));
+
+/* Superio Chip */
+
+static inline void superio_enter(void)
+{
+ outb(0x87, REG);
+ outb(0x01, REG);
+ outb(0x55, REG);
+ outb(0x55, REG);
+}
+
+static inline void superio_exit(void)
+{
+ outb(0x02, REG);
+ outb(0x02, VAL);
+}
+
+static inline void superio_select(int ldn)
+{
+ outb(LDNREG, REG);
+ outb(ldn, VAL);
+}
+
+static inline int superio_inb(int reg)
+{
+ outb(reg, REG);
+ return inb(VAL);
+}
+
+static inline void superio_outb(int val, int reg)
+{
+ outb(reg, REG);
+ outb(val, VAL);
+}
+
+static inline int superio_inw(int reg)
+{
+ int val;
+ outb(reg++, REG);
+ val = inb(VAL) << 8;
+ outb(reg, REG);
+ val |= inb(VAL);
+ return val;
+}
+
+static inline void superio_outw(int val, int reg)
+{
+ outb(reg++, REG);
+ outb(val >> 8, VAL);
+ outb(reg, REG);
+ outb(val, VAL);
+}
+
+/* watchdog timer handling */
+
+static void wdt_keepalive(void)
+{
+ if (test_bit(WDTS_USE_GP, &wdt_status))
+ inb(base);
+ else
+ /* The timer reloads with around 5 msec delay */
+ outb(0x55, CIR_DR(base));
+ set_bit(WDTS_KEEPALIVE, &wdt_status);
+}
+
+static void wdt_start(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+
+ superio_select(GPIO);
+ if (test_bit(WDTS_USE_GP, &wdt_status))
+ superio_outb(WDT_GAMEPORT, WDTCTRL);
+ else
+ superio_outb(WDT_CIRINT, WDTCTRL);
+ if (!testmode)
+ superio_outb(WDT_TOV1 | WDT_KRST | WDT_PWROK, WDTCFG);
+ else
+ superio_outb(WDT_TOV1, WDTCFG);
+ superio_outb(timeout>>8, WDTVALMSB);
+ superio_outb(timeout, WDTVALLSB);
+
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+}
+
+static void wdt_stop(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+
+ superio_select(GPIO);
+ superio_outb(0x00, WDTCTRL);
+ superio_outb(WDT_TOV1, WDTCFG);
+ superio_outb(0x00, WDTVALMSB);
+ superio_outb(0x00, WDTVALLSB);
+
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+}
+
+/**
+ * wdt_set_timeout - set a new timeout value with watchdog ioctl
+ * @t: timeout value in seconds
+ *
+ * The hardware device has a 16 bit watchdog timer, thus the
+ * timeout time ranges between 1 and 65535 seconds.
+ *
+ * Used within WDIOC_SETTIMEOUT watchdog device ioctl.
+ */
+
+static int wdt_set_timeout(int t)
+{
+ unsigned long flags;
+
+ if (t < 1 || t > 65535)
+ return -EINVAL;
+
+ timeout = t;
+
+ spin_lock_irqsave(&spinlock, flags);
+ if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
+ superio_enter();
+
+ superio_select(GPIO);
+ superio_outb(t>>8, WDTVALMSB);
+ superio_outb(t, WDTVALLSB);
+
+ superio_exit();
+ }
+ spin_unlock_irqrestore(&spinlock, flags);
+ return 0;
+}
+
+/**
+ * wdt_get_status - determines the status supported by watchdog ioctl
+ * @status: status returned to user space
+ *
+ * The status bit of the device does not allow to distinguish
+ * between a regular system reset and a watchdog forced reset.
+ * But, in test mode it is useful, so it is supported through
+ * WDIOC_GETSTATUS watchdog ioctl. Additionally the driver
+ * reports the keepalive signal and the acception of the magic.
+ *
+ * Used within WDIOC_GETSTATUS watchdog device ioctl.
+ */
+
+static int wdt_get_status(int *status)
+{
+ unsigned long flags;
+
+ *status = 0;
+ if (testmode) {
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+ superio_select(GPIO);
+ if (superio_inb(WDTCTRL) & WDT_ZERO) {
+ superio_outb(0x00, WDTCTRL);
+ clear_bit(WDTS_TIMER_RUN, &wdt_status);
+ *status |= WDIOF_CARDRESET;
+ }
+
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+ }
+ if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status))
+ *status |= WDIOF_KEEPALIVEPING;
+ if (test_bit(WDTS_EXPECTED, &wdt_status))
+ *status |= WDIOF_MAGICCLOSE;
+ return 0;
+}
+
+/* /dev/watchdog handling */
+
+/**
+ * wdt_open - watchdog file_operations .open
+ * @inode: inode of the device
+ * @file: file handle to the device
+ *
+ * The watchdog timer starts by opening the device.
+ *
+ * Used within the file operation of the watchdog device.
+ */
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+ if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status))
+ return -EBUSY;
+ if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
+ if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status))
+ __module_get(THIS_MODULE);
+ wdt_start();
+ }
+ return nonseekable_open(inode, file);
+}
+
+/**
+ * wdt_release - watchdog file_operations .release
+ * @inode: inode of the device
+ * @file: file handle to the device
+ *
+ * Closing the watchdog device either stops the watchdog timer
+ * or in the case, that nowayout is set or the magic character
+ * wasn't written, a critical warning about an running watchdog
+ * timer is given.
+ *
+ * Used within the file operation of the watchdog device.
+ */
+
+static int wdt_release(struct inode *inode, struct file *file)
+{
+ if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
+ if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) {
+ wdt_stop();
+ clear_bit(WDTS_TIMER_RUN, &wdt_status);
+ } else {
+ wdt_keepalive();
+ printk(KERN_CRIT PFX
+ "unexpected close, not stopping watchdog!\n");
+ }
+ }
+ clear_bit(WDTS_DEV_OPEN, &wdt_status);
+ return 0;
+}
+
+/**
+ * wdt_write - watchdog file_operations .write
+ * @file: file handle to the watchdog
+ * @buf: buffer to write
+ * @count: count of bytes
+ * @ppos: pointer to the position to write. No seeks allowed
+ *
+ * A write to a watchdog device is defined as a keepalive signal. Any
+ * write of data will do, as we don't define content meaning.
+ *
+ * Used within the file operation of the watchdog device.
+ */
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ if (count) {
+ clear_bit(WDTS_EXPECTED, &wdt_status);
+ wdt_keepalive();
+ }
+ if (!nowayout) {
+ size_t ofs;
+
+ /* note: just in case someone wrote the magic character long ago */
+ for (ofs = 0; ofs != count; ofs++) {
+ char c;
+ if (get_user(c, buf + ofs))
+ return -EFAULT;
+ if (c == WD_MAGIC)
+ set_bit(WDTS_EXPECTED, &wdt_status);
+ }
+ }
+ return count;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+ .firmware_version = 1,
+ .identity = WATCHDOG_NAME,
+};
+
+/**
+ * wdt_ioctl - watchdog file_operations .unlocked_ioctl
+ * @file: file handle to the device
+ * @cmd: watchdog command
+ * @arg: argument pointer
+ *
+ * The watchdog API defines a common set of functions for all watchdogs
+ * according to their available features.
+ *
+ * Used within the file operation of the watchdog device.
+ */
+
+static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int rc = 0, status, new_options, new_timeout;
+ union {
+ struct watchdog_info __user *ident;
+ int __user *i;
+ } uarg;
+
+ uarg.i = (int __user *)arg;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(uarg.ident,
+ &ident, sizeof(ident)) ? -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ wdt_get_status(&status);
+ return put_user(status, uarg.i);
+
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, uarg.i);
+
+ case WDIOC_KEEPALIVE:
+ wdt_keepalive();
+ return 0;
+
+ case WDIOC_SETOPTIONS:
+ if (get_user(new_options, uarg.i))
+ return -EFAULT;
+
+ switch (new_options) {
+ case WDIOS_DISABLECARD:
+ if (test_bit(WDTS_TIMER_RUN, &wdt_status))
+ wdt_stop();
+ clear_bit(WDTS_TIMER_RUN, &wdt_status);
+ return 0;
+
+ case WDIOS_ENABLECARD:
+ if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status))
+ wdt_start();
+ return 0;
+
+ default:
+ return -EFAULT;
+ }
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_timeout, uarg.i))
+ return -EFAULT;
+ rc = wdt_set_timeout(new_timeout);
+ case WDIOC_GETTIMEOUT:
+ if (put_user(timeout, uarg.i))
+ return -EFAULT;
+ return rc;
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT)
+ wdt_stop();
+ return NOTIFY_DONE;
+}
+
+static const struct file_operations wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = wdt_write,
+ .unlocked_ioctl = wdt_ioctl,
+ .open = wdt_open,
+ .release = wdt_release,
+};
+
+static struct miscdevice wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &wdt_fops,
+};
+
+static struct notifier_block wdt_notifier = {
+ .notifier_call = wdt_notify_sys,
+};
+
+static int __init it87_wdt_init(void)
+{
+ int rc = 0;
+ u16 chip_type;
+ u8 chip_rev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+ chip_type = superio_inw(CHIPID);
+ chip_rev = superio_inb(CHIPREV) & 0x0f;
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+
+ switch (chip_type) {
+ case IT8716_ID:
+ case IT8718_ID:
+ case IT8726_ID:
+ break;
+ case IT8712_ID:
+ if (chip_rev > 7)
+ break;
+ case IT8705_ID:
+ printk(KERN_ERR PFX
+ "Unsupported Chip found, Chip %04x Revision %02x\n",
+ chip_type, chip_rev);
+ return -ENODEV;
+ case NO_DEV_ID:
+ printk(KERN_ERR PFX "no device\n");
+ return -ENODEV;
+ default:
+ printk(KERN_ERR PFX
+ "Unknown Chip found, Chip %04x Revision %04x\n",
+ chip_type, chip_rev);
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+
+ superio_select(GPIO);
+ superio_outb(WDT_TOV1, WDTCFG);
+ superio_outb(0x00, WDTCTRL);
+
+ /* First try to get Gameport support */
+ if (chip_type != IT8718_ID && !nogameport) {
+ superio_select(GAMEPORT);
+ base = superio_inw(BASEREG);
+ if (!base) {
+ base = GP_BASE_DEFAULT;
+ superio_outw(base, BASEREG);
+ }
+ gpact = superio_inb(ACTREG);
+ superio_outb(0x01, ACTREG);
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+ if (request_region(base, 1, WATCHDOG_NAME))
+ set_bit(WDTS_USE_GP, &wdt_status);
+ else
+ rc = -EIO;
+ } else {
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+ }
+
+ /* If we haven't Gameport support, try to get CIR support */
+ if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+ if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
+ if (rc == -EIO)
+ printk(KERN_ERR PFX
+ "I/O Address 0x%04x and 0x%04x"
+ " already in use\n", base, CIR_BASE);
+ else
+ printk(KERN_ERR PFX
+ "I/O Address 0x%04x already in use\n",
+ CIR_BASE);
+ rc = -EIO;
+ goto err_out;
+ }
+ base = CIR_BASE;
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+
+ superio_select(CIR);
+ superio_outw(base, BASEREG);
+ superio_outb(0x00, CIR_ILS);
+ ciract = superio_inb(ACTREG);
+ superio_outb(0x01, ACTREG);
+ if (rc == -EIO) {
+ superio_select(GAMEPORT);
+ superio_outb(gpact, ACTREG);
+ }
+
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+ }
+
+ if (timeout < 1 || timeout > 65535) {
+ timeout = DEFAULT_TIMEOUT;
+ printk(KERN_WARNING PFX
+ "Timeout value out of range, use default %d sec\n",
+ DEFAULT_TIMEOUT);
+ }
+
+ rc = register_reboot_notifier(&wdt_notifier);
+ if (rc) {
+ printk(KERN_ERR PFX
+ "Cannot register reboot notifier (err=%d)\n", rc);
+ goto err_out_region;
+ }
+
+ rc = misc_register(&wdt_miscdev);
+ if (rc) {
+ printk(KERN_ERR PFX
+ "Cannot register miscdev on minor=%d (err=%d)\n",
+ wdt_miscdev.minor, rc);
+ goto err_out_reboot;
+ }
+
+ /* Initialize CIR to use it as keepalive source */
+ if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+ outb(0x00, CIR_RCR(base));
+ outb(0xc0, CIR_TCR1(base));
+ outb(0x5c, CIR_TCR2(base));
+ outb(0x10, CIR_IER(base));
+ outb(0x00, CIR_BDHR(base));
+ outb(0x01, CIR_BDLR(base));
+ outb(0x09, CIR_IER(base));
+ }
+
+ printk(KERN_INFO PFX "Chip it%04x revision %d initialized. "
+ "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d "
+ "nogameport=%d)\n", chip_type, chip_rev, timeout,
+ nowayout, testmode, exclusive, nogameport);
+
+ return 0;
+
+err_out_reboot:
+ unregister_reboot_notifier(&wdt_notifier);
+err_out_region:
+ release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
+ if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+ superio_select(CIR);
+ superio_outb(ciract, ACTREG);
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+ }
+err_out:
+ if (chip_type != IT8718_ID && !nogameport) {
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+ superio_select(GAMEPORT);
+ superio_outb(gpact, ACTREG);
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+ }
+
+ return rc;
+}
+
+static void __exit it87_wdt_exit(void)
+{
+ unsigned long flags;
+ int nolock;
+
+ nolock = !spin_trylock_irqsave(&spinlock, flags);
+ superio_enter();
+ superio_select(GPIO);
+ superio_outb(0x00, WDTCTRL);
+ superio_outb(0x00, WDTCFG);
+ superio_outb(0x00, WDTVALMSB);
+ superio_outb(0x00, WDTVALLSB);
+ if (test_bit(WDTS_USE_GP, &wdt_status)) {
+ superio_select(GAMEPORT);
+ superio_outb(gpact, ACTREG);
+ } else {
+ superio_select(CIR);
+ superio_outb(ciract, ACTREG);
+ }
+ superio_exit();
+ if (!nolock)
+ spin_unlock_irqrestore(&spinlock, flags);
+
+ misc_deregister(&wdt_miscdev);
+ unregister_reboot_notifier(&wdt_notifier);
+ release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
+}
+
+module_init(it87_wdt_init);
+module_exit(it87_wdt_exit);
+
+MODULE_AUTHOR("Oliver Schuster");
+MODULE_DESCRIPTION("Hardware Watchdog Device Driver for IT87xx EC-LPC I/O");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 3a11dad..7bcbb7f 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/char/watchdog/omap_wdt.c
+ * omap_wdt.c
*
- * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog
+ * Watchdog driver for the TI OMAP 16xx & 24xx/34xx 32KHz (non-secure) watchdog
*
* Author: MontaVista Software, Inc.
* <gdavis@mvista.com> or <source@mvista.com>
@@ -47,50 +47,68 @@
#include "omap_wdt.h"
+static struct platform_device *omap_wdt_dev;
+
static unsigned timer_margin;
module_param(timer_margin, uint, 0);
MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
-static int omap_wdt_users;
-static struct clk *armwdt_ck;
-static struct clk *mpu_wdt_ick;
-static struct clk *mpu_wdt_fck;
-
static unsigned int wdt_trgr_pattern = 0x1234;
static spinlock_t wdt_lock;
-static void omap_wdt_ping(void)
+struct omap_wdt_dev {
+ void __iomem *base; /* physical */
+ struct device *dev;
+ int omap_wdt_users;
+ struct clk *armwdt_ck;
+ struct clk *mpu_wdt_ick;
+ struct clk *mpu_wdt_fck;
+ struct resource *mem;
+ struct miscdevice omap_wdt_miscdev;
+};
+
+static void omap_wdt_ping(struct omap_wdt_dev *wdev)
{
+ void __iomem *base = wdev->base;
+
/* wait for posted write to complete */
- while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+ while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
cpu_relax();
+
wdt_trgr_pattern = ~wdt_trgr_pattern;
- omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
+ __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
+
/* wait for posted write to complete */
- while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+ while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
cpu_relax();
/* reloaded WCRR from WLDR */
}
-static void omap_wdt_enable(void)
+static void omap_wdt_enable(struct omap_wdt_dev *wdev)
{
+ void __iomem *base = wdev->base;
+
/* Sequence to enable the watchdog */
- omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
- while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+ __raw_writel(0xBBBB, base + OMAP_WATCHDOG_SPR);
+ while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
cpu_relax();
- omap_writel(0x4444, OMAP_WATCHDOG_SPR);
- while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+
+ __raw_writel(0x4444, base + OMAP_WATCHDOG_SPR);
+ while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
cpu_relax();
}
-static void omap_wdt_disable(void)
+static void omap_wdt_disable(struct omap_wdt_dev *wdev)
{
+ void __iomem *base = wdev->base;
+
/* sequence required to disable watchdog */
- omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+ __raw_writel(0xAAAA, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
cpu_relax();
- omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+
+ __raw_writel(0x5555, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
cpu_relax();
}
@@ -103,83 +121,90 @@
timer_margin = new_timeout;
}
-static void omap_wdt_set_timeout(void)
+static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
{
u32 pre_margin = GET_WLDR_VAL(timer_margin);
+ void __iomem *base = wdev->base;
/* just count up at 32 KHz */
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
cpu_relax();
- omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+
+ __raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
+ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
cpu_relax();
}
/*
* Allow only one task to hold it open
*/
-
static int omap_wdt_open(struct inode *inode, struct file *file)
{
- if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
+ struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
+ void __iomem *base = wdev->base;
+
+ if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
return -EBUSY;
if (cpu_is_omap16xx())
- clk_enable(armwdt_ck); /* Enable the clock */
+ clk_enable(wdev->armwdt_ck); /* Enable the clock */
- if (cpu_is_omap24xx()) {
- clk_enable(mpu_wdt_ick); /* Enable the interface clock */
- clk_enable(mpu_wdt_fck); /* Enable the functional clock */
+ if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+ clk_enable(wdev->mpu_wdt_ick); /* Enable the interface clock */
+ clk_enable(wdev->mpu_wdt_fck); /* Enable the functional clock */
}
/* initialize prescaler */
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
- cpu_relax();
- omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
cpu_relax();
- omap_wdt_set_timeout();
- omap_wdt_enable();
+ __raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
+ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
+ cpu_relax();
+
+ file->private_data = (void *) wdev;
+
+ omap_wdt_set_timeout(wdev);
+ omap_wdt_enable(wdev);
+
return nonseekable_open(inode, file);
}
static int omap_wdt_release(struct inode *inode, struct file *file)
{
+ struct omap_wdt_dev *wdev = file->private_data;
+
/*
* Shut off the timer unless NOWAYOUT is defined.
*/
#ifndef CONFIG_WATCHDOG_NOWAYOUT
- omap_wdt_disable();
- if (cpu_is_omap16xx()) {
- clk_disable(armwdt_ck); /* Disable the clock */
- clk_put(armwdt_ck);
- armwdt_ck = NULL;
- }
+ omap_wdt_disable(wdev);
- if (cpu_is_omap24xx()) {
- clk_disable(mpu_wdt_ick); /* Disable the clock */
- clk_disable(mpu_wdt_fck); /* Disable the clock */
- clk_put(mpu_wdt_ick);
- clk_put(mpu_wdt_fck);
- mpu_wdt_ick = NULL;
- mpu_wdt_fck = NULL;
+ if (cpu_is_omap16xx())
+ clk_disable(wdev->armwdt_ck); /* Disable the clock */
+
+ if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+ clk_disable(wdev->mpu_wdt_ick); /* Disable the clock */
+ clk_disable(wdev->mpu_wdt_fck); /* Disable the clock */
}
#else
printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
#endif
- omap_wdt_users = 0;
+ wdev->omap_wdt_users = 0;
+
return 0;
}
static ssize_t omap_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
+ struct omap_wdt_dev *wdev = file->private_data;
+
/* Refresh LOAD_TIME. */
if (len) {
spin_lock(&wdt_lock);
- omap_wdt_ping();
+ omap_wdt_ping(wdev);
spin_unlock(&wdt_lock);
}
return len;
@@ -188,6 +213,7 @@
static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
+ struct omap_wdt_dev *wdev;
int new_margin;
static const struct watchdog_info ident = {
.identity = "OMAP Watchdog",
@@ -195,6 +221,8 @@
.firmware_version = 0,
};
+ wdev = file->private_data;
+
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user((struct watchdog_info __user *)arg, &ident,
@@ -203,14 +231,14 @@
return put_user(0, (int __user *)arg);
case WDIOC_GETBOOTSTATUS:
if (cpu_is_omap16xx())
- return put_user(omap_readw(ARM_SYSST),
+ return put_user(__raw_readw(ARM_SYSST),
(int __user *)arg);
if (cpu_is_omap24xx())
return put_user(omap_prcm_get_reset_sources(),
(int __user *)arg);
case WDIOC_KEEPALIVE:
spin_lock(&wdt_lock);
- omap_wdt_ping();
+ omap_wdt_ping(wdev);
spin_unlock(&wdt_lock);
return 0;
case WDIOC_SETTIMEOUT:
@@ -219,11 +247,11 @@
omap_wdt_adjust_timeout(new_margin);
spin_lock(&wdt_lock);
- omap_wdt_disable();
- omap_wdt_set_timeout();
- omap_wdt_enable();
+ omap_wdt_disable(wdev);
+ omap_wdt_set_timeout(wdev);
+ omap_wdt_enable(wdev);
- omap_wdt_ping();
+ omap_wdt_ping(wdev);
spin_unlock(&wdt_lock);
/* Fall */
case WDIOC_GETTIMEOUT:
@@ -241,96 +269,173 @@
.release = omap_wdt_release,
};
-static struct miscdevice omap_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &omap_wdt_fops,
-};
-
static int __init omap_wdt_probe(struct platform_device *pdev)
{
struct resource *res, *mem;
+ struct omap_wdt_dev *wdev;
int ret;
/* reserve static register mappings */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENOENT;
+ if (!res) {
+ ret = -ENOENT;
+ goto err_get_resource;
+ }
+
+ if (omap_wdt_dev) {
+ ret = -EBUSY;
+ goto err_busy;
+ }
mem = request_mem_region(res->start, res->end - res->start + 1,
pdev->name);
- if (mem == NULL)
- return -EBUSY;
+ if (!mem) {
+ ret = -EBUSY;
+ goto err_busy;
+ }
- platform_set_drvdata(pdev, mem);
+ wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
+ if (!wdev) {
+ ret = -ENOMEM;
+ goto err_kzalloc;
+ }
- omap_wdt_users = 0;
+ wdev->omap_wdt_users = 0;
+ wdev->mem = mem;
if (cpu_is_omap16xx()) {
- armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
- if (IS_ERR(armwdt_ck)) {
- ret = PTR_ERR(armwdt_ck);
- armwdt_ck = NULL;
- goto fail;
+ wdev->armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
+ if (IS_ERR(wdev->armwdt_ck)) {
+ ret = PTR_ERR(wdev->armwdt_ck);
+ wdev->armwdt_ck = NULL;
+ goto err_clk;
}
}
if (cpu_is_omap24xx()) {
- mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
- if (IS_ERR(mpu_wdt_ick)) {
- ret = PTR_ERR(mpu_wdt_ick);
- mpu_wdt_ick = NULL;
- goto fail;
+ wdev->mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
+ if (IS_ERR(wdev->mpu_wdt_ick)) {
+ ret = PTR_ERR(wdev->mpu_wdt_ick);
+ wdev->mpu_wdt_ick = NULL;
+ goto err_clk;
}
- mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
- if (IS_ERR(mpu_wdt_fck)) {
- ret = PTR_ERR(mpu_wdt_fck);
- mpu_wdt_fck = NULL;
- goto fail;
+ wdev->mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
+ if (IS_ERR(wdev->mpu_wdt_fck)) {
+ ret = PTR_ERR(wdev->mpu_wdt_fck);
+ wdev->mpu_wdt_fck = NULL;
+ goto err_clk;
}
}
- omap_wdt_disable();
+ if (cpu_is_omap34xx()) {
+ wdev->mpu_wdt_ick = clk_get(&pdev->dev, "wdt2_ick");
+ if (IS_ERR(wdev->mpu_wdt_ick)) {
+ ret = PTR_ERR(wdev->mpu_wdt_ick);
+ wdev->mpu_wdt_ick = NULL;
+ goto err_clk;
+ }
+ wdev->mpu_wdt_fck = clk_get(&pdev->dev, "wdt2_fck");
+ if (IS_ERR(wdev->mpu_wdt_fck)) {
+ ret = PTR_ERR(wdev->mpu_wdt_fck);
+ wdev->mpu_wdt_fck = NULL;
+ goto err_clk;
+ }
+ }
+ wdev->base = ioremap(res->start, res->end - res->start + 1);
+ if (!wdev->base) {
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ platform_set_drvdata(pdev, wdev);
+
+ omap_wdt_disable(wdev);
omap_wdt_adjust_timeout(timer_margin);
- omap_wdt_miscdev.parent = &pdev->dev;
- ret = misc_register(&omap_wdt_miscdev);
- if (ret)
- goto fail;
+ wdev->omap_wdt_miscdev.parent = &pdev->dev;
+ wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
+ wdev->omap_wdt_miscdev.name = "watchdog";
+ wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
- pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
+ ret = misc_register(&(wdev->omap_wdt_miscdev));
+ if (ret)
+ goto err_misc;
+
+ pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
+ __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
+ timer_margin);
/* autogate OCP interface clock */
- omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
+ __raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG);
+
+ omap_wdt_dev = pdev;
+
return 0;
-fail:
- if (armwdt_ck)
- clk_put(armwdt_ck);
- if (mpu_wdt_ick)
- clk_put(mpu_wdt_ick);
- if (mpu_wdt_fck)
- clk_put(mpu_wdt_fck);
- release_resource(mem);
+err_misc:
+ platform_set_drvdata(pdev, NULL);
+ iounmap(wdev->base);
+
+err_ioremap:
+ wdev->base = NULL;
+
+err_clk:
+ if (wdev->armwdt_ck)
+ clk_put(wdev->armwdt_ck);
+ if (wdev->mpu_wdt_ick)
+ clk_put(wdev->mpu_wdt_ick);
+ if (wdev->mpu_wdt_fck)
+ clk_put(wdev->mpu_wdt_fck);
+ kfree(wdev);
+
+err_kzalloc:
+ release_mem_region(res->start, res->end - res->start + 1);
+
+err_busy:
+err_get_resource:
+
return ret;
}
static void omap_wdt_shutdown(struct platform_device *pdev)
{
- omap_wdt_disable();
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+ if (wdev->omap_wdt_users)
+ omap_wdt_disable(wdev);
}
static int omap_wdt_remove(struct platform_device *pdev)
{
- struct resource *mem = platform_get_drvdata(pdev);
- misc_deregister(&omap_wdt_miscdev);
- release_resource(mem);
- if (armwdt_ck)
- clk_put(armwdt_ck);
- if (mpu_wdt_ick)
- clk_put(mpu_wdt_ick);
- if (mpu_wdt_fck)
- clk_put(mpu_wdt_fck);
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res)
+ return -ENOENT;
+
+ misc_deregister(&(wdev->omap_wdt_miscdev));
+ release_mem_region(res->start, res->end - res->start + 1);
+ platform_set_drvdata(pdev, NULL);
+
+ if (wdev->armwdt_ck) {
+ clk_put(wdev->armwdt_ck);
+ wdev->armwdt_ck = NULL;
+ }
+
+ if (wdev->mpu_wdt_ick) {
+ clk_put(wdev->mpu_wdt_ick);
+ wdev->mpu_wdt_ick = NULL;
+ }
+
+ if (wdev->mpu_wdt_fck) {
+ clk_put(wdev->mpu_wdt_fck);
+ wdev->mpu_wdt_fck = NULL;
+ }
+ iounmap(wdev->base);
+
+ kfree(wdev);
+ omap_wdt_dev = NULL;
+
return 0;
}
@@ -344,17 +449,23 @@
static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
{
- if (omap_wdt_users)
- omap_wdt_disable();
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+ if (wdev->omap_wdt_users)
+ omap_wdt_disable(wdev);
+
return 0;
}
static int omap_wdt_resume(struct platform_device *pdev)
{
- if (omap_wdt_users) {
- omap_wdt_enable();
- omap_wdt_ping();
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+ if (wdev->omap_wdt_users) {
+ omap_wdt_enable(wdev);
+ omap_wdt_ping(wdev);
}
+
return 0;
}
diff --git a/drivers/watchdog/omap_wdt.h b/drivers/watchdog/omap_wdt.h
index 52a532a5..fc02ec6 100644
--- a/drivers/watchdog/omap_wdt.h
+++ b/drivers/watchdog/omap_wdt.h
@@ -30,25 +30,15 @@
#ifndef _OMAP_WATCHDOG_H
#define _OMAP_WATCHDOG_H
-#define OMAP1610_WATCHDOG_BASE 0xfffeb000
-#define OMAP2420_WATCHDOG_BASE 0x48022000 /*WDT Timer 2 */
-
-#ifdef CONFIG_ARCH_OMAP24XX
-#define OMAP_WATCHDOG_BASE OMAP2420_WATCHDOG_BASE
-#else
-#define OMAP_WATCHDOG_BASE OMAP1610_WATCHDOG_BASE
-#define RM_RSTST_WKUP 0
-#endif
-
-#define OMAP_WATCHDOG_REV (OMAP_WATCHDOG_BASE + 0x00)
-#define OMAP_WATCHDOG_SYS_CONFIG (OMAP_WATCHDOG_BASE + 0x10)
-#define OMAP_WATCHDOG_STATUS (OMAP_WATCHDOG_BASE + 0x14)
-#define OMAP_WATCHDOG_CNTRL (OMAP_WATCHDOG_BASE + 0x24)
-#define OMAP_WATCHDOG_CRR (OMAP_WATCHDOG_BASE + 0x28)
-#define OMAP_WATCHDOG_LDR (OMAP_WATCHDOG_BASE + 0x2c)
-#define OMAP_WATCHDOG_TGR (OMAP_WATCHDOG_BASE + 0x30)
-#define OMAP_WATCHDOG_WPS (OMAP_WATCHDOG_BASE + 0x34)
-#define OMAP_WATCHDOG_SPR (OMAP_WATCHDOG_BASE + 0x48)
+#define OMAP_WATCHDOG_REV (0x00)
+#define OMAP_WATCHDOG_SYS_CONFIG (0x10)
+#define OMAP_WATCHDOG_STATUS (0x14)
+#define OMAP_WATCHDOG_CNTRL (0x24)
+#define OMAP_WATCHDOG_CRR (0x28)
+#define OMAP_WATCHDOG_LDR (0x2c)
+#define OMAP_WATCHDOG_TGR (0x30)
+#define OMAP_WATCHDOG_WPS (0x34)
+#define OMAP_WATCHDOG_SPR (0x48)
/* Using the prescaler, the OMAP watchdog could go for many
* months before firing. These limits work without scaling,
diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c
new file mode 100644
index 0000000..14a339f
--- /dev/null
+++ b/drivers/watchdog/orion5x_wdt.c
@@ -0,0 +1,245 @@
+/*
+ * drivers/watchdog/orion5x_wdt.c
+ *
+ * Watchdog driver for Orion5x processors
+ *
+ * Author: Sylver Bruneau <sylver.bruneau@googlemail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+/*
+ * Watchdog timer block registers.
+ */
+#define TIMER_CTRL (TIMER_VIRT_BASE + 0x0000)
+#define WDT_EN 0x0010
+#define WDT_VAL (TIMER_VIRT_BASE + 0x0024)
+
+#define WDT_MAX_DURATION (0xffffffff / ORION5X_TCLK)
+#define WDT_IN_USE 0
+#define WDT_OK_TO_CLOSE 1
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static int heartbeat = WDT_MAX_DURATION; /* (seconds) */
+static unsigned long wdt_status;
+static spinlock_t wdt_lock;
+
+static void wdt_enable(void)
+{
+ u32 reg;
+
+ spin_lock(&wdt_lock);
+
+ /* Set watchdog duration */
+ writel(ORION5X_TCLK * heartbeat, WDT_VAL);
+
+ /* Clear watchdog timer interrupt */
+ reg = readl(BRIDGE_CAUSE);
+ reg &= ~WDT_INT_REQ;
+ writel(reg, BRIDGE_CAUSE);
+
+ /* Enable watchdog timer */
+ reg = readl(TIMER_CTRL);
+ reg |= WDT_EN;
+ writel(reg, TIMER_CTRL);
+
+ /* Enable reset on watchdog */
+ reg = readl(CPU_RESET_MASK);
+ reg |= WDT_RESET;
+ writel(reg, CPU_RESET_MASK);
+
+ spin_unlock(&wdt_lock);
+}
+
+static void wdt_disable(void)
+{
+ u32 reg;
+
+ spin_lock(&wdt_lock);
+
+ /* Disable reset on watchdog */
+ reg = readl(CPU_RESET_MASK);
+ reg &= ~WDT_RESET;
+ writel(reg, CPU_RESET_MASK);
+
+ /* Disable watchdog timer */
+ reg = readl(TIMER_CTRL);
+ reg &= ~WDT_EN;
+ writel(reg, TIMER_CTRL);
+
+ spin_unlock(&wdt_lock);
+}
+
+static int orion5x_wdt_get_timeleft(int *time_left)
+{
+ spin_lock(&wdt_lock);
+ *time_left = readl(WDT_VAL) / ORION5X_TCLK;
+ spin_unlock(&wdt_lock);
+ return 0;
+}
+
+static int orion5x_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+ return -EBUSY;
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ wdt_enable();
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t orion5x_wdt_write(struct file *file, const char *data,
+ size_t len, loff_t *ppos)
+{
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ }
+ }
+ wdt_enable();
+ }
+ return len;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING,
+ .identity = "Orion5x Watchdog",
+};
+
+
+static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = -ENOTTY;
+ int time;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ wdt_enable();
+ ret = 0;
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ ret = get_user(time, (int *)arg);
+ if (ret)
+ break;
+
+ if (time <= 0 || time > WDT_MAX_DURATION) {
+ ret = -EINVAL;
+ break;
+ }
+ heartbeat = time;
+ wdt_enable();
+ /* Fall through */
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(heartbeat, (int *)arg);
+ break;
+
+ case WDIOC_GETTIMELEFT:
+ if (orion5x_wdt_get_timeleft(&time)) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = put_user(time, (int *)arg);
+ break;
+ }
+ return ret;
+}
+
+static int orion5x_wdt_release(struct inode *inode, struct file *file)
+{
+ if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+ wdt_disable();
+ else
+ printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+ "timer will not stop\n");
+ clear_bit(WDT_IN_USE, &wdt_status);
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ return 0;
+}
+
+
+static const struct file_operations orion5x_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = orion5x_wdt_write,
+ .unlocked_ioctl = orion5x_wdt_ioctl,
+ .open = orion5x_wdt_open,
+ .release = orion5x_wdt_release,
+};
+
+static struct miscdevice orion5x_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &orion5x_wdt_fops,
+};
+
+static int __init orion5x_wdt_init(void)
+{
+ int ret;
+
+ spin_lock_init(&wdt_lock);
+
+ ret = misc_register(&orion5x_wdt_miscdev);
+ if (ret == 0)
+ printk("Orion5x Watchdog Timer: heartbeat %d sec\n",
+ heartbeat);
+
+ return ret;
+}
+
+static void __exit orion5x_wdt_exit(void)
+{
+ misc_deregister(&orion5x_wdt_miscdev);
+}
+
+module_init(orion5x_wdt_init);
+module_exit(orion5x_wdt_exit);
+
+MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>");
+MODULE_DESCRIPTION("Orion5x Processor Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default is "
+ __MODULE_STRING(WDT_MAX_DURATION) ")");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c
new file mode 100644
index 0000000..09cb183
--- /dev/null
+++ b/drivers/watchdog/riowd.c
@@ -0,0 +1,259 @@
+/* riowd.c - driver for hw watchdog inside Super I/O of RIO
+ *
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/smp_lock.h>
+#include <linux/watchdog.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+
+/* RIO uses the NatSemi Super I/O power management logical device
+ * as its' watchdog.
+ *
+ * When the watchdog triggers, it asserts a line to the BBC (Boot Bus
+ * Controller) of the machine. The BBC can only be configured to
+ * trigger a power-on reset when the signal is asserted. The BBC
+ * can be configured to ignore the signal entirely as well.
+ *
+ * The only Super I/O device register we care about is at index
+ * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255).
+ * If set to zero, this disables the watchdog. When set, the system
+ * must periodically (before watchdog expires) clear (set to zero) and
+ * re-set the watchdog else it will trigger.
+ *
+ * There are two other indexed watchdog registers inside this Super I/O
+ * logical device, but they are unused. The first, at index 0x06 is
+ * the watchdog control and can be used to make the watchdog timer re-set
+ * when the PS/2 mouse or serial lines show activity. The second, at
+ * index 0x07 is merely a sampling of the line from the watchdog to the
+ * BBC.
+ *
+ * The watchdog device generates no interrupts.
+ */
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
+MODULE_SUPPORTED_DEVICE("watchdog");
+MODULE_LICENSE("GPL");
+
+#define DRIVER_NAME "riowd"
+#define PFX DRIVER_NAME ": "
+
+struct riowd {
+ void __iomem *regs;
+ spinlock_t lock;
+};
+
+static struct riowd *riowd_device;
+
+#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)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->lock, flags);
+ writeb(index, p->regs + 0);
+ writeb(val, p->regs + 1);
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static int riowd_open(struct inode *inode, struct file *filp)
+{
+ cycle_kernel_lock();
+ nonseekable_open(inode, filp);
+ return 0;
+}
+
+static int riowd_release(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+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,
+ };
+ void __user *argp = (void __user *)arg;
+ struct riowd *p = riowd_device;
+ unsigned int options;
+ int new_margin;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user(argp, &info, sizeof(info)))
+ return -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ if (put_user(0, (int __user *)argp))
+ return -EFAULT;
+ break;
+
+ case WDIOC_KEEPALIVE:
+ riowd_writereg(p, riowd_timeout, WDTO_INDEX);
+ break;
+
+ case WDIOC_SETOPTIONS:
+ if (copy_from_user(&options, argp, sizeof(options)))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD)
+ riowd_writereg(p, 0, WDTO_INDEX);
+ else if (options & WDIOS_ENABLECARD)
+ riowd_writereg(p, riowd_timeout, WDTO_INDEX);
+ else
+ return -EINVAL;
+
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_margin, (int __user *)argp))
+ return -EFAULT;
+ if ((new_margin < 60) || (new_margin > (255 * 60)))
+ return -EINVAL;
+ riowd_timeout = (new_margin + 59) / 60;
+ riowd_writereg(p, riowd_timeout, WDTO_INDEX);
+ /* Fall */
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(riowd_timeout * 60, (int __user *)argp);
+
+ default:
+ return -EINVAL;
+ };
+
+ return 0;
+}
+
+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);
+ return 1;
+ }
+
+ return 0;
+}
+
+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 int __devinit riowd_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct riowd *p;
+ int err = -EINVAL;
+
+ if (riowd_device)
+ goto out;
+
+ err = -ENOMEM;
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ goto out;
+
+ spin_lock_init(&p->lock);
+
+ 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;
+ }
+
+ err = misc_register(&riowd_miscdev);
+ if (err) {
+ printk(KERN_ERR PFX "Cannot register watchdog misc device.\n");
+ goto out_iounmap;
+ }
+
+ printk(KERN_INFO PFX "Hardware watchdog [%i minutes], "
+ "regs at %p\n", riowd_timeout, p->regs);
+
+ 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);
+
+out:
+ return err;
+}
+
+static int __devexit riowd_remove(struct of_device *op)
+{
+ struct riowd *p = dev_get_drvdata(&op->dev);
+
+ misc_deregister(&riowd_miscdev);
+ of_iounmap(&op->resource[0], p->regs, 2);
+ kfree(p);
+
+ 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);
+}
+
+static void __exit riowd_exit(void)
+{
+ of_unregister_driver(&riowd_driver);
+}
+
+module_init(riowd_init);
+module_exit(riowd_exit);
diff --git a/drivers/watchdog/w83697ug_wdt.c b/drivers/watchdog/w83697ug_wdt.c
new file mode 100644
index 0000000..c73b5e2
--- /dev/null
+++ b/drivers/watchdog/w83697ug_wdt.c
@@ -0,0 +1,392 @@
+/*
+ * w83697ug/uf WDT driver
+ *
+ * (c) Copyright 2008 Flemming Fransen <ff@nrvissing.net>
+ * reused original code to supoprt w83697ug/uf.
+ *
+ * Based on w83627hf_wdt.c which is based on advantechwdt.c
+ * which is based on wdt.c.
+ * Original copyright messages:
+ *
+ * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
+ * added support for W83627THF.
+ *
+ * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
+ *
+ * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ * http://www.redhat.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 1995 Alan Cox <alan@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <asm/system.h>
+
+#define WATCHDOG_NAME "w83697ug/uf WDT"
+#define PFX WATCHDOG_NAME ": "
+#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
+
+static unsigned long wdt_is_open;
+static char expect_close;
+static DEFINE_SPINLOCK(io_lock);
+
+static int wdt_io = 0x2e;
+module_param(wdt_io, int, 0);
+MODULE_PARM_DESC(wdt_io, "w83697ug/uf WDT io port (default 0x2e)");
+
+static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,
+ "Watchdog timeout in seconds. 1<= timeout <=255 (default="
+ __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/*
+ * Kernel methods.
+ */
+
+#define WDT_EFER (wdt_io+0) /* Extended Function Enable Registers */
+#define WDT_EFIR (wdt_io+0) /* Extended Function Index Register
+ (same as EFER) */
+#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
+
+static void w83697ug_select_wd_register(void)
+{
+ unsigned char c;
+ unsigned char version;
+
+ outb_p(0x87, WDT_EFER); /* Enter extended function mode */
+ outb_p(0x87, WDT_EFER); /* Again according to manual */
+
+ outb(0x20, WDT_EFER); /* check chip version */
+ version = inb(WDT_EFDR);
+
+ if (version == 0x68) { /* W83697UG */
+ printk(KERN_INFO PFX "Watchdog chip version 0x%02x = "
+ "W83697UG/UF found at 0x%04x\n", version, wdt_io);
+
+ outb_p(0x2b, WDT_EFER);
+ c = inb_p(WDT_EFDR); /* select WDT0 */
+ c &= ~0x04;
+ outb_p(0x2b, WDT_EFER);
+ outb_p(c, WDT_EFDR); /* set pin118 to WDT0 */
+
+ } else {
+ printk(KERN_ERR PFX "No W83697UG/UF could be found\n");
+ return -EIO;
+ }
+
+ outb_p(0x07, WDT_EFER); /* point to logical device number reg */
+ outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */
+ outb_p(0x30, WDT_EFER); /* select CR30 */
+ c = inb_p(WDT_EFDR);
+ outb_p(c || 0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
+}
+
+static void w83697ug_unselect_wd_register(void)
+{
+ outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
+}
+
+static void w83697ug_init(void)
+{
+ unsigned char t;
+
+ w83697ug_select_wd_register();
+
+ outb_p(0xF6, WDT_EFER); /* Select CRF6 */
+ t = inb_p(WDT_EFDR); /* read CRF6 */
+ if (t != 0) {
+ printk(KERN_INFO PFX "Watchdog already running."
+ " Resetting timeout to %d sec\n", timeout);
+ outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */
+ }
+ outb_p(0xF5, WDT_EFER); /* Select CRF5 */
+ t = inb_p(WDT_EFDR); /* read CRF5 */
+ t &= ~0x0C; /* set second mode &
+ disable keyboard turning off watchdog */
+ outb_p(t, WDT_EFDR); /* Write back to CRF5 */
+
+ w83697ug_unselect_wd_register();
+}
+
+static void wdt_ctrl(int timeout)
+{
+ spin_lock(&io_lock);
+
+ w83697ug_select_wd_register();
+
+ outb_p(0xF4, WDT_EFER); /* Select CRF4 */
+ outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF4 */
+
+ w83697ug_unselect_wd_register();
+
+ spin_unlock(&io_lock);
+}
+
+static int wdt_ping(void)
+{
+ wdt_ctrl(timeout);
+ return 0;
+}
+
+static int wdt_disable(void)
+{
+ wdt_ctrl(0);
+ return 0;
+}
+
+static int wdt_set_heartbeat(int t)
+{
+ if (t < 1 || t > 255)
+ return -EINVAL;
+
+ timeout = t;
+ return 0;
+}
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ if (count) {
+ if (!nowayout) {
+ size_t i;
+
+ expect_close = 0;
+
+ for (i = 0; i != count; i++) {
+ char c;
+ if (get_user(c, buf + i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_close = 42;
+ }
+ }
+ wdt_ping();
+ }
+ return count;
+}
+
+static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int new_timeout;
+ static const struct watchdog_info ident = {
+ .options = WDIOF_KEEPALIVEPING |
+ WDIOF_SETTIMEOUT |
+ WDIOF_MAGICCLOSE,
+ .firmware_version = 1,
+ .identity = "W83697UG WDT",
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user(argp, &ident, sizeof(ident)))
+ return -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+
+ case WDIOC_SETOPTIONS:
+ {
+ int options, retval = -EINVAL;
+
+ if (get_user(options, p))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD) {
+ wdt_disable();
+ retval = 0;
+ }
+
+ if (options & WDIOS_ENABLECARD) {
+ wdt_ping();
+ retval = 0;
+ }
+
+ return retval;
+ }
+
+ case WDIOC_KEEPALIVE:
+ wdt_ping();
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_timeout, p))
+ return -EFAULT;
+ if (wdt_set_heartbeat(new_timeout))
+ return -EINVAL;
+ wdt_ping();
+ /* Fall */
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(timeout, p);
+
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(0, &wdt_is_open))
+ return -EBUSY;
+ /*
+ * Activate
+ */
+
+ wdt_ping();
+ return nonseekable_open(inode, file);
+}
+
+static int wdt_close(struct inode *inode, struct file *file)
+{
+ if (expect_close == 42)
+ wdt_disable();
+ else {
+ printk(KERN_CRIT PFX
+ "Unexpected close, not stopping watchdog!\n");
+ wdt_ping();
+ }
+ expect_close = 0;
+ clear_bit(0, &wdt_is_open);
+ return 0;
+}
+
+/*
+ * Notifier for system down
+ */
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT)
+ wdt_disable(); /* Turn the WDT off */
+
+ return NOTIFY_DONE;
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+static const struct file_operations wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = wdt_write,
+ .unlocked_ioctl = wdt_ioctl,
+ .open = wdt_open,
+ .release = wdt_close,
+};
+
+static struct miscdevice wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &wdt_fops,
+};
+
+/*
+ * The WDT needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+
+static struct notifier_block wdt_notifier = {
+ .notifier_call = wdt_notify_sys,
+};
+
+static int __init wdt_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising.\n");
+
+ if (wdt_set_heartbeat(timeout)) {
+ wdt_set_heartbeat(WATCHDOG_TIMEOUT);
+ printk(KERN_INFO PFX
+ "timeout value must be 1<=timeout<=255, using %d\n",
+ WATCHDOG_TIMEOUT);
+ }
+
+ if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
+ printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+ wdt_io);
+ ret = -EIO;
+ goto out;
+ }
+
+ w83697ug_init();
+
+ ret = register_reboot_notifier(&wdt_notifier);
+ if (ret != 0) {
+ printk(KERN_ERR PFX
+ "cannot register reboot notifier (err=%d)\n", ret);
+ goto unreg_regions;
+ }
+
+ ret = misc_register(&wdt_miscdev);
+ if (ret != 0) {
+ printk(KERN_ERR PFX
+ "cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ goto unreg_reboot;
+ }
+
+ printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+ timeout, nowayout);
+
+out:
+ return ret;
+unreg_reboot:
+ unregister_reboot_notifier(&wdt_notifier);
+unreg_regions:
+ release_region(wdt_io, 1);
+ goto out;
+}
+
+static void __exit wdt_exit(void)
+{
+ misc_deregister(&wdt_miscdev);
+ unregister_reboot_notifier(&wdt_notifier);
+ release_region(wdt_io, 1);
+}
+
+module_init(wdt_init);
+module_exit(wdt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Flemming Frandsen <ff@nrvissing.net>");
+MODULE_DESCRIPTION("w83697ug/uf WDT driver");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 363286c..d2a8fdf 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -1,4 +1,5 @@
obj-y += grant-table.o features.o events.o manage.o
obj-y += xenbus/
+obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
obj-$(CONFIG_XEN_BALLOON) += balloon.o
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 2e15da54..8c83abc 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -53,7 +53,6 @@
#include <asm/tlb.h>
#include <xen/interface/memory.h>
-#include <xen/balloon.h>
#include <xen/xenbus.h>
#include <xen/features.h>
#include <xen/page.h>
@@ -226,9 +225,8 @@
}
set_xen_guest_handle(reservation.extent_start, frame_list);
- reservation.nr_extents = nr_pages;
- rc = HYPERVISOR_memory_op(
- XENMEM_populate_physmap, &reservation);
+ reservation.nr_extents = nr_pages;
+ rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
if (rc < nr_pages) {
if (rc > 0) {
int ret;
@@ -236,7 +234,7 @@
/* We hit the Xen hard limit: reprobe. */
reservation.nr_extents = rc;
ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
- &reservation);
+ &reservation);
BUG_ON(ret != rc);
}
if (rc >= 0)
@@ -420,7 +418,7 @@
unsigned long pfn;
struct page *page;
- if (!is_running_on_xen())
+ if (!xen_pv_domain())
return -ENODEV;
pr_info("xen_balloon: Initialising balloon driver.\n");
@@ -464,136 +462,13 @@
module_exit(balloon_exit);
-static void balloon_update_driver_allowance(long delta)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&balloon_lock, flags);
- balloon_stats.driver_pages += delta;
- spin_unlock_irqrestore(&balloon_lock, flags);
-}
-
-static int dealloc_pte_fn(
- pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
-{
- unsigned long mfn = pte_mfn(*pte);
- int ret;
- struct xen_memory_reservation reservation = {
- .nr_extents = 1,
- .extent_order = 0,
- .domid = DOMID_SELF
- };
- set_xen_guest_handle(reservation.extent_start, &mfn);
- set_pte_at(&init_mm, addr, pte, __pte_ma(0ull));
- set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY);
- ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
- BUG_ON(ret != 1);
- return 0;
-}
-
-static struct page **alloc_empty_pages_and_pagevec(int nr_pages)
-{
- unsigned long vaddr, flags;
- struct page *page, **pagevec;
- int i, ret;
-
- pagevec = kmalloc(sizeof(page) * nr_pages, GFP_KERNEL);
- if (pagevec == NULL)
- return NULL;
-
- for (i = 0; i < nr_pages; i++) {
- page = pagevec[i] = alloc_page(GFP_KERNEL);
- if (page == NULL)
- goto err;
-
- vaddr = (unsigned long)page_address(page);
-
- scrub_page(page);
-
- spin_lock_irqsave(&balloon_lock, flags);
-
- if (xen_feature(XENFEAT_auto_translated_physmap)) {
- unsigned long gmfn = page_to_pfn(page);
- struct xen_memory_reservation reservation = {
- .nr_extents = 1,
- .extent_order = 0,
- .domid = DOMID_SELF
- };
- set_xen_guest_handle(reservation.extent_start, &gmfn);
- ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
- &reservation);
- if (ret == 1)
- ret = 0; /* success */
- } else {
- ret = apply_to_page_range(&init_mm, vaddr, PAGE_SIZE,
- dealloc_pte_fn, NULL);
- }
-
- if (ret != 0) {
- spin_unlock_irqrestore(&balloon_lock, flags);
- __free_page(page);
- goto err;
- }
-
- totalram_pages = --balloon_stats.current_pages;
-
- spin_unlock_irqrestore(&balloon_lock, flags);
- }
-
- out:
- schedule_work(&balloon_worker);
- flush_tlb_all();
- return pagevec;
-
- err:
- spin_lock_irqsave(&balloon_lock, flags);
- while (--i >= 0)
- balloon_append(pagevec[i]);
- spin_unlock_irqrestore(&balloon_lock, flags);
- kfree(pagevec);
- pagevec = NULL;
- goto out;
-}
-
-static void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages)
-{
- unsigned long flags;
- int i;
-
- if (pagevec == NULL)
- return;
-
- spin_lock_irqsave(&balloon_lock, flags);
- for (i = 0; i < nr_pages; i++) {
- BUG_ON(page_count(pagevec[i]) != 1);
- balloon_append(pagevec[i]);
- }
- spin_unlock_irqrestore(&balloon_lock, flags);
-
- kfree(pagevec);
-
- schedule_work(&balloon_worker);
-}
-
-static void balloon_release_driver_page(struct page *page)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&balloon_lock, flags);
- balloon_append(page);
- balloon_stats.driver_pages--;
- spin_unlock_irqrestore(&balloon_lock, flags);
-
- schedule_work(&balloon_worker);
-}
-
-
-#define BALLOON_SHOW(name, format, args...) \
- static ssize_t show_##name(struct sys_device *dev, \
- char *buf) \
- { \
- return sprintf(buf, format, ##args); \
- } \
+#define BALLOON_SHOW(name, format, args...) \
+ static ssize_t show_##name(struct sys_device *dev, \
+ struct sysdev_attribute *attr, \
+ char *buf) \
+ { \
+ return sprintf(buf, format, ##args); \
+ } \
static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL)
BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
@@ -604,7 +479,8 @@
(balloon_stats.hard_limit!=~0UL) ? PAGES2KB(balloon_stats.hard_limit) : 0);
BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages));
-static ssize_t show_target_kb(struct sys_device *dev, char *buf)
+static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr,
+ char *buf)
{
return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages));
}
@@ -614,19 +490,14 @@
const char *buf,
size_t count)
{
- char memstring[64], *endchar;
+ char *endchar;
unsigned long long target_bytes;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (count <= 1)
- return -EBADMSG; /* runt */
- if (count > sizeof(memstring))
- return -EFBIG; /* too long */
- strcpy(memstring, buf);
+ target_bytes = memparse(buf, &endchar);
- target_bytes = memparse(memstring, &endchar);
balloon_set_new_target(target_bytes >> PAGE_SHIFT);
return count;
@@ -694,20 +565,4 @@
return error;
}
-static void unregister_balloon(struct sys_device *sysdev)
-{
- int i;
-
- sysfs_remove_group(&sysdev->kobj, &balloon_info_group);
- for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++)
- sysdev_remove_file(sysdev, balloon_attrs[i]);
- sysdev_unregister(sysdev);
- sysdev_class_unregister(&balloon_sysdev_class);
-}
-
-static void balloon_sysfs_exit(void)
-{
- unregister_balloon(&balloon_sysdev);
-}
-
MODULE_LICENSE("GPL");
diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c
new file mode 100644
index 0000000..565280ec
--- /dev/null
+++ b/drivers/xen/cpu_hotplug.c
@@ -0,0 +1,90 @@
+#include <linux/notifier.h>
+
+#include <xen/xenbus.h>
+
+#include <asm-x86/xen/hypervisor.h>
+#include <asm/cpu.h>
+
+static void enable_hotplug_cpu(int cpu)
+{
+ if (!cpu_present(cpu))
+ arch_register_cpu(cpu);
+
+ cpu_set(cpu, cpu_present_map);
+}
+
+static void disable_hotplug_cpu(int cpu)
+{
+ if (cpu_present(cpu))
+ arch_unregister_cpu(cpu);
+
+ cpu_clear(cpu, cpu_present_map);
+}
+
+static void vcpu_hotplug(unsigned int cpu)
+{
+ int err;
+ char dir[32], state[32];
+
+ if (!cpu_possible(cpu))
+ return;
+
+ sprintf(dir, "cpu/%u", cpu);
+ err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
+ if (err != 1) {
+ printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
+ return;
+ }
+
+ if (strcmp(state, "online") == 0) {
+ enable_hotplug_cpu(cpu);
+ } else if (strcmp(state, "offline") == 0) {
+ (void)cpu_down(cpu);
+ disable_hotplug_cpu(cpu);
+ } else {
+ printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
+ state, cpu);
+ }
+}
+
+static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ unsigned int cpu;
+ char *cpustr;
+ const char *node = vec[XS_WATCH_PATH];
+
+ cpustr = strstr(node, "cpu/");
+ if (cpustr != NULL) {
+ sscanf(cpustr, "cpu/%u", &cpu);
+ vcpu_hotplug(cpu);
+ }
+}
+
+static int setup_cpu_watcher(struct notifier_block *notifier,
+ unsigned long event, void *data)
+{
+ static struct xenbus_watch cpu_watch = {
+ .node = "cpu",
+ .callback = handle_vcpu_hotplug_event};
+
+ (void)register_xenbus_watch(&cpu_watch);
+
+ return NOTIFY_DONE;
+}
+
+static int __init setup_vcpu_hotplug_event(void)
+{
+ static struct notifier_block xsn_cpu = {
+ .notifier_call = setup_cpu_watcher };
+
+ if (!xen_pv_domain())
+ return -ENODEV;
+
+ register_xenstore_notifier(&xsn_cpu);
+
+ return 0;
+}
+
+arch_initcall(setup_vcpu_hotplug_event);
+
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 0e0c285..c3290bc 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -84,17 +84,6 @@
/* Xen will never allocate port zero for any purpose. */
#define VALID_EVTCHN(chn) ((chn) != 0)
-/*
- * Force a proper event-channel callback from Xen after clearing the
- * callback mask. We do this in a very simple manner, by making a call
- * down into Xen. The pending flag will be checked by Xen on return.
- */
-void force_evtchn_callback(void)
-{
- (void)HYPERVISOR_xen_version(0, NULL);
-}
-EXPORT_SYMBOL_GPL(force_evtchn_callback);
-
static struct irq_chip xen_dynamic_chip;
/* Constructor for packed IRQ information. */
@@ -175,6 +164,12 @@
sync_set_bit(port, &s->evtchn_pending[0]);
}
+static inline int test_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ return sync_test_bit(port, &s->evtchn_pending[0]);
+}
+
/**
* notify_remote_via_irq - send event to remote end of event channel via irq
@@ -365,6 +360,10 @@
per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
[index_from_irq(irq)] = -1;
break;
+ case IRQT_IPI:
+ per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn))
+ [index_from_irq(irq)] = -1;
+ break;
default:
break;
}
@@ -743,6 +742,25 @@
clear_evtchn(evtchn);
}
+void xen_set_irq_pending(int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ set_evtchn(evtchn);
+}
+
+bool xen_test_irq_pending(int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+ bool ret = false;
+
+ if (VALID_EVTCHN(evtchn))
+ ret = test_evtchn(evtchn);
+
+ return ret;
+}
+
/* Poll waiting for an irq to become pending. In the usual case, the
irq will be disabled so it won't deliver an interrupt. */
void xen_poll_irq(int irq)
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index e9e1116..06592b9 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -508,7 +508,7 @@
unsigned int max_nr_glist_frames, nr_glist_frames;
unsigned int nr_init_grefs;
- if (!is_running_on_xen())
+ if (!xen_domain())
return -ENODEV;
nr_grant_frames = 1;
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 57ceb53..7f24a98 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -814,7 +814,7 @@
DPRINTK("");
err = -ENODEV;
- if (!is_running_on_xen())
+ if (!xen_domain())
goto out_error;
/* Register ourselves with the kernel bus subsystem */
@@ -829,7 +829,7 @@
/*
* Domain0 doesn't have a store_evtchn or store_mfn yet.
*/
- if (is_initial_xendomain()) {
+ if (xen_initial_domain()) {
/* dom0 not yet supported */
} else {
xenstored_ready = 1;
@@ -846,7 +846,7 @@
goto out_unreg_back;
}
- if (!is_initial_xendomain())
+ if (!xen_initial_domain())
xenbus_probe(NULL);
return 0;
@@ -937,7 +937,7 @@
unsigned long timeout = jiffies + 10*HZ;
struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
- if (!ready_to_wait_for_devices || !is_running_on_xen())
+ if (!ready_to_wait_for_devices || !xen_domain())
return;
while (exists_disconnected_device(drv)) {
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 654d972..88786ba 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -311,8 +311,6 @@
buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
buffer->Pid = cpu_to_le16((__u16)current->tgid);
buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
- spin_lock(&GlobalMid_Lock);
- spin_unlock(&GlobalMid_Lock);
if (treeCon) {
buffer->Tid = treeCon->tid;
if (treeCon->ses) {
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 33a6b7e..d152856 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -226,6 +226,8 @@
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);
@@ -342,6 +344,8 @@
}
EXPORT_SYMBOL(generic_block_fiemap);
+#endif /* CONFIG_BLOCK */
+
static int file_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
diff --git a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h
index 8786e01..9695701 100644
--- a/include/asm-generic/siginfo.h
+++ b/include/asm-generic/siginfo.h
@@ -199,6 +199,8 @@
*/
#define TRAP_BRKPT (__SI_FAULT|1) /* process breakpoint */
#define TRAP_TRACE (__SI_FAULT|2) /* process trace trap */
+#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */
+#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint/watchpoint */
#define NSIGTRAP 2
/*
diff --git a/include/asm-parisc/siginfo.h b/include/asm-parisc/siginfo.h
index d4909f5..d703472 100644
--- a/include/asm-parisc/siginfo.h
+++ b/include/asm-parisc/siginfo.h
@@ -3,11 +3,6 @@
#include <asm-generic/siginfo.h>
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */
-#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */
#undef NSIGTRAP
#define NSIGTRAP 4
diff --git a/include/asm-x86/bios_ebda.h b/include/asm-x86/bios_ebda.h
index ec42ed8..79b4b88 100644
--- a/include/asm-x86/bios_ebda.h
+++ b/include/asm-x86/bios_ebda.h
@@ -16,4 +16,21 @@
void reserve_ebda_region(void);
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+/*
+ * This is obviously not a great place for this, but we want to be
+ * able to scatter it around anywhere in the kernel.
+ */
+void check_for_bios_corruption(void);
+void start_periodic_check_for_corruption(void);
+#else
+static inline void check_for_bios_corruption(void)
+{
+}
+
+static inline void start_periodic_check_for_corruption(void)
+{
+}
+#endif
+
#endif /* ASM_X86__BIOS_EBDA_H */
diff --git a/include/asm-x86/boot.h b/include/asm-x86/boot.h
index 825de5d..1d63bd5 100644
--- a/include/asm-x86/boot.h
+++ b/include/asm-x86/boot.h
@@ -2,9 +2,7 @@
#define ASM_X86__BOOT_H
/* Don't touch these, unless you really know what you're doing. */
-#define DEF_INITSEG 0x9000
#define DEF_SYSSEG 0x1000
-#define DEF_SETUPSEG 0x9020
#define DEF_SYSSIZE 0x7F00
/* Internal svga startup constants */
diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h
index b73fea5..ebc3078 100644
--- a/include/asm-x86/desc.h
+++ b/include/asm-x86/desc.h
@@ -24,6 +24,11 @@
desc->d = info->seg_32bit;
desc->g = info->limit_in_pages;
desc->base2 = (info->base_addr & 0xff000000) >> 24;
+ /*
+ * Don't allow setting of the lm bit. It is useless anyway
+ * because 64bit system calls require __USER_CS:
+ */
+ desc->l = 0;
}
extern struct desc_ptr idt_descr;
@@ -97,7 +102,15 @@
native_write_gdt_entry(dt, entry, desc, type)
#define write_idt_entry(dt, entry, g) \
native_write_idt_entry(dt, entry, g)
-#endif
+
+static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries)
+{
+}
+
+static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries)
+{
+}
+#endif /* CONFIG_PARAVIRT */
static inline void native_write_idt_entry(gate_desc *idt, int entry,
const gate_desc *gate)
diff --git a/include/asm-x86/microcode.h b/include/asm-x86/microcode.h
new file mode 100644
index 0000000..62c793b
--- /dev/null
+++ b/include/asm-x86/microcode.h
@@ -0,0 +1,47 @@
+#ifndef ASM_X86__MICROCODE_H
+#define ASM_X86__MICROCODE_H
+
+struct cpu_signature {
+ unsigned int sig;
+ unsigned int pf;
+ unsigned int rev;
+};
+
+struct device;
+
+struct microcode_ops {
+ int (*request_microcode_user) (int cpu, const void __user *buf, size_t size);
+ int (*request_microcode_fw) (int cpu, struct device *device);
+
+ void (*apply_microcode) (int cpu);
+
+ int (*collect_cpu_info) (int cpu, struct cpu_signature *csig);
+ void (*microcode_fini_cpu) (int cpu);
+};
+
+struct ucode_cpu_info {
+ struct cpu_signature cpu_sig;
+ int valid;
+ void *mc;
+};
+extern struct ucode_cpu_info ucode_cpu_info[];
+
+#ifdef CONFIG_MICROCODE_INTEL
+extern struct microcode_ops * __init init_intel_microcode(void);
+#else
+static inline struct microcode_ops * __init init_intel_microcode(void)
+{
+ return NULL;
+}
+#endif /* CONFIG_MICROCODE_INTEL */
+
+#ifdef CONFIG_MICROCODE_AMD
+extern struct microcode_ops * __init init_amd_microcode(void);
+#else
+static inline struct microcode_ops * __init init_amd_microcode(void)
+{
+ return NULL;
+}
+#endif
+
+#endif /* ASM_X86__MICROCODE_H */
diff --git a/include/asm-x86/mmzone_64.h b/include/asm-x86/mmzone_64.h
index 626b03a..6480f33 100644
--- a/include/asm-x86/mmzone_64.h
+++ b/include/asm-x86/mmzone_64.h
@@ -7,7 +7,7 @@
#ifdef CONFIG_NUMA
-#define VIRTUAL_BUG_ON(x)
+#include <linux/mmdebug.h>
#include <asm/smp.h>
@@ -29,7 +29,6 @@
{
unsigned nid;
VIRTUAL_BUG_ON(!memnodemap);
- VIRTUAL_BUG_ON((addr >> memnode_shift) >= memnodemapsize);
nid = memnodemap[addr >> memnode_shift];
VIRTUAL_BUG_ON(nid >= MAX_NUMNODES || !node_data[nid]);
return nid;
diff --git a/include/asm-x86/page_32.h b/include/asm-x86/page_32.h
index 72f7305..9c5a737 100644
--- a/include/asm-x86/page_32.h
+++ b/include/asm-x86/page_32.h
@@ -73,7 +73,12 @@
#endif
#ifndef __ASSEMBLY__
+#define __phys_addr_const(x) ((x) - PAGE_OFFSET)
+#ifdef CONFIG_DEBUG_VIRTUAL
+extern unsigned long __phys_addr(unsigned long);
+#else
#define __phys_addr(x) ((x) - PAGE_OFFSET)
+#endif
#define __phys_reloc_hide(x) RELOC_HIDE((x), 0)
#ifdef CONFIG_FLATMEM
diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h
index d7d358a..8d6ae2f 100644
--- a/include/asm-x86/paravirt.h
+++ b/include/asm-x86/paravirt.h
@@ -124,6 +124,9 @@
int entrynum, const void *desc, int size);
void (*write_idt_entry)(gate_desc *,
int entrynum, const gate_desc *gate);
+ void (*alloc_ldt)(struct desc_struct *ldt, unsigned entries);
+ void (*free_ldt)(struct desc_struct *ldt, unsigned entries);
+
void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t);
void (*set_iopl_mask)(unsigned mask);
@@ -325,6 +328,7 @@
int (*spin_is_locked)(struct raw_spinlock *lock);
int (*spin_is_contended)(struct raw_spinlock *lock);
void (*spin_lock)(struct raw_spinlock *lock);
+ void (*spin_lock_flags)(struct raw_spinlock *lock, unsigned long flags);
int (*spin_trylock)(struct raw_spinlock *lock);
void (*spin_unlock)(struct raw_spinlock *lock);
};
@@ -830,6 +834,16 @@
(aux) = __aux; \
} while (0)
+static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries)
+{
+ PVOP_VCALL2(pv_cpu_ops.alloc_ldt, ldt, entries);
+}
+
+static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries)
+{
+ PVOP_VCALL2(pv_cpu_ops.free_ldt, ldt, entries);
+}
+
static inline void load_TR_desc(void)
{
PVOP_VCALL0(pv_cpu_ops.load_tr_desc);
@@ -1394,6 +1408,12 @@
PVOP_VCALL1(pv_lock_ops.spin_lock, lock);
}
+static __always_inline void __raw_spin_lock_flags(struct raw_spinlock *lock,
+ unsigned long flags)
+{
+ PVOP_VCALL2(pv_lock_ops.spin_lock_flags, lock, flags);
+}
+
static __always_inline int __raw_spin_trylock(struct raw_spinlock *lock)
{
return PVOP_CALL1(int, pv_lock_ops.spin_trylock, lock);
diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h
index c7d3546..ee7cbb3 100644
--- a/include/asm-x86/processor.h
+++ b/include/asm-x86/processor.h
@@ -586,41 +586,6 @@
write_cr4(cr4);
}
-struct microcode_header {
- unsigned int hdrver;
- unsigned int rev;
- unsigned int date;
- unsigned int sig;
- unsigned int cksum;
- unsigned int ldrver;
- unsigned int pf;
- unsigned int datasize;
- unsigned int totalsize;
- unsigned int reserved[3];
-};
-
-struct microcode {
- struct microcode_header hdr;
- unsigned int bits[0];
-};
-
-typedef struct microcode microcode_t;
-typedef struct microcode_header microcode_header_t;
-
-/* microcode format is extended from prescott processors */
-struct extended_signature {
- unsigned int sig;
- unsigned int pf;
- unsigned int cksum;
-};
-
-struct extended_sigtable {
- unsigned int count;
- unsigned int cksum;
- unsigned int reserved[3];
- struct extended_signature sigs[0];
-};
-
typedef struct {
unsigned long seg;
} mm_segment_t;
diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h
index d64a610..ac578f1 100644
--- a/include/asm-x86/ptrace.h
+++ b/include/asm-x86/ptrace.h
@@ -177,11 +177,11 @@
#ifdef CONFIG_X86_32
extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
- int error_code);
-#else
-void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
+ int error_code, int si_code);
#endif
+void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
+
extern long syscall_trace_enter(struct pt_regs *);
extern void syscall_trace_leave(struct pt_regs *);
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index 29324c1..6df2615 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -50,12 +50,16 @@
struct smp_ops {
void (*smp_prepare_boot_cpu)(void);
void (*smp_prepare_cpus)(unsigned max_cpus);
- int (*cpu_up)(unsigned cpu);
void (*smp_cpus_done)(unsigned max_cpus);
void (*smp_send_stop)(void);
void (*smp_send_reschedule)(int cpu);
+ int (*cpu_up)(unsigned cpu);
+ int (*cpu_disable)(void);
+ void (*cpu_die)(unsigned int cpu);
+ void (*play_dead)(void);
+
void (*send_call_func_ipi)(cpumask_t mask);
void (*send_call_func_single_ipi)(int cpu);
};
@@ -94,6 +98,21 @@
return smp_ops.cpu_up(cpu);
}
+static inline int __cpu_disable(void)
+{
+ return smp_ops.cpu_disable();
+}
+
+static inline void __cpu_die(unsigned int cpu)
+{
+ smp_ops.cpu_die(cpu);
+}
+
+static inline void play_dead(void)
+{
+ smp_ops.play_dead();
+}
+
static inline void smp_send_reschedule(int cpu)
{
smp_ops.smp_send_reschedule(cpu);
@@ -109,16 +128,19 @@
smp_ops.send_call_func_ipi(mask);
}
+void cpu_disable_common(void);
void native_smp_prepare_boot_cpu(void);
void native_smp_prepare_cpus(unsigned int max_cpus);
void native_smp_cpus_done(unsigned int max_cpus);
int native_cpu_up(unsigned int cpunum);
+int native_cpu_disable(void);
+void native_cpu_die(unsigned int cpu);
+void native_play_dead(void);
+void play_dead_common(void);
+
void native_send_call_func_ipi(cpumask_t mask);
void native_send_call_func_single_ipi(int cpu);
-extern int __cpu_disable(void);
-extern void __cpu_die(unsigned int cpu);
-
void smp_store_cpu_info(int id);
#define cpu_physical_id(cpu) per_cpu(x86_cpu_to_apicid, cpu)
@@ -205,9 +227,5 @@
#endif /* CONFIG_X86_LOCAL_APIC */
-#ifdef CONFIG_HOTPLUG_CPU
-extern void cpu_uninit(void);
-#endif
-
#endif /* __ASSEMBLY__ */
#endif /* ASM_X86__SMP_H */
diff --git a/include/asm-x86/spinlock.h b/include/asm-x86/spinlock.h
index 93adae3..157ff7f 100644
--- a/include/asm-x86/spinlock.h
+++ b/include/asm-x86/spinlock.h
@@ -21,8 +21,10 @@
#ifdef CONFIG_X86_32
# define LOCK_PTR_REG "a"
+# define REG_PTR_MODE "k"
#else
# define LOCK_PTR_REG "D"
+# define REG_PTR_MODE "q"
#endif
#if defined(CONFIG_X86_32) && \
@@ -54,19 +56,7 @@
* much between them in performance though, especially as locks are out of line.
*/
#if (NR_CPUS < 256)
-static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
-{
- int tmp = ACCESS_ONCE(lock->slock);
-
- return (((tmp >> 8) & 0xff) != (tmp & 0xff));
-}
-
-static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
-{
- int tmp = ACCESS_ONCE(lock->slock);
-
- return (((tmp >> 8) - tmp) & 0xff) > 1;
-}
+#define TICKET_SHIFT 8
static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
{
@@ -89,19 +79,17 @@
static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock)
{
- int tmp;
- short new;
+ int tmp, new;
- asm volatile("movw %2,%w0\n\t"
+ asm volatile("movzwl %2, %0\n\t"
"cmpb %h0,%b0\n\t"
+ "leal 0x100(%" REG_PTR_MODE "0), %1\n\t"
"jne 1f\n\t"
- "movw %w0,%w1\n\t"
- "incb %h1\n\t"
LOCK_PREFIX "cmpxchgw %w1,%2\n\t"
"1:"
"sete %b1\n\t"
"movzbl %b1,%0\n\t"
- : "=&a" (tmp), "=Q" (new), "+m" (lock->slock)
+ : "=&a" (tmp), "=&q" (new), "+m" (lock->slock)
:
: "memory", "cc");
@@ -116,19 +104,7 @@
: "memory", "cc");
}
#else
-static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
-{
- int tmp = ACCESS_ONCE(lock->slock);
-
- return (((tmp >> 16) & 0xffff) != (tmp & 0xffff));
-}
-
-static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
-{
- int tmp = ACCESS_ONCE(lock->slock);
-
- return (((tmp >> 16) - tmp) & 0xffff) > 1;
-}
+#define TICKET_SHIFT 16
static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
{
@@ -146,7 +122,7 @@
/* don't need lfence here, because loads are in-order */
"jmp 1b\n"
"2:"
- : "+Q" (inc), "+m" (lock->slock), "=r" (tmp)
+ : "+r" (inc), "+m" (lock->slock), "=&r" (tmp)
:
: "memory", "cc");
}
@@ -160,13 +136,13 @@
"movl %0,%1\n\t"
"roll $16, %0\n\t"
"cmpl %0,%1\n\t"
+ "leal 0x00010000(%" REG_PTR_MODE "0), %1\n\t"
"jne 1f\n\t"
- "addl $0x00010000, %1\n\t"
LOCK_PREFIX "cmpxchgl %1,%2\n\t"
"1:"
"sete %b1\n\t"
"movzbl %b1,%0\n\t"
- : "=&a" (tmp), "=r" (new), "+m" (lock->slock)
+ : "=&a" (tmp), "=&q" (new), "+m" (lock->slock)
:
: "memory", "cc");
@@ -182,7 +158,19 @@
}
#endif
-#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
+{
+ int tmp = ACCESS_ONCE(lock->slock);
+
+ return !!(((tmp >> TICKET_SHIFT) ^ tmp) & ((1 << TICKET_SHIFT) - 1));
+}
+
+static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
+{
+ int tmp = ACCESS_ONCE(lock->slock);
+
+ return (((tmp >> TICKET_SHIFT) - tmp) & ((1 << TICKET_SHIFT) - 1)) > 1;
+}
#ifdef CONFIG_PARAVIRT
/*
@@ -272,6 +260,13 @@
{
__ticket_spin_unlock(lock);
}
+
+static __always_inline void __raw_spin_lock_flags(raw_spinlock_t *lock,
+ unsigned long flags)
+{
+ __raw_spin_lock(lock);
+}
+
#endif /* CONFIG_PARAVIRT */
static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock)
diff --git a/include/asm-x86/tlbflush.h b/include/asm-x86/tlbflush.h
index ef68b76..3cdd08b 100644
--- a/include/asm-x86/tlbflush.h
+++ b/include/asm-x86/tlbflush.h
@@ -119,6 +119,10 @@
{
}
+static inline void reset_lazy_tlbstate(void)
+{
+}
+
#else /* SMP */
#include <asm/smp.h>
@@ -151,6 +155,12 @@
char __cacheline_padding[L1_CACHE_BYTES-8];
};
DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate);
+
+void reset_lazy_tlbstate(void);
+#else
+static inline void reset_lazy_tlbstate(void)
+{
+}
#endif
#endif /* SMP */
diff --git a/include/asm-x86/traps.h b/include/asm-x86/traps.h
index 2ccebc6..7a692ba 100644
--- a/include/asm-x86/traps.h
+++ b/include/asm-x86/traps.h
@@ -1,6 +1,8 @@
#ifndef ASM_X86__TRAPS_H
#define ASM_X86__TRAPS_H
+#include <asm/debugreg.h>
+
/* Common in X86_32 and X86_64 */
asmlinkage void divide_error(void);
asmlinkage void debug(void);
@@ -36,6 +38,16 @@
void do_general_protection(struct pt_regs *, long);
void do_nmi(struct pt_regs *, long);
+static inline int get_si_code(unsigned long condition)
+{
+ if (condition & DR_STEP)
+ return TRAP_TRACE;
+ else if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3))
+ return TRAP_HWBKPT;
+ else
+ return TRAP_BRKPT;
+}
+
extern int panic_on_unrecovered_nmi;
extern int kstack_depth_to_print;
diff --git a/include/asm-x86/xen/hypervisor.h b/include/asm-x86/xen/hypervisor.h
index 0ef3a88..445a247 100644
--- a/include/asm-x86/xen/hypervisor.h
+++ b/include/asm-x86/xen/hypervisor.h
@@ -54,7 +54,6 @@
/* arch/i386/kernel/setup.c */
extern struct shared_info *HYPERVISOR_shared_info;
extern struct start_info *xen_start_info;
-#define is_initial_xendomain() (xen_start_info->flags & SIF_INITDOMAIN)
/* arch/i386/mach-xen/evtchn.c */
/* Force a proper event-channel callback from Xen. */
@@ -67,6 +66,17 @@
#define MULTI_UVMFLAGS_INDEX 3
#define MULTI_UVMDOMID_INDEX 4
-#define is_running_on_xen() (xen_start_info ? 1 : 0)
+enum xen_domain_type {
+ XEN_NATIVE,
+ XEN_PV_DOMAIN,
+ XEN_HVM_DOMAIN,
+};
+
+extern enum xen_domain_type xen_domain_type;
+
+#define xen_domain() (xen_domain_type != XEN_NATIVE)
+#define xen_pv_domain() (xen_domain_type == XEN_PV_DOMAIN)
+#define xen_initial_domain() (xen_pv_domain() && xen_start_info->flags & SIF_INITDOMAIN)
+#define xen_hvm_domain() (xen_domain_type == XEN_HVM_DOMAIN)
#endif /* ASM_X86__XEN__HYPERVISOR_H */
diff --git a/include/linux/elf.h b/include/linux/elf.h
index edc3dac..0b61ca4 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -360,6 +360,7 @@
#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
+#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
/* Note header in a PT_NOTE section */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 2651f80..75d81f1 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -182,7 +182,7 @@
extern int get_option(char **str, int *pint);
extern char *get_options(const char *str, int nints, int *ints);
-extern unsigned long long memparse(char *ptr, char **retptr);
+extern unsigned long long memparse(const char *ptr, char **retptr);
extern int core_kernel_text(unsigned long addr);
extern int __kernel_text_address(unsigned long addr);
diff --git a/include/linux/key.h b/include/linux/key.h
index c45c962..1b70e35 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -299,6 +299,7 @@
#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/include/linux/mm.h b/include/linux/mm.h
index 72a15dc..c61ba10 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -7,6 +7,7 @@
#include <linux/gfp.h>
#include <linux/list.h>
+#include <linux/mmdebug.h>
#include <linux/mmzone.h>
#include <linux/rbtree.h>
#include <linux/prio_tree.h>
@@ -219,12 +220,6 @@
*/
#include <linux/page-flags.h>
-#ifdef CONFIG_DEBUG_VM
-#define VM_BUG_ON(cond) BUG_ON(cond)
-#else
-#define VM_BUG_ON(condition) do { } while(0)
-#endif
-
/*
* Methods to modify the page usage count.
*
@@ -919,7 +914,7 @@
}
#endif /* CONFIG_MMU && !__ARCH_HAS_4LEVEL_HACK */
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
/*
* We tuck a spinlock to guard each pagetable page into its struct page,
* at page->private, with BUILD_BUG_ON to make sure that this will not
@@ -932,14 +927,14 @@
} while (0)
#define pte_lock_deinit(page) ((page)->mapping = NULL)
#define pte_lockptr(mm, pmd) ({(void)(mm); __pte_lockptr(pmd_page(*(pmd)));})
-#else
+#else /* !USE_SPLIT_PTLOCKS */
/*
* We use mm->page_table_lock to guard all pagetable pages of the mm.
*/
#define pte_lock_init(page) do {} while (0)
#define pte_lock_deinit(page) do {} while (0)
#define pte_lockptr(mm, pmd) ({(void)(pmd); &(mm)->page_table_lock;})
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* USE_SPLIT_PTLOCKS */
static inline void pgtable_page_ctor(struct page *page)
{
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index bf33413..9d49fa3 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -21,11 +21,13 @@
struct address_space;
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#define USE_SPLIT_PTLOCKS (NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS)
+
+#if USE_SPLIT_PTLOCKS
typedef atomic_long_t mm_counter_t;
-#else /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#else /* !USE_SPLIT_PTLOCKS */
typedef unsigned long mm_counter_t;
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* !USE_SPLIT_PTLOCKS */
/*
* Each physical page in the system has a struct page associated with
@@ -65,7 +67,7 @@
* see PAGE_MAPPING_ANON below.
*/
};
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
spinlock_t ptl;
#endif
struct kmem_cache *slab; /* SLUB: Pointer to slab */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 9c288c9..bde891f 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -65,7 +65,7 @@
* -ENOSYS when not supported (equal to NULL callback)
* or a negative errno value when something bad happened
*
- * Return values for the get_ro callback should be:
+ * Return values for the get_cd callback should be:
* 0 for a absent card
* 1 for a present card
* -ENOSYS when not supported (equal to NULL callback)
diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
new file mode 100644
index 0000000..8a55098
--- /dev/null
+++ b/include/linux/mmdebug.h
@@ -0,0 +1,18 @@
+#ifndef LINUX_MM_DEBUG_H
+#define LINUX_MM_DEBUG_H 1
+
+#include <linux/autoconf.h>
+
+#ifdef CONFIG_DEBUG_VM
+#define VM_BUG_ON(cond) BUG_ON(cond)
+#else
+#define VM_BUG_ON(cond) do { } while (0)
+#endif
+
+#ifdef CONFIG_DEBUG_VIRTUAL
+#define VIRTUAL_BUG_ON(cond) BUG_ON(cond)
+#else
+#define VIRTUAL_BUG_ON(cond) do { } while (0)
+#endif
+
+#endif
diff --git a/include/linux/rtc/m48t59.h b/include/linux/rtc/m48t59.h
index e8c7c21..6fc9614 100644
--- a/include/linux/rtc/m48t59.h
+++ b/include/linux/rtc/m48t59.h
@@ -18,40 +18,47 @@
/*
* M48T59 Register Offset
*/
-#define M48T59_YEAR 0x1fff
-#define M48T59_MONTH 0x1ffe
-#define M48T59_MDAY 0x1ffd /* Day of Month */
-#define M48T59_WDAY 0x1ffc /* Day of Week */
+#define M48T59_YEAR 0xf
+#define M48T59_MONTH 0xe
+#define M48T59_MDAY 0xd /* Day of Month */
+#define M48T59_WDAY 0xc /* Day of Week */
#define M48T59_WDAY_CB 0x20 /* Century Bit */
#define M48T59_WDAY_CEB 0x10 /* Century Enable Bit */
-#define M48T59_HOUR 0x1ffb
-#define M48T59_MIN 0x1ffa
-#define M48T59_SEC 0x1ff9
-#define M48T59_CNTL 0x1ff8
+#define M48T59_HOUR 0xb
+#define M48T59_MIN 0xa
+#define M48T59_SEC 0x9
+#define M48T59_CNTL 0x8
#define M48T59_CNTL_READ 0x40
#define M48T59_CNTL_WRITE 0x80
-#define M48T59_WATCHDOG 0x1ff7
-#define M48T59_INTR 0x1ff6
+#define M48T59_WATCHDOG 0x7
+#define M48T59_INTR 0x6
#define M48T59_INTR_AFE 0x80 /* Alarm Interrupt Enable */
#define M48T59_INTR_ABE 0x20
-#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_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_FLAGS_WDT 0x80 /* watchdog timer expired */
#define M48T59_FLAGS_AF 0x40 /* alarm */
#define M48T59_FLAGS_BF 0x10 /* low battery */
-#define M48T59_NVRAM_SIZE 0x1ff0
+#define M48T59RTC_TYPE_M48T59 0 /* to keep compatibility */
+#define M48T59RTC_TYPE_M48T02 1
+#define M48T59RTC_TYPE_M48T08 2
struct m48t59_plat_data {
- /* The method to access M48T59 registers,
- * NOTE: The 'ofs' should be 0x00~0x1fff
- */
+ /* The method to access M48T59 registers */
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/include/linux/sched.h b/include/linux/sched.h
index 5d0819e..c226c7b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -352,7 +352,7 @@
extern void arch_unmap_area(struct mm_struct *, unsigned long);
extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
/*
* The mm counters are not protected by its page_table_lock,
* so must be incremented atomically.
@@ -363,7 +363,7 @@
#define inc_mm_counter(mm, member) atomic_long_inc(&(mm)->_##member)
#define dec_mm_counter(mm, member) atomic_long_dec(&(mm)->_##member)
-#else /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#else /* !USE_SPLIT_PTLOCKS */
/*
* The mm counters are protected by its page_table_lock,
* so can be incremented directly.
@@ -374,7 +374,7 @@
#define inc_mm_counter(mm, member) (mm)->_##member++
#define dec_mm_counter(mm, member) (mm)->_##member--
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* !USE_SPLIT_PTLOCKS */
#define get_mm_rss(mm) \
(get_mm_counter(mm, file_rss) + get_mm_counter(mm, anon_rss))
diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h
new file mode 100644
index 0000000..5b88e36
--- /dev/null
+++ b/include/linux/usb/ehci_def.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2001-2002 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_USB_EHCI_DEF_H
+#define __LINUX_USB_EHCI_DEF_H
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct ehci_caps {
+ /* these fields are specified as 8 and 16 bit registers,
+ * but some hosts can't perform 8 or 16 bit PCI accesses.
+ */
+ u32 hc_capbase;
+#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
+#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
+ u32 hcs_params; /* HCSPARAMS - offset 0x4 */
+#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */
+#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
+#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
+#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
+#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
+#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
+#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
+
+ u32 hcc_params; /* HCCPARAMS - offset 0x8 */
+#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */
+#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
+#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
+#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */
+ u8 portroute [8]; /* nibbles for routing - offset 0xC */
+} __attribute__ ((packed));
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct ehci_regs {
+
+ /* USBCMD: offset 0x00 */
+ u32 command;
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK (1<<11) /* enable "park" on async qh */
+#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
+#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
+#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
+#define CMD_ASE (1<<5) /* async schedule enable */
+#define CMD_PSE (1<<4) /* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET (1<<1) /* reset HC not bus */
+#define CMD_RUN (1<<0) /* start/stop HC */
+
+ /* USBSTS: offset 0x04 */
+ u32 status;
+#define STS_ASS (1<<15) /* Async Schedule Status */
+#define STS_PSS (1<<14) /* Periodic Schedule Status */
+#define STS_RECL (1<<13) /* Reclamation */
+#define STS_HALT (1<<12) /* Not running (any reason) */
+/* some bits reserved */
+ /* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA (1<<5) /* Interrupted on async advance */
+#define STS_FATAL (1<<4) /* such as some PCI access errors */
+#define STS_FLR (1<<3) /* frame list rolled over */
+#define STS_PCD (1<<2) /* port change detect */
+#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
+#define STS_INT (1<<0) /* "normal" completion (short, ...) */
+
+ /* USBINTR: offset 0x08 */
+ u32 intr_enable;
+
+ /* FRINDEX: offset 0x0C */
+ u32 frame_index; /* current microframe number */
+ /* CTRLDSSEGMENT: offset 0x10 */
+ u32 segment; /* address bits 63:32 if needed */
+ /* PERIODICLISTBASE: offset 0x14 */
+ u32 frame_list; /* points to periodic list */
+ /* ASYNCLISTADDR: offset 0x18 */
+ u32 async_next; /* address of next async queue head */
+
+ u32 reserved [9];
+
+ /* CONFIGFLAG: offset 0x40 */
+ u32 configured_flag;
+#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
+
+ /* PORTSC: offset 0x44 */
+ u32 port_status [0]; /* up to N_PORTS */
+/* 31:23 reserved */
+#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
+#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
+#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */
+/* 19:16 for port testing */
+#define PORT_LED_OFF (0<<14)
+#define PORT_LED_AMBER (1<<14)
+#define PORT_LED_GREEN (2<<14)
+#define PORT_LED_MASK (3<<14)
+#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
+#define PORT_POWER (1<<12) /* true: has power (see PPC) */
+#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */
+/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+/* 9 reserved */
+#define PORT_RESET (1<<8) /* reset port */
+#define PORT_SUSPEND (1<<7) /* suspend port */
+#define PORT_RESUME (1<<6) /* resume it */
+#define PORT_OCC (1<<5) /* over current change */
+#define PORT_OC (1<<4) /* over current active */
+#define PORT_PEC (1<<3) /* port enable change */
+#define PORT_PE (1<<2) /* port enable */
+#define PORT_CSC (1<<1) /* connect status change */
+#define PORT_CONNECT (1<<0) /* device connected */
+#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
+} __attribute__ ((packed));
+
+#define USBMODE 0x68 /* USB Device mode */
+#define USBMODE_SDIS (1<<3) /* Stream disable */
+#define USBMODE_BE (1<<2) /* BE/LE endianness select */
+#define USBMODE_CM_HC (3<<0) /* host controller mode */
+#define USBMODE_CM_IDLE (0<<0) /* idle state */
+
+/* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console. (nonstandard enumeration.)
+ */
+struct ehci_dbg_port {
+ u32 control;
+#define DBGP_OWNER (1<<30)
+#define DBGP_ENABLED (1<<28)
+#define DBGP_DONE (1<<16)
+#define DBGP_INUSE (1<<10)
+#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
+# define DBGP_ERR_BAD 1
+# define DBGP_ERR_SIGNAL 2
+#define DBGP_ERROR (1<<6)
+#define DBGP_GO (1<<5)
+#define DBGP_OUT (1<<4)
+#define DBGP_LEN(x) (((x)>>0)&0x0f)
+ u32 pids;
+#define DBGP_PID_GET(x) (((x)>>16)&0xff)
+#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok))
+ u32 data03;
+ u32 data47;
+ u32 address;
+#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep))
+} __attribute__ ((packed));
+
+#endif /* __LINUX_USB_EHCI_DEF_H */
diff --git a/include/sound/core.h b/include/sound/core.h
index e5eec5f..35424a9 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -43,9 +43,6 @@
#ifdef CONFIG_PCI
struct pci_dev;
#endif
-#ifdef CONFIG_SBUS
-struct sbus_dev;
-#endif
/* device allocation stuff */
diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h
index d787a6b..7ccce94 100644
--- a/include/sound/memalloc.h
+++ b/include/sound/memalloc.h
@@ -37,7 +37,6 @@
#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
@@ -49,7 +48,6 @@
#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/include/xen/balloon.h b/include/xen/balloon.h
deleted file mode 100644
index fe43b0f..0000000
--- a/include/xen/balloon.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/******************************************************************************
- * balloon.h
- *
- * Xen balloon driver - enables returning/claiming memory to/from Xen.
- *
- * Copyright (c) 2003, B Dragovic
- * Copyright (c) 2003-2004, M Williamson, K Fraser
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation; or, when distributed
- * separately from the Linux kernel or incorporated into other
- * software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef __XEN_BALLOON_H__
-#define __XEN_BALLOON_H__
-
-#include <linux/spinlock.h>
-
-#if 0
-/*
- * Inform the balloon driver that it should allow some slop for device-driver
- * memory activities.
- */
-void balloon_update_driver_allowance(long delta);
-
-/* Allocate/free a set of empty pages in low memory (i.e., no RAM mapped). */
-struct page **alloc_empty_pages_and_pagevec(int nr_pages);
-void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages);
-
-void balloon_release_driver_page(struct page *page);
-
-/*
- * Prevent the balloon driver from changing the memory reservation during
- * a driver critical region.
- */
-extern spinlock_t balloon_lock;
-#define balloon_lock(__flags) spin_lock_irqsave(&balloon_lock, __flags)
-#define balloon_unlock(__flags) spin_unlock_irqrestore(&balloon_lock, __flags)
-#endif
-
-#endif /* __XEN_BALLOON_H__ */
diff --git a/include/xen/events.h b/include/xen/events.h
index 4680ff3..0d5f1ad 100644
--- a/include/xen/events.h
+++ b/include/xen/events.h
@@ -46,6 +46,8 @@
/* Clear an irq's pending state, in preparation for polling on it */
void xen_clear_irq_pending(int irq);
+void xen_set_irq_pending(int irq);
+bool xen_test_irq_pending(int irq);
/* Poll waiting for an irq to become pending. In the usual case, the
irq will be disabled so it won't deliver an interrupt. */
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 50ec088..1bf369b 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -118,10 +118,8 @@
extern int sg_big_buff;
#endif
-#ifdef __sparc__
-extern char reboot_command [];
-extern int stop_a_enabled;
-extern int scons_pwroff;
+#ifdef CONFIG_SPARC
+#include <asm/system.h>
#endif
#ifdef __hppa__
@@ -415,7 +413,7 @@
.mode = 0644,
.proc_handler = &proc_dointvec,
},
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
{
.ctl_name = KERN_SPARC_REBOOT,
.procname = "reboot-cmd",
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index ce697e0..aa81d28 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -495,6 +495,15 @@
If unsure, say N.
+config DEBUG_VIRTUAL
+ bool "Debug VM translations"
+ depends on DEBUG_KERNEL && X86
+ help
+ Enable some costly sanity checks in virtual to page code. This can
+ catch mistakes with virt_to_page() and friends.
+
+ If unsure, say N.
+
config DEBUG_WRITECOUNT
bool "Debug filesystem writers count"
depends on DEBUG_KERNEL
diff --git a/lib/cmdline.c b/lib/cmdline.c
index 5ba8a94..f5f3ad8 100644
--- a/lib/cmdline.c
+++ b/lib/cmdline.c
@@ -126,7 +126,7 @@
* megabyte, or one gigabyte, respectively.
*/
-unsigned long long memparse(char *ptr, char **retptr)
+unsigned long long memparse(const char *ptr, char **retptr)
{
char *endptr; /* local pointer to end of parsed string */
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 85b9a0d..bba06c4 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -180,6 +180,13 @@
pmd_t *pmd;
pte_t *ptep, pte;
+ /*
+ * XXX we might need to change this if we add VIRTUAL_BUG_ON for
+ * architectures that do not vmalloc module space
+ */
+ VIRTUAL_BUG_ON(!is_vmalloc_addr(vmalloc_addr) &&
+ !is_module_address(addr));
+
if (!pgd_none(*pgd)) {
pud = pud_offset(pgd, addr);
if (!pud_none(*pud)) {
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 05ebce2..85c487b 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1345,7 +1345,7 @@
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/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig
index de6004d..05048e4 100644
--- a/net/netfilter/ipvs/Kconfig
+++ b/net/netfilter/ipvs/Kconfig
@@ -2,8 +2,8 @@
# IP Virtual Server configuration
#
menuconfig IP_VS
- tristate "IP virtual server support (EXPERIMENTAL)"
- depends on NETFILTER
+ tristate "IP virtual server support"
+ depends on NET && INET && 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/scripts/Kbuild.include b/scripts/Kbuild.include
index d64e6ba..982dcae 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -105,12 +105,12 @@
# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
cc-option = $(call try-run,\
- $(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",$(1),$(2))
+ $(CC) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2))
# cc-option-yn
# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
cc-option-yn = $(call try-run,\
- $(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",y,n)
+ $(CC) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n)
# cc-option-align
# Prefix align with either -falign or -malign
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index a7b46ec..1b3534d 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -33,9 +33,6 @@
#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <sound/memalloc.h>
-#ifdef CONFIG_SBUS
-#include <asm/sbus.h>
-#endif
MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>");
@@ -162,39 +159,6 @@
}
#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
@@ -231,11 +195,6 @@
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);
@@ -306,11 +265,6 @@
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);
@@ -419,7 +373,7 @@
long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
struct snd_mem_list *mem;
int devno;
- static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
+ static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG" };
mutex_lock(&list_mutex);
seq_printf(seq, "pages : %li bytes (%li pages per %likB)\n",
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
index 49acee0..f87933e 100644
--- a/sound/sparc/amd7930.c
+++ b/sound/sparc/amd7930.c
@@ -1,6 +1,6 @@
/*
* Driver for AMD7930 sound chips found on Sparcs.
- * Copyright (C) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (C) 2002, 2008 David S. Miller <davem@davemloft.net>
*
* Based entirely upon drivers/sbus/audio/amd7930.c which is:
* Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
@@ -35,6 +35,8 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -44,7 +46,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/sbus.h>
#include <asm/prom.h>
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
@@ -335,8 +336,8 @@
int pgain;
int mgain;
+ struct of_device *op;
unsigned int irq;
- unsigned int regs_size;
struct snd_amd7930 *next;
};
@@ -905,13 +906,16 @@
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)
- sbus_iounmap(amd->regs, amd->regs_size);
+ of_iounmap(&op->resource[0], amd->regs,
+ resource_size(&op->resource[0]));
kfree(amd);
@@ -930,13 +934,12 @@
};
static int __devinit snd_amd7930_create(struct snd_card *card,
- struct resource *rp,
- unsigned int reg_size,
+ struct of_device *op,
int irq, int dev,
struct snd_amd7930 **ramd)
{
- unsigned long flags;
struct snd_amd7930 *amd;
+ unsigned long flags;
int err;
*ramd = NULL;
@@ -946,9 +949,10 @@
spin_lock_init(&amd->lock);
amd->card = card;
- amd->regs_size = reg_size;
+ amd->op = op;
- amd->regs = sbus_ioremap(rp, 0, amd->regs_size, "amd7930");
+ amd->regs = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]), "amd7930");
if (!amd->regs) {
snd_printk("amd7930-%d: Unable to map chip registers.\n", dev);
return -EIO;
@@ -997,12 +1001,15 @@
return 0;
}
-static int __devinit amd7930_attach_common(struct resource *rp, int irq)
+static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
+ struct resource *rp = &op->resource[0];
static int dev_num;
struct snd_card *card;
struct snd_amd7930 *amd;
- int err;
+ int err, irq;
+
+ irq = op->irqs[0];
if (dev_num >= SNDRV_CARDS)
return -ENODEV;
@@ -1023,8 +1030,7 @@
(unsigned long long)rp->start,
irq);
- if ((err = snd_amd7930_create(card, rp,
- (rp->end - rp->start) + 1,
+ if ((err = snd_amd7930_create(card, op,
irq, dev_num, &amd)) < 0)
goto out_err;
@@ -1049,43 +1055,7 @@
return err;
}
-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[] = {
+static const struct of_device_id amd7930_match[] = {
{
.name = "audio",
},
@@ -1100,20 +1070,7 @@
static int __init amd7930_init(void)
{
- 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);
+ return of_register_driver(&amd7930_sbus_driver, &of_bus_type);
}
static void __exit amd7930_exit(void)
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index 791d2fb..d44bf98 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -1,6 +1,6 @@
/*
* Driver for CS4231 sound chips found on Sparcs.
- * Copyright (C) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (C) 2002, 2008 David S. Miller <davem@davemloft.net>
*
* Based entirely upon drivers/sbus/audio/cs4231.c which is:
* Copyright (C) 1996, 1997, 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
@@ -17,7 +17,8 @@
#include <linux/moduleparam.h>
#include <linux/irq.h>
#include <linux/io.h>
-
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -29,13 +30,12 @@
#ifdef CONFIG_SBUS
#define SBUS_SUPPORT
-#include <asm/sbus.h>
#endif
#if defined(CONFIG_PCI) && defined(CONFIG_SPARC64)
#define EBUS_SUPPORT
#include <linux/pci.h>
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
#endif
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
@@ -70,8 +70,6 @@
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
@@ -114,21 +112,12 @@
struct mutex mce_mutex; /* mutex for mce register */
struct mutex open_mutex; /* mutex for ALSA open/close */
- union {
-#ifdef SBUS_SUPPORT
- struct sbus_dev *sdev;
-#endif
-#ifdef EBUS_SUPPORT
- struct pci_dev *pdev;
-#endif
- } dev_u;
+ struct of_device *op;
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
*/
@@ -267,27 +256,19 @@
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
}
/*
@@ -1258,7 +1239,9 @@
pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
strcpy(pcm->name, "CS4231");
- chip->p_dma.preallocate(chip, pcm);
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ &chip->op->dev,
+ 64 * 1024, 128 * 1024);
chip->pcm = pcm;
@@ -1627,8 +1610,7 @@
if (err < 0)
goto out_err;
- chip->next = cs4231_list;
- cs4231_list = chip;
+ dev_set_drvdata(&chip->op->dev, chip);
dev++;
return 0;
@@ -1783,24 +1765,19 @@
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)
- sbus_iounmap(chip->port, chip->regs_size);
+ of_iounmap(&op->resource[0], chip->port, chip->regs_size);
return 0;
}
@@ -1817,7 +1794,7 @@
};
static int __init snd_cs4231_sbus_create(struct snd_card *card,
- struct sbus_dev *sdev,
+ struct of_device *op,
int dev)
{
struct snd_cs4231 *chip = card->private_data;
@@ -1828,13 +1805,13 @@
spin_lock_init(&chip->p_dma.sbus_info.lock);
mutex_init(&chip->mce_mutex);
mutex_init(&chip->open_mutex);
- chip->dev_u.sdev = sdev;
- chip->regs_size = sdev->reg_addrs[0].reg_size;
+ chip->op = op;
+ chip->regs_size = resource_size(&op->resource[0]);
memcpy(&chip->image, &snd_cs4231_original_image,
sizeof(snd_cs4231_original_image));
- chip->port = sbus_ioremap(&sdev->resource[0], 0,
- chip->regs_size, "cs4231");
+ chip->port = of_ioremap(&op->resource[0], 0,
+ chip->regs_size, "cs4231");
if (!chip->port) {
snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev);
return -EIO;
@@ -1849,22 +1826,20 @@
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(sdev->irqs[0], snd_cs4231_sbus_interrupt,
+ if (request_irq(op->irqs[0], snd_cs4231_sbus_interrupt,
IRQF_SHARED, "cs4231", chip)) {
snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d\n",
- dev, sdev->irqs[0]);
+ dev, op->irqs[0]);
snd_cs4231_sbus_free(chip);
return -EBUSY;
}
- chip->irq[0] = sdev->irqs[0];
+ chip->irq[0] = op->irqs[0];
if (snd_cs4231_probe(chip) < 0) {
snd_cs4231_sbus_free(chip);
@@ -1881,9 +1856,9 @@
return 0;
}
-static int __init cs4231_sbus_attach(struct sbus_dev *sdev)
+static int __devinit cs4231_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
- struct resource *rp = &sdev->resource[0];
+ struct resource *rp = &op->resource[0];
struct snd_card *card;
int err;
@@ -1895,9 +1870,9 @@
card->shortname,
rp->flags & 0xffL,
(unsigned long long)rp->start,
- sdev->irqs[0]);
+ op->irqs[0]);
- err = snd_cs4231_sbus_create(card, sdev, dev);
+ err = snd_cs4231_sbus_create(card, op, dev);
if (err < 0) {
snd_card_free(card);
return err;
@@ -1950,30 +1925,25 @@
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);
- iounmap(chip->c_dma.ebus_info.regs);
+ of_iounmap(&op->resource[2], chip->c_dma.ebus_info.regs, 0x10);
}
if (chip->p_dma.ebus_info.regs) {
ebus_dma_unregister(&chip->p_dma.ebus_info);
- iounmap(chip->p_dma.ebus_info.regs);
+ of_iounmap(&op->resource[1], chip->p_dma.ebus_info.regs, 0x10);
}
if (chip->port)
- iounmap(chip->port);
+ of_iounmap(&op->resource[0], chip->port, 0x10);
return 0;
}
@@ -1990,7 +1960,7 @@
};
static int __init snd_cs4231_ebus_create(struct snd_card *card,
- struct linux_ebus_device *edev,
+ struct of_device *op,
int dev)
{
struct snd_cs4231 *chip = card->private_data;
@@ -2002,35 +1972,35 @@
mutex_init(&chip->mce_mutex);
mutex_init(&chip->open_mutex);
chip->flags |= CS4231_FLAG_EBUS;
- chip->dev_u.pdev = edev->bus->self;
+ chip->op = op;
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 = edev->irqs[0];
+ chip->c_dma.ebus_info.irq = op->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 = edev->irqs[1];
+ chip->p_dma.ebus_info.irq = op->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 = 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);
+ 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");
if (!chip->port || !chip->p_dma.ebus_info.regs ||
!chip->c_dma.ebus_info.regs) {
snd_cs4231_ebus_free(chip);
@@ -2078,7 +2048,7 @@
return 0;
}
-static int __init cs4231_ebus_attach(struct linux_ebus_device *edev)
+static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_device_id *match)
{
struct snd_card *card;
int err;
@@ -2089,10 +2059,10 @@
sprintf(card->longname, "%s at 0x%lx, irq %d",
card->shortname,
- edev->resource[0].start,
- edev->irqs[0]);
+ op->resource[0].start,
+ op->irqs[0]);
- err = snd_cs4231_ebus_create(card, edev, dev);
+ err = snd_cs4231_ebus_create(card, op, dev);
if (err < 0) {
snd_card_free(card);
return err;
@@ -2102,68 +2072,57 @@
}
#endif
+static int __devinit cs4231_probe(struct of_device *op, const struct of_device_id *match)
+{
+#ifdef EBUS_SUPPORT
+ if (!strcmp(op->node->parent->name, "ebus"))
+ return cs4231_ebus_probe(op, match);
+#endif
+#ifdef SBUS_SUPPORT
+ if (!strcmp(op->node->parent->name, "sbus") ||
+ !strcmp(op->node->parent->name, "sbi"))
+ return cs4231_sbus_probe(op, match);
+#endif
+ return -ENODEV;
+}
+
+static int __devexit cs4231_remove(struct of_device *op)
+{
+ struct snd_cs4231 *chip = dev_get_drvdata(&op->dev);
+
+ snd_card_free(chip->card);
+
+ return 0;
+}
+
+static const struct of_device_id cs4231_match[] = {
+ {
+ .name = "SUNW,CS4231",
+ },
+ {
+ .name = "audio",
+ .compatible = "SUNW,CS4231",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, cs4231_match);
+
+static struct of_platform_driver cs4231_driver = {
+ .name = "audio",
+ .match_table = cs4231_match,
+ .probe = cs4231_probe,
+ .remove = __devexit_p(cs4231_remove),
+};
+
static int __init cs4231_init(void)
{
-#ifdef SBUS_SUPPORT
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
-#endif
-#ifdef EBUS_SUPPORT
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev;
-#endif
- int found;
-
- found = 0;
-
-#ifdef SBUS_SUPPORT
- for_all_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, "SUNW,CS4231")) {
- if (cs4231_sbus_attach(sdev) == 0)
- found++;
- }
- }
-#endif
-#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;
- }
-
- if (match &&
- cs4231_ebus_attach(edev) == 0)
- found++;
- }
- }
-#endif
-
-
- return (found > 0) ? 0 : -EIO;
+ return of_register_driver(&cs4231_driver, &of_bus_type);
}
static void __exit cs4231_exit(void)
{
- struct snd_cs4231 *p = cs4231_list;
-
- while (p != NULL) {
- struct snd_cs4231 *next = p->next;
-
- snd_card_free(p->card);
-
- p = next;
- }
-
- cs4231_list = NULL;
+ of_unregister_driver(&cs4231_driver);
}
module_init(cs4231_init);
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index c534a2a..c257ad8 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -57,6 +57,7 @@
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -66,7 +67,7 @@
#include <sound/initval.h>
#include <linux/of.h>
-#include <asm/sbus.h>
+#include <linux/of_device.h>
#include <asm/atomic.h>
MODULE_AUTHOR("Rudolf Koenig, Brent Baccala and Martin Habets");
@@ -297,7 +298,7 @@
/* This structure holds the information for both chips (DBRI & CS4215) */
struct snd_dbri {
int regs_size, irq; /* Needed for unload */
- struct sbus_dev *sdev; /* SBUS device info */
+ struct of_device *op; /* OF device info */
spinlock_t lock;
struct dbri_dma *dma; /* Pointer to our DMA block */
@@ -2093,14 +2094,15 @@
*/
if (info->dvma_buffer == 0) {
if (DBRI_STREAMNO(substream) == DBRI_PLAY)
- direction = SBUS_DMA_TODEVICE;
+ direction = DMA_TO_DEVICE;
else
- direction = SBUS_DMA_FROMDEVICE;
+ direction = DMA_FROM_DEVICE;
- info->dvma_buffer = sbus_map_single(dbri->sdev,
- runtime->dma_area,
- params_buffer_bytes(hw_params),
- direction);
+ info->dvma_buffer =
+ dma_map_single(&dbri->op->dev,
+ runtime->dma_area,
+ params_buffer_bytes(hw_params),
+ direction);
}
direction = params_buffer_bytes(hw_params);
@@ -2121,12 +2123,12 @@
*/
if (info->dvma_buffer) {
if (DBRI_STREAMNO(substream) == DBRI_PLAY)
- direction = SBUS_DMA_TODEVICE;
+ direction = DMA_TO_DEVICE;
else
- direction = SBUS_DMA_FROMDEVICE;
+ direction = DMA_FROM_DEVICE;
- sbus_unmap_single(dbri->sdev, info->dvma_buffer,
- substream->runtime->buffer_size, direction);
+ dma_unmap_single(&dbri->op->dev, info->dvma_buffer,
+ substream->runtime->buffer_size, direction);
info->dvma_buffer = 0;
}
if (info->pipe != -1) {
@@ -2519,31 +2521,32 @@
static void snd_dbri_free(struct snd_dbri *dbri);
static int __devinit snd_dbri_create(struct snd_card *card,
- struct sbus_dev *sdev,
- int irq, int dev)
+ struct of_device *op,
+ int irq, int dev)
{
struct snd_dbri *dbri = card->private_data;
int err;
spin_lock_init(&dbri->lock);
- dbri->sdev = sdev;
+ dbri->op = op;
dbri->irq = irq;
- dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma),
- &dbri->dma_dvma);
+ dbri->dma = dma_alloc_coherent(&op->dev,
+ sizeof(struct dbri_dma),
+ &dbri->dma_dvma, GFP_ATOMIC);
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 = sdev->reg_addrs[0].reg_size;
- dbri->regs = sbus_ioremap(&sdev->resource[0], 0,
- dbri->regs_size, "DBRI Registers");
+ dbri->regs_size = resource_size(&op->resource[0]);
+ dbri->regs = of_ioremap(&op->resource[0], 0,
+ dbri->regs_size, "DBRI Registers");
if (!dbri->regs) {
printk(KERN_ERR "DBRI: could not allocate registers\n");
- sbus_free_consistent(sdev, sizeof(struct dbri_dma),
- (void *)dbri->dma, dbri->dma_dvma);
+ dma_free_coherent(&op->dev, sizeof(struct dbri_dma),
+ (void *)dbri->dma, dbri->dma_dvma);
return -EIO;
}
@@ -2551,9 +2554,9 @@
"DBRI audio", dbri);
if (err) {
printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
- sbus_iounmap(dbri->regs, dbri->regs_size);
- sbus_free_consistent(sdev, sizeof(struct dbri_dma),
- (void *)dbri->dma, dbri->dma_dvma);
+ 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);
return err;
}
@@ -2577,27 +2580,23 @@
free_irq(dbri->irq, dbri);
if (dbri->regs)
- sbus_iounmap(dbri->regs, dbri->regs_size);
+ of_iounmap(&dbri->op->resource[0], dbri->regs, dbri->regs_size);
if (dbri->dma)
- sbus_free_consistent(dbri->sdev, sizeof(struct dbri_dma),
- (void *)dbri->dma, dbri->dma_dvma);
+ dma_free_coherent(&dbri->op->dev,
+ sizeof(struct dbri_dma),
+ (void *)dbri->dma, dbri->dma_dvma);
}
-static int __devinit dbri_probe(struct of_device *of_dev,
- const struct of_device_id *match)
+static int __devinit dbri_probe(struct of_device *op, 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]) {
@@ -2605,7 +2604,7 @@
return -ENOENT;
}
- irq = sdev->irqs[0];
+ irq = op->irqs[0];
if (irq <= 0) {
printk(KERN_ERR "DBRI-%d: No IRQ.\n", dev);
return -ENODEV;
@@ -2618,12 +2617,12 @@
strcpy(card->driver, "DBRI");
strcpy(card->shortname, "Sun DBRI");
- rp = &sdev->resource[0];
+ rp = &op->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, sdev, irq, dev);
+ err = snd_dbri_create(card, op, irq, dev);
if (err < 0) {
snd_card_free(card);
return err;
@@ -2640,7 +2639,7 @@
/* /proc file handling */
snd_dbri_proc(card);
- dev_set_drvdata(&of_dev->dev, card);
+ dev_set_drvdata(&op->dev, card);
err = snd_card_register(card);
if (err < 0)
@@ -2648,7 +2647,7 @@
printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n",
dev, dbri->regs,
- dbri->irq, sdev->prom_name[9], dbri->mm.version);
+ dbri->irq, op->node->name[9], dbri->mm.version);
dev++;
return 0;
@@ -2659,19 +2658,19 @@
return err;
}
-static int __devexit dbri_remove(struct of_device *dev)
+static int __devexit dbri_remove(struct of_device *op)
{
- struct snd_card *card = dev_get_drvdata(&dev->dev);
+ struct snd_card *card = dev_get_drvdata(&op->dev);
snd_dbri_free(card->private_data);
snd_card_free(card);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id dbri_match[] = {
+static const struct of_device_id dbri_match[] = {
{
.name = "SUNW,DBRIe",
},
@@ -2693,7 +2692,7 @@
/* Probe for the dbri chip and then attach the driver. */
static int __init dbri_init(void)
{
- return of_register_driver(&dbri_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&dbri_sbus_driver, &of_bus_type);
}
static void __exit dbri_exit(void)