diff -wur linux-2.6.10/MAINTAINERS linux-2.6.10-lab/MAINTAINERS --- linux-2.6.10/MAINTAINERS 2004-12-24 16:35:00.000000000 -0500 +++ linux-2.6.10-lab/MAINTAINERS 2007-10-04 19:10:40.000000000 -0400 @@ -937,6 +937,13 @@ L: iss_storagedev@hp.com S: Supported +HOST AP DRIVER +P: Jouni Malinen +M: jkmaline@cc.hut.fi +L: hostap@shmoo.com +W: http://hostap.epitest.fi/ +S: Maintained + HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series P: Jaroslav Kysela M: perex@suse.cz diff -wur linux-2.6.10/Makefile linux-2.6.10-lab/Makefile --- linux-2.6.10/Makefile 2004-12-24 16:35:01.000000000 -0500 +++ linux-2.6.10-lab/Makefile 2007-10-04 19:10:40.000000000 -0400 @@ -4,6 +4,19 @@ EXTRAVERSION = NAME=Woozy Numbat +# +# The following six lines makes this make default to +# a cross-compiled arm version of Linux. This makes +# it easier to drive make directly (without all the extra params +# each time or the requirement of a separate script). +# +ifndef ARCH +ARCH=arm +endif +ifndef CROSS_COMPILE +CROSS_COMPILE=arm-linux- +endif + # *DOCUMENTATION* # To see a list of typical targets execute "make help" # More info can be located in ./README @@ -203,7 +216,8 @@ HOSTCC = gcc HOSTCXX = g++ -HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -idirafter "`$(CC) -print-file-name=include`/../../../../../include/" + HOSTCXXFLAGS = -O2 # Decide whether to build built-in, modular, or both. @@ -866,11 +880,11 @@ .PHONY: _modinst_ _modinst_: - @if [ -z "`$(DEPMOD) -V | grep module-init-tools`" ]; then \ - echo "Warning: you may need to install module-init-tools"; \ - echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\ - sleep 1; \ - fi +## @if [ -z "`$(DEPMOD) -V | grep module-init-tools`" ]; then \ +## echo "Warning: you may need to install module-init-tools"; \ +## echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\ +## sleep 1; \ +## fi @rm -rf $(MODLIB)/kernel @rm -f $(MODLIB)/source @mkdir -p $(MODLIB)/kernel @@ -893,7 +907,9 @@ endif .PHONY: _modinst_post _modinst_post: _modinst_ - if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi +## if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi + @rm -f $(MODLIB)/build + @rm -f $(MODLIB)/source else # CONFIG_MODULES @@ -970,7 +986,8 @@ # mrproper: rm-dirs := $(wildcard $(MRPROPER_DIRS)) mrproper: rm-files := $(wildcard $(MRPROPER_FILES)) -mrproper-dirs := $(addprefix _mrproper_,Documentation/DocBook scripts) +# mrproper-dirs := $(addprefix _mrproper_,Documentation/DocBook scripts) +mrproper-dirs := $(addprefix _mrproper_,scripts) .PHONY: $(mrproper-dirs) mrproper archmrproper $(mrproper-dirs): @@ -1063,8 +1080,8 @@ # Documentation targets # --------------------------------------------------------------------------- -%docs: scripts_basic FORCE - $(Q)$(MAKE) $(build)=Documentation/DocBook $@ +# %docs: scripts_basic FORCE +# $(Q)$(MAKE) $(build)=Documentation/DocBook $@ else # KBUILD_EXTMOD diff -wur linux-2.6.10/arch/arm/Kconfig linux-2.6.10-lab/arch/arm/Kconfig --- linux-2.6.10/arch/arm/Kconfig 2004-12-24 16:34:57.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/Kconfig 2007-10-04 19:13:12.000000000 -0400 @@ -83,8 +83,8 @@ config ARCH_CO285 bool "Co-EBSA285" - select FOOTBRIDGE - select FOOTBRIDGE_ADDIN +# select FOOTBRIDGE +# select FOOTBRIDGE_ADDIN config ARCH_EBSA110 bool "EBSA-110" @@ -103,7 +103,7 @@ config ARCH_FOOTBRIDGE bool "FootBridge" - select FOOTBRIDGE +# select FOOTBRIDGE config ARCH_INTEGRATOR bool "Integrator" @@ -177,35 +177,35 @@ endchoice -source "arch/arm/mach-clps711x/Kconfig" +# source "arch/arm/mach-clps711x/Kconfig" -source "arch/arm/mach-epxa10db/Kconfig" +# source "arch/arm/mach-epxa10db/Kconfig" -source "arch/arm/mach-footbridge/Kconfig" +# source "arch/arm/mach-footbridge/Kconfig" -source "arch/arm/mach-integrator/Kconfig" +# source "arch/arm/mach-integrator/Kconfig" -source "arch/arm/mach-iop3xx/Kconfig" +# source "arch/arm/mach-iop3xx/Kconfig" -source "arch/arm/mach-ixp4xx/Kconfig" +# source "arch/arm/mach-ixp4xx/Kconfig" -source "arch/arm/mach-ixp2000/Kconfig" +# source "arch/arm/mach-ixp2000/Kconfig" source "arch/arm/mach-pxa/Kconfig" -source "arch/arm/mach-sa1100/Kconfig" +# source "arch/arm/mach-sa1100/Kconfig" -source "arch/arm/mach-omap/Kconfig" +# source "arch/arm/mach-omap/Kconfig" -source "arch/arm/mach-s3c2410/Kconfig" +# source "arch/arm/mach-s3c2410/Kconfig" -source "arch/arm/mach-lh7a40x/Kconfig" +# source "arch/arm/mach-lh7a40x/Kconfig" -source "arch/arm/mach-imx/Kconfig" +# source "arch/arm/mach-imx/Kconfig" -source "arch/arm/mach-h720x/Kconfig" +# source "arch/arm/mach-h720x/Kconfig" -source "arch/arm/mach-versatile/Kconfig" +# source "arch/arm/mach-versatile/Kconfig" # Definitions to make life easier config ARCH_ACORN @@ -396,7 +396,7 @@ In any case, make sure that MTD support is configured out for the first attempt. -if (ARCH_SA1100 || ARCH_INTEGRATOR) +if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_PXA) source "drivers/cpufreq/Kconfig" @@ -421,9 +421,22 @@ If in doubt, say Y. +config CPU_FREQ_PXA + bool + depends on CPU_FREQ && ARCH_PXA + default y + select CPU_FREQ_DEFAULT_GOV_USERSPACE + +config CPU_FREQ_TABLE + tristate + depends on CPU_FREQ + default y + endif -source "drivers/pci/Kconfig" +source "drivers/gpio/Kconfig" + +# source "drivers/pci/Kconfig" source "drivers/pcmcia/Kconfig" @@ -482,25 +495,7 @@ source "drivers/base/Kconfig" -config PM - bool "Power Management support" - ---help--- - "Power Management" means that parts of your computer are shut - off or put into a power conserving "sleep" mode if they are not - being used. There are two competing standards for doing this: APM - and ACPI. If you want to use either one, say Y here and then also - to the requisite support below. - - Power Management is most important for battery powered laptop - computers; if you have a laptop, check out the Linux Laptop home - page on the WWW at or - Tuxmobil - Linux on Mobile Computers at - and the Battery Powered Linux mini-HOWTO, available from - . - - Note that, even if you say N here, Linux on the x86 architecture - will issue the hlt instruction if nothing is to be done, thereby - sending the processor to sleep and saving power. +source "kernel/power/Kconfig" config PREEMPT bool "Preemptible Kernel (EXPERIMENTAL)" @@ -650,35 +645,35 @@ endmenu -source "drivers/parport/Kconfig" +# source "drivers/parport/Kconfig" if ALIGNMENT_TRAP source "drivers/mtd/Kconfig" endif -source "drivers/pnp/Kconfig" +# source "drivers/pnp/Kconfig" source "drivers/block/Kconfig" -source "drivers/md/Kconfig" +# source "drivers/md/Kconfig" -source "drivers/acorn/block/Kconfig" +# source "drivers/acorn/block/Kconfig" source "net/Kconfig" if ARCH_CLPS7500 || ARCH_IOP3XX || ARCH_IXP4XX || ARCH_L7200 || ARCH_LH7A40X || ARCH_PXA || ARCH_RPC || ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE -source "drivers/ide/Kconfig" +# source "drivers/ide/Kconfig" endif source "drivers/scsi/Kconfig" -source "drivers/message/fusion/Kconfig" +# source "drivers/message/fusion/Kconfig" -source "drivers/ieee1394/Kconfig" +# source "drivers/ieee1394/Kconfig" -source "drivers/message/i2o/Kconfig" +# source "drivers/message/i2o/Kconfig" -source "drivers/isdn/Kconfig" +# source "drivers/isdn/Kconfig" # # input before char - char/joystick depends on it. As does USB. @@ -691,7 +686,7 @@ #source "drivers/l3/Kconfig" -source "drivers/media/Kconfig" +# source "drivers/media/Kconfig" source "fs/Kconfig" @@ -714,3 +709,4 @@ source "crypto/Kconfig" source "lib/Kconfig" + diff -wur linux-2.6.10/arch/arm/Kconfig.debug linux-2.6.10-lab/arch/arm/Kconfig.debug --- linux-2.6.10/arch/arm/Kconfig.debug 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/Kconfig.debug 2007-10-04 19:10:15.000000000 -0400 @@ -115,4 +115,5 @@ The uncompressor code port configuration is now handled by CONFIG_S3C2410_LOWLEVEL_UART_PORT. +source "drivers/char/ppoke/Kconfig" endmenu diff -wur linux-2.6.10/arch/arm/Makefile linux-2.6.10-lab/arch/arm/Makefile --- linux-2.6.10/arch/arm/Makefile 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/Makefile 2007-10-04 19:10:15.000000000 -0400 @@ -144,8 +144,8 @@ core-$(CONFIG_VFP) += arch/arm/vfp/ drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/ -drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/ -drivers-$(CONFIG_ARCH_L7200) += drivers/acorn/char/ +# drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/ +# drivers-$(CONFIG_ARCH_L7200) += drivers/acorn/char/ libs-y += arch/arm/lib/ diff -wur linux-2.6.10/arch/arm/kernel/compat.c linux-2.6.10-lab/arch/arm/kernel/compat.c --- linux-2.6.10/arch/arm/kernel/compat.c 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/kernel/compat.c 2007-10-04 19:10:14.000000000 -0400 @@ -64,8 +64,12 @@ unsigned long initrd_size; /* 68 */ unsigned long rd_start; /* 72 */ unsigned long system_rev; /* 76 */ +#ifdef CONFIG_ARCH_FIONA + unsigned char system_serial_data[BOARD_SERIALNUM_SIZE]; +#else unsigned long system_serial_low; /* 80 */ unsigned long system_serial_high; /* 84 */ +#endif unsigned long mem_fclk_21285; /* 88 */ } s; char unused[256]; @@ -143,8 +147,12 @@ tag = tag_next(tag); tag->hdr.tag = ATAG_SERIAL; tag->hdr.size = tag_size(tag_serialnr); +#ifdef CONFIG_ARCH_FIONA + memcpy(tag->u.serialnr.data, params->u1.s.system_serial_data, BOARD_SERIALNUM_SIZE); +#else tag->u.serialnr.low = params->u1.s.system_serial_low; tag->u.serialnr.high = params->u1.s.system_serial_high; +#endif tag = tag_next(tag); tag->hdr.tag = ATAG_REVISION; diff -wur linux-2.6.10/arch/arm/kernel/process.c linux-2.6.10-lab/arch/arm/kernel/process.c --- linux-2.6.10/arch/arm/kernel/process.c 2004-12-24 16:35:28.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/kernel/process.c 2007-10-04 19:10:14.000000000 -0400 @@ -33,6 +33,10 @@ #include #include +#ifdef CONFIG_ARCH_FIONA +#include +#endif + extern const char *processor_modes[]; extern void setup_mm_for_reboot(char mode); @@ -152,6 +156,14 @@ */ setup_mm_for_reboot(reboot_mode); +#ifdef CONFIG_ARCH_FIONA + // set the OneNAND back into async read mode so bootloader can fetch page zero + fiona_set_onenand_async(); + + // reset the OneNAND DBS bit to ensure the proper page zero is present + fiona_reset_onenand_dbs_bit(); +#endif + /* * Now call the architecture specific reboot code. */ diff -wur linux-2.6.10/arch/arm/kernel/setup.c linux-2.6.10-lab/arch/arm/kernel/setup.c --- linux-2.6.10/arch/arm/kernel/setup.c 2004-12-24 16:34:57.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/kernel/setup.c 2007-10-04 19:10:14.000000000 -0400 @@ -67,12 +67,19 @@ unsigned int system_rev; EXPORT_SYMBOL(system_rev); +unsigned int board_resistance = 0; +EXPORT_SYMBOL(board_resistance); +#ifdef CONFIG_ARCH_FIONA +unsigned char system_serial_data[BOARD_SERIALNUM_SIZE]; +EXPORT_SYMBOL(system_serial_data); +#else unsigned int system_serial_low; EXPORT_SYMBOL(system_serial_low); unsigned int system_serial_high; EXPORT_SYMBOL(system_serial_high); +#endif unsigned int elf_hwcap; EXPORT_SYMBOL(elf_hwcap); @@ -595,8 +602,12 @@ static int __init parse_tag_serialnr(const struct tag *tag) { +#ifdef CONFIG_ARCH_FIONA + memcpy(system_serial_data, tag->u.serialnr.data, BOARD_SERIALNUM_SIZE); +#else system_serial_low = tag->u.serialnr.low; system_serial_high = tag->u.serialnr.high; +#endif return 0; } @@ -610,6 +621,16 @@ __tagtable(ATAG_REVISION, parse_tag_revision); + +static int __init parse_tag_board_resistance(const struct tag *tag) +{ + board_resistance = tag->u.board_resistance.mohms; + printk("Fiona Board Resistance : %d mOhms\n",board_resistance); + return 0; +} + +__tagtable(ATAG_BOARD_RESISTANCE, parse_tag_board_resistance); + static int __init parse_tag_cmdline(const struct tag *tag) { strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE); @@ -780,6 +801,9 @@ static int c_show(struct seq_file *m, void *v) { int i; +#ifdef CONFIG_ARCH_FIONA + char serial_num[BOARD_SERIALNUM_SIZE + 1]; +#endif seq_printf(m, "Processor\t: %s rev %d (%s)\n", cpu_name, (int)processor_id & 15, elf_platform); @@ -841,8 +865,15 @@ seq_printf(m, "Hardware\t: %s\n", machine_name); seq_printf(m, "Revision\t: %04x\n", system_rev); + +#ifdef CONFIG_ARCH_FIONA + memset(serial_num, '\0', sizeof(serial_num)); + strncpy(serial_num, system_serial_data, BOARD_SERIALNUM_SIZE); + seq_printf(m, "Serial\t\t: \"%s\"\n", serial_num); +#else seq_printf(m, "Serial\t\t: %08x%08x\n", system_serial_high, system_serial_low); +#endif return 0; } diff -wur linux-2.6.10/arch/arm/mach-pxa/Kconfig linux-2.6.10-lab/arch/arm/mach-pxa/Kconfig --- linux-2.6.10/arch/arm/mach-pxa/Kconfig 2004-12-24 16:34:26.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/mach-pxa/Kconfig 2007-10-04 19:10:15.000000000 -0400 @@ -1,10 +1,26 @@ if ARCH_PXA +config ARCH_LAB126 + bool + default n + menu "Intel PXA2xx Implementations" choice prompt "Select target board" +config ARCH_GUMSTIX + bool "Gumstix Platform" + depends on ARCH_PXA + +config ARCH_FIONA + bool "Fiona Platform" + select PXA25x + select PXA_SSP + select ARCH_LAB126 + select ZLIB_DEFLATE + depends on ARCH_PXA + config ARCH_LUBBOCK bool "Intel DBPXA250 Development Platform" select PXA25x @@ -22,6 +38,28 @@ endmenu + +choice + depends on ARCH_GUMSTIX + prompt "Gumstix Platform Version" + default ARCH_GUMSTIX_F + +config ARCH_GUMSTIX_ORIG + bool "Original Gumstix" + select PXA25x + help + The original gumstix platform, including the gs-200x and gs-400x and the waysmall + systems using these boards. + +config ARCH_GUMSTIX_F + bool "Gumstix-F" + select PXA25x + help + The updated Gumstix boards with 60-pin connector, including gs-200f, gs-400f and the + waysmall systems using these boards, including ws-200ax and ws-400ax. + +endchoice + config PXA25x bool help @@ -37,4 +75,10 @@ help Enable support for iWMMXt +config PXA_SSP + tristate + help + Enable PXA ssp support + endif + diff -wur linux-2.6.10/arch/arm/mach-pxa/Makefile linux-2.6.10-lab/arch/arm/mach-pxa/Makefile --- linux-2.6.10/arch/arm/mach-pxa/Makefile 2004-12-24 16:34:49.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/mach-pxa/Makefile 2007-10-04 19:10:15.000000000 -0400 @@ -8,6 +8,9 @@ obj-$(CONFIG_PXA27x) += pxa27x.o # Specific board support +obj-$(CONFIG_ARCH_FIONA) += fiona.o +obj-$(CONFIG_ARCH_FIONA) += boot_globals.o +obj-$(CONFIG_ARCH_GUMSTIX) += gumstix.o obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o obj-$(CONFIG_ARCH_PXA_IDP) += idp.o @@ -22,3 +25,5 @@ # Misc features obj-$(CONFIG_PM) += pm.o sleep.o +obj-$(CONFIG_CPU_FREQ) += cpu-pxa.o +obj-$(CONFIG_PXA_SSP) += ssp.o diff -wur linux-2.6.10/arch/arm/mach-pxa/generic.c linux-2.6.10-lab/arch/arm/mach-pxa/generic.c --- linux-2.6.10/arch/arm/mach-pxa/generic.c 2004-12-24 16:34:29.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/mach-pxa/generic.c 2007-10-04 19:10:15.000000000 -0400 @@ -219,6 +219,10 @@ .name = "pxa2xx-uart", .id = 2, }; +static struct platform_device hwuart_device = { + .name = "pxa2xx-uart", + .id = 3, +}; static struct platform_device *devices[] __initdata = { &pxamci_device, @@ -227,6 +231,7 @@ &ffuart_device, &btuart_device, &stuart_device, + &hwuart_device, }; static int __init pxa_init(void) diff -wur linux-2.6.10/arch/arm/mach-pxa/irq.c linux-2.6.10-lab/arch/arm/mach-pxa/irq.c --- linux-2.6.10/arch/arm/mach-pxa/irq.c 2004-12-24 16:35:27.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/mach-pxa/irq.c 2007-10-04 19:10:15.000000000 -0400 @@ -97,23 +97,31 @@ type = __IRQT_RISEDGE | __IRQT_FALEDGE; } +#ifdef DEBUG printk(KERN_DEBUG "IRQ%d (GPIO%d): ", irq, gpio); +#endif pxa_gpio_mode(gpio | GPIO_IN); if (type & __IRQT_RISEDGE) { +#ifdef DEBUG printk("rising "); +#endif __set_bit (gpio, GPIO_IRQ_rising_edge); } else __clear_bit (gpio, GPIO_IRQ_rising_edge); if (type & __IRQT_FALEDGE) { +#ifdef DEBUG printk("falling "); +#endif __set_bit (gpio, GPIO_IRQ_falling_edge); } else __clear_bit (gpio, GPIO_IRQ_falling_edge); +#ifdef DEBUG printk("edges\n"); +#endif GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx]; GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx]; diff -wur linux-2.6.10/arch/arm/mach-pxa/mainstone.c linux-2.6.10-lab/arch/arm/mach-pxa/mainstone.c --- linux-2.6.10/arch/arm/mach-pxa/mainstone.c 2004-12-24 16:35:40.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/mach-pxa/mainstone.c 2007-10-04 19:10:15.000000000 -0400 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,7 @@ #include #include +#include #include #include @@ -120,6 +122,44 @@ .resource = smc91x_resources, }; +static int mst_audio_startup(snd_pcm_substream_t *substream, void *priv) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF; + return 0; +} + +static void mst_audio_shutdown(snd_pcm_substream_t *substream, void *priv) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF; +} + +static long mst_audio_suspend_mask; + +static void mst_audio_suspend(void *priv) +{ + mst_audio_suspend_mask = MST_MSCWR2; + MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF; +} + +static void mst_audio_resume(void *priv) +{ + MST_MSCWR2 &= mst_audio_suspend_mask | ~MST_MSCWR2_AC97_SPKROFF; +} + +static pxa2xx_audio_ops_t mst_audio_ops = { + .startup = mst_audio_startup, + .shutdown = mst_audio_shutdown, + .suspend = mst_audio_suspend, + .resume = mst_audio_resume, +}; + +static struct platform_device mst_audio_device = { + .name = "pxa2xx-ac97", + .id = -1, + .dev = { .platform_data = &mst_audio_ops }, +}; static void mainstone_backlight_power(int on) { @@ -228,7 +268,14 @@ static void __init mainstone_init(void) { + /* + * On Mainstone, we route AC97_SYSCLK via GPIO45 to + * the audio daughter card + */ + pxa_gpio_mode(GPIO45_SYSCLK_AC97_MD); + platform_device_register(&smc91x_device); + platform_device_register(&mst_audio_device); /* reading Mainstone's "Virtual Configuration Register" might be handy to select LCD type here */ diff -wur linux-2.6.10/arch/arm/mach-pxa/pm.c linux-2.6.10-lab/arch/arm/mach-pxa/pm.c --- linux-2.6.10/arch/arm/mach-pxa/pm.c 2004-12-24 16:35:00.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/mach-pxa/pm.c 2007-10-04 19:10:15.000000000 -0400 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -23,11 +24,15 @@ #include #include +#ifdef CONFIG_ARCH_FIONA +#include +#endif + /* * Debug macros */ -#undef DEBUG +#define DEBUG extern void pxa_cpu_suspend(void); extern void pxa_cpu_resume(void); @@ -63,6 +68,80 @@ }; +#ifdef CONFIG_PM_DEBUG + +static void blink_led(int count, int cadence) +{ + int x; + for (x=0; x @@ -34,6 +37,31 @@ #include #include +#define PXA_SSP_PORTS 3 + +struct ssp_info_ { + int irq; + u32 clock; +}; + +/* + * SSP port clock and IRQ settings + */ +static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = { +#if defined (CONFIG_PXA27x) + {IRQ_SSP, CKEN23_SSP1}, + {IRQ_SSP2, CKEN3_SSP2}, + {IRQ_SSP3, CKEN4_SSP3}, +#else + {IRQ_SSP, CKEN3_SSP}, + {IRQ_NSSP, CKEN9_NSSP}, + {IRQ_ASSP, CKEN10_ASSP}, +#endif +}; + +static DECLARE_MUTEX(sem); +static int use_count[PXA_SSP_PORTS] = {0, 0, 0}; + static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct ssp_dev *dev = (struct ssp_dev*) dev_id; @@ -171,6 +199,30 @@ } /** + * ssp_config - configure SSP port settings + * @mode: port operating mode + * @flags: port config flags + * @psp_flags: port PSP config flags + * @speed: port speed + * + * Port MUST be disabled by ssp_disable before making any config changes. + */ +int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed) +{ + dev->mode = mode; + dev->flags = flags; + dev->psp_flags = psp_flags; + dev->speed = speed; + + /* set up port type, speed, port settings */ + SSCR0_P(dev->port) = (dev->speed | dev->mode); + SSCR1_P(dev->port) = dev->flags; + SSPSP_P(dev->port) = dev->psp_flags; + + return 0; +} + +/** * ssp_init - setup the SSP port * * initialise and claim resources for the SSP port. @@ -180,82 +232,46 @@ * %-EBUSY if the resources are already in use * %0 on success */ -int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags, - u32 speed) +int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags) { - int ret, irq; + int ret; - if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) { + if (port > PXA_SSP_PORTS || port == 0) + return -ENODEV; + + down(&sem); + if (use_count[port - 1]) { + up(&sem); return -EBUSY; } + use_count[port - 1]++; - switch (port) { - case 1: - irq = IRQ_SSP; - break; -#if defined (CONFIG_PXA27x) - case 2: - irq = IRQ_SSP2; - break; - case 3: - irq = IRQ_SSP3; - break; -#else - case 2: - irq = IRQ_NSSP; - break; - case 3: - irq = IRQ_ASSP; - break; -#endif - default: - return -ENODEV; + if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) { + use_count[port - 1]--; + up(&sem); + return -EBUSY; } - dev->port = port; - dev->mode = mode; - dev->flags = flags; - dev->psp_flags = psp_flags; - dev->speed = speed; - /* set up port type, speed, port settings */ - SSCR0_P(dev->port) = (dev->speed | dev->mode); - SSCR1_P(dev->port) = dev->flags; - SSPSP_P(dev->port) = dev->psp_flags; - - ret = request_irq(irq, ssp_interrupt, 0, "SSP", dev); + /* do we need to get irq */ + if (!(init_flags & SSP_NO_IRQ)) { + ret = request_irq(ssp_info[port-1].irq, ssp_interrupt, + 0, "SSP", dev); if (ret) goto out_region; + dev->irq = ssp_info[port-1].irq; + } else + dev->irq = 0; /* turn on SSP port clock */ - switch (dev->port) { -#if defined (CONFIG_PXA27x) - case 1: - pxa_set_cken(CKEN23_SSP1, 1); - break; - case 2: - pxa_set_cken(CKEN3_SSP2, 1); - break; - case 3: - pxa_set_cken(CKEN4_SSP3, 1); - break; -#else - case 1: - pxa_set_cken(CKEN3_SSP, 1); - break; - case 2: - pxa_set_cken(CKEN9_NSSP, 1); - break; - case 3: - pxa_set_cken(CKEN10_ASSP, 1); - break; -#endif - } - + pxa_set_cken(ssp_info[port-1].clock, 1); + up(&sem); return 0; out_region: - release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c); + release_mem_region(__PREG(SSCR0_P(port)), 0x2c); + use_count[port - 1]--; + up(&sem); return ret; } @@ -266,46 +282,20 @@ */ void ssp_exit(struct ssp_dev *dev) { - int irq; - + down(&sem); SSCR0_P(dev->port) &= ~SSCR0_SSE; - /* find irq, save power and turn off SSP port clock */ - switch (dev->port) { -#if defined (CONFIG_PXA27x) - case 1: - irq = IRQ_SSP; - pxa_set_cken(CKEN23_SSP1, 0); - break; - case 2: - irq = IRQ_SSP2; - pxa_set_cken(CKEN3_SSP2, 0); - break; - case 3: - irq = IRQ_SSP3; - pxa_set_cken(CKEN4_SSP3, 0); - break; -#else - case 1: - irq = IRQ_SSP; - pxa_set_cken(CKEN3_SSP, 0); - break; - case 2: - irq = IRQ_NSSP; - pxa_set_cken(CKEN9_NSSP, 0); - break; - case 3: - irq = IRQ_ASSP; - pxa_set_cken(CKEN10_ASSP, 0); - break; -#endif - default: + if (dev->port > PXA_SSP_PORTS || dev->port == 0) { printk(KERN_WARNING "SSP: tried to close invalid port\n"); return; } - free_irq(irq, dev); + pxa_set_cken(ssp_info[dev->port-1].clock, 0); + if (dev->irq) + free_irq(dev->irq, dev); release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c); + use_count[dev->port - 1]--; + up(&sem); } EXPORT_SYMBOL(ssp_write_word); @@ -317,3 +307,9 @@ EXPORT_SYMBOL(ssp_restore_state); EXPORT_SYMBOL(ssp_init); EXPORT_SYMBOL(ssp_exit); +EXPORT_SYMBOL(ssp_config); + +MODULE_DESCRIPTION("PXA SSP driver"); +MODULE_AUTHOR("Liam Girdwood"); +MODULE_LICENSE("GPL"); + diff -wur linux-2.6.10/arch/arm/mach-pxa/time.c linux-2.6.10-lab/arch/arm/mach-pxa/time.c --- linux-2.6.10/arch/arm/mach-pxa/time.c 2004-12-24 16:34:44.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/mach-pxa/time.c 2007-10-04 19:10:15.000000000 -0400 @@ -29,6 +29,9 @@ #include #include +#if defined(CONFIG_ARCH_FIONA) +#include +#endif static inline unsigned long pxa_get_rtc_time(void) { @@ -75,6 +78,10 @@ { int next_match; +#if defined(CONFIG_ARCH_FIONA) + boot_globals_t *bg; +#endif + write_seqlock(&xtime_lock); /* Loop until we get ahead of the free running timer. @@ -98,6 +105,16 @@ next_match = (OSMR0 += LATCH); } while( (signed long)(next_match - OSCR) <= 8 ); +#if defined(CONFIG_ARCH_FIONA) + bg = get_boot_globals(); + if (bg != NULL) { + bg_in_use_t *bd = &bg->globals; + + bd->saved_rtc = RCNR; + bd->saved_rtc_checksum = ~bd->saved_rtc; + } +#endif + write_sequnlock(&xtime_lock); return IRQ_HANDLED; diff -wur linux-2.6.10/arch/arm/mm/consistent.c linux-2.6.10-lab/arch/arm/mm/consistent.c --- linux-2.6.10/arch/arm/mm/consistent.c 2004-12-24 16:35:24.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/mm/consistent.c 2007-10-04 19:10:15.000000000 -0400 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mm/consistent.c * - * Copyright (C) 2000-2002 Russell King + * Copyright (C) 2000-2004 Russell King * * 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 @@ -65,6 +65,7 @@ struct list_head vm_list; unsigned long vm_start; unsigned long vm_end; + struct page *vm_pages; }; static struct vm_region consistent_head = { @@ -206,6 +207,8 @@ pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start); struct page *end = page + (1 << order); + c->vm_pages = page; + /* * Set the "dma handle" */ @@ -215,6 +218,9 @@ BUG_ON(!pte_none(*pte)); set_page_count(page, 1); + /* + * x86 does not mark the pages reserved... + */ SetPageReserved(page); set_pte(pte, mk_pte(page, prot)); page++; @@ -264,6 +270,53 @@ } EXPORT_SYMBOL(dma_alloc_writecombine); +static int dma_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size) +{ + unsigned long flags, user_size, kern_size; + struct vm_region *c; + int ret = -ENXIO; + + user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + + spin_lock_irqsave(&consistent_lock, flags); + c = vm_region_find(&consistent_head, (unsigned long)cpu_addr); + spin_unlock_irqrestore(&consistent_lock, flags); + + if (c) { + unsigned long off = vma->vm_pgoff; + + kern_size = (c->vm_end - c->vm_start) >> PAGE_SHIFT; + + if (off < kern_size && + user_size <= (kern_size - off)) { + vma->vm_flags |= VM_RESERVED; + ret = remap_pfn_range(vma, vma->vm_start, + page_to_pfn(c->vm_pages) + off, + user_size << PAGE_SHIFT, + vma->vm_page_prot); + } + } + + return ret; +} + +int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size) +{ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + return dma_mmap(dev, vma, cpu_addr, dma_addr, size); +} +EXPORT_SYMBOL(dma_mmap_coherent); + +int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size) +{ + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + return dma_mmap(dev, vma, cpu_addr, dma_addr, size); +} +EXPORT_SYMBOL(dma_mmap_writecombine); + /* * free a page as defined by the above mapping. */ @@ -300,6 +353,10 @@ if (pfn_valid(pfn)) { struct page *page = pfn_to_page(pfn); + + /* + * x86 does not mark the pages reserved... + */ ClearPageReserved(page); __free_page(page); diff -wur linux-2.6.10/arch/arm/mm/proc-xscale.S linux-2.6.10-lab/arch/arm/mm/proc-xscale.S --- linux-2.6.10/arch/arm/mm/proc-xscale.S 2004-12-24 16:35:25.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/mm/proc-xscale.S 2007-10-04 19:10:15.000000000 -0400 @@ -580,11 +580,62 @@ movne r2, #0 @ no -> fault str r2, [r0] @ hardware version + + @ We try to map 64K page entries when possible. + @ We do that for kernel space only since the usage pattern from + @ the setting of VM area is quite simple. User space is not worth + @ the implied complexity because of ever randomly changing PTEs + @ (page aging, swapout, etc) requiring constant coherency checks. + @ Since PTEs are usually set in increasing order, we test the + @ possibility for a large page only when given the last PTE of a + @ 64K boundary. + tsteq r1, #L_PTE_USER + andeq r1, r0, #(15 << 2) + teqeq r1, #(15 << 2) + beq 1f + mov ip, #0 mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer mov pc, lr + @ See if we have 16 identical PTEs but with consecutive base addresses +1: bic r3, r2, #0x0000f000 + mov r1, #0x0000f000 +2: eor r2, r2, r3 + teq r2, r1 + bne 4f + subs r1, r1, #0x00001000 + ldr r2, [r0, #-4]! + bne 2b + eors r2, r2, r3 + bne 4f + + @ Now create our LARGE PTE from the current EXT one. + bic r3, r3, #PTE_TYPE_MASK + orr r3, r3, #PTE_TYPE_LARGE + and r2, r3, #0x30 @ EXT_AP --> LARGE_AP0 + orr r2, r2, r2, lsl #2 @ add LARGE_AP1 + orr r2, r2, r2, lsl #4 @ add LARGE_AP3 + LARGE_AP2 + and r1, r3, #0x3c0 @ EXT_TEX + bic r3, r3, #0x3c0 + orr r2, r2, r1, lsl #(12 - 6) @ --> LARGE_TEX + orr r2, r2, r3 @ add remaining bits + + @ then put it in the pagetable + mov r3, r2 +3: strd r2, [r0], #8 + tst r0, #(15 << 2) + bne 3b + + @ Then sync the 2 corresponding cache lines + sub r0, r0, #(16 << 2) + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line +4: orr r0, r0, #(15 << 2) + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + mov ip, #0 + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr .ltorg diff -wur linux-2.6.10/arch/arm/tools/mach-types linux-2.6.10-lab/arch/arm/tools/mach-types --- linux-2.6.10/arch/arm/tools/mach-types 2004-12-24 16:34:45.000000000 -0500 +++ linux-2.6.10-lab/arch/arm/tools/mach-types 2007-10-04 19:10:14.000000000 -0400 @@ -381,7 +381,7 @@ spearhead ARCH_SPEARHEAD SPEARHEAD 370 pantera ARCH_PANTERA PANTERA 371 prayoglite ARCH_PRAYOGLITE PRAYOGLITE 372 -gumstik ARCH_GUMSTIK GUMSTIK 373 +gumstix ARCH_GUMSTIX GUMSTIX 373 rcube ARCH_RCUBE RCUBE 374 rea_olv ARCH_REA_OLV REA_OLV 375 pxa_iphone ARCH_PXA_IPHONE PXA_IPHONE 376 @@ -634,3 +634,4 @@ cm4008 MACH_CM4008 CM4008 624 p2001 MACH_P2001 P2001 625 twister MACH_TWISTER TWISTER 626 +fiona ARCH_FIONA FIONA 627 diff -wur linux-2.6.10/drivers/Makefile linux-2.6.10-lab/drivers/Makefile --- linux-2.6.10/drivers/Makefile 2004-12-24 16:36:00.000000000 -0500 +++ linux-2.6.10-lab/drivers/Makefile 2007-10-04 19:10:40.000000000 -0400 @@ -5,17 +5,17 @@ # Rewritten to use lists instead of if-statements. # -obj-$(CONFIG_PCI) += pci/ -obj-$(CONFIG_PARISC) += parisc/ +# obj-$(CONFIG_PCI) += pci/ +# obj-$(CONFIG_PARISC) += parisc/ obj-y += video/ -obj-$(CONFIG_ACPI_BOOT) += acpi/ +# obj-$(CONFIG_ACPI_BOOT) += acpi/ # PnP must come after ACPI since it will eventually need to check if acpi # was used and do nothing if so -obj-$(CONFIG_PNP) += pnp/ +# obj-$(CONFIG_PNP) += pnp/ # char/ comes before serial/ etc so that the VT console is the boot-time # default. -obj-y += char/ +obj-y += char/ char/ppoke/ # i810fb and intelfb depend on char/agp/ obj-$(CONFIG_FB_I810) += video/i810/ @@ -25,38 +25,41 @@ # serial drivers start registering their serio ports obj-$(CONFIG_SERIO) += input/serio/ obj-y += serial/ -obj-$(CONFIG_PARPORT) += parport/ -obj-y += base/ block/ misc/ net/ media/ -obj-$(CONFIG_NUBUS) += nubus/ -obj-$(CONFIG_ATM) += atm/ -obj-$(CONFIG_PPC_PMAC) += macintosh/ -obj-$(CONFIG_IDE) += ide/ -obj-$(CONFIG_FC4) += fc4/ +# obj-$(CONFIG_PARPORT) += parport/ +# obj-y += base/ block/ misc/ net/ media/ +obj-y += base/ block/ misc/ net/ +# obj-$(CONFIG_NUBUS) += nubus/ +# obj-$(CONFIG_ATM) += atm/ +# obj-$(CONFIG_PPC_PMAC) += macintosh/ +# obj-$(CONFIG_IDE) += ide/ +# obj-$(CONFIG_FC4) += fc4/ obj-$(CONFIG_SCSI) += scsi/ -obj-$(CONFIG_FUSION) += message/ -obj-$(CONFIG_IEEE1394) += ieee1394/ +# obj-$(CONFIG_FUSION) += message/ +# obj-$(CONFIG_IEEE1394) += ieee1394/ obj-y += cdrom/ obj-$(CONFIG_MTD) += mtd/ +obj-$(CONFIG_RFS_XSR) += xsr/ obj-$(CONFIG_PCCARD) += pcmcia/ -obj-$(CONFIG_DIO) += dio/ -obj-$(CONFIG_SBUS) += sbus/ -obj-$(CONFIG_ZORRO) += zorro/ -obj-$(CONFIG_MAC) += macintosh/ +# obj-$(CONFIG_DIO) += dio/ +# obj-$(CONFIG_SBUS) += sbus/ +# obj-$(CONFIG_ZORRO) += zorro/ +# obj-$(CONFIG_MAC) += macintosh/ obj-$(CONFIG_PARIDE) += block/paride/ -obj-$(CONFIG_TC) += tc/ +# obj-$(CONFIG_TC) += tc/ obj-$(CONFIG_USB) += usb/ obj-$(CONFIG_USB_GADGET) += usb/gadget/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_GAMEPORT) += input/gameport/ -obj-$(CONFIG_I2O) += message/ +# obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_I2C) += i2c/ -obj-$(CONFIG_W1) += w1/ -obj-$(CONFIG_PHONE) += telephony/ -obj-$(CONFIG_MD) += md/ -obj-$(CONFIG_BT) += bluetooth/ -obj-$(CONFIG_ISDN) += isdn/ -obj-$(CONFIG_MCA) += mca/ -obj-$(CONFIG_EISA) += eisa/ +# obj-$(CONFIG_W1) += w1/ +# obj-$(CONFIG_PHONE) += telephony/ +# obj-$(CONFIG_MD) += md/ +# obj-$(CONFIG_BT) += bluetooth/ +# obj-$(CONFIG_ISDN) += isdn/ +# obj-$(CONFIG_MCA) += mca/ +# obj-$(CONFIG_EISA) += eisa/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_MMC) += mmc/ +obj-$(CONFIG_PROC_GPIO) += gpio/ obj-y += firmware/ diff -wur linux-2.6.10/drivers/base/power/resume.c linux-2.6.10-lab/drivers/base/power/resume.c --- linux-2.6.10/drivers/base/power/resume.c 2004-12-24 16:35:24.000000000 -0500 +++ linux-2.6.10-lab/drivers/base/power/resume.c 2007-10-04 19:10:37.000000000 -0400 @@ -9,8 +9,10 @@ */ #include +#include #include "power.h" + extern int sysdev_resume(void); @@ -27,10 +29,45 @@ return 0; } +#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_ARCH_FIONA) + +#include +#include +static void fdputs(char *s) +{ + int size = 0; + int x = 0, wait = 0; + char *cur = s; + + //return; + if (s == NULL) + return; + size = strlen(s); + + // Print the string, waiting for each character to shift out before + // writing the next one... + for (x=0; x 10) { + STTHR = '^'; + return; + } + } + } +} +#endif void dpm_resume(void) { +#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_ARCH_FIONA) + char theStr[255]; + theStr[0] = '\0'; +#endif + down(&dpm_list_sem); while(!list_empty(&dpm_off)) { struct list_head * entry = dpm_off.next; @@ -42,7 +79,25 @@ up(&dpm_list_sem); if (!dev->power.prev_state) + { +#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_ARCH_FIONA) + if ((dev->driver) && (dev->driver->name)) { + sprintf(theStr,"Resuming device: %s\n",dev->driver->name); + fdputs(theStr); + } + else { + sprintf(theStr,"Resuming device no-name...\n"); + fdputs(theStr); + } +#endif resume_device(dev); + } +#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_ARCH_FIONA) + else { + sprintf(theStr,"Did not resume device %s - power.prev_state (%d) not zero\n",dev->driver->name,dev->power.prev_state); + fdputs(theStr); + } +#endif down(&dpm_list_sem); put_device(dev); } diff -wur linux-2.6.10/drivers/block/Kconfig linux-2.6.10-lab/drivers/block/Kconfig --- linux-2.6.10/drivers/block/Kconfig 2004-12-24 16:34:26.000000000 -0500 +++ linux-2.6.10-lab/drivers/block/Kconfig 2007-10-04 19:10:29.000000000 -0400 @@ -425,7 +425,7 @@ this option is dangerous unless the CD-RW media is known good, as we don't do deferred write error handling yet. -source "drivers/s390/block/Kconfig" +# source "drivers/s390/block/Kconfig" source "drivers/block/Kconfig.iosched" diff -wur linux-2.6.10/drivers/char/Kconfig linux-2.6.10-lab/drivers/char/Kconfig --- linux-2.6.10/drivers/char/Kconfig 2004-12-24 16:33:49.000000000 -0500 +++ linux-2.6.10-lab/drivers/char/Kconfig 2007-10-04 19:10:40.000000000 -0400 @@ -600,6 +600,8 @@ source "drivers/char/watchdog/Kconfig" +source "drivers/char/ioc/Kconfig" + config DS1620 tristate "NetWinder thermometer support" depends on ARCH_NETWINDER @@ -730,6 +732,8 @@ To compile this driver as a module, choose M here: the module will be called rtc. + + config SGI_DS1286 tristate "SGI DS1286 RTC support" depends on SGI_IP22 @@ -805,6 +809,10 @@ This option enables support for the LCD display and buttons found on Cobalt systems through a misc device. +config SA1100_RTC + tristate "SA1100/PXA2xx Real Time Clock" + depends on ARCH_SA1100 || ARCH_PXA + config DTLK tristate "Double Talk PC internal speech card support" help diff -wur linux-2.6.10/drivers/char/Makefile linux-2.6.10-lab/drivers/char/Makefile --- linux-2.6.10/drivers/char/Makefile 2004-12-24 16:35:29.000000000 -0500 +++ linux-2.6.10-lab/drivers/char/Makefile 2007-10-04 19:10:40.000000000 -0400 @@ -53,6 +53,8 @@ obj-$(CONFIG_PRINTER) += lp.o obj-$(CONFIG_TIPAR) += tipar.o +obj-$(CONFIG_IOC) += ioc/ + obj-$(CONFIG_DTLK) += dtlk.o obj-$(CONFIG_R3964) += n_r3964.o obj-$(CONFIG_APPLICOM) += applicom.o @@ -61,6 +63,7 @@ obj-$(CONFIG_HPET) += hpet.o obj-$(CONFIG_GEN_RTC) += genrtc.o obj-$(CONFIG_EFI_RTC) += efirtc.o +obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o obj-$(CONFIG_SGI_DS1286) += ds1286.o obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o obj-$(CONFIG_DS1302) += ds1302.o diff -wur linux-2.6.10/drivers/char/watchdog/sa1100_wdt.c linux-2.6.10-lab/drivers/char/watchdog/sa1100_wdt.c --- linux-2.6.10/drivers/char/watchdog/sa1100_wdt.c 2004-12-24 16:34:45.000000000 -0500 +++ linux-2.6.10-lab/drivers/char/watchdog/sa1100_wdt.c 2007-10-04 19:10:38.000000000 -0400 @@ -16,8 +16,11 @@ * (c) Copyright 2000 Oleg Drokin * * 27/11/2000 Initial release + * + * + * Lab126 changes copyright (C) 2007 Lab126, Inc. */ -#include + #include #include #include @@ -35,17 +38,73 @@ #include #include -#define OSCR_FREQ 3686400 -#define SA1100_CLOSE_MAGIC (0x5afc4453) +#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM) +#include +#endif + +#define OSCR_FREQ CLOCK_TICK_RATE static unsigned long sa1100wdt_users; -static int expect_close; static int pre_margin; static int boot_status; -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; + +#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM) +static wait_queue_head_t pm_event_wq; +static pid_t pm_handler_thread_pid = 0; +static DECLARE_COMPLETION(pm_handler_thread_exited); + +static void init_wdt(void) +{ + OSMR3 = OSCR + pre_margin; + OSSR = OSSR_M3; + OWER = OWER_WME; + OIER |= OIER_E3; +} + +static int pm_handler_thread(void *unused) +{ + daemonize("wdtpmd"); + allow_signal(SIGKILL); + + while (1) { + wait_event_interruptible(pm_event_wq, 0); + + if (current->flags & PF_FREEZE) { + refrigerator(PF_FREEZE); + + init_wdt(); + } + + if (signal_pending(current)) { + break; + } + } + + complete_and_exit(&pm_handler_thread_exited, 0); + + return 0; +} + +static void start_pm_thread(void) +{ + init_waitqueue_head(&pm_event_wq); + + pm_handler_thread_pid = kernel_thread(pm_handler_thread, NULL, CLONE_KERNEL); +} + +static void +stop_pm_thread( + void) +{ + int ret; + + if (pm_handler_thread_pid > 0) { + ret = kill_proc(pm_handler_thread_pid, SIGKILL, 1); + if (ret == 0) { + wait_for_completion(&pm_handler_thread_exited); + } + } +} #endif /* @@ -58,63 +117,46 @@ return -EBUSY; /* Activate SA1100 Watchdog timer */ +#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM) + init_wdt(); +#else OSMR3 = OSCR + pre_margin; OSSR = OSSR_M3; OWER = OWER_WME; OIER |= OIER_E3; +#endif + return 0; } /* - * Shut off the timer. - * Lock it in if it's a module and we defined ...NOWAYOUT - * Oddly, the watchdog can only be enabled, but we can turn off - * the interrupt, which appears to prevent the watchdog timing out. + * The watchdog cannot be disabled. + * + * Previous comments suggested that turning off the interrupt by + * clearing OIER[E3] would prevent the watchdog timing out but this + * does not appear to be true (at least on the PXA255). */ static int sa1100dog_release(struct inode *inode, struct file *file) { - OSMR3 = OSCR + pre_margin; - - if (expect_close == SA1100_CLOSE_MAGIC) { - OIER &= ~OIER_E3; - } else { - printk(KERN_CRIT "WATCHDOG: WDT device closed unexpectedly. WDT will not stop!\n"); - } + printk(KERN_CRIT "WATCHDOG: Device closed - timer will not stop\n"); clear_bit(1, &sa1100wdt_users); - expect_close = 0; return 0; } -static ssize_t sa1100dog_write(struct file *file, const char *data, size_t len, loff_t *ppos) +static ssize_t sa1100dog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { - if (len) { - if (!nowayout) { - size_t i; - - expect_close = 0; - - for (i = 0; i != len; i++) { - char c; - - if (get_user(c, data + i)) - return -EFAULT; - if (c == 'V') - expect_close = SA1100_CLOSE_MAGIC; - } - } + if (len) /* Refresh OSMR3 timer. */ OSMR3 = OSCR + pre_margin; - } return len; } static struct watchdog_info ident = { - .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | - WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, - .identity = "SA1100 Watchdog", + .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + .identity = "SA1100/PXA255 Watchdog", }; static int sa1100dog_ioctl(struct inode *inode, struct file *file, @@ -122,23 +164,25 @@ { int ret = -ENOIOCTLCMD; int time; + void __user *argp = (void __user *)arg; + int __user *p = argp; switch (cmd) { case WDIOC_GETSUPPORT: - ret = copy_to_user((struct watchdog_info *)arg, &ident, + ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; break; case WDIOC_GETSTATUS: - ret = put_user(0, (int *)arg); + ret = put_user(0, p); break; case WDIOC_GETBOOTSTATUS: - ret = put_user(boot_status, (int *)arg); + ret = put_user(boot_status, p); break; case WDIOC_SETTIMEOUT: - ret = get_user(time, (int *)arg); + ret = get_user(time, p); if (ret) break; @@ -152,7 +196,7 @@ /*fall through*/ case WDIOC_GETTIMEOUT: - ret = put_user(pre_margin / OSCR_FREQ, (int *)arg); + ret = put_user(pre_margin / OSCR_FREQ, p); break; case WDIOC_KEEPALIVE: @@ -163,7 +207,7 @@ return ret; } -static struct file_operations sa1100dog_fops = +static const struct file_operations sa1100dog_fops = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -176,8 +220,8 @@ static struct miscdevice sa1100dog_miscdev = { .minor = WATCHDOG_MINOR, - .name = "SA1100/PXA2xx watchdog", - .fops = &sa1100dog_fops, + .name = "watchdog", + .fops = (struct file_operations *)&sa1100dog_fops, }; static int margin __initdata = 60; /* (secs) Default is 1 minute */ @@ -186,6 +230,10 @@ { int ret; +#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM) + start_pm_thread(); +#endif + /* * Read the reset status, and save it for later. If * we suspend, RCSR will be cleared, and the watchdog @@ -198,12 +246,15 @@ if (ret == 0) printk("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n", margin); - return ret; } static void __exit sa1100dog_exit(void) { +#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM) + stop_pm_thread(); +#endif + misc_deregister(&sa1100dog_miscdev); } @@ -216,8 +267,5 @@ module_param(margin, int, 0); MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)"); -module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); - MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff -wur linux-2.6.10/drivers/cpufreq/Kconfig linux-2.6.10-lab/drivers/cpufreq/Kconfig --- linux-2.6.10/drivers/cpufreq/Kconfig 2004-12-24 16:35:28.000000000 -0500 +++ linux-2.6.10-lab/drivers/cpufreq/Kconfig 2007-10-04 19:10:37.000000000 -0400 @@ -13,9 +13,13 @@ If in doubt, say N. +if CPU_FREQ + +config CPU_FREQ_TABLE + def_tristate y + config CPU_FREQ_DEBUG bool "Enable CPUfreq debugging" - depends on CPU_FREQ help Say Y here to enable CPUfreq subsystem (including drivers) debugging. You will need to activate it via the kernel @@ -27,23 +31,29 @@ 2 to activate CPUfreq drivers debugging, and 4 to activate CPUfreq governor debugging -config CPU_FREQ_PROC_INTF - tristate "/proc/cpufreq interface (deprecated)" - depends on CPU_FREQ && PROC_FS - help - This enables the /proc/cpufreq interface for controlling - CPUFreq. Please note that it is recommended to use the sysfs - interface instead (which is built automatically). - - For details, take a look at . - - If in doubt, say N. +config CPU_FREQ_STAT + tristate "CPU frequency translation statistics" + select CPU_FREQ_TABLE + default y + help + This driver exports CPU frequency statistics information through sysfs + file system + +config CPU_FREQ_STAT_DETAILS + bool "CPU frequency translation statistics details" + depends on CPU_FREQ_STAT + help + This will show detail CPU frequency translation table in sysfs file + system + +# Note that it is not currently possible to set the other governors (such as ondemand) +# as the default, since if they fail to initialise, cpufreq will be +# left in an undefined state. choice prompt "Default CPUFreq governor" - depends on CPU_FREQ - default CPU_FREQ_DEFAULT_GOV_PERFORMANCE if !CPU_FREQ_SA1100 && !CPU_FREQ_SA1110 default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110 + default CPU_FREQ_DEFAULT_GOV_PERFORMANCE help This option sets which CPUFreq governor shall be loaded at startup. If in doubt, select 'performance'. @@ -69,7 +79,6 @@ config CPU_FREQ_GOV_PERFORMANCE tristate "'performance' governor" - depends on CPU_FREQ help This cpufreq governor sets the frequency statically to the highest available CPU frequency. @@ -78,7 +87,6 @@ config CPU_FREQ_GOV_POWERSAVE tristate "'powersave' governor" - depends on CPU_FREQ help This cpufreq governor sets the frequency statically to the lowest available CPU frequency. @@ -87,7 +95,6 @@ config CPU_FREQ_GOV_USERSPACE tristate "'userspace' governor for userspace frequency scaling" - depends on CPU_FREQ help Enable this cpufreq governor when you either want to set the CPU frequency manually or when an userspace program shall @@ -98,24 +105,8 @@ If in doubt, say Y. -config CPU_FREQ_24_API - bool "/proc/sys/cpu/ interface (2.4. / OLD)" - depends on CPU_FREQ_GOV_USERSPACE - depends on SYSCTL - help - This enables the /proc/sys/cpu/ sysctl interface for controlling - the CPUFreq,"userspace" governor. This is the same interface - as known from the 2.4.-kernel patches for CPUFreq, and offers - the same functionality as long as "userspace" is the - selected governor for the specified CPU. - - For details, take a look at . - - If in doubt, say N. - config CPU_FREQ_GOV_ONDEMAND tristate "'ondemand' cpufreq policy governor" - depends on CPU_FREQ help 'ondemand' - This driver adds a dynamic cpufreq policy governor. The governor does a periodic polling and @@ -127,3 +118,25 @@ For details, take a look at linux/Documentation/cpu-freq. If in doubt, say N. + +config CPU_FREQ_GOV_CONSERVATIVE + tristate "'conservative' cpufreq governor" + depends on CPU_FREQ + help + 'conservative' - this driver is rather similar to the 'ondemand' + governor both in its source code and its purpose, the difference is + its optimisation for better suitability in a battery powered + environment. The frequency is gracefully increased and decreased + rather than jumping to 100% when speed is required. + + If you have a desktop machine then you should really be considering + the 'ondemand' governor instead, however if you are using a laptop, + PDA or even an AMD64 based computer (due to the unacceptable + step-by-step latency issues between the minimum and maximum frequency + transitions in the CPU) you will probably want to use this governor. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + +endif # CPU_FREQ diff -wur linux-2.6.10/drivers/cpufreq/Makefile linux-2.6.10-lab/drivers/cpufreq/Makefile --- linux-2.6.10/drivers/cpufreq/Makefile 2004-12-24 16:35:49.000000000 -0500 +++ linux-2.6.10-lab/drivers/cpufreq/Makefile 2007-10-04 19:10:37.000000000 -0400 @@ -1,13 +1,15 @@ # CPUfreq core obj-$(CONFIG_CPU_FREQ) += cpufreq.o +# CPUfreq stats +obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o # CPUfreq governors obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o +obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o -obj-$(CONFIG_CPU_FREQ_PROC_INTF) += proc_intf.o diff -wur linux-2.6.10/drivers/cpufreq/cpufreq.c linux-2.6.10-lab/drivers/cpufreq/cpufreq.c --- linux-2.6.10/drivers/cpufreq/cpufreq.c 2004-12-24 16:34:26.000000000 -0500 +++ linux-2.6.10-lab/drivers/cpufreq/cpufreq.c 2007-10-04 19:10:37.000000000 -0400 @@ -33,7 +33,7 @@ */ static struct cpufreq_driver *cpufreq_driver; static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS]; -static spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED; +spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED; /* we keep a copy of all ->add'ed CPU's struct sys_device here; @@ -63,7 +63,7 @@ static LIST_HEAD(cpufreq_governor_list); static DECLARE_MUTEX (cpufreq_governor_sem); -static struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu) +struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu) { struct cpufreq_policy *data; unsigned long flags; @@ -102,12 +102,14 @@ err_out: return NULL; } +EXPORT_SYMBOL_GPL(cpufreq_cpu_get); -static void cpufreq_cpu_put(struct cpufreq_policy *data) +void cpufreq_cpu_put(struct cpufreq_policy *data) { kobject_put(&data->kobj); module_put(cpufreq_driver->owner); } +EXPORT_SYMBOL_GPL(cpufreq_cpu_put); /********************************************************************* @@ -128,7 +130,7 @@ * is set, and disabled upon cpufreq driver removal */ static unsigned int disable_ratelimit = 1; -static spinlock_t disable_ratelimit_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(disable_ratelimit_lock); static inline void cpufreq_debug_enable_ratelimit(void) { @@ -221,7 +223,7 @@ } if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) || - (val == CPUFREQ_RESUMECHANGE)) { + (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); dprintk("scaling loops_per_jiffy to %lu for frequency %u kHz\n", loops_per_jiffy, ci->new); } @@ -256,7 +258,7 @@ (likely(cpufreq_cpu_data[freqs->cpu]->cur)) && (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur))) { - printk(KERN_WARNING "Warning: CPU frequency is %u, " + dprintk(KERN_WARNING "Warning: CPU frequency is %u, " "cpufreq assumed %u kHz.\n", freqs->old, cpufreq_cpu_data[freqs->cpu]->cur); freqs->old = cpufreq_cpu_data[freqs->cpu]->cur; } @@ -285,7 +287,7 @@ /** * cpufreq_parse_governor - parse a governor string */ -int cpufreq_parse_governor (char *str_governor, unsigned int *policy, +static int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpufreq_governor **governor) { if (!cpufreq_driver) @@ -519,7 +521,7 @@ policy = cpufreq_cpu_get(policy->cpu); if (!policy) return -EINVAL; - ret = fattr->show ? fattr->show(policy,buf) : 0; + ret = fattr->show ? fattr->show(policy,buf) : -EIO; cpufreq_cpu_put(policy); return ret; } @@ -533,7 +535,7 @@ policy = cpufreq_cpu_get(policy->cpu); if (!policy) return -EINVAL; - ret = fattr->store ? fattr->store(policy,buf,count) : 0; + ret = fattr->store ? fattr->store(policy,buf,count) : -EIO; cpufreq_cpu_put(policy); return ret; } @@ -625,7 +627,7 @@ ret = kobject_register(&policy->kobj); if (ret) - goto err_out; + goto err_out_driver_exit; /* set up files for this cpu device */ drv_attr = cpufreq_driver->attr; @@ -671,6 +673,10 @@ kobject_unregister(&policy->kobj); wait_for_completion(&policy->kobj_unregister); +err_out_driver_exit: + if (cpufreq_driver->exit) + cpufreq_driver->exit(policy); + err_out: kfree(policy); @@ -763,8 +769,11 @@ spin_unlock_irqrestore(&cpufreq_driver_lock, flags); #endif + down(&data->lock); if (cpufreq_driver->target) __cpufreq_governor(data, CPUFREQ_GOV_STOP); + cpufreq_driver->target = NULL; + up(&data->lock); kobject_unregister(&data->kobj); @@ -809,7 +818,7 @@ { struct cpufreq_freqs freqs; - printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing " + dprintk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing " "core thinks of %u, is %u kHz.\n", old_freq, new_freq); freqs.cpu = cpu; @@ -861,11 +870,92 @@ /** + * cpufreq_suspend - let the low level driver prepare for suspend + */ + +static int cpufreq_suspend(struct sys_device * sysdev, u32 state) +{ + int cpu = sysdev->id; + unsigned int ret = 0; + unsigned int cur_freq = 0; + struct cpufreq_policy *cpu_policy; + + dprintk("resuming cpu %u\n", cpu); + + if (!cpu_online(cpu)) + return 0; + + /* we may be lax here as interrupts are off. Nonetheless + * we need to grab the correct cpu policy, as to check + * whether we really run on this CPU. + */ + + cpu_policy = cpufreq_cpu_get(cpu); + if (!cpu_policy) + return -EINVAL; + + /* only handle each CPU group once */ + if (unlikely(cpu_policy->cpu != cpu)) { + cpufreq_cpu_put(cpu_policy); + return 0; + } + + if (cpufreq_driver->suspend) { + ret = cpufreq_driver->suspend(cpu_policy, state); + if (ret) { + printk(KERN_ERR "cpufreq: suspend failed in ->suspend " + "step on CPU %u\n", cpu_policy->cpu); + cpufreq_cpu_put(cpu_policy); + return ret; + } + } + + + if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS) + goto out; + + if (cpufreq_driver->get) + cur_freq = cpufreq_driver->get(cpu_policy->cpu); + + if (!cur_freq || !cpu_policy->cur) { +#ifdef CPUFREQ_PM_ERR + printk(KERN_ERR "cpufreq: suspend failed to assert current " + "frequency is what timing core thinks it is.\n"); +#endif + goto out; + } + + if (unlikely(cur_freq != cpu_policy->cur)) { + struct cpufreq_freqs freqs; + + if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN)) + dprintk(KERN_DEBUG "Warning: CPU frequency is %u, " + "cpufreq assumed %u kHz.\n", + cur_freq, cpu_policy->cur); + + freqs.cpu = cpu; + freqs.old = cpu_policy->cur; + freqs.new = cur_freq; + + notifier_call_chain(&cpufreq_transition_notifier_list, + CPUFREQ_SUSPENDCHANGE, &freqs); + adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs); + + cpu_policy->cur = cur_freq; + } + + out: + cpufreq_cpu_put(cpu_policy); + return 0; +} + +/** * cpufreq_resume - restore proper CPU frequency handling after resume * * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) * 2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync - * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are restored. + * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are + * restored. */ static int cpufreq_resume(struct sys_device * sysdev) { @@ -893,6 +983,16 @@ return 0; } + if (cpufreq_driver->resume) { + ret = cpufreq_driver->resume(cpu_policy); + if (ret) { + printk(KERN_ERR "cpufreq: resume failed in ->resume " + "step on CPU %u\n", cpu_policy->cpu); + cpufreq_cpu_put(cpu_policy); + return ret; + } + } + if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { unsigned int cur_freq = 0; @@ -900,21 +1000,28 @@ cur_freq = cpufreq_driver->get(cpu_policy->cpu); if (!cur_freq || !cpu_policy->cur) { - printk(KERN_ERR "cpufreq: resume failed to assert current frequency is what timing core thinks it is.\n"); +#ifdef CPUFREQ_PM_ERR + printk(KERN_ERR "cpufreq: resume failed to assert " + "current frequency is what timing core " + "thinks it is.\n"); +#endif goto out; } if (unlikely(cur_freq != cpu_policy->cur)) { struct cpufreq_freqs freqs; - printk(KERN_WARNING "Warning: CPU frequency is %u, " - "cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur); + if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN)) + dprintk(KERN_WARNING "Warning: CPU frequency" + "is %u, cpufreq assumed %u kHz.\n", + cur_freq, cpu_policy->cur); freqs.cpu = cpu; freqs.old = cpu_policy->cur; freqs.new = cur_freq; - notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs); + notifier_call_chain(&cpufreq_transition_notifier_list, + CPUFREQ_RESUMECHANGE, &freqs); adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); cpu_policy->cur = cur_freq; @@ -930,6 +1037,7 @@ static struct sysdev_driver cpufreq_sysdev_driver = { .add = cpufreq_add_dev, .remove = cpufreq_remove_dev, + .suspend = cpufreq_suspend, .resume = cpufreq_resume, }; @@ -1018,7 +1126,7 @@ lock_cpu_hotplug(); dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu, target_freq, relation); - if (cpu_online(policy->cpu)) + if (cpu_online(policy->cpu) && cpufreq_driver->target) retval = cpufreq_driver->target(policy, target_freq, relation); unlock_cpu_hotplug(); return retval; @@ -1030,7 +1138,7 @@ unsigned int target_freq, unsigned int relation) { - unsigned int ret; + int ret; policy = cpufreq_cpu_get(policy->cpu); if (!policy) @@ -1051,7 +1159,7 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) { - int ret = -EINVAL; + int ret; if (!try_module_get(policy->governor->owner)) return -EINVAL; diff -wur linux-2.6.10/drivers/cpufreq/cpufreq_ondemand.c linux-2.6.10-lab/drivers/cpufreq/cpufreq_ondemand.c --- linux-2.6.10/drivers/cpufreq/cpufreq_ondemand.c 2004-12-24 16:35:29.000000000 -0500 +++ linux-2.6.10-lab/drivers/cpufreq/cpufreq_ondemand.c 2007-10-04 19:10:37.000000000 -0400 @@ -34,13 +34,9 @@ */ #define DEF_FREQUENCY_UP_THRESHOLD (80) -#define MIN_FREQUENCY_UP_THRESHOLD (0) +#define MIN_FREQUENCY_UP_THRESHOLD (11) #define MAX_FREQUENCY_UP_THRESHOLD (100) -#define DEF_FREQUENCY_DOWN_THRESHOLD (20) -#define MIN_FREQUENCY_DOWN_THRESHOLD (0) -#define MAX_FREQUENCY_DOWN_THRESHOLD (100) - /* * The polling frequency of this governor depends on the capability of * the processor. Default polling frequency is 1000 times the transition @@ -55,9 +51,9 @@ #define MIN_SAMPLING_RATE (def_sampling_rate / 2) #define MAX_SAMPLING_RATE (500 * def_sampling_rate) #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) -#define DEF_SAMPLING_DOWN_FACTOR (10) +#define DEF_SAMPLING_DOWN_FACTOR (1) +#define MAX_SAMPLING_DOWN_FACTOR (10) #define TRANSITION_LATENCY_LIMIT (10 * 1000) -#define sampling_rate_in_HZ(x) (((x * HZ) < (1000 * 1000))?1:((x * HZ) / (1000 * 1000))) static void do_dbs_timer(void *data); @@ -78,15 +74,23 @@ unsigned int sampling_rate; unsigned int sampling_down_factor; unsigned int up_threshold; - unsigned int down_threshold; + unsigned int ignore_nice; }; static struct dbs_tuners dbs_tuners_ins = { .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, - .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD, .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, }; +static inline unsigned int get_cpu_idle_time(unsigned int cpu) +{ + return kstat_cpu(cpu).cpustat.idle + + kstat_cpu(cpu).cpustat.iowait + + ( !dbs_tuners_ins.ignore_nice ? + kstat_cpu(cpu).cpustat.nice : + 0); +} + /************************** sysfs interface ************************/ static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf) { @@ -115,7 +119,7 @@ show_one(sampling_rate, sampling_rate); show_one(sampling_down_factor, sampling_down_factor); show_one(up_threshold, up_threshold); -show_one(down_threshold, down_threshold); +show_one(ignore_nice, ignore_nice); static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused, const char *buf, size_t count) @@ -126,6 +130,9 @@ if (ret != 1 ) return -EINVAL; + if (input > MAX_SAMPLING_DOWN_FACTOR || input < 1) + return -EINVAL; + down(&dbs_sem); dbs_tuners_ins.sampling_down_factor = input; up(&dbs_sem); @@ -161,8 +168,7 @@ down(&dbs_sem); if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || - input < MIN_FREQUENCY_UP_THRESHOLD || - input <= dbs_tuners_ins.down_threshold) { + input < MIN_FREQUENCY_UP_THRESHOLD) { up(&dbs_sem); return -EINVAL; } @@ -173,22 +179,35 @@ return count; } -static ssize_t store_down_threshold(struct cpufreq_policy *unused, +static ssize_t store_ignore_nice(struct cpufreq_policy *policy, const char *buf, size_t count) { unsigned int input; int ret; + + unsigned int j; + ret = sscanf (buf, "%u", &input); + if ( ret != 1 ) + return -EINVAL; + + if ( input > 1 ) + input = 1; down(&dbs_sem); - if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD || - input < MIN_FREQUENCY_DOWN_THRESHOLD || - input >= dbs_tuners_ins.up_threshold) { + if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */ up(&dbs_sem); - return -EINVAL; + return count; } + dbs_tuners_ins.ignore_nice = input; - dbs_tuners_ins.down_threshold = input; + /* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */ + for_each_online_cpu(j) { + struct cpu_dbs_info_s *j_dbs_info; + j_dbs_info = &per_cpu(cpu_dbs_info, j); + j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j); + j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up; + } up(&dbs_sem); return count; @@ -201,7 +220,7 @@ define_one_rw(sampling_rate); define_one_rw(sampling_down_factor); define_one_rw(up_threshold); -define_one_rw(down_threshold); +define_one_rw(ignore_nice); static struct attribute * dbs_attributes[] = { &sampling_rate_max.attr, @@ -209,7 +228,7 @@ &sampling_rate.attr, &sampling_down_factor.attr, &up_threshold.attr, - &down_threshold.attr, + &ignore_nice.attr, NULL }; @@ -222,48 +241,68 @@ static void dbs_check_cpu(int cpu) { - unsigned int idle_ticks, up_idle_ticks, down_idle_ticks; - unsigned int total_idle_ticks; - unsigned int freq_down_step; + unsigned int idle_ticks, up_idle_ticks, total_ticks; + unsigned int freq_next; unsigned int freq_down_sampling_rate; static int down_skip[NR_CPUS]; struct cpu_dbs_info_s *this_dbs_info; + struct cpufreq_policy *policy; + unsigned int j; + this_dbs_info = &per_cpu(cpu_dbs_info, cpu); if (!this_dbs_info->enable) return; + policy = this_dbs_info->cur_policy; /* - * The default safe range is 20% to 80% - * Every sampling_rate, we check - * - If current idle time is less than 20%, then we try to - * increase frequency - * Every sampling_rate*sampling_down_factor, we check - * - If current idle time is more than 80%, then we try to - * decrease frequency + * Every sampling_rate, we check, if current idle time is less + * than 20% (default), then we try to increase frequency + * Every sampling_rate*sampling_down_factor, we look for a the lowest + * frequency which can sustain the load while keeping idle time over + * 30%. If such a frequency exist, we try to decrease to this frequency. * * Any frequency increase takes it to the maximum frequency. * Frequency reduction happens at minimum steps of - * 5% of max_frequency + * 5% (default) of current frequency */ + /* Check for frequency increase */ - total_idle_ticks = kstat_cpu(cpu).cpustat.idle + - kstat_cpu(cpu).cpustat.iowait; - idle_ticks = total_idle_ticks - - this_dbs_info->prev_cpu_idle_up; - this_dbs_info->prev_cpu_idle_up = total_idle_ticks; + idle_ticks = UINT_MAX; + for_each_cpu_mask(j, policy->cpus) { + unsigned int tmp_idle_ticks, total_idle_ticks; + struct cpu_dbs_info_s *j_dbs_info; + + j_dbs_info = &per_cpu(cpu_dbs_info, j); + total_idle_ticks = get_cpu_idle_time(j); + tmp_idle_ticks = total_idle_ticks - + j_dbs_info->prev_cpu_idle_up; + j_dbs_info->prev_cpu_idle_up = total_idle_ticks; + + if (tmp_idle_ticks < idle_ticks) + idle_ticks = tmp_idle_ticks; + } /* Scale idle ticks by 100 and compare with up and down ticks */ idle_ticks *= 100; up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) * - sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate); + usecs_to_jiffies(dbs_tuners_ins.sampling_rate); if (idle_ticks < up_idle_ticks) { - __cpufreq_driver_target(this_dbs_info->cur_policy, - this_dbs_info->cur_policy->max, - CPUFREQ_RELATION_H); down_skip[cpu] = 0; - this_dbs_info->prev_cpu_idle_down = total_idle_ticks; + for_each_cpu_mask(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + + j_dbs_info = &per_cpu(cpu_dbs_info, j); + j_dbs_info->prev_cpu_idle_down = + j_dbs_info->prev_cpu_idle_up; + } + /* if we are already at full speed then break out early */ + if (policy->cur == policy->max) + return; + + __cpufreq_driver_target(policy, policy->max, + CPUFREQ_RELATION_H); return; } @@ -272,48 +311,61 @@ if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor) return; - idle_ticks = total_idle_ticks - - this_dbs_info->prev_cpu_idle_down; - /* Scale idle ticks by 100 and compare with up and down ticks */ - idle_ticks *= 100; + idle_ticks = UINT_MAX; + for_each_cpu_mask(j, policy->cpus) { + unsigned int tmp_idle_ticks, total_idle_ticks; + struct cpu_dbs_info_s *j_dbs_info; + + j_dbs_info = &per_cpu(cpu_dbs_info, j); + /* Check for frequency decrease */ + total_idle_ticks = j_dbs_info->prev_cpu_idle_up; + tmp_idle_ticks = total_idle_ticks - + j_dbs_info->prev_cpu_idle_down; + j_dbs_info->prev_cpu_idle_down = total_idle_ticks; + + if (tmp_idle_ticks < idle_ticks) + idle_ticks = tmp_idle_ticks; + } + down_skip[cpu] = 0; - this_dbs_info->prev_cpu_idle_down = total_idle_ticks; + /* if we cannot reduce the frequency anymore, break out early */ + if (policy->cur == policy->min) + return; + /* Compute how many ticks there are between two measurements */ freq_down_sampling_rate = dbs_tuners_ins.sampling_rate * dbs_tuners_ins.sampling_down_factor; - down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) * - sampling_rate_in_HZ(freq_down_sampling_rate); - - if (idle_ticks > down_idle_ticks ) { - freq_down_step = (5 * this_dbs_info->cur_policy->max) / 100; + total_ticks = usecs_to_jiffies(freq_down_sampling_rate); - /* max freq cannot be less than 100. But who knows.... */ - if (unlikely(freq_down_step == 0)) - freq_down_step = 5; + /* + * The optimal frequency is the frequency that is the lowest that + * can support the current CPU usage without triggering the up + * policy. To be safe, we focus 10 points under the threshold. + */ + freq_next = ((total_ticks - idle_ticks) * 100) / total_ticks; + freq_next = (freq_next * policy->cur) / + (dbs_tuners_ins.up_threshold - 10); - __cpufreq_driver_target(this_dbs_info->cur_policy, - this_dbs_info->cur_policy->cur - freq_down_step, - CPUFREQ_RELATION_H); - return; - } + if (freq_next <= ((policy->cur * 95) / 100)) + __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L); } static void do_dbs_timer(void *data) { int i; down(&dbs_sem); - for (i = 0; i < NR_CPUS; i++) - if (cpu_online(i)) + for_each_online_cpu(i) dbs_check_cpu(i); schedule_delayed_work(&dbs_work, - sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate)); + usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); up(&dbs_sem); } static inline void dbs_timer_init(void) { INIT_WORK(&dbs_work, do_dbs_timer, NULL); - schedule_work(&dbs_work); + schedule_delayed_work(&dbs_work, + usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); return; } @@ -328,6 +380,7 @@ { unsigned int cpu = policy->cpu; struct cpu_dbs_info_s *this_dbs_info; + unsigned int j; this_dbs_info = &per_cpu(cpu_dbs_info, cpu); @@ -344,14 +397,15 @@ break; down(&dbs_sem); - this_dbs_info->cur_policy = policy; - - this_dbs_info->prev_cpu_idle_up = - kstat_cpu(cpu).cpustat.idle + - kstat_cpu(cpu).cpustat.iowait; - this_dbs_info->prev_cpu_idle_down = - kstat_cpu(cpu).cpustat.idle + - kstat_cpu(cpu).cpustat.iowait; + for_each_cpu_mask(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + j_dbs_info = &per_cpu(cpu_dbs_info, j); + j_dbs_info->cur_policy = policy; + + j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j); + j_dbs_info->prev_cpu_idle_down + = j_dbs_info->prev_cpu_idle_up; + } this_dbs_info->enable = 1; sysfs_create_group(&policy->kobj, &dbs_attr_group); dbs_enable++; @@ -370,6 +424,7 @@ def_sampling_rate = (latency / 1000) * DEF_SAMPLING_RATE_LATENCY_MULTIPLIER; dbs_tuners_ins.sampling_rate = def_sampling_rate; + dbs_tuners_ins.ignore_nice = 0; dbs_timer_init(); } @@ -409,12 +464,11 @@ return 0; } -struct cpufreq_governor cpufreq_gov_dbs = { +static struct cpufreq_governor cpufreq_gov_dbs = { .name = "ondemand", .governor = cpufreq_governor_dbs, .owner = THIS_MODULE, }; -EXPORT_SYMBOL(cpufreq_gov_dbs); static int __init cpufreq_gov_dbs_init(void) { diff -wur linux-2.6.10/drivers/cpufreq/cpufreq_userspace.c linux-2.6.10-lab/drivers/cpufreq/cpufreq_userspace.c --- linux-2.6.10/drivers/cpufreq/cpufreq_userspace.c 2004-12-24 16:33:59.000000000 -0500 +++ linux-2.6.10-lab/drivers/cpufreq/cpufreq_userspace.c 2007-10-04 19:10:37.000000000 -0400 @@ -17,51 +17,13 @@ #include #include #include -#include #include -#include #include #include #include #include -#define CTL_CPU_VARS_SPEED_MAX(cpunr) { \ - .ctl_name = CPU_NR_FREQ_MAX, \ - .data = &cpu_max_freq[cpunr], \ - .procname = "speed-max", \ - .maxlen = sizeof(cpu_max_freq[cpunr]),\ - .mode = 0444, \ - .proc_handler = proc_dointvec, } - -#define CTL_CPU_VARS_SPEED_MIN(cpunr) { \ - .ctl_name = CPU_NR_FREQ_MIN, \ - .data = &cpu_min_freq[cpunr], \ - .procname = "speed-min", \ - .maxlen = sizeof(cpu_min_freq[cpunr]),\ - .mode = 0444, \ - .proc_handler = proc_dointvec, } - -#define CTL_CPU_VARS_SPEED(cpunr) { \ - .ctl_name = CPU_NR_FREQ, \ - .procname = "speed", \ - .mode = 0644, \ - .proc_handler = cpufreq_procctl, \ - .strategy = cpufreq_sysctl, \ - .extra1 = (void*) (cpunr), } - -#define CTL_TABLE_CPU_VARS(cpunr) static ctl_table ctl_cpu_vars_##cpunr[] = {\ - CTL_CPU_VARS_SPEED_MAX(cpunr), \ - CTL_CPU_VARS_SPEED_MIN(cpunr), \ - CTL_CPU_VARS_SPEED(cpunr), \ - { .ctl_name = 0, }, } - -/* the ctl_table entry for each CPU */ -#define CPU_ENUM(s) { \ - .ctl_name = (CPU_NR + s), \ - .procname = #s, \ - .mode = 0555, \ - .child = ctl_cpu_vars_##s } /** * A few values needed by the userspace governor @@ -96,17 +58,17 @@ /** - * _cpufreq_set - set the CPU frequency + * cpufreq_set - set the CPU frequency * @freq: target frequency in kHz * @cpu: CPU for which the frequency is to be set * * Sets the CPU frequency to freq. */ -static int _cpufreq_set(unsigned int freq, unsigned int cpu) +static int cpufreq_set(unsigned int freq, unsigned int cpu) { int ret = -EINVAL; - dprintk("_cpufreq_set for cpu %u, freq %u kHz\n", cpu, freq); + dprintk("cpufreq_set for cpu %u, freq %u kHz\n", cpu, freq); down(&userspace_sem); if (!cpu_is_managed[cpu]) @@ -134,359 +96,6 @@ return ret; } - -#ifdef CONFIG_CPU_FREQ_24_API - -#warning The /proc/sys/cpu/ and sysctl interface to cpufreq will be removed from the 2.6. kernel series soon after 2005-01-01 - -static unsigned int warning_print = 0; - -int __deprecated cpufreq_set(unsigned int freq, unsigned int cpu) -{ - return _cpufreq_set(freq, cpu); -} -EXPORT_SYMBOL_GPL(cpufreq_set); - - -/** - * cpufreq_setmax - set the CPU to the maximum frequency - * @cpu - affected cpu; - * - * Sets the CPU frequency to the maximum frequency supported by - * this CPU. - */ -int __deprecated cpufreq_setmax(unsigned int cpu) -{ - if (!cpu_is_managed[cpu] || !cpu_online(cpu)) - return -EINVAL; - return _cpufreq_set(cpu_max_freq[cpu], cpu); -} -EXPORT_SYMBOL_GPL(cpufreq_setmax); - -/*********************** cpufreq_sysctl interface ********************/ -static int -cpufreq_procctl(ctl_table *ctl, int write, struct file *filp, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - char buf[16], *p; - int cpu = (long) ctl->extra1; - unsigned int len, left = *lenp; - - if (!left || (*ppos && !write) || !cpu_online(cpu)) { - *lenp = 0; - return 0; - } - - if (!warning_print) { - warning_print++; - printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and " - "will be removed from (new) 2.6. kernels soon " - "after 2005-01-01\n"); - } - - if (write) { - unsigned int freq; - - len = left; - if (left > sizeof(buf)) - left = sizeof(buf); - if (copy_from_user(buf, buffer, left)) - return -EFAULT; - buf[sizeof(buf) - 1] = '\0'; - - freq = simple_strtoul(buf, &p, 0); - _cpufreq_set(freq, cpu); - } else { - len = sprintf(buf, "%d\n", cpufreq_get(cpu)); - if (len > left) - len = left; - if (copy_to_user(buffer, buf, len)) - return -EFAULT; - } - - *lenp = len; - *ppos += len; - return 0; -} - -static int -cpufreq_sysctl(ctl_table *table, int __user *name, int nlen, - void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) -{ - int cpu = (long) table->extra1; - - if (!cpu_online(cpu)) - return -EINVAL; - - if (!warning_print) { - warning_print++; - printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and " - "will be removed from (new) 2.6. kernels soon " - "after 2005-01-01\n"); - } - - if (oldval && oldlenp) { - size_t oldlen; - - if (get_user(oldlen, oldlenp)) - return -EFAULT; - - if (oldlen != sizeof(unsigned int)) - return -EINVAL; - - if (put_user(cpufreq_get(cpu), (unsigned int __user *)oldval) || - put_user(sizeof(unsigned int), oldlenp)) - return -EFAULT; - } - if (newval && newlen) { - unsigned int freq; - - if (newlen != sizeof(unsigned int)) - return -EINVAL; - - if (get_user(freq, (unsigned int __user *)newval)) - return -EFAULT; - - _cpufreq_set(freq, cpu); - } - return 1; -} - -/* ctl_table ctl_cpu_vars_{0,1,...,(NR_CPUS-1)} */ -/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */ - CTL_TABLE_CPU_VARS(0); -#if NR_CPUS > 1 - CTL_TABLE_CPU_VARS(1); -#endif -#if NR_CPUS > 2 - CTL_TABLE_CPU_VARS(2); -#endif -#if NR_CPUS > 3 - CTL_TABLE_CPU_VARS(3); -#endif -#if NR_CPUS > 4 - CTL_TABLE_CPU_VARS(4); -#endif -#if NR_CPUS > 5 - CTL_TABLE_CPU_VARS(5); -#endif -#if NR_CPUS > 6 - CTL_TABLE_CPU_VARS(6); -#endif -#if NR_CPUS > 7 - CTL_TABLE_CPU_VARS(7); -#endif -#if NR_CPUS > 8 - CTL_TABLE_CPU_VARS(8); -#endif -#if NR_CPUS > 9 - CTL_TABLE_CPU_VARS(9); -#endif -#if NR_CPUS > 10 - CTL_TABLE_CPU_VARS(10); -#endif -#if NR_CPUS > 11 - CTL_TABLE_CPU_VARS(11); -#endif -#if NR_CPUS > 12 - CTL_TABLE_CPU_VARS(12); -#endif -#if NR_CPUS > 13 - CTL_TABLE_CPU_VARS(13); -#endif -#if NR_CPUS > 14 - CTL_TABLE_CPU_VARS(14); -#endif -#if NR_CPUS > 15 - CTL_TABLE_CPU_VARS(15); -#endif -#if NR_CPUS > 16 - CTL_TABLE_CPU_VARS(16); -#endif -#if NR_CPUS > 17 - CTL_TABLE_CPU_VARS(17); -#endif -#if NR_CPUS > 18 - CTL_TABLE_CPU_VARS(18); -#endif -#if NR_CPUS > 19 - CTL_TABLE_CPU_VARS(19); -#endif -#if NR_CPUS > 20 - CTL_TABLE_CPU_VARS(20); -#endif -#if NR_CPUS > 21 - CTL_TABLE_CPU_VARS(21); -#endif -#if NR_CPUS > 22 - CTL_TABLE_CPU_VARS(22); -#endif -#if NR_CPUS > 23 - CTL_TABLE_CPU_VARS(23); -#endif -#if NR_CPUS > 24 - CTL_TABLE_CPU_VARS(24); -#endif -#if NR_CPUS > 25 - CTL_TABLE_CPU_VARS(25); -#endif -#if NR_CPUS > 26 - CTL_TABLE_CPU_VARS(26); -#endif -#if NR_CPUS > 27 - CTL_TABLE_CPU_VARS(27); -#endif -#if NR_CPUS > 28 - CTL_TABLE_CPU_VARS(28); -#endif -#if NR_CPUS > 29 - CTL_TABLE_CPU_VARS(29); -#endif -#if NR_CPUS > 30 - CTL_TABLE_CPU_VARS(30); -#endif -#if NR_CPUS > 31 - CTL_TABLE_CPU_VARS(31); -#endif -#if NR_CPUS > 32 -#error please extend CPU enumeration -#endif - -/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */ -static ctl_table ctl_cpu_table[NR_CPUS + 1] = { - CPU_ENUM(0), -#if NR_CPUS > 1 - CPU_ENUM(1), -#endif -#if NR_CPUS > 2 - CPU_ENUM(2), -#endif -#if NR_CPUS > 3 - CPU_ENUM(3), -#endif -#if NR_CPUS > 4 - CPU_ENUM(4), -#endif -#if NR_CPUS > 5 - CPU_ENUM(5), -#endif -#if NR_CPUS > 6 - CPU_ENUM(6), -#endif -#if NR_CPUS > 7 - CPU_ENUM(7), -#endif -#if NR_CPUS > 8 - CPU_ENUM(8), -#endif -#if NR_CPUS > 9 - CPU_ENUM(9), -#endif -#if NR_CPUS > 10 - CPU_ENUM(10), -#endif -#if NR_CPUS > 11 - CPU_ENUM(11), -#endif -#if NR_CPUS > 12 - CPU_ENUM(12), -#endif -#if NR_CPUS > 13 - CPU_ENUM(13), -#endif -#if NR_CPUS > 14 - CPU_ENUM(14), -#endif -#if NR_CPUS > 15 - CPU_ENUM(15), -#endif -#if NR_CPUS > 16 - CPU_ENUM(16), -#endif -#if NR_CPUS > 17 - CPU_ENUM(17), -#endif -#if NR_CPUS > 18 - CPU_ENUM(18), -#endif -#if NR_CPUS > 19 - CPU_ENUM(19), -#endif -#if NR_CPUS > 20 - CPU_ENUM(20), -#endif -#if NR_CPUS > 21 - CPU_ENUM(21), -#endif -#if NR_CPUS > 22 - CPU_ENUM(22), -#endif -#if NR_CPUS > 23 - CPU_ENUM(23), -#endif -#if NR_CPUS > 24 - CPU_ENUM(24), -#endif -#if NR_CPUS > 25 - CPU_ENUM(25), -#endif -#if NR_CPUS > 26 - CPU_ENUM(26), -#endif -#if NR_CPUS > 27 - CPU_ENUM(27), -#endif -#if NR_CPUS > 28 - CPU_ENUM(28), -#endif -#if NR_CPUS > 29 - CPU_ENUM(29), -#endif -#if NR_CPUS > 30 - CPU_ENUM(30), -#endif -#if NR_CPUS > 31 - CPU_ENUM(31), -#endif -#if NR_CPUS > 32 -#error please extend CPU enumeration -#endif - { - .ctl_name = 0, - } -}; - -static ctl_table ctl_cpu[2] = { - { - .ctl_name = CTL_CPU, - .procname = "cpu", - .mode = 0555, - .child = ctl_cpu_table, - }, - { - .ctl_name = 0, - } -}; - -static struct ctl_table_header *cpufreq_sysctl_table; - -static inline void cpufreq_sysctl_init(void) -{ - cpufreq_sysctl_table = register_sysctl_table(ctl_cpu, 0); -} - -static inline void cpufreq_sysctl_exit(void) -{ - unregister_sysctl_table(cpufreq_sysctl_table); -} - -#else -#define cpufreq_sysctl_init() do {} while(0) -#define cpufreq_sysctl_exit() do {} while(0) -#endif /* CONFIG_CPU_FREQ_24API */ - - /************************** sysfs interface ************************/ static ssize_t show_speed (struct cpufreq_policy *policy, char *buf) { @@ -503,7 +112,7 @@ if (ret != 1) return -EINVAL; - _cpufreq_set(freq, policy->cpu); + cpufreq_set(freq, policy->cpu); return count; } @@ -577,7 +186,6 @@ static int __init cpufreq_gov_userspace_init(void) { - cpufreq_sysctl_init(); cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); return cpufreq_register_governor(&cpufreq_gov_userspace); } @@ -587,7 +195,6 @@ { cpufreq_unregister_governor(&cpufreq_gov_userspace); cpufreq_unregister_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); - cpufreq_sysctl_exit(); } diff -wur linux-2.6.10/drivers/cpufreq/freq_table.c linux-2.6.10-lab/drivers/cpufreq/freq_table.c --- linux-2.6.10/drivers/cpufreq/freq_table.c 2004-12-24 16:35:28.000000000 -0500 +++ linux-2.6.10-lab/drivers/cpufreq/freq_table.c 2007-10-04 19:10:37.000000000 -0400 @@ -214,6 +214,11 @@ } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr); +struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu) +{ + return show_table[cpu]; +} +EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table); MODULE_AUTHOR ("Dominik Brodowski "); MODULE_DESCRIPTION ("CPUfreq frequency table helpers"); diff -wur linux-2.6.10/drivers/i2c/algos/Makefile linux-2.6.10-lab/drivers/i2c/algos/Makefile --- linux-2.6.10/drivers/i2c/algos/Makefile 2004-12-24 16:35:23.000000000 -0500 +++ linux-2.6.10-lab/drivers/i2c/algos/Makefile 2007-10-04 19:10:38.000000000 -0400 @@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o +obj-$(CONFIG_I2C_PXA) += i2c-algo-pxa.o ifeq ($(CONFIG_I2C_DEBUG_ALGO),y) EXTRA_CFLAGS += -DDEBUG diff -wur linux-2.6.10/drivers/i2c/busses/Kconfig linux-2.6.10-lab/drivers/i2c/busses/Kconfig --- linux-2.6.10/drivers/i2c/busses/Kconfig 2004-12-24 16:35:25.000000000 -0500 +++ linux-2.6.10-lab/drivers/i2c/busses/Kconfig 2007-10-04 19:10:38.000000000 -0400 @@ -466,4 +466,15 @@ This driver can also be built as a module. If so, the module will be called i2c-pca-isa. +config I2C_PXA + tristate "I2C interface in Intel PXA2x0" + depends on ARCH_PXA && I2C + help + This supports the use of the PXA I2C interface found on the Intel + PXA 25x and PXA 26x systems. Say Y if you have one of these. + You should also say Y for the PXA I2C peripheral driver support below. + + To compile this driver as a module, say M here: the + modules will be called i2c-pxa and i2c-algo-pxa. + endmenu diff -wur linux-2.6.10/drivers/i2c/busses/Makefile linux-2.6.10-lab/drivers/i2c/busses/Makefile --- linux-2.6.10/drivers/i2c/busses/Makefile 2004-12-24 16:33:51.000000000 -0500 +++ linux-2.6.10-lab/drivers/i2c/busses/Makefile 2007-10-04 19:10:38.000000000 -0400 @@ -26,6 +26,7 @@ obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o +obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o @@ -36,6 +37,7 @@ obj-$(CONFIG_I2C_VIA) += i2c-via.o obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o +obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o diff -wur linux-2.6.10/drivers/i2c/chips/Kconfig linux-2.6.10-lab/drivers/i2c/chips/Kconfig --- linux-2.6.10/drivers/i2c/chips/Kconfig 2004-12-24 16:34:58.000000000 -0500 +++ linux-2.6.10-lab/drivers/i2c/chips/Kconfig 2007-10-04 19:10:38.000000000 -0400 @@ -347,6 +347,11 @@ This driver can also be built as a module. If so, the module will be called i2c-rtc8564. +config RS5C372_RTC + tristate "RS5C372 Real Time Clock" + depends on I2C + + config ISP1301_OMAP tristate "Philips ISP1301 with OMAP OTG" depends on I2C && ARCH_OMAP_OTG diff -wur linux-2.6.10/drivers/i2c/chips/Makefile linux-2.6.10-lab/drivers/i2c/chips/Makefile --- linux-2.6.10/drivers/i2c/chips/Makefile 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-lab/drivers/i2c/chips/Makefile 2007-10-04 19:10:38.000000000 -0400 @@ -30,6 +30,7 @@ obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o +obj-$(CONFIG_RS5C372_RTC) += rs5c372.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o diff -wur linux-2.6.10/drivers/misc/Kconfig linux-2.6.10-lab/drivers/misc/Kconfig --- linux-2.6.10/drivers/misc/Kconfig 2004-12-24 16:34:26.000000000 -0500 +++ linux-2.6.10-lab/drivers/misc/Kconfig 2007-10-04 19:10:29.000000000 -0400 @@ -29,5 +29,21 @@ If unsure, say N. +config PROC_SERIALNUMBER + bool "Device serial number driver" + default n + ---help--- + This option enables the creation of the /proc/serialnumber entry, + which returns the unique serial number of the device. + +config PROC_BOOTDATA + bool "Boot data driver" + default n + ---help--- + This option enables the creation of the /proc/bd/ entries, + which provide an interface for accessing various shared boot + global data entries in the common memory space between the + kernel and bootloader + endmenu diff -wur linux-2.6.10/drivers/misc/Makefile linux-2.6.10-lab/drivers/misc/Makefile --- linux-2.6.10/drivers/misc/Makefile 2004-12-24 16:35:28.000000000 -0500 +++ linux-2.6.10-lab/drivers/misc/Makefile 2007-10-04 19:10:29.000000000 -0400 @@ -4,3 +4,5 @@ obj- := misc.o # Dummy rule to force built-in.o to be made obj-$(CONFIG_IBM_ASM) += ibmasm/ +obj-$(CONFIG_PROC_SERIALNUMBER) += serialnumber.o +obj-$(CONFIG_PROC_BOOTDATA) += bootdata.o diff -wur linux-2.6.10/drivers/mmc/mmc.c linux-2.6.10-lab/drivers/mmc/mmc.c --- linux-2.6.10/drivers/mmc/mmc.c 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-lab/drivers/mmc/mmc.c 2007-10-04 19:10:37.000000000 -0400 @@ -6,6 +6,9 @@ * 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. + * + * Lab126 changes Copyright (C) 2005, 2006 Lab126, Inc. + * */ #include #include @@ -16,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -25,8 +30,16 @@ #ifdef CONFIG_MMC_DEBUG #define DBG(x...) printk(KERN_DEBUG x) +#define MDEBUG(x...) printk(x) #else #define DBG(x...) do { } while (0) +#define MDEBUG(x...) do { } while (0) +#endif + +#if defined(CONFIG_PM_DEBUG) || defined(CONFIG_MMC_DEBUG) +#define pinfo(x...) printk(x) +#else +#define pinfo(x...) do {} while (0) #endif #define CMD_RETRIES 3 @@ -125,8 +138,17 @@ complete(mrq->done_data); } +#ifdef CONFIG_ARCH_LAB126 +#define MMC_WAIT_REQUEST_TIMEOUT (1 * HZ) +#define MMC_WAIT_REQUEST_RETRIES 3 +#endif + int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) { +#ifdef CONFIG_ARCH_LAB126 + if (host != NULL && mrq != NULL) { + int retries; +#endif DECLARE_COMPLETION(complete); mrq->done_data = &complete; @@ -134,7 +156,30 @@ mmc_start_request(host, mrq); +#ifndef CONFIG_ARCH_LAB126 wait_for_completion(&complete); +#else + retries = 0; + + while (wait_for_completion_interruptible_timeout(&complete, MMC_WAIT_REQUEST_TIMEOUT) == 0) { + + if ((retries++ >= MMC_WAIT_REQUEST_RETRIES) || !host->ops->card_inserted()) { + struct mmc_command *cmd = mrq->cmd; + + cmd->error = MMC_ERR_ABORTED; + cmd->retries = 0; + + mmc_request_done(host, mrq); + + host->card_busy = NULL; + + break; + } + + } +#endif + + } return 0; } @@ -172,7 +217,134 @@ EXPORT_SYMBOL(mmc_wait_for_cmd); +/** + * mmc_wait_for_app_cmd - start an application command and wait for + completion + * @host: MMC host to start command + * @rca: RCA to send MMC_APP_CMD to + * @cmd: MMC command to start + * @retries: maximum number of retries + * + * Sends a MMC_APP_CMD, checks the card response, sends the command + * in the parameter and waits for it to complete. Return any error + * that occurred while the command was executing. Do not attempt to + * parse the response. + */ +int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca, + struct mmc_command *cmd, int retries) +{ + struct mmc_request mrq; + struct mmc_command appcmd; + + int i, err; + + BUG_ON(host->card_busy == NULL); + BUG_ON(retries < 0); + + err = MMC_ERR_INVALID; + + /* + * We have to resend MMC_APP_CMD for each attempt so + * we cannot use the retries field in mmc_command. + */ + for (i = 0;i <= retries;i++) { + memset(&mrq, 0, sizeof(struct mmc_request)); + appcmd.opcode = MMC_APP_CMD; + appcmd.arg = rca << 16; + appcmd.flags = MMC_RSP_R1; + appcmd.retries = 0; + memset(appcmd.resp, 0, sizeof(appcmd.resp)); + appcmd.data = NULL; + + mrq.cmd = &appcmd; + appcmd.data = NULL; + + mmc_wait_for_req(host, &mrq); + + if (appcmd.error) { + err = appcmd.error; + continue; + } + + /* Check that card supported application commands */ + if (!(appcmd.resp[0] & R1_APP_CMD)) + return MMC_ERR_FAILED; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + memset(cmd->resp, 0, sizeof(cmd->resp)); + cmd->retries = 0; + + mrq.cmd = cmd; + cmd->data = NULL; + + mmc_wait_for_req(host, &mrq); + + err = cmd->error; + if (cmd->error == MMC_ERR_NONE) + break; + } + + return err; +} + +EXPORT_SYMBOL(mmc_wait_for_app_cmd); + +/** + * mmc_set_data_timeout - set the timeout for a data command + * @data: data phase for command + * @card: the MMC card associated with the data transfer + * @write: flag to differentiate reads from writes + */ +void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, + int write) +{ + unsigned int mult; + + /* + * SD cards use a 100 multiplier rather than 10 + */ + mult = mmc_card_sd(card) ? 100 : 10; + + /* + * Scale up the multiplier (and therefore the timeout) by + * the r2w factor for writes. + */ + if (write) + mult <<= card->csd.r2w_factor; + + data->timeout_ns = card->csd.tacc_ns * mult; + data->timeout_clks = card->csd.tacc_clks * mult; + + /* + * SD cards also have an upper limit on the timeout. + */ + if (mmc_card_sd(card)) { + unsigned int timeout_us, limit_us; + + timeout_us = data->timeout_ns / 1000; + timeout_us += data->timeout_clks * 1000 / + (card->host->ios.clock / 1000); + + if (write) + limit_us = 250000; + else + limit_us = 100000; + + /* + * SDHC cards always use these fixed values. + */ + if (timeout_us > limit_us || mmc_card_blockaddr(card)) { + data->timeout_ns = limit_us * 1000; + data->timeout_clks = 0; + } + } +} + +EXPORT_SYMBOL(mmc_set_data_timeout); + +static int mmc_select_card(struct mmc_host *host, struct mmc_card *card); /** * __mmc_claim_host - exclusively claim a host @@ -191,6 +363,13 @@ unsigned long flags; int err = 0; +#ifdef CONFIG_ARCH_LAB126 + if (host == NULL) { + /* this case can be hit on card abort */ + return MMC_ERR_ABORTED; + } +#endif + add_wait_queue(&host->wq, &wait); spin_lock_irqsave(&host->lock, flags); while (1) { @@ -206,16 +385,17 @@ spin_unlock_irqrestore(&host->lock, flags); remove_wait_queue(&host->wq, &wait); - if (card != (void *)-1 && host->card_selected != card) { - struct mmc_command cmd; - - host->card_selected = card; + if (card != (void *)-1) { + err = mmc_select_card(host, card); - cmd.opcode = MMC_SELECT_CARD; - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1; +#ifdef CONFIG_ARCH_LAB126 + if (err == MMC_ERR_ABORTED) { + host->ops->clear(host); + } +#endif - err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) + return err; } return err; @@ -234,7 +414,14 @@ { unsigned long flags; +#ifdef CONFIG_ARCH_LAB126 + if (host == NULL) { + /* this case can be hit on card abort */ + return; + } +#else BUG_ON(host->card_busy == NULL); +#endif spin_lock_irqsave(&host->lock, flags); host->card_busy = NULL; @@ -245,6 +432,63 @@ EXPORT_SYMBOL(mmc_release_host); +static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) +{ + int err; + struct mmc_command cmd; + + BUG_ON(host->card_busy == NULL); + + if (host->card_selected == card) + return MMC_ERR_NONE; + + host->card_selected = card; + + cmd.opcode = MMC_SELECT_CARD; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) + return err; + + /* + * Default bus width is 1 bit. + */ + host->ios.bus_width = MMC_BUS_WIDTH_1; + + /* + * We can only change the bus width of the selected + * card so therefore we have to put the handling + * here. + */ + if (host->caps & MMC_CAP_4_BIT_DATA) { + /* + * The card is in 1 bit mode by default so + * we only need to change if it supports the + * wider version. + */ + if (mmc_card_sd(card) && + (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { + struct mmc_command cmd; + cmd.opcode = SD_APP_SET_BUS_WIDTH; + cmd.arg = SD_BUS_WIDTH_4; + cmd.flags = MMC_RSP_R1; + + err = mmc_wait_for_app_cmd(host, card->rca, &cmd, + CMD_RETRIES); + if (err != MMC_ERR_NONE) + return err; + + host->ios.bus_width = MMC_BUS_WIDTH_4; + } + } + + host->ops->set_ios(host, &host->ios); + + return MMC_ERR_NONE; +} + /* * Ensure that no card is selected. */ @@ -321,12 +565,33 @@ memset(&card->cid, 0, sizeof(struct mmc_cid)); + if (mmc_card_sd(card)) { + /* + * SD doesn't currently have a version field so we will + * have to assume we can parse this. + */ + card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); + card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); + card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); + card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); + card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); + card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); + card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); + card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4); + card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4); + card->cid.serial = UNSTUFF_BITS(resp, 24, 32); + card->cid.year = UNSTUFF_BITS(resp, 12, 8); + card->cid.month = UNSTUFF_BITS(resp, 8, 4); + + card->cid.year += 2000; /* SD cards year offset */ + } + else { /* - * The selection of the format here is guesswork based upon - * information people have sent to date. + * The selection of the format here is based upon published + * specs from sandisk and from what people have reported. */ switch (card->csd.mmca_vsn) { - case 0: /* MMC v1.? */ + case 0: /* MMC v1.0 - v1.2 */ case 1: /* MMC v1.4 */ card->cid.manfid = UNSTUFF_BITS(resp, 104, 24); card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); @@ -343,8 +608,9 @@ card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; break; - case 2: /* MMC v2.x ? */ - case 3: /* MMC v3.x ? */ + case 2: /* MMC v2.0 - v2.2 */ + case 3: /* MMC v3.1 - v3.3 */ + case 4: /* MMC v4.0 */ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); @@ -365,6 +631,7 @@ break; } } +} /* * Given a 128-bit response, decode to our card CSD structure. @@ -375,12 +642,66 @@ unsigned int e, m, csd_struct; u32 *resp = card->raw_csd; + if (mmc_card_sd(card)) { + csd_struct = UNSTUFF_BITS(resp, 126, 2); + + switch (csd_struct) { + case 0: + m = UNSTUFF_BITS(resp, 115, 4); + e = UNSTUFF_BITS(resp, 112, 3); + csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; + csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; + + m = UNSTUFF_BITS(resp, 99, 4); + e = UNSTUFF_BITS(resp, 96, 3); + csd->max_dtr = tran_exp[e] * tran_mant[m]; + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + e = UNSTUFF_BITS(resp, 47, 3); + m = UNSTUFF_BITS(resp, 62, 12); + csd->capacity = (1 + m) << (e + 2); + + csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); + csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); + break; + case 1: /* - * We only understand CSD structure v1.1 and v2. - * v2 has extra information in bits 15, 11 and 10. + * This is a block-addressed SDHC card. Most + * interesting fields are unused and have fixed + * values. To avoid getting tripped by buggy cards, + * we assume those fixed values ourselves. + */ + mmc_card_set_blockaddr(card); + + csd->tacc_ns = 0; /* Unused */ + csd->tacc_clks = 0; /* Unused */ + + m = UNSTUFF_BITS(resp, 99, 4); + e = UNSTUFF_BITS(resp, 96, 3); + csd->max_dtr = tran_exp[e] * tran_mant[m]; + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + m = UNSTUFF_BITS(resp, 48, 22); + csd->capacity = (1 + m) << 10; + + csd->read_blkbits = 9; + csd->r2w_factor = 4; /* Unused */ + break; + default: + printk("%s: unrecognised CSD structure version %d\n", + card->host->host_name, csd_struct); + mmc_card_set_bad(card); + return; + } + + } + else { + /* + * We only understand CSD structure v1.1 and v1.2. + * v1.2 has extra information in bits 15, 11 and 10. */ csd_struct = UNSTUFF_BITS(resp, 126, 2); - if (csd_struct != 1 && csd_struct != 2) { + if (csd_struct != 1 && csd_struct != 2 && csd_struct != 3) { printk("%s: unrecognised CSD structure version %d\n", card->host->host_name, csd_struct); mmc_card_set_bad(card); @@ -404,6 +725,39 @@ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); } +} + +/* + * Given a 64-bit response, decode to our card SCR structure. + */ +static void mmc_decode_scr(struct mmc_card *card) +{ + struct sd_scr *scr = &card->scr; + unsigned int scr_struct; + u32 resp[4]; + + BUG_ON(!mmc_card_sd(card)); + + resp[3] = card->raw_scr[1]; + resp[2] = card->raw_scr[0]; + + scr_struct = UNSTUFF_BITS(resp, 60, 4); + +// testing of SCR v1 and v3 cards indicates that the spec is +// backwards compatible, so we shouldn't limit the operation +// cards based on the SCR version field value +#if 0 + if (scr_struct != 0) { + printk("%s: unrecognised SCR structure version %d\n", + card->host->host_name, scr_struct); + mmc_card_set_bad(card); + return; + } +#endif + + scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4); + scr->bus_widths = UNSTUFF_BITS(resp, 48, 4); +} /* * Locate a MMC card on this MMC host given a raw CID. @@ -472,9 +826,12 @@ { int bit = fls(host->ocr_avail) - 1; + MDEBUG("MMC: mmc_power_up()\n"); + host->ios.vdd = bit; host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.power_mode = MMC_POWER_UP; + host->ios.bus_width = MMC_BUS_WIDTH_1; host->ops->set_ios(host, &host->ios); mmc_delay(1); @@ -488,10 +845,12 @@ static void mmc_power_off(struct mmc_host *host) { + MDEBUG("MMC: mmc_power_off()\n"); host->ios.clock = 0; host->ios.vdd = 0; host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.power_mode = MMC_POWER_OFF; + host->ios.bus_width = MMC_BUS_WIDTH_1; host->ops->set_ios(host, &host->ios); } @@ -523,6 +882,69 @@ return err; } +static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) +{ + struct mmc_command cmd; + int i, err = 0; + + cmd.opcode = SD_APP_OP_COND; + cmd.arg = ocr; + cmd.flags = MMC_RSP_R3; + + for (i = 100; i; i--) { + err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) + break; + + if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + break; + + err = MMC_ERR_TIMEOUT; + + mmc_delay(10); + } + + if (rocr) + *rocr = cmd.resp[0]; + + return err; +} + +static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2) +{ + struct mmc_command cmd; + int err, sd2; + static const u8 test_pattern = 0xAA; + + /* + * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND + * before SD_APP_OP_COND. This command will harmlessly fail for + * SD 1.0 cards. + */ + cmd.opcode = SD_SEND_IF_COND; + cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; + cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err == MMC_ERR_NONE) { + if ((cmd.resp[0] & 0xFF) == test_pattern) { + sd2 = 1; + } else { + sd2 = 0; + err = MMC_ERR_FAILED; + } + } else { + /* + * Treat errors as SD 1.0 card. + */ + sd2 = 0; + err = MMC_ERR_NONE; + } + if (rsd2) + *rsd2 = sd2; + return err; +} + /* * Discover cards by requesting their CID. If this command * times out, it is not an error; there are no further cards @@ -561,11 +983,36 @@ err = PTR_ERR(card); break; } + MDEBUG("MMC: mmc_discover_cards adding card to list\n"); list_add(&card->node, &host->cards); } card->state &= ~MMC_STATE_DEAD; + if (host->mode == MMC_MODE_SD) { + mmc_card_set_sd(card); + + cmd.opcode = SD_SEND_RELATIVE_ADDR; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) + mmc_card_set_dead(card); + + card->rca = cmd.resp[0] >> 16; + + if (!host->ops->get_ro) { + printk(KERN_WARNING "%s: host does not support " + "reading read-only switch. assuming " + "write-enable.\n", host->host_name); + } + else { + if (host->ops->get_ro(host)) + mmc_card_set_readonly(card); + } + } + else { cmd.opcode = MMC_SET_RELATIVE_ADDR; cmd.arg = card->rca << 16; cmd.flags = MMC_RSP_R1; @@ -575,6 +1022,7 @@ mmc_card_set_dead(card); } } +} static void mmc_read_csds(struct mmc_host *host) { @@ -604,6 +1052,80 @@ } } +static void mmc_read_scrs(struct mmc_host *host) +{ + int err; + struct mmc_card *card; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + + struct scatterlist sg; + + list_for_each_entry(card, &host->cards, node) { + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + if (!mmc_card_sd(card)) + continue; + + err = mmc_select_card(host, card); + if (err != MMC_ERR_NONE) + { + mmc_card_set_dead(card); + continue; + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_APP_CMD; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) { + mmc_card_set_dead(card); + continue; + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_APP_SEND_SCR; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz_bits = 3; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, (u8*)card->raw_scr, 64); + + err = mmc_wait_for_req(host, &mrq); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + card->raw_scr[0] = ntohl(card->raw_scr[0]); + card->raw_scr[1] = ntohl(card->raw_scr[1]); + + mmc_decode_scr(card); + } + + mmc_deselect_cards(host); +} + static unsigned int mmc_calculate_clock(struct mmc_host *host) { struct mmc_card *card; @@ -643,8 +1165,11 @@ cmd.flags = MMC_RSP_R1; err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); - if (err == MMC_ERR_NONE) + if (err == MMC_ERR_NONE) { + MDEBUG("Card responded in mmc_check_cards - 0x%x\n",(int)card); continue; + } + else MDEBUG("Couldn't find card in mmc_check_cards - dead card 0x%x\n",(int)card); mmc_card_set_dead(card); } @@ -656,13 +1181,31 @@ int err; u32 ocr; + host->mode = MMC_MODE_MMC; + mmc_power_up(host); mmc_idle_cards(host); + err = mmc_send_if_cond(host, host->ocr_avail, NULL); + if (err != MMC_ERR_NONE) { + return; + } + err = mmc_send_op_cond(host, 0, &ocr); + + /* + * If we fail to detect any cards then try + * searching for SD cards. + */ + if (err != MMC_ERR_NONE) + { + err = mmc_send_app_op_cond(host, 0, &ocr); if (err != MMC_ERR_NONE) return; + host->mode = MMC_MODE_SD; + } + host->ocr = mmc_select_voltage(host, ocr); /* @@ -701,7 +1244,21 @@ * all get the idea that they should be ready for CMD2. * (My SanDisk card seems to need this.) */ + if (host->mode == MMC_MODE_SD) { + int err, sd2; + err = mmc_send_if_cond(host, host->ocr, &sd2); + if (err == MMC_ERR_NONE) { + /* + * If SD_SEND_IF_COND indicates an SD 2.0 + * compliant card and we should set bit 30 + * of the ocr to indicate that we can handle + * block-addressed SDHC cards. + */ + mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL); + } + } else { mmc_send_op_cond(host, host->ocr, NULL); + } mmc_discover_cards(host); @@ -712,6 +1269,9 @@ host->ops->set_ios(host, &host->ios); mmc_read_csds(host); + + if (host->mode == MMC_MODE_SD) + mmc_read_scrs(host); } @@ -737,8 +1297,11 @@ mmc_claim_host(host); - if (host->ios.power_mode == MMC_POWER_ON) + if (host->ios.power_mode == MMC_POWER_ON) { + msleep(100); mmc_check_cards(host); + MDEBUG("mmc_rescan found MMC_POWER_ON, checking for existence of cards\n"); + } mmc_setup(host); @@ -760,19 +1323,25 @@ * If this is a new and good card, register it. */ if (!mmc_card_present(card) && !mmc_card_dead(card)) { - if (mmc_register_card(card)) + if (mmc_register_card(card)) { + MDEBUG("MMC: calling mmc_card_set_dead (card = 0x%x).\n",(int)card); mmc_card_set_dead(card); - else + } + else { + MDEBUG("MMC: calling mmc_card_set_present (card = 0x%x).\n",(int)card); mmc_card_set_present(card); } + } /* * If this card is dead, destroy it. */ if (mmc_card_dead(card)) { + MDEBUG("MMC: Removing card from list (card = 0x%x).\n",(int) card); list_del(&card->node); mmc_remove_card(card); } + else MDEBUG("MMC: mmc card NOT dead and NOT removed (card = 0x%x).\n",(int) card); } /* @@ -781,6 +1350,8 @@ */ if (list_empty(&host->cards)) mmc_power_off(host); + else + MDEBUG("Card list NOT empty in mmc_rescan\n"); } @@ -851,9 +1422,12 @@ { struct list_head *l, *n; + MDEBUG("MMC: mmc_remove_host called\n"); + list_for_each_safe(l, n, &host->cards) { struct mmc_card *card = mmc_list_to_card(l); + MDEBUG("MMC: mmc_remove_host calling mmc_remove_card\n"); mmc_remove_card(card); } @@ -885,8 +1459,26 @@ */ int mmc_suspend_host(struct mmc_host *host, u32 state) { + pinfo("MMC: mmc_suspend_host()...\n"); mmc_claim_host(host); mmc_deselect_cards(host); + +#ifdef CONFIG_FIONA_PM_MMC + { + struct list_head *l, *n; + + list_for_each_safe(l, n, &host->cards) { + struct mmc_card *card = mmc_list_to_card(l); + + MDEBUG("MMC: mmc_suspend_host() removing card 0x%X\n", (int)card); + mmc_card_set_dead(card); + + list_del(&card->node); + mmc_remove_card(card); + } + } +#endif + mmc_power_off(host); mmc_release_host(host); @@ -901,7 +1493,14 @@ */ int mmc_resume_host(struct mmc_host *host) { +#ifdef CONFIG_FIONA_PM_MMC + extern struct mmc_host *g_pm_mmc_resume_host; + + /* we need to defer resume processing because of "fpow" */ + g_pm_mmc_resume_host = host; +#else mmc_detect_change(host); +#endif return 0; } diff -wur linux-2.6.10/drivers/mmc/mmc_block.c linux-2.6.10-lab/drivers/mmc/mmc_block.c --- linux-2.6.10/drivers/mmc/mmc_block.c 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-lab/drivers/mmc/mmc_block.c 2007-10-04 19:10:37.000000000 -0400 @@ -16,6 +16,7 @@ * Author: Andrew Christian * 28 May 2002 */ +#include #include #include #include @@ -42,6 +43,16 @@ */ #define MMC_SHIFT 3 + +#if defined(CONFIG_MMC_DEBUG) || defined(CONFIG_PM_DEBUG) +#define pinfo(x...) printk(x) +#else +#define pinfo(x...) do {} while(0) +#endif + +extern int mmc_suspend_host(struct mmc_host *host, u32 state); +extern int mmc_resume_host(struct mmc_host *host); + static int major; /* @@ -95,6 +106,10 @@ if (md->usage == 2) check_disk_change(inode->i_bdev); ret = 0; + + if ((filp->f_mode & FMODE_WRITE) && + mmc_card_readonly(md->queue.card)) + ret = -EROFS; } return ret; @@ -168,7 +183,12 @@ int ret; if (mmc_card_claim_host(card)) +#ifndef CONFIG_ARCH_LAB126 goto cmd_err; +#else + /* this case can occur on card abort */ + goto cmd_err_skip_release; +#endif do { struct mmc_blk_request brq; @@ -178,17 +198,20 @@ brq.mrq.cmd = &brq.cmd; brq.mrq.data = &brq.data; - brq.cmd.arg = req->sector << 9; + brq.cmd.arg = req->sector; + if (!mmc_card_blockaddr(card)) + brq.cmd.arg <<= 9; brq.cmd.flags = MMC_RSP_R1; brq.data.req = req; - brq.data.timeout_ns = card->csd.tacc_ns * 10; - brq.data.timeout_clks = card->csd.tacc_clks * 10; + brq.data.blksz_bits = md->block_bits; brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; brq.stop.flags = MMC_RSP_R1B; + mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ); + if (rq_data_dir(req) == READ) { brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK; brq.data.flags |= MMC_DATA_READ; @@ -267,6 +290,10 @@ cmd_err: mmc_card_release_host(card); +#ifdef CONFIG_ARCH_LAB126 +cmd_err_skip_release: +#endif + /* * This is a little draconian, but until we get proper * error handling sorted out here, its the best we can @@ -332,11 +359,21 @@ md->disk->private_data = md; md->disk->queue = md->queue.queue; md->disk->driverfs_dev = &card->dev; + md->disk->flags |= GENHD_FL_REMOVABLE; sprintf(md->disk->disk_name, "mmcblk%d", devidx); sprintf(md->disk->devfs_name, "mmc/blk%d", devidx); - md->block_bits = card->csd.read_blkbits; + /* the rest of the block operation code is written assuming */ + /* 512-byte blocks, so let the system know that it should */ + /* operate using 512-byte blocks as well */ + /* md->block_bits = card->csd.read_blkbits; */ + md->block_bits = 9; // (1 << 9) equals 512 + + /* in addition, adjust the known capacity by the delta */ + if (card->csd.read_blkbits > md->block_bits) { + card->csd.capacity <<= (card->csd.read_blkbits - md->block_bits); + } blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits); set_capacity(md->disk, card->csd.capacity); @@ -351,9 +388,19 @@ struct mmc_command cmd; int err; + /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */ + if (mmc_card_blockaddr(card)) + return 0; + mmc_card_claim_host(card); cmd.opcode = MMC_SET_BLOCKLEN; - cmd.arg = 1 << card->csd.read_blkbits; + + /* the rest of the block operation code is written assuming */ + /* 512-byte blocks, so base the block size on the block data- */ + /* based size, rather than the raw CSD-based size from the card */ + /* cmd.arg = 1 << card->csd.read_blkbits; */ + cmd.arg = 1 << md->block_bits; // (1 << 9) equals 512 + cmd.flags = MMC_RSP_R1; err = mmc_wait_for_cmd(card->host, &cmd, 5); mmc_card_release_host(card); @@ -372,7 +419,10 @@ struct mmc_blk_data *md; int err; - if (card->csd.cmdclass & ~0x1ff) + /* + * Check that the card supports the command class(es) we need. + */ + if (!(card->csd.cmdclass & CCC_BLOCK_READ)) return -ENODEV; if (card->csd.read_blkbits < 9) { @@ -389,9 +439,10 @@ if (err) goto out; - printk(KERN_INFO "%s: %s %s %dKiB\n", + printk(KERN_INFO "%s: %s %s %dKiB %s\n", md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), - (card->csd.capacity << card->csd.read_blkbits) / 1024); + (int)(((long long)card->csd.capacity << md->block_bits) / 1024), + mmc_card_readonly(card)?"(read-only)":""); mmc_set_drvdata(card, md); add_disk(md->disk); @@ -428,22 +479,15 @@ #ifdef CONFIG_PM static int mmc_blk_suspend(struct mmc_card *card, u32 state) { - struct mmc_blk_data *md = mmc_get_drvdata(card); + pinfo("mmc_blk_suspend(%d)\n", state); + + mmc_blk_remove(card); - if (md) { - mmc_queue_suspend(&md->queue); - } return 0; } static int mmc_blk_resume(struct mmc_card *card) { - struct mmc_blk_data *md = mmc_get_drvdata(card); - - if (md) { - mmc_blk_set_blksize(md, card); - mmc_queue_resume(&md->queue); - } return 0; } #else diff -wur linux-2.6.10/drivers/mmc/mmc_queue.c linux-2.6.10-lab/drivers/mmc/mmc_queue.c --- linux-2.6.10/drivers/mmc/mmc_queue.c 2004-12-24 16:34:58.000000000 -0500 +++ linux-2.6.10-lab/drivers/mmc/mmc_queue.c 2007-10-04 19:10:37.000000000 -0400 @@ -18,6 +18,10 @@ #define MMC_QUEUE_EXIT (1 << 0) #define MMC_QUEUE_SUSPENDED (1 << 1) +#ifdef CONFIG_ARCH_LAB126 +#include +#endif + /* * Prepare a MMC request. Essentially, this means passing the * preparation off to the media driver. The media driver will @@ -92,7 +96,16 @@ } set_current_state(TASK_RUNNING); +#ifdef CONFIG_ARCH_LAB126 + cpufreq_enable_speed_changes(0); +#endif + mq->issue_fn(mq, req); + +#ifdef CONFIG_ARCH_LAB126 + cpufreq_enable_speed_changes(1); +#endif + } while (1); remove_wait_queue(&mq->thread_wq, &wait); up(&mq->thread_sem); diff -wur linux-2.6.10/drivers/mmc/mmc_sysfs.c linux-2.6.10-lab/drivers/mmc/mmc_sysfs.c --- linux-2.6.10/drivers/mmc/mmc_sysfs.c 2004-12-24 16:35:01.000000000 -0500 +++ linux-2.6.10-lab/drivers/mmc/mmc_sysfs.c 2007-10-04 19:10:37.000000000 -0400 @@ -21,6 +21,12 @@ #define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) +#if defined(CONFIG_MMC_DEBUG) || defined(CONFIG_PM_DEBUG) +#define pinfo(x...) printk(x) +#else +#define pinfo(x...) do {} while(0) +#endif + static void mmc_release_card(struct device *dev) { struct mmc_card *card = dev_to_mmc_card(dev); @@ -80,8 +86,12 @@ struct mmc_card *card = dev_to_mmc_card(dev); int ret = 0; - if (dev->driver && drv->suspend) + pinfo("mmc_bus_suspend(%d)\n",state); + + if (dev->driver && drv->suspend) { + pinfo("mmc_bus_suspend(%d) calling drv->suspend for %s\n",state,dev->driver->name); ret = drv->suspend(card, state); + } return ret; } @@ -91,8 +101,12 @@ struct mmc_card *card = dev_to_mmc_card(dev); int ret = 0; - if (dev->driver && drv->resume) + pinfo("mmc_bus_resume()\n"); + + if (dev->driver && drv->resume) { + pinfo("mmc_bus_resume() calling drv->resume for %s\n",dev->driver->name); ret = drv->resume(card); + } return ret; } @@ -163,6 +177,7 @@ card->raw_cid[2], card->raw_cid[3]); MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], card->raw_csd[2], card->raw_csd[3]); +MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]); MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year); MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev); MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev); @@ -174,6 +189,7 @@ static struct device_attribute *mmc_dev_attributes[] = { &dev_attr_cid, &dev_attr_csd, + &dev_attr_scr, &dev_attr_date, &dev_attr_fwrev, &dev_attr_hwrev, @@ -229,7 +245,9 @@ static int __init mmc_init(void) { - return bus_register(&mmc_bus_type); + int rc = 0; + rc = bus_register(&mmc_bus_type); + return(rc); } static void __exit mmc_exit(void) diff -wur linux-2.6.10/drivers/mmc/mmci.c linux-2.6.10-lab/drivers/mmc/mmci.c --- linux-2.6.10/drivers/mmc/mmci.c 2004-12-24 16:35:23.000000000 -0500 +++ linux-2.6.10-lab/drivers/mmc/mmci.c 2007-10-04 19:10:37.000000000 -0400 @@ -37,6 +37,12 @@ #define DBG(host,fmt,args...) do { } while (0) #endif +#if defined(CONFIG_MMC_DEBUG) || defined(CONFIG_PM_DEBUG) +#define pinfo(x...) printk(x) +#else +#define pinfo(x...) do {} while(0) +#endif + static unsigned int fmax = 515633; static void @@ -607,9 +613,12 @@ struct mmc_host *mmc = amba_get_drvdata(dev); int ret = 0; + pinfo("mmci_suspend(%d)\n",state); + if (mmc) { struct mmci_host *host = mmc_priv(mmc); + pinfo("mmci_suspend(%d) calling mmc_suspend_host()\n",state); ret = mmc_suspend_host(mmc, state); if (ret == 0) writel(0, host->base + MMCIMASK0); @@ -623,11 +632,14 @@ struct mmc_host *mmc = amba_get_drvdata(dev); int ret = 0; + pinfo("mmci_resume(%d)\n",state); + if (mmc) { struct mmci_host *host = mmc_priv(mmc); writel(MCI_IRQENABLE, host->base + MMCIMASK0); + pinfo("mmci_resume(%d) calling mmc_resume_host()\n",state); ret = mmc_resume_host(mmc); } diff -wur linux-2.6.10/drivers/mmc/pxamci.c linux-2.6.10-lab/drivers/mmc/pxamci.c --- linux-2.6.10/drivers/mmc/pxamci.c 2004-12-24 16:35:18.000000000 -0500 +++ linux-2.6.10-lab/drivers/mmc/pxamci.c 2007-10-04 19:10:37.000000000 -0400 @@ -15,6 +15,8 @@ * * 1 and 3 byte data transfers not supported * max block length up to 1023 + * + * Lab126 changes Copyright (C) 2005, 2006 Lab126, Inc. */ #include #include @@ -27,6 +29,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -36,18 +43,45 @@ #include #include +#ifdef CONFIG_ARCH_LAB126 +#ifdef CONFIG_ARCH_FIONA +#include +#ifdef CONFIG_FIONA_PM_MMC +#include +#endif +#else +#error unsupported board configuration +#endif + +#include +#endif + #include "pxamci.h" #ifdef CONFIG_MMC_DEBUG -#define DBG(x...) printk(KERN_DEBUG x) +//#define DBG(x...) printk(KERN_DEBUG x) +#define _DBG(x...) do { } while (0) +#define DBG(x...) printk(x) +#define MDEBUG(x...) printk(x) #else +#define _DBG(x...) do { } while (0) #define DBG(x...) do { } while (0) +#define MDEBUG(x...) do { } while (0) +#endif + +#if defined(CONFIG_MMC_DEBUG) || defined(CONFIG_PM_DEBUG) +#define pinfo(x...) printk(x) +#else +#define pinfo(x...) do {} while(0) #endif #define DRIVER_NAME "pxa2xx-mci" #define NR_SG 1 +extern int mmc_suspend_host(struct mmc_host *host, u32 state); +extern int mmc_resume_host(struct mmc_host *host); + struct pxamci_host { struct mmc_host *mmc; spinlock_t lock; @@ -79,6 +113,7 @@ static void pxamci_stop_clock(struct pxamci_host *host) { + _DBG("PXAMCI: pxamci_stop_clock called \n"); if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { unsigned long timeout = 10000; unsigned int v; @@ -173,7 +208,11 @@ static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) { + +#ifndef CONFIG_ARCH_LAB126 WARN_ON(host->cmd != NULL); +#endif + host->cmd = cmd; if (cmd->flags & MMC_RSP_BUSY) @@ -206,7 +245,7 @@ static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) { - DBG("PXAMCI: request done\n"); + _DBG("PXAMCI: request done\n"); host->mrq = NULL; host->cmd = NULL; host->data = NULL; @@ -277,8 +316,7 @@ return 0; DCSR(host->dma) = 0; - dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, - host->dma_dir); + dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, host->dma_dir); if (stat & STAT_READ_TIME_OUT) data->error = MMC_ERR_TIMEOUT; @@ -317,12 +355,12 @@ ireg = readl(host->base + MMC_I_REG); - DBG("PXAMCI: irq %08x\n", ireg); + _DBG("PXAMCI: irq %08x\n", ireg); if (ireg) { unsigned stat = readl(host->base + MMC_STAT); - DBG("PXAMCI: stat %08x\n", stat); + _DBG("PXAMCI: stat %08x\n", stat); if (ireg & END_CMD_RES) handled |= pxamci_cmd_done(host, stat); @@ -338,7 +376,10 @@ struct pxamci_host *host = mmc_priv(mmc); unsigned int cmdat; +#ifndef CONFIG_ARCH_LAB126 + /* mrq can be NULL on card abort case */ WARN_ON(host->mrq != NULL); +#endif host->mrq = mrq; @@ -362,6 +403,17 @@ pxamci_start_cmd(host, mrq->cmd, cmdat); } +static int pxamci_get_ro(struct mmc_host *mmc) +{ + struct pxamci_host *host = mmc_priv(mmc); + + if (host->pdata && host->pdata->get_ro) + return host->pdata->get_ro(mmc->dev); + + /* Host doesn't support read only detection so assume writeable */ + return 0; +} + static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct pxamci_host *host = mmc_priv(mmc); @@ -372,9 +424,9 @@ if (ios->clock) { unsigned int clk = CLOCKRATE / ios->clock; - if (CLOCKRATE / clk > ios->clock) - clk <<= 1; + if(clk > (1<<6)) clk = (1<<6); host->clkrt = fls(clk) - 1; + MDEBUG("PXAMCI: Starting HW clock in pxamci_set_ioc\n"); pxa_set_cken(CKEN12_MMC, 1); /* @@ -382,6 +434,7 @@ */ } else { pxamci_stop_clock(host); + MDEBUG("PXAMCI: Stopping HW clock in pxamci_set_ioc\n"); pxa_set_cken(CKEN12_MMC, 0); } @@ -399,9 +452,346 @@ host->clkrt, host->cmdat); } +#ifdef CONFIG_ARCH_LAB126 + +void pxamci_clear(struct mmc_host *mmc) +{ + struct pxamci_host *host = mmc_priv(mmc); + + pxamci_stop_clock(host); + writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| + END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, + host->base + MMC_I_MASK); + + DRCMRRXMMC = 0; + DRCMRTXMMC = 0; +} + +int pxamci_card_inserted(void) +{ + return mmc_query_insertion_state(); +} + +#define MMC_NOTIFY_THREAD "mmcdd" + +static DECLARE_COMPLETION(mmc_detect_thread_exited); + +static struct { + pid_t thread_pid; + wait_queue_head_t event_wq; + unsigned int event_count; +} mmc_detect_data; + +#undef NOTIFY_SEM + +#ifdef NOTIFY_SEM +static void mmc_detect_notify_sem(void) +{ + int sem_id; + + // retrieve the notification semaphore + sem_id = sys_semget(MMC_NOTIFY_SEM_KEY, 1, 0666); + if (sem_id >= 0) { + struct sembuf sem_operations[1]; + + // signal the semaphore + sem_operations[0].sem_num = 0; // which semaphore to use + sem_operations[0].sem_op = 1; // add one from the semaphore value + sem_operations[0].sem_flg = 0; // set wait flag + + // do the signal + sys_semop(sem_id, sem_operations, 1); + + } else { + // semaphore doesn't exist; ignore as nobody may be waiting on it + + } +} +#endif + +static void mmc_detect_notify(int enabled, int notify) +{ + int err; + + char *envp[] = { + "HOME=/", + "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + NULL + }; + + char *argv[] = { + MMC_NOTIFY_SCRIPT, + enabled ? "1" : "0", + notify ? "1" : "0", + NULL + }; + + MDEBUG("mmc_detect_notify(CARD_%s)\n", (enabled ? "INSERTED" : "REMOVED")); + if ((err = call_usermodehelper(argv[0], argv, envp, 0)) < 0) { + printk("mmc: notification exec failed: \"" MMC_NOTIFY_SCRIPT "\", err %d\n", err); + } +} + +#ifdef CONFIG_FIONA_PM_MMC +static void mmc_detect_notify_signal(void); + +struct mmc_host *g_pm_mmc_resume_host = NULL; + +static int pm_mmc_wake_notify = 0; +static int pm_mmc_power_mode = FPOW_MODE_ON; + +static int mmc_bus_fpow_getmode(void *private); +static FPOW_ERR mmc_bus_fpow_setmode(void *private, u32 state, u32 mode); + +static fpow_component *mmc_fpow_dev = NULL; + +static int mmc_register_with_fpow(struct device *dev, fpow_component **fpow_dev) +{ + struct fpow_registration_rec reg; + int rc = 0; + + memclr(®, sizeof(reg)); + strcpy((char*)®.name, "mmc"); + + reg.device_class = FPOW_CLASS_MMC; + reg.supported_modes = FPOW_MODE_ON_SUPPORTED | FPOW_MODE_SLEEP_SUPPORTED | FPOW_MODE_OFF_SUPPORTED; + reg.private = (void *)dev; + reg.getmode = mmc_bus_fpow_getmode; + reg.setmode = mmc_bus_fpow_setmode; + *fpow_dev = fpow_register(®); + if (*fpow_dev == NULL) { + printk("MMC: Failed to register with fpow !!\n"); + rc = -1; + } + + return rc; +} + +static FPOW_ERR mmc_bus_fpow_setmode(void *private, u32 state, u32 mode) +{ + FPOW_ERR ret = FPOW_NO_ERR; + + powdebug("mmc_bus_fpow_setmode(mode=%s)\n", fpow_mode_to_str(mode)); + + // if we're already in the correct mode, we don't need to do anything + if (pm_mmc_power_mode != mode) { + + switch (mode) { + + case FPOW_MODE_ON : + pm_mmc_wake_notify = 1; + mmc_detect_notify_signal(); + // (fall through) + + case FPOW_MODE_SLEEP : + case FPOW_MODE_OFF : + pm_mmc_power_mode = mode; + break; + + default : + ret = -EINVAL; + break; + } + + } + + return ret; +} + +static int mmc_bus_fpow_getmode(void *private) +{ + powdebug("mmc_bus_fpow_getmode()\n"); + + return pm_mmc_power_mode; +} + +static void mmc_perform_suspend(void) +{ + // force an unmount of the card, without notification + mmc_detect_notify(0, 0); +} + +static void mmc_perform_resume(void) +{ + if (g_pm_mmc_resume_host != NULL) { + MDEBUG("mmc_perform_resume: host=%p\n", g_pm_mmc_resume_host); + + // force device rescan + mmc_detect_change(g_pm_mmc_resume_host); + flush_scheduled_work(); + + g_pm_mmc_resume_host = NULL; + } +} +#endif + + +#define SETTLE_COUNT_MAX 10 +#define SETTLE_DELAY 10 + +static int mmc_detect_notify_thread(void *arg) +{ + int last_notify = -1; + int settle_count; + + daemonize(MMC_NOTIFY_THREAD); + allow_signal(SIGKILL); + + while (1) { + wait_event_interruptible(mmc_detect_data.event_wq, mmc_detect_data.event_count != 0); + +#ifdef CONFIG_PM + if (current->