diff options
362 files changed, 20162 insertions, 8153 deletions
diff --git a/Documentation/DocBook/deviceiobook.tmpl b/Documentation/DocBook/deviceiobook.tmpl index c917de681cc..361c884d860 100644 --- a/Documentation/DocBook/deviceiobook.tmpl +++ b/Documentation/DocBook/deviceiobook.tmpl @@ -316,7 +316,7 @@ CPU B: spin_unlock_irqrestore(&dev_lock, flags) <chapter id="pubfunctions"> <title>Public Functions Provided</title> -!Iinclude/asm-i386/io.h +!Iinclude/asm-x86/io_32.h !Elib/iomap.c </chapter> diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index e5da4f2b7c2..230cbf75378 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -45,8 +45,8 @@ </sect1> <sect1><title>Atomic and pointer manipulation</title> -!Iinclude/asm-i386/atomic.h -!Iinclude/asm-i386/unaligned.h +!Iinclude/asm-x86/atomic_32.h +!Iinclude/asm-x86/unaligned_32.h </sect1> <sect1><title>Delaying, scheduling, and timer routines</title> @@ -119,7 +119,7 @@ X!Ilib/string.c !Elib/string.c </sect1> <sect1><title>Bit Operations</title> -!Iinclude/asm-i386/bitops.h +!Iinclude/asm-x86/bitops_32.h </sect1> </chapter> @@ -155,8 +155,8 @@ X!Ilib/string.c !Emm/slab.c </sect1> <sect1><title>User Space Memory Access</title> -!Iinclude/asm-i386/uaccess.h -!Earch/i386/lib/usercopy.c +!Iinclude/asm-x86/uaccess_32.h +!Earch/x86/lib/usercopy_32.c </sect1> <sect1><title>More Memory Management Functions</title> !Emm/readahead.c @@ -293,7 +293,7 @@ X!Ekernel/module.c </sect1> <sect1><title>MTRR Handling</title> -!Earch/i386/kernel/cpu/mtrr/main.c +!Earch/x86/kernel/cpu/mtrr/main.c </sect1> <sect1><title>PCI Support Library</title> @@ -316,14 +316,14 @@ X!Edrivers/pci/hotplug.c <sect1><title>MCA Architecture</title> <sect2><title>MCA Device Functions</title> <para> - Refer to the file arch/i386/kernel/mca.c for more information. + Refer to the file arch/x86/kernel/mca_32.c for more information. </para> <!-- FIXME: Removed for now since no structured comments in source -X!Earch/i386/kernel/mca.c +X!Earch/x86/kernel/mca_32.c --> </sect2> <sect2><title>MCA Bus DMA</title> -!Iinclude/asm-i386/mca_dma.h +!Iinclude/asm-x86/mca_dma.h </sect2> </sect1> </chapter> diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl index 582032eea87..4c63e586416 100644 --- a/Documentation/DocBook/kernel-hacking.tmpl +++ b/Documentation/DocBook/kernel-hacking.tmpl @@ -1239,7 +1239,7 @@ static struct block_device_operations opt_fops = { </para> <para> - <filename>include/asm-i386/delay.h:</filename> + <filename>include/asm-x86/delay_32.h:</filename> </para> <programlisting> #define ndelay(n) (__builtin_constant_p(n) ? \ @@ -1265,7 +1265,7 @@ static struct block_device_operations opt_fops = { </programlisting> <para> - <filename>include/asm-i386/uaccess.h:</filename> + <filename>include/asm-x86/uaccess_32.h:</filename> </para> <programlisting> diff --git a/Documentation/DocBook/mcabook.tmpl b/Documentation/DocBook/mcabook.tmpl index 42a760cd746..529a53dc138 100644 --- a/Documentation/DocBook/mcabook.tmpl +++ b/Documentation/DocBook/mcabook.tmpl @@ -101,7 +101,7 @@ <chapter id="dmafunctions"> <title>DMA Functions Provided</title> -!Iinclude/asm-i386/mca_dma.h +!Iinclude/asm-x86/mca_dma.h </chapter> </book> diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl index a8c8cce5063..6fbc41d98c1 100644 --- a/Documentation/DocBook/mtdnand.tmpl +++ b/Documentation/DocBook/mtdnand.tmpl @@ -275,16 +275,13 @@ int __init board_init (void) int err = 0; /* Allocate memory for MTD device structure and private data */ - board_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); + board_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!board_mtd) { printk ("Unable to allocate NAND MTD device structure.\n"); err = -ENOMEM; goto out; } - /* Initialize structures */ - memset ((char *) board_mtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip)); - /* map physical adress */ baseaddr = (unsigned long)ioremap(CHIP_PHYSICAL_ADDRESS, 1024); if(!baseaddr){ diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index 2b5f64726a2..fbbccb5e751 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -1,5 +1,5 @@ /* - * linux/atari/atakeyb.c + * linux/arch/m68k/atari/atakeyb.c * * Atari Keyboard driver for 680x0 Linux * @@ -11,6 +11,9 @@ /* * Atari support by Robert de Vries * enhanced by Bjoern Brauel and Roman Hodek + * + * 2.6 and input cleanup (removed autorepeat stuff) for 2.6.21 + * 06/07 Michael Schmitz */ #include <linux/module.h> @@ -32,7 +35,6 @@ #include <asm/atari_joystick.h> #include <asm/irq.h> -static void atakeyb_rep(unsigned long ignore); extern unsigned int keymap_count; /* Hook for MIDI serial driver */ @@ -104,25 +106,6 @@ static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, }; * - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR] */ -static u_short ataplain_map[NR_KEYS] __initdata = { - 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, - 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009, - 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, - 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73, - 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, - 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, - 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200, - 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, - 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114, - 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, - 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307, - 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, - 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 -}; - typedef enum kb_state_t { KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC } KB_STATE_T; @@ -137,41 +120,6 @@ typedef struct keyboard_state { KEYBOARD_STATE kb_state; -#define DEFAULT_KEYB_REP_DELAY (HZ/4) -#define DEFAULT_KEYB_REP_RATE (HZ/25) - -/* These could be settable by some ioctl() in future... */ -static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY; -static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE; - -static unsigned char rep_scancode; -static struct timer_list atakeyb_rep_timer = { - .function = atakeyb_rep, -}; - -static void atakeyb_rep(unsigned long ignore) -{ - /* Disable keyboard for the time we call handle_scancode(), else a race - * in the keyboard tty queue may happen */ - atari_disable_irq(IRQ_MFP_ACIA); - del_timer(&atakeyb_rep_timer); - - /* A keyboard int may have come in before we disabled the irq, so - * double-check whether rep_scancode is still != 0 */ - if (rep_scancode) { - init_timer(&atakeyb_rep_timer); - atakeyb_rep_timer.expires = jiffies + key_repeat_rate; - add_timer(&atakeyb_rep_timer); - - //handle_scancode(rep_scancode, 1); - if (atari_input_keyboard_interrupt_hook) - atari_input_keyboard_interrupt_hook(rep_scancode, 1); - } - - atari_enable_irq(IRQ_MFP_ACIA); -} - - /* ++roman: If a keyboard overrun happened, we can't tell in general how much * bytes have been lost and in which state of the packet structure we are now. * This usually causes keyboards bytes to be interpreted as mouse movements @@ -209,9 +157,6 @@ repeat: /* ...happens often if interrupts were disabled for too long */ printk(KERN_DEBUG "Keyboard overrun\n"); scancode = acia.key_data; - /* Turn off autorepeating in case a break code has been lost */ - del_timer(&atakeyb_rep_timer); - rep_scancode = 0; if (ikbd_self_test) /* During self test, don't do resyncing, just process the code */ goto interpret_scancode; @@ -281,11 +226,12 @@ repeat: * make codes instead. Therefore, simply ignore * break_flag... */ - int keyval = plain_map[scancode], keytyp; + int keyval, keytyp; set_bit(scancode, broken_keys); self_test_last_rcv = jiffies; - keyval = plain_map[scancode]; + /* new Linux scancodes; approx. */ + keyval = scancode; keytyp = KTYP(keyval) - 0xf0; keyval = KVAL(keyval); @@ -301,19 +247,6 @@ repeat: } else if (test_bit(scancode, broken_keys)) break; -#if 0 // FIXME; hangs at boot - if (break_flag) { - del_timer(&atakeyb_rep_timer); - rep_scancode = 0; - } else { - del_timer(&atakeyb_rep_timer); - rep_scancode = scancode; - atakeyb_rep_timer.expires = jiffies + key_repeat_delay; - add_timer(&atakeyb_rep_timer); - } -#endif - - // handle_scancode(scancode, !break_flag); if (atari_input_keyboard_interrupt_hook) atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag); break; @@ -639,9 +572,6 @@ int __init atari_keyb_init(void) if (atari_keyb_done) return 0; - /* setup key map */ - memcpy(key_maps[0], ataplain_map, sizeof(plain_map)); - kb_state.state = KEYBOARD; kb_state.len = 0; @@ -704,26 +634,6 @@ int __init atari_keyb_init(void) return 0; } -int atari_kbdrate(struct kbd_repeat *k) -{ - if (k->delay > 0) { - /* convert from msec to jiffies */ - key_repeat_delay = (k->delay * HZ + 500) / 1000; - if (key_repeat_delay < 1) - key_repeat_delay = 1; - } - if (k->period > 0) { - key_repeat_rate = (k->period * HZ + 500) / 1000; - if (key_repeat_rate < 1) - key_repeat_rate = 1; - } - - k->delay = key_repeat_delay * 1000 / HZ; - k->period = key_repeat_rate * 1000 / HZ; - - return 0; -} - int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode) { #ifdef CONFIG_MAGIC_SYSRQ diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 54878f07cf0..44982c1dfa2 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -118,7 +118,7 @@ endchoice config SH_FPU bool "FPU support" - depends on CPU_SH4 + depends on CPU_HAS_FPU default y help Selecting this option will enable support for SH processors that @@ -178,12 +178,6 @@ config CPU_HAS_INTEVT config CPU_HAS_MASKREG_IRQ bool -config CPU_HAS_INTC_IRQ - bool - -config CPU_HAS_INTC2_IRQ - bool - config CPU_HAS_IPR_IRQ bool @@ -205,6 +199,9 @@ config CPU_HAS_PTEA config CPU_HAS_DSP bool +config CPU_HAS_FPU + bool + endmenu menu "Board support" @@ -258,7 +255,6 @@ config SH_7780_SOLUTION_ENGINE bool "SolutionEngine7780" select SOLUTION_ENGINE select SYS_SUPPORTS_PCI - select CPU_HAS_INTC2_IRQ depends on CPU_SUBTYPE_SH7780 help Select 7780 SolutionEngine if configuring for a Renesas SH7780 @@ -309,7 +305,7 @@ config SH_MPC1211 config SH_SH03 bool "Interface CTP/PCI-SH03" - depends on CPU_SUBTYPE_SH7751 && BROKEN + depends on CPU_SUBTYPE_SH7751 select CPU_HAS_IPR_IRQ select SYS_SUPPORTS_PCI help @@ -395,11 +391,22 @@ config SH_LBOX_RE2 help Select L-BOX RE2 if configuring for the NTT COMWARE L-BOX RE2. +config SH_X3PROTO + bool "SH-X3 Prototype board" + depends on CPU_SUBTYPE_SHX3 + +config SH_MAGIC_PANEL_R2 + bool "Magic Panel R2" + depends on CPU_SUBTYPE_SH7720 + help + Select Magic Panel R2 if configuring for Magic Panel R2. + endmenu source "arch/sh/boards/renesas/hs7751rvoip/Kconfig" source "arch/sh/boards/renesas/rts7751r2d/Kconfig" source "arch/sh/boards/renesas/r7780rp/Kconfig" +source "arch/sh/boards/magicpanelr2/Kconfig" menu "Timer and clock configuration" @@ -563,10 +570,19 @@ config NR_CPUS source "kernel/Kconfig.preempt" -config NODES_SHIFT - int - default "1" - depends on NEED_MULTIPLE_NODES +config GUSA + def_bool y + depends on !SMP + help + This enables support for gUSA (general UserSpace Atomicity). + This is the default implementation for both UP and non-ll/sc + CPUs, and is used by the libc, amongst others. + + For additional information, design information can be found + in <http://lc.linux.or.jp/lc2002/papers/niibe0919p.pdf>. + + This should only be disabled for special cases where alternate + atomicity implementations exist. endmenu @@ -659,6 +675,17 @@ config SUPERHYWAY tristate "SuperHyway Bus support" depends on CPU_SUBTYPE_SH4_202 +config MAPLE + bool "Maple Bus support" + depends on SH_DREAMCAST + help + The Maple Bus is SEGA's serial communication bus for peripherals + on the Dreamcast. Without this bus support you won't be able to + get your Dreamcast keyboard etc to work, so most users + probably want to say 'Y' here, unless you are only using the + Dreamcast with a serial line terminal or a remote network + connection. + config CF_ENABLER bool "Compact Flash Enabler support" depends on SOLUTION_ENGINE || SH_SH03 diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug index 52f6a99c8ec..b507b501f0c 100644 --- a/arch/sh/Kconfig.debug +++ b/arch/sh/Kconfig.debug @@ -28,13 +28,17 @@ config EARLY_SCIF_CONSOLE serial I/O. config EARLY_SCIF_CONSOLE_PORT - hex "SCIF port for early console" + hex depends on EARLY_SCIF_CONSOLE default "0xffe00000" if CPU_SUBTYPE_SH7780 + default "0xffea0000" if CPU_SUBTYPE_SH7785 default "0xfffe9800" if CPU_SUBTYPE_SH7206 default "0xf8420000" if CPU_SUBTYPE_SH7619 default "0xa4400000" if CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7705 + default "0xa4430000" if CPU_SUBTYPE_SH7720 + default "0xffc30000" if CPU_SUBTYPE_SHX3 default "0xffe80000" if CPU_SH4 + default "0x00000000" config EARLY_PRINTK bool "Early printk support" diff --git a/arch/sh/Makefile b/arch/sh/Makefile index 97ac58682d0..a0a2083aad3 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -118,6 +118,7 @@ machdir-$(CONFIG_SH_7751_SYSTEMH) += renesas/systemh machdir-$(CONFIG_SH_EDOSK7705) += renesas/edosk7705 machdir-$(CONFIG_SH_HIGHLANDER) += renesas/r7780rp machdir-$(CONFIG_SH_7710VOIPGW) += renesas/sh7710voipgw +machdir-$(CONFIG_SH_X3PROTO) += renesas/x3proto machdir-$(CONFIG_SH_SH4202_MICRODEV) += superh/microdev machdir-$(CONFIG_SH_LANDISK) += landisk machdir-$(CONFIG_SH_TITAN) += titan @@ -125,6 +126,7 @@ machdir-$(CONFIG_SH_SHMIN) += shmin machdir-$(CONFIG_SH_7206_SOLUTION_ENGINE) += se/7206 machdir-$(CONFIG_SH_7619_SOLUTION_ENGINE) += se/7619 machdir-$(CONFIG_SH_LBOX_RE2) += lboxre2 +machdir-$(CONFIG_SH_MAGIC_PANEL_R2) += magicpanelr2 incdir-y := $(notdir $(machdir-y)) @@ -135,7 +137,7 @@ endif # Companion chips core-$(CONFIG_HD6446X_SERIES) += arch/sh/cchips/hd6446x/ -core-$(CONFIG_VOYAGERGX) += arch/sh/cchips/voyagergx/ +core-$(CONFIG_MFD_SM501) += arch/sh/cchips/voyagergx/ cpuincdir-$(CONFIG_CPU_SH2) := cpu-sh2 cpuincdir-$(CONFIG_CPU_SH2A) := cpu-sh2a diff --git a/arch/sh/boards/hp6xx/hp6xx_apm.c b/arch/sh/boards/hp6xx/hp6xx_apm.c index d1c1460c8a0..640ca2a74f1 100644 --- a/arch/sh/boards/hp6xx/hp6xx_apm.c +++ b/arch/sh/boards/hp6xx/hp6xx_apm.c @@ -20,9 +20,9 @@ #define APM_CRITICAL 10 #define APM_LOW 30 -#define HP680_BATTERY_MAX 875 -#define HP680_BATTERY_MIN 600 -#define HP680_BATTERY_AC_ON 900 +#define HP680_BATTERY_MAX 898 +#define HP680_BATTERY_MIN 486 +#define HP680_BATTERY_AC_ON 1023 #define MODNAME "hp6x0_apm" @@ -65,7 +65,7 @@ static void hp6x0_apm_get_power_status(struct apm_power_info *info) static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev) { - if (!apm_suspended) + if (!APM_DISABLED) apm_queue_event(APM_USER_SUSPEND); return IRQ_HANDLED; @@ -91,7 +91,6 @@ static int __init hp6x0_apm_init(void) static void __exit hp6x0_apm_exit(void) { free_irq(HP680_BTN_IRQ, 0); - apm_get_info = NULL; } module_init(hp6x0_apm_init); diff --git a/arch/sh/boards/hp6xx/setup.c b/arch/sh/boards/hp6xx/setup.c index 7ae708930ba..2f414ac3c69 100644 --- a/arch/sh/boards/hp6xx/setup.c +++ b/arch/sh/boards/hp6xx/setup.c @@ -7,7 +7,7 @@ * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. * - * Setup code for an HP680 (internal peripherials only) + * Setup code for HP620/HP660/HP680/HP690 (internal peripherials only) */ #include <linux/types.h> #include <linux/init.h> @@ -19,7 +19,7 @@ #include <asm/cpu/dac.h> #define SCPCR 0xa4000116 -#define SCPDR 0xa4000136 +#define SCPDR 0xa4000136 /* CF Slot */ static struct resource cf_ide_resources[] = { @@ -34,7 +34,7 @@ static struct resource cf_ide_resources[] = { .flags = IORESOURCE_MEM, }, [2] = { - .start = 93, + .start = 77, .flags = IORESOURCE_IRQ, }, }; @@ -46,10 +46,22 @@ static struct platform_device cf_ide_device = { .resource = cf_ide_resources, }; +static struct platform_device jornadakbd_device = { + .name = "jornada680_kbd", + .id = -1, +}; + static struct platform_device *hp6xx_devices[] __initdata = { - &cf_ide_device, + &cf_ide_device, + &jornadakbd_device, }; +static void __init hp6xx_init_irq(void) +{ + /* Gets touchscreen and powerbutton IRQ working */ + plat_irq_setup_pins(IRQ_MODE_IRQ); +} + static int __init hp6xx_devices_setup(void) { return platform_add_devices(hp6xx_devices, ARRAY_SIZE(hp6xx_devices)); @@ -61,11 +73,11 @@ static void __init hp6xx_setup(char **cmdline_p) u16 v; v = inw(HD64461_STBCR); - v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST | - HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST | - HD64461_STBCR_SAFEST | HD64461_STBCR_SPC0ST | - HD64461_STBCR_SMIAST | HD64461_STBCR_SAFECKE_OST | - HD64461_STBCR_SAFECKE_IST; + v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST | + HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST | + HD64461_STBCR_SAFEST | HD64461_STBCR_SPC0ST | + HD64461_STBCR_SMIAST | HD64461_STBCR_SAFECKE_OST| + HD64461_STBCR_SAFECKE_IST; #ifndef CONFIG_HD64461_ENABLER v |= HD64461_STBCR_SPC1ST; #endif @@ -101,6 +113,9 @@ device_initcall(hp6xx_devices_setup); static struct sh_machine_vector mv_hp6xx __initmv = { .mv_name = "hp6xx", .mv_setup = hp6xx_setup, - .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM, + /* IRQ's : CPU(64) + CCHIP(16) + FREE_TO_USE(6) */ + .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM + 6, .mv_irq_demux = hd64461_irq_demux, + /* Enable IRQ0 -> IRQ3 in IRQ_MODE */ + .mv_init_irq = hp6xx_init_irq, }; diff --git a/arch/sh/boards/magicpanelr2/Kconfig b/arch/sh/boards/magicpanelr2/Kconfig new file mode 100644 index 00000000000..b0abddc3e84 --- /dev/null +++ b/arch/sh/boards/magicpanelr2/Kconfig @@ -0,0 +1,13 @@ +if SH_MAGIC_PANEL_R2 + +menu "Magic Panel R2 options" + +config SH_MAGIC_PANEL_R2_VERSION + int SH_MAGIC_PANEL_R2_VERSION + default "3" + help + Set the version of the Magic Panel R2 + +endmenu + +endif diff --git a/arch/sh/boards/magicpanelr2/Makefile b/arch/sh/boards/magicpanelr2/Makefile new file mode 100644 index 00000000000..7a6d586b907 --- /dev/null +++ b/arch/sh/boards/magicpanelr2/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Magic Panel specific parts +# + +obj-y := setup.o
\ No newline at end of file diff --git a/arch/sh/boards/magicpanelr2/setup.c b/arch/sh/boards/magicpanelr2/setup.c new file mode 100644 index 00000000000..f3b8b07ea5d --- /dev/null +++ b/arch/sh/boards/magicpanelr2/setup.c @@ -0,0 +1,394 @@ +/* + * linux/arch/sh/boards/magicpanel/setup.c + * + * Copyright (C) 2007 Markus Brunner, Mark Jonas + * + * Magic Panel Release 2 board setup + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <linux/mtd/map.h> +#include <asm/magicpanelr2.h> +#include <asm/heartbeat.h> + +#define LAN9115_READY (ctrl_inl(0xA8000084UL) & 0x00000001UL) + +/* Prefer cmdline over RedBoot */ +static const char *probes[] = { "cmdlinepart", "RedBoot", NULL }; + +/* Wait until reset finished. Timeout is 100ms. */ +static int __init ethernet_reset_finished(void) +{ + int i; + + if (LAN9115_READY) + return 1; + + for (i = 0; i < 10; ++i) { + mdelay(10); + if (LAN9115_READY) + return 1; + } + + return 0; +} + +static void __init reset_ethernet(void) +{ + /* PMDR: LAN_RESET=on */ + CLRBITS_OUTB(0x10, PORT_PMDR); + + udelay(200); + + /* PMDR: LAN_RESET=off */ + SETBITS_OUTB(0x10, PORT_PMDR); +} + +static void __init setup_chip_select(void) +{ + /* CS2: LAN (0x08000000 - 0x0bffffff) */ + /* no idle cycles, normal space, 8 bit data bus */ + ctrl_outl(0x36db0400, CS2BCR); + /* (SW:1.5 WR:3 HW:1.5), ext. wait */ + ctrl_outl(0x000003c0, CS2WCR); + + /* CS4: CAN1 (0xb0000000 - 0xb3ffffff) */ + /* no idle cycles, normal space, 8 bit data bus */ + ctrl_outl(0x00000200, CS4BCR); + /* (SW:1.5 WR:3 HW:1.5), ext. wait */ + ctrl_outl(0x00100981, CS4WCR); + + /* CS5a: CAN2 (0xb4000000 - 0xb5ffffff) */ + /* no idle cycles, normal space, 8 bit data bus */ + ctrl_outl(0x00000200, CS5ABCR); + /* (SW:1.5 WR:3 HW:1.5), ext. wait */ + ctrl_outl(0x00100981, CS5AWCR); + + /* CS5b: CAN3 (0xb6000000 - 0xb7ffffff) */ + /* no idle cycles, normal space, 8 bit data bus */ + ctrl_outl(0x00000200, CS5BBCR); + /* (SW:1.5 WR:3 HW:1.5), ext. wait */ + ctrl_outl(0x00100981, CS5BWCR); + + /* CS6a: Rotary (0xb8000000 - 0xb9ffffff) */ + /* no idle cycles, normal space, 8 bit data bus */ + ctrl_outl(0x00000200, CS6ABCR); + /* (SW:1.5 WR:3 HW:1.5), no ext. wait */ + ctrl_outl(0x001009C1, CS6AWCR); +} + +static void __init setup_port_multiplexing(void) +{ + /* A7 GPO(LED8); A6 GPO(LED7); A5 GPO(LED6); A4 GPO(LED5); + * A3 GPO(LED4); A2 GPO(LED3); A1 GPO(LED2); A0 GPO(LED1); + */ + ctrl_outw(0x5555, PORT_PACR); /* 01 01 01 01 01 01 01 01 */ + + /* B7 GPO(RST4); B6 GPO(RST3); B5 GPO(RST2); B4 GPO(RST1); + * B3 GPO(PB3); B2 GPO(PB2); B1 GPO(PB1); B0 GPO(PB0); + */ + ctrl_outw(0x5555, PORT_PBCR); /* 01 01 01 01 01 01 01 01 */ + + /* C7 GPO(PC7); C6 GPO(PC6); C5 GPO(PC5); C4 GPO(PC4); + * C3 LCD_DATA3; C2 LCD_DATA2; C1 LCD_DATA1; C0 LCD_DATA0; + */ + ctrl_outw(0x5500, PORT_PCCR); /* 01 01 01 01 00 00 00 00 */ + + /* D7 GPO(PD7); D6 GPO(PD6); D5 GPO(PD5); D4 GPO(PD4); + * D3 GPO(PD3); D2 GPO(PD2); D1 GPO(PD1); D0 GPO(PD0); + */ + ctrl_outw(0x5555, PORT_PDCR); /* 01 01 01 01 01 01 01 01 */ + + /* E7 (x); E6 GPI(nu); E5 GPI(nu); E4 LCD_M_DISP; + * E3 LCD_CL1; E2 LCD_CL2; E1 LCD_DON; E0 LCD_FLM; + */ + ctrl_outw(0x3C00, PORT_PECR); /* 00 11 11 00 00 00 00 00 */ + + /* F7 (x); F6 DA1(VLCD); F5 DA0(nc); F4 AN3; + * F3 AN2(MID_AD); F2 AN1(EARTH_AD); F1 AN0(TEMP); F0 GPI+(nc); + */ + ctrl_outw(0x0002, PORT_PFCR); /* 00 00 00 00 00 00 00 10 */ + + /* G7 (x); G6 IRQ5(TOUCH_BUSY); G5 IRQ4(TOUCH_IRQ); G4 GPI(KEY2); + * G3 GPI(KEY1); G2 GPO(LED11); G1 GPO(LED10); G0 GPO(LED9); + */ + ctrl_outw(0x03D5, PORT_PGCR); /* 00 00 00 11 11 01 01 01 */ + + /* H7 (x); H6 /RAS(BRAS); H5 /CAS(BCAS); H4 CKE(BCKE); + * H3 GPO(EARTH_OFF); H2 GPO(EARTH_TEST); H1 USB2_PWR; H0 USB1_PWR; + */ + ctrl_outw(0x0050, PORT_PHCR); /* 00 00 00 00 01 01 00 00 */ + + /* J7 (x); J6 AUDCK; J5 ASEBRKAK; J4 AUDATA3; + * J3 AUDATA2; J2 AUDATA1; J1 AUDATA0; J0 AUDSYNC; + */ + ctrl_outw(0x0000, PORT_PJCR); /* 00 00 00 00 00 00 00 00 */ + + /* K7 (x); K6 (x); K5 (x); K4 (x); + * K3 PINT7(/PWR2); K2 PINT6(/PWR1); K1 PINT5(nu); K0 PINT4(FLASH_READY) + */ + ctrl_outw(0x00FF, PORT_PKCR); /* 00 00 00 00 11 11 11 11 */ + + /* L7 TRST; L6 TMS; L5 TDO; L4 TDI; + * L3 TCK; L2 (x); L1 (x); L0 (x); + */ + ctrl_outw(0x0000, PORT_PLCR); /* 00 00 00 00 00 00 00 00 */ + + /* M7 GPO(CURRENT_SINK); M6 GPO(PWR_SWITCH); M5 GPO(LAN_SPEED); + * M4 GPO(LAN_RESET); M3 GPO(BUZZER); M2 GPO(LCD_BL); + * M1 CS5B(CAN3_CS); M0 GPI+(nc); + */ + ctrl_outw(0x5552, PORT_PMCR); /* 01 01 01 01 01 01 00 10 */ + + /* CURRENT_SINK=off, PWR_SWITCH=off, LAN_SPEED=100MBit, + * LAN_RESET=off, BUZZER=off, LCD_BL=off + */ +#if CONFIG_SH_MAGIC_PANEL_R2_VERSION == 2 + ctrl_outb(0x30, PORT_PMDR); +#elif CONFIG_SH_MAGIC_PANEL_R2_VERSION == 3 + ctrl_outb(0xF0, PORT_PMDR); +#else +#error Unknown revision of PLATFORM_MP_R2 +#endif + + /* P7 (x); P6 (x); P5 (x); + * P4 GPO(nu); P3 IRQ3(LAN_IRQ); P2 IRQ2(CAN3_IRQ); + * P1 IRQ1(CAN2_IRQ); P0 IRQ0(CAN1_IRQ) + */ + ctrl_outw(0x0100, PORT_PPCR); /* 00 00 00 01 00 00 00 00 */ + ctrl_outb(0x10, PORT_PPDR); + + /* R7 A25; R6 A24; R5 A23; R4 A22; + * R3 A21; R2 A20; R1 A19; R0 A0; + */ + ctrl_outw(0x0000, PORT_PRCR); /* 00 00 00 00 00 00 00 00 */ + + /* S7 (x); S6 (x); S5 (x); S4 GPO(EEPROM_CS2); + * S3 GPO(EEPROM_CS1); S2 SIOF0_TXD; S1 SIOF0_RXD; S0 SIOF0_SCK; + */ + ctrl_outw(0x0140, PORT_PSCR); /* 00 00 00 01 01 00 00 00 */ + + /* T7 (x); T6 (x); T5 (x); T4 COM1_CTS; + * T3 COM1_RTS; T2 COM1_TXD; T1 COM1_RXD; T0 GPO(WDOG) + */ + ctrl_outw(0x0001, PORT_PTCR); /* 00 00 00 00 00 00 00 01 */ + + /* U7 (x); U6 (x); U5 (x); U4 GPI+(/AC_FAULT); + * U3 GPO(TOUCH_CS); U2 TOUCH_TXD; U1 TOUCH_RXD; U0 TOUCH_SCK; + */ + ctrl_outw(0x0240, PORT_PUCR); /* 00 00 00 10 01 00 00 00 */ + + /* V7 (x); V6 (x); V5 (x); V4 GPO(MID2); + * V3 GPO(MID1); V2 CARD_TxD; V1 CARD_RxD; V0 GPI+(/BAT_FAULT); + */ + ctrl_outw(0x0142, PORT_PVCR); /* 00 00 00 01 01 00 00 10 */ +} + +static void __init mpr2_setup(char **cmdline_p) +{ + __set_io_port_base(0xa0000000); + + /* set Pin Select Register A: + * /PCC_CD1, /PCC_CD2, PCC_BVD1, PCC_BVD2, + * /IOIS16, IRQ4, IRQ5, USB1d_SUSPEND + */ + ctrl_outw(0xAABC, PORT_PSELA); + /* set Pin Select Register B: + * /SCIF0_RTS, /SCIF0_CTS, LCD_VCPWC, + * LCD_VEPWC, IIC_SDA, IIC_SCL, Reserved + */ + ctrl_outw(0x3C00, PORT_PSELB); + /* set Pin Select Register C: + * SIOF1_SCK, SIOF1_RxD, SCIF1_RxD, SCIF1_TxD, Reserved + */ + ctrl_outw(0x0000, PORT_PSELC); + /* set Pin Select Register D: Reserved, SIOF1_TxD, Reserved, SIOF1_MCLK, + * Reserved, SIOF1_SYNC, Reserved, SCIF1_SCK, Reserved + */ + ctrl_outw(0x0000, PORT_PSELD); + /* set USB TxRx Control: Reserved, DRV, Reserved, USB_TRANS, USB_SEL */ + ctrl_outw(0x0101, PORT_UTRCTL); + /* set USB Clock Control: USSCS, USSTB, Reserved (HighByte always A5) */ + ctrl_outw(0xA5C0, PORT_UCLKCR_W); + + setup_chip_select(); + + setup_port_multiplexing(); + + reset_ethernet(); + + printk(KERN_INFO "Magic Panel Release 2 A.%i\n", + CONFIG_SH_MAGIC_PANEL_R2_VERSION); + + if (ethernet_reset_finished() == 0) + printk(KERN_WARNING "Ethernet not ready\n"); +} + +static struct resource smc911x_resources[] = { + [0] = { + .start = 0xa8000000, + .end = 0xabffffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 35, + .end = 35, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc911x_device = { + .name = "smc911x", + .id = -1, + .num_resources = ARRAY_SIZE(smc911x_resources), + .resource = smc911x_resources, +}; + +static struct resource heartbeat_resources[] = { + [0] = { + .start = PA_LED, + .end = PA_LED, + .flags = IORESOURCE_MEM, + }, +}; + +static struct heartbeat_data heartbeat_data = { + .flags = HEARTBEAT_INVERTED, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .dev = { + .platform_data = &heartbeat_data, + }, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + +static struct mtd_partition *parsed_partitions; + +static struct mtd_partition mpr2_partitions[] = { + /* Reserved for bootloader, read-only */ + { + .name = "Bootloader", + .offset = 0x00000000UL, + .size = MPR2_MTD_BOOTLOADER_SIZE, + .mask_flags = MTD_WRITEABLE, + }, + /* Reserved for kernel image */ + { + .name = "Kernel", + .offset = MTDPART_OFS_NXTBLK, + .size = MPR2_MTD_KERNEL_SIZE, + }, + /* Rest is used for Flash FS */ + { + .name = "Flash_FS", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, + } +}; + +static struct physmap_flash_data flash_data = { + .width = 2, +}; + +static struct resource flash_resource = { + .start = 0x00000000, + .end = 0x2000000UL, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device flash_device = { + .name = "physmap-flash", + .id = -1, + .resource = &flash_resource, + .num_resources = 1, + .dev = { + .platform_data = &flash_data, + }, +}; + +static struct mtd_info *flash_mtd; + +static struct map_info mpr2_flash_map = { + .name = "Magic Panel R2 Flash", + .size = 0x2000000UL, + .bankwidth = 2, +}; + +static void __init set_mtd_partitions(void) +{ + int nr_parts = 0; + + simple_map_init(&mpr2_flash_map); + flash_mtd = do_map_probe("cfi_probe", &mpr2_flash_map); + nr_parts = parse_mtd_partitions(flash_mtd, probes, + &parsed_partitions, 0); + /* If there is no partition table, used the hard coded table */ + if (nr_parts <= 0) { + flash_data.parts = mpr2_partitions; + flash_data.nr_parts = ARRAY_SIZE(mpr2_partitions); + } else { + flash_data.nr_parts = nr_parts; + flash_data.parts = parsed_partitions; + } +} + +/* + * Add all resources to the platform_device + */ + +static struct platform_device *mpr2_devices[] __initdata = { + &heartbeat_device, + &smc911x_device, + &flash_device, +}; + + +static int __init mpr2_devices_setup(void) +{ + set_mtd_partitions(); + return platform_add_devices(mpr2_devices, ARRAY_SIZE(mpr2_devices)); +} +device_initcall(mpr2_devices_setup); + +/* + * Initialize IRQ setting + */ +static void __init init_mpr2_IRQ(void) +{ + plat_irq_setup_pins(IRQ_MODE_IRQ); /* install handlers for IRQ0-5 */ + + set_irq_type(32, IRQ_TYPE_LEVEL_LOW); /* IRQ0 CAN1 */ + set_irq_type(33, IRQ_TYPE_LEVEL_LOW); /* IRQ1 CAN2 */ + set_irq_type(34, IRQ_TYPE_LEVEL_LOW); /* IRQ2 CAN3 */ + set_irq_type(35, IRQ_TYPE_LEVEL_LOW); /* IRQ3 SMSC9115 */ + set_irq_type(36, IRQ_TYPE_EDGE_RISING); /* IRQ4 touchscreen */ + set_irq_type(37, IRQ_TYPE_EDGE_FALLING); /* IRQ5 touchscreen */ + + intc_set_priority(32, 13); /* IRQ0 CAN1 */ + intc_set_priority(33, 13); /* IRQ0 CAN2 */ + intc_set_priority(34, 13); /* IRQ0 CAN3 */ + intc_set_priority(35, 6); /* IRQ3 SMSC9115 */ +} + +/* + * The Machine Vector + */ + +static struct sh_machine_vector mv_mpr2 __initmv = { + .mv_name = "mpr2", + .mv_setup = mpr2_setup, + .mv_init_irq = init_mpr2_IRQ, +}; diff --git a/arch/sh/boards/mpc1211/setup.c b/arch/sh/boards/mpc1211/setup.c index 8ce03e00b0a..fede36361dc 100644 --- a/arch/sh/boards/mpc1211/setup.c +++ b/arch/sh/boards/mpc1211/setup.c @@ -285,7 +285,7 @@ static int put_smb_blk(unsigned char *p, int address, int command, int no) static struct resource heartbeat_resources[] = { [0] = { .start = 0xa2000000, - .end = 0xa2000000 + 8 - 1, + .end = 0xa2000000, .flags = IORESOURCE_MEM, }, }; diff --git a/arch/sh/boards/renesas/r7780rp/Makefile b/arch/sh/boards/renesas/r7780rp/Makefile index b1d20afb4eb..dd26182fbf5 100644 --- a/arch/sh/boards/renesas/r7780rp/Makefile +++ b/arch/sh/boards/renesas/r7780rp/Makefile @@ -1,9 +1,10 @@ # # Makefile for the R7780RP-1 specific parts of the kernel # -irqinit-y := irq-r7780rp.o +irqinit-$(CONFIG_SH_R7780MP) := irq-r7780mp.o irqinit-$(CONFIG_SH_R7785RP) := irq-r7785rp.o -obj-y := setup.o irq.o $(irqinit-y) +irqinit-$(CONFIG_SH_R7780RP) := irq-r7780rp.o irq.o +obj-y := setup.o $(irqinit-y) ifneq ($(CONFIG_SH_R7785RP),y) obj-$(CONFIG_PUSH_SWITCH) += psw.o diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c b/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c new file mode 100644 index 00000000000..59b47fe061f --- /dev/null +++ b/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c @@ -0,0 +1,61 @@ +/* + * Renesas Solutions Highlander R7780MP Support. + * + * Copyright (C) 2002 Atom Create Engineering Co., Ltd. + * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2007 Magnus Damm + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <asm/r7780rp.h> + +enum { + UNUSED = 0, + + /* board specific interrupt sources */ + AX88796, /* Ethernet controller */ + CF, /* Compact Flash */ + PSW, /* Push Switch */ + EXT1, /* EXT1n IRQ */ + EXT4, /* EXT4n IRQ */ +}; + +static struct intc_vect vectors[] __initdata = { + INTC_IRQ(CF, IRQ_CF), + INTC_IRQ(PSW, IRQ_PSW), + INTC_IRQ(AX88796, IRQ_AX88796), + INTC_IRQ(EXT1, IRQ_EXT1), + INTC_IRQ(EXT4, IRQ_EXT4), +}; + +static struct intc_mask_reg mask_registers[] __initdata = { + { 0xa4000000, 0, 16, /* IRLMSK */ + { 0, 0, 0, 0, CF, 0, 0, 0, + 0, 0, 0, EXT4, 0, EXT1, PSW, AX88796 } }, +}; + +static unsigned char irl2irq[HL_NR_IRL] __initdata = { + 0, IRQ_CF, 0, 0, + 0, 0, 0, 0, + 0, IRQ_EXT4, 0, IRQ_EXT1, + 0, IRQ_AX88796, IRQ_PSW, +}; + +static DECLARE_INTC_DESC(intc_desc, "r7780mp", vectors, + NULL, NULL, mask_registers, NULL, NULL); + +unsigned char * __init highlander_init_irq_r7780mp(void) +{ + if ((ctrl_inw(0xa4000700) & 0xf000) == 0x2000) { + printk(KERN_INFO "Using r7780mp interrupt controller.\n"); + register_intc_controller(&intc_desc); + return irl2irq; + } + + return NULL; +} diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c b/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c index f5f358746c9..fa4a534cade 100644 --- a/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c +++ b/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c @@ -9,13 +9,15 @@ * for more details. */ #include <linux/init.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/r7780rp.h> -void __init highlander_init_irq(void) +unsigned char * __init highlander_init_irq_r7780rp(void) { int i; for (i = 0; i < 15; i++) make_r7780rp_irq(i); + + return NULL; } diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c b/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c index dd6ec4ce44d..b2c6a84673b 100644 --- a/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c +++ b/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c @@ -1,19 +1,55 @@ /* - * Renesas Solutions Highlander R7780RP-1 Support. + * Renesas Solutions Highlander R7785RP Support. * * Copyright (C) 2002 Atom Create Engineering Co., Ltd. * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2007 Magnus Damm * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. */ #include <linux/init.h> -#include <asm/io.h> +#include <linux/irq.h> +#include <linux/io.h> #include <asm/r7780rp.h> -void __init highlander_init_irq(void) +enum { + UNUSED = 0, + + /* board specific interrupt sources */ + AX88796, /* Ethernet controller */ + CF, /* Compact Flash */ +}; + +static struct intc_vect vectors[] __initdata = { + INTC_IRQ(CF, IRQ_CF), + INTC_IRQ(AX88796, IRQ_AX88796), +}; + +static struct intc_mask_reg mask_registers[] __initdata = { + { 0xa4000010, 0, 16, /* IRLMCR1 */ + { 0, 0, 0, 0, CF, AX88796, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 } }, +}; + +static unsigned char irl2irq[HL_NR_IRL] __initdata = { + 0, IRQ_CF, 0, 0, + 0, 0, 0, 0, + 0, 0, IRQ_AX88796, 0, + 0, 0, 0, +}; + +static DECLARE_INTC_DESC(intc_desc, "r7785rp", vectors, + NULL, NULL, mask_registers, NULL, NULL); + +unsigned char * __init highlander_init_irq_r7785rp(void) { + if ((ctrl_inw(0xa4000158) & 0xf000) != 0x1000) + return NULL; + + printk(KERN_INFO "Using r7785rp interrupt controller.\n"); + ctrl_outw(0x0000, PA_IRLSSR1); /* FPGA IRLSSR1(CF_CD clear) */ /* Setup the FPGA IRL */ @@ -24,6 +60,6 @@ void __init highlander_init_irq(void) ctrl_outw(0x4321, PA_IRLPRE); /* FPGA IRLE */ ctrl_outw(0x0000, PA_IRLPRF); /* FPGA IRLF */ - make_r7780rp_irq(1); /* CF card */ - make_r7780rp_irq(10); /* On-board ethernet */ + register_intc_controller(&intc_desc); + return irl2irq; } diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c index adb529d01ba..afe9de73666 100644 --- a/arch/sh/boards/renesas/r7780rp/setup.c +++ b/arch/sh/boards/renesas/r7780rp/setup.c @@ -19,6 +19,7 @@ #include <asm/machvec.h> #include <asm/r7780rp.h> #include <asm/clock.h> +#include <asm/heartbeat.h> #include <asm/io.h> static struct resource r8a66597_usb_host_resources[] = { @@ -30,8 +31,8 @@ static struct resource r8a66597_usb_host_resources[] = { }, [1] = { .name = "r8a66597_hcd", - .start = 11, /* irq number */ - .end = 11, + .start = IRQ_EXT1, /* irq number */ + .end = IRQ_EXT1, .flags = IORESOURCE_IRQ, }, }; @@ -56,8 +57,8 @@ static struct resource m66592_usb_peripheral_resources[] = { }, [1] = { .name = "m66592_udc", - .start = 9, /* irq number */ - .end = 9, + .start = IRQ_EXT4, /* irq number */ + .end = IRQ_EXT4, .flags = IORESOURCE_IRQ, }, }; @@ -85,11 +86,7 @@ static struct resource cf_ide_resources[] = { .flags = IORESOURCE_MEM, }, [2] = { -#ifdef CONFIG_SH_R7780RP - .start = 4, -#else - .start = 1, -#endif + .start = IRQ_CF, .flags = IORESOURCE_IRQ, }, }; @@ -108,16 +105,23 @@ static struct platform_device cf_ide_device = { }, }; -static unsigned char heartbeat_bit_pos[] = { 2, 1, 0, 3, 6, 5, 4, 7 }; - static struct resource heartbeat_resources[] = { [0] = { .start = PA_OBLED, - .end = PA_OBLED + ARRAY_SIZE(heartbeat_bit_pos) - 1, + .end = PA_OBLED, .flags = IORESOURCE_MEM, }, }; +#ifndef CONFIG_SH_R7785RP +static unsigned char heartbeat_bit_pos[] = { 2, 1, 0, 3, 6, 5, 4, 7 }; + +static struct heartbeat_data heartbeat_data = { + .bit_pos = heartbeat_bit_pos, + .nr_bits = ARRAY_SIZE(heartbeat_bit_pos), +}; +#endif + static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, @@ -125,7 +129,7 @@ static struct platform_device heartbeat_device = { /* R7785RP has a slightly more sensible FPGA.. */ #ifndef CONFIG_SH_R7785RP .dev = { - .platform_data = heartbeat_bit_pos, + .platform_data = &heartbeat_data, }, #endif .num_resources = ARRAY_SIZE(heartbeat_resources), @@ -217,12 +221,50 @@ static void __init highlander_setup(char **cmdline_p) pm_power_off = r7780rp_power_off; } +static unsigned char irl2irq[HL_NR_IRL]; + +int highlander_irq_demux(int irq) +{ + if (irq >= HL_NR_IRL || !irl2irq[irq]) + return irq; + + return irl2irq[irq]; +} + +void __init highlander_init_irq(void) +{ + unsigned char *ucp = NULL; + + do { +#ifdef CONFIG_SH_R7780MP + ucp = highlander_init_irq_r7780mp(); + if (ucp) + break; +#endif +#ifdef CONFIG_SH_R7785RP + ucp = highlander_init_irq_r7785rp(); + if (ucp) + break; +#endif +#ifdef CONFIG_SH_R7780RP + highlander_init_irq_r7780rp(); + ucp = irl2irq; + break; +#endif + } while (0); + + if (ucp) { + plat_irq_setup_pins(IRQ_MODE_IRL3210); + memcpy(irl2irq, ucp, HL_NR_IRL); + } +} + /* * The Machine Vector */ static struct sh_machine_vector mv_highlander __initmv = { .mv_name = "Highlander", - .mv_nr_irqs = 109, .mv_setup = highlander_setup, .mv_init_irq = highlander_init_irq, + .mv_irq_demux = highlander_irq_demux, }; diff --git a/arch/sh/boards/renesas/rts7751r2d/Kconfig b/arch/sh/boards/renesas/rts7751r2d/Kconfig index 7780d1fb13f..8122a9667fc 100644 --- a/arch/sh/boards/renesas/rts7751r2d/Kconfig +++ b/arch/sh/boards/renesas/rts7751r2d/Kconfig @@ -1,11 +1,22 @@ if SH_RTS7751R2D -menu "RTS7751R2D options" +menu "RTS7751R2D Board Revision" -config RTS7751R2D_REV11 - bool "RTS7751R2D Rev. 1.1 board support" +config RTS7751R2D_PLUS + bool "R2D-PLUS" help - Selecting this option will support version rev. 1.1. + Selecting this option will configure the kernel for R2D-PLUS. + + R2D-PLUS is the smaller of the two R2D board versions, equipped + with a single PCI slot. + +config RTS7751R2D_1 + bool "R2D-1" + help + Selecting this option will configure the kernel for R2D-1. + + R2D-1 is the larger of the two R2D board versions, equipped + with two PCI slots. endmenu endif diff --git a/arch/sh/boards/renesas/rts7751r2d/irq.c b/arch/sh/boards/renesas/rts7751r2d/irq.c index 0bae9041ace..7cc2813adfe 100644 --- a/arch/sh/boards/renesas/rts7751r2d/irq.c +++ b/arch/sh/boards/renesas/rts7751r2d/irq.c @@ -1,84 +1,159 @@ /* * linux/arch/sh/boards/renesas/rts7751r2d/irq.c * + * Copyright (C) 2007 Magnus Damm * Copyright (C) 2000 Kazumoto Kojima * - * Renesas Technology Sales RTS7751R2D Support. + * Renesas Technology Sales RTS7751R2D Support, R2D-PLUS and R2D-1. * * Modified for RTS7751R2D by * Atom Create Engineering Co., Ltd. 2002. */ #include <linux/init.h> -#include <linux/interrupt.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <asm/voyagergx.h> #include <asm/rts7751r2d.h> -#if defined(CONFIG_RTS7751R2D_REV11) -static int mask_pos[] = {11, 9, 8, 12, 10, 6, 5, 4, 7, 14, 13, 0, 0, 0, 0}; -#else -static int mask_pos[] = {6, 11, 9, 8, 12, 10, 5, 4, 7, 14, 13, 0, 0, 0, 0}; -#endif +#define R2D_NR_IRL 13 -extern int voyagergx_irq_demux(int irq); -extern void setup_voyagergx_irq(void); +enum { + UNUSED = 0, -static void enable_rts7751r2d_irq(unsigned int irq) -{ - /* Set priority in IPR back to original value */ - ctrl_outw(ctrl_inw(IRLCNTR1) | (1 << mask_pos[irq]), IRLCNTR1); -} + /* board specific interrupt sources (R2D-1 and R2D-PLUS) */ + EXT, /* EXT_INT0-3 */ + RTC_T, RTC_A, /* Real Time Clock */ + AX88796, /* Ethernet controller (R2D-1 board) */ + KEY, /* Key input (R2D-PLUS board) */ + SDCARD, /* SD Card */ + CF_CD, CF_IDE, /* CF Card Detect + CF IDE */ + SM501, /* SM501 aka Voyager */ + PCI_INTD_RTL8139, /* Ethernet controller */ + PCI_INTC_PCI1520, /* Cardbus/PCMCIA bridge */ + PCI_INTB_RTL8139, /* Ethernet controller with HUB (R2D-PLUS board) */ + PCI_INTB_SLOT, /* PCI Slot 3.3v (R2D-1 board) */ + PCI_INTA_SLOT, /* PCI Slot 3.3v */ + TP, /* Touch Panel */ +}; -static void disable_rts7751r2d_irq(unsigned int irq) -{ - /* Set the priority in IPR to 0 */ - ctrl_outw(ctrl_inw(IRLCNTR1) & (0xffff ^ (1 << mask_pos[irq])), - IRLCNTR1); -} +#ifdef CONFIG_RTS7751R2D_1 + +/* Vectors for R2D-1 */ +static struct intc_vect vectors_r2d_1[] __initdata = { + INTC_IRQ(EXT, IRQ_EXT), + INTC_IRQ(RTC_T, IRQ_RTC_T), INTC_IRQ(RTC_A, IRQ_RTC_A), + INTC_IRQ(AX88796, IRQ_AX88796), INTC_IRQ(SDCARD, IRQ_SDCARD), + INTC_IRQ(CF_CD, IRQ_CF_CD), INTC_IRQ(CF_IDE, IRQ_CF_IDE), /* ng */ + INTC_IRQ(SM501, IRQ_VOYAGER), + INTC_IRQ(PCI_INTD_RTL8139, IRQ_PCI_INTD), + INTC_IRQ(PCI_INTC_PCI1520, IRQ_PCI_INTC), + INTC_IRQ(PCI_INTB_SLOT, IRQ_PCI_INTB), + INTC_IRQ(PCI_INTA_SLOT, IRQ_PCI_INTA), + INTC_IRQ(TP, IRQ_TP), +}; + +/* IRLMSK mask register layout for R2D-1 */ +static struct intc_mask_reg mask_registers_r2d_1[] __initdata = { + { 0xa4000000, 0, 16, /* IRLMSK */ + { TP, PCI_INTA_SLOT, PCI_INTB_SLOT, + PCI_INTC_PCI1520, PCI_INTD_RTL8139, + SM501, CF_IDE, CF_CD, SDCARD, AX88796, + RTC_A, RTC_T, 0, 0, 0, EXT } }, +}; + +/* IRLn to IRQ table for R2D-1 */ +static unsigned char irl2irq_r2d_1[R2D_NR_IRL] __initdata = { + IRQ_PCI_INTD, IRQ_CF_IDE, IRQ_CF_CD, IRQ_PCI_INTC, + IRQ_VOYAGER, IRQ_AX88796, IRQ_RTC_A, IRQ_RTC_T, + IRQ_SDCARD, IRQ_PCI_INTA, IRQ_PCI_INTB, IRQ_EXT, + IRQ_TP, +}; + +static DECLARE_INTC_DESC(intc_desc_r2d_1, "r2d-1", vectors_r2d_1, + NULL, NULL, mask_registers_r2d_1, NULL, NULL); + +#endif /* CONFIG_RTS7751R2D_1 */ + +#ifdef CONFIG_RTS7751R2D_PLUS + +/* Vectors for R2D-PLUS */ +static struct intc_vect vectors_r2d_plus[] __initdata = { + INTC_IRQ(EXT, IRQ_EXT), + INTC_IRQ(RTC_T, IRQ_RTC_T), INTC_IRQ(RTC_A, IRQ_RTC_A), + INTC_IRQ(KEY, IRQ_KEY), INTC_IRQ(SDCARD, IRQ_SDCARD), + INTC_IRQ(CF_CD, IRQ_CF_CD), INTC_IRQ(CF_IDE, IRQ_CF_IDE), + INTC_IRQ(SM501, IRQ_VOYAGER), + INTC_IRQ(PCI_INTD_RTL8139, IRQ_PCI_INTD), + INTC_IRQ(PCI_INTC_PCI1520, IRQ_PCI_INTC), + INTC_IRQ(PCI_INTB_RTL8139, IRQ_PCI_INTB), + INTC_IRQ(PCI_INTA_SLOT, IRQ_PCI_INTA), + INTC_IRQ(TP, IRQ_TP), +}; + +/* IRLMSK mask register layout for R2D-PLUS */ +static struct intc_mask_reg mask_registers_r2d_plus[] __initdata = { + { 0xa4000000, 0, 16, /* IRLMSK */ + { TP, PCI_INTA_SLOT, PCI_INTB_RTL8139, + PCI_INTC_PCI1520, PCI_INTD_RTL8139, + SM501, CF_IDE, CF_CD, SDCARD, KEY, + RTC_A, RTC_T, 0, 0, 0, EXT } }, +}; + +/* IRLn to IRQ table for R2D-PLUS */ +static unsigned char irl2irq_r2d_plus[R2D_NR_IRL] __initdata = { + IRQ_PCI_INTD, IRQ_CF_IDE, IRQ_CF_CD, IRQ_PCI_INTC, + IRQ_VOYAGER, IRQ_KEY, IRQ_RTC_A, IRQ_RTC_T, + IRQ_SDCARD, IRQ_PCI_INTA, IRQ_PCI_INTB, IRQ_EXT, + IRQ_TP, +}; + +static DECLARE_INTC_DESC(intc_desc_r2d_plus, "r2d-plus", vectors_r2d_plus, + NULL, NULL, mask_registers_r2d_plus, NULL, NULL); + +#endif /* CONFIG_RTS7751R2D_PLUS */ + +static unsigned char irl2irq[R2D_NR_IRL]; int rts7751r2d_irq_demux(int irq) { - return voyagergx_irq_demux(irq); -} + if (irq >= R2D_NR_IRL || !irl2irq[irq]) + return irq; -static struct irq_chip rts7751r2d_irq_chip __read_mostly = { - .name = "rts7751r2d", - .mask = disable_rts7751r2d_irq, - .unmask = enable_rts7751r2d_irq, - .mask_ack = disable_rts7751r2d_irq, -}; + return irl2irq[irq]; +} /* * Initialize IRQ setting */ void __init init_rts7751r2d_IRQ(void) { - int i; - - /* IRL0=KEY Input - * IRL1=Ethernet - * IRL2=CF Card - * IRL3=CF Card Insert - * IRL4=PCMCIA - * IRL5=VOYAGER - * IRL6=RTC Alarm - * IRL7=RTC Timer - * IRL8=SD Card - * IRL9=PCI Slot #1 - * IRL10=PCI Slot #2 - * IRL11=Extention #0 - * IRL12=Extention #1 - * IRL13=Extention #2 - * IRL14=Extention #3 - */ - - for (i=0; i<15; i++) { - disable_irq_nosync(i); - set_irq_chip_and_handler_name(i, &rts7751r2d_irq_chip, - handle_level_irq, "level"); - enable_rts7751r2d_irq(i); + struct intc_desc *d; + + switch (ctrl_inw(PA_VERREG) & 0xf0) { +#ifdef CONFIG_RTS7751R2D_PLUS + case 0x10: + printk(KERN_INFO "Using R2D-PLUS interrupt controller.\n"); + d = &intc_desc_r2d_plus; + memcpy(irl2irq, irl2irq_r2d_plus, R2D_NR_IRL); + break; +#endif +#ifdef CONFIG_RTS7751R2D_1 + case 0x00: /* according to manual */ + case 0x30: /* in reality */ + printk(KERN_INFO "Using R2D-1 interrupt controller.\n"); + d = &intc_desc_r2d_1; + memcpy(irl2irq, irl2irq_r2d_1, R2D_NR_IRL); + break; +#endif + default: + printk(KERN_INFO "Unknown R2D interrupt controller 0x%04x\n", + ctrl_inw(PA_VERREG)); + return; } + register_intc_controller(d); +#ifdef CONFIG_MFD_SM501 setup_voyagergx_irq(); +#endif } diff --git a/arch/sh/boards/renesas/rts7751r2d/setup.c b/arch/sh/boards/renesas/rts7751r2d/setup.c index 6f7029d3324..37f2c0b447f 100644 --- a/arch/sh/boards/renesas/rts7751r2d/setup.c +++ b/arch/sh/boards/renesas/rts7751r2d/setup.c @@ -45,20 +45,16 @@ static void __init voyagergx_serial_init(void) static struct resource cf_ide_resources[] = { [0] = { .start = PA_AREA5_IO + 0x1000, - .end = PA_AREA5_IO + 0x1000 + 0x08 - 1, + .end = PA_AREA5_IO + 0x1000 + 0x10 - 0x2, .flags = IORESOURCE_MEM, }, [1] = { .start = PA_AREA5_IO + 0x80c, - .end = PA_AREA5_IO + 0x80c + 0x16 - 1, + .end = PA_AREA5_IO + 0x80c, .flags = IORESOURCE_MEM, }, [2] = { -#ifdef CONFIG_RTS7751R2D_REV11 - .start = 1, -#else - .start = 2, -#endif + .start = IRQ_CF_IDE, .flags = IORESOURCE_IRQ, }, }; @@ -77,12 +73,28 @@ static struct platform_device cf_ide_device = { }, }; +static struct resource heartbeat_resources[] = { + [0] = { + .start = PA_OUTPORT, + .end = PA_OUTPORT, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + +#ifdef CONFIG_MFD_SM501 static struct plat_serial8250_port uart_platform_data[] = { { .membase = (void __iomem *)VOYAGER_UART_BASE, .mapbase = VOYAGER_UART_BASE, .iotype = UPIO_MEM, - .irq = VOYAGER_UART0_IRQ, + .irq = IRQ_SM501_U0, .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, .regshift = 2, .uartclk = (9600 * 16), @@ -98,21 +110,6 @@ static struct platform_device uart_device = { }, }; -static struct resource heartbeat_resources[] = { - [0] = { - .start = PA_OUTPORT, - .end = PA_OUTPORT + 8 - 1, - .flags = IORESOURCE_MEM, - }, -}; - -static struct platform_device heartbeat_device = { - .name = "heartbeat", - .id = -1, - .num_resources = ARRAY_SIZE(heartbeat_resources), - .resource = heartbeat_resources, -}; - static struct resource sm501_resources[] = { [0] = { .start = 0x10000000, @@ -125,7 +122,7 @@ static struct resource sm501_resources[] = { .flags = IORESOURCE_MEM, }, [2] = { - .start = 32, + .start = IRQ_SM501_CV, .flags = IORESOURCE_IRQ, }, }; @@ -137,22 +134,19 @@ static struct platform_device sm501_device = { .resource = sm501_resources, }; +#endif /* CONFIG_MFD_SM501 */ + static struct platform_device *rts7751r2d_devices[] __initdata = { +#ifdef CONFIG_MFD_SM501 &uart_device, - &heartbeat_device, &sm501_device, +#endif + &cf_ide_device, + &heartbeat_device, }; static int __init rts7751r2d_devices_setup(void) { - int ret; - - if (ctrl_inw(PA_BVERREG) == 0x10) { /* only working on R2D-PLUS */ - ret = platform_device_register(&cf_ide_device); - if (ret) - return ret; - } - return platform_add_devices(rts7751r2d_devices, ARRAY_SIZE(rts7751r2d_devices)); } @@ -163,6 +157,34 @@ static void rts7751r2d_power_off(void) ctrl_outw(0x0001, PA_POWOFF); } +static inline unsigned char is_ide_ioaddr(unsigned long addr) +{ + return ((cf_ide_resources[0].start <= addr && + addr <= cf_ide_resources[0].end) || + (cf_ide_resources[1].start <= addr && + addr <= cf_ide_resources[1].end)); +} + +void rts7751r2d_writeb(u8 b, void __iomem *addr) +{ + unsigned long tmp = (unsigned long __force)addr; + + if (is_ide_ioaddr(tmp)) + ctrl_outw((u16)b, tmp); + else + ctrl_outb(b, tmp); +} + +u8 rts7751r2d_readb(void __iomem *addr) +{ + unsigned long tmp = (unsigned long __force)addr; + + if (is_ide_ioaddr(tmp)) + return ctrl_inw(tmp) & 0xff; + else + return ctrl_inb(tmp); +} + /* * Initialize the board */ @@ -187,12 +209,11 @@ static void __init rts7751r2d_setup(char **cmdline_p) static struct sh_machine_vector mv_rts7751r2d __initmv = { .mv_name = "RTS7751R2D", .mv_setup = rts7751r2d_setup, - .mv_nr_irqs = 72, - .mv_init_irq = init_rts7751r2d_IRQ, .mv_irq_demux = rts7751r2d_irq_demux, - -#ifdef CONFIG_USB_SM501 + .mv_writeb = rts7751r2d_writeb, + .mv_readb = rts7751r2d_readb, +#if defined(CONFIG_MFD_SM501) && defined(CONFIG_USB_OHCI_HCD) .mv_consistent_alloc = voyagergx_consistent_alloc, .mv_consistent_free = voyagergx_consistent_free, #endif diff --git a/arch/sh/boards/renesas/x3proto/Makefile b/arch/sh/boards/renesas/x3proto/Makefile new file mode 100644 index 00000000000..983e4551fec --- /dev/null +++ b/arch/sh/boards/renesas/x3proto/Makefile @@ -0,0 +1 @@ +obj-y += setup.o ilsel.o diff --git a/arch/sh/boards/renesas/x3proto/ilsel.c b/arch/sh/boards/renesas/x3proto/ilsel.c new file mode 100644 index 00000000000..6d4454fef97 --- /dev/null +++ b/arch/sh/boards/renesas/x3proto/ilsel.c @@ -0,0 +1,151 @@ +/* + * arch/sh/boards/renesas/x3proto/ilsel.c + * + * Helper routines for SH-X3 proto board ILSEL. + * + * Copyright (C) 2007 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/bitmap.h> +#include <linux/io.h> +#include <asm/ilsel.h> + +/* + * ILSEL is split across: + * + * ILSEL0 - 0xb8100004 [ Levels 1 - 4 ] + * ILSEL1 - 0xb8100006 [ Levels 5 - 8 ] + * ILSEL2 - 0xb8100008 [ Levels 9 - 12 ] + * ILSEL3 - 0xb810000a [ Levels 13 - 15 ] + * + * With each level being relative to an ilsel_source_t. + */ +#define ILSEL_BASE 0xb8100004 +#define ILSEL_LEVELS 15 + +/* + * ILSEL level map, in descending order from the highest level down. + * + * Supported levels are 1 - 15 spread across ILSEL0 - ILSEL4, mapping + * directly to IRLs. As the IRQs are numbered in reverse order relative + * to the interrupt level, the level map is carefully managed to ensure a + * 1:1 mapping between the bit position and the IRQ number. + * + * This careful constructions allows ilsel_enable*() to be referenced + * directly for hooking up an ILSEL set and getting back an IRQ which can + * subsequently be used for internal accounting in the (optional) disable + * path. + */ +static unsigned long ilsel_level_map; + +static inline unsigned int ilsel_offset(unsigned int bit) +{ + return ILSEL_LEVELS - bit - 1; +} + +static inline unsigned long mk_ilsel_addr(unsigned int bit) +{ + return ILSEL_BASE + ((ilsel_offset(bit) >> 1) & ~0x1); +} + +static inline unsigned int mk_ilsel_shift(unsigned int bit) +{ + return (ilsel_offset(bit) & 0x3) << 2; +} + +static void __ilsel_enable(ilsel_source_t set, unsigned int bit) +{ + unsigned int tmp, shift; + unsigned long addr; + + addr = mk_ilsel_addr(bit); + shift = mk_ilsel_shift(bit); + + pr_debug("%s: bit#%d: addr - 0x%08lx (shift %d, set %d)\n", + __FUNCTION__, bit, addr, shift, set); + + tmp = ctrl_inw(addr); + tmp &= ~(0xf << shift); + tmp |= set << shift; + ctrl_outw(tmp, addr); +} + +/** + * ilsel_enable - Enable an ILSEL set. + * @set: ILSEL source (see ilsel_source_t enum in include/asm-sh/ilsel.h). + * + * Enables a given non-aliased ILSEL source (<= ILSEL_KEY) at the highest + * available interrupt level. Callers should take care to order callsites + * noting descending interrupt levels. Aliasing FPGA and external board + * IRQs need to use ilsel_enable_fixed(). + * + * The return value is an IRQ number that can later be taken down with + * ilsel_disable(). + */ +int ilsel_enable(ilsel_source_t set) +{ + unsigned int bit; + + /* Aliased sources must use ilsel_enable_fixed() */ + BUG_ON(set > ILSEL_KEY); + + do { + bit = find_first_zero_bit(&ilsel_level_map, ILSEL_LEVELS); + } while (test_and_set_bit(bit, &ilsel_level_map)); + + __ilsel_enable(set, bit); + + return bit; +} +EXPORT_SYMBOL_GPL(ilsel_enable); + +/** + * ilsel_enable_fixed - Enable an ILSEL set at a fixed interrupt level + * @set: ILSEL source (see ilsel_source_t enum in include/asm-sh/ilsel.h). + * @level: Interrupt level (1 - 15) + * + * Enables a given ILSEL source at a fixed interrupt level. Necessary + * both for level reservation as well as for aliased sources that only + * exist on special ILSEL#s. + * + * Returns an IRQ number (as ilsel_enable()). + */ +int ilsel_enable_fixed(ilsel_source_t set, unsigned int level) +{ + unsigned int bit = ilsel_offset(level - 1); + + if (test_and_set_bit(bit, &ilsel_level_map)) + return -EBUSY; + + __ilsel_enable(set, bit); + + return bit; +} +EXPORT_SYMBOL_GPL(ilsel_enable_fixed); + +/** + * ilsel_disable - Disable an ILSEL set + * @irq: Bit position for ILSEL set value (retval from enable routines) + * + * Disable a previously enabled ILSEL set. + */ +void ilsel_disable(unsigned int irq) +{ + unsigned long addr; + unsigned int tmp; + + addr = mk_ilsel_addr(irq); + + tmp = ctrl_inw(addr); + tmp &= ~(0xf << mk_ilsel_shift(irq)); + ctrl_outw(tmp, addr); + + clear_bit(irq, &ilsel_level_map); +} +EXPORT_SYMBOL_GPL(ilsel_disable); diff --git a/arch/sh/boards/renesas/x3proto/setup.c b/arch/sh/boards/renesas/x3proto/setup.c new file mode 100644 index 00000000000..abc5b6d418f --- /dev/null +++ b/arch/sh/boards/renesas/x3proto/setup.c @@ -0,0 +1,136 @@ +/* + * arch/sh/boards/renesas/x3proto/setup.c + * + * Renesas SH-X3 Prototype Board Support. + * + * Copyright (C) 2007 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/io.h> +#include <asm/ilsel.h> + +static struct resource heartbeat_resources[] = { + [0] = { + .start = 0xb8140020, + .end = 0xb8140020, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + +static struct resource smc91x_resources[] = { + [0] = { + .start = 0x18000300, + .end = 0x18000300 + 0x10 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + /* Filled in by ilsel */ + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = -1, + .resource = smc91x_resources, + .num_resources = ARRAY_SIZE(smc91x_resources), +}; + +static struct resource r8a66597_usb_host_resources[] = { + [0] = { + .name = "r8a66597_hcd", + .start = 0x18040000, + .end = 0x18080000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "r8a66597_hcd", + /* Filled in by ilsel */ + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device r8a66597_usb_host_device = { + .name = "r8a66597_hcd", + .id = -1, + .dev = { + .dma_mask = NULL, /* don't use dma */ + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(r8a66597_usb_host_resources), + .resource = r8a66597_usb_host_resources, +}; + +static struct resource m66592_usb_peripheral_resources[] = { + [0] = { + .name = "m66592_udc", + .start = 0x18080000, + .end = 0x180c0000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "m66592_udc", + /* Filled in by ilsel */ + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device m66592_usb_peripheral_device = { + .name = "m66592_udc", + .id = -1, + .dev = { + .dma_mask = NULL, /* don't use dma */ + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(m66592_usb_peripheral_resources), + .resource = m66592_usb_peripheral_resources, +}; + +static struct platform_device *x3proto_devices[] __initdata = { + &heartbeat_device, + &smc91x_device, + &r8a66597_usb_host_device, + &m66592_usb_peripheral_device, +}; + +static int __init x3proto_devices_setup(void) +{ + r8a66597_usb_host_resources[1].start = + r8a66597_usb_host_resources[1].end = ilsel_enable(ILSEL_USBH_I); + + m66592_usb_peripheral_resources[1].start = + m66592_usb_peripheral_resources[1].end = ilsel_enable(ILSEL_USBP_I); + + smc91x_resources[1].start = + smc91x_resources[1].end = ilsel_enable(ILSEL_LAN); + + return platform_add_devices(x3proto_devices, + ARRAY_SIZE(x3proto_devices)); +} +device_initcall(x3proto_devices_setup); + +static void __init x3proto_init_irq(void) +{ + plat_irq_setup_pins(IRQ_MODE_IRL3210); + + /* Set ICR0.LVLMODE */ + ctrl_outl(ctrl_inl(0xfe410000) | (1 << 21), 0xfe410000); +} + +static struct sh_machine_vector mv_x3proto __initmv = { + .mv_name = "x3proto", + .mv_init_irq = x3proto_init_irq, +}; diff --git a/arch/sh/boards/se/7206/io.c b/arch/sh/boards/se/7206/io.c index b557273e0cb..1308e618e04 100644 --- a/arch/sh/boards/se/7206/io.c +++ b/arch/sh/boards/se/7206/io.c @@ -26,22 +26,24 @@ static inline void delay(void) static inline volatile __u16 * port2adr(unsigned int port) { - if (port >= 0x2000) + if (port >= 0x2000 && port < 0x2020) return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000)); - else if (port >= 0x300 || port < 0x310) + else if (port >= 0x300 && port < 0x310) return (volatile __u16 *) (PA_SMSC + (port - 0x300)); + + return (volatile __u16 *)port; } unsigned char se7206_inb(unsigned long port) { - return (*port2adr(port))&0xff; + return (*port2adr(port)) & 0xff; } unsigned char se7206_inb_p(unsigned long port) { unsigned long v; - v = (*port2adr(port))&0xff; + v = (*port2adr(port)) & 0xff; delay(); return v; } @@ -51,12 +53,6 @@ unsigned short se7206_inw(unsigned long port) return *port2adr(port);; } -unsigned int se7206_inl(unsigned long port) -{ - maybebadio(port); - return 0; -} - void se7206_outb(unsigned char value, unsigned long port) { *(port2adr(port)) = value; @@ -73,11 +69,6 @@ void se7206_outw(unsigned short value, unsigned long port) *port2adr(port) = value; } -void se7206_outl(unsigned int value, unsigned long port) -{ - maybebadio(port); -} - void se7206_insb(unsigned long port, void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); @@ -95,11 +86,6 @@ void se7206_insw(unsigned long port, void *addr, unsigned long count) *ap++ = *p; } -void se7206_insl(unsigned long port, void *addr, unsigned long count) -{ - maybebadio(port); -} - void se7206_outsb(unsigned long port, const void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); @@ -116,8 +102,3 @@ void se7206_outsw(unsigned long port, const void *addr, unsigned long count) while (count--) *p = *ap++; } - -void se7206_outsl(unsigned long port, const void *addr, unsigned long count) -{ - maybebadio(port); -} diff --git a/arch/sh/boards/se/7206/setup.c b/arch/sh/boards/se/7206/setup.c index a074b62505e..5b3ee089d91 100644 --- a/arch/sh/boards/se/7206/setup.c +++ b/arch/sh/boards/se/7206/setup.c @@ -6,14 +6,13 @@ * Copyright (C) 2007 Paul Mundt * * Hitachi 7206 SolutionEngine Support. - * */ - #include <linux/init.h> #include <linux/platform_device.h> #include <asm/se7206.h> #include <asm/io.h> #include <asm/machvec.h> +#include <asm/heartbeat.h> static struct resource smc91x_resources[] = { [0] = { @@ -37,10 +36,16 @@ static struct platform_device smc91x_device = { static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 }; +static struct heartbeat_data heartbeat_data = { + .bit_pos = heartbeat_bit_pos, + .nr_bits = ARRAY_SIZE(heartbeat_bit_pos), + .regsize = 32, +}; + static struct resource heartbeat_resources[] = { [0] = { .start = PA_LED, - .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1, + .end = PA_LED, .flags = IORESOURCE_MEM, }, }; @@ -49,7 +54,7 @@ static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, .dev = { - .platform_data = heartbeat_bit_pos, + .platform_data = &heartbeat_data, }, .num_resources = ARRAY_SIZE(heartbeat_resources), .resource = heartbeat_resources, @@ -75,24 +80,18 @@ static struct sh_machine_vector mv_se __initmv = { .mv_nr_irqs = 256, .mv_inb = se7206_inb, .mv_inw = se7206_inw, - .mv_inl = se7206_inl, .mv_outb = se7206_outb, .mv_outw = se7206_outw, - .mv_outl = se7206_outl, .mv_inb_p = se7206_inb_p, .mv_inw_p = se7206_inw, - .mv_inl_p = se7206_inl, .mv_outb_p = se7206_outb_p, .mv_outw_p = se7206_outw, - .mv_outl_p = se7206_outl, .mv_insb = se7206_insb, .mv_insw = se7206_insw, - .mv_insl = se7206_insl, .mv_outsb = se7206_outsb, .mv_outsw = se7206_outsw, - .mv_outsl = se7206_outsl, .mv_init_irq = init_se7206_IRQ, }; diff --git a/arch/sh/boards/se/7343/irq.c b/arch/sh/boards/se/7343/irq.c index 360153ecc55..763f6deba81 100644 --- a/arch/sh/boards/se/7343/irq.c +++ b/arch/sh/boards/se/7343/irq.c @@ -99,8 +99,11 @@ shmse_irq_demux(int irq) * * We configure IRQ5 as a cascade IRQ. */ -static struct irqaction irq5 = { no_action, 0, CPU_MASK_NONE, "IRQ5-cascade", - NULL, NULL}; +static struct irqaction irq5 = { + .handler = no_action, + .mask = CPU_MASK_NONE, + .name = "IRQ5-cascade", +}; static struct ipr_data se7343_irq5_ipr_map[] = { { IRQ5_IRQ, IRQ5_IPR_ADDR+2, IRQ5_IPR_POS, IRQ5_PRIORITY }, diff --git a/arch/sh/boards/se/7343/setup.c b/arch/sh/boards/se/7343/setup.c index 8fec155e2ff..c9431b3a051 100644 --- a/arch/sh/boards/se/7343/setup.c +++ b/arch/sh/boards/se/7343/setup.c @@ -33,7 +33,7 @@ static struct platform_device smc91x_device = { static struct resource heartbeat_resources[] = { [0] = { .start = PA_LED, - .end = PA_LED + 8 - 1, + .end = PA_LED, .flags = IORESOURCE_MEM, }, }; diff --git a/arch/sh/boards/se/770x/setup.c b/arch/sh/boards/se/770x/setup.c index 2962da148f3..d07a3368f54 100644 --- a/arch/sh/boards/se/770x/setup.c +++ b/arch/sh/boards/se/770x/setup.c @@ -12,6 +12,7 @@ #include <asm/se.h> #include <asm/io.h> #include <asm/smc37c93x.h> +#include <asm/heartbeat.h> void init_se_IRQ(void); @@ -90,10 +91,15 @@ static struct platform_device cf_ide_device = { static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 }; +static struct heartbeat_data heartbeat_data = { + .bit_pos = heartbeat_bit_pos, + .nr_bits = ARRAY_SIZE(heartbeat_bit_pos), +}; + static struct resource heartbeat_resources[] = { [0] = { .start = PA_LED, - .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1, + .end = PA_LED, .flags = IORESOURCE_MEM, }, }; @@ -102,7 +108,7 @@ static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, .dev = { - .platform_data = heartbeat_bit_pos, + .platform_data = &heartbeat_data, }, .num_resources = ARRAY_SIZE(heartbeat_resources), .resource = heartbeat_resources, diff --git a/arch/sh/boards/se/7722/setup.c b/arch/sh/boards/se/7722/setup.c index 495fc7e2b60..03b63457e17 100644 --- a/arch/sh/boards/se/7722/setup.c +++ b/arch/sh/boards/se/7722/setup.c @@ -18,12 +18,10 @@ #include <asm/io.h> /* Heartbeat */ -static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - static struct resource heartbeat_resources[] = { [0] = { .start = PA_LED, - .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1, + .end = PA_LED, .flags = IORESOURCE_MEM, }, }; @@ -31,9 +29,6 @@ static struct resource heartbeat_resources[] = { static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, - .dev = { - .platform_data = heartbeat_bit_pos, - }, .num_resources = ARRAY_SIZE(heartbeat_resources), .resource = heartbeat_resources, }; @@ -109,7 +104,7 @@ static void __init se7722_setup(char **cmdline_p) ctrl_outl(0x00051001, MSTPCR0); ctrl_outl(0x00000000, MSTPCR1); /* KEYSC, VOU, BEU, CEU, VEU, VPU, LCDC */ - ctrl_outl(0xffffbfC0, MSTPCR2); + ctrl_outl(0xffffbfC0, MSTPCR2); ctrl_outw(0x0000, PORT_PECR); /* PORT E 1 = IRQ5 ,E 0 = BS */ ctrl_outw(0x1000, PORT_PJCR); /* PORT J 1 = IRQ1,J 0 =IRQ0 */ diff --git a/arch/sh/boards/se/7751/setup.c b/arch/sh/boards/se/7751/setup.c index 7873d07e40c..deefbfd9259 100644 --- a/arch/sh/boards/se/7751/setup.c +++ b/arch/sh/boards/se/7751/setup.c @@ -13,13 +13,19 @@ #include <asm/machvec.h> #include <asm/se7751.h> #include <asm/io.h> +#include <asm/heartbeat.h> static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 }; +static struct heartbeat_data heartbeat_data = { + .bit_pos = heartbeat_bit_pos, + .nr_bits = ARRAY_SIZE(heartbeat_bit_pos), +}; + static struct resource heartbeat_resources[] = { [0] = { .start = PA_LED, - .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1, + .end = PA_LED, .flags = IORESOURCE_MEM, }, }; @@ -28,14 +34,13 @@ static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, .dev = { - .platform_data = heartbeat_bit_pos, + .platform_data = &heartbeat_data, }, .num_resources = ARRAY_SIZE(heartbeat_resources), .resource = heartbeat_resources, }; static struct platform_device *se7751_devices[] __initdata = { - &smc91x_device, &heartbeat_device, }; diff --git a/arch/sh/boards/se/7780/irq.c b/arch/sh/boards/se/7780/irq.c index 87491474600..6bd70da6bb4 100644 --- a/arch/sh/boards/se/7780/irq.c +++ b/arch/sh/boards/se/7780/irq.c @@ -16,32 +16,6 @@ #include <asm/io.h> #include <asm/se7780.h> -static struct intc2_data intc2_irq_table[] = { - { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT1 */ - { 4, 0, 30, 0, 30, 3 }, /* daughter board EXTINT2 */ - { 6, 0, 29, 0, 29, 3 }, /* daughter board EXTINT3 */ - { 8, 0, 28, 0, 28, 3 }, /* SMC 91C111 (LAN) */ - { 10, 0, 27, 0, 27, 3 }, /* daughter board EXTINT4 */ - { 4, 0, 30, 0, 30, 3 }, /* daughter board EXTINT5 */ - { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT6 */ - { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT7 */ - { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT8 */ - { 0 , 0, 24, 0, 24, 3 }, /* SM501 */ -}; - -static struct intc2_desc intc2_irq_desc __read_mostly = { - .prio_base = 0, /* N/A */ - .msk_base = 0xffd00044, - .mskclr_base = 0xffd00064, - - .intc2_data = intc2_irq_table, - .nr_irqs = ARRAY_SIZE(intc2_irq_table), - - .chip = { - .name = "INTC2-se7780", - }, -}; - /* * Initialize IRQ setting */ @@ -68,5 +42,5 @@ void __init init_se7780_IRQ(void) /* FPGA + 0x0A */ ctrl_outw((IRQPIN_PCCPW << IRQPOS_PCCPW), FPGA_INTSEL3); - register_intc2_controller(&intc2_irq_desc); + plat_irq_setup_pins(IRQ_MODE_IRQ); /* install handlers for IRQ0-7 */ } diff --git a/arch/sh/boards/se/7780/setup.c b/arch/sh/boards/se/7780/setup.c index 723f2fd4d55..76e53b26a80 100644 --- a/arch/sh/boards/se/7780/setup.c +++ b/arch/sh/boards/se/7780/setup.c @@ -16,12 +16,10 @@ #include <asm/io.h> /* Heartbeat */ -static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - static struct resource heartbeat_resources[] = { [0] = { .start = PA_LED, - .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1, + .end = PA_LED, .flags = IORESOURCE_MEM, }, }; @@ -29,9 +27,6 @@ static struct resource heartbeat_resources[] = { static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, - .dev = { - .platform_data = heartbeat_bit_pos, - }, .num_resources = ARRAY_SIZE(heartbeat_resources), .resource = heartbeat_resources, }; diff --git a/arch/sh/boards/sh03/setup.c b/arch/sh/boards/sh03/setup.c index 9c031a8c0a1..934ac4f1c48 100644 --- a/arch/sh/boards/sh03/setup.c +++ b/arch/sh/boards/sh03/setup.c @@ -15,33 +15,9 @@ #include <asm/sh03/sh03.h> #include <asm/addrspace.h> -static struct ipr_data ipr_irq_table[] = { - { IRL0_IRQ, 0, IRL0_IPR_POS, IRL0_PRIORITY }, - { IRL1_IRQ, 0, IRL1_IPR_POS, IRL1_PRIORITY }, - { IRL2_IRQ, 0, IRL2_IPR_POS, IRL2_PRIORITY }, - { IRL3_IRQ, 0, IRL3_IPR_POS, IRL3_PRIORITY }, -}; - -static unsigned long ipr_offsets[] = { - INTC_IPRD, -}; - -static struct ipr_desc ipr_irq_desc = { - .ipr_offsets = ipr_offsets, - .nr_offsets = ARRAY_SIZE(ipr_offsets), - - .ipr_data = ipr_irq_table, - .nr_irqs = ARRAY_SIZE(ipr_irq_table), - - .chip = { - .name = "IPR-sh03", - }, -}; - static void __init init_sh03_IRQ(void) { - ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); - register_ipr_controller(&ipr_irq_desc); + plat_irq_setup_pins(IRQ_MODE_IRQ); } extern void *cf_io_base; @@ -68,7 +44,7 @@ static void __init sh03_setup(char **cmdline_p) static struct resource heartbeat_resources[] = { [0] = { .start = 0xa0800000, - .end = 0xa0800000 + 8 - 1, + .end = 0xa0800000, .flags = IORESOURCE_MEM, }, }; diff --git a/arch/sh/boards/shmin/setup.c b/arch/sh/boards/shmin/setup.c index dfd124509f4..16e5dae8ecf 100644 --- a/arch/sh/boards/shmin/setup.c +++ b/arch/sh/boards/shmin/setup.c @@ -14,36 +14,12 @@ #define PFC_PHCR 0xa400010eUL #define INTC_ICR1 0xa4000010UL -#define INTC_IPRC 0xa4000016UL - -static struct ipr_data ipr_irq_table[] = { - { 32, 0, 0, 0 }, - { 33, 0, 4, 0 }, - { 34, 0, 8, 8 }, - { 35, 0, 12, 0 }, -}; - -static unsigned long ipr_offsets[] = { - INTC_IPRC, -}; - -static struct ipr_desc ipr_irq_desc = { - .ipr_offsets = ipr_offsets, - .nr_offsets = ARRAY_SIZE(ipr_offsets), - - .ipr_data = ipr_irq_table, - .nr_irqs = ARRAY_SIZE(ipr_irq_table), - - .chip = { - .name = "IPR-shmin", - }, -}; static void __init init_shmin_irq(void) { ctrl_outw(0x2a00, PFC_PHCR); // IRQ0-3=IRQ ctrl_outw(0x0aaa, INTC_ICR1); // IRQ0-3=IRQ-mode,Low-active. - register_ipr_controller(&ipr_irq_desc); + plat_irq_setup_pins(IRQ_MODE_IRQ); } static void __iomem *shmin_ioport_map(unsigned long port, unsigned int size) diff --git a/arch/sh/boards/snapgear/setup.c b/arch/sh/boards/snapgear/setup.c index 84271d85a8d..2b594f60000 100644 --- a/arch/sh/boards/snapgear/setup.c +++ b/arch/sh/boards/snapgear/setup.c @@ -68,37 +68,11 @@ module_init(eraseconfig_init); * IRL3 = crypto */ -static struct ipr_data ipr_irq_table[] = { - { IRL0_IRQ, 0, IRL0_IPR_POS, IRL0_PRIORITY }, - { IRL1_IRQ, 0, IRL1_IPR_POS, IRL1_PRIORITY }, - { IRL2_IRQ, 0, IRL2_IPR_POS, IRL2_PRIORITY }, - { IRL3_IRQ, 0, IRL3_IPR_POS, IRL3_PRIORITY }, -}; - -static unsigned long ipr_offsets[] = { - INTC_IPRD, -}; - -static struct ipr_desc ipr_irq_desc = { - .ipr_offsets = ipr_offsets, - .nr_offsets = ARRAY_SIZE(ipr_offsets), - - .ipr_data = ipr_irq_table, - .nr_irqs = ARRAY_SIZE(ipr_irq_table), - - .chip = { - .name = "IPR-snapgear", - }, -}; - static void __init init_snapgear_IRQ(void) { - /* enable individual interrupt mode for externals */ - ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); - printk("Setup SnapGear IRQ/IPR ...\n"); - - register_ipr_controller(&ipr_irq_desc); + /* enable individual interrupt mode for externals */ + plat_irq_setup_pins(IRQ_MODE_IRQ); } /* diff --git a/arch/sh/boards/titan/setup.c b/arch/sh/boards/titan/setup.c index 606d25a4b87..5de3b2ad71a 100644 --- a/arch/sh/boards/titan/setup.c +++ b/arch/sh/boards/titan/setup.c @@ -12,38 +12,10 @@ #include <asm/titan.h> #include <asm/io.h> -static struct ipr_data ipr_irq_table[] = { - /* IRQ, IPR idx, shift, prio */ - { TITAN_IRQ_WAN, 3, 12, 8 }, /* eth0 (WAN) */ - { TITAN_IRQ_LAN, 3, 8, 8 }, /* eth1 (LAN) */ - { TITAN_IRQ_MPCIA, 3, 4, 8 }, /* mPCI A (top) */ - { TITAN_IRQ_USB, 3, 0, 8 }, /* mPCI B (bottom), USB */ -}; - -static unsigned long ipr_offsets[] = { /* stolen from setup-sh7750.c */ - 0xffd00004UL, /* 0: IPRA */ - 0xffd00008UL, /* 1: IPRB */ - 0xffd0000cUL, /* 2: IPRC */ - 0xffd00010UL, /* 3: IPRD */ -}; - -static struct ipr_desc ipr_irq_desc = { - .ipr_offsets = ipr_offsets, - .nr_offsets = ARRAY_SIZE(ipr_offsets), - - .ipr_data = ipr_irq_table, - .nr_irqs = ARRAY_SIZE(ipr_irq_table), - - .chip = { - .name = "IPR-titan", - }, -}; static void __init init_titan_irq(void) { /* enable individual interrupt mode for externals */ - ipr_irq_enable_irlm(); - /* register ipr irqs */ - register_ipr_controller(&ipr_irq_desc); + plat_irq_setup_pins(IRQ_MODE_IRQ); } static struct sh_machine_vector mv_titan __initmv = { diff --git a/arch/sh/cchips/Kconfig b/arch/sh/cchips/Kconfig index 2e516e9a6ed..7892361eedc 100644 --- a/arch/sh/cchips/Kconfig +++ b/arch/sh/cchips/Kconfig @@ -1,18 +1,5 @@ menu "Companion Chips" -config VOYAGERGX - bool "VoyagerGX chip support" - depends on SH_RTS7751R2D - help - Selecting this option will support Silicon Motion, Inc. SM501. - Designed to complement needs for the embedded industry, it - provides video and 2D capability. To reduce system cost a - wide variety of include I/O is supported, including analog RGB - and digital LCD Panel interface, 8-bit parallel interface, USB, - UART, IrDA, Zoom Video, AC97 or I2S, SSP, PWM, and I2C. There - are additional GPIO bits that can be used to interface to - external as well. - config HD6446X_SERIES bool diff --git a/arch/sh/cchips/hd6446x/hd64461.c b/arch/sh/cchips/hd6446x/hd64461.c index 97f6512aa1b..f1a4a0763c5 100644 --- a/arch/sh/cchips/hd6446x/hd64461.c +++ b/arch/sh/cchips/hd6446x/hd64461.c @@ -14,6 +14,9 @@ #include <asm/irq.h> #include <asm/hd64461.h> +/* This belongs in cpu specific */ +#define INTC_ICR1 0xA4140010UL + static void disable_hd64461_irq(unsigned int irq) { unsigned short nimr; @@ -121,10 +124,15 @@ int hd64461_irq_demux(int irq) } } } - return __irq_demux(irq); + return irq; } -static struct irqaction irq0 = { hd64461_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "HD64461", NULL, NULL }; +static struct irqaction irq0 = { + .handler = hd64461_interrupt, + .flags = IRQF_DISABLED, + .mask = CPU_MASK_NONE, + .name = "HD64461", +}; int __init setup_hd64461(void) { @@ -143,6 +151,7 @@ int __init setup_hd64461(void) #endif outw(0xffff, HD64461_NIMR); + /* IRQ 80 -> 95 belongs to HD64461 */ for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) { irq_desc[i].chip = &hd64461_irq_type; } diff --git a/arch/sh/cchips/hd6446x/hd64465/setup.c b/arch/sh/cchips/hd6446x/hd64465/setup.c index d126e1f30de..5cef0db4018 100644 --- a/arch/sh/cchips/hd6446x/hd64465/setup.c +++ b/arch/sh/cchips/hd6446x/hd64465/setup.c @@ -147,7 +147,12 @@ int hd64465_irq_demux(int irq) return irq; } -static struct irqaction irq0 = { hd64465_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "HD64465", NULL, NULL}; +static struct irqaction irq0 = { + .handler = hd64465_interrupt, + .flags = IRQF_DISABLED, + .mask = CPU_MASK_NONE, + .name = "HD64465", +}; static int __init setup_hd64465(void) diff --git a/arch/sh/cchips/voyagergx/irq.c b/arch/sh/cchips/voyagergx/irq.c index d70e5c8461b..ade30387684 100644 --- a/arch/sh/cchips/voyagergx/irq.c +++ b/arch/sh/cchips/voyagergx/irq.c @@ -23,149 +23,79 @@ #include <asm/voyagergx.h> #include <asm/rts7751r2d.h> -static void disable_voyagergx_irq(unsigned int irq) -{ - unsigned long val; - unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE); - - pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask); - val = readl((void __iomem *)VOYAGER_INT_MASK); - val &= ~mask; - writel(val, (void __iomem *)VOYAGER_INT_MASK); -} - -static void enable_voyagergx_irq(unsigned int irq) -{ - unsigned long val; - unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE); - - pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask); - val = readl((void __iomem *)VOYAGER_INT_MASK); - val |= mask; - writel(val, (void __iomem *)VOYAGER_INT_MASK); -} - -static void mask_and_ack_voyagergx(unsigned int irq) -{ - disable_voyagergx_irq(irq); -} - -static void end_voyagergx_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_voyagergx_irq(irq); -} - -static unsigned int startup_voyagergx_irq(unsigned int irq) -{ - enable_voyagergx_irq(irq); - return 0; -} - -static void shutdown_voyagergx_irq(unsigned int irq) -{ - disable_voyagergx_irq(irq); -} - -static struct hw_interrupt_type voyagergx_irq_type = { - .typename = "VOYAGERGX-IRQ", - .startup = startup_voyagergx_irq, - .shutdown = shutdown_voyagergx_irq, - .enable = enable_voyagergx_irq, - .disable = disable_voyagergx_irq, - .ack = mask_and_ack_voyagergx, - .end = end_voyagergx_irq, +enum { + UNUSED = 0, + + /* voyager specific interrupt sources */ + UP, G54, G53, G52, G51, G50, G49, G48, + I2C, PW, DMA, PCI, I2S, AC, US, + U1, U0, CV, MC, S1, S0, + UH, TWOD, ZD, PV, CI, }; -static irqreturn_t voyagergx_interrupt(int irq, void *dev_id) -{ - printk(KERN_INFO - "VoyagerGX: spurious interrupt, status: 0x%x\n", - (unsigned int)readl((void __iomem *)INT_STATUS)); - return IRQ_HANDLED; -} - -static struct { - int (*func)(int, void *); - void *dev; -} voyagergx_demux[VOYAGER_IRQ_NUM]; +static struct intc_vect vectors[] __initdata = { + INTC_IRQ(UP, IRQ_SM501_UP), INTC_IRQ(G54, IRQ_SM501_G54), + INTC_IRQ(G53, IRQ_SM501_G53), INTC_IRQ(G52, IRQ_SM501_G52), + INTC_IRQ(G51, IRQ_SM501_G51), INTC_IRQ(G50, IRQ_SM501_G50), + INTC_IRQ(G49, IRQ_SM501_G49), INTC_IRQ(G48, IRQ_SM501_G48), + INTC_IRQ(I2C, IRQ_SM501_I2C), INTC_IRQ(PW, IRQ_SM501_PW), + INTC_IRQ(DMA, IRQ_SM501_DMA), INTC_IRQ(PCI, IRQ_SM501_PCI), + INTC_IRQ(I2S, IRQ_SM501_I2S), INTC_IRQ(AC, IRQ_SM501_AC), + INTC_IRQ(US, IRQ_SM501_US), INTC_IRQ(U1, IRQ_SM501_U1), + INTC_IRQ(U0, IRQ_SM501_U0), INTC_IRQ(CV, IRQ_SM501_CV), + INTC_IRQ(MC, IRQ_SM501_MC), INTC_IRQ(S1, IRQ_SM501_S1), + INTC_IRQ(S0, IRQ_SM501_S0), INTC_IRQ(UH, IRQ_SM501_UH), + INTC_IRQ(TWOD, IRQ_SM501_2D), INTC_IRQ(ZD, IRQ_SM501_ZD), + INTC_IRQ(PV, IRQ_SM501_PV), INTC_IRQ(CI, IRQ_SM501_CI), +}; -void voyagergx_register_irq_demux(int irq, - int (*demux)(int irq, void *dev), void *dev) -{ - voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = demux; - voyagergx_demux[irq - VOYAGER_IRQ_BASE].dev = dev; -} +static struct intc_mask_reg mask_registers[] __initdata = { + { VOYAGER_INT_MASK, 0, 32, /* "Interrupt Mask", MMIO_base + 0x30 */ + { UP, G54, G53, G52, G51, G50, G49, G48, + I2C, PW, 0, DMA, PCI, I2S, AC, US, + 0, 0, U1, U0, CV, MC, S1, S0, + 0, UH, 0, 0, TWOD, ZD, PV, CI } }, +}; -void voyagergx_unregister_irq_demux(int irq) -{ - voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0; -} +static DECLARE_INTC_DESC(intc_desc, "voyagergx", vectors, + NULL, NULL, mask_registers, NULL, NULL); + +static unsigned int voyagergx_stat2irq[32] = { + IRQ_SM501_CI, IRQ_SM501_PV, IRQ_SM501_ZD, IRQ_SM501_2D, + 0, 0, IRQ_SM501_UH, 0, + IRQ_SM501_S0, IRQ_SM501_S1, IRQ_SM501_MC, IRQ_SM501_CV, + IRQ_SM501_U0, IRQ_SM501_U1, 0, 0, + IRQ_SM501_US, IRQ_SM501_AC, IRQ_SM501_I2S, IRQ_SM501_PCI, + IRQ_SM501_DMA, 0, IRQ_SM501_PW, IRQ_SM501_I2C, + IRQ_SM501_G48, IRQ_SM501_G49, IRQ_SM501_G50, IRQ_SM501_G51, + IRQ_SM501_G52, IRQ_SM501_G53, IRQ_SM501_G54, IRQ_SM501_UP +}; -int voyagergx_irq_demux(int irq) +static void voyagergx_irq_demux(unsigned int irq, struct irq_desc *desc) { - - if (irq == IRQ_VOYAGER ) { - unsigned long i = 0, bit __attribute__ ((unused)); - unsigned long val = readl((void __iomem *)INT_STATUS); - - if (val & (1 << 1)) - i = 1; - else if (val & (1 << 2)) - i = 2; - else if (val & (1 << 6)) - i = 6; - else if (val & (1 << 10)) - i = 10; - else if (val & (1 << 11)) - i = 11; - else if (val & (1 << 12)) - i = 12; - else if (val & (1 << 17)) - i = 17; - else - printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val); - pr_debug("voyagergx_irq_demux %ld \n", i); - if (i < VOYAGER_IRQ_NUM) { - irq = VOYAGER_IRQ_BASE + i; - if (voyagergx_demux[i].func != 0) - irq = voyagergx_demux[i].func(irq, - voyagergx_demux[i].dev); + unsigned long intv = ctrl_inl(INT_STATUS); + struct irq_desc *ext_desc; + unsigned int ext_irq; + unsigned int k = 0; + + while (intv) { + ext_irq = voyagergx_stat2irq[k]; + if (ext_irq && (intv & 1)) { + ext_desc = irq_desc + ext_irq; + handle_level_irq(ext_irq, ext_desc); } + intv >>= 1; + k++; } - return irq; } -static struct irqaction irq0 = { - .name = "voyagergx", - .handler = voyagergx_interrupt, - .flags = IRQF_DISABLED, - .mask = CPU_MASK_NONE, -}; - void __init setup_voyagergx_irq(void) { - int i, flag; - - printk(KERN_INFO "VoyagerGX configured at 0x%x on irq %d(mapped into %d to %d)\n", - VOYAGER_BASE, + printk(KERN_INFO "VoyagerGX on irq %d (mapped into %d to %d)\n", IRQ_VOYAGER, VOYAGER_IRQ_BASE, VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1); - for (i=0; i<VOYAGER_IRQ_NUM; i++) { - flag = 0; - switch (VOYAGER_IRQ_BASE + i) { - case VOYAGER_USBH_IRQ: - case VOYAGER_8051_IRQ: - case VOYAGER_UART0_IRQ: - case VOYAGER_UART1_IRQ: - case VOYAGER_AC97_IRQ: - flag = 1; - } - if (flag == 1) - irq_desc[VOYAGER_IRQ_BASE + i].chip = &voyagergx_irq_type; - } - - setup_irq(IRQ_VOYAGER, &irq0); + register_intc_controller(&intc_desc); + set_irq_chained_handler(IRQ_VOYAGER, voyagergx_irq_demux); } diff --git a/arch/sh/configs/dreamcast_defconfig b/arch/sh/configs/dreamcast_defconfig index 3fdd270eecf..57728788b75 100644 --- a/arch/sh/configs/dreamcast_defconfig +++ b/arch/sh/configs/dreamcast_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.22-rc4 -# Sat Jul 7 03:47:45 2007 +# Linux kernel version: 2.6.23-rc7 +# Fri Sep 21 15:46:27 2007 # CONFIG_SUPERH=y CONFIG_RWSEM_GENERIC_SPINLOCK=y @@ -18,30 +18,26 @@ CONFIG_STACKTRACE_SUPPORT=y CONFIG_LOCKDEP_SUPPORT=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # -# Code maturity level options +# General setup # CONFIG_EXPERIMENTAL=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y -# CONFIG_IPC_NS is not set CONFIG_SYSVIPC_SYSCTL=y # CONFIG_POSIX_MQUEUE is not set CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set # CONFIG_TASKSTATS is not set -# CONFIG_UTS_NS is not set +# CONFIG_USER_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set CONFIG_LOG_BUF_SHIFT=14 @@ -64,7 +60,6 @@ CONFIG_FUTEX=y CONFIG_ANON_INODES=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y -CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_VM_EVENT_COUNTERS=y @@ -74,24 +69,17 @@ CONFIG_SLAB=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 - -# -# Loadable module support -# CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y - -# -# Block layer -# CONFIG_BLOCK=y # CONFIG_LBD is not set # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set # # IO Schedulers @@ -112,7 +100,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" CONFIG_CPU_SH4=y # CONFIG_CPU_SUBTYPE_SH7619 is not set # CONFIG_CPU_SUBTYPE_SH7206 is not set -# CONFIG_CPU_SUBTYPE_SH7300 is not set # CONFIG_CPU_SUBTYPE_SH7705 is not set # CONFIG_CPU_SUBTYPE_SH7706 is not set # CONFIG_CPU_SUBTYPE_SH7707 is not set @@ -120,6 +107,7 @@ CONFIG_CPU_SH4=y # CONFIG_CPU_SUBTYPE_SH7709 is not set # CONFIG_CPU_SUBTYPE_SH7710 is not set # CONFIG_CPU_SUBTYPE_SH7712 is not set +# CONFIG_CPU_SUBTYPE_SH7720 is not set # CONFIG_CPU_SUBTYPE_SH7750 is not set CONFIG_CPU_SUBTYPE_SH7091=y # CONFIG_CPU_SUBTYPE_SH7750R is not set @@ -134,7 +122,6 @@ CONFIG_CPU_SUBTYPE_SH7091=y # CONFIG_CPU_SUBTYPE_SH7780 is not set # CONFIG_CPU_SUBTYPE_SH7785 is not set # CONFIG_CPU_SUBTYPE_SHX3 is not set -# CONFIG_CPU_SUBTYPE_SH73180 is not set # CONFIG_CPU_SUBTYPE_SH7343 is not set # CONFIG_CPU_SUBTYPE_SH7722 is not set @@ -177,7 +164,9 @@ CONFIG_NR_QUICK=2 # Cache configuration # # CONFIG_SH_DIRECT_MAPPED is not set -# CONFIG_SH_WRITETHROUGH is not set +CONFIG_CACHE_WRITEBACK=y +# CONFIG_CACHE_WRITETHROUGH is not set +# CONFIG_CACHE_OFF is not set # # Processor features @@ -185,12 +174,11 @@ CONFIG_NR_QUICK=2 CONFIG_CPU_LITTLE_ENDIAN=y # CONFIG_CPU_BIG_ENDIAN is not set CONFIG_SH_FPU=y -# CONFIG_SH_DSP is not set CONFIG_SH_STORE_QUEUES=y CONFIG_CPU_HAS_INTEVT=y -CONFIG_CPU_HAS_IPR_IRQ=y CONFIG_CPU_HAS_SR_RB=y CONFIG_CPU_HAS_PTEA=y +CONFIG_CPU_HAS_FPU=y # # Board support @@ -270,6 +258,7 @@ CONFIG_CMDLINE="console=ttySC1,115200 panic=3" # # Bus options # +CONFIG_MAPLE=y CONFIG_PCI=y CONFIG_SH_PCIDMA_NONCOHERENT=y CONFIG_PCI_AUTO=y @@ -368,6 +357,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set # CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set # # Device Drivers @@ -380,27 +370,10 @@ CONFIG_DEFAULT_TCP_CONG="cubic" CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set # CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# # CONFIG_CONNECTOR is not set # CONFIG_MTD is not set - -# -# Parallel port support -# # CONFIG_PARPORT is not set - -# -# Plug and Play support -# -# CONFIG_PNPACPI is not set - -# -# Block devices -# -# CONFIG_BLK_CPQ_DA is not set +CONFIG_BLK_DEV=y # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_UMEM is not set @@ -411,14 +384,11 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_BLK_DEV_RAM is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set - -# -# Misc devices -# +CONFIG_MISC_DEVICES=y # CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set # CONFIG_SGI_IOC4 is not set # CONFIG_TIFM_CORE is not set -# CONFIG_BLINK is not set # CONFIG_IDE is not set # @@ -426,12 +396,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set # CONFIG_SCSI_NETLINK is not set # CONFIG_ATA is not set - -# -# Multi-device support (RAID and LVM) -# # CONFIG_MD is not set # @@ -444,26 +411,16 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # # CONFIG_FIREWIRE is not set # CONFIG_IEEE1394 is not set - -# -# I2O device support -# # CONFIG_I2O is not set - -# -# Network device support -# CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set # CONFIG_DUMMY is not set # CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ARCNET is not set # CONFIG_PHYLIB is not set - -# -# Ethernet (10 or 100Mbit) -# CONFIG_NET_ETHERNET=y CONFIG_MII=y # CONFIG_STNIC is not set @@ -472,10 +429,6 @@ CONFIG_MII=y # CONFIG_CASSINI is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_SMC91X is not set - -# -# Tulip family network device support -# # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set CONFIG_NET_PCI=y @@ -520,15 +473,7 @@ CONFIG_8139TOO=y # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# # CONFIG_ISDN is not set - -# -# Telephony Support -# # CONFIG_PHONE is not set # @@ -536,6 +481,7 @@ CONFIG_8139TOO=y # CONFIG_INPUT=y # CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set # # Userland interfaces @@ -606,10 +552,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# # CONFIG_IPMI_HANDLER is not set CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set @@ -631,10 +573,6 @@ CONFIG_HW_RANDOM=y # CONFIG_APPLICOM is not set # CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# # CONFIG_TCG_TPM is not set CONFIG_DEVPORT=y # CONFIG_I2C is not set @@ -644,11 +582,8 @@ CONFIG_DEVPORT=y # # CONFIG_SPI is not set # CONFIG_SPI_MASTER is not set - -# -# Dallas's 1-wire bus -# # CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set # @@ -673,6 +608,7 @@ CONFIG_DEVPORT=y # # CONFIG_DISPLAY_SUPPORT is not set # CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y CONFIG_FIRMWARE_EDID=y # CONFIG_FB_DDC is not set @@ -699,7 +635,6 @@ CONFIG_FB_DEFERRED_IO=y # CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set CONFIG_FB_PVR2=y -# CONFIG_FB_EPSON1355 is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_NVIDIA is not set # CONFIG_FB_RIVA is not set @@ -725,6 +660,7 @@ CONFIG_FB_PVR2=y # CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set CONFIG_FONTS=y CONFIG_FONT_8x8=y @@ -749,16 +685,10 @@ CONFIG_LOGO_SUPERH_CLUT224=y # Sound # # CONFIG_SOUND is not set - -# -# HID Devices -# +CONFIG_HID_SUPPORT=y CONFIG_HID=y # CONFIG_HID_DEBUG is not set - -# -# USB support -# +CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB_ARCH_HAS_EHCI=y @@ -773,32 +703,8 @@ CONFIG_USB_ARCH_HAS_EHCI=y # # CONFIG_USB_GADGET is not set # CONFIG_MMC is not set - -# -# LED devices -# # CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# - -# -# InfiniBand support -# # CONFIG_INFINIBAND is not set - -# -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# - -# -# Real Time Clock -# # CONFIG_RTC_CLASS is not set # @@ -815,6 +721,11 @@ CONFIG_USB_ARCH_HAS_EHCI=y # # +# Userspace I/O +# +# CONFIG_UIO is not set + +# # File systems # # CONFIG_EXT2_FS is not set @@ -890,7 +801,6 @@ CONFIG_RAMFS=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set # # Partition Types @@ -935,10 +845,6 @@ CONFIG_ENABLE_MUST_CHECK=y # # CONFIG_KEYS is not set # CONFIG_SECURITY is not set - -# -# Cryptographic options -# # CONFIG_CRYPTO is not set # @@ -949,6 +855,7 @@ CONFIG_BITREVERSE=y # CONFIG_CRC16 is not set # CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y +# CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set CONFIG_PLIST=y CONFIG_HAS_IOMEM=y diff --git a/arch/sh/configs/hp6xx_defconfig b/arch/sh/configs/hp6xx_defconfig index b931d9b2d57..756d38dc2f7 100644 --- a/arch/sh/configs/hp6xx_defconfig +++ b/arch/sh/configs/hp6xx_defconfig @@ -1,37 +1,47 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18 -# Tue Oct 3 11:10:06 2006 +# Linux kernel version: 2.6.23-rc4 +# Tue Sep 11 19:42:44 2007 # CONFIG_SUPERH=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_BUG=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_SYS_SUPPORTS_PM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # -# Code maturity level options +# General setup # CONFIG_EXPERIMENTAL=y CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y # CONFIG_SYSVIPC is not set -# CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_UTS_NS is not set -# CONFIG_IKCONFIG is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_USER_NS is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set -CONFIG_INITRAMFS_SOURCE="" -CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y CONFIG_EMBEDDED=y CONFIG_UID16=y @@ -44,27 +54,25 @@ CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y +CONFIG_ANON_INODES=y CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y CONFIG_SHMEM=y -CONFIG_SLAB=y CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set - -# -# Loadable module support -# # CONFIG_MODULES is not set - -# -# Block layer -# CONFIG_BLOCK=y # CONFIG_LBD is not set # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set # # IO Schedulers @@ -82,55 +90,17 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # # System type # -# CONFIG_SH_SOLUTION_ENGINE is not set -# CONFIG_SH_7751_SOLUTION_ENGINE is not set -# CONFIG_SH_7300_SOLUTION_ENGINE is not set -# CONFIG_SH_7343_SOLUTION_ENGINE is not set -# CONFIG_SH_73180_SOLUTION_ENGINE is not set -# CONFIG_SH_7751_SYSTEMH is not set -CONFIG_SH_HP6XX=y -# CONFIG_SH_EC3104 is not set -# CONFIG_SH_SATURN is not set -# CONFIG_SH_DREAMCAST is not set -# CONFIG_SH_BIGSUR is not set -# CONFIG_SH_MPC1211 is not set -# CONFIG_SH_SH03 is not set -# CONFIG_SH_SECUREEDGE5410 is not set -# CONFIG_SH_HS7751RVOIP is not set -# CONFIG_SH_7710VOIPGW is not set -# CONFIG_SH_RTS7751R2D is not set -# CONFIG_SH_R7780RP is not set -# CONFIG_SH_EDOSK7705 is not set -# CONFIG_SH_SH4202_MICRODEV is not set -# CONFIG_SH_LANDISK is not set -# CONFIG_SH_TITAN is not set -# CONFIG_SH_SHMIN is not set -# CONFIG_SH_UNKNOWN is not set - -# -# Processor selection -# CONFIG_CPU_SH3=y - -# -# SH-2 Processor Support -# -# CONFIG_CPU_SUBTYPE_SH7604 is not set - -# -# SH-3 Processor Support -# -# CONFIG_CPU_SUBTYPE_SH7300 is not set +# CONFIG_CPU_SUBTYPE_SH7619 is not set +# CONFIG_CPU_SUBTYPE_SH7206 is not set # CONFIG_CPU_SUBTYPE_SH7705 is not set # CONFIG_CPU_SUBTYPE_SH7706 is not set # CONFIG_CPU_SUBTYPE_SH7707 is not set # CONFIG_CPU_SUBTYPE_SH7708 is not set CONFIG_CPU_SUBTYPE_SH7709=y # CONFIG_CPU_SUBTYPE_SH7710 is not set - -# -# SH-4 Processor Support -# +# CONFIG_CPU_SUBTYPE_SH7712 is not set +# CONFIG_CPU_SUBTYPE_SH7720 is not set # CONFIG_CPU_SUBTYPE_SH7750 is not set # CONFIG_CPU_SUBTYPE_SH7091 is not set # CONFIG_CPU_SUBTYPE_SH7750R is not set @@ -139,66 +109,78 @@ CONFIG_CPU_SUBTYPE_SH7709=y # CONFIG_CPU_SUBTYPE_SH7751R is not set # CONFIG_CPU_SUBTYPE_SH7760 is not set # CONFIG_CPU_SUBTYPE_SH4_202 is not set - -# -# ST40 Processor Support -# # CONFIG_CPU_SUBTYPE_ST40STB1 is not set # CONFIG_CPU_SUBTYPE_ST40GX1 is not set - -# -# SH-4A Processor Support -# # CONFIG_CPU_SUBTYPE_SH7770 is not set # CONFIG_CPU_SUBTYPE_SH7780 is not set - -# -# SH4AL-DSP Processor Support -# -# CONFIG_CPU_SUBTYPE_SH73180 is not set +# CONFIG_CPU_SUBTYPE_SH7785 is not set +# CONFIG_CPU_SUBTYPE_SHX3 is not set # CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set # # Memory management options # +CONFIG_QUICKLIST=y CONFIG_MMU=y CONFIG_PAGE_OFFSET=0x80000000 -CONFIG_MEMORY_START=0x0c000000 +CONFIG_MEMORY_START=0x0d000000 CONFIG_MEMORY_SIZE=0x00400000 CONFIG_VSYSCALL=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_MAX_ACTIVE_REGIONS=1 +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_64KB is not set CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y # CONFIG_DISCONTIGMEM_MANUAL is not set # CONFIG_SPARSEMEM_MANUAL is not set CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y -# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPARSEMEM_STATIC=y CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_NR_QUICK=2 # # Cache configuration # # CONFIG_SH_DIRECT_MAPPED is not set -# CONFIG_SH_WRITETHROUGH is not set -# CONFIG_SH_OCRAM is not set +CONFIG_CACHE_WRITEBACK=y +# CONFIG_CACHE_WRITETHROUGH is not set +# CONFIG_CACHE_OFF is not set # # Processor features # CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set # CONFIG_SH_FPU_EMU is not set -# CONFIG_SH_DSP is not set CONFIG_SH_ADC=y CONFIG_CPU_HAS_INTEVT=y -CONFIG_CPU_HAS_PINT_IRQ=y CONFIG_CPU_HAS_SR_RB=y # -# Timer support +# Board support +# +# CONFIG_SH_SOLUTION_ENGINE is not set +CONFIG_SH_HP6XX=y + +# +# Timer and clock configuration # CONFIG_SH_TMU=y +CONFIG_SH_TIMER_IRQ=16 CONFIG_SH_PCLK_FREQ=22110000 +# CONFIG_TICK_ONESHOT is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set # # CPU Frequency scaling @@ -208,6 +190,7 @@ CONFIG_SH_PCLK_FREQ=22110000 # # DMA support # +CONFIG_SH_DMA_API=y CONFIG_SH_DMA=y CONFIG_NR_ONCHIP_DMA_CHANNELS=4 # CONFIG_NR_DMA_CHANNELS_BOOL is not set @@ -223,14 +206,21 @@ CONFIG_HD64461_IOBASE=0xb0000000 CONFIG_HD64461_ENABLER=y # +# Additional SuperH Device Drivers +# +# CONFIG_HEARTBEAT is not set +# CONFIG_PUSH_SWITCH is not set + +# # Kernel features # # CONFIG_HZ_100 is not set CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=250 # CONFIG_KEXEC is not set -# CONFIG_SMP is not set +# CONFIG_CRASH_DUMP is not set CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set @@ -240,14 +230,13 @@ CONFIG_PREEMPT_NONE=y # CONFIG_ZERO_PAGE_OFFSET=0x00001000 CONFIG_BOOT_LINK_OFFSET=0x00800000 -# CONFIG_UBC_WAKEUP is not set # CONFIG_CMDLINE_BOOL is not set # # Bus options # CONFIG_ISA=y -# CONFIG_PCI is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set # # PCCARD (PCMCIA/CardBus) support @@ -266,14 +255,9 @@ CONFIG_PCMCIA_IOCTL=y CONFIG_PCMCIA_PROBE=y # -# PCI Hotplug Support -# - -# # Executable file formats # CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_FLAT is not set # CONFIG_BINFMT_MISC is not set # @@ -282,8 +266,9 @@ CONFIG_BINFMT_ELF=y CONFIG_PM=y CONFIG_PM_LEGACY=y # CONFIG_PM_DEBUG is not set -# CONFIG_PM_SYSFS_DEPRECATED is not set -CONFIG_APM=y +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND=y +CONFIG_APM_EMULATION=y # # Networking @@ -301,109 +286,76 @@ CONFIG_APM=y CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=y # CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# - -# -# Memory Technology Devices (MTD) -# # CONFIG_MTD is not set - -# -# Parallel port support -# # CONFIG_PARPORT is not set - -# -# Plug and Play support -# # CONFIG_PNP is not set - -# -# Block devices -# +CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_COW_COMMON is not set # CONFIG_BLK_DEV_LOOP is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_RAM is not set # CONFIG_CDROM_PKTCDVD is not set - -# -# ATA/ATAPI/MFM/RLL support -# -CONFIG_IDE=y -CONFIG_IDE_MAX_HWIFS=4 -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_IDE_SATA is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -CONFIG_BLK_DEV_IDECS=y -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_IDE_TASK_IOCTL is not set - -# -# IDE chipset support/bugfixes -# -CONFIG_IDE_GENERIC=y -# CONFIG_IDE_ARM is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_BLK_DEV_IDEDMA is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_BLK_DEV_HD is not set +CONFIG_MISC_DEVICES=y +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IDE is not set # # SCSI device support # # CONFIG_RAID_ATTRS is not set -# CONFIG_SCSI is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set # CONFIG_SCSI_NETLINK is not set - -# -# Serial ATA (prod) and Parallel ATA (experimental) drivers -# -# CONFIG_ATA is not set - -# -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Multi-device support (RAID and LVM) -# +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_PATA_LEGACY is not set +# CONFIG_PATA_PCMCIA is not set +# CONFIG_PATA_QDI is not set +# CONFIG_PATA_WINBOND_VLB is not set +CONFIG_PATA_PLATFORM=y # CONFIG_MD is not set - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# - -# -# I2O device support -# - -# -# ISDN subsystem -# - -# -# Telephony Support -# # CONFIG_PHONE is not set # @@ -411,19 +363,17 @@ CONFIG_IDE_GENERIC=y # CONFIG_INPUT=y # CONFIG_INPUT_FF_MEMLESS is not set +CONFIG_INPUT_POLLDEV=y # # Userland interfaces # -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_PSAUX=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_JOYDEV is not set CONFIG_INPUT_TSDEV=y CONFIG_INPUT_TSDEV_SCREEN_X=240 CONFIG_INPUT_TSDEV_SCREEN_Y=320 -# CONFIG_INPUT_EVDEV is not set +CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_EVBUG is not set # @@ -436,9 +386,12 @@ CONFIG_INPUT_KEYBOARD=y # CONFIG_KEYBOARD_XTKBD is not set # CONFIG_KEYBOARD_NEWTON is not set # CONFIG_KEYBOARD_STOWAWAY is not set +CONFIG_KEYBOARD_HP6XX=y # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_FUJITSU is not set # CONFIG_TOUCHSCREEN_GUNZE is not set # CONFIG_TOUCHSCREEN_ELO is not set # CONFIG_TOUCHSCREEN_MTOUCH is not set @@ -447,6 +400,7 @@ CONFIG_TOUCHSCREEN_HP600=y # CONFIG_TOUCHSCREEN_PENMOUNT is not set # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set # CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_UCB1400 is not set # CONFIG_INPUT_MISC is not set # @@ -476,46 +430,29 @@ CONFIG_HW_CONSOLE=y # # Non-8250 serial port support # -# CONFIG_SERIAL_SH_SCI is not set +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=3 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# +CONFIG_LEGACY_PTY_COUNT=64 # CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# # CONFIG_WATCHDOG is not set CONFIG_HW_RANDOM=y -# CONFIG_GEN_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # -# Ftape, the floppy tape device driver -# - -# # PCMCIA character devices # # CONFIG_SYNCLINK_CS is not set # CONFIG_CARDMAN_4000 is not set # CONFIG_CARDMAN_4040 is not set # CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# # CONFIG_TCG_TPM is not set -# CONFIG_TELCLOCK is not set - -# -# I2C support -# +CONFIG_DEVPORT=y # CONFIG_I2C is not set # @@ -523,48 +460,55 @@ CONFIG_HW_RANDOM=y # # CONFIG_SPI is not set # CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set # -# Dallas's 1-wire bus -# - -# -# Hardware Monitoring support -# -CONFIG_HWMON=y -# CONFIG_HWMON_VID is not set -# CONFIG_SENSORS_ABITUGURU is not set -# CONFIG_SENSORS_F71805F is not set -# CONFIG_SENSORS_VT1211 is not set -# CONFIG_HWMON_DEBUG_CHIP is not set - -# -# Misc devices +# Multifunction device drivers # +# CONFIG_MFD_SM501 is not set # # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y +# CONFIG_DAB is not set # -# Digital Video Broadcasting Devices +# Graphics support # +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_HP680=y # -# Graphics support +# Display device support # -CONFIG_FIRMWARE_EDID=y +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB_DDC is not set CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_SYS_FOPS is not set +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_SVGALIB is not set # CONFIG_FB_MACMODES is not set # CONFIG_FB_BACKLIGHT is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set -# CONFIG_FB_EPSON1355 is not set + +# +# Frame buffer hardware drivers +# # CONFIG_FB_S1D13XXX is not set CONFIG_FB_HIT=y # CONFIG_FB_VIRTUAL is not set @@ -575,6 +519,7 @@ CONFIG_FB_HIT=y # CONFIG_MDA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set CONFIG_FONTS=y # CONFIG_FONT_8x8 is not set @@ -587,79 +532,49 @@ CONFIG_FONT_PEARL_8x8=y # CONFIG_FONT_SUN8x16 is not set # CONFIG_FONT_SUN12x22 is not set # CONFIG_FONT_10x18 is not set - -# -# Logo configuration -# # CONFIG_LOGO is not set -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound # -CONFIG_SOUND=y - -# -# Advanced Linux Sound Architecture -# -# CONFIG_SND is not set - -# -# Open Sound System -# -CONFIG_SOUND_PRIME=y -# CONFIG_OSS_OBSOLETE_DRIVER is not set -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set -CONFIG_SOUND_SH_DAC_AUDIO=y -CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL=1 - -# -# USB support -# -# CONFIG_USB_ARCH_HAS_HCD is not set -# CONFIG_USB_ARCH_HAS_OHCI is not set -# CONFIG_USB_ARCH_HAS_EHCI is not set - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -# - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set # CONFIG_MMC is not set - -# -# LED devices -# # CONFIG_NEW_LEDS is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set # -# LED drivers -# - -# -# LED Triggers +# RTC interfaces # +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set # -# InfiniBand support +# SPI RTC drivers # # -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# Platform RTC drivers # +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_V3020 is not set # -# Real Time Clock +# on-CPU RTC drivers # -# CONFIG_RTC_CLASS is not set +CONFIG_RTC_DRV_SH=y # # DMA Engine support @@ -675,16 +590,23 @@ CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL=1 # # +# Userspace I/O +# +# CONFIG_UIO is not set + +# # File systems # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set # CONFIG_EXT2_FS_XIP is not set # CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_INOTIFY=y @@ -705,7 +627,7 @@ CONFIG_DNOTIFY=y # DOS/FAT/NT Filesystems # CONFIG_FAT_FS=y -# CONFIG_MSDOS_FS is not set +CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_FAT_DEFAULT_CODEPAGE=437 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" @@ -755,7 +677,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set +CONFIG_NLS_CODEPAGE_850=y # CONFIG_NLS_CODEPAGE_852 is not set # CONFIG_NLS_CODEPAGE_855 is not set # CONFIG_NLS_CODEPAGE_857 is not set @@ -799,34 +721,73 @@ CONFIG_NLS_DEFAULT="iso8859-1" # # Kernel hacking # +CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set CONFIG_ENABLE_MUST_CHECK=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_FS is not set -# CONFIG_UNWIND_INFO is not set # CONFIG_SH_STANDARD_BIOS is not set -# CONFIG_KGDB is not set +# CONFIG_EARLY_SCIF_CONSOLE is not set +# CONFIG_SH_KGDB is not set # # Security options # # CONFIG_KEYS is not set # CONFIG_SECURITY is not set - -# -# Cryptographic options -# -# CONFIG_CRYPTO is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_HW is not set # # Library routines # +CONFIG_BITREVERSE=y # CONFIG_CRC_CCITT is not set -# CONFIG_CRC16 is not set +CONFIG_CRC16=y +# CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y +# CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/sh/configs/magicpanelr2_defconfig b/arch/sh/configs/magicpanelr2_defconfig new file mode 100644 index 00000000000..f8398a5f10e --- /dev/null +++ b/arch/sh/configs/magicpanelr2_defconfig @@ -0,0 +1,925 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc2 +# Fri Aug 17 12:15:16 2007 +# +CONFIG_SUPERH=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +CONFIG_AUDIT=y +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_SYSFS_DEPRECATED=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" + +# +# System type +# +CONFIG_CPU_SH3=y +# CONFIG_CPU_SUBTYPE_SH7619 is not set +# CONFIG_CPU_SUBTYPE_SH7206 is not set +# CONFIG_CPU_SUBTYPE_SH7705 is not set +# CONFIG_CPU_SUBTYPE_SH7706 is not set +# CONFIG_CPU_SUBTYPE_SH7707 is not set +# CONFIG_CPU_SUBTYPE_SH7708 is not set +# CONFIG_CPU_SUBTYPE_SH7709 is not set +# CONFIG_CPU_SUBTYPE_SH7710 is not set +# CONFIG_CPU_SUBTYPE_SH7712 is not set +CONFIG_CPU_SUBTYPE_SH7720=y +# CONFIG_CPU_SUBTYPE_SH7750 is not set +# CONFIG_CPU_SUBTYPE_SH7091 is not set +# CONFIG_CPU_SUBTYPE_SH7750R is not set +# CONFIG_CPU_SUBTYPE_SH7750S is not set +# CONFIG_CPU_SUBTYPE_SH7751 is not set +# CONFIG_CPU_SUBTYPE_SH7751R is not set +# CONFIG_CPU_SUBTYPE_SH7760 is not set +# CONFIG_CPU_SUBTYPE_SH4_202 is not set +# CONFIG_CPU_SUBTYPE_ST40STB1 is not set +# CONFIG_CPU_SUBTYPE_ST40GX1 is not set +# CONFIG_CPU_SUBTYPE_SH7770 is not set +# CONFIG_CPU_SUBTYPE_SH7780 is not set +# CONFIG_CPU_SUBTYPE_SH7785 is not set +# CONFIG_CPU_SUBTYPE_SHX3 is not set +# CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set + +# +# Memory management options +# +CONFIG_QUICKLIST=y +CONFIG_MMU=y +CONFIG_PAGE_OFFSET=0x80000000 +CONFIG_MEMORY_START=0x0C000000 +CONFIG_MEMORY_SIZE=0x03F00000 +CONFIG_VSYSCALL=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_MAX_ACTIVE_REGIONS=1 +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_SPARSEMEM_STATIC=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_NR_QUICK=2 + +# +# Cache configuration +# +# CONFIG_SH_DIRECT_MAPPED is not set +CONFIG_CACHE_WRITEBACK=y +# CONFIG_CACHE_WRITETHROUGH is not set +# CONFIG_CACHE_OFF is not set + +# +# Processor features +# +CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set +# CONFIG_SH_FPU_EMU is not set +CONFIG_SH_DSP=y +CONFIG_SH_ADC=y +CONFIG_CPU_HAS_INTEVT=y +CONFIG_CPU_HAS_INTC_IRQ=y +CONFIG_CPU_HAS_SR_RB=y +CONFIG_CPU_HAS_DSP=y + +# +# Board support +# +CONFIG_SH_MAGIC_PANEL_R2=y + +# +# Magic Panel R2 options +# +CONFIG_SH_MAGIC_PANEL_R2_VERSION=3 + +# +# Timer and clock configuration +# +CONFIG_SH_TMU=y +CONFIG_SH_TIMER_IRQ=16 +CONFIG_SH_PCLK_FREQ=24000000 +# CONFIG_TICK_ONESHOT is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# DMA support +# +CONFIG_SH_DMA_API=y +CONFIG_SH_DMA=y +CONFIG_NR_ONCHIP_DMA_CHANNELS=6 +# CONFIG_NR_DMA_CHANNELS_BOOL is not set + +# +# Companion Chips +# + +# +# Additional SuperH Device Drivers +# +CONFIG_HEARTBEAT=y +# CONFIG_PUSH_SWITCH is not set + +# +# Kernel features +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set + +# +# Boot options +# +CONFIG_ZERO_PAGE_OFFSET=0x00001000 +CONFIG_BOOT_LINK_OFFSET=0x00800000 +# CONFIG_CMDLINE_BOOL is not set + +# +# Bus options +# +# CONFIG_ARCH_SUPPORTS_MSI is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=y +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +CONFIG_MTD_CMDLINE_PARTS=y + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0x0000000 +CONFIG_MTD_PHYSMAP_LEN=0 +CONFIG_MTD_PHYSMAP_BANKWIDTH=0 +# CONFIG_MTD_SOLUTIONENGINE is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_STNIC is not set +# CONFIG_SMC91X is not set +CONFIG_SMC911X=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +CONFIG_INPUT_MOUSE=y +# CONFIG_MOUSE_PS2 is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=2 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_HCTOSYS is not set +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_SH=y + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_XATTR is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_WRITEBUFFER is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_BIND34=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +CONFIG_NLS_CODEPAGE_850=y +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DETECT_SOFTLOCKUP is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_DEBUG_KOBJECT=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FRAME_POINTER=y +# CONFIG_FORCED_INLINING is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SH_STANDARD_BIOS is not set +CONFIG_EARLY_SCIF_CONSOLE=y +CONFIG_EARLY_SCIF_CONSOLE_PORT=0xa4430000 +CONFIG_EARLY_PRINTK=y +# CONFIG_DEBUG_BOOTMEM is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_4KSTACKS is not set +CONFIG_SH_KGDB=y + +# +# KGDB configuration options +# +# CONFIG_MORE_COMPILE_OPTIONS is not set +# CONFIG_KGDB_NMI is not set +CONFIG_KGDB_SYSRQ=y + +# +# Serial port setup +# +CONFIG_KGDB_DEFPORT=0 +CONFIG_KGDB_DEFBAUD=115200 +CONFIG_KGDB_DEFPARITY_N=y +# CONFIG_KGDB_DEFPARITY_E is not set +# CONFIG_KGDB_DEFPARITY_O is not set +CONFIG_KGDB_DEFBITS_8=y +# CONFIG_KGDB_DEFBITS_7 is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/sh/configs/rts7751r2d_defconfig b/arch/sh/configs/rts7751r2d1_defconfig index b64f73b704d..2dc754e5b73 100644 --- a/arch/sh/configs/rts7751r2d_defconfig +++ b/arch/sh/configs/rts7751r2d1_defconfig @@ -1,46 +1,47 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21-rc1 -# Thu Mar 1 16:42:40 2007 +# Linux kernel version: 2.6.23-rc2 +# Tue Aug 14 18:04:44 2007 # CONFIG_SUPERH=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_BUG=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_CALIBRATE_DELAY=y -# CONFIG_GENERIC_TIME is not set +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_SYS_SUPPORTS_PCI=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_LOCKDEP_SUPPORT=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # -# Code maturity level options +# General setup # CONFIG_EXPERIMENTAL=y CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y -# CONFIG_IPC_NS is not set CONFIG_SYSVIPC_SYSCTL=y # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -# CONFIG_UTS_NS is not set +# CONFIG_USER_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y CONFIG_EMBEDDED=y @@ -54,31 +55,29 @@ CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y +CONFIG_ANON_INODES=y CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y CONFIG_SHMEM=y -CONFIG_SLAB=y CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set - -# -# Loadable module support -# CONFIG_MODULES=y # CONFIG_MODULE_UNLOAD is not set # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set # CONFIG_KMOD is not set - -# -# Block layer -# CONFIG_BLOCK=y # CONFIG_LBD is not set # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set # # IO Schedulers @@ -96,61 +95,16 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # # System type # -# CONFIG_SH_SOLUTION_ENGINE is not set -# CONFIG_SH_7751_SOLUTION_ENGINE is not set -# CONFIG_SH_7300_SOLUTION_ENGINE is not set -# CONFIG_SH_7343_SOLUTION_ENGINE is not set -# CONFIG_SH_73180_SOLUTION_ENGINE is not set -# CONFIG_SH_7751_SYSTEMH is not set -# CONFIG_SH_HP6XX is not set -# CONFIG_SH_SATURN is not set -# CONFIG_SH_DREAMCAST is not set -# CONFIG_SH_MPC1211 is not set -# CONFIG_SH_SH03 is not set -# CONFIG_SH_SECUREEDGE5410 is not set -# CONFIG_SH_HS7751RVOIP is not set -# CONFIG_SH_7710VOIPGW is not set -CONFIG_SH_RTS7751R2D=y -# CONFIG_SH_R7780RP is not set -# CONFIG_SH_EDOSK7705 is not set -# CONFIG_SH_SH4202_MICRODEV is not set -# CONFIG_SH_LANDISK is not set -# CONFIG_SH_TITAN is not set -# CONFIG_SH_SHMIN is not set -# CONFIG_SH_7206_SOLUTION_ENGINE is not set -# CONFIG_SH_7619_SOLUTION_ENGINE is not set -# CONFIG_SH_UNKNOWN is not set - -# -# Processor selection -# CONFIG_CPU_SH4=y - -# -# SH-2 Processor Support -# -# CONFIG_CPU_SUBTYPE_SH7604 is not set # CONFIG_CPU_SUBTYPE_SH7619 is not set - -# -# SH-2A Processor Support -# # CONFIG_CPU_SUBTYPE_SH7206 is not set - -# -# SH-3 Processor Support -# -# CONFIG_CPU_SUBTYPE_SH7300 is not set # CONFIG_CPU_SUBTYPE_SH7705 is not set # CONFIG_CPU_SUBTYPE_SH7706 is not set # CONFIG_CPU_SUBTYPE_SH7707 is not set # CONFIG_CPU_SUBTYPE_SH7708 is not set # CONFIG_CPU_SUBTYPE_SH7709 is not set # CONFIG_CPU_SUBTYPE_SH7710 is not set - -# -# SH-4 Processor Support -# +# CONFIG_CPU_SUBTYPE_SH7712 is not set # CONFIG_CPU_SUBTYPE_SH7750 is not set # CONFIG_CPU_SUBTYPE_SH7091 is not set # CONFIG_CPU_SUBTYPE_SH7750R is not set @@ -159,35 +113,30 @@ CONFIG_CPU_SH4=y CONFIG_CPU_SUBTYPE_SH7751R=y # CONFIG_CPU_SUBTYPE_SH7760 is not set # CONFIG_CPU_SUBTYPE_SH4_202 is not set - -# -# ST40 Processor Support -# # CONFIG_CPU_SUBTYPE_ST40STB1 is not set # CONFIG_CPU_SUBTYPE_ST40GX1 is not set - -# -# SH-4A Processor Support -# # CONFIG_CPU_SUBTYPE_SH7770 is not set # CONFIG_CPU_SUBTYPE_SH7780 is not set # CONFIG_CPU_SUBTYPE_SH7785 is not set - -# -# SH4AL-DSP Processor Support -# -# CONFIG_CPU_SUBTYPE_SH73180 is not set +# CONFIG_CPU_SUBTYPE_SHX3 is not set # CONFIG_CPU_SUBTYPE_SH7343 is not set # CONFIG_CPU_SUBTYPE_SH7722 is not set # # Memory management options # +CONFIG_QUICKLIST=y CONFIG_MMU=y CONFIG_PAGE_OFFSET=0x80000000 CONFIG_MEMORY_START=0x0c000000 CONFIG_MEMORY_SIZE=0x04000000 CONFIG_VSYSCALL=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_MAX_ACTIVE_REGIONS=1 +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_PAGE_SIZE_4KB=y # CONFIG_PAGE_SIZE_8KB is not set # CONFIG_PAGE_SIZE_64KB is not set @@ -197,17 +146,19 @@ CONFIG_FLATMEM_MANUAL=y # CONFIG_SPARSEMEM_MANUAL is not set CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y -# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPARSEMEM_STATIC=y CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_RESOURCES_64BIT is not set CONFIG_ZONE_DMA_FLAG=0 +CONFIG_NR_QUICK=2 # # Cache configuration # # CONFIG_SH_DIRECT_MAPPED is not set -# CONFIG_SH_WRITETHROUGH is not set -# CONFIG_SH_OCRAM is not set +CONFIG_CACHE_WRITEBACK=y +# CONFIG_CACHE_WRITETHROUGH is not set +# CONFIG_CACHE_OFF is not set # # Processor features @@ -215,7 +166,6 @@ CONFIG_ZONE_DMA_FLAG=0 CONFIG_CPU_LITTLE_ENDIAN=y # CONFIG_CPU_BIG_ENDIAN is not set CONFIG_SH_FPU=y -# CONFIG_SH_DSP is not set # CONFIG_SH_STORE_QUEUES is not set CONFIG_CPU_HAS_INTEVT=y CONFIG_CPU_HAS_INTC_IRQ=y @@ -223,17 +173,31 @@ CONFIG_CPU_HAS_SR_RB=y CONFIG_CPU_HAS_PTEA=y # -# Timer support +# Board support # -CONFIG_SH_TMU=y +# CONFIG_SH_7751_SYSTEMH is not set +# CONFIG_SH_SECUREEDGE5410 is not set +# CONFIG_SH_HS7751RVOIP is not set +CONFIG_SH_RTS7751R2D=y +# CONFIG_SH_LANDISK is not set +# CONFIG_SH_TITAN is not set +# CONFIG_SH_LBOX_RE2 is not set # # RTS7751R2D options # -CONFIG_RTS7751R2D_REV11=y +# CONFIG_RTS7751R2D_PLUS is not set +CONFIG_RTS7751R2D_1=y + +# +# Timer and clock configuration +# +CONFIG_SH_TMU=y CONFIG_SH_TIMER_IRQ=16 -# CONFIG_NO_IDLE_HZ is not set CONFIG_SH_PCLK_FREQ=60000000 +# CONFIG_TICK_ONESHOT is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set # # CPU Frequency scaling @@ -244,19 +208,15 @@ CONFIG_SH_PCLK_FREQ=60000000 # DMA support # # CONFIG_SH_DMA is not set -# CONFIG_NR_ONCHIP_DMA_CHANNELS is not set -# CONFIG_NR_DMA_CHANNELS_BOOL is not set # # Companion Chips # -CONFIG_VOYAGERGX=y -# CONFIG_HD6446X_SERIES is not set -CONFIG_HEARTBEAT=y # # Additional SuperH Device Drivers # +CONFIG_HEARTBEAT=y # CONFIG_PUSH_SWITCH is not set # @@ -268,7 +228,7 @@ CONFIG_HZ_250=y # CONFIG_HZ_1000 is not set CONFIG_HZ=250 # CONFIG_KEXEC is not set -# CONFIG_SMP is not set +# CONFIG_CRASH_DUMP is not set CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set @@ -289,15 +249,12 @@ CONFIG_PCI=y CONFIG_SH_PCIDMA_NONCOHERENT=y CONFIG_PCI_AUTO=y CONFIG_PCI_AUTO_UPDATE_RESOURCES=y +# CONFIG_ARCH_SUPPORTS_MSI is not set # # PCCARD (PCMCIA/CardBus) support # # CONFIG_PCCARD is not set - -# -# PCI Hotplug Support -# CONFIG_HOTPLUG_PCI=y # CONFIG_HOTPLUG_PCI_FAKE is not set # CONFIG_HOTPLUG_PCI_CPCI is not set @@ -307,15 +264,9 @@ CONFIG_HOTPLUG_PCI=y # Executable file formats # CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_FLAT is not set # CONFIG_BINFMT_MISC is not set # -# Power management options (EXPERIMENTAL) -# -# CONFIG_PM is not set - -# # Networking # CONFIG_NET=y @@ -323,7 +274,6 @@ CONFIG_NET=y # # Networking options # -# CONFIG_NETDEBUG is not set CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y @@ -360,20 +310,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_INET6_TUNNEL is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# # CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# # CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set @@ -399,8 +337,17 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set -# CONFIG_IEEE80211 is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set CONFIG_WIRELESS_EXT=y +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set # # Device Drivers @@ -413,31 +360,10 @@ CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=m # CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# # CONFIG_CONNECTOR is not set - -# -# Memory Technology Devices (MTD) -# # CONFIG_MTD is not set - -# -# Parallel port support -# # CONFIG_PARPORT is not set - -# -# Plug and Play support -# -# CONFIG_PNPACPI is not set - -# -# Block devices -# -# CONFIG_BLK_CPQ_DA is not set +CONFIG_BLK_DEV=y # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_UMEM is not set @@ -449,19 +375,13 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -# CONFIG_BLK_DEV_INITRD is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set - -# -# Misc devices -# +CONFIG_MISC_DEVICES=y +# CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set # CONFIG_SGI_IOC4 is not set # CONFIG_TIFM_CORE is not set - -# -# ATA/ATAPI/MFM/RLL support -# # CONFIG_IDE is not set # @@ -469,6 +389,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y +CONFIG_SCSI_DMA=y # CONFIG_SCSI_TGT is not set # CONFIG_SCSI_NETLINK is not set CONFIG_SCSI_PROC_FS=y @@ -490,6 +411,7 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set # CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m # # SCSI Transports @@ -497,12 +419,8 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_SPI_ATTRS is not set # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set -# CONFIG_SCSI_SAS_ATTRS is not set # CONFIG_SCSI_SAS_LIBSAS is not set - -# -# SCSI low-level drivers -# +CONFIG_SCSI_LOWLEVEL=y # CONFIG_ISCSI_TCP is not set # CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_3W_9XXX is not set @@ -512,7 +430,6 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_AIC94XX is not set -# CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ARCMSR is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set @@ -535,10 +452,6 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set # CONFIG_SCSI_SRP is not set - -# -# Serial ATA (prod) and Parallel ATA (experimental) drivers -# CONFIG_ATA=y # CONFIG_ATA_NONSTANDARD is not set # CONFIG_SATA_AHCI is not set @@ -561,6 +474,7 @@ CONFIG_ATA=y # CONFIG_PATA_AMD is not set # CONFIG_PATA_ARTOP is not set # CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD640_PCI is not set # CONFIG_PATA_CMD64X is not set # CONFIG_PATA_CS5520 is not set # CONFIG_PATA_CS5530 is not set @@ -593,10 +507,6 @@ CONFIG_ATA=y # CONFIG_PATA_VIA is not set # CONFIG_PATA_WINBOND is not set CONFIG_PATA_PLATFORM=y - -# -# Multi-device support (RAID and LVM) -# # CONFIG_MD is not set # @@ -610,35 +520,18 @@ CONFIG_PATA_PLATFORM=y # # IEEE 1394 (FireWire) support # +# CONFIG_FIREWIRE is not set # CONFIG_IEEE1394 is not set - -# -# I2O device support -# # CONFIG_I2O is not set - -# -# Network device support -# CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set # CONFIG_DUMMY is not set # CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set - -# -# ARCnet devices -# # CONFIG_ARCNET is not set - -# -# PHY device support -# # CONFIG_PHYLIB is not set - -# -# Ethernet (10 or 100Mbit) -# CONFIG_NET_ETHERNET=y CONFIG_MII=y # CONFIG_STNIC is not set @@ -647,10 +540,6 @@ CONFIG_MII=y # CONFIG_CASSINI is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_SMC91X is not set - -# -# Tulip family network device support -# # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set CONFIG_NET_PCI=y @@ -677,10 +566,7 @@ CONFIG_8139TOO=y # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_SC92031 is not set - -# -# Ethernet (1000 Mbit) -# +CONFIG_NETDEV_1000=y # CONFIG_ACENIC is not set # CONFIG_DL2K is not set # CONFIG_E1000 is not set @@ -691,61 +577,26 @@ CONFIG_8139TOO=y # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set -# CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set # CONFIG_QLA3XXX is not set # CONFIG_ATL1 is not set - -# -# Ethernet (10000 Mbit) -# +CONFIG_NETDEV_10000=y # CONFIG_CHELSIO_T1 is not set # CONFIG_CHELSIO_T3 is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set # CONFIG_MYRI10GE is not set # CONFIG_NETXEN_NIC is not set - -# -# Token Ring devices -# +# CONFIG_MLX4_CORE is not set # CONFIG_TR is not set # -# Wireless LAN (non-hamradio) -# -CONFIG_NET_RADIO=y -# CONFIG_NET_WIRELESS_RTNETLINK is not set - -# -# Obsolete Wireless cards support (pre-802.11) -# -# CONFIG_STRIP is not set - -# -# Wireless 802.11b ISA/PCI cards support -# -# CONFIG_IPW2100 is not set -# CONFIG_IPW2200 is not set -CONFIG_HERMES=m -# CONFIG_PLX_HERMES is not set -# CONFIG_TMD_HERMES is not set -# CONFIG_NORTEL_HERMES is not set -# CONFIG_PCI_HERMES is not set -# CONFIG_ATMEL is not set - -# -# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support -# -# CONFIG_PRISM54 is not set -# CONFIG_HOSTAP is not set -CONFIG_NET_WIRELESS=y - -# -# Wan interfaces +# Wireless LAN # +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set # CONFIG_WAN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set @@ -756,15 +607,7 @@ CONFIG_NET_WIRELESS=y # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# # CONFIG_ISDN is not set - -# -# Telephony Support -# # CONFIG_PHONE is not set # @@ -772,6 +615,7 @@ CONFIG_NET_WIRELESS=y # CONFIG_INPUT=y # CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set # # Userland interfaces @@ -788,6 +632,7 @@ CONFIG_INPUT=y # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set # CONFIG_INPUT_TOUCHSCREEN is not set # CONFIG_INPUT_MISC is not set @@ -828,32 +673,15 @@ CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# # CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# # CONFIG_WATCHDOG is not set CONFIG_HW_RANDOM=y -# CONFIG_GEN_RTC is not set -# CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set # CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# # CONFIG_TCG_TPM is not set - -# -# I2C support -# +CONFIG_DEVPORT=y # CONFIG_I2C is not set # @@ -861,21 +689,24 @@ CONFIG_HW_RANDOM=y # # CONFIG_SPI is not set # CONFIG_SPI_MASTER is not set - -# -# Dallas's 1-wire bus -# # CONFIG_W1 is not set - -# -# Hardware Monitoring support -# +# CONFIG_POWER_SUPPLY is not set CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set # CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set # CONFIG_HWMON_DEBUG_CHIP is not set # @@ -887,22 +718,31 @@ CONFIG_MFD_SM501=y # Multimedia devices # # CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y # -# Digital Video Broadcasting Devices +# Graphics support # -# CONFIG_DVB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # -# Graphics support +# Display device support # -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y # CONFIG_FIRMWARE_EDID is not set # CONFIG_FB_DDC is not set CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_SYS_FOPS is not set +CONFIG_FB_DEFERRED_IO=y # CONFIG_FB_SVGALIB is not set # CONFIG_FB_MACMODES is not set # CONFIG_FB_BACKLIGHT is not set @@ -910,14 +750,13 @@ CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_TILEBLITTING is not set # -# Frambuffer hardware drivers +# Frame buffer hardware drivers # # CONFIG_FB_CIRRUS is not set # CONFIG_FB_PM2 is not set # CONFIG_FB_CYBER2000 is not set # CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set -# CONFIG_FB_EPSON1355 is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_NVIDIA is not set # CONFIG_FB_RIVA is not set @@ -932,7 +771,10 @@ CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_KYRO is not set # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set # CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set CONFIG_FB_SM501=y # CONFIG_FB_VIRTUAL is not set @@ -941,14 +783,11 @@ CONFIG_FB_SM501=y # CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set # CONFIG_FONTS is not set CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y - -# -# Logo configuration -# CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set @@ -1048,35 +887,34 @@ CONFIG_SND_AC97_CODEC=m # CONFIG_SND_VIA82XX_MODEM is not set # CONFIG_SND_VX222 is not set CONFIG_SND_YMFPCI=m +CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y # CONFIG_SND_AC97_POWER_SAVE is not set # -# SoC audio support +# SUPERH devices +# + +# +# System on Chip audio support # # CONFIG_SND_SOC is not set # +# SoC Audio support for SuperH +# + +# # Open Sound System # CONFIG_SOUND_PRIME=m -# CONFIG_OBSOLETE_OSS is not set -# CONFIG_SOUND_BT878 is not set -# CONFIG_SOUND_ICH is not set # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set -# CONFIG_SOUND_VIA82CXXX is not set CONFIG_AC97_BUS=m - -# -# HID Devices -# +CONFIG_HID_SUPPORT=y CONFIG_HID=y # CONFIG_HID_DEBUG is not set - -# -# USB support -# +CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB_ARCH_HAS_EHCI=y @@ -1090,37 +928,9 @@ CONFIG_USB_ARCH_HAS_EHCI=y # USB Gadget Support # # CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# # CONFIG_MMC is not set - -# -# LED devices -# # CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# - -# -# InfiniBand support -# # CONFIG_INFINIBAND is not set - -# -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# - -# -# Real Time Clock -# CONFIG_RTC_LIB=y CONFIG_RTC_CLASS=y CONFIG_RTC_HCTOSYS=y @@ -1134,18 +944,28 @@ CONFIG_RTC_INTF_SYSFS=y CONFIG_RTC_INTF_PROC=y CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# SPI RTC drivers +# # -# RTC drivers +# Platform RTC drivers # # CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_DS1742 is not set # CONFIG_RTC_DRV_M48T86 is not set -CONFIG_RTC_DRV_SH=y -# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_M48T59 is not set # CONFIG_RTC_DRV_V3020 is not set # +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_SH=y + +# # DMA Engine support # # CONFIG_DMA_ENGINE is not set @@ -1159,12 +979,9 @@ CONFIG_RTC_DRV_SH=y # # -# Auxiliary Display support -# - -# -# Virtualization +# Userspace I/O # +# CONFIG_UIO is not set # # File systems @@ -1247,7 +1064,6 @@ CONFIG_RAMFS=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set # # Partition Types @@ -1321,7 +1137,6 @@ CONFIG_ENABLE_MUST_CHECK=y # CONFIG_DEBUG_FS is not set # CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_SH_STANDARD_BIOS is not set CONFIG_EARLY_SCIF_CONSOLE=y @@ -1334,10 +1149,6 @@ CONFIG_EARLY_PRINTK=y # # CONFIG_KEYS is not set # CONFIG_SECURITY is not set - -# -# Cryptographic options -# # CONFIG_CRYPTO is not set # @@ -1346,8 +1157,11 @@ CONFIG_EARLY_PRINTK=y CONFIG_BITREVERSE=y # CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y +# CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/sh/configs/rts7751r2dplus_defconfig b/arch/sh/configs/rts7751r2dplus_defconfig new file mode 100644 index 00000000000..4ff5a752dcd --- /dev/null +++ b/arch/sh/configs/rts7751r2dplus_defconfig @@ -0,0 +1,1167 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc2 +# Tue Aug 14 16:33:08 2007 +# +CONFIG_SUPERH=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_SYS_SUPPORTS_PCI=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# System type +# +CONFIG_CPU_SH4=y +# CONFIG_CPU_SUBTYPE_SH7619 is not set +# CONFIG_CPU_SUBTYPE_SH7206 is not set +# CONFIG_CPU_SUBTYPE_SH7705 is not set +# CONFIG_CPU_SUBTYPE_SH7706 is not set +# CONFIG_CPU_SUBTYPE_SH7707 is not set +# CONFIG_CPU_SUBTYPE_SH7708 is not set +# CONFIG_CPU_SUBTYPE_SH7709 is not set +# CONFIG_CPU_SUBTYPE_SH7710 is not set +# CONFIG_CPU_SUBTYPE_SH7712 is not set +# CONFIG_CPU_SUBTYPE_SH7750 is not set +# CONFIG_CPU_SUBTYPE_SH7091 is not set +# CONFIG_CPU_SUBTYPE_SH7750R is not set +# CONFIG_CPU_SUBTYPE_SH7750S is not set +# CONFIG_CPU_SUBTYPE_SH7751 is not set +CONFIG_CPU_SUBTYPE_SH7751R=y +# CONFIG_CPU_SUBTYPE_SH7760 is not set +# CONFIG_CPU_SUBTYPE_SH4_202 is not set +# CONFIG_CPU_SUBTYPE_ST40STB1 is not set +# CONFIG_CPU_SUBTYPE_ST40GX1 is not set +# CONFIG_CPU_SUBTYPE_SH7770 is not set +# CONFIG_CPU_SUBTYPE_SH7780 is not set +# CONFIG_CPU_SUBTYPE_SH7785 is not set +# CONFIG_CPU_SUBTYPE_SHX3 is not set +# CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set + +# +# Memory management options +# +CONFIG_QUICKLIST=y +CONFIG_MMU=y +CONFIG_PAGE_OFFSET=0x80000000 +CONFIG_MEMORY_START=0x0c000000 +CONFIG_MEMORY_SIZE=0x04000000 +CONFIG_VSYSCALL=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_MAX_ACTIVE_REGIONS=1 +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_SPARSEMEM_STATIC=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_NR_QUICK=2 + +# +# Cache configuration +# +# CONFIG_SH_DIRECT_MAPPED is not set +CONFIG_CACHE_WRITEBACK=y +# CONFIG_CACHE_WRITETHROUGH is not set +# CONFIG_CACHE_OFF is not set + +# +# Processor features +# +CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_SH_FPU=y +# CONFIG_SH_STORE_QUEUES is not set +CONFIG_CPU_HAS_INTEVT=y +CONFIG_CPU_HAS_INTC_IRQ=y +CONFIG_CPU_HAS_SR_RB=y +CONFIG_CPU_HAS_PTEA=y + +# +# Board support +# +# CONFIG_SH_7751_SYSTEMH is not set +# CONFIG_SH_SECUREEDGE5410 is not set +# CONFIG_SH_HS7751RVOIP is not set +CONFIG_SH_RTS7751R2D=y +# CONFIG_SH_LANDISK is not set +# CONFIG_SH_TITAN is not set +# CONFIG_SH_LBOX_RE2 is not set + +# +# RTS7751R2D options +# +CONFIG_RTS7751R2D_PLUS=y +# CONFIG_RTS7751R2D_1 is not set + +# +# Timer and clock configuration +# +CONFIG_SH_TMU=y +CONFIG_SH_TIMER_IRQ=16 +CONFIG_SH_PCLK_FREQ=60000000 +# CONFIG_TICK_ONESHOT is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# DMA support +# +# CONFIG_SH_DMA is not set + +# +# Companion Chips +# + +# +# Additional SuperH Device Drivers +# +CONFIG_HEARTBEAT=y +# CONFIG_PUSH_SWITCH is not set + +# +# Kernel features +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set + +# +# Boot options +# +CONFIG_ZERO_PAGE_OFFSET=0x00010000 +CONFIG_BOOT_LINK_OFFSET=0x00800000 +# CONFIG_UBC_WAKEUP is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1 earlyprintk=serial" + +# +# Bus options +# +CONFIG_PCI=y +CONFIG_SH_PCIDMA_NONCOHERENT=y +CONFIG_PCI_AUTO=y +CONFIG_PCI_AUTO_UPDATE_RESOURCES=y +# CONFIG_ARCH_SUPPORTS_MSI is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_FAKE is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +CONFIG_WIRELESS_EXT=y +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=m +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_SVW is not set +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +CONFIG_PATA_PLATFORM=y +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ARCNET is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_STNIC is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_SMC91X is not set +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +CONFIG_8139TOO=y +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_SC92031 is not set +CONFIG_NETDEV_1000=y +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set +CONFIG_NETDEV_10000=y +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_CONSOLE is not set +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=1 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_SM501=y + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_SYS_FOPS is not set +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +CONFIG_FB_SM501=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +# CONFIG_LOGO_LINUX_CLUT224 is not set +# CONFIG_LOGO_SUPERH_MONO is not set +# CONFIG_LOGO_SUPERH_VGA16 is not set +CONFIG_LOGO_SUPERH_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=y + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_AC97_CODEC=m +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# PCI devices +# +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VX222 is not set +CONFIG_SND_YMFPCI=m +CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y +# CONFIG_SND_AC97_POWER_SAVE is not set + +# +# SUPERH devices +# + +# +# System on Chip audio support +# +# CONFIG_SND_SOC is not set + +# +# SoC Audio support for SuperH +# + +# +# Open Sound System +# +CONFIG_SOUND_PRIME=m +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +CONFIG_AC97_BUS=m +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_INFINIBAND is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_SH=y + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_MINIX_FS=y +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_CODEPAGE_932=y +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Profiling support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=y + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_SH_STANDARD_BIOS is not set +CONFIG_EARLY_SCIF_CONSOLE=y +CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe80000 +CONFIG_EARLY_PRINTK=y +# CONFIG_SH_KGDB is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/sh/configs/se7206_defconfig b/arch/sh/configs/se7206_defconfig index f2f2a3c9c32..0d0cda90827 100644 --- a/arch/sh/configs/se7206_defconfig +++ b/arch/sh/configs/se7206_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.22-rc4 -# Fri Jun 15 19:37:46 2007 +# Linux kernel version: 2.6.23-rc4 +# Thu Sep 13 16:40:16 2007 # CONFIG_SUPERH=y CONFIG_RWSEM_GENERIC_SPINLOCK=y @@ -17,25 +17,22 @@ CONFIG_STACKTRACE_SUPPORT=y CONFIG_LOCKDEP_SUPPORT=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # -# Code maturity level options +# General setup # CONFIG_EXPERIMENTAL=y CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# CONFIG_LOCALVERSION="" # CONFIG_LOCALVERSION_AUTO is not set # CONFIG_SYSVIPC is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -# CONFIG_UTS_NS is not set +# CONFIG_USER_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set CONFIG_LOG_BUF_SHIFT=14 @@ -60,23 +57,17 @@ CONFIG_SIGNALFD=y CONFIG_TIMERFD=y CONFIG_EVENTFD=y # CONFIG_VM_EVENT_COUNTERS is not set -CONFIG_SLAB=y -# CONFIG_SLUB is not set +CONFIG_SLUB_DEBUG=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y # CONFIG_SLOB is not set CONFIG_TINY_SHMEM=y CONFIG_BASE_SMALL=1 - -# -# Loadable module support -# # CONFIG_MODULES is not set - -# -# Block layer -# CONFIG_BLOCK=y # CONFIG_LBD is not set # CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set # # IO Schedulers @@ -98,7 +89,6 @@ CONFIG_CPU_SH2=y CONFIG_CPU_SH2A=y # CONFIG_CPU_SUBTYPE_SH7619 is not set CONFIG_CPU_SUBTYPE_SH7206=y -# CONFIG_CPU_SUBTYPE_SH7300 is not set # CONFIG_CPU_SUBTYPE_SH7705 is not set # CONFIG_CPU_SUBTYPE_SH7706 is not set # CONFIG_CPU_SUBTYPE_SH7707 is not set @@ -106,6 +96,7 @@ CONFIG_CPU_SUBTYPE_SH7206=y # CONFIG_CPU_SUBTYPE_SH7709 is not set # CONFIG_CPU_SUBTYPE_SH7710 is not set # CONFIG_CPU_SUBTYPE_SH7712 is not set +# CONFIG_CPU_SUBTYPE_SH7720 is not set # CONFIG_CPU_SUBTYPE_SH7750 is not set # CONFIG_CPU_SUBTYPE_SH7091 is not set # CONFIG_CPU_SUBTYPE_SH7750R is not set @@ -119,7 +110,7 @@ CONFIG_CPU_SUBTYPE_SH7206=y # CONFIG_CPU_SUBTYPE_SH7770 is not set # CONFIG_CPU_SUBTYPE_SH7780 is not set # CONFIG_CPU_SUBTYPE_SH7785 is not set -# CONFIG_CPU_SUBTYPE_SH73180 is not set +# CONFIG_CPU_SUBTYPE_SHX3 is not set # CONFIG_CPU_SUBTYPE_SH7343 is not set # CONFIG_CPU_SUBTYPE_SH7722 is not set @@ -136,15 +127,16 @@ CONFIG_ARCH_SPARSEMEM_DEFAULT=y CONFIG_MAX_ACTIVE_REGIONS=1 CONFIG_ARCH_POPULATES_NODE_MAP=y CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y CONFIG_PAGE_SIZE_4KB=y # CONFIG_PAGE_SIZE_8KB is not set # CONFIG_PAGE_SIZE_64KB is not set CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y +# CONFIG_FLATMEM_MANUAL is not set # CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y CONFIG_SPARSEMEM_STATIC=y CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_RESOURCES_64BIT is not set @@ -155,7 +147,9 @@ CONFIG_NR_QUICK=2 # Cache configuration # # CONFIG_SH_DIRECT_MAPPED is not set -# CONFIG_SH_WRITETHROUGH is not set +CONFIG_CACHE_WRITEBACK=y +# CONFIG_CACHE_WRITETHROUGH is not set +# CONFIG_CACHE_OFF is not set # # Processor features @@ -163,8 +157,6 @@ CONFIG_NR_QUICK=2 # CONFIG_CPU_LITTLE_ENDIAN is not set CONFIG_CPU_BIG_ENDIAN=y # CONFIG_SH_FPU_EMU is not set -# CONFIG_SH_DSP is not set -CONFIG_CPU_HAS_IPR_IRQ=y # # Board support @@ -185,12 +177,23 @@ CONFIG_SH_CLK_MD=6 # # CPU Frequency scaling # -# CONFIG_CPU_FREQ is not set +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +# CONFIG_SH_CPU_FREQ is not set # # DMA support # -# CONFIG_SH_DMA is not set # # Companion Chips @@ -199,17 +202,17 @@ CONFIG_SH_CLK_MD=6 # # Additional SuperH Device Drivers # -# CONFIG_HEARTBEAT is not set +CONFIG_HEARTBEAT=y # CONFIG_PUSH_SWITCH is not set # # Kernel features # -CONFIG_HZ_100=y +# CONFIG_HZ_100 is not set # CONFIG_HZ_250 is not set # CONFIG_HZ_300 is not set -# CONFIG_HZ_1000 is not set -CONFIG_HZ=100 +CONFIG_HZ_1000=y +CONFIG_HZ=1000 # CONFIG_KEXEC is not set # CONFIG_CRASH_DUMP is not set CONFIG_PREEMPT_NONE=y @@ -221,11 +224,13 @@ CONFIG_PREEMPT_NONE=y # CONFIG_ZERO_PAGE_OFFSET=0x00001000 CONFIG_BOOT_LINK_OFFSET=0x00800000 -# CONFIG_CMDLINE_BOOL is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttySC3,115200 earlyprintk=serial ignore_loglevel" # # Bus options # +# CONFIG_CF_ENABLER is not set # CONFIG_ARCH_SUPPORTS_MSI is not set # @@ -315,6 +320,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set # CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set # # Device Drivers @@ -325,11 +331,9 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# # CONFIG_CONNECTOR is not set CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set @@ -411,31 +415,16 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=4 # UBI - Unsorted block images # # CONFIG_MTD_UBI is not set - -# -# Parallel port support -# # CONFIG_PARPORT is not set - -# -# Plug and Play support -# -# CONFIG_PNPACPI is not set - -# -# Block devices -# +CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_COW_COMMON is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set - -# -# Misc devices -# -# CONFIG_BLINK is not set +CONFIG_MISC_DEVICES=y +# CONFIG_EEPROM_93CX6 is not set # CONFIG_IDE is not set # @@ -443,27 +432,18 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=4 # # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set # CONFIG_SCSI_NETLINK is not set # CONFIG_ATA is not set - -# -# Multi-device support (RAID and LVM) -# # CONFIG_MD is not set - -# -# Network device support -# CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set # CONFIG_DUMMY is not set # CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_PHYLIB is not set - -# -# Ethernet (10 or 100Mbit) -# CONFIG_NET_ETHERNET=y CONFIG_MII=y # CONFIG_STNIC is not set @@ -483,15 +463,7 @@ CONFIG_NETDEV_10000=y # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# # CONFIG_ISDN is not set - -# -# Telephony Support -# # CONFIG_PHONE is not set # @@ -499,6 +471,7 @@ CONFIG_NETDEV_10000=y # CONFIG_INPUT=y # CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set # # Userland interfaces @@ -546,19 +519,11 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_UNIX98_PTYS is not set # CONFIG_LEGACY_PTYS is not set - -# -# IPMI -# # CONFIG_IPMI_HANDLER is not set # CONFIG_WATCHDOG is not set # CONFIG_HW_RANDOM is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# # CONFIG_TCG_TPM is not set # CONFIG_I2C is not set @@ -567,11 +532,8 @@ CONFIG_SERIAL_CORE_CONSOLE=y # # CONFIG_SPI is not set # CONFIG_SPI_MASTER is not set - -# -# Dallas's 1-wire bus -# # CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set # @@ -596,25 +558,21 @@ CONFIG_DAB=y # # CONFIG_DISPLAY_SUPPORT is not set # CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y # CONFIG_FB is not set # # Sound # # CONFIG_SOUND is not set - -# -# HID Devices -# +CONFIG_HID_SUPPORT=y CONFIG_HID=y # CONFIG_HID_DEBUG is not set - -# -# USB support -# -# CONFIG_USB_ARCH_HAS_HCD is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y # CONFIG_USB_ARCH_HAS_OHCI is not set # CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB is not set # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' @@ -625,31 +583,7 @@ CONFIG_HID=y # # CONFIG_USB_GADGET is not set # CONFIG_MMC is not set - -# -# LED devices -# # CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# - -# -# InfiniBand support -# - -# -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# - -# -# Real Time Clock -# # CONFIG_RTC_CLASS is not set # @@ -666,6 +600,11 @@ CONFIG_HID=y # # +# Userspace I/O +# +# CONFIG_UIO is not set + +# # File systems # # CONFIG_EXT2_FS is not set @@ -736,7 +675,6 @@ CONFIG_RAMFS=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set # # Partition Types @@ -752,12 +690,12 @@ CONFIG_MSDOS_PARTITION=y # # Distributed Lock Manager # -# CONFIG_DLM is not set # # Profiling support # -# CONFIG_PROFILING is not set +CONFIG_PROFILING=y +# CONFIG_OPROFILE is not set # # Kernel hacking @@ -768,19 +706,41 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set # CONFIG_HEADERS_CHECK is not set -# CONFIG_DEBUG_KERNEL is not set -# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +CONFIG_SLUB_DEBUG_ON=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FRAME_POINTER=y +CONFIG_FORCED_INLINING=y +# CONFIG_FAULT_INJECTION is not set # CONFIG_SH_STANDARD_BIOS is not set -# CONFIG_EARLY_SCIF_CONSOLE is not set +CONFIG_EARLY_SCIF_CONSOLE=y +CONFIG_EARLY_SCIF_CONSOLE_PORT=0xfffe9800 +CONFIG_EARLY_PRINTK=y +# CONFIG_DEBUG_BOOTMEM is not set +CONFIG_DEBUG_STACKOVERFLOW=y +CONFIG_DEBUG_STACK_USAGE=y +# CONFIG_4KSTACKS is not set # # Security options # # CONFIG_KEYS is not set - -# -# Cryptographic options -# # CONFIG_CRYPTO is not set # @@ -791,6 +751,7 @@ CONFIG_BITREVERSE=y # CONFIG_CRC16 is not set # CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y +# CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_HAS_IOMEM=y diff --git a/arch/sh/configs/shx3_defconfig b/arch/sh/configs/shx3_defconfig index 219bad558b1..a794c082709 100644 --- a/arch/sh/configs/shx3_defconfig +++ b/arch/sh/configs/shx3_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.22-rc4 -# Wed Jun 20 14:09:27 2007 +# Linux kernel version: 2.6.23-rc7 +# Fri Sep 21 19:07:30 2007 # CONFIG_SUPERH=y CONFIG_RWSEM_GENERIC_SPINLOCK=y @@ -13,32 +13,33 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_TIME=y CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_SYS_SUPPORTS_SMP=y +CONFIG_SYS_SUPPORTS_NUMA=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_LOCKDEP_SUPPORT=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # -# Code maturity level options +# General setup # CONFIG_EXPERIMENTAL=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y -# CONFIG_IPC_NS is not set CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set -# CONFIG_UTS_NS is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 @@ -63,34 +64,26 @@ CONFIG_FUTEX=y CONFIG_ANON_INODES=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y -CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_VM_EVENT_COUNTERS=y -CONFIG_SLAB=y +# CONFIG_SLAB is not set # CONFIG_SLUB is not set -# CONFIG_SLOB is not set +CONFIG_SLOB=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 - -# -# Loadable module support -# CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y - -# -# Block layer -# CONFIG_BLOCK=y # CONFIG_LBD is not set # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set # # IO Schedulers @@ -113,7 +106,6 @@ CONFIG_CPU_SH4A=y CONFIG_CPU_SHX3=y # CONFIG_CPU_SUBTYPE_SH7619 is not set # CONFIG_CPU_SUBTYPE_SH7206 is not set -# CONFIG_CPU_SUBTYPE_SH7300 is not set # CONFIG_CPU_SUBTYPE_SH7705 is not set # CONFIG_CPU_SUBTYPE_SH7706 is not set # CONFIG_CPU_SUBTYPE_SH7707 is not set @@ -121,6 +113,7 @@ CONFIG_CPU_SHX3=y # CONFIG_CPU_SUBTYPE_SH7709 is not set # CONFIG_CPU_SUBTYPE_SH7710 is not set # CONFIG_CPU_SUBTYPE_SH7712 is not set +# CONFIG_CPU_SUBTYPE_SH7720 is not set # CONFIG_CPU_SUBTYPE_SH7750 is not set # CONFIG_CPU_SUBTYPE_SH7091 is not set # CONFIG_CPU_SUBTYPE_SH7750R is not set @@ -135,7 +128,6 @@ CONFIG_CPU_SHX3=y # CONFIG_CPU_SUBTYPE_SH7780 is not set # CONFIG_CPU_SUBTYPE_SH7785 is not set CONFIG_CPU_SUBTYPE_SHX3=y -# CONFIG_CPU_SUBTYPE_SH73180 is not set # CONFIG_CPU_SUBTYPE_SH7343 is not set # CONFIG_CPU_SUBTYPE_SH7722 is not set @@ -148,12 +140,15 @@ CONFIG_PAGE_OFFSET=0x80000000 CONFIG_MEMORY_START=0x0c000000 CONFIG_MEMORY_SIZE=0x04000000 CONFIG_VSYSCALL=y +# CONFIG_NUMA is not set CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_ARCH_SPARSEMEM_DEFAULT=y -CONFIG_MAX_ACTIVE_REGIONS=1 +CONFIG_MAX_ACTIVE_REGIONS=6 CONFIG_ARCH_POPULATES_NODE_MAP=y CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_MEMORY_PROBE=y CONFIG_PAGE_SIZE_4KB=y # CONFIG_PAGE_SIZE_8KB is not set # CONFIG_PAGE_SIZE_64KB is not set @@ -163,12 +158,14 @@ CONFIG_HUGETLB_PAGE_SIZE_64K=y # CONFIG_HUGETLB_PAGE_SIZE_4MB is not set # CONFIG_HUGETLB_PAGE_SIZE_64MB is not set CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y +# CONFIG_FLATMEM_MANUAL is not set # CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y CONFIG_SPARSEMEM_STATIC=y +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTPLUG_SPARSE=y CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_RESOURCES_64BIT is not set CONFIG_ZONE_DMA_FLAG=0 @@ -178,24 +175,25 @@ CONFIG_NR_QUICK=2 # Cache configuration # # CONFIG_SH_DIRECT_MAPPED is not set -# CONFIG_SH_WRITETHROUGH is not set +# CONFIG_CACHE_WRITEBACK is not set +# CONFIG_CACHE_WRITETHROUGH is not set +CONFIG_CACHE_OFF=y # # Processor features # CONFIG_CPU_LITTLE_ENDIAN=y # CONFIG_CPU_BIG_ENDIAN is not set -# CONFIG_SH_FPU is not set -# CONFIG_SH_FPU_EMU is not set -CONFIG_SH_DSP=y +CONFIG_SH_FPU=y CONFIG_SH_STORE_QUEUES=y CONFIG_CPU_HAS_INTEVT=y -CONFIG_CPU_HAS_INTC2_IRQ=y CONFIG_CPU_HAS_SR_RB=y +CONFIG_CPU_HAS_FPU=y # # Board support # +CONFIG_SH_X3PROTO=y # # Timer and clock configuration @@ -204,13 +202,25 @@ CONFIG_SH_TMU=y CONFIG_SH_TIMER_IRQ=16 CONFIG_SH_PCLK_FREQ=50000000 CONFIG_TICK_ONESHOT=y -CONFIG_NO_HZ=y +# CONFIG_NO_HZ is not set CONFIG_HIGH_RES_TIMERS=y # # CPU Frequency scaling # -# CONFIG_CPU_FREQ is not set +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_SH_CPU_FREQ=y # # DMA support @@ -237,6 +247,7 @@ CONFIG_HZ_250=y CONFIG_HZ=250 CONFIG_KEXEC=y # CONFIG_CRASH_DUMP is not set +# CONFIG_SMP is not set # CONFIG_PREEMPT_NONE is not set # CONFIG_PREEMPT_VOLUNTARY is not set CONFIG_PREEMPT=y @@ -249,7 +260,7 @@ CONFIG_ZERO_PAGE_OFFSET=0x00001000 CONFIG_BOOT_LINK_OFFSET=0x00800000 # CONFIG_UBC_WAKEUP is not set CONFIG_CMDLINE_BOOL=y -CONFIG_CMDLINE="console=ttySC0,115200 ip=192.168.1.2:::255.255.255.0 root=/dev/nfs nfsroot=192.168.1.1:/exports/devel/rfs/mobiler noaliencache earlyprintk=bios ignore_loglevel" +CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=bios ignore_loglevel" # # Bus options @@ -265,12 +276,106 @@ CONFIG_CMDLINE="console=ttySC0,115200 ip=192.168.1.2:::255.255.255.0 root=/dev/n # Executable file formats # CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_MISC=y # # Networking # -# CONFIG_NET is not set +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_UNIX is not set +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set # # Device Drivers @@ -285,37 +390,21 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_DEBUG_DRIVER is not set # CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# +# CONFIG_CONNECTOR is not set # CONFIG_MTD is not set - -# -# Parallel port support -# # CONFIG_PARPORT is not set - -# -# Plug and Play support -# -# CONFIG_PNPACPI is not set - -# -# Block devices -# +CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_COW_COMMON is not set # CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_CDROM_PKTCDVD is not set - -# -# Misc devices -# -# CONFIG_BLINK is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_EEPROM_93CX6 is not set # CONFIG_IDE is not set # @@ -323,6 +412,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y +CONFIG_SCSI_DMA=y # CONFIG_SCSI_TGT is not set # CONFIG_SCSI_NETLINK is not set CONFIG_SCSI_PROC_FS=y @@ -351,73 +441,54 @@ CONFIG_SCSI_WAIT_SCAN=m # # CONFIG_SCSI_SPI_ATTRS is not set # CONFIG_SCSI_FC_ATTRS is not set -# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set # CONFIG_SCSI_SAS_LIBSAS is not set - -# -# SCSI low-level drivers -# +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set # CONFIG_SCSI_DEBUG is not set CONFIG_ATA=y # CONFIG_ATA_NONSTANDARD is not set CONFIG_PATA_PLATFORM=y - -# -# Multi-device support (RAID and LVM) -# # CONFIG_MD is not set - -# -# ISDN subsystem -# - -# -# Telephony Support -# +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_STNIC is not set +CONFIG_SMC91X=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set # CONFIG_PHONE is not set # # Input device support # -CONFIG_INPUT=y -# CONFIG_INPUT_FF_MEMLESS is not set - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -# CONFIG_INPUT_EVDEV is not set -# CONFIG_INPUT_EVBUG is not set - -# -# Input Device Drivers -# -CONFIG_INPUT_KEYBOARD=y -CONFIG_KEYBOARD_ATKBD=y -# CONFIG_KEYBOARD_SUNKBD is not set -# CONFIG_KEYBOARD_LKKBD is not set -# CONFIG_KEYBOARD_XTKBD is not set -# CONFIG_KEYBOARD_NEWTON is not set -# CONFIG_KEYBOARD_STOWAWAY is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TABLET is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set +# CONFIG_INPUT is not set # # Hardware I/O ports # -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_SERIO_SERPORT is not set -CONFIG_SERIO_LIBPS2=y -# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO is not set # CONFIG_GAMEPORT is not set # @@ -442,19 +513,18 @@ CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set # -# IPMI +# Watchdog Device Drivers # -# CONFIG_IPMI_HANDLER is not set -# CONFIG_WATCHDOG is not set -CONFIG_HW_RANDOM=y +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SH_WDT is not set +# CONFIG_HW_RANDOM is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# # CONFIG_TCG_TPM is not set # CONFIG_I2C is not set @@ -463,11 +533,8 @@ CONFIG_HW_RANDOM=y # # CONFIG_SPI is not set # CONFIG_SPI_MASTER is not set - -# -# Dallas's 1-wire bus -# # CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set # @@ -479,6 +546,7 @@ CONFIG_HW_RANDOM=y # Multimedia devices # # CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set # CONFIG_DAB is not set # @@ -491,24 +559,18 @@ CONFIG_HW_RANDOM=y # # CONFIG_DISPLAY_SUPPORT is not set # CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_FB is not set # # Sound # # CONFIG_SOUND is not set - -# -# HID Devices -# -# CONFIG_HID is not set - -# -# USB support -# -# CONFIG_USB_ARCH_HAS_HCD is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y # CONFIG_USB_ARCH_HAS_OHCI is not set # CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB is not set # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' @@ -517,68 +579,32 @@ CONFIG_HW_RANDOM=y # # USB Gadget Support # -# CONFIG_USB_GADGET is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_PXA2XX is not set +CONFIG_USB_GADGET_M66592=y +CONFIG_USB_M66592=y +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set # CONFIG_MMC is not set - -# -# LED devices -# # CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# - -# -# InfiniBand support -# - -# -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# - -# -# Real Time Clock -# -CONFIG_RTC_LIB=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_HCTOSYS=y -CONFIG_RTC_HCTOSYS_DEVICE="rtc0" -# CONFIG_RTC_DEBUG is not set - -# -# RTC interfaces -# -CONFIG_RTC_INTF_SYSFS=y -CONFIG_RTC_INTF_PROC=y -CONFIG_RTC_INTF_DEV=y -# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set -# CONFIG_RTC_DRV_TEST is not set - -# -# I2C RTC drivers -# - -# -# SPI RTC drivers -# - -# -# Platform RTC drivers -# -# CONFIG_RTC_DRV_DS1553 is not set -# CONFIG_RTC_DRV_DS1742 is not set -# CONFIG_RTC_DRV_M48T86 is not set -# CONFIG_RTC_DRV_V3020 is not set - -# -# on-CPU RTC drivers -# -CONFIG_RTC_DRV_SH=y +# CONFIG_RTC_CLASS is not set # # DMA Engine support @@ -594,6 +620,11 @@ CONFIG_RTC_DRV_SH=y # # +# Userspace I/O +# +CONFIG_UIO=m + +# # File systems # CONFIG_EXT2_FS=y @@ -612,6 +643,7 @@ CONFIG_FS_MBCACHE=y # CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set # CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_INOTIFY=y @@ -667,6 +699,17 @@ CONFIG_RAMFS=y # CONFIG_UFS_FS is not set # +# Network File Systems +# +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# # Partition Types # # CONFIG_PARTITION_ADVANCED is not set @@ -678,6 +721,11 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_NLS is not set # +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# # Profiling support # CONFIG_PROFILING=y @@ -687,31 +735,28 @@ CONFIG_PROFILING=y # Kernel hacking # CONFIG_TRACE_IRQFLAGS_SUPPORT=y -CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_TIME is not set # CONFIG_ENABLE_MUST_CHECK is not set CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_FS=y # CONFIG_HEADERS_CHECK is not set CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DEBUG_SHIRQ=y CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y # CONFIG_SCHEDSTATS is not set # CONFIG_TIMER_STATS is not set -CONFIG_DEBUG_SLAB=y -CONFIG_DEBUG_SLAB_LEAK=y CONFIG_DEBUG_PREEMPT=y # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set -CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_LOCK_ALLOC=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set # CONFIG_PROVE_LOCKING is not set -CONFIG_LOCKDEP=y -CONFIG_DEBUG_LOCKDEP=y +# CONFIG_LOCK_STAT is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -CONFIG_STACKTRACE=y # CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set @@ -735,10 +780,6 @@ CONFIG_DEBUG_STACK_USAGE=y # # CONFIG_KEYS is not set # CONFIG_SECURITY is not set - -# -# Cryptographic options -# # CONFIG_CRYPTO is not set # @@ -749,6 +790,7 @@ CONFIG_BITREVERSE=y # CONFIG_CRC16 is not set # CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y +# CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set CONFIG_PLIST=y CONFIG_HAS_IOMEM=y diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig index ee711431e50..4e711a0c3da 100644 --- a/arch/sh/drivers/dma/Kconfig +++ b/arch/sh/drivers/dma/Kconfig @@ -12,6 +12,7 @@ config SH_DMA config NR_ONCHIP_DMA_CHANNELS int depends on SH_DMA + default "6" if CPU_SUBTYPE_SH7720 default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R default "12" if CPU_SUBTYPE_SH7780 default "4" diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c index 06ed0609a95..958bac1c585 100644 --- a/arch/sh/drivers/dma/dma-sh.c +++ b/arch/sh/drivers/dma/dma-sh.c @@ -24,13 +24,19 @@ static int dmte_irq_map[] = { DMTE1_IRQ, DMTE2_IRQ, DMTE3_IRQ, -#if defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ +#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ defined(CONFIG_CPU_SUBTYPE_SH7760) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) || \ defined(CONFIG_CPU_SUBTYPE_SH7780) DMTE4_IRQ, DMTE5_IRQ, +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7760) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) DMTE6_IRQ, - DMTE7_IRQ, + DMTE7_IRQ, #endif }; @@ -196,7 +202,8 @@ static int sh_dmac_get_dma_residue(struct dma_channel *chan) return ctrl_inl(DMATCR[chan->chan]) << calc_xmit_shift(chan); } -#ifdef CONFIG_CPU_SUBTYPE_SH7780 +#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) #define dmaor_read_reg() ctrl_inw(DMAOR) #define dmaor_write_reg(data) ctrl_outw(data, DMAOR) #else diff --git a/arch/sh/drivers/heartbeat.c b/arch/sh/drivers/heartbeat.c index 10c1828c9ff..b76a14f12ce 100644 --- a/arch/sh/drivers/heartbeat.c +++ b/arch/sh/drivers/heartbeat.c @@ -24,24 +24,44 @@ #include <linux/sched.h> #include <linux/timer.h> #include <linux/io.h> +#include <asm/heartbeat.h> #define DRV_NAME "heartbeat" -#define DRV_VERSION "0.1.0" +#define DRV_VERSION "0.1.1" -struct heartbeat_data { - void __iomem *base; - unsigned char bit_pos[8]; - struct timer_list timer; -}; +static unsigned char default_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + +static inline void heartbeat_toggle_bit(struct heartbeat_data *hd, + unsigned bit, unsigned int inverted) +{ + unsigned int new; + + new = (1 << hd->bit_pos[bit]); + if (inverted) + new = ~new; + + switch (hd->regsize) { + case 32: + iowrite32(new, hd->base); + break; + case 16: + iowrite16(new, hd->base); + break; + default: + iowrite8(new, hd->base); + break; + } +} static void heartbeat_timer(unsigned long data) { struct heartbeat_data *hd = (struct heartbeat_data *)data; static unsigned bit = 0, up = 1; - ctrl_outw(1 << hd->bit_pos[bit], (unsigned long)hd->base); + heartbeat_toggle_bit(hd, bit, hd->flags & HEARTBEAT_INVERTED); + bit += up; - if ((bit == 0) || (bit == ARRAY_SIZE(hd->bit_pos)-1)) + if ((bit == 0) || (bit == (hd->nr_bits)-1)) up = -up; mod_timer(&hd->timer, jiffies + (110 - ((300 << FSHIFT) / @@ -64,21 +84,31 @@ static int heartbeat_drv_probe(struct platform_device *pdev) return -EINVAL; } - hd = kmalloc(sizeof(struct heartbeat_data), GFP_KERNEL); - if (unlikely(!hd)) - return -ENOMEM; - if (pdev->dev.platform_data) { - memcpy(hd->bit_pos, pdev->dev.platform_data, - ARRAY_SIZE(hd->bit_pos)); + hd = pdev->dev.platform_data; } else { - int i; + hd = kzalloc(sizeof(struct heartbeat_data), GFP_KERNEL); + if (unlikely(!hd)) + return -ENOMEM; + } + + hd->base = ioremap_nocache(res->start, res->end - res->start + 1); + if (!unlikely(hd->base)) { + dev_err(&pdev->dev, "ioremap failed\n"); + + if (!pdev->dev.platform_data) + kfree(hd); + + return -ENXIO; + } - for (i = 0; i < ARRAY_SIZE(hd->bit_pos); i++) - hd->bit_pos[i] = i; + if (!hd->nr_bits) { + hd->bit_pos = default_bit_pos; + hd->nr_bits = ARRAY_SIZE(default_bit_pos); } - hd->base = (void __iomem *)(unsigned long)res->start; + if (!hd->regsize) + hd->regsize = 8; /* default access size */ setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd); platform_set_drvdata(pdev, hd); @@ -91,10 +121,12 @@ static int heartbeat_drv_remove(struct platform_device *pdev) struct heartbeat_data *hd = platform_get_drvdata(pdev); del_timer_sync(&hd->timer); + iounmap(hd->base); platform_set_drvdata(pdev, NULL); - kfree(hd); + if (!pdev->dev.platform_data) + kfree(hd); return 0; } diff --git a/arch/sh/drivers/pci/ops-rts7751r2d.c b/arch/sh/drivers/pci/ops-rts7751r2d.c index 4a518d94804..ec8430c8d2d 100644 --- a/arch/sh/drivers/pci/ops-rts7751r2d.c +++ b/arch/sh/drivers/pci/ops-rts7751r2d.c @@ -19,10 +19,10 @@ #include "pci-sh4.h" static u8 rts7751r2d_irq_tab[] __initdata = { - IRQ_PCISLOT1, - IRQ_PCISLOT2, - IRQ_PCMCIA, - IRQ_PCIETH, + IRQ_PCI_INTA, + IRQ_PCI_INTB, + IRQ_PCI_INTC, + IRQ_PCI_INTD, }; int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index 5508e45d483..e516087fb43 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -79,19 +79,6 @@ static int __init sh7780_pci_init(void) ctrl_outl(0xAAAA0000, INTC_ICR1); /* INTPRI: priority=3(all) */ ctrl_outl(0x33333333, INTC_INTPRI); - } else { - /* INTC SH-4 Mode */ - ctrl_outl(0x00200000, INTC_ICR0); - /* enable PCIINTA - PCIINTD */ - ctrl_outl(0x00078000, INTC_INT2MSKCR); - /* disable IRL4-7 Interrupt */ - ctrl_outl(0x40000000, INTC_INTMSK1); - /* disable IRL4-7 Interrupt */ - ctrl_outl(0x0000fffe, INTC_INTMSK2); - /* enable IRL0-3 Interrupt */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); - /* enable IRL0-3 Interrupt */ - ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); } if ((ret = sh4_pci_check_direct()) != 0) diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index 92807ffa8e2..b5f1e23ed57 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c @@ -83,6 +83,8 @@ static void propagate_rate(struct clk *clk) continue; if (likely(clkp->ops && clkp->ops->recalc)) clkp->ops->recalc(clkp); + if (unlikely(clkp->flags & CLK_RATE_PROPAGATES)) + propagate_rate(clkp); } } diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index 9172e97dc26..c217c4bf008 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c @@ -22,6 +22,7 @@ #include <asm/cache.h> #include <asm/io.h> #include <asm/ubc.h> +#include <asm/smp.h> /* * Generic wrapper for command line arguments to disable on-chip @@ -143,12 +144,15 @@ static void __init cache_init(void) flags &= ~CCR_CACHE_EMODE; #endif -#ifdef CONFIG_SH_WRITETHROUGH - /* Turn on Write-through caching */ +#if defined(CONFIG_CACHE_WRITETHROUGH) + /* Write-through */ flags |= CCR_CACHE_WT; -#else - /* .. or default to Write-back */ +#elif defined(CONFIG_CACHE_WRITEBACK) + /* Write-back */ flags |= CCR_CACHE_CB; +#else + /* Off */ + flags &= ~CCR_CACHE_ENABLE; #endif ctrl_outl(flags, CCR); @@ -213,8 +217,11 @@ static void __init dsp_init(void) * Each processor family is still responsible for doing its own probing * and cache configuration in detect_cpu_and_cache_system(). */ -asmlinkage void __init sh_cpu_init(void) + +asmlinkage void __cpuinit sh_cpu_init(void) { + current_thread_info()->cpu = hard_smp_processor_id(); + /* First, probe the CPU */ detect_cpu_and_cache_system(); @@ -224,9 +231,10 @@ asmlinkage void __init sh_cpu_init(void) /* Init the cache */ cache_init(); - shm_align_mask = max_t(unsigned long, - current_cpu_data.dcache.way_size - 1, - PAGE_SIZE - 1); + if (raw_smp_processor_id() == 0) + shm_align_mask = max_t(unsigned long, + current_cpu_data.dcache.way_size - 1, + PAGE_SIZE - 1); /* Disable the FPU */ if (fpu_disabled) { @@ -265,6 +273,7 @@ asmlinkage void __init sh_cpu_init(void) * like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB. So .. * we wake it up and hope that all is well. */ - ubc_wakeup(); + if (raw_smp_processor_id() == 0) + ubc_wakeup(); speculative_execution_init(); } diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile index 60bfc05cf35..8da8e178f09 100644 --- a/arch/sh/kernel/cpu/irq/Makefile +++ b/arch/sh/kernel/cpu/irq/Makefile @@ -1,9 +1,7 @@ # # Makefile for the Linux/SuperH CPU-specifc IRQ handlers. # -obj-y += imask.o +obj-y += imask.o intc.o obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o -obj-$(CONFIG_CPU_HAS_INTC_IRQ) += intc.o -obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c index 9345a7130e9..6ac018c15e0 100644 --- a/arch/sh/kernel/cpu/irq/intc.c +++ b/arch/sh/kernel/cpu/irq/intc.c @@ -20,145 +20,258 @@ #include <linux/module.h> #include <linux/io.h> #include <linux/interrupt.h> +#include <linux/bootmem.h> + +#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ + ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ + ((addr_e) << 16) | ((addr_d << 24))) + +#define _INTC_SHIFT(h) (h & 0x1f) +#define _INTC_WIDTH(h) ((h >> 5) & 0xf) +#define _INTC_FN(h) ((h >> 9) & 0xf) +#define _INTC_MODE(h) ((h >> 13) & 0x7) +#define _INTC_ADDR_E(h) ((h >> 16) & 0xff) +#define _INTC_ADDR_D(h) ((h >> 24) & 0xff) + +struct intc_handle_int { + unsigned int irq; + unsigned long handle; +}; + +struct intc_desc_int { + unsigned long *reg; +#ifdef CONFIG_SMP + unsigned long *smp; +#endif + unsigned int nr_reg; + struct intc_handle_int *prio; + unsigned int nr_prio; + struct intc_handle_int *sense; + unsigned int nr_sense; + struct irq_chip chip; +}; -#define _INTC_MK(fn, idx, bit, value) \ - ((fn) << 24 | ((value) << 16) | ((idx) << 8) | (bit)) -#define _INTC_FN(h) (h >> 24) -#define _INTC_VALUE(h) ((h >> 16) & 0xff) -#define _INTC_IDX(h) ((h >> 8) & 0xff) -#define _INTC_BIT(h) (h & 0xff) +#ifdef CONFIG_SMP +#define IS_SMP(x) x.smp +#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c)) +#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1) +#else +#define IS_SMP(x) 0 +#define INTC_REG(d, x, c) (d->reg[(x)]) +#define SMP_NR(d, x) 1 +#endif -#define _INTC_PTR(desc, member, data) \ - (desc->member + _INTC_IDX(data)) +static unsigned int intc_prio_level[NR_IRQS]; /* for now */ -static inline struct intc_desc *get_intc_desc(unsigned int irq) +static inline struct intc_desc_int *get_intc_desc(unsigned int irq) { struct irq_chip *chip = get_irq_chip(irq); - return (void *)((char *)chip - offsetof(struct intc_desc, chip)); + return (void *)((char *)chip - offsetof(struct intc_desc_int, chip)); } static inline unsigned int set_field(unsigned int value, unsigned int field_value, - unsigned int width, - unsigned int shift) + unsigned int handle) { + unsigned int width = _INTC_WIDTH(handle); + unsigned int shift = _INTC_SHIFT(handle); + value &= ~(((1 << width) - 1) << shift); value |= field_value << shift; return value; } -static inline unsigned int set_prio_field(struct intc_desc *desc, - unsigned int value, - unsigned int priority, - unsigned int data) +static void write_8(unsigned long addr, unsigned long h, unsigned long data) { - unsigned int width = _INTC_PTR(desc, prio_regs, data)->field_width; - - return set_field(value, priority, width, _INTC_BIT(data)); + ctrl_outb(set_field(0, data, h), addr); } -static void disable_prio_16(struct intc_desc *desc, unsigned int data) +static void write_16(unsigned long addr, unsigned long h, unsigned long data) { - unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg; - - ctrl_outw(set_prio_field(desc, ctrl_inw(addr), 0, data), addr); + ctrl_outw(set_field(0, data, h), addr); } -static void enable_prio_16(struct intc_desc *desc, unsigned int data) +static void write_32(unsigned long addr, unsigned long h, unsigned long data) { - unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg; - unsigned int prio = _INTC_VALUE(data); - - ctrl_outw(set_prio_field(desc, ctrl_inw(addr), prio, data), addr); + ctrl_outl(set_field(0, data, h), addr); } -static void disable_prio_32(struct intc_desc *desc, unsigned int data) +static void modify_8(unsigned long addr, unsigned long h, unsigned long data) { - unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg; - - ctrl_outl(set_prio_field(desc, ctrl_inl(addr), 0, data), addr); + ctrl_outb(set_field(ctrl_inb(addr), data, h), addr); } -static void enable_prio_32(struct intc_desc *desc, unsigned int data) +static void modify_16(unsigned long addr, unsigned long h, unsigned long data) { - unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg; - unsigned int prio = _INTC_VALUE(data); - - ctrl_outl(set_prio_field(desc, ctrl_inl(addr), prio, data), addr); + ctrl_outw(set_field(ctrl_inw(addr), data, h), addr); } -static void disable_mask_8(struct intc_desc *desc, unsigned int data) +static void modify_32(unsigned long addr, unsigned long h, unsigned long data) { - ctrl_outb(1 << _INTC_BIT(data), - _INTC_PTR(desc, mask_regs, data)->set_reg); + ctrl_outl(set_field(ctrl_inl(addr), data, h), addr); } -static void enable_mask_8(struct intc_desc *desc, unsigned int data) +enum { REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 }; + +static void (*intc_reg_fns[])(unsigned long addr, + unsigned long h, + unsigned long data) = { + [REG_FN_WRITE_BASE + 0] = write_8, + [REG_FN_WRITE_BASE + 1] = write_16, + [REG_FN_WRITE_BASE + 3] = write_32, + [REG_FN_MODIFY_BASE + 0] = modify_8, + [REG_FN_MODIFY_BASE + 1] = modify_16, + [REG_FN_MODIFY_BASE + 3] = modify_32, +}; + +enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */ + MODE_MASK_REG, /* Bit(s) set -> interrupt disabled */ + MODE_DUAL_REG, /* Two registers, set bit to enable / disable */ + MODE_PRIO_REG, /* Priority value written to enable interrupt */ + MODE_PCLR_REG, /* Above plus all bits set to disable interrupt */ +}; + +static void intc_mode_field(unsigned long addr, + unsigned long handle, + void (*fn)(unsigned long, + unsigned long, + unsigned long), + unsigned int irq) { - ctrl_outb(1 << _INTC_BIT(data), - _INTC_PTR(desc, mask_regs, data)->clr_reg); + fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1)); } -static void disable_mask_32(struct intc_desc *desc, unsigned int data) +static void intc_mode_zero(unsigned long addr, + unsigned long handle, + void (*fn)(unsigned long, + unsigned long, + unsigned long), + unsigned int irq) { - ctrl_outl(1 << _INTC_BIT(data), - _INTC_PTR(desc, mask_regs, data)->set_reg); + fn(addr, handle, 0); } -static void enable_mask_32(struct intc_desc *desc, unsigned int data) +static void intc_mode_prio(unsigned long addr, + unsigned long handle, + void (*fn)(unsigned long, + unsigned long, + unsigned long), + unsigned int irq) { - ctrl_outl(1 << _INTC_BIT(data), - _INTC_PTR(desc, mask_regs, data)->clr_reg); + fn(addr, handle, intc_prio_level[irq]); } -enum { REG_FN_ERROR=0, - REG_FN_MASK_8, REG_FN_MASK_32, - REG_FN_PRIO_16, REG_FN_PRIO_32 }; - -static struct { - void (*enable)(struct intc_desc *, unsigned int); - void (*disable)(struct intc_desc *, unsigned int); -} intc_reg_fns[] = { - [REG_FN_MASK_8] = { enable_mask_8, disable_mask_8 }, - [REG_FN_MASK_32] = { enable_mask_32, disable_mask_32 }, - [REG_FN_PRIO_16] = { enable_prio_16, disable_prio_16 }, - [REG_FN_PRIO_32] = { enable_prio_32, disable_prio_32 }, +static void (*intc_enable_fns[])(unsigned long addr, + unsigned long handle, + void (*fn)(unsigned long, + unsigned long, + unsigned long), + unsigned int irq) = { + [MODE_ENABLE_REG] = intc_mode_field, + [MODE_MASK_REG] = intc_mode_zero, + [MODE_DUAL_REG] = intc_mode_field, + [MODE_PRIO_REG] = intc_mode_prio, + [MODE_PCLR_REG] = intc_mode_prio, }; -static void intc_enable(unsigned int irq) +static void (*intc_disable_fns[])(unsigned long addr, + unsigned long handle, + void (*fn)(unsigned long, + unsigned long, + unsigned long), + unsigned int irq) = { + [MODE_ENABLE_REG] = intc_mode_zero, + [MODE_MASK_REG] = intc_mode_field, + [MODE_DUAL_REG] = intc_mode_field, + [MODE_PRIO_REG] = intc_mode_zero, + [MODE_PCLR_REG] = intc_mode_field, +}; + +static inline void _intc_enable(unsigned int irq, unsigned long handle) { - struct intc_desc *desc = get_intc_desc(irq); - unsigned int data = (unsigned int) get_irq_chip_data(irq); + struct intc_desc_int *d = get_intc_desc(irq); + unsigned long addr; + unsigned int cpu; + + for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) { + addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu); + intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\ + [_INTC_FN(handle)], irq); + } +} - intc_reg_fns[_INTC_FN(data)].enable(desc, data); +static void intc_enable(unsigned int irq) +{ + _intc_enable(irq, (unsigned long)get_irq_chip_data(irq)); } static void intc_disable(unsigned int irq) { - struct intc_desc *desc = get_intc_desc(irq); - unsigned int data = (unsigned int) get_irq_chip_data(irq); - - intc_reg_fns[_INTC_FN(data)].disable(desc, data); + struct intc_desc_int *d = get_intc_desc(irq); + unsigned long handle = (unsigned long) get_irq_chip_data(irq); + unsigned long addr; + unsigned int cpu; + + for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { + addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu); + intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\ + [_INTC_FN(handle)], irq); + } } -static void set_sense_16(struct intc_desc *desc, unsigned int data) +static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp, + unsigned int nr_hp, + unsigned int irq) { - unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg; - unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width; - unsigned int bit = _INTC_BIT(data); - unsigned int value = _INTC_VALUE(data); + int i; + + /* this doesn't scale well, but... + * + * this function should only be used for cerain uncommon + * operations such as intc_set_priority() and intc_set_sense() + * and in those rare cases performance doesn't matter that much. + * keeping the memory footprint low is more important. + * + * one rather simple way to speed this up and still keep the + * memory footprint down is to make sure the array is sorted + * and then perform a bisect to lookup the irq. + */ - ctrl_outw(set_field(ctrl_inw(addr), value, width, bit), addr); + for (i = 0; i < nr_hp; i++) { + if ((hp + i)->irq != irq) + continue; + + return hp + i; + } + + return NULL; } -static void set_sense_32(struct intc_desc *desc, unsigned int data) +int intc_set_priority(unsigned int irq, unsigned int prio) { - unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg; - unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width; - unsigned int bit = _INTC_BIT(data); - unsigned int value = _INTC_VALUE(data); + struct intc_desc_int *d = get_intc_desc(irq); + struct intc_handle_int *ihp; + + if (!intc_prio_level[irq] || prio <= 1) + return -EINVAL; + + ihp = intc_find_irq(d->prio, d->nr_prio, irq); + if (ihp) { + if (prio >= (1 << _INTC_WIDTH(ihp->handle))) + return -EINVAL; - ctrl_outl(set_field(ctrl_inl(addr), value, width, bit), addr); + intc_prio_level[irq] = prio; + + /* + * only set secondary masking method directly + * primary masking method is using intc_prio_level[irq] + * priority level will be set during next enable() + */ + + if (_INTC_FN(ihp->handle) != REG_FN_ERR) + _intc_enable(irq, ihp->handle); + } + return 0; } #define VALID(x) (x | 0x80) @@ -172,79 +285,38 @@ static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = { static int intc_set_sense(unsigned int irq, unsigned int type) { - struct intc_desc *desc = get_intc_desc(irq); + struct intc_desc_int *d = get_intc_desc(irq); unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK]; - unsigned int i, j, data, bit; - intc_enum enum_id = 0; - - for (i = 0; i < desc->nr_vectors; i++) { - struct intc_vect *vect = desc->vectors + i; - - if (evt2irq(vect->vect) != irq) - continue; + struct intc_handle_int *ihp; + unsigned long addr; - enum_id = vect->enum_id; - break; - } - - if (!enum_id || !value) + if (!value) return -EINVAL; - value ^= VALID(0); - - for (i = 0; i < desc->nr_sense_regs; i++) { - struct intc_sense_reg *sr = desc->sense_regs + i; - - for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) { - if (sr->enum_ids[j] != enum_id) - continue; - - bit = sr->reg_width - ((j + 1) * sr->field_width); - data = _INTC_MK(0, i, bit, value); - - switch(sr->reg_width) { - case 16: - set_sense_16(desc, data); - break; - case 32: - set_sense_32(desc, data); - break; - } - - return 0; - } + ihp = intc_find_irq(d->sense, d->nr_sense, irq); + if (ihp) { + addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0); + intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value); } - - return -EINVAL; + return 0; } -static unsigned int __init intc_find_mask_handler(unsigned int width) +static unsigned int __init intc_get_reg(struct intc_desc_int *d, + unsigned long address) { - switch (width) { - case 8: - return REG_FN_MASK_8; - case 32: - return REG_FN_MASK_32; - } + unsigned int k; - BUG(); - return REG_FN_ERROR; -} - -static unsigned int __init intc_find_prio_handler(unsigned int width) -{ - switch (width) { - case 16: - return REG_FN_PRIO_16; - case 32: - return REG_FN_PRIO_32; + for (k = 0; k < d->nr_reg; k++) { + if (d->reg[k] == address) + return k; } BUG(); - return REG_FN_ERROR; + return 0; } -static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id) +static intc_enum __init intc_grp_id(struct intc_desc *desc, + intc_enum enum_id) { struct intc_group *g = desc->groups; unsigned int i, j; @@ -289,10 +361,12 @@ static unsigned int __init intc_prio_value(struct intc_desc *desc, } static unsigned int __init intc_mask_data(struct intc_desc *desc, + struct intc_desc_int *d, intc_enum enum_id, int do_grps) { struct intc_mask_reg *mr = desc->mask_regs; - unsigned int i, j, fn; + unsigned int i, j, fn, mode; + unsigned long reg_e, reg_d; for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) { mr = desc->mask_regs + i; @@ -301,25 +375,46 @@ static unsigned int __init intc_mask_data(struct intc_desc *desc, if (mr->enum_ids[j] != enum_id) continue; - fn = intc_find_mask_handler(mr->reg_width); - if (fn == REG_FN_ERROR) - return 0; + if (mr->set_reg && mr->clr_reg) { + fn = REG_FN_WRITE_BASE; + mode = MODE_DUAL_REG; + reg_e = mr->clr_reg; + reg_d = mr->set_reg; + } else { + fn = REG_FN_MODIFY_BASE; + if (mr->set_reg) { + mode = MODE_ENABLE_REG; + reg_e = mr->set_reg; + reg_d = mr->set_reg; + } else { + mode = MODE_MASK_REG; + reg_e = mr->clr_reg; + reg_d = mr->clr_reg; + } + } - return _INTC_MK(fn, i, (mr->reg_width - 1) - j, 0); + fn += (mr->reg_width >> 3) - 1; + return _INTC_MK(fn, mode, + intc_get_reg(d, reg_e), + intc_get_reg(d, reg_d), + 1, + (mr->reg_width - 1) - j); } } if (do_grps) - return intc_mask_data(desc, intc_grp_id(desc, enum_id), 0); + return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0); return 0; } static unsigned int __init intc_prio_data(struct intc_desc *desc, + struct intc_desc_int *d, intc_enum enum_id, int do_grps) { struct intc_prio_reg *pr = desc->prio_regs; - unsigned int i, j, fn, bit, prio; + unsigned int i, j, fn, mode, bit; + unsigned long reg_e, reg_d; for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) { pr = desc->prio_regs + i; @@ -328,28 +423,72 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc, if (pr->enum_ids[j] != enum_id) continue; - fn = intc_find_prio_handler(pr->reg_width); - if (fn == REG_FN_ERROR) - return 0; + if (pr->set_reg && pr->clr_reg) { + fn = REG_FN_WRITE_BASE; + mode = MODE_PCLR_REG; + reg_e = pr->set_reg; + reg_d = pr->clr_reg; + } else { + fn = REG_FN_MODIFY_BASE; + mode = MODE_PRIO_REG; + if (!pr->set_reg) + BUG(); + reg_e = pr->set_reg; + reg_d = pr->set_reg; + } - prio = intc_prio_value(desc, enum_id, 1); + fn += (pr->reg_width >> 3) - 1; bit = pr->reg_width - ((j + 1) * pr->field_width); BUG_ON(bit < 0); - return _INTC_MK(fn, i, bit, prio); + return _INTC_MK(fn, mode, + intc_get_reg(d, reg_e), + intc_get_reg(d, reg_d), + pr->field_width, bit); } } if (do_grps) - return intc_prio_data(desc, intc_grp_id(desc, enum_id), 0); + return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0); return 0; } -static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id, +static unsigned int __init intc_sense_data(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id) +{ + struct intc_sense_reg *sr = desc->sense_regs; + unsigned int i, j, fn, bit; + + for (i = 0; sr && enum_id && i < desc->nr_sense_regs; i++) { + sr = desc->sense_regs + i; + + for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) { + if (sr->enum_ids[j] != enum_id) + continue; + + fn = REG_FN_MODIFY_BASE; + fn += (sr->reg_width >> 3) - 1; + bit = sr->reg_width - ((j + 1) * sr->field_width); + + BUG_ON(bit < 0); + + return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg), + 0, sr->field_width, bit); + } + } + + return 0; +} + +static void __init intc_register_irq(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, unsigned int irq) { + struct intc_handle_int *hp; unsigned int data[2], primary; /* Prefer single interrupt source bitmap over other combinations: @@ -359,15 +498,15 @@ static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id, * 4. priority, multiple interrupt sources (groups) */ - data[0] = intc_mask_data(desc, enum_id, 0); - data[1] = intc_prio_data(desc, enum_id, 0); + data[0] = intc_mask_data(desc, d, enum_id, 0); + data[1] = intc_prio_data(desc, d, enum_id, 0); primary = 0; if (!data[0] && data[1]) primary = 1; - data[0] = data[0] ? data[0] : intc_mask_data(desc, enum_id, 1); - data[1] = data[1] ? data[1] : intc_prio_data(desc, enum_id, 1); + data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1); + data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1); if (!data[primary]) primary ^= 1; @@ -375,31 +514,118 @@ static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id, BUG_ON(!data[primary]); /* must have primary masking method */ disable_irq_nosync(irq); - set_irq_chip_and_handler_name(irq, &desc->chip, + set_irq_chip_and_handler_name(irq, &d->chip, handle_level_irq, "level"); set_irq_chip_data(irq, (void *)data[primary]); + /* record the desired priority level */ + intc_prio_level[irq] = intc_prio_value(desc, enum_id, 1); + /* enable secondary masking method if present */ if (data[!primary]) - intc_reg_fns[_INTC_FN(data[!primary])].enable(desc, - data[!primary]); + _intc_enable(irq, data[!primary]); + + /* add irq to d->prio list if priority is available */ + if (data[1]) { + hp = d->prio + d->nr_prio; + hp->irq = irq; + hp->handle = data[1]; + + if (primary) { + /* + * only secondary priority should access registers, so + * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority() + */ + + hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0); + hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0); + } + d->nr_prio++; + } + + /* add irq to d->sense list if sense is available */ + data[0] = intc_sense_data(desc, d, enum_id); + if (data[0]) { + (d->sense + d->nr_sense)->irq = irq; + (d->sense + d->nr_sense)->handle = data[0]; + d->nr_sense++; + } /* irq should be disabled by default */ - desc->chip.mask(irq); + d->chip.mask(irq); } +static unsigned int __init save_reg(struct intc_desc_int *d, + unsigned int cnt, + unsigned long value, + unsigned int smp) +{ + if (value) { + d->reg[cnt] = value; +#ifdef CONFIG_SMP + d->smp[cnt] = smp; +#endif + return 1; + } + + return 0; +} + + void __init register_intc_controller(struct intc_desc *desc) { - unsigned int i; + unsigned int i, k, smp; + struct intc_desc_int *d; + + d = alloc_bootmem(sizeof(*d)); + + d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0; + d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0; + d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0; + + d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg)); +#ifdef CONFIG_SMP + d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp)); +#endif + k = 0; + + if (desc->mask_regs) { + for (i = 0; i < desc->nr_mask_regs; i++) { + smp = IS_SMP(desc->mask_regs[i]); + k += save_reg(d, k, desc->mask_regs[i].set_reg, smp); + k += save_reg(d, k, desc->mask_regs[i].clr_reg, smp); + } + } + + if (desc->prio_regs) { + d->prio = alloc_bootmem(desc->nr_vectors * sizeof(*d->prio)); + + for (i = 0; i < desc->nr_prio_regs; i++) { + smp = IS_SMP(desc->prio_regs[i]); + k += save_reg(d, k, desc->prio_regs[i].set_reg, smp); + k += save_reg(d, k, desc->prio_regs[i].clr_reg, smp); + } + } + + if (desc->sense_regs) { + d->sense = alloc_bootmem(desc->nr_vectors * sizeof(*d->sense)); + + for (i = 0; i < desc->nr_sense_regs; i++) { + k += save_reg(d, k, desc->sense_regs[i].reg, 0); + } + } + + BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ - desc->chip.mask = intc_disable; - desc->chip.unmask = intc_enable; - desc->chip.mask_ack = intc_disable; - desc->chip.set_type = intc_set_sense; + d->chip.name = desc->name; + d->chip.mask = intc_disable; + d->chip.unmask = intc_enable; + d->chip.mask_ack = intc_disable; + d->chip.set_type = intc_set_sense; for (i = 0; i < desc->nr_vectors; i++) { struct intc_vect *vect = desc->vectors + i; - intc_register_irq(desc, vect->enum_id, evt2irq(vect->vect)); + intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect)); } } diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c deleted file mode 100644 index cc5221390e0..00000000000 --- a/arch/sh/kernel/cpu/irq/intc2.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Interrupt handling for INTC2-based IRQ. - * - * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) - * Copyright (C) 2005, 2006 Paul Mundt (lethal@linux-sh.org) - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * These are the "new Hitachi style" interrupts, as present on the - * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780. - */ -#include <linux/kernel.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <asm/smp.h> - -static inline struct intc2_desc *get_intc2_desc(unsigned int irq) -{ - struct irq_chip *chip = get_irq_chip(irq); - return (void *)((char *)chip - offsetof(struct intc2_desc, chip)); -} - -static void disable_intc2_irq(unsigned int irq) -{ - struct intc2_data *p = get_irq_chip_data(irq); - struct intc2_desc *d = get_intc2_desc(irq); - - ctrl_outl(1 << p->msk_shift, d->msk_base + p->msk_offset + - (hard_smp_processor_id() * 4)); -} - -static void enable_intc2_irq(unsigned int irq) -{ - struct intc2_data *p = get_irq_chip_data(irq); - struct intc2_desc *d = get_intc2_desc(irq); - - ctrl_outl(1 << p->msk_shift, d->mskclr_base + p->msk_offset + - (hard_smp_processor_id() * 4)); -} - -/* - * Setup an INTC2 style interrupt. - * NOTE: Unlike IPR interrupts, parameters are not shifted by this code, - * allowing the use of the numbers straight out of the datasheet. - * For example: - * PIO1 which is INTPRI00[19,16] and INTMSK00[13] - * would be: ^ ^ ^ ^ - * | | | | - * { 84, 0, 16, 0, 13 }, - * - * in the intc2_data table. - */ -void register_intc2_controller(struct intc2_desc *desc) -{ - int i; - - desc->chip.mask = disable_intc2_irq; - desc->chip.unmask = enable_intc2_irq; - desc->chip.mask_ack = disable_intc2_irq; - - for (i = 0; i < desc->nr_irqs; i++) { - unsigned long ipr, flags; - struct intc2_data *p = desc->intc2_data + i; - - disable_irq_nosync(p->irq); - - if (desc->prio_base) { - /* Set the priority level */ - local_irq_save(flags); - - ipr = ctrl_inl(desc->prio_base + p->ipr_offset); - ipr &= ~(0xf << p->ipr_shift); - ipr |= p->priority << p->ipr_shift; - ctrl_outl(ipr, desc->prio_base + p->ipr_offset); - - local_irq_restore(flags); - } - - set_irq_chip_and_handler_name(p->irq, &desc->chip, - handle_level_irq, "level"); - set_irq_chip_data(p->irq, p); - - disable_intc2_irq(p->irq); - } -} diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c index abbf17427e5..5916d9096b9 100644 --- a/arch/sh/kernel/cpu/sh2/probe.c +++ b/arch/sh/kernel/cpu/sh2/probe.c @@ -10,26 +10,25 @@ * for more details. */ #include <linux/init.h> -#include <linux/smp.h> #include <asm/processor.h> #include <asm/cache.h> int __init detect_cpu_and_cache_system(void) { #if defined(CONFIG_CPU_SUBTYPE_SH7619) - current_cpu_data.type = CPU_SH7619; - current_cpu_data.dcache.ways = 4; - current_cpu_data.dcache.way_incr = (1<<12); - current_cpu_data.dcache.sets = 256; - current_cpu_data.dcache.entry_shift = 4; - current_cpu_data.dcache.linesz = L1_CACHE_BYTES; - current_cpu_data.dcache.flags = 0; + boot_cpu_data.type = CPU_SH7619; + boot_cpu_data.dcache.ways = 4; + boot_cpu_data.dcache.way_incr = (1<<12); + boot_cpu_data.dcache.sets = 256; + boot_cpu_data.dcache.entry_shift = 4; + boot_cpu_data.dcache.linesz = L1_CACHE_BYTES; + boot_cpu_data.dcache.flags = 0; #endif /* * SH-2 doesn't have separate caches */ - current_cpu_data.dcache.flags |= SH_CACHE_COMBINED; - current_cpu_data.icache = current_cpu_data.dcache; + boot_cpu_data.dcache.flags |= SH_CACHE_COMBINED; + boot_cpu_data.icache = boot_cpu_data.dcache; return 0; } diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c index a979b981e6a..ec6adc3f306 100644 --- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c +++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c @@ -12,6 +12,61 @@ #include <linux/serial.h> #include <asm/sci.h> +enum { + UNUSED = 0, + + /* interrupt sources */ + IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7, + WDT, EDMAC, CMT0, CMT1, + SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI, + SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI, + SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI, + HIF_HIFI, HIF_HIFBI, + DMAC0, DMAC1, DMAC2, DMAC3, + SIOF, + + /* interrupt groups */ + SCIF0, SCIF1, SCIF2, +}; + +static struct intc_vect vectors[] __initdata = { + INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65), + INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67), + INTC_IRQ(IRQ4, 80), INTC_IRQ(IRQ5, 81), + INTC_IRQ(IRQ6, 82), INTC_IRQ(IRQ7, 83), + INTC_IRQ(WDT, 84), INTC_IRQ(EDMAC, 85), + INTC_IRQ(CMT0, 86), INTC_IRQ(CMT1, 87), + INTC_IRQ(SCIF0_ERI, 88), INTC_IRQ(SCIF0_RXI, 89), + INTC_IRQ(SCIF0_BRI, 90), INTC_IRQ(SCIF0_TXI, 91), + INTC_IRQ(SCIF1_ERI, 92), INTC_IRQ(SCIF1_RXI, 93), + INTC_IRQ(SCIF1_BRI, 94), INTC_IRQ(SCIF1_TXI, 95), + INTC_IRQ(SCIF2_ERI, 96), INTC_IRQ(SCIF2_RXI, 97), + INTC_IRQ(SCIF2_BRI, 98), INTC_IRQ(SCIF2_TXI, 99), + INTC_IRQ(HIF_HIFI, 100), INTC_IRQ(HIF_HIFBI, 101), + INTC_IRQ(DMAC0, 104), INTC_IRQ(DMAC1, 105), + INTC_IRQ(DMAC2, 106), INTC_IRQ(DMAC3, 107), + INTC_IRQ(SIOF, 108), +}; + +static struct intc_group groups[] __initdata = { + INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI), + INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI), + INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI), +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xf8140006, 0, 16, 4, /* IPRA */ { IRQ0, IRQ1, IRQ2, IRQ3 } }, + { 0xf8140008, 0, 16, 4, /* IPRB */ { IRQ4, IRQ5, IRQ6, IRQ7 } }, + { 0xf8080000, 0, 16, 4, /* IPRC */ { WDT, EDMAC, CMT0, CMT1 } }, + { 0xf8080002, 0, 16, 4, /* IPRD */ { SCIF0, SCIF1, SCIF2 } }, + { 0xf8080004, 0, 16, 4, /* IPRE */ { HIF_HIFI, HIF_HIFBI } }, + { 0xf8080006, 0, 16, 4, /* IPRF */ { DMAC0, DMAC1, DMAC2, DMAC3 } }, + { 0xf8080008, 0, 16, 4, /* IPRG */ { SIOF } }, +}; + +static DECLARE_INTC_DESC(intc_desc, "sh7619", vectors, groups, + NULL, NULL, prio_registers, NULL); + static struct plat_sci_port sci_platform_data[] = { { .mapbase = 0xf8400000, @@ -52,43 +107,7 @@ static int __init sh7619_devices_setup(void) } __initcall(sh7619_devices_setup); -static struct ipr_data ipr_irq_table[] = { - { 86, 0, 4, 2 }, /* CMI0 */ - { 88, 1, 12, 3 }, /* SCIF0_ERI */ - { 89, 1, 12, 3 }, /* SCIF0_RXI */ - { 90, 1, 12, 3 }, /* SCIF0_BRI */ - { 91, 1, 12, 3 }, /* SCIF0_TXI */ - { 92, 1, 8, 3 }, /* SCIF1_ERI */ - { 93, 1, 8, 3 }, /* SCIF1_RXI */ - { 94, 1, 8, 3 }, /* SCIF1_BRI */ - { 95, 1, 8, 3 }, /* SCIF1_TXI */ - { 96, 1, 4, 3 }, /* SCIF2_ERI */ - { 97, 1, 4, 3 }, /* SCIF2_RXI */ - { 98, 1, 4, 3 }, /* SCIF2_BRI */ - { 99, 1, 4, 3 }, /* SCIF2_TXI */ -}; - -static unsigned long ipr_offsets[] = { - 0xf8080000, /* IPRC */ - 0xf8080002, /* IPRD */ - 0xf8080004, /* IPRE */ - 0xf8080006, /* IPRF */ - 0xf8080008, /* IPRG */ -}; - -static struct ipr_desc ipr_irq_desc = { - .ipr_offsets = ipr_offsets, - .nr_offsets = ARRAY_SIZE(ipr_offsets), - - .ipr_data = ipr_irq_table, - .nr_irqs = ARRAY_SIZE(ipr_irq_table), - - .chip = { - .name = "IPR-sh7619", - }, -}; - void __init plat_irq_setup(void) { - register_ipr_controller(&ipr_irq_desc); + register_intc_controller(&intc_desc); } diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c index f455c350978..6d02465704b 100644 --- a/arch/sh/kernel/cpu/sh2a/probe.c +++ b/arch/sh/kernel/cpu/sh2a/probe.c @@ -17,15 +17,15 @@ int __init detect_cpu_and_cache_system(void) { /* Just SH7206 for now .. */ - current_cpu_data.type = CPU_SH7206; - current_cpu_data.flags |= CPU_HAS_OP32; + boot_cpu_data.type = CPU_SH7206; + boot_cpu_data.flags |= CPU_HAS_OP32; - current_cpu_data.dcache.ways = 4; - current_cpu_data.dcache.way_incr = (1 << 11); - current_cpu_data.dcache.sets = 128; - current_cpu_data.dcache.entry_shift = 4; - current_cpu_data.dcache.linesz = L1_CACHE_BYTES; - current_cpu_data.dcache.flags = 0; + boot_cpu_data.dcache.ways = 4; + boot_cpu_data.dcache.way_incr = (1 << 11); + boot_cpu_data.dcache.sets = 128; + boot_cpu_data.dcache.entry_shift = 4; + boot_cpu_data.dcache.linesz = L1_CACHE_BYTES; + boot_cpu_data.dcache.flags = 0; /* * The icache is the same as the dcache as far as this setup is @@ -33,7 +33,7 @@ int __init detect_cpu_and_cache_system(void) * lacks the U bit that the dcache has, none of this has any bearing * on the cache info. */ - current_cpu_data.icache = current_cpu_data.dcache; + boot_cpu_data.icache = boot_cpu_data.dcache; return 0; } diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c index deab1650016..bd745aa8722 100644 --- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c +++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c @@ -12,27 +12,184 @@ #include <linux/serial.h> #include <asm/sci.h> +enum { + UNUSED = 0, + + /* interrupt sources */ + IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7, + PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7, + ADC_ADI0, ADC_ADI1, + DMAC0_DEI, DMAC0_HEI, DMAC1_DEI, DMAC1_HEI, + DMAC2_DEI, DMAC2_HEI, DMAC3_DEI, DMAC3_HEI, + DMAC4_DEI, DMAC4_HEI, DMAC5_DEI, DMAC5_HEI, + DMAC6_DEI, DMAC6_HEI, DMAC7_DEI, DMAC7_HEI, + CMT0, CMT1, BSC, WDT, + MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D, + MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F, + MTU2_TGI1A, MTU2_TGI1B, MTU2_TCI1V, MTU2_TCI1U, + MTU2_TGI2A, MTU2_TGI2B, MTU2_TCI2V, MTU2_TCI2U, + MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D, MTU2_TCI3V, + MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D, MTU2_TCI4V, + MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W, + POE2_OEI1, POE2_OEI2, + MTU2S_TGI3A, MTU2S_TGI3B, MTU2S_TGI3C, MTU2S_TGI3D, MTU2S_TCI3V, + MTU2S_TGI4A, MTU2S_TGI4B, MTU2S_TGI4C, MTU2S_TGI4D, MTU2S_TCI4V, + MTU2S_TGI5U, MTU2S_TGI5V, MTU2S_TGI5W, + POE2_OEI3, + IIC3_STPI, IIC3_NAKI, IIC3_RXI, IIC3_TXI, IIC3_TEI, + SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI, + SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI, + SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI, + SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI, + + /* interrupt groups */ + PINT, DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7, + MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU, + MTU3_ABCD, MTU4_ABCD, MTU5, POE2_12, MTU3S_ABCD, MTU4S_ABCD, MTU5S, + IIC3, SCIF0, SCIF1, SCIF2, SCIF3, +}; + +static struct intc_vect vectors[] __initdata = { + INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65), + INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67), + INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69), + INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71), + INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81), + INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83), + INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85), + INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87), + INTC_IRQ(ADC_ADI0, 92), INTC_IRQ(ADC_ADI1, 96), + INTC_IRQ(DMAC0_DEI, 108), INTC_IRQ(DMAC0_HEI, 109), + INTC_IRQ(DMAC1_DEI, 112), INTC_IRQ(DMAC1_HEI, 113), + INTC_IRQ(DMAC2_DEI, 116), INTC_IRQ(DMAC2_HEI, 117), + INTC_IRQ(DMAC3_DEI, 120), INTC_IRQ(DMAC3_HEI, 121), + INTC_IRQ(DMAC4_DEI, 124), INTC_IRQ(DMAC4_HEI, 125), + INTC_IRQ(DMAC5_DEI, 128), INTC_IRQ(DMAC5_HEI, 129), + INTC_IRQ(DMAC6_DEI, 132), INTC_IRQ(DMAC6_HEI, 133), + INTC_IRQ(DMAC7_DEI, 136), INTC_IRQ(DMAC7_HEI, 137), + INTC_IRQ(CMT0, 140), INTC_IRQ(CMT1, 144), + INTC_IRQ(BSC, 148), INTC_IRQ(WDT, 152), + INTC_IRQ(MTU2_TGI0A, 156), INTC_IRQ(MTU2_TGI0B, 157), + INTC_IRQ(MTU2_TGI0C, 158), INTC_IRQ(MTU2_TGI0D, 159), + INTC_IRQ(MTU2_TCI0V, 160), + INTC_IRQ(MTU2_TGI0E, 161), INTC_IRQ(MTU2_TGI0F, 162), + INTC_IRQ(MTU2_TGI1A, 164), INTC_IRQ(MTU2_TGI1B, 165), + INTC_IRQ(MTU2_TCI1V, 168), INTC_IRQ(MTU2_TCI1U, 169), + INTC_IRQ(MTU2_TGI2A, 172), INTC_IRQ(MTU2_TGI2B, 173), + INTC_IRQ(MTU2_TCI2V, 176), INTC_IRQ(MTU2_TCI2U, 177), + INTC_IRQ(MTU2_TGI3A, 180), INTC_IRQ(MTU2_TGI3B, 181), + INTC_IRQ(MTU2_TGI3C, 182), INTC_IRQ(MTU2_TGI3D, 183), + INTC_IRQ(MTU2_TCI3V, 184), + INTC_IRQ(MTU2_TGI4A, 188), INTC_IRQ(MTU2_TGI4B, 189), + INTC_IRQ(MTU2_TGI4C, 190), INTC_IRQ(MTU2_TGI4D, 191), + INTC_IRQ(MTU2_TCI4V, 192), + INTC_IRQ(MTU2_TGI5U, 196), INTC_IRQ(MTU2_TGI5V, 197), + INTC_IRQ(MTU2_TGI5W, 198), + INTC_IRQ(POE2_OEI1, 200), INTC_IRQ(POE2_OEI2, 201), + INTC_IRQ(MTU2S_TGI3A, 204), INTC_IRQ(MTU2S_TGI3B, 205), + INTC_IRQ(MTU2S_TGI3C, 206), INTC_IRQ(MTU2S_TGI3D, 207), + INTC_IRQ(MTU2S_TCI3V, 208), + INTC_IRQ(MTU2S_TGI4A, 212), INTC_IRQ(MTU2S_TGI4B, 213), + INTC_IRQ(MTU2S_TGI4C, 214), INTC_IRQ(MTU2S_TGI4D, 215), + INTC_IRQ(MTU2S_TCI4V, 216), + INTC_IRQ(MTU2S_TGI5U, 220), INTC_IRQ(MTU2S_TGI5V, 221), + INTC_IRQ(MTU2S_TGI5W, 222), + INTC_IRQ(POE2_OEI3, 224), + INTC_IRQ(IIC3_STPI, 228), INTC_IRQ(IIC3_NAKI, 229), + INTC_IRQ(IIC3_RXI, 230), INTC_IRQ(IIC3_TXI, 231), + INTC_IRQ(IIC3_TEI, 232), + INTC_IRQ(SCIF0_BRI, 240), INTC_IRQ(SCIF0_ERI, 241), + INTC_IRQ(SCIF0_RXI, 242), INTC_IRQ(SCIF0_TXI, 243), + INTC_IRQ(SCIF1_BRI, 244), INTC_IRQ(SCIF1_ERI, 245), + INTC_IRQ(SCIF1_RXI, 246), INTC_IRQ(SCIF1_TXI, 247), + INTC_IRQ(SCIF2_BRI, 248), INTC_IRQ(SCIF2_ERI, 249), + INTC_IRQ(SCIF2_RXI, 250), INTC_IRQ(SCIF2_TXI, 251), + INTC_IRQ(SCIF3_BRI, 252), INTC_IRQ(SCIF3_ERI, 253), + INTC_IRQ(SCIF3_RXI, 254), INTC_IRQ(SCIF3_TXI, 255), +}; + +static struct intc_group groups[] __initdata = { + INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3, + PINT4, PINT5, PINT6, PINT7), + INTC_GROUP(DMAC0, DMAC0_DEI, DMAC0_HEI), + INTC_GROUP(DMAC1, DMAC1_DEI, DMAC1_HEI), + INTC_GROUP(DMAC2, DMAC2_DEI, DMAC2_HEI), + INTC_GROUP(DMAC3, DMAC3_DEI, DMAC3_HEI), + INTC_GROUP(DMAC4, DMAC4_DEI, DMAC4_HEI), + INTC_GROUP(DMAC5, DMAC5_DEI, DMAC5_HEI), + INTC_GROUP(DMAC6, DMAC6_DEI, DMAC6_HEI), + INTC_GROUP(DMAC7, DMAC7_DEI, DMAC7_HEI), + INTC_GROUP(MTU0_ABCD, MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D), + INTC_GROUP(MTU0_VEF, MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F), + INTC_GROUP(MTU1_AB, MTU2_TGI1A, MTU2_TGI1B), + INTC_GROUP(MTU1_VU, MTU2_TCI1V, MTU2_TCI1U), + INTC_GROUP(MTU2_AB, MTU2_TGI2A, MTU2_TGI2B), + INTC_GROUP(MTU2_VU, MTU2_TCI2V, MTU2_TCI2U), + INTC_GROUP(MTU3_ABCD, MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D), + INTC_GROUP(MTU4_ABCD, MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D), + INTC_GROUP(MTU5, MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W), + INTC_GROUP(POE2_12, POE2_OEI1, POE2_OEI2), + INTC_GROUP(MTU3S_ABCD, MTU2S_TGI3A, MTU2S_TGI3B, + MTU2S_TGI3C, MTU2S_TGI3D), + INTC_GROUP(MTU4S_ABCD, MTU2S_TGI4A, MTU2S_TGI4B, + MTU2S_TGI4C, MTU2S_TGI4D), + INTC_GROUP(MTU5S, MTU2S_TGI5U, MTU2S_TGI5V, MTU2S_TGI5W), + INTC_GROUP(IIC3, IIC3_STPI, IIC3_NAKI, IIC3_RXI, IIC3_TXI, IIC3_TEI), + INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI), + INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI), + INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI), + INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI), +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } }, + { 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } }, + { 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, ADC_ADI0, ADC_ADI1 } }, + { 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0, DMAC1, DMAC2, DMAC3 } }, + { 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4, DMAC5, DMAC6, DMAC7 } }, + { 0xfffe0c04, 0, 16, 4, /* IPR08 */ { CMT0, CMT1, BSC, WDT } }, + { 0xfffe0c06, 0, 16, 4, /* IPR09 */ { MTU0_ABCD, MTU0_VEF, + MTU1_AB, MTU1_VU } }, + { 0xfffe0c08, 0, 16, 4, /* IPR10 */ { MTU2_AB, MTU2_VU, + MTU3_ABCD, MTU2_TCI3V } }, + { 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { MTU4_ABCD, MTU2_TCI4V, + MTU5, POE2_12 } }, + { 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { MTU3S_ABCD, MTU2S_TCI3V, + MTU4S_ABCD, MTU2S_TCI4V } }, + { 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { MTU5S, POE2_OEI3, IIC3, 0 } }, + { 0xfffe0c10, 0, 16, 4, /* IPR14 */ { SCIF0, SCIF1, SCIF2, SCIF3 } }, +}; + +static struct intc_mask_reg mask_registers[] __initdata = { + { 0xfffe0808, 0, 16, /* PINTER */ + { 0, 0, 0, 0, 0, 0, 0, 0, + PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } }, +}; + +static DECLARE_INTC_DESC(intc_desc, "sh7206", vectors, groups, + NULL, mask_registers, prio_registers, NULL); + static struct plat_sci_port sci_platform_data[] = { { .mapbase = 0xfffe8000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 241, 242, 243, 240}, + .irqs = { 241, 242, 243, 240 }, }, { .mapbase = 0xfffe8800, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 247, 244, 245, 246}, + .irqs = { 245, 246, 247, 244 }, }, { .mapbase = 0xfffe9000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 249, 250, 251, 248}, + .irqs = { 249, 250, 251, 248 }, }, { .mapbase = 0xfffe9800, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 253, 254, 255, 252}, + .irqs = { 253, 254, 255, 252 }, }, { .flags = 0, } @@ -57,57 +214,7 @@ static int __init sh7206_devices_setup(void) } __initcall(sh7206_devices_setup); -static struct ipr_data ipr_irq_table[] = { - { 140, 7, 12, 2 }, /* CMI0 */ - { 164, 8, 4, 2 }, /* MTU2_TGI1A */ - { 240, 13, 12, 3 }, /* SCIF0_BRI */ - { 241, 13, 12, 3 }, /* SCIF0_ERI */ - { 242, 13, 12, 3 }, /* SCIF0_RXI */ - { 243, 13, 12, 3 }, /* SCIF0_TXI */ - { 244, 13, 8, 3 }, /* SCIF1_BRI */ - { 245, 13, 8, 3 }, /* SCIF1_ERI */ - { 246, 13, 8, 3 }, /* SCIF1_RXI */ - { 247, 13, 8, 3 }, /* SCIF1_TXI */ - { 248, 13, 4, 3 }, /* SCIF2_BRI */ - { 249, 13, 4, 3 }, /* SCIF2_ERI */ - { 250, 13, 4, 3 }, /* SCIF2_RXI */ - { 251, 13, 4, 3 }, /* SCIF2_TXI */ - { 252, 13, 0, 3 }, /* SCIF3_BRI */ - { 253, 13, 0, 3 }, /* SCIF3_ERI */ - { 254, 13, 0, 3 }, /* SCIF3_RXI */ - { 255, 13, 0, 3 }, /* SCIF3_TXI */ -}; - -static unsigned long ipr_offsets[] = { - 0xfffe0818, /* IPR01 */ - 0xfffe081a, /* IPR02 */ - 0, /* unused */ - 0, /* unused */ - 0xfffe0820, /* IPR05 */ - 0xfffe0c00, /* IPR06 */ - 0xfffe0c02, /* IPR07 */ - 0xfffe0c04, /* IPR08 */ - 0xfffe0c06, /* IPR09 */ - 0xfffe0c08, /* IPR10 */ - 0xfffe0c0a, /* IPR11 */ - 0xfffe0c0c, /* IPR12 */ - 0xfffe0c0e, /* IPR13 */ - 0xfffe0c10, /* IPR14 */ -}; - -static struct ipr_desc ipr_irq_desc = { - .ipr_offsets = ipr_offsets, - .nr_offsets = ARRAY_SIZE(ipr_offsets), - - .ipr_data = ipr_irq_table, - .nr_irqs = ARRAY_SIZE(ipr_irq_table), - - .chip = { - .name = "IPR-sh7206", - }, -}; - void __init plat_irq_setup(void) { - register_ipr_controller(&ipr_irq_desc); + register_intc_controller(&intc_desc); } diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile index 55b750763f6..646eb693361 100644 --- a/arch/sh/kernel/cpu/sh3/Makefile +++ b/arch/sh/kernel/cpu/sh3/Makefile @@ -6,12 +6,13 @@ obj-y := ex.o probe.o entry.o # CPU subtype setup obj-$(CONFIG_CPU_SUBTYPE_SH7705) += setup-sh7705.o -obj-$(CONFIG_CPU_SUBTYPE_SH7706) += setup-sh7709.o -obj-$(CONFIG_CPU_SUBTYPE_SH7707) += setup-sh7709.o -obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh7708.o -obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh7709.o +obj-$(CONFIG_CPU_SUBTYPE_SH7706) += setup-sh770x.o +obj-$(CONFIG_CPU_SUBTYPE_SH7707) += setup-sh770x.o +obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh770x.o +obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh770x.o obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o obj-$(CONFIG_CPU_SUBTYPE_SH7712) += setup-sh7710.o +obj-$(CONFIG_CPU_SUBTYPE_SH7720) += setup-sh7720.o # Primary on-chip clocks (common) clock-$(CONFIG_CPU_SH3) := clock-sh3.o @@ -19,5 +20,6 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o clock-$(CONFIG_CPU_SUBTYPE_SH7706) := clock-sh7706.o clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o clock-$(CONFIG_CPU_SUBTYPE_SH7710) := clock-sh7710.o +clock-$(CONFIG_CPU_SUBTYPE_SH7720) := clock-sh7710.o obj-y += $(clock-y) diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c index 647623b22ed..bf579e061e0 100644 --- a/arch/sh/kernel/cpu/sh3/probe.c +++ b/arch/sh/kernel/cpu/sh3/probe.c @@ -50,44 +50,47 @@ int __init detect_cpu_and_cache_system(void) back_to_P1(); - current_cpu_data.dcache.ways = 4; - current_cpu_data.dcache.entry_shift = 4; - current_cpu_data.dcache.linesz = L1_CACHE_BYTES; - current_cpu_data.dcache.flags = 0; + boot_cpu_data.dcache.ways = 4; + boot_cpu_data.dcache.entry_shift = 4; + boot_cpu_data.dcache.linesz = L1_CACHE_BYTES; + boot_cpu_data.dcache.flags = 0; /* * 7709A/7729 has 16K cache (256-entry), while 7702 has only * 2K(direct) 7702 is not supported (yet) */ if (data0 == data1 && data2 == data3) { /* Shadow */ - current_cpu_data.dcache.way_incr = (1 << 11); - current_cpu_data.dcache.entry_mask = 0x7f0; - current_cpu_data.dcache.sets = 128; - current_cpu_data.type = CPU_SH7708; + boot_cpu_data.dcache.way_incr = (1 << 11); + boot_cpu_data.dcache.entry_mask = 0x7f0; + boot_cpu_data.dcache.sets = 128; + boot_cpu_data.type = CPU_SH7708; - current_cpu_data.flags |= CPU_HAS_MMU_PAGE_ASSOC; + boot_cpu_data.flags |= CPU_HAS_MMU_PAGE_ASSOC; } else { /* 7709A or 7729 */ - current_cpu_data.dcache.way_incr = (1 << 12); - current_cpu_data.dcache.entry_mask = 0xff0; - current_cpu_data.dcache.sets = 256; - current_cpu_data.type = CPU_SH7729; + boot_cpu_data.dcache.way_incr = (1 << 12); + boot_cpu_data.dcache.entry_mask = 0xff0; + boot_cpu_data.dcache.sets = 256; + boot_cpu_data.type = CPU_SH7729; #if defined(CONFIG_CPU_SUBTYPE_SH7706) - current_cpu_data.type = CPU_SH7706; + boot_cpu_data.type = CPU_SH7706; #endif #if defined(CONFIG_CPU_SUBTYPE_SH7710) - current_cpu_data.type = CPU_SH7710; + boot_cpu_data.type = CPU_SH7710; #endif #if defined(CONFIG_CPU_SUBTYPE_SH7712) - current_cpu_data.type = CPU_SH7712; + boot_cpu_data.type = CPU_SH7712; +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7720) + boot_cpu_data.type = CPU_SH7720; #endif #if defined(CONFIG_CPU_SUBTYPE_SH7705) - current_cpu_data.type = CPU_SH7705; + boot_cpu_data.type = CPU_SH7705; #if defined(CONFIG_SH7705_CACHE_32KB) - current_cpu_data.dcache.way_incr = (1 << 13); - current_cpu_data.dcache.entry_mask = 0x1ff0; - current_cpu_data.dcache.sets = 512; + boot_cpu_data.dcache.way_incr = (1 << 13); + boot_cpu_data.dcache.entry_mask = 0x1ff0; + boot_cpu_data.dcache.sets = 512; ctrl_outl(CCR_CACHE_32KB, CCR3); #else ctrl_outl(CCR_CACHE_16KB, CCR3); @@ -98,9 +101,8 @@ int __init detect_cpu_and_cache_system(void) /* * SH-3 doesn't have separate caches */ - current_cpu_data.dcache.flags |= SH_CACHE_COMBINED; - current_cpu_data.icache = current_cpu_data.dcache; + boot_cpu_data.dcache.flags |= SH_CACHE_COMBINED; + boot_cpu_data.icache = boot_cpu_data.dcache; return 0; } - diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c index ebd9d06d8bd..f6c65f2659e 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c @@ -1,7 +1,7 @@ /* * SH7705 Setup * - * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2006, 2007 Paul Mundt * Copyright (C) 2007 Nobuhiro Iwamatsu * * This file is subject to the terms and conditions of the GNU General Public @@ -10,8 +10,90 @@ */ #include <linux/platform_device.h> #include <linux/init.h> +#include <linux/irq.h> #include <linux/serial.h> #include <asm/sci.h> +#include <asm/rtc.h> + +enum { + UNUSED = 0, + + /* interrupt sources */ + IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, + PINT07, PINT815, + DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3, + SCIF0_ERI, SCIF0_RXI, SCIF0_TXI, + SCIF2_ERI, SCIF2_RXI, SCIF2_TXI, + ADC_ADI, + USB_USI0, USB_USI1, + TPU0, TPU1, TPU2, TPU3, + TMU0, TMU1, TMU2_TUNI, TMU2_TICPI, + RTC_ATI, RTC_PRI, RTC_CUI, + WDT, + REF_RCMI, + + /* interrupt groups */ + RTC, TMU2, DMAC, USB, SCIF2, SCIF0, +}; + +static struct intc_vect vectors[] __initdata = { + INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0), + INTC_VECT(PINT07, 0x700), INTC_VECT(PINT815, 0x720), + INTC_VECT(DMAC_DEI0, 0x800), INTC_VECT(DMAC_DEI1, 0x820), + INTC_VECT(DMAC_DEI2, 0x840), INTC_VECT(DMAC_DEI3, 0x860), + INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0), + INTC_VECT(SCIF0_TXI, 0x8e0), + INTC_VECT(SCIF2_ERI, 0x900), INTC_VECT(SCIF2_RXI, 0x920), + INTC_VECT(SCIF2_TXI, 0x960), + INTC_VECT(ADC_ADI, 0x980), + INTC_VECT(USB_USI0, 0xa20), INTC_VECT(USB_USI1, 0xa40), + INTC_VECT(TPU0, 0xc00), INTC_VECT(TPU1, 0xc20), + INTC_VECT(TPU3, 0xc80), INTC_VECT(TPU1, 0xca0), + INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), + INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460), + INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0), + INTC_VECT(RTC_CUI, 0x4c0), + INTC_VECT(WDT, 0x560), + INTC_VECT(REF_RCMI, 0x580), +}; + +static struct intc_group groups[] __initdata = { + INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), + INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI), + INTC_GROUP(DMAC, DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3), + INTC_GROUP(USB, USB_USI0, USB_USI1), + INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI), + INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI), +}; + +static struct intc_prio priorities[] __initdata = { + INTC_PRIO(DMAC, 7), + INTC_PRIO(SCIF2, 3), + INTC_PRIO(SCIF0, 3), +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, + { 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, 0, 0 } }, + { 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } }, + { 0xa4000018, 0, 16, 4, /* IPRD */ { PINT07, PINT815, IRQ5, IRQ4 } }, + { 0xa400001a, 0, 16, 4, /* IPRE */ { DMAC, SCIF0, SCIF2, ADC_ADI } }, + { 0xa4080000, 0, 16, 4, /* IPRF */ { 0, 0, USB } }, + { 0xa4080002, 0, 16, 4, /* IPRG */ { TPU0, TPU1 } }, + { 0xa4080004, 0, 16, 4, /* IPRH */ { TPU2, TPU3 } }, + +}; + +static DECLARE_INTC_DESC(intc_desc, "sh7705", vectors, groups, + priorities, NULL, prio_registers, NULL); + +static struct intc_vect vectors_irq[] __initdata = { + INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620), + INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660), +}; + +static DECLARE_INTC_DESC(intc_desc_irq, "sh7705-irq", vectors_irq, NULL, + priorities, NULL, prio_registers, NULL); static struct plat_sci_port sci_platform_data[] = { { @@ -37,8 +119,43 @@ static struct platform_device sci_device = { }, }; +static struct resource rtc_resources[] = { + [0] = { + .start = 0xfffffec0, + .end = 0xfffffec0 + 0x1e, + .flags = IORESOURCE_IO, + }, + [1] = { + .start = 20, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = 21, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = 22, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct sh_rtc_platform_info rtc_info = { + .capabilities = RTC_CAP_4_DIGIT_YEAR, +}; + +static struct platform_device rtc_device = { + .name = "sh-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(rtc_resources), + .resource = rtc_resources, + .dev = { + .platform_data = &rtc_info, + }, +}; + static struct platform_device *sh7705_devices[] __initdata = { &sci_device, + &rtc_device, }; static int __init sh7705_devices_setup(void) @@ -48,51 +165,16 @@ static int __init sh7705_devices_setup(void) } __initcall(sh7705_devices_setup); -static struct ipr_data ipr_irq_table[] = { - /* IRQ, IPR-idx, shift, priority */ - { 16, 0, 12, 2 }, /* TMU0 TUNI*/ - { 17, 0, 8, 2 }, /* TMU1 TUNI */ - { 18, 0, 4, 2 }, /* TMU2 TUNI */ - { 27, 1, 12, 2 }, /* WDT ITI */ - { 20, 0, 0, 2 }, /* RTC ATI (alarm) */ - { 21, 0, 0, 2 }, /* RTC PRI (period) */ - { 22, 0, 0, 2 }, /* RTC CUI (carry) */ - { 48, 4, 12, 7 }, /* DMAC DMTE0 */ - { 49, 4, 12, 7 }, /* DMAC DMTE1 */ - { 50, 4, 12, 7 }, /* DMAC DMTE2 */ - { 51, 4, 12, 7 }, /* DMAC DMTE3 */ - { 52, 4, 8, 3 }, /* SCIF0 ERI */ - { 53, 4, 8, 3 }, /* SCIF0 RXI */ - { 55, 4, 8, 3 }, /* SCIF0 TXI */ - { 56, 4, 4, 3 }, /* SCIF1 ERI */ - { 57, 4, 4, 3 }, /* SCIF1 RXI */ - { 59, 4, 4, 3 }, /* SCIF1 TXI */ -}; - -static unsigned long ipr_offsets[] = { - 0xFFFFFEE2, /* 0: IPRA */ - 0xFFFFFEE4, /* 1: IPRB */ - 0xA4000016, /* 2: IPRC */ - 0xA4000018, /* 3: IPRD */ - 0xA400001A, /* 4: IPRE */ - 0xA4080000, /* 5: IPRF */ - 0xA4080002, /* 6: IPRG */ - 0xA4080004, /* 7: IPRH */ -}; - -static struct ipr_desc ipr_irq_desc = { - .ipr_offsets = ipr_offsets, - .nr_offsets = ARRAY_SIZE(ipr_offsets), - - .ipr_data = ipr_irq_table, - .nr_irqs = ARRAY_SIZE(ipr_irq_table), - - .chip = { - .name = "IPR-sh7705", - }, -}; +void __init plat_irq_setup_pins(int mode) +{ + if (mode == IRQ_MODE_IRQ) { + register_intc_controller(&intc_desc_irq); + return; + } + BUG(); +} void __init plat_irq_setup(void) { - register_ipr_controller(&ipr_irq_desc); + register_intc_controller(&intc_desc); } diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7708.c b/arch/sh/kernel/cpu/sh3/setup-sh7708.c deleted file mode 100644 index f933723911c..00000000000 --- a/arch/sh/kernel/cpu/sh3/setup-sh7708.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SH7708 Setup - * - * Copyright (C) 2006 Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#include <linux/platform_device.h> -#include <linux/init.h> -#include <linux/serial.h> -#include <asm/sci.h> - -static struct plat_sci_port sci_platform_data[] = { - { - .mapbase = 0xfffffe80, - .flags = UPF_BOOT_AUTOCONF, - .type = PORT_SCI, - .irqs = { 23, 24, 25, 0 }, - }, { - .flags = 0, - } -}; - -static struct platform_device sci_device = { - .name = "sh-sci", - .id = -1, - .dev = { - .platform_data = sci_platform_data, - }, -}; - -static struct platform_device *sh7708_devices[] __initdata = { - &sci_device, -}; - -static int __init sh7708_devices_setup(void) -{ - return platform_add_devices(sh7708_devices, - ARRAY_SIZE(sh7708_devices)); -} -__initcall(sh7708_devices_setup); diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c deleted file mode 100644 index 086f8e2545a..00000000000 --- a/arch/sh/kernel/cpu/sh3/setup-sh7709.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * SH7707/SH7709 Setup - * - * Copyright (C) 2006 Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#include <linux/platform_device.h> -#include <linux/init.h> -#include <linux/serial.h> -#include <asm/sci.h> - -static struct resource rtc_resources[] = { - [0] = { - .start = 0xfffffec0, - .end = 0xfffffec0 + 0x1e, - .flags = IORESOURCE_IO, - }, - [1] = { - .start = 20, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = 21, - .flags = IORESOURCE_IRQ, - }, - [3] = { - .start = 22, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct plat_sci_port sci_platform_data[] = { - { - .mapbase = 0xfffffe80, - .flags = UPF_BOOT_AUTOCONF, - .type = PORT_SCI, - .irqs = { 23, 24, 25, 0 }, - }, { - .mapbase = 0xa4000150, - .flags = UPF_BOOT_AUTOCONF, - .type = PORT_SCIF, - .irqs = { 56, 57, 59, 58 }, - }, { - .mapbase = 0xa4000140, - .flags = UPF_BOOT_AUTOCONF, - .type = PORT_IRDA, - .irqs = { 52, 53, 55, 54 }, - }, { - .flags = 0, - } -}; - -static struct platform_device sci_device = { - .name = "sh-sci", - .id = -1, - .dev = { - .platform_data = sci_platform_data, - }, -}; - -static struct platform_device rtc_device = { - .name = "sh-rtc", - .id = -1, - .num_resources = ARRAY_SIZE(rtc_resources), - .resource = rtc_resources, -}; - -static struct platform_device *sh7709_devices[] __initdata = { - &sci_device, - &rtc_device, -}; - -static int __init sh7709_devices_setup(void) -{ - return platform_add_devices(sh7709_devices, - ARRAY_SIZE(sh7709_devices)); -} -__initcall(sh7709_devices_setup); - -static struct ipr_data ipr_irq_table[] = { - { 16, 0, 12, 2 }, /* TMU TUNI0 */ - { 17, 0, 8, 4 }, /* TMU TUNI1 */ - { 18, 0, 4, 1 }, /* TMU TUNI1 */ - { 19, 0, 4, 1 }, /* TMU TUNI1 */ - { 20, 0, 0, 2 }, /* RTC CUI */ - { 21, 0, 0, 2 }, /* RTC CUI */ - { 22, 0, 0, 2 }, /* RTC CUI */ - - { 23, 1, 4, 3 }, /* SCI */ - { 24, 1, 4, 3 }, /* SCI */ - { 25, 1, 4, 3 }, /* SCI */ - { 26, 1, 4, 3 }, /* SCI */ - { 27, 1, 12, 3 }, /* WDT ITI */ - - { 32, 2, 0, 1 }, /* IRQ 0 */ - { 33, 2, 4, 1 }, /* IRQ 1 */ - { 34, 2, 8, 1 }, /* IRQ 2 APM */ - { 35, 2, 12, 1 }, /* IRQ 3 TOUCHSCREEN */ - - { 36, 3, 0, 1 }, /* IRQ 4 */ - { 37, 3, 4, 1 }, /* IRQ 5 */ - - { 48, 4, 12, 7 }, /* DMA */ - { 49, 4, 12, 7 }, /* DMA */ - { 50, 4, 12, 7 }, /* DMA */ - { 51, 4, 12, 7 }, /* DMA */ - - { 52, 4, 8, 3 }, /* IRDA */ - { 53, 4, 8, 3 }, /* IRDA */ - { 54, 4, 8, 3 }, /* IRDA */ - { 55, 4, 8, 3 }, /* IRDA */ - - { 56, 4, 4, 3 }, /* SCIF */ - { 57, 4, 4, 3 }, /* SCIF */ - { 58, 4, 4, 3 }, /* SCIF */ - { 59, 4, 4, 3 }, /* SCIF */ -}; - -static unsigned long ipr_offsets[] = { - 0xfffffee2, /* 0: IPRA */ - 0xfffffee4, /* 1: IPRB */ - 0xa4000016, /* 2: IPRC */ - 0xa4000018, /* 3: IPRD */ - 0xa400001a, /* 4: IPRE */ -}; - -static struct ipr_desc ipr_irq_desc = { - .ipr_offsets = ipr_offsets, - .nr_offsets = ARRAY_SIZE(ipr_offsets), - - .ipr_data = ipr_irq_table, - .nr_irqs = ARRAY_SIZE(ipr_irq_table), - - .chip = { - .name = "IPR-sh7709", - }, -}; - -void __init plat_irq_setup(void) -{ - register_ipr_controller(&ipr_irq_desc); -} diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c new file mode 100644 index 00000000000..60b04b1f945 --- /dev/null +++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c @@ -0,0 +1,224 @@ +/* + * SH3 Setup code for SH7706, SH7707, SH7708, SH7709 + * + * Copyright (C) 2007 Magnus Damm + * + * Based on setup-sh7709.c + * + * Copyright (C) 2006 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <asm/sci.h> + +enum { + UNUSED = 0, + + /* interrupt sources */ + IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, + PINT07, PINT815, + DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3, + SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI, + SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI, + SCI_ERI, SCI_RXI, SCI_TXI, SCI_TEI, + ADC_ADI, + LCDC, PCC0, PCC1, + TMU0, TMU1, TMU2_TUNI, TMU2_TICPI, + RTC_ATI, RTC_PRI, RTC_CUI, + WDT, + REF_RCMI, REF_ROVI, + + /* interrupt groups */ + RTC, REF, TMU2, DMAC, SCI, SCIF2, SCIF0, +}; + +static struct intc_vect vectors[] __initdata = { + INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), + INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460), + INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0), + INTC_VECT(RTC_CUI, 0x4c0), + INTC_VECT(SCI_ERI, 0x4e0), INTC_VECT(SCI_RXI, 0x500), + INTC_VECT(SCI_TXI, 0x520), INTC_VECT(SCI_TEI, 0x540), + INTC_VECT(WDT, 0x560), + INTC_VECT(REF_RCMI, 0x580), + INTC_VECT(REF_ROVI, 0x5a0), +#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0), + INTC_VECT(DMAC_DEI0, 0x800), INTC_VECT(DMAC_DEI1, 0x820), + INTC_VECT(DMAC_DEI2, 0x840), INTC_VECT(DMAC_DEI3, 0x860), + INTC_VECT(ADC_ADI, 0x980), + INTC_VECT(SCIF2_ERI, 0x900), INTC_VECT(SCIF2_RXI, 0x920), + INTC_VECT(SCIF2_BRI, 0x940), INTC_VECT(SCIF2_TXI, 0x960), +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + INTC_VECT(PINT07, 0x700), INTC_VECT(PINT815, 0x720), + INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0), + INTC_VECT(SCIF0_BRI, 0x8c0), INTC_VECT(SCIF0_TXI, 0x8e0), +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7707) + INTC_VECT(LCDC, 0x9a0), + INTC_VECT(PCC0, 0x9c0), INTC_VECT(PCC1, 0x9e0), +#endif +}; + +static struct intc_group groups[] __initdata = { + INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), + INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI), + INTC_GROUP(REF, REF_RCMI, REF_ROVI), + INTC_GROUP(DMAC, DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3), + INTC_GROUP(SCI, SCI_ERI, SCI_RXI, SCI_TXI, SCI_TEI), + INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI), + INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI), +}; + +static struct intc_prio priorities[] __initdata = { + INTC_PRIO(DMAC, 7), + INTC_PRIO(SCI, 3), + INTC_PRIO(SCIF2, 3), + INTC_PRIO(SCIF0, 3), +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, + { 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, SCI, 0 } }, +#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + { 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } }, + { 0xa4000018, 0, 16, 4, /* IPRD */ { 0, 0, IRQ5, IRQ4 } }, + { 0xa400001a, 0, 16, 4, /* IPRE */ { DMAC, 0, SCIF2, ADC_ADI } }, +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + { 0xa4000018, 0, 16, 4, /* IPRD */ { PINT07, PINT815, } }, + { 0xa400001a, 0, 16, 4, /* IPRE */ { 0, SCIF0 } }, +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7707) + { 0xa400001c, 0, 16, 4, /* IPRF */ { 0, LCDC, PCC0, PCC1, } }, +#endif +}; + +static DECLARE_INTC_DESC(intc_desc, "sh770x", vectors, groups, + priorities, NULL, prio_registers, NULL); + +#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) +static struct intc_vect vectors_irq[] __initdata = { + INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620), + INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660), +}; + +static DECLARE_INTC_DESC(intc_desc_irq, "sh770x-irq", vectors_irq, NULL, + priorities, NULL, prio_registers, NULL); +#endif + +static struct resource rtc_resources[] = { + [0] = { + .start = 0xfffffec0, + .end = 0xfffffec0 + 0x1e, + .flags = IORESOURCE_IO, + }, + [1] = { + .start = 20, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = 21, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = 22, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device rtc_device = { + .name = "sh-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(rtc_resources), + .resource = rtc_resources, +}; + +static struct plat_sci_port sci_platform_data[] = { + { + .mapbase = 0xfffffe80, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCI, + .irqs = { 23, 24, 25, 0 }, + }, +#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + { + .mapbase = 0xa4000150, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 56, 57, 59, 58 }, + }, +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + { + .mapbase = 0xa4000140, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_IRDA, + .irqs = { 52, 53, 55, 54 }, + }, +#endif + { + .flags = 0, + } +}; + +static struct platform_device sci_device = { + .name = "sh-sci", + .id = -1, + .dev = { + .platform_data = sci_platform_data, + }, +}; + +static struct platform_device *sh770x_devices[] __initdata = { + &sci_device, + &rtc_device, +}; + +static int __init sh770x_devices_setup(void) +{ + return platform_add_devices(sh770x_devices, + ARRAY_SIZE(sh770x_devices)); +} +__initcall(sh770x_devices_setup); + +#define INTC_ICR1 0xa4000010UL +#define INTC_ICR1_IRQLVL (1<<14) + +void __init plat_irq_setup_pins(int mode) +{ + if (mode == IRQ_MODE_IRQ) { +#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + ctrl_outw(ctrl_inw(INTC_ICR1) & ~INTC_ICR1_IRQLVL, INTC_ICR1); + register_intc_controller(&intc_desc_irq); + return; +#endif + } + BUG(); +} + +void __init plat_irq_setup(void) +{ + register_intc_controller(&intc_desc); +} diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c index 13228489337..84e5629fa84 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c @@ -1,7 +1,7 @@ /* - * SH7710 Setup + * SH3 Setup code for SH7710, SH7712 * - * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2006, 2007 Paul Mundt * Copyright (C) 2007 Nobuhiro Iwamatsu * * This file is subject to the terms and conditions of the GNU General Public @@ -10,8 +10,140 @@ */ #include <linux/platform_device.h> #include <linux/init.h> +#include <linux/irq.h> #include <linux/serial.h> #include <asm/sci.h> +#include <asm/rtc.h> + +enum { + UNUSED = 0, + + /* interrupt sources */ + IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, + DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3, + SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI, + SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI, + DMAC_DEI4, DMAC_DEI5, + IPSEC, + EDMAC0, EDMAC1, EDMAC2, + SIOF0_ERI, SIOF0_TXI, SIOF0_RXI, SIOF0_CCI, + SIOF1_ERI, SIOF1_TXI, SIOF1_RXI, SIOF1_CCI, + TMU0, TMU1, TMU2, + RTC_ATI, RTC_PRI, RTC_CUI, + WDT, + REF, + + /* interrupt groups */ + RTC, DMAC1, SCIF0, SCIF1, DMAC2, SIOF0, SIOF1, +}; + +static struct intc_vect vectors[] __initdata = { + INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0), + INTC_VECT(DMAC_DEI0, 0x800), INTC_VECT(DMAC_DEI1, 0x820), + INTC_VECT(DMAC_DEI2, 0x840), INTC_VECT(DMAC_DEI3, 0x860), + INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0), + INTC_VECT(SCIF0_BRI, 0x8c0), INTC_VECT(SCIF0_TXI, 0x8e0), + INTC_VECT(SCIF1_ERI, 0x900), INTC_VECT(SCIF1_RXI, 0x920), + INTC_VECT(SCIF1_BRI, 0x940), INTC_VECT(SCIF1_TXI, 0x960), + INTC_VECT(DMAC_DEI4, 0xb80), INTC_VECT(DMAC_DEI5, 0xba0), +#ifdef CONFIG_CPU_SUBTYPE_SH7710 + INTC_VECT(IPSEC, 0xbe0), +#endif + INTC_VECT(EDMAC0, 0xc00), INTC_VECT(EDMAC1, 0xc20), + INTC_VECT(EDMAC2, 0xc40), + INTC_VECT(SIOF0_ERI, 0xe00), INTC_VECT(SIOF0_TXI, 0xe20), + INTC_VECT(SIOF0_RXI, 0xe40), INTC_VECT(SIOF0_CCI, 0xe60), + INTC_VECT(SIOF1_ERI, 0xe80), INTC_VECT(SIOF1_TXI, 0xea0), + INTC_VECT(SIOF1_RXI, 0xec0), INTC_VECT(SIOF1_CCI, 0xee0), + INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), + INTC_VECT(TMU2, 0x440), + INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0), + INTC_VECT(RTC_CUI, 0x4c0), + INTC_VECT(WDT, 0x560), + INTC_VECT(REF, 0x580), +}; + +static struct intc_group groups[] __initdata = { + INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), + INTC_GROUP(DMAC1, DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3), + INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI), + INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI), + INTC_GROUP(DMAC2, DMAC_DEI4, DMAC_DEI5), + INTC_GROUP(SIOF0, SIOF0_ERI, SIOF0_TXI, SIOF0_RXI, SIOF0_CCI), + INTC_GROUP(SIOF1, SIOF1_ERI, SIOF1_TXI, SIOF1_RXI, SIOF1_CCI), +}; + +static struct intc_prio priorities[] __initdata = { + INTC_PRIO(DMAC1, 7), + INTC_PRIO(DMAC2, 7), + INTC_PRIO(SCIF0, 3), + INTC_PRIO(SCIF1, 3), + INTC_PRIO(SIOF0, 3), + INTC_PRIO(SIOF1, 3), + INTC_PRIO(EDMAC0, 5), + INTC_PRIO(EDMAC1, 5), + INTC_PRIO(EDMAC2, 5), +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, + { 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, 0, 0 } }, + { 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } }, + { 0xa4000018, 0, 16, 4, /* IPRD */ { 0, 0, IRQ5, IRQ4 } }, + { 0xa400001a, 0, 16, 4, /* IPRE */ { DMAC1, SCIF0, SCIF1 } }, + { 0xa4080000, 0, 16, 4, /* IPRF */ { 0, DMAC2 } }, +#ifdef CONFIG_CPU_SUBTYPE_SH7710 + { 0xa4080000, 0, 16, 4, /* IPRF */ { IPSEC } }, +#endif + { 0xa4080002, 0, 16, 4, /* IPRG */ { EDMAC0, EDMAC1, EDMAC2 } }, + { 0xa4080004, 0, 16, 4, /* IPRH */ { 0, 0, 0, SIOF0 } }, + { 0xa4080006, 0, 16, 4, /* IPRI */ { 0, 0, SIOF1 } }, +}; + +static DECLARE_INTC_DESC(intc_desc, "sh7710", vectors, groups, + priorities, NULL, prio_registers, NULL); + +static struct intc_vect vectors_irq[] __initdata = { + INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620), + INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660), +}; + +static DECLARE_INTC_DESC(intc_desc_irq, "sh7710-irq", vectors_irq, NULL, + priorities, NULL, prio_registers, NULL); + +static struct resource rtc_resources[] = { + [0] = { + .start = 0xa413fec0, + .end = 0xa413fec0 + 0x1e, + .flags = IORESOURCE_IO, + }, + [1] = { + .start = 20, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = 21, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = 22, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct sh_rtc_platform_info rtc_info = { + .capabilities = RTC_CAP_4_DIGIT_YEAR, +}; + +static struct platform_device rtc_device = { + .name = "sh-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(rtc_resources), + .resource = rtc_resources, + .dev = { + .platform_data = &rtc_info, + }, +}; static struct plat_sci_port sci_platform_data[] = { { @@ -20,7 +152,7 @@ static struct plat_sci_port sci_platform_data[] = { .type = PORT_SCIF, .irqs = { 52, 53, 55, 54 }, }, { - .mapbase = 0xa4420000, + .mapbase = 0xa4410000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, .irqs = { 56, 57, 59, 58 }, @@ -40,6 +172,7 @@ static struct platform_device sci_device = { static struct platform_device *sh7710_devices[] __initdata = { &sci_device, + &rtc_device, }; static int __init sh7710_devices_setup(void) @@ -49,59 +182,16 @@ static int __init sh7710_devices_setup(void) } __initcall(sh7710_devices_setup); -static struct ipr_data ipr_irq_table[] = { - /* IRQ, IPR-idx, shift, priority */ - { 16, 0, 12, 2 }, /* TMU0 TUNI*/ - { 17, 0, 8, 2 }, /* TMU1 TUNI */ - { 18, 0, 4, 2 }, /* TMU2 TUNI */ - { 27, 1, 12, 2 }, /* WDT ITI */ - { 20, 0, 0, 2 }, /* RTC ATI (alarm) */ - { 21, 0, 0, 2 }, /* RTC PRI (period) */ - { 22, 0, 0, 2 }, /* RTC CUI (carry) */ - { 48, 4, 12, 7 }, /* DMAC DMTE0 */ - { 49, 4, 12, 7 }, /* DMAC DMTE1 */ - { 50, 4, 12, 7 }, /* DMAC DMTE2 */ - { 51, 4, 12, 7 }, /* DMAC DMTE3 */ - { 52, 4, 8, 3 }, /* SCIF0 ERI */ - { 53, 4, 8, 3 }, /* SCIF0 RXI */ - { 54, 4, 8, 3 }, /* SCIF0 BRI */ - { 55, 4, 8, 3 }, /* SCIF0 TXI */ - { 56, 4, 4, 3 }, /* SCIF1 ERI */ - { 57, 4, 4, 3 }, /* SCIF1 RXI */ - { 58, 4, 4, 3 }, /* SCIF1 BRI */ - { 59, 4, 4, 3 }, /* SCIF1 TXI */ - { 76, 5, 8, 7 }, /* DMAC DMTE4 */ - { 77, 5, 8, 7 }, /* DMAC DMTE5 */ - { 80, 6, 12, 5 }, /* EDMAC EINT0 */ - { 81, 6, 8, 5 }, /* EDMAC EINT1 */ - { 82, 6, 4, 5 }, /* EDMAC EINT2 */ -}; - -static unsigned long ipr_offsets[] = { - 0xA414FEE2, /* 0: IPRA */ - 0xA414FEE4, /* 1: IPRB */ - 0xA4140016, /* 2: IPRC */ - 0xA4140018, /* 3: IPRD */ - 0xA414001A, /* 4: IPRE */ - 0xA4080000, /* 5: IPRF */ - 0xA4080002, /* 6: IPRG */ - 0xA4080004, /* 7: IPRH */ - 0xA4080006, /* 8: IPRI */ -}; - -static struct ipr_desc ipr_irq_desc = { - .ipr_offsets = ipr_offsets, - .nr_offsets = ARRAY_SIZE(ipr_offsets), - - .ipr_data = ipr_irq_table, - .nr_irqs = ARRAY_SIZE(ipr_irq_table), - - .chip = { - .name = "IPR-sh7710", - }, -}; +void __init plat_irq_setup_pins(int mode) +{ + if (mode == IRQ_MODE_IRQ) { + register_intc_controller(&intc_desc_irq); + return; + } + BUG(); +} void __init plat_irq_setup(void) { - register_ipr_controller(&ipr_irq_desc); + register_intc_controller(&intc_desc); } diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c new file mode 100644 index 00000000000..a0929b8a95a --- /dev/null +++ b/arch/sh/kernel/cpu/sh3/setup-sh7720.c @@ -0,0 +1,210 @@ +/* + * SH7720 Setup + * + * Copyright (C) 2007 Markus Brunner, Mark Jonas + * + * Based on arch/sh/kernel/cpu/sh4/setup-sh7750.c: + * + * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2006 Jamie Lenehan + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/platform_device.h> +#include <linux/init.h> +#include <linux/serial.h> +#include <linux/io.h> +#include <asm/sci.h> +#include <asm/rtc.h> + +#define INTC_ICR1 0xA4140010UL +#define INTC_ICR_IRLM 0x4000 +#define INTC_ICR_IRQ (~INTC_ICR_IRLM) + +static struct resource rtc_resources[] = { + [0] = { + .start = 0xa413fec0, + .end = 0xa413fec0 + 0x28 - 1, + .flags = IORESOURCE_IO, + }, + [1] = { + /* Period IRQ */ + .start = 21, + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* Carry IRQ */ + .start = 22, + .flags = IORESOURCE_IRQ, + }, + [3] = { + /* Alarm IRQ */ + .start = 20, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct sh_rtc_platform_info rtc_info = { + .capabilities = RTC_CAP_4_DIGIT_YEAR, +}; + +static struct platform_device rtc_device = { + .name = "sh-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(rtc_resources), + .resource = rtc_resources, + .dev = { + .platform_data = &rtc_info, + }, +}; + +static struct plat_sci_port sci_platform_data[] = { + { + .mapbase = 0xa4430000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 80, 80, 80, 80 }, + }, { + .mapbase = 0xa4438000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 81, 81, 81, 81 }, + }, { + + .flags = 0, + } +}; + +static struct platform_device sci_device = { + .name = "sh-sci", + .id = -1, + .dev = { + .platform_data = sci_platform_data, + }, +}; + +static struct platform_device *sh7720_devices[] __initdata = { + &rtc_device, + &sci_device, +}; + +static int __init sh7720_devices_setup(void) +{ + return platform_add_devices(sh7720_devices, + ARRAY_SIZE(sh7720_devices)); +} +__initcall(sh7720_devices_setup); + +enum { + UNUSED = 0, + + /* interrupt sources */ + TMU0, TMU1, TMU2, RTC_ATI, RTC_PRI, RTC_CUI, + WDT, REF_RCMI, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND, + IRQ0, IRQ1, IRQ2, IRQ3, + USBF_SPD, TMU_SUNI, IRQ5, IRQ4, + DMAC1_DEI0, DMAC1_DEI1, DMAC1_DEI2, DMAC1_DEI3, LCDC, SSL, + ADC, DMAC2_DEI4, DMAC2_DEI5, USBFI0, USBFI1, CMT, + SCIF0, SCIF1, + PINT07, PINT815, TPU0, TPU1, TPU2, TPU3, IIC, + SIOF0, SIOF1, MMCI0, MMCI1, MMCI2, MMCI3, PCC, + USBHI, AFEIF, + H_UDI, + /* interrupt groups */ + TMU, RTC, SIM, DMAC1, USBFI, DMAC2, USB, TPU, MMC, +}; + +static struct intc_vect vectors[] __initdata = { + INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), + INTC_VECT(TMU2, 0x440), INTC_VECT(RTC_ATI, 0x480), + INTC_VECT(RTC_PRI, 0x4a0), INTC_VECT(RTC_CUI, 0x4c0), + INTC_VECT(SIM_ERI, 0x4e0), INTC_VECT(SIM_RXI, 0x500), + INTC_VECT(SIM_TXI, 0x520), INTC_VECT(SIM_TEND, 0x540), + INTC_VECT(WDT, 0x560), INTC_VECT(REF_RCMI, 0x580), + /* H_UDI cannot be masked */ INTC_VECT(TMU_SUNI, 0x6c0), + INTC_VECT(USBF_SPD, 0x6e0), INTC_VECT(DMAC1_DEI0, 0x800), + INTC_VECT(DMAC1_DEI1, 0x820), INTC_VECT(DMAC1_DEI2, 0x840), + INTC_VECT(DMAC1_DEI3, 0x860), INTC_VECT(LCDC, 0x900), + INTC_VECT(SSL, 0x980), INTC_VECT(USBFI0, 0xa20), + INTC_VECT(USBFI1, 0xa40), INTC_VECT(USBHI, 0xa60), + INTC_VECT(DMAC2_DEI4, 0xb80), INTC_VECT(DMAC2_DEI5, 0xba0), + INTC_VECT(ADC, 0xbe0), INTC_VECT(SCIF0, 0xc00), + INTC_VECT(SCIF1, 0xc20), INTC_VECT(PINT07, 0xc80), + INTC_VECT(PINT815, 0xca0), INTC_VECT(SIOF0, 0xd00), + INTC_VECT(SIOF1, 0xd20), INTC_VECT(TPU0, 0xd80), + INTC_VECT(TPU1, 0xda0), INTC_VECT(TPU2, 0xdc0), + INTC_VECT(TPU3, 0xde0), INTC_VECT(IIC, 0xe00), + INTC_VECT(MMCI0, 0xe80), INTC_VECT(MMCI1, 0xea0), + INTC_VECT(MMCI2, 0xec0), INTC_VECT(MMCI3, 0xee0), + INTC_VECT(CMT, 0xf00), INTC_VECT(PCC, 0xf60), + INTC_VECT(AFEIF, 0xfe0), +}; + +static struct intc_group groups[] __initdata = { + INTC_GROUP(TMU, TMU0, TMU1, TMU2), + INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), + INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND), + INTC_GROUP(DMAC1, DMAC1_DEI0, DMAC1_DEI1, DMAC1_DEI2, DMAC1_DEI3), + INTC_GROUP(USBFI, USBFI0, USBFI1), + INTC_GROUP(DMAC2, DMAC2_DEI4, DMAC2_DEI5), + INTC_GROUP(TPU, TPU0, TPU1, TPU2, TPU3), + INTC_GROUP(MMC, MMCI0, MMCI1, MMCI2, MMCI3), +}; + +static struct intc_prio priorities[] __initdata = { + INTC_PRIO(SCIF0, 2), + INTC_PRIO(SCIF1, 2), + INTC_PRIO(DMAC1, 1), + INTC_PRIO(DMAC2, 1), + INTC_PRIO(RTC, 2), + INTC_PRIO(TMU, 2), + INTC_PRIO(TPU, 2), +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xA414FEE2UL, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, + { 0xA414FEE4UL, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, SIM, 0 } }, + { 0xA4140016UL, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } }, + { 0xA4140018UL, 0, 16, 4, /* IPRD */ { USBF_SPD, TMU_SUNI, IRQ5, IRQ4 } }, + { 0xA414001AUL, 0, 16, 4, /* IPRE */ { DMAC1, 0, LCDC, SSL } }, + { 0xA4080000UL, 0, 16, 4, /* IPRF */ { ADC, DMAC2, USBFI, CMT } }, + { 0xA4080002UL, 0, 16, 4, /* IPRG */ { SCIF0, SCIF1, 0, 0 } }, + { 0xA4080004UL, 0, 16, 4, /* IPRH */ { PINT07, PINT815, TPU, IIC } }, + { 0xA4080006UL, 0, 16, 4, /* IPRI */ { SIOF0, SIOF1, MMC, PCC } }, + { 0xA4080008UL, 0, 16, 4, /* IPRJ */ { 0, USBHI, 0, AFEIF } }, +}; + +static DECLARE_INTC_DESC(intc_desc, "sh7720", vectors, groups, + priorities, NULL, prio_registers, NULL); + +static struct intc_sense_reg sense_registers[] __initdata = { + { INTC_ICR1, 16, 2, { 0, 0, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0 } }, +}; + +static struct intc_vect vectors_irq[] __initdata = { + INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620), + INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660), + INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0), +}; + +static DECLARE_INTC_DESC(intc_irq_desc, "sh7720-irq", vectors_irq, + NULL, priorities, NULL, prio_registers, sense_registers); + +void __init plat_irq_setup_pins(int mode) +{ + switch (mode) { + case IRQ_MODE_IRQ: + ctrl_outw(ctrl_inw(INTC_ICR1) & INTC_ICR_IRQ, INTC_ICR1); + register_intc_controller(&intc_irq_desc); + break; + default: + BUG(); + } +} + +void __init plat_irq_setup(void) +{ + register_intc_controller(&intc_desc); +} diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c index 98d28fb1ce1..21375d777e9 100644 --- a/arch/sh/kernel/cpu/sh4/probe.c +++ b/arch/sh/kernel/cpu/sh4/probe.c @@ -3,7 +3,7 @@ * * CPU Subtype Probing for SH-4. * - * Copyright (C) 2001 - 2006 Paul Mundt + * Copyright (C) 2001 - 2007 Paul Mundt * Copyright (C) 2003 Richard Curnow * * This file is subject to the terms and conditions of the GNU General Public @@ -12,7 +12,6 @@ */ #include <linux/init.h> #include <linux/io.h> -#include <linux/smp.h> #include <asm/processor.h> #include <asm/cache.h> @@ -36,37 +35,34 @@ int __init detect_cpu_and_cache_system(void) /* * Setup some sane SH-4 defaults for the icache */ - current_cpu_data.icache.way_incr = (1 << 13); - current_cpu_data.icache.entry_shift = 5; - current_cpu_data.icache.sets = 256; - current_cpu_data.icache.ways = 1; - current_cpu_data.icache.linesz = L1_CACHE_BYTES; + boot_cpu_data.icache.way_incr = (1 << 13); + boot_cpu_data.icache.entry_shift = 5; + boot_cpu_data.icache.sets = 256; + boot_cpu_data.icache.ways = 1; + boot_cpu_data.icache.linesz = L1_CACHE_BYTES; /* * And again for the dcache .. */ - current_cpu_data.dcache.way_incr = (1 << 14); - current_cpu_data.dcache.entry_shift = 5; - current_cpu_data.dcache.sets = 512; - current_cpu_data.dcache.ways = 1; - current_cpu_data.dcache.linesz = L1_CACHE_BYTES; + boot_cpu_data.dcache.way_incr = (1 << 14); + boot_cpu_data.dcache.entry_shift = 5; + boot_cpu_data.dcache.sets = 512; + boot_cpu_data.dcache.ways = 1; + boot_cpu_data.dcache.linesz = L1_CACHE_BYTES; /* - * Setup some generic flags we can probe - * (L2 and DSP detection only work on SH-4A) + * Setup some generic flags we can probe on SH-4A parts */ if (((pvr >> 16) & 0xff) == 0x10) { - if ((cvr & 0x02000000) == 0) - current_cpu_data.flags |= CPU_HAS_L2_CACHE; if ((cvr & 0x10000000) == 0) - current_cpu_data.flags |= CPU_HAS_DSP; + boot_cpu_data.flags |= CPU_HAS_DSP; - current_cpu_data.flags |= CPU_HAS_LLSC; + boot_cpu_data.flags |= CPU_HAS_LLSC; } /* FPU detection works for everyone */ if ((cvr & 0x20000000) == 1) - current_cpu_data.flags |= CPU_HAS_FPU; + boot_cpu_data.flags |= CPU_HAS_FPU; /* Mask off the upper chip ID */ pvr &= 0xffff; @@ -77,140 +73,140 @@ int __init detect_cpu_and_cache_system(void) */ switch (pvr) { case 0x205: - current_cpu_data.type = CPU_SH7750; - current_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | + boot_cpu_data.type = CPU_SH7750; + boot_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | CPU_HAS_PERF_COUNTER; break; case 0x206: - current_cpu_data.type = CPU_SH7750S; - current_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | + boot_cpu_data.type = CPU_SH7750S; + boot_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | CPU_HAS_PERF_COUNTER; break; case 0x1100: - current_cpu_data.type = CPU_SH7751; - current_cpu_data.flags |= CPU_HAS_FPU; + boot_cpu_data.type = CPU_SH7751; + boot_cpu_data.flags |= CPU_HAS_FPU; break; case 0x2001: case 0x2004: - current_cpu_data.type = CPU_SH7770; - current_cpu_data.icache.ways = 4; - current_cpu_data.dcache.ways = 4; + boot_cpu_data.type = CPU_SH7770; + boot_cpu_data.icache.ways = 4; + boot_cpu_data.dcache.ways = 4; - current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_LLSC; + boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_LLSC; break; case 0x2006: case 0x200A: if (prr == 0x61) - current_cpu_data.type = CPU_SH7781; + boot_cpu_data.type = CPU_SH7781; else - current_cpu_data.type = CPU_SH7780; + boot_cpu_data.type = CPU_SH7780; - current_cpu_data.icache.ways = 4; - current_cpu_data.dcache.ways = 4; + boot_cpu_data.icache.ways = 4; + boot_cpu_data.dcache.ways = 4; - current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER | + boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER | CPU_HAS_LLSC; break; case 0x3000: case 0x3003: case 0x3009: - current_cpu_data.type = CPU_SH7343; - current_cpu_data.icache.ways = 4; - current_cpu_data.dcache.ways = 4; - current_cpu_data.flags |= CPU_HAS_LLSC; + boot_cpu_data.type = CPU_SH7343; + boot_cpu_data.icache.ways = 4; + boot_cpu_data.dcache.ways = 4; + boot_cpu_data.flags |= CPU_HAS_LLSC; break; case 0x3004: case 0x3007: - current_cpu_data.type = CPU_SH7785; - current_cpu_data.icache.ways = 4; - current_cpu_data.dcache.ways = 4; - current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER | + boot_cpu_data.type = CPU_SH7785; + boot_cpu_data.icache.ways = 4; + boot_cpu_data.dcache.ways = 4; + boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER | CPU_HAS_LLSC; break; case 0x3008: if (prr == 0xa0) { - current_cpu_data.type = CPU_SH7722; - current_cpu_data.icache.ways = 4; - current_cpu_data.dcache.ways = 4; - current_cpu_data.flags |= CPU_HAS_LLSC; + boot_cpu_data.type = CPU_SH7722; + boot_cpu_data.icache.ways = 4; + boot_cpu_data.dcache.ways = 4; + boot_cpu_data.flags |= CPU_HAS_LLSC; } break; case 0x4000: /* 1st cut */ case 0x4001: /* 2nd cut */ - current_cpu_data.type = CPU_SHX3; - current_cpu_data.icache.ways = 4; - current_cpu_data.dcache.ways = 4; - current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER | + boot_cpu_data.type = CPU_SHX3; + boot_cpu_data.icache.ways = 4; + boot_cpu_data.dcache.ways = 4; + boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER | CPU_HAS_LLSC; break; case 0x8000: - current_cpu_data.type = CPU_ST40RA; - current_cpu_data.flags |= CPU_HAS_FPU; + boot_cpu_data.type = CPU_ST40RA; + boot_cpu_data.flags |= CPU_HAS_FPU; break; case 0x8100: - current_cpu_data.type = CPU_ST40GX1; - current_cpu_data.flags |= CPU_HAS_FPU; + boot_cpu_data.type = CPU_ST40GX1; + boot_cpu_data.flags |= CPU_HAS_FPU; break; case 0x700: - current_cpu_data.type = CPU_SH4_501; - current_cpu_data.icache.ways = 2; - current_cpu_data.dcache.ways = 2; + boot_cpu_data.type = CPU_SH4_501; + boot_cpu_data.icache.ways = 2; + boot_cpu_data.dcache.ways = 2; break; case 0x600: - current_cpu_data.type = CPU_SH4_202; - current_cpu_data.icache.ways = 2; - current_cpu_data.dcache.ways = 2; - current_cpu_data.flags |= CPU_HAS_FPU; + boot_cpu_data.type = CPU_SH4_202; + boot_cpu_data.icache.ways = 2; + boot_cpu_data.dcache.ways = 2; + boot_cpu_data.flags |= CPU_HAS_FPU; break; case 0x500 ... 0x501: switch (prr) { case 0x10: - current_cpu_data.type = CPU_SH7750R; + boot_cpu_data.type = CPU_SH7750R; break; case 0x11: - current_cpu_data.type = CPU_SH7751R; + boot_cpu_data.type = CPU_SH7751R; break; case 0x50 ... 0x5f: - current_cpu_data.type = CPU_SH7760; + boot_cpu_data.type = CPU_SH7760; break; } - current_cpu_data.icache.ways = 2; - current_cpu_data.dcache.ways = 2; + boot_cpu_data.icache.ways = 2; + boot_cpu_data.dcache.ways = 2; - current_cpu_data.flags |= CPU_HAS_FPU; + boot_cpu_data.flags |= CPU_HAS_FPU; break; default: - current_cpu_data.type = CPU_SH_NONE; + boot_cpu_data.type = CPU_SH_NONE; break; } #ifdef CONFIG_SH_DIRECT_MAPPED - current_cpu_data.icache.ways = 1; - current_cpu_data.dcache.ways = 1; + boot_cpu_data.icache.ways = 1; + boot_cpu_data.dcache.ways = 1; #endif #ifdef CONFIG_CPU_HAS_PTEA - current_cpu_data.flags |= CPU_HAS_PTEA; + boot_cpu_data.flags |= CPU_HAS_PTEA; #endif /* * On anything that's not a direct-mapped cache, look to the CVR * for I/D-cache specifics. */ - if (current_cpu_data.icache.ways > 1) { + if (boot_cpu_data.icache.ways > 1) { size = sizes[(cvr >> 20) & 0xf]; - current_cpu_data.icache.way_incr = (size >> 1); - current_cpu_data.icache.sets = (size >> 6); + boot_cpu_data.icache.way_incr = (size >> 1); + boot_cpu_data.icache.sets = (size >> 6); } /* And the rest of the D-cache */ - if (current_cpu_data.dcache.ways > 1) { + if (boot_cpu_data.dcache.ways > 1) { size = sizes[(cvr >> 16) & 0xf]; - current_cpu_data.dcache.way_incr = (size >> 1); - current_cpu_data.dcache.sets = (size >> 6); + boot_cpu_data.dcache.way_incr = (size >> 1); + boot_cpu_data.dcache.sets = (size >> 6); } /* @@ -218,7 +214,7 @@ int __init detect_cpu_and_cache_system(void) * * SH-4A's have an optional PIPT L2. */ - if (current_cpu_data.flags & CPU_HAS_L2_CACHE) { + if (boot_cpu_data.flags & CPU_HAS_L2_CACHE) { /* * Size calculation is much more sensible * than it is for the L1. @@ -229,22 +225,22 @@ int __init detect_cpu_and_cache_system(void) BUG_ON(!size); - current_cpu_data.scache.way_incr = (1 << 16); - current_cpu_data.scache.entry_shift = 5; - current_cpu_data.scache.ways = 4; - current_cpu_data.scache.linesz = L1_CACHE_BYTES; + boot_cpu_data.scache.way_incr = (1 << 16); + boot_cpu_data.scache.entry_shift = 5; + boot_cpu_data.scache.ways = 4; + boot_cpu_data.scache.linesz = L1_CACHE_BYTES; - current_cpu_data.scache.entry_mask = - (current_cpu_data.scache.way_incr - - current_cpu_data.scache.linesz); + boot_cpu_data.scache.entry_mask = + (boot_cpu_data.scache.way_incr - + boot_cpu_data.scache.linesz); - current_cpu_data.scache.sets = size / - (current_cpu_data.scache.linesz * - current_cpu_data.scache.ways); + boot_cpu_data.scache.sets = size / + (boot_cpu_data.scache.linesz * + boot_cpu_data.scache.ways); - current_cpu_data.scache.way_size = - (current_cpu_data.scache.sets * - current_cpu_data.scache.linesz); + boot_cpu_data.scache.way_size = + (boot_cpu_data.scache.sets * + boot_cpu_data.scache.linesz); } return 0; diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c index f2286de22bd..523f68a9ce0 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c @@ -104,7 +104,7 @@ enum { DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF, }; -static struct intc_vect vectors[] = { +static struct intc_vect vectors[] __initdata = { INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620), INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460), @@ -118,7 +118,7 @@ static struct intc_vect vectors[] = { INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0), }; -static struct intc_group groups[] = { +static struct intc_group groups[] __initdata = { INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI), INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI), @@ -126,20 +126,20 @@ static struct intc_group groups[] = { INTC_GROUP(REF, REF_RCMI, REF_ROVI), }; -static struct intc_prio priorities[] = { +static struct intc_prio priorities[] __initdata = { INTC_PRIO(SCIF, 3), INTC_PRIO(SCI1, 3), INTC_PRIO(DMAC, 7), }; -static struct intc_prio_reg prio_registers[] = { - { 0xffd00004, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, - { 0xffd00008, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } }, - { 0xffd0000c, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } }, - { 0xffd00010, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } }, - { 0xfe080000, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0, - TMU4, TMU3, - PCIC1, PCIC0_PCISERR } }, +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, + { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } }, + { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } }, + { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } }, + { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0, + TMU4, TMU3, + PCIC1, PCIC0_PCISERR } }, }; static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups, @@ -150,13 +150,13 @@ static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups, defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ defined(CONFIG_CPU_SUBTYPE_SH7751) || \ defined(CONFIG_CPU_SUBTYPE_SH7091) -static struct intc_vect vectors_dma4[] = { +static struct intc_vect vectors_dma4[] __initdata = { INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), INTC_VECT(DMAC_DMAE, 0x6c0), }; -static struct intc_group groups_dma4[] = { +static struct intc_group groups_dma4[] __initdata = { INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3, DMAC_DMAE), }; @@ -168,7 +168,7 @@ static DECLARE_INTC_DESC(intc_desc_dma4, "sh7750_dma4", /* SH7750R and SH7751R both have 8-channel DMA controllers */ #if defined(CONFIG_CPU_SUBTYPE_SH7750R) || defined(CONFIG_CPU_SUBTYPE_SH7751R) -static struct intc_vect vectors_dma8[] = { +static struct intc_vect vectors_dma8[] __initdata = { INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0), @@ -176,7 +176,7 @@ static struct intc_vect vectors_dma8[] = { INTC_VECT(DMAC_DMAE, 0x6c0), }; -static struct intc_group groups_dma8[] = { +static struct intc_group groups_dma8[] __initdata = { INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE), @@ -191,11 +191,11 @@ static DECLARE_INTC_DESC(intc_desc_dma8, "sh7750_dma8", #if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ defined(CONFIG_CPU_SUBTYPE_SH7751) || \ defined(CONFIG_CPU_SUBTYPE_SH7751R) -static struct intc_vect vectors_tmu34[] = { +static struct intc_vect vectors_tmu34[] __initdata = { INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80), }; -static struct intc_mask_reg mask_registers[] = { +static struct intc_mask_reg mask_registers[] __initdata = { { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TMU4, TMU3, @@ -210,7 +210,7 @@ static DECLARE_INTC_DESC(intc_desc_tmu34, "sh7750_tmu34", #endif /* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */ -static struct intc_vect vectors_irlm[] = { +static struct intc_vect vectors_irlm[] __initdata = { INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0), INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360), }; @@ -220,14 +220,14 @@ static DECLARE_INTC_DESC(intc_desc_irlm, "sh7750_irlm", vectors_irlm, NULL, /* SH7751 and SH7751R both have PCI */ #if defined(CONFIG_CPU_SUBTYPE_SH7751) || defined(CONFIG_CPU_SUBTYPE_SH7751R) -static struct intc_vect vectors_pci[] = { +static struct intc_vect vectors_pci[] __initdata = { INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0), INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0), INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60), INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20), }; -static struct intc_group groups_pci[] = { +static struct intc_group groups_pci[] __initdata = { INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3), }; @@ -282,13 +282,19 @@ void __init plat_irq_setup(void) #define INTC_ICR 0xffd00000UL #define INTC_ICR_IRLM (1<<7) -/* enable individual interrupt mode for external interupts */ -void __init ipr_irq_enable_irlm(void) +void __init plat_irq_setup_pins(int mode) { #if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7091) BUG(); /* impossible to mask interrupts on SH7750 and SH7091 */ + return; #endif - register_intc_controller(&intc_desc_irlm); - ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); + switch (mode) { + case IRQ_MODE_IRQ: /* individual interrupt mode for IRL3-0 */ + ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); + register_intc_controller(&intc_desc_irlm); + break; + default: + BUG(); + } } diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c index 47fa2705625..7a898cb1d94 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c @@ -12,6 +12,136 @@ #include <linux/serial.h> #include <asm/sci.h> +enum { + UNUSED = 0, + + /* interrupt sources */ + IRL0, IRL1, IRL2, IRL3, + HUDI, GPIOI, + DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3, + DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7, + DMAC_DMAE, + IRQ4, IRQ5, IRQ6, IRQ7, + HCAN20, HCAN21, + SSI0, SSI1, + HAC0, HAC1, + I2C0, I2C1, + USB, LCDC, + DMABRG0, DMABRG1, DMABRG2, + SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI, + SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI, + SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI, + SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI, + HSPI, + MMCIF0, MMCIF1, MMCIF2, MMCIF3, + MFI, ADC, CMT, + TMU0, TMU1, TMU2_TUNI, TMU2_TICPI, + WDT, + REF_RCMI, REF_ROVI, + + /* interrupt groups */ + DMAC, DMABRG, SCIF0, SCIF1, SCIF2, SIM, MMCIF, TMU2, REF, +}; + +static struct intc_vect vectors[] __initdata = { + INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620), + INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), + INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), + INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0), + INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0), + INTC_VECT(DMAC_DMAE, 0x6c0), + INTC_VECT(IRQ4, 0x800), INTC_VECT(IRQ5, 0x820), + INTC_VECT(IRQ6, 0x840), INTC_VECT(IRQ6, 0x860), + INTC_VECT(HCAN20, 0x900), INTC_VECT(HCAN21, 0x920), + INTC_VECT(SSI0, 0x940), INTC_VECT(SSI1, 0x960), + INTC_VECT(HAC0, 0x980), INTC_VECT(HAC1, 0x9a0), + INTC_VECT(I2C0, 0x9c0), INTC_VECT(I2C1, 0x9e0), + INTC_VECT(USB, 0xa00), INTC_VECT(LCDC, 0xa20), + INTC_VECT(DMABRG0, 0xa80), INTC_VECT(DMABRG1, 0xaa0), + INTC_VECT(DMABRG2, 0xac0), + INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0), + INTC_VECT(SCIF0_BRI, 0x8c0), INTC_VECT(SCIF0_TXI, 0x8e0), + INTC_VECT(SCIF1_ERI, 0xb00), INTC_VECT(SCIF1_RXI, 0xb20), + INTC_VECT(SCIF1_BRI, 0xb40), INTC_VECT(SCIF1_TXI, 0xb60), + INTC_VECT(SCIF2_ERI, 0xb80), INTC_VECT(SCIF2_RXI, 0xba0), + INTC_VECT(SCIF2_BRI, 0xbc0), INTC_VECT(SCIF2_TXI, 0xbe0), + INTC_VECT(SIM_ERI, 0xc00), INTC_VECT(SIM_RXI, 0xc20), + INTC_VECT(SIM_TXI, 0xc40), INTC_VECT(SIM_TEI, 0xc60), + INTC_VECT(HSPI, 0xc80), + INTC_VECT(MMCIF0, 0xd00), INTC_VECT(MMCIF1, 0xd20), + INTC_VECT(MMCIF2, 0xd40), INTC_VECT(MMCIF3, 0xd60), + INTC_VECT(MFI, 0xe80), /* 0xf80 according to data sheet */ + INTC_VECT(ADC, 0xf80), INTC_VECT(CMT, 0xfa0), + INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), + INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460), + INTC_VECT(WDT, 0x560), + INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0), +}; + +static struct intc_group groups[] __initdata = { + INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, + DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5, + DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE), + INTC_GROUP(DMABRG, DMABRG0, DMABRG1, DMABRG2), + INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI), + INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI), + INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI), + INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI), + INTC_GROUP(MMCIF, MMCIF0, MMCIF1, MMCIF2, MMCIF3), + INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI), + INTC_GROUP(REF, REF_RCMI, REF_ROVI), +}; + +static struct intc_prio priorities[] __initdata = { + INTC_PRIO(SCIF0, 3), + INTC_PRIO(SCIF1, 3), + INTC_PRIO(SCIF2, 3), + INTC_PRIO(SIM, 3), + INTC_PRIO(DMAC, 7), + INTC_PRIO(DMABRG, 13), +}; + +static struct intc_mask_reg mask_registers[] __initdata = { + { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */ + { IRQ4, IRQ5, IRQ6, IRQ7, 0, 0, HCAN20, HCAN21, + SSI0, SSI1, HAC0, HAC1, I2C0, I2C1, USB, LCDC, + 0, DMABRG0, DMABRG1, DMABRG2, + SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI, + SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI, + SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI, } }, + { 0xfe080044, 0xfe080064, 32, /* INTMSK04 / INTMSKCLR04 */ + { 0, 0, 0, 0, 0, 0, 0, 0, + SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI, + HSPI, MMCIF0, MMCIF1, MMCIF2, + MMCIF3, 0, 0, 0, 0, 0, 0, 0, + 0, MFI, 0, 0, 0, 0, ADC, CMT, } }, +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2 } }, + { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, 0, 0 } }, + { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, 0, HUDI } }, + { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } }, + { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { IRQ4, IRQ5, IRQ6, IRQ7 } }, + { 0xfe080004, 0, 32, 4, /* INTPRI04 */ { HCAN20, HCAN21, SSI0, SSI1, + HAC0, HAC1, I2C0, I2C1 } }, + { 0xfe080008, 0, 32, 4, /* INTPRI08 */ { USB, LCDC, DMABRG, SCIF0, + SCIF1, SCIF2, SIM, HSPI } }, + { 0xfe08000c, 0, 32, 4, /* INTPRI0C */ { 0, 0, MMCIF, 0, + MFI, 0, ADC, CMT } }, +}; + +static DECLARE_INTC_DESC(intc_desc, "sh7760", vectors, groups, + priorities, mask_registers, prio_registers, NULL); + +static struct intc_vect vectors_irq[] __initdata = { + INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0), + INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360), +}; + +static DECLARE_INTC_DESC(intc_desc_irq, "sh7760-irq", vectors_irq, groups, + priorities, mask_registers, prio_registers, NULL); + static struct plat_sci_port sci_platform_data[] = { { .mapbase = 0xfe600000, @@ -29,6 +159,11 @@ static struct plat_sci_port sci_platform_data[] = { .type = PORT_SCIF, .irqs = { 76, 77, 79, 78 }, }, { + .mapbase = 0xfe480000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCI, + .irqs = { 80, 81, 82, 0 }, + }, { .flags = 0, } }; @@ -52,114 +187,18 @@ static int __init sh7760_devices_setup(void) } __initcall(sh7760_devices_setup); -static struct intc2_data intc2_irq_table[] = { - {48, 0, 28, 0, 31, 3}, /* IRQ 4 */ - {49, 0, 24, 0, 30, 3}, /* IRQ 3 */ - {50, 0, 20, 0, 29, 3}, /* IRQ 2 */ - {51, 0, 16, 0, 28, 3}, /* IRQ 1 */ - {56, 4, 28, 0, 25, 3}, /* HCAN2_CHAN0 */ - {57, 4, 24, 0, 24, 3}, /* HCAN2_CHAN1 */ - {58, 4, 20, 0, 23, 3}, /* I2S_CHAN0 */ - {59, 4, 16, 0, 22, 3}, /* I2S_CHAN1 */ - {60, 4, 12, 0, 21, 3}, /* AC97_CHAN0 */ - {61, 4, 8, 0, 20, 3}, /* AC97_CHAN1 */ - {62, 4, 4, 0, 19, 3}, /* I2C_CHAN0 */ - {63, 4, 0, 0, 18, 3}, /* I2C_CHAN1 */ - {52, 8, 16, 0, 11, 3}, /* SCIF0_ERI_IRQ */ - {53, 8, 16, 0, 10, 3}, /* SCIF0_RXI_IRQ */ - {54, 8, 16, 0, 9, 3}, /* SCIF0_BRI_IRQ */ - {55, 8, 16, 0, 8, 3}, /* SCIF0_TXI_IRQ */ - {64, 8, 28, 0, 17, 3}, /* USBHI_IRQ */ - {65, 8, 24, 0, 16, 3}, /* LCDC */ - {68, 8, 20, 0, 14, 13}, /* DMABRGI0_IRQ */ - {69, 8, 20, 0, 13, 13}, /* DMABRGI1_IRQ */ - {70, 8, 20, 0, 12, 13}, /* DMABRGI2_IRQ */ - {72, 8, 12, 0, 7, 3}, /* SCIF1_ERI_IRQ */ - {73, 8, 12, 0, 6, 3}, /* SCIF1_RXI_IRQ */ - {74, 8, 12, 0, 5, 3}, /* SCIF1_BRI_IRQ */ - {75, 8, 12, 0, 4, 3}, /* SCIF1_TXI_IRQ */ - {76, 8, 8, 0, 3, 3}, /* SCIF2_ERI_IRQ */ - {77, 8, 8, 0, 2, 3}, /* SCIF2_RXI_IRQ */ - {78, 8, 8, 0, 1, 3}, /* SCIF2_BRI_IRQ */ - {79, 8, 8, 0, 0, 3}, /* SCIF2_TXI_IRQ */ - {80, 8, 4, 4, 23, 3}, /* SIM_ERI */ - {81, 8, 4, 4, 22, 3}, /* SIM_RXI */ - {82, 8, 4, 4, 21, 3}, /* SIM_TXI */ - {83, 8, 4, 4, 20, 3}, /* SIM_TEI */ - {84, 8, 0, 4, 19, 3}, /* HSPII */ - {88, 12, 20, 4, 18, 3}, /* MMCI0 */ - {89, 12, 20, 4, 17, 3}, /* MMCI1 */ - {90, 12, 20, 4, 16, 3}, /* MMCI2 */ - {91, 12, 20, 4, 15, 3}, /* MMCI3 */ - {92, 12, 12, 4, 6, 3}, /* MFI */ - {108,12, 4, 4, 1, 3}, /* ADC */ - {109,12, 0, 4, 0, 3}, /* CMTI */ -}; - -static struct intc2_desc intc2_irq_desc __read_mostly = { - .prio_base = 0xfe080000, - .msk_base = 0xfe080040, - .mskclr_base = 0xfe080060, - - .intc2_data = intc2_irq_table, - .nr_irqs = ARRAY_SIZE(intc2_irq_table), - - .chip = { - .name = "INTC2-sh7760", - }, -}; - -static struct ipr_data ipr_irq_table[] = { - /* IRQ, IPR-idx, shift, priority */ - { 16, 0, 12, 2 }, /* TMU0 TUNI*/ - { 17, 0, 8, 2 }, /* TMU1 TUNI */ - { 18, 0, 4, 2 }, /* TMU2 TUNI */ - { 19, 0, 4, 2 }, /* TMU2 TIPCI */ - { 27, 1, 12, 2 }, /* WDT ITI */ - { 28, 1, 8, 2 }, /* REF RCMI */ - { 29, 1, 8, 2 }, /* REF ROVI */ - { 32, 2, 0, 7 }, /* HUDI */ - { 33, 2, 12, 7 }, /* GPIOI */ - { 34, 2, 8, 7 }, /* DMAC DMTE0 */ - { 35, 2, 8, 7 }, /* DMAC DMTE1 */ - { 36, 2, 8, 7 }, /* DMAC DMTE2 */ - { 37, 2, 8, 7 }, /* DMAC DMTE3 */ - { 38, 2, 8, 7 }, /* DMAC DMAE */ - { 44, 2, 8, 7 }, /* DMAC DMTE4 */ - { 45, 2, 8, 7 }, /* DMAC DMTE5 */ - { 46, 2, 8, 7 }, /* DMAC DMTE6 */ - { 47, 2, 8, 7 }, /* DMAC DMTE7 */ -/* these here are only valid if INTC_ICR bit 7 is set to 1! - * XXX: maybe CONFIG_SH_IRLMODE symbol? SH7751 could use it too */ -#if 0 - { 2, 3, 12, 3 }, /* IRL0 */ - { 5, 3, 8, 3 }, /* IRL1 */ - { 8, 3, 4, 3 }, /* IRL2 */ - { 11, 3, 0, 3 }, /* IRL3 */ -#endif -}; - -static unsigned long ipr_offsets[] = { - 0xffd00004UL, /* 0: IPRA */ - 0xffd00008UL, /* 1: IPRB */ - 0xffd0000cUL, /* 2: IPRC */ - 0xffd00010UL, /* 3: IPRD */ -}; - -static struct ipr_desc ipr_irq_desc = { - .ipr_offsets = ipr_offsets, - .nr_offsets = ARRAY_SIZE(ipr_offsets), - - .ipr_data = ipr_irq_table, - .nr_irqs = ARRAY_SIZE(ipr_irq_table), - - .chip = { - .name = "IPR-sh7760", - }, -}; +void __init plat_irq_setup_pins(int mode) +{ + switch (mode) { + case IRQ_MODE_IRQ: + register_intc_controller(&intc_desc_irq); + break; + default: + BUG(); + } +} void __init plat_irq_setup(void) { - register_intc2_controller(&intc2_irq_desc); - register_ipr_controller(&ipr_irq_desc); + register_intc_controller(&intc_desc); } diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index c21512c6044..b22a78c807e 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -58,11 +58,11 @@ do { \ */ void sq_flush_range(unsigned long start, unsigned int len) { - volatile unsigned long *sq = (unsigned long *)start; + unsigned long *sq = (unsigned long *)start; /* Flush the queues */ for (len >>= 5; len--; sq += 8) - prefetchw((void *)sq); + prefetchw(sq); /* Wait for completion */ store_queue_barrier(); diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile index e6a1fb5f848..24539873943 100644 --- a/arch/sh/kernel/cpu/sh4a/Makefile +++ b/arch/sh/kernel/cpu/sh4a/Makefile @@ -10,6 +10,9 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o +# SMP setup +smp-$(CONFIG_CPU_SUBTYPE_SHX3) := smp-shx3.o + # Primary on-chip clocks (common) clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o @@ -18,4 +21,5 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o -obj-y += $(clock-y) +obj-y += $(clock-y) +obj-$(CONFIG_SMP) += $(smp-y) diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c index 91d61cf91ba..c0a3f079dfd 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c @@ -41,3 +41,7 @@ static int __init sh7343_devices_setup(void) ARRAY_SIZE(sh7343_devices)); } __initcall(sh7343_devices_setup); + +void __init plat_irq_setup(void) +{ +} diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c index 25b913e07e2..55f66104431 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c @@ -84,7 +84,7 @@ enum { SIM, RTC, DMAC0123, VIOVOU, USB, DMAC45, FLCTL, I2C, SDHI, }; -static struct intc_vect vectors[] = { +static struct intc_vect vectors[] __initdata = { INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620), INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660), INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0), @@ -117,7 +117,7 @@ static struct intc_vect vectors[] = { INTC_VECT(JPU, 0x560), INTC_VECT(LCDC, 0x580), }; -static struct intc_group groups[] = { +static struct intc_group groups[] __initdata = { INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI), INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), INTC_GROUP(DMAC0123, DMAC0, DMAC1, DMAC2, DMAC3), @@ -130,7 +130,7 @@ static struct intc_group groups[] = { INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2, SDHI3), }; -static struct intc_prio priorities[] = { +static struct intc_prio priorities[] __initdata = { INTC_PRIO(SCIF0, 3), INTC_PRIO(SCIF1, 3), INTC_PRIO(SCIF2, 3), @@ -138,7 +138,7 @@ static struct intc_prio priorities[] = { INTC_PRIO(TMU1, 2), }; -static struct intc_mask_reg mask_registers[] = { +static struct intc_mask_reg mask_registers[] __initdata = { { 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */ { } }, { 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */ @@ -168,24 +168,24 @@ static struct intc_mask_reg mask_registers[] = { { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, }; -static struct intc_prio_reg prio_registers[] = { - { 0xa4080000, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, IRDA } }, - { 0xa4080004, 16, 4, /* IPRB */ { JPU, LCDC, SIM } }, - { 0xa4080008, 16, 4, /* IPRC */ { } }, - { 0xa408000c, 16, 4, /* IPRD */ { } }, - { 0xa4080010, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, 0, VPU } }, - { 0xa4080014, 16, 4, /* IPRF */ { KEYSC, DMAC45, USB, CMT } }, - { 0xa4080018, 16, 4, /* IPRG */ { SCIF0, SCIF1, SCIF2 } }, - { 0xa408001c, 16, 4, /* IPRH */ { SIOF0, SIOF1, FLCTL, I2C } }, - { 0xa4080020, 16, 4, /* IPRI */ { SIO, 0, TSIF, RTC } }, - { 0xa4080024, 16, 4, /* IPRJ */ { 0, 0, SIU } }, - { 0xa4080028, 16, 4, /* IPRK */ { 0, 0, 0, SDHI } }, - { 0xa408002c, 16, 4, /* IPRL */ { TWODG, 0, TPU } }, - { 0xa4140010, 32, 4, /* INTPRI00 */ +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xa4080000, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, IRDA } }, + { 0xa4080004, 0, 16, 4, /* IPRB */ { JPU, LCDC, SIM } }, + { 0xa4080008, 0, 16, 4, /* IPRC */ { } }, + { 0xa408000c, 0, 16, 4, /* IPRD */ { } }, + { 0xa4080010, 0, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, 0, VPU } }, + { 0xa4080014, 0, 16, 4, /* IPRF */ { KEYSC, DMAC45, USB, CMT } }, + { 0xa4080018, 0, 16, 4, /* IPRG */ { SCIF0, SCIF1, SCIF2 } }, + { 0xa408001c, 0, 16, 4, /* IPRH */ { SIOF0, SIOF1, FLCTL, I2C } }, + { 0xa4080020, 0, 16, 4, /* IPRI */ { SIO, 0, TSIF, RTC } }, + { 0xa4080024, 0, 16, 4, /* IPRJ */ { 0, 0, SIU } }, + { 0xa4080028, 0, 16, 4, /* IPRK */ { 0, 0, 0, SDHI } }, + { 0xa408002c, 0, 16, 4, /* IPRL */ { TWODG, 0, TPU } }, + { 0xa4140010, 0, 32, 4, /* INTPRI00 */ { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, }; -static struct intc_sense_reg sense_registers[] = { +static struct intc_sense_reg sense_registers[] __initdata = { { 0xa414001c, 16, 2, /* ICR1 */ { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, }; diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c index 6a04cc5f5ac..32f4f59a837 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c @@ -51,3 +51,7 @@ static int __init sh7770_devices_setup(void) ARRAY_SIZE(sh7770_devices)); } __initcall(sh7770_devices_setup); + +void __init plat_irq_setup(void) +{ +} diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c index a4127ec1520..e8fd33ff060 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c @@ -10,6 +10,7 @@ #include <linux/platform_device.h> #include <linux/init.h> #include <linux/serial.h> +#include <linux/io.h> #include <asm/sci.h> static struct resource rtc_resources[] = { @@ -114,7 +115,7 @@ enum { PCIC5, SCIF1, MMCIF, TMU345, FLCTL, GPIO, }; -static struct intc_vect vectors[] = { +static struct intc_vect vectors[] __initdata = { INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0), INTC_VECT(RTC_CUI, 0x4c0), INTC_VECT(WDT, 0x560), @@ -150,7 +151,7 @@ static struct intc_vect vectors[] = { INTC_VECT(GPIOI2, 0xfc0), INTC_VECT(GPIOI3, 0xfe0), }; -static struct intc_group groups[] = { +static struct intc_group groups[] __initdata = { INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI), INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, @@ -167,12 +168,12 @@ static struct intc_group groups[] = { INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3), }; -static struct intc_prio priorities[] = { +static struct intc_prio priorities[] __initdata = { INTC_PRIO(SCIF0, 3), INTC_PRIO(SCIF1, 3), }; -static struct intc_mask_reg mask_registers[] = { +static struct intc_mask_reg mask_registers[] __initdata = { { 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */ { 0, 0, 0, 0, 0, 0, GPIO, FLCTL, SSI, MMCIF, HSPI, SIOF, PCIC5, PCIINTD, PCIINTC, PCIINTB, @@ -180,16 +181,18 @@ static struct intc_mask_reg mask_registers[] = { HUDI, 0, WDT, SCIF1, SCIF0, RTC, TMU345, TMU012 } }, }; -static struct intc_prio_reg prio_registers[] = { - { 0xffd40000, 32, 8, /* INT2PRI0 */ { TMU0, TMU1, TMU2, TMU2_TICPI } }, - { 0xffd40004, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, RTC } }, - { 0xffd40008, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1, WDT } }, - { 0xffd4000c, 32, 8, /* INT2PRI3 */ { HUDI, DMAC0, DMAC1 } }, - { 0xffd40010, 32, 8, /* INT2PRI4 */ { CMT, HAC, PCISERR, PCIINTA, } }, - { 0xffd40014, 32, 8, /* INT2PRI5 */ { PCIINTB, PCIINTC, - PCIINTD, PCIC5 } }, - { 0xffd40018, 32, 8, /* INT2PRI6 */ { SIOF, HSPI, MMCIF, SSI } }, - { 0xffd4001c, 32, 8, /* INT2PRI7 */ { FLCTL, GPIO } }, +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xffd40000, 0, 32, 8, /* INT2PRI0 */ { TMU0, TMU1, + TMU2, TMU2_TICPI } }, + { 0xffd40004, 0, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, RTC } }, + { 0xffd40008, 0, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1, WDT } }, + { 0xffd4000c, 0, 32, 8, /* INT2PRI3 */ { HUDI, DMAC0, DMAC1 } }, + { 0xffd40010, 0, 32, 8, /* INT2PRI4 */ { CMT, HAC, + PCISERR, PCIINTA, } }, + { 0xffd40014, 0, 32, 8, /* INT2PRI5 */ { PCIINTB, PCIINTC, + PCIINTD, PCIC5 } }, + { 0xffd40018, 0, 32, 8, /* INT2PRI6 */ { SIOF, HSPI, MMCIF, SSI } }, + { 0xffd4001c, 0, 32, 8, /* INT2PRI7 */ { FLCTL, GPIO } }, }; static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups, priorities, @@ -197,24 +200,24 @@ static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups, priorities, /* Support for external interrupt pins in IRQ mode */ -static struct intc_vect irq_vectors[] = { +static struct intc_vect irq_vectors[] __initdata = { INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280), INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300), INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380), INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200), }; -static struct intc_mask_reg irq_mask_registers[] = { +static struct intc_mask_reg irq_mask_registers[] __initdata = { { 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */ { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, }; -static struct intc_prio_reg irq_prio_registers[] = { - { 0xffd00010, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3, - IRQ4, IRQ5, IRQ6, IRQ7 } }, +static struct intc_prio_reg irq_prio_registers[] __initdata = { + { 0xffd00010, 0, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3, + IRQ4, IRQ5, IRQ6, IRQ7 } }, }; -static struct intc_sense_reg irq_sense_registers[] = { +static struct intc_sense_reg irq_sense_registers[] __initdata = { { 0xffd0001c, 32, 2, /* ICR1 */ { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, }; @@ -225,7 +228,7 @@ static DECLARE_INTC_DESC(intc_irq_desc, "sh7780-irq", irq_vectors, /* External interrupt pins in IRL mode */ -static struct intc_vect irl_vectors[] = { +static struct intc_vect irl_vectors[] __initdata = { INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220), INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260), INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0), @@ -236,16 +239,16 @@ static struct intc_vect irl_vectors[] = { INTC_VECT(IRL_HHHL, 0x3c0), }; -static struct intc_mask_reg irl3210_mask_registers[] = { - { 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */ +static struct intc_mask_reg irl3210_mask_registers[] __initdata = { + { 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */ { IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH, IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH, IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH, IRL_HHLL, IRL_HHLH, IRL_HHHL, } }, }; -static struct intc_mask_reg irl7654_mask_registers[] = { - { 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */ +static struct intc_mask_reg irl7654_mask_registers[] __initdata = { + { 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH, IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH, @@ -259,8 +262,28 @@ static DECLARE_INTC_DESC(intc_irl7654_desc, "sh7780-irl7654", irl_vectors, static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7780-irl3210", irl_vectors, NULL, NULL, irl3210_mask_registers, NULL, NULL); +#define INTC_ICR0 0xffd00000 +#define INTC_INTMSK0 0xffd00044 +#define INTC_INTMSK1 0xffd00048 +#define INTC_INTMSK2 0xffd40080 +#define INTC_INTMSKCLR1 0xffd00068 +#define INTC_INTMSKCLR2 0xffd40084 + void __init plat_irq_setup(void) { + /* disable IRQ7-0 */ + ctrl_outl(0xff000000, INTC_INTMSK0); + + /* disable IRL3-0 + IRL7-4 */ + ctrl_outl(0xc0000000, INTC_INTMSK1); + ctrl_outl(0xfffefffe, INTC_INTMSK2); + + /* select IRL mode for IRL3-0 + IRL7-4 */ + ctrl_outl(ctrl_inl(INTC_ICR0) & ~0x00c00000, INTC_ICR0); + + /* disable holding function, ie enable "SH-4 Mode" */ + ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00200000, INTC_ICR0); + register_intc_controller(&intc_desc); } @@ -268,12 +291,28 @@ void __init plat_irq_setup_pins(int mode) { switch (mode) { case IRQ_MODE_IRQ: + /* select IRQ mode for IRL3-0 + IRL7-4 */ + ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00c00000, INTC_ICR0); register_intc_controller(&intc_irq_desc); break; case IRQ_MODE_IRL7654: - register_intc_controller(&intc_irl7654_desc); + /* enable IRL7-4 but don't provide any masking */ + ctrl_outl(0x40000000, INTC_INTMSKCLR1); + ctrl_outl(0x0000fffe, INTC_INTMSKCLR2); break; case IRQ_MODE_IRL3210: + /* enable IRL0-3 but don't provide any masking */ + ctrl_outl(0x80000000, INTC_INTMSKCLR1); + ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); + break; + case IRQ_MODE_IRL7654_MASK: + /* enable IRL7-4 and mask using cpu intc controller */ + ctrl_outl(0x40000000, INTC_INTMSKCLR1); + register_intc_controller(&intc_irl7654_desc); + break; + case IRQ_MODE_IRL3210_MASK: + /* enable IRL0-3 and mask using cpu intc controller */ + ctrl_outl(0x80000000, INTC_INTMSKCLR1); register_intc_controller(&intc_irl3210_desc); break; default: diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c index cf047562e43..39b215d6cee 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c @@ -10,6 +10,9 @@ #include <linux/platform_device.h> #include <linux/init.h> #include <linux/serial.h> +#include <linux/io.h> +#include <linux/mm.h> +#include <asm/mmzone.h> #include <asm/sci.h> static struct plat_sci_port sci_platform_data[] = { @@ -72,46 +75,281 @@ static int __init sh7785_devices_setup(void) } __initcall(sh7785_devices_setup); -static struct intc2_data intc2_irq_table[] = { - { 28, 0, 24, 0, 0, 2 }, /* TMU0 */ - - { 40, 8, 24, 0, 2, 3 }, /* SCIF0 ERI */ - { 41, 8, 24, 0, 2, 3 }, /* SCIF0 RXI */ - { 42, 8, 24, 0, 2, 3 }, /* SCIF0 BRI */ - { 43, 8, 24, 0, 2, 3 }, /* SCIF0 TXI */ - - { 44, 8, 16, 0, 3, 3 }, /* SCIF1 ERI */ - { 45, 8, 16, 0, 3, 3 }, /* SCIF1 RXI */ - { 46, 8, 16, 0, 3, 3 }, /* SCIF1 BRI */ - { 47, 8, 16, 0, 3, 3 }, /* SCIF1 TXI */ - - { 64, 0x14, 8, 0, 14, 2 }, /* PCIC0 */ - { 65, 0x14, 0, 0, 15, 2 }, /* PCIC1 */ - { 66, 0x18, 24, 0, 16, 2 }, /* PCIC2 */ - { 67, 0x18, 16, 0, 17, 2 }, /* PCIC3 */ - { 68, 0x18, 8, 0, 18, 2 }, /* PCIC4 */ - - { 60, 8, 8, 0, 4, 3 }, /* SCIF2 ERI, RXI, BRI, TXI */ - { 60, 8, 0, 0, 5, 3 }, /* SCIF3 ERI, RXI, BRI, TXI */ - { 60, 12, 24, 0, 6, 3 }, /* SCIF4 ERI, RXI, BRI, TXI */ - { 60, 12, 16, 0, 7, 3 }, /* SCIF5 ERI, RXI, BRI, TXI */ +enum { + UNUSED = 0, + + /* interrupt sources */ + + IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH, + IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH, + IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH, + IRL0_HHLL, IRL0_HHLH, IRL0_HHHL, + + IRL4_LLLL, IRL4_LLLH, IRL4_LLHL, IRL4_LLHH, + IRL4_LHLL, IRL4_LHLH, IRL4_LHHL, IRL4_LHHH, + IRL4_HLLL, IRL4_HLLH, IRL4_HLHL, IRL4_HLHH, + IRL4_HHLL, IRL4_HHLH, IRL4_HHHL, + + IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7, + WDT, + TMU0, TMU1, TMU2, TMU2_TICPI, + HUDI, + DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3, + DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE, + SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI, + SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI, + DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8, DMAC1_DMINT9, + DMAC1_DMINT10, DMAC1_DMINT11, DMAC1_DMAE, + HSPI, + SCIF2, SCIF3, SCIF4, SCIF5, + PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD, + PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0, + SIOF, + MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY, + DU, + GDTA_GACLI, GDTA_GAMCI, GDTA_GAERI, + TMU3, TMU4, TMU5, + SSI0, SSI1, + HAC0, HAC1, + FLCTL_FLSTE, FLCTL_FLEND, FLCTL_FLTRQ0, FLCTL_FLTRQ1, + GPIOI0, GPIOI1, GPIOI2, GPIOI3, + + /* interrupt groups */ + + TMU012, DMAC0, SCIF0, SCIF1, DMAC1, + PCIC5, MMCIF, GDTA, TMU345, FLCTL, GPIO }; -static struct intc2_desc intc2_irq_desc __read_mostly = { - .prio_base = 0xffd40000, - .msk_base = 0xffd40038, - .mskclr_base = 0xffd4003c, +static struct intc_vect vectors[] __initdata = { + INTC_VECT(WDT, 0x560), + INTC_VECT(TMU0, 0x580), INTC_VECT(TMU1, 0x5a0), + INTC_VECT(TMU2, 0x5c0), INTC_VECT(TMU2_TICPI, 0x5e0), + INTC_VECT(HUDI, 0x600), + INTC_VECT(DMAC0_DMINT0, 0x620), INTC_VECT(DMAC0_DMINT1, 0x640), + INTC_VECT(DMAC0_DMINT2, 0x660), INTC_VECT(DMAC0_DMINT3, 0x680), + INTC_VECT(DMAC0_DMINT4, 0x6a0), INTC_VECT(DMAC0_DMINT5, 0x6c0), + INTC_VECT(DMAC0_DMAE, 0x6e0), + INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720), + INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760), + INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0), + INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0), + INTC_VECT(DMAC1_DMINT6, 0x880), INTC_VECT(DMAC1_DMINT7, 0x8a0), + INTC_VECT(DMAC1_DMINT8, 0x8c0), INTC_VECT(DMAC1_DMINT9, 0x8e0), + INTC_VECT(DMAC1_DMINT10, 0x900), INTC_VECT(DMAC1_DMINT11, 0x920), + INTC_VECT(DMAC1_DMAE, 0x940), + INTC_VECT(HSPI, 0x960), + INTC_VECT(SCIF2, 0x980), INTC_VECT(SCIF3, 0x9a0), + INTC_VECT(SCIF4, 0x9c0), INTC_VECT(SCIF5, 0x9e0), + INTC_VECT(PCISERR, 0xa00), INTC_VECT(PCIINTA, 0xa20), + INTC_VECT(PCIINTB, 0xa40), INTC_VECT(PCIINTC, 0xa60), + INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIERR, 0xaa0), + INTC_VECT(PCIPWD3, 0xac0), INTC_VECT(PCIPWD2, 0xae0), + INTC_VECT(PCIPWD1, 0xb00), INTC_VECT(PCIPWD0, 0xb20), + INTC_VECT(SIOF, 0xc00), + INTC_VECT(MMCIF_FSTAT, 0xd00), INTC_VECT(MMCIF_TRAN, 0xd20), + INTC_VECT(MMCIF_ERR, 0xd40), INTC_VECT(MMCIF_FRDY, 0xd60), + INTC_VECT(DU, 0xd80), + INTC_VECT(GDTA_GACLI, 0xda0), INTC_VECT(GDTA_GAMCI, 0xdc0), + INTC_VECT(GDTA_GAERI, 0xde0), + INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20), + INTC_VECT(TMU5, 0xe40), + INTC_VECT(SSI0, 0xe80), INTC_VECT(SSI1, 0xea0), + INTC_VECT(HAC0, 0xec0), INTC_VECT(HAC1, 0xee0), + INTC_VECT(FLCTL_FLSTE, 0xf00), INTC_VECT(FLCTL_FLEND, 0xf20), + INTC_VECT(FLCTL_FLTRQ0, 0xf40), INTC_VECT(FLCTL_FLTRQ1, 0xf60), + INTC_VECT(GPIOI0, 0xf80), INTC_VECT(GPIOI1, 0xfa0), + INTC_VECT(GPIOI2, 0xfc0), INTC_VECT(GPIOI3, 0xfe0), +}; - .intc2_data = intc2_irq_table, - .nr_irqs = ARRAY_SIZE(intc2_irq_table), +static struct intc_group groups[] __initdata = { + INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI), + INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, + DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE), + INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI), + INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI), + INTC_GROUP(DMAC1, DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8, + DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11, DMAC1_DMAE), + INTC_GROUP(PCIC5, PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0), + INTC_GROUP(MMCIF, MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY), + INTC_GROUP(GDTA, GDTA_GACLI, GDTA_GAMCI, GDTA_GAERI), + INTC_GROUP(TMU345, TMU3, TMU4, TMU5), + INTC_GROUP(FLCTL, FLCTL_FLSTE, FLCTL_FLEND, + FLCTL_FLTRQ0, FLCTL_FLTRQ1), + INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3), +}; - .chip = { - .name = "INTC2-sh7785", - }, +static struct intc_prio priorities[] __initdata = { + INTC_PRIO(SCIF0, 3), + INTC_PRIO(SCIF1, 3), + INTC_PRIO(SCIF2, 3), + INTC_PRIO(SCIF3, 3), + INTC_PRIO(SCIF4, 3), + INTC_PRIO(SCIF5, 3), +}; + +static struct intc_mask_reg mask_registers[] __initdata = { + { 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */ + { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, + + { 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */ + { IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH, + IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH, + IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH, + IRL0_HHLL, IRL0_HHLH, IRL0_HHHL, 0, + IRL4_LLLL, IRL4_LLLH, IRL4_LLHL, IRL4_LLHH, + IRL4_LHLL, IRL4_LHLH, IRL4_LHHL, IRL4_LHHH, + IRL4_HLLL, IRL4_HLLH, IRL4_HLHL, IRL4_HLHH, + IRL4_HHLL, IRL4_HHLH, IRL4_HHHL, 0, } }, + + { 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */ + { 0, 0, 0, GDTA, DU, SSI0, SSI1, GPIO, + FLCTL, MMCIF, HSPI, SIOF, PCIC5, PCIINTD, PCIINTC, PCIINTB, + PCIINTA, PCISERR, HAC1, HAC0, DMAC1, DMAC0, HUDI, WDT, + SCIF5, SCIF4, SCIF3, SCIF2, SCIF1, SCIF0, TMU345, TMU012 } }, +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xffd00010, 0, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3, + IRQ4, IRQ5, IRQ6, IRQ7 } }, + { 0xffd40000, 0, 32, 8, /* INT2PRI0 */ { TMU0, TMU1, + TMU2, TMU2_TICPI } }, + { 0xffd40004, 0, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, } }, + { 0xffd40008, 0, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1, + SCIF2, SCIF3 } }, + { 0xffd4000c, 0, 32, 8, /* INT2PRI3 */ { SCIF4, SCIF5, WDT, } }, + { 0xffd40010, 0, 32, 8, /* INT2PRI4 */ { HUDI, DMAC0, DMAC1, } }, + { 0xffd40014, 0, 32, 8, /* INT2PRI5 */ { HAC0, HAC1, + PCISERR, PCIINTA } }, + { 0xffd40018, 0, 32, 8, /* INT2PRI6 */ { PCIINTB, PCIINTC, + PCIINTD, PCIC5 } }, + { 0xffd4001c, 0, 32, 8, /* INT2PRI7 */ { SIOF, HSPI, MMCIF, } }, + { 0xffd40020, 0, 32, 8, /* INT2PRI8 */ { FLCTL, GPIO, SSI0, SSI1, } }, + { 0xffd40024, 0, 32, 8, /* INT2PRI9 */ { DU, GDTA, } }, }; +static DECLARE_INTC_DESC(intc_desc, "sh7785", vectors, groups, priorities, + mask_registers, prio_registers, NULL); + +/* Support for external interrupt pins in IRQ mode */ + +static struct intc_vect vectors_irq0123[] __initdata = { + INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280), + INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300), +}; + +static struct intc_vect vectors_irq4567[] __initdata = { + INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380), + INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200), +}; + +static struct intc_sense_reg sense_registers[] __initdata = { + { 0xffd0001c, 32, 2, /* ICR1 */ { IRQ0, IRQ1, IRQ2, IRQ3, + IRQ4, IRQ5, IRQ6, IRQ7 } }, +}; + +static DECLARE_INTC_DESC(intc_desc_irq0123, "sh7785-irq0123", vectors_irq0123, + NULL, NULL, mask_registers, prio_registers, + sense_registers); + +static DECLARE_INTC_DESC(intc_desc_irq4567, "sh7785-irq4567", vectors_irq4567, + NULL, NULL, mask_registers, prio_registers, + sense_registers); + +/* External interrupt pins in IRL mode */ + +static struct intc_vect vectors_irl0123[] __initdata = { + INTC_VECT(IRL0_LLLL, 0x200), INTC_VECT(IRL0_LLLH, 0x220), + INTC_VECT(IRL0_LLHL, 0x240), INTC_VECT(IRL0_LLHH, 0x260), + INTC_VECT(IRL0_LHLL, 0x280), INTC_VECT(IRL0_LHLH, 0x2a0), + INTC_VECT(IRL0_LHHL, 0x2c0), INTC_VECT(IRL0_LHHH, 0x2e0), + INTC_VECT(IRL0_HLLL, 0x300), INTC_VECT(IRL0_HLLH, 0x320), + INTC_VECT(IRL0_HLHL, 0x340), INTC_VECT(IRL0_HLHH, 0x360), + INTC_VECT(IRL0_HHLL, 0x380), INTC_VECT(IRL0_HHLH, 0x3a0), + INTC_VECT(IRL0_HHHL, 0x3c0), +}; + +static struct intc_vect vectors_irl4567[] __initdata = { + INTC_VECT(IRL4_LLLL, 0xb00), INTC_VECT(IRL4_LLLH, 0xb20), + INTC_VECT(IRL4_LLHL, 0xb40), INTC_VECT(IRL4_LLHH, 0xb60), + INTC_VECT(IRL4_LHLL, 0xb80), INTC_VECT(IRL4_LHLH, 0xba0), + INTC_VECT(IRL4_LHHL, 0xbc0), INTC_VECT(IRL4_LHHH, 0xbe0), + INTC_VECT(IRL4_HLLL, 0xc00), INTC_VECT(IRL4_HLLH, 0xc20), + INTC_VECT(IRL4_HLHL, 0xc40), INTC_VECT(IRL4_HLHH, 0xc60), + INTC_VECT(IRL4_HHLL, 0xc80), INTC_VECT(IRL4_HHLH, 0xca0), + INTC_VECT(IRL4_HHHL, 0xcc0), +}; + +static DECLARE_INTC_DESC(intc_desc_irl0123, "sh7785-irl0123", vectors_irl0123, + NULL, NULL, mask_registers, NULL, NULL); + +static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7785-irl4567", vectors_irl4567, + NULL, NULL, mask_registers, NULL, NULL); + +#define INTC_ICR0 0xffd00000 +#define INTC_INTMSK0 0xffd00044 +#define INTC_INTMSK1 0xffd00048 +#define INTC_INTMSK2 0xffd40080 +#define INTC_INTMSKCLR1 0xffd00068 +#define INTC_INTMSKCLR2 0xffd40084 + void __init plat_irq_setup(void) { - register_intc2_controller(&intc2_irq_desc); + /* disable IRQ3-0 + IRQ7-4 */ + ctrl_outl(0xff000000, INTC_INTMSK0); + + /* disable IRL3-0 + IRL7-4 */ + ctrl_outl(0xc0000000, INTC_INTMSK1); + ctrl_outl(0xfffefffe, INTC_INTMSK2); + + /* select IRL mode for IRL3-0 + IRL7-4 */ + ctrl_outl(ctrl_inl(INTC_ICR0) & ~0x00c00000, INTC_ICR0); + + /* disable holding function, ie enable "SH-4 Mode" */ + ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00200000, INTC_ICR0); + + register_intc_controller(&intc_desc); +} + +void __init plat_irq_setup_pins(int mode) +{ + switch (mode) { + case IRQ_MODE_IRQ7654: + /* select IRQ mode for IRL7-4 */ + ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00400000, INTC_ICR0); + register_intc_controller(&intc_desc_irq4567); + break; + case IRQ_MODE_IRQ3210: + /* select IRQ mode for IRL3-0 */ + ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00800000, INTC_ICR0); + register_intc_controller(&intc_desc_irq0123); + break; + case IRQ_MODE_IRL7654: + /* enable IRL7-4 but don't provide any masking */ + ctrl_outl(0x40000000, INTC_INTMSKCLR1); + ctrl_outl(0x0000fffe, INTC_INTMSKCLR2); + break; + case IRQ_MODE_IRL3210: + /* enable IRL0-3 but don't provide any masking */ + ctrl_outl(0x80000000, INTC_INTMSKCLR1); + ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); + break; + case IRQ_MODE_IRL7654_MASK: + /* enable IRL7-4 and mask using cpu intc controller */ + ctrl_outl(0x40000000, INTC_INTMSKCLR1); + register_intc_controller(&intc_desc_irl4567); + break; + case IRQ_MODE_IRL3210_MASK: + /* enable IRL0-3 and mask using cpu intc controller */ + ctrl_outl(0x80000000, INTC_INTMSKCLR1); + register_intc_controller(&intc_desc_irl0123); + break; + default: + BUG(); + } } +void __init plat_mem_setup(void) +{ + /* Register the URAM space as Node 1 */ + setup_bootmem_node(1, 0xe55f0000, 0xe5610000); +} diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c index 704c064f70d..c6cdd7e3b04 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c +++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/serial.h> #include <linux/io.h> +#include <asm/mmzone.h> #include <asm/sci.h> static struct plat_sci_port sci_platform_data[] = { @@ -58,28 +59,229 @@ static int __init shx3_devices_setup(void) } __initcall(shx3_devices_setup); -static struct intc2_data intc2_irq_table[] = { - { 16, 0, 0, 0, 1, 2 }, /* TMU0 */ - { 40, 4, 0, 0x20, 0, 3 }, /* SCIF0 ERI */ - { 41, 4, 0, 0x20, 1, 3 }, /* SCIF0 RXI */ - { 42, 4, 0, 0x20, 2, 3 }, /* SCIF0 BRI */ - { 43, 4, 0, 0x20, 3, 3 }, /* SCIF0 TXI */ +enum { + UNUSED = 0, + + /* interrupt sources */ + IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH, + IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH, + IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH, + IRL_HHLL, IRL_HHLH, IRL_HHHL, + IRQ0, IRQ1, IRQ2, IRQ3, + HUDII, + TMU0, TMU1, TMU2, TMU3, TMU4, TMU5, + PCII0, PCII1, PCII2, PCII3, PCII4, + PCII5, PCII6, PCII7, PCII8, PCII9, + SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI, + SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI, + SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI, + SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI, + DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3, + DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE, + DU, + DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8, DMAC1_DMINT9, + DMAC1_DMINT10, DMAC1_DMINT11, DMAC1_DMAE, + IIC, VIN0, VIN1, VCORE0, ATAPI, + DTU0_TEND, DTU0_AE, DTU0_TMISS, + DTU1_TEND, DTU1_AE, DTU1_TMISS, + DTU2_TEND, DTU2_AE, DTU2_TMISS, + DTU3_TEND, DTU3_AE, DTU3_TMISS, + FE0, FE1, + GPIO0, GPIO1, GPIO2, GPIO3, + PAM, IRM, + INTICI0, INTICI1, INTICI2, INTICI3, + INTICI4, INTICI5, INTICI6, INTICI7, + + /* interrupt groups */ + IRL, PCII56789, SCIF0, SCIF1, SCIF2, SCIF3, + DMAC0, DMAC1, DTU0, DTU1, DTU2, DTU3, +}; + +static struct intc_vect vectors[] __initdata = { + INTC_VECT(HUDII, 0x3e0), + INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), + INTC_VECT(TMU2, 0x440), INTC_VECT(TMU3, 0x460), + INTC_VECT(TMU4, 0x480), INTC_VECT(TMU5, 0x4a0), + INTC_VECT(PCII0, 0x500), INTC_VECT(PCII1, 0x520), + INTC_VECT(PCII2, 0x540), INTC_VECT(PCII3, 0x560), + INTC_VECT(PCII4, 0x580), INTC_VECT(PCII5, 0x5a0), + INTC_VECT(PCII6, 0x5c0), INTC_VECT(PCII7, 0x5e0), + INTC_VECT(PCII8, 0x600), INTC_VECT(PCII9, 0x620), + INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720), + INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760), + INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0), + INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0), + INTC_VECT(SCIF2_ERI, 0x800), INTC_VECT(SCIF2_RXI, 0x820), + INTC_VECT(SCIF2_BRI, 0x840), INTC_VECT(SCIF2_TXI, 0x860), + INTC_VECT(SCIF3_ERI, 0x880), INTC_VECT(SCIF3_RXI, 0x8a0), + INTC_VECT(SCIF3_BRI, 0x8c0), INTC_VECT(SCIF3_TXI, 0x8e0), + INTC_VECT(DMAC0_DMINT0, 0x900), INTC_VECT(DMAC0_DMINT1, 0x920), + INTC_VECT(DMAC0_DMINT2, 0x940), INTC_VECT(DMAC0_DMINT3, 0x960), + INTC_VECT(DMAC0_DMINT4, 0x980), INTC_VECT(DMAC0_DMINT5, 0x9a0), + INTC_VECT(DMAC0_DMAE, 0x9c0), + INTC_VECT(DU, 0x9e0), + INTC_VECT(DMAC1_DMINT6, 0xa00), INTC_VECT(DMAC1_DMINT7, 0xa20), + INTC_VECT(DMAC1_DMINT8, 0xa40), INTC_VECT(DMAC1_DMINT9, 0xa60), + INTC_VECT(DMAC1_DMINT10, 0xa80), INTC_VECT(DMAC1_DMINT11, 0xaa0), + INTC_VECT(DMAC1_DMAE, 0xac0), + INTC_VECT(IIC, 0xae0), + INTC_VECT(VIN0, 0xb00), INTC_VECT(VIN1, 0xb20), + INTC_VECT(VCORE0, 0xb00), INTC_VECT(ATAPI, 0xb60), + INTC_VECT(DTU0_TEND, 0xc00), INTC_VECT(DTU0_AE, 0xc20), + INTC_VECT(DTU0_TMISS, 0xc40), + INTC_VECT(DTU1_TEND, 0xc60), INTC_VECT(DTU1_AE, 0xc80), + INTC_VECT(DTU1_TMISS, 0xca0), + INTC_VECT(DTU2_TEND, 0xcc0), INTC_VECT(DTU2_AE, 0xce0), + INTC_VECT(DTU2_TMISS, 0xd00), + INTC_VECT(DTU3_TEND, 0xd20), INTC_VECT(DTU3_AE, 0xd40), + INTC_VECT(DTU3_TMISS, 0xd60), + INTC_VECT(FE0, 0xe00), INTC_VECT(FE1, 0xe20), + INTC_VECT(GPIO0, 0xe40), INTC_VECT(GPIO1, 0xe60), + INTC_VECT(GPIO2, 0xe80), INTC_VECT(GPIO3, 0xea0), + INTC_VECT(PAM, 0xec0), INTC_VECT(IRM, 0xee0), + INTC_VECT(INTICI0, 0xf00), INTC_VECT(INTICI1, 0xf20), + INTC_VECT(INTICI2, 0xf40), INTC_VECT(INTICI3, 0xf60), + INTC_VECT(INTICI4, 0xf80), INTC_VECT(INTICI5, 0xfa0), + INTC_VECT(INTICI6, 0xfc0), INTC_VECT(INTICI7, 0xfe0), }; -static struct intc2_desc intc2_irq_desc __read_mostly = { - .prio_base = 0xfe410000, - .msk_base = 0xfe410820, - .mskclr_base = 0xfe410850, +static struct intc_group groups[] __initdata = { + INTC_GROUP(IRL, IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH, + IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH, + IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH, + IRL_HHLL, IRL_HHLH, IRL_HHHL), + INTC_GROUP(PCII56789, PCII5, PCII6, PCII7, PCII8, PCII9), + INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI), + INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI), + INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI), + INTC_GROUP(SCIF3, SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI), + INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, + DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE), + INTC_GROUP(DMAC1, DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8, + DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11), + INTC_GROUP(DTU0, DTU0_TEND, DTU0_AE, DTU0_TMISS), + INTC_GROUP(DTU1, DTU1_TEND, DTU1_AE, DTU1_TMISS), + INTC_GROUP(DTU2, DTU2_TEND, DTU2_AE, DTU2_TMISS), + INTC_GROUP(DTU3, DTU3_TEND, DTU3_AE, DTU3_TMISS), +}; - .intc2_data = intc2_irq_table, - .nr_irqs = ARRAY_SIZE(intc2_irq_table), +static struct intc_prio priorities[] __initdata = { + INTC_PRIO(SCIF0, 3), + INTC_PRIO(SCIF1, 3), + INTC_PRIO(SCIF2, 3), + INTC_PRIO(SCIF3, 3), +}; - .chip = { - .name = "INTC2-SHX3", - }, +static struct intc_mask_reg mask_registers[] __initdata = { + { 0xfe410030, 0xfe410050, 32, /* CnINTMSK0 / CnINTMSKCLR0 */ + { IRQ0, IRQ1, IRQ2, IRQ3 } }, + { 0xfe410040, 0xfe410060, 32, /* CnINTMSK1 / CnINTMSKCLR1 */ + { IRL } }, + { 0xfe410820, 0xfe410850, 32, /* CnINT2MSK0 / CnINT2MSKCLR0 */ + { FE1, FE0, 0, ATAPI, VCORE0, VIN1, VIN0, IIC, + DU, GPIO3, GPIO2, GPIO1, GPIO0, PAM, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* HUDI bits ignored */ + 0, TMU5, TMU4, TMU3, TMU2, TMU1, TMU0, 0, } }, + { 0xfe410830, 0xfe410860, 32, /* CnINT2MSK1 / CnINT2MSKCLR1 */ + { 0, 0, 0, 0, DTU3, DTU2, DTU1, DTU0, /* IRM bits ignored */ + PCII9, PCII8, PCII7, PCII6, PCII5, PCII4, PCII3, PCII2, + PCII1, PCII0, DMAC1_DMAE, DMAC1_DMINT11, + DMAC1_DMINT10, DMAC1_DMINT9, DMAC1_DMINT8, DMAC1_DMINT7, + DMAC1_DMINT6, DMAC0_DMAE, DMAC0_DMINT5, DMAC0_DMINT4, + DMAC0_DMINT3, DMAC0_DMINT2, DMAC0_DMINT1, DMAC0_DMINT0 } }, + { 0xfe410840, 0xfe410870, 32, /* CnINT2MSK2 / CnINT2MSKCLR2 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + SCIF3_TXI, SCIF3_BRI, SCIF3_RXI, SCIF3_ERI, + SCIF2_TXI, SCIF2_BRI, SCIF2_RXI, SCIF2_ERI, + SCIF1_TXI, SCIF1_BRI, SCIF1_RXI, SCIF1_ERI, + SCIF0_TXI, SCIF0_BRI, SCIF0_RXI, SCIF0_ERI } }, +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xfe410010, 0, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3 } }, + + { 0xfe410800, 0, 32, 4, /* INT2PRI0 */ { 0, HUDII, TMU5, TMU4, + TMU3, TMU2, TMU1, TMU0 } }, + { 0xfe410804, 0, 32, 4, /* INT2PRI1 */ { DTU3, DTU2, DTU1, DTU0, + SCIF3, SCIF2, + SCIF1, SCIF0 } }, + { 0xfe410808, 0, 32, 4, /* INT2PRI2 */ { DMAC1, DMAC0, + PCII56789, PCII4, + PCII3, PCII2, + PCII1, PCII0 } }, + { 0xfe41080c, 0, 32, 4, /* INT2PRI3 */ { FE1, FE0, ATAPI, VCORE0, + VIN1, VIN0, IIC, DU} }, + { 0xfe410810, 0, 32, 4, /* INT2PRI4 */ { 0, 0, PAM, GPIO3, + GPIO2, GPIO1, GPIO0, IRM } }, + { 0xfe410090, 0xfe4100a0, 32, 4, /* CnICIPRI / CnICIPRICLR */ + { INTICI7, INTICI6, INTICI5, INTICI4, + INTICI3, INTICI2, INTICI1, INTICI0 }, INTC_SMP(4, 4) }, +}; + +static DECLARE_INTC_DESC(intc_desc, "shx3", vectors, groups, priorities, + mask_registers, prio_registers, NULL); + +/* Support for external interrupt pins in IRQ mode */ +static struct intc_vect vectors_irq[] __initdata = { + INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280), + INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300), +}; + +static struct intc_sense_reg sense_registers[] __initdata = { + { 0xfe41001c, 32, 2, /* ICR1 */ { IRQ0, IRQ1, IRQ2, IRQ3 } }, }; +static DECLARE_INTC_DESC(intc_desc_irq, "shx3-irq", vectors_irq, groups, + priorities, mask_registers, prio_registers, + sense_registers); + +/* External interrupt pins in IRL mode */ +static struct intc_vect vectors_irl[] __initdata = { + INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220), + INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260), + INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0), + INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0), + INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320), + INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360), + INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0), + INTC_VECT(IRL_HHHL, 0x3c0), +}; + +static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups, + priorities, mask_registers, prio_registers, NULL); + +void __init plat_irq_setup_pins(int mode) +{ + switch (mode) { + case IRQ_MODE_IRQ: + register_intc_controller(&intc_desc_irq); + break; + case IRQ_MODE_IRL3210: + register_intc_controller(&intc_desc_irl); + break; + default: + BUG(); + } +} + void __init plat_irq_setup(void) { - register_intc2_controller(&intc2_irq_desc); + register_intc_controller(&intc_desc); +} + +void __init plat_mem_setup(void) +{ + unsigned int nid = 1; + + /* Register CPU#0 URAM space as Node 1 */ + setup_bootmem_node(nid++, 0x145f0000, 0x14610000); /* CPU0 */ + +#if 0 + /* XXX: Not yet.. */ + setup_bootmem_node(nid++, 0x14df0000, 0x14e10000); /* CPU1 */ + setup_bootmem_node(nid++, 0x155f0000, 0x15610000); /* CPU2 */ + setup_bootmem_node(nid++, 0x15df0000, 0x15e10000); /* CPU3 */ +#endif + + setup_bootmem_node(nid++, 0x16000000, 0x16020000); /* CSM */ } diff --git a/arch/sh/kernel/cpu/sh4a/smp-shx3.c b/arch/sh/kernel/cpu/sh4a/smp-shx3.c new file mode 100644 index 00000000000..e5e06845fa4 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4a/smp-shx3.c @@ -0,0 +1,120 @@ +/* + * SH-X3 SMP + * + * Copyright (C) 2007 Paul Mundt + * Copyright (C) 2007 Magnus Damm + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/cpumask.h> +#include <linux/smp.h> +#include <linux/interrupt.h> +#include <linux/io.h> + +void __init plat_smp_setup(void) +{ + unsigned int cpu = 0; + int i, num; + + cpus_clear(cpu_possible_map); + cpu_set(cpu, cpu_possible_map); + + __cpu_number_map[0] = 0; + __cpu_logical_map[0] = 0; + + /* + * Do this stupidly for now.. we don't have an easy way to probe + * for the total number of cores. + */ + for (i = 1, num = 0; i < NR_CPUS; i++) { + cpu_set(i, cpu_possible_map); + __cpu_number_map[i] = ++num; + __cpu_logical_map[num] = i; + } + + printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num); +} + +void __init plat_prepare_cpus(unsigned int max_cpus) +{ +} + +#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12)) +#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12)) + +#define STBCR_MSTP 0x00000001 +#define STBCR_RESET 0x00000002 +#define STBCR_LTSLP 0x80000000 + +#define STBCR_AP_VAL (STBCR_RESET | STBCR_LTSLP) + +void plat_start_cpu(unsigned int cpu, unsigned long entry_point) +{ + ctrl_outl(entry_point, RESET_REG(cpu)); + + if (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP)) + ctrl_outl(STBCR_MSTP, STBCR_REG(cpu)); + + while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP)) + ; + + /* Start up secondary processor by sending a reset */ + ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu)); +} + +int plat_smp_processor_id(void) +{ + return ctrl_inl(0xff000048); /* CPIDR */ +} + +void plat_send_ipi(unsigned int cpu, unsigned int message) +{ + unsigned long addr = 0xfe410070 + (cpu * 4); + + BUG_ON(cpu >= 4); + BUG_ON(message >= SMP_MSG_NR); + + ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */ +} + +struct ipi_data { + void (*handler)(void *); + void *arg; + unsigned int message; +}; + +static irqreturn_t ipi_interrupt_handler(int irq, void *arg) +{ + struct ipi_data *id = arg; + unsigned int cpu = hard_smp_processor_id(); + unsigned int offs = 4 * cpu; + unsigned int x; + + x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */ + x &= (1 << (id->message << 2)); + ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */ + + id->handler(id->arg); + + return IRQ_HANDLED; +} + +static struct ipi_data ipi_handlers[SMP_MSG_NR]; + +int plat_register_ipi_handler(unsigned int message, + void (*handler)(void *), void *arg) +{ + struct ipi_data *id = &ipi_handlers[message]; + + BUG_ON(SMP_MSG_NR >= 8); + BUG_ON(message >= SMP_MSG_NR); + + id->handler = handler; + id->arg = arg; + id->message = message; + + return request_irq(104 + message, ipi_interrupt_handler, 0, "IPI", id); +} diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c index 71d1c427b90..e0590ffebd7 100644 --- a/arch/sh/kernel/cpufreq.c +++ b/arch/sh/kernel/cpufreq.c @@ -77,8 +77,6 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy, static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) { - printk(KERN_INFO "cpufreq: SuperH CPU frequency driver.\n"); - if (!cpu_online(policy->cpu)) return -ENODEV; @@ -143,6 +141,7 @@ static struct cpufreq_driver sh_cpufreq_driver = { static int __init sh_cpufreq_module_init(void) { + printk(KERN_INFO "cpufreq: SuperH CPU frequency driver.\n"); return cpufreq_register_driver(&sh_cpufreq_driver); } diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c index 80b637c3020..2f30977558a 100644 --- a/arch/sh/kernel/early_printk.c +++ b/arch/sh/kernel/early_printk.c @@ -3,7 +3,7 @@ * * Copyright (C) 1999, 2000 Niibe Yutaka * Copyright (C) 2002 M. R. Brown - * Copyright (C) 2004 - 2006 Paul Mundt + * Copyright (C) 2004 - 2007 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -13,6 +13,7 @@ #include <linux/tty.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/delay.h> #ifdef CONFIG_SH_STANDARD_BIOS #include <asm/sh_bios.h> @@ -62,6 +63,16 @@ static struct console bios_console = { #include <linux/serial_core.h> #include "../../../drivers/serial/sh-sci.h" +#if defined(CONFIG_CPU_SUBTYPE_SH7720) +#define EPK_SCSMR_VALUE 0x000 +#define EPK_SCBRR_VALUE 0x00C +#define EPK_FIFO_SIZE 64 +#define EPK_FIFO_BITS (0x7f00 >> 8) +#else +#define EPK_FIFO_SIZE 16 +#define EPK_FIFO_BITS (0x1f00 >> 8) +#endif + static struct uart_port scif_port = { .mapbase = CONFIG_EARLY_SCIF_CONSOLE_PORT, .membase = (char __iomem *)CONFIG_EARLY_SCIF_CONSOLE_PORT, @@ -69,7 +80,7 @@ static struct uart_port scif_port = { static void scif_sercon_putc(int c) { - while (((sci_in(&scif_port, SCFDR) & 0x1f00 >> 8) == 16)) + while (((sci_in(&scif_port, SCFDR) & EPK_FIFO_BITS) >= EPK_FIFO_SIZE)) ; sci_out(&scif_port, SCxTDR, c); @@ -105,7 +116,22 @@ static struct console scif_console = { .index = -1, }; -#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS) +#if !defined(CONFIG_SH_STANDARD_BIOS) +#if defined(CONFIG_CPU_SUBTYPE_SH7720) +static void scif_sercon_init(char *s) +{ + sci_out(&scif_port, SCSCR, 0x0000); /* clear TE and RE */ + sci_out(&scif_port, SCFCR, 0x4006); /* reset */ + sci_out(&scif_port, SCSCR, 0x0000); /* select internal clock */ + sci_out(&scif_port, SCSMR, EPK_SCSMR_VALUE); + sci_out(&scif_port, SCBRR, EPK_SCBRR_VALUE); + + mdelay(1); /* wait 1-bit time */ + + sci_out(&scif_port, SCFCR, 0x0030); /* TTRG=b'11 */ + sci_out(&scif_port, SCSCR, 0x0030); /* TE, RE */ +} +#elif defined(CONFIG_CPU_SH4) #define DEFAULT_BAUD 115200 /* * Simple SCIF init, primarily aimed at SH7750 and other similar SH-4 @@ -146,7 +172,8 @@ static void scif_sercon_init(char *s) ctrl_outw(0, scif_port.mapbase + 36); ctrl_outw(0x30, scif_port.mapbase + 8); } -#endif /* CONFIG_CPU_SH4 && !CONFIG_SH_STANDARD_BIOS */ +#endif /* defined(CONFIG_CPU_SUBTYPE_SH7720) */ +#endif /* !defined(CONFIG_SH_STANDARD_BIOS) */ #endif /* CONFIG_EARLY_SCIF_CONSOLE */ /* @@ -163,17 +190,12 @@ static struct console *early_console = #endif ; -static int __initdata keep_early; -static int early_console_initialized; - -int __init setup_early_printk(char *buf) +static int __init setup_early_printk(char *buf) { - if (!buf) - return 0; + int keep_early = 0; - if (early_console_initialized) + if (!buf) return 0; - early_console_initialized = 1; if (strstr(buf, "keep")) keep_early = 1; @@ -186,7 +208,8 @@ int __init setup_early_printk(char *buf) if (!strncmp(buf, "serial", 6)) { early_console = &scif_console; -#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS) +#if (defined(CONFIG_CPU_SH4) || defined(CONFIG_CPU_SUBTYPE_SH7720)) && \ + !defined(CONFIG_SH_STANDARD_BIOS) scif_sercon_init(buf + 6); #endif } diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index b4672802719..e0317ed080c 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S @@ -176,7 +176,7 @@ work_notifysig: jmp @r1 lds r0, pr work_resched: -#ifndef CONFIG_PREEMPT +#if defined(CONFIG_GUSA) && !defined(CONFIG_PREEMPT) ! gUSA handling mov.l @(OFF_SP,r15), r0 ! get user space stack pointer mov r0, r1 diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S index 0bccc0ca5a0..3338239717f 100644 --- a/arch/sh/kernel/head.S +++ b/arch/sh/kernel/head.S @@ -54,8 +54,8 @@ ENTRY(_stext) mov.l 1f, r0 ! MD=1, RB=0, BL=0, IMASK=0xF ldc r0, sr ! Initialize global interrupt mask - mov #0, r0 #ifdef CONFIG_CPU_HAS_SR_RB + mov #0, r0 ldc r0, r6_bank #endif @@ -72,15 +72,18 @@ ENTRY(_stext) ! mov.l 2f, r0 mov r0, r15 ! Set initial r15 (stack pointer) - mov #(THREAD_SIZE >> 10), r1 - shll8 r1 ! r1 = THREAD_SIZE - shll2 r1 - sub r1, r0 ! #ifdef CONFIG_CPU_HAS_SR_RB + mov.l 7f, r0 ldc r0, r7_bank ! ... and initial thread_info #endif ! Clear BSS area +#ifdef CONFIG_SMP + mov.l 3f, r0 + cmp/eq #0, r0 ! skip clear if set to zero + bt 10f +#endif + mov.l 3f, r1 add #4, r1 mov.l 4f, r2 @@ -89,13 +92,14 @@ ENTRY(_stext) bf/s 9b ! while (r1 < r2) mov.l r0,@-r2 +10: ! Additional CPU initialization mov.l 6f, r0 jsr @r0 nop SYNCO() ! Wait for pending instructions.. - + ! Start kernel mov.l 5f, r0 jmp @r0 @@ -107,8 +111,10 @@ ENTRY(_stext) #else 1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF #endif +ENTRY(stack_start) 2: .long init_thread_union+THREAD_SIZE 3: .long __bss_start 4: .long _end 5: .long start_kernel 6: .long sh_cpu_init +7: .long init_thread_union diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c index edd1ec214e6..2fdc700dfd6 100644 --- a/arch/sh/kernel/kgdb_stub.c +++ b/arch/sh/kernel/kgdb_stub.c @@ -150,13 +150,6 @@ struct kgdb_regs trap_registers; char kgdb_in_gdb_mode; char in_nmi; /* Set during NMI to prevent reentry */ int kgdb_nofault; /* Boolean to ignore bus errs (i.e. in GDB) */ -int kgdb_enabled = 1; /* Default to enabled, cmdline can disable */ - -/* Exposed for user access */ -struct task_struct *kgdb_current; -unsigned int kgdb_g_imask; -int kgdb_trapa_val; -int kgdb_excode; /* Default values for SCI (can override via kernel args in setup.c) */ #ifndef CONFIG_KGDB_DEFPORT @@ -616,7 +609,7 @@ static short *get_step_address(void) else addr = trap_registers.pc + 2; - kgdb_flush_icache_range(addr, addr + 2); + flush_icache_range(addr, addr + 2); return (short *) addr; } @@ -639,8 +632,7 @@ static void do_single_step(void) *addr = STEP_OPCODE; /* Flush and return */ - kgdb_flush_icache_range((long) addr, (long) addr + 2); - return; + flush_icache_range((long) addr, (long) addr + 2); } /* Undo a single step */ @@ -650,7 +642,7 @@ static void undo_single_step(void) /* Use stepped_address in case we stopped elsewhere */ if (stepped_opcode != 0) { *(short*)stepped_address = stepped_opcode; - kgdb_flush_icache_range(stepped_address, stepped_address + 2); + flush_icache_range(stepped_address, stepped_address + 2); } stepped_opcode = 0; } @@ -736,7 +728,7 @@ static void write_mem_msg(int binary) ebin_to_mem(ptr, (char*)addr, length); else hex_to_mem(ptr, (char*)addr, length); - kgdb_flush_icache_range(addr, addr + length); + flush_icache_range(addr, addr + length); ptr = 0; send_ok_msg(); } @@ -815,14 +807,10 @@ static void set_regs_msg(void) /* * Bring up the ports.. */ -static int kgdb_serial_setup(void) +static int __init kgdb_serial_setup(void) { - extern int kgdb_console_setup(struct console *co, char *options); struct console dummy; - - kgdb_console_setup(&dummy, 0); - - return 0; + return kgdb_console_setup(&dummy, 0); } #else #define kgdb_serial_setup() 0 @@ -833,22 +821,6 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) { int sigval; - if (excep_code == NMI_VEC) { -#ifndef CONFIG_KGDB_NMI - printk(KERN_NOTICE "KGDB: Ignoring unexpected NMI?\n"); - return; -#else /* CONFIG_KGDB_NMI */ - if (!kgdb_enabled) { - kgdb_enabled = 1; - kgdb_init(); - } -#endif /* CONFIG_KGDB_NMI */ - } - - /* Ignore if we're disabled */ - if (!kgdb_enabled) - return; - /* Enter GDB mode (e.g. after detach) */ if (!kgdb_in_gdb_mode) { /* Do serial setup, notify user, issue preemptive ack */ @@ -959,18 +931,10 @@ static void handle_exception(struct pt_regs *regs) /* Get excode for command loop call, user access */ asm("stc r2_bank, %0":"=r"(excep_code)); - kgdb_excode = excep_code; - - /* Other interesting environment items for reference */ - asm("stc r6_bank, %0":"=r"(kgdb_g_imask)); - kgdb_current = current; - kgdb_trapa_val = trapa_value; /* Act on the exception */ kgdb_command_loop(excep_code, trapa_value); - kgdb_current = NULL; - /* Copy back the (maybe modified) registers */ for (count = 0; count < 16; count++) regs->regs[count] = trap_registers.regs[count]; @@ -994,11 +958,8 @@ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5, } /* Initialise the KGDB data structures and serial configuration */ -int kgdb_init(void) +int __init kgdb_init(void) { - if (!kgdb_enabled) - return 1; - in_nmi = 0; kgdb_nofault = 0; stepped_opcode = 0; diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 15ae322dbd7..b4469992d6b 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -19,6 +19,7 @@ #include <linux/tick.h> #include <linux/reboot.h> #include <linux/fs.h> +#include <linux/preempt.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> #include <asm/pgalloc.h> @@ -349,12 +350,11 @@ struct task_struct *__switch_to(struct task_struct *prev, unlazy_fpu(prev, task_pt_regs(prev)); #endif -#ifdef CONFIG_PREEMPT +#if defined(CONFIG_GUSA) && defined(CONFIG_PREEMPT) { - unsigned long flags; struct pt_regs *regs; - local_irq_save(flags); + preempt_disable(); regs = task_pt_regs(prev); if (user_mode(regs) && regs->regs[15] >= 0xc0000000) { int offset = (int)regs->regs[15]; @@ -365,7 +365,7 @@ struct task_struct *__switch_to(struct task_struct *prev, /* Go to rewind point */ regs->pc = regs->regs[0] + offset; } - local_irq_restore(flags); + preempt_enable_no_resched(); } #endif diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 2cf7dec0d69..b3027a6775b 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -22,6 +22,7 @@ #include <linux/mm.h> #include <linux/kexec.h> #include <linux/module.h> +#include <linux/smp.h> #include <asm/uaccess.h> #include <asm/io.h> #include <asm/page.h> @@ -42,7 +43,13 @@ extern void * __rd_start, * __rd_end; * This value will be used at the very early stage of serial setup. * The bigger value means no problem. */ -struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 10000000, }; +struct sh_cpuinfo cpu_data[NR_CPUS] __read_mostly = { + [0] = { + .type = CPU_SH_NONE, + .loops_per_jiffy = 10000000, + }, +}; +EXPORT_SYMBOL(cpu_data); /* * The machine vector. First entry in .machvec.init, or clobbered by @@ -272,6 +279,10 @@ void __init setup_arch(char **cmdline_p) sh_mv.mv_setup(cmdline_p); paging_init(); + +#ifdef CONFIG_SMP + plat_smp_setup(); +#endif } static const char *cpu_name[] = { @@ -279,7 +290,7 @@ static const char *cpu_name[] = { [CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706", [CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708", [CPU_SH7709] = "SH7709", [CPU_SH7710] = "SH7710", - [CPU_SH7712] = "SH7712", + [CPU_SH7712] = "SH7712", [CPU_SH7720] = "SH7720", [CPU_SH7729] = "SH7729", [CPU_SH7750] = "SH7750", [CPU_SH7750S] = "SH7750S", [CPU_SH7750R] = "SH7750R", [CPU_SH7751] = "SH7751", [CPU_SH7751R] = "SH7751R", diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c index 37aef0a8519..548e4285b37 100644 --- a/arch/sh/kernel/sh_ksyms.c +++ b/arch/sh/kernel/sh_ksyms.c @@ -8,7 +8,7 @@ #include <linux/vmalloc.h> #include <linux/pci.h> #include <linux/irq.h> - +#include <asm/sections.h> #include <asm/semaphore.h> #include <asm/processor.h> #include <asm/uaccess.h> @@ -43,7 +43,6 @@ EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(__copy_user); -EXPORT_SYMBOL(boot_cpu_data); #ifdef CONFIG_MMU EXPORT_SYMBOL(get_vm_area); @@ -53,6 +52,7 @@ EXPORT_SYMBOL(get_vm_area); EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__down); EXPORT_SYMBOL(__down_interruptible); +EXPORT_SYMBOL(__down_trylock); EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(__ndelay); @@ -128,7 +128,8 @@ DECLARE_EXPORT(__movstrSI12_i4); #endif /* __GNUC__ == 4 */ #endif -#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) +#if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \ + defined(CONFIG_SH7705_CACHE_32KB)) /* needed by some modules */ EXPORT_SYMBOL(flush_cache_all); EXPORT_SYMBOL(flush_cache_range); @@ -136,17 +137,11 @@ EXPORT_SYMBOL(flush_dcache_page); EXPORT_SYMBOL(__flush_purge_region); #endif -#if defined(CONFIG_MMU) && (defined(CONFIG_CPU_SH4) || \ - defined(CONFIG_SH7705_CACHE_32KB)) +#if !defined(CONFIG_CACHE_OFF) && defined(CONFIG_MMU) && \ + (defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)) EXPORT_SYMBOL(clear_user_page); #endif -EXPORT_SYMBOL(__down_trylock); - -#ifdef CONFIG_SMP -EXPORT_SYMBOL(synchronize_irq); -#endif - EXPORT_SYMBOL(csum_partial); EXPORT_SYMBOL(csum_partial_copy_generic); #ifdef CONFIG_IPV6 @@ -154,3 +149,4 @@ EXPORT_SYMBOL(csum_ipv6_magic); #endif EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(__clear_user); +EXPORT_SYMBOL(_ebss); diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index 706d81ccd10..2f42442cf16 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c @@ -507,13 +507,11 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, ctrl_inw(regs->pc - 4)); break; } +#ifdef CONFIG_GUSA } else { /* gUSA handling */ -#ifdef CONFIG_PREEMPT - unsigned long flags; + preempt_disable(); - local_irq_save(flags); -#endif if (regs->regs[15] >= 0xc0000000) { int offset = (int)regs->regs[15]; @@ -524,8 +522,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, regs->pc = regs->regs[0] + offset - instruction_size(ctrl_inw(regs->pc-4)); } -#ifdef CONFIG_PREEMPT - local_irq_restore(flags); + + preempt_enable_no_resched(); #endif } diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index 283e1425ced..94075e1a1e6 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c @@ -3,68 +3,40 @@ * * SMP support for the SuperH processors. * - * Copyright (C) 2002, 2003 Paul Mundt + * Copyright (C) 2002 - 2007 Paul Mundt + * Copyright (C) 2006 - 2007 Akio Idehara * - * 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 file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. */ - #include <linux/err.h> #include <linux/cache.h> #include <linux/cpumask.h> #include <linux/delay.h> #include <linux/init.h> -#include <linux/interrupt.h> #include <linux/spinlock.h> -#include <linux/threads.h> +#include <linux/mm.h> #include <linux/module.h> -#include <linux/time.h> -#include <linux/timex.h> -#include <linux/sched.h> -#include <linux/module.h> - +#include <linux/interrupt.h> #include <asm/atomic.h> #include <asm/processor.h> #include <asm/system.h> #include <asm/mmu_context.h> #include <asm/smp.h> +#include <asm/cacheflush.h> +#include <asm/sections.h> -/* - * This was written with the Sega Saturn (SMP SH-2 7604) in mind, - * but is designed to be usable regardless if there's an MMU - * present or not. - */ -struct sh_cpuinfo cpu_data[NR_CPUS]; - -extern void per_cpu_trap_init(void); +int __cpu_number_map[NR_CPUS]; /* Map physical to logical */ +int __cpu_logical_map[NR_CPUS]; /* Map logical to physical */ cpumask_t cpu_possible_map; EXPORT_SYMBOL(cpu_possible_map); cpumask_t cpu_online_map; EXPORT_SYMBOL(cpu_online_map); -static atomic_t cpus_booted = ATOMIC_INIT(0); -/* These are defined by the board-specific code. */ - -/* - * Cause the function described by call_data to be executed on the passed - * cpu. When the function has finished, increment the finished field of - * call_data. - */ -void __smp_send_ipi(unsigned int cpu, unsigned int action); - -/* - * Find the number of available processors - */ -unsigned int __smp_probe_cpus(void); - -/* - * Start a particular processor - */ -void __smp_slave_init(unsigned int cpu); +static atomic_t cpus_booted = ATOMIC_INIT(0); /* * Run specified function on a particular processor. @@ -73,74 +45,123 @@ void __smp_call_function(unsigned int cpu); static inline void __init smp_store_cpu_info(unsigned int cpu) { - cpu_data[cpu].loops_per_jiffy = loops_per_jiffy; + struct sh_cpuinfo *c = cpu_data + cpu; + + c->loops_per_jiffy = loops_per_jiffy; } void __init smp_prepare_cpus(unsigned int max_cpus) { unsigned int cpu = smp_processor_id(); - int i; - atomic_set(&cpus_booted, 1); - smp_store_cpu_info(cpu); - - for (i = 0; i < __smp_probe_cpus(); i++) - cpu_set(i, cpu_possible_map); + init_new_context(current, &init_mm); + current_thread_info()->cpu = cpu; + plat_prepare_cpus(max_cpus); + +#ifndef CONFIG_HOTPLUG_CPU + cpu_present_map = cpu_possible_map; +#endif } void __devinit smp_prepare_boot_cpu(void) { unsigned int cpu = smp_processor_id(); + __cpu_number_map[0] = cpu; + __cpu_logical_map[0] = cpu; + cpu_set(cpu, cpu_online_map); cpu_set(cpu, cpu_possible_map); } -int __cpu_up(unsigned int cpu) +asmlinkage void __cpuinit start_secondary(void) { - struct task_struct *tsk; + unsigned int cpu; + struct mm_struct *mm = &init_mm; - tsk = fork_idle(cpu); + atomic_inc(&mm->mm_count); + atomic_inc(&mm->mm_users); + current->active_mm = mm; + BUG_ON(current->mm); + enter_lazy_tlb(mm, current); - if (IS_ERR(tsk)) - panic("Failed forking idle task for cpu %d\n", cpu); - - task_thread_info(tsk)->cpu = cpu; + per_cpu_trap_init(); + + preempt_disable(); + + local_irq_enable(); + + calibrate_delay(); + + cpu = smp_processor_id(); + smp_store_cpu_info(cpu); cpu_set(cpu, cpu_online_map); - return 0; + cpu_idle(); } -int start_secondary(void *unused) +extern struct { + unsigned long sp; + unsigned long bss_start; + unsigned long bss_end; + void *start_kernel_fn; + void *cpu_init_fn; + void *thread_info; +} stack_start; + +int __cpuinit __cpu_up(unsigned int cpu) { - unsigned int cpu; + struct task_struct *tsk; + unsigned long timeout; - cpu = smp_processor_id(); + tsk = fork_idle(cpu); + if (IS_ERR(tsk)) { + printk(KERN_ERR "Failed forking idle task for cpu %d\n", cpu); + return PTR_ERR(tsk); + } - atomic_inc(&init_mm.mm_count); - current->active_mm = &init_mm; + /* Fill in data in head.S for secondary cpus */ + stack_start.sp = tsk->thread.sp; + stack_start.thread_info = tsk->stack; + stack_start.bss_start = 0; /* don't clear bss for secondary cpus */ + stack_start.start_kernel_fn = start_secondary; - smp_store_cpu_info(cpu); + flush_cache_all(); - __smp_slave_init(cpu); - preempt_disable(); - per_cpu_trap_init(); - - atomic_inc(&cpus_booted); + plat_start_cpu(cpu, (unsigned long)_stext); - cpu_idle(); - return 0; + timeout = jiffies + HZ; + while (time_before(jiffies, timeout)) { + if (cpu_online(cpu)) + break; + + udelay(10); + } + + if (cpu_online(cpu)) + return 0; + + return -ENOENT; } void __init smp_cpus_done(unsigned int max_cpus) { - smp_mb(); + unsigned long bogosum = 0; + int cpu; + + for_each_online_cpu(cpu) + bogosum += cpu_data[cpu].loops_per_jiffy; + + printk(KERN_INFO "SMP: Total of %d processors activated " + "(%lu.%02lu BogoMIPS).\n", num_online_cpus(), + bogosum / (500000/HZ), + (bogosum / (5000/HZ)) % 100); } void smp_send_reschedule(int cpu) { - __smp_send_ipi(cpu, SMP_MSG_RESCHEDULE); + plat_send_ipi(cpu, SMP_MSG_RESCHEDULE); } static void stop_this_cpu(void *unused) @@ -157,7 +178,6 @@ void smp_send_stop(void) smp_call_function(stop_this_cpu, 0, 1, 0); } - struct smp_fn_call_struct smp_fn_call = { .lock = SPIN_LOCK_UNLOCKED, .finished = ATOMIC_INIT(0), @@ -175,9 +195,6 @@ int smp_call_function(void (*func)(void *info), void *info, int retry, int wait) unsigned int nr_cpus = atomic_read(&cpus_booted); int i; - if (nr_cpus < 2) - return 0; - /* Can deadlock when called with interrupts disabled */ WARN_ON(irqs_disabled()); @@ -189,7 +206,7 @@ int smp_call_function(void (*func)(void *info), void *info, int retry, int wait) for (i = 0; i < nr_cpus; i++) if (i != smp_processor_id()) - __smp_call_function(i); + plat_send_ipi(i, SMP_MSG_FUNCTION); if (wait) while (atomic_read(&smp_fn_call.finished) != (nr_cpus - 1)); @@ -205,3 +222,143 @@ int setup_profiling_timer(unsigned int multiplier) return 0; } +static void flush_tlb_all_ipi(void *info) +{ + local_flush_tlb_all(); +} + +void flush_tlb_all(void) +{ + on_each_cpu(flush_tlb_all_ipi, 0, 1, 1); +} + +static void flush_tlb_mm_ipi(void *mm) +{ + local_flush_tlb_mm((struct mm_struct *)mm); +} + +/* + * The following tlb flush calls are invoked when old translations are + * being torn down, or pte attributes are changing. For single threaded + * address spaces, a new context is obtained on the current cpu, and tlb + * context on other cpus are invalidated to force a new context allocation + * at switch_mm time, should the mm ever be used on other cpus. For + * multithreaded address spaces, intercpu interrupts have to be sent. + * Another case where intercpu interrupts are required is when the target + * mm might be active on another cpu (eg debuggers doing the flushes on + * behalf of debugees, kswapd stealing pages from another process etc). + * Kanoj 07/00. + */ + +void flush_tlb_mm(struct mm_struct *mm) +{ + preempt_disable(); + + if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { + smp_call_function(flush_tlb_mm_ipi, (void *)mm, 1, 1); + } else { + int i; + for (i = 0; i < num_online_cpus(); i++) + if (smp_processor_id() != i) + cpu_context(i, mm) = 0; + } + local_flush_tlb_mm(mm); + + preempt_enable(); +} + +struct flush_tlb_data { + struct vm_area_struct *vma; + unsigned long addr1; + unsigned long addr2; +}; + +static void flush_tlb_range_ipi(void *info) +{ + struct flush_tlb_data *fd = (struct flush_tlb_data *)info; + + local_flush_tlb_range(fd->vma, fd->addr1, fd->addr2); +} + +void flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + + preempt_disable(); + if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { + struct flush_tlb_data fd; + + fd.vma = vma; + fd.addr1 = start; + fd.addr2 = end; + smp_call_function(flush_tlb_range_ipi, (void *)&fd, 1, 1); + } else { + int i; + for (i = 0; i < num_online_cpus(); i++) + if (smp_processor_id() != i) + cpu_context(i, mm) = 0; + } + local_flush_tlb_range(vma, start, end); + preempt_enable(); +} + +static void flush_tlb_kernel_range_ipi(void *info) +{ + struct flush_tlb_data *fd = (struct flush_tlb_data *)info; + + local_flush_tlb_kernel_range(fd->addr1, fd->addr2); +} + +void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + struct flush_tlb_data fd; + + fd.addr1 = start; + fd.addr2 = end; + on_each_cpu(flush_tlb_kernel_range_ipi, (void *)&fd, 1, 1); +} + +static void flush_tlb_page_ipi(void *info) +{ + struct flush_tlb_data *fd = (struct flush_tlb_data *)info; + + local_flush_tlb_page(fd->vma, fd->addr1); +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + preempt_disable(); + if ((atomic_read(&vma->vm_mm->mm_users) != 1) || + (current->mm != vma->vm_mm)) { + struct flush_tlb_data fd; + + fd.vma = vma; + fd.addr1 = page; + smp_call_function(flush_tlb_page_ipi, (void *)&fd, 1, 1); + } else { + int i; + for (i = 0; i < num_online_cpus(); i++) + if (smp_processor_id() != i) + cpu_context(i, vma->vm_mm) = 0; + } + local_flush_tlb_page(vma, page); + preempt_enable(); +} + +static void flush_tlb_one_ipi(void *info) +{ + struct flush_tlb_data *fd = (struct flush_tlb_data *)info; + local_flush_tlb_one(fd->addr1, fd->addr2); +} + +void flush_tlb_one(unsigned long asid, unsigned long vaddr) +{ + struct flush_tlb_data fd; + + fd.addr1 = asid; + fd.addr2 = vaddr; + + smp_call_function(flush_tlb_one_ipi, (void *)&fd, 1, 1); + local_flush_tlb_one(asid, vaddr); +} diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S index 91fb7024e06..10bec45415b 100644 --- a/arch/sh/kernel/syscalls.S +++ b/arch/sh/kernel/syscalls.S @@ -14,24 +14,6 @@ #include <linux/sys.h> #include <linux/linkage.h> -#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE) -#define sys_nfsservctl sys_ni_syscall -#endif - -#if !defined(CONFIG_MMU) -#define sys_madvise sys_ni_syscall -#define sys_readahead sys_ni_syscall -#define sys_mprotect sys_ni_syscall -#define sys_msync sys_ni_syscall -#define sys_mlock sys_ni_syscall -#define sys_munlock sys_ni_syscall -#define sys_mlockall sys_ni_syscall -#define sys_munlockall sys_ni_syscall -#define sys_mremap sys_ni_syscall -#define sys_mincore sys_ni_syscall -#define sys_remap_file_pages sys_ni_syscall -#endif - .data ENTRY(sys_call_table) .long sys_restart_syscall /* 0 - old "setup()" system call*/ diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c index 8a545d54e2d..628ec9a15e3 100644 --- a/arch/sh/kernel/timers/timer-tmu.c +++ b/arch/sh/kernel/timers/timer-tmu.c @@ -173,7 +173,8 @@ static int tmu_timer_init(void) tmu_timer_stop(); -#if !defined(CONFIG_CPU_SUBTYPE_SH7760) && \ +#if !defined(CONFIG_CPU_SUBTYPE_SH7720) && \ + !defined(CONFIG_CPU_SUBTYPE_SH7760) && \ !defined(CONFIG_CPU_SUBTYPE_SH7785) && \ !defined(CONFIG_CPU_SUBTYPE_SHX3) ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index 67015044d74..dcb46e71da1 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -807,12 +807,13 @@ static inline void __init gdb_vbr_init(void) } #endif -void __init per_cpu_trap_init(void) +void __cpuinit per_cpu_trap_init(void) { extern void *vbr_base; #ifdef CONFIG_SH_STANDARD_BIOS - gdb_vbr_init(); + if (raw_smp_processor_id() == 0) + gdb_vbr_init(); #endif /* NOTE: The VBR value should be at P1 diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index 9cb95af7b09..6d5abba2ee2 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S @@ -62,6 +62,8 @@ SECTIONS __nosave_end = .; PERCPU(PAGE_SIZE) + + . = ALIGN(L1_CACHE_BYTES); .data.cacheline_aligned : { *(.data.cacheline_aligned) } _edata = .; /* End of data section */ @@ -89,7 +91,14 @@ SECTIONS __con_initcall_end = .; SECURITY_INIT + /* .exit.text is discarded at runtime, not link time, to deal with + references from .rodata */ + .exit.text : { *(.exit.text) } + .exit.data : { *(.exit.data) } + #ifdef CONFIG_BLK_DEV_INITRD + . = ALIGN(PAGE_SIZE); + __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; @@ -107,6 +116,7 @@ SECTIONS *(.bss.page_aligned) *(.bss) . = ALIGN(4); + _ebss = .; /* uClinux MTD sucks */ _end = . ; } diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 43f3972a5fb..cf446bbab5b 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -2,7 +2,6 @@ # Processor families # config CPU_SH2 - select SH_WRITETHROUGH if !CPU_SH2A bool config CPU_SH2A @@ -19,6 +18,7 @@ config CPU_SH4 select CPU_HAS_INTEVT select CPU_HAS_SR_RB select CPU_HAS_PTEA if (!CPU_SUBTYPE_ST40 && !CPU_SH4A) || CPU_SHX2 + select CPU_HAS_FPU if !CPU_SH4AL_DSP config CPU_SH4A bool @@ -32,7 +32,6 @@ config CPU_SH4AL_DSP config CPU_SUBTYPE_ST40 bool select CPU_SH4 - select CPU_HAS_INTC2_IRQ config CPU_SHX2 bool @@ -52,26 +51,22 @@ choice config CPU_SUBTYPE_SH7619 bool "Support SH7619 processor" select CPU_SH2 - select CPU_HAS_IPR_IRQ # SH-2A Processor Support config CPU_SUBTYPE_SH7206 bool "Support SH7206 processor" select CPU_SH2A - select CPU_HAS_IPR_IRQ # SH-3 Processor Support config CPU_SUBTYPE_SH7705 bool "Support SH7705 processor" select CPU_SH3 - select CPU_HAS_IPR_IRQ config CPU_SUBTYPE_SH7706 bool "Support SH7706 processor" select CPU_SH3 - select CPU_HAS_IPR_IRQ help Select SH7706 if you have a 133 Mhz SH-3 HD6417706 CPU. @@ -91,14 +86,12 @@ config CPU_SUBTYPE_SH7708 config CPU_SUBTYPE_SH7709 bool "Support SH7709 processor" select CPU_SH3 - select CPU_HAS_IPR_IRQ help Select SH7709 if you have a 80 Mhz SH-3 HD6417709 CPU. config CPU_SUBTYPE_SH7710 bool "Support SH7710 processor" select CPU_SH3 - select CPU_HAS_IPR_IRQ select CPU_HAS_DSP help Select SH7710 if you have a SH3-DSP SH7710 CPU. @@ -106,24 +99,28 @@ config CPU_SUBTYPE_SH7710 config CPU_SUBTYPE_SH7712 bool "Support SH7712 processor" select CPU_SH3 - select CPU_HAS_IPR_IRQ select CPU_HAS_DSP help Select SH7712 if you have a SH3-DSP SH7712 CPU. +config CPU_SUBTYPE_SH7720 + bool "Support SH7720 processor" + select CPU_SH3 + select CPU_HAS_DSP + help + Select SH7720 if you have a SH3-DSP SH7720 CPU. + # SH-4 Processor Support config CPU_SUBTYPE_SH7750 bool "Support SH7750 processor" select CPU_SH4 - select CPU_HAS_INTC_IRQ help Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU. config CPU_SUBTYPE_SH7091 bool "Support SH7091 processor" select CPU_SH4 - select CPU_HAS_INTC_IRQ help Select SH7091 if you have an SH-4 based Sega device (such as the Dreamcast, Naomi, and Naomi 2). @@ -131,17 +128,14 @@ config CPU_SUBTYPE_SH7091 config CPU_SUBTYPE_SH7750R bool "Support SH7750R processor" select CPU_SH4 - select CPU_HAS_INTC_IRQ config CPU_SUBTYPE_SH7750S bool "Support SH7750S processor" select CPU_SH4 - select CPU_HAS_INTC_IRQ config CPU_SUBTYPE_SH7751 bool "Support SH7751 processor" select CPU_SH4 - select CPU_HAS_INTC_IRQ help Select SH7751 if you have a 166 Mhz SH-4 HD6417751 CPU, or if you have a HD6417751R CPU. @@ -149,13 +143,10 @@ config CPU_SUBTYPE_SH7751 config CPU_SUBTYPE_SH7751R bool "Support SH7751R processor" select CPU_SH4 - select CPU_HAS_INTC_IRQ config CPU_SUBTYPE_SH7760 bool "Support SH7760 processor" select CPU_SH4 - select CPU_HAS_INTC2_IRQ - select CPU_HAS_IPR_IRQ config CPU_SUBTYPE_SH4_202 bool "Support SH4-202 processor" @@ -185,19 +176,21 @@ config CPU_SUBTYPE_SH7770 config CPU_SUBTYPE_SH7780 bool "Support SH7780 processor" select CPU_SH4A - select CPU_HAS_INTC_IRQ config CPU_SUBTYPE_SH7785 bool "Support SH7785 processor" select CPU_SH4A select CPU_SHX2 - select CPU_HAS_INTC2_IRQ + select ARCH_SPARSEMEM_ENABLE + select SYS_SUPPORTS_NUMA config CPU_SUBTYPE_SHX3 bool "Support SH-X3 processor" select CPU_SH4A select CPU_SHX3 - select CPU_HAS_INTC2_IRQ + select ARCH_SPARSEMEM_ENABLE + select SYS_SUPPORTS_NUMA + select SYS_SUPPORTS_SMP # SH4AL-DSP Processor Support @@ -209,7 +202,6 @@ config CPU_SUBTYPE_SH7722 bool "Support SH7722 processor" select CPU_SH4AL_DSP select CPU_SHX2 - select CPU_HAS_INTC_IRQ select ARCH_SPARSEMEM_ENABLE select SYS_SUPPORTS_NUMA @@ -274,7 +266,7 @@ config 32BIT config X2TLB bool "Enable extended TLB mode" - depends on CPU_SHX2 && MMU && EXPERIMENTAL + depends on (CPU_SHX2 || CPU_SHX3) && MMU && EXPERIMENTAL help Selecting this option will enable the extended mode of the SH-X2 TLB. For legacy SH-X behaviour and interoperability, say N. For @@ -307,6 +299,7 @@ config NUMA config NODES_SHIFT int + default "3" if CPU_SUBTYPE_SHX3 default "1" depends on NEED_MULTIPLE_NODES @@ -323,7 +316,9 @@ config ARCH_SPARSEMEM_DEFAULT config MAX_ACTIVE_REGIONS int - default "2" if (CPU_SUBTYPE_SH7722 && SPARSEMEM) + default "6" if (CPU_SUBTYPE_SHX3 && SPARSEMEM) + default "2" if SPARSEMEM && (CPU_SUBTYPE_SH7722 || \ + CPU_SUBTYPE_SH7785) default "1" config ARCH_POPULATES_NODE_MAP @@ -342,25 +337,27 @@ config ARCH_MEMORY_PROBE choice prompt "Kernel page size" + default PAGE_SIZE_8KB if X2TLB default PAGE_SIZE_4KB config PAGE_SIZE_4KB bool "4kB" + depends on !X2TLB help This is the default page size used by all SuperH CPUs. config PAGE_SIZE_8KB bool "8kB" - depends on EXPERIMENTAL && X2TLB + depends on X2TLB help This enables 8kB pages as supported by SH-X2 and later MMUs. config PAGE_SIZE_64KB bool "64kB" - depends on EXPERIMENTAL && CPU_SH4 + depends on CPU_SH4 help This enables support for 64kB pages, possible on all SH-4 - CPUs and later. Highly experimental, not recommended. + CPUs and later. endchoice @@ -412,8 +409,17 @@ config SH_DIRECT_MAPPED Turn this option off for platforms that do not have a direct-mapped cache, and you have no need to run the caches in such a configuration. -config SH_WRITETHROUGH - bool "Use write-through caching" +choice + prompt "Cache mode" + default CACHE_WRITEBACK if CPU_SH2A || CPU_SH3 || CPU_SH4 + default CACHE_WRITETHROUGH if (CPU_SH2 && !CPU_SH2A) + +config CACHE_WRITEBACK + bool "Write-back" + depends on CPU_SH2A || CPU_SH3 || CPU_SH4 + +config CACHE_WRITETHROUGH + bool "Write-through" help Selecting this option will configure the caches in write-through mode, as opposed to the default write-back configuration. @@ -424,4 +430,9 @@ config SH_WRITETHROUGH If unsure, say N. +config CACHE_OFF + bool "Off" + +endchoice + endmenu diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index 4061e89d84d..ee30fb44dfe 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile @@ -4,29 +4,32 @@ obj-y := init.o extable.o consistent.o -obj-$(CONFIG_CPU_SH2) += cache-sh2.o -obj-$(CONFIG_CPU_SH3) += cache-sh3.o -obj-$(CONFIG_CPU_SH4) += cache-sh4.o +ifndef CONFIG_CACHE_OFF +obj-$(CONFIG_CPU_SH2) += cache-sh2.o +obj-$(CONFIG_CPU_SH3) += cache-sh3.o +obj-$(CONFIG_CPU_SH4) += cache-sh4.o +obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o +endif mmu-y := tlb-nommu.o pg-nommu.o -mmu-$(CONFIG_CPU_SH3) += fault-nommu.o -mmu-$(CONFIG_CPU_SH4) += fault-nommu.o mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o tlb-flush.o \ ioremap.o obj-y += $(mmu-y) ifdef CONFIG_DEBUG_FS -obj-$(CONFIG_CPU_SH4) += cache-debugfs.o +obj-$(CONFIG_CPU_SH4) += cache-debugfs.o endif ifdef CONFIG_MMU -obj-$(CONFIG_CPU_SH3) += tlb-sh3.o -obj-$(CONFIG_CPU_SH4) += tlb-sh4.o pg-sh4.o -obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o +obj-$(CONFIG_CPU_SH3) += tlb-sh3.o +obj-$(CONFIG_CPU_SH4) += tlb-sh4.o +ifndef CONFIG_CACHE_OFF +obj-$(CONFIG_CPU_SH4) += pg-sh4.o +obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o +endif endif obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o obj-$(CONFIG_32BIT) += pmb.o obj-$(CONFIG_NUMA) += numa.o diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 86486326ef1..226b190c5b9 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -2,7 +2,7 @@ * arch/sh/mm/cache-sh4.c * * Copyright (C) 1999, 2000, 2002 Niibe Yutaka - * Copyright (C) 2001 - 2006 Paul Mundt + * Copyright (C) 2001 - 2007 Paul Mundt * Copyright (C) 2003 Richard Curnow * * This file is subject to the terms and conditions of the GNU General Public @@ -44,7 +44,7 @@ static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) = static void compute_alias(struct cache_info *c) { c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1); - c->n_aliases = (c->alias_mask >> PAGE_SHIFT) + 1; + c->n_aliases = c->alias_mask ? (c->alias_mask >> PAGE_SHIFT) + 1 : 0; } static void __init emit_cache_params(void) @@ -54,21 +54,35 @@ static void __init emit_cache_params(void) ctrl_inl(CCN_CVR), ctrl_inl(CCN_PRR)); printk("I-cache : n_ways=%d n_sets=%d way_incr=%d\n", - current_cpu_data.icache.ways, - current_cpu_data.icache.sets, - current_cpu_data.icache.way_incr); + boot_cpu_data.icache.ways, + boot_cpu_data.icache.sets, + boot_cpu_data.icache.way_incr); printk("I-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", - current_cpu_data.icache.entry_mask, - current_cpu_data.icache.alias_mask, - current_cpu_data.icache.n_aliases); + boot_cpu_data.icache.entry_mask, + boot_cpu_data.icache.alias_mask, + boot_cpu_data.icache.n_aliases); printk("D-cache : n_ways=%d n_sets=%d way_incr=%d\n", - current_cpu_data.dcache.ways, - current_cpu_data.dcache.sets, - current_cpu_data.dcache.way_incr); + boot_cpu_data.dcache.ways, + boot_cpu_data.dcache.sets, + boot_cpu_data.dcache.way_incr); printk("D-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", - current_cpu_data.dcache.entry_mask, - current_cpu_data.dcache.alias_mask, - current_cpu_data.dcache.n_aliases); + boot_cpu_data.dcache.entry_mask, + boot_cpu_data.dcache.alias_mask, + boot_cpu_data.dcache.n_aliases); + + /* + * Emit Secondary Cache parameters if the CPU has a probed L2. + */ + if (boot_cpu_data.flags & CPU_HAS_L2_CACHE) { + printk("S-cache : n_ways=%d n_sets=%d way_incr=%d\n", + boot_cpu_data.scache.ways, + boot_cpu_data.scache.sets, + boot_cpu_data.scache.way_incr); + printk("S-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", + boot_cpu_data.scache.entry_mask, + boot_cpu_data.scache.alias_mask, + boot_cpu_data.scache.n_aliases); + } if (!__flush_dcache_segment_fn) panic("unknown number of cache ways\n"); @@ -79,10 +93,11 @@ static void __init emit_cache_params(void) */ void __init p3_cache_init(void) { - compute_alias(¤t_cpu_data.icache); - compute_alias(¤t_cpu_data.dcache); + compute_alias(&boot_cpu_data.icache); + compute_alias(&boot_cpu_data.dcache); + compute_alias(&boot_cpu_data.scache); - switch (current_cpu_data.dcache.ways) { + switch (boot_cpu_data.dcache.ways) { case 1: __flush_dcache_segment_fn = __flush_dcache_segment_1way; break; @@ -187,13 +202,13 @@ void flush_cache_sigtramp(unsigned long addr) : "m" (__m(v))); index = CACHE_IC_ADDRESS_ARRAY | - (v & current_cpu_data.icache.entry_mask); + (v & boot_cpu_data.icache.entry_mask); local_irq_save(flags); jump_to_P2(); - for (i = 0; i < current_cpu_data.icache.ways; - i++, index += current_cpu_data.icache.way_incr) + for (i = 0; i < boot_cpu_data.icache.ways; + i++, index += boot_cpu_data.icache.way_incr) ctrl_outl(0, index); /* Clear out Valid-bit */ back_to_P1(); @@ -210,7 +225,7 @@ static inline void flush_cache_4096(unsigned long start, * All types of SH-4 require PC to be in P2 to operate on the I-cache. * Some types of SH-4 require PC to be in P2 to operate on the D-cache. */ - if ((current_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) || + if ((boot_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) || (start < CACHE_OC_ADDRESS_ARRAY)) exec_offset = 0x20000000; @@ -232,7 +247,7 @@ void flush_dcache_page(struct page *page) int i, n; /* Loop all the D-cache */ - n = current_cpu_data.dcache.n_aliases; + n = boot_cpu_data.dcache.n_aliases; for (i = 0; i < n; i++, addr += 4096) flush_cache_4096(addr, phys); } @@ -264,7 +279,7 @@ static inline void flush_icache_all(void) void flush_dcache_all(void) { - (*__flush_dcache_segment_fn)(0UL, current_cpu_data.dcache.way_size); + (*__flush_dcache_segment_fn)(0UL, boot_cpu_data.dcache.way_size); wmb(); } @@ -278,8 +293,8 @@ static void __flush_cache_mm(struct mm_struct *mm, unsigned long start, unsigned long end) { unsigned long d = 0, p = start & PAGE_MASK; - unsigned long alias_mask = current_cpu_data.dcache.alias_mask; - unsigned long n_aliases = current_cpu_data.dcache.n_aliases; + unsigned long alias_mask = boot_cpu_data.dcache.alias_mask; + unsigned long n_aliases = boot_cpu_data.dcache.n_aliases; unsigned long select_bit; unsigned long all_aliases_mask; unsigned long addr_offset; @@ -366,7 +381,7 @@ void flush_cache_mm(struct mm_struct *mm) * If cache is only 4k-per-way, there are never any 'aliases'. Since * the cache is physically tagged, the data can just be left in there. */ - if (current_cpu_data.dcache.n_aliases == 0) + if (boot_cpu_data.dcache.n_aliases == 0) return; /* @@ -403,7 +418,7 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigned long phys = pfn << PAGE_SHIFT; unsigned int alias_mask; - alias_mask = current_cpu_data.dcache.alias_mask; + alias_mask = boot_cpu_data.dcache.alias_mask; /* We only need to flush D-cache when we have alias */ if ((address^phys) & alias_mask) { @@ -417,7 +432,7 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long address, phys); } - alias_mask = current_cpu_data.icache.alias_mask; + alias_mask = boot_cpu_data.icache.alias_mask; if (vma->vm_flags & VM_EXEC) { /* * Evict entries from the portion of the cache from which code @@ -449,7 +464,7 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, * If cache is only 4k-per-way, there are never any 'aliases'. Since * the cache is physically tagged, the data can just be left in there. */ - if (current_cpu_data.dcache.n_aliases == 0) + if (boot_cpu_data.dcache.n_aliases == 0) return; /* @@ -510,7 +525,7 @@ static void __flush_cache_4096(unsigned long addr, unsigned long phys, unsigned long a, ea, p; unsigned long temp_pc; - dcache = ¤t_cpu_data.dcache; + dcache = &boot_cpu_data.dcache; /* Write this way for better assembly. */ way_count = dcache->ways; way_incr = dcache->way_incr; @@ -585,7 +600,7 @@ static void __flush_dcache_segment_1way(unsigned long start, base_addr = ((base_addr >> 16) << 16); base_addr |= start; - dcache = ¤t_cpu_data.dcache; + dcache = &boot_cpu_data.dcache; linesz = dcache->linesz; way_incr = dcache->way_incr; way_size = dcache->way_size; @@ -627,7 +642,7 @@ static void __flush_dcache_segment_2way(unsigned long start, base_addr = ((base_addr >> 16) << 16); base_addr |= start; - dcache = ¤t_cpu_data.dcache; + dcache = &boot_cpu_data.dcache; linesz = dcache->linesz; way_incr = dcache->way_incr; way_size = dcache->way_size; @@ -686,7 +701,7 @@ static void __flush_dcache_segment_4way(unsigned long start, base_addr = ((base_addr >> 16) << 16); base_addr |= start; - dcache = ¤t_cpu_data.dcache; + dcache = &boot_cpu_data.dcache; linesz = dcache->linesz; way_incr = dcache->way_incr; way_size = dcache->way_size; diff --git a/arch/sh/mm/copy_page.S b/arch/sh/mm/copy_page.S index ae039f2da16..a81dbdb0559 100644 --- a/arch/sh/mm/copy_page.S +++ b/arch/sh/mm/copy_page.S @@ -141,47 +141,38 @@ ENTRY(__copy_user_page) .long 9999b, 6000f ; \ .previous ENTRY(__copy_user) - tst r6,r6 ! Check explicitly for zero - bf 1f - rts - mov #0,r0 ! normal return -1: - mov.l r10,@-r15 - mov.l r9,@-r15 - mov.l r8,@-r15 + ! Check if small number of bytes + mov #11,r0 mov r4,r3 - add r6,r3 ! last destination address - mov #12,r0 ! Check if small number of bytes - cmp/gt r0,r6 - bt 2f - bra .L_cleanup_loop - nop -2: - neg r5,r0 ! Calculate bytes needed to align source + cmp/gt r0,r6 ! r6 (len) > r0 (11) + bf/s .L_cleanup_loop_no_pop + add r6,r3 ! last destination address + + ! Calculate bytes needed to align to src + mov.l r11,@-r15 + neg r5,r0 + mov.l r10,@-r15 add #4,r0 + mov.l r9,@-r15 and #3,r0 + mov.l r8,@-r15 tst r0,r0 - bt .L_jump - mov r0,r1 + bt 2f -.L_loop1: - ! Copy bytes to align source -EX( mov.b @r5+,r0 ) - dt r1 -EX( mov.b r0,@r4 ) +1: + ! Copy bytes to long word align src +EX( mov.b @r5+,r1 ) + dt r0 add #-1,r6 - bf/s .L_loop1 +EX( mov.b r1,@r4 ) + bf/s 1b add #1,r4 -.L_jump: - mov r6,r2 ! Calculate number of longwords to copy + ! Jump to appropriate routine depending on dest +2: mov #3,r1 + mov r6, r2 + and r4,r1 shlr2 r2 - tst r2,r2 - bt .L_cleanup - - mov r4,r0 ! Jump to appropriate routine - and #3,r0 - mov r0,r1 shll2 r1 mova .L_jump_tbl,r0 mov.l @(r0,r1),r1 @@ -195,43 +186,97 @@ EX( mov.b r0,@r4 ) .long .L_dest10 .long .L_dest11 +/* + * Come here if there are less than 12 bytes to copy + * + * Keep the branch target close, so the bf/s callee doesn't overflow + * and result in a more expensive branch being inserted. This is the + * fast-path for small copies, the jump via the jump table will hit the + * default slow-path cleanup. -PFM. + */ +.L_cleanup_loop_no_pop: + tst r6,r6 ! Check explicitly for zero + bt 1f + +2: +EX( mov.b @r5+,r0 ) + dt r6 +EX( mov.b r0,@r4 ) + bf/s 2b + add #1,r4 + +1: mov #0,r0 ! normal return +5000: + +# Exception handler: +.section .fixup, "ax" +6000: + mov.l 8000f,r1 + mov r3,r0 + jmp @r1 + sub r4,r0 + .align 2 +8000: .long 5000b + +.previous + rts + nop + ! Destination = 00 .L_dest00: - mov r2,r7 - shlr2 r7 - shlr r7 - tst r7,r7 - mov #7,r0 - bt/s 1f - and r0,r2 - .align 2 + ! Skip the large copy for small transfers + mov #(32+32-4), r0 + cmp/gt r6, r0 ! r0 (60) > r6 (len) + bt 1f + + ! Align dest to a 32 byte boundary + neg r4,r0 + add #0x20, r0 + and #0x1f, r0 + tst r0, r0 + bt 2f + + sub r0, r6 + shlr2 r0 +3: +EX( mov.l @r5+,r1 ) + dt r0 +EX( mov.l r1,@r4 ) + bf/s 3b + add #4,r4 + 2: EX( mov.l @r5+,r0 ) +EX( mov.l @r5+,r1 ) +EX( mov.l @r5+,r2 ) +EX( mov.l @r5+,r7 ) EX( mov.l @r5+,r8 ) EX( mov.l @r5+,r9 ) EX( mov.l @r5+,r10 ) -EX( mov.l r0,@r4 ) -EX( mov.l r8,@(4,r4) ) -EX( mov.l r9,@(8,r4) ) -EX( mov.l r10,@(12,r4) ) -EX( mov.l @r5+,r0 ) -EX( mov.l @r5+,r8 ) -EX( mov.l @r5+,r9 ) -EX( mov.l @r5+,r10 ) - dt r7 -EX( mov.l r0,@(16,r4) ) -EX( mov.l r8,@(20,r4) ) -EX( mov.l r9,@(24,r4) ) -EX( mov.l r10,@(28,r4) ) +EX( mov.l @r5+,r11 ) +EX( movca.l r0,@r4 ) + add #-32, r6 +EX( mov.l r1,@(4,r4) ) + mov #32, r0 +EX( mov.l r2,@(8,r4) ) + cmp/gt r6, r0 ! r0 (32) > r6 (len) +EX( mov.l r7,@(12,r4) ) +EX( mov.l r8,@(16,r4) ) +EX( mov.l r9,@(20,r4) ) +EX( mov.l r10,@(24,r4) ) +EX( mov.l r11,@(28,r4) ) bf/s 2b add #32,r4 - tst r2,r2 + +1: mov r6, r0 + shlr2 r0 + tst r0, r0 bt .L_cleanup 1: -EX( mov.l @r5+,r0 ) - dt r2 -EX( mov.l r0,@r4 ) +EX( mov.l @r5+,r1 ) + dt r0 +EX( mov.l r1,@r4 ) bf/s 1b add #4,r4 @@ -250,7 +295,7 @@ EX( mov.l r0,@r4 ) and r0,r2 2: dt r7 -#ifdef __LITTLE_ENDIAN__ +#ifdef CONFIG_CPU_LITTLE_ENDIAN EX( mov.l @r5+,r0 ) EX( mov.l @r5+,r1 ) EX( mov.l @r5+,r8 ) @@ -320,7 +365,7 @@ EX( mov.w r0,@(2,r4) ) 1: ! Read longword, write two words per iteration EX( mov.l @r5+,r0 ) dt r2 -#ifdef __LITTLE_ENDIAN__ +#ifdef CONFIG_CPU_LITTLE_ENDIAN EX( mov.w r0,@r4 ) shlr16 r0 EX( mov.w r0,@(2,r4) ) @@ -342,7 +387,7 @@ EX( mov.w r0,@r4 ) ! Read longword, write byte, word, byte per iteration EX( mov.l @r5+,r0 ) dt r2 -#ifdef __LITTLE_ENDIAN__ +#ifdef CONFIG_CPU_LITTLE_ENDIAN EX( mov.b r0,@r4 ) shlr8 r0 add #1,r4 @@ -379,6 +424,7 @@ EX( mov.b r0,@r4 ) .L_exit: mov #0,r0 ! normal return + 5000: # Exception handler: @@ -394,5 +440,6 @@ EX( mov.b r0,@r4 ) .previous mov.l @r15+,r8 mov.l @r15+,r9 + mov.l @r15+,r10 rts - mov.l @r15+,r10 + mov.l @r15+,r11 diff --git a/arch/sh/mm/fault-nommu.c b/arch/sh/mm/fault-nommu.c deleted file mode 100644 index c6f5b51ec2c..00000000000 --- a/arch/sh/mm/fault-nommu.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * arch/sh/mm/fault-nommu.c - * - * Copyright (C) 2002 - 2007 Paul Mundt - * - * Based on linux/arch/sh/mm/fault.c: - * Copyright (C) 1999 Niibe Yutaka - * - * Released under the terms of the GNU GPL v2.0. - */ -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/hardirq.h> -#include <linux/kprobes.h> -#include <asm/system.h> -#include <asm/ptrace.h> -#include <asm/kgdb.h> - -/* - * This routine handles page faults. It determines the address, - * and the problem, and then passes it off to one of the appropriate - * routines. - */ -asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, - unsigned long writeaccess, - unsigned long address) -{ - trace_hardirqs_on(); - local_irq_enable(); - -#if defined(CONFIG_SH_KGDB) - if (kgdb_nofault && kgdb_bus_err_hook) - kgdb_bus_err_hook(); -#endif - - /* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - * - */ - if (address < PAGE_SIZE) { - printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - } else { - printk(KERN_ALERT "Unable to handle kernel paging request"); - } - - printk(" at virtual address %08lx\n", address); - printk(KERN_ALERT "pc = %08lx\n", regs->pc); - - die("Oops", regs, writeaccess); - do_exit(SIGKILL); -} - -asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs, - unsigned long writeaccess, - unsigned long address) -{ -#if defined(CONFIG_SH_KGDB) - if (kgdb_nofault && kgdb_bus_err_hook) - kgdb_bus_err_hook(); -#endif - - return (address >= TASK_SIZE); -} diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index a08a4a958ad..7d43758dc24 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c @@ -145,7 +145,7 @@ repeat: ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos)); -#ifdef CONFIG_SH_WRITETHROUGH +#ifdef CONFIG_CACHE_WRITETHROUGH /* * When we are in 32-bit address extended mode, CCR.CB becomes * invalid, so care must be taken to manually adjust cacheable diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index f74cf667c8f..2d1dd604430 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c @@ -4,27 +4,14 @@ * SH-4 specific TLB operations * * Copyright (C) 1999 Niibe Yutaka - * Copyright (C) 2002 Paul Mundt + * Copyright (C) 2002 - 2007 Paul Mundt * * Released under the terms of the GNU GPL v2.0. */ -#include <linux/signal.h> -#include <linux/sched.h> #include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/ptrace.h> -#include <linux/mman.h> #include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/interrupt.h> - +#include <linux/io.h> #include <asm/system.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/pgalloc.h> #include <asm/mmu_context.h> #include <asm/cacheflush.h> @@ -34,22 +21,27 @@ void update_mmu_cache(struct vm_area_struct * vma, unsigned long flags; unsigned long pteval; unsigned long vpn; - struct page *page; - unsigned long pfn; /* Ptrace may call this routine. */ if (vma && current->active_mm != vma->vm_mm) return; - pfn = pte_pfn(pte); - if (pfn_valid(pfn)) { - page = pfn_to_page(pfn); - if (!test_bit(PG_mapped, &page->flags)) { - unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; - __flush_wback_region((void *)P1SEGADDR(phys), PAGE_SIZE); - __set_bit(PG_mapped, &page->flags); +#ifndef CONFIG_CACHE_OFF + { + unsigned long pfn = pte_pfn(pte); + + if (pfn_valid(pfn)) { + struct page *page = pfn_to_page(pfn); + + if (!test_bit(PG_mapped, &page->flags)) { + unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; + __flush_wback_region((void *)P1SEGADDR(phys), + PAGE_SIZE); + __set_bit(PG_mapped, &page->flags); + } } } +#endif local_irq_save(flags); @@ -57,16 +49,26 @@ void update_mmu_cache(struct vm_area_struct * vma, vpn = (address & MMU_VPN_MASK) | get_asid(); ctrl_outl(vpn, MMU_PTEH); - pteval = pte_val(pte); + pteval = pte.pte_low; /* Set PTEA register */ +#ifdef CONFIG_X2TLB + /* + * For the extended mode TLB this is trivial, only the ESZ and + * EPR bits need to be written out to PTEA, with the remainder of + * the protection bits (with the exception of the compat-mode SZ + * and PR bits, which are cleared) being written out in PTEL. + */ + ctrl_outl(pte.pte_high, MMU_PTEA); +#else if (cpu_data->flags & CPU_HAS_PTEA) /* TODO: make this look less hacky */ ctrl_outl(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA); +#endif /* Set PTEL register */ pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ -#ifdef CONFIG_SH_WRITETHROUGH +#ifdef CONFIG_CACHE_WRITETHROUGH pteval |= _PAGE_WT; #endif /* conveniently, we want all the software flags to be 0 anyway */ @@ -93,4 +95,3 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page) ctrl_outl(data, addr); back_to_P1(); } - diff --git a/arch/sh64/Kconfig b/arch/sh64/Kconfig index 5664631d8ae..b3327ce8e82 100644 --- a/arch/sh64/Kconfig +++ b/arch/sh64/Kconfig @@ -36,6 +36,14 @@ config GENERIC_CALIBRATE_DELAY bool default y +config GENERIC_HARDIRQS + bool + default y + +config GENERIC_IRQ_PROBE + bool + default y + config RWSEM_XCHGADD_ALGORITHM bool @@ -58,18 +66,12 @@ choice prompt "SuperH system type" default SH_SIMULATOR -config SH_GENERIC - bool "Generic" - config SH_SIMULATOR bool "Simulator" config SH_CAYMAN bool "Cayman" -config SH_ROMRAM - bool "ROM/RAM" - config SH_HARP bool "ST50-Harp" @@ -152,60 +154,54 @@ comment "Memory options" config CACHED_MEMORY_OFFSET hex "Cached Area Offset" - depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR default "20000000" config MEMORY_START hex "Physical memory start address" - depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR default "80000000" config MEMORY_SIZE_IN_MB - int "Memory size (in MB)" if SH_HARP || SH_CAYMAN || SH_SIMULATOR - default "64" if SH_HARP || SH_CAYMAN + int "Memory size (in MB)" default "8" if SH_SIMULATOR + default "64" comment "Cache options" -config DCACHE_DISABLED - bool "DCache Disabling" - depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR - choice prompt "DCache mode" - depends on !DCACHE_DISABLED && !SH_SIMULATOR + default DCACHE_DISABLED if SH_SIMULATOR default DCACHE_WRITE_BACK config DCACHE_WRITE_BACK bool "Write-back" + depends on !SH_SIMULATOR config DCACHE_WRITE_THROUGH bool "Write-through" + depends on !SH_SIMULATOR + +config DCACHE_DISABLED + bool "Disabled" endchoice config ICACHE_DISABLED bool "ICache Disabling" - depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR config PCIDEVICE_MEMORY_START hex - depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR default "C0000000" config DEVICE_MEMORY_START hex - depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR default "E0000000" config FLASH_MEMORY_START hex "Flash memory/on-chip devices start address" - depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR default "00000000" config PCI_BLOCK_START hex "PCI block start address" - depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR default "40000000" comment "CPU Subtype specific options" @@ -214,8 +210,10 @@ config SH64_ID2815_WORKAROUND bool "Include workaround for SH5-101 cut2 silicon defect ID2815" comment "Misc options" + config HEARTBEAT bool "Heartbeat LED" + depends on SH_CAYMAN config HDSP253_LED bool "Support for HDSP-253 LED" @@ -242,6 +240,7 @@ config SBUS config PCI bool "PCI support" + depends on SH_CAYMAN help Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside @@ -294,15 +293,3 @@ source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - -# -# Use the generic interrupt handling code in kernel/irq/: -# -config GENERIC_HARDIRQS - bool - default y - -config GENERIC_IRQ_PROBE - bool - default y - diff --git a/arch/sh64/Kconfig.debug b/arch/sh64/Kconfig.debug index 26d842c0713..05c07c4e4ed 100644 --- a/arch/sh64/Kconfig.debug +++ b/arch/sh64/Kconfig.debug @@ -5,9 +5,6 @@ source "lib/Kconfig.debug" config EARLY_PRINTK bool "Early SCIF console support" -config DEBUG_KERNEL_WITH_GDB_STUB - bool "GDB Stub kernel debug" - config SH64_PROC_TLB bool "Debug: report TLB fill/purge activity through /proc/tlb" depends on PROC_FS @@ -28,17 +25,9 @@ config POOR_MANS_STRACE config SH_ALPHANUMERIC bool "Enable debug outputs to on-board alphanumeric display" + depends on SH_CAYMAN config SH_NO_BSS_INIT bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)" -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - default y if KGDB - help - If you say Y here the resulting kernel image will be slightly larger - and slower, but it will give very useful debugging information. - If you don't debug the kernel, you can say N, but we may not be able - to solve problems without frame pointers. - endmenu diff --git a/arch/sh64/Makefile b/arch/sh64/Makefile index ebf20043991..8290c6380d7 100644 --- a/arch/sh64/Makefile +++ b/arch/sh64/Makefile @@ -40,6 +40,8 @@ OBJCOPYFLAGS := -O binary -R .note -R .comment -R .stab -R .stabstr -S # KBUILD_DEFCONFIG := cayman_defconfig +KBUILD_IMAGE := arch/$(ARCH)/boot/zImage + ifdef LOADADDR LINKFLAGS += -Ttext $(word 1,$(LOADADDR)) endif @@ -47,7 +49,6 @@ endif machine-$(CONFIG_SH_CAYMAN) := cayman machine-$(CONFIG_SH_SIMULATOR) := sim machine-$(CONFIG_SH_HARP) := harp -machine-$(CONFIG_SH_ROMRAM) := romram head-y := arch/$(ARCH)/kernel/head.o arch/$(ARCH)/kernel/init_task.o @@ -106,6 +107,5 @@ arch/$(ARCH)/lib/syscalltab.h: arch/sh64/kernel/syscalls.S CLEAN_FILES += arch/$(ARCH)/lib/syscalltab.h define archhelp - @echo ' zImage - Compressed kernel image (arch/sh64/boot/zImage)' + @echo '* zImage - Compressed kernel image' endef - diff --git a/arch/sh64/configs/cayman_defconfig b/arch/sh64/configs/cayman_defconfig index 78443414334..91b59118c1b 100644 --- a/arch/sh64/configs/cayman_defconfig +++ b/arch/sh64/configs/cayman_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.22 -# Fri Jul 20 12:28:34 2007 +# Linux kernel version: 2.6.23-rc8 +# Tue Oct 9 15:37:16 2007 # CONFIG_SUPERH=y CONFIG_SUPERH64=y @@ -11,21 +11,20 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # -# Code maturity level options +# General setup # CONFIG_EXPERIMENTAL=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y @@ -57,7 +56,6 @@ CONFIG_FUTEX=y CONFIG_ANON_INODES=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y -CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_VM_EVENT_COUNTERS=y @@ -67,7 +65,12 @@ CONFIG_SLAB=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 -# CONFIG_MODULES is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y CONFIG_BLOCK=y # CONFIG_LBD is not set # CONFIG_BLK_DEV_IO_TRACE is not set @@ -90,10 +93,8 @@ CONFIG_DEFAULT_IOSCHED="cfq" # # System type # -# CONFIG_SH_GENERIC is not set # CONFIG_SH_SIMULATOR is not set CONFIG_SH_CAYMAN=y -# CONFIG_SH_ROMRAM is not set # CONFIG_SH_HARP is not set CONFIG_CPU_SH5=y CONFIG_CPU_SUBTYPE_SH5_101=y @@ -119,9 +120,9 @@ CONFIG_MEMORY_SIZE_IN_MB=128 # # Cache options # -# CONFIG_DCACHE_DISABLED is not set CONFIG_DCACHE_WRITE_BACK=y # CONFIG_DCACHE_WRITE_THROUGH is not set +# CONFIG_DCACHE_DISABLED is not set # CONFIG_ICACHE_DISABLED is not set CONFIG_PCIDEVICE_MEMORY_START=C0000000 CONFIG_DEVICE_MEMORY_START=E0000000 @@ -151,7 +152,6 @@ CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_RESOURCES_64BIT is not set CONFIG_ZONE_DMA_FLAG=0 CONFIG_NR_QUICK=1 -CONFIG_VIRT_TO_BUS=y # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) @@ -276,7 +276,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_MTD is not set # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y -# CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_UMEM is not set @@ -325,6 +324,7 @@ CONFIG_SCSI_MULTI_LUN=y # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set # CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m # # SCSI Transports @@ -332,12 +332,8 @@ CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set -# CONFIG_SCSI_SAS_ATTRS is not set # CONFIG_SCSI_SAS_LIBSAS is not set - -# -# SCSI low-level drivers -# +CONFIG_SCSI_LOWLEVEL=y # CONFIG_ISCSI_TCP is not set # CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_3W_9XXX is not set @@ -347,7 +343,6 @@ CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_AIC94XX is not set -# CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ARCMSR is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set @@ -449,6 +444,7 @@ CONFIG_NETDEV_1000=y # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set @@ -572,7 +568,6 @@ CONFIG_WATCHDOG=y # Watchdog Device Drivers # # CONFIG_SOFT_WATCHDOG is not set -# CONFIG_SH_WDT is not set # # PCI-based Watchdog Cards @@ -586,7 +581,59 @@ CONFIG_HW_RANDOM=y # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set CONFIG_DEVPORT=y -# CONFIG_I2C is not set +CONFIG_I2C=m +CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_CHARDEV is not set + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_DS1682 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set # # SPI support @@ -599,16 +646,51 @@ CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set # CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set # CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6650 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_DME1737 is not set # CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set # CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_THMC50 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_VT1211 is not set # CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set # CONFIG_HWMON_DEBUG_CHIP is not set @@ -621,8 +703,115 @@ CONFIG_HWMON=y # # Multimedia devices # -# CONFIG_VIDEO_DEV is not set -# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_DEV=m +# CONFIG_VIDEO_V4L1 is not set +# CONFIG_VIDEO_V4L1_COMPAT is not set +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +# CONFIG_VIDEO_VIVI is not set +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_TEA5761 is not set +# CONFIG_VIDEO_SAA7134 is not set +# CONFIG_VIDEO_HEXIUM_ORION is not set +# CONFIG_VIDEO_HEXIUM_GEMINI is not set +# CONFIG_VIDEO_CX88 is not set +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_RADIO_ADAPTERS is not set +CONFIG_DVB_CORE=y +# CONFIG_DVB_CORE_ATTACH is not set +CONFIG_DVB_CAPTURE_DRIVERS=y + +# +# Supported SAA7146 based PCI Adapters +# + +# +# Supported FlexCopII (B2C2) Adapters +# +# CONFIG_DVB_B2C2_FLEXCOP is not set + +# +# Supported BT878 Adapters +# + +# +# Supported Pluto2 Adapters +# +# CONFIG_DVB_PLUTO2 is not set + +# +# Supported DVB Frontends +# + +# +# Customise DVB Frontends +# +# CONFIG_DVB_FE_CUSTOMISE is not set + +# +# DVB-S (satellite) frontends +# +# CONFIG_DVB_STV0299 is not set +# CONFIG_DVB_CX24110 is not set +# CONFIG_DVB_CX24123 is not set +# CONFIG_DVB_TDA8083 is not set +# CONFIG_DVB_MT312 is not set +# CONFIG_DVB_VES1X93 is not set +# CONFIG_DVB_S5H1420 is not set +# CONFIG_DVB_TDA10086 is not set + +# +# DVB-T (terrestrial) frontends +# +# CONFIG_DVB_SP8870 is not set +# CONFIG_DVB_SP887X is not set +# CONFIG_DVB_CX22700 is not set +# CONFIG_DVB_CX22702 is not set +# CONFIG_DVB_L64781 is not set +# CONFIG_DVB_TDA1004X is not set +# CONFIG_DVB_NXT6000 is not set +# CONFIG_DVB_MT352 is not set +# CONFIG_DVB_ZL10353 is not set +# CONFIG_DVB_DIB3000MB is not set +# CONFIG_DVB_DIB3000MC is not set +# CONFIG_DVB_DIB7000M is not set +# CONFIG_DVB_DIB7000P is not set + +# +# DVB-C (cable) frontends +# +# CONFIG_DVB_VES1820 is not set +# CONFIG_DVB_TDA10021 is not set +# CONFIG_DVB_TDA10023 is not set +# CONFIG_DVB_STV0297 is not set + +# +# ATSC (North American/Korean Terrestrial/Cable DTV) frontends +# +# CONFIG_DVB_NXT200X is not set +# CONFIG_DVB_OR51211 is not set +# CONFIG_DVB_OR51132 is not set +# CONFIG_DVB_BCM3510 is not set +# CONFIG_DVB_LGDT330X is not set + +# +# Tuners/PLL support +# +# CONFIG_DVB_PLL is not set +# CONFIG_DVB_TDA826X is not set +# CONFIG_DVB_TDA827X is not set +# CONFIG_DVB_TUNER_QT1010 is not set +# CONFIG_DVB_TUNER_MT2060 is not set + +# +# Miscellaneous devices +# +# CONFIG_DVB_LNBP21 is not set +# CONFIG_DVB_ISL6421 is not set +# CONFIG_DVB_TUA6100 is not set CONFIG_DAB=y # @@ -635,6 +824,7 @@ CONFIG_DAB=y # # CONFIG_DISPLAY_SUPPORT is not set # CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_FB=y CONFIG_FIRMWARE_EDID=y # CONFIG_FB_DDC is not set @@ -728,24 +918,8 @@ CONFIG_USB_ARCH_HAS_EHCI=y # # CONFIG_USB_GADGET is not set # CONFIG_MMC is not set - -# -# LED devices -# # CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# # CONFIG_INFINIBAND is not set - -# -# Real Time Clock -# # CONFIG_RTC_CLASS is not set # @@ -929,9 +1103,9 @@ CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_LIST is not set CONFIG_FRAME_POINTER=y CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set # CONFIG_FAULT_INJECTION is not set # CONFIG_EARLY_PRINTK is not set -# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set CONFIG_SH64_PROC_TLB=y CONFIG_SH64_PROC_ASIDS=y CONFIG_SH64_SR_WATCH=y @@ -960,5 +1134,3 @@ CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y -CONFIG_GENERIC_HARDIRQS=y -CONFIG_GENERIC_IRQ_PROBE=y diff --git a/arch/sh64/configs/harp_defconfig b/arch/sh64/configs/harp_defconfig new file mode 100644 index 00000000000..e4b84b51baf --- /dev/null +++ b/arch/sh64/configs/harp_defconfig @@ -0,0 +1,756 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc8 +# Mon Oct 1 18:01:38 2007 +# +CONFIG_SUPERH=y +CONFIG_SUPERH64=y +CONFIG_MMU=y +CONFIG_QUICKLIST=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +# CONFIG_SYSVIPC is not set +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# +# System type +# +# CONFIG_SH_SIMULATOR is not set +# CONFIG_SH_CAYMAN is not set +CONFIG_SH_HARP=y +CONFIG_CPU_SH5=y +CONFIG_CPU_SUBTYPE_SH5_101=y +# CONFIG_CPU_SUBTYPE_SH5_103 is not set +CONFIG_LITTLE_ENDIAN=y +# CONFIG_BIG_ENDIAN is not set +CONFIG_SH_FPU=y +# CONFIG_SH64_FPU_DENORM_FLUSH is not set +CONFIG_SH64_PGTABLE_2_LEVEL=y +# CONFIG_SH64_PGTABLE_3_LEVEL is not set +CONFIG_HUGETLB_PAGE_SIZE_64K=y +# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set +CONFIG_SH64_USER_MISALIGNED_FIXUP=y + +# +# Memory options +# +CONFIG_CACHED_MEMORY_OFFSET=0x20000000 +CONFIG_MEMORY_START=0x80000000 +CONFIG_MEMORY_SIZE_IN_MB=128 + +# +# Cache options +# +CONFIG_DCACHE_WRITE_BACK=y +# CONFIG_DCACHE_WRITE_THROUGH is not set +# CONFIG_DCACHE_DISABLED is not set +# CONFIG_ICACHE_DISABLED is not set +CONFIG_PCIDEVICE_MEMORY_START=C0000000 +CONFIG_DEVICE_MEMORY_START=E0000000 +CONFIG_FLASH_MEMORY_START=0x00000000 +CONFIG_PCI_BLOCK_START=0x40000000 + +# +# CPU Subtype specific options +# +CONFIG_SH64_ID2815_WORKAROUND=y + +# +# Misc options +# +# CONFIG_SH_DMA is not set +CONFIG_PREEMPT=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_NR_QUICK=1 + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_ARCH_SUPPORTS_MSI is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set +# CONFIG_STNIC is not set +# CONFIG_SMC91X is not set +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=2 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB_DDC is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_SYS_FOPS is not set +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +# CONFIG_LOGO_LINUX_CLUT224 is not set +# CONFIG_LOGO_SUPERH_MONO is not set +# CONFIG_LOGO_SUPERH_VGA16 is not set +CONFIG_LOGO_SUPERH_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_MINIX_FS=y +CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +CONFIG_SCHEDSTATS=y +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FRAME_POINTER=y +CONFIG_FORCED_INLINING=y +# CONFIG_FAULT_INJECTION is not set +# CONFIG_EARLY_PRINTK is not set +# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set +CONFIG_SH64_PROC_TLB=y +CONFIG_SH64_PROC_ASIDS=y +CONFIG_SH64_SR_WATCH=y +# CONFIG_POOR_MANS_STRACE is not set +# CONFIG_SH_ALPHANUMERIC is not set +# CONFIG_SH_NO_BSS_INIT is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/sh64/configs/sim_defconfig b/arch/sh64/configs/sim_defconfig new file mode 100644 index 00000000000..f83bae659dc --- /dev/null +++ b/arch/sh64/configs/sim_defconfig @@ -0,0 +1,566 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc8 +# Mon Oct 1 17:50:35 2007 +# +CONFIG_SUPERH=y +CONFIG_SUPERH64=y +CONFIG_MMU=y +CONFIG_QUICKLIST=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_USER_NS is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# +# System type +# +CONFIG_SH_SIMULATOR=y +# CONFIG_SH_CAYMAN is not set +# CONFIG_SH_HARP is not set +CONFIG_CPU_SH5=y +CONFIG_CPU_SUBTYPE_SH5_101=y +# CONFIG_CPU_SUBTYPE_SH5_103 is not set +CONFIG_LITTLE_ENDIAN=y +# CONFIG_BIG_ENDIAN is not set +CONFIG_SH_FPU=y +# CONFIG_SH64_FPU_DENORM_FLUSH is not set +CONFIG_SH64_PGTABLE_2_LEVEL=y +# CONFIG_SH64_PGTABLE_3_LEVEL is not set +CONFIG_HUGETLB_PAGE_SIZE_64K=y +# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set +CONFIG_SH64_USER_MISALIGNED_FIXUP=y + +# +# Memory options +# +CONFIG_CACHED_MEMORY_OFFSET=0x20000000 +CONFIG_MEMORY_START=0x80000000 +CONFIG_MEMORY_SIZE_IN_MB=128 + +# +# Cache options +# +# CONFIG_DCACHE_WRITE_BACK is not set +# CONFIG_DCACHE_WRITE_THROUGH is not set +CONFIG_DCACHE_DISABLED=y +# CONFIG_ICACHE_DISABLED is not set +CONFIG_PCIDEVICE_MEMORY_START=C0000000 +CONFIG_DEVICE_MEMORY_START=E0000000 +CONFIG_FLASH_MEMORY_START=0x00000000 +CONFIG_PCI_BLOCK_START=0x40000000 + +# +# CPU Subtype specific options +# +CONFIG_SH64_ID2815_WORKAROUND=y + +# +# Misc options +# +# CONFIG_SH_DMA is not set +CONFIG_PREEMPT=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_NR_QUICK=1 + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_ARCH_SUPPORTS_MSI is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Networking +# +# CONFIG_NET is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +# CONFIG_BLK_DEV is not set +# CONFIG_MISC_DEVICES is not set +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_SCSI_DEBUG is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=2 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB_DDC is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_SYS_FOPS is not set +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +# CONFIG_LOGO_LINUX_CLUT224 is not set +# CONFIG_LOGO_SUPERH_MONO is not set +# CONFIG_LOGO_SUPERH_VGA16 is not set +CONFIG_LOGO_SUPERH_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +CONFIG_MINIX_FS=y +CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +CONFIG_PROFILING=y +# CONFIG_OPROFILE is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +CONFIG_SCHEDSTATS=y +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FRAME_POINTER=y +CONFIG_FORCED_INLINING=y +# CONFIG_FAULT_INJECTION is not set +# CONFIG_EARLY_PRINTK is not set +# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set +CONFIG_SH64_PROC_TLB=y +CONFIG_SH64_PROC_ASIDS=y +CONFIG_SH64_SR_WATCH=y +# CONFIG_POOR_MANS_STRACE is not set +# CONFIG_SH_ALPHANUMERIC is not set +CONFIG_SH_NO_BSS_INIT=y + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/sh64/kernel/Makefile b/arch/sh64/kernel/Makefile index 5816657c079..e3467bda616 100644 --- a/arch/sh64/kernel/Makefile +++ b/arch/sh64/kernel/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_SH_DMA) += dma.o obj-$(CONFIG_SH_FPU) += fpu.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_KALLSYMS) += unwind.o -obj-$(CONFIG_PCI) += pci-dma.o pcibios.o +obj-$(CONFIG_PCI) += pcibios.o obj-$(CONFIG_MODULES) += module.o ifeq ($(CONFIG_PCI),y) diff --git a/arch/sh64/kernel/alphanum.c b/arch/sh64/kernel/alphanum.c index 91707c1acd7..d1619d95fba 100644 --- a/arch/sh64/kernel/alphanum.c +++ b/arch/sh64/kernel/alphanum.c @@ -13,7 +13,6 @@ #include <linux/sched.h> void mach_alphanum(int pos, unsigned char val); -void mach_led(int pos, int val); void print_seg(char *file, int line) { diff --git a/arch/sh64/kernel/sh_ksyms.c b/arch/sh64/kernel/sh_ksyms.c index 461ea3de316..b1705acc8e6 100644 --- a/arch/sh64/kernel/sh_ksyms.c +++ b/arch/sh64/kernel/sh_ksyms.c @@ -31,16 +31,11 @@ extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); /* platform dependent support */ EXPORT_SYMBOL(dump_fpu); -EXPORT_SYMBOL(iounmap); -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(kernel_thread); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy_nocheck); -EXPORT_SYMBOL(strstr); - #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); #endif @@ -50,27 +45,18 @@ EXPORT_SYMBOL(__down_trylock); EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__put_user_asm_l); EXPORT_SYMBOL(__get_user_asm_l); -EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(__copy_user); EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memscan); -EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strlen); - +EXPORT_SYMBOL(udelay); +EXPORT_SYMBOL(__udelay); +EXPORT_SYMBOL(ndelay); +EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(flush_dcache_page); - -/* For ext3 */ EXPORT_SYMBOL(sh64_page_clear); /* Ugh. These come in from libgcc.a at link time. */ +#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name) -extern void __sdivsi3(void); -extern void __muldi3(void); -extern void __udivsi3(void); -extern char __div_table; -EXPORT_SYMBOL(__sdivsi3); -EXPORT_SYMBOL(__muldi3); -EXPORT_SYMBOL(__udivsi3); -EXPORT_SYMBOL(__div_table); - - +DECLARE_EXPORT(__sdivsi3); +DECLARE_EXPORT(__muldi3); +DECLARE_EXPORT(__udivsi3); diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c index b37f4f4981d..06f3c179e34 100644 --- a/arch/sh64/kernel/time.c +++ b/arch/sh64/kernel/time.c @@ -476,8 +476,18 @@ static irqreturn_t sh64_rtc_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction irq0 = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL}; -static struct irqaction irq1 = { sh64_rtc_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "rtc", NULL, NULL}; +static struct irqaction irq0 = { + .handler = timer_interrupt, + .flags = IRQF_DISABLED, + .mask = CPU_MASK_NONE, + .name = "timer", +}; +static struct irqaction irq1 = { + .handler = sh64_rtc_interrupt, + .flags = IRQF_DISABLED, + .mask = CPU_MASK_NONE, + .name = "rtc", +}; void __init time_init(void) { diff --git a/arch/sh64/kernel/vmlinux.lds.S b/arch/sh64/kernel/vmlinux.lds.S index 267b4f9af2e..f533a064da5 100644 --- a/arch/sh64/kernel/vmlinux.lds.S +++ b/arch/sh64/kernel/vmlinux.lds.S @@ -30,14 +30,6 @@ #define LOAD_OFFSET CONFIG_CACHED_MEMORY_OFFSET #include <asm-generic/vmlinux.lds.h> -#ifdef NOTDEF -#ifdef CONFIG_LITTLE_ENDIAN -OUTPUT_FORMAT("elf32-sh64l-linux", "elf32-sh64l-linux", "elf32-sh64l-linux") -#else -OUTPUT_FORMAT("elf32-sh64", "elf32-sh64", "elf32-sh64") -#endif -#endif - OUTPUT_ARCH(sh:sh5) #define C_PHYS(x) AT (ADDR(x) - LOAD_OFFSET) @@ -74,10 +66,12 @@ SECTIONS __ex_table : C_PHYS(__ex_table) { *(__ex_table) } __stop___ex_table = .; - RODATA - _etext = .; /* End of text section */ + NOTES + + RODATA + .data : C_PHYS(.data) { /* Data */ DATA_DATA CONSTRUCTORS @@ -86,13 +80,9 @@ SECTIONS . = ALIGN(PAGE_SIZE); .data.page_aligned : C_PHYS(.data.page_aligned) { *(.data.page_aligned) } - . = ALIGN(PAGE_SIZE); - __per_cpu_start = .; - .data.percpu : C_PHYS(.data.percpu) { - *(.data.percpu) - *(.data.percpu.shared_aligned) - } - __per_cpu_end = . ; + PERCPU(PAGE_SIZE) + + . = ALIGN(L1_CACHE_BYTES); .data.cacheline_aligned : C_PHYS(.data.cacheline_aligned) { *(.data.cacheline_aligned) } _edata = .; /* End of data section */ @@ -145,38 +135,6 @@ SECTIONS *(.exitcall.exit) } - /* Stabs debugging sections. */ - .stab 0 : C_PHYS(.stab) { *(.stab) } - .stabstr 0 : C_PHYS(.stabstr) { *(.stabstr) } - .stab.excl 0 : C_PHYS(.stab.excl) { *(.stab.excl) } - .stab.exclstr 0 : C_PHYS(.stab.exclstr) { *(.stab.exclstr) } - .stab.index 0 : C_PHYS(.stab.index) { *(.stab.index) } - .stab.indexstr 0 : C_PHYS(.stab.indexstr) { *(.stab.indexstr) } - .comment 0 : C_PHYS(.comment) { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging section are relative to the beginning - of the section so we begin .debug at 0. */ - /* DWARF 1 */ - .debug 0 : C_PHYS(.debug) { *(.debug) } - .line 0 : C_PHYS(.line) { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : C_PHYS(.debug_srcinfo) { *(.debug_srcinfo) } - .debug_sfnames 0 : C_PHYS(.debug_sfnames) { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : C_PHYS(.debug_aranges) { *(.debug_aranges) } - .debug_pubnames 0 : C_PHYS(.debug_pubnames) { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : C_PHYS(.debug_info) { *(.debug_info) } - .debug_abbrev 0 : C_PHYS(.debug_abbrev) { *(.debug_abbrev) } - .debug_line 0 : C_PHYS(.debug_line) { *(.debug_line) } - .debug_frame 0 : C_PHYS(.debug_frame) { *(.debug_frame) } - .debug_str 0 : C_PHYS(.debug_str) { *(.debug_str) } - .debug_loc 0 : C_PHYS(.debug_loc) { *(.debug_loc) } - .debug_macinfo 0 : C_PHYS(.debug_macinfo) { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : C_PHYS(.debug_weaknames) { *(.debug_weaknames) } - .debug_funcnames 0 : C_PHYS(.debug_funcnames) { *(.debug_funcnames) } - .debug_typenames 0 : C_PHYS(.debug_typenames) { *(.debug_typenames) } - .debug_varnames 0 : C_PHYS(.debug_varnames) { *(.debug_varnames) } - /* These must appear regardless of . */ + STABS_DEBUG + DWARF_DEBUG } diff --git a/arch/sh64/lib/c-checksum.c b/arch/sh64/lib/c-checksum.c index bd550176024..053137abd8a 100644 --- a/arch/sh64/lib/c-checksum.c +++ b/arch/sh64/lib/c-checksum.c @@ -10,6 +10,7 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/kernel.h> +#include <linux/module.h> #include <asm/byteorder.h> #include <asm/uaccess.h> @@ -110,7 +111,7 @@ static unsigned long do_csum(const unsigned char *buff, int len) if (odd) result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); - pr_debug("\nCHECKSUM is 0x%x\n", result); + pr_debug("\nCHECKSUM is 0x%lx\n", result); out: return result; diff --git a/arch/sh64/lib/io.c b/arch/sh64/lib/io.c index 587baa3dffb..a3f3a2b8e25 100644 --- a/arch/sh64/lib/io.c +++ b/arch/sh64/lib/io.c @@ -11,30 +11,11 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/delay.h> +#include <linux/module.h> #include <asm/system.h> #include <asm/processor.h> #include <asm/io.h> -/* - * readX/writeX() are used to access memory mapped devices. On some - * architectures the memory mapped IO stuff needs to be accessed - * differently. On the SuperH architecture, we just read/write the - * memory location directly. - */ - -/* This is horrible at the moment - needs more work to do something sensible */ -#define IO_DELAY() - -#define OUT_DELAY(x,type) \ -void out##x##_p(unsigned type value,unsigned long port){out##x(value,port);IO_DELAY();} - -#define IN_DELAY(x,type) \ -unsigned type in##x##_p(unsigned long port) {unsigned type tmp=in##x(port);IO_DELAY();return tmp;} - -#if 1 -OUT_DELAY(b, long) OUT_DELAY(w, long) OUT_DELAY(l, long) - IN_DELAY(b, long) IN_DELAY(w, long) IN_DELAY(l, long) -#endif /* Now for the string version of these functions */ void outsb(unsigned long port, const void *addr, unsigned long count) { @@ -45,6 +26,7 @@ void outsb(unsigned long port, const void *addr, unsigned long count) outb(*p, port); } } +EXPORT_SYMBOL(outsb); void insb(unsigned long port, void *addr, unsigned long count) { @@ -55,6 +37,7 @@ void insb(unsigned long port, void *addr, unsigned long count) *p = inb(port); } } +EXPORT_SYMBOL(insb); /* For the 16 and 32 bit string functions, we have to worry about alignment. * The SH does not do unaligned accesses, so we have to read as bytes and @@ -74,6 +57,7 @@ void outsw(unsigned long port, const void *addr, unsigned long count) outw(tmp, port); } } +EXPORT_SYMBOL(outsw); void insw(unsigned long port, void *addr, unsigned long count) { @@ -87,6 +71,7 @@ void insw(unsigned long port, void *addr, unsigned long count) p[1] = (tmp >> 8) & 0xff; } } +EXPORT_SYMBOL(insw); void outsl(unsigned long port, const void *addr, unsigned long count) { @@ -100,6 +85,7 @@ void outsl(unsigned long port, const void *addr, unsigned long count) outl(tmp, port); } } +EXPORT_SYMBOL(outsl); void insl(unsigned long port, void *addr, unsigned long count) { @@ -116,6 +102,7 @@ void insl(unsigned long port, void *addr, unsigned long count) } } +EXPORT_SYMBOL(insl); void memcpy_toio(void __iomem *to, const void *from, long count) { @@ -126,6 +113,7 @@ void memcpy_toio(void __iomem *to, const void *from, long count) writeb(*p++, to++); } } +EXPORT_SYMBOL(memcpy_toio); void memcpy_fromio(void *to, void __iomem *from, long count) { @@ -137,3 +125,4 @@ void memcpy_fromio(void *to, void __iomem *from, long count) from++; } } +EXPORT_SYMBOL(memcpy_fromio); diff --git a/arch/sh64/lib/iomap.c b/arch/sh64/lib/iomap.c index 5cd3d5e9c76..253d1e351d4 100644 --- a/arch/sh64/lib/iomap.c +++ b/arch/sh64/lib/iomap.c @@ -17,12 +17,15 @@ ioport_map(unsigned long port, unsigned int len) { return (void __iomem *)port; } +EXPORT_SYMBOL(ioport_map); void ioport_unmap(void __iomem *addr) { /* Nothing .. */ } +EXPORT_SYMBOL(ioport_unmap); +#ifdef CONFIG_PCI void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) { unsigned long start = pci_resource_start(dev, bar); @@ -41,14 +44,11 @@ void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) /* What? */ return NULL; } +EXPORT_SYMBOL(pci_iomap); void pci_iounmap(struct pci_dev *dev, void __iomem *addr) { /* Nothing .. */ } - -EXPORT_SYMBOL(ioport_map); -EXPORT_SYMBOL(ioport_unmap); -EXPORT_SYMBOL(pci_iomap); EXPORT_SYMBOL(pci_iounmap); - +#endif diff --git a/arch/sh64/mach-cayman/setup.c b/arch/sh64/mach-cayman/setup.c index c3611cc2735..726c520d7eb 100644 --- a/arch/sh64/mach-cayman/setup.c +++ b/arch/sh64/mach-cayman/setup.c @@ -18,19 +18,11 @@ * lethal@linux-sh.org: 15th May 2003 * Use the generic procfs cpuinfo interface, just return a valid board name. */ - -#include <linux/stddef.h> #include <linux/init.h> -#include <linux/mm.h> -#include <linux/bootmem.h> -#include <linux/delay.h> #include <linux/kernel.h> -#include <linux/seq_file.h> -#include <asm/processor.h> #include <asm/platform.h> -#include <asm/io.h> #include <asm/irq.h> -#include <asm/page.h> +#include <asm/io.h> /* * Platform Dependent Interrupt Priorities. diff --git a/arch/sh64/mach-harp/Makefile b/arch/sh64/mach-harp/Makefile index 63f065bad2f..2f2963fa213 100644 --- a/arch/sh64/mach-harp/Makefile +++ b/arch/sh64/mach-harp/Makefile @@ -1,14 +1 @@ -# -# Makefile for the ST50 Harp specific parts of the kernel -# -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# - -O_TARGET := harp.o - obj-y := setup.o - -include $(TOPDIR)/Rules.make - diff --git a/arch/sh64/mach-harp/setup.c b/arch/sh64/mach-harp/setup.c index fcd90afac29..05011cb369b 100644 --- a/arch/sh64/mach-harp/setup.c +++ b/arch/sh64/mach-harp/setup.c @@ -17,20 +17,10 @@ * lethal@linux-sh.org: 15th May 2003 * Use the generic procfs cpuinfo interface, just return a valid board name. */ - -#include <linux/stddef.h> #include <linux/init.h> -#include <linux/mm.h> -#include <linux/bootmem.h> -#include <linux/delay.h> #include <linux/kernel.h> -#include <asm/processor.h> #include <asm/platform.h> -#include <asm/io.h> #include <asm/irq.h> -#include <asm/page.h> - -#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource))) /* * Platform Dependent Interrupt Priorities. @@ -78,8 +68,10 @@ struct resource io_resources[] = { }; struct resource kram_resources[] = { - { "Kernel code", 0, 0 }, /* These must be last in the array */ - { "Kernel data", 0, 0 } /* These must be last in the array */ + /* These must be last in the array */ + { .name = "Kernel code", .start = 0, .end = 0 }, + /* These must be last in the array */ + { .name = "Kernel data", .start = 0, .end = 0 } }; struct resource xram_resources[] = { @@ -95,13 +87,13 @@ struct sh64_platform platform_parms = { .initial_root_dev = 0x0100, .loader_type = 1, .io_res_p = io_resources, - .io_res_count = RES_COUNT(io_resources), + .io_res_count = ARRAY_SIZE(io_resources), .kram_res_p = kram_resources, - .kram_res_count = RES_COUNT(kram_resources), + .kram_res_count = ARRAY_SIZE(kram_resources), .xram_res_p = xram_resources, - .xram_res_count = RES_COUNT(xram_resources), + .xram_res_count = ARRAY_SIZE(xram_resources), .rom_res_p = rom_resources, - .rom_res_count = RES_COUNT(rom_resources), + .rom_res_count = ARRAY_SIZE(rom_resources), }; int platform_int_priority[NR_INTC_IRQS] = { @@ -135,4 +127,3 @@ const char *get_system_type(void) { return "ST50 Harp"; } - diff --git a/arch/sh64/mach-romram/Makefile b/arch/sh64/mach-romram/Makefile deleted file mode 100644 index 02d05c05afa..00000000000 --- a/arch/sh64/mach-romram/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# Makefile for the SH-5 ROM/RAM specific parts of the kernel -# -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# - -O_TARGET := romram.o - -obj-y := setup.o - -include $(TOPDIR)/Rules.make - diff --git a/arch/sh64/mach-romram/setup.c b/arch/sh64/mach-romram/setup.c deleted file mode 100644 index eb98a1640cc..00000000000 --- a/arch/sh64/mach-romram/setup.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * arch/sh64/mach-romram/setup.c - * - * SH-5 ROM/RAM Platform Support - * - * This file handles the architecture-dependent parts of initialization - * - * Copyright (C) 2000, 2001 Paolo Alberelli - * - * benedict.gaster@superh.com: 3rd May 2002 - * Added support for ramdisk, removing statically linked romfs at the same time. * - * - * lethal@linux-sh.org: 15th May 2003 - * Use the generic procfs cpuinfo interface, just return a valid board name. - * - * Sean.McGoogan@superh.com 17th Feb 2004 - * copied from arch/sh64/mach-harp/setup.c - */ - -#include <linux/stddef.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/bootmem.h> -#include <linux/delay.h> -#include <linux/kernel.h> -#include <asm/processor.h> -#include <asm/platform.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/page.h> - -#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource))) - -/* - * Platform Dependent Interrupt Priorities. - */ - -/* Using defaults defined in irq.h */ -#define RES NO_PRIORITY /* Disabled */ -#define IR0 IRL0_PRIORITY /* IRLs */ -#define IR1 IRL1_PRIORITY -#define IR2 IRL2_PRIORITY -#define IR3 IRL3_PRIORITY -#define PCA INTA_PRIORITY /* PCI Ints */ -#define PCB INTB_PRIORITY -#define PCC INTC_PRIORITY -#define PCD INTD_PRIORITY -#define SER TOP_PRIORITY -#define ERR TOP_PRIORITY -#define PW0 TOP_PRIORITY -#define PW1 TOP_PRIORITY -#define PW2 TOP_PRIORITY -#define PW3 TOP_PRIORITY -#define DM0 NO_PRIORITY /* DMA Ints */ -#define DM1 NO_PRIORITY -#define DM2 NO_PRIORITY -#define DM3 NO_PRIORITY -#define DAE NO_PRIORITY -#define TU0 TIMER_PRIORITY /* TMU Ints */ -#define TU1 NO_PRIORITY -#define TU2 NO_PRIORITY -#define TI2 NO_PRIORITY -#define ATI NO_PRIORITY /* RTC Ints */ -#define PRI NO_PRIORITY -#define CUI RTC_PRIORITY -#define ERI SCIF_PRIORITY /* SCIF Ints */ -#define RXI SCIF_PRIORITY -#define BRI SCIF_PRIORITY -#define TXI SCIF_PRIORITY -#define ITI TOP_PRIORITY /* WDT Ints */ - -/* - * Platform dependent structures: maps and parms block. - */ -struct resource io_resources[] = { - /* To be updated with external devices */ -}; - -struct resource kram_resources[] = { - { "Kernel code", 0, 0 }, /* These must be last in the array */ - { "Kernel data", 0, 0 } /* These must be last in the array */ -}; - -struct resource xram_resources[] = { - /* To be updated with external devices */ -}; - -struct resource rom_resources[] = { - /* To be updated with external devices */ -}; - -struct sh64_platform platform_parms = { - .readonly_rootfs = 1, - .initial_root_dev = 0x0100, - .loader_type = 1, - .io_res_p = io_resources, - .io_res_count = RES_COUNT(io_resources), - .kram_res_p = kram_resources, - .kram_res_count = RES_COUNT(kram_resources), - .xram_res_p = xram_resources, - .xram_res_count = RES_COUNT(xram_resources), - .rom_res_p = rom_resources, - .rom_res_count = RES_COUNT(rom_resources), -}; - -int platform_int_priority[NR_INTC_IRQS] = { - IR0, IR1, IR2, IR3, PCA, PCB, PCC, PCD, /* IRQ 0- 7 */ - RES, RES, RES, RES, SER, ERR, PW3, PW2, /* IRQ 8-15 */ - PW1, PW0, DM0, DM1, DM2, DM3, DAE, RES, /* IRQ 16-23 */ - RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 24-31 */ - TU0, TU1, TU2, TI2, ATI, PRI, CUI, ERI, /* IRQ 32-39 */ - RXI, BRI, TXI, RES, RES, RES, RES, RES, /* IRQ 40-47 */ - RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 48-55 */ - RES, RES, RES, RES, RES, RES, RES, ITI, /* IRQ 56-63 */ -}; - -void __init platform_setup(void) -{ - /* ROM/RAM platform leaves the decision to head.S, for now */ - platform_parms.fpu_flags = fpu_in_use; -} - -void __init platform_monitor(void) -{ - /* Nothing yet .. */ -} - -void __init platform_reserve(void) -{ - /* Nothing yet .. */ -} - -const char *get_system_type(void) -{ - return "ROM/RAM"; -} - diff --git a/arch/sh64/mach-sim/Makefile b/arch/sh64/mach-sim/Makefile index 819c4078fdc..2f2963fa213 100644 --- a/arch/sh64/mach-sim/Makefile +++ b/arch/sh64/mach-sim/Makefile @@ -1,14 +1 @@ -# -# Makefile for the SH-5 Simulator specific parts of the kernel -# -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# - -O_TARGET := sim.o - obj-y := setup.o - -include $(TOPDIR)/Rules.make - diff --git a/arch/sh64/mach-sim/setup.c b/arch/sh64/mach-sim/setup.c index f09400c1ad1..e3386ec1ce1 100644 --- a/arch/sh64/mach-sim/setup.c +++ b/arch/sh64/mach-sim/setup.c @@ -14,46 +14,10 @@ * lethal@linux-sh.org: 15th May 2003 * Use the generic procfs cpuinfo interface, just return a valid board name. */ - -#include <linux/stddef.h> #include <linux/init.h> -#include <linux/mm.h> -#include <linux/bootmem.h> -#include <linux/delay.h> #include <linux/kernel.h> -#include <asm/addrspace.h> -#include <asm/processor.h> #include <asm/platform.h> -#include <asm/io.h> #include <asm/irq.h> -#include <asm/page.h> - -#ifdef CONFIG_BLK_DEV_INITRD -#include "../rootfs/rootfs.h" -#endif - -static __init void platform_monitor(void); -static __init void platform_setup(void); -static __init void platform_reserve(void); - - -#define PHYS_MEMORY CONFIG_MEMORY_SIZE_IN_MB*1024*1024 - -#if (PHYS_MEMORY < P1SEG_FOOTPRINT_RAM) -#error "Invalid kernel configuration. Physical memory below footprint requirements." -#endif - -#define RAM_DISK_START CONFIG_MEMORY_START+P1SEG_INITRD_BLOCK /* Top of 4MB */ -#ifdef PLATFORM_ROMFS_SIZE -#define RAM_DISK_SIZE (PAGE_ALIGN(PLATFORM_ROMFS_SIZE)) /* Variable Top */ -#if ((RAM_DISK_START + RAM_DISK_SIZE) > (CONFIG_MEMORY_START + PHYS_MEMORY)) -#error "Invalid kernel configuration. ROM RootFS exceeding physical memory." -#endif -#else -#define RAM_DISK_SIZE P1SEG_INITRD_BLOCK_SIZE /* Top of 4MB */ -#endif - -#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource))) /* * Platform Dependent Interrupt Priorities. @@ -101,8 +65,10 @@ struct resource io_resources[] = { }; struct resource kram_resources[] = { - { "Kernel code", 0, 0 }, /* These must be last in the array */ - { "Kernel data", 0, 0 } /* These must be last in the array */ + /* These must be last in the array */ + { .name = "Kernel code", .start = 0, .end = 0 }, + /* These must be last in the array */ + { .name = "Kernel data", .start = 0, .end = 0 } }; struct resource xram_resources[] = { @@ -117,16 +83,14 @@ struct sh64_platform platform_parms = { .readonly_rootfs = 1, .initial_root_dev = 0x0100, .loader_type = 1, - .initrd_start = RAM_DISK_START, - .initrd_size = RAM_DISK_SIZE, .io_res_p = io_resources, - .io_res_count = RES_COUNT(io_resources), + .io_res_count = ARRAY_SIZE(io_resources), .kram_res_p = kram_resources, - .kram_res_count = RES_COUNT(kram_resources), + .kram_res_count = ARRAY_SIZE(kram_resources), .xram_res_p = xram_resources, - .xram_res_count = RES_COUNT(xram_resources), + .xram_res_count = ARRAY_SIZE(xram_resources), .rom_res_p = rom_resources, - .rom_res_count = RES_COUNT(rom_resources), + .rom_res_count = ARRAY_SIZE(rom_resources), }; int platform_int_priority[NR_IRQS] = { @@ -160,4 +124,3 @@ const char *get_system_type(void) { return "SH-5 Simulator"; } - diff --git a/arch/sh64/mm/Makefile b/arch/sh64/mm/Makefile index ff19378ac90..d0e81363248 100644 --- a/arch/sh64/mm/Makefile +++ b/arch/sh64/mm/Makefile @@ -13,7 +13,8 @@ # unless it's something special (ie not a .c file). # -obj-y := init.o fault.o ioremap.o extable.o cache.o tlbmiss.o tlb.o +obj-y := cache.o consistent.o extable.o fault.o init.o ioremap.o \ + tlbmiss.o tlb.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o @@ -41,4 +42,3 @@ CFLAGS_tlbmiss.o += -ffixed-r7 \ -ffixed-r41 -ffixed-r42 -ffixed-r43 \ -ffixed-r60 -ffixed-r61 -ffixed-r62 \ -fomit-frame-pointer - diff --git a/arch/sh64/kernel/pci-dma.c b/arch/sh64/mm/consistent.c index a9328f89475..8875a2a40da 100644 --- a/arch/sh64/kernel/pci-dma.c +++ b/arch/sh64/mm/consistent.c @@ -11,6 +11,7 @@ #include <linux/mm.h> #include <linux/string.h> #include <linux/pci.h> +#include <linux/module.h> #include <asm/io.h> void *consistent_alloc(struct pci_dev *hwdev, size_t size, @@ -36,6 +37,7 @@ void *consistent_alloc(struct pci_dev *hwdev, size_t size, return vp; } +EXPORT_SYMBOL(consistent_alloc); void consistent_free(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) @@ -47,4 +49,4 @@ void consistent_free(struct pci_dev *hwdev, size_t size, iounmap(vaddr); } - +EXPORT_SYMBOL(consistent_free); diff --git a/arch/sh64/mm/init.c b/arch/sh64/mm/init.c index 559717f30d1..21cf42de23e 100644 --- a/arch/sh64/mm/init.c +++ b/arch/sh64/mm/init.c @@ -22,10 +22,6 @@ #include <asm/pgtable.h> #include <asm/tlb.h> -#ifdef CONFIG_BLK_DEV_INITRD -#include <linux/blk.h> -#endif - DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); /* diff --git a/arch/sh64/mm/ioremap.c b/arch/sh64/mm/ioremap.c index 990857756d4..535304e6601 100644 --- a/arch/sh64/mm/ioremap.c +++ b/arch/sh64/mm/ioremap.c @@ -19,11 +19,12 @@ #include <linux/sched.h> #include <linux/string.h> #include <linux/io.h> -#include <asm/pgalloc.h> -#include <asm/tlbflush.h> #include <linux/ioport.h> #include <linux/bootmem.h> #include <linux/proc_fs.h> +#include <linux/module.h> +#include <asm/pgalloc.h> +#include <asm/tlbflush.h> static void shmedia_mapioaddr(unsigned long, unsigned long); static unsigned long shmedia_ioremap(struct resource *, u32, int); @@ -80,6 +81,7 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag } return (void *) (offset + (char *)addr); } +EXPORT_SYMBOL(__ioremap); void iounmap(void *addr) { @@ -94,6 +96,7 @@ void iounmap(void *addr) kfree(area); } +EXPORT_SYMBOL(iounmap); static struct resource shmedia_iomap = { .name = "shmedia_iomap", diff --git a/arch/um/Makefile b/arch/um/Makefile index 989224f2134..0666729eb97 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -176,9 +176,9 @@ include/asm-um/arch: @echo ' SYMLINK $@' ifneq ($(KBUILD_SRC),) $(Q)mkdir -p $(objtree)/include/asm-um - $(Q)ln -fsn $(srctree)/include/asm-$(SUBARCH) include/asm-um/arch + $(Q)ln -fsn $(srctree)/include/asm-$(HEADER_ARCH) include/asm-um/arch else - $(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch + $(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(HEADER_ARCH) arch endif $(objtree)/$(ARCH_DIR)/include: @@ -232,4 +232,4 @@ $(ARCH_DIR)/include/kern_constants.h: $(objtree)/$(ARCH_DIR)/include @echo ' SYMLINK $@' $(Q)ln -sf ../../../include/asm-um/asm-offsets.h $@ -export SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING OS +export SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING OS HEADER_ARCH diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 index c9f1c5b24c9..60107ed4905 100644 --- a/arch/um/Makefile-i386 +++ b/arch/um/Makefile-i386 @@ -1,4 +1,4 @@ -core-y += arch/um/sys-i386/ arch/i386/crypto/ +core-y += arch/um/sys-i386/ arch/x86/crypto/ TOP_ADDR := $(CONFIG_TOP_ADDR) @@ -12,6 +12,7 @@ LDFLAGS += -m elf_i386 ELF_ARCH := $(SUBARCH) ELF_FORMAT := elf32-$(SUBARCH) OBJCOPYFLAGS := -O binary -R .note -R .comment -S +HEADER_ARCH := x86 ifeq ("$(origin SUBARCH)", "command line") ifneq ("$(shell uname -m | sed -e s/i.86/i386/)", "$(SUBARCH)") @@ -24,6 +25,11 @@ export LDFLAGS HOSTCFLAGS HOSTLDFLAGS UML_OBJCOPYFLAGS endif endif +CFLAGS += -DCONFIG_X86_32 +AFLAGS += -DCONFIG_X86_32 +CONFIG_X86_32 := y +export CONFIG_X86_32 + ARCH_KERNEL_DEFINES += -U__$(SUBARCH)__ -U$(SUBARCH) # First of all, tune CFLAGS for the specific CPU. This actually sets cflags-y. diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64 index 69ecea63fda..8a00e5f6934 100644 --- a/arch/um/Makefile-x86_64 +++ b/arch/um/Makefile-x86_64 @@ -1,7 +1,7 @@ # Copyright 2003 - 2004 Pathscale, Inc # Released under the GPL -core-y += arch/um/sys-x86_64/ arch/x86_64/crypto/ +core-y += arch/um/sys-x86_64/ arch/x86/crypto/ START := 0x60000000 _extra_flags_ = -fno-builtin -m64 @@ -18,6 +18,7 @@ CPPFLAGS += -m64 ELF_ARCH := i386:x86-64 ELF_FORMAT := elf64-x86-64 +HEADER_ARCH := x86 # Not on all 64-bit distros /lib is a symlink to /lib64. PLD is an example. diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index a9a4b85ca51..bf23dd3e24d 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules @@ -28,5 +28,5 @@ endef ifdef subarch-obj-y obj-y += subarch.o -subarch-y = $(addprefix ../../$(SUBARCH)/,$(subarch-obj-y)) +subarch-y = $(addprefix ../../$(HEADER_ARCH)/,$(subarch-obj-y)) endif diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index d6b3ecd4b77..a4618b6b85b 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -4,9 +4,9 @@ obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o -subarch-obj-y = lib/bitops.o lib/semaphore.o lib/string.o -subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem.o -subarch-obj-$(CONFIG_MODULES) += kernel/module.o +subarch-obj-y = lib/bitops_32.o lib/semaphore_32.o lib/string_32.o +subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o +subarch-obj-$(CONFIG_MODULES) += kernel/module_32.o USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index 4d9e5efa6fb..ea8185d8540 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -11,8 +11,8 @@ obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o obj-$(CONFIG_MODULES) += um_module.o -subarch-obj-y = lib/bitops.o lib/csum-partial.o lib/memcpy.o lib/thunk.o -subarch-obj-$(CONFIG_MODULES) += kernel/module.o +subarch-obj-y = lib/bitops_64.o lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o +subarch-obj-$(CONFIG_MODULES) += kernel/module_64.o ldt-y = ../sys-i386/ldt.o diff --git a/arch/x86/kernel/bugs_64.c b/arch/x86/kernel/bugs_64.c index 4e5e9d364d6..9a189cef640 100644 --- a/arch/x86/kernel/bugs_64.c +++ b/arch/x86/kernel/bugs_64.c @@ -1,6 +1,4 @@ /* - * arch/x86_64/kernel/bugs.c - * * Copyright (C) 1994 Linus Torvalds * Copyright (C) 2000 SuSE */ diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 59266f03d1c..205fd5ba57f 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -1,6 +1,4 @@ /* - * arch/i386/cpu/bugs.c - * * Copyright (C) 1994 Linus Torvalds * * Cyrix stuff, June 1998 by: diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c index 5c2faa10e9f..f4548c93ccf 100644 --- a/arch/x86/kernel/cpuid.c +++ b/arch/x86/kernel/cpuid.c @@ -11,8 +11,6 @@ * ----------------------------------------------------------------------- */ /* - * cpuid.c - * * x86 CPUID access device * * This device is accessed by lseek() to the appropriate CPUID level diff --git a/arch/x86/kernel/crash_dump_32.c b/arch/x86/kernel/crash_dump_32.c index 3f532df488b..32e75d0731a 100644 --- a/arch/x86/kernel/crash_dump_32.c +++ b/arch/x86/kernel/crash_dump_32.c @@ -1,5 +1,5 @@ /* - * kernel/crash_dump.c - Memory preserving reboot related code. + * Memory preserving reboot related code. * * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) * Copyright (C) IBM Corporation, 2004. All rights reserved diff --git a/arch/x86/kernel/crash_dump_64.c b/arch/x86/kernel/crash_dump_64.c index 942deac4d43..15e6c6bc4a4 100644 --- a/arch/x86/kernel/crash_dump_64.c +++ b/arch/x86/kernel/crash_dump_64.c @@ -1,5 +1,5 @@ /* - * kernel/crash_dump.c - Memory preserving reboot related code. + * Memory preserving reboot related code. * * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) * Copyright (C) IBM Corporation, 2004. All rights reserved diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 6c34bdd22e2..8561f626eda 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -1,5 +1,5 @@ /* - * linux/arch/x86_64/kernel/head64.c -- prepare to run common code + * prepare to run common code * * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE */ diff --git a/arch/x86/kernel/i387_32.c b/arch/x86/kernel/i387_32.c index 665847281ed..7d2e12f6c78 100644 --- a/arch/x86/kernel/i387_32.c +++ b/arch/x86/kernel/i387_32.c @@ -1,6 +1,4 @@ /* - * linux/arch/i386/kernel/i387.c - * * Copyright (C) 1994 Linus Torvalds * * Pentium III FXSR, SSE support diff --git a/arch/x86/kernel/i387_64.c b/arch/x86/kernel/i387_64.c index 1d58c13bc6b..56c1f114710 100644 --- a/arch/x86/kernel/i387_64.c +++ b/arch/x86/kernel/i387_64.c @@ -1,6 +1,4 @@ /* - * linux/arch/x86_64/kernel/i387.c - * * Copyright (C) 1994 Linus Torvalds * Copyright (C) 2002 Andi Kleen, SuSE Labs * diff --git a/arch/x86/kernel/i8237.c b/arch/x86/kernel/i8237.c index 6f508e8d7c5..29313832df0 100644 --- a/arch/x86/kernel/i8237.c +++ b/arch/x86/kernel/i8237.c @@ -1,5 +1,5 @@ /* - * i8237.c: 8237A DMA controller suspend functions. + * 8237A DMA controller suspend functions. * * Written by Pierre Ossman, 2005. * diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c index ac15e4cbd9c..5cc8841ca2c 100644 --- a/arch/x86/kernel/i8253.c +++ b/arch/x86/kernel/i8253.c @@ -1,5 +1,5 @@ /* - * i8253.c 8253/PIT functions + * 8253/PIT functions * */ #include <linux/clockchips.h> diff --git a/arch/x86/kernel/ioport_32.c b/arch/x86/kernel/ioport_32.c index 3d310a946d7..4ed48dc8df1 100644 --- a/arch/x86/kernel/ioport_32.c +++ b/arch/x86/kernel/ioport_32.c @@ -1,6 +1,4 @@ /* - * linux/arch/i386/kernel/ioport.c - * * This contains the io-permission bitmap code - written by obz, with changes * by Linus. */ diff --git a/arch/x86/kernel/ioport_64.c b/arch/x86/kernel/ioport_64.c index 653efa30b0f..5f62fad64da 100644 --- a/arch/x86/kernel/ioport_64.c +++ b/arch/x86/kernel/ioport_64.c @@ -1,6 +1,4 @@ /* - * linux/arch/x86_64/kernel/ioport.c - * * This contains the io-permission bitmap code - written by obz, with changes * by Linus. */ diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index 4f681bcdb1f..e173b763f14 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c @@ -1,6 +1,4 @@ /* - * linux/arch/i386/kernel/irq.c - * * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar * * This file contains the lowest level x86-specific interrupt diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c index bd11e42b22b..865669efc54 100644 --- a/arch/x86/kernel/irq_64.c +++ b/arch/x86/kernel/irq_64.c @@ -1,6 +1,4 @@ /* - * linux/arch/x86_64/kernel/irq.c - * * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar * * This file contains the lowest level x86_64-specific interrupt diff --git a/arch/x86/kernel/kprobes_32.c b/arch/x86/kernel/kprobes_32.c index 448a50b1324..c2d03e96ae9 100644 --- a/arch/x86/kernel/kprobes_32.c +++ b/arch/x86/kernel/kprobes_32.c @@ -1,6 +1,5 @@ /* * Kernel Probes (KProbes) - * arch/i386/kernel/kprobes.c * * 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 diff --git a/arch/x86/kernel/kprobes_64.c b/arch/x86/kernel/kprobes_64.c index a30e004682e..1df17a0ec0c 100644 --- a/arch/x86/kernel/kprobes_64.c +++ b/arch/x86/kernel/kprobes_64.c @@ -1,6 +1,5 @@ /* * Kernel Probes (KProbes) - * arch/x86_64/kernel/kprobes.c * * 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 diff --git a/arch/x86/kernel/ldt_32.c b/arch/x86/kernel/ldt_32.c index e0b2d17f4f1..a8b18421863 100644 --- a/arch/x86/kernel/ldt_32.c +++ b/arch/x86/kernel/ldt_32.c @@ -1,6 +1,4 @@ /* - * linux/arch/i386/kernel/ldt.c - * * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com> */ diff --git a/arch/x86/kernel/ldt_64.c b/arch/x86/kernel/ldt_64.c index bc9ffd5c19c..3796523d616 100644 --- a/arch/x86/kernel/ldt_64.c +++ b/arch/x86/kernel/ldt_64.c @@ -1,6 +1,4 @@ /* - * linux/arch/x86_64/kernel/ldt.c - * * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com> * Copyright (C) 2002 Andi Kleen diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c index 91966bafb3d..deda9a221cf 100644 --- a/arch/x86/kernel/machine_kexec_32.c +++ b/arch/x86/kernel/machine_kexec_32.c @@ -1,5 +1,5 @@ /* - * machine_kexec.c - handle transition of Linux booting another kernel + * handle transition of Linux booting another kernel * Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com> * * This source code is licensed under the GNU General Public License, diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index c3a55470367..cd1899a2f0c 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c @@ -1,5 +1,5 @@ /* - * machine_kexec.c - handle transition of Linux booting another kernel + * handle transition of Linux booting another kernel * Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com> * * This source code is licensed under the GNU General Public License, diff --git a/arch/x86/kernel/mca_32.c b/arch/x86/kernel/mca_32.c index b83672b8952..9482033ed0f 100644 --- a/arch/x86/kernel/mca_32.c +++ b/arch/x86/kernel/mca_32.c @@ -1,5 +1,4 @@ /* - * linux/arch/i386/kernel/mca.c * Written by Martin Kolinek, February 1996 * * Changes: diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c index 0c1069b8d63..c044de310b6 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c @@ -11,8 +11,6 @@ * ----------------------------------------------------------------------- */ /* - * msr.c - * * x86 MSR access device * * This device is accessed by lseek() to the appropriate register number diff --git a/arch/x86/kernel/nmi_32.c b/arch/x86/kernel/nmi_32.c index 95d3fc203cf..f803ed0ed1c 100644 --- a/arch/x86/kernel/nmi_32.c +++ b/arch/x86/kernel/nmi_32.c @@ -1,6 +1,4 @@ /* - * linux/arch/i386/nmi.c - * * NMI watchdog support on APIC systems * * Started by Ingo Molnar <mingo@redhat.com> diff --git a/arch/x86/kernel/nmi_64.c b/arch/x86/kernel/nmi_64.c index e60ac0da528..a576fd74006 100644 --- a/arch/x86/kernel/nmi_64.c +++ b/arch/x86/kernel/nmi_64.c @@ -1,6 +1,4 @@ /* - * linux/arch/x86_64/nmi.c - * * NMI watchdog support on APIC systems * * Started by Ingo Molnar <mingo@redhat.com> diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 84664710b78..097aeafce5f 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -1,6 +1,4 @@ /* - * linux/arch/i386/kernel/process.c - * * Copyright (C) 1995 Linus Torvalds * * Pentium III FXSR, SSE support diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 6f9dbbe65ee..7352d4b377e 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -1,6 +1,4 @@ /* - * linux/arch/x86-64/kernel/process.c - * * Copyright (C) 1995 Linus Torvalds * * Pentium III FXSR, SSE support diff --git a/arch/x86/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c index 7c1b92522e9..0cecd7513c9 100644 --- a/arch/x86/kernel/ptrace_32.c +++ b/arch/x86/kernel/ptrace_32.c @@ -1,4 +1,3 @@ -/* ptrace.c */ /* By Ross Biro 1/23/92 */ /* * Pentium III FXSR, SSE support diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c index eea3702427b..c0cac42df3b 100644 --- a/arch/x86/kernel/ptrace_64.c +++ b/arch/x86/kernel/ptrace_64.c @@ -1,4 +1,3 @@ -/* ptrace.c */ /* By Ross Biro 1/23/92 */ /* * Pentium III FXSR, SSE support diff --git a/arch/x86/kernel/reboot_32.c b/arch/x86/kernel/reboot_32.c index b37ed226830..9e2269d0091 100644 --- a/arch/x86/kernel/reboot_32.c +++ b/arch/x86/kernel/reboot_32.c @@ -1,7 +1,3 @@ -/* - * linux/arch/i386/kernel/reboot.c - */ - #include <linux/mm.h> #include <linux/module.h> #include <linux/delay.h> diff --git a/arch/x86/kernel/reboot_fixups_32.c b/arch/x86/kernel/reboot_fixups_32.c index 139eb03490f..8b30b26ad06 100644 --- a/arch/x86/kernel/reboot_fixups_32.c +++ b/arch/x86/kernel/reboot_fixups_32.c @@ -1,6 +1,4 @@ /* - * linux/arch/i386/kernel/reboot_fixups.c - * * This is a good place to put board specific reboot fixups. * * List of supported fixups: diff --git a/arch/x86/kernel/scx200_32.c b/arch/x86/kernel/scx200_32.c index c7d3df23f58..48759772091 100644 --- a/arch/x86/kernel/scx200_32.c +++ b/arch/x86/kernel/scx200_32.c @@ -1,8 +1,8 @@ -/* linux/arch/i386/kernel/scx200.c - - Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> - - National Semiconductor SCx200 support. */ +/* + * Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> + * + * National Semiconductor SCx200 support. + */ #include <linux/module.h> #include <linux/errno.h> diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c index d474cd639bc..c8e1bc38d42 100644 --- a/arch/x86/kernel/setup_32.c +++ b/arch/x86/kernel/setup_32.c @@ -1,6 +1,4 @@ /* - * linux/arch/i386/kernel/setup.c - * * Copyright (C) 1995 Linus Torvalds * * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c index 32054bf5ba4..b7da90e79c7 100644 --- a/arch/x86/kernel/setup_64.c +++ b/arch/x86/kernel/setup_64.c @@ -1,10 +1,5 @@ /* - * linux/arch/x86-64/kernel/setup.c - * * Copyright (C) 1995 Linus Torvalds - * - * Nov 2001 Dave Jones <davej@suse.de> - * Forked from i386 setup code. */ /* diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index c03570f7fe8..d01d51fcce2 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c @@ -1,6 +1,4 @@ /* - * linux/arch/i386/kernel/signal.c - * * Copyright (C) 1991, 1992 Linus Torvalds * * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index 739175b01e0..683802bec41 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c @@ -1,6 +1,4 @@ /* - * linux/arch/x86_64/kernel/signal.c - * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs * diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index cb910911358..413e527cdeb 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c @@ -1,6 +1,4 @@ /* - * arch/x86_64/kernel/stacktrace.c - * * Stack trace management functions * * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> diff --git a/arch/x86/kernel/summit_32.c b/arch/x86/kernel/summit_32.c index d0e01a3acf3..91c7acc8d99 100644 --- a/arch/x86/kernel/summit_32.c +++ b/arch/x86/kernel/summit_32.c @@ -1,5 +1,5 @@ /* - * arch/i386/kernel/summit.c - IBM Summit-Specific Code + * IBM Summit-Specific Code * * Written By: Matthew Dobson, IBM Corporation * diff --git a/arch/x86/kernel/sys_i386_32.c b/arch/x86/kernel/sys_i386_32.c index 42147304de8..f8bae9ba032 100644 --- a/arch/x86/kernel/sys_i386_32.c +++ b/arch/x86/kernel/sys_i386_32.c @@ -1,6 +1,4 @@ /* - * linux/arch/i386/kernel/sys_i386.c - * * This file contains various random system calls that * have a non-standard calling sequence on the Linux/i386 * platform. diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index 4770b7a2052..907942ee6e7 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c @@ -1,7 +1,3 @@ -/* - * linux/arch/x86_64/kernel/sys_x86_64.c - */ - #include <linux/errno.h> #include <linux/sched.h> #include <linux/syscalls.h> diff --git a/arch/x86/kernel/sysenter_32.c b/arch/x86/kernel/sysenter_32.c index 4eb2e408764..5a2d951e260 100644 --- a/arch/x86/kernel/sysenter_32.c +++ b/arch/x86/kernel/sysenter_32.c @@ -1,6 +1,4 @@ /* - * linux/arch/i386/kernel/sysenter.c - * * (C) Copyright 2002 Linus Torvalds * Portions based on the vdso-randomization code from exec-shield: * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c index 56dadfc2f41..8a322c96bc2 100644 --- a/arch/x86/kernel/time_32.c +++ b/arch/x86/kernel/time_32.c @@ -1,6 +1,4 @@ /* - * linux/arch/i386/kernel/time.c - * * Copyright (C) 1991, 1992, 1995 Linus Torvalds * * This file contains the PC-specific time handling details: diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index e0134d6c88d..c821edc3221 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c @@ -1,6 +1,4 @@ /* - * linux/arch/x86-64/kernel/time.c - * * "High Precision Event Timer" based timekeeping. * * Copyright (c) 1991,1992,1995 Linus Torvalds diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c index 45782356a61..c25f23eb397 100644 --- a/arch/x86/kernel/topology.c +++ b/arch/x86/kernel/topology.c @@ -1,5 +1,5 @@ /* - * arch/i386/kernel/topology.c - Populate sysfs with topology information + * Populate sysfs with topology information * * Written by: Matthew Dobson, IBM Corporation * Original Code: Paul Dorwin, IBM Corporation, Patrick Mochel, OSDL diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 47b0bef335b..05c27ecaf2a 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c @@ -1,6 +1,4 @@ /* - * linux/arch/i386/traps.c - * * Copyright (C) 1991, 1992 Linus Torvalds * * Pentium III FXSR, SSE support diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c index 03888420775..bc7116acf8f 100644 --- a/arch/x86/kernel/traps_64.c +++ b/arch/x86/kernel/traps_64.c @@ -1,6 +1,4 @@ /* - * linux/arch/x86-64/traps.c - * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs * diff --git a/arch/x86/kernel/tsc_32.c b/arch/x86/kernel/tsc_32.c index 3ed0ae8c918..b85ad754f70 100644 --- a/arch/x86/kernel/tsc_32.c +++ b/arch/x86/kernel/tsc_32.c @@ -1,9 +1,3 @@ -/* - * This code largely moved from arch/i386/kernel/timer/timer_tsc.c - * which was originally moved from arch/i386/kernel/time.c. - * See comments there for proper credits. - */ - #include <linux/sched.h> #include <linux/clocksource.h> #include <linux/workqueue.h> diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c index 355f5f506c8..9125efe66a0 100644 --- a/arch/x86/kernel/tsc_sync.c +++ b/arch/x86/kernel/tsc_sync.c @@ -1,5 +1,5 @@ /* - * arch/x86_64/kernel/tsc_sync.c: check TSC synchronization. + * check TSC synchronization. * * Copyright (C) 2006, Red Hat, Inc., Ingo Molnar * diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index f2dcd1d27c0..157e4bedd3c 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -1,6 +1,4 @@ /* - * linux/kernel/vm86.c - * * Copyright (C) 1994 Linus Torvalds * * 29 dec 2001 - Fixed oopses caused by unchecked access to the vm86 diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c index 06c34949bfd..93847d84815 100644 --- a/arch/x86/kernel/vsyscall_64.c +++ b/arch/x86/kernel/vsyscall_64.c @@ -1,6 +1,4 @@ /* - * linux/arch/x86_64/kernel/vsyscall.c - * * Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE * Copyright 2003 Andi Kleen, SuSE Labs. * diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c index ded1d6ac6ff..f948d3a14a9 100644 --- a/drivers/input/keyboard/atakbd.c +++ b/drivers/input/keyboard/atakbd.c @@ -55,7 +55,140 @@ MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>"); MODULE_DESCRIPTION("Atari keyboard driver"); MODULE_LICENSE("GPL"); -static unsigned char atakbd_keycode[0x72]; +/* + 0x47: KP_7 71 + 0x48: KP_8 72 + 0x49: KP_9 73 + 0x62: KP_/ 98 + 0x4b: KP_4 75 + 0x4c: KP_5 76 + 0x4d: KP_6 77 + 0x37: KP_* 55 + 0x4f: KP_1 79 + 0x50: KP_2 80 + 0x51: KP_3 81 + 0x4a: KP_- 74 + 0x52: KP_0 82 + 0x53: KP_. 83 + 0x4e: KP_+ 78 + + 0x67: Up 103 + 0x6c: Down 108 + 0x69: Left 105 + 0x6a: Right 106 + */ + + +static unsigned char atakbd_keycode[0x72] = { /* American layout */ + [0] = KEY_GRAVE, + [1] = KEY_ESC, + [2] = KEY_1, + [3] = KEY_2, + [4] = KEY_3, + [5] = KEY_4, + [6] = KEY_5, + [7] = KEY_6, + [8] = KEY_7, + [9] = KEY_8, + [10] = KEY_9, + [11] = KEY_0, + [12] = KEY_MINUS, + [13] = KEY_EQUAL, + [14] = KEY_BACKSPACE, + [15] = KEY_TAB, + [16] = KEY_Q, + [17] = KEY_W, + [18] = KEY_E, + [19] = KEY_R, + [20] = KEY_T, + [21] = KEY_Y, + [22] = KEY_U, + [23] = KEY_I, + [24] = KEY_O, + [25] = KEY_P, + [26] = KEY_LEFTBRACE, + [27] = KEY_RIGHTBRACE, + [28] = KEY_ENTER, + [29] = KEY_LEFTCTRL, + [30] = KEY_A, + [31] = KEY_S, + [32] = KEY_D, + [33] = KEY_F, + [34] = KEY_G, + [35] = KEY_H, + [36] = KEY_J, + [37] = KEY_K, + [38] = KEY_L, + [39] = KEY_SEMICOLON, + [40] = KEY_APOSTROPHE, + [41] = KEY_BACKSLASH, /* FIXME, '#' */ + [42] = KEY_LEFTSHIFT, + [43] = KEY_GRAVE, /* FIXME: '~' */ + [44] = KEY_Z, + [45] = KEY_X, + [46] = KEY_C, + [47] = KEY_V, + [48] = KEY_B, + [49] = KEY_N, + [50] = KEY_M, + [51] = KEY_COMMA, + [52] = KEY_DOT, + [53] = KEY_SLASH, + [54] = KEY_RIGHTSHIFT, + [55] = KEY_KPASTERISK, + [56] = KEY_LEFTALT, + [57] = KEY_SPACE, + [58] = KEY_CAPSLOCK, + [59] = KEY_F1, + [60] = KEY_F2, + [61] = KEY_F3, + [62] = KEY_F4, + [63] = KEY_F5, + [64] = KEY_F6, + [65] = KEY_F7, + [66] = KEY_F8, + [67] = KEY_F9, + [68] = KEY_F10, + [69] = KEY_ESC, + [70] = KEY_DELETE, + [71] = KEY_KP7, + [72] = KEY_KP8, + [73] = KEY_KP9, + [74] = KEY_KPMINUS, + [75] = KEY_KP4, + [76] = KEY_KP5, + [77] = KEY_KP6, + [78] = KEY_KPPLUS, + [79] = KEY_KP1, + [80] = KEY_KP2, + [81] = KEY_KP3, + [82] = KEY_KP0, + [83] = KEY_KPDOT, + [90] = KEY_KPLEFTPAREN, + [91] = KEY_KPRIGHTPAREN, + [92] = KEY_KPASTERISK, /* FIXME */ + [93] = KEY_KPASTERISK, + [94] = KEY_KPPLUS, + [95] = KEY_HELP, + [96] = KEY_BACKSLASH, /* FIXME: '<' */ + [97] = KEY_KPASTERISK, /* FIXME */ + [98] = KEY_KPSLASH, + [99] = KEY_KPLEFTPAREN, + [100] = KEY_KPRIGHTPAREN, + [101] = KEY_KPSLASH, + [102] = KEY_KPASTERISK, + [103] = KEY_UP, + [104] = KEY_KPASTERISK, /* FIXME */ + [105] = KEY_LEFT, + [106] = KEY_RIGHT, + [107] = KEY_KPASTERISK, /* FIXME */ + [108] = KEY_DOWN, + [109] = KEY_KPASTERISK, /* FIXME */ + [110] = KEY_KPASTERISK, /* FIXME */ + [111] = KEY_KPASTERISK, /* FIXME */ + [112] = KEY_KPASTERISK, /* FIXME */ + [113] = KEY_KPASTERISK /* FIXME */ +}; static struct input_dev *atakbd_dev; @@ -86,21 +219,20 @@ static int __init atakbd_init(void) { int i; - if (!ATARIHW_PRESENT(ST_MFP)) + if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) return -EIO; - // TODO: request_mem_region if not done in arch code - - if (!(atakbd_dev = input_allocate_device())) - return -ENOMEM; - // need to init core driver if not already done so if (atari_keyb_init()) return -ENODEV; + atakbd_dev = input_allocate_device(); + if (!atakbd_dev) + return -ENOMEM; + atakbd_dev->name = "Atari Keyboard"; atakbd_dev->phys = "atakbd/input0"; - atakbd_dev->id.bustype = BUS_ATARI; + atakbd_dev->id.bustype = BUS_HOST; atakbd_dev->id.vendor = 0x0001; atakbd_dev->id.product = 0x0001; atakbd_dev->id.version = 0x0100; @@ -111,16 +243,17 @@ static int __init atakbd_init(void) atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode); for (i = 1; i < 0x72; i++) { - atakbd_keycode[i] = i; set_bit(atakbd_keycode[i], atakbd_dev->keybit); } - input_register_device(atakbd_dev); + /* error check */ + if (input_register_device(atakbd_dev)) { + input_free_device(atakbd_dev); + return -ENOMEM; + } atari_input_keyboard_interrupt_hook = atakbd_interrupt; - printk(KERN_INFO "input: %s at IKBD ACIA\n", atakbd_dev->name); - return 0; } diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c index 43ab6566fb6..c8c7244b48a 100644 --- a/drivers/input/mouse/atarimouse.c +++ b/drivers/input/mouse/atarimouse.c @@ -73,14 +73,11 @@ static void atamouse_interrupt(char *buf) { int buttons, dx, dy; -/* ikbd_mouse_disable(); */ - buttons = (buf[0] & 1) | ((buf[0] & 2) << 1); #ifdef FIXED_ATARI_JOYSTICK buttons |= atari_mouse_buttons & 2; atari_mouse_buttons = buttons; #endif -/* ikbd_mouse_rel_pos(); */ /* only relative events get here */ dx = buf[1]; @@ -126,15 +123,16 @@ static int __init atamouse_init(void) if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) return -ENODEV; - if (!(atamouse_dev = input_allocate_device())) - return -ENOMEM; - if (!(atari_keyb_init())) return -ENODEV; + atamouse_dev = input_allocate_device(); + if (!atamouse_dev) + return -ENOMEM; + atamouse_dev->name = "Atari mouse"; atamouse_dev->phys = "atamouse/input0"; - atamouse_dev->id.bustype = BUS_ATARI; + atamouse_dev->id.bustype = BUS_HOST; atamouse_dev->id.vendor = 0x0001; atamouse_dev->id.product = 0x0002; atamouse_dev->id.version = 0x0100; @@ -145,9 +143,11 @@ static int __init atamouse_init(void) atamouse_dev->open = atamouse_open; atamouse_dev->close = atamouse_close; - input_register_device(atamouse_dev); + if (input_register_device(atamouse_dev)) { + input_free_device(atamouse_dev); + return -ENOMEM; + } - printk(KERN_INFO "input: %s at keyboard ACIA\n", atamouse_dev->name); return 0; } diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig index 0a419a0de60..8749fa4ffce 100644 --- a/drivers/kvm/Kconfig +++ b/drivers/kvm/Kconfig @@ -17,6 +17,7 @@ if VIRTUALIZATION config KVM tristate "Kernel-based Virtual Machine (KVM) support" depends on X86 && EXPERIMENTAL + select PREEMPT_NOTIFIERS select ANON_INODES ---help--- Support hosting fully virtualized guest machines using hardware diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile index c0a789fa9d6..e5a8f4d3e97 100644 --- a/drivers/kvm/Makefile +++ b/drivers/kvm/Makefile @@ -2,7 +2,7 @@ # Makefile for Kernel-based Virtual Machine module # -kvm-objs := kvm_main.o mmu.o x86_emulate.o +kvm-objs := kvm_main.o mmu.o x86_emulate.o i8259.o irq.o lapic.o ioapic.o obj-$(CONFIG_KVM) += kvm.o kvm-intel-objs = vmx.o obj-$(CONFIG_KVM_INTEL) += kvm-intel.o diff --git a/drivers/kvm/i8259.c b/drivers/kvm/i8259.c new file mode 100644 index 00000000000..a679157bc59 --- /dev/null +++ b/drivers/kvm/i8259.c @@ -0,0 +1,450 @@ +/* + * 8259 interrupt controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (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. + * Authors: + * Yaozu (Eddie) Dong <Eddie.dong@intel.com> + * Port from Qemu. + */ +#include <linux/mm.h> +#include "irq.h" + +/* + * set irq level. If an edge is detected, then the IRR is set to 1 + */ +static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level) +{ + int mask; + mask = 1 << irq; + if (s->elcr & mask) /* level triggered */ + if (level) { + s->irr |= mask; + s->last_irr |= mask; + } else { + s->irr &= ~mask; + s->last_irr &= ~mask; + } + else /* edge triggered */ + if (level) { + if ((s->last_irr & mask) == 0) + s->irr |= mask; + s->last_irr |= mask; + } else + s->last_irr &= ~mask; +} + +/* + * return the highest priority found in mask (highest = smallest + * number). Return 8 if no irq + */ +static inline int get_priority(struct kvm_kpic_state *s, int mask) +{ + int priority; + if (mask == 0) + return 8; + priority = 0; + while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) + priority++; + return priority; +} + +/* + * return the pic wanted interrupt. return -1 if none + */ +static int pic_get_irq(struct kvm_kpic_state *s) +{ + int mask, cur_priority, priority; + + mask = s->irr & ~s->imr; + priority = get_priority(s, mask); + if (priority == 8) + return -1; + /* + * compute current priority. If special fully nested mode on the + * master, the IRQ coming from the slave is not taken into account + * for the priority computation. + */ + mask = s->isr; + if (s->special_fully_nested_mode && s == &s->pics_state->pics[0]) + mask &= ~(1 << 2); + cur_priority = get_priority(s, mask); + if (priority < cur_priority) + /* + * higher priority found: an irq should be generated + */ + return (priority + s->priority_add) & 7; + else + return -1; +} + +/* + * raise irq to CPU if necessary. must be called every time the active + * irq may change + */ +static void pic_update_irq(struct kvm_pic *s) +{ + int irq2, irq; + + irq2 = pic_get_irq(&s->pics[1]); + if (irq2 >= 0) { + /* + * if irq request by slave pic, signal master PIC + */ + pic_set_irq1(&s->pics[0], 2, 1); + pic_set_irq1(&s->pics[0], 2, 0); + } + irq = pic_get_irq(&s->pics[0]); + if (irq >= 0) + s->irq_request(s->irq_request_opaque, 1); + else + s->irq_request(s->irq_request_opaque, 0); +} + +void kvm_pic_update_irq(struct kvm_pic *s) +{ + pic_update_irq(s); +} + +void kvm_pic_set_irq(void *opaque, int irq, int level) +{ + struct kvm_pic *s = opaque; + + pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); + pic_update_irq(s); +} + +/* + * acknowledge interrupt 'irq' + */ +static inline void pic_intack(struct kvm_kpic_state *s, int irq) +{ + if (s->auto_eoi) { + if (s->rotate_on_auto_eoi) + s->priority_add = (irq + 1) & 7; + } else + s->isr |= (1 << irq); + /* + * We don't clear a level sensitive interrupt here + */ + if (!(s->elcr & (1 << irq))) + s->irr &= ~(1 << irq); +} + +int kvm_pic_read_irq(struct kvm_pic *s) +{ + int irq, irq2, intno; + + irq = pic_get_irq(&s->pics[0]); + if (irq >= 0) { + pic_intack(&s->pics[0], irq); + if (irq == 2) { + irq2 = pic_get_irq(&s->pics[1]); + if (irq2 >= 0) + pic_intack(&s->pics[1], irq2); + else + /* + * spurious IRQ on slave controller + */ + irq2 = 7; + intno = s->pics[1].irq_base + irq2; + irq = irq2 + 8; + } else + intno = s->pics[0].irq_base + irq; + } else { + /* + * spurious IRQ on host controller + */ + irq = 7; + intno = s->pics[0].irq_base + irq; + } + pic_update_irq(s); + + return intno; +} + +static void pic_reset(void *opaque) +{ + struct kvm_kpic_state *s = opaque; + + s->last_irr = 0; + s->irr = 0; + s->imr = 0; + s->isr = 0; + s->priority_add = 0; + s->irq_base = 0; + s->read_reg_select = 0; + s->poll = 0; + s->special_mask = 0; + s->init_state = 0; + s->auto_eoi = 0; + s->rotate_on_auto_eoi = 0; + s->special_fully_nested_mode = 0; + s->init4 = 0; +} + +static void pic_ioport_write(void *opaque, u32 addr, u32 val) +{ + struct kvm_kpic_state *s = opaque; + int priority, cmd, irq; + + addr &= 1; + if (addr == 0) { + if (val & 0x10) { + pic_reset(s); /* init */ + /* + * deassert a pending interrupt + */ + s->pics_state->irq_request(s->pics_state-> + irq_request_opaque, 0); + s->init_state = 1; + s->init4 = val & 1; + if (val & 0x02) + printk(KERN_ERR "single mode not supported"); + if (val & 0x08) + printk(KERN_ERR + "level sensitive irq not supported"); + } else if (val & 0x08) { + if (val & 0x04) + s->poll = 1; + if (val & 0x02) + s->read_reg_select = val & 1; + if (val & 0x40) + s->special_mask = (val >> 5) & 1; + } else { + cmd = val >> 5; + switch (cmd) { + case 0: + case 4: + s->rotate_on_auto_eoi = cmd >> 2; + break; + case 1: /* end of interrupt */ + case 5: + priority = get_priority(s, s->isr); + if (priority != 8) { + irq = (priority + s->priority_add) & 7; + s->isr &= ~(1 << irq); + if (cmd == 5) + s->priority_add = (irq + 1) & 7; + pic_update_irq(s->pics_state); + } + break; + case 3: + irq = val & 7; + s->isr &= ~(1 << irq); + pic_update_irq(s->pics_state); + break; + case 6: + s->priority_add = (val + 1) & 7; + pic_update_irq(s->pics_state); + break; + case 7: + irq = val & 7; + s->isr &= ~(1 << irq); + s->priority_add = (irq + 1) & 7; + pic_update_irq(s->pics_state); + break; + default: + break; /* no operation */ + } + } + } else + switch (s->init_state) { + case 0: /* normal mode */ + s->imr = val; + pic_update_irq(s->pics_state); + break; + case 1: + s->irq_base = val & 0xf8; + s->init_state = 2; + break; + case 2: + if (s->init4) + s->init_state = 3; + else + s->init_state = 0; + break; + case 3: + s->special_fully_nested_mode = (val >> 4) & 1; + s->auto_eoi = (val >> 1) & 1; + s->init_state = 0; + break; + } +} + +static u32 pic_poll_read(struct kvm_kpic_state *s, u32 addr1) +{ + int ret; + + ret = pic_get_irq(s); + if (ret >= 0) { + if (addr1 >> 7) { + s->pics_state->pics[0].isr &= ~(1 << 2); + s->pics_state->pics[0].irr &= ~(1 << 2); + } + s->irr &= ~(1 << ret); + s->isr &= ~(1 << ret); + if (addr1 >> 7 || ret != 2) + pic_update_irq(s->pics_state); + } else { + ret = 0x07; + pic_update_irq(s->pics_state); + } + + return ret; +} + +static u32 pic_ioport_read(void *opaque, u32 addr1) +{ + struct kvm_kpic_state *s = opaque; + unsigned int addr; + int ret; + + addr = addr1; + addr &= 1; + if (s->poll) { + ret = pic_poll_read(s, addr1); + s->poll = 0; + } else + if (addr == 0) + if (s->read_reg_select) + ret = s->isr; + else + ret = s->irr; + else + ret = s->imr; + return ret; +} + +static void elcr_ioport_write(void *opaque, u32 addr, u32 val) +{ + struct kvm_kpic_state *s = opaque; + s->elcr = val & s->elcr_mask; +} + +static u32 elcr_ioport_read(void *opaque, u32 addr1) +{ + struct kvm_kpic_state *s = opaque; + return s->elcr; +} + +static int picdev_in_range(struct kvm_io_device *this, gpa_t addr) +{ + switch (addr) { + case 0x20: + case 0x21: + case 0xa0: + case 0xa1: + case 0x4d0: + case 0x4d1: + return 1; + default: + return 0; + } +} + +static void picdev_write(struct kvm_io_device *this, + gpa_t addr, int len, const void *val) +{ + struct kvm_pic *s = this->private; + unsigned char data = *(unsigned char *)val; + + if (len != 1) { + if (printk_ratelimit()) + printk(KERN_ERR "PIC: non byte write\n"); + return; + } + switch (addr) { + case 0x20: + case 0x21: + case 0xa0: + case 0xa1: + pic_ioport_write(&s->pics[addr >> 7], addr, data); + break; + case 0x4d0: + case 0x4d1: + elcr_ioport_write(&s->pics[addr & 1], addr, data); + break; + } +} + +static void picdev_read(struct kvm_io_device *this, + gpa_t addr, int len, void *val) +{ + struct kvm_pic *s = this->private; + unsigned char data = 0; + + if (len != 1) { + if (printk_ratelimit()) + printk(KERN_ERR "PIC: non byte read\n"); + return; + } + switch (addr) { + case 0x20: + case 0x21: + case 0xa0: + case 0xa1: + data = pic_ioport_read(&s->pics[addr >> 7], addr); + break; + case 0x4d0: + case 0x4d1: + data = elcr_ioport_read(&s->pics[addr & 1], addr); + break; + } + *(unsigned char *)val = data; +} + +/* + * callback when PIC0 irq status changed + */ +static void pic_irq_request(void *opaque, int level) +{ + struct kvm *kvm = opaque; + struct kvm_vcpu *vcpu = kvm->vcpus[0]; + + pic_irqchip(kvm)->output = level; + if (vcpu) + kvm_vcpu_kick(vcpu); +} + +struct kvm_pic *kvm_create_pic(struct kvm *kvm) +{ + struct kvm_pic *s; + s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL); + if (!s) + return NULL; + s->pics[0].elcr_mask = 0xf8; + s->pics[1].elcr_mask = 0xde; + s->irq_request = pic_irq_request; + s->irq_request_opaque = kvm; + s->pics[0].pics_state = s; + s->pics[1].pics_state = s; + + /* + * Initialize PIO device + */ + s->dev.read = picdev_read; + s->dev.write = picdev_write; + s->dev.in_range = picdev_in_range; + s->dev.private = s; + kvm_io_bus_register_dev(&kvm->pio_bus, &s->dev); + return s; +} diff --git a/drivers/kvm/ioapic.c b/drivers/kvm/ioapic.c new file mode 100644 index 00000000000..c7992e667fd --- /dev/null +++ b/drivers/kvm/ioapic.c @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2001 MandrakeSoft S.A. + * + * MandrakeSoft S.A. + * 43, rue d'Aboukir + * 75002 Paris - France + * http://www.linux-mandrake.com/ + * http://www.mandrakesoft.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Yunhong Jiang <yunhong.jiang@intel.com> + * Yaozu (Eddie) Dong <eddie.dong@intel.com> + * Based on Xen 3.1 code. + */ + +#include "kvm.h" +#include <linux/kvm.h> +#include <linux/mm.h> +#include <linux/highmem.h> +#include <linux/smp.h> +#include <linux/hrtimer.h> +#include <linux/io.h> +#include <asm/processor.h> +#include <asm/msr.h> +#include <asm/page.h> +#include <asm/current.h> +#include <asm/apicdef.h> +#include <asm/io_apic.h> +#include "irq.h" +/* #define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */ +#define ioapic_debug(fmt, arg...) +static void ioapic_deliver(struct kvm_ioapic *vioapic, int irq); + +static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, + unsigned long addr, + unsigned long length) +{ + unsigned long result = 0; + + switch (ioapic->ioregsel) { + case IOAPIC_REG_VERSION: + result = ((((IOAPIC_NUM_PINS - 1) & 0xff) << 16) + | (IOAPIC_VERSION_ID & 0xff)); + break; + + case IOAPIC_REG_APIC_ID: + case IOAPIC_REG_ARB_ID: + result = ((ioapic->id & 0xf) << 24); + break; + + default: + { + u32 redir_index = (ioapic->ioregsel - 0x10) >> 1; + u64 redir_content; + + ASSERT(redir_index < IOAPIC_NUM_PINS); + + redir_content = ioapic->redirtbl[redir_index].bits; + result = (ioapic->ioregsel & 0x1) ? + (redir_content >> 32) & 0xffffffff : + redir_content & 0xffffffff; + break; + } + } + + return result; +} + +static void ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) +{ + union ioapic_redir_entry *pent; + + pent = &ioapic->redirtbl[idx]; + + if (!pent->fields.mask) { + ioapic_deliver(ioapic, idx); + if (pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) + pent->fields.remote_irr = 1; + } + if (!pent->fields.trig_mode) + ioapic->irr &= ~(1 << idx); +} + +static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) +{ + unsigned index; + + switch (ioapic->ioregsel) { + case IOAPIC_REG_VERSION: + /* Writes are ignored. */ + break; + + case IOAPIC_REG_APIC_ID: + ioapic->id = (val >> 24) & 0xf; + break; + + case IOAPIC_REG_ARB_ID: + break; + + default: + index = (ioapic->ioregsel - 0x10) >> 1; + + ioapic_debug("change redir index %x val %x", index, val); + if (index >= IOAPIC_NUM_PINS) + return; + if (ioapic->ioregsel & 1) { + ioapic->redirtbl[index].bits &= 0xffffffff; + ioapic->redirtbl[index].bits |= (u64) val << 32; + } else { + ioapic->redirtbl[index].bits &= ~0xffffffffULL; + ioapic->redirtbl[index].bits |= (u32) val; + ioapic->redirtbl[index].fields.remote_irr = 0; + } + if (ioapic->irr & (1 << index)) + ioapic_service(ioapic, index); + break; + } +} + +static void ioapic_inj_irq(struct kvm_ioapic *ioapic, + struct kvm_lapic *target, + u8 vector, u8 trig_mode, u8 delivery_mode) +{ + ioapic_debug("irq %d trig %d deliv %d", vector, trig_mode, + delivery_mode); + + ASSERT((delivery_mode == dest_Fixed) || + (delivery_mode == dest_LowestPrio)); + + kvm_apic_set_irq(target, vector, trig_mode); +} + +static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest, + u8 dest_mode) +{ + u32 mask = 0; + int i; + struct kvm *kvm = ioapic->kvm; + struct kvm_vcpu *vcpu; + + ioapic_debug("dest %d dest_mode %d", dest, dest_mode); + + if (dest_mode == 0) { /* Physical mode. */ + if (dest == 0xFF) { /* Broadcast. */ + for (i = 0; i < KVM_MAX_VCPUS; ++i) + if (kvm->vcpus[i] && kvm->vcpus[i]->apic) + mask |= 1 << i; + return mask; + } + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = kvm->vcpus[i]; + if (!vcpu) + continue; + if (kvm_apic_match_physical_addr(vcpu->apic, dest)) { + if (vcpu->apic) + mask = 1 << i; + break; + } + } + } else if (dest != 0) /* Logical mode, MDA non-zero. */ + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = kvm->vcpus[i]; + if (!vcpu) + continue; + if (vcpu->apic && + kvm_apic_match_logical_addr(vcpu->apic, dest)) + mask |= 1 << vcpu->vcpu_id; + } + ioapic_debug("mask %x", mask); + return mask; +} + +static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq) +{ + u8 dest = ioapic->redirtbl[irq].fields.dest_id; + u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode; + u8 delivery_mode = ioapic->redirtbl[irq].fields.delivery_mode; + u8 vector = ioapic->redirtbl[irq].fields.vector; + u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode; + u32 deliver_bitmask; + struct kvm_lapic *target; + struct kvm_vcpu *vcpu; + int vcpu_id; + + ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " + "vector=%x trig_mode=%x", + dest, dest_mode, delivery_mode, vector, trig_mode); + + deliver_bitmask = ioapic_get_delivery_bitmask(ioapic, dest, dest_mode); + if (!deliver_bitmask) { + ioapic_debug("no target on destination"); + return; + } + + switch (delivery_mode) { + case dest_LowestPrio: + target = + kvm_apic_round_robin(ioapic->kvm, vector, deliver_bitmask); + if (target != NULL) + ioapic_inj_irq(ioapic, target, vector, + trig_mode, delivery_mode); + else + ioapic_debug("null round robin: " + "mask=%x vector=%x delivery_mode=%x", + deliver_bitmask, vector, dest_LowestPrio); + break; + case dest_Fixed: + for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { + if (!(deliver_bitmask & (1 << vcpu_id))) + continue; + deliver_bitmask &= ~(1 << vcpu_id); + vcpu = ioapic->kvm->vcpus[vcpu_id]; + if (vcpu) { + target = vcpu->apic; + ioapic_inj_irq(ioapic, target, vector, + trig_mode, delivery_mode); + } + } + break; + + /* TODO: NMI */ + default: + printk(KERN_WARNING "Unsupported delivery mode %d\n", + delivery_mode); + break; + } +} + +void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) +{ + u32 old_irr = ioapic->irr; + u32 mask = 1 << irq; + union ioapic_redir_entry entry; + + if (irq >= 0 && irq < IOAPIC_NUM_PINS) { + entry = ioapic->redirtbl[irq]; + level ^= entry.fields.polarity; + if (!level) + ioapic->irr &= ~mask; + else { + ioapic->irr |= mask; + if ((!entry.fields.trig_mode && old_irr != ioapic->irr) + || !entry.fields.remote_irr) + ioapic_service(ioapic, irq); + } + } +} + +static int get_eoi_gsi(struct kvm_ioapic *ioapic, int vector) +{ + int i; + + for (i = 0; i < IOAPIC_NUM_PINS; i++) + if (ioapic->redirtbl[i].fields.vector == vector) + return i; + return -1; +} + +void kvm_ioapic_update_eoi(struct kvm *kvm, int vector) +{ + struct kvm_ioapic *ioapic = kvm->vioapic; + union ioapic_redir_entry *ent; + int gsi; + + gsi = get_eoi_gsi(ioapic, vector); + if (gsi == -1) { + printk(KERN_WARNING "Can't find redir item for %d EOI\n", + vector); + return; + } + + ent = &ioapic->redirtbl[gsi]; + ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); + + ent->fields.remote_irr = 0; + if (!ent->fields.mask && (ioapic->irr & (1 << gsi))) + ioapic_deliver(ioapic, gsi); +} + +static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr) +{ + struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; + + return ((addr >= ioapic->base_address && + (addr < ioapic->base_address + IOAPIC_MEM_LENGTH))); +} + +static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len, + void *val) +{ + struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; + u32 result; + + ioapic_debug("addr %lx", (unsigned long)addr); + ASSERT(!(addr & 0xf)); /* check alignment */ + + addr &= 0xff; + switch (addr) { + case IOAPIC_REG_SELECT: + result = ioapic->ioregsel; + break; + + case IOAPIC_REG_WINDOW: + result = ioapic_read_indirect(ioapic, addr, len); + break; + + default: + result = 0; + break; + } + switch (len) { + case 8: + *(u64 *) val = result; + break; + case 1: + case 2: + case 4: + memcpy(val, (char *)&result, len); + break; + default: + printk(KERN_WARNING "ioapic: wrong length %d\n", len); + } +} + +static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len, + const void *val) +{ + struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; + u32 data; + + ioapic_debug("ioapic_mmio_write addr=%lx len=%d val=%p\n", + addr, len, val); + ASSERT(!(addr & 0xf)); /* check alignment */ + if (len == 4 || len == 8) + data = *(u32 *) val; + else { + printk(KERN_WARNING "ioapic: Unsupported size %d\n", len); + return; + } + + addr &= 0xff; + switch (addr) { + case IOAPIC_REG_SELECT: + ioapic->ioregsel = data; + break; + + case IOAPIC_REG_WINDOW: + ioapic_write_indirect(ioapic, data); + break; + + default: + break; + } +} + +int kvm_ioapic_init(struct kvm *kvm) +{ + struct kvm_ioapic *ioapic; + int i; + + ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL); + if (!ioapic) + return -ENOMEM; + kvm->vioapic = ioapic; + for (i = 0; i < IOAPIC_NUM_PINS; i++) + ioapic->redirtbl[i].fields.mask = 1; + ioapic->base_address = IOAPIC_DEFAULT_BASE_ADDRESS; + ioapic->dev.read = ioapic_mmio_read; + ioapic->dev.write = ioapic_mmio_write; + ioapic->dev.in_range = ioapic_in_range; + ioapic->dev.private = ioapic; + ioapic->kvm = kvm; + kvm_io_bus_register_dev(&kvm->mmio_bus, &ioapic->dev); + return 0; +} diff --git a/drivers/kvm/irq.c b/drivers/kvm/irq.c new file mode 100644 index 00000000000..7628c7ff628 --- /dev/null +++ b/drivers/kvm/irq.c @@ -0,0 +1,98 @@ +/* + * irq.c: API for in kernel interrupt controller + * Copyright (c) 2007, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * Authors: + * Yaozu (Eddie) Dong <Eddie.dong@intel.com> + * + */ + +#include <linux/module.h> + +#include "kvm.h" +#include "irq.h" + +/* + * check if there is pending interrupt without + * intack. + */ +int kvm_cpu_has_interrupt(struct kvm_vcpu *v) +{ + struct kvm_pic *s; + + if (kvm_apic_has_interrupt(v) == -1) { /* LAPIC */ + if (kvm_apic_accept_pic_intr(v)) { + s = pic_irqchip(v->kvm); /* PIC */ + return s->output; + } else + return 0; + } + return 1; +} +EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); + +/* + * Read pending interrupt vector and intack. + */ +int kvm_cpu_get_interrupt(struct kvm_vcpu *v) +{ + struct kvm_pic *s; + int vector; + + vector = kvm_get_apic_interrupt(v); /* APIC */ + if (vector == -1) { + if (kvm_apic_accept_pic_intr(v)) { + s = pic_irqchip(v->kvm); + s->output = 0; /* PIC */ + vector = kvm_pic_read_irq(s); + } + } + return vector; +} +EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); + +static void vcpu_kick_intr(void *info) +{ +#ifdef DEBUG + struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info; + printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu); +#endif +} + +void kvm_vcpu_kick(struct kvm_vcpu *vcpu) +{ + int ipi_pcpu = vcpu->cpu; + + if (waitqueue_active(&vcpu->wq)) { + wake_up_interruptible(&vcpu->wq); + ++vcpu->stat.halt_wakeup; + } + if (vcpu->guest_mode) + smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0); +} + +void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) +{ + kvm_inject_apic_timer_irqs(vcpu); + /* TODO: PIT, RTC etc. */ +} +EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); + +void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec) +{ + kvm_apic_timer_intr_post(vcpu, vec); + /* TODO: PIT, RTC etc. */ +} +EXPORT_SYMBOL_GPL(kvm_timer_intr_post); diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h new file mode 100644 index 00000000000..11fc014e2b3 --- /dev/null +++ b/drivers/kvm/irq.h @@ -0,0 +1,165 @@ +/* + * irq.h: in kernel interrupt controller related definitions + * Copyright (c) 2007, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * Authors: + * Yaozu (Eddie) Dong <Eddie.dong@intel.com> + * + */ + +#ifndef __IRQ_H +#define __IRQ_H + +#include "kvm.h" + +typedef void irq_request_func(void *opaque, int level); + +struct kvm_kpic_state { + u8 last_irr; /* edge detection */ + u8 irr; /* interrupt request register */ + u8 imr; /* interrupt mask register */ + u8 isr; /* interrupt service register */ + u8 priority_add; /* highest irq priority */ + u8 irq_base; + u8 read_reg_select; + u8 poll; + u8 special_mask; + u8 init_state; + u8 auto_eoi; + u8 rotate_on_auto_eoi; + u8 special_fully_nested_mode; + u8 init4; /* true if 4 byte init */ + u8 elcr; /* PIIX edge/trigger selection */ + u8 elcr_mask; + struct kvm_pic *pics_state; +}; + +struct kvm_pic { + struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */ + irq_request_func *irq_request; + void *irq_request_opaque; + int output; /* intr from master PIC */ + struct kvm_io_device dev; +}; + +struct kvm_pic *kvm_create_pic(struct kvm *kvm); +void kvm_pic_set_irq(void *opaque, int irq, int level); +int kvm_pic_read_irq(struct kvm_pic *s); +int kvm_cpu_get_interrupt(struct kvm_vcpu *v); +int kvm_cpu_has_interrupt(struct kvm_vcpu *v); +void kvm_pic_update_irq(struct kvm_pic *s); + +#define IOAPIC_NUM_PINS KVM_IOAPIC_NUM_PINS +#define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */ +#define IOAPIC_EDGE_TRIG 0 +#define IOAPIC_LEVEL_TRIG 1 + +#define IOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000 +#define IOAPIC_MEM_LENGTH 0x100 + +/* Direct registers. */ +#define IOAPIC_REG_SELECT 0x00 +#define IOAPIC_REG_WINDOW 0x10 +#define IOAPIC_REG_EOI 0x40 /* IA64 IOSAPIC only */ + +/* Indirect registers. */ +#define IOAPIC_REG_APIC_ID 0x00 /* x86 IOAPIC only */ +#define IOAPIC_REG_VERSION 0x01 +#define IOAPIC_REG_ARB_ID 0x02 /* x86 IOAPIC only */ + +struct kvm_ioapic { + u64 base_address; + u32 ioregsel; + u32 id; + u32 irr; + u32 pad; + union ioapic_redir_entry { + u64 bits; + struct { + u8 vector; + u8 delivery_mode:3; + u8 dest_mode:1; + u8 delivery_status:1; + u8 polarity:1; + u8 remote_irr:1; + u8 trig_mode:1; + u8 mask:1; + u8 reserve:7; + u8 reserved[4]; + u8 dest_id; + } fields; + } redirtbl[IOAPIC_NUM_PINS]; + struct kvm_io_device dev; + struct kvm *kvm; +}; + +struct kvm_lapic { + unsigned long base_address; + struct kvm_io_device dev; + struct { + atomic_t pending; + s64 period; /* unit: ns */ + u32 divide_count; + ktime_t last_update; + struct hrtimer dev; + } timer; + struct kvm_vcpu *vcpu; + struct page *regs_page; + void *regs; +}; + +#ifdef DEBUG +#define ASSERT(x) \ +do { \ + if (!(x)) { \ + printk(KERN_EMERG "assertion failed %s: %d: %s\n", \ + __FILE__, __LINE__, #x); \ + BUG(); \ + } \ +} while (0) +#else +#define ASSERT(x) do { } while (0) +#endif + +void kvm_vcpu_kick(struct kvm_vcpu *vcpu); +int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu); +int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu); +int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu); +int kvm_create_lapic(struct kvm_vcpu *vcpu); +void kvm_lapic_reset(struct kvm_vcpu *vcpu); +void kvm_free_apic(struct kvm_lapic *apic); +u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu); +void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); +void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); +struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector, + unsigned long bitmap); +u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); +void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); +int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest); +void kvm_ioapic_update_eoi(struct kvm *kvm, int vector); +int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); +int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig); +void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); +int kvm_ioapic_init(struct kvm *kvm); +void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); +int kvm_lapic_enabled(struct kvm_vcpu *vcpu); +int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); +void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec); +void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec); +void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); +void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); +void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); + +#endif diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index 336be86c6f5..ad0813843ad 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h @@ -13,60 +13,38 @@ #include <linux/signal.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/preempt.h> #include <asm/signal.h> -#include "vmx.h" #include <linux/kvm.h> #include <linux/kvm_para.h> -#define CR0_PE_MASK (1ULL << 0) -#define CR0_MP_MASK (1ULL << 1) -#define CR0_TS_MASK (1ULL << 3) -#define CR0_NE_MASK (1ULL << 5) -#define CR0_WP_MASK (1ULL << 16) -#define CR0_NW_MASK (1ULL << 29) -#define CR0_CD_MASK (1ULL << 30) -#define CR0_PG_MASK (1ULL << 31) - -#define CR3_WPT_MASK (1ULL << 3) -#define CR3_PCD_MASK (1ULL << 4) - -#define CR3_RESEVED_BITS 0x07ULL -#define CR3_L_MODE_RESEVED_BITS (~((1ULL << 40) - 1) | 0x0fe7ULL) -#define CR3_FLAGS_MASK ((1ULL << 5) - 1) - -#define CR4_VME_MASK (1ULL << 0) -#define CR4_PSE_MASK (1ULL << 4) -#define CR4_PAE_MASK (1ULL << 5) -#define CR4_PGE_MASK (1ULL << 7) -#define CR4_VMXE_MASK (1ULL << 13) +#define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1) +#define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD)) +#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS|0xFFFFFF0000000000ULL) #define KVM_GUEST_CR0_MASK \ - (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK \ - | CR0_NW_MASK | CR0_CD_MASK) + (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE \ + | X86_CR0_NW | X86_CR0_CD) #define KVM_VM_CR0_ALWAYS_ON \ - (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK | CR0_TS_MASK \ - | CR0_MP_MASK) + (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE | X86_CR0_TS \ + | X86_CR0_MP) #define KVM_GUEST_CR4_MASK \ - (CR4_PSE_MASK | CR4_PAE_MASK | CR4_PGE_MASK | CR4_VMXE_MASK | CR4_VME_MASK) -#define KVM_PMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK) -#define KVM_RMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK | CR4_VME_MASK) + (X86_CR4_VME | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_VMXE) +#define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE) +#define KVM_RMODE_VM_CR4_ALWAYS_ON (X86_CR4_VME | X86_CR4_PAE | X86_CR4_VMXE) #define INVALID_PAGE (~(hpa_t)0) #define UNMAPPED_GVA (~(gpa_t)0) #define KVM_MAX_VCPUS 4 #define KVM_ALIAS_SLOTS 4 -#define KVM_MEMORY_SLOTS 4 +#define KVM_MEMORY_SLOTS 8 #define KVM_NUM_MMU_PAGES 1024 #define KVM_MIN_FREE_MMU_PAGES 5 #define KVM_REFILL_PAGES 25 #define KVM_MAX_CPUID_ENTRIES 40 -#define FX_IMAGE_SIZE 512 -#define FX_IMAGE_ALIGN 16 -#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN) - #define DE_VECTOR 0 #define NM_VECTOR 7 #define DF_VECTOR 8 @@ -158,15 +136,8 @@ struct kvm_mmu_page { }; }; -struct vmcs { - u32 revision_id; - u32 abort; - char data[0]; -}; - -#define vmx_msr_entry kvm_msr_entry - struct kvm_vcpu; +extern struct kmem_cache *kvm_vcpu_cache; /* * x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level @@ -260,6 +231,7 @@ struct kvm_stat { u32 signal_exits; u32 irq_window_exits; u32 halt_exits; + u32 halt_wakeup; u32 request_irq_exits; u32 irq_exits; u32 light_exits; @@ -328,21 +300,17 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus, struct kvm_vcpu { struct kvm *kvm; - union { - struct vmcs *vmcs; - struct vcpu_svm *svm; - }; + struct preempt_notifier preempt_notifier; + int vcpu_id; struct mutex mutex; int cpu; - int launched; u64 host_tsc; struct kvm_run *run; int interrupt_window_open; int guest_mode; unsigned long requests; unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */ -#define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long) - unsigned long irq_pending[NR_IRQ_WORDS]; + DECLARE_BITMAP(irq_pending, KVM_NR_INTERRUPTS); unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */ unsigned long rip; /* needs vcpu_load_rsp_rip() */ @@ -357,15 +325,15 @@ struct kvm_vcpu { u64 pdptrs[4]; /* pae */ u64 shadow_efer; u64 apic_base; + struct kvm_lapic *apic; /* kernel irqchip context */ +#define VCPU_MP_STATE_RUNNABLE 0 +#define VCPU_MP_STATE_UNINITIALIZED 1 +#define VCPU_MP_STATE_INIT_RECEIVED 2 +#define VCPU_MP_STATE_SIPI_RECEIVED 3 +#define VCPU_MP_STATE_HALTED 4 + int mp_state; + int sipi_vector; u64 ia32_misc_enable_msr; - int nmsrs; - int save_nmsrs; - int msr_offset_efer; -#ifdef CONFIG_X86_64 - int msr_offset_kernel_gs_base; -#endif - struct vmx_msr_entry *guest_msrs; - struct vmx_msr_entry *host_msrs; struct kvm_mmu mmu; @@ -379,16 +347,10 @@ struct kvm_vcpu { struct kvm_guest_debug guest_debug; - char fx_buf[FX_BUF_SIZE]; - char *host_fx_image; - char *guest_fx_image; + struct i387_fxsave_struct host_fx_image; + struct i387_fxsave_struct guest_fx_image; int fpu_active; int guest_fpu_loaded; - struct vmx_host_state { - int loaded; - u16 fs_sel, gs_sel, ldt_sel; - int fs_gs_ldt_reload_needed; - } vmx_host_state; int mmio_needed; int mmio_read_completed; @@ -399,6 +361,7 @@ struct kvm_vcpu { gva_t mmio_fault_cr2; struct kvm_pio_request pio; void *pio_data; + wait_queue_head_t wq; int sigset_active; sigset_t sigset; @@ -436,7 +399,7 @@ struct kvm_memory_slot { }; struct kvm { - spinlock_t lock; /* protects everything except vcpus */ + struct mutex lock; /* protects everything except vcpus */ int naliases; struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS]; int nmemslots; @@ -447,39 +410,59 @@ struct kvm { struct list_head active_mmu_pages; int n_free_mmu_pages; struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES]; - int nvcpus; - struct kvm_vcpu vcpus[KVM_MAX_VCPUS]; - int memory_config_version; - int busy; + struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; unsigned long rmap_overflow; struct list_head vm_list; struct file *filp; struct kvm_io_bus mmio_bus; struct kvm_io_bus pio_bus; + struct kvm_pic *vpic; + struct kvm_ioapic *vioapic; + int round_robin_prev_vcpu; }; +static inline struct kvm_pic *pic_irqchip(struct kvm *kvm) +{ + return kvm->vpic; +} + +static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm) +{ + return kvm->vioapic; +} + +static inline int irqchip_in_kernel(struct kvm *kvm) +{ + return pic_irqchip(kvm) != 0; +} + struct descriptor_table { u16 limit; unsigned long base; } __attribute__((packed)); -struct kvm_arch_ops { +struct kvm_x86_ops { int (*cpu_has_kvm_support)(void); /* __init */ int (*disabled_by_bios)(void); /* __init */ void (*hardware_enable)(void *dummy); /* __init */ void (*hardware_disable)(void *dummy); + void (*check_processor_compatibility)(void *rtn); int (*hardware_setup)(void); /* __init */ void (*hardware_unsetup)(void); /* __exit */ - int (*vcpu_create)(struct kvm_vcpu *vcpu); + /* Create, but do not attach this VCPU */ + struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id); void (*vcpu_free)(struct kvm_vcpu *vcpu); + void (*vcpu_reset)(struct kvm_vcpu *vcpu); - void (*vcpu_load)(struct kvm_vcpu *vcpu); + void (*prepare_guest_switch)(struct kvm_vcpu *vcpu); + void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu); void (*vcpu_put)(struct kvm_vcpu *vcpu); void (*vcpu_decache)(struct kvm_vcpu *vcpu); int (*set_guest_debug)(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg); + void (*guest_debug_pre)(struct kvm_vcpu *vcpu); int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata); int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg); @@ -505,27 +488,43 @@ struct kvm_arch_ops { unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags); - void (*invlpg)(struct kvm_vcpu *vcpu, gva_t addr); void (*tlb_flush)(struct kvm_vcpu *vcpu); void (*inject_page_fault)(struct kvm_vcpu *vcpu, unsigned long addr, u32 err_code); void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code); - int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run); - int (*vcpu_setup)(struct kvm_vcpu *vcpu); + void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run); + int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu); void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu); void (*patch_hypercall)(struct kvm_vcpu *vcpu, unsigned char *hypercall_addr); + int (*get_irq)(struct kvm_vcpu *vcpu); + void (*set_irq)(struct kvm_vcpu *vcpu, int vec); + void (*inject_pending_irq)(struct kvm_vcpu *vcpu); + void (*inject_pending_vectors)(struct kvm_vcpu *vcpu, + struct kvm_run *run); }; -extern struct kvm_arch_ops *kvm_arch_ops; +extern struct kvm_x86_ops *kvm_x86_ops; + +/* The guest did something we don't support. */ +#define pr_unimpl(vcpu, fmt, ...) \ + do { \ + if (printk_ratelimit()) \ + printk(KERN_ERR "kvm: %i: cpu%i " fmt, \ + current->tgid, (vcpu)->vcpu_id , ## __VA_ARGS__); \ + } while(0) #define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt) #define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt) -int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module); -void kvm_exit_arch(void); +int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id); +void kvm_vcpu_uninit(struct kvm_vcpu *vcpu); + +int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size, + struct module *module); +void kvm_exit_x86(void); int kvm_mmu_module_init(void); void kvm_mmu_module_exit(void); @@ -545,8 +544,6 @@ static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; } hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva); struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva); -void kvm_emulator_want_group7_invlpg(void); - extern hpa_t bad_page_address; struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); @@ -561,6 +558,7 @@ enum emulation_result { int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run, unsigned long cr2, u16 error_code); +void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context); void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, @@ -574,9 +572,11 @@ int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); struct x86_emulate_ctxt; -int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, - int size, unsigned long count, int string, int down, - gva_t address, int rep, unsigned port); +int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned port); +int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned long count, int down, + gva_t address, int rep, unsigned port); void kvm_emulate_cpuid(struct kvm_vcpu *vcpu); int kvm_emulate_halt(struct kvm_vcpu *vcpu); int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address); @@ -590,34 +590,33 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0); void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0); void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0); +unsigned long get_cr8(struct kvm_vcpu *vcpu); void lmsw(struct kvm_vcpu *vcpu, unsigned long msw); +void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l); int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data); void fx_init(struct kvm_vcpu *vcpu); -void load_msrs(struct vmx_msr_entry *e, int n); -void save_msrs(struct vmx_msr_entry *e, int n); void kvm_resched(struct kvm_vcpu *vcpu); void kvm_load_guest_fpu(struct kvm_vcpu *vcpu); void kvm_put_guest_fpu(struct kvm_vcpu *vcpu); void kvm_flush_remote_tlbs(struct kvm *kvm); -int kvm_read_guest(struct kvm_vcpu *vcpu, - gva_t addr, - unsigned long size, - void *dest); - -int kvm_write_guest(struct kvm_vcpu *vcpu, - gva_t addr, - unsigned long size, - void *data); +int emulator_read_std(unsigned long addr, + void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu); +int emulator_write_emulated(unsigned long addr, + const void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu); unsigned long segment_base(u16 selector); void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, - const u8 *old, const u8 *new, int bytes); + const u8 *new, int bytes); int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva); void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu); int kvm_mmu_load(struct kvm_vcpu *vcpu); @@ -656,17 +655,17 @@ static inline int is_long_mode(struct kvm_vcpu *vcpu) static inline int is_pae(struct kvm_vcpu *vcpu) { - return vcpu->cr4 & CR4_PAE_MASK; + return vcpu->cr4 & X86_CR4_PAE; } static inline int is_pse(struct kvm_vcpu *vcpu) { - return vcpu->cr4 & CR4_PSE_MASK; + return vcpu->cr4 & X86_CR4_PSE; } static inline int is_paging(struct kvm_vcpu *vcpu) { - return vcpu->cr0 & CR0_PG_MASK; + return vcpu->cr0 & X86_CR0_PG; } static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot) @@ -746,12 +745,12 @@ static inline unsigned long read_msr(unsigned long msr) } #endif -static inline void fx_save(void *image) +static inline void fx_save(struct i387_fxsave_struct *image) { asm ("fxsave (%0)":: "r" (image)); } -static inline void fx_restore(void *image) +static inline void fx_restore(struct i387_fxsave_struct *image) { asm ("fxrstor (%0)":: "r" (image)); } diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index cd0557954e5..353e58527d1 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -18,6 +18,7 @@ #include "kvm.h" #include "x86_emulate.h" #include "segment_descriptor.h" +#include "irq.h" #include <linux/kvm.h> #include <linux/module.h> @@ -37,6 +38,7 @@ #include <linux/cpumask.h> #include <linux/smp.h> #include <linux/anon_inodes.h> +#include <linux/profile.h> #include <asm/processor.h> #include <asm/msr.h> @@ -52,9 +54,11 @@ static LIST_HEAD(vm_list); static cpumask_t cpus_hardware_enabled; -struct kvm_arch_ops *kvm_arch_ops; +struct kvm_x86_ops *kvm_x86_ops; +struct kmem_cache *kvm_vcpu_cache; +EXPORT_SYMBOL_GPL(kvm_vcpu_cache); -static void hardware_disable(void *ignored); +static __read_mostly struct preempt_ops kvm_preempt_ops; #define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x) @@ -73,6 +77,7 @@ static struct kvm_stats_debugfs_item { { "signal_exits", STAT_OFFSET(signal_exits) }, { "irq_window", STAT_OFFSET(irq_window_exits) }, { "halt_exits", STAT_OFFSET(halt_exits) }, + { "halt_wakeup", STAT_OFFSET(halt_wakeup) }, { "request_irq", STAT_OFFSET(request_irq_exits) }, { "irq_exits", STAT_OFFSET(irq_exits) }, { "light_exits", STAT_OFFSET(light_exits) }, @@ -84,10 +89,17 @@ static struct dentry *debugfs_dir; #define MAX_IO_MSRS 256 -#define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL -#define LMSW_GUEST_MASK 0x0eULL -#define CR4_RESEVED_BITS (~((1ULL << 11) - 1)) -#define CR8_RESEVED_BITS (~0x0fULL) +#define CR0_RESERVED_BITS \ + (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \ + | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \ + | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG)) +#define CR4_RESERVED_BITS \ + (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\ + | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \ + | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR \ + | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE)) + +#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR) #define EFER_RESERVED_BITS 0xfffffffffffff2fe #ifdef CONFIG_X86_64 @@ -139,82 +151,14 @@ static inline int valid_vcpu(int n) return likely(n >= 0 && n < KVM_MAX_VCPUS); } -int kvm_read_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size, - void *dest) -{ - unsigned char *host_buf = dest; - unsigned long req_size = size; - - while (size) { - hpa_t paddr; - unsigned now; - unsigned offset; - hva_t guest_buf; - - paddr = gva_to_hpa(vcpu, addr); - - if (is_error_hpa(paddr)) - break; - - guest_buf = (hva_t)kmap_atomic( - pfn_to_page(paddr >> PAGE_SHIFT), - KM_USER0); - offset = addr & ~PAGE_MASK; - guest_buf |= offset; - now = min(size, PAGE_SIZE - offset); - memcpy(host_buf, (void*)guest_buf, now); - host_buf += now; - addr += now; - size -= now; - kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0); - } - return req_size - size; -} -EXPORT_SYMBOL_GPL(kvm_read_guest); - -int kvm_write_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size, - void *data) -{ - unsigned char *host_buf = data; - unsigned long req_size = size; - - while (size) { - hpa_t paddr; - unsigned now; - unsigned offset; - hva_t guest_buf; - gfn_t gfn; - - paddr = gva_to_hpa(vcpu, addr); - - if (is_error_hpa(paddr)) - break; - - gfn = vcpu->mmu.gva_to_gpa(vcpu, addr) >> PAGE_SHIFT; - mark_page_dirty(vcpu->kvm, gfn); - guest_buf = (hva_t)kmap_atomic( - pfn_to_page(paddr >> PAGE_SHIFT), KM_USER0); - offset = addr & ~PAGE_MASK; - guest_buf |= offset; - now = min(size, PAGE_SIZE - offset); - memcpy((void*)guest_buf, host_buf, now); - host_buf += now; - addr += now; - size -= now; - kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0); - } - return req_size - size; -} -EXPORT_SYMBOL_GPL(kvm_write_guest); - void kvm_load_guest_fpu(struct kvm_vcpu *vcpu) { if (!vcpu->fpu_active || vcpu->guest_fpu_loaded) return; vcpu->guest_fpu_loaded = 1; - fx_save(vcpu->host_fx_image); - fx_restore(vcpu->guest_fx_image); + fx_save(&vcpu->host_fx_image); + fx_restore(&vcpu->guest_fx_image); } EXPORT_SYMBOL_GPL(kvm_load_guest_fpu); @@ -224,8 +168,8 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) return; vcpu->guest_fpu_loaded = 0; - fx_save(vcpu->guest_fx_image); - fx_restore(vcpu->host_fx_image); + fx_save(&vcpu->guest_fx_image); + fx_restore(&vcpu->host_fx_image); } EXPORT_SYMBOL_GPL(kvm_put_guest_fpu); @@ -234,13 +178,21 @@ EXPORT_SYMBOL_GPL(kvm_put_guest_fpu); */ static void vcpu_load(struct kvm_vcpu *vcpu) { + int cpu; + mutex_lock(&vcpu->mutex); - kvm_arch_ops->vcpu_load(vcpu); + cpu = get_cpu(); + preempt_notifier_register(&vcpu->preempt_notifier); + kvm_x86_ops->vcpu_load(vcpu, cpu); + put_cpu(); } static void vcpu_put(struct kvm_vcpu *vcpu) { - kvm_arch_ops->vcpu_put(vcpu); + preempt_disable(); + kvm_x86_ops->vcpu_put(vcpu); + preempt_notifier_unregister(&vcpu->preempt_notifier); + preempt_enable(); mutex_unlock(&vcpu->mutex); } @@ -261,8 +213,10 @@ void kvm_flush_remote_tlbs(struct kvm *kvm) atomic_set(&completed, 0); cpus_clear(cpus); needed = 0; - for (i = 0; i < kvm->nvcpus; ++i) { - vcpu = &kvm->vcpus[i]; + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = kvm->vcpus[i]; + if (!vcpu) + continue; if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests)) continue; cpu = vcpu->cpu; @@ -286,37 +240,79 @@ void kvm_flush_remote_tlbs(struct kvm *kvm) } } +int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) +{ + struct page *page; + int r; + + mutex_init(&vcpu->mutex); + vcpu->cpu = -1; + vcpu->mmu.root_hpa = INVALID_PAGE; + vcpu->kvm = kvm; + vcpu->vcpu_id = id; + if (!irqchip_in_kernel(kvm) || id == 0) + vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; + else + vcpu->mp_state = VCPU_MP_STATE_UNINITIALIZED; + init_waitqueue_head(&vcpu->wq); + + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) { + r = -ENOMEM; + goto fail; + } + vcpu->run = page_address(page); + + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) { + r = -ENOMEM; + goto fail_free_run; + } + vcpu->pio_data = page_address(page); + + r = kvm_mmu_create(vcpu); + if (r < 0) + goto fail_free_pio_data; + + return 0; + +fail_free_pio_data: + free_page((unsigned long)vcpu->pio_data); +fail_free_run: + free_page((unsigned long)vcpu->run); +fail: + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(kvm_vcpu_init); + +void kvm_vcpu_uninit(struct kvm_vcpu *vcpu) +{ + kvm_mmu_destroy(vcpu); + if (vcpu->apic) + hrtimer_cancel(&vcpu->apic->timer.dev); + kvm_free_apic(vcpu->apic); + free_page((unsigned long)vcpu->pio_data); + free_page((unsigned long)vcpu->run); +} +EXPORT_SYMBOL_GPL(kvm_vcpu_uninit); + static struct kvm *kvm_create_vm(void) { struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL); - int i; if (!kvm) return ERR_PTR(-ENOMEM); kvm_io_bus_init(&kvm->pio_bus); - spin_lock_init(&kvm->lock); + mutex_init(&kvm->lock); INIT_LIST_HEAD(&kvm->active_mmu_pages); kvm_io_bus_init(&kvm->mmio_bus); - for (i = 0; i < KVM_MAX_VCPUS; ++i) { - struct kvm_vcpu *vcpu = &kvm->vcpus[i]; - - mutex_init(&vcpu->mutex); - vcpu->cpu = -1; - vcpu->kvm = kvm; - vcpu->mmu.root_hpa = INVALID_PAGE; - } spin_lock(&kvm_lock); list_add(&kvm->vm_list, &vm_list); spin_unlock(&kvm_lock); return kvm; } -static int kvm_dev_open(struct inode *inode, struct file *filp) -{ - return 0; -} - /* * Free any memory in @free but not in @dont. */ @@ -353,7 +349,7 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu) { int i; - for (i = 0; i < 2; ++i) + for (i = 0; i < ARRAY_SIZE(vcpu->pio.guest_pages); ++i) if (vcpu->pio.guest_pages[i]) { __free_page(vcpu->pio.guest_pages[i]); vcpu->pio.guest_pages[i] = NULL; @@ -362,30 +358,11 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu) static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu) { - if (!vcpu->vmcs) - return; - vcpu_load(vcpu); kvm_mmu_unload(vcpu); vcpu_put(vcpu); } -static void kvm_free_vcpu(struct kvm_vcpu *vcpu) -{ - if (!vcpu->vmcs) - return; - - vcpu_load(vcpu); - kvm_mmu_destroy(vcpu); - vcpu_put(vcpu); - kvm_arch_ops->vcpu_free(vcpu); - free_page((unsigned long)vcpu->run); - vcpu->run = NULL; - free_page((unsigned long)vcpu->pio_data); - vcpu->pio_data = NULL; - free_pio_guest_pages(vcpu); -} - static void kvm_free_vcpus(struct kvm *kvm) { unsigned int i; @@ -394,14 +371,15 @@ static void kvm_free_vcpus(struct kvm *kvm) * Unpin any mmu pages first. */ for (i = 0; i < KVM_MAX_VCPUS; ++i) - kvm_unload_vcpu_mmu(&kvm->vcpus[i]); - for (i = 0; i < KVM_MAX_VCPUS; ++i) - kvm_free_vcpu(&kvm->vcpus[i]); -} + if (kvm->vcpus[i]) + kvm_unload_vcpu_mmu(kvm->vcpus[i]); + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + if (kvm->vcpus[i]) { + kvm_x86_ops->vcpu_free(kvm->vcpus[i]); + kvm->vcpus[i] = NULL; + } + } -static int kvm_dev_release(struct inode *inode, struct file *filp) -{ - return 0; } static void kvm_destroy_vm(struct kvm *kvm) @@ -411,6 +389,8 @@ static void kvm_destroy_vm(struct kvm *kvm) spin_unlock(&kvm_lock); kvm_io_bus_destroy(&kvm->pio_bus); kvm_io_bus_destroy(&kvm->mmio_bus); + kfree(kvm->vpic); + kfree(kvm->vioapic); kvm_free_vcpus(kvm); kvm_free_physmem(kvm); kfree(kvm); @@ -426,7 +406,7 @@ static int kvm_vm_release(struct inode *inode, struct file *filp) static void inject_gp(struct kvm_vcpu *vcpu) { - kvm_arch_ops->inject_gp(vcpu, 0); + kvm_x86_ops->inject_gp(vcpu, 0); } /* @@ -437,58 +417,60 @@ static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT; unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2; int i; - u64 pdpte; u64 *pdpt; int ret; struct page *page; + u64 pdpte[ARRAY_SIZE(vcpu->pdptrs)]; - spin_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->lock); page = gfn_to_page(vcpu->kvm, pdpt_gfn); - /* FIXME: !page - emulate? 0xff? */ + if (!page) { + ret = 0; + goto out; + } + pdpt = kmap_atomic(page, KM_USER0); + memcpy(pdpte, pdpt+offset, sizeof(pdpte)); + kunmap_atomic(pdpt, KM_USER0); - ret = 1; - for (i = 0; i < 4; ++i) { - pdpte = pdpt[offset + i]; - if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) { + for (i = 0; i < ARRAY_SIZE(pdpte); ++i) { + if ((pdpte[i] & 1) && (pdpte[i] & 0xfffffff0000001e6ull)) { ret = 0; goto out; } } + ret = 1; - for (i = 0; i < 4; ++i) - vcpu->pdptrs[i] = pdpt[offset + i]; - + memcpy(vcpu->pdptrs, pdpte, sizeof(vcpu->pdptrs)); out: - kunmap_atomic(pdpt, KM_USER0); - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); return ret; } void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) { - if (cr0 & CR0_RESEVED_BITS) { + if (cr0 & CR0_RESERVED_BITS) { printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n", cr0, vcpu->cr0); inject_gp(vcpu); return; } - if ((cr0 & CR0_NW_MASK) && !(cr0 & CR0_CD_MASK)) { + if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) { printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n"); inject_gp(vcpu); return; } - if ((cr0 & CR0_PG_MASK) && !(cr0 & CR0_PE_MASK)) { + if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) { printk(KERN_DEBUG "set_cr0: #GP, set PG flag " "and a clear PE flag\n"); inject_gp(vcpu); return; } - if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) { + if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) { #ifdef CONFIG_X86_64 if ((vcpu->shadow_efer & EFER_LME)) { int cs_db, cs_l; @@ -499,7 +481,7 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) inject_gp(vcpu); return; } - kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); + kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); if (cs_l) { printk(KERN_DEBUG "set_cr0: #GP, start paging " "in long mode while CS.L == 1\n"); @@ -518,12 +500,12 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) } - kvm_arch_ops->set_cr0(vcpu, cr0); + kvm_x86_ops->set_cr0(vcpu, cr0); vcpu->cr0 = cr0; - spin_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->lock); kvm_mmu_reset_context(vcpu); - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); return; } EXPORT_SYMBOL_GPL(set_cr0); @@ -536,62 +518,72 @@ EXPORT_SYMBOL_GPL(lmsw); void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) { - if (cr4 & CR4_RESEVED_BITS) { + if (cr4 & CR4_RESERVED_BITS) { printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n"); inject_gp(vcpu); return; } if (is_long_mode(vcpu)) { - if (!(cr4 & CR4_PAE_MASK)) { + if (!(cr4 & X86_CR4_PAE)) { printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while " "in long mode\n"); inject_gp(vcpu); return; } - } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK) + } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & X86_CR4_PAE) && !load_pdptrs(vcpu, vcpu->cr3)) { printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n"); inject_gp(vcpu); + return; } - if (cr4 & CR4_VMXE_MASK) { + if (cr4 & X86_CR4_VMXE) { printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n"); inject_gp(vcpu); return; } - kvm_arch_ops->set_cr4(vcpu, cr4); - spin_lock(&vcpu->kvm->lock); + kvm_x86_ops->set_cr4(vcpu, cr4); + vcpu->cr4 = cr4; + mutex_lock(&vcpu->kvm->lock); kvm_mmu_reset_context(vcpu); - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); } EXPORT_SYMBOL_GPL(set_cr4); void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) { if (is_long_mode(vcpu)) { - if (cr3 & CR3_L_MODE_RESEVED_BITS) { + if (cr3 & CR3_L_MODE_RESERVED_BITS) { printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n"); inject_gp(vcpu); return; } } else { - if (cr3 & CR3_RESEVED_BITS) { - printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n"); - inject_gp(vcpu); - return; - } - if (is_paging(vcpu) && is_pae(vcpu) && - !load_pdptrs(vcpu, cr3)) { - printk(KERN_DEBUG "set_cr3: #GP, pdptrs " - "reserved bits\n"); - inject_gp(vcpu); - return; + if (is_pae(vcpu)) { + if (cr3 & CR3_PAE_RESERVED_BITS) { + printk(KERN_DEBUG + "set_cr3: #GP, reserved bits\n"); + inject_gp(vcpu); + return; + } + if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) { + printk(KERN_DEBUG "set_cr3: #GP, pdptrs " + "reserved bits\n"); + inject_gp(vcpu); + return; + } + } else { + if (cr3 & CR3_NONPAE_RESERVED_BITS) { + printk(KERN_DEBUG + "set_cr3: #GP, reserved bits\n"); + inject_gp(vcpu); + return; + } } } - vcpu->cr3 = cr3; - spin_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->lock); /* * Does the new cr3 value map to physical memory? (Note, we * catch an invalid cr3 even in real-mode, because it would @@ -603,46 +595,73 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) */ if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT))) inject_gp(vcpu); - else + else { + vcpu->cr3 = cr3; vcpu->mmu.new_cr3(vcpu); - spin_unlock(&vcpu->kvm->lock); + } + mutex_unlock(&vcpu->kvm->lock); } EXPORT_SYMBOL_GPL(set_cr3); void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) { - if ( cr8 & CR8_RESEVED_BITS) { + if (cr8 & CR8_RESERVED_BITS) { printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8); inject_gp(vcpu); return; } - vcpu->cr8 = cr8; + if (irqchip_in_kernel(vcpu->kvm)) + kvm_lapic_set_tpr(vcpu, cr8); + else + vcpu->cr8 = cr8; } EXPORT_SYMBOL_GPL(set_cr8); -void fx_init(struct kvm_vcpu *vcpu) +unsigned long get_cr8(struct kvm_vcpu *vcpu) +{ + if (irqchip_in_kernel(vcpu->kvm)) + return kvm_lapic_get_cr8(vcpu); + else + return vcpu->cr8; +} +EXPORT_SYMBOL_GPL(get_cr8); + +u64 kvm_get_apic_base(struct kvm_vcpu *vcpu) { - struct __attribute__ ((__packed__)) fx_image_s { - u16 control; //fcw - u16 status; //fsw - u16 tag; // ftw - u16 opcode; //fop - u64 ip; // fpu ip - u64 operand;// fpu dp - u32 mxcsr; - u32 mxcsr_mask; + if (irqchip_in_kernel(vcpu->kvm)) + return vcpu->apic_base; + else + return vcpu->apic_base; +} +EXPORT_SYMBOL_GPL(kvm_get_apic_base); - } *fx_image; +void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data) +{ + /* TODO: reserve bits check */ + if (irqchip_in_kernel(vcpu->kvm)) + kvm_lapic_set_base(vcpu, data); + else + vcpu->apic_base = data; +} +EXPORT_SYMBOL_GPL(kvm_set_apic_base); + +void fx_init(struct kvm_vcpu *vcpu) +{ + unsigned after_mxcsr_mask; - fx_save(vcpu->host_fx_image); + /* Initialize guest FPU by resetting ours and saving into guest's */ + preempt_disable(); + fx_save(&vcpu->host_fx_image); fpu_init(); - fx_save(vcpu->guest_fx_image); - fx_restore(vcpu->host_fx_image); + fx_save(&vcpu->guest_fx_image); + fx_restore(&vcpu->host_fx_image); + preempt_enable(); - fx_image = (struct fx_image_s *)vcpu->guest_fx_image; - fx_image->mxcsr = 0x1f80; - memset(vcpu->guest_fx_image + sizeof(struct fx_image_s), - 0, FX_IMAGE_SIZE - sizeof(struct fx_image_s)); + vcpu->cr0 |= X86_CR0_ET; + after_mxcsr_mask = offsetof(struct i387_fxsave_struct, st_space); + vcpu->guest_fx_image.mxcsr = 0x1f80; + memset((void *)&vcpu->guest_fx_image + after_mxcsr_mask, + 0, sizeof(struct i387_fxsave_struct) - after_mxcsr_mask); } EXPORT_SYMBOL_GPL(fx_init); @@ -661,7 +680,6 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, unsigned long i; struct kvm_memory_slot *memslot; struct kvm_memory_slot old, new; - int memory_config_version; r = -EINVAL; /* General sanity checks */ @@ -681,10 +699,8 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, if (!npages) mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES; -raced: - spin_lock(&kvm->lock); + mutex_lock(&kvm->lock); - memory_config_version = kvm->memory_config_version; new = old = *memslot; new.base_gfn = base_gfn; @@ -707,11 +723,6 @@ raced: (base_gfn >= s->base_gfn + s->npages))) goto out_unlock; } - /* - * Do memory allocations outside lock. memory_config_version will - * detect any races. - */ - spin_unlock(&kvm->lock); /* Deallocate if slot is being removed */ if (!npages) @@ -728,14 +739,14 @@ raced: new.phys_mem = vmalloc(npages * sizeof(struct page *)); if (!new.phys_mem) - goto out_free; + goto out_unlock; memset(new.phys_mem, 0, npages * sizeof(struct page *)); for (i = 0; i < npages; ++i) { new.phys_mem[i] = alloc_page(GFP_HIGHUSER | __GFP_ZERO); if (!new.phys_mem[i]) - goto out_free; + goto out_unlock; set_page_private(new.phys_mem[i],0); } } @@ -746,39 +757,25 @@ raced: new.dirty_bitmap = vmalloc(dirty_bytes); if (!new.dirty_bitmap) - goto out_free; + goto out_unlock; memset(new.dirty_bitmap, 0, dirty_bytes); } - spin_lock(&kvm->lock); - - if (memory_config_version != kvm->memory_config_version) { - spin_unlock(&kvm->lock); - kvm_free_physmem_slot(&new, &old); - goto raced; - } - - r = -EAGAIN; - if (kvm->busy) - goto out_unlock; - if (mem->slot >= kvm->nmemslots) kvm->nmemslots = mem->slot + 1; *memslot = new; - ++kvm->memory_config_version; kvm_mmu_slot_remove_write_access(kvm, mem->slot); kvm_flush_remote_tlbs(kvm); - spin_unlock(&kvm->lock); + mutex_unlock(&kvm->lock); kvm_free_physmem_slot(&old, &new); return 0; out_unlock: - spin_unlock(&kvm->lock); -out_free: + mutex_unlock(&kvm->lock); kvm_free_physmem_slot(&new, &old); out: return r; @@ -795,14 +792,8 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, int n; unsigned long any = 0; - spin_lock(&kvm->lock); + mutex_lock(&kvm->lock); - /* - * Prevent changes to guest memory configuration even while the lock - * is not taken. - */ - ++kvm->busy; - spin_unlock(&kvm->lock); r = -EINVAL; if (log->slot >= KVM_MEMORY_SLOTS) goto out; @@ -821,18 +812,17 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n)) goto out; - spin_lock(&kvm->lock); - kvm_mmu_slot_remove_write_access(kvm, log->slot); - kvm_flush_remote_tlbs(kvm); - memset(memslot->dirty_bitmap, 0, n); - spin_unlock(&kvm->lock); + /* If nothing is dirty, don't bother messing with page tables. */ + if (any) { + kvm_mmu_slot_remove_write_access(kvm, log->slot); + kvm_flush_remote_tlbs(kvm); + memset(memslot->dirty_bitmap, 0, n); + } r = 0; out: - spin_lock(&kvm->lock); - --kvm->busy; - spin_unlock(&kvm->lock); + mutex_unlock(&kvm->lock); return r; } @@ -862,7 +852,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, < alias->target_phys_addr) goto out; - spin_lock(&kvm->lock); + mutex_lock(&kvm->lock); p = &kvm->aliases[alias->slot]; p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT; @@ -876,7 +866,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, kvm_mmu_zap_all(kvm); - spin_unlock(&kvm->lock); + mutex_unlock(&kvm->lock); return 0; @@ -884,6 +874,63 @@ out: return r; } +static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) +{ + int r; + + r = 0; + switch (chip->chip_id) { + case KVM_IRQCHIP_PIC_MASTER: + memcpy (&chip->chip.pic, + &pic_irqchip(kvm)->pics[0], + sizeof(struct kvm_pic_state)); + break; + case KVM_IRQCHIP_PIC_SLAVE: + memcpy (&chip->chip.pic, + &pic_irqchip(kvm)->pics[1], + sizeof(struct kvm_pic_state)); + break; + case KVM_IRQCHIP_IOAPIC: + memcpy (&chip->chip.ioapic, + ioapic_irqchip(kvm), + sizeof(struct kvm_ioapic_state)); + break; + default: + r = -EINVAL; + break; + } + return r; +} + +static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) +{ + int r; + + r = 0; + switch (chip->chip_id) { + case KVM_IRQCHIP_PIC_MASTER: + memcpy (&pic_irqchip(kvm)->pics[0], + &chip->chip.pic, + sizeof(struct kvm_pic_state)); + break; + case KVM_IRQCHIP_PIC_SLAVE: + memcpy (&pic_irqchip(kvm)->pics[1], + &chip->chip.pic, + sizeof(struct kvm_pic_state)); + break; + case KVM_IRQCHIP_IOAPIC: + memcpy (ioapic_irqchip(kvm), + &chip->chip.ioapic, + sizeof(struct kvm_ioapic_state)); + break; + default: + r = -EINVAL; + break; + } + kvm_pic_update_irq(pic_irqchip(kvm)); + return r; +} + static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) { int i; @@ -930,37 +977,26 @@ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) } EXPORT_SYMBOL_GPL(gfn_to_page); +/* WARNING: Does not work on aliased pages. */ void mark_page_dirty(struct kvm *kvm, gfn_t gfn) { - int i; struct kvm_memory_slot *memslot; - unsigned long rel_gfn; - for (i = 0; i < kvm->nmemslots; ++i) { - memslot = &kvm->memslots[i]; - - if (gfn >= memslot->base_gfn - && gfn < memslot->base_gfn + memslot->npages) { + memslot = __gfn_to_memslot(kvm, gfn); + if (memslot && memslot->dirty_bitmap) { + unsigned long rel_gfn = gfn - memslot->base_gfn; - if (!memslot->dirty_bitmap) - return; - - rel_gfn = gfn - memslot->base_gfn; - - /* avoid RMW */ - if (!test_bit(rel_gfn, memslot->dirty_bitmap)) - set_bit(rel_gfn, memslot->dirty_bitmap); - return; - } + /* avoid RMW */ + if (!test_bit(rel_gfn, memslot->dirty_bitmap)) + set_bit(rel_gfn, memslot->dirty_bitmap); } } -static int emulator_read_std(unsigned long addr, +int emulator_read_std(unsigned long addr, void *val, unsigned int bytes, - struct x86_emulate_ctxt *ctxt) + struct kvm_vcpu *vcpu) { - struct kvm_vcpu *vcpu = ctxt->vcpu; void *data = val; while (bytes) { @@ -990,26 +1026,42 @@ static int emulator_read_std(unsigned long addr, return X86EMUL_CONTINUE; } +EXPORT_SYMBOL_GPL(emulator_read_std); static int emulator_write_std(unsigned long addr, const void *val, unsigned int bytes, - struct x86_emulate_ctxt *ctxt) + struct kvm_vcpu *vcpu) { - printk(KERN_ERR "emulator_write_std: addr %lx n %d\n", - addr, bytes); + pr_unimpl(vcpu, "emulator_write_std: addr %lx n %d\n", addr, bytes); return X86EMUL_UNHANDLEABLE; } +/* + * Only apic need an MMIO device hook, so shortcut now.. + */ +static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu, + gpa_t addr) +{ + struct kvm_io_device *dev; + + if (vcpu->apic) { + dev = &vcpu->apic->dev; + if (dev->in_range(dev, addr)) + return dev; + } + return NULL; +} + static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, gpa_t addr) { - /* - * Note that its important to have this wrapper function because - * in the very near future we will be checking for MMIOs against - * the LAPIC as well as the general MMIO bus - */ - return kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); + struct kvm_io_device *dev; + + dev = vcpu_find_pervcpu_dev(vcpu, addr); + if (dev == NULL) + dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); + return dev; } static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, @@ -1021,9 +1073,8 @@ static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, static int emulator_read_emulated(unsigned long addr, void *val, unsigned int bytes, - struct x86_emulate_ctxt *ctxt) + struct kvm_vcpu *vcpu) { - struct kvm_vcpu *vcpu = ctxt->vcpu; struct kvm_io_device *mmio_dev; gpa_t gpa; @@ -1031,7 +1082,7 @@ static int emulator_read_emulated(unsigned long addr, memcpy(val, vcpu->mmio_data, bytes); vcpu->mmio_read_completed = 0; return X86EMUL_CONTINUE; - } else if (emulator_read_std(addr, val, bytes, ctxt) + } else if (emulator_read_std(addr, val, bytes, vcpu) == X86EMUL_CONTINUE) return X86EMUL_CONTINUE; @@ -1061,7 +1112,6 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, { struct page *page; void *virt; - unsigned offset = offset_in_page(gpa); if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT)) return 0; @@ -1070,7 +1120,7 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, return 0; mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT); virt = kmap_atomic(page, KM_USER0); - kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes); + kvm_mmu_pte_write(vcpu, gpa, val, bytes); memcpy(virt + offset_in_page(gpa), val, bytes); kunmap_atomic(virt, KM_USER0); return 1; @@ -1079,14 +1129,13 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, static int emulator_write_emulated_onepage(unsigned long addr, const void *val, unsigned int bytes, - struct x86_emulate_ctxt *ctxt) + struct kvm_vcpu *vcpu) { - struct kvm_vcpu *vcpu = ctxt->vcpu; struct kvm_io_device *mmio_dev; gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); if (gpa == UNMAPPED_GVA) { - kvm_arch_ops->inject_page_fault(vcpu, addr, 2); + kvm_x86_ops->inject_page_fault(vcpu, addr, 2); return X86EMUL_PROPAGATE_FAULT; } @@ -1111,31 +1160,32 @@ static int emulator_write_emulated_onepage(unsigned long addr, return X86EMUL_CONTINUE; } -static int emulator_write_emulated(unsigned long addr, +int emulator_write_emulated(unsigned long addr, const void *val, unsigned int bytes, - struct x86_emulate_ctxt *ctxt) + struct kvm_vcpu *vcpu) { /* Crossing a page boundary? */ if (((addr + bytes - 1) ^ addr) & PAGE_MASK) { int rc, now; now = -addr & ~PAGE_MASK; - rc = emulator_write_emulated_onepage(addr, val, now, ctxt); + rc = emulator_write_emulated_onepage(addr, val, now, vcpu); if (rc != X86EMUL_CONTINUE) return rc; addr += now; val += now; bytes -= now; } - return emulator_write_emulated_onepage(addr, val, bytes, ctxt); + return emulator_write_emulated_onepage(addr, val, bytes, vcpu); } +EXPORT_SYMBOL_GPL(emulator_write_emulated); static int emulator_cmpxchg_emulated(unsigned long addr, const void *old, const void *new, unsigned int bytes, - struct x86_emulate_ctxt *ctxt) + struct kvm_vcpu *vcpu) { static int reported; @@ -1143,12 +1193,12 @@ static int emulator_cmpxchg_emulated(unsigned long addr, reported = 1; printk(KERN_WARNING "kvm: emulating exchange as write\n"); } - return emulator_write_emulated(addr, new, bytes, ctxt); + return emulator_write_emulated(addr, new, bytes, vcpu); } static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) { - return kvm_arch_ops->get_segment_base(vcpu, seg); + return kvm_x86_ops->get_segment_base(vcpu, seg); } int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address) @@ -1158,10 +1208,8 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address) int emulate_clts(struct kvm_vcpu *vcpu) { - unsigned long cr0; - - cr0 = vcpu->cr0 & ~CR0_TS_MASK; - kvm_arch_ops->set_cr0(vcpu, cr0); + vcpu->cr0 &= ~X86_CR0_TS; + kvm_x86_ops->set_cr0(vcpu, vcpu->cr0); return X86EMUL_CONTINUE; } @@ -1171,11 +1219,10 @@ int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, unsigned long *dest) switch (dr) { case 0 ... 3: - *dest = kvm_arch_ops->get_dr(vcpu, dr); + *dest = kvm_x86_ops->get_dr(vcpu, dr); return X86EMUL_CONTINUE; default: - printk(KERN_DEBUG "%s: unexpected dr %u\n", - __FUNCTION__, dr); + pr_unimpl(vcpu, "%s: unexpected dr %u\n", __FUNCTION__, dr); return X86EMUL_UNHANDLEABLE; } } @@ -1185,7 +1232,7 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value) unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U; int exception; - kvm_arch_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception); + kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception); if (exception) { /* FIXME: better handling */ return X86EMUL_UNHANDLEABLE; @@ -1193,25 +1240,25 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value) return X86EMUL_CONTINUE; } -static void report_emulation_failure(struct x86_emulate_ctxt *ctxt) +void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context) { static int reported; u8 opcodes[4]; - unsigned long rip = ctxt->vcpu->rip; + unsigned long rip = vcpu->rip; unsigned long rip_linear; - rip_linear = rip + get_segment_base(ctxt->vcpu, VCPU_SREG_CS); + rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS); if (reported) return; - emulator_read_std(rip_linear, (void *)opcodes, 4, ctxt); + emulator_read_std(rip_linear, (void *)opcodes, 4, vcpu); - printk(KERN_ERR "emulation failed but !mmio_needed?" - " rip %lx %02x %02x %02x %02x\n", - rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]); + printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n", + context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]); reported = 1; } +EXPORT_SYMBOL_GPL(kvm_report_emulation_failure); struct x86_emulate_ops emulate_ops = { .read_std = emulator_read_std, @@ -1231,12 +1278,12 @@ int emulate_instruction(struct kvm_vcpu *vcpu, int cs_db, cs_l; vcpu->mmio_fault_cr2 = cr2; - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); - kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); + kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); emulate_ctxt.vcpu = vcpu; - emulate_ctxt.eflags = kvm_arch_ops->get_rflags(vcpu); + emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu); emulate_ctxt.cr2 = cr2; emulate_ctxt.mode = (emulate_ctxt.eflags & X86_EFLAGS_VM) ? X86EMUL_MODE_REAL : cs_l @@ -1259,9 +1306,13 @@ int emulate_instruction(struct kvm_vcpu *vcpu, emulate_ctxt.fs_base = get_segment_base(vcpu, VCPU_SREG_FS); vcpu->mmio_is_write = 0; + vcpu->pio.string = 0; r = x86_emulate_memop(&emulate_ctxt, &emulate_ops); + if (vcpu->pio.string) + return EMULATE_DO_MMIO; if ((r || vcpu->mmio_is_write) && run) { + run->exit_reason = KVM_EXIT_MMIO; run->mmio.phys_addr = vcpu->mmio_phys_addr; memcpy(run->mmio.data, vcpu->mmio_data, 8); run->mmio.len = vcpu->mmio_size; @@ -1272,14 +1323,14 @@ int emulate_instruction(struct kvm_vcpu *vcpu, if (kvm_mmu_unprotect_page_virt(vcpu, cr2)) return EMULATE_DONE; if (!vcpu->mmio_needed) { - report_emulation_failure(&emulate_ctxt); + kvm_report_emulation_failure(vcpu, "mmio"); return EMULATE_FAIL; } return EMULATE_DO_MMIO; } - kvm_arch_ops->decache_regs(vcpu); - kvm_arch_ops->set_rflags(vcpu, emulate_ctxt.eflags); + kvm_x86_ops->decache_regs(vcpu); + kvm_x86_ops->set_rflags(vcpu, emulate_ctxt.eflags); if (vcpu->mmio_is_write) { vcpu->mmio_needed = 0; @@ -1290,14 +1341,45 @@ int emulate_instruction(struct kvm_vcpu *vcpu, } EXPORT_SYMBOL_GPL(emulate_instruction); -int kvm_emulate_halt(struct kvm_vcpu *vcpu) +/* + * The vCPU has executed a HLT instruction with in-kernel mode enabled. + */ +static void kvm_vcpu_block(struct kvm_vcpu *vcpu) { - if (vcpu->irq_summary) - return 1; + DECLARE_WAITQUEUE(wait, current); - vcpu->run->exit_reason = KVM_EXIT_HLT; + add_wait_queue(&vcpu->wq, &wait); + + /* + * We will block until either an interrupt or a signal wakes us up + */ + while (!kvm_cpu_has_interrupt(vcpu) + && !signal_pending(current) + && vcpu->mp_state != VCPU_MP_STATE_RUNNABLE + && vcpu->mp_state != VCPU_MP_STATE_SIPI_RECEIVED) { + set_current_state(TASK_INTERRUPTIBLE); + vcpu_put(vcpu); + schedule(); + vcpu_load(vcpu); + } + + __set_current_state(TASK_RUNNING); + remove_wait_queue(&vcpu->wq, &wait); +} + +int kvm_emulate_halt(struct kvm_vcpu *vcpu) +{ ++vcpu->stat.halt_exits; - return 0; + if (irqchip_in_kernel(vcpu->kvm)) { + vcpu->mp_state = VCPU_MP_STATE_HALTED; + kvm_vcpu_block(vcpu); + if (vcpu->mp_state != VCPU_MP_STATE_RUNNABLE) + return -EINTR; + return 1; + } else { + vcpu->run->exit_reason = KVM_EXIT_HLT; + return 0; + } } EXPORT_SYMBOL_GPL(kvm_emulate_halt); @@ -1305,7 +1387,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run) { unsigned long nr, a0, a1, a2, a3, a4, a5, ret; - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); ret = -KVM_EINVAL; #ifdef CONFIG_X86_64 if (is_long_mode(vcpu)) { @@ -1329,6 +1411,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run) } switch (nr) { default: + run->hypercall.nr = nr; run->hypercall.args[0] = a0; run->hypercall.args[1] = a1; run->hypercall.args[2] = a2; @@ -1337,11 +1420,11 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run) run->hypercall.args[5] = a5; run->hypercall.ret = ret; run->hypercall.longmode = is_long_mode(vcpu); - kvm_arch_ops->decache_regs(vcpu); + kvm_x86_ops->decache_regs(vcpu); return 0; } vcpu->regs[VCPU_REGS_RAX] = ret; - kvm_arch_ops->decache_regs(vcpu); + kvm_x86_ops->decache_regs(vcpu); return 1; } EXPORT_SYMBOL_GPL(kvm_hypercall); @@ -1355,26 +1438,26 @@ void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) { struct descriptor_table dt = { limit, base }; - kvm_arch_ops->set_gdt(vcpu, &dt); + kvm_x86_ops->set_gdt(vcpu, &dt); } void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) { struct descriptor_table dt = { limit, base }; - kvm_arch_ops->set_idt(vcpu, &dt); + kvm_x86_ops->set_idt(vcpu, &dt); } void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, unsigned long *rflags) { lmsw(vcpu, msw); - *rflags = kvm_arch_ops->get_rflags(vcpu); + *rflags = kvm_x86_ops->get_rflags(vcpu); } unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr) { - kvm_arch_ops->decache_cr4_guest_bits(vcpu); + kvm_x86_ops->decache_cr4_guest_bits(vcpu); switch (cr) { case 0: return vcpu->cr0; @@ -1396,7 +1479,7 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val, switch (cr) { case 0: set_cr0(vcpu, mk_cr_64(vcpu->cr0, val)); - *rflags = kvm_arch_ops->get_rflags(vcpu); + *rflags = kvm_x86_ops->get_rflags(vcpu); break; case 2: vcpu->cr2 = val; @@ -1439,7 +1522,7 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa) mark_page_dirty(vcpu->kvm, para_state_gpa >> PAGE_SHIFT); para_state_page = pfn_to_page(para_state_hpa >> PAGE_SHIFT); - para_state = kmap_atomic(para_state_page, KM_USER0); + para_state = kmap(para_state_page); printk(KERN_DEBUG ".... guest version: %d\n", para_state->guest_version); printk(KERN_DEBUG ".... size: %d\n", para_state->size); @@ -1470,12 +1553,12 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa) mark_page_dirty(vcpu->kvm, hypercall_gpa >> PAGE_SHIFT); hypercall = kmap_atomic(pfn_to_page(hypercall_hpa >> PAGE_SHIFT), KM_USER1) + (hypercall_hpa & ~PAGE_MASK); - kvm_arch_ops->patch_hypercall(vcpu, hypercall); + kvm_x86_ops->patch_hypercall(vcpu, hypercall); kunmap_atomic(hypercall, KM_USER1); para_state->ret = 0; err_kunmap_skip: - kunmap_atomic(para_state, KM_USER0); + kunmap(para_state_page); return 0; err_gp: return 1; @@ -1511,7 +1594,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) data = 3; break; case MSR_IA32_APICBASE: - data = vcpu->apic_base; + data = kvm_get_apic_base(vcpu); break; case MSR_IA32_MISC_ENABLE: data = vcpu->ia32_misc_enable_msr; @@ -1522,7 +1605,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) break; #endif default: - printk(KERN_ERR "kvm: unhandled rdmsr: 0x%x\n", msr); + pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr); return 1; } *pdata = data; @@ -1537,7 +1620,7 @@ EXPORT_SYMBOL_GPL(kvm_get_msr_common); */ int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) { - return kvm_arch_ops->get_msr(vcpu, msr_index, pdata); + return kvm_x86_ops->get_msr(vcpu, msr_index, pdata); } #ifdef CONFIG_X86_64 @@ -1558,7 +1641,7 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer) return; } - kvm_arch_ops->set_efer(vcpu, efer); + kvm_x86_ops->set_efer(vcpu, efer); efer &= ~EFER_LMA; efer |= vcpu->shadow_efer & EFER_LMA; @@ -1577,11 +1660,11 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) break; #endif case MSR_IA32_MC0_STATUS: - printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n", + pr_unimpl(vcpu, "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n", __FUNCTION__, data); break; case MSR_IA32_MCG_STATUS: - printk(KERN_WARNING "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n", + pr_unimpl(vcpu, "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n", __FUNCTION__, data); break; case MSR_IA32_UCODE_REV: @@ -1589,7 +1672,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) case 0x200 ... 0x2ff: /* MTRRs */ break; case MSR_IA32_APICBASE: - vcpu->apic_base = data; + kvm_set_apic_base(vcpu, data); break; case MSR_IA32_MISC_ENABLE: vcpu->ia32_misc_enable_msr = data; @@ -1601,7 +1684,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) return vcpu_register_para(vcpu, data); default: - printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr); + pr_unimpl(vcpu, "unhandled wrmsr: 0x%x\n", msr); return 1; } return 0; @@ -1615,44 +1698,24 @@ EXPORT_SYMBOL_GPL(kvm_set_msr_common); */ int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) { - return kvm_arch_ops->set_msr(vcpu, msr_index, data); + return kvm_x86_ops->set_msr(vcpu, msr_index, data); } void kvm_resched(struct kvm_vcpu *vcpu) { if (!need_resched()) return; - vcpu_put(vcpu); cond_resched(); - vcpu_load(vcpu); } EXPORT_SYMBOL_GPL(kvm_resched); -void load_msrs(struct vmx_msr_entry *e, int n) -{ - int i; - - for (i = 0; i < n; ++i) - wrmsrl(e[i].index, e[i].data); -} -EXPORT_SYMBOL_GPL(load_msrs); - -void save_msrs(struct vmx_msr_entry *e, int n) -{ - int i; - - for (i = 0; i < n; ++i) - rdmsrl(e[i].index, e[i].data); -} -EXPORT_SYMBOL_GPL(save_msrs); - void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) { int i; u32 function; struct kvm_cpuid_entry *e, *best; - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); function = vcpu->regs[VCPU_REGS_RAX]; vcpu->regs[VCPU_REGS_RAX] = 0; vcpu->regs[VCPU_REGS_RBX] = 0; @@ -1678,8 +1741,8 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) vcpu->regs[VCPU_REGS_RCX] = best->ecx; vcpu->regs[VCPU_REGS_RDX] = best->edx; } - kvm_arch_ops->decache_regs(vcpu); - kvm_arch_ops->skip_emulated_instruction(vcpu); + kvm_x86_ops->decache_regs(vcpu); + kvm_x86_ops->skip_emulated_instruction(vcpu); } EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); @@ -1690,11 +1753,9 @@ static int pio_copy_data(struct kvm_vcpu *vcpu) unsigned bytes; int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1; - kvm_arch_ops->vcpu_put(vcpu); q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE, PAGE_KERNEL); if (!q) { - kvm_arch_ops->vcpu_load(vcpu); free_pio_guest_pages(vcpu); return -ENOMEM; } @@ -1706,7 +1767,6 @@ static int pio_copy_data(struct kvm_vcpu *vcpu) memcpy(p, q, bytes); q -= vcpu->pio.guest_page_offset; vunmap(q); - kvm_arch_ops->vcpu_load(vcpu); free_pio_guest_pages(vcpu); return 0; } @@ -1717,7 +1777,7 @@ static int complete_pio(struct kvm_vcpu *vcpu) long delta; int r; - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); if (!io->string) { if (io->in) @@ -1727,7 +1787,7 @@ static int complete_pio(struct kvm_vcpu *vcpu) if (io->in) { r = pio_copy_data(vcpu); if (r) { - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); return r; } } @@ -1750,79 +1810,109 @@ static int complete_pio(struct kvm_vcpu *vcpu) vcpu->regs[VCPU_REGS_RSI] += delta; } - kvm_arch_ops->decache_regs(vcpu); + kvm_x86_ops->decache_regs(vcpu); io->count -= io->cur_count; io->cur_count = 0; - if (!io->count) - kvm_arch_ops->skip_emulated_instruction(vcpu); return 0; } -void kernel_pio(struct kvm_io_device *pio_dev, struct kvm_vcpu *vcpu) +static void kernel_pio(struct kvm_io_device *pio_dev, + struct kvm_vcpu *vcpu, + void *pd) { /* TODO: String I/O for in kernel device */ + mutex_lock(&vcpu->kvm->lock); if (vcpu->pio.in) kvm_iodevice_read(pio_dev, vcpu->pio.port, vcpu->pio.size, - vcpu->pio_data); + pd); else kvm_iodevice_write(pio_dev, vcpu->pio.port, vcpu->pio.size, - vcpu->pio_data); + pd); + mutex_unlock(&vcpu->kvm->lock); +} + +static void pio_string_write(struct kvm_io_device *pio_dev, + struct kvm_vcpu *vcpu) +{ + struct kvm_pio_request *io = &vcpu->pio; + void *pd = vcpu->pio_data; + int i; + + mutex_lock(&vcpu->kvm->lock); + for (i = 0; i < io->cur_count; i++) { + kvm_iodevice_write(pio_dev, io->port, + io->size, + pd); + pd += io->size; + } + mutex_unlock(&vcpu->kvm->lock); } -int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, - int size, unsigned long count, int string, int down, +int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned port) +{ + struct kvm_io_device *pio_dev; + + vcpu->run->exit_reason = KVM_EXIT_IO; + vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; + vcpu->run->io.size = vcpu->pio.size = size; + vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; + vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = 1; + vcpu->run->io.port = vcpu->pio.port = port; + vcpu->pio.in = in; + vcpu->pio.string = 0; + vcpu->pio.down = 0; + vcpu->pio.guest_page_offset = 0; + vcpu->pio.rep = 0; + + kvm_x86_ops->cache_regs(vcpu); + memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4); + kvm_x86_ops->decache_regs(vcpu); + + kvm_x86_ops->skip_emulated_instruction(vcpu); + + pio_dev = vcpu_find_pio_dev(vcpu, port); + if (pio_dev) { + kernel_pio(pio_dev, vcpu, vcpu->pio_data); + complete_pio(vcpu); + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(kvm_emulate_pio); + +int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned long count, int down, gva_t address, int rep, unsigned port) { unsigned now, in_page; - int i; + int i, ret = 0; int nr_pages = 1; struct page *page; struct kvm_io_device *pio_dev; vcpu->run->exit_reason = KVM_EXIT_IO; vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; - vcpu->run->io.size = size; + vcpu->run->io.size = vcpu->pio.size = size; vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; - vcpu->run->io.count = count; - vcpu->run->io.port = port; - vcpu->pio.count = count; - vcpu->pio.cur_count = count; - vcpu->pio.size = size; + vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = count; + vcpu->run->io.port = vcpu->pio.port = port; vcpu->pio.in = in; - vcpu->pio.port = port; - vcpu->pio.string = string; + vcpu->pio.string = 1; vcpu->pio.down = down; vcpu->pio.guest_page_offset = offset_in_page(address); vcpu->pio.rep = rep; - pio_dev = vcpu_find_pio_dev(vcpu, port); - if (!string) { - kvm_arch_ops->cache_regs(vcpu); - memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4); - kvm_arch_ops->decache_regs(vcpu); - if (pio_dev) { - kernel_pio(pio_dev, vcpu); - complete_pio(vcpu); - return 1; - } - return 0; - } - /* TODO: String I/O for in kernel device */ - if (pio_dev) - printk(KERN_ERR "kvm_setup_pio: no string io support\n"); - if (!count) { - kvm_arch_ops->skip_emulated_instruction(vcpu); + kvm_x86_ops->skip_emulated_instruction(vcpu); return 1; } - now = min(count, PAGE_SIZE / size); - if (!down) in_page = PAGE_SIZE - offset_in_page(address); else @@ -1841,20 +1931,23 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, /* * String I/O in reverse. Yuck. Kill the guest, fix later. */ - printk(KERN_ERR "kvm: guest string pio down\n"); + pr_unimpl(vcpu, "guest string pio down\n"); inject_gp(vcpu); return 1; } vcpu->run->io.count = now; vcpu->pio.cur_count = now; + if (vcpu->pio.cur_count == vcpu->pio.count) + kvm_x86_ops->skip_emulated_instruction(vcpu); + for (i = 0; i < nr_pages; ++i) { - spin_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->lock); page = gva_to_page(vcpu, address + i * PAGE_SIZE); if (page) get_page(page); vcpu->pio.guest_pages[i] = page; - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); if (!page) { inject_gp(vcpu); free_pio_guest_pages(vcpu); @@ -1862,11 +1955,145 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, } } - if (!vcpu->pio.in) - return pio_copy_data(vcpu); - return 0; + pio_dev = vcpu_find_pio_dev(vcpu, port); + if (!vcpu->pio.in) { + /* string PIO write */ + ret = pio_copy_data(vcpu); + if (ret >= 0 && pio_dev) { + pio_string_write(pio_dev, vcpu); + complete_pio(vcpu); + if (vcpu->pio.count == 0) + ret = 1; + } + } else if (pio_dev) + pr_unimpl(vcpu, "no string pio read support yet, " + "port %x size %d count %ld\n", + port, size, count); + + return ret; +} +EXPORT_SYMBOL_GPL(kvm_emulate_pio_string); + +/* + * Check if userspace requested an interrupt window, and that the + * interrupt window is open. + * + * No need to exit to userspace if we already have an interrupt queued. + */ +static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + return (!vcpu->irq_summary && + kvm_run->request_interrupt_window && + vcpu->interrupt_window_open && + (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF)); +} + +static void post_kvm_run_save(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0; + kvm_run->cr8 = get_cr8(vcpu); + kvm_run->apic_base = kvm_get_apic_base(vcpu); + if (irqchip_in_kernel(vcpu->kvm)) + kvm_run->ready_for_interrupt_injection = 1; + else + kvm_run->ready_for_interrupt_injection = + (vcpu->interrupt_window_open && + vcpu->irq_summary == 0); +} + +static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + int r; + + if (unlikely(vcpu->mp_state == VCPU_MP_STATE_SIPI_RECEIVED)) { + printk("vcpu %d received sipi with vector # %x\n", + vcpu->vcpu_id, vcpu->sipi_vector); + kvm_lapic_reset(vcpu); + kvm_x86_ops->vcpu_reset(vcpu); + vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; + } + +preempted: + if (vcpu->guest_debug.enabled) + kvm_x86_ops->guest_debug_pre(vcpu); + +again: + r = kvm_mmu_reload(vcpu); + if (unlikely(r)) + goto out; + + preempt_disable(); + + kvm_x86_ops->prepare_guest_switch(vcpu); + kvm_load_guest_fpu(vcpu); + + local_irq_disable(); + + if (signal_pending(current)) { + local_irq_enable(); + preempt_enable(); + r = -EINTR; + kvm_run->exit_reason = KVM_EXIT_INTR; + ++vcpu->stat.signal_exits; + goto out; + } + + if (irqchip_in_kernel(vcpu->kvm)) + kvm_x86_ops->inject_pending_irq(vcpu); + else if (!vcpu->mmio_read_completed) + kvm_x86_ops->inject_pending_vectors(vcpu, kvm_run); + + vcpu->guest_mode = 1; + + if (vcpu->requests) + if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests)) + kvm_x86_ops->tlb_flush(vcpu); + + kvm_x86_ops->run(vcpu, kvm_run); + + vcpu->guest_mode = 0; + local_irq_enable(); + + ++vcpu->stat.exits; + + preempt_enable(); + + /* + * Profile KVM exit RIPs: + */ + if (unlikely(prof_on == KVM_PROFILING)) { + kvm_x86_ops->cache_regs(vcpu); + profile_hit(KVM_PROFILING, (void *)vcpu->rip); + } + + r = kvm_x86_ops->handle_exit(kvm_run, vcpu); + + if (r > 0) { + if (dm_request_for_irq_injection(vcpu, kvm_run)) { + r = -EINTR; + kvm_run->exit_reason = KVM_EXIT_INTR; + ++vcpu->stat.request_irq_exits; + goto out; + } + if (!need_resched()) { + ++vcpu->stat.light_exits; + goto again; + } + } + +out: + if (r > 0) { + kvm_resched(vcpu); + goto preempted; + } + + post_kvm_run_save(vcpu, kvm_run); + + return r; } -EXPORT_SYMBOL_GPL(kvm_setup_pio); + static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { @@ -1875,11 +2102,18 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) vcpu_load(vcpu); + if (unlikely(vcpu->mp_state == VCPU_MP_STATE_UNINITIALIZED)) { + kvm_vcpu_block(vcpu); + vcpu_put(vcpu); + return -EAGAIN; + } + if (vcpu->sigset_active) sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); /* re-sync apic's tpr */ - vcpu->cr8 = kvm_run->cr8; + if (!irqchip_in_kernel(vcpu->kvm)) + set_cr8(vcpu, kvm_run->cr8); if (vcpu->pio.cur_count) { r = complete_pio(vcpu); @@ -1897,19 +2131,18 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) /* * Read-modify-write. Back to userspace. */ - kvm_run->exit_reason = KVM_EXIT_MMIO; r = 0; goto out; } } if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL) { - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); vcpu->regs[VCPU_REGS_RAX] = kvm_run->hypercall.ret; - kvm_arch_ops->decache_regs(vcpu); + kvm_x86_ops->decache_regs(vcpu); } - r = kvm_arch_ops->run(vcpu, kvm_run); + r = __vcpu_run(vcpu, kvm_run); out: if (vcpu->sigset_active) @@ -1924,7 +2157,7 @@ static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, { vcpu_load(vcpu); - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); regs->rax = vcpu->regs[VCPU_REGS_RAX]; regs->rbx = vcpu->regs[VCPU_REGS_RBX]; @@ -1946,7 +2179,7 @@ static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, #endif regs->rip = vcpu->rip; - regs->rflags = kvm_arch_ops->get_rflags(vcpu); + regs->rflags = kvm_x86_ops->get_rflags(vcpu); /* * Don't leak debug flags in case they were set for guest debugging @@ -1984,9 +2217,9 @@ static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, #endif vcpu->rip = regs->rip; - kvm_arch_ops->set_rflags(vcpu, regs->rflags); + kvm_x86_ops->set_rflags(vcpu, regs->rflags); - kvm_arch_ops->decache_regs(vcpu); + kvm_x86_ops->decache_regs(vcpu); vcpu_put(vcpu); @@ -1996,13 +2229,14 @@ static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, static void get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg) { - return kvm_arch_ops->get_segment(vcpu, var, seg); + return kvm_x86_ops->get_segment(vcpu, var, seg); } static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { struct descriptor_table dt; + int pending_vec; vcpu_load(vcpu); @@ -2016,24 +2250,31 @@ static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, get_segment(vcpu, &sregs->tr, VCPU_SREG_TR); get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); - kvm_arch_ops->get_idt(vcpu, &dt); + kvm_x86_ops->get_idt(vcpu, &dt); sregs->idt.limit = dt.limit; sregs->idt.base = dt.base; - kvm_arch_ops->get_gdt(vcpu, &dt); + kvm_x86_ops->get_gdt(vcpu, &dt); sregs->gdt.limit = dt.limit; sregs->gdt.base = dt.base; - kvm_arch_ops->decache_cr4_guest_bits(vcpu); + kvm_x86_ops->decache_cr4_guest_bits(vcpu); sregs->cr0 = vcpu->cr0; sregs->cr2 = vcpu->cr2; sregs->cr3 = vcpu->cr3; sregs->cr4 = vcpu->cr4; - sregs->cr8 = vcpu->cr8; + sregs->cr8 = get_cr8(vcpu); sregs->efer = vcpu->shadow_efer; - sregs->apic_base = vcpu->apic_base; - - memcpy(sregs->interrupt_bitmap, vcpu->irq_pending, - sizeof sregs->interrupt_bitmap); + sregs->apic_base = kvm_get_apic_base(vcpu); + + if (irqchip_in_kernel(vcpu->kvm)) { + memset(sregs->interrupt_bitmap, 0, + sizeof sregs->interrupt_bitmap); + pending_vec = kvm_x86_ops->get_irq(vcpu); + if (pending_vec >= 0) + set_bit(pending_vec, (unsigned long *)sregs->interrupt_bitmap); + } else + memcpy(sregs->interrupt_bitmap, vcpu->irq_pending, + sizeof sregs->interrupt_bitmap); vcpu_put(vcpu); @@ -2043,56 +2284,69 @@ static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, static void set_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg) { - return kvm_arch_ops->set_segment(vcpu, var, seg); + return kvm_x86_ops->set_segment(vcpu, var, seg); } static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { int mmu_reset_needed = 0; - int i; + int i, pending_vec, max_bits; struct descriptor_table dt; vcpu_load(vcpu); dt.limit = sregs->idt.limit; dt.base = sregs->idt.base; - kvm_arch_ops->set_idt(vcpu, &dt); + kvm_x86_ops->set_idt(vcpu, &dt); dt.limit = sregs->gdt.limit; dt.base = sregs->gdt.base; - kvm_arch_ops->set_gdt(vcpu, &dt); + kvm_x86_ops->set_gdt(vcpu, &dt); vcpu->cr2 = sregs->cr2; mmu_reset_needed |= vcpu->cr3 != sregs->cr3; vcpu->cr3 = sregs->cr3; - vcpu->cr8 = sregs->cr8; + set_cr8(vcpu, sregs->cr8); mmu_reset_needed |= vcpu->shadow_efer != sregs->efer; #ifdef CONFIG_X86_64 - kvm_arch_ops->set_efer(vcpu, sregs->efer); + kvm_x86_ops->set_efer(vcpu, sregs->efer); #endif - vcpu->apic_base = sregs->apic_base; + kvm_set_apic_base(vcpu, sregs->apic_base); - kvm_arch_ops->decache_cr4_guest_bits(vcpu); + kvm_x86_ops->decache_cr4_guest_bits(vcpu); mmu_reset_needed |= vcpu->cr0 != sregs->cr0; - kvm_arch_ops->set_cr0(vcpu, sregs->cr0); + vcpu->cr0 = sregs->cr0; + kvm_x86_ops->set_cr0(vcpu, sregs->cr0); mmu_reset_needed |= vcpu->cr4 != sregs->cr4; - kvm_arch_ops->set_cr4(vcpu, sregs->cr4); + kvm_x86_ops->set_cr4(vcpu, sregs->cr4); if (!is_long_mode(vcpu) && is_pae(vcpu)) load_pdptrs(vcpu, vcpu->cr3); if (mmu_reset_needed) kvm_mmu_reset_context(vcpu); - memcpy(vcpu->irq_pending, sregs->interrupt_bitmap, - sizeof vcpu->irq_pending); - vcpu->irq_summary = 0; - for (i = 0; i < NR_IRQ_WORDS; ++i) - if (vcpu->irq_pending[i]) - __set_bit(i, &vcpu->irq_summary); + if (!irqchip_in_kernel(vcpu->kvm)) { + memcpy(vcpu->irq_pending, sregs->interrupt_bitmap, + sizeof vcpu->irq_pending); + vcpu->irq_summary = 0; + for (i = 0; i < ARRAY_SIZE(vcpu->irq_pending); ++i) + if (vcpu->irq_pending[i]) + __set_bit(i, &vcpu->irq_summary); + } else { + max_bits = (sizeof sregs->interrupt_bitmap) << 3; + pending_vec = find_first_bit( + (const unsigned long *)sregs->interrupt_bitmap, + max_bits); + /* Only pending external irq is handled here */ + if (pending_vec < max_bits) { + kvm_x86_ops->set_irq(vcpu, pending_vec); + printk("Set back pending irq %d\n", pending_vec); + } + } set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); set_segment(vcpu, &sregs->ds, VCPU_SREG_DS); @@ -2109,6 +2363,16 @@ static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, return 0; } +void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) +{ + struct kvm_segment cs; + + get_segment(vcpu, &cs, VCPU_SREG_CS); + *db = cs.db; + *l = cs.l; +} +EXPORT_SYMBOL_GPL(kvm_get_cs_db_l_bits); + /* * List of msr numbers which we expose to userspace through KVM_GET_MSRS * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST. @@ -2236,13 +2500,13 @@ static int kvm_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, gpa_t gpa; vcpu_load(vcpu); - spin_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->lock); gpa = vcpu->mmu.gva_to_gpa(vcpu, vaddr); tr->physical_address = gpa; tr->valid = gpa != UNMAPPED_GVA; tr->writeable = 1; tr->usermode = 0; - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); vcpu_put(vcpu); return 0; @@ -2253,6 +2517,8 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, { if (irq->irq < 0 || irq->irq >= 256) return -EINVAL; + if (irqchip_in_kernel(vcpu->kvm)) + return -ENXIO; vcpu_load(vcpu); set_bit(irq->irq, vcpu->irq_pending); @@ -2270,7 +2536,7 @@ static int kvm_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, vcpu_load(vcpu); - r = kvm_arch_ops->set_guest_debug(vcpu, dbg); + r = kvm_x86_ops->set_guest_debug(vcpu, dbg); vcpu_put(vcpu); @@ -2285,7 +2551,6 @@ static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma, unsigned long pgoff; struct page *page; - *type = VM_FAULT_MINOR; pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; if (pgoff == 0) page = virt_to_page(vcpu->run); @@ -2294,6 +2559,9 @@ static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma, else return NOPAGE_SIGBUS; get_page(page); + if (type != NULL) + *type = VM_FAULT_MINOR; + return page; } @@ -2346,74 +2614,52 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) { int r; struct kvm_vcpu *vcpu; - struct page *page; - r = -EINVAL; if (!valid_vcpu(n)) - goto out; - - vcpu = &kvm->vcpus[n]; - - mutex_lock(&vcpu->mutex); - - if (vcpu->vmcs) { - mutex_unlock(&vcpu->mutex); - return -EEXIST; - } - - page = alloc_page(GFP_KERNEL | __GFP_ZERO); - r = -ENOMEM; - if (!page) - goto out_unlock; - vcpu->run = page_address(page); - - page = alloc_page(GFP_KERNEL | __GFP_ZERO); - r = -ENOMEM; - if (!page) - goto out_free_run; - vcpu->pio_data = page_address(page); + return -EINVAL; - vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf, - FX_IMAGE_ALIGN); - vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE; - vcpu->cr0 = 0x10; + vcpu = kvm_x86_ops->vcpu_create(kvm, n); + if (IS_ERR(vcpu)) + return PTR_ERR(vcpu); - r = kvm_arch_ops->vcpu_create(vcpu); - if (r < 0) - goto out_free_vcpus; + preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops); - r = kvm_mmu_create(vcpu); - if (r < 0) - goto out_free_vcpus; + /* We do fxsave: this must be aligned. */ + BUG_ON((unsigned long)&vcpu->host_fx_image & 0xF); - kvm_arch_ops->vcpu_load(vcpu); + vcpu_load(vcpu); r = kvm_mmu_setup(vcpu); - if (r >= 0) - r = kvm_arch_ops->vcpu_setup(vcpu); vcpu_put(vcpu); - if (r < 0) - goto out_free_vcpus; + goto free_vcpu; + mutex_lock(&kvm->lock); + if (kvm->vcpus[n]) { + r = -EEXIST; + mutex_unlock(&kvm->lock); + goto mmu_unload; + } + kvm->vcpus[n] = vcpu; + mutex_unlock(&kvm->lock); + + /* Now it's all set up, let userspace reach it */ r = create_vcpu_fd(vcpu); if (r < 0) - goto out_free_vcpus; + goto unlink; + return r; - spin_lock(&kvm_lock); - if (n >= kvm->nvcpus) - kvm->nvcpus = n + 1; - spin_unlock(&kvm_lock); +unlink: + mutex_lock(&kvm->lock); + kvm->vcpus[n] = NULL; + mutex_unlock(&kvm->lock); - return r; +mmu_unload: + vcpu_load(vcpu); + kvm_mmu_unload(vcpu); + vcpu_put(vcpu); -out_free_vcpus: - kvm_free_vcpu(vcpu); -out_free_run: - free_page((unsigned long)vcpu->run); - vcpu->run = NULL; -out_unlock: - mutex_unlock(&vcpu->mutex); -out: +free_vcpu: + kvm_x86_ops->vcpu_free(vcpu); return r; } @@ -2493,7 +2739,7 @@ struct fxsave { static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { - struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image; + struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image; vcpu_load(vcpu); @@ -2513,7 +2759,7 @@ static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { - struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image; + struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image; vcpu_load(vcpu); @@ -2531,6 +2777,27 @@ static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) return 0; } +static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu, + struct kvm_lapic_state *s) +{ + vcpu_load(vcpu); + memcpy(s->regs, vcpu->apic->regs, sizeof *s); + vcpu_put(vcpu); + + return 0; +} + +static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu, + struct kvm_lapic_state *s) +{ + vcpu_load(vcpu); + memcpy(vcpu->apic->regs, s->regs, sizeof *s); + kvm_apic_post_state_restore(vcpu); + vcpu_put(vcpu); + + return 0; +} + static long kvm_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -2700,6 +2967,31 @@ static long kvm_vcpu_ioctl(struct file *filp, r = 0; break; } + case KVM_GET_LAPIC: { + struct kvm_lapic_state lapic; + + memset(&lapic, 0, sizeof lapic); + r = kvm_vcpu_ioctl_get_lapic(vcpu, &lapic); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &lapic, sizeof lapic)) + goto out; + r = 0; + break; + } + case KVM_SET_LAPIC: { + struct kvm_lapic_state lapic; + + r = -EFAULT; + if (copy_from_user(&lapic, argp, sizeof lapic)) + goto out; + r = kvm_vcpu_ioctl_set_lapic(vcpu, &lapic);; + if (r) + goto out; + r = 0; + break; + } default: ; } @@ -2753,6 +3045,75 @@ static long kvm_vm_ioctl(struct file *filp, goto out; break; } + case KVM_CREATE_IRQCHIP: + r = -ENOMEM; + kvm->vpic = kvm_create_pic(kvm); + if (kvm->vpic) { + r = kvm_ioapic_init(kvm); + if (r) { + kfree(kvm->vpic); + kvm->vpic = NULL; + goto out; + } + } + else + goto out; + break; + case KVM_IRQ_LINE: { + struct kvm_irq_level irq_event; + + r = -EFAULT; + if (copy_from_user(&irq_event, argp, sizeof irq_event)) + goto out; + if (irqchip_in_kernel(kvm)) { + mutex_lock(&kvm->lock); + if (irq_event.irq < 16) + kvm_pic_set_irq(pic_irqchip(kvm), + irq_event.irq, + irq_event.level); + kvm_ioapic_set_irq(kvm->vioapic, + irq_event.irq, + irq_event.level); + mutex_unlock(&kvm->lock); + r = 0; + } + break; + } + case KVM_GET_IRQCHIP: { + /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ + struct kvm_irqchip chip; + + r = -EFAULT; + if (copy_from_user(&chip, argp, sizeof chip)) + goto out; + r = -ENXIO; + if (!irqchip_in_kernel(kvm)) + goto out; + r = kvm_vm_ioctl_get_irqchip(kvm, &chip); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &chip, sizeof chip)) + goto out; + r = 0; + break; + } + case KVM_SET_IRQCHIP: { + /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ + struct kvm_irqchip chip; + + r = -EFAULT; + if (copy_from_user(&chip, argp, sizeof chip)) + goto out; + r = -ENXIO; + if (!irqchip_in_kernel(kvm)) + goto out; + r = kvm_vm_ioctl_set_irqchip(kvm, &chip); + if (r) + goto out; + r = 0; + break; + } default: ; } @@ -2768,12 +3129,14 @@ static struct page *kvm_vm_nopage(struct vm_area_struct *vma, unsigned long pgoff; struct page *page; - *type = VM_FAULT_MINOR; pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; page = gfn_to_page(kvm, pgoff); if (!page) return NOPAGE_SIGBUS; get_page(page); + if (type != NULL) + *type = VM_FAULT_MINOR; + return page; } @@ -2861,12 +3224,20 @@ static long kvm_dev_ioctl(struct file *filp, r = 0; break; } - case KVM_CHECK_EXTENSION: - /* - * No extensions defined at present. - */ - r = 0; + case KVM_CHECK_EXTENSION: { + int ext = (long)argp; + + switch (ext) { + case KVM_CAP_IRQCHIP: + case KVM_CAP_HLT: + r = 1; + break; + default: + r = 0; + break; + } break; + } case KVM_GET_VCPU_MMAP_SIZE: r = -EINVAL; if (arg) @@ -2881,8 +3252,6 @@ out: } static struct file_operations kvm_chardev_ops = { - .open = kvm_dev_open, - .release = kvm_dev_release, .unlocked_ioctl = kvm_dev_ioctl, .compat_ioctl = kvm_dev_ioctl, }; @@ -2893,25 +3262,6 @@ static struct miscdevice kvm_dev = { &kvm_chardev_ops, }; -static int kvm_reboot(struct notifier_block *notifier, unsigned long val, - void *v) -{ - if (val == SYS_RESTART) { - /* - * Some (well, at least mine) BIOSes hang on reboot if - * in vmx root mode. - */ - printk(KERN_INFO "kvm: exiting hardware virtualization\n"); - on_each_cpu(hardware_disable, NULL, 0, 1); - } - return NOTIFY_OK; -} - -static struct notifier_block kvm_reboot_notifier = { - .notifier_call = kvm_reboot, - .priority = 0, -}; - /* * Make sure that a cpu that is being hot-unplugged does not have any vcpus * cached on it. @@ -2925,7 +3275,9 @@ static void decache_vcpus_on_cpu(int cpu) spin_lock(&kvm_lock); list_for_each_entry(vm, &vm_list, vm_list) for (i = 0; i < KVM_MAX_VCPUS; ++i) { - vcpu = &vm->vcpus[i]; + vcpu = vm->vcpus[i]; + if (!vcpu) + continue; /* * If the vcpu is locked, then it is running on some * other cpu and therefore it is not cached on the @@ -2936,7 +3288,7 @@ static void decache_vcpus_on_cpu(int cpu) */ if (mutex_trylock(&vcpu->mutex)) { if (vcpu->cpu == cpu) { - kvm_arch_ops->vcpu_decache(vcpu); + kvm_x86_ops->vcpu_decache(vcpu); vcpu->cpu = -1; } mutex_unlock(&vcpu->mutex); @@ -2952,7 +3304,7 @@ static void hardware_enable(void *junk) if (cpu_isset(cpu, cpus_hardware_enabled)) return; cpu_set(cpu, cpus_hardware_enabled); - kvm_arch_ops->hardware_enable(NULL); + kvm_x86_ops->hardware_enable(NULL); } static void hardware_disable(void *junk) @@ -2963,7 +3315,7 @@ static void hardware_disable(void *junk) return; cpu_clear(cpu, cpus_hardware_enabled); decache_vcpus_on_cpu(cpu); - kvm_arch_ops->hardware_disable(NULL); + kvm_x86_ops->hardware_disable(NULL); } static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, @@ -2994,6 +3346,25 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, return NOTIFY_OK; } +static int kvm_reboot(struct notifier_block *notifier, unsigned long val, + void *v) +{ + if (val == SYS_RESTART) { + /* + * Some (well, at least mine) BIOSes hang on reboot if + * in vmx root mode. + */ + printk(KERN_INFO "kvm: exiting hardware virtualization\n"); + on_each_cpu(hardware_disable, NULL, 0, 1); + } + return NOTIFY_OK; +} + +static struct notifier_block kvm_reboot_notifier = { + .notifier_call = kvm_reboot, + .priority = 0, +}; + void kvm_io_bus_init(struct kvm_io_bus *bus) { memset(bus, 0, sizeof(*bus)); @@ -3047,18 +3418,15 @@ static u64 stat_get(void *_offset) spin_lock(&kvm_lock); list_for_each_entry(kvm, &vm_list, vm_list) for (i = 0; i < KVM_MAX_VCPUS; ++i) { - vcpu = &kvm->vcpus[i]; - total += *(u32 *)((void *)vcpu + offset); + vcpu = kvm->vcpus[i]; + if (vcpu) + total += *(u32 *)((void *)vcpu + offset); } spin_unlock(&kvm_lock); return total; } -static void stat_set(void *offset, u64 val) -{ -} - -DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, stat_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, NULL, "%llu\n"); static __init void kvm_init_debug(void) { @@ -3105,11 +3473,34 @@ static struct sys_device kvm_sysdev = { hpa_t bad_page_address; -int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) +static inline +struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn) +{ + return container_of(pn, struct kvm_vcpu, preempt_notifier); +} + +static void kvm_sched_in(struct preempt_notifier *pn, int cpu) +{ + struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn); + + kvm_x86_ops->vcpu_load(vcpu, cpu); +} + +static void kvm_sched_out(struct preempt_notifier *pn, + struct task_struct *next) +{ + struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn); + + kvm_x86_ops->vcpu_put(vcpu); +} + +int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size, + struct module *module) { int r; + int cpu; - if (kvm_arch_ops) { + if (kvm_x86_ops) { printk(KERN_ERR "kvm: already loaded the other module\n"); return -EEXIST; } @@ -3123,12 +3514,20 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) return -EOPNOTSUPP; } - kvm_arch_ops = ops; + kvm_x86_ops = ops; - r = kvm_arch_ops->hardware_setup(); + r = kvm_x86_ops->hardware_setup(); if (r < 0) goto out; + for_each_online_cpu(cpu) { + smp_call_function_single(cpu, + kvm_x86_ops->check_processor_compatibility, + &r, 0, 1); + if (r < 0) + goto out_free_0; + } + on_each_cpu(hardware_enable, NULL, 0, 1); r = register_cpu_notifier(&kvm_cpu_notifier); if (r) @@ -3143,6 +3542,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) if (r) goto out_free_3; + /* A kmem cache lets us meet the alignment requirements of fx_save. */ + kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size, + __alignof__(struct kvm_vcpu), 0, 0); + if (!kvm_vcpu_cache) { + r = -ENOMEM; + goto out_free_4; + } + kvm_chardev_ops.owner = module; r = misc_register(&kvm_dev); @@ -3151,9 +3558,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) goto out_free; } + kvm_preempt_ops.sched_in = kvm_sched_in; + kvm_preempt_ops.sched_out = kvm_sched_out; + return r; out_free: + kmem_cache_destroy(kvm_vcpu_cache); +out_free_4: sysdev_unregister(&kvm_sysdev); out_free_3: sysdev_class_unregister(&kvm_sysdev_class); @@ -3162,22 +3574,24 @@ out_free_2: unregister_cpu_notifier(&kvm_cpu_notifier); out_free_1: on_each_cpu(hardware_disable, NULL, 0, 1); - kvm_arch_ops->hardware_unsetup(); +out_free_0: + kvm_x86_ops->hardware_unsetup(); out: - kvm_arch_ops = NULL; + kvm_x86_ops = NULL; return r; } -void kvm_exit_arch(void) +void kvm_exit_x86(void) { misc_deregister(&kvm_dev); + kmem_cache_destroy(kvm_vcpu_cache); sysdev_unregister(&kvm_sysdev); sysdev_class_unregister(&kvm_sysdev_class); unregister_reboot_notifier(&kvm_reboot_notifier); unregister_cpu_notifier(&kvm_cpu_notifier); on_each_cpu(hardware_disable, NULL, 0, 1); - kvm_arch_ops->hardware_unsetup(); - kvm_arch_ops = NULL; + kvm_x86_ops->hardware_unsetup(); + kvm_x86_ops = NULL; } static __init int kvm_init(void) @@ -3220,5 +3634,5 @@ static __exit void kvm_exit(void) module_init(kvm_init) module_exit(kvm_exit) -EXPORT_SYMBOL_GPL(kvm_init_arch); -EXPORT_SYMBOL_GPL(kvm_exit_arch); +EXPORT_SYMBOL_GPL(kvm_init_x86); +EXPORT_SYMBOL_GPL(kvm_exit_x86); diff --git a/drivers/kvm/kvm_svm.h b/drivers/kvm/kvm_svm.h index a869983d683..a0e415daef5 100644 --- a/drivers/kvm/kvm_svm.h +++ b/drivers/kvm/kvm_svm.h @@ -20,7 +20,10 @@ static const u32 host_save_user_msrs[] = { #define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs) #define NUM_DB_REGS 4 +struct kvm_vcpu; + struct vcpu_svm { + struct kvm_vcpu vcpu; struct vmcb *vmcb; unsigned long vmcb_pa; struct svm_cpu_data *svm_data; diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c new file mode 100644 index 00000000000..a190587cf6a --- /dev/null +++ b/drivers/kvm/lapic.c @@ -0,0 +1,1064 @@ + +/* + * Local APIC virtualization + * + * Copyright (C) 2006 Qumranet, Inc. + * Copyright (C) 2007 Novell + * Copyright (C) 2007 Intel + * + * Authors: + * Dor Laor <dor.laor@qumranet.com> + * Gregory Haskins <ghaskins@novell.com> + * Yaozu (Eddie) Dong <eddie.dong@intel.com> + * + * Based on Xen 3.1 code, Copyright (c) 2004, Intel Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include "kvm.h" +#include <linux/kvm.h> +#include <linux/mm.h> +#include <linux/highmem.h> +#include <linux/smp.h> +#include <linux/hrtimer.h> +#include <linux/io.h> +#include <linux/module.h> +#include <asm/processor.h> +#include <asm/msr.h> +#include <asm/page.h> +#include <asm/current.h> +#include <asm/apicdef.h> +#include <asm/atomic.h> +#include <asm/div64.h> +#include "irq.h" + +#define PRId64 "d" +#define PRIx64 "llx" +#define PRIu64 "u" +#define PRIo64 "o" + +#define APIC_BUS_CYCLE_NS 1 + +/* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */ +#define apic_debug(fmt, arg...) + +#define APIC_LVT_NUM 6 +/* 14 is the version for Xeon and Pentium 8.4.8*/ +#define APIC_VERSION (0x14UL | ((APIC_LVT_NUM - 1) << 16)) +#define LAPIC_MMIO_LENGTH (1 << 12) +/* followed define is not in apicdef.h */ +#define APIC_SHORT_MASK 0xc0000 +#define APIC_DEST_NOSHORT 0x0 +#define APIC_DEST_MASK 0x800 +#define MAX_APIC_VECTOR 256 + +#define VEC_POS(v) ((v) & (32 - 1)) +#define REG_POS(v) (((v) >> 5) << 4) +static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off) +{ + return *((u32 *) (apic->regs + reg_off)); +} + +static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val) +{ + *((u32 *) (apic->regs + reg_off)) = val; +} + +static inline int apic_test_and_set_vector(int vec, void *bitmap) +{ + return test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); +} + +static inline int apic_test_and_clear_vector(int vec, void *bitmap) +{ + return test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); +} + +static inline void apic_set_vector(int vec, void *bitmap) +{ + set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); +} + +static inline void apic_clear_vector(int vec, void *bitmap) +{ + clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); +} + +static inline int apic_hw_enabled(struct kvm_lapic *apic) +{ + return (apic)->vcpu->apic_base & MSR_IA32_APICBASE_ENABLE; +} + +static inline int apic_sw_enabled(struct kvm_lapic *apic) +{ + return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED; +} + +static inline int apic_enabled(struct kvm_lapic *apic) +{ + return apic_sw_enabled(apic) && apic_hw_enabled(apic); +} + +#define LVT_MASK \ + (APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK) + +#define LINT_MASK \ + (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \ + APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER) + +static inline int kvm_apic_id(struct kvm_lapic *apic) +{ + return (apic_get_reg(apic, APIC_ID) >> 24) & 0xff; +} + +static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type) +{ + return !(apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED); +} + +static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type) +{ + return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK; +} + +static inline int apic_lvtt_period(struct kvm_lapic *apic) +{ + return apic_get_reg(apic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC; +} + +static unsigned int apic_lvt_mask[APIC_LVT_NUM] = { + LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */ + LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */ + LVT_MASK | APIC_MODE_MASK, /* LVTPC */ + LINT_MASK, LINT_MASK, /* LVT0-1 */ + LVT_MASK /* LVTERR */ +}; + +static int find_highest_vector(void *bitmap) +{ + u32 *word = bitmap; + int word_offset = MAX_APIC_VECTOR >> 5; + + while ((word_offset != 0) && (word[(--word_offset) << 2] == 0)) + continue; + + if (likely(!word_offset && !word[0])) + return -1; + else + return fls(word[word_offset << 2]) - 1 + (word_offset << 5); +} + +static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic) +{ + return apic_test_and_set_vector(vec, apic->regs + APIC_IRR); +} + +static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) +{ + apic_clear_vector(vec, apic->regs + APIC_IRR); +} + +static inline int apic_find_highest_irr(struct kvm_lapic *apic) +{ + int result; + + result = find_highest_vector(apic->regs + APIC_IRR); + ASSERT(result == -1 || result >= 16); + + return result; +} + +int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; + int highest_irr; + + if (!apic) + return 0; + highest_irr = apic_find_highest_irr(apic); + + return highest_irr; +} +EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr); + +int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig) +{ + if (!apic_test_and_set_irr(vec, apic)) { + /* a new pending irq is set in IRR */ + if (trig) + apic_set_vector(vec, apic->regs + APIC_TMR); + else + apic_clear_vector(vec, apic->regs + APIC_TMR); + kvm_vcpu_kick(apic->vcpu); + return 1; + } + return 0; +} + +static inline int apic_find_highest_isr(struct kvm_lapic *apic) +{ + int result; + + result = find_highest_vector(apic->regs + APIC_ISR); + ASSERT(result == -1 || result >= 16); + + return result; +} + +static void apic_update_ppr(struct kvm_lapic *apic) +{ + u32 tpr, isrv, ppr; + int isr; + + tpr = apic_get_reg(apic, APIC_TASKPRI); + isr = apic_find_highest_isr(apic); + isrv = (isr != -1) ? isr : 0; + + if ((tpr & 0xf0) >= (isrv & 0xf0)) + ppr = tpr & 0xff; + else + ppr = isrv & 0xf0; + + apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x", + apic, ppr, isr, isrv); + + apic_set_reg(apic, APIC_PROCPRI, ppr); +} + +static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr) +{ + apic_set_reg(apic, APIC_TASKPRI, tpr); + apic_update_ppr(apic); +} + +int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest) +{ + return kvm_apic_id(apic) == dest; +} + +int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) +{ + int result = 0; + u8 logical_id; + + logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR)); + + switch (apic_get_reg(apic, APIC_DFR)) { + case APIC_DFR_FLAT: + if (logical_id & mda) + result = 1; + break; + case APIC_DFR_CLUSTER: + if (((logical_id >> 4) == (mda >> 0x4)) + && (logical_id & mda & 0xf)) + result = 1; + break; + default: + printk(KERN_WARNING "Bad DFR vcpu %d: %08x\n", + apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR)); + break; + } + + return result; +} + +static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, + int short_hand, int dest, int dest_mode) +{ + int result = 0; + struct kvm_lapic *target = vcpu->apic; + + apic_debug("target %p, source %p, dest 0x%x, " + "dest_mode 0x%x, short_hand 0x%x", + target, source, dest, dest_mode, short_hand); + + ASSERT(!target); + switch (short_hand) { + case APIC_DEST_NOSHORT: + if (dest_mode == 0) { + /* Physical mode. */ + if ((dest == 0xFF) || (dest == kvm_apic_id(target))) + result = 1; + } else + /* Logical mode. */ + result = kvm_apic_match_logical_addr(target, dest); + break; + case APIC_DEST_SELF: + if (target == source) + result = 1; + break; + case APIC_DEST_ALLINC: + result = 1; + break; + case APIC_DEST_ALLBUT: + if (target != source) + result = 1; + break; + default: + printk(KERN_WARNING "Bad dest shorthand value %x\n", + short_hand); + break; + } + + return result; +} + +/* + * Add a pending IRQ into lapic. + * Return 1 if successfully added and 0 if discarded. + */ +static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, + int vector, int level, int trig_mode) +{ + int orig_irr, result = 0; + struct kvm_vcpu *vcpu = apic->vcpu; + + switch (delivery_mode) { + case APIC_DM_FIXED: + case APIC_DM_LOWEST: + /* FIXME add logic for vcpu on reset */ + if (unlikely(!apic_enabled(apic))) + break; + + orig_irr = apic_test_and_set_irr(vector, apic); + if (orig_irr && trig_mode) { + apic_debug("level trig mode repeatedly for vector %d", + vector); + break; + } + + if (trig_mode) { + apic_debug("level trig mode for vector %d", vector); + apic_set_vector(vector, apic->regs + APIC_TMR); + } else + apic_clear_vector(vector, apic->regs + APIC_TMR); + + if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE) + kvm_vcpu_kick(vcpu); + else if (vcpu->mp_state == VCPU_MP_STATE_HALTED) { + vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; + if (waitqueue_active(&vcpu->wq)) + wake_up_interruptible(&vcpu->wq); + } + + result = (orig_irr == 0); + break; + + case APIC_DM_REMRD: + printk(KERN_DEBUG "Ignoring delivery mode 3\n"); + break; + + case APIC_DM_SMI: + printk(KERN_DEBUG "Ignoring guest SMI\n"); + break; + case APIC_DM_NMI: + printk(KERN_DEBUG "Ignoring guest NMI\n"); + break; + + case APIC_DM_INIT: + if (level) { + if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE) + printk(KERN_DEBUG + "INIT on a runnable vcpu %d\n", + vcpu->vcpu_id); + vcpu->mp_state = VCPU_MP_STATE_INIT_RECEIVED; + kvm_vcpu_kick(vcpu); + } else { + printk(KERN_DEBUG + "Ignoring de-assert INIT to vcpu %d\n", + vcpu->vcpu_id); + } + + break; + + case APIC_DM_STARTUP: + printk(KERN_DEBUG "SIPI to vcpu %d vector 0x%02x\n", + vcpu->vcpu_id, vector); + if (vcpu->mp_state == VCPU_MP_STATE_INIT_RECEIVED) { + vcpu->sipi_vector = vector; + vcpu->mp_state = VCPU_MP_STATE_SIPI_RECEIVED; + if (waitqueue_active(&vcpu->wq)) + wake_up_interruptible(&vcpu->wq); + } + break; + + default: + printk(KERN_ERR "TODO: unsupported delivery mode %x\n", + delivery_mode); + break; + } + return result; +} + +struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector, + unsigned long bitmap) +{ + int vcpu_id; + int last; + int next; + struct kvm_lapic *apic; + + last = kvm->round_robin_prev_vcpu; + next = last; + + do { + if (++next == KVM_MAX_VCPUS) + next = 0; + if (kvm->vcpus[next] == NULL || !test_bit(next, &bitmap)) + continue; + apic = kvm->vcpus[next]->apic; + if (apic && apic_enabled(apic)) + break; + apic = NULL; + } while (next != last); + kvm->round_robin_prev_vcpu = next; + + if (!apic) { + vcpu_id = ffs(bitmap) - 1; + if (vcpu_id < 0) { + vcpu_id = 0; + printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n"); + } + apic = kvm->vcpus[vcpu_id]->apic; + } + + return apic; +} + +static void apic_set_eoi(struct kvm_lapic *apic) +{ + int vector = apic_find_highest_isr(apic); + + /* + * Not every write EOI will has corresponding ISR, + * one example is when Kernel check timer on setup_IO_APIC + */ + if (vector == -1) + return; + + apic_clear_vector(vector, apic->regs + APIC_ISR); + apic_update_ppr(apic); + + if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR)) + kvm_ioapic_update_eoi(apic->vcpu->kvm, vector); +} + +static void apic_send_ipi(struct kvm_lapic *apic) +{ + u32 icr_low = apic_get_reg(apic, APIC_ICR); + u32 icr_high = apic_get_reg(apic, APIC_ICR2); + + unsigned int dest = GET_APIC_DEST_FIELD(icr_high); + unsigned int short_hand = icr_low & APIC_SHORT_MASK; + unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG; + unsigned int level = icr_low & APIC_INT_ASSERT; + unsigned int dest_mode = icr_low & APIC_DEST_MASK; + unsigned int delivery_mode = icr_low & APIC_MODE_MASK; + unsigned int vector = icr_low & APIC_VECTOR_MASK; + + struct kvm_lapic *target; + struct kvm_vcpu *vcpu; + unsigned long lpr_map = 0; + int i; + + apic_debug("icr_high 0x%x, icr_low 0x%x, " + "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, " + "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n", + icr_high, icr_low, short_hand, dest, + trig_mode, level, dest_mode, delivery_mode, vector); + + for (i = 0; i < KVM_MAX_VCPUS; i++) { + vcpu = apic->vcpu->kvm->vcpus[i]; + if (!vcpu) + continue; + + if (vcpu->apic && + apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) { + if (delivery_mode == APIC_DM_LOWEST) + set_bit(vcpu->vcpu_id, &lpr_map); + else + __apic_accept_irq(vcpu->apic, delivery_mode, + vector, level, trig_mode); + } + } + + if (delivery_mode == APIC_DM_LOWEST) { + target = kvm_apic_round_robin(vcpu->kvm, vector, lpr_map); + if (target != NULL) + __apic_accept_irq(target, delivery_mode, + vector, level, trig_mode); + } +} + +static u32 apic_get_tmcct(struct kvm_lapic *apic) +{ + u32 counter_passed; + ktime_t passed, now = apic->timer.dev.base->get_time(); + u32 tmcct = apic_get_reg(apic, APIC_TMICT); + + ASSERT(apic != NULL); + + if (unlikely(ktime_to_ns(now) <= + ktime_to_ns(apic->timer.last_update))) { + /* Wrap around */ + passed = ktime_add(( { + (ktime_t) { + .tv64 = KTIME_MAX - + (apic->timer.last_update).tv64}; } + ), now); + apic_debug("time elapsed\n"); + } else + passed = ktime_sub(now, apic->timer.last_update); + + counter_passed = div64_64(ktime_to_ns(passed), + (APIC_BUS_CYCLE_NS * apic->timer.divide_count)); + tmcct -= counter_passed; + + if (tmcct <= 0) { + if (unlikely(!apic_lvtt_period(apic))) + tmcct = 0; + else + do { + tmcct += apic_get_reg(apic, APIC_TMICT); + } while (tmcct <= 0); + } + + return tmcct; +} + +static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset) +{ + u32 val = 0; + + if (offset >= LAPIC_MMIO_LENGTH) + return 0; + + switch (offset) { + case APIC_ARBPRI: + printk(KERN_WARNING "Access APIC ARBPRI register " + "which is for P6\n"); + break; + + case APIC_TMCCT: /* Timer CCR */ + val = apic_get_tmcct(apic); + break; + + default: + apic_update_ppr(apic); + val = apic_get_reg(apic, offset); + break; + } + + return val; +} + +static void apic_mmio_read(struct kvm_io_device *this, + gpa_t address, int len, void *data) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)this->private; + unsigned int offset = address - apic->base_address; + unsigned char alignment = offset & 0xf; + u32 result; + + if ((alignment + len) > 4) { + printk(KERN_ERR "KVM_APIC_READ: alignment error %lx %d", + (unsigned long)address, len); + return; + } + result = __apic_read(apic, offset & ~0xf); + + switch (len) { + case 1: + case 2: + case 4: + memcpy(data, (char *)&result + alignment, len); + break; + default: + printk(KERN_ERR "Local APIC read with len = %x, " + "should be 1,2, or 4 instead\n", len); + break; + } +} + +static void update_divide_count(struct kvm_lapic *apic) +{ + u32 tmp1, tmp2, tdcr; + + tdcr = apic_get_reg(apic, APIC_TDCR); + tmp1 = tdcr & 0xf; + tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; + apic->timer.divide_count = 0x1 << (tmp2 & 0x7); + + apic_debug("timer divide count is 0x%x\n", + apic->timer.divide_count); +} + +static void start_apic_timer(struct kvm_lapic *apic) +{ + ktime_t now = apic->timer.dev.base->get_time(); + + apic->timer.last_update = now; + + apic->timer.period = apic_get_reg(apic, APIC_TMICT) * + APIC_BUS_CYCLE_NS * apic->timer.divide_count; + atomic_set(&apic->timer.pending, 0); + hrtimer_start(&apic->timer.dev, + ktime_add_ns(now, apic->timer.period), + HRTIMER_MODE_ABS); + + apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016" + PRIx64 ", " + "timer initial count 0x%x, period %lldns, " + "expire @ 0x%016" PRIx64 ".\n", __FUNCTION__, + APIC_BUS_CYCLE_NS, ktime_to_ns(now), + apic_get_reg(apic, APIC_TMICT), + apic->timer.period, + ktime_to_ns(ktime_add_ns(now, + apic->timer.period))); +} + +static void apic_mmio_write(struct kvm_io_device *this, + gpa_t address, int len, const void *data) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)this->private; + unsigned int offset = address - apic->base_address; + unsigned char alignment = offset & 0xf; + u32 val; + + /* + * APIC register must be aligned on 128-bits boundary. + * 32/64/128 bits registers must be accessed thru 32 bits. + * Refer SDM 8.4.1 + */ + if (len != 4 || alignment) { + if (printk_ratelimit()) + printk(KERN_ERR "apic write: bad size=%d %lx\n", + len, (long)address); + return; + } + + val = *(u32 *) data; + + /* too common printing */ + if (offset != APIC_EOI) + apic_debug("%s: offset 0x%x with length 0x%x, and value is " + "0x%x\n", __FUNCTION__, offset, len, val); + + offset &= 0xff0; + + switch (offset) { + case APIC_ID: /* Local APIC ID */ + apic_set_reg(apic, APIC_ID, val); + break; + + case APIC_TASKPRI: + apic_set_tpr(apic, val & 0xff); + break; + + case APIC_EOI: + apic_set_eoi(apic); + break; + + case APIC_LDR: + apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK); + break; + + case APIC_DFR: + apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF); + break; + + case APIC_SPIV: + apic_set_reg(apic, APIC_SPIV, val & 0x3ff); + if (!(val & APIC_SPIV_APIC_ENABLED)) { + int i; + u32 lvt_val; + + for (i = 0; i < APIC_LVT_NUM; i++) { + lvt_val = apic_get_reg(apic, + APIC_LVTT + 0x10 * i); + apic_set_reg(apic, APIC_LVTT + 0x10 * i, + lvt_val | APIC_LVT_MASKED); + } + atomic_set(&apic->timer.pending, 0); + + } + break; + + case APIC_ICR: + /* No delay here, so we always clear the pending bit */ + apic_set_reg(apic, APIC_ICR, val & ~(1 << 12)); + apic_send_ipi(apic); + break; + + case APIC_ICR2: + apic_set_reg(apic, APIC_ICR2, val & 0xff000000); + break; + + case APIC_LVTT: + case APIC_LVTTHMR: + case APIC_LVTPC: + case APIC_LVT0: + case APIC_LVT1: + case APIC_LVTERR: + /* TODO: Check vector */ + if (!apic_sw_enabled(apic)) + val |= APIC_LVT_MASKED; + + val &= apic_lvt_mask[(offset - APIC_LVTT) >> 4]; + apic_set_reg(apic, offset, val); + + break; + + case APIC_TMICT: + hrtimer_cancel(&apic->timer.dev); + apic_set_reg(apic, APIC_TMICT, val); + start_apic_timer(apic); + return; + + case APIC_TDCR: + if (val & 4) + printk(KERN_ERR "KVM_WRITE:TDCR %x\n", val); + apic_set_reg(apic, APIC_TDCR, val); + update_divide_count(apic); + break; + + default: + apic_debug("Local APIC Write to read-only register %x\n", + offset); + break; + } + +} + +static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)this->private; + int ret = 0; + + + if (apic_hw_enabled(apic) && + (addr >= apic->base_address) && + (addr < (apic->base_address + LAPIC_MMIO_LENGTH))) + ret = 1; + + return ret; +} + +void kvm_free_apic(struct kvm_lapic *apic) +{ + if (!apic) + return; + + hrtimer_cancel(&apic->timer.dev); + + if (apic->regs_page) { + __free_page(apic->regs_page); + apic->regs_page = 0; + } + + kfree(apic); +} + +/* + *---------------------------------------------------------------------- + * LAPIC interface + *---------------------------------------------------------------------- + */ + +void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; + + if (!apic) + return; + apic_set_tpr(apic, ((cr8 & 0x0f) << 4)); +} + +u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; + u64 tpr; + + if (!apic) + return 0; + tpr = (u64) apic_get_reg(apic, APIC_TASKPRI); + + return (tpr & 0xf0) >> 4; +} +EXPORT_SYMBOL_GPL(kvm_lapic_get_cr8); + +void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; + + if (!apic) { + value |= MSR_IA32_APICBASE_BSP; + vcpu->apic_base = value; + return; + } + if (apic->vcpu->vcpu_id) + value &= ~MSR_IA32_APICBASE_BSP; + + vcpu->apic_base = value; + apic->base_address = apic->vcpu->apic_base & + MSR_IA32_APICBASE_BASE; + + /* with FSB delivery interrupt, we can restart APIC functionality */ + apic_debug("apic base msr is 0x%016" PRIx64 ", and base address is " + "0x%lx.\n", apic->apic_base, apic->base_address); + +} + +u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu) +{ + return vcpu->apic_base; +} +EXPORT_SYMBOL_GPL(kvm_lapic_get_base); + +void kvm_lapic_reset(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic; + int i; + + apic_debug("%s\n", __FUNCTION__); + + ASSERT(vcpu); + apic = vcpu->apic; + ASSERT(apic != NULL); + + /* Stop the timer in case it's a reset to an active apic */ + hrtimer_cancel(&apic->timer.dev); + + apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24); + apic_set_reg(apic, APIC_LVR, APIC_VERSION); + + for (i = 0; i < APIC_LVT_NUM; i++) + apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); + apic_set_reg(apic, APIC_LVT0, + SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT)); + + apic_set_reg(apic, APIC_DFR, 0xffffffffU); + apic_set_reg(apic, APIC_SPIV, 0xff); + apic_set_reg(apic, APIC_TASKPRI, 0); + apic_set_reg(apic, APIC_LDR, 0); + apic_set_reg(apic, APIC_ESR, 0); + apic_set_reg(apic, APIC_ICR, 0); + apic_set_reg(apic, APIC_ICR2, 0); + apic_set_reg(apic, APIC_TDCR, 0); + apic_set_reg(apic, APIC_TMICT, 0); + for (i = 0; i < 8; i++) { + apic_set_reg(apic, APIC_IRR + 0x10 * i, 0); + apic_set_reg(apic, APIC_ISR + 0x10 * i, 0); + apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); + } + apic->timer.divide_count = 0; + atomic_set(&apic->timer.pending, 0); + if (vcpu->vcpu_id == 0) + vcpu->apic_base |= MSR_IA32_APICBASE_BSP; + apic_update_ppr(apic); + + apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr=" + "0x%016" PRIx64 ", base_address=0x%0lx.\n", __FUNCTION__, + vcpu, kvm_apic_id(apic), + vcpu->apic_base, apic->base_address); +} +EXPORT_SYMBOL_GPL(kvm_lapic_reset); + +int kvm_lapic_enabled(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; + int ret = 0; + + if (!apic) + return 0; + ret = apic_enabled(apic); + + return ret; +} +EXPORT_SYMBOL_GPL(kvm_lapic_enabled); + +/* + *---------------------------------------------------------------------- + * timer interface + *---------------------------------------------------------------------- + */ + +/* TODO: make sure __apic_timer_fn runs in current pCPU */ +static int __apic_timer_fn(struct kvm_lapic *apic) +{ + int result = 0; + wait_queue_head_t *q = &apic->vcpu->wq; + + atomic_inc(&apic->timer.pending); + if (waitqueue_active(q)) + { + apic->vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; + wake_up_interruptible(q); + } + if (apic_lvtt_period(apic)) { + result = 1; + apic->timer.dev.expires = ktime_add_ns( + apic->timer.dev.expires, + apic->timer.period); + } + return result; +} + +static int __inject_apic_timer_irq(struct kvm_lapic *apic) +{ + int vector; + + vector = apic_lvt_vector(apic, APIC_LVTT); + return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0); +} + +static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) +{ + struct kvm_lapic *apic; + int restart_timer = 0; + + apic = container_of(data, struct kvm_lapic, timer.dev); + + restart_timer = __apic_timer_fn(apic); + + if (restart_timer) + return HRTIMER_RESTART; + else + return HRTIMER_NORESTART; +} + +int kvm_create_lapic(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic; + + ASSERT(vcpu != NULL); + apic_debug("apic_init %d\n", vcpu->vcpu_id); + + apic = kzalloc(sizeof(*apic), GFP_KERNEL); + if (!apic) + goto nomem; + + vcpu->apic = apic; + + apic->regs_page = alloc_page(GFP_KERNEL); + if (apic->regs_page == NULL) { + printk(KERN_ERR "malloc apic regs error for vcpu %x\n", + vcpu->vcpu_id); + goto nomem; + } + apic->regs = page_address(apic->regs_page); + memset(apic->regs, 0, PAGE_SIZE); + apic->vcpu = vcpu; + + hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + apic->timer.dev.function = apic_timer_fn; + apic->base_address = APIC_DEFAULT_PHYS_BASE; + vcpu->apic_base = APIC_DEFAULT_PHYS_BASE; + + kvm_lapic_reset(vcpu); + apic->dev.read = apic_mmio_read; + apic->dev.write = apic_mmio_write; + apic->dev.in_range = apic_mmio_range; + apic->dev.private = apic; + + return 0; +nomem: + kvm_free_apic(apic); + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(kvm_create_lapic); + +int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->apic; + int highest_irr; + + if (!apic || !apic_enabled(apic)) + return -1; + + apic_update_ppr(apic); + highest_irr = apic_find_highest_irr(apic); + if ((highest_irr == -1) || + ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI))) + return -1; + return highest_irr; +} + +int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu) +{ + u32 lvt0 = apic_get_reg(vcpu->apic, APIC_LVT0); + int r = 0; + + if (vcpu->vcpu_id == 0) { + if (!apic_hw_enabled(vcpu->apic)) + r = 1; + if ((lvt0 & APIC_LVT_MASKED) == 0 && + GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT) + r = 1; + } + return r; +} + +void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->apic; + + if (apic && apic_lvt_enabled(apic, APIC_LVTT) && + atomic_read(&apic->timer.pending) > 0) { + if (__inject_apic_timer_irq(apic)) + atomic_dec(&apic->timer.pending); + } +} + +void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec) +{ + struct kvm_lapic *apic = vcpu->apic; + + if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec) + apic->timer.last_update = ktime_add_ns( + apic->timer.last_update, + apic->timer.period); +} + +int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) +{ + int vector = kvm_apic_has_interrupt(vcpu); + struct kvm_lapic *apic = vcpu->apic; + + if (vector == -1) + return -1; + + apic_set_vector(vector, apic->regs + APIC_ISR); + apic_update_ppr(apic); + apic_clear_irr(vector, apic); + return vector; +} + +void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->apic; + + apic->base_address = vcpu->apic_base & + MSR_IA32_APICBASE_BASE; + apic_set_reg(apic, APIC_LVR, APIC_VERSION); + apic_update_ppr(apic); + hrtimer_cancel(&apic->timer.dev); + update_divide_count(apic); + start_apic_timer(apic); +} + +void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->apic; + struct hrtimer *timer; + + if (!apic) + return; + + timer = &apic->timer.dev; + if (hrtimer_cancel(timer)) + hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS); +} +EXPORT_SYMBOL_GPL(kvm_migrate_apic_timer); diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index 23965aa5ee7..6d84d30f5ed 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c @@ -158,7 +158,7 @@ static struct kmem_cache *mmu_page_header_cache; static int is_write_protection(struct kvm_vcpu *vcpu) { - return vcpu->cr0 & CR0_WP_MASK; + return vcpu->cr0 & X86_CR0_WP; } static int is_cpuid_PSE36(void) @@ -202,15 +202,14 @@ static void set_shadow_pte(u64 *sptep, u64 spte) } static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache, - struct kmem_cache *base_cache, int min, - gfp_t gfp_flags) + struct kmem_cache *base_cache, int min) { void *obj; if (cache->nobjs >= min) return 0; while (cache->nobjs < ARRAY_SIZE(cache->objects)) { - obj = kmem_cache_zalloc(base_cache, gfp_flags); + obj = kmem_cache_zalloc(base_cache, GFP_KERNEL); if (!obj) return -ENOMEM; cache->objects[cache->nobjs++] = obj; @@ -225,14 +224,14 @@ static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc) } static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache, - int min, gfp_t gfp_flags) + int min) { struct page *page; if (cache->nobjs >= min) return 0; while (cache->nobjs < ARRAY_SIZE(cache->objects)) { - page = alloc_page(gfp_flags); + page = alloc_page(GFP_KERNEL); if (!page) return -ENOMEM; set_page_private(page, 0); @@ -247,44 +246,28 @@ static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc) free_page((unsigned long)mc->objects[--mc->nobjs]); } -static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags) +static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu) { int r; + kvm_mmu_free_some_pages(vcpu); r = mmu_topup_memory_cache(&vcpu->mmu_pte_chain_cache, - pte_chain_cache, 4, gfp_flags); + pte_chain_cache, 4); if (r) goto out; r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache, - rmap_desc_cache, 1, gfp_flags); + rmap_desc_cache, 1); if (r) goto out; - r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4, gfp_flags); + r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4); if (r) goto out; r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache, - mmu_page_header_cache, 4, gfp_flags); + mmu_page_header_cache, 4); out: return r; } -static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu) -{ - int r; - - r = __mmu_topup_memory_caches(vcpu, GFP_NOWAIT); - kvm_mmu_free_some_pages(vcpu); - if (r < 0) { - spin_unlock(&vcpu->kvm->lock); - kvm_arch_ops->vcpu_put(vcpu); - r = __mmu_topup_memory_caches(vcpu, GFP_KERNEL); - kvm_arch_ops->vcpu_load(vcpu); - spin_lock(&vcpu->kvm->lock); - kvm_mmu_free_some_pages(vcpu); - } - return r; -} - static void mmu_free_memory_caches(struct kvm_vcpu *vcpu) { mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache); @@ -969,7 +952,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu) static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu) { ++vcpu->stat.tlb_flush; - kvm_arch_ops->tlb_flush(vcpu); + kvm_x86_ops->tlb_flush(vcpu); } static void paging_new_cr3(struct kvm_vcpu *vcpu) @@ -982,7 +965,7 @@ static void inject_page_fault(struct kvm_vcpu *vcpu, u64 addr, u32 err_code) { - kvm_arch_ops->inject_page_fault(vcpu, addr, err_code); + kvm_x86_ops->inject_page_fault(vcpu, addr, err_code); } static void paging_free(struct kvm_vcpu *vcpu) @@ -1071,15 +1054,15 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu) { int r; - spin_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->lock); r = mmu_topup_memory_caches(vcpu); if (r) goto out; mmu_alloc_roots(vcpu); - kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa); + kvm_x86_ops->set_cr3(vcpu, vcpu->mmu.root_hpa); kvm_mmu_flush_tlb(vcpu); out: - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); return r; } EXPORT_SYMBOL_GPL(kvm_mmu_load); @@ -1124,7 +1107,7 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, } void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, - const u8 *old, const u8 *new, int bytes) + const u8 *new, int bytes) { gfn_t gfn = gpa >> PAGE_SHIFT; struct kvm_mmu_page *page; diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h index 4b5391c717f..6b094b44f8f 100644 --- a/drivers/kvm/paging_tmpl.h +++ b/drivers/kvm/paging_tmpl.h @@ -58,7 +58,10 @@ struct guest_walker { int level; gfn_t table_gfn[PT_MAX_FULL_LEVELS]; pt_element_t *table; + pt_element_t pte; pt_element_t *ptep; + struct page *page; + int index; pt_element_t inherited_ar; gfn_t gfn; u32 error_code; @@ -80,11 +83,14 @@ static int FNAME(walk_addr)(struct guest_walker *walker, pgprintk("%s: addr %lx\n", __FUNCTION__, addr); walker->level = vcpu->mmu.root_level; walker->table = NULL; + walker->page = NULL; + walker->ptep = NULL; root = vcpu->cr3; #if PTTYPE == 64 if (!is_long_mode(vcpu)) { walker->ptep = &vcpu->pdptrs[(addr >> 30) & 3]; root = *walker->ptep; + walker->pte = root; if (!(root & PT_PRESENT_MASK)) goto not_present; --walker->level; @@ -96,10 +102,11 @@ static int FNAME(walk_addr)(struct guest_walker *walker, walker->level - 1, table_gfn); slot = gfn_to_memslot(vcpu->kvm, table_gfn); hpa = safe_gpa_to_hpa(vcpu, root & PT64_BASE_ADDR_MASK); - walker->table = kmap_atomic(pfn_to_page(hpa >> PAGE_SHIFT), KM_USER0); + walker->page = pfn_to_page(hpa >> PAGE_SHIFT); + walker->table = kmap_atomic(walker->page, KM_USER0); ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || - (vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) == 0); + (vcpu->cr3 & CR3_NONPAE_RESERVED_BITS) == 0); walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK; @@ -108,6 +115,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker, hpa_t paddr; ptep = &walker->table[index]; + walker->index = index; ASSERT(((unsigned long)walker->table & PAGE_MASK) == ((unsigned long)ptep & PAGE_MASK)); @@ -148,16 +156,20 @@ static int FNAME(walk_addr)(struct guest_walker *walker, walker->inherited_ar &= walker->table[index]; table_gfn = (*ptep & PT_BASE_ADDR_MASK) >> PAGE_SHIFT; - paddr = safe_gpa_to_hpa(vcpu, *ptep & PT_BASE_ADDR_MASK); kunmap_atomic(walker->table, KM_USER0); - walker->table = kmap_atomic(pfn_to_page(paddr >> PAGE_SHIFT), - KM_USER0); + paddr = safe_gpa_to_hpa(vcpu, table_gfn << PAGE_SHIFT); + walker->page = pfn_to_page(paddr >> PAGE_SHIFT); + walker->table = kmap_atomic(walker->page, KM_USER0); --walker->level; walker->table_gfn[walker->level - 1 ] = table_gfn; pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__, walker->level - 1, table_gfn); } - walker->ptep = ptep; + walker->pte = *ptep; + if (walker->page) + walker->ptep = NULL; + if (walker->table) + kunmap_atomic(walker->table, KM_USER0); pgprintk("%s: pte %llx\n", __FUNCTION__, (u64)*ptep); return 1; @@ -175,13 +187,9 @@ err: walker->error_code |= PFERR_USER_MASK; if (fetch_fault) walker->error_code |= PFERR_FETCH_MASK; - return 0; -} - -static void FNAME(release_walker)(struct guest_walker *walker) -{ if (walker->table) kunmap_atomic(walker->table, KM_USER0); + return 0; } static void FNAME(mark_pagetable_dirty)(struct kvm *kvm, @@ -193,7 +201,7 @@ static void FNAME(mark_pagetable_dirty)(struct kvm *kvm, static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu, u64 *shadow_pte, gpa_t gaddr, - pt_element_t *gpte, + pt_element_t gpte, u64 access_bits, int user_fault, int write_fault, @@ -202,23 +210,34 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu, gfn_t gfn) { hpa_t paddr; - int dirty = *gpte & PT_DIRTY_MASK; + int dirty = gpte & PT_DIRTY_MASK; u64 spte = *shadow_pte; int was_rmapped = is_rmap_pte(spte); pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d" " user_fault %d gfn %lx\n", - __FUNCTION__, spte, (u64)*gpte, access_bits, + __FUNCTION__, spte, (u64)gpte, access_bits, write_fault, user_fault, gfn); if (write_fault && !dirty) { - *gpte |= PT_DIRTY_MASK; + pt_element_t *guest_ent, *tmp = NULL; + + if (walker->ptep) + guest_ent = walker->ptep; + else { + tmp = kmap_atomic(walker->page, KM_USER0); + guest_ent = &tmp[walker->index]; + } + + *guest_ent |= PT_DIRTY_MASK; + if (!walker->ptep) + kunmap_atomic(tmp, KM_USER0); dirty = 1; FNAME(mark_pagetable_dirty)(vcpu->kvm, walker); } spte |= PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_DIRTY_MASK; - spte |= *gpte & PT64_NX_MASK; + spte |= gpte & PT64_NX_MASK; if (!dirty) access_bits &= ~PT_WRITABLE_MASK; @@ -255,7 +274,7 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu, access_bits &= ~PT_WRITABLE_MASK; if (is_writeble_pte(spte)) { spte &= ~PT_WRITABLE_MASK; - kvm_arch_ops->tlb_flush(vcpu); + kvm_x86_ops->tlb_flush(vcpu); } if (write_fault) *ptwrite = 1; @@ -273,13 +292,13 @@ unshadowed: rmap_add(vcpu, shadow_pte); } -static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t *gpte, +static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, u64 *shadow_pte, u64 access_bits, int user_fault, int write_fault, int *ptwrite, struct guest_walker *walker, gfn_t gfn) { - access_bits &= *gpte; - FNAME(set_pte_common)(vcpu, shadow_pte, *gpte & PT_BASE_ADDR_MASK, + access_bits &= gpte; + FNAME(set_pte_common)(vcpu, shadow_pte, gpte & PT_BASE_ADDR_MASK, gpte, access_bits, user_fault, write_fault, ptwrite, walker, gfn); } @@ -295,22 +314,22 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page, if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) return; pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte); - FNAME(set_pte)(vcpu, &gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0, + FNAME(set_pte)(vcpu, gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0, 0, NULL, NULL, (gpte & PT_BASE_ADDR_MASK) >> PAGE_SHIFT); } -static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t *gpde, +static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t gpde, u64 *shadow_pte, u64 access_bits, int user_fault, int write_fault, int *ptwrite, struct guest_walker *walker, gfn_t gfn) { gpa_t gaddr; - access_bits &= *gpde; + access_bits &= gpde; gaddr = (gpa_t)gfn << PAGE_SHIFT; if (PTTYPE == 32 && is_cpuid_PSE36()) - gaddr |= (*gpde & PT32_DIR_PSE36_MASK) << + gaddr |= (gpde & PT32_DIR_PSE36_MASK) << (32 - PT32_DIR_PSE36_SHIFT); FNAME(set_pte_common)(vcpu, shadow_pte, gaddr, gpde, access_bits, user_fault, write_fault, @@ -328,9 +347,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, int level; u64 *shadow_ent; u64 *prev_shadow_ent = NULL; - pt_element_t *guest_ent = walker->ptep; - if (!is_present_pte(*guest_ent)) + if (!is_present_pte(walker->pte)) return NULL; shadow_addr = vcpu->mmu.root_hpa; @@ -364,12 +382,12 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, if (level - 1 == PT_PAGE_TABLE_LEVEL && walker->level == PT_DIRECTORY_LEVEL) { metaphysical = 1; - hugepage_access = *guest_ent; + hugepage_access = walker->pte; hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK; - if (*guest_ent & PT64_NX_MASK) + if (walker->pte & PT64_NX_MASK) hugepage_access |= (1 << 2); hugepage_access >>= PT_WRITABLE_SHIFT; - table_gfn = (*guest_ent & PT_BASE_ADDR_MASK) + table_gfn = (walker->pte & PT_BASE_ADDR_MASK) >> PAGE_SHIFT; } else { metaphysical = 0; @@ -386,12 +404,12 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, } if (walker->level == PT_DIRECTORY_LEVEL) { - FNAME(set_pde)(vcpu, guest_ent, shadow_ent, + FNAME(set_pde)(vcpu, walker->pte, shadow_ent, walker->inherited_ar, user_fault, write_fault, ptwrite, walker, walker->gfn); } else { ASSERT(walker->level == PT_PAGE_TABLE_LEVEL); - FNAME(set_pte)(vcpu, guest_ent, shadow_ent, + FNAME(set_pte)(vcpu, walker->pte, shadow_ent, walker->inherited_ar, user_fault, write_fault, ptwrite, walker, walker->gfn); } @@ -442,7 +460,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, if (!r) { pgprintk("%s: guest page fault\n", __FUNCTION__); inject_page_fault(vcpu, addr, walker.error_code); - FNAME(release_walker)(&walker); vcpu->last_pt_write_count = 0; /* reset fork detector */ return 0; } @@ -452,8 +469,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __FUNCTION__, shadow_pte, *shadow_pte, write_pt); - FNAME(release_walker)(&walker); - if (!write_pt) vcpu->last_pt_write_count = 0; /* reset fork detector */ @@ -482,7 +497,6 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) gpa |= vaddr & ~PAGE_MASK; } - FNAME(release_walker)(&walker); return gpa; } diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index bc818cc126e..729f1cd9360 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c @@ -16,12 +16,12 @@ #include "kvm_svm.h" #include "x86_emulate.h" +#include "irq.h" #include <linux/module.h> #include <linux/kernel.h> #include <linux/vmalloc.h> #include <linux/highmem.h> -#include <linux/profile.h> #include <linux/sched.h> #include <asm/desc.h> @@ -38,7 +38,6 @@ MODULE_LICENSE("GPL"); #define DR7_GD_MASK (1 << 13) #define DR6_BD_MASK (1 << 13) -#define CR4_DE_MASK (1UL << 3) #define SEG_TYPE_LDT 2 #define SEG_TYPE_BUSY_TSS16 3 @@ -50,6 +49,13 @@ MODULE_LICENSE("GPL"); #define SVM_FEATURE_LBRV (1 << 1) #define SVM_DEATURE_SVML (1 << 2) +static void kvm_reput_irq(struct vcpu_svm *svm); + +static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu) +{ + return container_of(vcpu, struct vcpu_svm, vcpu); +} + unsigned long iopm_base; unsigned long msrpm_base; @@ -94,20 +100,6 @@ static inline u32 svm_has(u32 feat) return svm_features & feat; } -static unsigned get_addr_size(struct kvm_vcpu *vcpu) -{ - struct vmcb_save_area *sa = &vcpu->svm->vmcb->save; - u16 cs_attrib; - - if (!(sa->cr0 & CR0_PE_MASK) || (sa->rflags & X86_EFLAGS_VM)) - return 2; - - cs_attrib = sa->cs.attrib; - - return (cs_attrib & SVM_SELECTOR_L_MASK) ? 8 : - (cs_attrib & SVM_SELECTOR_DB_MASK) ? 4 : 2; -} - static inline u8 pop_irq(struct kvm_vcpu *vcpu) { int word_index = __ffs(vcpu->irq_summary); @@ -182,7 +174,7 @@ static inline void write_dr7(unsigned long val) static inline void force_new_asid(struct kvm_vcpu *vcpu) { - vcpu->svm->asid_generation--; + to_svm(vcpu)->asid_generation--; } static inline void flush_guest_tlb(struct kvm_vcpu *vcpu) @@ -195,22 +187,24 @@ static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer) if (!(efer & KVM_EFER_LMA)) efer &= ~KVM_EFER_LME; - vcpu->svm->vmcb->save.efer = efer | MSR_EFER_SVME_MASK; + to_svm(vcpu)->vmcb->save.efer = efer | MSR_EFER_SVME_MASK; vcpu->shadow_efer = efer; } static void svm_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code) { - vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | + struct vcpu_svm *svm = to_svm(vcpu); + + svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_VALID_ERR | SVM_EVTINJ_TYPE_EXEPT | GP_VECTOR; - vcpu->svm->vmcb->control.event_inj_err = error_code; + svm->vmcb->control.event_inj_err = error_code; } static void inject_ud(struct kvm_vcpu *vcpu) { - vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | + to_svm(vcpu)->vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_EXEPT | UD_VECTOR; } @@ -229,19 +223,21 @@ static int is_external_interrupt(u32 info) static void skip_emulated_instruction(struct kvm_vcpu *vcpu) { - if (!vcpu->svm->next_rip) { + struct vcpu_svm *svm = to_svm(vcpu); + + if (!svm->next_rip) { printk(KERN_DEBUG "%s: NOP\n", __FUNCTION__); return; } - if (vcpu->svm->next_rip - vcpu->svm->vmcb->save.rip > 15) { + if (svm->next_rip - svm->vmcb->save.rip > MAX_INST_SIZE) { printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n", __FUNCTION__, - vcpu->svm->vmcb->save.rip, - vcpu->svm->next_rip); + svm->vmcb->save.rip, + svm->next_rip); } - vcpu->rip = vcpu->svm->vmcb->save.rip = vcpu->svm->next_rip; - vcpu->svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; + vcpu->rip = svm->vmcb->save.rip = svm->next_rip; + svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; vcpu->interrupt_window_open = 1; } @@ -351,8 +347,8 @@ err_1: } -static int set_msr_interception(u32 *msrpm, unsigned msr, - int read, int write) +static void set_msr_interception(u32 *msrpm, unsigned msr, + int read, int write) { int i; @@ -367,11 +363,10 @@ static int set_msr_interception(u32 *msrpm, unsigned msr, u32 mask = ((write) ? 0 : 2) | ((read) ? 0 : 1); *base = (*base & ~(0x3 << msr_shift)) | (mask << msr_shift); - return 1; + return; } } - printk(KERN_DEBUG "%s: not found 0x%x\n", __FUNCTION__, msr); - return 0; + BUG(); } static __init int svm_hardware_setup(void) @@ -382,8 +377,6 @@ static __init int svm_hardware_setup(void) void *iopm_va, *msrpm_va; int r; - kvm_emulator_want_group7_invlpg(); - iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER); if (!iopm_pages) @@ -458,11 +451,6 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type) seg->base = 0; } -static int svm_vcpu_setup(struct kvm_vcpu *vcpu) -{ - return 0; -} - static void init_vmcb(struct vmcb *vmcb) { struct vmcb_control_area *control = &vmcb->control; @@ -563,59 +551,83 @@ static void init_vmcb(struct vmcb *vmcb) * cr0 val on cpu init should be 0x60000010, we enable cpu * cache by default. the orderly way is to enable cache in bios. */ - save->cr0 = 0x00000010 | CR0_PG_MASK | CR0_WP_MASK; - save->cr4 = CR4_PAE_MASK; + save->cr0 = 0x00000010 | X86_CR0_PG | X86_CR0_WP; + save->cr4 = X86_CR4_PAE; /* rdx = ?? */ } -static int svm_create_vcpu(struct kvm_vcpu *vcpu) +static void svm_vcpu_reset(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + init_vmcb(svm->vmcb); +} + +static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) { + struct vcpu_svm *svm; struct page *page; - int r; + int err; + + svm = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); + if (!svm) { + err = -ENOMEM; + goto out; + } + + err = kvm_vcpu_init(&svm->vcpu, kvm, id); + if (err) + goto free_svm; + + if (irqchip_in_kernel(kvm)) { + err = kvm_create_lapic(&svm->vcpu); + if (err < 0) + goto free_svm; + } - r = -ENOMEM; - vcpu->svm = kzalloc(sizeof *vcpu->svm, GFP_KERNEL); - if (!vcpu->svm) - goto out1; page = alloc_page(GFP_KERNEL); - if (!page) - goto out2; - - vcpu->svm->vmcb = page_address(page); - clear_page(vcpu->svm->vmcb); - vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT; - vcpu->svm->asid_generation = 0; - memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs)); - init_vmcb(vcpu->svm->vmcb); - - fx_init(vcpu); - vcpu->fpu_active = 1; - vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; - if (vcpu == &vcpu->kvm->vcpus[0]) - vcpu->apic_base |= MSR_IA32_APICBASE_BSP; + if (!page) { + err = -ENOMEM; + goto uninit; + } - return 0; + svm->vmcb = page_address(page); + clear_page(svm->vmcb); + svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT; + svm->asid_generation = 0; + memset(svm->db_regs, 0, sizeof(svm->db_regs)); + init_vmcb(svm->vmcb); -out2: - kfree(vcpu->svm); -out1: - return r; + fx_init(&svm->vcpu); + svm->vcpu.fpu_active = 1; + svm->vcpu.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; + if (svm->vcpu.vcpu_id == 0) + svm->vcpu.apic_base |= MSR_IA32_APICBASE_BSP; + + return &svm->vcpu; + +uninit: + kvm_vcpu_uninit(&svm->vcpu); +free_svm: + kmem_cache_free(kvm_vcpu_cache, svm); +out: + return ERR_PTR(err); } static void svm_free_vcpu(struct kvm_vcpu *vcpu) { - if (!vcpu->svm) - return; - if (vcpu->svm->vmcb) - __free_page(pfn_to_page(vcpu->svm->vmcb_pa >> PAGE_SHIFT)); - kfree(vcpu->svm); + struct vcpu_svm *svm = to_svm(vcpu); + + __free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT)); + kvm_vcpu_uninit(vcpu); + kmem_cache_free(kvm_vcpu_cache, svm); } -static void svm_vcpu_load(struct kvm_vcpu *vcpu) +static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { - int cpu, i; + struct vcpu_svm *svm = to_svm(vcpu); + int i; - cpu = get_cpu(); if (unlikely(cpu != vcpu->cpu)) { u64 tsc_this, delta; @@ -625,23 +637,24 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu) */ rdtscll(tsc_this); delta = vcpu->host_tsc - tsc_this; - vcpu->svm->vmcb->control.tsc_offset += delta; + svm->vmcb->control.tsc_offset += delta; vcpu->cpu = cpu; + kvm_migrate_apic_timer(vcpu); } for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) - rdmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]); + rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); } static void svm_vcpu_put(struct kvm_vcpu *vcpu) { + struct vcpu_svm *svm = to_svm(vcpu); int i; for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) - wrmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]); + wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); rdtscll(vcpu->host_tsc); - put_cpu(); } static void svm_vcpu_decache(struct kvm_vcpu *vcpu) @@ -650,31 +663,34 @@ static void svm_vcpu_decache(struct kvm_vcpu *vcpu) static void svm_cache_regs(struct kvm_vcpu *vcpu) { - vcpu->regs[VCPU_REGS_RAX] = vcpu->svm->vmcb->save.rax; - vcpu->regs[VCPU_REGS_RSP] = vcpu->svm->vmcb->save.rsp; - vcpu->rip = vcpu->svm->vmcb->save.rip; + struct vcpu_svm *svm = to_svm(vcpu); + + vcpu->regs[VCPU_REGS_RAX] = svm->vmcb->save.rax; + vcpu->regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp; + vcpu->rip = svm->vmcb->save.rip; } static void svm_decache_regs(struct kvm_vcpu *vcpu) { - vcpu->svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX]; - vcpu->svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP]; - vcpu->svm->vmcb->save.rip = vcpu->rip; + struct vcpu_svm *svm = to_svm(vcpu); + svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX]; + svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP]; + svm->vmcb->save.rip = vcpu->rip; } static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu) { - return vcpu->svm->vmcb->save.rflags; + return to_svm(vcpu)->vmcb->save.rflags; } static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) { - vcpu->svm->vmcb->save.rflags = rflags; + to_svm(vcpu)->vmcb->save.rflags = rflags; } static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg) { - struct vmcb_save_area *save = &vcpu->svm->vmcb->save; + struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save; switch (seg) { case VCPU_SREG_CS: return &save->cs; @@ -716,36 +732,36 @@ static void svm_get_segment(struct kvm_vcpu *vcpu, var->unusable = !var->present; } -static void svm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) -{ - struct vmcb_seg *s = svm_seg(vcpu, VCPU_SREG_CS); - - *db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1; - *l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1; -} - static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) { - dt->limit = vcpu->svm->vmcb->save.idtr.limit; - dt->base = vcpu->svm->vmcb->save.idtr.base; + struct vcpu_svm *svm = to_svm(vcpu); + + dt->limit = svm->vmcb->save.idtr.limit; + dt->base = svm->vmcb->save.idtr.base; } static void svm_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) { - vcpu->svm->vmcb->save.idtr.limit = dt->limit; - vcpu->svm->vmcb->save.idtr.base = dt->base ; + struct vcpu_svm *svm = to_svm(vcpu); + + svm->vmcb->save.idtr.limit = dt->limit; + svm->vmcb->save.idtr.base = dt->base ; } static void svm_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) { - dt->limit = vcpu->svm->vmcb->save.gdtr.limit; - dt->base = vcpu->svm->vmcb->save.gdtr.base; + struct vcpu_svm *svm = to_svm(vcpu); + + dt->limit = svm->vmcb->save.gdtr.limit; + dt->base = svm->vmcb->save.gdtr.base; } static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) { - vcpu->svm->vmcb->save.gdtr.limit = dt->limit; - vcpu->svm->vmcb->save.gdtr.base = dt->base ; + struct vcpu_svm *svm = to_svm(vcpu); + + svm->vmcb->save.gdtr.limit = dt->limit; + svm->vmcb->save.gdtr.base = dt->base ; } static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) @@ -754,39 +770,42 @@ static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) { + struct vcpu_svm *svm = to_svm(vcpu); + #ifdef CONFIG_X86_64 if (vcpu->shadow_efer & KVM_EFER_LME) { - if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) { + if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) { vcpu->shadow_efer |= KVM_EFER_LMA; - vcpu->svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME; + svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME; } - if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK) ) { + if (is_paging(vcpu) && !(cr0 & X86_CR0_PG) ) { vcpu->shadow_efer &= ~KVM_EFER_LMA; - vcpu->svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME); + svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME); } } #endif - if ((vcpu->cr0 & CR0_TS_MASK) && !(cr0 & CR0_TS_MASK)) { - vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); + if ((vcpu->cr0 & X86_CR0_TS) && !(cr0 & X86_CR0_TS)) { + svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); vcpu->fpu_active = 1; } vcpu->cr0 = cr0; - cr0 |= CR0_PG_MASK | CR0_WP_MASK; - cr0 &= ~(CR0_CD_MASK | CR0_NW_MASK); - vcpu->svm->vmcb->save.cr0 = cr0; + cr0 |= X86_CR0_PG | X86_CR0_WP; + cr0 &= ~(X86_CR0_CD | X86_CR0_NW); + svm->vmcb->save.cr0 = cr0; } static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) { vcpu->cr4 = cr4; - vcpu->svm->vmcb->save.cr4 = cr4 | CR4_PAE_MASK; + to_svm(vcpu)->vmcb->save.cr4 = cr4 | X86_CR4_PAE; } static void svm_set_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg) { + struct vcpu_svm *svm = to_svm(vcpu); struct vmcb_seg *s = svm_seg(vcpu, seg); s->base = var->base; @@ -805,16 +824,16 @@ static void svm_set_segment(struct kvm_vcpu *vcpu, s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT; } if (seg == VCPU_SREG_CS) - vcpu->svm->vmcb->save.cpl - = (vcpu->svm->vmcb->save.cs.attrib + svm->vmcb->save.cpl + = (svm->vmcb->save.cs.attrib >> SVM_SELECTOR_DPL_SHIFT) & 3; } /* FIXME: - vcpu->svm->vmcb->control.int_ctl &= ~V_TPR_MASK; - vcpu->svm->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK); + svm(vcpu)->vmcb->control.int_ctl &= ~V_TPR_MASK; + svm(vcpu)->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK); */ @@ -823,61 +842,68 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) return -EOPNOTSUPP; } +static int svm_get_irq(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + u32 exit_int_info = svm->vmcb->control.exit_int_info; + + if (is_external_interrupt(exit_int_info)) + return exit_int_info & SVM_EVTINJ_VEC_MASK; + return -1; +} + static void load_host_msrs(struct kvm_vcpu *vcpu) { #ifdef CONFIG_X86_64 - wrmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base); + wrmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base); #endif } static void save_host_msrs(struct kvm_vcpu *vcpu) { #ifdef CONFIG_X86_64 - rdmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base); + rdmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base); #endif } -static void new_asid(struct kvm_vcpu *vcpu, struct svm_cpu_data *svm_data) +static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data) { if (svm_data->next_asid > svm_data->max_asid) { ++svm_data->asid_generation; svm_data->next_asid = 1; - vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID; + svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID; } - vcpu->cpu = svm_data->cpu; - vcpu->svm->asid_generation = svm_data->asid_generation; - vcpu->svm->vmcb->control.asid = svm_data->next_asid++; -} - -static void svm_invlpg(struct kvm_vcpu *vcpu, gva_t address) -{ - invlpga(address, vcpu->svm->vmcb->control.asid); // is needed? + svm->vcpu.cpu = svm_data->cpu; + svm->asid_generation = svm_data->asid_generation; + svm->vmcb->control.asid = svm_data->next_asid++; } static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr) { - return vcpu->svm->db_regs[dr]; + return to_svm(vcpu)->db_regs[dr]; } static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, int *exception) { + struct vcpu_svm *svm = to_svm(vcpu); + *exception = 0; - if (vcpu->svm->vmcb->save.dr7 & DR7_GD_MASK) { - vcpu->svm->vmcb->save.dr7 &= ~DR7_GD_MASK; - vcpu->svm->vmcb->save.dr6 |= DR6_BD_MASK; + if (svm->vmcb->save.dr7 & DR7_GD_MASK) { + svm->vmcb->save.dr7 &= ~DR7_GD_MASK; + svm->vmcb->save.dr6 |= DR6_BD_MASK; *exception = DB_VECTOR; return; } switch (dr) { case 0 ... 3: - vcpu->svm->db_regs[dr] = value; + svm->db_regs[dr] = value; return; case 4 ... 5: - if (vcpu->cr4 & CR4_DE_MASK) { + if (vcpu->cr4 & X86_CR4_DE) { *exception = UD_VECTOR; return; } @@ -886,7 +912,7 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, *exception = GP_VECTOR; return; } - vcpu->svm->vmcb->save.dr7 = value; + svm->vmcb->save.dr7 = value; return; } default: @@ -897,42 +923,44 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, } } -static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - u32 exit_int_info = vcpu->svm->vmcb->control.exit_int_info; + u32 exit_int_info = svm->vmcb->control.exit_int_info; + struct kvm *kvm = svm->vcpu.kvm; u64 fault_address; u32 error_code; enum emulation_result er; int r; - if (is_external_interrupt(exit_int_info)) - push_irq(vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK); + if (!irqchip_in_kernel(kvm) && + is_external_interrupt(exit_int_info)) + push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK); - spin_lock(&vcpu->kvm->lock); + mutex_lock(&kvm->lock); - fault_address = vcpu->svm->vmcb->control.exit_info_2; - error_code = vcpu->svm->vmcb->control.exit_info_1; - r = kvm_mmu_page_fault(vcpu, fault_address, error_code); + fault_address = svm->vmcb->control.exit_info_2; + error_code = svm->vmcb->control.exit_info_1; + r = kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code); if (r < 0) { - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&kvm->lock); return r; } if (!r) { - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&kvm->lock); return 1; } - er = emulate_instruction(vcpu, kvm_run, fault_address, error_code); - spin_unlock(&vcpu->kvm->lock); + er = emulate_instruction(&svm->vcpu, kvm_run, fault_address, + error_code); + mutex_unlock(&kvm->lock); switch (er) { case EMULATE_DONE: return 1; case EMULATE_DO_MMIO: - ++vcpu->stat.mmio_exits; - kvm_run->exit_reason = KVM_EXIT_MMIO; + ++svm->vcpu.stat.mmio_exits; return 0; case EMULATE_FAIL: - vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__); + kvm_report_emulation_failure(&svm->vcpu, "pagetable"); break; default: BUG(); @@ -942,252 +970,142 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 0; } -static int nm_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); - if (!(vcpu->cr0 & CR0_TS_MASK)) - vcpu->svm->vmcb->save.cr0 &= ~CR0_TS_MASK; - vcpu->fpu_active = 1; + svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); + if (!(svm->vcpu.cr0 & X86_CR0_TS)) + svm->vmcb->save.cr0 &= ~X86_CR0_TS; + svm->vcpu.fpu_active = 1; - return 1; + return 1; } -static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { /* * VMCB is undefined after a SHUTDOWN intercept * so reinitialize it. */ - clear_page(vcpu->svm->vmcb); - init_vmcb(vcpu->svm->vmcb); + clear_page(svm->vmcb); + init_vmcb(svm->vmcb); kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; return 0; } -static int io_get_override(struct kvm_vcpu *vcpu, - struct vmcb_seg **seg, - int *addr_override) -{ - u8 inst[MAX_INST_SIZE]; - unsigned ins_length; - gva_t rip; - int i; - - rip = vcpu->svm->vmcb->save.rip; - ins_length = vcpu->svm->next_rip - rip; - rip += vcpu->svm->vmcb->save.cs.base; - - if (ins_length > MAX_INST_SIZE) - printk(KERN_DEBUG - "%s: inst length err, cs base 0x%llx rip 0x%llx " - "next rip 0x%llx ins_length %u\n", - __FUNCTION__, - vcpu->svm->vmcb->save.cs.base, - vcpu->svm->vmcb->save.rip, - vcpu->svm->vmcb->control.exit_info_2, - ins_length); - - if (kvm_read_guest(vcpu, rip, ins_length, inst) != ins_length) - /* #PF */ - return 0; - - *addr_override = 0; - *seg = NULL; - for (i = 0; i < ins_length; i++) - switch (inst[i]) { - case 0xf0: - case 0xf2: - case 0xf3: - case 0x66: - continue; - case 0x67: - *addr_override = 1; - continue; - case 0x2e: - *seg = &vcpu->svm->vmcb->save.cs; - continue; - case 0x36: - *seg = &vcpu->svm->vmcb->save.ss; - continue; - case 0x3e: - *seg = &vcpu->svm->vmcb->save.ds; - continue; - case 0x26: - *seg = &vcpu->svm->vmcb->save.es; - continue; - case 0x64: - *seg = &vcpu->svm->vmcb->save.fs; - continue; - case 0x65: - *seg = &vcpu->svm->vmcb->save.gs; - continue; - default: - return 1; - } - printk(KERN_DEBUG "%s: unexpected\n", __FUNCTION__); - return 0; -} - -static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, gva_t *address) +static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - unsigned long addr_mask; - unsigned long *reg; - struct vmcb_seg *seg; - int addr_override; - struct vmcb_save_area *save_area = &vcpu->svm->vmcb->save; - u16 cs_attrib = save_area->cs.attrib; - unsigned addr_size = get_addr_size(vcpu); - - if (!io_get_override(vcpu, &seg, &addr_override)) - return 0; - - if (addr_override) - addr_size = (addr_size == 2) ? 4: (addr_size >> 1); + u32 io_info = svm->vmcb->control.exit_info_1; //address size bug? + int size, down, in, string, rep; + unsigned port; - if (ins) { - reg = &vcpu->regs[VCPU_REGS_RDI]; - seg = &vcpu->svm->vmcb->save.es; - } else { - reg = &vcpu->regs[VCPU_REGS_RSI]; - seg = (seg) ? seg : &vcpu->svm->vmcb->save.ds; - } + ++svm->vcpu.stat.io_exits; - addr_mask = ~0ULL >> (64 - (addr_size * 8)); + svm->next_rip = svm->vmcb->control.exit_info_2; - if ((cs_attrib & SVM_SELECTOR_L_MASK) && - !(vcpu->svm->vmcb->save.rflags & X86_EFLAGS_VM)) { - *address = (*reg & addr_mask); - return addr_mask; - } + string = (io_info & SVM_IOIO_STR_MASK) != 0; - if (!(seg->attrib & SVM_SELECTOR_P_SHIFT)) { - svm_inject_gp(vcpu, 0); - return 0; + if (string) { + if (emulate_instruction(&svm->vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO) + return 0; + return 1; } - *address = (*reg & addr_mask) + seg->base; - return addr_mask; -} - -static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - u32 io_info = vcpu->svm->vmcb->control.exit_info_1; //address size bug? - int size, down, in, string, rep; - unsigned port; - unsigned long count; - gva_t address = 0; - - ++vcpu->stat.io_exits; - - vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2; - in = (io_info & SVM_IOIO_TYPE_MASK) != 0; port = io_info >> 16; size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT; - string = (io_info & SVM_IOIO_STR_MASK) != 0; rep = (io_info & SVM_IOIO_REP_MASK) != 0; - count = 1; - down = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0; + down = (svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0; - if (string) { - unsigned addr_mask; - - addr_mask = io_adress(vcpu, in, &address); - if (!addr_mask) { - printk(KERN_DEBUG "%s: get io address failed\n", - __FUNCTION__); - return 1; - } - - if (rep) - count = vcpu->regs[VCPU_REGS_RCX] & addr_mask; - } - return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down, - address, rep, port); + return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port); } -static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { return 1; } -static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int halt_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1; - skip_emulated_instruction(vcpu); - return kvm_emulate_halt(vcpu); + svm->next_rip = svm->vmcb->save.rip + 1; + skip_emulated_instruction(&svm->vcpu); + return kvm_emulate_halt(&svm->vcpu); } -static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int vmmcall_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 3; - skip_emulated_instruction(vcpu); - return kvm_hypercall(vcpu, kvm_run); + svm->next_rip = svm->vmcb->save.rip + 3; + skip_emulated_instruction(&svm->vcpu); + return kvm_hypercall(&svm->vcpu, kvm_run); } -static int invalid_op_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int invalid_op_interception(struct vcpu_svm *svm, + struct kvm_run *kvm_run) { - inject_ud(vcpu); + inject_ud(&svm->vcpu); return 1; } -static int task_switch_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int task_switch_interception(struct vcpu_svm *svm, + struct kvm_run *kvm_run) { - printk(KERN_DEBUG "%s: task swiche is unsupported\n", __FUNCTION__); + pr_unimpl(&svm->vcpu, "%s: task switch is unsupported\n", __FUNCTION__); kvm_run->exit_reason = KVM_EXIT_UNKNOWN; return 0; } -static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; - kvm_emulate_cpuid(vcpu); + svm->next_rip = svm->vmcb->save.rip + 2; + kvm_emulate_cpuid(&svm->vcpu); return 1; } -static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int emulate_on_interception(struct vcpu_svm *svm, + struct kvm_run *kvm_run) { - if (emulate_instruction(vcpu, NULL, 0, 0) != EMULATE_DONE) - printk(KERN_ERR "%s: failed\n", __FUNCTION__); + if (emulate_instruction(&svm->vcpu, NULL, 0, 0) != EMULATE_DONE) + pr_unimpl(&svm->vcpu, "%s: failed\n", __FUNCTION__); return 1; } static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data) { + struct vcpu_svm *svm = to_svm(vcpu); + switch (ecx) { case MSR_IA32_TIME_STAMP_COUNTER: { u64 tsc; rdtscll(tsc); - *data = vcpu->svm->vmcb->control.tsc_offset + tsc; + *data = svm->vmcb->control.tsc_offset + tsc; break; } case MSR_K6_STAR: - *data = vcpu->svm->vmcb->save.star; + *data = svm->vmcb->save.star; break; #ifdef CONFIG_X86_64 case MSR_LSTAR: - *data = vcpu->svm->vmcb->save.lstar; + *data = svm->vmcb->save.lstar; break; case MSR_CSTAR: - *data = vcpu->svm->vmcb->save.cstar; + *data = svm->vmcb->save.cstar; break; case MSR_KERNEL_GS_BASE: - *data = vcpu->svm->vmcb->save.kernel_gs_base; + *data = svm->vmcb->save.kernel_gs_base; break; case MSR_SYSCALL_MASK: - *data = vcpu->svm->vmcb->save.sfmask; + *data = svm->vmcb->save.sfmask; break; #endif case MSR_IA32_SYSENTER_CS: - *data = vcpu->svm->vmcb->save.sysenter_cs; + *data = svm->vmcb->save.sysenter_cs; break; case MSR_IA32_SYSENTER_EIP: - *data = vcpu->svm->vmcb->save.sysenter_eip; + *data = svm->vmcb->save.sysenter_eip; break; case MSR_IA32_SYSENTER_ESP: - *data = vcpu->svm->vmcb->save.sysenter_esp; + *data = svm->vmcb->save.sysenter_esp; break; default: return kvm_get_msr_common(vcpu, ecx, data); @@ -1195,57 +1113,59 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data) return 0; } -static int rdmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int rdmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - u32 ecx = vcpu->regs[VCPU_REGS_RCX]; + u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX]; u64 data; - if (svm_get_msr(vcpu, ecx, &data)) - svm_inject_gp(vcpu, 0); + if (svm_get_msr(&svm->vcpu, ecx, &data)) + svm_inject_gp(&svm->vcpu, 0); else { - vcpu->svm->vmcb->save.rax = data & 0xffffffff; - vcpu->regs[VCPU_REGS_RDX] = data >> 32; - vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; - skip_emulated_instruction(vcpu); + svm->vmcb->save.rax = data & 0xffffffff; + svm->vcpu.regs[VCPU_REGS_RDX] = data >> 32; + svm->next_rip = svm->vmcb->save.rip + 2; + skip_emulated_instruction(&svm->vcpu); } return 1; } static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) { + struct vcpu_svm *svm = to_svm(vcpu); + switch (ecx) { case MSR_IA32_TIME_STAMP_COUNTER: { u64 tsc; rdtscll(tsc); - vcpu->svm->vmcb->control.tsc_offset = data - tsc; + svm->vmcb->control.tsc_offset = data - tsc; break; } case MSR_K6_STAR: - vcpu->svm->vmcb->save.star = data; + svm->vmcb->save.star = data; break; #ifdef CONFIG_X86_64 case MSR_LSTAR: - vcpu->svm->vmcb->save.lstar = data; + svm->vmcb->save.lstar = data; break; case MSR_CSTAR: - vcpu->svm->vmcb->save.cstar = data; + svm->vmcb->save.cstar = data; break; case MSR_KERNEL_GS_BASE: - vcpu->svm->vmcb->save.kernel_gs_base = data; + svm->vmcb->save.kernel_gs_base = data; break; case MSR_SYSCALL_MASK: - vcpu->svm->vmcb->save.sfmask = data; + svm->vmcb->save.sfmask = data; break; #endif case MSR_IA32_SYSENTER_CS: - vcpu->svm->vmcb->save.sysenter_cs = data; + svm->vmcb->save.sysenter_cs = data; break; case MSR_IA32_SYSENTER_EIP: - vcpu->svm->vmcb->save.sysenter_eip = data; + svm->vmcb->save.sysenter_eip = data; break; case MSR_IA32_SYSENTER_ESP: - vcpu->svm->vmcb->save.sysenter_esp = data; + svm->vmcb->save.sysenter_esp = data; break; default: return kvm_set_msr_common(vcpu, ecx, data); @@ -1253,37 +1173,39 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) return 0; } -static int wrmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - u32 ecx = vcpu->regs[VCPU_REGS_RCX]; - u64 data = (vcpu->svm->vmcb->save.rax & -1u) - | ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32); - vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; - if (svm_set_msr(vcpu, ecx, data)) - svm_inject_gp(vcpu, 0); + u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX]; + u64 data = (svm->vmcb->save.rax & -1u) + | ((u64)(svm->vcpu.regs[VCPU_REGS_RDX] & -1u) << 32); + svm->next_rip = svm->vmcb->save.rip + 2; + if (svm_set_msr(&svm->vcpu, ecx, data)) + svm_inject_gp(&svm->vcpu, 0); else - skip_emulated_instruction(vcpu); + skip_emulated_instruction(&svm->vcpu); return 1; } -static int msr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - if (vcpu->svm->vmcb->control.exit_info_1) - return wrmsr_interception(vcpu, kvm_run); + if (svm->vmcb->control.exit_info_1) + return wrmsr_interception(svm, kvm_run); else - return rdmsr_interception(vcpu, kvm_run); + return rdmsr_interception(svm, kvm_run); } -static int interrupt_window_interception(struct kvm_vcpu *vcpu, +static int interrupt_window_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { + svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR); + svm->vmcb->control.int_ctl &= ~V_IRQ_MASK; /* * If the user space waits to inject interrupts, exit as soon as * possible */ if (kvm_run->request_interrupt_window && - !vcpu->irq_summary) { - ++vcpu->stat.irq_window_exits; + !svm->vcpu.irq_summary) { + ++svm->vcpu.stat.irq_window_exits; kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; return 0; } @@ -1291,7 +1213,7 @@ static int interrupt_window_interception(struct kvm_vcpu *vcpu, return 1; } -static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu, +static int (*svm_exit_handlers[])(struct vcpu_svm *svm, struct kvm_run *kvm_run) = { [SVM_EXIT_READ_CR0] = emulate_on_interception, [SVM_EXIT_READ_CR3] = emulate_on_interception, @@ -1338,15 +1260,25 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu, }; -static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) { - u32 exit_code = vcpu->svm->vmcb->control.exit_code; + struct vcpu_svm *svm = to_svm(vcpu); + u32 exit_code = svm->vmcb->control.exit_code; + + kvm_reput_irq(svm); - if (is_external_interrupt(vcpu->svm->vmcb->control.exit_int_info) && + if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) { + kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; + kvm_run->fail_entry.hardware_entry_failure_reason + = svm->vmcb->control.exit_code; + return 0; + } + + if (is_external_interrupt(svm->vmcb->control.exit_int_info) && exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR) printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x " "exit_code 0x%x\n", - __FUNCTION__, vcpu->svm->vmcb->control.exit_int_info, + __FUNCTION__, svm->vmcb->control.exit_int_info, exit_code); if (exit_code >= ARRAY_SIZE(svm_exit_handlers) @@ -1356,7 +1288,7 @@ static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 0; } - return svm_exit_handlers[exit_code](vcpu, kvm_run); + return svm_exit_handlers[exit_code](svm, kvm_run); } static void reload_tss(struct kvm_vcpu *vcpu) @@ -1368,93 +1300,126 @@ static void reload_tss(struct kvm_vcpu *vcpu) load_TR_desc(); } -static void pre_svm_run(struct kvm_vcpu *vcpu) +static void pre_svm_run(struct vcpu_svm *svm) { int cpu = raw_smp_processor_id(); struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu); - vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING; - if (vcpu->cpu != cpu || - vcpu->svm->asid_generation != svm_data->asid_generation) - new_asid(vcpu, svm_data); + svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING; + if (svm->vcpu.cpu != cpu || + svm->asid_generation != svm_data->asid_generation) + new_asid(svm, svm_data); } -static inline void kvm_do_inject_irq(struct kvm_vcpu *vcpu) +static inline void svm_inject_irq(struct vcpu_svm *svm, int irq) { struct vmcb_control_area *control; - control = &vcpu->svm->vmcb->control; - control->int_vector = pop_irq(vcpu); + control = &svm->vmcb->control; + control->int_vector = irq; control->int_ctl &= ~V_INTR_PRIO_MASK; control->int_ctl |= V_IRQ_MASK | ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT); } -static void kvm_reput_irq(struct kvm_vcpu *vcpu) +static void svm_set_irq(struct kvm_vcpu *vcpu, int irq) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + svm_inject_irq(svm, irq); +} + +static void svm_intr_assist(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + struct vmcb *vmcb = svm->vmcb; + int intr_vector = -1; + + kvm_inject_pending_timer_irqs(vcpu); + if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) && + ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) { + intr_vector = vmcb->control.exit_int_info & + SVM_EVTINJ_VEC_MASK; + vmcb->control.exit_int_info = 0; + svm_inject_irq(svm, intr_vector); + return; + } + + if (vmcb->control.int_ctl & V_IRQ_MASK) + return; + + if (!kvm_cpu_has_interrupt(vcpu)) + return; + + if (!(vmcb->save.rflags & X86_EFLAGS_IF) || + (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) || + (vmcb->control.event_inj & SVM_EVTINJ_VALID)) { + /* unable to deliver irq, set pending irq */ + vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR); + svm_inject_irq(svm, 0x0); + return; + } + /* Okay, we can deliver the interrupt: grab it and update PIC state. */ + intr_vector = kvm_cpu_get_interrupt(vcpu); + svm_inject_irq(svm, intr_vector); + kvm_timer_intr_post(vcpu, intr_vector); +} + +static void kvm_reput_irq(struct vcpu_svm *svm) { - struct vmcb_control_area *control = &vcpu->svm->vmcb->control; + struct vmcb_control_area *control = &svm->vmcb->control; - if (control->int_ctl & V_IRQ_MASK) { + if ((control->int_ctl & V_IRQ_MASK) + && !irqchip_in_kernel(svm->vcpu.kvm)) { control->int_ctl &= ~V_IRQ_MASK; - push_irq(vcpu, control->int_vector); + push_irq(&svm->vcpu, control->int_vector); } - vcpu->interrupt_window_open = + svm->vcpu.interrupt_window_open = !(control->int_state & SVM_INTERRUPT_SHADOW_MASK); } +static void svm_do_inject_vector(struct vcpu_svm *svm) +{ + struct kvm_vcpu *vcpu = &svm->vcpu; + int word_index = __ffs(vcpu->irq_summary); + int bit_index = __ffs(vcpu->irq_pending[word_index]); + int irq = word_index * BITS_PER_LONG + bit_index; + + clear_bit(bit_index, &vcpu->irq_pending[word_index]); + if (!vcpu->irq_pending[word_index]) + clear_bit(word_index, &vcpu->irq_summary); + svm_inject_irq(svm, irq); +} + static void do_interrupt_requests(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - struct vmcb_control_area *control = &vcpu->svm->vmcb->control; + struct vcpu_svm *svm = to_svm(vcpu); + struct vmcb_control_area *control = &svm->vmcb->control; - vcpu->interrupt_window_open = + svm->vcpu.interrupt_window_open = (!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) && - (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF)); + (svm->vmcb->save.rflags & X86_EFLAGS_IF)); - if (vcpu->interrupt_window_open && vcpu->irq_summary) + if (svm->vcpu.interrupt_window_open && svm->vcpu.irq_summary) /* * If interrupts enabled, and not blocked by sti or mov ss. Good. */ - kvm_do_inject_irq(vcpu); + svm_do_inject_vector(svm); /* * Interrupts blocked. Wait for unblock. */ - if (!vcpu->interrupt_window_open && - (vcpu->irq_summary || kvm_run->request_interrupt_window)) { + if (!svm->vcpu.interrupt_window_open && + (svm->vcpu.irq_summary || kvm_run->request_interrupt_window)) { control->intercept |= 1ULL << INTERCEPT_VINTR; } else control->intercept &= ~(1ULL << INTERCEPT_VINTR); } -static void post_kvm_run_save(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) -{ - kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open && - vcpu->irq_summary == 0); - kvm_run->if_flag = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF) != 0; - kvm_run->cr8 = vcpu->cr8; - kvm_run->apic_base = vcpu->apic_base; -} - -/* - * Check if userspace requested an interrupt window, and that the - * interrupt window is open. - * - * No need to exit to userspace if we already have an interrupt queued. - */ -static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) -{ - return (!vcpu->irq_summary && - kvm_run->request_interrupt_window && - vcpu->interrupt_window_open && - (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF)); -} - static void save_db_regs(unsigned long *db_regs) { asm volatile ("mov %%dr0, %0" : "=r"(db_regs[0])); @@ -1476,49 +1441,37 @@ static void svm_flush_tlb(struct kvm_vcpu *vcpu) force_new_asid(vcpu); } -static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu) +{ +} + +static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { + struct vcpu_svm *svm = to_svm(vcpu); u16 fs_selector; u16 gs_selector; u16 ldt_selector; - int r; - -again: - r = kvm_mmu_reload(vcpu); - if (unlikely(r)) - return r; - - if (!vcpu->mmio_read_completed) - do_interrupt_requests(vcpu, kvm_run); - clgi(); - - vcpu->guest_mode = 1; - if (vcpu->requests) - if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests)) - svm_flush_tlb(vcpu); - - pre_svm_run(vcpu); + pre_svm_run(svm); save_host_msrs(vcpu); fs_selector = read_fs(); gs_selector = read_gs(); ldt_selector = read_ldt(); - vcpu->svm->host_cr2 = kvm_read_cr2(); - vcpu->svm->host_dr6 = read_dr6(); - vcpu->svm->host_dr7 = read_dr7(); - vcpu->svm->vmcb->save.cr2 = vcpu->cr2; + svm->host_cr2 = kvm_read_cr2(); + svm->host_dr6 = read_dr6(); + svm->host_dr7 = read_dr7(); + svm->vmcb->save.cr2 = vcpu->cr2; - if (vcpu->svm->vmcb->save.dr7 & 0xff) { + if (svm->vmcb->save.dr7 & 0xff) { write_dr7(0); - save_db_regs(vcpu->svm->host_db_regs); - load_db_regs(vcpu->svm->db_regs); + save_db_regs(svm->host_db_regs); + load_db_regs(svm->db_regs); } - if (vcpu->fpu_active) { - fx_save(vcpu->host_fx_image); - fx_restore(vcpu->guest_fx_image); - } + clgi(); + + local_irq_enable(); asm volatile ( #ifdef CONFIG_X86_64 @@ -1532,34 +1485,33 @@ again: #endif #ifdef CONFIG_X86_64 - "mov %c[rbx](%[vcpu]), %%rbx \n\t" - "mov %c[rcx](%[vcpu]), %%rcx \n\t" - "mov %c[rdx](%[vcpu]), %%rdx \n\t" - "mov %c[rsi](%[vcpu]), %%rsi \n\t" - "mov %c[rdi](%[vcpu]), %%rdi \n\t" - "mov %c[rbp](%[vcpu]), %%rbp \n\t" - "mov %c[r8](%[vcpu]), %%r8 \n\t" - "mov %c[r9](%[vcpu]), %%r9 \n\t" - "mov %c[r10](%[vcpu]), %%r10 \n\t" - "mov %c[r11](%[vcpu]), %%r11 \n\t" - "mov %c[r12](%[vcpu]), %%r12 \n\t" - "mov %c[r13](%[vcpu]), %%r13 \n\t" - "mov %c[r14](%[vcpu]), %%r14 \n\t" - "mov %c[r15](%[vcpu]), %%r15 \n\t" + "mov %c[rbx](%[svm]), %%rbx \n\t" + "mov %c[rcx](%[svm]), %%rcx \n\t" + "mov %c[rdx](%[svm]), %%rdx \n\t" + "mov %c[rsi](%[svm]), %%rsi \n\t" + "mov %c[rdi](%[svm]), %%rdi \n\t" + "mov %c[rbp](%[svm]), %%rbp \n\t" + "mov %c[r8](%[svm]), %%r8 \n\t" + "mov %c[r9](%[svm]), %%r9 \n\t" + "mov %c[r10](%[svm]), %%r10 \n\t" + "mov %c[r11](%[svm]), %%r11 \n\t" + "mov %c[r12](%[svm]), %%r12 \n\t" + "mov %c[r13](%[svm]), %%r13 \n\t" + "mov %c[r14](%[svm]), %%r14 \n\t" + "mov %c[r15](%[svm]), %%r15 \n\t" #else - "mov %c[rbx](%[vcpu]), %%ebx \n\t" - "mov %c[rcx](%[vcpu]), %%ecx \n\t" - "mov %c[rdx](%[vcpu]), %%edx \n\t" - "mov %c[rsi](%[vcpu]), %%esi \n\t" - "mov %c[rdi](%[vcpu]), %%edi \n\t" - "mov %c[rbp](%[vcpu]), %%ebp \n\t" + "mov %c[rbx](%[svm]), %%ebx \n\t" + "mov %c[rcx](%[svm]), %%ecx \n\t" + "mov %c[rdx](%[svm]), %%edx \n\t" + "mov %c[rsi](%[svm]), %%esi \n\t" + "mov %c[rdi](%[svm]), %%edi \n\t" + "mov %c[rbp](%[svm]), %%ebp \n\t" #endif #ifdef CONFIG_X86_64 /* Enter guest mode */ "push %%rax \n\t" - "mov %c[svm](%[vcpu]), %%rax \n\t" - "mov %c[vmcb](%%rax), %%rax \n\t" + "mov %c[vmcb](%[svm]), %%rax \n\t" SVM_VMLOAD "\n\t" SVM_VMRUN "\n\t" SVM_VMSAVE "\n\t" @@ -1567,8 +1519,7 @@ again: #else /* Enter guest mode */ "push %%eax \n\t" - "mov %c[svm](%[vcpu]), %%eax \n\t" - "mov %c[vmcb](%%eax), %%eax \n\t" + "mov %c[vmcb](%[svm]), %%eax \n\t" SVM_VMLOAD "\n\t" SVM_VMRUN "\n\t" SVM_VMSAVE "\n\t" @@ -1577,73 +1528,69 @@ again: /* Save guest registers, load host registers */ #ifdef CONFIG_X86_64 - "mov %%rbx, %c[rbx](%[vcpu]) \n\t" - "mov %%rcx, %c[rcx](%[vcpu]) \n\t" - "mov %%rdx, %c[rdx](%[vcpu]) \n\t" - "mov %%rsi, %c[rsi](%[vcpu]) \n\t" - "mov %%rdi, %c[rdi](%[vcpu]) \n\t" - "mov %%rbp, %c[rbp](%[vcpu]) \n\t" - "mov %%r8, %c[r8](%[vcpu]) \n\t" - "mov %%r9, %c[r9](%[vcpu]) \n\t" - "mov %%r10, %c[r10](%[vcpu]) \n\t" - "mov %%r11, %c[r11](%[vcpu]) \n\t" - "mov %%r12, %c[r12](%[vcpu]) \n\t" - "mov %%r13, %c[r13](%[vcpu]) \n\t" - "mov %%r14, %c[r14](%[vcpu]) \n\t" - "mov %%r15, %c[r15](%[vcpu]) \n\t" + "mov %%rbx, %c[rbx](%[svm]) \n\t" + "mov %%rcx, %c[rcx](%[svm]) \n\t" + "mov %%rdx, %c[rdx](%[svm]) \n\t" + "mov %%rsi, %c[rsi](%[svm]) \n\t" + "mov %%rdi, %c[rdi](%[svm]) \n\t" + "mov %%rbp, %c[rbp](%[svm]) \n\t" + "mov %%r8, %c[r8](%[svm]) \n\t" + "mov %%r9, %c[r9](%[svm]) \n\t" + "mov %%r10, %c[r10](%[svm]) \n\t" + "mov %%r11, %c[r11](%[svm]) \n\t" + "mov %%r12, %c[r12](%[svm]) \n\t" + "mov %%r13, %c[r13](%[svm]) \n\t" + "mov %%r14, %c[r14](%[svm]) \n\t" + "mov %%r15, %c[r15](%[svm]) \n\t" "pop %%r15; pop %%r14; pop %%r13; pop %%r12;" "pop %%r11; pop %%r10; pop %%r9; pop %%r8;" "pop %%rbp; pop %%rdi; pop %%rsi;" "pop %%rdx; pop %%rcx; pop %%rbx; \n\t" #else - "mov %%ebx, %c[rbx](%[vcpu]) \n\t" - "mov %%ecx, %c[rcx](%[vcpu]) \n\t" - "mov %%edx, %c[rdx](%[vcpu]) \n\t" - "mov %%esi, %c[rsi](%[vcpu]) \n\t" - "mov %%edi, %c[rdi](%[vcpu]) \n\t" - "mov %%ebp, %c[rbp](%[vcpu]) \n\t" + "mov %%ebx, %c[rbx](%[svm]) \n\t" + "mov %%ecx, %c[rcx](%[svm]) \n\t" + "mov %%edx, %c[rdx](%[svm]) \n\t" + "mov %%esi, %c[rsi](%[svm]) \n\t" + "mov %%edi, %c[rdi](%[svm]) \n\t" + "mov %%ebp, %c[rbp](%[svm]) \n\t" "pop %%ebp; pop %%edi; pop %%esi;" "pop %%edx; pop %%ecx; pop %%ebx; \n\t" #endif : - : [vcpu]"a"(vcpu), - [svm]"i"(offsetof(struct kvm_vcpu, svm)), + : [svm]"a"(svm), [vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)), - [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])), - [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])), - [rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])), - [rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])), - [rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])), - [rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP])) + [rbx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBX])), + [rcx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RCX])), + [rdx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDX])), + [rsi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RSI])), + [rdi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDI])), + [rbp]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBP])) #ifdef CONFIG_X86_64 - ,[r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])), - [r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])), - [r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])), - [r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])), - [r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])), - [r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])), - [r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])), - [r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15])) + ,[r8 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R8])), + [r9 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R9 ])), + [r10]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R10])), + [r11]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R11])), + [r12]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R12])), + [r13]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R13])), + [r14]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R14])), + [r15]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R15])) #endif : "cc", "memory" ); - vcpu->guest_mode = 0; + local_irq_disable(); - if (vcpu->fpu_active) { - fx_save(vcpu->guest_fx_image); - fx_restore(vcpu->host_fx_image); - } + stgi(); - if ((vcpu->svm->vmcb->save.dr7 & 0xff)) - load_db_regs(vcpu->svm->host_db_regs); + if ((svm->vmcb->save.dr7 & 0xff)) + load_db_regs(svm->host_db_regs); - vcpu->cr2 = vcpu->svm->vmcb->save.cr2; + vcpu->cr2 = svm->vmcb->save.cr2; - write_dr6(vcpu->svm->host_dr6); - write_dr7(vcpu->svm->host_dr7); - kvm_write_cr2(vcpu->svm->host_cr2); + write_dr6(svm->host_dr6); + write_dr7(svm->host_dr7); + kvm_write_cr2(svm->host_cr2); load_fs(fs_selector); load_gs(gs_selector); @@ -1652,57 +1599,19 @@ again: reload_tss(vcpu); - /* - * Profile KVM exit RIPs: - */ - if (unlikely(prof_on == KVM_PROFILING)) - profile_hit(KVM_PROFILING, - (void *)(unsigned long)vcpu->svm->vmcb->save.rip); - - stgi(); - - kvm_reput_irq(vcpu); - - vcpu->svm->next_rip = 0; - - if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) { - kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; - kvm_run->fail_entry.hardware_entry_failure_reason - = vcpu->svm->vmcb->control.exit_code; - post_kvm_run_save(vcpu, kvm_run); - return 0; - } - - r = handle_exit(vcpu, kvm_run); - if (r > 0) { - if (signal_pending(current)) { - ++vcpu->stat.signal_exits; - post_kvm_run_save(vcpu, kvm_run); - kvm_run->exit_reason = KVM_EXIT_INTR; - return -EINTR; - } - - if (dm_request_for_irq_injection(vcpu, kvm_run)) { - ++vcpu->stat.request_irq_exits; - post_kvm_run_save(vcpu, kvm_run); - kvm_run->exit_reason = KVM_EXIT_INTR; - return -EINTR; - } - kvm_resched(vcpu); - goto again; - } - post_kvm_run_save(vcpu, kvm_run); - return r; + svm->next_rip = 0; } static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) { - vcpu->svm->vmcb->save.cr3 = root; + struct vcpu_svm *svm = to_svm(vcpu); + + svm->vmcb->save.cr3 = root; force_new_asid(vcpu); if (vcpu->fpu_active) { - vcpu->svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR); - vcpu->svm->vmcb->save.cr0 |= CR0_TS_MASK; + svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR); + svm->vmcb->save.cr0 |= X86_CR0_TS; vcpu->fpu_active = 0; } } @@ -1711,26 +1620,27 @@ static void svm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr, uint32_t err_code) { - uint32_t exit_int_info = vcpu->svm->vmcb->control.exit_int_info; + struct vcpu_svm *svm = to_svm(vcpu); + uint32_t exit_int_info = svm->vmcb->control.exit_int_info; ++vcpu->stat.pf_guest; if (is_page_fault(exit_int_info)) { - vcpu->svm->vmcb->control.event_inj_err = 0; - vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | - SVM_EVTINJ_VALID_ERR | - SVM_EVTINJ_TYPE_EXEPT | - DF_VECTOR; + svm->vmcb->control.event_inj_err = 0; + svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | + SVM_EVTINJ_VALID_ERR | + SVM_EVTINJ_TYPE_EXEPT | + DF_VECTOR; return; } vcpu->cr2 = addr; - vcpu->svm->vmcb->save.cr2 = addr; - vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | - SVM_EVTINJ_VALID_ERR | - SVM_EVTINJ_TYPE_EXEPT | - PF_VECTOR; - vcpu->svm->vmcb->control.event_inj_err = err_code; + svm->vmcb->save.cr2 = addr; + svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | + SVM_EVTINJ_VALID_ERR | + SVM_EVTINJ_TYPE_EXEPT | + PF_VECTOR; + svm->vmcb->control.event_inj_err = err_code; } @@ -1757,17 +1667,25 @@ svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) hypercall[3] = 0xc3; } -static struct kvm_arch_ops svm_arch_ops = { +static void svm_check_processor_compat(void *rtn) +{ + *(int *)rtn = 0; +} + +static struct kvm_x86_ops svm_x86_ops = { .cpu_has_kvm_support = has_svm, .disabled_by_bios = is_disabled, .hardware_setup = svm_hardware_setup, .hardware_unsetup = svm_hardware_unsetup, + .check_processor_compatibility = svm_check_processor_compat, .hardware_enable = svm_hardware_enable, .hardware_disable = svm_hardware_disable, .vcpu_create = svm_create_vcpu, .vcpu_free = svm_free_vcpu, + .vcpu_reset = svm_vcpu_reset, + .prepare_guest_switch = svm_prepare_guest_switch, .vcpu_load = svm_vcpu_load, .vcpu_put = svm_vcpu_put, .vcpu_decache = svm_vcpu_decache, @@ -1778,7 +1696,7 @@ static struct kvm_arch_ops svm_arch_ops = { .get_segment_base = svm_get_segment_base, .get_segment = svm_get_segment, .set_segment = svm_set_segment, - .get_cs_db_l_bits = svm_get_cs_db_l_bits, + .get_cs_db_l_bits = kvm_get_cs_db_l_bits, .decache_cr4_guest_bits = svm_decache_cr4_guest_bits, .set_cr0 = svm_set_cr0, .set_cr3 = svm_set_cr3, @@ -1795,26 +1713,30 @@ static struct kvm_arch_ops svm_arch_ops = { .get_rflags = svm_get_rflags, .set_rflags = svm_set_rflags, - .invlpg = svm_invlpg, .tlb_flush = svm_flush_tlb, .inject_page_fault = svm_inject_page_fault, .inject_gp = svm_inject_gp, .run = svm_vcpu_run, + .handle_exit = handle_exit, .skip_emulated_instruction = skip_emulated_instruction, - .vcpu_setup = svm_vcpu_setup, .patch_hypercall = svm_patch_hypercall, + .get_irq = svm_get_irq, + .set_irq = svm_set_irq, + .inject_pending_irq = svm_intr_assist, + .inject_pending_vectors = do_interrupt_requests, }; static int __init svm_init(void) { - return kvm_init_arch(&svm_arch_ops, THIS_MODULE); + return kvm_init_x86(&svm_x86_ops, sizeof(struct vcpu_svm), + THIS_MODULE); } static void __exit svm_exit(void) { - kvm_exit_arch(); + kvm_exit_x86(); } module_init(svm_init) diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 80628f69916..4f115a8e45e 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c @@ -16,6 +16,8 @@ */ #include "kvm.h" +#include "x86_emulate.h" +#include "irq.h" #include "vmx.h" #include "segment_descriptor.h" @@ -23,7 +25,6 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/highmem.h> -#include <linux/profile.h> #include <linux/sched.h> #include <asm/io.h> @@ -32,6 +33,39 @@ MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); +struct vmcs { + u32 revision_id; + u32 abort; + char data[0]; +}; + +struct vcpu_vmx { + struct kvm_vcpu vcpu; + int launched; + u8 fail; + struct kvm_msr_entry *guest_msrs; + struct kvm_msr_entry *host_msrs; + int nmsrs; + int save_nmsrs; + int msr_offset_efer; +#ifdef CONFIG_X86_64 + int msr_offset_kernel_gs_base; +#endif + struct vmcs *vmcs; + struct { + int loaded; + u16 fs_sel, gs_sel, ldt_sel; + int gs_ldt_reload_needed; + int fs_reload_needed; + }host_state; + +}; + +static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) +{ + return container_of(vcpu, struct vcpu_vmx, vcpu); +} + static int init_rmode_tss(struct kvm *kvm); static DEFINE_PER_CPU(struct vmcs *, vmxarea); @@ -40,18 +74,17 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs); static struct page *vmx_io_bitmap_a; static struct page *vmx_io_bitmap_b; -#ifdef CONFIG_X86_64 -#define HOST_IS_64 1 -#else -#define HOST_IS_64 0 -#endif #define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE) -static struct vmcs_descriptor { +static struct vmcs_config { int size; int order; u32 revision_id; -} vmcs_descriptor; + u32 pin_based_exec_ctrl; + u32 cpu_based_exec_ctrl; + u32 vmexit_ctrl; + u32 vmentry_ctrl; +} vmcs_config; #define VMX_SEGMENT_FIELD(seg) \ [VCPU_SREG_##seg] = { \ @@ -89,16 +122,32 @@ static const u32 vmx_msr_index[] = { }; #define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index) -static inline u64 msr_efer_save_restore_bits(struct vmx_msr_entry msr) +static void load_msrs(struct kvm_msr_entry *e, int n) +{ + int i; + + for (i = 0; i < n; ++i) + wrmsrl(e[i].index, e[i].data); +} + +static void save_msrs(struct kvm_msr_entry *e, int n) +{ + int i; + + for (i = 0; i < n; ++i) + rdmsrl(e[i].index, e[i].data); +} + +static inline u64 msr_efer_save_restore_bits(struct kvm_msr_entry msr) { return (u64)msr.data & EFER_SAVE_RESTORE_BITS; } -static inline int msr_efer_need_save_restore(struct kvm_vcpu *vcpu) +static inline int msr_efer_need_save_restore(struct vcpu_vmx *vmx) { - int efer_offset = vcpu->msr_offset_efer; - return msr_efer_save_restore_bits(vcpu->host_msrs[efer_offset]) != - msr_efer_save_restore_bits(vcpu->guest_msrs[efer_offset]); + int efer_offset = vmx->msr_offset_efer; + return msr_efer_save_restore_bits(vmx->host_msrs[efer_offset]) != + msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]); } static inline int is_page_fault(u32 intr_info) @@ -121,23 +170,33 @@ static inline int is_external_interrupt(u32 intr_info) == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); } -static int __find_msr_index(struct kvm_vcpu *vcpu, u32 msr) +static inline int cpu_has_vmx_tpr_shadow(void) +{ + return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW); +} + +static inline int vm_need_tpr_shadow(struct kvm *kvm) +{ + return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm))); +} + +static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) { int i; - for (i = 0; i < vcpu->nmsrs; ++i) - if (vcpu->guest_msrs[i].index == msr) + for (i = 0; i < vmx->nmsrs; ++i) + if (vmx->guest_msrs[i].index == msr) return i; return -1; } -static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr) +static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr) { int i; - i = __find_msr_index(vcpu, msr); + i = __find_msr_index(vmx, msr); if (i >= 0) - return &vcpu->guest_msrs[i]; + return &vmx->guest_msrs[i]; return NULL; } @@ -156,23 +215,24 @@ static void vmcs_clear(struct vmcs *vmcs) static void __vcpu_clear(void *arg) { - struct kvm_vcpu *vcpu = arg; + struct vcpu_vmx *vmx = arg; int cpu = raw_smp_processor_id(); - if (vcpu->cpu == cpu) - vmcs_clear(vcpu->vmcs); - if (per_cpu(current_vmcs, cpu) == vcpu->vmcs) + if (vmx->vcpu.cpu == cpu) + vmcs_clear(vmx->vmcs); + if (per_cpu(current_vmcs, cpu) == vmx->vmcs) per_cpu(current_vmcs, cpu) = NULL; - rdtscll(vcpu->host_tsc); + rdtscll(vmx->vcpu.host_tsc); } -static void vcpu_clear(struct kvm_vcpu *vcpu) +static void vcpu_clear(struct vcpu_vmx *vmx) { - if (vcpu->cpu != raw_smp_processor_id() && vcpu->cpu != -1) - smp_call_function_single(vcpu->cpu, __vcpu_clear, vcpu, 0, 1); + if (vmx->vcpu.cpu != raw_smp_processor_id() && vmx->vcpu.cpu != -1) + smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, + vmx, 0, 1); else - __vcpu_clear(vcpu); - vcpu->launched = 0; + __vcpu_clear(vmx); + vmx->launched = 0; } static unsigned long vmcs_readl(unsigned long field) @@ -282,121 +342,122 @@ static void reload_tss(void) #endif } -static void load_transition_efer(struct kvm_vcpu *vcpu) +static void load_transition_efer(struct vcpu_vmx *vmx) { u64 trans_efer; - int efer_offset = vcpu->msr_offset_efer; + int efer_offset = vmx->msr_offset_efer; - trans_efer = vcpu->host_msrs[efer_offset].data; + trans_efer = vmx->host_msrs[efer_offset].data; trans_efer &= ~EFER_SAVE_RESTORE_BITS; - trans_efer |= msr_efer_save_restore_bits( - vcpu->guest_msrs[efer_offset]); + trans_efer |= msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]); wrmsrl(MSR_EFER, trans_efer); - vcpu->stat.efer_reload++; + vmx->vcpu.stat.efer_reload++; } static void vmx_save_host_state(struct kvm_vcpu *vcpu) { - struct vmx_host_state *hs = &vcpu->vmx_host_state; + struct vcpu_vmx *vmx = to_vmx(vcpu); - if (hs->loaded) + if (vmx->host_state.loaded) return; - hs->loaded = 1; + vmx->host_state.loaded = 1; /* * Set host fs and gs selectors. Unfortunately, 22.2.3 does not * allow segment selectors with cpl > 0 or ti == 1. */ - hs->ldt_sel = read_ldt(); - hs->fs_gs_ldt_reload_needed = hs->ldt_sel; - hs->fs_sel = read_fs(); - if (!(hs->fs_sel & 7)) - vmcs_write16(HOST_FS_SELECTOR, hs->fs_sel); - else { + vmx->host_state.ldt_sel = read_ldt(); + vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel; + vmx->host_state.fs_sel = read_fs(); + if (!(vmx->host_state.fs_sel & 7)) { + vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel); + vmx->host_state.fs_reload_needed = 0; + } else { vmcs_write16(HOST_FS_SELECTOR, 0); - hs->fs_gs_ldt_reload_needed = 1; + vmx->host_state.fs_reload_needed = 1; } - hs->gs_sel = read_gs(); - if (!(hs->gs_sel & 7)) - vmcs_write16(HOST_GS_SELECTOR, hs->gs_sel); + vmx->host_state.gs_sel = read_gs(); + if (!(vmx->host_state.gs_sel & 7)) + vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel); else { vmcs_write16(HOST_GS_SELECTOR, 0); - hs->fs_gs_ldt_reload_needed = 1; + vmx->host_state.gs_ldt_reload_needed = 1; } #ifdef CONFIG_X86_64 vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE)); vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE)); #else - vmcs_writel(HOST_FS_BASE, segment_base(hs->fs_sel)); - vmcs_writel(HOST_GS_BASE, segment_base(hs->gs_sel)); + vmcs_writel(HOST_FS_BASE, segment_base(vmx->host_state.fs_sel)); + vmcs_writel(HOST_GS_BASE, segment_base(vmx->host_state.gs_sel)); #endif #ifdef CONFIG_X86_64 - if (is_long_mode(vcpu)) { - save_msrs(vcpu->host_msrs + vcpu->msr_offset_kernel_gs_base, 1); + if (is_long_mode(&vmx->vcpu)) { + save_msrs(vmx->host_msrs + + vmx->msr_offset_kernel_gs_base, 1); } #endif - load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs); - if (msr_efer_need_save_restore(vcpu)) - load_transition_efer(vcpu); + load_msrs(vmx->guest_msrs, vmx->save_nmsrs); + if (msr_efer_need_save_restore(vmx)) + load_transition_efer(vmx); } -static void vmx_load_host_state(struct kvm_vcpu *vcpu) +static void vmx_load_host_state(struct vcpu_vmx *vmx) { - struct vmx_host_state *hs = &vcpu->vmx_host_state; + unsigned long flags; - if (!hs->loaded) + if (!vmx->host_state.loaded) return; - hs->loaded = 0; - if (hs->fs_gs_ldt_reload_needed) { - load_ldt(hs->ldt_sel); - load_fs(hs->fs_sel); + vmx->host_state.loaded = 0; + if (vmx->host_state.fs_reload_needed) + load_fs(vmx->host_state.fs_sel); + if (vmx->host_state.gs_ldt_reload_needed) { + load_ldt(vmx->host_state.ldt_sel); /* * If we have to reload gs, we must take care to * preserve our gs base. */ - local_irq_disable(); - load_gs(hs->gs_sel); + local_irq_save(flags); + load_gs(vmx->host_state.gs_sel); #ifdef CONFIG_X86_64 wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE)); #endif - local_irq_enable(); - - reload_tss(); + local_irq_restore(flags); } - save_msrs(vcpu->guest_msrs, vcpu->save_nmsrs); - load_msrs(vcpu->host_msrs, vcpu->save_nmsrs); - if (msr_efer_need_save_restore(vcpu)) - load_msrs(vcpu->host_msrs + vcpu->msr_offset_efer, 1); + reload_tss(); + save_msrs(vmx->guest_msrs, vmx->save_nmsrs); + load_msrs(vmx->host_msrs, vmx->save_nmsrs); + if (msr_efer_need_save_restore(vmx)) + load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1); } /* * Switches to specified vcpu, until a matching vcpu_put(), but assumes * vcpu mutex is already taken. */ -static void vmx_vcpu_load(struct kvm_vcpu *vcpu) +static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { - u64 phys_addr = __pa(vcpu->vmcs); - int cpu; + struct vcpu_vmx *vmx = to_vmx(vcpu); + u64 phys_addr = __pa(vmx->vmcs); u64 tsc_this, delta; - cpu = get_cpu(); - - if (vcpu->cpu != cpu) - vcpu_clear(vcpu); + if (vcpu->cpu != cpu) { + vcpu_clear(vmx); + kvm_migrate_apic_timer(vcpu); + } - if (per_cpu(current_vmcs, cpu) != vcpu->vmcs) { + if (per_cpu(current_vmcs, cpu) != vmx->vmcs) { u8 error; - per_cpu(current_vmcs, cpu) = vcpu->vmcs; + per_cpu(current_vmcs, cpu) = vmx->vmcs; asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0" : "=g"(error) : "a"(&phys_addr), "m"(phys_addr) : "cc"); if (error) printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n", - vcpu->vmcs, phys_addr); + vmx->vmcs, phys_addr); } if (vcpu->cpu != cpu) { @@ -426,9 +487,8 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu) static void vmx_vcpu_put(struct kvm_vcpu *vcpu) { - vmx_load_host_state(vcpu); + vmx_load_host_state(to_vmx(vcpu)); kvm_put_guest_fpu(vcpu); - put_cpu(); } static void vmx_fpu_activate(struct kvm_vcpu *vcpu) @@ -436,9 +496,9 @@ static void vmx_fpu_activate(struct kvm_vcpu *vcpu) if (vcpu->fpu_active) return; vcpu->fpu_active = 1; - vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK); - if (vcpu->cr0 & CR0_TS_MASK) - vmcs_set_bits(GUEST_CR0, CR0_TS_MASK); + vmcs_clear_bits(GUEST_CR0, X86_CR0_TS); + if (vcpu->cr0 & X86_CR0_TS) + vmcs_set_bits(GUEST_CR0, X86_CR0_TS); update_exception_bitmap(vcpu); } @@ -447,13 +507,13 @@ static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu) if (!vcpu->fpu_active) return; vcpu->fpu_active = 0; - vmcs_set_bits(GUEST_CR0, CR0_TS_MASK); + vmcs_set_bits(GUEST_CR0, X86_CR0_TS); update_exception_bitmap(vcpu); } static void vmx_vcpu_decache(struct kvm_vcpu *vcpu) { - vcpu_clear(vcpu); + vcpu_clear(to_vmx(vcpu)); } static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) @@ -501,59 +561,62 @@ static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code) /* * Swap MSR entry in host/guest MSR entry array. */ -void move_msr_up(struct kvm_vcpu *vcpu, int from, int to) +#ifdef CONFIG_X86_64 +static void move_msr_up(struct vcpu_vmx *vmx, int from, int to) { - struct vmx_msr_entry tmp; - tmp = vcpu->guest_msrs[to]; - vcpu->guest_msrs[to] = vcpu->guest_msrs[from]; - vcpu->guest_msrs[from] = tmp; - tmp = vcpu->host_msrs[to]; - vcpu->host_msrs[to] = vcpu->host_msrs[from]; - vcpu->host_msrs[from] = tmp; + struct kvm_msr_entry tmp; + + tmp = vmx->guest_msrs[to]; + vmx->guest_msrs[to] = vmx->guest_msrs[from]; + vmx->guest_msrs[from] = tmp; + tmp = vmx->host_msrs[to]; + vmx->host_msrs[to] = vmx->host_msrs[from]; + vmx->host_msrs[from] = tmp; } +#endif /* * Set up the vmcs to automatically save and restore system * msrs. Don't touch the 64-bit msrs if the guest is in legacy * mode, as fiddling with msrs is very expensive. */ -static void setup_msrs(struct kvm_vcpu *vcpu) +static void setup_msrs(struct vcpu_vmx *vmx) { int save_nmsrs; save_nmsrs = 0; #ifdef CONFIG_X86_64 - if (is_long_mode(vcpu)) { + if (is_long_mode(&vmx->vcpu)) { int index; - index = __find_msr_index(vcpu, MSR_SYSCALL_MASK); + index = __find_msr_index(vmx, MSR_SYSCALL_MASK); if (index >= 0) - move_msr_up(vcpu, index, save_nmsrs++); - index = __find_msr_index(vcpu, MSR_LSTAR); + move_msr_up(vmx, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_LSTAR); if (index >= 0) - move_msr_up(vcpu, index, save_nmsrs++); - index = __find_msr_index(vcpu, MSR_CSTAR); + move_msr_up(vmx, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_CSTAR); if (index >= 0) - move_msr_up(vcpu, index, save_nmsrs++); - index = __find_msr_index(vcpu, MSR_KERNEL_GS_BASE); + move_msr_up(vmx, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_KERNEL_GS_BASE); if (index >= 0) - move_msr_up(vcpu, index, save_nmsrs++); + move_msr_up(vmx, index, save_nmsrs++); /* * MSR_K6_STAR is only needed on long mode guests, and only * if efer.sce is enabled. */ - index = __find_msr_index(vcpu, MSR_K6_STAR); - if ((index >= 0) && (vcpu->shadow_efer & EFER_SCE)) - move_msr_up(vcpu, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_K6_STAR); + if ((index >= 0) && (vmx->vcpu.shadow_efer & EFER_SCE)) + move_msr_up(vmx, index, save_nmsrs++); } #endif - vcpu->save_nmsrs = save_nmsrs; + vmx->save_nmsrs = save_nmsrs; #ifdef CONFIG_X86_64 - vcpu->msr_offset_kernel_gs_base = - __find_msr_index(vcpu, MSR_KERNEL_GS_BASE); + vmx->msr_offset_kernel_gs_base = + __find_msr_index(vmx, MSR_KERNEL_GS_BASE); #endif - vcpu->msr_offset_efer = __find_msr_index(vcpu, MSR_EFER); + vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER); } /* @@ -589,7 +652,7 @@ static void guest_write_tsc(u64 guest_tsc) static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) { u64 data; - struct vmx_msr_entry *msr; + struct kvm_msr_entry *msr; if (!pdata) { printk(KERN_ERR "BUG: get_msr called with NULL pdata\n"); @@ -620,7 +683,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) data = vmcs_readl(GUEST_SYSENTER_ESP); break; default: - msr = find_msr_entry(vcpu, msr_index); + msr = find_msr_entry(to_vmx(vcpu), msr_index); if (msr) { data = msr->data; break; @@ -639,15 +702,16 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) */ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) { - struct vmx_msr_entry *msr; + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct kvm_msr_entry *msr; int ret = 0; switch (msr_index) { #ifdef CONFIG_X86_64 case MSR_EFER: ret = kvm_set_msr_common(vcpu, msr_index, data); - if (vcpu->vmx_host_state.loaded) - load_transition_efer(vcpu); + if (vmx->host_state.loaded) + load_transition_efer(vmx); break; case MSR_FS_BASE: vmcs_writel(GUEST_FS_BASE, data); @@ -669,11 +733,11 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) guest_write_tsc(data); break; default: - msr = find_msr_entry(vcpu, msr_index); + msr = find_msr_entry(vmx, msr_index); if (msr) { msr->data = data; - if (vcpu->vmx_host_state.loaded) - load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs); + if (vmx->host_state.loaded) + load_msrs(vmx->guest_msrs, vmx->save_nmsrs); break; } ret = kvm_set_msr_common(vcpu, msr_index, data); @@ -740,6 +804,20 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) return 0; } +static int vmx_get_irq(struct kvm_vcpu *vcpu) +{ + u32 idtv_info_field; + + idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD); + if (idtv_info_field & INTR_INFO_VALID_MASK) { + if (is_external_interrupt(idtv_info_field)) + return idtv_info_field & VECTORING_INFO_VECTOR_MASK; + else + printk("pending exception: not handled yet\n"); + } + return -1; +} + static __init int cpu_has_kvm_support(void) { unsigned long ecx = cpuid_ecx(1); @@ -751,7 +829,10 @@ static __init int vmx_disabled_by_bios(void) u64 msr; rdmsrl(MSR_IA32_FEATURE_CONTROL, msr); - return (msr & 5) == 1; /* locked but not enabled */ + return (msr & (MSR_IA32_FEATURE_CONTROL_LOCKED | + MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED)) + == MSR_IA32_FEATURE_CONTROL_LOCKED; + /* locked but not enabled */ } static void hardware_enable(void *garbage) @@ -761,10 +842,15 @@ static void hardware_enable(void *garbage) u64 old; rdmsrl(MSR_IA32_FEATURE_CONTROL, old); - if ((old & 5) != 5) + if ((old & (MSR_IA32_FEATURE_CONTROL_LOCKED | + MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED)) + != (MSR_IA32_FEATURE_CONTROL_LOCKED | + MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED)) /* enable and lock */ - wrmsrl(MSR_IA32_FEATURE_CONTROL, old | 5); - write_cr4(read_cr4() | CR4_VMXE); /* FIXME: not cpu hotplug safe */ + wrmsrl(MSR_IA32_FEATURE_CONTROL, old | + MSR_IA32_FEATURE_CONTROL_LOCKED | + MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED); + write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */ asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr) : "memory", "cc"); } @@ -774,14 +860,102 @@ static void hardware_disable(void *garbage) asm volatile (ASM_VMX_VMXOFF : : : "cc"); } -static __init void setup_vmcs_descriptor(void) +static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, + u32 msr, u32* result) +{ + u32 vmx_msr_low, vmx_msr_high; + u32 ctl = ctl_min | ctl_opt; + + rdmsr(msr, vmx_msr_low, vmx_msr_high); + + ctl &= vmx_msr_high; /* bit == 0 in high word ==> must be zero */ + ctl |= vmx_msr_low; /* bit == 1 in low word ==> must be one */ + + /* Ensure minimum (required) set of control bits are supported. */ + if (ctl_min & ~ctl) + return -EIO; + + *result = ctl; + return 0; +} + +static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) { u32 vmx_msr_low, vmx_msr_high; + u32 min, opt; + u32 _pin_based_exec_control = 0; + u32 _cpu_based_exec_control = 0; + u32 _vmexit_control = 0; + u32 _vmentry_control = 0; + + min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; + opt = 0; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, + &_pin_based_exec_control) < 0) + return -EIO; + + min = CPU_BASED_HLT_EXITING | +#ifdef CONFIG_X86_64 + CPU_BASED_CR8_LOAD_EXITING | + CPU_BASED_CR8_STORE_EXITING | +#endif + CPU_BASED_USE_IO_BITMAPS | + CPU_BASED_MOV_DR_EXITING | + CPU_BASED_USE_TSC_OFFSETING; +#ifdef CONFIG_X86_64 + opt = CPU_BASED_TPR_SHADOW; +#else + opt = 0; +#endif + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, + &_cpu_based_exec_control) < 0) + return -EIO; +#ifdef CONFIG_X86_64 + if ((_cpu_based_exec_control & CPU_BASED_TPR_SHADOW)) + _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING & + ~CPU_BASED_CR8_STORE_EXITING; +#endif + + min = 0; +#ifdef CONFIG_X86_64 + min |= VM_EXIT_HOST_ADDR_SPACE_SIZE; +#endif + opt = 0; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS, + &_vmexit_control) < 0) + return -EIO; + + min = opt = 0; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS, + &_vmentry_control) < 0) + return -EIO; rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high); - vmcs_descriptor.size = vmx_msr_high & 0x1fff; - vmcs_descriptor.order = get_order(vmcs_descriptor.size); - vmcs_descriptor.revision_id = vmx_msr_low; + + /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ + if ((vmx_msr_high & 0x1fff) > PAGE_SIZE) + return -EIO; + +#ifdef CONFIG_X86_64 + /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */ + if (vmx_msr_high & (1u<<16)) + return -EIO; +#endif + + /* Require Write-Back (WB) memory type for VMCS accesses. */ + if (((vmx_msr_high >> 18) & 15) != 6) + return -EIO; + + vmcs_conf->size = vmx_msr_high & 0x1fff; + vmcs_conf->order = get_order(vmcs_config.size); + vmcs_conf->revision_id = vmx_msr_low; + + vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control; + vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control; + vmcs_conf->vmexit_ctrl = _vmexit_control; + vmcs_conf->vmentry_ctrl = _vmentry_control; + + return 0; } static struct vmcs *alloc_vmcs_cpu(int cpu) @@ -790,12 +964,12 @@ static struct vmcs *alloc_vmcs_cpu(int cpu) struct page *pages; struct vmcs *vmcs; - pages = alloc_pages_node(node, GFP_KERNEL, vmcs_descriptor.order); + pages = alloc_pages_node(node, GFP_KERNEL, vmcs_config.order); if (!pages) return NULL; vmcs = page_address(pages); - memset(vmcs, 0, vmcs_descriptor.size); - vmcs->revision_id = vmcs_descriptor.revision_id; /* vmcs revision id */ + memset(vmcs, 0, vmcs_config.size); + vmcs->revision_id = vmcs_config.revision_id; /* vmcs revision id */ return vmcs; } @@ -806,7 +980,7 @@ static struct vmcs *alloc_vmcs(void) static void free_vmcs(struct vmcs *vmcs) { - free_pages((unsigned long)vmcs, vmcs_descriptor.order); + free_pages((unsigned long)vmcs, vmcs_config.order); } static void free_kvm_area(void) @@ -817,8 +991,6 @@ static void free_kvm_area(void) free_vmcs(per_cpu(vmxarea, cpu)); } -extern struct vmcs *alloc_vmcs_cpu(int cpu); - static __init int alloc_kvm_area(void) { int cpu; @@ -839,7 +1011,8 @@ static __init int alloc_kvm_area(void) static __init int hardware_setup(void) { - setup_vmcs_descriptor(); + if (setup_vmcs_config(&vmcs_config) < 0) + return -EIO; return alloc_kvm_area(); } @@ -879,8 +1052,8 @@ static void enter_pmode(struct kvm_vcpu *vcpu) flags |= (vcpu->rmode.save_iopl << IOPL_SHIFT); vmcs_writel(GUEST_RFLAGS, flags); - vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~CR4_VME_MASK) | - (vmcs_readl(CR4_READ_SHADOW) & CR4_VME_MASK)); + vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) | + (vmcs_readl(CR4_READ_SHADOW) & X86_CR4_VME)); update_exception_bitmap(vcpu); @@ -897,7 +1070,7 @@ static void enter_pmode(struct kvm_vcpu *vcpu) vmcs_write32(GUEST_CS_AR_BYTES, 0x9b); } -static int rmode_tss_base(struct kvm* kvm) +static gva_t rmode_tss_base(struct kvm* kvm) { gfn_t base_gfn = kvm->memslots[0].base_gfn + kvm->memslots[0].npages - 3; return base_gfn << PAGE_SHIFT; @@ -937,7 +1110,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu) flags |= IOPL_MASK | X86_EFLAGS_VM; vmcs_writel(GUEST_RFLAGS, flags); - vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | CR4_VME_MASK); + vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME); update_exception_bitmap(vcpu); vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) >> 4); @@ -975,10 +1148,10 @@ static void enter_lmode(struct kvm_vcpu *vcpu) vcpu->shadow_efer |= EFER_LMA; - find_msr_entry(vcpu, MSR_EFER)->data |= EFER_LMA | EFER_LME; + find_msr_entry(to_vmx(vcpu), MSR_EFER)->data |= EFER_LMA | EFER_LME; vmcs_write32(VM_ENTRY_CONTROLS, vmcs_read32(VM_ENTRY_CONTROLS) - | VM_ENTRY_CONTROLS_IA32E_MASK); + | VM_ENTRY_IA32E_MODE); } static void exit_lmode(struct kvm_vcpu *vcpu) @@ -987,7 +1160,7 @@ static void exit_lmode(struct kvm_vcpu *vcpu) vmcs_write32(VM_ENTRY_CONTROLS, vmcs_read32(VM_ENTRY_CONTROLS) - & ~VM_ENTRY_CONTROLS_IA32E_MASK); + & ~VM_ENTRY_IA32E_MODE); } #endif @@ -1002,17 +1175,17 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) { vmx_fpu_deactivate(vcpu); - if (vcpu->rmode.active && (cr0 & CR0_PE_MASK)) + if (vcpu->rmode.active && (cr0 & X86_CR0_PE)) enter_pmode(vcpu); - if (!vcpu->rmode.active && !(cr0 & CR0_PE_MASK)) + if (!vcpu->rmode.active && !(cr0 & X86_CR0_PE)) enter_rmode(vcpu); #ifdef CONFIG_X86_64 if (vcpu->shadow_efer & EFER_LME) { - if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) + if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) enter_lmode(vcpu); - if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK)) + if (is_paging(vcpu) && !(cr0 & X86_CR0_PG)) exit_lmode(vcpu); } #endif @@ -1022,14 +1195,14 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON); vcpu->cr0 = cr0; - if (!(cr0 & CR0_TS_MASK) || !(cr0 & CR0_PE_MASK)) + if (!(cr0 & X86_CR0_TS) || !(cr0 & X86_CR0_PE)) vmx_fpu_activate(vcpu); } static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) { vmcs_writel(GUEST_CR3, cr3); - if (vcpu->cr0 & CR0_PE_MASK) + if (vcpu->cr0 & X86_CR0_PE) vmx_fpu_deactivate(vcpu); } @@ -1045,23 +1218,24 @@ static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer) { - struct vmx_msr_entry *msr = find_msr_entry(vcpu, MSR_EFER); + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct kvm_msr_entry *msr = find_msr_entry(vmx, MSR_EFER); vcpu->shadow_efer = efer; if (efer & EFER_LMA) { vmcs_write32(VM_ENTRY_CONTROLS, vmcs_read32(VM_ENTRY_CONTROLS) | - VM_ENTRY_CONTROLS_IA32E_MASK); + VM_ENTRY_IA32E_MODE); msr->data = efer; } else { vmcs_write32(VM_ENTRY_CONTROLS, vmcs_read32(VM_ENTRY_CONTROLS) & - ~VM_ENTRY_CONTROLS_IA32E_MASK); + ~VM_ENTRY_IA32E_MODE); msr->data = efer & ~EFER_LME; } - setup_msrs(vcpu); + setup_msrs(vmx); } #endif @@ -1210,17 +1384,6 @@ static int init_rmode_tss(struct kvm* kvm) return 1; } -static void vmcs_write32_fixedbits(u32 msr, u32 vmcs_field, u32 val) -{ - u32 msr_high, msr_low; - - rdmsr(msr, msr_low, msr_high); - - val &= msr_high; - val |= msr_low; - vmcs_write32(vmcs_field, val); -} - static void seg_setup(int seg) { struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; @@ -1234,7 +1397,7 @@ static void seg_setup(int seg) /* * Sets up the vmcs for emulated real mode. */ -static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) +static int vmx_vcpu_setup(struct vcpu_vmx *vmx) { u32 host_sysenter_cs; u32 junk; @@ -1243,27 +1406,36 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) int i; int ret = 0; unsigned long kvm_vmx_return; + u64 msr; + u32 exec_control; - if (!init_rmode_tss(vcpu->kvm)) { + if (!init_rmode_tss(vmx->vcpu.kvm)) { ret = -ENOMEM; goto out; } - memset(vcpu->regs, 0, sizeof(vcpu->regs)); - vcpu->regs[VCPU_REGS_RDX] = get_rdx_init_val(); - vcpu->cr8 = 0; - vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; - if (vcpu == &vcpu->kvm->vcpus[0]) - vcpu->apic_base |= MSR_IA32_APICBASE_BSP; + vmx->vcpu.rmode.active = 0; - fx_init(vcpu); + vmx->vcpu.regs[VCPU_REGS_RDX] = get_rdx_init_val(); + set_cr8(&vmx->vcpu, 0); + msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; + if (vmx->vcpu.vcpu_id == 0) + msr |= MSR_IA32_APICBASE_BSP; + kvm_set_apic_base(&vmx->vcpu, msr); + + fx_init(&vmx->vcpu); /* * GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode * insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4. Sigh. */ - vmcs_write16(GUEST_CS_SELECTOR, 0xf000); - vmcs_writel(GUEST_CS_BASE, 0x000f0000); + if (vmx->vcpu.vcpu_id == 0) { + vmcs_write16(GUEST_CS_SELECTOR, 0xf000); + vmcs_writel(GUEST_CS_BASE, 0x000f0000); + } else { + vmcs_write16(GUEST_CS_SELECTOR, vmx->vcpu.sipi_vector << 8); + vmcs_writel(GUEST_CS_BASE, vmx->vcpu.sipi_vector << 12); + } vmcs_write32(GUEST_CS_LIMIT, 0xffff); vmcs_write32(GUEST_CS_AR_BYTES, 0x9b); @@ -1288,7 +1460,10 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) vmcs_writel(GUEST_SYSENTER_EIP, 0); vmcs_writel(GUEST_RFLAGS, 0x02); - vmcs_writel(GUEST_RIP, 0xfff0); + if (vmx->vcpu.vcpu_id == 0) + vmcs_writel(GUEST_RIP, 0xfff0); + else + vmcs_writel(GUEST_RIP, 0); vmcs_writel(GUEST_RSP, 0); //todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0 @@ -1316,20 +1491,18 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) vmcs_write64(GUEST_IA32_DEBUGCTL, 0); /* Control */ - vmcs_write32_fixedbits(MSR_IA32_VMX_PINBASED_CTLS, - PIN_BASED_VM_EXEC_CONTROL, - PIN_BASED_EXT_INTR_MASK /* 20.6.1 */ - | PIN_BASED_NMI_EXITING /* 20.6.1 */ - ); - vmcs_write32_fixedbits(MSR_IA32_VMX_PROCBASED_CTLS, - CPU_BASED_VM_EXEC_CONTROL, - CPU_BASED_HLT_EXITING /* 20.6.2 */ - | CPU_BASED_CR8_LOAD_EXITING /* 20.6.2 */ - | CPU_BASED_CR8_STORE_EXITING /* 20.6.2 */ - | CPU_BASED_ACTIVATE_IO_BITMAP /* 20.6.2 */ - | CPU_BASED_MOV_DR_EXITING - | CPU_BASED_USE_TSC_OFFSETING /* 21.3 */ - ); + vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, + vmcs_config.pin_based_exec_ctrl); + + exec_control = vmcs_config.cpu_based_exec_ctrl; + if (!vm_need_tpr_shadow(vmx->vcpu.kvm)) { + exec_control &= ~CPU_BASED_TPR_SHADOW; +#ifdef CONFIG_X86_64 + exec_control |= CPU_BASED_CR8_STORE_EXITING | + CPU_BASED_CR8_LOAD_EXITING; +#endif + } + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control); vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0); vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0); @@ -1377,46 +1550,48 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) u32 index = vmx_msr_index[i]; u32 data_low, data_high; u64 data; - int j = vcpu->nmsrs; + int j = vmx->nmsrs; if (rdmsr_safe(index, &data_low, &data_high) < 0) continue; if (wrmsr_safe(index, data_low, data_high) < 0) continue; data = data_low | ((u64)data_high << 32); - vcpu->host_msrs[j].index = index; - vcpu->host_msrs[j].reserved = 0; - vcpu->host_msrs[j].data = data; - vcpu->guest_msrs[j] = vcpu->host_msrs[j]; - ++vcpu->nmsrs; + vmx->host_msrs[j].index = index; + vmx->host_msrs[j].reserved = 0; + vmx->host_msrs[j].data = data; + vmx->guest_msrs[j] = vmx->host_msrs[j]; + ++vmx->nmsrs; } - setup_msrs(vcpu); + setup_msrs(vmx); - vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS, VM_EXIT_CONTROLS, - (HOST_IS_64 << 9)); /* 22.2,1, 20.7.1 */ + vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl); /* 22.2.1, 20.8.1 */ - vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS, - VM_ENTRY_CONTROLS, 0); + vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl); + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */ #ifdef CONFIG_X86_64 - vmcs_writel(VIRTUAL_APIC_PAGE_ADDR, 0); - vmcs_writel(TPR_THRESHOLD, 0); + vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0); + if (vm_need_tpr_shadow(vmx->vcpu.kvm)) + vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, + page_to_phys(vmx->vcpu.apic->regs_page)); + vmcs_write32(TPR_THRESHOLD, 0); #endif vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL); vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK); - vcpu->cr0 = 0x60000010; - vmx_set_cr0(vcpu, vcpu->cr0); // enter rmode - vmx_set_cr4(vcpu, 0); + vmx->vcpu.cr0 = 0x60000010; + vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); // enter rmode + vmx_set_cr4(&vmx->vcpu, 0); #ifdef CONFIG_X86_64 - vmx_set_efer(vcpu, 0); + vmx_set_efer(&vmx->vcpu, 0); #endif - vmx_fpu_activate(vcpu); - update_exception_bitmap(vcpu); + vmx_fpu_activate(&vmx->vcpu); + update_exception_bitmap(&vmx->vcpu); return 0; @@ -1424,6 +1599,13 @@ out: return ret; } +static void vmx_vcpu_reset(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + vmx_vcpu_setup(vmx); +} + static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq) { u16 ent[2]; @@ -1443,8 +1625,8 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq) return; } - if (kvm_read_guest(vcpu, irq * sizeof(ent), sizeof(ent), &ent) != - sizeof(ent)) { + if (emulator_read_std(irq * sizeof(ent), &ent, sizeof(ent), vcpu) != + X86EMUL_CONTINUE) { vcpu_printf(vcpu, "%s: read guest err\n", __FUNCTION__); return; } @@ -1454,9 +1636,9 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq) ip = vmcs_readl(GUEST_RIP); - if (kvm_write_guest(vcpu, ss_base + sp - 2, 2, &flags) != 2 || - kvm_write_guest(vcpu, ss_base + sp - 4, 2, &cs) != 2 || - kvm_write_guest(vcpu, ss_base + sp - 6, 2, &ip) != 2) { + if (emulator_write_emulated(ss_base + sp - 2, &flags, 2, vcpu) != X86EMUL_CONTINUE || + emulator_write_emulated(ss_base + sp - 4, &cs, 2, vcpu) != X86EMUL_CONTINUE || + emulator_write_emulated(ss_base + sp - 6, &ip, 2, vcpu) != X86EMUL_CONTINUE) { vcpu_printf(vcpu, "%s: write guest err\n", __FUNCTION__); return; } @@ -1469,6 +1651,16 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq) vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6)); } +static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) +{ + if (vcpu->rmode.active) { + inject_rmode_irq(vcpu, irq); + return; + } + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); +} + static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) { int word_index = __ffs(vcpu->irq_summary); @@ -1478,13 +1670,7 @@ static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) clear_bit(bit_index, &vcpu->irq_pending[word_index]); if (!vcpu->irq_pending[word_index]) clear_bit(word_index, &vcpu->irq_summary); - - if (vcpu->rmode.active) { - inject_rmode_irq(vcpu, irq); - return; - } - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, - irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); + vmx_inject_irq(vcpu, irq); } @@ -1568,7 +1754,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info); } - if (is_external_interrupt(vect_info)) { + if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) { int irq = vect_info & VECTORING_INFO_VECTOR_MASK; set_bit(irq, vcpu->irq_pending); set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary); @@ -1591,29 +1777,28 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) if (is_page_fault(intr_info)) { cr2 = vmcs_readl(EXIT_QUALIFICATION); - spin_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->lock); r = kvm_mmu_page_fault(vcpu, cr2, error_code); if (r < 0) { - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); return r; } if (!r) { - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); return 1; } er = emulate_instruction(vcpu, kvm_run, cr2, error_code); - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); switch (er) { case EMULATE_DONE: return 1; case EMULATE_DO_MMIO: ++vcpu->stat.mmio_exits; - kvm_run->exit_reason = KVM_EXIT_MMIO; return 0; case EMULATE_FAIL: - vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__); + kvm_report_emulation_failure(vcpu, "pagetable"); break; default: BUG(); @@ -1653,80 +1838,29 @@ static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 0; } -static int get_io_count(struct kvm_vcpu *vcpu, unsigned long *count) -{ - u64 inst; - gva_t rip; - int countr_size; - int i, n; - - if ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_VM)) { - countr_size = 2; - } else { - u32 cs_ar = vmcs_read32(GUEST_CS_AR_BYTES); - - countr_size = (cs_ar & AR_L_MASK) ? 8: - (cs_ar & AR_DB_MASK) ? 4: 2; - } - - rip = vmcs_readl(GUEST_RIP); - if (countr_size != 8) - rip += vmcs_readl(GUEST_CS_BASE); - - n = kvm_read_guest(vcpu, rip, sizeof(inst), &inst); - - for (i = 0; i < n; i++) { - switch (((u8*)&inst)[i]) { - case 0xf0: - case 0xf2: - case 0xf3: - case 0x2e: - case 0x36: - case 0x3e: - case 0x26: - case 0x64: - case 0x65: - case 0x66: - break; - case 0x67: - countr_size = (countr_size == 2) ? 4: (countr_size >> 1); - default: - goto done; - } - } - return 0; -done: - countr_size *= 8; - *count = vcpu->regs[VCPU_REGS_RCX] & (~0ULL >> (64 - countr_size)); - //printk("cx: %lx\n", vcpu->regs[VCPU_REGS_RCX]); - return 1; -} - static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - u64 exit_qualification; + unsigned long exit_qualification; int size, down, in, string, rep; unsigned port; - unsigned long count; - gva_t address; ++vcpu->stat.io_exits; - exit_qualification = vmcs_read64(EXIT_QUALIFICATION); - in = (exit_qualification & 8) != 0; - size = (exit_qualification & 7) + 1; + exit_qualification = vmcs_readl(EXIT_QUALIFICATION); string = (exit_qualification & 16) != 0; + + if (string) { + if (emulate_instruction(vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO) + return 0; + return 1; + } + + size = (exit_qualification & 7) + 1; + in = (exit_qualification & 8) != 0; down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0; - count = 1; rep = (exit_qualification & 32) != 0; port = exit_qualification >> 16; - address = 0; - if (string) { - if (rep && !get_io_count(vcpu, &count)) - return 1; - address = vmcs_readl(GUEST_LINEAR_ADDRESS); - } - return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down, - address, rep, port); + + return kvm_emulate_pio(vcpu, kvm_run, in, size, port); } static void @@ -1743,11 +1877,11 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - u64 exit_qualification; + unsigned long exit_qualification; int cr; int reg; - exit_qualification = vmcs_read64(EXIT_QUALIFICATION); + exit_qualification = vmcs_readl(EXIT_QUALIFICATION); cr = exit_qualification & 15; reg = (exit_qualification >> 8) & 15; switch ((exit_qualification >> 4) & 3) { @@ -1772,13 +1906,14 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) vcpu_load_rsp_rip(vcpu); set_cr8(vcpu, vcpu->regs[reg]); skip_emulated_instruction(vcpu); - return 1; + kvm_run->exit_reason = KVM_EXIT_SET_TPR; + return 0; }; break; case 2: /* clts */ vcpu_load_rsp_rip(vcpu); vmx_fpu_deactivate(vcpu); - vcpu->cr0 &= ~CR0_TS_MASK; + vcpu->cr0 &= ~X86_CR0_TS; vmcs_writel(CR0_READ_SHADOW, vcpu->cr0); vmx_fpu_activate(vcpu); skip_emulated_instruction(vcpu); @@ -1793,7 +1928,7 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 1; case 8: vcpu_load_rsp_rip(vcpu); - vcpu->regs[reg] = vcpu->cr8; + vcpu->regs[reg] = get_cr8(vcpu); vcpu_put_rsp_rip(vcpu); skip_emulated_instruction(vcpu); return 1; @@ -1808,14 +1943,14 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) break; } kvm_run->exit_reason = 0; - printk(KERN_ERR "kvm: unhandled control register: op %d cr %d\n", + pr_unimpl(vcpu, "unhandled control register: op %d cr %d\n", (int)(exit_qualification >> 4) & 3, cr); return 0; } static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - u64 exit_qualification; + unsigned long exit_qualification; unsigned long val; int dr, reg; @@ -1823,7 +1958,7 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) * FIXME: this code assumes the host is debugging the guest. * need to deal with guest debugging itself too. */ - exit_qualification = vmcs_read64(EXIT_QUALIFICATION); + exit_qualification = vmcs_readl(EXIT_QUALIFICATION); dr = exit_qualification & 7; reg = (exit_qualification >> 8) & 15; vcpu_load_rsp_rip(vcpu); @@ -1886,19 +2021,21 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 1; } -static void post_kvm_run_save(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) +static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) { - kvm_run->if_flag = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) != 0; - kvm_run->cr8 = vcpu->cr8; - kvm_run->apic_base = vcpu->apic_base; - kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open && - vcpu->irq_summary == 0); + return 1; } static int handle_interrupt_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { + u32 cpu_based_vm_exec_control; + + /* clear pending irq */ + cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); /* * If the user space waits to inject interrupts, exit as soon as * possible @@ -1943,6 +2080,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu, [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window, [EXIT_REASON_HLT] = handle_halt, [EXIT_REASON_VMCALL] = handle_vmcall, + [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold }; static const int kvm_vmx_max_exit_handlers = @@ -1956,6 +2094,14 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) { u32 vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); u32 exit_reason = vmcs_read32(VM_EXIT_REASON); + struct vcpu_vmx *vmx = to_vmx(vcpu); + + if (unlikely(vmx->fail)) { + kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; + kvm_run->fail_entry.hardware_entry_failure_reason + = vmcs_read32(VM_INSTRUCTION_ERROR); + return 0; + } if ( (vectoring_info & VECTORING_INFO_VALID_MASK) && exit_reason != EXIT_REASON_EXCEPTION_NMI ) @@ -1971,57 +2117,91 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) return 0; } -/* - * Check if userspace requested an interrupt window, and that the - * interrupt window is open. - * - * No need to exit to userspace if we already have an interrupt queued. - */ -static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) +static void vmx_flush_tlb(struct kvm_vcpu *vcpu) { - return (!vcpu->irq_summary && - kvm_run->request_interrupt_window && - vcpu->interrupt_window_open && - (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF)); } -static void vmx_flush_tlb(struct kvm_vcpu *vcpu) +static void update_tpr_threshold(struct kvm_vcpu *vcpu) { + int max_irr, tpr; + + if (!vm_need_tpr_shadow(vcpu->kvm)) + return; + + if (!kvm_lapic_enabled(vcpu) || + ((max_irr = kvm_lapic_find_highest_irr(vcpu)) == -1)) { + vmcs_write32(TPR_THRESHOLD, 0); + return; + } + + tpr = (kvm_lapic_get_cr8(vcpu) & 0x0f) << 4; + vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4); } -static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static void enable_irq_window(struct kvm_vcpu *vcpu) { - u8 fail; - int r; + u32 cpu_based_vm_exec_control; -preempted: - if (vcpu->guest_debug.enabled) - kvm_guest_debug_pre(vcpu); + cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); +} -again: - if (!vcpu->mmio_read_completed) - do_interrupt_requests(vcpu, kvm_run); +static void vmx_intr_assist(struct kvm_vcpu *vcpu) +{ + u32 idtv_info_field, intr_info_field; + int has_ext_irq, interrupt_window_open; + int vector; - vmx_save_host_state(vcpu); - kvm_load_guest_fpu(vcpu); + kvm_inject_pending_timer_irqs(vcpu); + update_tpr_threshold(vcpu); - r = kvm_mmu_reload(vcpu); - if (unlikely(r)) - goto out; + has_ext_irq = kvm_cpu_has_interrupt(vcpu); + intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD); + idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD); + if (intr_info_field & INTR_INFO_VALID_MASK) { + if (idtv_info_field & INTR_INFO_VALID_MASK) { + /* TODO: fault when IDT_Vectoring */ + printk(KERN_ERR "Fault when IDT_Vectoring\n"); + } + if (has_ext_irq) + enable_irq_window(vcpu); + return; + } + if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) { + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, + vmcs_read32(VM_EXIT_INSTRUCTION_LEN)); + + if (unlikely(idtv_info_field & INTR_INFO_DELIEVER_CODE_MASK)) + vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, + vmcs_read32(IDT_VECTORING_ERROR_CODE)); + if (unlikely(has_ext_irq)) + enable_irq_window(vcpu); + return; + } + if (!has_ext_irq) + return; + interrupt_window_open = + ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && + (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0); + if (interrupt_window_open) { + vector = kvm_cpu_get_interrupt(vcpu); + vmx_inject_irq(vcpu, vector); + kvm_timer_intr_post(vcpu, vector); + } else + enable_irq_window(vcpu); +} + +static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); /* * Loading guest fpu may have cleared host cr0.ts */ vmcs_writel(HOST_CR0, read_cr0()); - local_irq_disable(); - - vcpu->guest_mode = 1; - if (vcpu->requests) - if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests)) - vmx_flush_tlb(vcpu); - asm ( /* Store host registers */ #ifdef CONFIG_X86_64 @@ -2115,8 +2295,8 @@ again: "pop %%ecx; popa \n\t" #endif "setbe %0 \n\t" - : "=q" (fail) - : "r"(vcpu->launched), "d"((unsigned long)HOST_RSP), + : "=q" (vmx->fail) + : "r"(vmx->launched), "d"((unsigned long)HOST_RSP), "c"(vcpu), [rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])), [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])), @@ -2138,59 +2318,10 @@ again: [cr2]"i"(offsetof(struct kvm_vcpu, cr2)) : "cc", "memory" ); - vcpu->guest_mode = 0; - local_irq_enable(); - - ++vcpu->stat.exits; - vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0; asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); - - if (unlikely(fail)) { - kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; - kvm_run->fail_entry.hardware_entry_failure_reason - = vmcs_read32(VM_INSTRUCTION_ERROR); - r = 0; - goto out; - } - /* - * Profile KVM exit RIPs: - */ - if (unlikely(prof_on == KVM_PROFILING)) - profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP)); - - vcpu->launched = 1; - r = kvm_handle_exit(kvm_run, vcpu); - if (r > 0) { - /* Give scheduler a change to reschedule. */ - if (signal_pending(current)) { - r = -EINTR; - kvm_run->exit_reason = KVM_EXIT_INTR; - ++vcpu->stat.signal_exits; - goto out; - } - - if (dm_request_for_irq_injection(vcpu, kvm_run)) { - r = -EINTR; - kvm_run->exit_reason = KVM_EXIT_INTR; - ++vcpu->stat.request_irq_exits; - goto out; - } - if (!need_resched()) { - ++vcpu->stat.light_exits; - goto again; - } - } - -out: - if (r > 0) { - kvm_resched(vcpu); - goto preempted; - } - - post_kvm_run_save(vcpu, kvm_run); - return r; + vmx->launched = 1; } static void vmx_inject_page_fault(struct kvm_vcpu *vcpu, @@ -2225,67 +2356,118 @@ static void vmx_inject_page_fault(struct kvm_vcpu *vcpu, static void vmx_free_vmcs(struct kvm_vcpu *vcpu) { - if (vcpu->vmcs) { - on_each_cpu(__vcpu_clear, vcpu, 0, 1); - free_vmcs(vcpu->vmcs); - vcpu->vmcs = NULL; + struct vcpu_vmx *vmx = to_vmx(vcpu); + + if (vmx->vmcs) { + on_each_cpu(__vcpu_clear, vmx, 0, 1); + free_vmcs(vmx->vmcs); + vmx->vmcs = NULL; } } static void vmx_free_vcpu(struct kvm_vcpu *vcpu) { + struct vcpu_vmx *vmx = to_vmx(vcpu); + vmx_free_vmcs(vcpu); + kfree(vmx->host_msrs); + kfree(vmx->guest_msrs); + kvm_vcpu_uninit(vcpu); + kmem_cache_free(kvm_vcpu_cache, vmx); } -static int vmx_create_vcpu(struct kvm_vcpu *vcpu) +static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) { - struct vmcs *vmcs; + int err; + struct vcpu_vmx *vmx = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); + int cpu; - vcpu->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!vcpu->guest_msrs) - return -ENOMEM; + if (!vmx) + return ERR_PTR(-ENOMEM); - vcpu->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!vcpu->host_msrs) - goto out_free_guest_msrs; + err = kvm_vcpu_init(&vmx->vcpu, kvm, id); + if (err) + goto free_vcpu; - vmcs = alloc_vmcs(); - if (!vmcs) - goto out_free_msrs; + if (irqchip_in_kernel(kvm)) { + err = kvm_create_lapic(&vmx->vcpu); + if (err < 0) + goto free_vcpu; + } - vmcs_clear(vmcs); - vcpu->vmcs = vmcs; - vcpu->launched = 0; + vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!vmx->guest_msrs) { + err = -ENOMEM; + goto uninit_vcpu; + } - return 0; + vmx->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!vmx->host_msrs) + goto free_guest_msrs; -out_free_msrs: - kfree(vcpu->host_msrs); - vcpu->host_msrs = NULL; + vmx->vmcs = alloc_vmcs(); + if (!vmx->vmcs) + goto free_msrs; -out_free_guest_msrs: - kfree(vcpu->guest_msrs); - vcpu->guest_msrs = NULL; + vmcs_clear(vmx->vmcs); - return -ENOMEM; + cpu = get_cpu(); + vmx_vcpu_load(&vmx->vcpu, cpu); + err = vmx_vcpu_setup(vmx); + vmx_vcpu_put(&vmx->vcpu); + put_cpu(); + if (err) + goto free_vmcs; + + return &vmx->vcpu; + +free_vmcs: + free_vmcs(vmx->vmcs); +free_msrs: + kfree(vmx->host_msrs); +free_guest_msrs: + kfree(vmx->guest_msrs); +uninit_vcpu: + kvm_vcpu_uninit(&vmx->vcpu); +free_vcpu: + kmem_cache_free(kvm_vcpu_cache, vmx); + return ERR_PTR(err); +} + +static void __init vmx_check_processor_compat(void *rtn) +{ + struct vmcs_config vmcs_conf; + + *(int *)rtn = 0; + if (setup_vmcs_config(&vmcs_conf) < 0) + *(int *)rtn = -EIO; + if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) { + printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n", + smp_processor_id()); + *(int *)rtn = -EIO; + } } -static struct kvm_arch_ops vmx_arch_ops = { +static struct kvm_x86_ops vmx_x86_ops = { .cpu_has_kvm_support = cpu_has_kvm_support, .disabled_by_bios = vmx_disabled_by_bios, .hardware_setup = hardware_setup, .hardware_unsetup = hardware_unsetup, + .check_processor_compatibility = vmx_check_processor_compat, .hardware_enable = hardware_enable, .hardware_disable = hardware_disable, .vcpu_create = vmx_create_vcpu, .vcpu_free = vmx_free_vcpu, + .vcpu_reset = vmx_vcpu_reset, + .prepare_guest_switch = vmx_save_host_state, .vcpu_load = vmx_vcpu_load, .vcpu_put = vmx_vcpu_put, .vcpu_decache = vmx_vcpu_decache, .set_guest_debug = set_guest_debug, + .guest_debug_pre = kvm_guest_debug_pre, .get_msr = vmx_get_msr, .set_msr = vmx_set_msr, .get_segment_base = vmx_get_segment_base, @@ -2314,9 +2496,13 @@ static struct kvm_arch_ops vmx_arch_ops = { .inject_gp = vmx_inject_gp, .run = vmx_vcpu_run, + .handle_exit = kvm_handle_exit, .skip_emulated_instruction = skip_emulated_instruction, - .vcpu_setup = vmx_vcpu_setup, .patch_hypercall = vmx_patch_hypercall, + .get_irq = vmx_get_irq, + .set_irq = vmx_inject_irq, + .inject_pending_irq = vmx_intr_assist, + .inject_pending_vectors = do_interrupt_requests, }; static int __init vmx_init(void) @@ -2347,7 +2533,7 @@ static int __init vmx_init(void) memset(iova, 0xff, PAGE_SIZE); kunmap(vmx_io_bitmap_b); - r = kvm_init_arch(&vmx_arch_ops, THIS_MODULE); + r = kvm_init_x86(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE); if (r) goto out1; @@ -2365,7 +2551,7 @@ static void __exit vmx_exit(void) __free_page(vmx_io_bitmap_b); __free_page(vmx_io_bitmap_a); - kvm_exit_arch(); + kvm_exit_x86(); } module_init(vmx_init) diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h index d0dc93df411..fd4e1466608 100644 --- a/drivers/kvm/vmx.h +++ b/drivers/kvm/vmx.h @@ -25,29 +25,36 @@ * */ -#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004 -#define CPU_BASED_USE_TSC_OFFSETING 0x00000008 -#define CPU_BASED_HLT_EXITING 0x00000080 -#define CPU_BASED_INVDPG_EXITING 0x00000200 -#define CPU_BASED_MWAIT_EXITING 0x00000400 -#define CPU_BASED_RDPMC_EXITING 0x00000800 -#define CPU_BASED_RDTSC_EXITING 0x00001000 -#define CPU_BASED_CR8_LOAD_EXITING 0x00080000 -#define CPU_BASED_CR8_STORE_EXITING 0x00100000 -#define CPU_BASED_TPR_SHADOW 0x00200000 -#define CPU_BASED_MOV_DR_EXITING 0x00800000 -#define CPU_BASED_UNCOND_IO_EXITING 0x01000000 -#define CPU_BASED_ACTIVATE_IO_BITMAP 0x02000000 -#define CPU_BASED_MSR_BITMAPS 0x10000000 -#define CPU_BASED_MONITOR_EXITING 0x20000000 -#define CPU_BASED_PAUSE_EXITING 0x40000000 +#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004 +#define CPU_BASED_USE_TSC_OFFSETING 0x00000008 +#define CPU_BASED_HLT_EXITING 0x00000080 +#define CPU_BASED_INVLPG_EXITING 0x00000200 +#define CPU_BASED_MWAIT_EXITING 0x00000400 +#define CPU_BASED_RDPMC_EXITING 0x00000800 +#define CPU_BASED_RDTSC_EXITING 0x00001000 +#define CPU_BASED_CR8_LOAD_EXITING 0x00080000 +#define CPU_BASED_CR8_STORE_EXITING 0x00100000 +#define CPU_BASED_TPR_SHADOW 0x00200000 +#define CPU_BASED_MOV_DR_EXITING 0x00800000 +#define CPU_BASED_UNCOND_IO_EXITING 0x01000000 +#define CPU_BASED_USE_IO_BITMAPS 0x02000000 +#define CPU_BASED_USE_MSR_BITMAPS 0x10000000 +#define CPU_BASED_MONITOR_EXITING 0x20000000 +#define CPU_BASED_PAUSE_EXITING 0x40000000 +#define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS 0x80000000 -#define PIN_BASED_EXT_INTR_MASK 0x1 -#define PIN_BASED_NMI_EXITING 0x8 +#define PIN_BASED_EXT_INTR_MASK 0x00000001 +#define PIN_BASED_NMI_EXITING 0x00000008 +#define PIN_BASED_VIRTUAL_NMIS 0x00000020 -#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 -#define VM_EXIT_HOST_ADD_SPACE_SIZE 0x00000200 +#define VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200 +#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 +#define VM_ENTRY_IA32E_MODE 0x00000200 +#define VM_ENTRY_SMM 0x00000400 +#define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800 + +#define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 /* VMCS Encodings */ enum vmcs_field { @@ -206,6 +213,7 @@ enum vmcs_field { #define EXIT_REASON_MSR_READ 31 #define EXIT_REASON_MSR_WRITE 32 #define EXIT_REASON_MWAIT_INSTRUCTION 36 +#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 /* * Interruption-information format @@ -261,9 +269,6 @@ enum vmcs_field { /* segment AR */ #define SEGMENT_AR_L_MASK (1 << 13) -/* entry controls */ -#define VM_ENTRY_CONTROLS_IA32E_MASK (1 << 9) - #define AR_TYPE_ACCESSES_MASK 1 #define AR_TYPE_READABLE_MASK (1 << 1) #define AR_TYPE_WRITEABLE_MASK (1 << 2) @@ -285,13 +290,21 @@ enum vmcs_field { #define AR_RESERVD_MASK 0xfffe0f00 -#define CR4_VMXE 0x2000 +#define MSR_IA32_VMX_BASIC 0x480 +#define MSR_IA32_VMX_PINBASED_CTLS 0x481 +#define MSR_IA32_VMX_PROCBASED_CTLS 0x482 +#define MSR_IA32_VMX_EXIT_CTLS 0x483 +#define MSR_IA32_VMX_ENTRY_CTLS 0x484 +#define MSR_IA32_VMX_MISC 0x485 +#define MSR_IA32_VMX_CR0_FIXED0 0x486 +#define MSR_IA32_VMX_CR0_FIXED1 0x487 +#define MSR_IA32_VMX_CR4_FIXED0 0x488 +#define MSR_IA32_VMX_CR4_FIXED1 0x489 +#define MSR_IA32_VMX_VMCS_ENUM 0x48a +#define MSR_IA32_VMX_PROCBASED_CTLS2 0x48b -#define MSR_IA32_VMX_BASIC 0x480 -#define MSR_IA32_FEATURE_CONTROL 0x03a -#define MSR_IA32_VMX_PINBASED_CTLS 0x481 -#define MSR_IA32_VMX_PROCBASED_CTLS 0x482 -#define MSR_IA32_VMX_EXIT_CTLS 0x483 -#define MSR_IA32_VMX_ENTRY_CTLS 0x484 +#define MSR_IA32_FEATURE_CONTROL 0x3a +#define MSR_IA32_FEATURE_CONTROL_LOCKED 0x1 +#define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED 0x4 #endif diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index 4b8a0cc9665..9737c3b2f48 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c @@ -6,7 +6,7 @@ * Copyright (c) 2005 Keir Fraser * * Linux coding style, mod r/m decoder, segment base fixes, real-mode - * privieged instructions: + * privileged instructions: * * Copyright (C) 2006 Qumranet * @@ -83,7 +83,7 @@ static u8 opcode_table[256] = { /* 0x20 - 0x27 */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, - 0, 0, 0, 0, + SrcImmByte, SrcImm, 0, 0, /* 0x28 - 0x2F */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, @@ -99,15 +99,24 @@ static u8 opcode_table[256] = { /* 0x40 - 0x4F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x57 */ - 0, 0, 0, 0, 0, 0, 0, 0, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0x58 - 0x5F */ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - /* 0x60 - 0x6F */ + /* 0x60 - 0x67 */ 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ , - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x70 - 0x7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + /* 0x68 - 0x6F */ + 0, 0, ImplicitOps|Mov, 0, + SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */ + SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */ + /* 0x70 - 0x77 */ + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + /* 0x78 - 0x7F */ + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0x80 - 0x87 */ ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, @@ -116,9 +125,9 @@ static u8 opcode_table[256] = { /* 0x88 - 0x8F */ ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov, ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, - 0, 0, 0, DstMem | SrcNone | ModRM | Mov, + 0, ModRM | DstReg, 0, DstMem | SrcNone | ModRM | Mov, /* 0x90 - 0x9F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps, ImplicitOps, 0, 0, /* 0xA0 - 0xA7 */ ByteOp | DstReg | SrcMem | Mov, DstReg | SrcMem | Mov, ByteOp | DstMem | SrcReg | Mov, DstMem | SrcReg | Mov, @@ -142,8 +151,10 @@ static u8 opcode_table[256] = { 0, 0, 0, 0, /* 0xD8 - 0xDF */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xE0 - 0xEF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE0 - 0xE7 */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE8 - 0xEF */ + ImplicitOps, SrcImm|ImplicitOps, 0, SrcImmByte|ImplicitOps, 0, 0, 0, 0, /* 0xF0 - 0xF7 */ 0, 0, 0, 0, ImplicitOps, 0, @@ -181,7 +192,10 @@ static u16 twobyte_table[256] = { /* 0x70 - 0x7F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0x90 - 0x9F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xA7 */ @@ -207,19 +221,6 @@ static u16 twobyte_table[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -/* - * Tell the emulator that of the Group 7 instructions (sgdt, lidt, etc.) we - * are interested only in invlpg and not in any of the rest. - * - * invlpg is a special instruction in that the data it references may not - * be mapped. - */ -void kvm_emulator_want_group7_invlpg(void) -{ - twobyte_table[1] &= ~SrcMem; -} -EXPORT_SYMBOL_GPL(kvm_emulator_want_group7_invlpg); - /* Type, address-of, and value of an instruction's operand. */ struct operand { enum { OP_REG, OP_MEM, OP_IMM } type; @@ -420,7 +421,7 @@ struct operand { #define insn_fetch(_type, _size, _eip) \ ({ unsigned long _x; \ rc = ops->read_std((unsigned long)(_eip) + ctxt->cs_base, &_x, \ - (_size), ctxt); \ + (_size), ctxt->vcpu); \ if ( rc != 0 ) \ goto done; \ (_eip) += (_size); \ @@ -428,10 +429,11 @@ struct operand { }) /* Access/update address held in a register, based on addressing mode. */ +#define address_mask(reg) \ + ((ad_bytes == sizeof(unsigned long)) ? \ + (reg) : ((reg) & ((1UL << (ad_bytes << 3)) - 1))) #define register_address(base, reg) \ - ((base) + ((ad_bytes == sizeof(unsigned long)) ? (reg) : \ - ((reg) & ((1UL << (ad_bytes << 3)) - 1)))) - + ((base) + address_mask(reg)) #define register_address_increment(reg, inc) \ do { \ /* signed type ensures sign extension to long */ \ @@ -443,8 +445,19 @@ struct operand { (((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \ } while (0) -void *decode_register(u8 modrm_reg, unsigned long *regs, - int highbyte_regs) +#define JMP_REL(rel) \ + do { \ + _eip += (int)(rel); \ + _eip = ((op_bytes == 2) ? (uint16_t)_eip : (uint32_t)_eip); \ + } while (0) + +/* + * Given the 'reg' portion of a ModRM byte, and a register block, return a + * pointer into the block that addresses the relevant register. + * @highbyte_regs specifies whether to decode AH,CH,DH,BH. + */ +static void *decode_register(u8 modrm_reg, unsigned long *regs, + int highbyte_regs) { void *p; @@ -464,13 +477,50 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt, if (op_bytes == 2) op_bytes = 3; *address = 0; - rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, ctxt); + rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, + ctxt->vcpu); if (rc) return rc; - rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, ctxt); + rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, + ctxt->vcpu); return rc; } +static int test_cc(unsigned int condition, unsigned int flags) +{ + int rc = 0; + + switch ((condition & 15) >> 1) { + case 0: /* o */ + rc |= (flags & EFLG_OF); + break; + case 1: /* b/c/nae */ + rc |= (flags & EFLG_CF); + break; + case 2: /* z/e */ + rc |= (flags & EFLG_ZF); + break; + case 3: /* be/na */ + rc |= (flags & (EFLG_CF|EFLG_ZF)); + break; + case 4: /* s */ + rc |= (flags & EFLG_SF); + break; + case 5: /* p/pe */ + rc |= (flags & EFLG_PF); + break; + case 7: /* le/ng */ + rc |= (flags & EFLG_ZF); + /* fall through */ + case 6: /* l/nge */ + rc |= (!(flags & EFLG_SF) != !(flags & EFLG_OF)); + break; + } + + /* Odd condition identifiers (lsb == 1) have inverted sense. */ + return (!!rc ^ (condition & 1)); +} + int x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { @@ -771,11 +821,15 @@ done_prefixes: goto srcmem_common; case SrcMem: src.bytes = (d & ByteOp) ? 1 : op_bytes; + /* Don't fetch the address for invlpg: it could be unmapped. */ + if (twobyte && b == 0x01 && modrm_reg == 7) + break; srcmem_common: src.type = OP_MEM; src.ptr = (unsigned long *)cr2; + src.val = 0; if ((rc = ops->read_emulated((unsigned long)src.ptr, - &src.val, src.bytes, ctxt)) != 0) + &src.val, src.bytes, ctxt->vcpu)) != 0) goto done; src.orig_val = src.val; break; @@ -814,7 +868,7 @@ done_prefixes: case DstReg: dst.type = OP_REG; if ((d & ByteOp) - && !(twobyte_table && (b == 0xb6 || b == 0xb7))) { + && !(twobyte && (b == 0xb6 || b == 0xb7))) { dst.ptr = decode_register(modrm_reg, _regs, (rex_prefix == 0)); dst.val = *(u8 *) dst.ptr; @@ -838,6 +892,7 @@ done_prefixes: dst.type = OP_MEM; dst.ptr = (unsigned long *)cr2; dst.bytes = (d & ByteOp) ? 1 : op_bytes; + dst.val = 0; if (d & BitOp) { unsigned long mask = ~(dst.bytes * 8 - 1); @@ -845,7 +900,7 @@ done_prefixes: } if (!(d & Mov) && /* optimisation - avoid slow emulated read */ ((rc = ops->read_emulated((unsigned long)dst.ptr, - &dst.val, dst.bytes, ctxt)) != 0)) + &dst.val, dst.bytes, ctxt->vcpu)) != 0)) goto done; break; } @@ -871,10 +926,27 @@ done_prefixes: sbb: /* sbb */ emulate_2op_SrcV("sbb", src, dst, _eflags); break; - case 0x20 ... 0x25: + case 0x20 ... 0x23: and: /* and */ emulate_2op_SrcV("and", src, dst, _eflags); break; + case 0x24: /* and al imm8 */ + dst.type = OP_REG; + dst.ptr = &_regs[VCPU_REGS_RAX]; + dst.val = *(u8 *)dst.ptr; + dst.bytes = 1; + dst.orig_val = dst.val; + goto and; + case 0x25: /* and ax imm16, or eax imm32 */ + dst.type = OP_REG; + dst.bytes = op_bytes; + dst.ptr = &_regs[VCPU_REGS_RAX]; + if (op_bytes == 2) + dst.val = *(u16 *)dst.ptr; + else + dst.val = *(u32 *)dst.ptr; + dst.orig_val = dst.val; + goto and; case 0x28 ... 0x2d: sub: /* sub */ emulate_2op_SrcV("sub", src, dst, _eflags); @@ -892,6 +964,17 @@ done_prefixes: goto cannot_emulate; dst.val = (s32) src.val; break; + case 0x6a: /* push imm8 */ + src.val = 0L; + src.val = insn_fetch(s8, 1, _eip); +push: + dst.type = OP_MEM; + dst.bytes = op_bytes; + dst.val = src.val; + register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes); + dst.ptr = (void *) register_address(ctxt->ss_base, + _regs[VCPU_REGS_RSP]); + break; case 0x80 ... 0x83: /* Grp1 */ switch (modrm_reg) { case 0: @@ -939,18 +1022,10 @@ done_prefixes: dst.val = src.val; lock_prefix = 1; break; - case 0xa0 ... 0xa1: /* mov */ - dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; - dst.val = src.val; - _eip += ad_bytes; /* skip src displacement */ - break; - case 0xa2 ... 0xa3: /* mov */ - dst.val = (unsigned long)_regs[VCPU_REGS_RAX]; - _eip += ad_bytes; /* skip dst displacement */ - break; case 0x88 ... 0x8b: /* mov */ - case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */ - dst.val = src.val; + goto mov; + case 0x8d: /* lea r16/r32, m */ + dst.val = modrm_val; break; case 0x8f: /* pop (sole member of Grp1a) */ /* 64-bit mode: POP always pops a 64-bit operand. */ @@ -958,10 +1033,19 @@ done_prefixes: dst.bytes = 8; if ((rc = ops->read_std(register_address(ctxt->ss_base, _regs[VCPU_REGS_RSP]), - &dst.val, dst.bytes, ctxt)) != 0) + &dst.val, dst.bytes, ctxt->vcpu)) != 0) goto done; register_address_increment(_regs[VCPU_REGS_RSP], dst.bytes); break; + case 0xa0 ... 0xa1: /* mov */ + dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; + dst.val = src.val; + _eip += ad_bytes; /* skip src displacement */ + break; + case 0xa2 ... 0xa3: /* mov */ + dst.val = (unsigned long)_regs[VCPU_REGS_RAX]; + _eip += ad_bytes; /* skip dst displacement */ + break; case 0xc0 ... 0xc1: grp2: /* Grp2 */ switch (modrm_reg) { @@ -989,12 +1073,41 @@ done_prefixes: break; } break; + case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */ + mov: + dst.val = src.val; + break; case 0xd0 ... 0xd1: /* Grp2 */ src.val = 1; goto grp2; case 0xd2 ... 0xd3: /* Grp2 */ src.val = _regs[VCPU_REGS_RCX]; goto grp2; + case 0xe8: /* call (near) */ { + long int rel; + switch (op_bytes) { + case 2: + rel = insn_fetch(s16, 2, _eip); + break; + case 4: + rel = insn_fetch(s32, 4, _eip); + break; + case 8: + rel = insn_fetch(s64, 8, _eip); + break; + default: + DPRINTF("Call: Invalid op_bytes\n"); + goto cannot_emulate; + } + src.val = (unsigned long) _eip; + JMP_REL(rel); + goto push; + } + case 0xe9: /* jmp rel */ + case 0xeb: /* jmp rel short */ + JMP_REL(src.val); + no_wb = 1; /* Disable writeback. */ + break; case 0xf6 ... 0xf7: /* Grp3 */ switch (modrm_reg) { case 0 ... 1: /* test */ @@ -1037,13 +1150,19 @@ done_prefixes: case 1: /* dec */ emulate_1op("dec", dst, _eflags); break; + case 4: /* jmp abs */ + if (b == 0xff) + _eip = dst.val; + else + goto cannot_emulate; + break; case 6: /* push */ /* 64-bit mode: PUSH always pushes a 64-bit operand. */ if (mode == X86EMUL_MODE_PROT64) { dst.bytes = 8; if ((rc = ops->read_std((unsigned long)dst.ptr, &dst.val, 8, - ctxt)) != 0) + ctxt->vcpu)) != 0) goto done; } register_address_increment(_regs[VCPU_REGS_RSP], @@ -1051,7 +1170,7 @@ done_prefixes: if ((rc = ops->write_std( register_address(ctxt->ss_base, _regs[VCPU_REGS_RSP]), - &dst.val, dst.bytes, ctxt)) != 0) + &dst.val, dst.bytes, ctxt->vcpu)) != 0) goto done; no_wb = 1; break; @@ -1086,11 +1205,11 @@ writeback: rc = ops->cmpxchg_emulated((unsigned long)dst. ptr, &dst.orig_val, &dst.val, dst.bytes, - ctxt); + ctxt->vcpu); else rc = ops->write_emulated((unsigned long)dst.ptr, &dst.val, dst.bytes, - ctxt); + ctxt->vcpu); if (rc != 0) goto done; default: @@ -1109,6 +1228,81 @@ done: special_insn: if (twobyte) goto twobyte_special_insn; + switch(b) { + case 0x50 ... 0x57: /* push reg */ + if (op_bytes == 2) + src.val = (u16) _regs[b & 0x7]; + else + src.val = (u32) _regs[b & 0x7]; + dst.type = OP_MEM; + dst.bytes = op_bytes; + dst.val = src.val; + register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes); + dst.ptr = (void *) register_address( + ctxt->ss_base, _regs[VCPU_REGS_RSP]); + break; + case 0x58 ... 0x5f: /* pop reg */ + dst.ptr = (unsigned long *)&_regs[b & 0x7]; + pop_instruction: + if ((rc = ops->read_std(register_address(ctxt->ss_base, + _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt->vcpu)) + != 0) + goto done; + + register_address_increment(_regs[VCPU_REGS_RSP], op_bytes); + no_wb = 1; /* Disable writeback. */ + break; + case 0x6c: /* insb */ + case 0x6d: /* insw/insd */ + if (kvm_emulate_pio_string(ctxt->vcpu, NULL, + 1, /* in */ + (d & ByteOp) ? 1 : op_bytes, /* size */ + rep_prefix ? + address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */ + (_eflags & EFLG_DF), /* down */ + register_address(ctxt->es_base, + _regs[VCPU_REGS_RDI]), /* address */ + rep_prefix, + _regs[VCPU_REGS_RDX] /* port */ + ) == 0) + return -1; + return 0; + case 0x6e: /* outsb */ + case 0x6f: /* outsw/outsd */ + if (kvm_emulate_pio_string(ctxt->vcpu, NULL, + 0, /* in */ + (d & ByteOp) ? 1 : op_bytes, /* size */ + rep_prefix ? + address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */ + (_eflags & EFLG_DF), /* down */ + register_address(override_base ? + *override_base : ctxt->ds_base, + _regs[VCPU_REGS_RSI]), /* address */ + rep_prefix, + _regs[VCPU_REGS_RDX] /* port */ + ) == 0) + return -1; + return 0; + case 0x70 ... 0x7f: /* jcc (short) */ { + int rel = insn_fetch(s8, 1, _eip); + + if (test_cc(b, _eflags)) + JMP_REL(rel); + break; + } + case 0x9c: /* pushf */ + src.val = (unsigned long) _eflags; + goto push; + case 0x9d: /* popf */ + dst.ptr = (unsigned long *) &_eflags; + goto pop_instruction; + case 0xc3: /* ret */ + dst.ptr = &_eip; + goto pop_instruction; + case 0xf4: /* hlt */ + ctxt->vcpu->halt_request = 1; + goto done; + } if (rep_prefix) { if (_regs[VCPU_REGS_RCX] == 0) { ctxt->vcpu->rip = _eip; @@ -1125,7 +1319,7 @@ special_insn: _regs[VCPU_REGS_RDI]); if ((rc = ops->read_emulated(register_address( override_base ? *override_base : ctxt->ds_base, - _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt)) != 0) + _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt->vcpu)) != 0) goto done; register_address_increment(_regs[VCPU_REGS_RSI], (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); @@ -1147,7 +1341,8 @@ special_insn: dst.type = OP_REG; dst.bytes = (d & ByteOp) ? 1 : op_bytes; dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; - if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes, ctxt)) != 0) + if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes, + ctxt->vcpu)) != 0) goto done; register_address_increment(_regs[VCPU_REGS_RSI], (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); @@ -1155,23 +1350,7 @@ special_insn: case 0xae ... 0xaf: /* scas */ DPRINTF("Urk! I don't handle SCAS.\n"); goto cannot_emulate; - case 0xf4: /* hlt */ - ctxt->vcpu->halt_request = 1; - goto done; - case 0xc3: /* ret */ - dst.ptr = &_eip; - goto pop_instruction; - case 0x58 ... 0x5f: /* pop reg */ - dst.ptr = (unsigned long *)&_regs[b & 0x7]; -pop_instruction: - if ((rc = ops->read_std(register_address(ctxt->ss_base, - _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt)) != 0) - goto done; - - register_address_increment(_regs[VCPU_REGS_RSP], op_bytes); - no_wb = 1; /* Disable writeback. */ - break; } goto writeback; @@ -1230,40 +1409,50 @@ twobyte_insn: break; case 0x40 ... 0x4f: /* cmov */ dst.val = dst.orig_val = src.val; - d &= ~Mov; /* default to no move */ + no_wb = 1; /* * First, assume we're decoding an even cmov opcode * (lsb == 0). */ switch ((b & 15) >> 1) { case 0: /* cmovo */ - d |= (_eflags & EFLG_OF) ? Mov : 0; + no_wb = (_eflags & EFLG_OF) ? 0 : 1; break; case 1: /* cmovb/cmovc/cmovnae */ - d |= (_eflags & EFLG_CF) ? Mov : 0; + no_wb = (_eflags & EFLG_CF) ? 0 : 1; break; case 2: /* cmovz/cmove */ - d |= (_eflags & EFLG_ZF) ? Mov : 0; + no_wb = (_eflags & EFLG_ZF) ? 0 : 1; break; case 3: /* cmovbe/cmovna */ - d |= (_eflags & (EFLG_CF | EFLG_ZF)) ? Mov : 0; + no_wb = (_eflags & (EFLG_CF | EFLG_ZF)) ? 0 : 1; break; case 4: /* cmovs */ - d |= (_eflags & EFLG_SF) ? Mov : 0; + no_wb = (_eflags & EFLG_SF) ? 0 : 1; break; case 5: /* cmovp/cmovpe */ - d |= (_eflags & EFLG_PF) ? Mov : 0; + no_wb = (_eflags & EFLG_PF) ? 0 : 1; break; case 7: /* cmovle/cmovng */ - d |= (_eflags & EFLG_ZF) ? Mov : 0; + no_wb = (_eflags & EFLG_ZF) ? 0 : 1; /* fall through */ case 6: /* cmovl/cmovnge */ - d |= (!(_eflags & EFLG_SF) != - !(_eflags & EFLG_OF)) ? Mov : 0; + no_wb &= (!(_eflags & EFLG_SF) != + !(_eflags & EFLG_OF)) ? 0 : 1; break; } /* Odd cmov opcodes (lsb == 1) have inverted sense. */ - d ^= (b & 1) ? Mov : 0; + no_wb ^= b & 1; + break; + case 0xa3: + bt: /* bt */ + src.val &= (dst.bytes << 3) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("bt", src, dst, _eflags); + break; + case 0xab: + bts: /* bts */ + src.val &= (dst.bytes << 3) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("bts", src, dst, _eflags); break; case 0xb0 ... 0xb1: /* cmpxchg */ /* @@ -1273,8 +1462,6 @@ twobyte_insn: src.orig_val = src.val; src.val = _regs[VCPU_REGS_RAX]; emulate_2op_SrcV("cmp", src, dst, _eflags); - /* Always write back. The question is: where to? */ - d |= Mov; if (_eflags & EFLG_ZF) { /* Success: write back to memory. */ dst.val = src.orig_val; @@ -1284,30 +1471,15 @@ twobyte_insn: dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; } break; - case 0xa3: - bt: /* bt */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ - emulate_2op_SrcV_nobyte("bt", src, dst, _eflags); - break; case 0xb3: btr: /* btr */ src.val &= (dst.bytes << 3) - 1; /* only subword offset */ emulate_2op_SrcV_nobyte("btr", src, dst, _eflags); break; - case 0xab: - bts: /* bts */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ - emulate_2op_SrcV_nobyte("bts", src, dst, _eflags); - break; case 0xb6 ... 0xb7: /* movzx */ dst.bytes = op_bytes; dst.val = (d & ByteOp) ? (u8) src.val : (u16) src.val; break; - case 0xbb: - btc: /* btc */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ - emulate_2op_SrcV_nobyte("btc", src, dst, _eflags); - break; case 0xba: /* Grp8 */ switch (modrm_reg & 3) { case 0: @@ -1320,6 +1492,11 @@ twobyte_insn: goto btc; } break; + case 0xbb: + btc: /* btc */ + src.val &= (dst.bytes << 3) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("btc", src, dst, _eflags); + break; case 0xbe ... 0xbf: /* movsx */ dst.bytes = op_bytes; dst.val = (d & ByteOp) ? (s8) src.val : (s16) src.val; @@ -1331,14 +1508,14 @@ twobyte_special_insn: /* Disable writeback. */ no_wb = 1; switch (b) { + case 0x06: + emulate_clts(ctxt->vcpu); + break; case 0x09: /* wbinvd */ break; case 0x0d: /* GrpP (prefetch) */ case 0x18: /* Grp16 (prefetch/nop) */ break; - case 0x06: - emulate_clts(ctxt->vcpu); - break; case 0x20: /* mov cr, reg */ if (modrm_mod != 3) goto cannot_emulate; @@ -1355,7 +1532,7 @@ twobyte_special_insn: | ((u64)_regs[VCPU_REGS_RDX] << 32); rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data); if (rc) { - kvm_arch_ops->inject_gp(ctxt->vcpu, 0); + kvm_x86_ops->inject_gp(ctxt->vcpu, 0); _eip = ctxt->vcpu->rip; } rc = X86EMUL_CONTINUE; @@ -1364,7 +1541,7 @@ twobyte_special_insn: /* rdmsr */ rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data); if (rc) { - kvm_arch_ops->inject_gp(ctxt->vcpu, 0); + kvm_x86_ops->inject_gp(ctxt->vcpu, 0); _eip = ctxt->vcpu->rip; } else { _regs[VCPU_REGS_RAX] = (u32)msr_data; @@ -1372,10 +1549,32 @@ twobyte_special_insn: } rc = X86EMUL_CONTINUE; break; + case 0x80 ... 0x8f: /* jnz rel, etc*/ { + long int rel; + + switch (op_bytes) { + case 2: + rel = insn_fetch(s16, 2, _eip); + break; + case 4: + rel = insn_fetch(s32, 4, _eip); + break; + case 8: + rel = insn_fetch(s64, 8, _eip); + break; + default: + DPRINTF("jnz: Invalid op_bytes\n"); + goto cannot_emulate; + } + if (test_cc(b, _eflags)) + JMP_REL(rel); + break; + } case 0xc7: /* Grp9 (cmpxchg8b) */ { u64 old, new; - if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0) + if ((rc = ops->read_emulated(cr2, &old, 8, ctxt->vcpu)) + != 0) goto done; if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) || ((u32) (old >> 32) != (u32) _regs[VCPU_REGS_RDX])) { @@ -1386,7 +1585,7 @@ twobyte_special_insn: new = ((u64)_regs[VCPU_REGS_RCX] << 32) | (u32) _regs[VCPU_REGS_RBX]; if ((rc = ops->cmpxchg_emulated(cr2, &old, - &new, 8, ctxt)) != 0) + &new, 8, ctxt->vcpu)) != 0) goto done; _eflags |= EFLG_ZF; } diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h index ea3407d7fee..92c73aa7f9a 100644 --- a/drivers/kvm/x86_emulate.h +++ b/drivers/kvm/x86_emulate.h @@ -60,7 +60,7 @@ struct x86_emulate_ops { * @bytes: [IN ] Number of bytes to read from memory. */ int (*read_std)(unsigned long addr, void *val, - unsigned int bytes, struct x86_emulate_ctxt * ctxt); + unsigned int bytes, struct kvm_vcpu *vcpu); /* * write_std: Write bytes of standard (non-emulated/special) memory. @@ -71,7 +71,7 @@ struct x86_emulate_ops { * @bytes: [IN ] Number of bytes to write to memory. */ int (*write_std)(unsigned long addr, const void *val, - unsigned int bytes, struct x86_emulate_ctxt * ctxt); + unsigned int bytes, struct kvm_vcpu *vcpu); /* * read_emulated: Read bytes from emulated/special memory area. @@ -82,7 +82,7 @@ struct x86_emulate_ops { int (*read_emulated) (unsigned long addr, void *val, unsigned int bytes, - struct x86_emulate_ctxt * ctxt); + struct kvm_vcpu *vcpu); /* * write_emulated: Read bytes from emulated/special memory area. @@ -94,7 +94,7 @@ struct x86_emulate_ops { int (*write_emulated) (unsigned long addr, const void *val, unsigned int bytes, - struct x86_emulate_ctxt * ctxt); + struct kvm_vcpu *vcpu); /* * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an @@ -108,12 +108,10 @@ struct x86_emulate_ops { const void *old, const void *new, unsigned int bytes, - struct x86_emulate_ctxt * ctxt); + struct kvm_vcpu *vcpu); }; -struct cpu_user_regs; - struct x86_emulate_ctxt { /* Register state before/after emulation. */ struct kvm_vcpu *vcpu; @@ -154,12 +152,4 @@ struct x86_emulate_ctxt { int x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops); -/* - * Given the 'reg' portion of a ModRM byte, and a register block, return a - * pointer into the block that addresses the relevant register. - * @highbyte_regs specifies whether to decode AH,CH,DH,BH. - */ -void *decode_register(u8 modrm_reg, unsigned long *regs, - int highbyte_regs); - #endif /* __X86_EMULATE_H__ */ diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c index a2191a4fcf7..342517261ec 100644 --- a/drivers/md/dm-emc.c +++ b/drivers/md/dm-emc.c @@ -54,8 +54,6 @@ static void emc_endio(struct bio *bio, int error) /* request is freed in block layer */ free_bio(bio); - - return 0; } static struct bio *get_failover_bio(struct dm_path *path, unsigned data_size) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index c606332512b..5599a36490f 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -674,7 +674,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, } /* Copy to userspace */ - retval=CALL(q,copy_to_user,q,data,count,nonblocking); + retval=CALL(q,video_copy_to_user,q,data,count,nonblocking); if (retval<0) goto done; diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 8bb7fdd306d..3eb6123227b 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -670,7 +670,7 @@ static struct videobuf_qtype_ops pci_ops = { .sync = __videobuf_sync, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, - .copy_to_user = __videobuf_copy_to_user, + .video_copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, }; diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index 2e3689a12a2..cd74341c984 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -320,7 +320,7 @@ static struct videobuf_qtype_ops qops = { .sync = __videobuf_sync, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, - .copy_to_user = __videobuf_copy_to_user, + .video_copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, }; diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index fbec8cd55e3..8848e8ac705 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -278,6 +278,14 @@ config SSFDC This enables read only access to SmartMedia formatted NAND flash. You can mount it with FAT file system. +config MTD_OOPS + tristate "Log panic/oops to an MTD buffer" + depends on MTD + help + This enables panic and oops messages to be logged to a circular + buffer in a flash partition where it can be read back at some + later point. + source "drivers/mtd/chips/Kconfig" source "drivers/mtd/maps/Kconfig" diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 6d958a4566f..7f0b04b4caa 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_NFTL) += nftl.o obj-$(CONFIG_INFTL) += inftl.o obj-$(CONFIG_RFD_FTL) += rfd_ftl.o obj-$(CONFIG_SSFDC) += ssfdc.o +obj-$(CONFIG_MTD_OOPS) += mtdoops.o nftl-objs := nftlcore.o nftlmount.o inftl-objs := inftlcore.o inftlmount.o diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 2f19fa78d24..3aa3dca56ae 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -526,7 +526,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, struct cfi_pri_intelext *extp = cfi->cmdset_priv; /* - * Probing of multi-partition flash ships. + * Probing of multi-partition flash chips. * * To support multiple partitions when available, we simply arrange * for each of them to have their own flchip structure even if they @@ -653,7 +653,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr resettime: timeo = jiffies + HZ; retry: - if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) { + if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) { /* * OK. We have possibility for contension on the write/erase * operations which are global to the real chip and not per @@ -798,6 +798,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr if (mode == FL_READY && chip->oldstate == FL_READY) return 0; + case FL_SHUTDOWN: + /* The machine is rebooting now,so no one can get chip anymore */ + return -EIO; default: sleep: set_current_state(TASK_UNINTERRUPTIBLE); @@ -1166,28 +1169,34 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - unsigned long ofs; + unsigned long ofs, last_end = 0; int chipnum; int ret = 0; if (!map->virt || (from + len > mtd->size)) return -EINVAL; - *mtdbuf = (void *)map->virt + from; - *retlen = 0; - /* Now lock the chip(s) to POINT state */ /* ofs: offset within the first chip that the first read should start */ chipnum = (from >> cfi->chipshift); ofs = from - (chipnum << cfi->chipshift); + *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs; + *retlen = 0; + while (len) { unsigned long thislen; if (chipnum >= cfi->numchips) break; + /* We cannot point across chips that are virtually disjoint */ + if (!last_end) + last_end = cfi->chips[chipnum].start; + else if (cfi->chips[chipnum].start != last_end) + break; + if ((len + ofs -1) >> cfi->chipshift) thislen = (1<<cfi->chipshift) - ofs; else @@ -1201,6 +1210,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si len -= thislen; ofs = 0; + last_end += 1 << cfi->chipshift; chipnum++; } return 0; @@ -1780,7 +1790,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, return ret; } -int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) +static int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) { unsigned long ofs, len; int ret; @@ -1930,7 +1940,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", __FUNCTION__, ofs, len); cfi_varsize_frob(mtd, do_printlockstatus_oneblock, - ofs, len, 0); + ofs, len, NULL); #endif ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, @@ -1940,7 +1950,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret); cfi_varsize_frob(mtd, do_printlockstatus_oneblock, - ofs, len, 0); + ofs, len, NULL); #endif return ret; @@ -1954,7 +1964,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", __FUNCTION__, ofs, len); cfi_varsize_frob(mtd, do_printlockstatus_oneblock, - ofs, len, 0); + ofs, len, NULL); #endif ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, @@ -1964,7 +1974,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret); cfi_varsize_frob(mtd, do_printlockstatus_oneblock, - ofs, len, 0); + ofs, len, NULL); #endif return ret; @@ -2255,7 +2265,7 @@ static void cfi_intelext_save_locks(struct mtd_info *mtd) adr = region->offset + block * len; status = cfi_varsize_frob(mtd, - do_getlockstatus_oneblock, adr, len, 0); + do_getlockstatus_oneblock, adr, len, NULL); if (status) set_bit(block, region->lockmap); else @@ -2402,10 +2412,10 @@ static int cfi_intelext_reset(struct mtd_info *mtd) and switch to array mode so any bootloader in flash is accessible for soft reboot. */ spin_lock(chip->mutex); - ret = get_chip(map, chip, chip->start, FL_SYNCING); + ret = get_chip(map, chip, chip->start, FL_SHUTDOWN); if (!ret) { map_write(map, CMD(0xff), chip->start); - chip->state = FL_READY; + chip->state = FL_SHUTDOWN; } spin_unlock(chip->mutex); } diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 1f644584046..389acc600f5 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -1609,7 +1609,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, } -int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) +static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) { unsigned long ofs, len; int ret; diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 58e561e8769..a67b23b87fc 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -17,7 +17,6 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -70,6 +69,7 @@ /* Fujitsu */ #define MBM29F040C 0x00A4 +#define MBM29F800BA 0x2258 #define MBM29LV650UE 0x22D7 #define MBM29LV320TE 0x22F6 #define MBM29LV320BE 0x22F9 @@ -129,6 +129,7 @@ #define LH28F640BF 0x00b0 /* ST - www.st.com */ +#define M29F800AB 0x0058 #define M29W800DT 0x00D7 #define M29W800DB 0x005B #define M29W160DT 0x22C4 @@ -646,6 +647,23 @@ static const struct amd_flash_info jedec_table[] = { } }, { .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29F800BA, + .name = "Fujitsu MBM29F800BA", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15), + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, .dev_id = MBM29LV650UE, .name = "Fujitsu MBM29LV650UE", .uaddr = { @@ -1510,6 +1528,23 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x1000,256) } + }, { + .mfr_id = MANUFACTURER_ST, + .dev_id = M29F800AB, + .name = "ST M29F800AB", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15), + } }, { .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ .dev_id = M29W800DT, diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index ff642f8fbee..811d56fd890 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -60,21 +60,22 @@ config MTD_DATAFLASH Sometimes DataFlash chips are packaged inside MMC-format cards; at this writing, the MMC stack won't handle those. -config MTD_DATAFLASH26 - tristate "AT91RM9200 DataFlash AT26xxx" - depends on MTD && ARCH_AT91RM9200 && AT91_SPI - help - This enables access to the DataFlash chip (AT26xxx) on an - AT91RM9200-based board. - If you have such a board and such a DataFlash, say 'Y'. - config MTD_M25P80 - tristate "Support for M25 SPI Flash" + tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" depends on SPI_MASTER && EXPERIMENTAL help - This enables access to ST M25P80 and similar SPI flash chips, - used for program and data storage. Set up your spi devices - with the right board-specific platform data. + This enables access to most modern SPI flash chips, used for + program and data storage. Series supported include Atmel AT26DF, + Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X. Other chips + are supported as well. See the driver source for the current list, + or to add other chips. + + Note that the original DataFlash chips (AT45 series, not AT26DF), + need an entirely different driver. + + Set up your spi devices with the right board-specific platform data, + if you want to specify device partitioning or to use a device which + doesn't support the JEDEC ID instruction. config MTD_SLRAM tristate "Uncached system RAM" diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index 8ab568b3f53..0f788d5c4bf 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -16,5 +16,4 @@ obj-$(CONFIG_MTD_MTDRAM) += mtdram.o obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o -obj-$(CONFIG_MTD_DATAFLASH26) += at91_dataflash26.o obj-$(CONFIG_MTD_M25P80) += m25p80.o diff --git a/drivers/mtd/devices/at91_dataflash26.c b/drivers/mtd/devices/at91_dataflash26.c deleted file mode 100644 index 64ce37f986f..00000000000 --- a/drivers/mtd/devices/at91_dataflash26.c +++ /dev/null @@ -1,485 +0,0 @@ -/* - * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder) - * This is a largely modified version of at91_dataflash.c that - * supports AT26xxx dataflash chips. The original driver supports - * AT45xxx chips. - * - * Note: This driver was only tested with an AT26F004. It should be - * easy to make it work with other AT26xxx dataflash devices, though. - * - * Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de> - * original Copyright (C) SAN People (Pty) Ltd - * - * 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/config.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/mtd/mtd.h> - -#include <asm/arch/at91_spi.h> - -#define DATAFLASH_MAX_DEVICES 4 /* max number of dataflash devices */ - -#define MANUFACTURER_ID_ATMEL 0x1F - -/* command codes */ - -#define AT26_OP_READ_STATUS 0x05 -#define AT26_OP_READ_DEV_ID 0x9F -#define AT26_OP_ERASE_PAGE_4K 0x20 -#define AT26_OP_READ_ARRAY_FAST 0x0B -#define AT26_OP_SEQUENTIAL_WRITE 0xAF -#define AT26_OP_WRITE_ENABLE 0x06 -#define AT26_OP_WRITE_DISABLE 0x04 -#define AT26_OP_SECTOR_PROTECT 0x36 -#define AT26_OP_SECTOR_UNPROTECT 0x39 - -/* status register bits */ - -#define AT26_STATUS_BUSY 0x01 -#define AT26_STATUS_WRITE_ENABLE 0x02 - -struct dataflash_local -{ - int spi; /* SPI chip-select number */ - unsigned int page_size; /* number of bytes per page */ -}; - - -/* Detected DataFlash devices */ -static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES]; -static int nr_devices = 0; - -/* Allocate a single SPI transfer descriptor. We're assuming that if multiple - SPI transfers occur at the same time, spi_access_bus() will serialize them. - If this is not valid, then either (i) each dataflash 'priv' structure - needs it's own transfer descriptor, (ii) we lock this one, or (iii) use - another mechanism. */ -static struct spi_transfer_list* spi_transfer_desc; - -/* - * Perform a SPI transfer to access the DataFlash device. - */ -static int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len, - char* txnext, int txnext_len, char* rxnext, int rxnext_len) -{ - struct spi_transfer_list* list = spi_transfer_desc; - - list->tx[0] = tx; list->txlen[0] = tx_len; - list->rx[0] = rx; list->rxlen[0] = rx_len; - - list->tx[1] = txnext; list->txlen[1] = txnext_len; - list->rx[1] = rxnext; list->rxlen[1] = rxnext_len; - - list->nr_transfers = nr; - /* Note: spi_transfer() always returns 0, there are no error checks */ - return spi_transfer(list); -} - -/* - * Return the status of the DataFlash device. - */ -static unsigned char at91_dataflash26_status(void) -{ - unsigned char command[2]; - - command[0] = AT26_OP_READ_STATUS; - command[1] = 0; - - do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0); - - return command[1]; -} - -/* - * Poll the DataFlash device until it is READY. - */ -static unsigned char at91_dataflash26_waitready(void) -{ - unsigned char status; - - while (1) { - status = at91_dataflash26_status(); - if (!(status & AT26_STATUS_BUSY)) - return status; - } -} - -/* - * Enable/disable write access - */ - static void at91_dataflash26_write_enable(int enable) -{ - unsigned char cmd[2]; - - DEBUG(MTD_DEBUG_LEVEL3, "write_enable: enable=%i\n", enable); - - if (enable) - cmd[0] = AT26_OP_WRITE_ENABLE; - else - cmd[0] = AT26_OP_WRITE_DISABLE; - cmd[1] = 0; - - do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0); -} - -/* - * Protect/unprotect sector - */ - static void at91_dataflash26_sector_protect(loff_t addr, int protect) -{ - unsigned char cmd[4]; - - DEBUG(MTD_DEBUG_LEVEL3, "sector_protect: addr=0x%06x prot=%d\n", - addr, protect); - - if (protect) - cmd[0] = AT26_OP_SECTOR_PROTECT; - else - cmd[0] = AT26_OP_SECTOR_UNPROTECT; - cmd[1] = (addr & 0x00FF0000) >> 16; - cmd[2] = (addr & 0x0000FF00) >> 8; - cmd[3] = (addr & 0x000000FF); - - do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0); -} - -/* - * Erase blocks of flash. - */ -static int at91_dataflash26_erase(struct mtd_info *mtd, - struct erase_info *instr) -{ - struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; - unsigned char cmd[4]; - - DEBUG(MTD_DEBUG_LEVEL1, "dataflash_erase: addr=0x%06x len=%i\n", - instr->addr, instr->len); - - /* Sanity checks */ - if (priv->page_size != 4096) - return -EINVAL; /* Can't handle other sizes at the moment */ - - if ( ((instr->len % mtd->erasesize) != 0) - || ((instr->len % priv->page_size) != 0) - || ((instr->addr % priv->page_size) != 0) - || ((instr->addr + instr->len) > mtd->size)) - return -EINVAL; - - spi_access_bus(priv->spi); - - while (instr->len > 0) { - at91_dataflash26_write_enable(1); - at91_dataflash26_sector_protect(instr->addr, 0); - at91_dataflash26_write_enable(1); - cmd[0] = AT26_OP_ERASE_PAGE_4K; - cmd[1] = (instr->addr & 0x00FF0000) >> 16; - cmd[2] = (instr->addr & 0x0000FF00) >> 8; - cmd[3] = (instr->addr & 0x000000FF); - - DEBUG(MTD_DEBUG_LEVEL3, "ERASE: (0x%02x) 0x%02x 0x%02x" - "0x%02x\n", - cmd[0], cmd[1], cmd[2], cmd[3]); - - do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0); - at91_dataflash26_waitready(); - - instr->addr += priv->page_size; /* next page */ - instr->len -= priv->page_size; - } - - at91_dataflash26_write_enable(0); - spi_release_bus(priv->spi); - - /* Inform MTD subsystem that erase is complete */ - instr->state = MTD_ERASE_DONE; - if (instr->callback) - instr->callback(instr); - - return 0; -} - -/* - * Read from the DataFlash device. - * from : Start offset in flash device - * len : Number of bytes to read - * retlen : Number of bytes actually read - * buf : Buffer that will receive data - */ -static int at91_dataflash26_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) -{ - struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; - unsigned char cmd[5]; - - DEBUG(MTD_DEBUG_LEVEL1, "dataflash_read: %lli .. %lli\n", - from, from+len); - - *retlen = 0; - - /* Sanity checks */ - if (!len) - return 0; - if (from + len > mtd->size) - return -EINVAL; - - cmd[0] = AT26_OP_READ_ARRAY_FAST; - cmd[1] = (from & 0x00FF0000) >> 16; - cmd[2] = (from & 0x0000FF00) >> 8; - cmd[3] = (from & 0x000000FF); - /* cmd[4] is a "Don't care" byte */ - - DEBUG(MTD_DEBUG_LEVEL3, "READ: (0x%02x) 0x%02x 0x%02x 0x%02x\n", - cmd[0], cmd[1], cmd[2], cmd[3]); - - spi_access_bus(priv->spi); - do_spi_transfer(2, cmd, 5, cmd, 5, buf, len, buf, len); - spi_release_bus(priv->spi); - - *retlen = len; - return 0; -} - -/* - * Write to the DataFlash device. - * to : Start offset in flash device - * len : Number of bytes to write - * retlen : Number of bytes actually written - * buf : Buffer containing the data - */ -static int at91_dataflash26_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; - unsigned int addr, buf_index = 0; - int ret = -EIO, sector, last_sector; - unsigned char status, cmd[5]; - - DEBUG(MTD_DEBUG_LEVEL1, "dataflash_write: %lli .. %lli\n", to, to+len); - - *retlen = 0; - - /* Sanity checks */ - if (!len) - return 0; - if (to + len > mtd->size) - return -EINVAL; - - spi_access_bus(priv->spi); - - addr = to; - last_sector = -1; - - while (buf_index < len) { - sector = addr / priv->page_size; - /* Write first byte if a new sector begins */ - if (sector != last_sector) { - at91_dataflash26_write_enable(1); - at91_dataflash26_sector_protect(addr, 0); - at91_dataflash26_write_enable(1); - - /* Program first byte of a new sector */ - cmd[0] = AT26_OP_SEQUENTIAL_WRITE; - cmd[1] = (addr & 0x00FF0000) >> 16; - cmd[2] = (addr & 0x0000FF00) >> 8; - cmd[3] = (addr & 0x000000FF); - cmd[4] = buf[buf_index++]; - do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0); - status = at91_dataflash26_waitready(); - addr++; - /* On write errors, the chip resets the write enable - flag. This also happens after the last byte of a - sector is successfully programmed. */ - if ( ( !(status & AT26_STATUS_WRITE_ENABLE)) - && ((addr % priv->page_size) != 0) ) { - DEBUG(MTD_DEBUG_LEVEL1, - "write error1: addr=0x%06x, " - "status=0x%02x\n", addr, status); - goto write_err; - } - (*retlen)++; - last_sector = sector; - } - - /* Write subsequent bytes in the same sector */ - cmd[0] = AT26_OP_SEQUENTIAL_WRITE; - cmd[1] = buf[buf_index++]; - do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0); - status = at91_dataflash26_waitready(); - addr++; - - if ( ( !(status & AT26_STATUS_WRITE_ENABLE)) - && ((addr % priv->page_size) != 0) ) { - DEBUG(MTD_DEBUG_LEVEL1, "write error2: addr=0x%06x, " - "status=0x%02x\n", addr, status); - goto write_err; - } - - (*retlen)++; - } - - ret = 0; - at91_dataflash26_write_enable(0); -write_err: - spi_release_bus(priv->spi); - return ret; -} - -/* - * Initialize and register DataFlash device with MTD subsystem. - */ -static int __init add_dataflash(int channel, char *name, int nr_pages, - int pagesize) -{ - struct mtd_info *device; - struct dataflash_local *priv; - - if (nr_devices >= DATAFLASH_MAX_DEVICES) { - printk(KERN_ERR "at91_dataflash26: Too many devices " - "detected\n"); - return 0; - } - - device = kzalloc(sizeof(struct mtd_info) + strlen(name) + 8, - GFP_KERNEL); - if (!device) - return -ENOMEM; - - device->name = (char *)&device[1]; - sprintf(device->name, "%s.spi%d", name, channel); - device->size = nr_pages * pagesize; - device->erasesize = pagesize; - device->owner = THIS_MODULE; - device->type = MTD_DATAFLASH; - device->flags = MTD_CAP_NORFLASH; - device->erase = at91_dataflash26_erase; - device->read = at91_dataflash26_read; - device->write = at91_dataflash26_write; - - priv = (struct dataflash_local *)kzalloc(sizeof(struct dataflash_local), - GFP_KERNEL); - if (!priv) { - kfree(device); - return -ENOMEM; - } - - priv->spi = channel; - priv->page_size = pagesize; - device->priv = priv; - - mtd_devices[nr_devices] = device; - nr_devices++; - printk(KERN_INFO "at91_dataflash26: %s detected [spi%i] (%i bytes)\n", - name, channel, device->size); - - return add_mtd_device(device); -} - -/* - * Detect and initialize DataFlash device connected to specified SPI channel. - * - */ - -struct dataflash26_types { - unsigned char id0; - unsigned char id1; - char *name; - int pagesize; - int nr_pages; -}; - -struct dataflash26_types df26_types[] = { - { - .id0 = 0x04, - .id1 = 0x00, - .name = "AT26F004", - .pagesize = 4096, - .nr_pages = 128, - }, - { - .id0 = 0x45, - .id1 = 0x01, - .name = "AT26DF081A", /* Not tested ! */ - .pagesize = 4096, - .nr_pages = 256, - }, -}; - -static int __init at91_dataflash26_detect(int channel) -{ - unsigned char status, cmd[5]; - int i; - - spi_access_bus(channel); - status = at91_dataflash26_status(); - - if (status == 0 || status == 0xff) { - printk(KERN_ERR "at91_dataflash26_detect: status error %d\n", - status); - spi_release_bus(channel); - return -ENODEV; - } - - cmd[0] = AT26_OP_READ_DEV_ID; - do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0); - spi_release_bus(channel); - - if (cmd[1] != MANUFACTURER_ID_ATMEL) - return -ENODEV; - - for (i = 0; i < ARRAY_SIZE(df26_types); i++) { - if ( cmd[2] == df26_types[i].id0 - && cmd[3] == df26_types[i].id1) - return add_dataflash(channel, - df26_types[i].name, - df26_types[i].nr_pages, - df26_types[i].pagesize); - } - - printk(KERN_ERR "at91_dataflash26_detect: Unsupported device " - "(0x%02x/0x%02x)\n", cmd[2], cmd[3]); - return -ENODEV; -} - -static int __init at91_dataflash26_init(void) -{ - spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list), - GFP_KERNEL); - if (!spi_transfer_desc) - return -ENOMEM; - - /* DataFlash (SPI chip select 0) */ - at91_dataflash26_detect(0); - -#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD - /* DataFlash card (SPI chip select 3) */ - at91_dataflash26_detect(3); -#endif - return 0; -} - -static void __exit at91_dataflash26_exit(void) -{ - int i; - - for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) { - if (mtd_devices[i]) { - del_mtd_device(mtd_devices[i]); - kfree(mtd_devices[i]->priv); - kfree(mtd_devices[i]); - } - } - nr_devices = 0; - kfree(spi_transfer_desc); -} - -module_init(at91_dataflash26_init); -module_exit(at91_dataflash26_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Hans J. Koch"); -MODULE_DESCRIPTION("DataFlash AT26xxx driver for Atmel AT91RM9200"); diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index 54aa7590764..d8cc94ec4e5 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c @@ -81,9 +81,7 @@ static unsigned long __initdata doc_locations[] = { #endif /* CONFIG_MTD_DOCPROBE_HIGH */ #elif defined(__PPC__) 0xe4000000, -#elif defined(CONFIG_MOMENCO_OCELOT_G) - 0xff000000, -##else +#else #warning Unknown architecture for DiskOnChip. No default probe locations defined #endif 0xffffffff }; diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 78c2511ae9e..98df5bcc02f 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -1,5 +1,5 @@ /* - * MTD SPI driver for ST M25Pxx flash chips + * MTD SPI driver for ST M25Pxx (and similar) serial flash chips * * Author: Mike Lavender, mike@steroidmicros.com * @@ -19,33 +19,32 @@ #include <linux/module.h> #include <linux/device.h> #include <linux/interrupt.h> -#include <linux/interrupt.h> +#include <linux/mutex.h> + #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> + #include <linux/spi/spi.h> #include <linux/spi/flash.h> -#include <asm/semaphore.h> - - -/* NOTE: AT 25F and SST 25LF series are very similar, - * but commands for sector erase and chip id differ... - */ #define FLASH_PAGESIZE 256 /* Flash opcodes. */ -#define OPCODE_WREN 6 /* Write enable */ -#define OPCODE_RDSR 5 /* Read status register */ -#define OPCODE_READ 3 /* Read data bytes */ -#define OPCODE_PP 2 /* Page program */ -#define OPCODE_SE 0xd8 /* Sector erase */ -#define OPCODE_RES 0xab /* Read Electronic Signature */ +#define OPCODE_WREN 0x06 /* Write enable */ +#define OPCODE_RDSR 0x05 /* Read status register */ +#define OPCODE_READ 0x03 /* Read data bytes (low frequency) */ +#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ +#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ +#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ +#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */ +#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ #define OPCODE_RDID 0x9f /* Read JEDEC ID */ /* Status Register bits. */ #define SR_WIP 1 /* Write in progress */ #define SR_WEL 2 /* Write enable latch */ +/* meaning of other SR_* bits may differ between vendors */ #define SR_BP0 4 /* Block protect 0 */ #define SR_BP1 8 /* Block protect 1 */ #define SR_BP2 0x10 /* Block protect 2 */ @@ -65,9 +64,10 @@ struct m25p { struct spi_device *spi; - struct semaphore lock; + struct mutex lock; struct mtd_info mtd; - unsigned partitioned; + unsigned partitioned:1; + u8 erase_opcode; u8 command[4]; }; @@ -150,8 +150,9 @@ static int wait_till_ready(struct m25p *flash) */ static int erase_sector(struct m25p *flash, u32 offset) { - DEBUG(MTD_DEBUG_LEVEL3, "%s: %s at 0x%08x\n", flash->spi->dev.bus_id, - __FUNCTION__, offset); + DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB at 0x%08x\n", + flash->spi->dev.bus_id, __FUNCTION__, + flash->mtd.erasesize / 1024, offset); /* Wait until finished previous write command. */ if (wait_till_ready(flash)) @@ -161,7 +162,7 @@ static int erase_sector(struct m25p *flash, u32 offset) write_enable(flash); /* Set up command buffer. */ - flash->command[0] = OPCODE_SE; + flash->command[0] = flash->erase_opcode; flash->command[1] = offset >> 16; flash->command[2] = offset >> 8; flash->command[3] = offset; @@ -201,13 +202,17 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) addr = instr->addr; len = instr->len; - down(&flash->lock); + mutex_lock(&flash->lock); + + /* REVISIT in some cases we could speed up erasing large regions + * by using OPCODE_SE instead of OPCODE_BE_4K + */ /* now erase those sectors */ while (len) { if (erase_sector(flash, addr)) { instr->state = MTD_ERASE_FAILED; - up(&flash->lock); + mutex_unlock(&flash->lock); return -EIO; } @@ -215,7 +220,7 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) len -= mtd->erasesize; } - up(&flash->lock); + mutex_unlock(&flash->lock); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); @@ -260,16 +265,19 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, if (retlen) *retlen = 0; - down(&flash->lock); + mutex_lock(&flash->lock); /* Wait till previous write/erase is done. */ if (wait_till_ready(flash)) { /* REVISIT status return?? */ - up(&flash->lock); + mutex_unlock(&flash->lock); return 1; } - /* NOTE: OPCODE_FAST_READ (if available) is faster... */ + /* FIXME switch to OPCODE_FAST_READ. It's required for higher + * clocks; and at this writing, every chip this driver handles + * supports that opcode. + */ /* Set up the write data buffer. */ flash->command[0] = OPCODE_READ; @@ -281,7 +289,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, *retlen = m.actual_length - sizeof(flash->command); - up(&flash->lock); + mutex_unlock(&flash->lock); return 0; } @@ -323,7 +331,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, t[1].tx_buf = buf; spi_message_add_tail(&t[1], &m); - down(&flash->lock); + mutex_lock(&flash->lock); /* Wait until finished previous write command. */ if (wait_till_ready(flash)) @@ -381,10 +389,10 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, if (retlen) *retlen += m.actual_length - sizeof(flash->command); - } - } + } + } - up(&flash->lock); + mutex_unlock(&flash->lock); return 0; } @@ -398,24 +406,118 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, struct flash_info { char *name; - u8 id; - u16 jedec_id; + + /* JEDEC id zero means "no ID" (most older chips); otherwise it has + * a high byte of zero plus three data bytes: the manufacturer id, + * then a two byte device id. + */ + u32 jedec_id; + + /* The size listed here is what works with OPCODE_SE, which isn't + * necessarily called a "sector" by the vendor. + */ unsigned sector_size; - unsigned n_sectors; + u16 n_sectors; + + u16 flags; +#define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */ }; + +/* NOTE: double check command sets and memory organization when you add + * more flash chips. This current list focusses on newer chips, which + * have been converging on command sets which including JEDEC ID. + */ static struct flash_info __devinitdata m25p_data [] = { - /* REVISIT: fill in JEDEC ids, for parts that have them */ - { "m25p05", 0x05, 0x2010, 32 * 1024, 2 }, - { "m25p10", 0x10, 0x2011, 32 * 1024, 4 }, - { "m25p20", 0x11, 0x2012, 64 * 1024, 4 }, - { "m25p40", 0x12, 0x2013, 64 * 1024, 8 }, - { "m25p80", 0x13, 0x0000, 64 * 1024, 16 }, - { "m25p16", 0x14, 0x2015, 64 * 1024, 32 }, - { "m25p32", 0x15, 0x2016, 64 * 1024, 64 }, - { "m25p64", 0x16, 0x2017, 64 * 1024, 128 }, + + /* Atmel -- some are (confusingly) marketed as "DataFlash" */ + { "at25fs010", 0x1f6601, 32 * 1024, 4, SECT_4K, }, + { "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, }, + + { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, }, + + { "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, }, + { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, }, + { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, }, + { "at26df321", 0x1f4701, 64 * 1024, 64, SECT_4K, }, + + /* Spansion -- single (large) sector size only, at least + * for the chips listed here (without boot sectors). + */ + { "s25sl004a", 0x010212, 64 * 1024, 8, }, + { "s25sl008a", 0x010213, 64 * 1024, 16, }, + { "s25sl016a", 0x010214, 64 * 1024, 32, }, + { "s25sl032a", 0x010215, 64 * 1024, 64, }, + { "s25sl064a", 0x010216, 64 * 1024, 128, }, + + /* SST -- large erase sizes are "overlays", "sectors" are 4K */ + { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, }, + { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, }, + { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, }, + { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, }, + + /* ST Microelectronics -- newer production may have feature updates */ + { "m25p05", 0x202010, 32 * 1024, 2, }, + { "m25p10", 0x202011, 32 * 1024, 4, }, + { "m25p20", 0x202012, 64 * 1024, 4, }, + { "m25p40", 0x202013, 64 * 1024, 8, }, + { "m25p80", 0, 64 * 1024, 16, }, + { "m25p16", 0x202015, 64 * 1024, 32, }, + { "m25p32", 0x202016, 64 * 1024, 64, }, + { "m25p64", 0x202017, 64 * 1024, 128, }, + { "m25p128", 0x202018, 256 * 1024, 64, }, + + { "m45pe80", 0x204014, 64 * 1024, 16, }, + { "m45pe16", 0x204015, 64 * 1024, 32, }, + + { "m25pe80", 0x208014, 64 * 1024, 16, }, + { "m25pe16", 0x208015, 64 * 1024, 32, SECT_4K, }, + + /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ + { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, }, + { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, }, + { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, }, + { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, }, + { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, }, + { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, }, + { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, }, }; +static struct flash_info *__devinit jedec_probe(struct spi_device *spi) +{ + int tmp; + u8 code = OPCODE_RDID; + u8 id[3]; + u32 jedec; + struct flash_info *info; + + /* JEDEC also defines an optional "extended device information" + * string for after vendor-specific data, after the three bytes + * we use here. Supporting some chips might require using it. + */ + tmp = spi_write_then_read(spi, &code, 1, id, 3); + if (tmp < 0) { + DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", + spi->dev.bus_id, tmp); + return NULL; + } + jedec = id[0]; + jedec = jedec << 8; + jedec |= id[1]; + jedec = jedec << 8; + jedec |= id[2]; + + for (tmp = 0, info = m25p_data; + tmp < ARRAY_SIZE(m25p_data); + tmp++, info++) { + if (info->jedec_id == jedec) + return info; + } + dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); + return NULL; +} + + /* * board specific setup should have ensured the SPI clock used here * matches what the READ command supports, at least until this driver @@ -429,37 +531,51 @@ static int __devinit m25p_probe(struct spi_device *spi) unsigned i; /* Platform data helps sort out which chip type we have, as - * well as how this board partitions it. + * well as how this board partitions it. If we don't have + * a chip ID, try the JEDEC id commands; they'll work for most + * newer chips, even if we don't recognize the particular chip. */ data = spi->dev.platform_data; - if (!data || !data->type) { - /* FIXME some chips can identify themselves with RES - * or JEDEC get-id commands. Try them ... - */ - DEBUG(MTD_DEBUG_LEVEL1, "%s: no chip id\n", - spi->dev.bus_id); - return -ENODEV; - } + if (data && data->type) { + for (i = 0, info = m25p_data; + i < ARRAY_SIZE(m25p_data); + i++, info++) { + if (strcmp(data->type, info->name) == 0) + break; + } - for (i = 0, info = m25p_data; i < ARRAY_SIZE(m25p_data); i++, info++) { - if (strcmp(data->type, info->name) == 0) - break; - } - if (i == ARRAY_SIZE(m25p_data)) { - DEBUG(MTD_DEBUG_LEVEL1, "%s: unrecognized id %s\n", - spi->dev.bus_id, data->type); + /* unrecognized chip? */ + if (i == ARRAY_SIZE(m25p_data)) { + DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n", + spi->dev.bus_id, data->type); + info = NULL; + + /* recognized; is that chip really what's there? */ + } else if (info->jedec_id) { + struct flash_info *chip = jedec_probe(spi); + + if (!chip || chip != info) { + dev_warn(&spi->dev, "found %s, expected %s\n", + chip ? chip->name : "UNKNOWN", + info->name); + info = NULL; + } + } + } else + info = jedec_probe(spi); + + if (!info) return -ENODEV; - } flash = kzalloc(sizeof *flash, GFP_KERNEL); if (!flash) return -ENOMEM; flash->spi = spi; - init_MUTEX(&flash->lock); + mutex_init(&flash->lock); dev_set_drvdata(&spi->dev, flash); - if (data->name) + if (data && data->name) flash->mtd.name = data->name; else flash->mtd.name = spi->dev.bus_id; @@ -468,17 +584,25 @@ static int __devinit m25p_probe(struct spi_device *spi) flash->mtd.writesize = 1; flash->mtd.flags = MTD_CAP_NORFLASH; flash->mtd.size = info->sector_size * info->n_sectors; - flash->mtd.erasesize = info->sector_size; flash->mtd.erase = m25p80_erase; flash->mtd.read = m25p80_read; flash->mtd.write = m25p80_write; + /* prefer "small sector" erase if possible */ + if (info->flags & SECT_4K) { + flash->erase_opcode = OPCODE_BE_4K; + flash->mtd.erasesize = 4096; + } else { + flash->erase_opcode = OPCODE_SE; + flash->mtd.erasesize = info->sector_size; + } + dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name, flash->mtd.size / 1024); DEBUG(MTD_DEBUG_LEVEL2, - "mtd .name = %s, .size = 0x%.8x (%uM) " - ".erasesize = 0x%.8x (%uK) .numeraseregions = %d\n", + "mtd .name = %s, .size = 0x%.8x (%uMiB) " + ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", flash->mtd.name, flash->mtd.size, flash->mtd.size / (1024*1024), flash->mtd.erasesize, flash->mtd.erasesize / 1024, @@ -488,7 +612,7 @@ static int __devinit m25p_probe(struct spi_device *spi) for (i = 0; i < flash->mtd.numeraseregions; i++) DEBUG(MTD_DEBUG_LEVEL2, "mtd.eraseregions[%d] = { .offset = 0x%.8x, " - ".erasesize = 0x%.8x (%uK), " + ".erasesize = 0x%.8x (%uKiB), " ".numblocks = %d }\n", i, flash->mtd.eraseregions[i].offset, flash->mtd.eraseregions[i].erasesize, @@ -516,14 +640,14 @@ static int __devinit m25p_probe(struct spi_device *spi) } if (nr_parts > 0) { - for (i = 0; i < data->nr_parts; i++) { + for (i = 0; i < nr_parts; i++) { DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " "{.name = %s, .offset = 0x%.8x, " - ".size = 0x%.8x (%uK) }\n", - i, data->parts[i].name, - data->parts[i].offset, - data->parts[i].size, - data->parts[i].size / 1024); + ".size = 0x%.8x (%uKiB) }\n", + i, parts[i].name, + parts[i].offset, + parts[i].size, + parts[i].size / 1024); } flash->partitioned = 1; return add_mtd_partitions(&flash->mtd, parts, nr_parts); @@ -560,6 +684,11 @@ static struct spi_driver m25p80_driver = { }, .probe = m25p_probe, .remove = __devexit_p(m25p_remove), + + /* REVISIT: many of these chips have deep power-down modes, which + * should clearly be entered on suspend() to minimize power use. + * And also when they're otherwise idle... + */ }; diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index a987e917f4e..a5ed6d232c3 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/mutex.h> #include <linux/spi/spi.h> #include <linux/spi/flash.h> @@ -89,7 +90,7 @@ struct dataflash { unsigned short page_offset; /* offset in flash address */ unsigned int page_size; /* of bytes per page */ - struct semaphore lock; + struct mutex lock; struct spi_device *spi; struct mtd_info mtd; @@ -167,7 +168,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) x.len = 4; spi_message_add_tail(&x, &msg); - down(&priv->lock); + mutex_lock(&priv->lock); while (instr->len > 0) { unsigned int pageaddr; int status; @@ -210,7 +211,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) instr->len -= priv->page_size; } } - up(&priv->lock); + mutex_unlock(&priv->lock); /* Inform MTD subsystem that erase is complete */ instr->state = MTD_ERASE_DONE; @@ -266,7 +267,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, x[1].len = len; spi_message_add_tail(&x[1], &msg); - down(&priv->lock); + mutex_lock(&priv->lock); /* Continuous read, max clock = f(car) which may be less than * the peak rate available. Some chips support commands with @@ -279,7 +280,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, /* plus 4 "don't care" bytes */ status = spi_sync(priv->spi, &msg); - up(&priv->lock); + mutex_unlock(&priv->lock); if (status >= 0) { *retlen = msg.actual_length - 8; @@ -336,7 +337,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, else writelen = len; - down(&priv->lock); + mutex_lock(&priv->lock); while (remaining > 0) { DEBUG(MTD_DEBUG_LEVEL3, "write @ %i:%i len=%i\n", pageaddr, offset, writelen); @@ -441,7 +442,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, else writelen = remaining; } - up(&priv->lock); + mutex_unlock(&priv->lock); return status; } @@ -463,7 +464,7 @@ add_dataflash(struct spi_device *spi, char *name, if (!priv) return -ENOMEM; - init_MUTEX(&priv->lock); + mutex_init(&priv->lock); priv->spi = spi; priv->page_size = pagesize; priv->page_offset = pageoffset; diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index e8f686f7a35..7060a0895ce 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c @@ -30,8 +30,8 @@ * * Notes: * Due to what I assume is more buggy SROM, the 64M PMC551 I - * have available claims that all 4 of it's DRAM banks have 64M - * of ram configured (making a grand total of 256M onboard). + * have available claims that all 4 of its DRAM banks have 64MiB + * of ram configured (making a grand total of 256MiB onboard). * This is slightly annoying since the BAR0 size reflects the * aperture size, not the dram size, and the V370PDC supplies no * other method for memory size discovery. This problem is @@ -70,7 +70,7 @@ * made the memory unusable, added a fix to code to touch up * the DRAM some. * - * Bugs/FIXME's: + * Bugs/FIXMEs: * * MUST fix the init function to not spin on a register * waiting for it to set .. this does not safely handle busted * devices that never reset the register correctly which will @@ -562,10 +562,10 @@ static u32 fixup_pmc551(struct pci_dev *dev) /* * Some screen fun */ - printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at " + printk(KERN_DEBUG "pmc551: %d%sB (0x%x) of %sprefetchable memory at " "0x%llx\n", (size < 1024) ? size : (size < 1048576) ? size >> 10 : size >> 20, - (size < 1024) ? 'B' : (size < 1048576) ? 'K' : 'M', size, + (size < 1024) ? "" : (size < 1048576) ? "Ki" : "Mi", size, ((dcmd & (0x1 << 3)) == 0) ? "non-" : "", (unsigned long long)pci_resource_start(dev, 0)); @@ -649,14 +649,10 @@ MODULE_DESCRIPTION(PMC551_VERSION); * Stuff these outside the ifdef so as to not bust compiled in driver support */ static int msize = 0; -#if defined(CONFIG_MTD_PMC551_APERTURE_SIZE) -static int asize = CONFIG_MTD_PMC551_APERTURE_SIZE; -#else static int asize = 0; -#endif module_param(msize, int, 0); -MODULE_PARM_DESC(msize, "memory size in Megabytes [1 - 1024]"); +MODULE_PARM_DESC(msize, "memory size in MiB [1 - 1024]"); module_param(asize, int, 0); MODULE_PARM_DESC(asize, "aperture size, must be <= memsize [1-1024]"); @@ -799,8 +795,7 @@ static int __init init_pmc551(void) mtd->owner = THIS_MODULE; if (add_mtd_device(mtd)) { - printk(KERN_NOTICE "pmc551: Failed to register new " - "device\n"); + printk(KERN_NOTICE "pmc551: Failed to register new device\n"); pci_iounmap(PCI_Device, priv->start); kfree(mtd->priv); kfree(mtd); @@ -811,13 +806,13 @@ static int __init init_pmc551(void) pci_dev_get(PCI_Device); printk(KERN_NOTICE "Registered pmc551 memory device.\n"); - printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n", + printk(KERN_NOTICE "Mapped %dMiB of memory from 0x%p to 0x%p\n", priv->asize >> 20, priv->start, priv->start + priv->asize); - printk(KERN_NOTICE "Total memory is %d%c\n", + printk(KERN_NOTICE "Total memory is %d%sB\n", (length < 1024) ? length : (length < 1048576) ? length >> 10 : length >> 20, - (length < 1024) ? 'B' : (length < 1048576) ? 'K' : 'M'); + (length < 1024) ? "" : (length < 1048576) ? "Ki" : "Mi"); priv->nextpmc551 = pmc551list; pmc551list = mtd; found++; @@ -850,7 +845,7 @@ static void __exit cleanup_pmc551(void) pmc551list = priv->nextpmc551; if (priv->start) { - printk(KERN_DEBUG "pmc551: unmapping %dM starting at " + printk(KERN_DEBUG "pmc551: unmapping %dMiB starting at " "0x%p\n", priv->asize >> 20, priv->start); pci_iounmap(priv->dev, priv->start); } diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index ecac0e438f4..b8917beeb65 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -580,14 +580,13 @@ int INFTL_mount(struct INFTLrecord *s) logical_block = block = BLOCK_NIL; /* Temporary buffer to store ANAC numbers. */ - ANACtable = kmalloc(s->nb_blocks * sizeof(u8), GFP_KERNEL); + ANACtable = kcalloc(s->nb_blocks, sizeof(u8), GFP_KERNEL); if (!ANACtable) { printk(KERN_WARNING "INFTL: allocation of ANACtable " "failed (%zd bytes)\n", s->nb_blocks * sizeof(u8)); return -ENOMEM; } - memset(ANACtable, 0, s->nb_blocks); /* * First pass is to explore each physical unit, and construct the diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 6cd132c7518..2a2a125b0c7 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -163,20 +163,12 @@ config MTD_SBC_GXX More info at <http://www.arcomcontrols.com/products/icp/pc104/processors/SBC_GX1.htm>. -config MTD_LUBBOCK - tristate "CFI Flash device mapped on Intel Lubbock XScale eval board" - depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS - help - This provides a driver for the on-board flash of the Intel - 'Lubbock' XScale evaluation board. - -config MTD_MAINSTONE - tristate "CFI Flash device mapped on Intel Mainstone XScale eval board" - depends on MACH_MAINSTONE && MTD_CFI_INTELEXT +config MTD_PXA2XX + tristate "CFI Flash device mapped on Intel XScale PXA2xx based boards" + depends on (PXA25x || PXA27x) && MTD_CFI_INTELEXT select MTD_PARTITIONS help - This provides a driver for the on-board flash of the Intel - 'Mainstone PXA27x evaluation board. + This provides a driver for the NOR flash attached to a PXA2xx chip. config MTD_OCTAGON tristate "JEDEC Flash device mapped on Octagon 5066 SBC" @@ -354,7 +346,7 @@ config MTD_CFI_FLAGADM config MTD_WALNUT tristate "Flash device mapped on IBM 405GP Walnut" - depends on MTD_JEDECPROBE && WALNUT + depends on MTD_JEDECPROBE && WALNUT && !PPC_MERGE help This enables access routines for the flash chips on the IBM 405GP Walnut board. If you have one of these boards and would like to @@ -370,7 +362,7 @@ config MTD_EBONY config MTD_OCOTEA tristate "Flash devices mapped on IBM 440GX Ocotea" - depends on MTD_CFI && OCOTEA + depends on MTD_CFI && OCOTEA && !PPC_MERGE help This enables access routines for the flash chips on the IBM 440GX Ocotea board. If you have one of these boards and would like to @@ -384,22 +376,6 @@ config MTD_REDWOOD Redwood board. If you have one of these boards and would like to use the flash chips on it, say 'Y'. -config MTD_TQM834x - tristate "Flash device mapped on TQ Components TQM834x Boards" - depends on MTD_CFI && TQM834x - help - This enables access routines for the flash chips on the - TQ Components TQM834x boards. If you have one of these boards - and would like to use the flash chips on it, say 'Y'. - -config MTD_OCELOT - tristate "Momenco Ocelot boot flash device" - depends on MOMENCO_OCELOT - help - This enables access routines for the boot flash device and for the - NVRAM on the Momenco Ocelot board. If you have one of these boards - and would like access to either of these, say 'Y'. - config MTD_SOLUTIONENGINE tristate "CFI Flash device mapped on Hitachi SolutionEngine" depends on SUPERH && MTD_CFI && MTD_REDBOOT_PARTS @@ -605,6 +581,13 @@ config MTD_SHARP_SL help This enables access to the flash chip on the Sharp SL Series of PDAs. +config MTD_INTEL_VR_NOR + tristate "NOR flash on Intel Vermilion Range Expansion Bus CS0" + depends on PCI + help + Map driver for a NOR flash bank located on the Expansion Bus of the + Intel Vermilion Range chipset. + config MTD_PLATRAM tristate "Map driver for platform device RAM (mtd-ram)" select MTD_RAM diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 970b189271a..316382a1401 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -20,8 +20,7 @@ obj-$(CONFIG_MTD_ESB2ROM) += esb2rom.o obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o -obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o -obj-$(CONFIG_MTD_MAINSTONE) += mainstone-flash.o +obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o obj-$(CONFIG_MTD_MBX860) += mbx860.o obj-$(CONFIG_MTD_CEIVA) += ceiva.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o @@ -43,7 +42,6 @@ obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o obj-$(CONFIG_MTD_VMAX) += vmax301.o obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o -obj-$(CONFIG_MTD_OCELOT) += ocelot.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o obj-$(CONFIG_MTD_PCI) += pci.o obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o @@ -70,4 +68,4 @@ obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o -obj-$(CONFIG_MTD_TQM834x) += tqm834x.o +obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c index 84fbe0e8c47..82811bcb043 100644 --- a/drivers/mtd/maps/alchemy-flash.c +++ b/drivers/mtd/maps/alchemy-flash.c @@ -75,13 +75,6 @@ #define BOARD_FLASH_WIDTH 2 /* 16-bits */ #endif -#ifdef CONFIG_MIPS_HYDROGEN3 -#define BOARD_MAP_NAME "Hydrogen3 Flash" -#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ -#define BOARD_FLASH_WIDTH 4 /* 32-bits */ -#define USE_LOCAL_ACCESSORS /* why? */ -#endif - #ifdef CONFIG_MIPS_BOSPORUS #define BOARD_MAP_NAME "Bosporus Flash" #define BOARD_FLASH_SIZE 0x01000000 /* 16MB */ @@ -130,13 +123,6 @@ int __init alchemy_mtd_init(void) window_addr = 0x20000000 - BOARD_FLASH_SIZE; window_size = BOARD_FLASH_SIZE; -#ifdef CONFIG_MIPS_MIRAGE_WHY - /* Boot ROM flash bank only; no user bank */ - window_addr = 0x1C000000; - window_size = 0x04000000; - /* USERFS from 0x1C00 0000 to 0x1FC00000 */ - alchemy_partitions[0].size = 0x03C00000; -#endif /* * Static partition definition selection diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c new file mode 100644 index 00000000000..1e7814ae212 --- /dev/null +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -0,0 +1,298 @@ +/* + * drivers/mtd/maps/intel_vr_nor.c + * + * An MTD map driver for a NOR flash bank on the Expansion Bus of the Intel + * Vermilion Range chipset. + * + * The Vermilion Range Expansion Bus supports four chip selects, each of which + * has 64MiB of address space. The 2nd BAR of the Expansion Bus PCI Device + * is a 256MiB memory region containing the address spaces for all four of the + * chip selects, with start addresses hardcoded on 64MiB boundaries. + * + * This map driver only supports NOR flash on chip select 0. The buswidth + * (either 8 bits or 16 bits) is determined by reading the Expansion Bus Timing + * and Control Register for Chip Select 0 (EXP_TIMING_CS0). This driver does + * not modify the value in the EXP_TIMING_CS0 register except to enable writing + * and disable boot acceleration. The timing parameters in the register are + * assumed to have been properly initialized by the BIOS. The reset default + * timing parameters are maximally conservative (slow), so access to the flash + * will be slower than it should be if the BIOS has not initialized the timing + * parameters. + * + * Author: Andy Lowe <alowe@mvista.com> + * + * 2006 (c) MontaVista Software, Inc. 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/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/cfi.h> +#include <linux/mtd/flashchip.h> + +#define DRV_NAME "vr_nor" + +struct vr_nor_mtd { + void __iomem *csr_base; + struct map_info map; + struct mtd_info *info; + int nr_parts; + struct pci_dev *dev; +}; + +/* Expansion Bus Configuration and Status Registers are in BAR 0 */ +#define EXP_CSR_MBAR 0 +/* Expansion Bus Memory Window is BAR 1 */ +#define EXP_WIN_MBAR 1 +/* Maximum address space for Chip Select 0 is 64MiB */ +#define CS0_SIZE 0x04000000 +/* Chip Select 0 is at offset 0 in the Memory Window */ +#define CS0_START 0x0 +/* Chip Select 0 Timing Register is at offset 0 in CSR */ +#define EXP_TIMING_CS0 0x00 +#define TIMING_CS_EN (1 << 31) /* Chip Select Enable */ +#define TIMING_BOOT_ACCEL_DIS (1 << 8) /* Boot Acceleration Disable */ +#define TIMING_WR_EN (1 << 1) /* Write Enable */ +#define TIMING_BYTE_EN (1 << 0) /* 8-bit vs 16-bit bus */ +#define TIMING_MASK 0x3FFF0000 + +static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p) +{ + if (p->nr_parts > 0) { +#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE) + del_mtd_partitions(p->info); +#endif + } else + del_mtd_device(p->info); +} + +static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p) +{ + int err = 0; +#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE) + struct mtd_partition *parts; + static const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + + /* register the flash bank */ +#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE) + /* partition the flash bank */ + p->nr_parts = parse_mtd_partitions(p->info, part_probes, &parts, 0); + if (p->nr_parts > 0) + err = add_mtd_partitions(p->info, parts, p->nr_parts); +#endif + if (p->nr_parts <= 0) + err = add_mtd_device(p->info); + + return err; +} + +static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p) +{ + map_destroy(p->info); +} + +static int __devinit vr_nor_mtd_setup(struct vr_nor_mtd *p) +{ + static const char *probe_types[] = + { "cfi_probe", "jedec_probe", NULL }; + const char **type; + + for (type = probe_types; !p->info && *type; type++) + p->info = do_map_probe(*type, &p->map); + if (!p->info) + return -ENODEV; + + p->info->owner = THIS_MODULE; + + return 0; +} + +static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p) +{ + unsigned int exp_timing_cs0; + + /* write-protect the flash bank */ + exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0); + exp_timing_cs0 &= ~TIMING_WR_EN; + writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0); + + /* unmap the flash window */ + iounmap(p->map.virt); + + /* unmap the csr window */ + iounmap(p->csr_base); +} + +/* + * Initialize the map_info structure and map the flash. + * Returns 0 on success, nonzero otherwise. + */ +static int __devinit vr_nor_init_maps(struct vr_nor_mtd *p) +{ + unsigned long csr_phys, csr_len; + unsigned long win_phys, win_len; + unsigned int exp_timing_cs0; + int err; + + csr_phys = pci_resource_start(p->dev, EXP_CSR_MBAR); + csr_len = pci_resource_len(p->dev, EXP_CSR_MBAR); + win_phys = pci_resource_start(p->dev, EXP_WIN_MBAR); + win_len = pci_resource_len(p->dev, EXP_WIN_MBAR); + + if (!csr_phys || !csr_len || !win_phys || !win_len) + return -ENODEV; + + if (win_len < (CS0_START + CS0_SIZE)) + return -ENXIO; + + p->csr_base = ioremap_nocache(csr_phys, csr_len); + if (!p->csr_base) + return -ENOMEM; + + exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0); + if (!(exp_timing_cs0 & TIMING_CS_EN)) { + dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 " + "is disabled.\n"); + err = -ENODEV; + goto release; + } + if ((exp_timing_cs0 & TIMING_MASK) == TIMING_MASK) { + dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 " + "is configured for maximally slow access times.\n"); + } + p->map.name = DRV_NAME; + p->map.bankwidth = (exp_timing_cs0 & TIMING_BYTE_EN) ? 1 : 2; + p->map.phys = win_phys + CS0_START; + p->map.size = CS0_SIZE; + p->map.virt = ioremap_nocache(p->map.phys, p->map.size); + if (!p->map.virt) { + err = -ENOMEM; + goto release; + } + simple_map_init(&p->map); + + /* Enable writes to flash bank */ + exp_timing_cs0 |= TIMING_BOOT_ACCEL_DIS | TIMING_WR_EN; + writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0); + + return 0; + + release: + iounmap(p->csr_base); + return err; +} + +static struct pci_device_id vr_nor_pci_ids[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x500D)}, + {0,} +}; + +static void __devexit vr_nor_pci_remove(struct pci_dev *dev) +{ + struct vr_nor_mtd *p = pci_get_drvdata(dev); + + pci_set_drvdata(dev, NULL); + vr_nor_destroy_partitions(p); + vr_nor_destroy_mtd_setup(p); + vr_nor_destroy_maps(p); + kfree(p); + pci_release_regions(dev); + pci_disable_device(dev); +} + +static int __devinit +vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct vr_nor_mtd *p = NULL; + unsigned int exp_timing_cs0; + int err; + + err = pci_enable_device(dev); + if (err) + goto out; + + err = pci_request_regions(dev, DRV_NAME); + if (err) + goto disable_dev; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + err = -ENOMEM; + if (!p) + goto release; + + p->dev = dev; + + err = vr_nor_init_maps(p); + if (err) + goto release; + + err = vr_nor_mtd_setup(p); + if (err) + goto destroy_maps; + + err = vr_nor_init_partitions(p); + if (err) + goto destroy_mtd_setup; + + pci_set_drvdata(dev, p); + + return 0; + + destroy_mtd_setup: + map_destroy(p->info); + + destroy_maps: + /* write-protect the flash bank */ + exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0); + exp_timing_cs0 &= ~TIMING_WR_EN; + writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0); + + /* unmap the flash window */ + iounmap(p->map.virt); + + /* unmap the csr window */ + iounmap(p->csr_base); + + release: + kfree(p); + pci_release_regions(dev); + + disable_dev: + pci_disable_device(dev); + + out: + return err; +} + +static struct pci_driver vr_nor_pci_driver = { + .name = DRV_NAME, + .probe = vr_nor_pci_probe, + .remove = __devexit_p(vr_nor_pci_remove), + .id_table = vr_nor_pci_ids, +}; + +static int __init vr_nor_mtd_init(void) +{ + return pci_register_driver(&vr_nor_pci_driver); +} + +static void __exit vr_nor_mtd_exit(void) +{ + pci_unregister_driver(&vr_nor_pci_driver); +} + +module_init(vr_nor_mtd_init); +module_exit(vr_nor_mtd_exit); + +MODULE_AUTHOR("Andy Lowe"); +MODULE_DESCRIPTION("MTD map driver for NOR flash on Intel Vermilion Range"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, vr_nor_pci_ids); diff --git a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c deleted file mode 100644 index e8560683b97..00000000000 --- a/drivers/mtd/maps/lubbock-flash.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * $Id: lubbock-flash.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $ - * - * Map driver for the Lubbock developer platform. - * - * Author: Nicolas Pitre - * Copyright: (C) 2001 MontaVista Software Inc. - * - * 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/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#include <asm/io.h> -#include <asm/hardware.h> -#include <asm/arch/pxa-regs.h> -#include <asm/arch/lubbock.h> -#include <asm/cacheflush.h> - -#define ROM_ADDR 0x00000000 -#define FLASH_ADDR 0x04000000 - -#define WINDOW_SIZE 64*1024*1024 - -static void lubbock_map_inval_cache(struct map_info *map, unsigned long from, ssize_t len) -{ - flush_ioremap_region(map->phys, map->cached, from, len); -} - -static struct map_info lubbock_maps[2] = { { - .size = WINDOW_SIZE, - .phys = 0x00000000, - .inval_cache = lubbock_map_inval_cache, -}, { - .size = WINDOW_SIZE, - .phys = 0x04000000, - .inval_cache = lubbock_map_inval_cache, -} }; - -static struct mtd_partition lubbock_partitions[] = { - { - .name = "Bootloader", - .size = 0x00040000, - .offset = 0, - .mask_flags = MTD_WRITEABLE /* force read-only */ - },{ - .name = "Kernel", - .size = 0x00100000, - .offset = 0x00040000, - },{ - .name = "Filesystem", - .size = MTDPART_SIZ_FULL, - .offset = 0x00140000 - } -}; - -static struct mtd_info *mymtds[2]; -static struct mtd_partition *parsed_parts[2]; -static int nr_parsed_parts[2]; - -static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; - -static int __init init_lubbock(void) -{ - int flashboot = (LUB_CONF_SWITCHES & 1); - int ret = 0, i; - - lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth = - (BOOT_DEF & 1) ? 2 : 4; - - /* Compensate for the nROMBT switch which swaps the flash banks */ - printk(KERN_NOTICE "Lubbock configured to boot from %s (bank %d)\n", - flashboot?"Flash":"ROM", flashboot); - - lubbock_maps[flashboot^1].name = "Lubbock Application Flash"; - lubbock_maps[flashboot].name = "Lubbock Boot ROM"; - - for (i = 0; i < 2; i++) { - lubbock_maps[i].virt = ioremap(lubbock_maps[i].phys, WINDOW_SIZE); - if (!lubbock_maps[i].virt) { - printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name); - if (!ret) - ret = -ENOMEM; - continue; - } - lubbock_maps[i].cached = ioremap_cached(lubbock_maps[i].phys, WINDOW_SIZE); - if (!lubbock_maps[i].cached) - printk(KERN_WARNING "Failed to ioremap cached %s\n", lubbock_maps[i].name); - simple_map_init(&lubbock_maps[i]); - - printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n", - lubbock_maps[i].name, lubbock_maps[i].phys, - lubbock_maps[i].bankwidth * 8); - - mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]); - - if (!mymtds[i]) { - iounmap((void *)lubbock_maps[i].virt); - if (lubbock_maps[i].cached) - iounmap(lubbock_maps[i].cached); - if (!ret) - ret = -EIO; - continue; - } - mymtds[i]->owner = THIS_MODULE; - - ret = parse_mtd_partitions(mymtds[i], probes, - &parsed_parts[i], 0); - - if (ret > 0) - nr_parsed_parts[i] = ret; - } - - if (!mymtds[0] && !mymtds[1]) - return ret; - - for (i = 0; i < 2; i++) { - if (!mymtds[i]) { - printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name); - } else if (nr_parsed_parts[i]) { - add_mtd_partitions(mymtds[i], parsed_parts[i], nr_parsed_parts[i]); - } else if (!i) { - printk("Using static partitions on %s\n", lubbock_maps[i].name); - add_mtd_partitions(mymtds[i], lubbock_partitions, ARRAY_SIZE(lubbock_partitions)); - } else { - printk("Registering %s as whole device\n", lubbock_maps[i].name); - add_mtd_device(mymtds[i]); - } - } - return 0; -} - -static void __exit cleanup_lubbock(void) -{ - int i; - for (i = 0; i < 2; i++) { - if (!mymtds[i]) - continue; - - if (nr_parsed_parts[i] || !i) - del_mtd_partitions(mymtds[i]); - else - del_mtd_device(mymtds[i]); - - map_destroy(mymtds[i]); - iounmap((void *)lubbock_maps[i].virt); - if (lubbock_maps[i].cached) - iounmap(lubbock_maps[i].cached); - - kfree(parsed_parts[i]); - } -} - -module_init(init_lubbock); -module_exit(cleanup_lubbock); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); -MODULE_DESCRIPTION("MTD map driver for Intel Lubbock"); diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c deleted file mode 100644 index d76487d82dc..00000000000 --- a/drivers/mtd/maps/mainstone-flash.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * $Id: $ - * - * Map driver for the Mainstone developer platform. - * - * Author: Nicolas Pitre - * Copyright: (C) 2001 MontaVista Software Inc. - * - * 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/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#include <asm/io.h> -#include <asm/hardware.h> -#include <asm/arch/pxa-regs.h> -#include <asm/arch/mainstone.h> -#include <asm/cacheflush.h> - - -#define ROM_ADDR 0x00000000 -#define FLASH_ADDR 0x04000000 - -#define WINDOW_SIZE 0x04000000 - -static void mainstone_map_inval_cache(struct map_info *map, unsigned long from, - ssize_t len) -{ - flush_ioremap_region(map->phys, map->cached, from, len); -} - -static struct map_info mainstone_maps[2] = { { - .size = WINDOW_SIZE, - .phys = PXA_CS0_PHYS, - .inval_cache = mainstone_map_inval_cache, -}, { - .size = WINDOW_SIZE, - .phys = PXA_CS1_PHYS, - .inval_cache = mainstone_map_inval_cache, -} }; - -static struct mtd_partition mainstone_partitions[] = { - { - .name = "Bootloader", - .size = 0x00040000, - .offset = 0, - .mask_flags = MTD_WRITEABLE /* force read-only */ - },{ - .name = "Kernel", - .size = 0x00400000, - .offset = 0x00040000, - },{ - .name = "Filesystem", - .size = MTDPART_SIZ_FULL, - .offset = 0x00440000 - } -}; - -static struct mtd_info *mymtds[2]; -static struct mtd_partition *parsed_parts[2]; -static int nr_parsed_parts[2]; - -static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; - -static int __init init_mainstone(void) -{ - int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */ - int ret = 0, i; - - mainstone_maps[0].bankwidth = (BOOT_DEF & 1) ? 2 : 4; - mainstone_maps[1].bankwidth = 4; - - /* Compensate for SW7 which swaps the flash banks */ - mainstone_maps[SW7].name = "processor flash"; - mainstone_maps[SW7 ^ 1].name = "main board flash"; - - printk(KERN_NOTICE "Mainstone configured to boot from %s\n", - mainstone_maps[0].name); - - for (i = 0; i < 2; i++) { - mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys, - WINDOW_SIZE); - if (!mainstone_maps[i].virt) { - printk(KERN_WARNING "Failed to ioremap %s\n", - mainstone_maps[i].name); - if (!ret) - ret = -ENOMEM; - continue; - } - mainstone_maps[i].cached = - ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE); - if (!mainstone_maps[i].cached) - printk(KERN_WARNING "Failed to ioremap cached %s\n", - mainstone_maps[i].name); - simple_map_init(&mainstone_maps[i]); - - printk(KERN_NOTICE - "Probing %s at physical address 0x%08lx" - " (%d-bit bankwidth)\n", - mainstone_maps[i].name, mainstone_maps[i].phys, - mainstone_maps[i].bankwidth * 8); - - mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]); - - if (!mymtds[i]) { - iounmap((void *)mainstone_maps[i].virt); - if (mainstone_maps[i].cached) - iounmap(mainstone_maps[i].cached); - if (!ret) - ret = -EIO; - continue; - } - mymtds[i]->owner = THIS_MODULE; - - ret = parse_mtd_partitions(mymtds[i], probes, - &parsed_parts[i], 0); - - if (ret > 0) - nr_parsed_parts[i] = ret; - } - - if (!mymtds[0] && !mymtds[1]) - return ret; - - for (i = 0; i < 2; i++) { - if (!mymtds[i]) { - printk(KERN_WARNING "%s is absent. Skipping\n", - mainstone_maps[i].name); - } else if (nr_parsed_parts[i]) { - add_mtd_partitions(mymtds[i], parsed_parts[i], - nr_parsed_parts[i]); - } else if (!i) { - printk("Using static partitions on %s\n", - mainstone_maps[i].name); - add_mtd_partitions(mymtds[i], mainstone_partitions, - ARRAY_SIZE(mainstone_partitions)); - } else { - printk("Registering %s as whole device\n", - mainstone_maps[i].name); - add_mtd_device(mymtds[i]); - } - } - return 0; -} - -static void __exit cleanup_mainstone(void) -{ - int i; - for (i = 0; i < 2; i++) { - if (!mymtds[i]) - continue; - - if (nr_parsed_parts[i] || !i) - del_mtd_partitions(mymtds[i]); - else - del_mtd_device(mymtds[i]); - - map_destroy(mymtds[i]); - iounmap((void *)mainstone_maps[i].virt); - if (mainstone_maps[i].cached) - iounmap(mainstone_maps[i].cached); - kfree(parsed_parts[i]); - } -} - -module_init(init_mainstone); -module_exit(cleanup_mainstone); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); -MODULE_DESCRIPTION("MTD map driver for Intel Mainstone"); diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index 7b96cd02f82..0c9b305a72e 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c @@ -158,68 +158,11 @@ static struct notifier_block nettel_notifier_block = { nettel_reboot_notifier, NULL, 0 }; -/* - * Erase the configuration file system. - * Used to support the software reset button. - */ -static void nettel_erasecallback(struct erase_info *done) -{ - wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; - wake_up(wait_q); -} - -static struct erase_info nettel_erase; - -int nettel_eraseconfig(void) -{ - struct mtd_info *mtd; - DECLARE_WAITQUEUE(wait, current); - wait_queue_head_t wait_q; - int ret; - - init_waitqueue_head(&wait_q); - mtd = get_mtd_device(NULL, 2); - if (!IS_ERR(mtd)) { - nettel_erase.mtd = mtd; - nettel_erase.callback = nettel_erasecallback; - nettel_erase.callback = NULL; - nettel_erase.addr = 0; - nettel_erase.len = mtd->size; - nettel_erase.priv = (u_long) &wait_q; - nettel_erase.priv = 0; - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&wait_q, &wait); - - ret = mtd->erase(mtd, &nettel_erase); - if (ret) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&wait_q, &wait); - put_mtd_device(mtd); - return(ret); - } - - schedule(); /* Wait for erase to finish. */ - remove_wait_queue(&wait_q, &wait); - - put_mtd_device(mtd); - } - - return(0); -} - -#else - -int nettel_eraseconfig(void) -{ - return(0); -} - #endif /****************************************************************************/ -int __init nettel_init(void) +static int __init nettel_init(void) { volatile unsigned long *amdpar; unsigned long amdaddr, maxsize; @@ -421,10 +364,6 @@ int __init nettel_init(void) intel_mtd->owner = THIS_MODULE; -#ifndef CONFIG_BLK_DEV_INITRD - ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1); -#endif - num_intel_partitions = sizeof(nettel_intel_partitions) / sizeof(nettel_intel_partitions[0]); @@ -477,7 +416,7 @@ out_unmap2: /****************************************************************************/ -void __exit nettel_cleanup(void) +static void __exit nettel_cleanup(void) { #ifdef CONFIG_MTD_CFI_INTELEXT unregister_reboot_notifier(&nettel_notifier_block); diff --git a/drivers/mtd/maps/ocelot.c b/drivers/mtd/maps/ocelot.c deleted file mode 100644 index 6977963d789..00000000000 --- a/drivers/mtd/maps/ocelot.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * $Id: ocelot.c,v 1.17 2005/11/07 11:14:27 gleixner Exp $ - * - * Flash on Momenco Ocelot - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <asm/io.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#define OCELOT_PLD 0x2c000000 -#define FLASH_WINDOW_ADDR 0x2fc00000 -#define FLASH_WINDOW_SIZE 0x00080000 -#define FLASH_BUSWIDTH 1 -#define NVRAM_WINDOW_ADDR 0x2c800000 -#define NVRAM_WINDOW_SIZE 0x00007FF0 -#define NVRAM_BUSWIDTH 1 - -static unsigned int cacheflush = 0; - -static struct mtd_info *flash_mtd; -static struct mtd_info *nvram_mtd; - -static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) -{ - struct map_info *map = mtd->priv; - size_t done = 0; - - /* If we use memcpy, it does word-wide writes. Even though we told the - GT64120A that it's an 8-bit wide region, word-wide writes don't work. - We end up just writing the first byte of the four to all four bytes. - So we have this loop instead */ - *retlen = len; - while(len) { - __raw_writeb(*(unsigned char *) from, map->virt + to); - from++; - to++; - len--; - } -} - -static struct mtd_partition *parsed_parts; - -struct map_info ocelot_flash_map = { - .name = "Ocelot boot flash", - .size = FLASH_WINDOW_SIZE, - .bankwidth = FLASH_BUSWIDTH, - .phys = FLASH_WINDOW_ADDR, -}; - -struct map_info ocelot_nvram_map = { - .name = "Ocelot NVRAM", - .size = NVRAM_WINDOW_SIZE, - .bankwidth = NVRAM_BUSWIDTH, - .phys = NVRAM_WINDOW_ADDR, -}; - -static const char *probes[] = { "RedBoot", NULL }; - -static int __init init_ocelot_maps(void) -{ - void *pld; - int nr_parts; - unsigned char brd_status; - - printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n", - FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR); - - /* First check whether the flash jumper is present */ - pld = ioremap(OCELOT_PLD, 0x10); - if (!pld) { - printk(KERN_NOTICE "Failed to ioremap Ocelot PLD\n"); - return -EIO; - } - brd_status = readb(pld+4); - iounmap(pld); - - /* Now ioremap the NVRAM space */ - ocelot_nvram_map.virt = ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE); - if (!ocelot_nvram_map.virt) { - printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n"); - return -EIO; - } - - simple_map_init(&ocelot_nvram_map); - - /* And do the RAM probe on it to get an MTD device */ - nvram_mtd = do_map_probe("map_ram", &ocelot_nvram_map); - if (!nvram_mtd) { - printk("NVRAM probe failed\n"); - goto fail_1; - } - nvram_mtd->owner = THIS_MODULE; - nvram_mtd->erasesize = 16; - /* Override the write() method */ - nvram_mtd->write = ocelot_ram_write; - - /* Now map the flash space */ - ocelot_flash_map.virt = ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE); - if (!ocelot_flash_map.virt) { - printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n"); - goto fail_2; - } - /* Now the cached version */ - ocelot_flash_map.cached = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0); - - simple_map_init(&ocelot_flash_map); - - /* Only probe for flash if the write jumper is present */ - if (brd_status & 0x40) { - flash_mtd = do_map_probe("jedec", &ocelot_flash_map); - } else { - printk(KERN_NOTICE "Ocelot flash write jumper not present. Treating as ROM\n"); - } - /* If that failed or the jumper's absent, pretend it's ROM */ - if (!flash_mtd) { - flash_mtd = do_map_probe("map_rom", &ocelot_flash_map); - /* If we're treating it as ROM, set the erase size */ - if (flash_mtd) - flash_mtd->erasesize = 0x10000; - } - if (!flash_mtd) - goto fail3; - - add_mtd_device(nvram_mtd); - - flash_mtd->owner = THIS_MODULE; - nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0); - - if (nr_parts > 0) - add_mtd_partitions(flash_mtd, parsed_parts, nr_parts); - else - add_mtd_device(flash_mtd); - - return 0; - - fail3: - iounmap((void *)ocelot_flash_map.virt); - if (ocelot_flash_map.cached) - iounmap((void *)ocelot_flash_map.cached); - fail_2: - map_destroy(nvram_mtd); - fail_1: - iounmap((void *)ocelot_nvram_map.virt); - - return -ENXIO; -} - -static void __exit cleanup_ocelot_maps(void) -{ - del_mtd_device(nvram_mtd); - map_destroy(nvram_mtd); - iounmap((void *)ocelot_nvram_map.virt); - - if (parsed_parts) - del_mtd_partitions(flash_mtd); - else - del_mtd_device(flash_mtd); - map_destroy(flash_mtd); - iounmap((void *)ocelot_flash_map.virt); - if (ocelot_flash_map.cached) - iounmap((void *)ocelot_flash_map.cached); -} - -module_init(init_ocelot_maps); -module_exit(cleanup_ocelot_maps); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>"); -MODULE_DESCRIPTION("MTD map driver for Momenco Ocelot board"); diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index cf75a566442..aeed9ea7971 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -232,7 +232,6 @@ static int __devinit of_flash_probe(struct of_device *dev, info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) goto err_out; - memset(info, 0, sizeof(*info)); dev_set_drvdata(&dev->dev, info); diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c index 7e0377ec1c4..02bde8c982e 100644 --- a/drivers/mtd/maps/pmcmsp-flash.c +++ b/drivers/mtd/maps/pmcmsp-flash.c @@ -73,13 +73,16 @@ int __init init_msp_flash(void) return -ENXIO; printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt); - msp_flash = (struct mtd_info **)kmalloc( - fcnt * sizeof(struct map_info *), GFP_KERNEL); - msp_parts = (struct mtd_partition **)kmalloc( - fcnt * sizeof(struct mtd_partition *), GFP_KERNEL); - msp_maps = (struct map_info *)kmalloc( - fcnt * sizeof(struct mtd_info), GFP_KERNEL); - memset(msp_maps, 0, fcnt * sizeof(struct mtd_info)); + + msp_flash = kmalloc(fcnt * sizeof(struct map_info *), GFP_KERNEL); + msp_parts = kmalloc(fcnt * sizeof(struct mtd_partition *), GFP_KERNEL); + msp_maps = kcalloc(fcnt, sizeof(struct mtd_info), GFP_KERNEL); + if (!msp_flash || !msp_parts || !msp_maps) { + kfree(msp_maps); + kfree(msp_parts); + kfree(msp_flash); + return -ENOMEM; + } /* loop over the flash devices, initializing each */ for (i = 0; i < fcnt; i++) { @@ -95,9 +98,8 @@ int __init init_msp_flash(void) continue; } - msp_parts[i] = (struct mtd_partition *)kmalloc( - pcnt * sizeof(struct mtd_partition), GFP_KERNEL); - memset(msp_parts[i], 0, pcnt * sizeof(struct mtd_partition)); + msp_parts[i] = kcalloc(pcnt, sizeof(struct mtd_partition), + GFP_KERNEL); /* now initialize the devices proper */ flash_name[5] = '0' + i; diff --git a/drivers/mtd/maps/pmcmsp-ramroot.c b/drivers/mtd/maps/pmcmsp-ramroot.c index 18049bceba8..30de5c0c09a 100644 --- a/drivers/mtd/maps/pmcmsp-ramroot.c +++ b/drivers/mtd/maps/pmcmsp-ramroot.c @@ -79,7 +79,6 @@ static int __init init_rrmap(void) rr_mtd->owner = THIS_MODULE; add_mtd_device(rr_mtd); - ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, rr_mtd->index); return 0; } diff --git a/drivers/mtd/maps/pq2fads.c b/drivers/mtd/maps/pq2fads.c deleted file mode 100644 index fb78d87cc13..00000000000 --- a/drivers/mtd/maps/pq2fads.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * drivers/mtd/maps/pq2fads.c - * - * Mapping for the flash SIMM on 8272ADS and PQ2FADS board - * - * Author: Vitaly Bordug <vbordug@ru.mvista.com> - * - * 2005 (c) MontaVista Software, Inc. 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/types.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <asm/io.h> -#include <asm/ppcboot.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/physmap.h> - -/* - NOTE: bank width and interleave relative to the installed flash - should have been chosen within MTD_CFI_GEOMETRY options. - */ -#define PQ2FADS_BANK_WIDTH 4 - -static struct mtd_partition pq2fads_partitions[] = { - { -#ifdef CONFIG_ADS8272 - .name = "HRCW", - .size = 0x40000, - .offset = 0, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, { - .name = "User FS", - .size = 0x5c0000, - .offset = 0x40000, -#else - .name = "User FS", - .size = 0x600000, - .offset = 0, -#endif - }, { - .name = "uImage", - .size = 0x100000, - .offset = 0x600000, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, { - .name = "bootloader", - .size = 0x40000, - .offset = 0x700000, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, { - .name = "bootloader env", - .size = 0x40000, - .offset = 0x740000, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - } -}; - - -/* pointer to MPC885ADS board info data */ -extern unsigned char __res[]; - -static int __init init_pq2fads_mtd(void) -{ - bd_t *bd = (bd_t *)__res; - physmap_configure(bd->bi_flashstart, bd->bi_flashsize, PQ2FADS_BANK_WIDTH, NULL); - - physmap_set_partitions(pq2fads_partitions, - sizeof (pq2fads_partitions) / - sizeof (pq2fads_partitions[0])); - return 0; -} - -static void __exit cleanup_pq2fads_mtd(void) -{ -} - -module_init(init_pq2fads_mtd); -module_exit(cleanup_pq2fads_mtd); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("MTD map and partitions for MPC8272ADS boards"); diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c new file mode 100644 index 00000000000..cb933ac475d --- /dev/null +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -0,0 +1,200 @@ +/* + * Map driver for Intel XScale PXA2xx platforms. + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> + +#include <asm/io.h> +#include <asm/hardware.h> + +#include <asm/mach/flash.h> + +static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from, + ssize_t len) +{ + consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE); +} + +struct pxa2xx_flash_info { + struct mtd_partition *parts; + int nr_parts; + struct mtd_info *mtd; + struct map_info map; +}; + + +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + + +static int __init pxa2xx_flash_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct flash_platform_data *flash = pdev->dev.platform_data; + struct pxa2xx_flash_info *info; + struct mtd_partition *parts; + struct resource *res; + int ret = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + info = kmalloc(sizeof(struct pxa2xx_flash_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + memset(info, 0, sizeof(struct pxa2xx_flash_info)); + info->map.name = (char *) flash->name; + info->map.bankwidth = flash->width; + info->map.phys = res->start; + info->map.size = res->end - res->start + 1; + info->parts = flash->parts; + info->nr_parts = flash->nr_parts; + + info->map.virt = ioremap(info->map.phys, info->map.size); + if (!info->map.virt) { + printk(KERN_WARNING "Failed to ioremap %s\n", + info->map.name); + return -ENOMEM; + } + info->map.cached = + ioremap_cached(info->map.phys, info->map.size); + if (!info->map.cached) + printk(KERN_WARNING "Failed to ioremap cached %s\n", + info->map.name); + info->map.inval_cache = pxa2xx_map_inval_cache; + simple_map_init(&info->map); + + printk(KERN_NOTICE + "Probing %s at physical address 0x%08lx" + " (%d-bit bankwidth)\n", + info->map.name, (unsigned long)info->map.phys, + info->map.bankwidth * 8); + + info->mtd = do_map_probe(flash->map_name, &info->map); + + if (!info->mtd) { + iounmap((void *)info->map.virt); + if (info->map.cached) + iounmap(info->map.cached); + return -EIO; + } + info->mtd->owner = THIS_MODULE; + +#ifdef CONFIG_MTD_PARTITIONS + ret = parse_mtd_partitions(info->mtd, probes, &parts, 0); + + if (ret > 0) { + info->nr_parts = ret; + info->parts = parts; + } +#endif + + if (info->nr_parts) { + add_mtd_partitions(info->mtd, info->parts, + info->nr_parts); + } else { + printk("Registering %s as whole device\n", + info->map.name); + add_mtd_device(info->mtd); + } + + dev_set_drvdata(dev, info); + return 0; +} + +static int __exit pxa2xx_flash_remove(struct device *dev) +{ + struct pxa2xx_flash_info *info = dev_get_drvdata(dev); + + dev_set_drvdata(dev, NULL); + +#ifdef CONFIG_MTD_PARTITIONS + if (info->nr_parts) + del_mtd_partitions(info->mtd); + else +#endif + del_mtd_device(info->mtd); + + map_destroy(info->mtd); + iounmap(info->map.virt); + if (info->map.cached) + iounmap(info->map.cached); + kfree(info->parts); + kfree(info); + return 0; +} + +#ifdef CONFIG_PM +static int pxa2xx_flash_suspend(struct device *dev, pm_message_t state) +{ + struct pxa2xx_flash_info *info = dev_get_drvdata(dev); + int ret = 0; + + if (info->mtd && info->mtd->suspend) + ret = info->mtd->suspend(info->mtd); + return ret; +} + +static int pxa2xx_flash_resume(struct device *dev) +{ + struct pxa2xx_flash_info *info = dev_get_drvdata(dev); + + if (info->mtd && info->mtd->resume) + info->mtd->resume(info->mtd); + return 0; +} +static void pxa2xx_flash_shutdown(struct device *dev) +{ + struct pxa2xx_flash_info *info = dev_get_drvdata(dev); + + if (info && info->mtd->suspend(info->mtd) == 0) + info->mtd->resume(info->mtd); +} +#else +#define pxa2xx_flash_suspend NULL +#define pxa2xx_flash_resume NULL +#define pxa2xx_flash_shutdown NULL +#endif + +static struct device_driver pxa2xx_flash_driver = { + .name = "pxa2xx-flash", + .bus = &platform_bus_type, + .probe = pxa2xx_flash_probe, + .remove = __exit_p(pxa2xx_flash_remove), + .suspend = pxa2xx_flash_suspend, + .resume = pxa2xx_flash_resume, + .shutdown = pxa2xx_flash_shutdown, +}; + +static int __init init_pxa2xx_flash(void) +{ + return driver_register(&pxa2xx_flash_driver); +} + +static void __exit cleanup_pxa2xx_flash(void) +{ + driver_unregister(&pxa2xx_flash_driver); +} + +module_init(init_pxa2xx_flash); +module_exit(cleanup_pxa2xx_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); +MODULE_DESCRIPTION("MTD map driver for Intel XScale PXA2xx"); diff --git a/drivers/mtd/maps/tqm834x.c b/drivers/mtd/maps/tqm834x.c deleted file mode 100644 index 9adc970e55e..00000000000 --- a/drivers/mtd/maps/tqm834x.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * drivers/mtd/maps/tqm834x.c - * - * MTD mapping driver for TQM834x boards - * - * Copyright 2005 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>. - * - * 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/init.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <asm/io.h> -#include <asm/ppcboot.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#define FLASH_BANK_MAX 2 - -extern unsigned char __res[]; - -/* trivial struct to describe partition information */ -struct mtd_part_def -{ - int nums; - unsigned char *type; - struct mtd_partition* mtd_part; -}; - -static struct mtd_info* mtd_banks[FLASH_BANK_MAX]; -static struct map_info* map_banks[FLASH_BANK_MAX]; -static struct mtd_part_def part_banks[FLASH_BANK_MAX]; - -static unsigned long num_banks; -static unsigned long start_scan_addr; - -#ifdef CONFIG_MTD_PARTITIONS -/* - * The following defines the partition layout of TQM834x boards. - * - * See include/linux/mtd/partitions.h for definition of the - * mtd_partition structure. - * - * Assume minimal initial size of 4 MiB per bank, will be updated - * later in init_tqm834x_mtd() routine. - */ - -/* Partition definition for the first flash bank which is always present. */ -static struct mtd_partition tqm834x_partitions_bank1[] = { - { - .name = "u-boot", /* u-boot firmware */ - .offset = 0x00000000, - .size = 0x00040000, /* 256 KiB */ - /*mask_flags: MTD_WRITEABLE, * force read-only */ - }, - { - .name = "env", /* u-boot environment */ - .offset = 0x00040000, - .size = 0x00020000, /* 128 KiB */ - /*mask_flags: MTD_WRITEABLE, * force read-only */ - }, - { - .name = "kernel", /* linux kernel image */ - .offset = 0x00060000, - .size = 0x00100000, /* 1 MiB */ - /*mask_flags: MTD_WRITEABLE, * force read-only */ - }, - { - .name = "initrd", /* ramdisk image */ - .offset = 0x00160000, - .size = 0x00200000, /* 2 MiB */ - }, - { - .name = "user", /* user data */ - .offset = 0x00360000, - .size = 0x000a0000, /* remaining space */ - /* NOTE: this parttion size is re-calcated in */ - /* init_tqm834x_mtd() to cover actual remaining space. */ - }, -}; - -/* Partition definition for the second flash bank which may be present on some - * TQM834x boards. - */ -static struct mtd_partition tqm834x_partitions_bank2[] = { - { - .name = "jffs2", /* jffs2 filesystem */ - .offset = 0x00000000, - .size = 0x00400000, /* whole device */ - /* NOTE: this parttion size is re-calcated in */ - /* init_tqm834x_mtd() to cover actual device size. */ - }, -}; - -#endif /* CONFIG_MTD_PARTITIONS */ - -static int __init init_tqm834x_mtd(void) -{ - int idx = 0, ret = 0; - unsigned long flash_addr, flash_size, mtd_size = 0; - - /* pointer to TQM834x board info data */ - bd_t *bd = (bd_t *)__res; -#ifdef CONFIG_MTD_CMDLINE_PARTS - int n; - char mtdid[4]; - const char *part_probes[] = { "cmdlinepart", NULL }; -#endif - - flash_addr = bd->bi_flashstart; - flash_size = bd->bi_flashsize; - - /* request maximum flash size address space */ - start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size); - if (!start_scan_addr) { - printk("%s: Failed to ioremap address: 0x%lx\n", - __FUNCTION__, flash_addr); - return -EIO; - } - - for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { - if (mtd_size >= flash_size) - break; - - pr_debug("%s: chip probing count %d\n", __FUNCTION__, idx); - - map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL); - if (map_banks[idx] == NULL) { - ret = -ENOMEM; - goto error_mem; - } - map_banks[idx]->name = kzalloc(16, GFP_KERNEL); - if (map_banks[idx]->name == NULL) { - ret = -ENOMEM; - goto error_mem; - } - - sprintf(map_banks[idx]->name, "TQM834x-%d", idx); - map_banks[idx]->size = flash_size; - map_banks[idx]->bankwidth = 4; - - simple_map_init(map_banks[idx]); - - map_banks[idx]->virt = (void __iomem *) - (start_scan_addr + ((idx > 0) ? - (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0)); - map_banks[idx]->phys = - flash_addr + ((idx > 0) ? - (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0); - - /* start to probe flash chips */ - mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]); - if (mtd_banks[idx]) { - mtd_banks[idx]->owner = THIS_MODULE; - mtd_size += mtd_banks[idx]->size; - num_banks++; - pr_debug("%s: bank %ld, name: %s, size: %d bytes \n", - __FUNCTION__, num_banks, - mtd_banks[idx]->name, mtd_banks[idx]->size); - } - } - - /* no supported flash chips found */ - if (!num_banks) { - printk("TQM834x: No supported flash chips found!\n"); - ret = -ENXIO; - goto error_mem; - } - -#ifdef CONFIG_MTD_PARTITIONS - /* - * Select static partition definitions - */ - n = ARRAY_SIZE(tqm834x_partitions_bank1); - part_banks[0].mtd_part = tqm834x_partitions_bank1; - part_banks[0].type = "static image bank1"; - part_banks[0].nums = n; - - /* update last partition size to cover actual remaining space */ - tqm834x_partitions_bank1[n - 1].size = - mtd_banks[0]->size - - tqm834x_partitions_bank1[n - 1].offset; - - /* check if we have second bank? */ - if (num_banks == 2) { - n = ARRAY_SIZE(tqm834x_partitions_bank2); - part_banks[1].mtd_part = tqm834x_partitions_bank2; - part_banks[1].type = "static image bank2"; - part_banks[1].nums = n; - - /* update last partition size to cover actual remaining space */ - tqm834x_partitions_bank2[n - 1].size = - mtd_banks[1]->size - - tqm834x_partitions_bank2[n - 1].offset; - } - - for(idx = 0; idx < num_banks ; idx++) { -#ifdef CONFIG_MTD_CMDLINE_PARTS - sprintf(mtdid, "%d", idx); - n = parse_mtd_partitions(mtd_banks[idx], - part_probes, - &part_banks[idx].mtd_part, - 0); - pr_debug("%s: %d command line partitions on bank %s\n", - __FUNCTION__, n, mtdid); - if (n > 0) { - part_banks[idx].type = "command line"; - part_banks[idx].nums = n; - } -#endif /* CONFIG_MTD_CMDLINE_PARTS */ - if (part_banks[idx].nums == 0) { - printk(KERN_NOTICE - "TQM834x flash bank %d: no partition info " - "available, registering whole device\n", idx); - add_mtd_device(mtd_banks[idx]); - } else { - printk(KERN_NOTICE - "TQM834x flash bank %d: Using %s partition " - "definition\n", idx, part_banks[idx].type); - add_mtd_partitions(mtd_banks[idx], - part_banks[idx].mtd_part, - part_banks[idx].nums); - } - } -#else /* ! CONFIG_MTD_PARTITIONS */ - printk(KERN_NOTICE "TQM834x flash: registering %d flash banks " - "at once\n", num_banks); - - for(idx = 0 ; idx < num_banks ; idx++) - add_mtd_device(mtd_banks[idx]); - -#endif /* CONFIG_MTD_PARTITIONS */ - - return 0; -error_mem: - for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { - if (map_banks[idx] != NULL) { - if (map_banks[idx]->name != NULL) { - kfree(map_banks[idx]->name); - map_banks[idx]->name = NULL; - } - kfree(map_banks[idx]); - map_banks[idx] = NULL; - } - } - - iounmap((void *)start_scan_addr); - - return ret; -} - -static void __exit cleanup_tqm834x_mtd(void) -{ - unsigned int idx = 0; - for(idx = 0 ; idx < num_banks ; idx++) { - /* destroy mtd_info previously allocated */ - if (mtd_banks[idx]) { - del_mtd_partitions(mtd_banks[idx]); - map_destroy(mtd_banks[idx]); - } - - /* release map_info not used anymore */ - kfree(map_banks[idx]->name); - kfree(map_banks[idx]); - } - - if (start_scan_addr) { - iounmap((void *)start_scan_addr); - start_scan_addr = 0; - } -} - -module_init(init_tqm834x_mtd); -module_exit(cleanup_tqm834x_mtd); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Wolfgang Denk <wd@denx.de>"); -MODULE_DESCRIPTION("MTD map driver for TQM834x boards"); diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index ef89780eb9d..74d9d30edab 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -24,10 +24,9 @@ #include <linux/kthread.h> #include <asm/uaccess.h> -static LIST_HEAD(blktrans_majors); +#include "mtdcore.h" -extern struct mutex mtd_table_mutex; -extern struct mtd_info *mtd_table[]; +static LIST_HEAD(blktrans_majors); struct mtd_blkcore_priv { struct task_struct *thread; @@ -202,7 +201,7 @@ static int blktrans_ioctl(struct inode *inode, struct file *file, } } -struct block_device_operations mtd_blktrans_ops = { +static struct block_device_operations mtd_blktrans_ops = { .owner = THIS_MODULE, .open = blktrans_open, .release = blktrans_release, diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index d091b2430b4..22ed96c4b7b 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -136,7 +136,8 @@ static int mtd_close(struct inode *inode, struct file *file) DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); - if (mtd->sync) + /* Only sync if opened RW */ + if ((file->f_mode & 2) && mtd->sync) mtd->sync(mtd); put_mtd_device(mtd); diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 41844ea0246..96be7ef62f3 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -178,7 +178,7 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs, /* Check alignment */ if (mtd->writesize > 1) { - loff_t __to = to; + uint64_t __to = to; if (do_div(__to, mtd->writesize) || (total_len % mtd->writesize)) return -EINVAL; } diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c153b64a830..6c2645e2837 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -22,6 +22,8 @@ #include <linux/mtd/mtd.h> +#include "mtdcore.h" + /* These are exported solely for the purpose of mtd_blkdevs.c. You should not use them for _anything_ else */ DEFINE_MUTEX(mtd_table_mutex); diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h new file mode 100644 index 00000000000..a33251f4b87 --- /dev/null +++ b/drivers/mtd/mtdcore.h @@ -0,0 +1,11 @@ +/* linux/drivers/mtd/mtdcore.h + * + * Header file for driver private mtdcore exports + * + */ + +/* These are exported solely for the purpose of mtd_blkdevs.c. You + should not use them for _anything_ else */ + +extern struct mutex mtd_table_mutex; +extern struct mtd_info *mtd_table[MAX_MTD_DEVICES]; diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c new file mode 100644 index 00000000000..f8af627f0b9 --- /dev/null +++ b/drivers/mtd/mtdoops.c @@ -0,0 +1,376 @@ +/* + * MTD Oops/Panic logger + * + * Copyright (C) 2007 Nokia Corporation. All rights reserved. + * + * Author: Richard Purdie <rpurdie@openedhand.com> + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/console.h> +#include <linux/vmalloc.h> +#include <linux/workqueue.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/mtd/mtd.h> + +#define OOPS_PAGE_SIZE 4096 + +static struct mtdoops_context { + int mtd_index; + struct work_struct work; + struct mtd_info *mtd; + int oops_pages; + int nextpage; + int nextcount; + + void *oops_buf; + int ready; + int writecount; +} oops_cxt; + +static void mtdoops_erase_callback(struct erase_info *done) +{ + wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; + wake_up(wait_q); +} + +static int mtdoops_erase_block(struct mtd_info *mtd, int offset) +{ + struct erase_info erase; + DECLARE_WAITQUEUE(wait, current); + wait_queue_head_t wait_q; + int ret; + + init_waitqueue_head(&wait_q); + erase.mtd = mtd; + erase.callback = mtdoops_erase_callback; + erase.addr = offset; + if (mtd->erasesize < OOPS_PAGE_SIZE) + erase.len = OOPS_PAGE_SIZE; + else + erase.len = mtd->erasesize; + erase.priv = (u_long)&wait_q; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&wait_q, &wait); + + ret = mtd->erase(mtd, &erase); + if (ret) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&wait_q, &wait); + printk (KERN_WARNING "mtdoops: erase of region [0x%x, 0x%x] " + "on \"%s\" failed\n", + erase.addr, erase.len, mtd->name); + return ret; + } + + schedule(); /* Wait for erase to finish. */ + remove_wait_queue(&wait_q, &wait); + + return 0; +} + +static int mtdoops_inc_counter(struct mtdoops_context *cxt) +{ + struct mtd_info *mtd = cxt->mtd; + size_t retlen; + u32 count; + int ret; + + cxt->nextpage++; + if (cxt->nextpage > cxt->oops_pages) + cxt->nextpage = 0; + cxt->nextcount++; + if (cxt->nextcount == 0xffffffff) + cxt->nextcount = 0; + + ret = mtd->read(mtd, cxt->nextpage * OOPS_PAGE_SIZE, 4, + &retlen, (u_char *) &count); + if ((retlen != 4) || (ret < 0)) { + printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)" + ", err %d.\n", cxt->nextpage * OOPS_PAGE_SIZE, + retlen, ret); + return 1; + } + + /* See if we need to erase the next block */ + if (count != 0xffffffff) + return 1; + + printk(KERN_DEBUG "mtdoops: Ready %d, %d (no erase)\n", + cxt->nextpage, cxt->nextcount); + cxt->ready = 1; + return 0; +} + +static void mtdoops_prepare(struct mtdoops_context *cxt) +{ + struct mtd_info *mtd = cxt->mtd; + int i = 0, j, ret, mod; + + /* We were unregistered */ + if (!mtd) + return; + + mod = (cxt->nextpage * OOPS_PAGE_SIZE) % mtd->erasesize; + if (mod != 0) { + cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / OOPS_PAGE_SIZE); + if (cxt->nextpage > cxt->oops_pages) + cxt->nextpage = 0; + } + + while (mtd->block_isbad && + mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE)) { +badblock: + printk(KERN_WARNING "mtdoops: Bad block at %08x\n", + cxt->nextpage * OOPS_PAGE_SIZE); + i++; + cxt->nextpage = cxt->nextpage + (mtd->erasesize / OOPS_PAGE_SIZE); + if (cxt->nextpage > cxt->oops_pages) + cxt->nextpage = 0; + if (i == (cxt->oops_pages / (mtd->erasesize / OOPS_PAGE_SIZE))) { + printk(KERN_ERR "mtdoops: All blocks bad!\n"); + return; + } + } + + for (j = 0, ret = -1; (j < 3) && (ret < 0); j++) + ret = mtdoops_erase_block(mtd, cxt->nextpage * OOPS_PAGE_SIZE); + + if (ret < 0) { + if (mtd->block_markbad) + mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE); + goto badblock; + } + + printk(KERN_DEBUG "mtdoops: Ready %d, %d \n", cxt->nextpage, cxt->nextcount); + + cxt->ready = 1; +} + +static void mtdoops_workfunc(struct work_struct *work) +{ + struct mtdoops_context *cxt = + container_of(work, struct mtdoops_context, work); + + mtdoops_prepare(cxt); +} + +static int find_next_position(struct mtdoops_context *cxt) +{ + struct mtd_info *mtd = cxt->mtd; + int page, maxpos = 0; + u32 count, maxcount = 0xffffffff; + size_t retlen; + + for (page = 0; page < cxt->oops_pages; page++) { + mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count); + if (count == 0xffffffff) + continue; + if (maxcount == 0xffffffff) { + maxcount = count; + maxpos = page; + } else if ((count < 0x40000000) && (maxcount > 0xc0000000)) { + maxcount = count; + maxpos = page; + } else if ((count > maxcount) && (count < 0xc0000000)) { + maxcount = count; + maxpos = page; + } else if ((count > maxcount) && (count > 0xc0000000) + && (maxcount > 0x80000000)) { + maxcount = count; + maxpos = page; + } + } + if (maxcount == 0xffffffff) { + cxt->nextpage = 0; + cxt->nextcount = 1; + cxt->ready = 1; + printk(KERN_DEBUG "mtdoops: Ready %d, %d (first init)\n", + cxt->nextpage, cxt->nextcount); + return 0; + } + + cxt->nextpage = maxpos; + cxt->nextcount = maxcount; + + return mtdoops_inc_counter(cxt); +} + + +static void mtdoops_notify_add(struct mtd_info *mtd) +{ + struct mtdoops_context *cxt = &oops_cxt; + int ret; + + if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0) + return; + + if (mtd->size < (mtd->erasesize * 2)) { + printk(KERN_ERR "MTD partition %d not big enough for mtdoops\n", + mtd->index); + return; + } + + cxt->mtd = mtd; + cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE; + + ret = find_next_position(cxt); + if (ret == 1) + mtdoops_prepare(cxt); + + printk(KERN_DEBUG "mtdoops: Attached to MTD device %d\n", mtd->index); +} + +static void mtdoops_notify_remove(struct mtd_info *mtd) +{ + struct mtdoops_context *cxt = &oops_cxt; + + if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0) + return; + + cxt->mtd = NULL; + flush_scheduled_work(); +} + +static void mtdoops_console_sync(void) +{ + struct mtdoops_context *cxt = &oops_cxt; + struct mtd_info *mtd = cxt->mtd; + size_t retlen; + int ret; + + if (!cxt->ready || !mtd) + return; + + if (cxt->writecount == 0) + return; + + if (cxt->writecount < OOPS_PAGE_SIZE) + memset(cxt->oops_buf + cxt->writecount, 0xff, + OOPS_PAGE_SIZE - cxt->writecount); + + ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE, + OOPS_PAGE_SIZE, &retlen, cxt->oops_buf); + cxt->ready = 0; + cxt->writecount = 0; + + if ((retlen != OOPS_PAGE_SIZE) || (ret < 0)) + printk(KERN_ERR "mtdoops: Write failure at %d (%td of %d written), err %d.\n", + cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret); + + ret = mtdoops_inc_counter(cxt); + if (ret == 1) + schedule_work(&cxt->work); +} + +static void +mtdoops_console_write(struct console *co, const char *s, unsigned int count) +{ + struct mtdoops_context *cxt = co->data; + struct mtd_info *mtd = cxt->mtd; + int i; + + if (!oops_in_progress) { + mtdoops_console_sync(); + return; + } + + if (!cxt->ready || !mtd) + return; + + if (cxt->writecount == 0) { + u32 *stamp = cxt->oops_buf; + *stamp = cxt->nextcount; + cxt->writecount = 4; + } + + if ((count + cxt->writecount) > OOPS_PAGE_SIZE) + count = OOPS_PAGE_SIZE - cxt->writecount; + + for (i = 0; i < count; i++, s++) + *((char *)(cxt->oops_buf) + cxt->writecount + i) = *s; + + cxt->writecount = cxt->writecount + count; +} + +static int __init mtdoops_console_setup(struct console *co, char *options) +{ + struct mtdoops_context *cxt = co->data; + + if (cxt->mtd_index != -1) + return -EBUSY; + if (co->index == -1) + return -EINVAL; + + cxt->mtd_index = co->index; + return 0; +} + +static struct mtd_notifier mtdoops_notifier = { + .add = mtdoops_notify_add, + .remove = mtdoops_notify_remove, +}; + +static struct console mtdoops_console = { + .name = "ttyMTD", + .write = mtdoops_console_write, + .setup = mtdoops_console_setup, + .unblank = mtdoops_console_sync, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &oops_cxt, +}; + +static int __init mtdoops_console_init(void) +{ + struct mtdoops_context *cxt = &oops_cxt; + + cxt->mtd_index = -1; + cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE); + + if (!cxt->oops_buf) { + printk(KERN_ERR "Failed to allocate oops buffer workspace\n"); + return -ENOMEM; + } + + INIT_WORK(&cxt->work, mtdoops_workfunc); + + register_console(&mtdoops_console); + register_mtd_user(&mtdoops_notifier); + return 0; +} + +static void __exit mtdoops_console_exit(void) +{ + struct mtdoops_context *cxt = &oops_cxt; + + unregister_mtd_user(&mtdoops_notifier); + unregister_console(&mtdoops_console); + vfree(cxt->oops_buf); +} + + +subsys_initcall(mtdoops_console_init); +module_exit(mtdoops_console_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>"); +MODULE_DESCRIPTION("MTD Oops/Panic console logger/driver"); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index f1d60b6f048..8f9c3baeb38 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -91,6 +91,25 @@ config MTD_NAND_AU1550 This enables the driver for the NAND flash controller on the AMD/Alchemy 1550 SOC. +config MTD_NAND_BF5XX + tristate "Blackfin on-chip NAND Flash Controller driver" + depends on BF54x && MTD_NAND + help + This enables the Blackfin on-chip NAND flash controller + + No board specific support is done by this driver, each board + must advertise a platform_device for the driver to attach. + + This driver can also be built as a module. If so, the module + will be called bf5xx-nand. + +config MTD_NAND_BF5XX_HWECC + bool "BF5XX NAND Hardware ECC" + depends on MTD_NAND_BF5XX + help + Enable the use of the BF5XX's internal ECC generator when + using NAND. + config MTD_NAND_RTC_FROM4 tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)" depends on SH_SOLUTION_ENGINE @@ -134,10 +153,10 @@ config MTD_NAND_S3C2410_HWECC config MTD_NAND_NDFC tristate "NDFC NanD Flash Controller" - depends on 44x + depends on 4xx && !PPC_MERGE select MTD_NAND_ECC_SMC help - NDFC Nand Flash Controllers are integrated in EP44x SoCs + NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs config MTD_NAND_S3C2410_CLKSTOP bool "S3C2410 NAND IDLE clock stop" @@ -237,7 +256,7 @@ config MTD_NAND_CAFE select REED_SOLOMON select REED_SOLOMON_DEC16 help - Use NAND flash attached to the CAFÉ chip designed for the $100 + Use NAND flash attached to the CAFÉ chip designed for the OLPC laptop. config MTD_NAND_CS553X @@ -280,5 +299,11 @@ config MTD_NAND_PLATFORM devices. You will need to provide platform-specific functions via platform_data. +config MTD_ALAUDA + tristate "MTD driver for Olympus MAUSB-10 and Fijufilm DPC-R1" + depends on MTD_NAND && USB + help + These two (and possibly other) Alauda-based cardreaders for + SmartMedia and xD allow raw flash access. endif # MTD_NAND diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index edba1db14bf..3ad6c0165da 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_NAND_TOTO) += toto.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o +obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o @@ -27,5 +28,6 @@ obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o +obj-$(CONFIG_MTD_ALAUDA) += alauda.o nand-objs := nand_base.o nand_bbt.o diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c new file mode 100644 index 00000000000..257937cd99b --- /dev/null +++ b/drivers/mtd/nand/alauda.c @@ -0,0 +1,742 @@ +/* + * MTD driver for Alauda chips + * + * Copyright (C) 2007 Joern Engel <joern@logfs.org> + * + * Based on drivers/usb/usb-skeleton.c which is: + * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) + * and on drivers/usb/storage/alauda.c, which is: + * (c) 2005 Daniel Drake <dsd@gentoo.org> + * + * Idea and initial work by Arnd Bergmann <arnd@arndb.de> + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kref.h> +#include <linux/usb.h> +#include <linux/mutex.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand_ecc.h> + +/* Control commands */ +#define ALAUDA_GET_XD_MEDIA_STATUS 0x08 +#define ALAUDA_ACK_XD_MEDIA_CHANGE 0x0a +#define ALAUDA_GET_XD_MEDIA_SIG 0x86 + +/* Common prefix */ +#define ALAUDA_BULK_CMD 0x40 + +/* The two ports */ +#define ALAUDA_PORT_XD 0x00 +#define ALAUDA_PORT_SM 0x01 + +/* Bulk commands */ +#define ALAUDA_BULK_READ_PAGE 0x84 +#define ALAUDA_BULK_READ_OOB 0x85 /* don't use, there's a chip bug */ +#define ALAUDA_BULK_READ_BLOCK 0x94 +#define ALAUDA_BULK_ERASE_BLOCK 0xa3 +#define ALAUDA_BULK_WRITE_PAGE 0xa4 +#define ALAUDA_BULK_WRITE_BLOCK 0xb4 +#define ALAUDA_BULK_RESET_MEDIA 0xe0 + +/* Address shifting */ +#define PBA_LO(pba) ((pba & 0xF) << 5) +#define PBA_HI(pba) (pba >> 3) +#define PBA_ZONE(pba) (pba >> 11) + +#define TIMEOUT HZ + +static struct usb_device_id alauda_table [] = { + { USB_DEVICE(0x0584, 0x0008) }, /* Fujifilm DPC-R1 */ + { USB_DEVICE(0x07b4, 0x010a) }, /* Olympus MAUSB-10 */ + { } +}; +MODULE_DEVICE_TABLE(usb, alauda_table); + +struct alauda_card { + u8 id; /* id byte */ + u8 chipshift; /* 1<<chipshift total size */ + u8 pageshift; /* 1<<pageshift page size */ + u8 blockshift; /* 1<<blockshift block size */ +}; + +struct alauda { + struct usb_device *dev; + struct usb_interface *interface; + struct mtd_info *mtd; + struct alauda_card *card; + struct mutex card_mutex; + u32 pagemask; + u32 bytemask; + u32 blockmask; + unsigned int write_out; + unsigned int bulk_in; + unsigned int bulk_out; + u8 port; + struct kref kref; +}; + +static struct alauda_card alauda_card_ids[] = { + /* NAND flash */ + { 0x6e, 20, 8, 12}, /* 1 MB */ + { 0xe8, 20, 8, 12}, /* 1 MB */ + { 0xec, 20, 8, 12}, /* 1 MB */ + { 0x64, 21, 8, 12}, /* 2 MB */ + { 0xea, 21, 8, 12}, /* 2 MB */ + { 0x6b, 22, 9, 13}, /* 4 MB */ + { 0xe3, 22, 9, 13}, /* 4 MB */ + { 0xe5, 22, 9, 13}, /* 4 MB */ + { 0xe6, 23, 9, 13}, /* 8 MB */ + { 0x73, 24, 9, 14}, /* 16 MB */ + { 0x75, 25, 9, 14}, /* 32 MB */ + { 0x76, 26, 9, 14}, /* 64 MB */ + { 0x79, 27, 9, 14}, /* 128 MB */ + { 0x71, 28, 9, 14}, /* 256 MB */ + + /* MASK ROM */ + { 0x5d, 21, 9, 13}, /* 2 MB */ + { 0xd5, 22, 9, 13}, /* 4 MB */ + { 0xd6, 23, 9, 13}, /* 8 MB */ + { 0x57, 24, 9, 13}, /* 16 MB */ + { 0x58, 25, 9, 13}, /* 32 MB */ + { } +}; + +static struct alauda_card *get_card(u8 id) +{ + struct alauda_card *card; + + for (card = alauda_card_ids; card->id; card++) + if (card->id == id) + return card; + return NULL; +} + +static void alauda_delete(struct kref *kref) +{ + struct alauda *al = container_of(kref, struct alauda, kref); + + if (al->mtd) { + del_mtd_device(al->mtd); + kfree(al->mtd); + } + usb_put_dev(al->dev); + kfree(al); +} + +static int alauda_get_media_status(struct alauda *al, void *buf) +{ + int ret; + + mutex_lock(&al->card_mutex); + ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0), + ALAUDA_GET_XD_MEDIA_STATUS, 0xc0, 0, 1, buf, 2, HZ); + mutex_unlock(&al->card_mutex); + return ret; +} + +static int alauda_ack_media(struct alauda *al) +{ + int ret; + + mutex_lock(&al->card_mutex); + ret = usb_control_msg(al->dev, usb_sndctrlpipe(al->dev, 0), + ALAUDA_ACK_XD_MEDIA_CHANGE, 0x40, 0, 1, NULL, 0, HZ); + mutex_unlock(&al->card_mutex); + return ret; +} + +static int alauda_get_media_signatures(struct alauda *al, void *buf) +{ + int ret; + + mutex_lock(&al->card_mutex); + ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0), + ALAUDA_GET_XD_MEDIA_SIG, 0xc0, 0, 0, buf, 4, HZ); + mutex_unlock(&al->card_mutex); + return ret; +} + +static void alauda_reset(struct alauda *al) +{ + u8 command[] = { + ALAUDA_BULK_CMD, ALAUDA_BULK_RESET_MEDIA, 0, 0, + 0, 0, 0, 0, al->port + }; + mutex_lock(&al->card_mutex); + usb_bulk_msg(al->dev, al->bulk_out, command, 9, NULL, HZ); + mutex_unlock(&al->card_mutex); +} + +static void correct_data(void *buf, void *read_ecc, + int *corrected, int *uncorrected) +{ + u8 calc_ecc[3]; + int err; + + nand_calculate_ecc(NULL, buf, calc_ecc); + err = nand_correct_data(NULL, buf, read_ecc, calc_ecc); + if (err) { + if (err > 0) + (*corrected)++; + else + (*uncorrected)++; + } +} + +struct alauda_sg_request { + struct urb *urb[3]; + struct completion comp; +}; + +static void alauda_complete(struct urb *urb) +{ + struct completion *comp = urb->context; + + if (comp) + complete(comp); +} + +static int __alauda_read_page(struct mtd_info *mtd, loff_t from, void *buf, + void *oob) +{ + struct alauda_sg_request sg; + struct alauda *al = mtd->priv; + u32 pba = from >> al->card->blockshift; + u32 page = (from >> al->card->pageshift) & al->pagemask; + u8 command[] = { + ALAUDA_BULK_CMD, ALAUDA_BULK_READ_PAGE, PBA_HI(pba), + PBA_ZONE(pba), 0, PBA_LO(pba) + page, 1, 0, al->port + }; + int i, err; + + for (i=0; i<3; i++) + sg.urb[i] = NULL; + + err = -ENOMEM; + for (i=0; i<3; i++) { + sg.urb[i] = usb_alloc_urb(0, GFP_NOIO); + if (!sg.urb[i]) + goto out; + } + init_completion(&sg.comp); + usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9, + alauda_complete, NULL); + usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, mtd->writesize, + alauda_complete, NULL); + usb_fill_bulk_urb(sg.urb[2], al->dev, al->bulk_in, oob, 16, + alauda_complete, &sg.comp); + + mutex_lock(&al->card_mutex); + for (i=0; i<3; i++) { + err = usb_submit_urb(sg.urb[i], GFP_NOIO); + if (err) + goto cancel; + } + if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) { + err = -ETIMEDOUT; +cancel: + for (i=0; i<3; i++) { + usb_kill_urb(sg.urb[i]); + } + } + mutex_unlock(&al->card_mutex); + +out: + usb_free_urb(sg.urb[0]); + usb_free_urb(sg.urb[1]); + usb_free_urb(sg.urb[2]); + return err; +} + +static int alauda_read_page(struct mtd_info *mtd, loff_t from, + void *buf, u8 *oob, int *corrected, int *uncorrected) +{ + int err; + + err = __alauda_read_page(mtd, from, buf, oob); + if (err) + return err; + correct_data(buf, oob+13, corrected, uncorrected); + correct_data(buf+256, oob+8, corrected, uncorrected); + return 0; +} + +static int alauda_write_page(struct mtd_info *mtd, loff_t to, void *buf, + void *oob) +{ + struct alauda_sg_request sg; + struct alauda *al = mtd->priv; + u32 pba = to >> al->card->blockshift; + u32 page = (to >> al->card->pageshift) & al->pagemask; + u8 command[] = { + ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_PAGE, PBA_HI(pba), + PBA_ZONE(pba), 0, PBA_LO(pba) + page, 32, 0, al->port + }; + int i, err; + + for (i=0; i<3; i++) + sg.urb[i] = NULL; + + err = -ENOMEM; + for (i=0; i<3; i++) { + sg.urb[i] = usb_alloc_urb(0, GFP_NOIO); + if (!sg.urb[i]) + goto out; + } + init_completion(&sg.comp); + usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9, + alauda_complete, NULL); + usb_fill_bulk_urb(sg.urb[1], al->dev, al->write_out, buf,mtd->writesize, + alauda_complete, NULL); + usb_fill_bulk_urb(sg.urb[2], al->dev, al->write_out, oob, 16, + alauda_complete, &sg.comp); + + mutex_lock(&al->card_mutex); + for (i=0; i<3; i++) { + err = usb_submit_urb(sg.urb[i], GFP_NOIO); + if (err) + goto cancel; + } + if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) { + err = -ETIMEDOUT; +cancel: + for (i=0; i<3; i++) { + usb_kill_urb(sg.urb[i]); + } + } + mutex_unlock(&al->card_mutex); + +out: + usb_free_urb(sg.urb[0]); + usb_free_urb(sg.urb[1]); + usb_free_urb(sg.urb[2]); + return err; +} + +static int alauda_erase_block(struct mtd_info *mtd, loff_t ofs) +{ + struct alauda_sg_request sg; + struct alauda *al = mtd->priv; + u32 pba = ofs >> al->card->blockshift; + u8 command[] = { + ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba), + PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, al->port + }; + u8 buf[2]; + int i, err; + + for (i=0; i<2; i++) + sg.urb[i] = NULL; + + err = -ENOMEM; + for (i=0; i<2; i++) { + sg.urb[i] = usb_alloc_urb(0, GFP_NOIO); + if (!sg.urb[i]) + goto out; + } + init_completion(&sg.comp); + usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9, + alauda_complete, NULL); + usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, 2, + alauda_complete, &sg.comp); + + mutex_lock(&al->card_mutex); + for (i=0; i<2; i++) { + err = usb_submit_urb(sg.urb[i], GFP_NOIO); + if (err) + goto cancel; + } + if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) { + err = -ETIMEDOUT; +cancel: + for (i=0; i<2; i++) { + usb_kill_urb(sg.urb[i]); + } + } + mutex_unlock(&al->card_mutex); + +out: + usb_free_urb(sg.urb[0]); + usb_free_urb(sg.urb[1]); + return err; +} + +static int alauda_read_oob(struct mtd_info *mtd, loff_t from, void *oob) +{ + static u8 ignore_buf[512]; /* write only */ + + return __alauda_read_page(mtd, from, ignore_buf, oob); +} + +static int popcount8(u8 c) +{ + int ret = 0; + + for ( ; c; c>>=1) + ret += c & 1; + return ret; +} + +static int alauda_isbad(struct mtd_info *mtd, loff_t ofs) +{ + u8 oob[16]; + int err; + + err = alauda_read_oob(mtd, ofs, oob); + if (err) + return err; + + /* A block is marked bad if two or more bits are zero */ + return popcount8(oob[5]) >= 7 ? 0 : 1; +} + +static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct alauda *al = mtd->priv; + void *bounce_buf; + int err, corrected=0, uncorrected=0; + + bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL); + if (!bounce_buf) + return -ENOMEM; + + *retlen = len; + while (len) { + u8 oob[16]; + size_t byte = from & al->bytemask; + size_t cplen = min(len, mtd->writesize - byte); + + err = alauda_read_page(mtd, from, bounce_buf, oob, + &corrected, &uncorrected); + if (err) + goto out; + + memcpy(buf, bounce_buf + byte, cplen); + buf += cplen; + from += cplen; + len -= cplen; + } + err = 0; + if (corrected) + err = -EUCLEAN; + if (uncorrected) + err = -EBADMSG; +out: + kfree(bounce_buf); + return err; +} + +static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct alauda *al = mtd->priv; + int err, corrected=0, uncorrected=0; + + if ((from & al->bytemask) || (len & al->bytemask)) + return alauda_bounce_read(mtd, from, len, retlen, buf); + + *retlen = len; + while (len) { + u8 oob[16]; + + err = alauda_read_page(mtd, from, buf, oob, + &corrected, &uncorrected); + if (err) + return err; + + buf += mtd->writesize; + from += mtd->writesize; + len -= mtd->writesize; + } + err = 0; + if (corrected) + err = -EUCLEAN; + if (uncorrected) + err = -EBADMSG; + return err; +} + +static int alauda_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct alauda *al = mtd->priv; + int err; + + if ((to & al->bytemask) || (len & al->bytemask)) + return -EINVAL; + + *retlen = len; + while (len) { + u32 page = (to >> al->card->pageshift) & al->pagemask; + u8 oob[16] = { 'h', 'e', 'l', 'l', 'o', 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + /* don't write to bad blocks */ + if (page == 0) { + err = alauda_isbad(mtd, to); + if (err) { + return -EIO; + } + } + nand_calculate_ecc(mtd, buf, &oob[13]); + nand_calculate_ecc(mtd, buf+256, &oob[8]); + + err = alauda_write_page(mtd, to, (void*)buf, oob); + if (err) + return err; + + buf += mtd->writesize; + to += mtd->writesize; + len -= mtd->writesize; + } + return 0; +} + +static int __alauda_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct alauda *al = mtd->priv; + u32 ofs = instr->addr; + u32 len = instr->len; + int err; + + if ((ofs & al->blockmask) || (len & al->blockmask)) + return -EINVAL; + + while (len) { + /* don't erase bad blocks */ + err = alauda_isbad(mtd, ofs); + if (err > 0) + err = -EIO; + if (err < 0) + return err; + + err = alauda_erase_block(mtd, ofs); + if (err < 0) + return err; + + ofs += mtd->erasesize; + len -= mtd->erasesize; + } + return 0; +} + +static int alauda_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + int err; + + err = __alauda_erase(mtd, instr); + instr->state = err ? MTD_ERASE_FAILED : MTD_ERASE_DONE; + mtd_erase_callback(instr); + return err; +} + +static int alauda_init_media(struct alauda *al) +{ + u8 buf[4], *b0=buf, *b1=buf+1; + struct alauda_card *card; + struct mtd_info *mtd; + int err; + + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); + if (!mtd) + return -ENOMEM; + + for (;;) { + err = alauda_get_media_status(al, buf); + if (err < 0) + goto error; + if (*b0 & 0x10) + break; + msleep(20); + } + + err = alauda_ack_media(al); + if (err) + goto error; + + msleep(10); + + err = alauda_get_media_status(al, buf); + if (err < 0) + goto error; + + if (*b0 != 0x14) { + /* media not ready */ + err = -EIO; + goto error; + } + err = alauda_get_media_signatures(al, buf); + if (err < 0) + goto error; + + card = get_card(*b1); + if (!card) { + printk(KERN_ERR"Alauda: unknown card id %02x\n", *b1); + err = -EIO; + goto error; + } + printk(KERN_INFO"pagesize=%x\nerasesize=%x\nsize=%xMiB\n", + 1<<card->pageshift, 1<<card->blockshift, + 1<<(card->chipshift-20)); + al->card = card; + al->pagemask = (1 << (card->blockshift - card->pageshift)) - 1; + al->bytemask = (1 << card->pageshift) - 1; + al->blockmask = (1 << card->blockshift) - 1; + + mtd->name = "alauda"; + mtd->size = 1<<card->chipshift; + mtd->erasesize = 1<<card->blockshift; + mtd->writesize = 1<<card->pageshift; + mtd->type = MTD_NANDFLASH; + mtd->flags = MTD_CAP_NANDFLASH; + mtd->read = alauda_read; + mtd->write = alauda_write; + mtd->erase = alauda_erase; + mtd->block_isbad = alauda_isbad; + mtd->priv = al; + mtd->owner = THIS_MODULE; + + err = add_mtd_device(mtd); + if (err) { + err = -ENFILE; + goto error; + } + + al->mtd = mtd; + alauda_reset(al); /* no clue whether this is necessary */ + return 0; +error: + kfree(mtd); + return err; +} + +static int alauda_check_media(struct alauda *al) +{ + u8 buf[2], *b0 = buf, *b1 = buf+1; + int err; + + err = alauda_get_media_status(al, buf); + if (err < 0) + return err; + + if ((*b1 & 0x01) == 0) { + /* door open */ + return -EIO; + } + if ((*b0 & 0x80) || ((*b0 & 0x1F) == 0x10)) { + /* no media ? */ + return -EIO; + } + if (*b0 & 0x08) { + /* media change ? */ + return alauda_init_media(al); + } + return 0; +} + +static int alauda_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct alauda *al; + struct usb_host_interface *iface; + struct usb_endpoint_descriptor *ep, + *ep_in=NULL, *ep_out=NULL, *ep_wr=NULL; + int i, err = -ENOMEM; + + al = kzalloc(2*sizeof(*al), GFP_KERNEL); + if (!al) + goto error; + + kref_init(&al->kref); + usb_set_intfdata(interface, al); + + al->dev = usb_get_dev(interface_to_usbdev(interface)); + al->interface = interface; + + iface = interface->cur_altsetting; + for (i = 0; i < iface->desc.bNumEndpoints; ++i) { + ep = &iface->endpoint[i].desc; + + if (usb_endpoint_is_bulk_in(ep)) { + ep_in = ep; + } else if (usb_endpoint_is_bulk_out(ep)) { + if (i==0) + ep_wr = ep; + else + ep_out = ep; + } + } + err = -EIO; + if (!ep_wr || !ep_in || !ep_out) + goto error; + + al->write_out = usb_sndbulkpipe(al->dev, + ep_wr->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + al->bulk_in = usb_rcvbulkpipe(al->dev, + ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + al->bulk_out = usb_sndbulkpipe(al->dev, + ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + + /* second device is identical up to now */ + memcpy(al+1, al, sizeof(*al)); + + mutex_init(&al[0].card_mutex); + mutex_init(&al[1].card_mutex); + + al[0].port = ALAUDA_PORT_XD; + al[1].port = ALAUDA_PORT_SM; + + info("alauda probed"); + alauda_check_media(al); + alauda_check_media(al+1); + + return 0; + +error: + if (al) + kref_put(&al->kref, alauda_delete); + return err; +} + +static void alauda_disconnect(struct usb_interface *interface) +{ + struct alauda *al; + + al = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + /* FIXME: prevent more I/O from starting */ + + /* decrement our usage count */ + if (al) + kref_put(&al->kref, alauda_delete); + + info("alauda gone"); +} + +static struct usb_driver alauda_driver = { + .name = "alauda", + .probe = alauda_probe, + .disconnect = alauda_disconnect, + .id_table = alauda_table, +}; + +static int __init alauda_init(void) +{ + return usb_register(&alauda_driver); +} + +static void __exit alauda_exit(void) +{ + usb_deregister(&alauda_driver); +} + +module_init(alauda_init); +module_exit(alauda_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c new file mode 100644 index 00000000000..1657ecd7488 --- /dev/null +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -0,0 +1,788 @@ +/* linux/drivers/mtd/nand/bf5xx_nand.c + * + * Copyright 2006-2007 Analog Devices Inc. + * http://blackfin.uclinux.org/ + * Bryan Wu <bryan.wu@analog.com> + * + * Blackfin BF5xx on-chip NAND flash controler driver + * + * Derived from drivers/mtd/nand/s3c2410.c + * Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk> + * + * Derived from drivers/mtd/nand/cafe.c + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> + * + * Changelog: + * 12-Jun-2007 Bryan Wu: Initial version + * 18-Jul-2007 Bryan Wu: + * - ECC_HW and ECC_SW supported + * - DMA supported in ECC_HW + * - YAFFS tested as rootfs in both ECC_HW and ECC_SW + * + * TODO: + * Enable JFFS2 over NAND as rootfs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/bitops.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +#include <asm/blackfin.h> +#include <asm/dma.h> +#include <asm/cacheflush.h> +#include <asm/nand.h> +#include <asm/portmux.h> + +#define DRV_NAME "bf5xx-nand" +#define DRV_VERSION "1.2" +#define DRV_AUTHOR "Bryan Wu <bryan.wu@analog.com>" +#define DRV_DESC "BF5xx on-chip NAND FLash Controller Driver" + +#ifdef CONFIG_MTD_NAND_BF5XX_HWECC +static int hardware_ecc = 1; +#else +static int hardware_ecc; +#endif + +static unsigned short bfin_nfc_pin_req[] = {P_NAND_CE, P_NAND_RB, 0}; + +/* + * Data structures for bf5xx nand flash controller driver + */ + +/* bf5xx nand info */ +struct bf5xx_nand_info { + /* mtd info */ + struct nand_hw_control controller; + struct mtd_info mtd; + struct nand_chip chip; + + /* platform info */ + struct bf5xx_nand_platform *platform; + + /* device info */ + struct device *device; + + /* DMA stuff */ + struct completion dma_completion; +}; + +/* + * Conversion functions + */ +static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd) +{ + return container_of(mtd, struct bf5xx_nand_info, mtd); +} + +static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev) +{ + return platform_get_drvdata(pdev); +} + +static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev) +{ + return pdev->dev.platform_data; +} + +/* + * struct nand_chip interface function pointers + */ + +/* + * bf5xx_nand_hwcontrol + * + * Issue command and address cycles to the chip + */ +static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + if (cmd == NAND_CMD_NONE) + return; + + while (bfin_read_NFC_STAT() & WB_FULL) + cpu_relax(); + + if (ctrl & NAND_CLE) + bfin_write_NFC_CMD(cmd); + else + bfin_write_NFC_ADDR(cmd); + SSYNC(); +} + +/* + * bf5xx_nand_devready() + * + * returns 0 if the nand is busy, 1 if it is ready + */ +static int bf5xx_nand_devready(struct mtd_info *mtd) +{ + unsigned short val = bfin_read_NFC_IRQSTAT(); + + if ((val & NBUSYIRQ) == NBUSYIRQ) + return 1; + else + return 0; +} + +/* + * ECC functions + * These allow the bf5xx to use the controller's ECC + * generator block to ECC the data as it passes through + */ + +/* + * ECC error correction function + */ +static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); + u32 syndrome[5]; + u32 calced, stored; + int i; + unsigned short failing_bit, failing_byte; + u_char data; + + calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16); + stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16); + + syndrome[0] = (calced ^ stored); + + /* + * syndrome 0: all zero + * No error in data + * No action + */ + if (!syndrome[0] || !calced || !stored) + return 0; + + /* + * sysdrome 0: only one bit is one + * ECC data was incorrect + * No action + */ + if (hweight32(syndrome[0]) == 1) { + dev_err(info->device, "ECC data was incorrect!\n"); + return 1; + } + + syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF); + syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF); + syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF); + syndrome[4] = syndrome[2] ^ syndrome[3]; + + for (i = 0; i < 5; i++) + dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]); + + dev_info(info->device, + "calced[0x%08x], stored[0x%08x]\n", + calced, stored); + + /* + * sysdrome 0: exactly 11 bits are one, each parity + * and parity' pair is 1 & 0 or 0 & 1. + * 1-bit correctable error + * Correct the error + */ + if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) { + dev_info(info->device, + "1-bit correctable error, correct it.\n"); + dev_info(info->device, + "syndrome[1] 0x%08x\n", syndrome[1]); + + failing_bit = syndrome[1] & 0x7; + failing_byte = syndrome[1] >> 0x3; + data = *(dat + failing_byte); + data = data ^ (0x1 << failing_bit); + *(dat + failing_byte) = data; + + return 0; + } + + /* + * sysdrome 0: random data + * More than 1-bit error, non-correctable error + * Discard data, mark bad block + */ + dev_err(info->device, + "More than 1-bit error, non-correctable error.\n"); + dev_err(info->device, + "Please discard data, mark bad block\n"); + + return 1; +} + +static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); + struct bf5xx_nand_platform *plat = info->platform; + unsigned short page_size = (plat->page_size ? 512 : 256); + int ret; + + ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); + + /* If page size is 512, correct second 256 bytes */ + if (page_size == 512) { + dat += 256; + read_ecc += 8; + calc_ecc += 8; + ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); + } + + return ret; +} + +static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + return; +} + +static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, + const u_char *dat, u_char *ecc_code) +{ + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); + struct bf5xx_nand_platform *plat = info->platform; + u16 page_size = (plat->page_size ? 512 : 256); + u16 ecc0, ecc1; + u32 code[2]; + u8 *p; + int bytes = 3, i; + + /* first 4 bytes ECC code for 256 page size */ + ecc0 = bfin_read_NFC_ECC0(); + ecc1 = bfin_read_NFC_ECC1(); + + code[0] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); + + dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); + + /* second 4 bytes ECC code for 512 page size */ + if (page_size == 512) { + ecc0 = bfin_read_NFC_ECC2(); + ecc1 = bfin_read_NFC_ECC3(); + code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); + bytes = 6; + dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]); + } + + p = (u8 *)code; + for (i = 0; i < bytes; i++) + ecc_code[i] = p[i]; + + return 0; +} + +/* + * PIO mode for buffer writing and reading + */ +static void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int i; + unsigned short val; + + /* + * Data reads are requested by first writing to NFC_DATA_RD + * and then reading back from NFC_READ. + */ + for (i = 0; i < len; i++) { + while (bfin_read_NFC_STAT() & WB_FULL) + cpu_relax(); + + /* Contents do not matter */ + bfin_write_NFC_DATA_RD(0x0000); + SSYNC(); + + while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY) + cpu_relax(); + + buf[i] = bfin_read_NFC_READ(); + + val = bfin_read_NFC_IRQSTAT(); + val |= RD_RDY; + bfin_write_NFC_IRQSTAT(val); + SSYNC(); + } +} + +static uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd) +{ + uint8_t val; + + bf5xx_nand_read_buf(mtd, &val, 1); + + return val; +} + +static void bf5xx_nand_write_buf(struct mtd_info *mtd, + const uint8_t *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) { + while (bfin_read_NFC_STAT() & WB_FULL) + cpu_relax(); + + bfin_write_NFC_DATA_WR(buf[i]); + SSYNC(); + } +} + +static void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int i; + u16 *p = (u16 *) buf; + len >>= 1; + + /* + * Data reads are requested by first writing to NFC_DATA_RD + * and then reading back from NFC_READ. + */ + bfin_write_NFC_DATA_RD(0x5555); + + SSYNC(); + + for (i = 0; i < len; i++) + p[i] = bfin_read_NFC_READ(); +} + +static void bf5xx_nand_write_buf16(struct mtd_info *mtd, + const uint8_t *buf, int len) +{ + int i; + u16 *p = (u16 *) buf; + len >>= 1; + + for (i = 0; i < len; i++) + bfin_write_NFC_DATA_WR(p[i]); + + SSYNC(); +} + +/* + * DMA functions for buffer writing and reading + */ +static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id) +{ + struct bf5xx_nand_info *info = dev_id; + + clear_dma_irqstat(CH_NFC); + disable_dma(CH_NFC); + complete(&info->dma_completion); + + return IRQ_HANDLED; +} + +static int bf5xx_nand_dma_rw(struct mtd_info *mtd, + uint8_t *buf, int is_read) +{ + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); + struct bf5xx_nand_platform *plat = info->platform; + unsigned short page_size = (plat->page_size ? 512 : 256); + unsigned short val; + + dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n", + mtd, buf, is_read); + + /* + * Before starting a dma transfer, be sure to invalidate/flush + * the cache over the address range of your DMA buffer to + * prevent cache coherency problems. Otherwise very subtle bugs + * can be introduced to your driver. + */ + if (is_read) + invalidate_dcache_range((unsigned int)buf, + (unsigned int)(buf + page_size)); + else + flush_dcache_range((unsigned int)buf, + (unsigned int)(buf + page_size)); + + /* + * This register must be written before each page is + * transferred to generate the correct ECC register + * values. + */ + bfin_write_NFC_RST(0x1); + SSYNC(); + + disable_dma(CH_NFC); + clear_dma_irqstat(CH_NFC); + + /* setup DMA register with Blackfin DMA API */ + set_dma_config(CH_NFC, 0x0); + set_dma_start_addr(CH_NFC, (unsigned long) buf); + set_dma_x_count(CH_NFC, (page_size >> 2)); + set_dma_x_modify(CH_NFC, 4); + + /* setup write or read operation */ + val = DI_EN | WDSIZE_32; + if (is_read) + val |= WNR; + set_dma_config(CH_NFC, val); + enable_dma(CH_NFC); + + /* Start PAGE read/write operation */ + if (is_read) + bfin_write_NFC_PGCTL(0x1); + else + bfin_write_NFC_PGCTL(0x2); + wait_for_completion(&info->dma_completion); + + return 0; +} + +static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd, + uint8_t *buf, int len) +{ + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); + struct bf5xx_nand_platform *plat = info->platform; + unsigned short page_size = (plat->page_size ? 512 : 256); + + dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len); + + if (len == page_size) + bf5xx_nand_dma_rw(mtd, buf, 1); + else + bf5xx_nand_read_buf(mtd, buf, len); +} + +static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd, + const uint8_t *buf, int len) +{ + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); + struct bf5xx_nand_platform *plat = info->platform; + unsigned short page_size = (plat->page_size ? 512 : 256); + + dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len); + + if (len == page_size) + bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0); + else + bf5xx_nand_write_buf(mtd, buf, len); +} + +/* + * System initialization functions + */ + +static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info) +{ + int ret; + unsigned short val; + + /* Do not use dma */ + if (!hardware_ecc) + return 0; + + init_completion(&info->dma_completion); + + /* Setup DMAC1 channel mux for NFC which shared with SDH */ + val = bfin_read_DMAC1_PERIMUX(); + val &= 0xFFFE; + bfin_write_DMAC1_PERIMUX(val); + SSYNC(); + + /* Request NFC DMA channel */ + ret = request_dma(CH_NFC, "BF5XX NFC driver"); + if (ret < 0) { + dev_err(info->device, " unable to get DMA channel\n"); + return ret; + } + + set_dma_callback(CH_NFC, (void *) bf5xx_nand_dma_irq, (void *) info); + + /* Turn off the DMA channel first */ + disable_dma(CH_NFC); + return 0; +} + +/* + * BF5XX NFC hardware initialization + * - pin mux setup + * - clear interrupt status + */ +static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info) +{ + int err = 0; + unsigned short val; + struct bf5xx_nand_platform *plat = info->platform; + + /* setup NFC_CTL register */ + dev_info(info->device, + "page_size=%d, data_width=%d, wr_dly=%d, rd_dly=%d\n", + (plat->page_size ? 512 : 256), + (plat->data_width ? 16 : 8), + plat->wr_dly, plat->rd_dly); + + val = (plat->page_size << NFC_PG_SIZE_OFFSET) | + (plat->data_width << NFC_NWIDTH_OFFSET) | + (plat->rd_dly << NFC_RDDLY_OFFSET) | + (plat->rd_dly << NFC_WRDLY_OFFSET); + dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val); + + bfin_write_NFC_CTL(val); + SSYNC(); + + /* clear interrupt status */ + bfin_write_NFC_IRQMASK(0x0); + SSYNC(); + val = bfin_read_NFC_IRQSTAT(); + bfin_write_NFC_IRQSTAT(val); + SSYNC(); + + if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { + printk(KERN_ERR DRV_NAME + ": Requesting Peripherals failed\n"); + return -EFAULT; + } + + /* DMA initialization */ + if (bf5xx_nand_dma_init(info)) + err = -ENXIO; + + return err; +} + +/* + * Device management interface + */ +static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info) +{ + struct mtd_info *mtd = &info->mtd; + +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *parts = info->platform->partitions; + int nr = info->platform->nr_partitions; + + return add_mtd_partitions(mtd, parts, nr); +#else + return add_mtd_device(mtd); +#endif +} + +static int bf5xx_nand_remove(struct platform_device *pdev) +{ + struct bf5xx_nand_info *info = to_nand_info(pdev); + struct mtd_info *mtd = NULL; + + platform_set_drvdata(pdev, NULL); + + /* first thing we need to do is release all our mtds + * and their partitions, then go through freeing the + * resources used + */ + mtd = &info->mtd; + if (mtd) { + nand_release(mtd); + kfree(mtd); + } + + peripheral_free_list(bfin_nfc_pin_req); + + /* free the common resources */ + kfree(info); + + return 0; +} + +/* + * bf5xx_nand_probe + * + * called by device layer when it finds a device matching + * one our driver can handled. This code checks to see if + * it can allocate all necessary resources then calls the + * nand layer to look for devices + */ +static int bf5xx_nand_probe(struct platform_device *pdev) +{ + struct bf5xx_nand_platform *plat = to_nand_plat(pdev); + struct bf5xx_nand_info *info = NULL; + struct nand_chip *chip = NULL; + struct mtd_info *mtd = NULL; + int err = 0; + + dev_dbg(&pdev->dev, "(%p)\n", pdev); + + if (!plat) { + dev_err(&pdev->dev, "no platform specific information\n"); + goto exit_error; + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + dev_err(&pdev->dev, "no memory for flash info\n"); + err = -ENOMEM; + goto exit_error; + } + + platform_set_drvdata(pdev, info); + + spin_lock_init(&info->controller.lock); + init_waitqueue_head(&info->controller.wq); + + info->device = &pdev->dev; + info->platform = plat; + + /* initialise chip data struct */ + chip = &info->chip; + + if (plat->data_width) + chip->options |= NAND_BUSWIDTH_16; + + chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN; + + chip->read_buf = (plat->data_width) ? + bf5xx_nand_read_buf16 : bf5xx_nand_read_buf; + chip->write_buf = (plat->data_width) ? + bf5xx_nand_write_buf16 : bf5xx_nand_write_buf; + + chip->read_byte = bf5xx_nand_read_byte; + + chip->cmd_ctrl = bf5xx_nand_hwcontrol; + chip->dev_ready = bf5xx_nand_devready; + + chip->priv = &info->mtd; + chip->controller = &info->controller; + + chip->IO_ADDR_R = (void __iomem *) NFC_READ; + chip->IO_ADDR_W = (void __iomem *) NFC_DATA_WR; + + chip->chip_delay = 0; + + /* initialise mtd info data struct */ + mtd = &info->mtd; + mtd->priv = chip; + mtd->owner = THIS_MODULE; + + /* initialise the hardware */ + err = bf5xx_nand_hw_init(info); + if (err != 0) + goto exit_error; + + /* setup hardware ECC data struct */ + if (hardware_ecc) { + if (plat->page_size == NFC_PG_SIZE_256) { + chip->ecc.bytes = 3; + chip->ecc.size = 256; + } else if (plat->page_size == NFC_PG_SIZE_512) { + chip->ecc.bytes = 6; + chip->ecc.size = 512; + } + + chip->read_buf = bf5xx_nand_dma_read_buf; + chip->write_buf = bf5xx_nand_dma_write_buf; + chip->ecc.calculate = bf5xx_nand_calculate_ecc; + chip->ecc.correct = bf5xx_nand_correct_data; + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.hwctl = bf5xx_nand_enable_hwecc; + } else { + chip->ecc.mode = NAND_ECC_SOFT; + } + + /* scan hardware nand chip and setup mtd info data struct */ + if (nand_scan(mtd, 1)) { + err = -ENXIO; + goto exit_error; + } + + /* add NAND partition */ + bf5xx_nand_add_partition(info); + + dev_dbg(&pdev->dev, "initialised ok\n"); + return 0; + +exit_error: + bf5xx_nand_remove(pdev); + + if (err == 0) + err = -EINVAL; + return err; +} + +/* PM Support */ +#ifdef CONFIG_PM + +static int bf5xx_nand_suspend(struct platform_device *dev, pm_message_t pm) +{ + struct bf5xx_nand_info *info = platform_get_drvdata(dev); + + return 0; +} + +static int bf5xx_nand_resume(struct platform_device *dev) +{ + struct bf5xx_nand_info *info = platform_get_drvdata(dev); + + if (info) + bf5xx_nand_hw_init(info); + + return 0; +} + +#else +#define bf5xx_nand_suspend NULL +#define bf5xx_nand_resume NULL +#endif + +/* driver device registration */ +static struct platform_driver bf5xx_nand_driver = { + .probe = bf5xx_nand_probe, + .remove = bf5xx_nand_remove, + .suspend = bf5xx_nand_suspend, + .resume = bf5xx_nand_resume, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init bf5xx_nand_init(void) +{ + printk(KERN_INFO "%s, Version %s (c) 2007 Analog Devices, Inc.\n", + DRV_DESC, DRV_VERSION); + + return platform_driver_register(&bf5xx_nand_driver); +} + +static void __exit bf5xx_nand_exit(void) +{ + platform_driver_unregister(&bf5xx_nand_driver); +} + +module_init(bf5xx_nand_init); +module_exit(bf5xx_nand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION(DRV_DESC); diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 6f32a35eb10..e2832d0b989 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -623,6 +623,11 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, uint32_t ctrl; int err = 0; + /* Very old versions shared the same PCI ident for all three + functions on the chip. Verify the class too... */ + if ((pdev->class >> 8) != PCI_CLASS_MEMORY_FLASH) + return -ENODEV; + err = pci_enable_device(pdev); if (err) return err; @@ -816,21 +821,57 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev) } static struct pci_device_id cafe_nand_tbl[] = { - { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 }, - { 0, } + { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID }, + { } }; MODULE_DEVICE_TABLE(pci, cafe_nand_tbl); +static int cafe_nand_resume(struct pci_dev *pdev) +{ + uint32_t ctrl; + struct mtd_info *mtd = pci_get_drvdata(pdev); + struct cafe_priv *cafe = mtd->priv; + + /* Start off by resetting the NAND controller completely */ + cafe_writel(cafe, 1, NAND_RESET); + cafe_writel(cafe, 0, NAND_RESET); + cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK); + + /* Restore timing configuration */ + cafe_writel(cafe, timing[0], NAND_TIMING1); + cafe_writel(cafe, timing[1], NAND_TIMING2); + cafe_writel(cafe, timing[2], NAND_TIMING3); + + /* Disable master reset, enable NAND clock */ + ctrl = cafe_readl(cafe, GLOBAL_CTRL); + ctrl &= 0xffffeff0; + ctrl |= 0x00007000; + cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL); + cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL); + cafe_writel(cafe, 0, NAND_DMA_CTRL); + cafe_writel(cafe, 0x7006, GLOBAL_CTRL); + cafe_writel(cafe, 0x700a, GLOBAL_CTRL); + + /* Set up DMA address */ + cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0); + if (sizeof(cafe->dmaaddr) > 4) + /* Shift in two parts to shut the compiler up */ + cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1); + else + cafe_writel(cafe, 0, NAND_DMA_ADDR1); + + /* Enable NAND IRQ in global IRQ mask register */ + cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK); + return 0; +} + static struct pci_driver cafe_nand_pci_driver = { .name = "CAFÉ NAND", .id_table = cafe_nand_tbl, .probe = cafe_nand_probe, .remove = __devexit_p(cafe_nand_remove), -#ifdef CONFIG_PMx - .suspend = cafe_nand_suspend, .resume = cafe_nand_resume, -#endif }; static int cafe_nand_init(void) diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index e96259f22cc..ab9f5c5db38 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -56,8 +56,6 @@ static unsigned long __initdata doc_locations[] = { #endif /* CONFIG_MTD_DOCPROBE_HIGH */ #elif defined(__PPC__) 0xe4000000, -#elif defined(CONFIG_MOMENCO_OCELOT_G) - 0xff000000, #else #warning Unknown architecture for DiskOnChip. No default probe locations defined #endif diff --git a/drivers/mtd/nand/excite_nandflash.c b/drivers/mtd/nand/excite_nandflash.c index 7e9afc4c775..bed87290dec 100644 --- a/drivers/mtd/nand/excite_nandflash.c +++ b/drivers/mtd/nand/excite_nandflash.c @@ -27,7 +27,6 @@ #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/err.h> -#include <linux/kernel.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 24ac6778b1a..b4e0e772389 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -7,7 +7,7 @@ * Basic support for AG-AND chips is provided. * * Additional technical information is available on - * http://www.linux-mtd.infradead.org/tech/nand.html + * http://www.linux-mtd.infradead.org/doc/nand.html * * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * 2002-2006 Thomas Gleixner (tglx@linutronix.de) @@ -2069,13 +2069,14 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, erase_exit: ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; - /* Do call back function */ - if (!ret) - mtd_erase_callback(instr); /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); + /* Do call back function */ + if (!ret) + mtd_erase_callback(instr); + /* * If BBT requires refresh and erase was successful, rewrite any * selected bad block tables diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 2fc674a190c..a3e3ab0185d 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -141,6 +141,7 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_STMICRO, "ST Micro"}, {NAND_MFR_HYNIX, "Hynix"}, {NAND_MFR_MICRON, "Micron"}, + {NAND_MFR_AMD, "AMD"}, {0x0, "Unknown"} }; diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 205df0f771f..a7574807dc4 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -1272,7 +1272,13 @@ static int prog_page(struct nandsim *ns, int num) mypage = NS_GET_PAGE(ns); if (mypage->byte == NULL) { NS_DBG("prog_page: allocating page %d\n", ns->regs.row); - mypage->byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL); + /* + * We allocate memory with GFP_NOFS because a flash FS may + * utilize this. If it is holding an FS lock, then gets here, + * then kmalloc runs writeback which goes to the FS again + * and deadlocks. This was seen in practice. + */ + mypage->byte = kmalloc(ns->geom.pgszoob, GFP_NOFS); if (mypage->byte == NULL) { NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row); return -1; diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index fd7a8d5ba29..1c0e89f00e8 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -24,7 +24,11 @@ #include <linux/platform_device.h> #include <asm/io.h> +#ifdef CONFIG_40x +#include <asm/ibm405.h> +#else #include <asm/ibm44x.h> +#endif struct ndfc_nand_mtd { struct mtd_info mtd; @@ -230,7 +234,11 @@ static int ndfc_nand_probe(struct platform_device *pdev) struct ndfc_controller *ndfc = &ndfc_ctrl; unsigned long long phys = settings->ndfc_erpn | res->start; +#ifndef CONFIG_PHYS_64BIT + ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1); +#else ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1); +#endif if (!ndfc->ndfcbase) { printk(KERN_ERR "NDFC: ioremap failed\n"); return -EIO; diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 5fac4c421a2..b79a9cf2d16 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -60,8 +60,8 @@ #include <asm/io.h> -#include <asm/arch/regs-nand.h> -#include <asm/arch/nand.h> +#include <asm/plat-s3c/regs-nand.h> +#include <asm/plat-s3c/nand.h> #ifdef CONFIG_MTD_NAND_S3C2410_HWECC static int hardware_ecc = 1; diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig index c257d397d08..cb41cbca64f 100644 --- a/drivers/mtd/onenand/Kconfig +++ b/drivers/mtd/onenand/Kconfig @@ -40,4 +40,27 @@ config MTD_ONENAND_OTP OTP block is fully-guaranteed to be a valid block. +config MTD_ONENAND_2X_PROGRAM + bool "OneNAND 2X program support" + help + The 2X Program is an extension of Program Operation. + Since the device is equipped with two DataRAMs, and two-plane NAND + Flash memory array, these two component enables simultaneous program + of 4KiB. Plane1 has only even blocks such as block0, block2, block4 + while Plane2 has only odd blocks such as block1, block3, block5. + So MTD regards it as 4KiB page size and 256KiB block size + + Now the following chips support it. (KFXXX16Q2M) + Demux: KFG2G16Q2M, KFH4G16Q2M, KFW8G16Q2M, + Mux: KFM2G16Q2M, KFN4G16Q2M, + + And more recent chips + +config MTD_ONENAND_SIM + tristate "OneNAND simulator support" + depends on MTD_PARTITIONS + help + The simulator may simulate various OneNAND flash chips for the + OneNAND MTD layer. + endif # MTD_ONENAND diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile index 269cfe46734..4d2eacfd7e1 100644 --- a/drivers/mtd/onenand/Makefile +++ b/drivers/mtd/onenand/Makefile @@ -8,4 +8,7 @@ obj-$(CONFIG_MTD_ONENAND) += onenand.o # Board specific. obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o +# Simulator +obj-$(CONFIG_MTD_ONENAND_SIM) += onenand_sim.o + onenand-objs = onenand_base.o onenand_bbt.o diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 0537fac8de7..b2c40f67db8 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -206,6 +206,15 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le default: block = (int) (addr >> this->erase_shift); page = (int) (addr >> this->page_shift); + + if (ONENAND_IS_2PLANE(this)) { + /* Make the even block number */ + block &= ~1; + /* Is it the odd plane? */ + if (addr & this->writesize) + block++; + page >>= 1; + } page &= this->page_mask; break; } @@ -216,8 +225,12 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le value = onenand_bufferram_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); - /* Switch to the next data buffer */ - ONENAND_SET_NEXT_BUFFERRAM(this); + if (ONENAND_IS_2PLANE(this)) + /* It is always BufferRAM0 */ + ONENAND_SET_BUFFERRAM0(this); + else + /* Switch to the next data buffer */ + ONENAND_SET_NEXT_BUFFERRAM(this); return 0; } @@ -247,6 +260,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le break; default: + if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG) + cmd = ONENAND_CMD_2X_PROG; dataram = ONENAND_CURRENT_BUFFERRAM(this); break; } @@ -318,12 +333,14 @@ static int onenand_wait(struct mtd_info *mtd, int state) if (interrupt & ONENAND_INT_READ) { int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); if (ecc) { - printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc); if (ecc & ONENAND_ECC_2BIT_ALL) { + printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc); mtd->ecc_stats.failed++; return ecc; - } else if (ecc & ONENAND_ECC_1BIT_ALL) + } else if (ecc & ONENAND_ECC_1BIT_ALL) { + printk(KERN_INFO "onenand_wait: correctable ECC error = 0x%04x\n", ecc); mtd->ecc_stats.corrected++; + } } } else if (state == FL_READING) { printk(KERN_ERR "onenand_wait: read timeout! ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt); @@ -445,8 +462,9 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area) struct onenand_chip *this = mtd->priv; if (ONENAND_CURRENT_BUFFERRAM(this)) { + /* Note: the 'this->writesize' is a real page size */ if (area == ONENAND_DATARAM) - return mtd->writesize; + return this->writesize; if (area == ONENAND_SPARERAM) return mtd->oobsize; } @@ -572,6 +590,30 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area, } /** + * onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode + * @param mtd MTD data structure + * @param addr address to check + * @return blockpage address + * + * Get blockpage address at 2x program mode + */ +static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr) +{ + struct onenand_chip *this = mtd->priv; + int blockpage, block, page; + + /* Calculate the even block number */ + block = (int) (addr >> this->erase_shift) & ~1; + /* Is it the odd plane? */ + if (addr & this->writesize) + block++; + page = (int) (addr >> (this->page_shift + 1)) & this->page_mask; + blockpage = (block << 7) | page; + + return blockpage; +} + +/** * onenand_check_bufferram - [GENERIC] Check BufferRAM information * @param mtd MTD data structure * @param addr address to check @@ -585,7 +627,10 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr) int blockpage, found = 0; unsigned int i; - blockpage = (int) (addr >> this->page_shift); + if (ONENAND_IS_2PLANE(this)) + blockpage = onenand_get_2x_blockpage(mtd, addr); + else + blockpage = (int) (addr >> this->page_shift); /* Is there valid data? */ i = ONENAND_CURRENT_BUFFERRAM(this); @@ -625,7 +670,10 @@ static void onenand_update_bufferram(struct mtd_info *mtd, loff_t addr, int blockpage; unsigned int i; - blockpage = (int) (addr >> this->page_shift); + if (ONENAND_IS_2PLANE(this)) + blockpage = onenand_get_2x_blockpage(mtd, addr); + else + blockpage = (int) (addr >> this->page_shift); /* Invalidate another BufferRAM */ i = ONENAND_NEXT_BUFFERRAM(this); @@ -717,36 +765,86 @@ static void onenand_release_device(struct mtd_info *mtd) } /** - * onenand_read - [MTD Interface] Read data from flash + * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer + * @param mtd MTD device structure + * @param buf destination address + * @param column oob offset to read from + * @param thislen oob length to read + */ +static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column, + int thislen) +{ + struct onenand_chip *this = mtd->priv; + struct nand_oobfree *free; + int readcol = column; + int readend = column + thislen; + int lastgap = 0; + unsigned int i; + uint8_t *oob_buf = this->oob_buf; + + free = this->ecclayout->oobfree; + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + if (readcol >= lastgap) + readcol += free->offset - lastgap; + if (readend >= lastgap) + readend += free->offset - lastgap; + lastgap = free->offset + free->length; + } + this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); + free = this->ecclayout->oobfree; + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + int free_end = free->offset + free->length; + if (free->offset < readend && free_end > readcol) { + int st = max_t(int,free->offset,readcol); + int ed = min_t(int,free_end,readend); + int n = ed - st; + memcpy(buf, oob_buf + st, n); + buf += n; + } else if (column == 0) + break; + } + return 0; +} + +/** + * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band * @param mtd MTD device structure * @param from offset to read from - * @param len number of bytes to read - * @param retlen pointer to variable to store the number of read bytes - * @param buf the databuffer to put data + * @param ops: oob operation description structure * - * Read with ecc -*/ -static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) + * OneNAND read main and/or out-of-band data + */ +static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) { struct onenand_chip *this = mtd->priv; struct mtd_ecc_stats stats; - int read = 0, column; - int thislen; + size_t len = ops->len; + size_t ooblen = ops->ooblen; + u_char *buf = ops->datbuf; + u_char *oobbuf = ops->oobbuf; + int read = 0, column, thislen; + int oobread = 0, oobcolumn, thisooblen, oobsize; int ret = 0, boundary = 0; + int writesize = this->writesize; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); + DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); + + if (ops->mode == MTD_OOB_AUTO) + oobsize = this->ecclayout->oobavail; + else + oobsize = mtd->oobsize; + + oobcolumn = from & (mtd->oobsize - 1); /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { - printk(KERN_ERR "onenand_read: Attempt read beyond end of device\n"); - *retlen = 0; + printk(KERN_ERR "onenand_read_ops_nolock: Attempt read beyond end of device\n"); + ops->retlen = 0; + ops->oobretlen = 0; return -EINVAL; } - /* Grab the lock and see if the device is available */ - onenand_get_device(mtd, FL_READING); - stats = mtd->ecc_stats; /* Read-while-load method */ @@ -754,22 +852,22 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, /* Do first load to bufferRAM */ if (read < len) { if (!onenand_check_bufferram(mtd, from)) { - this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); + this->command(mtd, ONENAND_CMD_READ, from, writesize); ret = this->wait(mtd, FL_READING); onenand_update_bufferram(mtd, from, !ret); } } - thislen = min_t(int, mtd->writesize, len - read); - column = from & (mtd->writesize - 1); - if (column + thislen > mtd->writesize) - thislen = mtd->writesize - column; + thislen = min_t(int, writesize, len - read); + column = from & (writesize - 1); + if (column + thislen > writesize) + thislen = writesize - column; while (!ret) { /* If there is more to load then start next load */ from += thislen; if (read + thislen < len) { - this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); + this->command(mtd, ONENAND_CMD_READ, from, writesize); /* * Chip boundary handling in DDP * Now we issued chip 1 read and pointed chip 1 @@ -785,6 +883,21 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, } /* While load is going, read from last bufferRAM */ this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); + + /* Read oob area if needed */ + if (oobbuf) { + thisooblen = oobsize - oobcolumn; + thisooblen = min_t(int, thisooblen, ooblen - oobread); + + if (ops->mode == MTD_OOB_AUTO) + onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); + else + this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); + oobread += thisooblen; + oobbuf += thisooblen; + oobcolumn = 0; + } + /* See if we are done */ read += thislen; if (read == len) @@ -794,7 +907,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2); ONENAND_SET_NEXT_BUFFERRAM(this); buf += thislen; - thislen = min_t(int, mtd->writesize, len - read); + thislen = min_t(int, writesize, len - read); column = 0; cond_resched(); /* Now wait for load */ @@ -802,15 +915,13 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, onenand_update_bufferram(mtd, from, !ret); } - /* Deselect and wake up anyone waiting on the device */ - onenand_release_device(mtd); - /* * Return success, if no ECC failures, else -EBADMSG * fs driver will take care of that, because * retlen == desired len and result == -EBADMSG */ - *retlen = read; + ops->retlen = read; + ops->oobretlen = oobread; if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; @@ -822,69 +933,29 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, } /** - * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer - * @param mtd MTD device structure - * @param buf destination address - * @param column oob offset to read from - * @param thislen oob length to read - */ -static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column, - int thislen) -{ - struct onenand_chip *this = mtd->priv; - struct nand_oobfree *free; - int readcol = column; - int readend = column + thislen; - int lastgap = 0; - unsigned int i; - uint8_t *oob_buf = this->oob_buf; - - free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { - if (readcol >= lastgap) - readcol += free->offset - lastgap; - if (readend >= lastgap) - readend += free->offset - lastgap; - lastgap = free->offset + free->length; - } - this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); - free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { - int free_end = free->offset + free->length; - if (free->offset < readend && free_end > readcol) { - int st = max_t(int,free->offset,readcol); - int ed = min_t(int,free_end,readend); - int n = ed - st; - memcpy(buf, oob_buf + st, n); - buf += n; - } else if (column == 0) - break; - } - return 0; -} - -/** - * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band + * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band * @param mtd MTD device structure * @param from offset to read from - * @param len number of bytes to read - * @param retlen pointer to variable to store the number of read bytes - * @param buf the databuffer to put data - * @param mode operation mode + * @param ops: oob operation description structure * * OneNAND read out-of-band data from the spare area */ -static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf, mtd_oob_mode_t mode) +static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) { struct onenand_chip *this = mtd->priv; int read = 0, thislen, column, oobsize; + size_t len = ops->ooblen; + mtd_oob_mode_t mode = ops->mode; + u_char *buf = ops->oobbuf; int ret = 0; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); + from += ops->ooboffs; + + DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); /* Initialize return length value */ - *retlen = 0; + ops->oobretlen = 0; if (mode == MTD_OOB_AUTO) oobsize = this->ecclayout->oobavail; @@ -894,7 +965,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, column = from & (mtd->oobsize - 1); if (unlikely(column >= oobsize)) { - printk(KERN_ERR "onenand_read_oob: Attempted to start read outside oob\n"); + printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n"); return -EINVAL; } @@ -902,13 +973,10 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, if (unlikely(from >= mtd->size || column + len > ((mtd->size >> this->page_shift) - (from >> this->page_shift)) * oobsize)) { - printk(KERN_ERR "onenand_read_oob: Attempted to read beyond end of device\n"); + printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n"); return -EINVAL; } - /* Grab the lock and see if the device is available */ - onenand_get_device(mtd, FL_READING); - while (read < len) { cond_resched(); @@ -928,7 +996,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); if (ret) { - printk(KERN_ERR "onenand_read_oob: read failed = 0x%x\n", ret); + printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret); break; } @@ -947,22 +1015,52 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, } } - /* Deselect and wake up anyone waiting on the device */ + ops->oobretlen = read; + return ret; +} + +/** + * onenand_read - [MTD Interface] Read data from flash + * @param mtd MTD device structure + * @param from offset to read from + * @param len number of bytes to read + * @param retlen pointer to variable to store the number of read bytes + * @param buf the databuffer to put data + * + * Read with ecc +*/ +static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_oob_ops ops = { + .len = len, + .ooblen = 0, + .datbuf = buf, + .oobbuf = NULL, + }; + int ret; + + onenand_get_device(mtd, FL_READING); + ret = onenand_read_ops_nolock(mtd, from, &ops); onenand_release_device(mtd); - *retlen = read; + *retlen = ops.retlen; return ret; } /** - * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band + * onenand_read_oob - [MTD Interface] Read main and/or out-of-band * @param mtd: MTD device structure * @param from: offset to read from * @param ops: oob operation description structure + + * Read main and/or out-of-band */ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { + int ret; + switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: @@ -972,8 +1070,15 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, default: return -EINVAL; } - return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->ooblen, - &ops->oobretlen, ops->oobbuf, ops->mode); + + onenand_get_device(mtd, FL_READING); + if (ops->datbuf) + ret = onenand_read_ops_nolock(mtd, from, ops); + else + ret = onenand_read_oob_nolock(mtd, from, ops); + onenand_release_device(mtd); + + return ret; } /** @@ -1079,7 +1184,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, /* Read more? */ if (read < len) { /* Update Page size */ - from += mtd->writesize; + from += this->writesize; column = 0; } } @@ -1097,7 +1202,6 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, * @param mtd MTD device structure * @param buf the databuffer to verify * @param to offset to read from - * */ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) { @@ -1125,7 +1229,6 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to * @param buf the databuffer to verify * @param addr offset to read from * @param len number of bytes to read and compare - * */ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len) { @@ -1135,12 +1238,12 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, int thislen, column; while (len != 0) { - thislen = min_t(int, mtd->writesize, len); - column = addr & (mtd->writesize - 1); - if (column + thislen > mtd->writesize) - thislen = mtd->writesize - column; + thislen = min_t(int, this->writesize, len); + column = addr & (this->writesize - 1); + if (column + thislen > this->writesize) + thislen = this->writesize - column; - this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); + this->command(mtd, ONENAND_CMD_READ, addr, this->writesize); onenand_update_bufferram(mtd, addr, 0); @@ -1171,50 +1274,101 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, #define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) /** - * onenand_write - [MTD Interface] write buffer to FLASH + * onenand_fill_auto_oob - [Internal] oob auto-placement transfer + * @param mtd MTD device structure + * @param oob_buf oob buffer + * @param buf source address + * @param column oob offset to write to + * @param thislen oob length to write + */ +static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, + const u_char *buf, int column, int thislen) +{ + struct onenand_chip *this = mtd->priv; + struct nand_oobfree *free; + int writecol = column; + int writeend = column + thislen; + int lastgap = 0; + unsigned int i; + + free = this->ecclayout->oobfree; + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + if (writecol >= lastgap) + writecol += free->offset - lastgap; + if (writeend >= lastgap) + writeend += free->offset - lastgap; + lastgap = free->offset + free->length; + } + free = this->ecclayout->oobfree; + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + int free_end = free->offset + free->length; + if (free->offset < writeend && free_end > writecol) { + int st = max_t(int,free->offset,writecol); + int ed = min_t(int,free_end,writeend); + int n = ed - st; + memcpy(oob_buf + st, buf, n); + buf += n; + } else if (column == 0) + break; + } + return 0; +} + +/** + * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band * @param mtd MTD device structure * @param to offset to write to - * @param len number of bytes to write - * @param retlen pointer to variable to store the number of written bytes - * @param buf the data to write + * @param ops oob operation description structure * - * Write with ECC + * Write main and/or oob with ECC */ -static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) { struct onenand_chip *this = mtd->priv; - int written = 0; + int written = 0, column, thislen, subpage; + int oobwritten = 0, oobcolumn, thisooblen, oobsize; + size_t len = ops->len; + size_t ooblen = ops->ooblen; + const u_char *buf = ops->datbuf; + const u_char *oob = ops->oobbuf; + u_char *oobbuf; int ret = 0; - int column, subpage; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); + DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ - *retlen = 0; + ops->retlen = 0; + ops->oobretlen = 0; /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { - printk(KERN_ERR "onenand_write: Attempt write to past end of device\n"); + printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n"); return -EINVAL; } /* Reject writes, which are not page aligned */ if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { - printk(KERN_ERR "onenand_write: Attempt to write not page aligned data\n"); + printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n"); return -EINVAL; } - column = to & (mtd->writesize - 1); + if (ops->mode == MTD_OOB_AUTO) + oobsize = this->ecclayout->oobavail; + else + oobsize = mtd->oobsize; - /* Grab the lock and see if the device is available */ - onenand_get_device(mtd, FL_WRITING); + oobcolumn = to & (mtd->oobsize - 1); + + column = to & (mtd->writesize - 1); /* Loop until all data write */ while (written < len) { - int thislen = min_t(int, mtd->writesize - column, len - written); u_char *wbuf = (u_char *) buf; + thislen = min_t(int, mtd->writesize - column, len - written); + thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten); + cond_resched(); this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen); @@ -1228,7 +1382,25 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, } this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize); - this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); + + if (oob) { + oobbuf = this->oob_buf; + + /* We send data to spare ram with oobsize + * to prevent byte access */ + memset(oobbuf, 0xff, mtd->oobsize); + if (ops->mode == MTD_OOB_AUTO) + onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen); + else + memcpy(oobbuf + oobcolumn, oob, thisooblen); + + oobwritten += thisooblen; + oob += thisooblen; + oobcolumn = 0; + } else + oobbuf = (u_char *) ffchars; + + this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); @@ -1236,16 +1408,20 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, /* In partial page write we don't update bufferram */ onenand_update_bufferram(mtd, to, !ret && !subpage); + if (ONENAND_IS_2PLANE(this)) { + ONENAND_SET_BUFFERRAM1(this); + onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage); + } if (ret) { - printk(KERN_ERR "onenand_write: write filaed %d\n", ret); + printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret); break; } /* Only check verify write turn on */ ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen); if (ret) { - printk(KERN_ERR "onenand_write: verify failed %d\n", ret); + printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret); break; } @@ -1262,54 +1438,14 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); - *retlen = written; + ops->retlen = written; return ret; } -/** - * onenand_fill_auto_oob - [Internal] oob auto-placement transfer - * @param mtd MTD device structure - * @param oob_buf oob buffer - * @param buf source address - * @param column oob offset to write to - * @param thislen oob length to write - */ -static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, - const u_char *buf, int column, int thislen) -{ - struct onenand_chip *this = mtd->priv; - struct nand_oobfree *free; - int writecol = column; - int writeend = column + thislen; - int lastgap = 0; - unsigned int i; - - free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { - if (writecol >= lastgap) - writecol += free->offset - lastgap; - if (writeend >= lastgap) - writeend += free->offset - lastgap; - lastgap = free->offset + free->length; - } - free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { - int free_end = free->offset + free->length; - if (free->offset < writeend && free_end > writecol) { - int st = max_t(int,free->offset,writecol); - int ed = min_t(int,free_end,writeend); - int n = ed - st; - memcpy(oob_buf + st, buf, n); - buf += n; - } else if (column == 0) - break; - } - return 0; -} /** - * onenand_do_write_oob - [Internal] OneNAND write out-of-band + * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write @@ -1319,18 +1455,23 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, * * OneNAND write out-of-band */ -static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf, mtd_oob_mode_t mode) +static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) { struct onenand_chip *this = mtd->priv; int column, ret = 0, oobsize; int written = 0; u_char *oobbuf; + size_t len = ops->ooblen; + const u_char *buf = ops->oobbuf; + mtd_oob_mode_t mode = ops->mode; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); + to += ops->ooboffs; + + DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ - *retlen = 0; + ops->oobretlen = 0; if (mode == MTD_OOB_AUTO) oobsize = this->ecclayout->oobavail; @@ -1340,13 +1481,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, column = to & (mtd->oobsize - 1); if (unlikely(column >= oobsize)) { - printk(KERN_ERR "onenand_write_oob: Attempted to start write outside oob\n"); + printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n"); return -EINVAL; } /* For compatibility with NAND: Do not allow write past end of page */ if (unlikely(column + len > oobsize)) { - printk(KERN_ERR "onenand_write_oob: " + printk(KERN_ERR "onenand_write_oob_nolock: " "Attempt to write past end of page\n"); return -EINVAL; } @@ -1355,13 +1496,10 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, if (unlikely(to >= mtd->size || column + len > ((mtd->size >> this->page_shift) - (to >> this->page_shift)) * oobsize)) { - printk(KERN_ERR "onenand_write_oob: Attempted to write past end of device\n"); + printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n"); return -EINVAL; } - /* Grab the lock and see if the device is available */ - onenand_get_device(mtd, FL_WRITING); - oobbuf = this->oob_buf; /* Loop until all data write */ @@ -1384,16 +1522,20 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); onenand_update_bufferram(mtd, to, 0); + if (ONENAND_IS_2PLANE(this)) { + ONENAND_SET_BUFFERRAM1(this); + onenand_update_bufferram(mtd, to + this->writesize, 0); + } ret = this->wait(mtd, FL_WRITING); if (ret) { - printk(KERN_ERR "onenand_write_oob: write failed %d\n", ret); + printk(KERN_ERR "onenand_write_oob_nolock: write failed %d\n", ret); break; } ret = onenand_verify_oob(mtd, oobbuf, to); if (ret) { - printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret); + printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret); break; } @@ -1406,11 +1548,37 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, column = 0; } - /* Deselect and wake up anyone waiting on the device */ - onenand_release_device(mtd); + ops->oobretlen = written; + + return ret; +} + +/** + * onenand_write - [MTD Interface] write buffer to FLASH + * @param mtd MTD device structure + * @param to offset to write to + * @param len number of bytes to write + * @param retlen pointer to variable to store the number of written bytes + * @param buf the data to write + * + * Write with ECC + */ +static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct mtd_oob_ops ops = { + .len = len, + .ooblen = 0, + .datbuf = (u_char *) buf, + .oobbuf = NULL, + }; + int ret; - *retlen = written; + onenand_get_device(mtd, FL_WRITING); + ret = onenand_write_ops_nolock(mtd, to, &ops); + onenand_release_device(mtd); + *retlen = ops.retlen; return ret; } @@ -1423,6 +1591,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, static int onenand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { + int ret; + switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: @@ -1432,21 +1602,27 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, default: return -EINVAL; } - return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->ooblen, - &ops->oobretlen, ops->oobbuf, ops->mode); + + onenand_get_device(mtd, FL_WRITING); + if (ops->datbuf) + ret = onenand_write_ops_nolock(mtd, to, ops); + else + ret = onenand_write_oob_nolock(mtd, to, ops); + onenand_release_device(mtd); + + return ret; } /** - * onenand_block_checkbad - [GENERIC] Check if a block is marked bad + * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad * @param mtd MTD device structure * @param ofs offset from device start - * @param getchip 0, if the chip is already selected * @param allowbbt 1, if its allowed to access the bbt area * * Check, if the block is bad. Either by reading the bad block table or * calling of the scan function. */ -static int onenand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) +static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt) { struct onenand_chip *this = mtd->priv; struct bbm_info *bbm = this->bbm; @@ -1507,7 +1683,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) cond_resched(); /* Check if we have a bad block, we do not erase bad blocks */ - if (onenand_block_checkbad(mtd, addr, 0, 0)) { + if (onenand_block_isbad_nolock(mtd, addr, 0)) { printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr); instr->state = MTD_ERASE_FAILED; goto erase_exit; @@ -1571,11 +1747,16 @@ static void onenand_sync(struct mtd_info *mtd) */ static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs) { + int ret; + /* Check for invalid offset */ if (ofs > mtd->size) return -EINVAL; - return onenand_block_checkbad(mtd, ofs, 1, 0); + onenand_get_device(mtd, FL_READING); + ret = onenand_block_isbad_nolock(mtd, ofs, 0); + onenand_release_device(mtd); + return ret; } /** @@ -1591,7 +1772,12 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) struct onenand_chip *this = mtd->priv; struct bbm_info *bbm = this->bbm; u_char buf[2] = {0, 0}; - size_t retlen; + struct mtd_oob_ops ops = { + .mode = MTD_OOB_PLACE, + .ooblen = 2, + .oobbuf = buf, + .ooboffs = 0, + }; int block; /* Get block number */ @@ -1601,7 +1787,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) /* We write two bytes, so we dont have to mess with 16 bit access */ ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); - return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf, MTD_OOB_PLACE); + return onenand_write_oob_nolock(mtd, ofs, &ops); } /** @@ -1624,7 +1810,10 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) return ret; } - return this->block_markbad(mtd, ofs); + onenand_get_device(mtd, FL_WRITING); + ret = this->block_markbad(mtd, ofs); + onenand_release_device(mtd); + return ret; } /** @@ -1823,13 +2012,19 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct onenand_chip *this = mtd->priv; + struct mtd_oob_ops ops = { + .len = len, + .ooblen = 0, + .datbuf = buf, + .oobbuf = NULL, + }; int ret; /* Enter OTP access mode */ this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); this->wait(mtd, FL_OTPING); - ret = mtd->read(mtd, from, len, retlen, buf); + ret = onenand_read_ops_nolock(mtd, from, &ops); /* Exit OTP access mode */ this->command(mtd, ONENAND_CMD_RESET, 0, 0); @@ -1841,19 +2036,20 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, /** * do_otp_write - [DEFAULT] Write OTP block area * @param mtd MTD device structure - * @param from The offset to write + * @param to The offset to write * @param len number of bytes to write * @param retlen pointer to variable to store the number of write bytes * @param buf the databuffer to put/get data * * Write OTP block area. */ -static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len, +static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, u_char *buf) { struct onenand_chip *this = mtd->priv; unsigned char *pbuf = buf; int ret; + struct mtd_oob_ops ops; /* Force buffer page aligned */ if (len < mtd->writesize) { @@ -1867,7 +2063,12 @@ static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len, this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); this->wait(mtd, FL_OTPING); - ret = mtd->write(mtd, from, len, retlen, pbuf); + ops.len = len; + ops.ooblen = 0; + ops.datbuf = pbuf; + ops.oobbuf = NULL; + ret = onenand_write_ops_nolock(mtd, to, &ops); + *retlen = ops.retlen; /* Exit OTP access mode */ this->command(mtd, ONENAND_CMD_RESET, 0, 0); @@ -1890,13 +2091,21 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct onenand_chip *this = mtd->priv; + struct mtd_oob_ops ops = { + .mode = MTD_OOB_PLACE, + .ooblen = len, + .oobbuf = buf, + .ooboffs = 0, + }; int ret; /* Enter OTP access mode */ this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); this->wait(mtd, FL_OTPING); - ret = onenand_do_write_oob(mtd, from, len, retlen, buf, MTD_OOB_PLACE); + ret = onenand_write_oob_nolock(mtd, from, &ops); + + *retlen = ops.oobretlen; /* Exit OTP access mode */ this->command(mtd, ONENAND_CMD_RESET, 0, 0); @@ -1943,13 +2152,16 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, if (((mtd->writesize * otp_pages) - (from + len)) < 0) return 0; + onenand_get_device(mtd, FL_OTPING); while (len > 0 && otp_pages > 0) { if (!action) { /* OTP Info functions */ struct otp_info *otpinfo; len -= sizeof(struct otp_info); - if (len <= 0) - return -ENOSPC; + if (len <= 0) { + ret = -ENOSPC; + break; + } otpinfo = (struct otp_info *) buf; otpinfo->start = from; @@ -1969,13 +2181,14 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, len -= size; *retlen += size; - if (ret < 0) - return ret; + if (ret) + break; } otp_pages--; } + onenand_release_device(mtd); - return 0; + return ret; } /** @@ -2107,6 +2320,7 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, * * Check and set OneNAND features * - lock scheme + * - two plane */ static void onenand_check_features(struct mtd_info *mtd) { @@ -2118,19 +2332,35 @@ static void onenand_check_features(struct mtd_info *mtd) process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; /* Lock scheme */ - if (density >= ONENAND_DEVICE_DENSITY_1Gb) { + switch (density) { + case ONENAND_DEVICE_DENSITY_4Gb: + this->options |= ONENAND_HAS_2PLANE; + + case ONENAND_DEVICE_DENSITY_2Gb: + /* 2Gb DDP don't have 2 plane */ + if (!ONENAND_IS_DDP(this)) + this->options |= ONENAND_HAS_2PLANE; + this->options |= ONENAND_HAS_UNLOCK_ALL; + + case ONENAND_DEVICE_DENSITY_1Gb: /* A-Die has all block unlock */ - if (process) { - printk(KERN_DEBUG "Chip support all block unlock\n"); + if (process) this->options |= ONENAND_HAS_UNLOCK_ALL; - } - } else { - /* Some OneNAND has continues lock scheme */ - if (!process) { - printk(KERN_DEBUG "Lock scheme is Continues Lock\n"); + break; + + default: + /* Some OneNAND has continuous lock scheme */ + if (!process) this->options |= ONENAND_HAS_CONT_LOCK; - } + break; } + + if (this->options & ONENAND_HAS_CONT_LOCK) + printk(KERN_DEBUG "Lock scheme is Continuous Lock\n"); + if (this->options & ONENAND_HAS_UNLOCK_ALL) + printk(KERN_DEBUG "Chip support all block unlock\n"); + if (this->options & ONENAND_HAS_2PLANE) + printk(KERN_DEBUG "Chip has 2 plane\n"); } /** @@ -2154,7 +2384,7 @@ static void onenand_print_device_info(int device, int version) (16 << density), vcc ? "2.65/3.3" : "1.8", device); - printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version); + printk(KERN_INFO "OneNAND version = 0x%04x\n", version); } static const struct onenand_manufacturers onenand_manuf_ids[] = { @@ -2257,6 +2487,8 @@ static int onenand_probe(struct mtd_info *mtd) this->erase_shift = ffs(mtd->erasesize) - 1; this->page_shift = ffs(mtd->writesize) - 1; this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1; + /* It's real page size */ + this->writesize = mtd->writesize; /* REVIST: Multichip handling */ @@ -2265,6 +2497,17 @@ static int onenand_probe(struct mtd_info *mtd) /* Check OneNAND features */ onenand_check_features(mtd); + /* + * We emulate the 4KiB page and 256KiB erase block size + * But oobsize is still 64 bytes. + * It is only valid if you turn on 2X program support, + * Otherwise it will be ignored by compiler. + */ + if (ONENAND_IS_2PLANE(this)) { + mtd->writesize <<= 1; + mtd->erasesize <<= 1; + } + return 0; } diff --git a/drivers/mtd/onenand/onenand_sim.c b/drivers/mtd/onenand/onenand_sim.c new file mode 100644 index 00000000000..0d89ad5776f --- /dev/null +++ b/drivers/mtd/onenand/onenand_sim.c @@ -0,0 +1,495 @@ +/* + * linux/drivers/mtd/onenand/onenand_sim.c + * + * The OneNAND simulator + * + * Copyright © 2005-2007 Samsung Electronics + * Kyungmin Park <kyungmin.park@samsung.com> + * + * 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/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/vmalloc.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/onenand.h> + +#include <linux/io.h> + +#ifndef CONFIG_ONENAND_SIM_MANUFACTURER +#define CONFIG_ONENAND_SIM_MANUFACTURER 0xec +#endif +#ifndef CONFIG_ONENAND_SIM_DEVICE_ID +#define CONFIG_ONENAND_SIM_DEVICE_ID 0x04 +#endif +#ifndef CONFIG_ONENAND_SIM_VERSION_ID +#define CONFIG_ONENAND_SIM_VERSION_ID 0x1e +#endif + +static int manuf_id = CONFIG_ONENAND_SIM_MANUFACTURER; +static int device_id = CONFIG_ONENAND_SIM_DEVICE_ID; +static int version_id = CONFIG_ONENAND_SIM_VERSION_ID; + +struct onenand_flash { + void __iomem *base; + void __iomem *data; +}; + +#define ONENAND_CORE(flash) (flash->data) +#define ONENAND_CORE_SPARE(flash, this, offset) \ + ((flash->data) + (this->chipsize) + (offset >> 5)) + +#define ONENAND_MAIN_AREA(this, offset) \ + (this->base + ONENAND_DATARAM + offset) + +#define ONENAND_SPARE_AREA(this, offset) \ + (this->base + ONENAND_SPARERAM + offset) + +#define ONENAND_GET_WP_STATUS(this) \ + (readw(this->base + ONENAND_REG_WP_STATUS)) + +#define ONENAND_SET_WP_STATUS(v, this) \ + (writew(v, this->base + ONENAND_REG_WP_STATUS)) + +/* It has all 0xff chars */ +#define MAX_ONENAND_PAGESIZE (2048 + 64) +static unsigned char *ffchars; + +static struct mtd_partition os_partitions[] = { + { + .name = "OneNAND simulator partition", + .offset = 0, + .size = MTDPART_SIZ_FULL, + }, +}; + +/* + * OneNAND simulator mtd + */ +struct onenand_info { + struct mtd_info mtd; + struct mtd_partition *parts; + struct onenand_chip onenand; + struct onenand_flash flash; +}; + +static struct onenand_info *info; + +#define DPRINTK(format, args...) \ +do { \ + printk(KERN_DEBUG "%s[%d]: " format "\n", __func__, \ + __LINE__, ##args); \ +} while (0) + +/** + * onenand_lock_handle - Handle Lock scheme + * @param this OneNAND device structure + * @param cmd The command to be sent + * + * Send lock command to OneNAND device. + * The lock scheme is depends on chip type. + */ +static void onenand_lock_handle(struct onenand_chip *this, int cmd) +{ + int block_lock_scheme; + int status; + + status = ONENAND_GET_WP_STATUS(this); + block_lock_scheme = !(this->options & ONENAND_HAS_CONT_LOCK); + + switch (cmd) { + case ONENAND_CMD_UNLOCK: + if (block_lock_scheme) + ONENAND_SET_WP_STATUS(ONENAND_WP_US, this); + else + ONENAND_SET_WP_STATUS(status | ONENAND_WP_US, this); + break; + + case ONENAND_CMD_LOCK: + if (block_lock_scheme) + ONENAND_SET_WP_STATUS(ONENAND_WP_LS, this); + else + ONENAND_SET_WP_STATUS(status | ONENAND_WP_LS, this); + break; + + case ONENAND_CMD_LOCK_TIGHT: + if (block_lock_scheme) + ONENAND_SET_WP_STATUS(ONENAND_WP_LTS, this); + else + ONENAND_SET_WP_STATUS(status | ONENAND_WP_LTS, this); + break; + + default: + break; + } +} + +/** + * onenand_bootram_handle - Handle BootRAM area + * @param this OneNAND device structure + * @param cmd The command to be sent + * + * Emulate BootRAM area. It is possible to do basic operation using BootRAM. + */ +static void onenand_bootram_handle(struct onenand_chip *this, int cmd) +{ + switch (cmd) { + case ONENAND_CMD_READID: + writew(manuf_id, this->base); + writew(device_id, this->base + 2); + writew(version_id, this->base + 4); + break; + + default: + /* REVIST: Handle other commands */ + break; + } +} + +/** + * onenand_update_interrupt - Set interrupt register + * @param this OneNAND device structure + * @param cmd The command to be sent + * + * Update interrupt register. The status is depends on command. + */ +static void onenand_update_interrupt(struct onenand_chip *this, int cmd) +{ + int interrupt = ONENAND_INT_MASTER; + + switch (cmd) { + case ONENAND_CMD_READ: + case ONENAND_CMD_READOOB: + interrupt |= ONENAND_INT_READ; + break; + + case ONENAND_CMD_PROG: + case ONENAND_CMD_PROGOOB: + interrupt |= ONENAND_INT_WRITE; + break; + + case ONENAND_CMD_ERASE: + interrupt |= ONENAND_INT_ERASE; + break; + + case ONENAND_CMD_RESET: + interrupt |= ONENAND_INT_RESET; + break; + + default: + break; + } + + writew(interrupt, this->base + ONENAND_REG_INTERRUPT); +} + +/** + * onenand_check_overwrite - Check over-write if happend + * @param dest The destination pointer + * @param src The source pointer + * @param count The length to be check + * @return 0 on same, otherwise 1 + * + * Compare the source with destination + */ +static int onenand_check_overwrite(void *dest, void *src, size_t count) +{ + unsigned int *s = (unsigned int *) src; + unsigned int *d = (unsigned int *) dest; + int i; + + count >>= 2; + for (i = 0; i < count; i++) + if ((*s++ ^ *d++) != 0) + return 1; + + return 0; +} + +/** + * onenand_data_handle - Handle OneNAND Core and DataRAM + * @param this OneNAND device structure + * @param cmd The command to be sent + * @param dataram Which dataram used + * @param offset The offset to OneNAND Core + * + * Copy data from OneNAND Core to DataRAM (read) + * Copy data from DataRAM to OneNAND Core (write) + * Erase the OneNAND Core (erase) + */ +static void onenand_data_handle(struct onenand_chip *this, int cmd, + int dataram, unsigned int offset) +{ + struct mtd_info *mtd = &info->mtd; + struct onenand_flash *flash = this->priv; + int main_offset, spare_offset; + void __iomem *src; + void __iomem *dest; + unsigned int i; + + if (dataram) { + main_offset = mtd->writesize; + spare_offset = mtd->oobsize; + } else { + main_offset = 0; + spare_offset = 0; + } + + switch (cmd) { + case ONENAND_CMD_READ: + src = ONENAND_CORE(flash) + offset; + dest = ONENAND_MAIN_AREA(this, main_offset); + memcpy(dest, src, mtd->writesize); + /* Fall through */ + + case ONENAND_CMD_READOOB: + src = ONENAND_CORE_SPARE(flash, this, offset); + dest = ONENAND_SPARE_AREA(this, spare_offset); + memcpy(dest, src, mtd->oobsize); + break; + + case ONENAND_CMD_PROG: + src = ONENAND_MAIN_AREA(this, main_offset); + dest = ONENAND_CORE(flash) + offset; + /* To handle partial write */ + for (i = 0; i < (1 << mtd->subpage_sft); i++) { + int off = i * this->subpagesize; + if (!memcmp(src + off, ffchars, this->subpagesize)) + continue; + if (memcmp(dest + off, ffchars, this->subpagesize) && + onenand_check_overwrite(dest + off, src + off, this->subpagesize)) + printk(KERN_ERR "over-write happend at 0x%08x\n", offset); + memcpy(dest + off, src + off, this->subpagesize); + } + /* Fall through */ + + case ONENAND_CMD_PROGOOB: + src = ONENAND_SPARE_AREA(this, spare_offset); + /* Check all data is 0xff chars */ + if (!memcmp(src, ffchars, mtd->oobsize)) + break; + + dest = ONENAND_CORE_SPARE(flash, this, offset); + if (memcmp(dest, ffchars, mtd->oobsize) && + onenand_check_overwrite(dest, src, mtd->oobsize)) + printk(KERN_ERR "OOB: over-write happend at 0x%08x\n", + offset); + memcpy(dest, src, mtd->oobsize); + break; + + case ONENAND_CMD_ERASE: + memset(ONENAND_CORE(flash) + offset, 0xff, mtd->erasesize); + memset(ONENAND_CORE_SPARE(flash, this, offset), 0xff, + (mtd->erasesize >> 5)); + break; + + default: + break; + } +} + +/** + * onenand_command_handle - Handle command + * @param this OneNAND device structure + * @param cmd The command to be sent + * + * Emulate OneNAND command. + */ +static void onenand_command_handle(struct onenand_chip *this, int cmd) +{ + unsigned long offset = 0; + int block = -1, page = -1, bufferram = -1; + int dataram = 0; + + switch (cmd) { + case ONENAND_CMD_UNLOCK: + case ONENAND_CMD_LOCK: + case ONENAND_CMD_LOCK_TIGHT: + case ONENAND_CMD_UNLOCK_ALL: + onenand_lock_handle(this, cmd); + break; + + case ONENAND_CMD_BUFFERRAM: + /* Do nothing */ + return; + + default: + block = (int) readw(this->base + ONENAND_REG_START_ADDRESS1); + if (block & (1 << ONENAND_DDP_SHIFT)) { + block &= ~(1 << ONENAND_DDP_SHIFT); + /* The half of chip block */ + block += this->chipsize >> (this->erase_shift + 1); + } + if (cmd == ONENAND_CMD_ERASE) + break; + + page = (int) readw(this->base + ONENAND_REG_START_ADDRESS8); + page = (page >> ONENAND_FPA_SHIFT); + bufferram = (int) readw(this->base + ONENAND_REG_START_BUFFER); + bufferram >>= ONENAND_BSA_SHIFT; + bufferram &= ONENAND_BSA_DATARAM1; + dataram = (bufferram == ONENAND_BSA_DATARAM1) ? 1 : 0; + break; + } + + if (block != -1) + offset += block << this->erase_shift; + + if (page != -1) + offset += page << this->page_shift; + + onenand_data_handle(this, cmd, dataram, offset); + + onenand_update_interrupt(this, cmd); +} + +/** + * onenand_writew - [OneNAND Interface] Emulate write operation + * @param value value to write + * @param addr address to write + * + * Write OneNAND register with value + */ +static void onenand_writew(unsigned short value, void __iomem * addr) +{ + struct onenand_chip *this = info->mtd.priv; + + /* BootRAM handling */ + if (addr < this->base + ONENAND_DATARAM) { + onenand_bootram_handle(this, value); + return; + } + /* Command handling */ + if (addr == this->base + ONENAND_REG_COMMAND) + onenand_command_handle(this, value); + + writew(value, addr); +} + +/** + * flash_init - Initialize OneNAND simulator + * @param flash OneNAND simulaotr data strucutres + * + * Initialize OneNAND simulator. + */ +static int __init flash_init(struct onenand_flash *flash) +{ + int density, size; + int buffer_size; + + flash->base = kzalloc(131072, GFP_KERNEL); + if (!flash->base) { + printk(KERN_ERR "Unable to allocate base address.\n"); + return -ENOMEM; + } + + density = device_id >> ONENAND_DEVICE_DENSITY_SHIFT; + size = ((16 << 20) << density); + + ONENAND_CORE(flash) = vmalloc(size + (size >> 5)); + if (!ONENAND_CORE(flash)) { + printk(KERN_ERR "Unable to allocate nand core address.\n"); + kfree(flash->base); + return -ENOMEM; + } + + memset(ONENAND_CORE(flash), 0xff, size + (size >> 5)); + + /* Setup registers */ + writew(manuf_id, flash->base + ONENAND_REG_MANUFACTURER_ID); + writew(device_id, flash->base + ONENAND_REG_DEVICE_ID); + writew(version_id, flash->base + ONENAND_REG_VERSION_ID); + + if (density < 2) + buffer_size = 0x0400; /* 1KiB page */ + else + buffer_size = 0x0800; /* 2KiB page */ + writew(buffer_size, flash->base + ONENAND_REG_DATA_BUFFER_SIZE); + + return 0; +} + +/** + * flash_exit - Clean up OneNAND simulator + * @param flash OneNAND simulaotr data strucutres + * + * Clean up OneNAND simulator. + */ +static void flash_exit(struct onenand_flash *flash) +{ + vfree(ONENAND_CORE(flash)); + kfree(flash->base); + kfree(flash); +} + +static int __init onenand_sim_init(void) +{ + /* Allocate all 0xff chars pointer */ + ffchars = kmalloc(MAX_ONENAND_PAGESIZE, GFP_KERNEL); + if (!ffchars) { + printk(KERN_ERR "Unable to allocate ff chars.\n"); + return -ENOMEM; + } + memset(ffchars, 0xff, MAX_ONENAND_PAGESIZE); + + /* Allocate OneNAND simulator mtd pointer */ + info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL); + if (!info) { + printk(KERN_ERR "Unable to allocate core structures.\n"); + kfree(ffchars); + return -ENOMEM; + } + + /* Override write_word function */ + info->onenand.write_word = onenand_writew; + + if (flash_init(&info->flash)) { + printk(KERN_ERR "Unable to allocat flash.\n"); + kfree(ffchars); + kfree(info); + return -ENOMEM; + } + + info->parts = os_partitions; + + info->onenand.base = info->flash.base; + info->onenand.priv = &info->flash; + + info->mtd.name = "OneNAND simulator"; + info->mtd.priv = &info->onenand; + info->mtd.owner = THIS_MODULE; + + if (onenand_scan(&info->mtd, 1)) { + flash_exit(&info->flash); + kfree(ffchars); + kfree(info); + return -ENXIO; + } + + add_mtd_partitions(&info->mtd, info->parts, ARRAY_SIZE(os_partitions)); + + return 0; +} + +static void __exit onenand_sim_exit(void) +{ + struct onenand_chip *this = info->mtd.priv; + struct onenand_flash *flash = this->priv; + + onenand_release(&info->mtd); + flash_exit(flash); + kfree(ffchars); + kfree(info); +} + +module_init(onenand_sim_init); +module_exit(onenand_sim_exit); + +MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>"); +MODULE_DESCRIPTION("The OneNAND flash simulator"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index 006c03aacb5..823fba4e6d2 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -779,10 +779,8 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) else { if (!mtd->erasesize) { printk(KERN_WARNING PREFIX "please provide block_size"); - kfree(part); - return; - } - else + goto out; + } else part->block_size = mtd->erasesize; } @@ -804,7 +802,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) if (!add_mtd_blktrans_dev((void*)part)) return; } - +out: kfree(part); } diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 94ee5493441..29c41eeb09f 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -1314,11 +1314,10 @@ static int paranoid_check_si(const struct ubi_device *ubi, * Make sure that all the physical eraseblocks are in one of the lists * or trees. */ - buf = kmalloc(ubi->peb_count, GFP_KERNEL); + buf = kzalloc(ubi->peb_count, GFP_KERNEL); if (!buf) return -ENOMEM; - memset(buf, 1, ubi->peb_count); for (pnum = 0; pnum < ubi->peb_count; pnum++) { err = ubi_io_is_bad(ubi, pnum); if (err < 0) { @@ -1326,28 +1325,28 @@ static int paranoid_check_si(const struct ubi_device *ubi, return err; } else if (err) - buf[pnum] = 0; + buf[pnum] = 1; } ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) - buf[seb->pnum] = 0; + buf[seb->pnum] = 1; list_for_each_entry(seb, &si->free, u.list) - buf[seb->pnum] = 0; + buf[seb->pnum] = 1; list_for_each_entry(seb, &si->corr, u.list) - buf[seb->pnum] = 0; + buf[seb->pnum] = 1; list_for_each_entry(seb, &si->erase, u.list) - buf[seb->pnum] = 0; + buf[seb->pnum] = 1; list_for_each_entry(seb, &si->alien, u.list) - buf[seb->pnum] = 0; + buf[seb->pnum] = 1; err = 0; for (pnum = 0; pnum < ubi->peb_count; pnum++) - if (buf[pnum]) { + if (!buf[pnum]) { ubi_err("PEB %d is not referred", pnum); err = 1; } diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index ebf1a3a88e1..b74dbeef805 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -1023,7 +1023,7 @@ static int lance_rx( struct net_device *dev ) DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac2); - printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s ", + printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s " "data %02x %02x %02x %02x %02x %02x %02x %02x " "len %d\n", dev->name, ((u_short *)data)[6], diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 6589239b79e..18770527df9 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -538,8 +538,9 @@ static void mace_set_multicast(struct net_device *dev) local_irq_restore(flags); } -static void mace_handle_misc_intrs(struct mace_data *mp, int intr) +static void mace_handle_misc_intrs(struct net_device *dev, int intr) { + struct mace_data *mp = netdev_priv(dev); volatile struct mace *mb = mp->mace; static int mace_babbles, mace_jabbers; @@ -571,7 +572,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) local_irq_save(flags); intr = mb->ir; /* read interrupt register */ - mace_handle_misc_intrs(mp, intr); + mace_handle_misc_intrs(dev, intr); if (intr & XMTINT) { fs = mb->xmtfs; @@ -645,7 +646,6 @@ static void mace_tx_timeout(struct net_device *dev) static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) { - struct mace_data *mp = netdev_priv(dev); struct sk_buff *skb; unsigned int frame_status = mf->rcvsts; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index b33d21f4eff..84f2d6382f1 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -784,7 +784,6 @@ static int mv643xx_eth_open(struct net_device *dev) unsigned int port_num = mp->port_num; unsigned int size; int err; - DECLARE_MAC_BUF(mac); /* Clear any pending ethernet port interrupts */ mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); @@ -1296,6 +1295,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) struct ethtool_cmd cmd; int duplex = DUPLEX_HALF; int speed = 0; /* default to auto-negotiation */ + DECLARE_MAC_BUF(mac); pd = pdev->dev.platform_data; if (pd == NULL) { diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c index 86c9c06433c..06ca4252155 100644 --- a/drivers/net/mvme147.c +++ b/drivers/net/mvme147.c @@ -85,7 +85,6 @@ struct net_device * __init mvme147lance_probe(int unit) dev->open = &m147lance_open; dev->stop = &m147lance_close; dev->hard_start_xmit = &lance_start_xmit; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; dev->tx_timeout = &lance_tx_timeout; dev->dma = 0; diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index 5f7ffa0a76c..3d4ed647c31 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -26,6 +26,7 @@ */ #include <linux/delay.h> +#include <linux/io.h> #include <linux/types.h> #include "b43.h" diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index 34a44c1b631..3488f2447bb 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -4,6 +4,7 @@ #include "b43.h" #include <linux/interrupt.h> +#include <linux/io.h> #include <linux/list.h> #include <linux/skbuff.h> diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c index fcb777383e7..f4faff6a7d6 100644 --- a/drivers/net/wireless/b43/sysfs.c +++ b/drivers/net/wireless/b43/sysfs.c @@ -23,13 +23,14 @@ */ +#include <linux/capability.h> +#include <linux/io.h> + #include "b43.h" #include "sysfs.h" #include "main.h" #include "phy.h" -#include <linux/capability.h> - #define GENERIC_FILESIZE 64 static int get_integer(const char *buf, size_t count) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 93ee05eeaeb..78277a118b6 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -1,7 +1,7 @@ /* * SuperH On-Chip RTC Support * - * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2006, 2007 Paul Mundt * Copyright (C) 2006 Jamie Lenehan * * Based on the old arch/sh/kernel/cpu/rtc.c by: @@ -23,16 +23,19 @@ #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/io.h> +#include <asm/rtc.h> #define DRV_NAME "sh-rtc" -#define DRV_VERSION "0.1.2" +#define DRV_VERSION "0.1.3" #ifdef CONFIG_CPU_SH3 #define rtc_reg_size sizeof(u16) #define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */ +#define RTC_DEF_CAPABILITIES 0UL #elif defined(CONFIG_CPU_SH4) #define rtc_reg_size sizeof(u32) #define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */ +#define RTC_DEF_CAPABILITIES RTC_CAP_4_DIGIT_YEAR #endif #define RTC_REG(r) ((r) * rtc_reg_size) @@ -80,6 +83,7 @@ struct sh_rtc { struct rtc_device *rtc_dev; spinlock_t lock; int rearm_aie; + unsigned long capabilities; /* See asm-sh/rtc.h for cap bits */ }; static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id) @@ -319,14 +323,14 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT)); tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT)) - 1; -#if defined(CONFIG_CPU_SH4) - yr = readw(rtc->regbase + RYRCNT); - yr100 = BCD2BIN(yr >> 8); - yr &= 0xff; -#else - yr = readb(rtc->regbase + RYRCNT); - yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20); -#endif + if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) { + yr = readw(rtc->regbase + RYRCNT); + yr100 = BCD2BIN(yr >> 8); + yr &= 0xff; + } else { + yr = readb(rtc->regbase + RYRCNT); + yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20); + } tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900; @@ -375,14 +379,14 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm) writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT); writeb(BIN2BCD(tm->tm_mon + 1), rtc->regbase + RMONCNT); -#ifdef CONFIG_CPU_SH3 - year = tm->tm_year % 100; - writeb(BIN2BCD(year), rtc->regbase + RYRCNT); -#else - year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) | - BIN2BCD(tm->tm_year % 100); - writew(year, rtc->regbase + RYRCNT); -#endif + if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) { + year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) | + BIN2BCD(tm->tm_year % 100); + writew(year, rtc->regbase + RYRCNT); + } else { + year = tm->tm_year % 100; + writeb(BIN2BCD(year), rtc->regbase + RYRCNT); + } /* Start RTC */ tmp = readb(rtc->regbase + RCR2); @@ -589,6 +593,17 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) goto err_badmap; } + rtc->capabilities = RTC_DEF_CAPABILITIES; + if (pdev->dev.platform_data) { + struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data; + + /* + * Some CPUs have special capabilities in addition to the + * default set. Add those in here. + */ + rtc->capabilities |= pinfo->capabilities; + } + platform_set_drvdata(pdev, rtc); return 0; diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 053fca41b08..73440e26834 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -4,6 +4,7 @@ * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) * * Copyright (C) 2002 - 2006 Paul Mundt + * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007). * * based off of the old drivers/char/sh-sci.c by: * @@ -301,6 +302,38 @@ static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag) } sci_out(port, SCFCR, fcr_val); } +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) +static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) +{ + unsigned int fcr_val = 0; + unsigned short data; + + if (cflag & CRTSCTS) { + /* enable RTS/CTS */ + if (port->mapbase == 0xa4430000) { /* SCIF0 */ + /* Clear PTCR bit 9-2; enable all scif pins but sck */ + data = ctrl_inw(PORT_PTCR); + ctrl_outw((data & 0xfc03), PORT_PTCR); + } else if (port->mapbase == 0xa4438000) { /* SCIF1 */ + /* Clear PVCR bit 9-2 */ + data = ctrl_inw(PORT_PVCR); + ctrl_outw((data & 0xfc03), PORT_PVCR); + } + fcr_val |= SCFCR_MCE; + } else { + if (port->mapbase == 0xa4430000) { /* SCIF0 */ + /* Clear PTCR bit 5-2; enable only tx and rx */ + data = ctrl_inw(PORT_PTCR); + ctrl_outw((data & 0xffc3), PORT_PTCR); + } else if (port->mapbase == 0xa4438000) { /* SCIF1 */ + /* Clear PVCR bit 5-2 */ + data = ctrl_inw(PORT_PVCR); + ctrl_outw((data & 0xffc3), PORT_PVCR); + } + } + sci_out(port, SCFCR, fcr_val); +} + #elif defined(CONFIG_CPU_SH3) /* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) @@ -1276,7 +1309,7 @@ static int __init sci_console_init(void) console_initcall(sci_console_init); #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ -#ifdef CONFIG_SH_KGDB +#ifdef CONFIG_SH_KGDB_CONSOLE /* * FIXME: Most of this can go away.. at the moment, we rely on * arch/sh/kernel/setup.c to do the command line parsing for kgdb, though @@ -1334,9 +1367,7 @@ int __init kgdb_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -#endif /* CONFIG_SH_KGDB */ -#ifdef CONFIG_SH_KGDB_CONSOLE static struct console kgdb_console = { .name = "ttySC", .device = uart_console_device, @@ -1432,7 +1463,7 @@ static int __devinit sci_probe(struct platform_device *dev) #ifdef CONFIG_CPU_FREQ cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); - dev_info(&dev->dev, "sci: CPU frequency notifier registered\n"); + dev_info(&dev->dev, "CPU frequency notifier registered\n"); #endif #ifdef CONFIG_SH_STANDARD_BIOS diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index cf75466ebf5..e89ae29645d 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -10,19 +10,19 @@ * Modified to support SH7300(SH-Mobile) SCIF. Takashi Kusuda (Jun 2003). * Modified to support H8/300 Series Yoshinori Sato (Feb 2004). * Removed SH7300 support (Jul 2007). + * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Aug 2007). */ #include <linux/serial_core.h> #include <asm/io.h> -#if defined(__H8300H__) || defined(__H8300S__) #include <asm/gpio.h> + #if defined(CONFIG_H83007) || defined(CONFIG_H83068) #include <asm/regs306x.h> #endif #if defined(CONFIG_H8S2678) #include <asm/regs267x.h> #endif -#endif #if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ defined(CONFIG_CPU_SUBTYPE_SH7707) || \ @@ -46,6 +46,10 @@ */ # define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0 # define SCIF_ONLY +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) +# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define SCIF_ONLY +#define SCIF_ORER 0x0200 /* overrun error bit */ #elif defined(CONFIG_SH_RTS7751R2D) # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ @@ -217,7 +221,8 @@ #define SCIF_RDF 0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ #define SCIF_DR 0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#if defined(CONFIG_CPU_SUBTYPE_SH7705) +#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) #define SCIF_ORER 0x0200 #define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER) #define SCIF_RFDC_MASK 0x007f @@ -254,7 +259,8 @@ # define SCxSR_FER(port) SCIF_FER # define SCxSR_PER(port) SCIF_PER # define SCxSR_BRK(port) SCIF_BRK -#if defined(CONFIG_CPU_SUBTYPE_SH7705) +#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) # define SCxSR_RDxF_CLEAR(port) (sci_in(port,SCxSR)&0xfffc) # define SCxSR_ERROR_CLEAR(port) (sci_in(port,SCxSR)&0xfd73) # define SCxSR_TDxE_CLEAR(port) (sci_in(port,SCxSR)&0xffdf) @@ -362,7 +368,8 @@ CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size) #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) +#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) #define SCIF_FNS(name, scif_offset, scif_size) \ CPU_SCIF_FNS(name, scif_offset, scif_size) #else @@ -388,7 +395,8 @@ CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) #endif -#if defined(CONFIG_CPU_SUBTYPE_SH7705) +#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) SCIF_FNS(SCSMR, 0x00, 16) SCIF_FNS(SCBRR, 0x04, 8) @@ -510,7 +518,15 @@ static inline void set_sh771x_scif_pfc(struct uart_port *port) return; } } - +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xa4430000) + return sci_in(port, SCxSR) & 0x0003 ? 1 : 0; + else if (port->mapbase == 0xa4438000) + return sci_in(port, SCxSR) & 0x0003 ? 1 : 0; + return 1; +} #elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ defined(CONFIG_CPU_SUBTYPE_SH7751) || \ defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ @@ -653,6 +669,7 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ if (port->mapbase == 0xffc60000) return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ + return 1; } #endif @@ -691,7 +708,8 @@ static inline int sci_rxd_in(struct uart_port *port) #if defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1) -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) +#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) #elif defined(__H8300H__) || defined(__H8300S__) #define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1) diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile index 8a143894e33..a96f4a8cfeb 100644 --- a/drivers/sh/Makefile +++ b/drivers/sh/Makefile @@ -2,5 +2,5 @@ # Makefile for the SuperH specific drivers. # -obj-$(CONFIG_SUPERHYWAY) += superhyway/ - +obj-$(CONFIG_SUPERHYWAY) += superhyway/ +obj-$(CONFIG_MAPLE) += maple/ diff --git a/drivers/sh/maple/Makefile b/drivers/sh/maple/Makefile new file mode 100644 index 00000000000..65dfeeb610e --- /dev/null +++ b/drivers/sh/maple/Makefile @@ -0,0 +1,3 @@ +# Makefile for Maple Bus + +obj-$(CONFIG_MAPLE) := maple.o diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c new file mode 100644 index 00000000000..161d1021b7e --- /dev/null +++ b/drivers/sh/maple/maple.c @@ -0,0 +1,735 @@ +/* + * Core maple bus functionality + * + * Copyright (C) 2007 Adrian McMenamin + * + * Based on 2.4 code by: + * + * Copyright (C) 2000-2001 YAEGASHI Takeshi + * Copyright (C) 2001 M. R. Brown + * Copyright (C) 2001 Paul Mundt + * + * and others. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/maple.h> +#include <linux/dma-mapping.h> +#include <asm/cacheflush.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/mach/dma.h> +#include <asm/mach/sysasic.h> +#include <asm/mach/maple.h> + +MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, M.R. Brown, Adrian McMenamin"); +MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}"); + +static void maple_dma_handler(struct work_struct *work); +static void maple_vblank_handler(struct work_struct *work); + +static DECLARE_WORK(maple_dma_process, maple_dma_handler); +static DECLARE_WORK(maple_vblank_process, maple_vblank_handler); + +static LIST_HEAD(maple_waitq); +static LIST_HEAD(maple_sentq); + +static DEFINE_MUTEX(maple_list_lock); + +static struct maple_driver maple_dummy_driver; +static struct device maple_bus; +static int subdevice_map[MAPLE_PORTS]; +static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; +static unsigned long maple_pnp_time; +static int started, scanning, liststatus; +static struct kmem_cache *maple_queue_cache; + +struct maple_device_specify { + int port; + int unit; +}; + +/** + * maple_driver_register - register a device driver + * automatically makes the driver bus a maple bus + * @drv: the driver to be registered + */ +int maple_driver_register(struct device_driver *drv) +{ + if (!drv) + return -EINVAL; + drv->bus = &maple_bus_type; + return driver_register(drv); +} +EXPORT_SYMBOL_GPL(maple_driver_register); + +/* set hardware registers to enable next round of dma */ +static void maplebus_dma_reset(void) +{ + ctrl_outl(MAPLE_MAGIC, MAPLE_RESET); + /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */ + ctrl_outl(1, MAPLE_TRIGTYPE); + ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED); + ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR); + ctrl_outl(1, MAPLE_ENABLE); +} + +/** + * maple_getcond_callback - setup handling MAPLE_COMMAND_GETCOND + * @dev: device responding + * @callback: handler callback + * @interval: interval in jiffies between callbacks + * @function: the function code for the device + */ +void maple_getcond_callback(struct maple_device *dev, + void (*callback) (struct mapleq * mq), + unsigned long interval, unsigned long function) +{ + dev->callback = callback; + dev->interval = interval; + dev->function = cpu_to_be32(function); + dev->when = jiffies; +} +EXPORT_SYMBOL_GPL(maple_getcond_callback); + +static int maple_dma_done(void) +{ + return (ctrl_inl(MAPLE_STATE) & 1) == 0; +} + +static void maple_release_device(struct device *dev) +{ + if (dev->type) { + kfree(dev->type->name); + kfree(dev->type); + } +} + +/** + * maple_add_packet - add a single instruction to the queue + * @mq: instruction to add to waiting queue + */ +void maple_add_packet(struct mapleq *mq) +{ + mutex_lock(&maple_list_lock); + list_add(&mq->list, &maple_waitq); + mutex_unlock(&maple_list_lock); +} +EXPORT_SYMBOL_GPL(maple_add_packet); + +static struct mapleq *maple_allocq(struct maple_device *dev) +{ + struct mapleq *mq; + + mq = kmalloc(sizeof(*mq), GFP_KERNEL); + if (!mq) + return NULL; + + mq->dev = dev; + mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL); + mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp); + if (!mq->recvbuf) { + kfree(mq); + return NULL; + } + + return mq; +} + +static struct maple_device *maple_alloc_dev(int port, int unit) +{ + struct maple_device *dev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->port = port; + dev->unit = unit; + dev->mq = maple_allocq(dev); + + if (!dev->mq) { + kfree(dev); + return NULL; + } + + return dev; +} + +static void maple_free_dev(struct maple_device *mdev) +{ + if (!mdev) + return; + if (mdev->mq) { + kmem_cache_free(maple_queue_cache, mdev->mq->recvbufdcsp); + kfree(mdev->mq); + } + kfree(mdev); +} + +/* process the command queue into a maple command block + * terminating command has bit 32 of first long set to 0 + */ +static void maple_build_block(struct mapleq *mq) +{ + int port, unit, from, to, len; + unsigned long *lsendbuf = mq->sendbuf; + + port = mq->dev->port & 3; + unit = mq->dev->unit; + len = mq->length; + from = port << 6; + to = (port << 6) | (unit > 0 ? (1 << (unit - 1)) & 0x1f : 0x20); + + *maple_lastptr &= 0x7fffffff; + maple_lastptr = maple_sendptr; + + *maple_sendptr++ = (port << 16) | len | 0x80000000; + *maple_sendptr++ = PHYSADDR(mq->recvbuf); + *maple_sendptr++ = + mq->command | (to << 8) | (from << 16) | (len << 24); + + while (len-- > 0) + *maple_sendptr++ = *lsendbuf++; +} + +/* build up command queue */ +static void maple_send(void) +{ + int i; + int maple_packets; + struct mapleq *mq, *nmq; + + if (!list_empty(&maple_sentq)) + return; + if (list_empty(&maple_waitq) || !maple_dma_done()) + return; + maple_packets = 0; + maple_sendptr = maple_lastptr = maple_sendbuf; + list_for_each_entry_safe(mq, nmq, &maple_waitq, list) { + maple_build_block(mq); + list_move(&mq->list, &maple_sentq); + if (maple_packets++ > MAPLE_MAXPACKETS) + break; + } + if (maple_packets > 0) { + for (i = 0; i < (1 << MAPLE_DMA_PAGES); i++) + dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE, + PAGE_SIZE, DMA_BIDIRECTIONAL); + } +} + +static int attach_matching_maple_driver(struct device_driver *driver, + void *devptr) +{ + struct maple_driver *maple_drv; + struct maple_device *mdev; + + mdev = devptr; + maple_drv = to_maple_driver(driver); + if (mdev->devinfo.function & be32_to_cpu(maple_drv->function)) { + if (maple_drv->connect(mdev) == 0) { + mdev->driver = maple_drv; + return 1; + } + } + return 0; +} + +static void maple_detach_driver(struct maple_device *mdev) +{ + if (!mdev) + return; + if (mdev->driver) { + if (mdev->driver->disconnect) + mdev->driver->disconnect(mdev); + } + mdev->driver = NULL; + if (mdev->registered) { + maple_release_device(&mdev->dev); + device_unregister(&mdev->dev); + } + mdev->registered = 0; + maple_free_dev(mdev); +} + +/* process initial MAPLE_COMMAND_DEVINFO for each device or port */ +static void maple_attach_driver(struct maple_device *dev) +{ + char *p; + + char *recvbuf; + unsigned long function; + int matched, retval; + + recvbuf = dev->mq->recvbuf; + memcpy(&dev->devinfo, recvbuf + 4, sizeof(dev->devinfo)); + memcpy(dev->product_name, dev->devinfo.product_name, 30); + memcpy(dev->product_licence, dev->devinfo.product_licence, 60); + dev->product_name[30] = '\0'; + dev->product_licence[60] = '\0'; + + for (p = dev->product_name + 29; dev->product_name <= p; p--) + if (*p == ' ') + *p = '\0'; + else + break; + + for (p = dev->product_licence + 59; dev->product_licence <= p; p--) + if (*p == ' ') + *p = '\0'; + else + break; + + function = be32_to_cpu(dev->devinfo.function); + + if (function > 0x200) { + /* Do this silently - as not a real device */ + function = 0; + dev->driver = &maple_dummy_driver; + sprintf(dev->dev.bus_id, "%d:0.port", dev->port); + } else { + printk(KERN_INFO + "Maple bus at (%d, %d): Connected function 0x%lX\n", + dev->port, dev->unit, function); + + matched = + bus_for_each_drv(&maple_bus_type, NULL, dev, + attach_matching_maple_driver); + + if (matched == 0) { + /* Driver does not exist yet */ + printk(KERN_INFO + "No maple driver found for this device\n"); + dev->driver = &maple_dummy_driver; + } + + sprintf(dev->dev.bus_id, "%d:0%d.%lX", dev->port, + dev->unit, function); + } + dev->function = function; + dev->dev.bus = &maple_bus_type; + dev->dev.parent = &maple_bus; + dev->dev.release = &maple_release_device; + retval = device_register(&dev->dev); + if (retval) { + printk(KERN_INFO + "Maple bus: Attempt to register device (%x, %x) failed.\n", + dev->port, dev->unit); + maple_free_dev(dev); + } + dev->registered = 1; +} + +/* + * if device has been registered for the given + * port and unit then return 1 - allows identification + * of which devices need to be attached or detached + */ +static int detach_maple_device(struct device *device, void *portptr) +{ + struct maple_device_specify *ds; + struct maple_device *mdev; + + ds = portptr; + mdev = to_maple_dev(device); + if (mdev->port == ds->port && mdev->unit == ds->unit) + return 1; + return 0; +} + +static int setup_maple_commands(struct device *device, void *ignored) +{ + struct maple_device *maple_dev = to_maple_dev(device); + + if ((maple_dev->interval > 0) + && time_after(jiffies, maple_dev->when)) { + maple_dev->when = jiffies + maple_dev->interval; + maple_dev->mq->command = MAPLE_COMMAND_GETCOND; + maple_dev->mq->sendbuf = &maple_dev->function; + maple_dev->mq->length = 1; + maple_add_packet(maple_dev->mq); + liststatus++; + } else { + if (time_after(jiffies, maple_pnp_time)) { + maple_dev->mq->command = MAPLE_COMMAND_DEVINFO; + maple_dev->mq->length = 0; + maple_add_packet(maple_dev->mq); + liststatus++; + } + } + + return 0; +} + +/* VBLANK bottom half - implemented via workqueue */ +static void maple_vblank_handler(struct work_struct *work) +{ + if (!maple_dma_done()) + return; + if (!list_empty(&maple_sentq)) + return; + ctrl_outl(0, MAPLE_ENABLE); + liststatus = 0; + bus_for_each_dev(&maple_bus_type, NULL, NULL, + setup_maple_commands); + if (time_after(jiffies, maple_pnp_time)) + maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; + if (liststatus && list_empty(&maple_sentq)) { + INIT_LIST_HEAD(&maple_sentq); + maple_send(); + } + maplebus_dma_reset(); +} + +/* handle devices added via hotplugs - placing them on queue for DEVINFO*/ +static void maple_map_subunits(struct maple_device *mdev, int submask) +{ + int retval, k, devcheck; + struct maple_device *mdev_add; + struct maple_device_specify ds; + + for (k = 0; k < 5; k++) { + ds.port = mdev->port; + ds.unit = k + 1; + retval = + bus_for_each_dev(&maple_bus_type, NULL, &ds, + detach_maple_device); + if (retval) { + submask = submask >> 1; + continue; + } + devcheck = submask & 0x01; + if (devcheck) { + mdev_add = maple_alloc_dev(mdev->port, k + 1); + if (!mdev_add) + return; + mdev_add->mq->command = MAPLE_COMMAND_DEVINFO; + mdev_add->mq->length = 0; + maple_add_packet(mdev_add->mq); + scanning = 1; + } + submask = submask >> 1; + } +} + +/* mark a device as removed */ +static void maple_clean_submap(struct maple_device *mdev) +{ + int killbit; + + killbit = (mdev->unit > 0 ? (1 << (mdev->unit - 1)) & 0x1f : 0x20); + killbit = ~killbit; + killbit &= 0xFF; + subdevice_map[mdev->port] = subdevice_map[mdev->port] & killbit; +} + +/* handle empty port or hotplug removal */ +static void maple_response_none(struct maple_device *mdev, + struct mapleq *mq) +{ + if (mdev->unit != 0) { + list_del(&mq->list); + maple_clean_submap(mdev); + printk(KERN_INFO + "Maple bus device detaching at (%d, %d)\n", + mdev->port, mdev->unit); + maple_detach_driver(mdev); + return; + } + if (!started) { + printk(KERN_INFO "No maple devices attached to port %d\n", + mdev->port); + return; + } + maple_clean_submap(mdev); +} + +/* preprocess hotplugs or scans */ +static void maple_response_devinfo(struct maple_device *mdev, + char *recvbuf) +{ + char submask; + if ((!started) || (scanning == 2)) { + maple_attach_driver(mdev); + return; + } + if (mdev->unit == 0) { + submask = recvbuf[2] & 0x1F; + if (submask ^ subdevice_map[mdev->port]) { + maple_map_subunits(mdev, submask); + subdevice_map[mdev->port] = submask; + } + } +} + +/* maple dma end bottom half - implemented via workqueue */ +static void maple_dma_handler(struct work_struct *work) +{ + struct mapleq *mq, *nmq; + struct maple_device *dev; + char *recvbuf; + enum maple_code code; + + if (!maple_dma_done()) + return; + ctrl_outl(0, MAPLE_ENABLE); + if (!list_empty(&maple_sentq)) { + list_for_each_entry_safe(mq, nmq, &maple_sentq, list) { + recvbuf = mq->recvbuf; + code = recvbuf[0]; + dev = mq->dev; + switch (code) { + case MAPLE_RESPONSE_NONE: + maple_response_none(dev, mq); + break; + + case MAPLE_RESPONSE_DEVINFO: + maple_response_devinfo(dev, recvbuf); + break; + + case MAPLE_RESPONSE_DATATRF: + if (dev->callback) + dev->callback(mq); + break; + + case MAPLE_RESPONSE_FILEERR: + case MAPLE_RESPONSE_AGAIN: + case MAPLE_RESPONSE_BADCMD: + case MAPLE_RESPONSE_BADFUNC: + printk(KERN_DEBUG + "Maple non-fatal error 0x%X\n", + code); + break; + + case MAPLE_RESPONSE_ALLINFO: + printk(KERN_DEBUG + "Maple - extended device information not supported\n"); + break; + + case MAPLE_RESPONSE_OK: + break; + + default: + break; + } + } + INIT_LIST_HEAD(&maple_sentq); + if (scanning == 1) { + maple_send(); + scanning = 2; + } else + scanning = 0; + + if (started == 0) + started = 1; + } + maplebus_dma_reset(); +} + +static irqreturn_t maplebus_dma_interrupt(int irq, void *dev_id) +{ + /* Load everything into the bottom half */ + schedule_work(&maple_dma_process); + return IRQ_HANDLED; +} + +static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id) +{ + schedule_work(&maple_vblank_process); + return IRQ_HANDLED; +} + +static struct irqaction maple_dma_irq = { + .name = "maple bus DMA handler", + .handler = maplebus_dma_interrupt, + .flags = IRQF_SHARED, +}; + +static struct irqaction maple_vblank_irq = { + .name = "maple bus VBLANK handler", + .handler = maplebus_vblank_interrupt, + .flags = IRQF_SHARED, +}; + +static int maple_set_dma_interrupt_handler(void) +{ + return setup_irq(HW_EVENT_MAPLE_DMA, &maple_dma_irq); +} + +static int maple_set_vblank_interrupt_handler(void) +{ + return setup_irq(HW_EVENT_VSYNC, &maple_vblank_irq); +} + +static int maple_get_dma_buffer(void) +{ + maple_sendbuf = + (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, + MAPLE_DMA_PAGES); + if (!maple_sendbuf) + return -ENOMEM; + return 0; +} + +static int match_maple_bus_driver(struct device *devptr, + struct device_driver *drvptr) +{ + struct maple_driver *maple_drv; + struct maple_device *maple_dev; + + maple_drv = container_of(drvptr, struct maple_driver, drv); + maple_dev = container_of(devptr, struct maple_device, dev); + /* Trap empty port case */ + if (maple_dev->devinfo.function == 0xFFFFFFFF) + return 0; + else if (maple_dev->devinfo.function & + be32_to_cpu(maple_drv->function)) + return 1; + return 0; +} + +static int maple_bus_uevent(struct device *dev, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + return 0; +} + +static void maple_bus_release(struct device *dev) +{ +} + +static struct maple_driver maple_dummy_driver = { + .drv = { + .name = "maple_dummy_driver", + .bus = &maple_bus_type, + }, +}; + +struct bus_type maple_bus_type = { + .name = "maple", + .match = match_maple_bus_driver, + .uevent = maple_bus_uevent, +}; +EXPORT_SYMBOL_GPL(maple_bus_type); + +static struct device maple_bus = { + .bus_id = "maple", + .release = maple_bus_release, +}; + +static int __init maple_bus_init(void) +{ + int retval, i; + struct maple_device *mdev[MAPLE_PORTS]; + ctrl_outl(0, MAPLE_STATE); + + retval = device_register(&maple_bus); + if (retval) + goto cleanup; + + retval = bus_register(&maple_bus_type); + if (retval) + goto cleanup_device; + + retval = driver_register(&maple_dummy_driver.drv); + + if (retval) + goto cleanup_bus; + + /* allocate memory for maple bus dma */ + retval = maple_get_dma_buffer(); + if (retval) { + printk(KERN_INFO + "Maple bus: Failed to allocate Maple DMA buffers\n"); + goto cleanup_basic; + } + + /* set up DMA interrupt handler */ + retval = maple_set_dma_interrupt_handler(); + if (retval) { + printk(KERN_INFO + "Maple bus: Failed to grab maple DMA IRQ\n"); + goto cleanup_dma; + } + + /* set up VBLANK interrupt handler */ + retval = maple_set_vblank_interrupt_handler(); + if (retval) { + printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n"); + goto cleanup_irq; + } + + maple_queue_cache = + kmem_cache_create("maple_queue_cache", 0x400, 0, + SLAB_HWCACHE_ALIGN, NULL); + + if (!maple_queue_cache) + goto cleanup_bothirqs; + + /* setup maple ports */ + for (i = 0; i < MAPLE_PORTS; i++) { + mdev[i] = maple_alloc_dev(i, 0); + if (!mdev[i]) { + while (i-- > 0) + maple_free_dev(mdev[i]); + goto cleanup_cache; + } + mdev[i]->registered = 0; + mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO; + mdev[i]->mq->length = 0; + maple_attach_driver(mdev[i]); + maple_add_packet(mdev[i]->mq); + subdevice_map[i] = 0; + } + + /* setup maplebus hardware */ + maplebus_dma_reset(); + + /* initial detection */ + maple_send(); + + maple_pnp_time = jiffies; + + printk(KERN_INFO "Maple bus core now registered.\n"); + + return 0; + +cleanup_cache: + kmem_cache_destroy(maple_queue_cache); + +cleanup_bothirqs: + free_irq(HW_EVENT_VSYNC, 0); + +cleanup_irq: + free_irq(HW_EVENT_MAPLE_DMA, 0); + +cleanup_dma: + free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES); + +cleanup_basic: + driver_unregister(&maple_dummy_driver.drv); + +cleanup_bus: + bus_unregister(&maple_bus_type); + +cleanup_device: + device_unregister(&maple_bus); + +cleanup: + printk(KERN_INFO "Maple bus registration failed\n"); + return retval; +} +subsys_initcall(maple_bus_init); diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 74d5182db4b..cfd13eb866b 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -11,6 +11,7 @@ #include "ssb_private.h" #include <linux/delay.h> +#include <linux/io.h> #include <linux/ssb/ssb.h> #include <linux/ssb/ssb_regs.h> #include <linux/dma-mapping.h> diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index 0899fccbd57..fbea2bd129c 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -125,8 +125,8 @@ static int hp680bl_remove(struct platform_device *pdev) { struct backlight_device *bd = platform_get_drvdata(pdev); - hp680bl_data.brightness = 0; - hp680bl_data.power = 0; + bd->props.brightness = 0; + bd->props.power = 0; hp680bl_send_intensity(bd); backlight_device_unregister(bd); diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index 7d6c29800d1..06805c9b237 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c @@ -667,6 +667,8 @@ static int pvr2_init_cable(void) related */ if (cable_type == CT_COMPOSITE) fb_writel(3 << 8, VOUTC); + else if (cable_type == CT_RGB) + fb_writel(1 << 9, VOUTC); else fb_writel(0, VOUTC); @@ -890,7 +892,7 @@ static int __init pvr2fb_dc_init(void) pvr2_fix.mmio_start = 0xa05f8000; /* registers start here */ pvr2_fix.mmio_len = 0x2000; - if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0, + if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, IRQF_SHARED, "pvr2 VBL handler", fb_info)) { return -EBUSY; } diff --git a/fs/Kconfig b/fs/Kconfig index f9eed6d7906..bb02b39380a 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1225,6 +1225,14 @@ config JFFS2_FS_WRITEBUFFER - NOR flash with transparent ECC - DataFlash +config JFFS2_FS_WBUF_VERIFY + bool "Verify JFFS2 write-buffer reads" + depends on JFFS2_FS_WRITEBUFFER + default n + help + This causes JFFS2 to read back every page written through the + write-buffer, and check for errors. + config JFFS2_SUMMARY bool "JFFS2 summary support (EXPERIMENTAL)" depends on JFFS2_FS && EXPERIMENTAL @@ -1295,52 +1303,71 @@ config JFFS2_ZLIB select ZLIB_DEFLATE depends on JFFS2_FS default y - help - Zlib is designed to be a free, general-purpose, legally unencumbered, - lossless data-compression library for use on virtually any computer - hardware and operating system. See <http://www.gzip.org/zlib/> for - further information. + help + Zlib is designed to be a free, general-purpose, legally unencumbered, + lossless data-compression library for use on virtually any computer + hardware and operating system. See <http://www.gzip.org/zlib/> for + further information. - Say 'Y' if unsure. + Say 'Y' if unsure. + +config JFFS2_LZO + bool "JFFS2 LZO compression support" if JFFS2_COMPRESSION_OPTIONS + select LZO_COMPRESS + select LZO_DECOMPRESS + depends on JFFS2_FS + default n + help + minilzo-based compression. Generally works better than Zlib. + + This feature was added in July, 2007. Say 'N' if you need + compatibility with older bootloaders or kernels. config JFFS2_RTIME bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS depends on JFFS2_FS default y - help - Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. + help + Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. config JFFS2_RUBIN bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS depends on JFFS2_FS default n - help - RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. + help + RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. choice - prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS - default JFFS2_CMODE_PRIORITY - depends on JFFS2_FS - help - You can set here the default compression mode of JFFS2 from - the available compression modes. Don't touch if unsure. + prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS + default JFFS2_CMODE_PRIORITY + depends on JFFS2_FS + help + You can set here the default compression mode of JFFS2 from + the available compression modes. Don't touch if unsure. config JFFS2_CMODE_NONE - bool "no compression" - help - Uses no compression. + bool "no compression" + help + Uses no compression. config JFFS2_CMODE_PRIORITY - bool "priority" - help - Tries the compressors in a predefined order and chooses the first - successful one. + bool "priority" + help + Tries the compressors in a predefined order and chooses the first + successful one. config JFFS2_CMODE_SIZE - bool "size (EXPERIMENTAL)" - help - Tries all compressors and chooses the one which has the smallest - result. + bool "size (EXPERIMENTAL)" + help + Tries all compressors and chooses the one which has the smallest + result. + +config JFFS2_CMODE_FAVOURLZO + bool "Favour LZO" + help + Tries all compressors and chooses the one which has the smallest + result but gives some preference to LZO (which has faster + decompression) at the expense of size. endchoice diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index c32b241e3d9..60e5d49ca03 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -17,4 +17,5 @@ jffs2-$(CONFIG_JFFS2_FS_POSIX_ACL) += acl.o jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o +jffs2-$(CONFIG_JFFS2_LZO) += compr_lzo.o jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 65b3a1b5b88..8ec9323e830 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c @@ -176,7 +176,7 @@ static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct spin_unlock(&inode->i_lock); } -static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) +struct posix_acl *jffs2_get_acl(struct inode *inode, int type) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct posix_acl *acl; @@ -247,8 +247,13 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) if (rc < 0) return rc; if (inode->i_mode != mode) { - inode->i_mode = mode; - jffs2_dirty_inode(inode); + struct iattr attr; + + attr.ia_valid = ATTR_MODE; + attr.ia_mode = mode; + rc = jffs2_do_setattr(inode, &attr); + if (rc < 0) + return rc; } if (rc == 0) acl = NULL; @@ -307,22 +312,16 @@ int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd) return generic_permission(inode, mask, jffs2_check_acl); } -int jffs2_init_acl(struct inode *inode, struct inode *dir) +int jffs2_init_acl(struct inode *inode, struct posix_acl *acl) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct posix_acl *acl = NULL, *clone; + struct posix_acl *clone; mode_t mode; int rc = 0; f->i_acl_access = JFFS2_ACL_NOT_CACHED; f->i_acl_default = JFFS2_ACL_NOT_CACHED; - if (!S_ISLNK(inode->i_mode)) { - acl = jffs2_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (!acl) - inode->i_mode &= ~current->fs->umask; - } + if (acl) { if (S_ISDIR(inode->i_mode)) { rc = jffs2_set_acl(inode, ACL_TYPE_DEFAULT, acl); diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index c84378cee82..90a2dbf5905 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h @@ -28,9 +28,10 @@ struct jffs2_acl_header { #define JFFS2_ACL_NOT_CACHED ((void *)-1) +extern struct posix_acl *jffs2_get_acl(struct inode *inode, int type); extern int jffs2_permission(struct inode *, int, struct nameidata *); extern int jffs2_acl_chmod(struct inode *); -extern int jffs2_init_acl(struct inode *, struct inode *); +extern int jffs2_init_acl(struct inode *, struct posix_acl *); extern void jffs2_clear_acl(struct jffs2_inode_info *); extern struct xattr_handler jffs2_acl_access_xattr_handler; @@ -38,6 +39,7 @@ extern struct xattr_handler jffs2_acl_default_xattr_handler; #else +#define jffs2_get_acl(inode, type) (NULL) #define jffs2_permission NULL #define jffs2_acl_chmod(inode) (0) #define jffs2_init_acl(inode,dir) (0) diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 504643f2e98..d568ae84674 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -23,8 +23,8 @@ static int jffs2_garbage_collect_thread(void *); void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) { spin_lock(&c->erase_completion_lock); - if (c->gc_task && jffs2_thread_should_wake(c)) - send_sig(SIGHUP, c->gc_task, 1); + if (c->gc_task && jffs2_thread_should_wake(c)) + send_sig(SIGHUP, c->gc_task, 1); spin_unlock(&c->erase_completion_lock); } diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 0ca2fff2617..722a6b68295 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -285,6 +285,14 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) than actually making progress? */ c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2; + /* What number of 'very dirty' eraseblocks do we allow before we + trigger the GC thread even if we don't _need_ the space. When we + can't mark nodes obsolete on the medium, the old dirty nodes cause + performance problems because we have to inspect and discard them. */ + c->vdirty_blocks_gctrigger = c->resv_blocks_gctrigger; + if (jffs2_can_mark_obsolete(c)) + c->vdirty_blocks_gctrigger *= 10; + /* If there's less than this amount of dirty space, don't bother trying to GC to make more space. It'll be a fruitless task */ c->nospc_dirty_size = c->sector_size + (c->flash_size / 100); @@ -303,6 +311,8 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024); dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n", c->nospc_dirty_size); + dbg_fsbuild("Very dirty blocks before GC triggered: %d\n", + c->vdirty_blocks_gctrigger); } int jffs2_do_mount_fs(struct jffs2_sb_info *c) diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index 485d065de41..86739ee53b3 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c @@ -5,7 +5,7 @@ * Created by Arjan van de Ven <arjanv@redhat.com> * * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, - * University of Szeged, Hungary + * University of Szeged, Hungary * * For licensing information, see the file 'LICENCE' in this directory. * @@ -24,6 +24,34 @@ static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; /* Statistics for blocks stored without compression */ static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0; + +/* + * Return 1 to use this compression + */ +static int jffs2_is_best_compression(struct jffs2_compressor *this, + struct jffs2_compressor *best, uint32_t size, uint32_t bestsize) +{ + switch (jffs2_compression_mode) { + case JFFS2_COMPR_MODE_SIZE: + if (bestsize > size) + return 1; + return 0; + case JFFS2_COMPR_MODE_FAVOURLZO: + if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size)) + return 1; + if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size)) + return 1; + if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100))) + return 1; + if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size) + return 1; + + return 0; + } + /* Shouldn't happen */ + return 0; +} + /* jffs2_compress: * @data: Pointer to uncompressed data * @cdata: Pointer to returned pointer to buffer for compressed data @@ -43,121 +71,124 @@ static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_co * *datalen accordingly to show the amount of data which were compressed. */ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - unsigned char *data_in, unsigned char **cpage_out, - uint32_t *datalen, uint32_t *cdatalen) + unsigned char *data_in, unsigned char **cpage_out, + uint32_t *datalen, uint32_t *cdatalen) { int ret = JFFS2_COMPR_NONE; - int compr_ret; - struct jffs2_compressor *this, *best=NULL; - unsigned char *output_buf = NULL, *tmp_buf; - uint32_t orig_slen, orig_dlen; - uint32_t best_slen=0, best_dlen=0; + int compr_ret; + struct jffs2_compressor *this, *best=NULL; + unsigned char *output_buf = NULL, *tmp_buf; + uint32_t orig_slen, orig_dlen; + uint32_t best_slen=0, best_dlen=0; - switch (jffs2_compression_mode) { - case JFFS2_COMPR_MODE_NONE: - break; - case JFFS2_COMPR_MODE_PRIORITY: - output_buf = kmalloc(*cdatalen,GFP_KERNEL); - if (!output_buf) { - printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n"); - goto out; - } - orig_slen = *datalen; - orig_dlen = *cdatalen; - spin_lock(&jffs2_compressor_list_lock); - list_for_each_entry(this, &jffs2_compressor_list, list) { - /* Skip decompress-only backwards-compatibility and disabled modules */ - if ((!this->compress)||(this->disabled)) - continue; + switch (jffs2_compression_mode) { + case JFFS2_COMPR_MODE_NONE: + break; + case JFFS2_COMPR_MODE_PRIORITY: + output_buf = kmalloc(*cdatalen,GFP_KERNEL); + if (!output_buf) { + printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n"); + goto out; + } + orig_slen = *datalen; + orig_dlen = *cdatalen; + spin_lock(&jffs2_compressor_list_lock); + list_for_each_entry(this, &jffs2_compressor_list, list) { + /* Skip decompress-only backwards-compatibility and disabled modules */ + if ((!this->compress)||(this->disabled)) + continue; - this->usecount++; - spin_unlock(&jffs2_compressor_list_lock); - *datalen = orig_slen; - *cdatalen = orig_dlen; - compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); - spin_lock(&jffs2_compressor_list_lock); - this->usecount--; - if (!compr_ret) { - ret = this->compr; - this->stat_compr_blocks++; - this->stat_compr_orig_size += *datalen; - this->stat_compr_new_size += *cdatalen; - break; - } - } - spin_unlock(&jffs2_compressor_list_lock); - if (ret == JFFS2_COMPR_NONE) kfree(output_buf); - break; - case JFFS2_COMPR_MODE_SIZE: - orig_slen = *datalen; - orig_dlen = *cdatalen; - spin_lock(&jffs2_compressor_list_lock); - list_for_each_entry(this, &jffs2_compressor_list, list) { - /* Skip decompress-only backwards-compatibility and disabled modules */ - if ((!this->compress)||(this->disabled)) - continue; - /* Allocating memory for output buffer if necessary */ - if ((this->compr_buf_size<orig_dlen)&&(this->compr_buf)) { - spin_unlock(&jffs2_compressor_list_lock); - kfree(this->compr_buf); - spin_lock(&jffs2_compressor_list_lock); - this->compr_buf_size=0; - this->compr_buf=NULL; - } - if (!this->compr_buf) { - spin_unlock(&jffs2_compressor_list_lock); - tmp_buf = kmalloc(orig_dlen,GFP_KERNEL); - spin_lock(&jffs2_compressor_list_lock); - if (!tmp_buf) { - printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n",orig_dlen); - continue; - } - else { - this->compr_buf = tmp_buf; - this->compr_buf_size = orig_dlen; - } - } - this->usecount++; - spin_unlock(&jffs2_compressor_list_lock); - *datalen = orig_slen; - *cdatalen = orig_dlen; - compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); - spin_lock(&jffs2_compressor_list_lock); - this->usecount--; - if (!compr_ret) { - if ((!best_dlen)||(best_dlen>*cdatalen)) { - best_dlen = *cdatalen; - best_slen = *datalen; - best = this; - } - } - } - if (best_dlen) { - *cdatalen = best_dlen; - *datalen = best_slen; - output_buf = best->compr_buf; - best->compr_buf = NULL; - best->compr_buf_size = 0; - best->stat_compr_blocks++; - best->stat_compr_orig_size += best_slen; - best->stat_compr_new_size += best_dlen; - ret = best->compr; - } - spin_unlock(&jffs2_compressor_list_lock); - break; - default: - printk(KERN_ERR "JFFS2: unknow compression mode.\n"); - } + this->usecount++; + spin_unlock(&jffs2_compressor_list_lock); + *datalen = orig_slen; + *cdatalen = orig_dlen; + compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); + spin_lock(&jffs2_compressor_list_lock); + this->usecount--; + if (!compr_ret) { + ret = this->compr; + this->stat_compr_blocks++; + this->stat_compr_orig_size += *datalen; + this->stat_compr_new_size += *cdatalen; + break; + } + } + spin_unlock(&jffs2_compressor_list_lock); + if (ret == JFFS2_COMPR_NONE) + kfree(output_buf); + break; + case JFFS2_COMPR_MODE_SIZE: + case JFFS2_COMPR_MODE_FAVOURLZO: + orig_slen = *datalen; + orig_dlen = *cdatalen; + spin_lock(&jffs2_compressor_list_lock); + list_for_each_entry(this, &jffs2_compressor_list, list) { + /* Skip decompress-only backwards-compatibility and disabled modules */ + if ((!this->compress)||(this->disabled)) + continue; + /* Allocating memory for output buffer if necessary */ + if ((this->compr_buf_size < orig_slen) && (this->compr_buf)) { + spin_unlock(&jffs2_compressor_list_lock); + kfree(this->compr_buf); + spin_lock(&jffs2_compressor_list_lock); + this->compr_buf_size=0; + this->compr_buf=NULL; + } + if (!this->compr_buf) { + spin_unlock(&jffs2_compressor_list_lock); + tmp_buf = kmalloc(orig_slen, GFP_KERNEL); + spin_lock(&jffs2_compressor_list_lock); + if (!tmp_buf) { + printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n", orig_slen); + continue; + } + else { + this->compr_buf = tmp_buf; + this->compr_buf_size = orig_slen; + } + } + this->usecount++; + spin_unlock(&jffs2_compressor_list_lock); + *datalen = orig_slen; + *cdatalen = orig_dlen; + compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); + spin_lock(&jffs2_compressor_list_lock); + this->usecount--; + if (!compr_ret) { + if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen)) + && (*cdatalen < *datalen)) { + best_dlen = *cdatalen; + best_slen = *datalen; + best = this; + } + } + } + if (best_dlen) { + *cdatalen = best_dlen; + *datalen = best_slen; + output_buf = best->compr_buf; + best->compr_buf = NULL; + best->compr_buf_size = 0; + best->stat_compr_blocks++; + best->stat_compr_orig_size += best_slen; + best->stat_compr_new_size += best_dlen; + ret = best->compr; + } + spin_unlock(&jffs2_compressor_list_lock); + break; + default: + printk(KERN_ERR "JFFS2: unknow compression mode.\n"); + } out: - if (ret == JFFS2_COMPR_NONE) { - *cpage_out = data_in; - *datalen = *cdatalen; - none_stat_compr_blocks++; - none_stat_compr_size += *datalen; - } - else { - *cpage_out = output_buf; - } + if (ret == JFFS2_COMPR_NONE) { + *cpage_out = data_in; + *datalen = *cdatalen; + none_stat_compr_blocks++; + none_stat_compr_size += *datalen; + } + else { + *cpage_out = output_buf; + } return ret; } @@ -165,8 +196,8 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint16_t comprtype, unsigned char *cdata_in, unsigned char *data_out, uint32_t cdatalen, uint32_t datalen) { - struct jffs2_compressor *this; - int ret; + struct jffs2_compressor *this; + int ret; /* Older code had a bug where it would write non-zero 'usercompr' fields. Deal with it. */ @@ -177,32 +208,32 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, case JFFS2_COMPR_NONE: /* This should be special-cased elsewhere, but we might as well deal with it */ memcpy(data_out, cdata_in, datalen); - none_stat_decompr_blocks++; + none_stat_decompr_blocks++; break; case JFFS2_COMPR_ZERO: memset(data_out, 0, datalen); break; default: - spin_lock(&jffs2_compressor_list_lock); - list_for_each_entry(this, &jffs2_compressor_list, list) { - if (comprtype == this->compr) { - this->usecount++; - spin_unlock(&jffs2_compressor_list_lock); - ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL); - spin_lock(&jffs2_compressor_list_lock); - if (ret) { - printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret); - } - else { - this->stat_decompr_blocks++; - } - this->usecount--; - spin_unlock(&jffs2_compressor_list_lock); - return ret; - } - } + spin_lock(&jffs2_compressor_list_lock); + list_for_each_entry(this, &jffs2_compressor_list, list) { + if (comprtype == this->compr) { + this->usecount++; + spin_unlock(&jffs2_compressor_list_lock); + ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL); + spin_lock(&jffs2_compressor_list_lock); + if (ret) { + printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret); + } + else { + this->stat_decompr_blocks++; + } + this->usecount--; + spin_unlock(&jffs2_compressor_list_lock); + return ret; + } + } printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype); - spin_unlock(&jffs2_compressor_list_lock); + spin_unlock(&jffs2_compressor_list_lock); return -EIO; } return 0; @@ -210,108 +241,119 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, int jffs2_register_compressor(struct jffs2_compressor *comp) { - struct jffs2_compressor *this; + struct jffs2_compressor *this; - if (!comp->name) { - printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n"); - return -1; - } - comp->compr_buf_size=0; - comp->compr_buf=NULL; - comp->usecount=0; - comp->stat_compr_orig_size=0; - comp->stat_compr_new_size=0; - comp->stat_compr_blocks=0; - comp->stat_decompr_blocks=0; - D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name)); + if (!comp->name) { + printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n"); + return -1; + } + comp->compr_buf_size=0; + comp->compr_buf=NULL; + comp->usecount=0; + comp->stat_compr_orig_size=0; + comp->stat_compr_new_size=0; + comp->stat_compr_blocks=0; + comp->stat_decompr_blocks=0; + D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name)); - spin_lock(&jffs2_compressor_list_lock); + spin_lock(&jffs2_compressor_list_lock); - list_for_each_entry(this, &jffs2_compressor_list, list) { - if (this->priority < comp->priority) { - list_add(&comp->list, this->list.prev); - goto out; - } - } - list_add_tail(&comp->list, &jffs2_compressor_list); + list_for_each_entry(this, &jffs2_compressor_list, list) { + if (this->priority < comp->priority) { + list_add(&comp->list, this->list.prev); + goto out; + } + } + list_add_tail(&comp->list, &jffs2_compressor_list); out: - D2(list_for_each_entry(this, &jffs2_compressor_list, list) { - printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); - }) + D2(list_for_each_entry(this, &jffs2_compressor_list, list) { + printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); + }) - spin_unlock(&jffs2_compressor_list_lock); + spin_unlock(&jffs2_compressor_list_lock); - return 0; + return 0; } int jffs2_unregister_compressor(struct jffs2_compressor *comp) { - D2(struct jffs2_compressor *this;) + D2(struct jffs2_compressor *this;) - D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name)); + D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name)); - spin_lock(&jffs2_compressor_list_lock); + spin_lock(&jffs2_compressor_list_lock); - if (comp->usecount) { - spin_unlock(&jffs2_compressor_list_lock); - printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n"); - return -1; - } - list_del(&comp->list); + if (comp->usecount) { + spin_unlock(&jffs2_compressor_list_lock); + printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n"); + return -1; + } + list_del(&comp->list); - D2(list_for_each_entry(this, &jffs2_compressor_list, list) { - printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); - }) - spin_unlock(&jffs2_compressor_list_lock); - return 0; + D2(list_for_each_entry(this, &jffs2_compressor_list, list) { + printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); + }) + spin_unlock(&jffs2_compressor_list_lock); + return 0; } void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) { - if (orig != comprbuf) - kfree(comprbuf); + if (orig != comprbuf) + kfree(comprbuf); } int __init jffs2_compressors_init(void) { /* Registering compressors */ #ifdef CONFIG_JFFS2_ZLIB - jffs2_zlib_init(); + jffs2_zlib_init(); #endif #ifdef CONFIG_JFFS2_RTIME - jffs2_rtime_init(); + jffs2_rtime_init(); #endif #ifdef CONFIG_JFFS2_RUBIN - jffs2_rubinmips_init(); - jffs2_dynrubin_init(); + jffs2_rubinmips_init(); + jffs2_dynrubin_init(); +#endif +#ifdef CONFIG_JFFS2_LZO + jffs2_lzo_init(); #endif /* Setting default compression mode */ #ifdef CONFIG_JFFS2_CMODE_NONE - jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; - D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");) + jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; + D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");) #else #ifdef CONFIG_JFFS2_CMODE_SIZE - jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; - D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");) + jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; + D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");) +#else +#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO + jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO; + D1(printk(KERN_INFO "JFFS2: default compression mode: favourlzo\n");) #else - D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");) + D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");) +#endif #endif #endif - return 0; + return 0; } int jffs2_compressors_exit(void) { /* Unregistering compressors */ +#ifdef CONFIG_JFFS2_LZO + jffs2_lzo_exit(); +#endif #ifdef CONFIG_JFFS2_RUBIN - jffs2_dynrubin_exit(); - jffs2_rubinmips_exit(); + jffs2_dynrubin_exit(); + jffs2_rubinmips_exit(); #endif #ifdef CONFIG_JFFS2_RTIME - jffs2_rtime_exit(); + jffs2_rtime_exit(); #endif #ifdef CONFIG_JFFS2_ZLIB - jffs2_zlib_exit(); + jffs2_zlib_exit(); #endif - return 0; + return 0; } diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index 68cc7010dbd..7d1d72faa77 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h @@ -2,7 +2,7 @@ * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, - * University of Szeged, Hungary + * University of Szeged, Hungary * * For licensing information, see the file 'LICENCE' in this directory. * @@ -27,34 +27,38 @@ #define JFFS2_RUBINMIPS_PRIORITY 10 #define JFFS2_DYNRUBIN_PRIORITY 20 #define JFFS2_LZARI_PRIORITY 30 -#define JFFS2_LZO_PRIORITY 40 #define JFFS2_RTIME_PRIORITY 50 #define JFFS2_ZLIB_PRIORITY 60 +#define JFFS2_LZO_PRIORITY 80 + #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */ -#define JFFS2_DYNRUBIN_DISABLED /* for decompression */ +#define JFFS2_DYNRUBIN_DISABLED /* for decompression */ #define JFFS2_COMPR_MODE_NONE 0 #define JFFS2_COMPR_MODE_PRIORITY 1 #define JFFS2_COMPR_MODE_SIZE 2 +#define JFFS2_COMPR_MODE_FAVOURLZO 3 + +#define FAVOUR_LZO_PERCENT 80 struct jffs2_compressor { - struct list_head list; - int priority; /* used by prirority comr. mode */ - char *name; - char compr; /* JFFS2_COMPR_XXX */ - int (*compress)(unsigned char *data_in, unsigned char *cpage_out, - uint32_t *srclen, uint32_t *destlen, void *model); - int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, - uint32_t cdatalen, uint32_t datalen, void *model); - int usecount; - int disabled; /* if seted the compressor won't compress */ - unsigned char *compr_buf; /* used by size compr. mode */ - uint32_t compr_buf_size; /* used by size compr. mode */ - uint32_t stat_compr_orig_size; - uint32_t stat_compr_new_size; - uint32_t stat_compr_blocks; - uint32_t stat_decompr_blocks; + struct list_head list; + int priority; /* used by prirority comr. mode */ + char *name; + char compr; /* JFFS2_COMPR_XXX */ + int (*compress)(unsigned char *data_in, unsigned char *cpage_out, + uint32_t *srclen, uint32_t *destlen, void *model); + int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, + uint32_t cdatalen, uint32_t datalen, void *model); + int usecount; + int disabled; /* if set the compressor won't compress */ + unsigned char *compr_buf; /* used by size compr. mode */ + uint32_t compr_buf_size; /* used by size compr. mode */ + uint32_t stat_compr_orig_size; + uint32_t stat_compr_new_size; + uint32_t stat_compr_blocks; + uint32_t stat_decompr_blocks; }; int jffs2_register_compressor(struct jffs2_compressor *comp); @@ -64,12 +68,12 @@ int jffs2_compressors_init(void); int jffs2_compressors_exit(void); uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - unsigned char *data_in, unsigned char **cpage_out, - uint32_t *datalen, uint32_t *cdatalen); + unsigned char *data_in, unsigned char **cpage_out, + uint32_t *datalen, uint32_t *cdatalen); int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - uint16_t comprtype, unsigned char *cdata_in, - unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); + uint16_t comprtype, unsigned char *cdata_in, + unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig); @@ -90,5 +94,9 @@ void jffs2_rtime_exit(void); int jffs2_zlib_init(void); void jffs2_zlib_exit(void); #endif +#ifdef CONFIG_JFFS2_LZO +int jffs2_lzo_init(void); +void jffs2_lzo_exit(void); +#endif #endif /* __JFFS2_COMPR_H__ */ diff --git a/fs/jffs2/compr_lzo.c b/fs/jffs2/compr_lzo.c new file mode 100644 index 00000000000..47b045797e4 --- /dev/null +++ b/fs/jffs2/compr_lzo.c @@ -0,0 +1,108 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright © 2007 Nokia Corporation. All rights reserved. + * + * Created by Richard Purdie <rpurdie@openedhand.com> + * + * For licensing information, see the file 'LICENCE' in this directory. + * + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/init.h> +#include <linux/lzo.h> +#include "compr.h" + +static void *lzo_mem; +static void *lzo_compress_buf; +static DEFINE_MUTEX(deflate_mutex); + +static void free_workspace(void) +{ + vfree(lzo_mem); + vfree(lzo_compress_buf); +} + +static int __init alloc_workspace(void) +{ + lzo_mem = vmalloc(LZO1X_MEM_COMPRESS); + lzo_compress_buf = vmalloc(lzo1x_worst_compress(PAGE_SIZE)); + + if (!lzo_mem || !lzo_compress_buf) { + printk(KERN_WARNING "Failed to allocate lzo deflate workspace\n"); + free_workspace(); + return -ENOMEM; + } + + return 0; +} + +static int jffs2_lzo_compress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t *sourcelen, uint32_t *dstlen, void *model) +{ + size_t compress_size; + int ret; + + mutex_lock(&deflate_mutex); + ret = lzo1x_1_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem); + mutex_unlock(&deflate_mutex); + + if (ret != LZO_E_OK) + return -1; + + if (compress_size > *dstlen) + return -1; + + memcpy(cpage_out, lzo_compress_buf, compress_size); + *dstlen = compress_size; + + return 0; +} + +static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t srclen, uint32_t destlen, void *model) +{ + size_t dl = destlen; + int ret; + + ret = lzo1x_decompress_safe(data_in, srclen, cpage_out, &dl); + + if (ret != LZO_E_OK || dl != destlen) + return -1; + + return 0; +} + +static struct jffs2_compressor jffs2_lzo_comp = { + .priority = JFFS2_LZO_PRIORITY, + .name = "lzo", + .compr = JFFS2_COMPR_LZO, + .compress = &jffs2_lzo_compress, + .decompress = &jffs2_lzo_decompress, + .disabled = 0, +}; + +int __init jffs2_lzo_init(void) +{ + int ret; + + ret = alloc_workspace(); + if (ret < 0) + return ret; + + ret = jffs2_register_compressor(&jffs2_lzo_comp); + if (ret) + free_workspace(); + + return ret; +} + +void jffs2_lzo_exit(void) +{ + jffs2_unregister_compressor(&jffs2_lzo_comp); + free_workspace(); +} diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index 0d0bfd2e4e0..546d1538d07 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c @@ -104,7 +104,7 @@ static int jffs2_rtime_decompress(unsigned char *data_in, } } } - return 0; + return 0; } static struct jffs2_compressor jffs2_rtime_comp = { diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c index ea0431e047d..c73fa89b5f8 100644 --- a/fs/jffs2/compr_rubin.c +++ b/fs/jffs2/compr_rubin.c @@ -384,7 +384,7 @@ static int jffs2_rubinmips_decompress(unsigned char *data_in, void *model) { rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); - return 0; + return 0; } static int jffs2_dynrubin_decompress(unsigned char *data_in, @@ -399,7 +399,7 @@ static int jffs2_dynrubin_decompress(unsigned char *data_in, bits[c] = data_in[c]; rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen); - return 0; + return 0; } static struct jffs2_compressor jffs2_rubinmips_comp = { diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 2b87fccc155..cfd301a5edf 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c @@ -181,7 +181,7 @@ static int jffs2_zlib_decompress(unsigned char *data_in, } zlib_inflateEnd(&inf_strm); mutex_unlock(&inflate_mutex); - return 0; + return 0; } static struct jffs2_compressor jffs2_zlib_comp = { @@ -203,11 +203,11 @@ int __init jffs2_zlib_init(void) ret = alloc_workspaces(); if (ret) - return ret; + return ret; ret = jffs2_register_compressor(&jffs2_zlib_comp); if (ret) - free_workspaces(); + free_workspaces(); return ret; } diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index c1dfca310dd..8353eb9c179 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -32,7 +32,7 @@ static int jffs2_mkdir (struct inode *,struct dentry *,int); static int jffs2_rmdir (struct inode *,struct dentry *); static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t); static int jffs2_rename (struct inode *, struct dentry *, - struct inode *, struct dentry *); + struct inode *, struct dentry *); const struct file_operations jffs2_dir_operations = { @@ -182,6 +182,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct inode *inode; + struct posix_acl *acl; int ret; ri = jffs2_alloc_raw_inode(); @@ -192,7 +193,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, D1(printk(KERN_DEBUG "jffs2_create()\n")); - inode = jffs2_new_inode(dir_i, mode, ri); + inode = jffs2_new_inode(dir_i, mode, ri, &acl); if (IS_ERR(inode)) { D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n")); @@ -212,12 +213,12 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, dentry->d_name.name, dentry->d_name.len); if (ret) - goto fail; + goto fail_acl; ret = jffs2_init_security(inode, dir_i); if (ret) - goto fail; - ret = jffs2_init_acl(inode, dir_i); + goto fail_acl; + ret = jffs2_init_acl(inode, acl); if (ret) goto fail; @@ -230,6 +231,8 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages)); return 0; + fail_acl: + posix_acl_release(acl); fail: make_bad_inode(inode); iput(inode); @@ -306,6 +309,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char struct jffs2_full_dirent *fd; int namelen; uint32_t alloclen; + struct posix_acl *acl; int ret, targetlen = strlen(target); /* FIXME: If you care. We'd need to use frags for the target @@ -332,7 +336,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char return ret; } - inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri); + inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri, &acl); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); @@ -362,6 +366,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); + posix_acl_release(acl); return PTR_ERR(fn); } @@ -372,6 +377,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); + posix_acl_release(acl); return -ENOMEM; } @@ -389,9 +395,10 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ret = jffs2_init_security(inode, dir_i); if (ret) { jffs2_clear_inode(inode); + posix_acl_release(acl); return ret; } - ret = jffs2_init_acl(inode, dir_i); + ret = jffs2_init_acl(inode, acl); if (ret) { jffs2_clear_inode(inode); return ret; @@ -469,6 +476,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) struct jffs2_full_dirent *fd; int namelen; uint32_t alloclen; + struct posix_acl *acl; int ret; mode |= S_IFDIR; @@ -491,7 +499,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) return ret; } - inode = jffs2_new_inode(dir_i, mode, ri); + inode = jffs2_new_inode(dir_i, mode, ri, &acl); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); @@ -518,6 +526,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); + posix_acl_release(acl); return PTR_ERR(fn); } /* No data here. Only a metadata node, which will be @@ -531,9 +540,10 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ret = jffs2_init_security(inode, dir_i); if (ret) { jffs2_clear_inode(inode); + posix_acl_release(acl); return ret; } - ret = jffs2_init_acl(inode, dir_i); + ret = jffs2_init_acl(inode, acl); if (ret) { jffs2_clear_inode(inode); return ret; @@ -629,6 +639,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de union jffs2_device_node dev; int devlen = 0; uint32_t alloclen; + struct posix_acl *acl; int ret; if (!new_valid_dev(rdev)) @@ -655,7 +666,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de return ret; } - inode = jffs2_new_inode(dir_i, mode, ri); + inode = jffs2_new_inode(dir_i, mode, ri, &acl); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); @@ -684,6 +695,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); + posix_acl_release(acl); return PTR_ERR(fn); } /* No data here. Only a metadata node, which will be @@ -697,9 +709,10 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de ret = jffs2_init_security(inode, dir_i); if (ret) { jffs2_clear_inode(inode); + posix_acl_release(acl); return ret; } - ret = jffs2_init_acl(inode, dir_i); + ret = jffs2_init_acl(inode, acl); if (ret) { jffs2_clear_inode(inode); return ret; @@ -770,7 +783,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de } static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, - struct inode *new_dir_i, struct dentry *new_dentry) + struct inode *new_dir_i, struct dentry *new_dentry) { int ret; struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 66e7c2f1e64..a1db9180633 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -38,8 +38,8 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, #ifdef __ECOS ret = jffs2_flash_erase(c, jeb); if (!ret) { - jffs2_erase_succeeded(c, jeb); - return; + jffs2_erase_succeeded(c, jeb); + return; } bad_offset = jeb->offset; #else /* Linux */ @@ -50,12 +50,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); if (!instr) { printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); list_move(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; c->dirty_size += c->sector_size; jeb->dirty_size = c->sector_size; spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); return; } @@ -82,12 +84,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, if (ret == -ENOMEM || ret == -EAGAIN) { /* Erase failed immediately. Refile it on the list */ D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); list_move(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; c->dirty_size += c->sector_size; jeb->dirty_size = c->sector_size; spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); return; } @@ -114,6 +118,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); list_del(&jeb->list); spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); jffs2_mark_erased_block(c, jeb); if (!--count) { @@ -134,6 +139,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) jffs2_free_jeb_node_refs(c, jeb); list_add(&jeb->list, &c->erasing_list); spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); jffs2_erase_block(c, jeb); @@ -142,23 +148,25 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) } /* Be nice */ - cond_resched(); + yield(); + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); } spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); done: D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); - - up(&c->erase_free_sem); } static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); list_move_tail(&jeb->list, &c->erase_complete_list); spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); /* Ensure that kupdated calls us again to mark them clean */ jffs2_erase_pending_trigger(c); } @@ -172,22 +180,26 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock failed too many times. */ if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { /* We'd like to give this block another try. */ + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); list_move(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; c->dirty_size += c->sector_size; jeb->dirty_size = c->sector_size; spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); return; } } + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); c->erasing_size -= c->sector_size; c->bad_size += c->sector_size; list_move(&jeb->list, &c->bad_list); c->nr_erasing_blocks--; spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); wake_up(&c->erase_wait); } @@ -317,6 +329,33 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl size_t retlen; int ret = -EIO; + if (c->mtd->point) { + unsigned long *wordebuf; + + ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size, &retlen, (unsigned char **)&ebuf); + if (ret) { + D1(printk(KERN_DEBUG "MTD point failed %d\n", ret)); + goto do_flash_read; + } + if (retlen < c->sector_size) { + /* Don't muck about if it won't let us point to the whole erase sector */ + D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen)); + c->mtd->unpoint(c->mtd, ebuf, jeb->offset, retlen); + goto do_flash_read; + } + wordebuf = ebuf-sizeof(*wordebuf); + retlen /= sizeof(*wordebuf); + do { + if (*++wordebuf != ~0) + break; + } while(--retlen); + c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size); + if (retlen) + printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n", + *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf)); + return 0; + } + do_flash_read: ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!ebuf) { printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset); @@ -362,7 +401,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb { size_t retlen; int ret; - uint32_t bad_offset; + uint32_t uninitialized_var(bad_offset); switch (jffs2_block_check_erase(c, jeb, &bad_offset)) { case -EAGAIN: goto refile; @@ -417,6 +456,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); } + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); c->erasing_size -= c->sector_size; c->free_size += jeb->free_size; @@ -429,23 +469,28 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb c->nr_erasing_blocks--; c->nr_free_blocks++; spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); wake_up(&c->erase_wait); return; filebad: + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); /* Stick it on a list (any list) so erase_failed can take it right off again. Silly, but shouldn't happen often. */ list_add(&jeb->list, &c->erasing_list); spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); jffs2_erase_failed(c, jeb, bad_offset); return; refile: /* Stick it back on the list from whence it came and come back later */ jffs2_erase_pending_trigger(c); + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); list_add(&jeb->list, &c->erase_complete_list); spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); return; } diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 8bc727b7169..ed85f9afdbc 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -24,7 +24,7 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c); -static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) +int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) { struct jffs2_full_dnode *old_metadata, *new_metadata; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); @@ -36,10 +36,8 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) unsigned int ivalid; uint32_t alloclen; int ret; + D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); - ret = inode_change_ok(inode, iattr); - if (ret) - return ret; /* Special cases - we don't want more than one data node for these types on the medium at any time. So setattr @@ -183,9 +181,14 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) { int rc; + rc = inode_change_ok(dentry->d_inode, iattr); + if (rc) + return rc; + rc = jffs2_do_setattr(dentry->d_inode, iattr); if (!rc && (iattr->ia_valid & ATTR_MODE)) rc = jffs2_acl_chmod(dentry->d_inode); + return rc; } @@ -399,7 +402,8 @@ void jffs2_write_super (struct super_block *sb) /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, fill in the raw_inode while you're at it. */ -struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri) +struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri, + struct posix_acl **acl) { struct inode *inode; struct super_block *sb = dir_i->i_sb; @@ -431,7 +435,23 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i } else { ri->gid = cpu_to_je16(current->fsgid); } - ri->mode = cpu_to_jemode(mode); + + /* POSIX ACLs have to be processed now, at least partly. + The umask is only applied if there's no default ACL */ + if (!S_ISLNK(mode)) { + *acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT); + if (IS_ERR(*acl)) { + make_bad_inode(inode); + iput(inode); + inode = (void *)*acl; + *acl = NULL; + return inode; + } + if (!(*acl)) + mode &= ~current->fs->umask; + } else { + *acl = NULL; + } ret = jffs2_do_new_inode (c, f, mode, ri); if (ret) { make_bad_inode(inode); diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 2d99e06ab22..32ff0373aa0 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -122,6 +122,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) struct jffs2_inode_cache *ic; struct jffs2_eraseblock *jeb; struct jffs2_raw_node_ref *raw; + uint32_t gcblock_dirty; int ret = 0, inum, nlink; int xattr = 0; @@ -236,6 +237,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) } raw = jeb->gc_node; + gcblock_dirty = jeb->dirty_size; while(ref_obsolete(raw)) { D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw))); @@ -282,7 +284,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) } else { ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw); } - goto release_sem; + goto test_gcnode; } #endif @@ -376,7 +378,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) if (ret != -EBADFD) { spin_unlock(&c->inocache_lock); - goto release_sem; + goto test_gcnode; } /* Fall through if it wanted us to, with inocache_lock held */ @@ -407,6 +409,12 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) jffs2_gc_release_inode(c, f); + test_gcnode: + if (jeb->dirty_size == gcblock_dirty && !ref_obsolete(jeb->gc_node)) { + /* Eep. This really should never happen. GC is broken */ + printk(KERN_ERR "Error garbage collecting node at %08x!\n", ref_offset(jeb->gc_node)); + ret = -ENOSPC; + } release_sem: up(&c->alloc_sem); @@ -556,7 +564,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, node = kmalloc(rawlen, GFP_KERNEL); if (!node) - return -ENOMEM; + return -ENOMEM; ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node); if (!ret && retlen != rawlen) @@ -598,10 +606,15 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, goto bail; } + if (strnlen(node->d.name, node->d.nsize) != node->d.nsize) { + printk(KERN_WARNING "Name in dirent node at 0x%08x contains zeroes\n", ref_offset(raw)); + goto bail; + } + if (node->d.nsize) { crc = crc32(0, node->d.name, node->d.nsize); if (je32_to_cpu(node->d.name_crc) != crc) { - printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ref_offset(raw), je32_to_cpu(node->d.name_crc), crc); goto bail; } @@ -624,7 +637,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, if (ret || (retlen != rawlen)) { printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", - rawlen, phys_ofs, ret, retlen); + rawlen, phys_ofs, ret, retlen); if (retlen) { jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL); } else { diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index b13298a824e..3a2197f3c81 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -69,6 +69,8 @@ struct jffs2_sb_info { uint8_t resv_blocks_gctrigger; /* ... wake up the GC thread */ uint8_t resv_blocks_gcbad; /* ... pick a block from the bad_list to GC */ uint8_t resv_blocks_gcmerge; /* ... merge pages when garbage collecting */ + /* Number of 'very dirty' blocks before we trigger immediate GC */ + uint8_t vdirty_blocks_gctrigger; uint32_t nospc_dirty_size; @@ -106,6 +108,9 @@ struct jffs2_sb_info { uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ +#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY + unsigned char *wbuf_verify; /* read-back buffer for verification */ +#endif #ifdef CONFIG_JFFS2_FS_WRITEBUFFER unsigned char *wbuf; /* Write-behind buffer for NAND flash */ uint32_t wbuf_ofs; diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index bc5509fe577..ec1aae9e695 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -127,7 +127,7 @@ static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_nod return ((struct jffs2_inode_cache *)raw); } - /* flash_offset & 3 always has to be zero, because nodes are + /* flash_offset & 3 always has to be zero, because nodes are always aligned at 4 bytes. So we have a couple of extra bits to play with, which indicate the node's status; see below: */ #define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */ diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index dbc908ad622..a0313fa8748 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -154,7 +154,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, while(ret == -EAGAIN) { ret = jffs2_do_reserve_space(c, minsize, len, sumsize); if (ret) { - D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); + D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); } } spin_unlock(&c->erase_completion_lock); @@ -423,7 +423,12 @@ struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, even after refiling c->nextblock */ if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE)) && (jeb != c->nextblock || (ofs & ~3) != jeb->offset + (c->sector_size - jeb->free_size))) { - printk(KERN_WARNING "argh. node added in wrong place\n"); + printk(KERN_WARNING "argh. node added in wrong place at 0x%08x(%d)\n", ofs & ~3, ofs & 3); + if (c->nextblock) + printk(KERN_WARNING "nextblock 0x%08x", c->nextblock->offset); + else + printk(KERN_WARNING "No nextblock"); + printk(", expected at %08x\n", jeb->offset + (c->sector_size - jeb->free_size)); return ERR_PTR(-EINVAL); } #endif @@ -717,6 +722,8 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c) { int ret = 0; uint32_t dirty; + int nr_very_dirty = 0; + struct jffs2_eraseblock *jeb; if (c->unchecked_size) { D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n", @@ -738,8 +745,18 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c) (dirty > c->nospc_dirty_size)) ret = 1; - D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", - c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no")); + list_for_each_entry(jeb, &c->very_dirty_list, list) { + nr_very_dirty++; + if (nr_very_dirty == c->vdirty_blocks_gctrigger) { + ret = 1; + /* In debug mode, actually go through and count them all */ + D1(continue); + break; + } + } + + D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x, vdirty_blocks %d: %s\n", + c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, nr_very_dirty, ret?"yes":"no")); return ret; } diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 80daea96bbc..f6743a915cf 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -173,12 +173,15 @@ int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long); extern const struct inode_operations jffs2_symlink_inode_operations; /* fs.c */ +struct posix_acl; + int jffs2_setattr (struct dentry *, struct iattr *); +int jffs2_do_setattr (struct inode *, struct iattr *); void jffs2_read_inode (struct inode *); void jffs2_clear_inode (struct inode *); void jffs2_dirty_inode(struct inode *inode); struct inode *jffs2_new_inode (struct inode *dir_i, int mode, - struct jffs2_raw_inode *ri); + struct jffs2_raw_inode *ri, struct posix_acl **acl); int jffs2_statfs (struct dentry *, struct kstatfs *); void jffs2_write_super (struct super_block *); int jffs2_remount_fs (struct super_block *, int *, char *); diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index b5baa356fed..2eae5d2dbeb 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -65,7 +65,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); if (!err && retlen < tn->csize) { JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); - c->mtd->unpoint(c->mtd, buffer, ofs, len); + c->mtd->unpoint(c->mtd, buffer, ofs, retlen); } else if (err) JFFS2_WARNING("MTD point failed: error code %d.\n", err); else @@ -211,7 +211,7 @@ static void jffs2_kill_tn(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info * * ordering. * * Returns 0 if the node was handled (including marking it obsolete) - * < 0 an if error occurred + * < 0 an if error occurred */ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, struct jffs2_readinode_info *rii, @@ -862,8 +862,8 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re JFFS2_ERROR("REF_UNCHECKED but unknown node at %#08x\n", ref_offset(ref)); JFFS2_ERROR("Node is {%04x,%04x,%08x,%08x}. Please report this error.\n", - je16_to_cpu(un->magic), je16_to_cpu(un->nodetype), - je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc)); + je16_to_cpu(un->magic), je16_to_cpu(un->nodetype), + je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc)); jffs2_mark_node_obsolete(c, ref); return 0; } diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 6c75cd43334..272872d27fd 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -101,7 +101,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) if (!ret && pointlen < c->mtd->size) { /* Don't muck about if it won't let us point to the whole flash */ D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen)); - c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); + c->mtd->unpoint(c->mtd, flashbuf, 0, pointlen); flashbuf = NULL; } if (ret) @@ -863,7 +863,7 @@ scan_more: switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) { case JFFS2_FEATURE_ROCOMPAT: printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs); - c->flags |= JFFS2_SB_FLAG_RO; + c->flags |= JFFS2_SB_FLAG_RO; if (!(jffs2_is_readonly(c))) return -EROFS; if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen))))) @@ -1004,6 +1004,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo { struct jffs2_full_dirent *fd; struct jffs2_inode_cache *ic; + uint32_t checkedlen; uint32_t crc; int err; @@ -1024,12 +1025,18 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo pseudo_random += je32_to_cpu(rd->version); - fd = jffs2_alloc_full_dirent(rd->nsize+1); + /* Should never happen. Did. (OLPC trac #4184)*/ + checkedlen = strnlen(rd->name, rd->nsize); + if (checkedlen < rd->nsize) { + printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n", + ofs, checkedlen); + } + fd = jffs2_alloc_full_dirent(checkedlen+1); if (!fd) { return -ENOMEM; } - memcpy(&fd->name, rd->name, rd->nsize); - fd->name[rd->nsize] = 0; + memcpy(&fd->name, rd->name, checkedlen); + fd->name[checkedlen] = 0; crc = crc32(0, fd->name, rd->nsize); if (crc != je32_to_cpu(rd->name_crc)) { @@ -1055,7 +1062,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo fd->next = NULL; fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); - fd->nhash = full_name_hash(fd->name, rd->nsize); + fd->nhash = full_name_hash(fd->name, checkedlen); fd->type = rd->type; jffs2_add_fd_to_list(c, fd, &ic->scan_dents); diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c index bc9f6ba1082..02c39c64ecb 100644 --- a/fs/jffs2/security.c +++ b/fs/jffs2/security.c @@ -38,9 +38,9 @@ int jffs2_init_security(struct inode *inode, struct inode *dir) } rc = do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, name, value, len, 0); - kfree(name); - kfree(value); - return rc; + kfree(name); + kfree(value); + return rc; } /* ---- XATTR Handler for "security.*" ----------------- */ diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index d828b296392..629af01e5ad 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -2,10 +2,10 @@ * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, - * Zoltan Sogor <weth@inf.u-szeged.hu>, - * Patrik Kluba <pajko@halom.u-szeged.hu>, - * University of Szeged, Hungary - * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com> + * Zoltan Sogor <weth@inf.u-szeged.hu>, + * Patrik Kluba <pajko@halom.u-szeged.hu>, + * University of Szeged, Hungary + * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com> * * For licensing information, see the file 'LICENCE' in this directory. * @@ -429,6 +429,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras case JFFS2_NODETYPE_DIRENT: { struct jffs2_sum_dirent_flash *spd; + int checkedlen; spd = sp; dbg_summary("Dirent at 0x%08x-0x%08x\n", @@ -436,12 +437,25 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen)); - fd = jffs2_alloc_full_dirent(spd->nsize+1); + /* This should never happen, but https://dev.laptop.org/ticket/4184 */ + checkedlen = strnlen(spd->name, spd->nsize); + if (!checkedlen) { + printk(KERN_ERR "Dirent at %08x has zero at start of name. Aborting mount.\n", + jeb->offset + je32_to_cpu(spd->offset)); + return -EIO; + } + if (checkedlen < spd->nsize) { + printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n", + jeb->offset + je32_to_cpu(spd->offset), checkedlen); + } + + + fd = jffs2_alloc_full_dirent(checkedlen+1); if (!fd) return -ENOMEM; - memcpy(&fd->name, spd->name, spd->nsize); - fd->name[spd->nsize] = 0; + memcpy(&fd->name, spd->name, checkedlen); + fd->name[checkedlen] = 0; ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); if (!ic) { @@ -455,7 +469,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras fd->next = NULL; fd->version = je32_to_cpu(spd->version); fd->ino = je32_to_cpu(spd->ino); - fd->nhash = full_name_hash(fd->name, spd->nsize); + fd->nhash = full_name_hash(fd->name, checkedlen); fd->type = spd->type; jffs2_add_fd_to_list(c, fd, &ic->scan_dents); diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index 0c6669e2139..8bf34f2fa5c 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h @@ -2,9 +2,9 @@ * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, - * Zoltan Sogor <weth@inf.u-szeged.hu>, - * Patrik Kluba <pajko@halom.u-szeged.hu>, - * University of Szeged, Hungary + * Zoltan Sogor <weth@inf.u-szeged.hu>, + * Patrik Kluba <pajko@halom.u-szeged.hu>, + * University of Szeged, Hungary * * For licensing information, see the file 'LICENCE' in this directory. * diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 91d1d0f1c66..d1d4f27464b 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -220,6 +220,47 @@ static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info return NULL; } +#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY +static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf, + uint32_t ofs) +{ + int ret; + size_t retlen; + char *eccstr; + + ret = c->mtd->read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify); + if (ret && ret != -EUCLEAN && ret != -EBADMSG) { + printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x failed: %d\n", c->wbuf_ofs, ret); + return ret; + } else if (retlen != c->wbuf_pagesize) { + printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x gave short read: %zd not %d.\n", ofs, retlen, c->wbuf_pagesize); + return -EIO; + } + if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize)) + return 0; + + if (ret == -EUCLEAN) + eccstr = "corrected"; + else if (ret == -EBADMSG) + eccstr = "correction failed"; + else + eccstr = "OK or unused"; + + printk(KERN_WARNING "Write verify error (ECC %s) at %08x. Wrote:\n", + eccstr, c->wbuf_ofs); + print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, + c->wbuf, c->wbuf_pagesize, 0); + + printk(KERN_WARNING "Read back:\n"); + print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, + c->wbuf_verify, c->wbuf_pagesize, 0); + + return -EIO; +} +#else +#define jffs2_verify_write(c,b,o) (0) +#endif + /* Recover from failure to write wbuf. Recover the nodes up to the * wbuf, not the one which we were starting to try to write. */ @@ -380,7 +421,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf); - if (ret || retlen != towrite) { + if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) { /* Argh. We tried. Really we did. */ printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); kfree(buf); @@ -587,15 +628,16 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); - if (ret || retlen != c->wbuf_pagesize) { - if (ret) - printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret); - else { - printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n", - retlen, c->wbuf_pagesize); - ret = -EIO; - } - + if (ret) { + printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n", ret); + goto wfail; + } else if (retlen != c->wbuf_pagesize) { + printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n", + retlen, c->wbuf_pagesize); + ret = -EIO; + goto wfail; + } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) { + wfail: jffs2_wbuf_recover(c); return ret; @@ -966,8 +1008,8 @@ exit: #define NR_OOB_SCAN_PAGES 4 -/* For historical reasons we use only 12 bytes for OOB clean marker */ -#define OOB_CM_SIZE 12 +/* For historical reasons we use only 8 bytes for OOB clean marker */ +#define OOB_CM_SIZE 8 static const struct jffs2_unknown_node oob_cleanmarker = { @@ -1021,8 +1063,8 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c, /* * Check for a valid cleanmarker. * Returns: 0 if a valid cleanmarker was found - * 1 if no cleanmarker was found - * negative error code if an error occurred + * 1 if no cleanmarker was found + * negative error code if an error occurred */ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) @@ -1138,11 +1180,22 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c) return -ENOMEM; } +#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY + c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); + if (!c->wbuf_verify) { + kfree(c->oobbuf); + kfree(c->wbuf); + return -ENOMEM; + } +#endif return 0; } void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) { +#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY + kfree(c->wbuf_verify); +#endif kfree(c->wbuf); kfree(c->oobbuf); } diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 664c164aa67..2f5695446d0 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -215,6 +215,17 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff BUG(); }); + if (strnlen(name, namelen) != namelen) { + /* This should never happen, but seems to have done on at least one + occasion: https://dev.laptop.org/ticket/4184 */ + printk(KERN_CRIT "Error in jffs2_write_dirent() -- name contains zero bytes!\n"); + printk(KERN_CRIT "Directory inode #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x\n", + je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino), + je32_to_cpu(rd->name_crc)); + WARN_ON(1); + return ERR_PTR(-EIO); + } + vecs[0].iov_base = rd; vecs[0].iov_len = sizeof(*rd); vecs[1].iov_base = (unsigned char *)name; @@ -226,7 +237,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); - fd->nhash = full_name_hash(name, strlen(name)); + fd->nhash = full_name_hash(name, namelen); fd->type = rd->type; memcpy(fd->name, name, namelen); fd->name[namelen]=0; diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h index 3b0ff292593..6e3b5ddfb7a 100644 --- a/fs/jffs2/xattr.h +++ b/fs/jffs2/xattr.h @@ -75,7 +75,7 @@ extern void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c); extern void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c); extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, - uint32_t xid, uint32_t version); + uint32_t xid, uint32_t version); extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); diff --git a/fs/jffs2/xattr_user.c b/fs/jffs2/xattr_user.c index 40942bc516b..8bbeab90ada 100644 --- a/fs/jffs2/xattr_user.c +++ b/fs/jffs2/xattr_user.c @@ -17,7 +17,7 @@ #include "nodelist.h" static int jffs2_user_getxattr(struct inode *inode, const char *name, - void *buffer, size_t size) + void *buffer, size_t size) { if (!strcmp(name, "")) return -EINVAL; @@ -25,7 +25,7 @@ static int jffs2_user_getxattr(struct inode *inode, const char *name, } static int jffs2_user_setxattr(struct inode *inode, const char *name, const void *buffer, - size_t size, int flags) + size_t size, int flags) { if (!strcmp(name, "")) return -EINVAL; diff --git a/include/asm-blackfin/mach-bf548/dma.h b/include/asm-blackfin/mach-bf548/dma.h index fcc8b4c34c6..14cb10cc24a 100644 --- a/include/asm-blackfin/mach-bf548/dma.h +++ b/include/asm-blackfin/mach-bf548/dma.h @@ -55,6 +55,7 @@ #define CH_SPORT3_RX 20 #define CH_SPORT3_TX 21 #define CH_SDH 22 +#define CH_NFC 22 #define CH_SPI2 23 #define CH_MEM_STREAM0_DEST 24 diff --git a/include/asm-blackfin/nand.h b/include/asm-blackfin/nand.h new file mode 100644 index 00000000000..afbaafa793f --- /dev/null +++ b/include/asm-blackfin/nand.h @@ -0,0 +1,47 @@ +/* linux/include/asm-blackfin/nand.h + * + * Copyright (c) 2007 Analog Devices, Inc. + * Bryan Wu <bryan.wu@analog.com> + * + * BF5XX - NAND flash controller platfrom_device info + * + * 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. + */ + +/* struct bf5xx_nand_platform + * + * define a interface between platfrom board specific code and + * bf54x NFC driver. + * + * nr_partitions = number of partitions pointed to be partitoons (or zero) + * partitions = mtd partition list + */ + +#define NFC_PG_SIZE_256 0 +#define NFC_PG_SIZE_512 1 +#define NFC_PG_SIZE_OFFSET 9 + +#define NFC_NWIDTH_8 0 +#define NFC_NWIDTH_16 1 +#define NFC_NWIDTH_OFFSET 8 + +#define NFC_RDDLY_OFFSET 4 +#define NFC_WRDLY_OFFSET 0 + +#define NFC_STAT_NBUSY 1 + +struct bf5xx_nand_platform { + /* NAND chip information */ + unsigned short page_size; + unsigned short data_width; + + /* RD/WR strobe delay timing information, all times in SCLK cycles */ + unsigned short rd_dly; + unsigned short wr_dly; + + /* NAND MTD partition information */ + int nr_partitions; + struct mtd_partition *partitions; +}; diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 0240e0506a0..5615440027e 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -153,7 +153,8 @@ #define TEXT_TEXT \ ALIGN_FUNCTION(); \ *(.text) \ - *(.text.init.refok) + *(.text.init.refok) \ + *(.exit.text.refok) /* sched.text is aling to function alignment to secure we have same * address even at second ld pass when generating System.map */ diff --git a/include/asm-m68k/Kbuild b/include/asm-m68k/Kbuild index c68e1680da0..1a922fad76f 100644 --- a/include/asm-m68k/Kbuild +++ b/include/asm-m68k/Kbuild @@ -1 +1,2 @@ include include/asm-generic/Kbuild.asm +header-y += cachectl.h diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h index a30fe9c6414..87f77b11931 100644 --- a/include/asm-m68k/unistd.h +++ b/include/asm-m68k/unistd.h @@ -351,6 +351,9 @@ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION +/* whitelist for checksyscalls */ +#define __IGNORE_restart_syscall + /* * "Conditional" syscalls * diff --git a/include/asm-sh/cacheflush.h b/include/asm-sh/cacheflush.h index 07f62ec9ff0..aa558da0847 100644 --- a/include/asm-sh/cacheflush.h +++ b/include/asm-sh/cacheflush.h @@ -1,16 +1,47 @@ #ifndef __ASM_SH_CACHEFLUSH_H #define __ASM_SH_CACHEFLUSH_H + #ifdef __KERNEL__ -#include <linux/mm.h> +#ifdef CONFIG_CACHE_OFF +/* + * Nothing to do when the cache is disabled, initial flush and explicit + * disabling is handled at CPU init time. + * + * See arch/sh/kernel/cpu/init.c:cache_init(). + */ +#define p3_cache_init() do { } while (0) +#define flush_cache_all() do { } while (0) +#define flush_cache_mm(mm) do { } while (0) +#define flush_cache_dup_mm(mm) do { } while (0) +#define flush_cache_range(vma, start, end) do { } while (0) +#define flush_cache_page(vma, vmaddr, pfn) do { } while (0) +#define flush_dcache_page(page) do { } while (0) +#define flush_icache_range(start, end) do { } while (0) +#define flush_icache_page(vma,pg) do { } while (0) +#define flush_dcache_mmap_lock(mapping) do { } while (0) +#define flush_dcache_mmap_unlock(mapping) do { } while (0) +#define flush_cache_sigtramp(vaddr) do { } while (0) +#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) +#define __flush_wback_region(start, size) do { (void)(start); } while (0) +#define __flush_purge_region(start, size) do { (void)(start); } while (0) +#define __flush_invalidate_region(start, size) do { (void)(start); } while (0) +#else #include <asm/cpu/cacheflush.h> +/* + * Consistent DMA requires that the __flush_xxx() primitives must be set + * for any of the enabled non-coherent caches (most of the UP CPUs), + * regardless of PIPT or VIPT cache configurations. + */ + /* Flush (write-back only) a region (smaller than a page) */ extern void __flush_wback_region(void *start, int size); /* Flush (write-back & invalidate) a region (smaller than a page) */ extern void __flush_purge_region(void *start, int size); /* Flush (invalidate only) a region (smaller than a page) */ extern void __flush_invalidate_region(void *start, int size); +#endif #define flush_cache_vmap(start, end) flush_cache_all() #define flush_cache_vunmap(start, end) flush_cache_all() diff --git a/include/asm-sh/cpu-sh3/cache.h b/include/asm-sh/cpu-sh3/cache.h index ffe08d2813f..255016fc91f 100644 --- a/include/asm-sh/cpu-sh3/cache.h +++ b/include/asm-sh/cpu-sh3/cache.h @@ -26,7 +26,9 @@ #define CCR_CACHE_ENABLE CCR_CACHE_CE #define CCR_CACHE_INVALIDATE CCR_CACHE_CF -#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7710) +#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7710) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) #define CCR3 0xa40000b4 #define CCR_CACHE_16KB 0x00010000 #define CCR_CACHE_32KB 0x00020000 diff --git a/include/asm-sh/cpu-sh3/dma.h b/include/asm-sh/cpu-sh3/dma.h index 3a66dc45802..54bfece328c 100644 --- a/include/asm-sh/cpu-sh3/dma.h +++ b/include/asm-sh/cpu-sh3/dma.h @@ -1,7 +1,20 @@ #ifndef __ASM_CPU_SH3_DMA_H #define __ASM_CPU_SH3_DMA_H + +#if defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7709) +#define SH_DMAC_BASE 0xa4010020 + +#define DMTE0_IRQ 48 +#define DMTE1_IRQ 49 +#define DMTE2_IRQ 50 +#define DMTE3_IRQ 51 +#define DMTE4_IRQ 76 +#define DMTE5_IRQ 77 + +#else #define SH_DMAC_BASE 0xa4000020 +#endif /* Definitions for the SuperH DMAC */ #define TM_BURST 0x00000020 diff --git a/include/asm-sh/cpu-sh3/gpio.h b/include/asm-sh/cpu-sh3/gpio.h new file mode 100644 index 00000000000..48770c1c7bd --- /dev/null +++ b/include/asm-sh/cpu-sh3/gpio.h @@ -0,0 +1,66 @@ +/* + * include/asm-sh/cpu-sh3/gpio.h + * + * Copyright (C) 2007 Markus Brunner, Mark Jonas + * + * Addresses for the Pin Function Controller + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef _CPU_SH3_GPIO_H +#define _CPU_SH3_GPIO_H + +#if defined(CONFIG_CPU_SUBTYPE_SH7720) + +/* Control registers */ +#define PORT_PACR 0xA4050100UL +#define PORT_PBCR 0xA4050102UL +#define PORT_PCCR 0xA4050104UL +#define PORT_PDCR 0xA4050106UL +#define PORT_PECR 0xA4050108UL +#define PORT_PFCR 0xA405010AUL +#define PORT_PGCR 0xA405010CUL +#define PORT_PHCR 0xA405010EUL +#define PORT_PJCR 0xA4050110UL +#define PORT_PKCR 0xA4050112UL +#define PORT_PLCR 0xA4050114UL +#define PORT_PMCR 0xA4050116UL +#define PORT_PPCR 0xA4050118UL +#define PORT_PRCR 0xA405011AUL +#define PORT_PSCR 0xA405011CUL +#define PORT_PTCR 0xA405011EUL +#define PORT_PUCR 0xA4050120UL +#define PORT_PVCR 0xA4050122UL + +/* Data registers */ +#define PORT_PADR 0xA4050140UL +/* Address of PORT_PBDR is wrong in the datasheet, see errata 2005-09-21 */ +#define PORT_PBDR 0xA4050142UL +#define PORT_PCDR 0xA4050144UL +#define PORT_PDDR 0xA4050146UL +#define PORT_PEDR 0xA4050148UL +#define PORT_PFDR 0xA405014AUL +#define PORT_PGDR 0xA405014CUL +#define PORT_PHDR 0xA405014EUL +#define PORT_PJDR 0xA4050150UL +#define PORT_PKDR 0xA4050152UL +#define PORT_PLDR 0xA4050154UL +#define PORT_PMDR 0xA4050156UL +#define PORT_PPDR 0xA4050158UL +#define PORT_PRDR 0xA405015AUL +#define PORT_PSDR 0xA405015CUL +#define PORT_PTDR 0xA405015EUL +#define PORT_PUDR 0xA4050160UL +#define PORT_PVDR 0xA4050162UL + +/* Pin Select Registers */ +#define PORT_PSELA 0xA4050124UL +#define PORT_PSELB 0xA4050126UL +#define PORT_PSELC 0xA4050128UL +#define PORT_PSELD 0xA405012AUL + +#endif + +#endif diff --git a/include/asm-sh/cpu-sh3/mmu_context.h b/include/asm-sh/cpu-sh3/mmu_context.h index b20786d42d0..16c2d63b7e3 100644 --- a/include/asm-sh/cpu-sh3/mmu_context.h +++ b/include/asm-sh/cpu-sh3/mmu_context.h @@ -27,12 +27,13 @@ #define TRA 0xffffffd0 #define EXPEVT 0xffffffd4 -#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \ - defined(CONFIG_CPU_SUBTYPE_SH7709) || \ +#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ defined(CONFIG_CPU_SUBTYPE_SH7706) || \ - defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) || \ + defined(CONFIG_CPU_SUBTYPE_SH7710) || \ defined(CONFIG_CPU_SUBTYPE_SH7712) || \ - defined(CONFIG_CPU_SUBTYPE_SH7710) + defined(CONFIG_CPU_SUBTYPE_SH7720) #define INTEVT 0xa4000000 /* INTEVTE2(0xa4000000) */ #else #define INTEVT 0xffffffd8 diff --git a/include/asm-sh/cpu-sh3/timer.h b/include/asm-sh/cpu-sh3/timer.h index b6c2020a2ad..3880ce047fe 100644 --- a/include/asm-sh/cpu-sh3/timer.h +++ b/include/asm-sh/cpu-sh3/timer.h @@ -23,11 +23,13 @@ * --------------------------------------------------------------------------- */ -#if !defined(CONFIG_CPU_SUBTYPE_SH7727) +#if !defined(CONFIG_CPU_SUBTYPE_SH7720) && \ + !defined(CONFIG_CPU_SUBTYPE_SH7727) #define TMU_TOCR 0xfffffe90 /* Byte access */ #endif -#if defined(CONFIG_CPU_SUBTYPE_SH7710) +#if defined(CONFIG_CPU_SUBTYPE_SH7710) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) #define TMU_012_TSTR 0xa412fe92 /* Byte access */ #define TMU0_TCOR 0xa412fe94 /* Long access */ @@ -56,7 +58,8 @@ #define TMU2_TCOR 0xfffffeac /* Long access */ #define TMU2_TCNT 0xfffffeb0 /* Long access */ #define TMU2_TCR 0xfffffeb4 /* Word access */ -#if !defined(CONFIG_CPU_SUBTYPE_SH7727) +#if !defined(CONFIG_CPU_SUBTYPE_SH7720) && \ + !defined(CONFIG_CPU_SUBTYPE_SH7727) #define TMU2_TCPR2 0xfffffeb8 /* Long access */ #endif #endif diff --git a/include/asm-sh/cpu-sh3/ubc.h b/include/asm-sh/cpu-sh3/ubc.h index 9d308cbe9b2..18467c57453 100644 --- a/include/asm-sh/cpu-sh3/ubc.h +++ b/include/asm-sh/cpu-sh3/ubc.h @@ -11,7 +11,8 @@ #ifndef __ASM_CPU_SH3_UBC_H #define __ASM_CPU_SH3_UBC_H -#if defined(CONFIG_CPU_SUBTYPE_SH7710) +#if defined(CONFIG_CPU_SUBTYPE_SH7710) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) #define UBC_BARA 0xa4ffffb0 #define UBC_BAMRA 0xa4ffffb4 #define UBC_BBRA 0xa4ffffb8 diff --git a/include/asm-sh/cpu-sh4/dma.h b/include/asm-sh/cpu-sh4/dma.h index 36e26a96476..aaf71b018c2 100644 --- a/include/asm-sh/cpu-sh4/dma.h +++ b/include/asm-sh/cpu-sh4/dma.h @@ -31,7 +31,7 @@ #define TS_32 0x00000030 #define TS_64 0x00000000 -#define CHCR_TS_MASK 0x30 +#define CHCR_TS_MASK 0x70 #define CHCR_TS_SHIFT 4 #define DMAOR_COD 0x00000008 diff --git a/include/asm-sh/cpu-sh4/mmu_context.h b/include/asm-sh/cpu-sh4/mmu_context.h index ff4c5fbbfaf..979acddc0f8 100644 --- a/include/asm-sh/cpu-sh4/mmu_context.h +++ b/include/asm-sh/cpu-sh4/mmu_context.h @@ -22,13 +22,21 @@ #define MMU_UTLB_ADDRESS_ARRAY 0xF6000000 #define MMU_PAGE_ASSOC_BIT 0x80 -#define MMU_NTLB_ENTRIES 64 /* for 7750 */ +#ifdef CONFIG_X2TLB +#define MMUCR_ME (1 << 7) +#else +#define MMUCR_ME (0) +#endif + #ifdef CONFIG_SH_STORE_QUEUES -#define MMU_CONTROL_INIT 0x05 /* SQMD=0, SV=0, TI=1, AT=1 */ +#define MMUCR_SQMD (1 << 9) #else -#define MMU_CONTROL_INIT 0x205 /* SQMD=1, SV=0, TI=1, AT=1 */ +#define MMUCR_SQMD (0) #endif +#define MMU_NTLB_ENTRIES 64 +#define MMU_CONTROL_INIT (0x05|MMUCR_SQMD|MMUCR_ME) + #define MMU_ITLB_DATA_ARRAY 0xF3000000 #define MMU_UTLB_DATA_ARRAY 0xF7000000 diff --git a/include/asm-sh/dma.h b/include/asm-sh/dma.h index 4c75b70b641..a65b02fd186 100644 --- a/include/asm-sh/dma.h +++ b/include/asm-sh/dma.h @@ -152,14 +152,9 @@ extern struct dma_info *get_dma_info_by_name(const char *dmac_name); extern int dma_extend(unsigned int chan, unsigned long op, void *param); extern int register_chan_caps(const char *dmac, struct dma_chan_caps *capslist); -#ifdef CONFIG_SYSFS /* arch/sh/drivers/dma/dma-sysfs.c */ extern int dma_create_sysfs_files(struct dma_channel *, struct dma_info *); extern void dma_remove_sysfs_files(struct dma_channel *, struct dma_info *); -#else -#define dma_create_sysfs_file(channel, info) do { } while (0) -#define dma_remove_sysfs_file(channel, info) do { } while (0) -#endif #ifdef CONFIG_PCI extern int isa_dma_bridge_buggy; diff --git a/include/asm-sh/dreamcast/maple.h b/include/asm-sh/dreamcast/maple.h new file mode 100644 index 00000000000..51f6a87f1f1 --- /dev/null +++ b/include/asm-sh/dreamcast/maple.h @@ -0,0 +1,37 @@ +#ifndef __ASM_MAPLE_H +#define __ASM_MAPLE_H + +#define MAPLE_PORTS 4 +#define MAPLE_PNP_INTERVAL HZ +#define MAPLE_MAXPACKETS 8 +#define MAPLE_DMA_ORDER 14 +#define MAPLE_DMA_SIZE (1 << MAPLE_DMA_ORDER) +#define MAPLE_DMA_PAGES ((MAPLE_DMA_ORDER > PAGE_SHIFT) ? \ + MAPLE_DMA_ORDER - PAGE_SHIFT : 0) + +/* Maple Bus registers */ +#define MAPLE_BASE 0xa05f6c00 +#define MAPLE_DMAADDR (MAPLE_BASE+0x04) +#define MAPLE_TRIGTYPE (MAPLE_BASE+0x10) +#define MAPLE_ENABLE (MAPLE_BASE+0x14) +#define MAPLE_STATE (MAPLE_BASE+0x18) +#define MAPLE_SPEED (MAPLE_BASE+0x80) +#define MAPLE_RESET (MAPLE_BASE+0x8c) + +#define MAPLE_MAGIC 0x6155404f +#define MAPLE_2MBPS 0 +#define MAPLE_TIMEOUT(n) ((n)<<15) + +/* Function codes */ +#define MAPLE_FUNC_CONTROLLER 0x001 +#define MAPLE_FUNC_MEMCARD 0x002 +#define MAPLE_FUNC_LCD 0x004 +#define MAPLE_FUNC_CLOCK 0x008 +#define MAPLE_FUNC_MICROPHONE 0x010 +#define MAPLE_FUNC_ARGUN 0x020 +#define MAPLE_FUNC_KEYBOARD 0x040 +#define MAPLE_FUNC_LIGHTGUN 0x080 +#define MAPLE_FUNC_PURUPURU 0x100 +#define MAPLE_FUNC_MOUSE 0x200 + +#endif /* __ASM_MAPLE_H */ diff --git a/include/asm-sh/gpio.h b/include/asm-sh/gpio.h new file mode 100644 index 00000000000..9bb27e0f11a --- /dev/null +++ b/include/asm-sh/gpio.h @@ -0,0 +1,19 @@ +/* + * include/asm-sh/gpio.h + * + * Copyright (C) 2007 Markus Brunner, Mark Jonas + * + * Addresses for the Pin Function Controller + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef __ASM_SH_GPIO_H +#define __ASM_SH_GPIO_H + +#if defined(CONFIG_CPU_SH3) +#include <asm/cpu/gpio.h> +#endif + +#endif /* __ASM_SH_GPIO_H */ diff --git a/include/asm-sh/hd64461.h b/include/asm-sh/hd64461.h index 4dd8592ca01..342ca55a266 100644 --- a/include/asm-sh/hd64461.h +++ b/include/asm-sh/hd64461.h @@ -226,6 +226,7 @@ #define HD64461_NIMR (CONFIG_HD64461_IOBASE + 0x5002) #define HD64461_IRQBASE OFFCHIP_IRQ_BASE +#define OFFCHIP_IRQ_BASE 64 #define HD64461_IRQ_NUM 16 #define HD64461_IRQ_UART (HD64461_IRQBASE+5) diff --git a/include/asm-sh/heartbeat.h b/include/asm-sh/heartbeat.h new file mode 100644 index 00000000000..724a43ed245 --- /dev/null +++ b/include/asm-sh/heartbeat.h @@ -0,0 +1,17 @@ +#ifndef __ASM_SH_HEARTBEAT_H +#define __ASM_SH_HEARTBEAT_H + +#include <linux/timer.h> + +#define HEARTBEAT_INVERTED (1 << 0) + +struct heartbeat_data { + void __iomem *base; + unsigned char *bit_pos; + unsigned int nr_bits; + struct timer_list timer; + unsigned int regsize; + unsigned long flags; +}; + +#endif /* __ASM_SH_HEARTBEAT_H */ diff --git a/include/asm-sh/hw_irq.h b/include/asm-sh/hw_irq.h index 20d42959f52..cb0b6c9f702 100644 --- a/include/asm-sh/hw_irq.h +++ b/include/asm-sh/hw_irq.h @@ -6,24 +6,6 @@ extern atomic_t irq_err_count; -struct intc2_data { - unsigned short irq; - unsigned char ipr_offset, ipr_shift; - unsigned char msk_offset, msk_shift; - unsigned char priority; -}; - -struct intc2_desc { - unsigned long prio_base; - unsigned long msk_base; - unsigned long mskclr_base; - struct intc2_data *intc2_data; - unsigned int nr_irqs; - struct irq_chip chip; -}; - -void register_intc2_controller(struct intc2_desc *); - struct ipr_data { unsigned char irq; unsigned char ipr_idx; /* Index for the IPR registered */ @@ -41,11 +23,6 @@ struct ipr_desc { void register_ipr_controller(struct ipr_desc *); -/* - * Enable individual interrupt mode for external IPR IRQs. - */ -void __init ipr_irq_enable_irlm(void); - typedef unsigned char intc_enum; struct intc_vect { @@ -54,6 +31,7 @@ struct intc_vect { }; #define INTC_VECT(enum_id, vect) { enum_id, vect } +#define INTC_IRQ(enum_id, irq) INTC_VECT(enum_id, irq2evt(irq)) struct intc_prio { intc_enum enum_id; @@ -64,19 +42,25 @@ struct intc_prio { struct intc_group { intc_enum enum_id; - intc_enum *enum_ids; + intc_enum enum_ids[32]; }; -#define INTC_GROUP(enum_id, ids...) { enum_id, (intc_enum []) { ids, 0 } } +#define INTC_GROUP(enum_id, ids...) { enum_id, { ids } } struct intc_mask_reg { unsigned long set_reg, clr_reg, reg_width; intc_enum enum_ids[32]; +#ifdef CONFIG_SMP + unsigned long smp; +#endif }; struct intc_prio_reg { - unsigned long reg, reg_width, field_width; + unsigned long set_reg, clr_reg, reg_width, field_width; intc_enum enum_ids[16]; +#ifdef CONFIG_SMP + unsigned long smp; +#endif }; struct intc_sense_reg { @@ -84,6 +68,12 @@ struct intc_sense_reg { intc_enum enum_ids[16]; }; +#ifdef CONFIG_SMP +#define INTC_SMP(stride, nr) .smp = (stride) | ((nr) << 8) +#else +#define INTC_SMP(stride, nr) +#endif + struct intc_desc { struct intc_vect *vectors; unsigned int nr_vectors; @@ -97,25 +87,28 @@ struct intc_desc { unsigned int nr_prio_regs; struct intc_sense_reg *sense_regs; unsigned int nr_sense_regs; - struct irq_chip chip; + char *name; }; #define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a) #define DECLARE_INTC_DESC(symbol, chipname, vectors, groups, \ priorities, mask_regs, prio_regs, sense_regs) \ -struct intc_desc symbol = { \ +struct intc_desc symbol __initdata = { \ _INTC_ARRAY(vectors), _INTC_ARRAY(groups), \ _INTC_ARRAY(priorities), \ _INTC_ARRAY(mask_regs), _INTC_ARRAY(prio_regs), \ _INTC_ARRAY(sense_regs), \ - .chip.name = chipname, \ + chipname, \ } void __init register_intc_controller(struct intc_desc *desc); +int intc_set_priority(unsigned int irq, unsigned int prio); void __init plat_irq_setup(void); -enum { IRQ_MODE_IRQ, IRQ_MODE_IRL7654, IRQ_MODE_IRL3210 }; +enum { IRQ_MODE_IRQ, IRQ_MODE_IRQ7654, IRQ_MODE_IRQ3210, + IRQ_MODE_IRL7654_MASK, IRQ_MODE_IRL3210_MASK, + IRQ_MODE_IRL7654, IRQ_MODE_IRL3210 }; void __init plat_irq_setup_pins(int mode); #endif /* __ASM_SH_HW_IRQ_H */ diff --git a/include/asm-sh/ilsel.h b/include/asm-sh/ilsel.h new file mode 100644 index 00000000000..e3d304b280f --- /dev/null +++ b/include/asm-sh/ilsel.h @@ -0,0 +1,45 @@ +#ifndef __ASM_SH_ILSEL_H +#define __ASM_SH_ILSEL_H + +typedef enum { + ILSEL_NONE, + ILSEL_LAN, + ILSEL_USBH_I, + ILSEL_USBH_S, + ILSEL_USBH_V, + ILSEL_RTC, + ILSEL_USBP_I, + ILSEL_USBP_S, + ILSEL_USBP_V, + ILSEL_KEY, + + /* + * ILSEL Aliases - corner cases for interleaved level tables. + * + * Someone thought this was a good idea and less hassle than + * demuxing a shared vector, really. + */ + + /* ILSEL0 and 2 */ + ILSEL_FPGA0, + ILSEL_FPGA1, + ILSEL_EX1, + ILSEL_EX2, + ILSEL_EX3, + ILSEL_EX4, + + /* ILSEL1 and 3 */ + ILSEL_FPGA2 = ILSEL_FPGA0, + ILSEL_FPGA3 = ILSEL_FPGA1, + ILSEL_EX5 = ILSEL_EX1, + ILSEL_EX6 = ILSEL_EX2, + ILSEL_EX7 = ILSEL_EX3, + ILSEL_EX8 = ILSEL_EX4, +} ilsel_source_t; + +/* arch/sh/boards/renesas/x3proto/ilsel.c */ +int ilsel_enable(ilsel_source_t set); +int ilsel_enable_fixed(ilsel_source_t set, unsigned int level); +void ilsel_disable(unsigned int irq); + +#endif /* __ASM_SH_ILSEL_H */ diff --git a/include/asm-sh/io.h b/include/asm-sh/io.h index e6a1877dcb2..1a336cdc75f 100644 --- a/include/asm-sh/io.h +++ b/include/asm-sh/io.h @@ -135,6 +135,32 @@ void __raw_readsl(unsigned long addr, void *data, int longlen); # define writel(v,a) ({ __raw_writel((v),(a)); mb(); }) #endif +#define __BUILD_MEMORY_STRING(bwlq, type) \ + \ +static inline void writes##bwlq(volatile void __iomem *mem, \ + const void *addr, unsigned int count) \ +{ \ + const volatile type *__addr = addr; \ + \ + while (count--) { \ + __raw_write##bwlq(*__addr, mem); \ + __addr++; \ + } \ +} \ + \ +static inline void reads##bwlq(volatile void __iomem *mem, void *addr, \ + unsigned int count) \ +{ \ + volatile type *__addr = addr; \ + \ + while (count--) { \ + *__addr = __raw_read##bwlq(mem); \ + __addr++; \ + } \ +} + +__BUILD_MEMORY_STRING(b, u8) +__BUILD_MEMORY_STRING(w, u16) #define writesl __raw_writesl #define readsl __raw_readsl diff --git a/include/asm-sh/kgdb.h b/include/asm-sh/kgdb.h index 74bd0953e5c..4bc8cb187d1 100644 --- a/include/asm-sh/kgdb.h +++ b/include/asm-sh/kgdb.h @@ -17,9 +17,6 @@ #define __KGDB_H #include <asm/ptrace.h> -#include <asm/cacheflush.h> - -struct console; /* Same as pt_regs but has vbr in place of syscall_nr */ struct kgdb_regs { @@ -35,10 +32,7 @@ struct kgdb_regs { /* State info */ extern char kgdb_in_gdb_mode; -extern int kgdb_done_init; -extern int kgdb_enabled; extern int kgdb_nofault; /* Ignore bus errors (in gdb mem access) */ -extern int kgdb_halt; /* Execute initial breakpoint at startup */ extern char in_nmi; /* Debounce flag to prevent NMI reentry*/ /* SCI */ @@ -59,6 +53,7 @@ extern kgdb_debug_hook_t *kgdb_debug_hook; extern kgdb_bus_error_hook_t *kgdb_bus_err_hook; /* Console */ +struct console; void kgdb_console_write(struct console *co, const char *s, unsigned count); extern int kgdb_console_setup(struct console *, char *); @@ -69,22 +64,7 @@ extern void longjmp(jmp_buf __jmpb, int __retval); extern int setjmp(jmp_buf __jmpb); /* Forced breakpoint */ -#define breakpoint() \ -do { \ - if (kgdb_enabled) \ - __asm__ __volatile__("trapa #0x3c"); \ -} while (0) - -/* KGDB should be able to flush all kernel text space */ -#if defined(CONFIG_CPU_SH4) -#define kgdb_flush_icache_range(start, end) \ -{ \ - __flush_purge_region((void*)(start), (int)(end) - (int)(start));\ - flush_icache_range((start), (end)); \ -} -#else -#define kgdb_flush_icache_range(start, end) do { } while (0) -#endif +#define breakpoint() __asm__ __volatile__("trapa #0x3c") /* Taken from sh-stub.c of GDB 4.18 */ static const char hexchars[] = "0123456789abcdef"; diff --git a/include/asm-sh/magicpanelr2.h b/include/asm-sh/magicpanelr2.h new file mode 100644 index 00000000000..c644a77ee35 --- /dev/null +++ b/include/asm-sh/magicpanelr2.h @@ -0,0 +1,67 @@ +/* + * include/asm-sh/magicpanelr2.h + * + * Copyright (C) 2007 Markus Brunner, Mark Jonas + * + * I/O addresses and bitmasks for Magic Panel Release 2 board + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef __ASM_SH_MAGICPANELR2_H +#define __ASM_SH_MAGICPANELR2_H + +#include <asm/gpio.h> + +#define __IO_PREFIX mpr2 +#include <asm/io_generic.h> + + +#define SETBITS_OUTB(mask, reg) ctrl_outb(ctrl_inb(reg) | mask, reg) +#define SETBITS_OUTW(mask, reg) ctrl_outw(ctrl_inw(reg) | mask, reg) +#define SETBITS_OUTL(mask, reg) ctrl_outl(ctrl_inl(reg) | mask, reg) +#define CLRBITS_OUTB(mask, reg) ctrl_outb(ctrl_inb(reg) & ~mask, reg) +#define CLRBITS_OUTW(mask, reg) ctrl_outw(ctrl_inw(reg) & ~mask, reg) +#define CLRBITS_OUTL(mask, reg) ctrl_outl(ctrl_inl(reg) & ~mask, reg) + + +#define PA_LED PORT_PADR /* LED */ + + +/* BSC */ +#define CMNCR 0xA4FD0000UL +#define CS0BCR 0xA4FD0004UL +#define CS2BCR 0xA4FD0008UL +#define CS3BCR 0xA4FD000CUL +#define CS4BCR 0xA4FD0010UL +#define CS5ABCR 0xA4FD0014UL +#define CS5BBCR 0xA4FD0018UL +#define CS6ABCR 0xA4FD001CUL +#define CS6BBCR 0xA4FD0020UL +#define CS0WCR 0xA4FD0024UL +#define CS2WCR 0xA4FD0028UL +#define CS3WCR 0xA4FD002CUL +#define CS4WCR 0xA4FD0030UL +#define CS5AWCR 0xA4FD0034UL +#define CS5BWCR 0xA4FD0038UL +#define CS6AWCR 0xA4FD003CUL +#define CS6BWCR 0xA4FD0040UL + + +/* usb */ + +#define PORT_UTRCTL 0xA405012CUL +#define PORT_UCLKCR_W 0xA40A0008UL + +#define INTC_ICR0 0xA414FEE0UL +#define INTC_ICR1 0xA4140010UL +#define INTC_ICR2 0xA4140012UL + +/* MTD */ + +#define MPR2_MTD_BOOTLOADER_SIZE 0x00060000UL +#define MPR2_MTD_KERNEL_SIZE 0x00200000UL + +#endif /* __ASM_SH_MAGICPANELR2_H */ diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index 6bc9bba1010..cb3d46c59ea 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h @@ -70,14 +70,14 @@ extern void clear_page_nommu(void *to); extern void copy_page_nommu(void *to, void *from); #endif -#if defined(CONFIG_MMU) && (defined(CONFIG_CPU_SH4) || \ - defined(CONFIG_SH7705_CACHE_32KB)) +#if !defined(CONFIG_CACHE_OFF) && defined(CONFIG_MMU) && \ + (defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)) struct page; extern void clear_user_page(void *to, unsigned long address, struct page *pg); extern void copy_user_page(void *to, void *from, unsigned long address, struct page *pg); extern void __clear_user_page(void *to, void *orig_to); extern void __copy_user_page(void *to, void *from, void *orig_to); -#elif defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH3) || !defined(CONFIG_MMU) +#else #define clear_user_page(page, vaddr, pg) clear_page(page) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) #endif @@ -88,6 +88,7 @@ extern void __copy_user_page(void *to, void *from, void *orig_to); #ifdef CONFIG_X2TLB typedef struct { unsigned long pte_low, pte_high; } pte_t; typedef struct { unsigned long long pgprot; } pgprot_t; +typedef struct { unsigned long long pgd; } pgd_t; #define pte_val(x) \ ((x).pte_low | ((unsigned long long)(x).pte_high << 32)) #define __pte(x) \ @@ -95,12 +96,11 @@ typedef struct { unsigned long long pgprot; } pgprot_t; #else typedef struct { unsigned long pte_low; } pte_t; typedef struct { unsigned long pgprot; } pgprot_t; +typedef struct { unsigned long pgd; } pgd_t; #define pte_val(x) ((x).pte_low) #define __pte(x) ((pte_t) { (x) } ) #endif -typedef struct { unsigned long pgd; } pgd_t; - #define pgd_val(x) ((x).pgd) #define pgprot_val(x) ((x).pgprot) diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h index e3fae12c0e4..cf0dd2b648c 100644 --- a/include/asm-sh/pgtable.h +++ b/include/asm-sh/pgtable.h @@ -42,13 +42,12 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; /* PGD bits */ #define PGDIR_SHIFT (PTE_SHIFT + PTE_BITS) -#define PGDIR_BITS (32 - PGDIR_SHIFT) #define PGDIR_SIZE (1UL << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE-1)) /* Entries per level */ #define PTRS_PER_PTE (PAGE_SIZE / (1 << PTE_MAGNITUDE)) -#define PTRS_PER_PGD (PAGE_SIZE / 4) +#define PTRS_PER_PGD (PAGE_SIZE / sizeof(pgd_t)) #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) #define FIRST_USER_ADDRESS 0 @@ -100,17 +99,18 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define _PAGE_HW_SHARED 0x002 /* SH-bit : shared among processes */ #define _PAGE_DIRTY 0x004 /* D-bit : page changed */ #define _PAGE_CACHABLE 0x008 /* C-bit : cachable */ -#ifndef CONFIG_X2TLB -# define _PAGE_SZ0 0x010 /* SZ0-bit : Size of page */ -# define _PAGE_RW 0x020 /* PR0-bit : write access allowed */ -# define _PAGE_USER 0x040 /* PR1-bit : user space access allowed*/ -# define _PAGE_SZ1 0x080 /* SZ1-bit : Size of page (on SH-4) */ -#endif +#define _PAGE_SZ0 0x010 /* SZ0-bit : Size of page */ +#define _PAGE_RW 0x020 /* PR0-bit : write access allowed */ +#define _PAGE_USER 0x040 /* PR1-bit : user space access allowed*/ +#define _PAGE_SZ1 0x080 /* SZ1-bit : Size of page (on SH-4) */ #define _PAGE_PRESENT 0x100 /* V-bit : page is valid */ #define _PAGE_PROTNONE 0x200 /* software: if not present */ #define _PAGE_ACCESSED 0x400 /* software: page referenced */ #define _PAGE_FILE _PAGE_WT /* software: pagecache or swap? */ +#define _PAGE_SZ_MASK (_PAGE_SZ0 | _PAGE_SZ1) +#define _PAGE_PR_MASK (_PAGE_RW | _PAGE_USER) + /* Extended mode bits */ #define _PAGE_EXT_ESZ0 0x0010 /* ESZ0-bit: Size of page */ #define _PAGE_EXT_ESZ1 0x0020 /* ESZ1-bit: Size of page */ @@ -126,11 +126,7 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define _PAGE_EXT_KERN_READ 0x2000 /* EPR5-bit: Kernel space readable */ /* Wrapper for extended mode pgprot twiddling */ -#ifdef CONFIG_X2TLB -# define _PAGE_EXT(x) ((unsigned long long)(x) << 32) -#else -# define _PAGE_EXT(x) (0) -#endif +#define _PAGE_EXT(x) ((unsigned long long)(x) << 32) /* software: moves to PTEA.TC (Timing Control) */ #define _PAGE_PCC_AREA5 0x00000000 /* use BSC registers for area5 */ @@ -146,10 +142,14 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define _PAGE_PCC_ATR16 0x60000001 /* Attribute Memory space, 6 bit bus */ /* Mask which drops unused bits from the PTEL value */ -#ifdef CONFIG_CPU_SH3 +#if defined(CONFIG_CPU_SH3) #define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED| \ _PAGE_FILE | _PAGE_SZ1 | \ _PAGE_HW_SHARED) +#elif defined(CONFIG_X2TLB) +/* Get rid of the legacy PR/SZ bits when using extended mode */ +#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | \ + _PAGE_FILE | _PAGE_PR_MASK | _PAGE_SZ_MASK) #else #define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE) #endif @@ -212,27 +212,36 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ - _PAGE_EXT(_PAGE_EXT_USER_READ | \ + _PAGE_EXT(_PAGE_EXT_KERN_READ | \ + _PAGE_EXT_KERN_WRITE | \ + _PAGE_EXT_USER_READ | \ _PAGE_EXT_USER_WRITE)) #define PAGE_EXECREAD __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ - _PAGE_EXT(_PAGE_EXT_USER_EXEC | \ + _PAGE_EXT(_PAGE_EXT_KERN_EXEC | \ + _PAGE_EXT_KERN_READ | \ + _PAGE_EXT_USER_EXEC | \ _PAGE_EXT_USER_READ)) #define PAGE_COPY PAGE_EXECREAD #define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ - _PAGE_EXT(_PAGE_EXT_USER_READ)) + _PAGE_EXT(_PAGE_EXT_KERN_READ | \ + _PAGE_EXT_USER_READ)) #define PAGE_WRITEONLY __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ - _PAGE_EXT(_PAGE_EXT_USER_WRITE)) + _PAGE_EXT(_PAGE_EXT_KERN_WRITE | \ + _PAGE_EXT_USER_WRITE)) #define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ - _PAGE_EXT(_PAGE_EXT_USER_WRITE | \ + _PAGE_EXT(_PAGE_EXT_KERN_WRITE | \ + _PAGE_EXT_KERN_READ | \ + _PAGE_EXT_KERN_EXEC | \ + _PAGE_EXT_USER_WRITE | \ _PAGE_EXT_USER_READ | \ _PAGE_EXT_USER_EXEC)) @@ -373,11 +382,15 @@ static inline void set_pte(pte_t *ptep, pte_t pte) #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) #define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT))) -#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) -#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) -#define pte_none(x) (!pte_val(x)) -#define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE)) +#define pfn_pte(pfn, prot) \ + __pte(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot)) +#define pfn_pmd(pfn, prot) \ + __pmd(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot)) + +#define pte_none(x) (!pte_val(x)) +#define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE)) + #define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0) #define pmd_none(x) (!pmd_val(x)) @@ -392,15 +405,15 @@ static inline void set_pte(pte_t *ptep, pte_t pte) * The following only work if pte_present() is true. * Undefined behaviour if not.. */ -#define pte_not_present(pte) (!(pte_val(pte) & _PAGE_PRESENT)) -#define pte_dirty(pte) (pte_val(pte) & _PAGE_DIRTY) -#define pte_young(pte) (pte_val(pte) & _PAGE_ACCESSED) -#define pte_file(pte) (pte_val(pte) & _PAGE_FILE) +#define pte_not_present(pte) (!((pte).pte_low & _PAGE_PRESENT)) +#define pte_dirty(pte) ((pte).pte_low & _PAGE_DIRTY) +#define pte_young(pte) ((pte).pte_low & _PAGE_ACCESSED) +#define pte_file(pte) ((pte).pte_low & _PAGE_FILE) #ifdef CONFIG_X2TLB #define pte_write(pte) ((pte).pte_high & _PAGE_EXT_USER_WRITE) #else -#define pte_write(pte) (pte_val(pte) & _PAGE_RW) +#define pte_write(pte) ((pte).pte_low & _PAGE_RW) #endif #define PTE_BIT_FUNC(h,fn,op) \ @@ -429,17 +442,10 @@ PTE_BIT_FUNC(low, mkyoung, |= _PAGE_ACCESSED); /* * Macro and implementation to make a page protection as uncachable. */ -#define pgprot_noncached pgprot_noncached +#define pgprot_writecombine(prot) \ + __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE) -static inline pgprot_t pgprot_noncached(pgprot_t _prot) -{ - unsigned long prot = pgprot_val(_prot); - - prot &= ~_PAGE_CACHABLE; - return __pgprot(prot); -} - -#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE) +#define pgprot_noncached pgprot_writecombine /* * Conversion functions: convert a page and protection to a page entry, @@ -451,28 +457,33 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { - set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) | - pgprot_val(newprot))); + pte.pte_low &= _PAGE_CHG_MASK; + pte.pte_low |= pgprot_val(newprot); + +#ifdef CONFIG_X2TLB + pte.pte_high |= pgprot_val(newprot) >> 32; +#endif + return pte; } -#define pmd_page_vaddr(pmd) pmd_val(pmd) +#define pmd_page_vaddr(pmd) ((unsigned long)pmd_val(pmd)) #define pmd_page(pmd) (virt_to_page(pmd_val(pmd))) /* to find an entry in a page-table-directory. */ -#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) -#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) +#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) +#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) /* to find an entry in a kernel page-table-directory */ -#define pgd_offset_k(address) pgd_offset(&init_mm, address) +#define pgd_offset_k(address) pgd_offset(&init_mm, address) /* Find an entry in the third-level page table.. */ -#define pte_index(address) \ - ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define pte_index(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) #define pte_offset_kernel(dir, address) \ ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address)) -#define pte_offset_map(dir, address) pte_offset_kernel(dir, address) -#define pte_offset_map_nested(dir, address) pte_offset_kernel(dir, address) +#define pte_offset_map(dir, address) pte_offset_kernel(dir, address) +#define pte_offset_map_nested(dir, address) pte_offset_kernel(dir, address) + #define pte_unmap(pte) do { } while (0) #define pte_unmap_nested(pte) do { } while (0) @@ -480,13 +491,14 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) #define pte_ERROR(e) \ printk("%s:%d: bad pte %p(%08lx%08lx).\n", __FILE__, __LINE__, \ &(e), (e).pte_high, (e).pte_low) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %016llx.\n", __FILE__, __LINE__, pgd_val(e)) #else #define pte_ERROR(e) \ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e)) -#endif - #define pgd_ERROR(e) \ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) +#endif struct vm_area_struct; extern void update_mmu_cache(struct vm_area_struct * vma, @@ -563,7 +575,8 @@ struct mm_struct; extern unsigned int kobjsize(const void *objp); #endif /* !CONFIG_MMU */ -#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) +#if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \ + defined(CONFIG_SH7705_CACHE_32KB)) #define __HAVE_ARCH_PTEP_GET_AND_CLEAR extern pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep); #endif diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h index 26d52174f4b..4f2922a1979 100644 --- a/include/asm-sh/processor.h +++ b/include/asm-sh/processor.h @@ -45,7 +45,7 @@ enum cpu_type { CPU_SH7705, CPU_SH7706, CPU_SH7707, CPU_SH7708, CPU_SH7708S, CPU_SH7708R, CPU_SH7709, CPU_SH7709A, CPU_SH7710, CPU_SH7712, - CPU_SH7729, + CPU_SH7720, CPU_SH7729, /* SH-4 types */ CPU_SH7750, CPU_SH7750S, CPU_SH7750R, CPU_SH7751, CPU_SH7751R, @@ -73,15 +73,10 @@ struct sh_cpuinfo { unsigned long flags; } __attribute__ ((aligned(SMP_CACHE_BYTES))); -extern struct sh_cpuinfo boot_cpu_data; - -#ifdef CONFIG_SMP extern struct sh_cpuinfo cpu_data[]; +#define boot_cpu_data cpu_data[0] #define current_cpu_data cpu_data[smp_processor_id()] -#else -#define cpu_data (&boot_cpu_data) -#define current_cpu_data boot_cpu_data -#endif +#define raw_current_cpu_data cpu_data[raw_smp_processor_id()] /* * User space process size: 2GB. diff --git a/include/asm-sh/r7780rp.h b/include/asm-sh/r7780rp.h index 4083b594992..de37f933aa4 100644 --- a/include/asm-sh/r7780rp.h +++ b/include/asm-sh/r7780rp.h @@ -65,24 +65,6 @@ #define PA_PMR (PA_BCR+0x0900) /* */ #define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */ - -#define IRQ_PCISLOT1 65 /* PCI Slot #1 IRQ */ -#define IRQ_PCISLOT2 66 /* PCI Slot #2 IRQ */ -#define IRQ_PCISLOT3 67 /* PCI Slot #3 IRQ */ -#define IRQ_PCISLOT4 68 /* PCI Slot #4 IRQ */ -#define IRQ_TP 2 /* Touch Panel IRQ */ -#define IRQ_SCI1 3 /* SCI1 IRQ */ -#define IRQ_SCI0 4 /* SCI0 IRQ */ -#define IRQ_2SERIAL 5 /* Serial IRQ */ -#define IRQ_RTC 6 /* RTC A / B IRQ */ -#define IRQ_EXTENTION6 7 /* EXT6n IRQ */ -#define IRQ_EXTENTION5 8 /* EXT5n IRQ */ -#define IRQ_EXTENTION4 9 /* EXT4n IRQ */ -#define IRQ_EXTENTION2 10 /* EXT2n IRQ */ -#define IRQ_EXTENTION1 11 /* EXT1n IRQ */ -#define IRQ_ONETH 13 /* On board Ethernet IRQ */ -#define IRQ_PSW 14 /* Push Switch IRQ */ - #define IVDR_CK_ON 8 /* iVDR Clock ON */ #elif defined(CONFIG_SH_R7780RP) @@ -203,11 +185,24 @@ #define PA_MMSR (PA_BCR+0x0400) #define IVDR_CK_ON 4 /* iVDR Clock ON */ +#endif +#define HL_FPGA_IRQ_BASE 200 +#define HL_NR_IRL 15 + +#define IRQ_AX88796 (HL_FPGA_IRQ_BASE + 0) +#define IRQ_CF (HL_FPGA_IRQ_BASE + 1) +#ifndef IRQ_PSW +#define IRQ_PSW (HL_FPGA_IRQ_BASE + 2) #endif +#define IRQ_EXT1 (HL_FPGA_IRQ_BASE + 3) +#define IRQ_EXT4 (HL_FPGA_IRQ_BASE + 4) void make_r7780rp_irq(unsigned int irq); -void highlander_init_irq(void); + +unsigned char *highlander_init_irq_r7780mp(void); +unsigned char *highlander_init_irq_r7780rp(void); +unsigned char *highlander_init_irq_r7785rp(void); #define __IO_PREFIX r7780rp #include <asm/io_generic.h> diff --git a/include/asm-sh/rtc.h b/include/asm-sh/rtc.h index 91aacc96151..858da99d37e 100644 --- a/include/asm-sh/rtc.h +++ b/include/asm-sh/rtc.h @@ -5,4 +5,10 @@ extern void (*board_time_init)(void); extern void (*rtc_sh_get_time)(struct timespec *); extern int (*rtc_sh_set_time)(const time_t); +#define RTC_CAP_4_DIGIT_YEAR (1 << 0) + +struct sh_rtc_platform_info { + unsigned long capabilities; +}; + #endif /* _ASM_RTC_H */ diff --git a/include/asm-sh/rts7751r2d.h b/include/asm-sh/rts7751r2d.h index 5d7800aa31b..83b9c111f17 100644 --- a/include/asm-sh/rts7751r2d.h +++ b/include/asm-sh/rts7751r2d.h @@ -9,7 +9,7 @@ * Renesas Technology Sales RTS7751R2D support */ -/* Box specific addresses. */ +/* Board specific addresses. */ #define PA_BCR 0xa4000000 /* FPGA */ #define PA_IRLMON 0xa4000002 /* Interrupt Status control */ @@ -20,19 +20,19 @@ #define PA_RTCCE 0xa400000c /* RTC(9701) Enable control */ #define PA_PCICD 0xa400000e /* PCI Extention detect control */ #define PA_VOYAGERRTS 0xa4000020 /* VOYAGER Reset control */ -#if defined(CONFIG_RTS7751R2D_REV11) -#define PA_AXRST 0xa4000022 /* AX_LAN Reset control */ -#define PA_CFRST 0xa4000024 /* CF Reset control */ -#define PA_ADMRTS 0xa4000026 /* SD Reset control */ -#define PA_EXTRST 0xa4000028 /* Extention Reset control */ -#define PA_CFCDINTCLR 0xa400002a /* CF Insert Interrupt clear */ -#else -#define PA_CFRST 0xa4000022 /* CF Reset control */ -#define PA_ADMRTS 0xa4000024 /* SD Reset control */ -#define PA_EXTRST 0xa4000026 /* Extention Reset control */ -#define PA_CFCDINTCLR 0xa4000028 /* CF Insert Interrupt clear */ -#define PA_KEYCTLCLR 0xa400002a /* Key Interrupt clear */ -#endif + +#define PA_R2D1_AXRST 0xa4000022 /* AX_LAN Reset control */ +#define PA_R2D1_CFRST 0xa4000024 /* CF Reset control */ +#define PA_R2D1_ADMRTS 0xa4000026 /* SD Reset control */ +#define PA_R2D1_EXTRST 0xa4000028 /* Extention Reset control */ +#define PA_R2D1_CFCDINTCLR 0xa400002a /* CF Insert Interrupt clear */ + +#define PA_R2DPLUS_CFRST 0xa4000022 /* CF Reset control */ +#define PA_R2DPLUS_ADMRTS 0xa4000024 /* SD Reset control */ +#define PA_R2DPLUS_EXTRST 0xa4000026 /* Extention Reset control */ +#define PA_R2DPLUS_CFCDINTCLR 0xa4000028 /* CF Insert Interrupt clear */ +#define PA_R2DPLUS_KEYCTLCLR 0xa400002a /* Key Interrupt clear */ + #define PA_POWOFF 0xa4000030 /* Board Power OFF control */ #define PA_VERREG 0xa4000032 /* FPGA Version Register */ #define PA_INPORT 0xa4000034 /* KEY Input Port control */ @@ -46,27 +46,22 @@ #define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */ -#if defined(CONFIG_RTS7751R2D_REV11) -#define IRQ_PCIETH 0 /* PCI Ethernet IRQ */ -#define IRQ_CFCARD 1 /* CF Card IRQ */ -#define IRQ_CFINST 2 /* CF Card Insert IRQ */ -#define IRQ_PCMCIA 3 /* PCMCIA IRQ */ -#define IRQ_VOYAGER 4 /* VOYAGER IRQ */ -#define IRQ_ONETH 5 /* On board Ethernet IRQ */ -#else -#define IRQ_KEYIN 0 /* Key Input IRQ */ -#define IRQ_PCIETH 1 /* PCI Ethernet IRQ */ -#define IRQ_CFCARD 2 /* CF Card IRQ */ -#define IRQ_CFINST 3 /* CF Card Insert IRQ */ -#define IRQ_PCMCIA 4 /* PCMCIA IRQ */ -#define IRQ_VOYAGER 5 /* VOYAGER IRQ */ -#endif -#define IRQ_RTCALM 6 /* RTC Alarm IRQ */ -#define IRQ_RTCTIME 7 /* RTC Timer IRQ */ -#define IRQ_SDCARD 8 /* SD Card IRQ */ -#define IRQ_PCISLOT1 9 /* PCI Slot #1 IRQ */ -#define IRQ_PCISLOT2 10 /* PCI Slot #2 IRQ */ -#define IRQ_EXTENTION 11 /* EXTn IRQ */ +#define R2D_FPGA_IRQ_BASE 100 + +#define IRQ_VOYAGER (R2D_FPGA_IRQ_BASE + 0) +#define IRQ_EXT (R2D_FPGA_IRQ_BASE + 1) +#define IRQ_TP (R2D_FPGA_IRQ_BASE + 2) +#define IRQ_RTC_T (R2D_FPGA_IRQ_BASE + 3) +#define IRQ_RTC_A (R2D_FPGA_IRQ_BASE + 4) +#define IRQ_SDCARD (R2D_FPGA_IRQ_BASE + 5) +#define IRQ_CF_CD (R2D_FPGA_IRQ_BASE + 6) +#define IRQ_CF_IDE (R2D_FPGA_IRQ_BASE + 7) +#define IRQ_AX88796 (R2D_FPGA_IRQ_BASE + 8) +#define IRQ_KEY (R2D_FPGA_IRQ_BASE + 9) +#define IRQ_PCI_INTA (R2D_FPGA_IRQ_BASE + 10) +#define IRQ_PCI_INTB (R2D_FPGA_IRQ_BASE + 11) +#define IRQ_PCI_INTC (R2D_FPGA_IRQ_BASE + 12) +#define IRQ_PCI_INTD (R2D_FPGA_IRQ_BASE + 13) /* arch/sh/boards/renesas/rts7751r2d/irq.c */ void init_rts7751r2d_IRQ(void); diff --git a/include/asm-sh/sections.h b/include/asm-sh/sections.h index 2a696b8ee4f..bd9cbc967c2 100644 --- a/include/asm-sh/sections.h +++ b/include/asm-sh/sections.h @@ -4,6 +4,7 @@ #include <asm-generic/sections.h> extern long __machvec_start, __machvec_end; +extern char _ebss[]; #endif /* __ASM_SH_SECTIONS_H */ diff --git a/include/asm-sh/sh03/io.h b/include/asm-sh/sh03/io.h index 4ff1eb90030..c39c785bba9 100644 --- a/include/asm-sh/sh03/io.h +++ b/include/asm-sh/sh03/io.h @@ -11,22 +11,13 @@ #include <linux/time.h> -#define INTC_IPRD 0xffd00010UL - #define IRL0_IRQ 2 -#define IRL0_IPR_POS 3 #define IRL0_PRIORITY 13 - #define IRL1_IRQ 5 -#define IRL1_IPR_POS 2 #define IRL1_PRIORITY 10 - #define IRL2_IRQ 8 -#define IRL2_IPR_POS 1 #define IRL2_PRIORITY 7 - #define IRL3_IRQ 11 -#define IRL3_IPR_POS 0 #define IRL3_PRIORITY 4 void heartbeat_sh03(void); diff --git a/include/asm-sh/smp.h b/include/asm-sh/smp.h index b99ca786c0c..9c8d34b07eb 100644 --- a/include/asm-sh/smp.h +++ b/include/asm-sh/smp.h @@ -1,12 +1,3 @@ -/* - * include/asm-sh/smp.h - * - * Copyright (C) 2002, 2003 Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive for - * more details. - */ #ifndef __ASM_SH_SMP_H #define __ASM_SH_SMP_H @@ -20,6 +11,15 @@ #include <asm/current.h> #define raw_smp_processor_id() (current_thread_info()->cpu) +#define hard_smp_processor_id() plat_smp_processor_id() + +/* Map from cpu id to sequential logical cpu number. */ +extern int __cpu_number_map[NR_CPUS]; +#define cpu_number_map(cpu) __cpu_number_map[cpu] + +/* The reverse map from sequential logical cpu number to cpu id. */ +extern int __cpu_logical_map[NR_CPUS]; +#define cpu_logical_map(cpu) __cpu_logical_map[cpu] /* I've no idea what the real meaning of this is */ #define PROC_CHANGE_PENALTY 20 @@ -35,10 +35,22 @@ struct smp_fn_call_struct { extern struct smp_fn_call_struct smp_fn_call; -#define SMP_MSG_RESCHEDULE 0x0001 +#define SMP_MSG_FUNCTION 0 +#define SMP_MSG_RESCHEDULE 1 +#define SMP_MSG_NR 2 -#endif /* CONFIG_SMP */ +void plat_smp_setup(void); +void plat_prepare_cpus(unsigned int max_cpus); +int plat_smp_processor_id(void); +void plat_start_cpu(unsigned int cpu, unsigned long entry_point); +void plat_send_ipi(unsigned int cpu, unsigned int message); +int plat_register_ipi_handler(unsigned int message, + void (*handler)(void *), void *arg); + +#else #define hard_smp_processor_id() (0) +#endif /* CONFIG_SMP */ + #endif /* __ASM_SH_SMP_H */ diff --git a/include/asm-sh/snapgear.h b/include/asm-sh/snapgear.h index 3554e3a74e9..042d95f51c4 100644 --- a/include/asm-sh/snapgear.h +++ b/include/asm-sh/snapgear.h @@ -19,20 +19,16 @@ * is the interrupt :-) */ -#define IRL0_IRQ 2 -#define IRL0_IPR_POS 3 +#define IRL0_IRQ 2 #define IRL0_PRIORITY 13 -#define IRL1_IRQ 5 -#define IRL1_IPR_POS 2 +#define IRL1_IRQ 5 #define IRL1_PRIORITY 10 -#define IRL2_IRQ 8 -#define IRL2_IPR_POS 1 +#define IRL2_IRQ 8 #define IRL2_PRIORITY 7 -#define IRL3_IRQ 11 -#define IRL3_IPR_POS 0 +#define IRL3_IRQ 11 #define IRL3_PRIORITY 4 #endif diff --git a/include/asm-sh/spinlock.h b/include/asm-sh/spinlock.h index 92f6e2008b2..e793181d64d 100644 --- a/include/asm-sh/spinlock.h +++ b/include/asm-sh/spinlock.h @@ -2,6 +2,7 @@ * include/asm-sh/spinlock.h * * Copyright (C) 2002, 2003 Paul Mundt + * Copyright (C) 2006, 2007 Akio Idehara * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -10,17 +11,22 @@ #ifndef __ASM_SH_SPINLOCK_H #define __ASM_SH_SPINLOCK_H -#include <asm/atomic.h> -#include <asm/spinlock_types.h> +/* + * The only locking implemented here uses SH-4A opcodes. For others, + * split this out as per atomic-*.h. + */ +#ifndef CONFIG_CPU_SH4A +#error "Need movli.l/movco.l for spinlocks" +#endif /* * Your basic SMP spinlocks, allowing only a single CPU anywhere */ -#define __raw_spin_is_locked(x) ((x)->lock != 0) +#define __raw_spin_is_locked(x) ((x)->lock <= 0) #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) #define __raw_spin_unlock_wait(x) \ - do { cpu_relax(); } while (__raw_spin_is_locked(x)) + do { cpu_relax(); } while ((x)->lock) /* * Simple spin lock operations. There are two variants, one clears IRQ's @@ -30,12 +36,19 @@ */ static inline void __raw_spin_lock(raw_spinlock_t *lock) { + unsigned long tmp; + unsigned long oldval; + __asm__ __volatile__ ( - "1:\n\t" - "tas.b @%0\n\t" - "bf/s 1b\n\t" - "nop\n\t" - : "=r" (lock->lock) + "1: \n\t" + "movli.l @%2, %0 ! __raw_spin_lock \n\t" + "mov %0, %1 \n\t" + "mov #0, %0 \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "cmp/pl %1 \n\t" + "bf 1b \n\t" + : "=&z" (tmp), "=&r" (oldval) : "r" (&lock->lock) : "t", "memory" ); @@ -43,12 +56,36 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock) static inline void __raw_spin_unlock(raw_spinlock_t *lock) { - //assert_spin_locked(lock); + unsigned long tmp; - lock->lock = 0; + __asm__ __volatile__ ( + "mov #1, %0 ! __raw_spin_unlock \n\t" + "mov.l %0, @%1 \n\t" + : "=&z" (tmp) + : "r" (&lock->lock) + : "t", "memory" + ); } -#define __raw_spin_trylock(x) (!test_and_set_bit(0, &(x)->lock)) +static inline int __raw_spin_trylock(raw_spinlock_t *lock) +{ + unsigned long tmp, oldval; + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%2, %0 ! __raw_spin_trylock \n\t" + "mov %0, %1 \n\t" + "mov #0, %0 \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "synco \n\t" + : "=&z" (tmp), "=&r" (oldval) + : "r" (&lock->lock) + : "t", "memory" + ); + + return oldval; +} /* * Read-write spinlocks, allowing multiple readers but only one writer. @@ -59,58 +96,124 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock) * read-locks. */ +/** + * read_can_lock - would read_trylock() succeed? + * @lock: the rwlock in question. + */ +#define __raw_read_can_lock(x) ((x)->lock > 0) + +/** + * write_can_lock - would write_trylock() succeed? + * @lock: the rwlock in question. + */ +#define __raw_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) + static inline void __raw_read_lock(raw_rwlock_t *rw) { - __raw_spin_lock(&rw->lock); - - atomic_inc(&rw->counter); + unsigned long tmp; - __raw_spin_unlock(&rw->lock); + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%1, %0 ! __raw_read_lock \n\t" + "cmp/pl %0 \n\t" + "bf 1b \n\t" + "add #-1, %0 \n\t" + "movco.l %0, @%1 \n\t" + "bf 1b \n\t" + : "=&z" (tmp) + : "r" (&rw->lock) + : "t", "memory" + ); } static inline void __raw_read_unlock(raw_rwlock_t *rw) { - __raw_spin_lock(&rw->lock); - - atomic_dec(&rw->counter); + unsigned long tmp; - __raw_spin_unlock(&rw->lock); + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%1, %0 ! __raw_read_unlock \n\t" + "add #1, %0 \n\t" + "movco.l %0, @%1 \n\t" + "bf 1b \n\t" + : "=&z" (tmp) + : "r" (&rw->lock) + : "t", "memory" + ); } static inline void __raw_write_lock(raw_rwlock_t *rw) { - __raw_spin_lock(&rw->lock); - atomic_set(&rw->counter, -1); + unsigned long tmp; + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%1, %0 ! __raw_write_lock \n\t" + "cmp/hs %2, %0 \n\t" + "bf 1b \n\t" + "sub %2, %0 \n\t" + "movco.l %0, @%1 \n\t" + "bf 1b \n\t" + : "=&z" (tmp) + : "r" (&rw->lock), "r" (RW_LOCK_BIAS) + : "t", "memory" + ); } static inline void __raw_write_unlock(raw_rwlock_t *rw) { - atomic_set(&rw->counter, 0); - __raw_spin_unlock(&rw->lock); + __asm__ __volatile__ ( + "mov.l %1, @%0 ! __raw_write_unlock \n\t" + : + : "r" (&rw->lock), "r" (RW_LOCK_BIAS) + : "t", "memory" + ); } -static inline int __raw_write_can_lock(raw_rwlock_t *rw) +static inline int __raw_read_trylock(raw_rwlock_t *rw) { - return (atomic_read(&rw->counter) == RW_LOCK_BIAS); -} + unsigned long tmp, oldval; -static inline int __raw_read_trylock(raw_rwlock_t *lock) -{ - atomic_t *count = (atomic_t*)lock; - if (atomic_dec_return(count) >= 0) - return 1; - atomic_inc(count); - return 0; + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%2, %0 ! __raw_read_trylock \n\t" + "mov %0, %1 \n\t" + "cmp/pl %0 \n\t" + "bf 2f \n\t" + "add #-1, %0 \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "2: \n\t" + "synco \n\t" + : "=&z" (tmp), "=&r" (oldval) + : "r" (&rw->lock) + : "t", "memory" + ); + + return (oldval > 0); } static inline int __raw_write_trylock(raw_rwlock_t *rw) { - if (atomic_sub_and_test(RW_LOCK_BIAS, &rw->counter)) - return 1; - - atomic_add(RW_LOCK_BIAS, &rw->counter); + unsigned long tmp, oldval; + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%2, %0 ! __raw_write_trylock \n\t" + "mov %0, %1 \n\t" + "cmp/hs %3, %0 \n\t" + "bf 2f \n\t" + "sub %3, %0 \n\t" + "2: \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "synco \n\t" + : "=&z" (tmp), "=&r" (oldval) + : "r" (&rw->lock), "r" (RW_LOCK_BIAS) + : "t", "memory" + ); - return 0; + return (oldval > (RW_LOCK_BIAS - 1)); } #define _raw_spin_relax(lock) cpu_relax() diff --git a/include/asm-sh/spinlock_types.h b/include/asm-sh/spinlock_types.h index 5c58134f2c4..b4d244e7b60 100644 --- a/include/asm-sh/spinlock_types.h +++ b/include/asm-sh/spinlock_types.h @@ -6,19 +6,16 @@ #endif typedef struct { - volatile unsigned long lock; + volatile unsigned int lock; } raw_spinlock_t; -#define __RAW_SPIN_LOCK_UNLOCKED { 1 } - -#include <asm/atomic.h> +#define __RAW_SPIN_LOCK_UNLOCKED { 1 } typedef struct { - raw_spinlock_t lock; - atomic_t counter; + volatile unsigned int lock; } raw_rwlock_t; #define RW_LOCK_BIAS 0x01000000 -#define __RAW_RW_LOCK_UNLOCKED { { 0 }, { RW_LOCK_BIAS } } +#define __RAW_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } #endif diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h index 24504253720..9d849e6df26 100644 --- a/include/asm-sh/system.h +++ b/include/asm-sh/system.h @@ -266,6 +266,7 @@ void disable_hlt(void); void enable_hlt(void); void default_idle(void); +void per_cpu_trap_init(void); asmlinkage void break_point_trap(void); asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5, diff --git a/include/asm-sh/voyagergx.h b/include/asm-sh/voyagergx.h index 64c936b2271..d825596562d 100644 --- a/include/asm-sh/voyagergx.h +++ b/include/asm-sh/voyagergx.h @@ -27,13 +27,35 @@ #define VOYAGER_UART_BASE (0x30000 + VOYAGER_BASE) #define VOYAGER_AC97_BASE (0xa0000 + VOYAGER_BASE) -#define VOYAGER_IRQ_NUM 32 -#define VOYAGER_IRQ_BASE 50 -#define VOYAGER_USBH_IRQ VOYAGER_IRQ_BASE + 6 -#define VOYAGER_8051_IRQ VOYAGER_IRQ_BASE + 10 -#define VOYAGER_UART0_IRQ VOYAGER_IRQ_BASE + 12 -#define VOYAGER_UART1_IRQ VOYAGER_IRQ_BASE + 13 -#define VOYAGER_AC97_IRQ VOYAGER_IRQ_BASE + 17 +#define VOYAGER_IRQ_NUM 26 +#define VOYAGER_IRQ_BASE 200 + +#define IRQ_SM501_UP (VOYAGER_IRQ_BASE + 0) +#define IRQ_SM501_G54 (VOYAGER_IRQ_BASE + 1) +#define IRQ_SM501_G53 (VOYAGER_IRQ_BASE + 2) +#define IRQ_SM501_G52 (VOYAGER_IRQ_BASE + 3) +#define IRQ_SM501_G51 (VOYAGER_IRQ_BASE + 4) +#define IRQ_SM501_G50 (VOYAGER_IRQ_BASE + 5) +#define IRQ_SM501_G49 (VOYAGER_IRQ_BASE + 6) +#define IRQ_SM501_G48 (VOYAGER_IRQ_BASE + 7) +#define IRQ_SM501_I2C (VOYAGER_IRQ_BASE + 8) +#define IRQ_SM501_PW (VOYAGER_IRQ_BASE + 9) +#define IRQ_SM501_DMA (VOYAGER_IRQ_BASE + 10) +#define IRQ_SM501_PCI (VOYAGER_IRQ_BASE + 11) +#define IRQ_SM501_I2S (VOYAGER_IRQ_BASE + 12) +#define IRQ_SM501_AC (VOYAGER_IRQ_BASE + 13) +#define IRQ_SM501_US (VOYAGER_IRQ_BASE + 14) +#define IRQ_SM501_U1 (VOYAGER_IRQ_BASE + 15) +#define IRQ_SM501_U0 (VOYAGER_IRQ_BASE + 16) +#define IRQ_SM501_CV (VOYAGER_IRQ_BASE + 17) +#define IRQ_SM501_MC (VOYAGER_IRQ_BASE + 18) +#define IRQ_SM501_S1 (VOYAGER_IRQ_BASE + 19) +#define IRQ_SM501_S0 (VOYAGER_IRQ_BASE + 20) +#define IRQ_SM501_UH (VOYAGER_IRQ_BASE + 21) +#define IRQ_SM501_2D (VOYAGER_IRQ_BASE + 22) +#define IRQ_SM501_ZD (VOYAGER_IRQ_BASE + 23) +#define IRQ_SM501_PV (VOYAGER_IRQ_BASE + 24) +#define IRQ_SM501_CI (VOYAGER_IRQ_BASE + 25) /* ----- MISC controle register ------------------------------ */ #define MISC_CTRL (0x000004 + VOYAGER_BASE) @@ -313,4 +335,7 @@ void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t); int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t); +/* arch/sh/cchips/voyagergx/irq.c */ +void setup_voyagergx_irq(void); + #endif /* _VOYAGER_GX_REG_H */ diff --git a/include/asm-sh64/gpio.h b/include/asm-sh64/gpio.h new file mode 100644 index 00000000000..6bc5a13d841 --- /dev/null +++ b/include/asm-sh64/gpio.h @@ -0,0 +1,8 @@ +#ifndef __ASM_SH64_GPIO_H +#define __ASM_SH64_GPIO_H + +/* + * This is just a stub, so that every arch using sh-sci has a gpio.h + */ + +#endif /* __ASM_SH64_GPIO_H */ diff --git a/include/asm-sh64/io.h b/include/asm-sh64/io.h index 1f37b693192..3de3ad99f45 100644 --- a/include/asm-sh64/io.h +++ b/include/asm-sh64/io.h @@ -119,6 +119,13 @@ void insw(unsigned long port, void *addr, unsigned long count); void outsl(unsigned long port, const void *addr, unsigned long count); void insl(unsigned long port, void *addr, unsigned long count); +#define inb_p(addr) inb(addr) +#define inw_p(addr) inw(addr) +#define inl_p(addr) inl(addr) +#define outb_p(x,addr) outb(x,addr) +#define outw_p(x,addr) outw(x,addr) +#define outl_p(x,addr) outl(x,addr) + #define __raw_readb readb #define __raw_readw readw #define __raw_readl readl diff --git a/include/asm-x86/cpufeature_64.h b/include/asm-x86/cpufeature_64.h index 2983501e8b3..e18496b7b85 100644 --- a/include/asm-x86/cpufeature_64.h +++ b/include/asm-x86/cpufeature_64.h @@ -7,7 +7,7 @@ #ifndef __ASM_X8664_CPUFEATURE_H #define __ASM_X8664_CPUFEATURE_H -#include <asm/cpufeature_32.h> +#include "cpufeature_32.h" #undef cpu_has_vme #define cpu_has_vme 0 diff --git a/include/asm-x86/io_apic_32.h b/include/asm-x86/io_apic_32.h index dbe734ddf2a..3f087883ea4 100644 --- a/include/asm-x86/io_apic_32.h +++ b/include/asm-x86/io_apic_32.h @@ -11,8 +11,6 @@ * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar */ -#ifdef CONFIG_X86_IO_APIC - /* * The structure of the IO-APIC: */ @@ -55,12 +53,6 @@ union IO_APIC_reg_03 { } __attribute__ ((packed)) bits; }; -/* - * # of IO-APICs and # of IRQ routing registers - */ -extern int nr_ioapics; -extern int nr_ioapic_registers[MAX_IO_APICS]; - enum ioapic_irq_destination_types { dest_Fixed = 0, dest_LowestPrio = 1, @@ -100,6 +92,14 @@ struct IO_APIC_route_entry { } __attribute__ ((packed)); +#ifdef CONFIG_X86_IO_APIC + +/* + * # of IO-APICs and # of IRQ routing registers + */ +extern int nr_ioapics; +extern int nr_ioapic_registers[MAX_IO_APICS]; + /* * MP-BIOS irq configuration table structures: */ diff --git a/include/asm-x86/processor-flags.h b/include/asm-x86/processor-flags.h index 5404e90edd5..199cab107d8 100644 --- a/include/asm-x86/processor-flags.h +++ b/include/asm-x86/processor-flags.h @@ -63,7 +63,7 @@ /* * x86-64 Task Priority Register, CR8 */ -#define X86_CR8_TPR 0x00000007 /* task priority register */ +#define X86_CR8_TPR 0x0000000F /* task priority register */ /* * AMD and Transmeta use MSRs for configuration; see <asm/msr-index.h> diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h index 840631fa5ff..6b563cae23d 100644 --- a/include/linux/jffs2.h +++ b/include/linux/jffs2.h @@ -46,6 +46,7 @@ #define JFFS2_COMPR_COPY 0x04 #define JFFS2_COMPR_DYNRUBIN 0x05 #define JFFS2_COMPR_ZLIB 0x06 +#define JFFS2_COMPR_LZO 0x07 /* Compatibility flags. */ #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ #define JFFS2_NODE_ACCURATE 0x2000 diff --git a/include/linux/kvm.h b/include/linux/kvm.h index e6edca81ab8..057a7f34ee3 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -4,8 +4,7 @@ /* * Userspace interface for /dev/kvm - kernel based virtual machine * - * Note: this interface is considered experimental and may change without - * notice. + * Note: you must update KVM_API_VERSION if you change this interface. */ #include <asm/types.h> @@ -13,14 +12,8 @@ #define KVM_API_VERSION 12 -/* - * Architectural interrupt line count, and the size of the bitmap needed - * to hold them. - */ +/* Architectural interrupt line count. */ #define KVM_NR_INTERRUPTS 256 -#define KVM_IRQ_BITMAP_SIZE_BYTES ((KVM_NR_INTERRUPTS + 7) / 8) -#define KVM_IRQ_BITMAP_SIZE(type) (KVM_IRQ_BITMAP_SIZE_BYTES / sizeof(type)) - /* for KVM_CREATE_MEMORY_REGION */ struct kvm_memory_region { @@ -41,20 +34,89 @@ struct kvm_memory_alias { __u64 target_phys_addr; }; -enum kvm_exit_reason { - KVM_EXIT_UNKNOWN = 0, - KVM_EXIT_EXCEPTION = 1, - KVM_EXIT_IO = 2, - KVM_EXIT_HYPERCALL = 3, - KVM_EXIT_DEBUG = 4, - KVM_EXIT_HLT = 5, - KVM_EXIT_MMIO = 6, - KVM_EXIT_IRQ_WINDOW_OPEN = 7, - KVM_EXIT_SHUTDOWN = 8, - KVM_EXIT_FAIL_ENTRY = 9, - KVM_EXIT_INTR = 10, +/* for KVM_IRQ_LINE */ +struct kvm_irq_level { + /* + * ACPI gsi notion of irq. + * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47.. + * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23.. + */ + __u32 irq; + __u32 level; +}; + +/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */ +struct kvm_pic_state { + __u8 last_irr; /* edge detection */ + __u8 irr; /* interrupt request register */ + __u8 imr; /* interrupt mask register */ + __u8 isr; /* interrupt service register */ + __u8 priority_add; /* highest irq priority */ + __u8 irq_base; + __u8 read_reg_select; + __u8 poll; + __u8 special_mask; + __u8 init_state; + __u8 auto_eoi; + __u8 rotate_on_auto_eoi; + __u8 special_fully_nested_mode; + __u8 init4; /* true if 4 byte init */ + __u8 elcr; /* PIIX edge/trigger selection */ + __u8 elcr_mask; +}; + +#define KVM_IOAPIC_NUM_PINS 24 +struct kvm_ioapic_state { + __u64 base_address; + __u32 ioregsel; + __u32 id; + __u32 irr; + __u32 pad; + union { + __u64 bits; + struct { + __u8 vector; + __u8 delivery_mode:3; + __u8 dest_mode:1; + __u8 delivery_status:1; + __u8 polarity:1; + __u8 remote_irr:1; + __u8 trig_mode:1; + __u8 mask:1; + __u8 reserve:7; + __u8 reserved[4]; + __u8 dest_id; + } fields; + } redirtbl[KVM_IOAPIC_NUM_PINS]; }; +#define KVM_IRQCHIP_PIC_MASTER 0 +#define KVM_IRQCHIP_PIC_SLAVE 1 +#define KVM_IRQCHIP_IOAPIC 2 + +struct kvm_irqchip { + __u32 chip_id; + __u32 pad; + union { + char dummy[512]; /* reserving space */ + struct kvm_pic_state pic; + struct kvm_ioapic_state ioapic; + } chip; +}; + +#define KVM_EXIT_UNKNOWN 0 +#define KVM_EXIT_EXCEPTION 1 +#define KVM_EXIT_IO 2 +#define KVM_EXIT_HYPERCALL 3 +#define KVM_EXIT_DEBUG 4 +#define KVM_EXIT_HLT 5 +#define KVM_EXIT_MMIO 6 +#define KVM_EXIT_IRQ_WINDOW_OPEN 7 +#define KVM_EXIT_SHUTDOWN 8 +#define KVM_EXIT_FAIL_ENTRY 9 +#define KVM_EXIT_INTR 10 +#define KVM_EXIT_SET_TPR 11 + /* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */ struct kvm_run { /* in */ @@ -106,11 +168,14 @@ struct kvm_run { } mmio; /* KVM_EXIT_HYPERCALL */ struct { + __u64 nr; __u64 args[6]; __u64 ret; __u32 longmode; __u32 pad; } hypercall; + /* Fix the size of the union. */ + char padding[256]; }; }; @@ -139,6 +204,12 @@ struct kvm_fpu { __u32 pad2; }; +/* for KVM_GET_LAPIC and KVM_SET_LAPIC */ +#define KVM_APIC_REG_SIZE 0x400 +struct kvm_lapic_state { + char regs[KVM_APIC_REG_SIZE]; +}; + struct kvm_segment { __u64 base; __u32 limit; @@ -164,7 +235,7 @@ struct kvm_sregs { __u64 cr0, cr2, cr3, cr4, cr8; __u64 efer; __u64 apic_base; - __u64 interrupt_bitmap[KVM_IRQ_BITMAP_SIZE(__u64)]; + __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64]; }; struct kvm_msr_entry { @@ -272,6 +343,12 @@ struct kvm_signal_mask { #define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */ /* + * Extension capability list. + */ +#define KVM_CAP_IRQCHIP 0 +#define KVM_CAP_HLT 1 + +/* * ioctls for VM fds */ #define KVM_SET_MEMORY_REGION _IOW(KVMIO, 0x40, struct kvm_memory_region) @@ -282,6 +359,11 @@ struct kvm_signal_mask { #define KVM_CREATE_VCPU _IO(KVMIO, 0x41) #define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log) #define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias) +/* Device model IOC */ +#define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60) +#define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level) +#define KVM_GET_IRQCHIP _IOWR(KVMIO, 0x62, struct kvm_irqchip) +#define KVM_SET_IRQCHIP _IOR(KVMIO, 0x63, struct kvm_irqchip) /* * ioctls for vcpu fds @@ -300,5 +382,7 @@ struct kvm_signal_mask { #define KVM_SET_SIGNAL_MASK _IOW(KVMIO, 0x8b, struct kvm_signal_mask) #define KVM_GET_FPU _IOR(KVMIO, 0x8c, struct kvm_fpu) #define KVM_SET_FPU _IOW(KVMIO, 0x8d, struct kvm_fpu) +#define KVM_GET_LAPIC _IOR(KVMIO, 0x8e, struct kvm_lapic_state) +#define KVM_SET_LAPIC _IOW(KVMIO, 0x8f, struct kvm_lapic_state) #endif diff --git a/include/linux/maple.h b/include/linux/maple.h new file mode 100644 index 00000000000..bad9a7b319d --- /dev/null +++ b/include/linux/maple.h @@ -0,0 +1,80 @@ +#ifndef __LINUX_MAPLE_H +#define __LINUX_MAPLE_H + +#include <linux/device.h> + +extern struct bus_type maple_bus_type; + +/* Maple Bus command and response codes */ +enum maple_code { + MAPLE_RESPONSE_FILEERR = -5, + MAPLE_RESPONSE_AGAIN = -4, /* request should be retransmitted */ + MAPLE_RESPONSE_BADCMD = -3, + MAPLE_RESPONSE_BADFUNC = -2, + MAPLE_RESPONSE_NONE = -1, /* unit didn't respond at all */ + MAPLE_COMMAND_DEVINFO = 1, + MAPLE_COMMAND_ALLINFO = 2, + MAPLE_COMMAND_RESET = 3, + MAPLE_COMMAND_KILL = 4, + MAPLE_RESPONSE_DEVINFO = 5, + MAPLE_RESPONSE_ALLINFO = 6, + MAPLE_RESPONSE_OK = 7, + MAPLE_RESPONSE_DATATRF = 8, + MAPLE_COMMAND_GETCOND = 9, + MAPLE_COMMAND_GETMINFO = 10, + MAPLE_COMMAND_BREAD = 11, + MAPLE_COMMAND_BWRITE = 12, + MAPLE_COMMAND_SETCOND = 14 +}; + +struct mapleq { + struct list_head list; + struct maple_device *dev; + void *sendbuf, *recvbuf, *recvbufdcsp; + unsigned char length; + enum maple_code command; +}; + +struct maple_devinfo { + unsigned long function; + unsigned long function_data[3]; + unsigned char area_code; + unsigned char connector_directon; + char product_name[31]; + char product_licence[61]; + unsigned short standby_power; + unsigned short max_power; +}; + +struct maple_device { + struct maple_driver *driver; + struct mapleq *mq; + void *private_data; + void (*callback) (struct mapleq * mq); + unsigned long when, interval, function; + struct maple_devinfo devinfo; + unsigned char port, unit; + char product_name[32]; + char product_licence[64]; + int registered; + struct device dev; +}; + +struct maple_driver { + unsigned long function; + int (*connect) (struct maple_device * dev); + void (*disconnect) (struct maple_device * dev); + struct device_driver drv; +}; + +void maple_getcond_callback(struct maple_device *dev, + void (*callback) (struct mapleq * mq), + unsigned long interval, + unsigned long function); +int maple_driver_register(struct device_driver *drv); +void maple_add_packet(struct mapleq *mq); + +#define to_maple_dev(n) container_of(n, struct maple_device, dev) +#define to_maple_driver(n) container_of(n, struct maple_driver, drv) + +#endif /* __LINUX_MAPLE_H */ diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index 123948b1454..e17c5343cf5 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -57,6 +57,15 @@ #define cfi_interleave_is_8(cfi) (0) #endif +#ifndef cfi_interleave +#warning No CONFIG_MTD_CFI_Ix selected. No NOR chip support can work. +static inline int cfi_interleave(void *cfi) +{ + BUG(); + return 0; +} +#endif + static inline int cfi_interleave_supported(int i) { switch (i) { diff --git a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h index a293a3b78e0..39e7d2a1be9 100644 --- a/include/linux/mtd/flashchip.h +++ b/include/linux/mtd/flashchip.h @@ -40,6 +40,7 @@ typedef enum { FL_POINT, FL_XIP_WHILE_ERASING, FL_XIP_WHILE_WRITING, + FL_SHUTDOWN, FL_UNKNOWN } flstate_t; diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index 81f3a314dd7..a9fae032ba8 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -125,7 +125,15 @@ #endif #ifndef map_bankwidth -#error "No bus width supported. What's the point?" +#warning "No CONFIG_MTD_MAP_BANK_WIDTH_xx selected. No NOR chip support can work" +static inline int map_bankwidth(void *map) +{ + BUG(); + return 0; +} +#define map_bankwidth_is_large(map) (0) +#define map_words(map) (0) +#define MAX_MAP_BANKWIDTH 1 #endif static inline int map_bankwidth_supported(int w) diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index fd64ccfbce0..783fc983417 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -133,6 +133,13 @@ struct mtd_info { int numeraseregions; struct mtd_erase_region_info *eraseregions; + /* + * Erase is an asynchronous operation. Device drivers are supposed + * to call instr->callback() whenever the operation completes, even + * if it completes with a failure. + * Callers are supposed to pass a callback function and wait for it + * to be called before writing to the block. + */ int (*erase) (struct mtd_info *mtd, struct erase_info *instr); /* This stuff for eXecute-In-Place */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index d2365c8dcac..c42bc7f533a 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -432,6 +432,7 @@ struct nand_chip { #define NAND_MFR_STMICRO 0x20 #define NAND_MFR_HYNIX 0xad #define NAND_MFR_MICRON 0x2c +#define NAND_MFR_AMD 0x01 /** * struct nand_flash_dev - NAND Flash Device ID Structure diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index a56d24ada50..fd0a260e070 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h @@ -60,6 +60,7 @@ struct onenand_bufferram { * @erase_shift: [INTERN] number of address bits in a block * @page_shift: [INTERN] number of address bits in a page * @page_mask: [INTERN] a page per block mask + * @writesize: [INTERN] a real page size * @bufferram_index: [INTERN] BufferRAM index * @bufferram: [INTERN] BufferRAM info * @readw: [REPLACEABLE] hardware specific function for read short @@ -100,6 +101,7 @@ struct onenand_chip { unsigned int erase_shift; unsigned int page_shift; unsigned int page_mask; + unsigned int writesize; unsigned int bufferram_index; struct onenand_bufferram bufferram[MAX_BUFFERRAM]; @@ -140,6 +142,8 @@ struct onenand_chip { #define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1) #define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1) #define ONENAND_SET_PREV_BUFFERRAM(this) (this->bufferram_index ^= 1) +#define ONENAND_SET_BUFFERRAM0(this) (this->bufferram_index = 0) +#define ONENAND_SET_BUFFERRAM1(this) (this->bufferram_index = 1) #define ONENAND_GET_SYS_CFG1(this) \ (this->read_word(this->base + ONENAND_REG_SYS_CFG1)) @@ -149,6 +153,13 @@ struct onenand_chip { #define ONENAND_IS_DDP(this) \ (this->device_id & ONENAND_DEVICE_IS_DDP) +#ifdef CONFIG_MTD_ONENAND_2X_PROGRAM +#define ONENAND_IS_2PLANE(this) \ + (this->options & ONENAND_HAS_2PLANE) +#else +#define ONENAND_IS_2PLANE(this) (0) +#endif + /* Check byte access in OneNAND */ #define ONENAND_CHECK_BYTE_ACCESS(addr) (addr & 0x1) @@ -157,6 +168,7 @@ struct onenand_chip { */ #define ONENAND_HAS_CONT_LOCK (0x0001) #define ONENAND_HAS_UNLOCK_ALL (0x0002) +#define ONENAND_HAS_2PLANE (0x0004) #define ONENAND_PAGEBUF_ALLOC (0x1000) #define ONENAND_OOBBUF_ALLOC (0x2000) diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h index af94719890e..c46161f4eee 100644 --- a/include/linux/mtd/onenand_regs.h +++ b/include/linux/mtd/onenand_regs.h @@ -74,6 +74,8 @@ #define ONENAND_DEVICE_DENSITY_512Mb (0x002) #define ONENAND_DEVICE_DENSITY_1Gb (0x003) +#define ONENAND_DEVICE_DENSITY_2Gb (0x004) +#define ONENAND_DEVICE_DENSITY_4Gb (0x005) /* * Version ID Register F002h (R) @@ -111,6 +113,8 @@ #define ONENAND_CMD_READOOB (0x13) #define ONENAND_CMD_PROG (0x80) #define ONENAND_CMD_PROGOOB (0x1A) +#define ONENAND_CMD_2X_PROG (0x7D) +#define ONENAND_CMD_2X_CACHE_PROG (0x7F) #define ONENAND_CMD_UNLOCK (0x23) #define ONENAND_CMD_LOCK (0x2A) #define ONENAND_CMD_LOCK_TIGHT (0x2C) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 5a11f889e56..39dd83b183a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1294,6 +1294,7 @@ static inline void netif_rx_complete(struct net_device *dev, /** * netif_tx_lock - grab network device transmit lock * @dev: network device + * @cpu: cpu number of lock owner * * Get network device transmit lock */ diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 9fa09fb800a..0fa5d591255 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -133,7 +133,7 @@ struct videobuf_qtype_ops { enum v4l2_memory memory); int (*sync) (struct videobuf_queue* q, struct videobuf_buffer *buf); - int (*copy_to_user) (struct videobuf_queue *q, + int (*video_copy_to_user)(struct videobuf_queue *q, char __user *data, size_t count, int nonblocking); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c7314f95264..6c97259e863 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1053,7 +1053,7 @@ static ctl_table vm_table[] = { .strategy = &sysctl_string, }, #endif -#if defined(CONFIG_X86_32) || \ +#if (defined(CONFIG_X86_32) && !defined(CONFIG_UML))|| \ (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL)) { .ctl_name = VM_VDSO_ENABLED, diff --git a/net/core/dev.c b/net/core/dev.c index 1e169a541ce..99b7bda37d1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -557,6 +557,7 @@ __setup("netdev=", netdev_boot_setup); /** * __dev_get_by_name - find a device by its name + * @net: the applicable net namespace * @name: name to find * * Find an interface by name. Must be called under RTNL semaphore @@ -581,6 +582,7 @@ struct net_device *__dev_get_by_name(struct net *net, const char *name) /** * dev_get_by_name - find a device by its name + * @net: the applicable net namespace * @name: name to find * * Find an interface by name. This can be called from any @@ -604,6 +606,7 @@ struct net_device *dev_get_by_name(struct net *net, const char *name) /** * __dev_get_by_index - find a device by its ifindex + * @net: the applicable net namespace * @ifindex: index of device * * Search for an interface by index. Returns %NULL if the device @@ -629,6 +632,7 @@ struct net_device *__dev_get_by_index(struct net *net, int ifindex) /** * dev_get_by_index - find a device by its ifindex + * @net: the applicable net namespace * @ifindex: index of device * * Search for an interface by index. Returns NULL if the device @@ -651,6 +655,7 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex) /** * dev_getbyhwaddr - find a device by its hardware address + * @net: the applicable net namespace * @type: media type of device * @ha: hardware address * @@ -709,6 +714,7 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype); /** * dev_get_by_flags - find any device with given flags + * @net: the applicable net namespace * @if_flags: IFF_* values * @mask: bitmask of bits in if_flags to check * @@ -948,6 +954,7 @@ void netdev_state_change(struct net_device *dev) /** * dev_load - load a network module + * @net: the applicable net namespace * @name: name of interface * * If a network interface is not present and the process has suitable @@ -1185,7 +1192,7 @@ int unregister_netdevice_notifier(struct notifier_block *nb) /** * call_netdevice_notifiers - call all network notifier blocks * @val: value passed unmodified to notifier function - * @v: pointer passed unmodified to notifier function + * @dev: net_device pointer passed unmodified to notifier function * * Call all network notifier blocks. Parameters and return value * are as for raw_notifier_call_chain(). @@ -2097,7 +2104,7 @@ static int process_backlog(struct napi_struct *napi, int quota) /** * __napi_schedule - schedule for receive - * @napi: entry to schedule + * @n: entry to schedule * * The entry's receive function will be scheduled to run */ @@ -3259,6 +3266,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) /** * dev_ioctl - network device ioctl + * @net: the applicable net namespace * @cmd: command to issue * @arg: pointer to a struct ifreq in user space * @@ -3436,6 +3444,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) /** * dev_new_index - allocate an ifindex + * @net: the applicable net namespace * * Returns a suitable unique value for a new device interface * number. The caller must hold the rtnl semaphore or the diff --git a/net/core/sock.c b/net/core/sock.c index 4ed9b507c1e..d45ecdccc6a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -869,6 +869,7 @@ static inline void sock_lock_init(struct sock *sk) /** * sk_alloc - All socket objects are allocated here + * @net: the applicable net namespace * @family: protocol family * @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) * @prot: struct proto associated with this new sock instance |