diff options
708 files changed, 25843 insertions, 17837 deletions
diff --git a/Documentation/acpi-hotkey.txt b/Documentation/acpi-hotkey.txt deleted file mode 100644 index 38040fa3764..00000000000 --- a/Documentation/acpi-hotkey.txt +++ /dev/null @@ -1,38 +0,0 @@ -driver/acpi/hotkey.c implement: -1. /proc/acpi/hotkey/event_config -(event based hotkey or event config interface): -a. add a event based hotkey(event) : -echo "0:bus::action:method:num:num" > event_config - -b. delete a event based hotkey(event): -echo "1:::::num:num" > event_config - -c. modify a event based hotkey(event): -echo "2:bus::action:method:num:num" > event_config - -2. /proc/acpi/hotkey/poll_config -(polling based hotkey or event config interface): -a.add a polling based hotkey(event) : -echo "0:bus:method:action:method:num" > poll_config -this adding command will create a proc file -/proc/acpi/hotkey/method, which is used to get -result of polling. - -b.delete a polling based hotkey(event): -echo "1:::::num" > event_config - -c.modify a polling based hotkey(event): -echo "2:bus:method:action:method:num" > poll_config - -3./proc/acpi/hotkey/action -(interface to call aml method associated with a -specific hotkey(event)) -echo "event_num:event_type:event_argument" > - /proc/acpi/hotkey/action. -The result of the execution of this aml method is -attached to /proc/acpi/hotkey/poll_method, which is dynamically -created. Please use command "cat /proc/acpi/hotkey/polling_method" -to retrieve it. - -Note: Use cmdline "acpi_generic_hotkey" to over-ride -platform-specific with generic driver. diff --git a/Documentation/arm/Samsung-S3C24XX/DMA.txt b/Documentation/arm/Samsung-S3C24XX/DMA.txt new file mode 100644 index 00000000000..37f4edcc5d8 --- /dev/null +++ b/Documentation/arm/Samsung-S3C24XX/DMA.txt @@ -0,0 +1,46 @@ + S3C2410 DMA + =========== + +Introduction +------------ + + The kernel provides an interface to manage DMA transfers + using the DMA channels in the cpu, so that the central + duty of managing channel mappings, and programming the + channel generators is in one place. + + +DMA Channel Ordering +-------------------- + + Many of the range do not have connections for the DMA + channels to all sources, which means that some devices + have a restricted number of channels that can be used. + + To allow flexibilty for each cpu type and board, the + dma code can be given an dma ordering structure which + allows the order of channel search to be specified, as + well as allowing the prohibition of certain claims. + + struct s3c24xx_dma_order has a list of channels, and + each channel within has a slot for a list of dma + channel numbers. The slots are searched in order, for + the presence of a dma channel number with DMA_CH_VALID + orred in. + + If the order has the flag DMA_CH_NEVER set, then after + checking the channel list, the system will return no + found channel, thus denying the request. + + A board support file can call s3c24xx_dma_order_set() + to register an complete ordering set. The routine will + copy the data, so the original can be discared with + __initdata. + + +Authour +------- + +Ben Dooks, +Copyright (c) 2007 Ben Dooks, Simtec Electronics +Licensed under the GPL v2 diff --git a/Documentation/arm/Samsung-S3C24XX/Overview.txt b/Documentation/arm/Samsung-S3C24XX/Overview.txt index 28d014714ab..c31b76fa66c 100644 --- a/Documentation/arm/Samsung-S3C24XX/Overview.txt +++ b/Documentation/arm/Samsung-S3C24XX/Overview.txt @@ -8,13 +8,10 @@ Introduction The Samsung S3C24XX range of ARM9 System-on-Chip CPUs are supported by the 's3c2410' architecture of ARM Linux. Currently the S3C2410, - S3C2440 and S3C2442 devices are supported. + S3C2412, S3C2413, S3C2440 and S3C2442 devices are supported. Support for the S3C2400 series is in progress. - Support for the S3C2412 and S3C2413 CPUs is being merged. - - Configuration ------------- @@ -26,6 +23,22 @@ Configuration please check the machine specific documentation. +Layout +------ + + The core support files are located in the platform code contained in + arch/arm/plat-s3c24xx with headers in include/asm-arm/plat-s3c24xx. + This directory should be kept to items shared between the platform + code (arch/arm/plat-s3c24xx) and the arch/arm/mach-s3c24* code. + + Each cpu has a directory with the support files for it, and the + machines that carry the device. For example S3C2410 is contained + in arch/arm/mach-s3c2410 and S3C2440 in arch/arm/mach-s3c2440 + + Register, kernel and platform data definitions are held in the + include/asm-arm/arch-s3c2410 directory. + + Machines -------- diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index c585aa8d62b..6a451f47d40 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -253,29 +253,6 @@ Who: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> --------------------------- -<<<<<<< test:Documentation/feature-removal-schedule.txt -What: ACPI hotkey driver (CONFIG_ACPI_HOTKEY) -When: 2.6.21 -Why: hotkey.c was an attempt to consolidate multiple drivers that use - ACPI to implement hotkeys. However, hotkeys are not documented - in the ACPI specification, so the drivers used undocumented - vendor-specific hooks and turned out to be more different than - the same. - - Further, the keys and the features supplied by each platform - are different, so there will always be a need for - platform-specific drivers. - - So the new plan is to delete hotkey.c and instead, work on the - platform specific drivers to try to make them look the same - to the user when they supply the same features. - - hotkey.c has always depended on CONFIG_EXPERIMENTAL - -Who: Len Brown <len.brown@intel.com> - ---------------------------- - What: /sys/firmware/acpi/namespace When: 2.6.21 Why: The ACPI namespace is effectively the symbol list for @@ -306,13 +283,6 @@ Who: Len Brown <len.brown@intel.com> --------------------------- -What: JFFS (version 1) -When: 2.6.21 -Why: Unmaintained for years, superceded by JFFS2 for years. -Who: Jeff Garzik <jeff@garzik.org> - ---------------------------- - What: sk98lin network driver When: July 2007 Why: In kernel tree version of driver is unmaintained. Sk98lin driver diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index f6a3961da34..c479d30eeaa 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -48,6 +48,7 @@ parameter is applicable: ISAPNP ISA PnP code is enabled. ISDN Appropriate ISDN support is enabled. JOY Appropriate joystick support is enabled. + LIBATA Libata driver is enabled LP Printer support is enabled. LOOP Loopback device support is enabled. M68k M68k architecture is enabled. @@ -1045,6 +1046,10 @@ and is between 256 and 4096 characters. It is defined in the file emulation library even if a 387 maths coprocessor is present. + noacpi [LIBATA] Disables use of ACPI in libata suspend/resume + when set. + Format: <int> + noaliencache [MM, NUMA] Disables the allcoation of alien caches in the slab allocator. Saves per-node memory, but will impact performance on real NUMA hardware. @@ -1282,6 +1287,12 @@ and is between 256 and 4096 characters. It is defined in the file This sorting is done to get a device order compatible with older (<= 2.4) kernels. nobfsort Don't sort PCI devices into breadth-first order. + cbiosize=nn[KMG] The fixed amount of bus space which is + reserved for the CardBus bridge's IO window. + The default value is 256 bytes. + cbmemsize=nn[KMG] The fixed amount of bus space which is + reserved for the CardBus bridge's memory + window. The default value is 64 megabytes. pcmv= [HW,PCMCIA] BadgePAD 4 diff --git a/Documentation/pci.txt b/Documentation/pci.txt index fd5028eca13..cdf2f3c0ab1 100644 --- a/Documentation/pci.txt +++ b/Documentation/pci.txt @@ -205,8 +205,8 @@ Tips on when/where to use the above attributes: exclusively called by the probe() routine, can be marked __devinit. Ditto for remove() and __devexit. - o If mydriver_probe() is marked with __devinit(), then all address - references to mydriver_probe must use __devexit_p(mydriver_probe) + o If mydriver_remove() is marked with __devexit(), then all address + references to mydriver_remove must use __devexit_p(mydriver_remove) (in the struct pci_driver declaration for example). __devexit_p() will generate the function name _or_ NULL if the function will be discarded. For an example, see drivers/net/tg3.c. diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 3b514672b80..b41397d6430 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -497,7 +497,7 @@ looks like in practice. | |- device_type = "cpu" | |- reg = <0> | |- clock-frequency = <5f5e1000> - | |- linux,boot-cpu + | |- 64-bit | |- linux,phandle = <2> | o memory@0 @@ -509,7 +509,6 @@ looks like in practice. o chosen |- name = "chosen" |- bootargs = "root=/dev/sda2" - |- linux,platform = <00000600> |- linux,phandle = <4> This tree is almost a minimal tree. It pretty much contains the @@ -519,7 +518,7 @@ physical memory layout. It also includes misc information passed through /chosen, like in this example, the platform type (mandatory) and the kernel command line arguments (optional). -The /cpus/PowerPC,970@0/linux,boot-cpu property is an example of a +The /cpus/PowerPC,970@0/64-bit property is an example of a property without a value. All other properties have a value. The significance of the #address-cells and #size-cells properties will be explained in chapter IV which defines precisely the required nodes and @@ -733,8 +732,7 @@ address which can extend beyond that limit. that typically get driven by the same platform code in the kernel, you would use a different "model" property but put a value in "compatible". The kernel doesn't directly use that - value (see /chosen/linux,platform for how the kernel chooses a - platform type) but it is generally useful. + value but it is generally useful. The root node is also generally where you add additional properties specific to your board like the serial number if any, that sort of @@ -778,7 +776,6 @@ address which can extend beyond that limit. bytes - d-cache-size : one cell, size of L1 data cache in bytes - i-cache-size : one cell, size of L1 instruction cache in bytes - - linux, boot-cpu : Should be defined if this cpu is the boot cpu. Recommended properties: @@ -843,11 +840,6 @@ address which can extend beyond that limit. the prom_init() trampoline when booting with an OF client interface, but that you have to provide yourself when using the flattened format. - Required properties: - - - linux,platform : This is your platform number as assigned by the - architecture maintainers - Recommended properties: - bootargs : This zero-terminated string is passed as the kernel diff --git a/Documentation/sony-laptop.txt b/Documentation/sony-laptop.txt new file mode 100644 index 00000000000..dfd26df056f --- /dev/null +++ b/Documentation/sony-laptop.txt @@ -0,0 +1,106 @@ +Sony Notebook Control Driver (SNC) Readme +----------------------------------------- + Copyright (C) 2004- 2005 Stelian Pop <stelian@popies.net> + Copyright (C) 2007 Mattia Dongili <malattia@linux.it> + +This mini-driver drives the SNC device present in the ACPI BIOS of +the Sony Vaio laptops. + +It gives access to some extra laptop functionalities. In its current +form, this driver let the user set or query the screen brightness +through the backlight subsystem and remove/apply power to some devices. + +Backlight control: +------------------ +If your laptop model supports it, you will find sysfs files in the +/sys/class/backlight/sony/ +directory. You will be able to query and set the current screen +brightness: + brightness get/set screen brightness (an iteger + between 0 and 7) + actual_brightness reading from this file will query the HW + to get real brightness value + max_brightness the maximum brightness value + + +Platform specific: +------------------ +Loading the sony-laptop module will create a +/sys/devices/platform/sony-laptop/ +directory populated with some files. + +You then read/write integer values from/to those files by using +standard UNIX tools. + +The files are: + brightness_default screen brightness which will be set + when the laptop will be rebooted + cdpower power on/off the internal CD drive + audiopower power on/off the internal sound card + lanpower power on/off the internal ethernet card + (only in debug mode) + +Note that some files may be missing if they are not supported +by your particular laptop model. + +Example usage: + # echo "1" > /sys/devices/platform/sony-laptop/brightness_default +sets the lowest screen brightness for the next and later reboots, + # echo "8" > /sys/devices/platform/sony-laptop/brightness_default +sets the highest screen brightness for the next and later reboots, + # cat /sys/devices/platform/sony-laptop/brightness_default +retrieves the value. + + # echo "0" > /sys/devices/platform/sony-laptop/audiopower +powers off the sound card, + # echo "1" > /sys/devices/platform/sony-laptop/audiopower +powers on the sound card. + +Development: +------------ + +If you want to help with the development of this driver (and +you are not afraid of any side effects doing strange things with +your ACPI BIOS could have on your laptop), load the driver and +pass the option 'debug=1'. + +REPEAT: DON'T DO THIS IF YOU DON'T LIKE RISKY BUSINESS. + +In your kernel logs you will find the list of all ACPI methods +the SNC device has on your laptop. You can see the GCDP/GCDP methods +used to pwer on/off the CD drive, but there are others. + +I HAVE NO IDEA WHAT THOSE METHODS DO. + +The sony-laptop driver creates, for some of those methods (the most +current ones found on several Vaio models), an entry under +/sys/devices/platform/sony-laptop, just like the 'cdpower' one. +You can create other entries corresponding to your own laptop methods by +further editing the source (see the 'sony_acpi_values' table, and add a new +entry to this table with your get/set method names using the +HANDLE_NAMES macro). + +Your mission, should you accept it, is to try finding out what +those entries are for, by reading/writing random values from/to those +files and find out what is the impact on your laptop. + +Should you find anything interesting, please report it back to me, +I will not disavow all knowledge of your actions :) + +Bugs/Limitations: +----------------- + +* This driver is not based on official documentation from Sony + (because there is none), so there is no guarantee this driver + will work at all, or do the right thing. Although this hasn't + happened to me, this driver could do very bad things to your + laptop, including permanent damage. + +* The sony-laptop and sonypi drivers do not interact at all. In the + future, sonypi could use sony-laptop to do (part of) its business. + +* spicctrl, which is the userspace tool used to communicate with the + sonypi driver (through /dev/sonypi) does not try to use the + sony-laptop driver. In the future, spicctrl could try sonypi first, + and if it isn't present, try sony-laptop instead. + diff --git a/MAINTAINERS b/MAINTAINERS index b0fd71b3f66..270c6b006b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -247,6 +247,13 @@ L: linux-acpi@vger.kernel.org W: http://acpi.sourceforge.net/ S: Supported +ACPI VIDEO DRIVER +P: Luming Yu +M: luming.yu@intel.com +L: linux-acpi@vger.kernel.org +W: http://acpi.sourceforge.net/ +S: Supported + AD1816 SOUND DRIVER P: Thorsten Knabe M: Thorsten Knabe <linux@thorsten-knabe.de> @@ -2623,8 +2630,8 @@ T: git kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git S: Maintained PCNET32 NETWORK DRIVER -P: Thomas Bogendörfer -M: tsbogend@alpha.franken.de +P: Don Fry +M: pcnet32@verizon.net L: netdev@vger.kernel.org S: Maintained @@ -3061,6 +3068,8 @@ S: Maintained SONY VAIO CONTROL DEVICE DRIVER P: Stelian Pop M: stelian@popies.net +P: Mattia Dongili +M: malattia@linux.it W: http://popies.net/sonypi/ S: Maintained diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 77d062eaf08..4409561ea32 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -245,6 +245,8 @@ config ARCH_IOP33X config ARCH_IOP13XX bool "IOP13xx-based" + depends on MMU + select PLAT_IOP select PCI help Support for Intel's IOP13XX (XScale) family of processors. @@ -283,6 +285,14 @@ config ARCH_L7200 If you have any questions or comments about the Linux kernel port to this board, send e-mail to <sjhill@cotw.com>. +config ARCH_NS9XXX + bool "NetSilicon NS9xxx" + help + Say Y here if you intend to run this kernel on a NetSilicon NS9xxx + System. + + <http://www.digi.com/products/microprocessors/index.jsp> + config ARCH_PNX4008 bool "Philips Nexperia PNX4008 Mobile" help @@ -292,6 +302,7 @@ config ARCH_PXA bool "PXA2xx-based" depends on MMU select ARCH_MTD_XIP + select GENERIC_TIME help Support for Intel's PXA2XX processor line. @@ -316,7 +327,7 @@ config ARCH_SA1100 Support for StrongARM 11x0 based boards. config ARCH_S3C2410 - bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442" + bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443" help Samsung S3C2410X CPU based systems, such as the Simtec Electronics BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or @@ -376,7 +387,16 @@ source "arch/arm/mach-omap1/Kconfig" source "arch/arm/mach-omap2/Kconfig" +source "arch/arm/plat-s3c24xx/Kconfig" + +if ARCH_S3C2410 +source "arch/arm/mach-s3c2400/Kconfig" source "arch/arm/mach-s3c2410/Kconfig" +source "arch/arm/mach-s3c2412/Kconfig" +source "arch/arm/mach-s3c2440/Kconfig" +source "arch/arm/mach-s3c2442/Kconfig" +source "arch/arm/mach-s3c2443/Kconfig" +endif source "arch/arm/mach-lh7a40x/Kconfig" @@ -390,10 +410,12 @@ source "arch/arm/mach-aaec2000/Kconfig" source "arch/arm/mach-realview/Kconfig" -source "arch/arm/mach-at91rm9200/Kconfig" +source "arch/arm/mach-at91/Kconfig" source "arch/arm/mach-netx/Kconfig" +source "arch/arm/mach-ns9xxx/Kconfig" + # Definitions to make life easier config ARCH_ACORN bool @@ -751,6 +773,20 @@ config XIP_PHYS_ADDR be linked for and stored to. This address is dependent on your own flash usage. +config KEXEC + bool "Kexec system call (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but it is indepedent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + It is an ongoing process to be certain the hardware in a machine + is properly shutdown, so do not be surprised if this code does not + initially work for you. It may help to enable device hotplugging + support. + endmenu if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX ) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 000f1100b55..1320418b5d6 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -124,10 +124,12 @@ endif machine-$(CONFIG_ARCH_H720X) := h720x machine-$(CONFIG_ARCH_AAEC2000) := aaec2000 machine-$(CONFIG_ARCH_REALVIEW) := realview - machine-$(CONFIG_ARCH_AT91) := at91rm9200 - machine-$(CONFIG_ARCH_EP93XX) := ep93xx - machine-$(CONFIG_ARCH_PNX4008) := pnx4008 - machine-$(CONFIG_ARCH_NETX) := netx + machine-$(CONFIG_ARCH_AT91) := at91rm9200 + machine-$(CONFIG_ARCH_EP93XX) := ep93xx + machine-$(CONFIG_ARCH_PNX4008) := pnx4008 + machine-$(CONFIG_ARCH_NETX) := netx + machine-$(CONFIG_ARCH_NS9XXX) := ns9xxx + textofs-$(CONFIG_ARCH_NS9XXX) := 0x00108000 ifeq ($(CONFIG_ARCH_EBSA110),y) # This is what happens if you forget the IOCS16 line. @@ -149,7 +151,7 @@ MACHINE := arch/arm/mach-$(machine-y)/ else MACHINE := endif - + export TEXT_OFFSET GZFLAGS MMUEXT # Do we have FASTFPE? @@ -161,6 +163,11 @@ endif # If we have a machine-specific directory, then include it in the build. core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ core-y += $(MACHINE) +core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2400/ +core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2412/ +core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2440/ +core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2442/ +core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2443/ core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) core-$(CONFIG_VFP) += arch/arm/vfp/ @@ -168,6 +175,7 @@ core-$(CONFIG_VFP) += arch/arm/vfp/ # If we have a common platform directory, then include it in the build. core-$(CONFIG_PLAT_IOP) += arch/arm/plat-iop/ core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/ +core-$(CONFIG_PLAT_S3C24XX) += arch/arm/plat-s3c24xx/ drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/ drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/ diff --git a/arch/arm/boot/.gitignore b/arch/arm/boot/.gitignore new file mode 100644 index 00000000000..171a0853caf --- /dev/null +++ b/arch/arm/boot/.gitignore @@ -0,0 +1,2 @@ +Image +zImage diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore new file mode 100644 index 00000000000..aefee20cbf9 --- /dev/null +++ b/arch/arm/boot/compressed/.gitignore @@ -0,0 +1 @@ +piggy.gz diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 2e635b814c1..6fbe7722aa4 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -32,7 +32,6 @@ #include <asm/cacheflush.h> -#undef DEBUG #undef STATS #ifdef STATS @@ -66,14 +65,13 @@ struct dmabounce_pool { }; struct dmabounce_device_info { - struct list_head node; - struct device *dev; struct list_head safe_buffers; #ifdef STATS unsigned long total_allocs; unsigned long map_op_count; unsigned long bounce_count; + int attr_res; #endif struct dmabounce_pool small; struct dmabounce_pool large; @@ -81,33 +79,23 @@ struct dmabounce_device_info { rwlock_t lock; }; -static LIST_HEAD(dmabounce_devs); - #ifdef STATS -static void print_alloc_stats(struct dmabounce_device_info *device_info) +static ssize_t dmabounce_show(struct device *dev, struct device_attribute *attr, + char *buf) { - printk(KERN_INFO - "%s: dmabounce: sbp: %lu, lbp: %lu, other: %lu, total: %lu\n", - device_info->dev->bus_id, - device_info->small.allocs, device_info->large.allocs, + struct dmabounce_device_info *device_info = dev->archdata.dmabounce; + return sprintf(buf, "%lu %lu %lu %lu %lu %lu\n", + device_info->small.allocs, + device_info->large.allocs, device_info->total_allocs - device_info->small.allocs - device_info->large.allocs, - device_info->total_allocs); + device_info->total_allocs, + device_info->map_op_count, + device_info->bounce_count); } -#endif - -/* find the given device in the dmabounce device list */ -static inline struct dmabounce_device_info * -find_dmabounce_dev(struct device *dev) -{ - struct dmabounce_device_info *d; - list_for_each_entry(d, &dmabounce_devs, node) - if (d->dev == dev) - return d; - - return NULL; -} +static DEVICE_ATTR(dmabounce_stats, 0400, dmabounce_show, NULL); +#endif /* allocate a 'safe' buffer and keep track of it */ @@ -162,8 +150,6 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr, if (pool) pool->allocs++; device_info->total_allocs++; - if (device_info->total_allocs % 1000 == 0) - print_alloc_stats(device_info); #endif write_lock_irqsave(&device_info->lock, flags); @@ -218,20 +204,11 @@ free_safe_buffer(struct dmabounce_device_info *device_info, struct safe_buffer * /* ************************************************** */ -#ifdef STATS -static void print_map_stats(struct dmabounce_device_info *device_info) -{ - dev_info(device_info->dev, - "dmabounce: map_op_count=%lu, bounce_count=%lu\n", - device_info->map_op_count, device_info->bounce_count); -} -#endif - static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction dir) { - struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); + struct dmabounce_device_info *device_info = dev->archdata.dmabounce; dma_addr_t dma_addr; int needs_bounce = 0; @@ -281,10 +258,14 @@ map_single(struct device *dev, void *ptr, size_t size, ptr = buf->safe; dma_addr = buf->safe_dma_addr; + } else { + /* + * We don't need to sync the DMA buffer since + * it was allocated via the coherent allocators. + */ + consistent_sync(ptr, size, dir); } - consistent_sync(ptr, size, dir); - return dma_addr; } @@ -292,7 +273,7 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { - struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); + struct dmabounce_device_info *device_info = dev->archdata.dmabounce; struct safe_buffer *buf = NULL; /* @@ -317,12 +298,12 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, DO_STATS ( device_info->bounce_count++ ); if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { - unsigned long ptr; + void *ptr = buf->ptr; dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n", - __func__, buf->safe, buf->ptr, size); - memcpy(buf->ptr, buf->safe, size); + __func__, buf->safe, ptr, size); + memcpy(ptr, buf->safe, size); /* * DMA buffers must have the same cache properties @@ -332,8 +313,8 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, * bidirectional case because we know the cache * lines will be coherent with the data written. */ - ptr = (unsigned long)buf->ptr; dmac_clean_range(ptr, ptr + size); + outer_clean_range(__pa(ptr), __pa(ptr) + size); } free_safe_buffer(device_info, buf); } @@ -343,7 +324,7 @@ static inline void sync_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { - struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); + struct dmabounce_device_info *device_info = dev->archdata.dmabounce; struct safe_buffer *buf = NULL; if (device_info) @@ -397,7 +378,10 @@ sync_single(struct device *dev, dma_addr_t dma_addr, size_t size, default: BUG(); } - consistent_sync(buf->safe, size, dir); + /* + * No need to sync the safe buffer - it was allocated + * via the coherent allocators. + */ } else { consistent_sync(dma_to_virt(dev, dma_addr), size, dir); } @@ -604,9 +588,10 @@ dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, device_info->total_allocs = 0; device_info->map_op_count = 0; device_info->bounce_count = 0; + device_info->attr_res = device_create_file(dev, &dev_attr_dmabounce_stats); #endif - list_add(&device_info->node, &dmabounce_devs); + dev->archdata.dmabounce = device_info; printk(KERN_INFO "dmabounce: registered device %s on %s bus\n", dev->bus_id, dev->bus->name); @@ -623,7 +608,9 @@ dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, void dmabounce_unregister_dev(struct device *dev) { - struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); + struct dmabounce_device_info *device_info = dev->archdata.dmabounce; + + dev->archdata.dmabounce = NULL; if (!device_info) { printk(KERN_WARNING @@ -645,12 +632,10 @@ dmabounce_unregister_dev(struct device *dev) dma_pool_destroy(device_info->large.pool); #ifdef STATS - print_alloc_stats(device_info); - print_map_stats(device_info); + if (device_info->attr_res == 0) + device_remove_file(dev, &dev_attr_dmabounce_stats); #endif - list_del(&device_info->node); - kfree(device_info); printk(KERN_INFO "dmabounce: device %s on %s bus unregistered\n", diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 09b9d1b6844..4deece5fbdf 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -14,7 +14,9 @@ * * o There is one CPU Interface per CPU, which sends interrupts sent * by the Distributor, and interrupts generated locally, to the - * associated CPU. + * associated CPU. The base address of the CPU interface is usually + * aliased so that the same address points to different chips depending + * on the CPU it is accessed from. * * Note that IRQs 0-31 are special - they are local to each CPU. * As such, the enable set/clear, pending set/clear and active bit @@ -31,10 +33,38 @@ #include <asm/mach/irq.h> #include <asm/hardware/gic.h> -static void __iomem *gic_dist_base; -static void __iomem *gic_cpu_base; static DEFINE_SPINLOCK(irq_controller_lock); +struct gic_chip_data { + unsigned int irq_offset; + void __iomem *dist_base; + void __iomem *cpu_base; +}; + +#ifndef MAX_GIC_NR +#define MAX_GIC_NR 1 +#endif + +static struct gic_chip_data gic_data[MAX_GIC_NR]; + +static inline void __iomem *gic_dist_base(unsigned int irq) +{ + struct gic_chip_data *gic_data = get_irq_chip_data(irq); + return gic_data->dist_base; +} + +static inline void __iomem *gic_cpu_base(unsigned int irq) +{ + struct gic_chip_data *gic_data = get_irq_chip_data(irq); + return gic_data->cpu_base; +} + +static inline unsigned int gic_irq(unsigned int irq) +{ + struct gic_chip_data *gic_data = get_irq_chip_data(irq); + return irq - gic_data->irq_offset; +} + /* * Routines to acknowledge, disable and enable interrupts * @@ -55,8 +85,8 @@ static void gic_ack_irq(unsigned int irq) u32 mask = 1 << (irq % 32); spin_lock(&irq_controller_lock); - writel(mask, gic_dist_base + GIC_DIST_ENABLE_CLEAR + (irq / 32) * 4); - writel(irq, gic_cpu_base + GIC_CPU_EOI); + writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_CLEAR + (gic_irq(irq) / 32) * 4); + writel(gic_irq(irq), gic_cpu_base(irq) + GIC_CPU_EOI); spin_unlock(&irq_controller_lock); } @@ -65,7 +95,7 @@ static void gic_mask_irq(unsigned int irq) u32 mask = 1 << (irq % 32); spin_lock(&irq_controller_lock); - writel(mask, gic_dist_base + GIC_DIST_ENABLE_CLEAR + (irq / 32) * 4); + writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_CLEAR + (gic_irq(irq) / 32) * 4); spin_unlock(&irq_controller_lock); } @@ -74,14 +104,14 @@ static void gic_unmask_irq(unsigned int irq) u32 mask = 1 << (irq % 32); spin_lock(&irq_controller_lock); - writel(mask, gic_dist_base + GIC_DIST_ENABLE_SET + (irq / 32) * 4); + writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_SET + (gic_irq(irq) / 32) * 4); spin_unlock(&irq_controller_lock); } #ifdef CONFIG_SMP static void gic_set_cpu(unsigned int irq, cpumask_t mask_val) { - void __iomem *reg = gic_dist_base + GIC_DIST_TARGET + (irq & ~3); + void __iomem *reg = gic_dist_base(irq) + GIC_DIST_TARGET + (gic_irq(irq) & ~3); unsigned int shift = (irq % 4) * 8; unsigned int cpu = first_cpu(mask_val); u32 val; @@ -95,6 +125,37 @@ static void gic_set_cpu(unsigned int irq, cpumask_t mask_val) } #endif +static void fastcall gic_handle_cascade_irq(unsigned int irq, + struct irq_desc *desc) +{ + struct gic_chip_data *chip_data = get_irq_data(irq); + struct irq_chip *chip = get_irq_chip(irq); + unsigned int cascade_irq; + unsigned long status; + + /* primary controller ack'ing */ + chip->ack(irq); + + spin_lock(&irq_controller_lock); + status = readl(chip_data->cpu_base + GIC_CPU_INTACK); + spin_unlock(&irq_controller_lock); + + cascade_irq = (status & 0x3ff); + if (cascade_irq > 1020) + goto out; + if (cascade_irq < 32 || cascade_irq >= NR_IRQS) { + do_bad_IRQ(cascade_irq, desc); + goto out; + } + + cascade_irq += chip_data->irq_offset; + generic_handle_irq(cascade_irq); + + out: + /* primary controller unmasking */ + chip->unmask(irq); +} + static struct irq_chip gic_chip = { .name = "GIC", .ack = gic_ack_irq, @@ -105,15 +166,29 @@ static struct irq_chip gic_chip = { #endif }; -void __init gic_dist_init(void __iomem *base) +void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) +{ + if (gic_nr >= MAX_GIC_NR) + BUG(); + if (set_irq_data(irq, &gic_data[gic_nr]) != 0) + BUG(); + set_irq_chained_handler(irq, gic_handle_cascade_irq); +} + +void __init gic_dist_init(unsigned int gic_nr, void __iomem *base, + unsigned int irq_start) { unsigned int max_irq, i; u32 cpumask = 1 << smp_processor_id(); + if (gic_nr >= MAX_GIC_NR) + BUG(); + cpumask |= cpumask << 8; cpumask |= cpumask << 16; - gic_dist_base = base; + gic_data[gic_nr].dist_base = base; + gic_data[gic_nr].irq_offset = (irq_start - 1) & ~31; writel(0, base + GIC_DIST_CTRL); @@ -158,8 +233,9 @@ void __init gic_dist_init(void __iomem *base) /* * Setup the Linux IRQ subsystem. */ - for (i = 29; i < max_irq; i++) { + for (i = irq_start; i < gic_data[gic_nr].irq_offset + max_irq; i++) { set_irq_chip(i, &gic_chip); + set_irq_chip_data(i, &gic_data[gic_nr]); set_irq_handler(i, handle_level_irq); set_irq_flags(i, IRQF_VALID | IRQF_PROBE); } @@ -167,9 +243,13 @@ void __init gic_dist_init(void __iomem *base) writel(1, base + GIC_DIST_CTRL); } -void __cpuinit gic_cpu_init(void __iomem *base) +void __cpuinit gic_cpu_init(unsigned int gic_nr, void __iomem *base) { - gic_cpu_base = base; + if (gic_nr >= MAX_GIC_NR) + BUG(); + + gic_data[gic_nr].cpu_base = base; + writel(0xf0, base + GIC_CPU_PRIMASK); writel(1, base + GIC_CPU_CTRL); } @@ -179,6 +259,7 @@ void gic_raise_softirq(cpumask_t cpumask, unsigned int irq) { unsigned long map = *cpus_addr(cpumask); - writel(map << 16 | irq, gic_dist_base + GIC_DIST_SOFTINT); + /* this always happens on GIC0 */ + writel(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT); } #endif diff --git a/arch/arm/configs/at91sam9263ek_defconfig b/arch/arm/configs/at91sam9263ek_defconfig new file mode 100644 index 00000000000..c72ab82873d --- /dev/null +++ b/arch/arm/configs/at91sam9263ek_defconfig @@ -0,0 +1,1184 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.20-rc1 +# Mon Jan 8 16:06:54 2007 +# +CONFIG_ARM=y +# CONFIG_GENERIC_TIME is not set +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SHMEM=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +CONFIG_ARCH_AT91=y +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set + +# +# Atmel AT91 System-on-Chip +# +# CONFIG_ARCH_AT91RM9200 is not set +# CONFIG_ARCH_AT91SAM9260 is not set +# CONFIG_ARCH_AT91SAM9261 is not set +CONFIG_ARCH_AT91SAM9263=y + +# +# AT91SAM9263 Board Type +# +CONFIG_MACH_AT91SAM9263EK=y + +# +# AT91 Board Options +# +CONFIG_MTD_AT91_DATAFLASH_CARD=y +# CONFIG_MTD_NAND_AT91_BUSWIDTH_16 is not set + +# +# AT91 Feature Selections +# +# CONFIG_AT91_PROGRAMMABLE_CLOCKS is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set + +# +# Bus support +# + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +# CONFIG_PREEMPT is not set +# CONFIG_NO_IDLE_HZ is not set +CONFIG_HZ=100 +# CONFIG_AEABI is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_RESOURCES_64BIT is not set +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="mem=64M console=ttyS0,115200 initrd=0x21100000,3145728 root=/dev/ram0 rw" +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +# CONFIG_VFP is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set +# CONFIG_APM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_DATAFLASH=y +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +CONFIG_MTD_NAND_AT91=y +# CONFIG_MTD_NAND_NANDSIM is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_TSDEV=y +CONFIG_INPUT_TSDEV_SCREEN_X=240 +CONFIG_INPUT_TSDEV_SCREEN_Y=320 +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=y +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_UCB1400 is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +# CONFIG_SERIAL_ATMEL_TTYAT is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_NVRAM is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +CONFIG_I2C_AT91=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_PCA is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_ATMEL=y +# CONFIG_SPI_BITBANG is not set + +# +# SPI Protocol Masters +# + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set +# CONFIG_USB_DABUSB is not set + +# +# Graphics support +# +# CONFIG_FIRMWARE_EDID is not set +CONFIG_FB=y +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE is not set + +# +# Logo configuration +# +# CONFIG_LOGO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# HID Devices +# +CONFIG_HID=y + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB_ARCH_HAS_EHCI is not set +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_MULTITHREAD_PROBE is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_SL811_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Input Devices +# +# CONFIG_USB_HID is not set + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_TOUCHSCREEN is not set +# CONFIG_USB_YEALINK is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_ATI_REMOTE2 is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET_MII is not set +# CONFIG_USB_USBNET is not set +CONFIG_USB_MON=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +CONFIG_USB_GADGET_AT91=y +CONFIG_USB_AT91=y +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_DUALSPEED is not set +CONFIG_USB_ZERO=m +# CONFIG_USB_ETH is not set +CONFIG_USB_GADGETFS=m +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_G_SERIAL=m +# CONFIG_USB_MIDI_GADGET is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_BLOCK=y +CONFIG_MMC_AT91=m +# CONFIG_MMC_TIFM_SD is not set + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +CONFIG_NLS_CODEPAGE_850=y +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FRAME_POINTER=y +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_ERRORS is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ICEDCC is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_PLIST=y +CONFIG_IOMAP_COPY=y diff --git a/arch/arm/configs/ateb9200_defconfig b/arch/arm/configs/ateb9200_defconfig index 3de5c643848..baa97698c74 100644 --- a/arch/arm/configs/ateb9200_defconfig +++ b/arch/arm/configs/ateb9200_defconfig @@ -1066,7 +1066,7 @@ CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_DRV_PCF8563 is not set # CONFIG_RTC_DRV_RS5C372 is not set # CONFIG_RTC_DRV_M48T86 is not set -CONFIG_RTC_DRV_AT91=y +CONFIG_RTC_DRV_AT91RM9200=y # CONFIG_RTC_DRV_TEST is not set # diff --git a/arch/arm/configs/csb337_defconfig b/arch/arm/configs/csb337_defconfig index 2cadd51506b..88e5d28aeec 100644 --- a/arch/arm/configs/csb337_defconfig +++ b/arch/arm/configs/csb337_defconfig @@ -355,10 +355,12 @@ CONFIG_MTD_CFI_UTIL=y # Mapping drivers for chip access # # CONFIG_MTD_COMPLEX_MAPPINGS is not set -# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0 +CONFIG_MTD_PHYSMAP_LEN=0 +CONFIG_MTD_PHYSMAP_BANKWIDTH=0 # CONFIG_MTD_ARM_INTEGRATOR is not set # CONFIG_MTD_PLATRAM is not set -CONFIG_MTD_CSB337=y # # Self-contained MTD device drivers @@ -986,7 +988,7 @@ CONFIG_RTC_DRV_DS1307=y # CONFIG_RTC_DRV_PCF8583 is not set # CONFIG_RTC_DRV_RS5C372 is not set # CONFIG_RTC_DRV_M48T86 is not set -CONFIG_RTC_DRV_AT91=y +CONFIG_RTC_DRV_AT91RM9200=y # CONFIG_RTC_DRV_TEST is not set # CONFIG_RTC_DRV_V3020 is not set diff --git a/arch/arm/configs/csb637_defconfig b/arch/arm/configs/csb637_defconfig index 94908c1df4c..669f035896f 100644 --- a/arch/arm/configs/csb637_defconfig +++ b/arch/arm/configs/csb637_defconfig @@ -355,10 +355,12 @@ CONFIG_MTD_CFI_UTIL=y # Mapping drivers for chip access # # CONFIG_MTD_COMPLEX_MAPPINGS is not set -# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0 +CONFIG_MTD_PHYSMAP_LEN=0 +CONFIG_MTD_PHYSMAP_BANKWIDTH=0 # CONFIG_MTD_ARM_INTEGRATOR is not set # CONFIG_MTD_PLATRAM is not set -CONFIG_MTD_CSB637=y # # Self-contained MTD device drivers diff --git a/arch/arm/configs/kafa_defconfig b/arch/arm/configs/kafa_defconfig index a4cdafc1548..a0f48d54fbc 100644 --- a/arch/arm/configs/kafa_defconfig +++ b/arch/arm/configs/kafa_defconfig @@ -718,7 +718,7 @@ CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_DRV_PCF8563 is not set # CONFIG_RTC_DRV_RS5C372 is not set # CONFIG_RTC_DRV_M48T86 is not set -CONFIG_RTC_DRV_AT91=y +CONFIG_RTC_DRV_AT91RM9200=y # CONFIG_RTC_DRV_TEST is not set # diff --git a/arch/arm/configs/ns9xxx_defconfig b/arch/arm/configs/ns9xxx_defconfig new file mode 100644 index 00000000000..0e5794c6a48 --- /dev/null +++ b/arch/arm/configs/ns9xxx_defconfig @@ -0,0 +1,621 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.20 +# Thu Feb 15 20:51:47 2007 +# +CONFIG_ARM=y +# CONFIG_GENERIC_TIME is not set +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_UTS_NS is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SHMEM=y +CONFIG_SLAB=y +# CONFIG_VM_EVENT_COUNTERS is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_L7200 is not set +CONFIG_ARCH_NS9XXX=y +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set + +# +# NS9xxx Implementations +# +CONFIG_MACH_CC9P9360DEV=y +CONFIG_PROCESSOR_NS9360=y +CONFIG_BOARD_A9M9750DEV=y + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set + +# +# Bus support +# + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +# CONFIG_PREEMPT is not set +# CONFIG_NO_IDLE_HZ is not set +CONFIG_HZ=100 +# CONFIG_AEABI is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +# CONFIG_VFP is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set +# CONFIG_APM is not set + +# +# Networking +# +# CONFIG_NET is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# ISDN subsystem +# + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_SERPORT is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# + +# +# Graphics support +# +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# HID Devices +# +CONFIG_HID=y + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DETECT_SOFTLOCKUP is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FRAME_POINTER=y +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_ICEDCC=y + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y +CONFIG_IOMAP_COPY=y diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig index 3b31a33d008..df19e363203 100644 --- a/arch/arm/configs/s3c2410_defconfig +++ b/arch/arm/configs/s3c2410_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.19-rc4 -# Fri Nov 3 17:41:31 2006 +# Linux kernel version: 2.6.20 +# Thu Feb 15 11:26:24 2007 # CONFIG_ARM=y # CONFIG_GENERIC_TIME is not set @@ -11,6 +11,8 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y CONFIG_HARDIRQS_SW_RESEND=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_VECTORS_BASE=0xffff0000 @@ -37,13 +39,14 @@ CONFIG_SYSVIPC=y # CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set +CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y # CONFIG_EMBEDDED is not set CONFIG_UID16=y -# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set @@ -76,7 +79,9 @@ CONFIG_KMOD=y # Block layer # CONFIG_BLOCK=y +# CONFIG_LBD is not set # CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set # # IO Schedulers @@ -110,6 +115,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_ARCH_IMX is not set # CONFIG_ARCH_IOP32X is not set # CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IOP13XX is not set # CONFIG_ARCH_IXP4XX is not set # CONFIG_ARCH_IXP2000 is not set # CONFIG_ARCH_IXP23XX is not set @@ -122,54 +128,73 @@ CONFIG_ARCH_S3C2410=y # CONFIG_ARCH_SHARK is not set # CONFIG_ARCH_LH7A40X is not set # CONFIG_ARCH_OMAP is not set +CONFIG_PLAT_S3C24XX=y +CONFIG_CPU_S3C244X=y +CONFIG_PM_SIMTEC=y +# CONFIG_S3C2410_BOOT_WATCHDOG is not set +# CONFIG_S3C2410_BOOT_ERROR_RESET is not set +# CONFIG_S3C2410_PM_DEBUG is not set +# CONFIG_S3C2410_PM_CHECK is not set +CONFIG_S3C2410_LOWLEVEL_UART_PORT=0 +CONFIG_S3C2410_DMA=y +# CONFIG_S3C2410_DMA_DEBUG is not set +CONFIG_MACH_SMDK=y # -# S3C24XX Implementations +# S3C2400 Machines # -# CONFIG_MACH_AML_M5900 is not set -CONFIG_MACH_ANUBIS=y -CONFIG_MACH_OSIRIS=y -CONFIG_ARCH_BAST=y -CONFIG_BAST_PC104_IRQ=y +CONFIG_CPU_S3C2410=y +CONFIG_CPU_S3C2410_DMA=y +CONFIG_S3C2410_PM=y +CONFIG_S3C2410_GPIO=y +CONFIG_S3C2410_CLOCK=y + +# +# S3C2410 Machines +# +CONFIG_ARCH_SMDK2410=y CONFIG_ARCH_H1940=y +CONFIG_PM_H1940=y CONFIG_MACH_N30=y -CONFIG_MACH_SMDK=y -CONFIG_ARCH_SMDK2410=y -CONFIG_ARCH_S3C2440=y -CONFIG_SMDK2440_CPU2440=y -CONFIG_SMDK2440_CPU2442=y -CONFIG_MACH_S3C2413=y -CONFIG_MACH_SMDK2413=y -CONFIG_MACH_VR1000=y -CONFIG_MACH_RX3715=y +CONFIG_ARCH_BAST=y CONFIG_MACH_OTOM=y -CONFIG_MACH_NEXCODER_2440=y -CONFIG_MACH_VSTMS=y -CONFIG_S3C2410_CLOCK=y -CONFIG_S3C2410_PM=y -CONFIG_CPU_S3C2410_DMA=y -CONFIG_CPU_S3C2410=y -CONFIG_S3C2412_PM=y +CONFIG_MACH_AML_M5900=y +CONFIG_BAST_PC104_IRQ=y +CONFIG_MACH_VR1000=y CONFIG_CPU_S3C2412=y -CONFIG_CPU_S3C244X=y +CONFIG_S3C2412_DMA=y +CONFIG_S3C2412_PM=y + +# +# S3C2412 Machines +# +CONFIG_MACH_SMDK2413=y +CONFIG_MACH_S3C2413=y +CONFIG_MACH_VSTMS=y CONFIG_CPU_S3C2440=y +CONFIG_S3C2440_DMA=y + +# +# S3C2440 Machines +# +CONFIG_MACH_ANUBIS=y +CONFIG_MACH_OSIRIS=y +CONFIG_MACH_RX3715=y +CONFIG_ARCH_S3C2440=y +CONFIG_MACH_NEXCODER_2440=y +CONFIG_SMDK2440_CPU2440=y CONFIG_CPU_S3C2442=y # -# S3C2410 Boot +# S3C2442 Machines # -# CONFIG_S3C2410_BOOT_WATCHDOG is not set -# CONFIG_S3C2410_BOOT_ERROR_RESET is not set +CONFIG_SMDK2440_CPU2442=y +CONFIG_CPU_S3C2443=y # -# S3C2410 Setup +# S3C2443 Machines # -CONFIG_S3C2410_DMA=y -# CONFIG_S3C2410_DMA_DEBUG is not set -# CONFIG_S3C2410_PM_DEBUG is not set -# CONFIG_S3C2410_PM_CHECK is not set -CONFIG_PM_SIMTEC=y -CONFIG_S3C2410_LOWLEVEL_UART_PORT=0 +CONFIG_MACH_SMDK2443=y # # Processor Type @@ -196,6 +221,7 @@ CONFIG_CPU_CP15_MMU=y # CONFIG_CPU_DCACHE_DISABLE is not set # CONFIG_CPU_DCACHE_WRITETHROUGH is not set # CONFIG_CPU_CACHE_ROUND_ROBIN is not set +# CONFIG_OUTER_CACHE is not set # # Bus support @@ -303,6 +329,7 @@ CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set # CONFIG_IPV6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set @@ -385,6 +412,7 @@ CONFIG_MTD_CMDLINE_PARTS=y # User Modules And Translation Layers # CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set # CONFIG_NFTL is not set @@ -531,6 +559,11 @@ CONFIG_BLK_DEV_IDE_BAST=y # CONFIG_SCSI_NETLINK is not set # +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# # Multi-device support (RAID and LVM) # # CONFIG_MD is not set @@ -682,7 +715,7 @@ CONFIG_SERIAL_NONSTANDARD=y # CONFIG_DIGIEPCA is not set # CONFIG_MOXA_INTELLIO is not set # CONFIG_MOXA_SMARTIO is not set -# CONFIG_ISI is not set +# CONFIG_MOXA_SMARTIO_NEW is not set # CONFIG_SYNCLINKMP is not set # CONFIG_N_HDLC is not set # CONFIG_RISCOM8 is not set @@ -700,13 +733,14 @@ CONFIG_SERIAL_8250_NR_UARTS=8 CONFIG_SERIAL_8250_RUNTIME_UARTS=4 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -# CONFIG_SERIAL_8250_DETECT_IRQ is not set -# CONFIG_SERIAL_8250_RSA is not set # CONFIG_SERIAL_8250_FOURPORT is not set # CONFIG_SERIAL_8250_ACCENT is not set # CONFIG_SERIAL_8250_BOCA is not set +# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set # CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set # # Non-8250 serial port support @@ -755,10 +789,6 @@ CONFIG_HW_RANDOM=y # CONFIG_NVRAM is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set - -# -# Ftape, the floppy tape device driver -# # CONFIG_RAW_DRIVER is not set # @@ -863,6 +893,7 @@ CONFIG_SENSORS_LM85=m # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_SMSC47M192 is not set # CONFIG_SENSORS_SMSC47B397 is not set @@ -870,6 +901,7 @@ CONFIG_SENSORS_LM85=m # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83791D is not set # CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set @@ -952,6 +984,11 @@ CONFIG_FONT_8x16=y # CONFIG_SOUND is not set # +# HID Devices +# +CONFIG_HID=y + +# # USB support # CONFIG_USB_ARCH_HAS_HCD=y @@ -1028,6 +1065,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # CONFIG_USB_KAWETH is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET_MII is not set # CONFIG_USB_USBNET is not set CONFIG_USB_MON=y @@ -1179,9 +1217,6 @@ CONFIG_RAMFS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set -CONFIG_JFFS_FS=y -CONFIG_JFFS_FS_VERBOSE=0 -# CONFIG_JFFS_PROC_FS is not set CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 CONFIG_JFFS2_FS_WRITEBUFFER=y @@ -1191,7 +1226,7 @@ CONFIG_JFFS2_FS_WRITEBUFFER=y CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y # CONFIG_JFFS2_RUBIN is not set -# CONFIG_CRAMFS is not set +CONFIG_CRAMFS=y # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set @@ -1285,6 +1320,11 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_UTF8 is not set # +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# # Profiling support # # CONFIG_PROFILING is not set @@ -1296,6 +1336,8 @@ CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_ENABLE_MUST_CHECK=y CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_DETECT_SOFTLOCKUP=y @@ -1311,12 +1353,10 @@ CONFIG_DEBUG_MUTEXES=y # CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_INFO=y -# CONFIG_DEBUG_FS is not set # CONFIG_DEBUG_VM is not set # CONFIG_DEBUG_LIST is not set CONFIG_FRAME_POINTER=y CONFIG_FORCED_INLINING=y -# CONFIG_HEADERS_CHECK is not set # CONFIG_RCU_TORTURE_TEST is not set CONFIG_DEBUG_USER=y # CONFIG_DEBUG_ERRORS is not set @@ -1339,6 +1379,7 @@ CONFIG_DEBUG_S3C2410_UART=0 # # Library routines # +CONFIG_BITREVERSE=y # CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set CONFIG_CRC32=y @@ -1346,3 +1387,4 @@ CONFIG_CRC32=y CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y CONFIG_PLIST=y +CONFIG_IOMAP_COPY=y diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 1b935fb94b8..bb28087bf81 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index f7598cbc7ec..ae89cdd82b1 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -356,6 +356,7 @@ CALL(sys_move_pages) /* 345 */ CALL(sys_getcpu) CALL(sys_ni_syscall) /* eventually epoll_pwait */ + CALL(sys_kexec_load) #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted diff --git a/arch/arm/kernel/crunch.c b/arch/arm/kernel/crunch.c index cec83783206..627d79414c9 100644 --- a/arch/arm/kernel/crunch.c +++ b/arch/arm/kernel/crunch.c @@ -75,6 +75,7 @@ static struct notifier_block crunch_notifier_block = { static int __init crunch_init(void) { thread_register_notifier(&crunch_notifier_block); + elf_hwcap |= HWCAP_CRUNCH; return 0; } diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index 71257e3d513..f1c0fb97417 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -1009,7 +1009,7 @@ ecard_probe(int slot, card_type_t type) ec->fiqmask = 4; } - for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++) + for (i = 0; i < ARRAY_SIZE(blacklist); i++) if (blacklist[i].manufacturer == ec->cid.manufacturer && blacklist[i].product == ec->cid.product) { ec->card_desc = blacklist[i].type; diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 8517c3c3eb3..cc10a093a54 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -99,7 +99,6 @@ common_invalid: @ cpsr_<exception>, "old_r0" mov r0, sp - and r2, r6, #0x1f b bad_mode /* diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c new file mode 100644 index 00000000000..863c66454f2 --- /dev/null +++ b/arch/arm/kernel/machine_kexec.c @@ -0,0 +1,78 @@ +/* + * machine_kexec.c - handle transition of Linux booting another kernel + */ + +#include <linux/mm.h> +#include <linux/kexec.h> +#include <linux/delay.h> +#include <linux/reboot.h> +#include <asm/pgtable.h> +#include <asm/pgalloc.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/cacheflush.h> +#include <asm/mach-types.h> + +const extern unsigned char relocate_new_kernel[]; +const extern unsigned int relocate_new_kernel_size; + +extern void setup_mm_for_reboot(char mode); + +extern unsigned long kexec_start_address; +extern unsigned long kexec_indirection_page; +extern unsigned long kexec_mach_type; + +/* + * Provide a dummy crash_notes definition while crash dump arrives to arm. + * This prevents breakage of crash_notes attribute in kernel/ksysfs.c. + */ + +int machine_kexec_prepare(struct kimage *image) +{ + return 0; +} + +void machine_kexec_cleanup(struct kimage *image) +{ +} + +void machine_shutdown(void) +{ +} + +void machine_crash_shutdown(struct pt_regs *regs) +{ +} + +void machine_kexec(struct kimage *image) +{ + unsigned long page_list; + unsigned long reboot_code_buffer_phys; + void *reboot_code_buffer; + + + page_list = image->head & PAGE_MASK; + + /* we need both effective and real address here */ + reboot_code_buffer_phys = + page_to_pfn(image->control_code_page) << PAGE_SHIFT; + reboot_code_buffer = page_address(image->control_code_page); + + /* Prepare parameters for reboot_code_buffer*/ + kexec_start_address = image->start; + kexec_indirection_page = page_list; + kexec_mach_type = machine_arch_type; + + /* copy our kernel relocation code to the control code page */ + memcpy(reboot_code_buffer, + relocate_new_kernel, relocate_new_kernel_size); + + + flush_icache_range((unsigned long) reboot_code_buffer, + (unsigned long) reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE); + printk(KERN_INFO "Bye!\n"); + + cpu_proc_fin(); + setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/ + cpu_reset(reboot_code_buffer_phys); +} diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index a9e8f7e55fd..782af3cb213 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -36,7 +36,13 @@ #include <asm/uaccess.h> #include <asm/mach/time.h> -extern const char *processor_modes[]; +static const char *processor_modes[] = { + "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , + "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26", + "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" , + "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32" +}; + extern void setup_mm_for_reboot(char mode); static volatile int hlt_counter; diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S new file mode 100644 index 00000000000..7baadae7cb2 --- /dev/null +++ b/arch/arm/kernel/relocate_kernel.S @@ -0,0 +1,74 @@ +/* + * relocate_kernel.S - put the kernel image in place to boot + */ + +#include <asm/kexec.h> + + .globl relocate_new_kernel +relocate_new_kernel: + + ldr r0,kexec_indirection_page + ldr r1,kexec_start_address + + +0: /* top, read another word for the indirection page */ + ldr r3, [r0],#4 + + /* Is it a destination page. Put destination address to r4 */ + tst r3,#1,0 + beq 1f + bic r4,r3,#1 + b 0b +1: + /* Is it an indirection page */ + tst r3,#2,0 + beq 1f + bic r0,r3,#2 + b 0b +1: + + /* are we done ? */ + tst r3,#4,0 + beq 1f + b 2f + +1: + /* is it source ? */ + tst r3,#8,0 + beq 0b + bic r3,r3,#8 + mov r6,#1024 +9: + ldr r5,[r3],#4 + str r5,[r4],#4 + subs r6,r6,#1 + bne 9b + b 0b + +2: + /* Jump to relocated kernel */ + mov lr,r1 + mov r0,#0 + ldr r1,kexec_mach_type + mov r2,#0 + mov pc,lr + + .globl kexec_start_address +kexec_start_address: + .long 0x0 + + .globl kexec_indirection_page +kexec_indirection_page: + .long 0x0 + + .globl kexec_mach_type +kexec_mach_type: + .long 0x0 + +relocate_new_kernel_end: + + .globl relocate_new_kernel_size +relocate_new_kernel_size: + .long relocate_new_kernel_end - relocate_new_kernel + + diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index ed522151878..03e37af315d 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -88,6 +88,9 @@ struct cpu_user_fns cpu_user; #ifdef MULTI_CACHE struct cpu_cache_fns cpu_cache; #endif +#ifdef CONFIG_OUTER_CACHE +struct outer_cache_fns outer_cache; +#endif struct stack { u32 irq[3]; diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index ee47c532e21..f61decb89ba 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -40,12 +40,14 @@ */ struct sys_timer *system_timer; +#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) /* this needs a better home */ DEFINE_SPINLOCK(rtc_lock); -#ifdef CONFIG_SA1100_RTC_MODULE +#ifdef CONFIG_RTC_DRV_CMOS_MODULE EXPORT_SYMBOL(rtc_lock); #endif +#endif /* pc-style 'CMOS' RTC support */ /* change this if you have some constant time drift */ #define USECS_PER_JIFFY (1000000/HZ) diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 908915675ed..24095601359 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -32,13 +32,6 @@ #include "ptrace.h" #include "signal.h" -const char *processor_modes[]= -{ "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , - "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26", - "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" , - "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32" -}; - static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; #ifdef CONFIG_DEBUG_USER @@ -289,7 +282,10 @@ asmlinkage void do_undefinstr(struct pt_regs *regs) regs->ARM_pc -= correction; pc = (void __user *)instruction_pointer(regs); - if (thumb_mode(regs)) { + + if (processor_mode(regs) == SVC_MODE) { + instr = *(u32 *) pc; + } else if (thumb_mode(regs)) { get_user(instr, (u16 __user *)pc); } else { get_user(instr, (u32 __user *)pc); @@ -337,12 +333,11 @@ asmlinkage void do_unexp_fiq (struct pt_regs *regs) * It never returns, and never tries to sync. We hope that we can at least * dump out some state information... */ -asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode) +asmlinkage void bad_mode(struct pt_regs *regs, int reason) { console_verbose(); - printk(KERN_CRIT "Bad mode in %s handler detected: mode %s\n", - handler[reason], processor_modes[proc_mode]); + printk(KERN_CRIT "Bad mode in %s handler detected\n", handler[reason]); die("Oops - bad mode", regs, 0); local_irq_disable(); diff --git a/arch/arm/mach-at91rm9200/Kconfig b/arch/arm/mach-at91/Kconfig index 9f11db8af23..bf0d96272e3 100644 --- a/arch/arm/mach-at91rm9200/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -9,11 +9,14 @@ config ARCH_AT91RM9200 bool "AT91RM9200" config ARCH_AT91SAM9260 - bool "AT91SAM9260" + bool "AT91SAM9260 or AT91SAM9XE" config ARCH_AT91SAM9261 bool "AT91SAM9261" +config ARCH_AT91SAM9263 + bool "AT91SAM9263" + endchoice # ---------------------------------------------------------- @@ -90,13 +93,22 @@ endif if ARCH_AT91SAM9260 -comment "AT91SAM9260 Board Type" +comment "AT91SAM9260 Variants" + +config ARCH_AT91SAM9260_SAM9XE + bool "AT91SAM9XE" + depends on ARCH_AT91SAM9260 + help + Select this if you are using Atmel's AT91SAM9XE System-on-Chip. + They are basicaly AT91SAM9260s with various sizes of embedded Flash. + +comment "AT91SAM9260 / AT91SAM9XE Board Type" config MACH_AT91SAM9260EK - bool "Atmel AT91SAM9260-EK Evaluation Kit" + bool "Atmel AT91SAM9260-EK / AT91SAM9XE Evaluation Kit" depends on ARCH_AT91SAM9260 help - Select this if you are using Atmel's AT91SAM9260-EK Evaluation Kit. + Select this if you are using Atmel's AT91SAM9260-EK or AT91SAM9XE Evaluation Kit <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3933> endif @@ -118,17 +130,32 @@ endif # ---------------------------------------------------------- +if ARCH_AT91SAM9263 + +comment "AT91SAM9263 Board Type" + +config MACH_AT91SAM9263EK + bool "Atmel AT91SAM9263-EK Evaluation Kit" + depends on ARCH_AT91SAM9263 + help + Select this if you are using Atmel's AT91SAM9263-EK Evaluation Kit. + <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4057> + +endif + +# ---------------------------------------------------------- + comment "AT91 Board Options" config MTD_AT91_DATAFLASH_CARD bool "Enable DataFlash Card support" - depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK) + depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK) help Enable support for the DataFlash card. config MTD_NAND_AT91_BUSWIDTH_16 bool "Enable 16-bit data bus interface to NAND flash" - depends on (MACH_AT91SAM9261EK || MACH_AT91SAM9260EK) + depends on (MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK) help On AT91SAM926x boards both types of NAND flash can be present (8 and 16 bit data bus width). diff --git a/arch/arm/mach-at91rm9200/Makefile b/arch/arm/mach-at91/Makefile index cf777007847..05de6cdc88f 100644 --- a/arch/arm/mach-at91rm9200/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200.o at91rm9200_time.o at91rm9200_devices.o obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o +obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_devices.o # AT91RM9200 board-specific support obj-$(CONFIG_MACH_ONEARM) += board-1arm.o @@ -31,6 +32,9 @@ obj-$(CONFIG_MACH_AT91SAM9260EK) += board-sam9260ek.o # AT91SAM9261 board-specific support obj-$(CONFIG_MACH_AT91SAM9261EK) += board-sam9261ek.o +# AT91SAM9263 board-specific support +obj-$(CONFIG_MACH_AT91SAM9263EK) += board-sam9263ek.o + # LEDs support led-$(CONFIG_ARCH_AT91RM9200DK) += leds.o led-$(CONFIG_MACH_AT91RM9200EK) += leds.o diff --git a/arch/arm/mach-at91rm9200/Makefile.boot b/arch/arm/mach-at91/Makefile.boot index e667dcc7cd3..e667dcc7cd3 100644 --- a/arch/arm/mach-at91rm9200/Makefile.boot +++ b/arch/arm/mach-at91/Makefile.boot diff --git a/arch/arm/mach-at91rm9200/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index a92e9a495b0..2ddcdd69df7 100644 --- a/arch/arm/mach-at91rm9200/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-at91rm9200/at91rm9200.c + * arch/arm/mach-at91/at91rm9200.c * * Copyright (C) 2005 SAN People * @@ -117,6 +117,36 @@ static struct clk pioD_clk = { .pmc_mask = 1 << AT91RM9200_ID_PIOD, .type = CLK_TYPE_PERIPHERAL, }; +static struct clk tc0_clk = { + .name = "tc0_clk", + .pmc_mask = 1 << AT91RM9200_ID_TC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc1_clk = { + .name = "tc1_clk", + .pmc_mask = 1 << AT91RM9200_ID_TC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc2_clk = { + .name = "tc2_clk", + .pmc_mask = 1 << AT91RM9200_ID_TC2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc3_clk = { + .name = "tc3_clk", + .pmc_mask = 1 << AT91RM9200_ID_TC3, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc4_clk = { + .name = "tc4_clk", + .pmc_mask = 1 << AT91RM9200_ID_TC4, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc5_clk = { + .name = "tc5_clk", + .pmc_mask = 1 << AT91RM9200_ID_TC5, + .type = CLK_TYPE_PERIPHERAL, +}; static struct clk *periph_clocks[] __initdata = { &pioA_clk, @@ -132,7 +162,12 @@ static struct clk *periph_clocks[] __initdata = { &twi_clk, &spi_clk, // ssc 0 .. ssc2 - // tc0 .. tc5 + &tc0_clk, + &tc1_clk, + &tc2_clk, + &tc3_clk, + &tc4_clk, + &tc5_clk, &ohci_clk, ðer_clk, // irq0 .. irq6 diff --git a/arch/arm/mach-at91rm9200/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 57fac7203fe..2624a4f22d6 100644 --- a/arch/arm/mach-at91rm9200/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-at91rm9200/at91rm9200_devices.c + * arch/arm/mach-at91/at91rm9200_devices.c * * Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org> * Copyright (C) 2005 David Brownell @@ -315,7 +315,7 @@ static struct platform_device at91rm9200_mmc_device = { .num_resources = ARRAY_SIZE(mmc_resources), }; -void __init at91_add_device_mmc(struct at91_mmc_data *data) +void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) { if (!data) return; @@ -361,7 +361,7 @@ void __init at91_add_device_mmc(struct at91_mmc_data *data) platform_device_register(&at91rm9200_mmc_device); } #else -void __init at91_add_device_mmc(struct at91_mmc_data *data) {} +void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {} #endif @@ -594,6 +594,10 @@ u8 at91_leds_timer; void __init at91_init_leds(u8 cpu_led, u8 timer_led) { + /* Enable GPIO to access the LEDs */ + at91_set_gpio_output(cpu_led, 1); + at91_set_gpio_output(timer_led, 1); + at91_leds_cpu = cpu_led; at91_leds_timer = timer_led; } diff --git a/arch/arm/mach-at91rm9200/at91rm9200_time.c b/arch/arm/mach-at91/at91rm9200_time.c index b999e192a7e..949199a244c 100644 --- a/arch/arm/mach-at91rm9200/at91rm9200_time.c +++ b/arch/arm/mach-at91/at91rm9200_time.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/at91rm9200_time.c + * linux/arch/arm/mach-at91/at91rm9200_time.c * * Copyright (C) 2003 SAN People * Copyright (C) 2003 ATMEL diff --git a/arch/arm/mach-at91rm9200/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index b14871adc30..6ea41d8266c 100644 --- a/arch/arm/mach-at91rm9200/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-at91rm9200/at91sam9260.c + * arch/arm/mach-at91/at91sam9260.c * * Copyright (C) 2006 SAN People * @@ -14,6 +14,7 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> +#include <asm/arch/cpu.h> #include <asm/arch/at91sam9260.h> #include <asm/arch/at91_pmc.h> #include <asm/arch/at91_rstc.h> @@ -27,7 +28,11 @@ static struct map_desc at91sam9260_io_desc[] __initdata = { .pfn = __phys_to_pfn(AT91_BASE_SYS), .length = SZ_16K, .type = MT_DEVICE, - }, { + } +}; + +static struct map_desc at91sam9260_sram_desc[] __initdata = { + { .virtual = AT91_IO_VIRT_BASE - AT91SAM9260_SRAM0_SIZE, .pfn = __phys_to_pfn(AT91SAM9260_SRAM0_BASE), .length = AT91SAM9260_SRAM0_SIZE, @@ -37,7 +42,14 @@ static struct map_desc at91sam9260_io_desc[] __initdata = { .pfn = __phys_to_pfn(AT91SAM9260_SRAM1_BASE), .length = AT91SAM9260_SRAM1_SIZE, .type = MT_DEVICE, - }, + } +}; + +static struct map_desc at91sam9xe_sram_desc[] __initdata = { + { + .pfn = __phys_to_pfn(AT91SAM9XE_SRAM_BASE), + .type = MT_DEVICE, + } }; /* -------------------------------------------------------------------- @@ -107,13 +119,28 @@ static struct clk spi1_clk = { .pmc_mask = 1 << AT91SAM9260_ID_SPI1, .type = CLK_TYPE_PERIPHERAL, }; +static struct clk tc0_clk = { + .name = "tc0_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc1_clk = { + .name = "tc1_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc2_clk = { + .name = "tc2_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC2, + .type = CLK_TYPE_PERIPHERAL, +}; static struct clk ohci_clk = { .name = "ohci_clk", .pmc_mask = 1 << AT91SAM9260_ID_UHP, .type = CLK_TYPE_PERIPHERAL, }; -static struct clk ether_clk = { - .name = "ether_clk", +static struct clk macb_clk = { + .name = "macb_clk", .pmc_mask = 1 << AT91SAM9260_ID_EMAC, .type = CLK_TYPE_PERIPHERAL, }; @@ -137,6 +164,21 @@ static struct clk usart5_clk = { .pmc_mask = 1 << AT91SAM9260_ID_US5, .type = CLK_TYPE_PERIPHERAL, }; +static struct clk tc3_clk = { + .name = "tc3_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC3, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc4_clk = { + .name = "tc4_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC4, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc5_clk = { + .name = "tc5_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC5, + .type = CLK_TYPE_PERIPHERAL, +}; static struct clk *periph_clocks[] __initdata = { &pioA_clk, @@ -152,14 +194,18 @@ static struct clk *periph_clocks[] __initdata = { &spi0_clk, &spi1_clk, // ssc - // tc0 .. tc2 + &tc0_clk, + &tc1_clk, + &tc2_clk, &ohci_clk, - ðer_clk, + &macb_clk, &isi_clk, &usart3_clk, &usart4_clk, &usart5_clk, - // tc3 .. tc5 + &tc3_clk, + &tc4_clk, + &tc5_clk, // irq0 .. irq2 }; @@ -213,7 +259,7 @@ static struct at91_gpio_bank at91sam9260_gpio[] = { static void at91sam9260_reset(void) { - at91_sys_write(AT91_RSTC_CR, (0xA5 << 24) | AT91_RSTC_PROCRST | AT91_RSTC_PERRST); + at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST); } @@ -221,11 +267,37 @@ static void at91sam9260_reset(void) * AT91SAM9260 processor initialization * -------------------------------------------------------------------- */ +static void __init at91sam9xe_initialize(void) +{ + unsigned long cidr, sram_size; + + cidr = at91_sys_read(AT91_DBGU_CIDR); + + switch (cidr & AT91_CIDR_SRAMSIZ) { + case AT91_CIDR_SRAMSIZ_32K: + sram_size = 2 * SZ_16K; + break; + case AT91_CIDR_SRAMSIZ_16K: + default: + sram_size = SZ_16K; + } + + at91sam9xe_sram_desc->virtual = AT91_IO_VIRT_BASE - sram_size; + at91sam9xe_sram_desc->length = sram_size; + + iotable_init(at91sam9xe_sram_desc, ARRAY_SIZE(at91sam9xe_sram_desc)); +} + void __init at91sam9260_initialize(unsigned long main_clock) { /* Map peripherals */ iotable_init(at91sam9260_io_desc, ARRAY_SIZE(at91sam9260_io_desc)); + if (cpu_is_at91sam9xe()) + at91sam9xe_initialize(); + else + iotable_init(at91sam9260_sram_desc, ARRAY_SIZE(at91sam9260_sram_desc)); + at91_arch_reset = at91sam9260_reset; at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1) | (1 << AT91SAM9260_ID_IRQ2); diff --git a/arch/arm/mach-at91rm9200/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index f42d3a40ec3..f7d342ccbeb 100644 --- a/arch/arm/mach-at91rm9200/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-at91rm9200/at91sam9260_devices.c + * arch/arm/mach-at91/at91sam9260_devices.c * * Copyright (C) 2006 Atmel * @@ -128,7 +128,7 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {} #if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE) static u64 eth_dmamask = 0xffffffffUL; -static struct eth_platform_data eth_data; +static struct at91_eth_data eth_data; static struct resource eth_resources[] = { [0] = { @@ -155,7 +155,7 @@ static struct platform_device at91sam9260_eth_device = { .num_resources = ARRAY_SIZE(eth_resources), }; -void __init at91_add_device_eth(struct eth_platform_data *data) +void __init at91_add_device_eth(struct at91_eth_data *data) { if (!data) return; @@ -192,7 +192,7 @@ void __init at91_add_device_eth(struct eth_platform_data *data) platform_device_register(&at91sam9260_eth_device); } #else -void __init at91_add_device_eth(struct eth_platform_data *data) {} +void __init at91_add_device_eth(struct at91_eth_data *data) {} #endif @@ -229,7 +229,7 @@ static struct platform_device at91sam9260_mmc_device = { .num_resources = ARRAY_SIZE(mmc_resources), }; -void __init at91_add_device_mmc(struct at91_mmc_data *data) +void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) { if (!data) return; @@ -275,7 +275,7 @@ void __init at91_add_device_mmc(struct at91_mmc_data *data) platform_device_register(&at91sam9260_mmc_device); } #else -void __init at91_add_device_mmc(struct at91_mmc_data *data) {} +void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {} #endif @@ -515,6 +515,10 @@ u8 at91_leds_timer; void __init at91_init_leds(u8 cpu_led, u8 timer_led) { + /* Enable GPIO to access the LEDs */ + at91_set_gpio_output(cpu_led, 1); + at91_set_gpio_output(timer_led, 1); + at91_leds_cpu = cpu_led; at91_leds_timer = timer_led; } diff --git a/arch/arm/mach-at91rm9200/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index d242bb885c6..784d1e682d6 100644 --- a/arch/arm/mach-at91rm9200/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-at91rm9200/at91sam9261.c + * arch/arm/mach-at91/at91sam9261.c * * Copyright (C) 2005 SAN People * @@ -97,6 +97,21 @@ static struct clk spi1_clk = { .pmc_mask = 1 << AT91SAM9261_ID_SPI1, .type = CLK_TYPE_PERIPHERAL, }; +static struct clk tc0_clk = { + .name = "tc0_clk", + .pmc_mask = 1 << AT91SAM9261_ID_TC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc1_clk = { + .name = "tc1_clk", + .pmc_mask = 1 << AT91SAM9261_ID_TC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc2_clk = { + .name = "tc2_clk", + .pmc_mask = 1 << AT91SAM9261_ID_TC2, + .type = CLK_TYPE_PERIPHERAL, +}; static struct clk ohci_clk = { .name = "ohci_clk", .pmc_mask = 1 << AT91SAM9261_ID_UHP, @@ -121,7 +136,9 @@ static struct clk *periph_clocks[] __initdata = { &spi0_clk, &spi1_clk, // ssc 0 .. ssc2 - // tc0 .. tc2 + &tc0_clk, + &tc1_clk, + &tc2_clk, &ohci_clk, &lcdc_clk, // irq0 .. irq2 @@ -208,7 +225,7 @@ static struct at91_gpio_bank at91sam9261_gpio[] = { static void at91sam9261_reset(void) { - at91_sys_write(AT91_RSTC_CR, (0xA5 << 24) | AT91_RSTC_PROCRST | AT91_RSTC_PERRST); + at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST); } diff --git a/arch/arm/mach-at91rm9200/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index ed1d79081b3..e1504766fd6 100644 --- a/arch/arm/mach-at91rm9200/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-at91rm9200/at91sam9261_devices.c + * arch/arm/mach-at91/at91sam9261_devices.c * * Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org> * Copyright (C) 2005 David Brownell @@ -159,7 +159,7 @@ static struct platform_device at91sam9261_mmc_device = { .num_resources = ARRAY_SIZE(mmc_resources), }; -void __init at91_add_device_mmc(struct at91_mmc_data *data) +void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) { if (!data) return; @@ -192,7 +192,7 @@ void __init at91_add_device_mmc(struct at91_mmc_data *data) platform_device_register(&at91sam9261_mmc_device); } #else -void __init at91_add_device_mmc(struct at91_mmc_data *data) {} +void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {} #endif @@ -513,6 +513,10 @@ u8 at91_leds_timer; void __init at91_init_leds(u8 cpu_led, u8 timer_led) { + /* Enable GPIO to access the LEDs */ + at91_set_gpio_output(cpu_led, 1); + at91_set_gpio_output(timer_led, 1); + at91_leds_cpu = cpu_led; at91_leds_timer = timer_led; } diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c new file mode 100644 index 00000000000..6aa342e8f1b --- /dev/null +++ b/arch/arm/mach-at91/at91sam9263.c @@ -0,0 +1,313 @@ +/* + * arch/arm/mach-at91/at91sam9263.c + * + * Copyright (C) 2007 Atmel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/module.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/arch/at91sam9263.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/at91_rstc.h> + +#include "generic.h" +#include "clock.h" + +static struct map_desc at91sam9263_io_desc[] __initdata = { + { + .virtual = AT91_VA_BASE_SYS, + .pfn = __phys_to_pfn(AT91_BASE_SYS), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_IO_VIRT_BASE - AT91SAM9263_SRAM0_SIZE, + .pfn = __phys_to_pfn(AT91SAM9263_SRAM0_BASE), + .length = AT91SAM9263_SRAM0_SIZE, + .type = MT_DEVICE, + }, { + .virtual = AT91_IO_VIRT_BASE - AT91SAM9263_SRAM0_SIZE - AT91SAM9263_SRAM1_SIZE, + .pfn = __phys_to_pfn(AT91SAM9263_SRAM1_BASE), + .length = AT91SAM9263_SRAM1_SIZE, + .type = MT_DEVICE, + }, +}; + +/* -------------------------------------------------------------------- + * Clocks + * -------------------------------------------------------------------- */ + +/* + * The peripheral clocks. + */ +static struct clk pioA_clk = { + .name = "pioA_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PIOA, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioB_clk = { + .name = "pioB_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PIOB, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioCDE_clk = { + .name = "pioCDE_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PIOCDE, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart0_clk = { + .name = "usart0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_US0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart1_clk = { + .name = "usart1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_US1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart2_clk = { + .name = "usart2_clk", + .pmc_mask = 1 << AT91SAM9263_ID_US2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk mmc0_clk = { + .name = "mci0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_MCI0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk mmc1_clk = { + .name = "mci1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_MCI1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk twi_clk = { + .name = "twi_clk", + .pmc_mask = 1 << AT91SAM9263_ID_TWI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi0_clk = { + .name = "spi0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SPI0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi1_clk = { + .name = "spi1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SPI1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tcb_clk = { + .name = "tcb_clk", + .pmc_mask = 1 << AT91SAM9263_ID_TCB, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk macb_clk = { + .name = "macb_clk", + .pmc_mask = 1 << AT91SAM9263_ID_EMAC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk udc_clk = { + .name = "udc_clk", + .pmc_mask = 1 << AT91SAM9263_ID_UDP, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk isi_clk = { + .name = "isi_clk", + .pmc_mask = 1 << AT91SAM9263_ID_ISI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk lcdc_clk = { + .name = "lcdc_clk", + .pmc_mask = 1 << AT91SAM9263_ID_ISI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ohci_clk = { + .name = "ohci_clk", + .pmc_mask = 1 << AT91SAM9263_ID_UHP, + .type = CLK_TYPE_PERIPHERAL, +}; + +static struct clk *periph_clocks[] __initdata = { + &pioA_clk, + &pioB_clk, + &pioCDE_clk, + &usart0_clk, + &usart1_clk, + &usart2_clk, + &mmc0_clk, + &mmc1_clk, + // can + &twi_clk, + &spi0_clk, + &spi1_clk, + // ssc0 .. ssc1 + // ac97 + &tcb_clk, + // pwmc + &macb_clk, + // 2dge + &udc_clk, + &isi_clk, + &lcdc_clk, + // dma + &ohci_clk, + // irq0 .. irq1 +}; + +/* + * The four programmable clocks. + * You must configure pin multiplexing to bring these signals out. + */ +static struct clk pck0 = { + .name = "pck0", + .pmc_mask = AT91_PMC_PCK0, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 0, +}; +static struct clk pck1 = { + .name = "pck1", + .pmc_mask = AT91_PMC_PCK1, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 1, +}; +static struct clk pck2 = { + .name = "pck2", + .pmc_mask = AT91_PMC_PCK2, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 2, +}; +static struct clk pck3 = { + .name = "pck3", + .pmc_mask = AT91_PMC_PCK3, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 3, +}; + +static void __init at91sam9263_register_clocks(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(periph_clocks); i++) + clk_register(periph_clocks[i]); + + clk_register(&pck0); + clk_register(&pck1); + clk_register(&pck2); + clk_register(&pck3); +} + +/* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ + +static struct at91_gpio_bank at91sam9263_gpio[] = { + { + .id = AT91SAM9263_ID_PIOA, + .offset = AT91_PIOA, + .clock = &pioA_clk, + }, { + .id = AT91SAM9263_ID_PIOB, + .offset = AT91_PIOB, + .clock = &pioB_clk, + }, { + .id = AT91SAM9263_ID_PIOCDE, + .offset = AT91_PIOC, + .clock = &pioCDE_clk, + }, { + .id = AT91SAM9263_ID_PIOCDE, + .offset = AT91_PIOD, + .clock = &pioCDE_clk, + }, { + .id = AT91SAM9263_ID_PIOCDE, + .offset = AT91_PIOE, + .clock = &pioCDE_clk, + } +}; + +static void at91sam9263_reset(void) +{ + at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST); +} + + +/* -------------------------------------------------------------------- + * AT91SAM9263 processor initialization + * -------------------------------------------------------------------- */ + +void __init at91sam9263_initialize(unsigned long main_clock) +{ + /* Map peripherals */ + iotable_init(at91sam9263_io_desc, ARRAY_SIZE(at91sam9263_io_desc)); + + at91_arch_reset = at91sam9263_reset; + at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1); + + /* Init clock subsystem */ + at91_clock_init(main_clock); + + /* Register the processor-specific clocks */ + at91sam9263_register_clocks(); + + /* Register GPIO subsystem */ + at91_gpio_init(at91sam9263_gpio, 5); +} + +/* -------------------------------------------------------------------- + * Interrupt initialization + * -------------------------------------------------------------------- */ + +/* + * The default interrupt priority levels (0 = lowest, 7 = highest). + */ +static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = { + 7, /* Advanced Interrupt Controller (FIQ) */ + 7, /* System Peripherals */ + 0, /* Parallel IO Controller A */ + 0, /* Parallel IO Controller B */ + 0, /* Parallel IO Controller C, D and E */ + 0, + 0, + 6, /* USART 0 */ + 6, /* USART 1 */ + 6, /* USART 2 */ + 0, /* Multimedia Card Interface 0 */ + 0, /* Multimedia Card Interface 1 */ + 4, /* CAN */ + 0, /* Two-Wire Interface */ + 6, /* Serial Peripheral Interface 0 */ + 6, /* Serial Peripheral Interface 1 */ + 5, /* Serial Synchronous Controller 0 */ + 5, /* Serial Synchronous Controller 1 */ + 6, /* AC97 Controller */ + 0, /* Timer Counter 0, 1 and 2 */ + 0, /* Pulse Width Modulation Controller */ + 3, /* Ethernet */ + 0, + 0, /* 2D Graphic Engine */ + 3, /* USB Device Port */ + 0, /* Image Sensor Interface */ + 3, /* LDC Controller */ + 0, /* DMA Controller */ + 0, + 3, /* USB Host port */ + 0, /* Advanced Interrupt Controller (IRQ0) */ + 0, /* Advanced Interrupt Controller (IRQ1) */ +}; + +void __init at91sam9263_init_interrupts(unsigned int priority[NR_AIC_IRQS]) +{ + if (!priority) + priority = at91sam9263_default_irq_priority; + + /* Initialize the AIC interrupt controller */ + at91_aic_init(priority); + + /* Enable GPIO interrupts */ + at91_gpio_irq_setup(); +} diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c new file mode 100644 index 00000000000..d9af7ca58bc --- /dev/null +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -0,0 +1,818 @@ +/* + * arch/arm/mach-at91/at91sam9263_devices.c + * + * Copyright (C) 2007 Atmel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <linux/platform_device.h> + +#include <asm/arch/board.h> +#include <asm/arch/gpio.h> +#include <asm/arch/at91sam9263.h> +#include <asm/arch/at91sam926x_mc.h> +#include <asm/arch/at91sam9263_matrix.h> + +#include "generic.h" + +#define SZ_512 0x00000200 +#define SZ_256 0x00000100 +#define SZ_16 0x00000010 + +/* -------------------------------------------------------------------- + * USB Host + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) +static u64 ohci_dmamask = 0xffffffffUL; +static struct at91_usbh_data usbh_data; + +static struct resource usbh_resources[] = { + [0] = { + .start = AT91SAM9263_UHP_BASE, + .end = AT91SAM9263_UHP_BASE + SZ_1M - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_ID_UHP, + .end = AT91SAM9263_ID_UHP, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at91_usbh_device = { + .name = "at91_ohci", + .id = -1, + .dev = { + .dma_mask = &ohci_dmamask, + .coherent_dma_mask = 0xffffffff, + .platform_data = &usbh_data, + }, + .resource = usbh_resources, + .num_resources = ARRAY_SIZE(usbh_resources), +}; + +void __init at91_add_device_usbh(struct at91_usbh_data *data) +{ + int i; + + if (!data) + return; + + /* Enable VBus control for UHP ports */ + for (i = 0; i < data->ports; i++) { + if (data->vbus_pin[i]) + at91_set_gpio_output(data->vbus_pin[i], 0); + } + + usbh_data = *data; + platform_device_register(&at91_usbh_device); +} +#else +void __init at91_add_device_usbh(struct at91_usbh_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * USB Device (Gadget) + * -------------------------------------------------------------------- */ + +#ifdef CONFIG_USB_GADGET_AT91 +static struct at91_udc_data udc_data; + +static struct resource udc_resources[] = { + [0] = { + .start = AT91SAM9263_BASE_UDP, + .end = AT91SAM9263_BASE_UDP + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_ID_UDP, + .end = AT91SAM9263_ID_UDP, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at91_udc_device = { + .name = "at91_udc", + .id = -1, + .dev = { + .platform_data = &udc_data, + }, + .resource = udc_resources, + .num_resources = ARRAY_SIZE(udc_resources), +}; + +void __init at91_add_device_udc(struct at91_udc_data *data) +{ + if (!data) + return; + + if (data->vbus_pin) { + at91_set_gpio_input(data->vbus_pin, 0); + at91_set_deglitch(data->vbus_pin, 1); + } + + /* Pullup pin is handled internally by USB device peripheral */ + + udc_data = *data; + platform_device_register(&at91_udc_device); +} +#else +void __init at91_add_device_udc(struct at91_udc_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * Ethernet + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE) +static u64 eth_dmamask = 0xffffffffUL; +static struct at91_eth_data eth_data; + +static struct resource eth_resources[] = { + [0] = { + .start = AT91SAM9263_BASE_EMAC, + .end = AT91SAM9263_BASE_EMAC + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_ID_EMAC, + .end = AT91SAM9263_ID_EMAC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at91sam9263_eth_device = { + .name = "macb", + .id = -1, + .dev = { + .dma_mask = ð_dmamask, + .coherent_dma_mask = 0xffffffff, + .platform_data = ð_data, + }, + .resource = eth_resources, + .num_resources = ARRAY_SIZE(eth_resources), +}; + +void __init at91_add_device_eth(struct at91_eth_data *data) +{ + if (!data) + return; + + if (data->phy_irq_pin) { + at91_set_gpio_input(data->phy_irq_pin, 0); + at91_set_deglitch(data->phy_irq_pin, 1); + } + + /* Pins used for MII and RMII */ + at91_set_A_periph(AT91_PIN_PE21, 0); /* ETXCK_EREFCK */ + at91_set_B_periph(AT91_PIN_PC25, 0); /* ERXDV */ + at91_set_A_periph(AT91_PIN_PE25, 0); /* ERX0 */ + at91_set_A_periph(AT91_PIN_PE26, 0); /* ERX1 */ + at91_set_A_periph(AT91_PIN_PE27, 0); /* ERXER */ + at91_set_A_periph(AT91_PIN_PE28, 0); /* ETXEN */ + at91_set_A_periph(AT91_PIN_PE23, 0); /* ETX0 */ + at91_set_A_periph(AT91_PIN_PE24, 0); /* ETX1 */ + at91_set_A_periph(AT91_PIN_PE30, 0); /* EMDIO */ + at91_set_A_periph(AT91_PIN_PE29, 0); /* EMDC */ + + if (!data->is_rmii) { + at91_set_A_periph(AT91_PIN_PE22, 0); /* ECRS */ + at91_set_B_periph(AT91_PIN_PC26, 0); /* ECOL */ + at91_set_B_periph(AT91_PIN_PC22, 0); /* ERX2 */ + at91_set_B_periph(AT91_PIN_PC23, 0); /* ERX3 */ + at91_set_B_periph(AT91_PIN_PC27, 0); /* ERXCK */ + at91_set_B_periph(AT91_PIN_PC20, 0); /* ETX2 */ + at91_set_B_periph(AT91_PIN_PC21, 0); /* ETX3 */ + at91_set_B_periph(AT91_PIN_PC24, 0); /* ETXER */ + } + + eth_data = *data; + platform_device_register(&at91sam9263_eth_device); +} +#else +void __init at91_add_device_eth(struct at91_eth_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * MMC / SD + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE) +static u64 mmc_dmamask = 0xffffffffUL; +static struct at91_mmc_data mmc0_data, mmc1_data; + +static struct resource mmc0_resources[] = { + [0] = { + .start = AT91SAM9263_BASE_MCI0, + .end = AT91SAM9263_BASE_MCI0 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_ID_MCI0, + .end = AT91SAM9263_ID_MCI0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at91sam9263_mmc0_device = { + .name = "at91_mci", + .id = 0, + .dev = { + .dma_mask = &mmc_dmamask, + .coherent_dma_mask = 0xffffffff, + .platform_data = &mmc0_data, + }, + .resource = mmc0_resources, + .num_resources = ARRAY_SIZE(mmc0_resources), +}; + +static struct resource mmc1_resources[] = { + [0] = { + .start = AT91SAM9263_BASE_MCI1, + .end = AT91SAM9263_BASE_MCI1 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_ID_MCI1, + .end = AT91SAM9263_ID_MCI1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at91sam9263_mmc1_device = { + .name = "at91_mci", + .id = 1, + .dev = { + .dma_mask = &mmc_dmamask, + .coherent_dma_mask = 0xffffffff, + .platform_data = &mmc1_data, + }, + .resource = mmc1_resources, + .num_resources = ARRAY_SIZE(mmc1_resources), +}; + +void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) +{ + if (!data) + return; + + /* input/irq */ + if (data->det_pin) { + at91_set_gpio_input(data->det_pin, 1); + at91_set_deglitch(data->det_pin, 1); + } + if (data->wp_pin) + at91_set_gpio_input(data->wp_pin, 1); + if (data->vcc_pin) + at91_set_gpio_output(data->vcc_pin, 0); + + if (mmc_id == 0) { /* MCI0 */ + /* CLK */ + at91_set_A_periph(AT91_PIN_PA12, 0); + + if (data->slot_b) { + /* CMD */ + at91_set_A_periph(AT91_PIN_PA16, 1); + + /* DAT0, maybe DAT1..DAT3 */ + at91_set_A_periph(AT91_PIN_PA17, 1); + if (data->wire4) { + at91_set_A_periph(AT91_PIN_PA18, 1); + at91_set_A_periph(AT91_PIN_PA19, 1); + at91_set_A_periph(AT91_PIN_PA20, 1); + } + } else { + /* CMD */ + at91_set_A_periph(AT91_PIN_PA1, 1); + + /* DAT0, maybe DAT1..DAT3 */ + at91_set_A_periph(AT91_PIN_PA0, 1); + if (data->wire4) { + at91_set_A_periph(AT91_PIN_PA3, 1); + at91_set_A_periph(AT91_PIN_PA4, 1); + at91_set_A_periph(AT91_PIN_PA5, 1); + } + } + + mmc0_data = *data; + at91_clock_associate("mci0_clk", &at91sam9263_mmc1_device.dev, "mci_clk"); + platform_device_register(&at91sam9263_mmc0_device); + } else { /* MCI1 */ + /* CLK */ + at91_set_A_periph(AT91_PIN_PA6, 0); + + if (data->slot_b) { + /* CMD */ + at91_set_A_periph(AT91_PIN_PA21, 1); + + /* DAT0, maybe DAT1..DAT3 */ + at91_set_A_periph(AT91_PIN_PA22, 1); + if (data->wire4) { + at91_set_A_periph(AT91_PIN_PA23, 1); + at91_set_A_periph(AT91_PIN_PA24, 1); + at91_set_A_periph(AT91_PIN_PA25, 1); + } + } else { + /* CMD */ + at91_set_A_periph(AT91_PIN_PA7, 1); + + /* DAT0, maybe DAT1..DAT3 */ + at91_set_A_periph(AT91_PIN_PA8, 1); + if (data->wire4) { + at91_set_A_periph(AT91_PIN_PA9, 1); + at91_set_A_periph(AT91_PIN_PA10, 1); + at91_set_A_periph(AT91_PIN_PA11, 1); + } + } + + mmc1_data = *data; + at91_clock_associate("mci1_clk", &at91sam9263_mmc1_device.dev, "mci_clk"); + platform_device_register(&at91sam9263_mmc1_device); + } +} +#else +void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * NAND / SmartMedia + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE) +static struct at91_nand_data nand_data; + +#define NAND_BASE AT91_CHIPSELECT_3 + +static struct resource nand_resources[] = { + { + .start = NAND_BASE, + .end = NAND_BASE + SZ_256M - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device at91sam9263_nand_device = { + .name = "at91_nand", + .id = -1, + .dev = { + .platform_data = &nand_data, + }, + .resource = nand_resources, + .num_resources = ARRAY_SIZE(nand_resources), +}; + +void __init at91_add_device_nand(struct at91_nand_data *data) +{ + unsigned long csa, mode; + + if (!data) + return; + + csa = at91_sys_read(AT91_MATRIX_EBI0CSA); + at91_sys_write(AT91_MATRIX_EBI0CSA, csa | AT91_MATRIX_EBI0_CS3A_SMC); + + /* set the bus interface characteristics */ + at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(0) | AT91_SMC_NCS_WRSETUP_(0) + | AT91_SMC_NRDSETUP_(0) | AT91_SMC_NCS_RDSETUP_(0)); + + at91_sys_write(AT91_SMC_PULSE(3), AT91_SMC_NWEPULSE_(3) | AT91_SMC_NCS_WRPULSE_(3) + | AT91_SMC_NRDPULSE_(3) | AT91_SMC_NCS_RDPULSE_(3)); + + at91_sys_write(AT91_SMC_CYCLE(3), AT91_SMC_NWECYCLE_(5) | AT91_SMC_NRDCYCLE_(5)); + + if (data->bus_width_16) + mode = AT91_SMC_DBW_16; + else + mode = AT91_SMC_DBW_8; + at91_sys_write(AT91_SMC_MODE(3), mode | AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(2)); + + /* enable pin */ + if (data->enable_pin) + at91_set_gpio_output(data->enable_pin, 1); + + /* ready/busy pin */ + if (data->rdy_pin) + at91_set_gpio_input(data->rdy_pin, 1); + + /* card detect pin */ + if (data->det_pin) + at91_set_gpio_input(data->det_pin, 1); + + nand_data = *data; + platform_device_register(&at91sam9263_nand_device); +} +#else +void __init at91_add_device_nand(struct at91_nand_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * TWI (i2c) + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE) + +static struct resource twi_resources[] = { + [0] = { + .start = AT91SAM9263_BASE_TWI, + .end = AT91SAM9263_BASE_TWI + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_ID_TWI, + .end = AT91SAM9263_ID_TWI, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at91sam9263_twi_device = { + .name = "at91_i2c", + .id = -1, + .resource = twi_resources, + .num_resources = ARRAY_SIZE(twi_resources), +}; + +void __init at91_add_device_i2c(void) +{ + /* pins used for TWI interface */ + at91_set_A_periph(AT91_PIN_PB4, 0); /* TWD */ + at91_set_multi_drive(AT91_PIN_PB4, 1); + + at91_set_A_periph(AT91_PIN_PB5, 0); /* TWCK */ + at91_set_multi_drive(AT91_PIN_PB5, 1); + + platform_device_register(&at91sam9263_twi_device); +} +#else +void __init at91_add_device_i2c(void) {} +#endif + + +/* -------------------------------------------------------------------- + * SPI + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE) +static u64 spi_dmamask = 0xffffffffUL; + +static struct resource spi0_resources[] = { + [0] = { + .start = AT91SAM9263_BASE_SPI0, + .end = AT91SAM9263_BASE_SPI0 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_ID_SPI0, + .end = AT91SAM9263_ID_SPI0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at91sam9263_spi0_device = { + .name = "atmel_spi", + .id = 0, + .dev = { + .dma_mask = &spi_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .resource = spi0_resources, + .num_resources = ARRAY_SIZE(spi0_resources), +}; + +static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA5, AT91_PIN_PA3, AT91_PIN_PA4, AT91_PIN_PB11 }; + +static struct resource spi1_resources[] = { + [0] = { + .start = AT91SAM9263_BASE_SPI1, + .end = AT91SAM9263_BASE_SPI1 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_ID_SPI1, + .end = AT91SAM9263_ID_SPI1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at91sam9263_spi1_device = { + .name = "atmel_spi", + .id = 1, + .dev = { + .dma_mask = &spi_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .resource = spi1_resources, + .num_resources = ARRAY_SIZE(spi1_resources), +}; + +static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB15, AT91_PIN_PB16, AT91_PIN_PB17, AT91_PIN_PB18 }; + +void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) +{ + int i; + unsigned long cs_pin; + short enable_spi0 = 0; + short enable_spi1 = 0; + + /* Choose SPI chip-selects */ + for (i = 0; i < nr_devices; i++) { + if (devices[i].controller_data) + cs_pin = (unsigned long) devices[i].controller_data; + else if (devices[i].bus_num == 0) + cs_pin = spi0_standard_cs[devices[i].chip_select]; + else + cs_pin = spi1_standard_cs[devices[i].chip_select]; + + if (devices[i].bus_num == 0) + enable_spi0 = 1; + else + enable_spi1 = 1; + + /* enable chip-select pin */ + at91_set_gpio_output(cs_pin, 1); + + /* pass chip-select pin to driver */ + devices[i].controller_data = (void *) cs_pin; + } + + spi_register_board_info(devices, nr_devices); + + /* Configure SPI bus(es) */ + if (enable_spi0) { + at91_set_B_periph(AT91_PIN_PA0, 0); /* SPI0_MISO */ + at91_set_B_periph(AT91_PIN_PA1, 0); /* SPI0_MOSI */ + at91_set_B_periph(AT91_PIN_PA2, 0); /* SPI1_SPCK */ + + at91_clock_associate("spi0_clk", &at91sam9263_spi0_device.dev, "spi_clk"); + platform_device_register(&at91sam9263_spi0_device); + } + if (enable_spi1) { + at91_set_A_periph(AT91_PIN_PB12, 0); /* SPI1_MISO */ + at91_set_A_periph(AT91_PIN_PB13, 0); /* SPI1_MOSI */ + at91_set_A_periph(AT91_PIN_PB14, 0); /* SPI1_SPCK */ + + at91_clock_associate("spi1_clk", &at91sam9263_spi1_device.dev, "spi_clk"); + platform_device_register(&at91sam9263_spi1_device); + } +} +#else +void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {} +#endif + + +/* -------------------------------------------------------------------- + * LEDs + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_LEDS) +u8 at91_leds_cpu; +u8 at91_leds_timer; + +void __init at91_init_leds(u8 cpu_led, u8 timer_led) +{ + /* Enable GPIO to access the LEDs */ + at91_set_gpio_output(cpu_led, 1); + at91_set_gpio_output(timer_led, 1); + + at91_leds_cpu = cpu_led; + at91_leds_timer = timer_led; +} +#else +void __init at91_init_leds(u8 cpu_led, u8 timer_led) {} +#endif + + +/* -------------------------------------------------------------------- + * UART + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_SERIAL_ATMEL) + +static struct resource dbgu_resources[] = { + [0] = { + .start = AT91_VA_BASE_SYS + AT91_DBGU, + .end = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91_ID_SYS, + .end = AT91_ID_SYS, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct atmel_uart_data dbgu_data = { + .use_dma_tx = 0, + .use_dma_rx = 0, /* DBGU not capable of receive DMA */ + .regs = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU), +}; + +static struct platform_device at91sam9263_dbgu_device = { + .name = "atmel_usart", + .id = 0, + .dev = { + .platform_data = &dbgu_data, + .coherent_dma_mask = 0xffffffff, + }, + .resource = dbgu_resources, + .num_resources = ARRAY_SIZE(dbgu_resources), +}; + +static inline void configure_dbgu_pins(void) +{ + at91_set_A_periph(AT91_PIN_PC30, 0); /* DRXD */ + at91_set_A_periph(AT91_PIN_PC31, 1); /* DTXD */ +} + +static struct resource uart0_resources[] = { + [0] = { + .start = AT91SAM9263_BASE_US0, + .end = AT91SAM9263_BASE_US0 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_ID_US0, + .end = AT91SAM9263_ID_US0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct atmel_uart_data uart0_data = { + .use_dma_tx = 1, + .use_dma_rx = 1, +}; + +static struct platform_device at91sam9263_uart0_device = { + .name = "atmel_usart", + .id = 1, + .dev = { + .platform_data = &uart0_data, + .coherent_dma_mask = 0xffffffff, + }, + .resource = uart0_resources, + .num_resources = ARRAY_SIZE(uart0_resources), +}; + +static inline void configure_usart0_pins(void) +{ + at91_set_A_periph(AT91_PIN_PA26, 1); /* TXD0 */ + at91_set_A_periph(AT91_PIN_PA27, 0); /* RXD0 */ + at91_set_A_periph(AT91_PIN_PA28, 0); /* RTS0 */ + at91_set_A_periph(AT91_PIN_PA29, 0); /* CTS0 */ +} + +static struct resource uart1_resources[] = { + [0] = { + .start = AT91SAM9263_BASE_US1, + .end = AT91SAM9263_BASE_US1 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_ID_US1, + .end = AT91SAM9263_ID_US1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct atmel_uart_data uart1_data = { + .use_dma_tx = 1, + .use_dma_rx = 1, +}; + +static struct platform_device at91sam9263_uart1_device = { + .name = "atmel_usart", + .id = 2, + .dev = { + .platform_data = &uart1_data, + .coherent_dma_mask = 0xffffffff, + }, + .resource = uart1_resources, + .num_resources = ARRAY_SIZE(uart1_resources), +}; + +static inline void configure_usart1_pins(void) +{ + at91_set_A_periph(AT91_PIN_PD0, 1); /* TXD1 */ + at91_set_A_periph(AT91_PIN_PD1, 0); /* RXD1 */ + at91_set_B_periph(AT91_PIN_PD7, 0); /* RTS1 */ + at91_set_B_periph(AT91_PIN_PD8, 0); /* CTS1 */ +} + +static struct resource uart2_resources[] = { + [0] = { + .start = AT91SAM9263_BASE_US2, + .end = AT91SAM9263_BASE_US2 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_ID_US2, + .end = AT91SAM9263_ID_US2, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct atmel_uart_data uart2_data = { + .use_dma_tx = 1, + .use_dma_rx = 1, +}; + +static struct platform_device at91sam9263_uart2_device = { + .name = "atmel_usart", + .id = 3, + .dev = { + .platform_data = &uart2_data, + .coherent_dma_mask = 0xffffffff, + }, + .resource = uart2_resources, + .num_resources = ARRAY_SIZE(uart2_resources), +}; + +static inline void configure_usart2_pins(void) +{ + at91_set_A_periph(AT91_PIN_PD2, 1); /* TXD2 */ + at91_set_A_periph(AT91_PIN_PD3, 0); /* RXD2 */ + at91_set_B_periph(AT91_PIN_PD5, 0); /* RTS2 */ + at91_set_B_periph(AT91_PIN_PD6, 0); /* CTS2 */ +} + +struct platform_device *at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */ +struct platform_device *atmel_default_console_device; /* the serial console device */ + +void __init at91_init_serial(struct at91_uart_config *config) +{ + int i; + + /* Fill in list of supported UARTs */ + for (i = 0; i < config->nr_tty; i++) { + switch (config->tty_map[i]) { + case 0: + configure_usart0_pins(); + at91_uarts[i] = &at91sam9263_uart0_device; + at91_clock_associate("usart0_clk", &at91sam9263_uart0_device.dev, "usart"); + break; + case 1: + configure_usart1_pins(); + at91_uarts[i] = &at91sam9263_uart1_device; + at91_clock_associate("usart1_clk", &at91sam9263_uart1_device.dev, "usart"); + break; + case 2: + configure_usart2_pins(); + at91_uarts[i] = &at91sam9263_uart2_device; + at91_clock_associate("usart2_clk", &at91sam9263_uart2_device.dev, "usart"); + break; + case 3: + configure_dbgu_pins(); + at91_uarts[i] = &at91sam9263_dbgu_device; + at91_clock_associate("mck", &at91sam9263_dbgu_device.dev, "usart"); + break; + default: + continue; + } + at91_uarts[i]->id = i; /* update ID number to mapped ID */ + } + + /* Set serial console device */ + if (config->console_tty < ATMEL_MAX_UART) + atmel_default_console_device = at91_uarts[config->console_tty]; + if (!atmel_default_console_device) + printk(KERN_INFO "AT91: No default serial console defined.\n"); +} + +void __init at91_add_device_serial(void) +{ + int i; + + for (i = 0; i < ATMEL_MAX_UART; i++) { + if (at91_uarts[i]) + platform_device_register(at91_uarts[i]); + } +} +#else +void __init at91_init_serial(struct at91_uart_config *config) {} +void __init at91_add_device_serial(void) {} +#endif + + +/* -------------------------------------------------------------------- */ +/* + * These devices are always present and don't need any board-specific + * setup. + */ +static int __init at91_add_standard_devices(void) +{ + return 0; +} + +arch_initcall(at91_add_standard_devices); diff --git a/arch/arm/mach-at91rm9200/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c index 99df5f6ee42..a4dded27fa1 100644 --- a/arch/arm/mach-at91rm9200/at91sam926x_time.c +++ b/arch/arm/mach-at91/at91sam926x_time.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/at91sam926x_time.c + * linux/arch/arm/mach-at91/at91sam926x_time.c * * Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France * Revision 2005 M. Nicolas Diremdjian, ATMEL Rousset, France @@ -30,7 +30,6 @@ * Returns number of microseconds since last timer interrupt. Note that interrupts * will have been disabled by do_gettimeofday() * 'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy. - * 'tick' is usecs per jiffy (linux/timex.h). */ static unsigned long at91sam926x_gettimeoffset(void) { @@ -39,7 +38,7 @@ static unsigned long at91sam926x_gettimeoffset(void) elapsed = (PIT_PICNT(t) * LATCH) + PIT_CPIV(t); /* hardware clock cycles */ - return (unsigned long)(elapsed * 1000000) / LATCH; + return (unsigned long)(elapsed * jiffies_to_usecs(1)) / LATCH; } /* diff --git a/arch/arm/mach-at91rm9200/board-1arm.c b/arch/arm/mach-at91/board-1arm.c index 971c3e2d8e3..2d3d4b6f7b0 100644 --- a/arch/arm/mach-at91rm9200/board-1arm.c +++ b/arch/arm/mach-at91/board-1arm.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/board-1arm.c + * linux/arch/arm/mach-at91/board-1arm.c * * Copyright (C) 2005 SAN People * diff --git a/arch/arm/mach-at91rm9200/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c index 654f0379550..b4518619063 100644 --- a/arch/arm/mach-at91rm9200/board-carmeva.c +++ b/arch/arm/mach-at91/board-carmeva.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/board-carmeva.c + * linux/arch/arm/mach-at91/board-carmeva.c * * Copyright (c) 2005 Peer Georgi * Conitec Datasystems @@ -134,7 +134,7 @@ static void __init carmeva_board_init(void) /* Compact Flash */ // at91_add_device_cf(&carmeva_cf_data); /* MMC */ - at91_add_device_mmc(&carmeva_mmc_data); + at91_add_device_mmc(0, &carmeva_mmc_data); } MACHINE_START(CARMEVA, "Carmeva") diff --git a/arch/arm/mach-at91rm9200/board-csb337.c b/arch/arm/mach-at91/board-csb337.c index b8bb8052607..e18a41e61f0 100644 --- a/arch/arm/mach-at91rm9200/board-csb337.c +++ b/arch/arm/mach-at91/board-csb337.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/board-csb337.c + * linux/arch/arm/mach-at91/board-csb337.c * * Copyright (C) 2005 SAN People * @@ -24,6 +24,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> +#include <linux/mtd/physmap.h> #include <asm/hardware.h> #include <asm/setup.h> @@ -112,6 +113,42 @@ static struct spi_board_info csb337_spi_devices[] = { }, }; +#define CSB_FLASH_BASE AT91_CHIPSELECT_0 +#define CSB_FLASH_SIZE 0x800000 + +static struct mtd_partition csb_flash_partitions[] = { + { + .name = "uMON flash", + .offset = 0, + .size = MTDPART_SIZ_FULL, + .mask_flags = MTD_WRITEABLE, /* read only */ + } +}; + +static struct physmap_flash_data csb_flash_data = { + .width = 2, + .parts = csb_flash_partitions, + .nr_parts = ARRAY_SIZE(csb_flash_partitions), +}; + +static struct resource csb_flash_resources[] = { + { + .start = CSB_FLASH_BASE, + .end = CSB_FLASH_BASE + CSB_FLASH_SIZE - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device csb_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &csb_flash_data, + }, + .resource = csb_flash_resources, + .num_resources = ARRAY_SIZE(csb_flash_resources), +}; + static void __init csb337_board_init(void) { /* Serial */ @@ -130,7 +167,9 @@ static void __init csb337_board_init(void) /* SPI */ at91_add_device_spi(csb337_spi_devices, ARRAY_SIZE(csb337_spi_devices)); /* MMC */ - at91_add_device_mmc(&csb337_mmc_data); + at91_add_device_mmc(0, &csb337_mmc_data); + /* NOR flash */ + platform_device_register(&csb_flash); } MACHINE_START(CSB337, "Cogent CSB337") diff --git a/arch/arm/mach-at91rm9200/board-csb637.c b/arch/arm/mach-at91/board-csb637.c index a29fa0e822c..77f04b935b3 100644 --- a/arch/arm/mach-at91rm9200/board-csb637.c +++ b/arch/arm/mach-at91/board-csb637.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/board-csb637.c + * linux/arch/arm/mach-at91/board-csb637.c * * Copyright (C) 2005 SAN People * @@ -23,6 +23,7 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/mtd/physmap.h> #include <asm/hardware.h> #include <asm/setup.h> @@ -81,6 +82,42 @@ static struct at91_udc_data __initdata csb637_udc_data = { .pullup_pin = AT91_PIN_PB1, }; +#define CSB_FLASH_BASE AT91_CHIPSELECT_0 +#define CSB_FLASH_SIZE 0x1000000 + +static struct mtd_partition csb_flash_partitions[] = { + { + .name = "uMON flash", + .offset = 0, + .size = MTDPART_SIZ_FULL, + .mask_flags = MTD_WRITEABLE, /* read only */ + } +}; + +static struct physmap_flash_data csb_flash_data = { + .width = 2, + .parts = csb_flash_partitions, + .nr_parts = ARRAY_SIZE(csb_flash_partitions), +}; + +static struct resource csb_flash_resources[] = { + { + .start = CSB_FLASH_BASE, + .end = CSB_FLASH_BASE + CSB_FLASH_SIZE - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device csb_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &csb_flash_data, + }, + .resource = csb_flash_resources, + .num_resources = ARRAY_SIZE(csb_flash_resources), +}; + static void __init csb637_board_init(void) { /* Serial */ @@ -95,6 +132,8 @@ static void __init csb637_board_init(void) at91_add_device_i2c(); /* SPI */ at91_add_device_spi(NULL, 0); + /* NOR flash */ + platform_device_register(&csb_flash); } MACHINE_START(CSB637, "Cogent CSB637") diff --git a/arch/arm/mach-at91rm9200/board-dk.c b/arch/arm/mach-at91/board-dk.c index 7522bf91bce..6043c38c0a9 100644 --- a/arch/arm/mach-at91rm9200/board-dk.c +++ b/arch/arm/mach-at91/board-dk.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/board-dk.c + * linux/arch/arm/mach-at91/board-dk.c * * Copyright (C) 2005 SAN People * @@ -194,7 +194,7 @@ static void __init dk_board_init(void) #else /* MMC */ at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */ - at91_add_device_mmc(&dk_mmc_data); + at91_add_device_mmc(0, &dk_mmc_data); #endif /* NAND */ at91_add_device_nand(&dk_nand_data); diff --git a/arch/arm/mach-at91rm9200/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c index 80b72cf7264..20458b5548f 100644 --- a/arch/arm/mach-at91rm9200/board-eb9200.c +++ b/arch/arm/mach-at91/board-eb9200.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/board-eb9200.c + * linux/arch/arm/mach-at91/board-eb9200.c * * Copyright (C) 2005 SAN People, adapted for ATEB9200 from Embest * by Andrew Patrikalakis @@ -109,7 +109,7 @@ static void __init eb9200_board_init(void) at91_add_device_spi(NULL, 0); /* MMC */ /* only supports 1 or 4 bit interface, not wired through to SPI */ - at91_add_device_mmc(&eb9200_mmc_data); + at91_add_device_mmc(0, &eb9200_mmc_data); } MACHINE_START(ATEB9200, "Embest ATEB9200") diff --git a/arch/arm/mach-at91rm9200/board-ek.c b/arch/arm/mach-at91/board-ek.c index c4fdb415f20..322fdd75a1e 100644 --- a/arch/arm/mach-at91rm9200/board-ek.c +++ b/arch/arm/mach-at91/board-ek.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/board-ek.c + * linux/arch/arm/mach-at91/board-ek.c * * Copyright (C) 2005 SAN People * @@ -154,7 +154,7 @@ static void __init ek_board_init(void) #else /* MMC */ at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */ - at91_add_device_mmc(&ek_mmc_data); + at91_add_device_mmc(0, &ek_mmc_data); #endif /* NOR Flash */ platform_device_register(&ek_flash); diff --git a/arch/arm/mach-at91rm9200/board-kafa.c b/arch/arm/mach-at91/board-kafa.c index 6ef3c487982..c77d84ce9ca 100644 --- a/arch/arm/mach-at91rm9200/board-kafa.c +++ b/arch/arm/mach-at91/board-kafa.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/board-kafa.c + * linux/arch/arm/mach-at91/board-kafa.c * * Copyright (C) 2006 Sperry-Sun * diff --git a/arch/arm/mach-at91rm9200/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c index 759d8191854..76f6e1e553e 100644 --- a/arch/arm/mach-at91rm9200/board-kb9202.c +++ b/arch/arm/mach-at91/board-kb9202.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/board-kb9202.c + * linux/arch/arm/mach-at91/board-kb9202.c * * Copyright (c) 2005 kb_admin * KwikByte, Inc. @@ -122,7 +122,7 @@ static void __init kb9202_board_init(void) /* USB Device */ at91_add_device_udc(&kb9202_udc_data); /* MMC */ - at91_add_device_mmc(&kb9202_mmc_data); + at91_add_device_mmc(0, &kb9202_mmc_data); /* I2C */ at91_add_device_i2c(); /* SPI */ diff --git a/arch/arm/mach-at91rm9200/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c index da5d58ac870..57fb4499d96 100644 --- a/arch/arm/mach-at91rm9200/board-sam9260ek.c +++ b/arch/arm/mach-at91/board-sam9260ek.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/board-ek.c + * linux/arch/arm/mach-at91/board-sam9260ek.c * * Copyright (C) 2005 SAN People * Copyright (C) 2006 Atmel @@ -118,7 +118,7 @@ static struct spi_board_info ek_spi_devices[] = { /* * MACB Ethernet device */ -static struct __initdata eth_platform_data ek_macb_data = { +static struct __initdata at91_eth_data ek_macb_data = { .phy_irq_pin = AT91_PIN_PA7, .is_rmii = 1, }; @@ -187,7 +187,7 @@ static void __init ek_board_init(void) /* Ethernet */ at91_add_device_eth(&ek_macb_data); /* MMC */ - at91_add_device_mmc(&ek_mmc_data); + at91_add_device_mmc(0, &ek_mmc_data); } MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK") diff --git a/arch/arm/mach-at91rm9200/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index 30b490d8886..b7e772467cf 100644 --- a/arch/arm/mach-at91rm9200/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/board-ek.c + * linux/arch/arm/mach-at91/board-sam9261ek.c * * Copyright (C) 2005 SAN People * Copyright (C) 2006 Atmel @@ -243,7 +243,7 @@ static void __init ek_board_init(void) at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices)); #else /* MMC */ - at91_add_device_mmc(&ek_mmc_data); + at91_add_device_mmc(0, &ek_mmc_data); #endif } diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c new file mode 100644 index 00000000000..8fdce11a880 --- /dev/null +++ b/arch/arm/mach-at91/board-sam9263ek.c @@ -0,0 +1,176 @@ +/* + * linux/arch/arm/mach-at91/board-sam9263ek.c + * + * Copyright (C) 2005 SAN People + * Copyright (C) 2007 Atmel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> + +#include <asm/hardware.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/irq.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <asm/arch/board.h> +#include <asm/arch/gpio.h> +#include <asm/arch/at91sam926x_mc.h> + +#include "generic.h" + + +/* + * Serial port configuration. + * 0 .. 2 = USART0 .. USART2 + * 3 = DBGU + */ +static struct at91_uart_config __initdata ek_uart_config = { + .console_tty = 0, /* ttyS0 */ + .nr_tty = 2, + .tty_map = { 3, 0, -1, -1, } /* ttyS0, ..., ttyS3 */ +}; + +static void __init ek_map_io(void) +{ + /* Initialize processor: 16.367 MHz crystal */ + at91sam9263_initialize(16367660); + + /* Setup the serial ports and console */ + at91_init_serial(&ek_uart_config); +} + +static void __init ek_init_irq(void) +{ + at91sam9263_init_interrupts(NULL); +} + + +/* + * USB Host port + */ +static struct at91_usbh_data __initdata ek_usbh_data = { + .ports = 2, + .vbus_pin = { AT91_PIN_PA24, AT91_PIN_PA21 }, +}; + +/* + * USB Device port + */ +static struct at91_udc_data __initdata ek_udc_data = { + .vbus_pin = AT91_PIN_PA25, + .pullup_pin = 0, /* pull-up driven by UDC */ +}; + + +/* + * SPI devices. + */ +static struct spi_board_info ek_spi_devices[] = { +#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD) + { /* DataFlash card */ + .modalias = "mtd_dataflash", + .chip_select = 0, + .max_speed_hz = 15 * 1000 * 1000, + .bus_num = 0, + }, +#endif +}; + + +/* + * MCI (SD/MMC) + */ +static struct at91_mmc_data __initdata ek_mmc_data = { + .wire4 = 1, + .det_pin = AT91_PIN_PE18, + .wp_pin = AT91_PIN_PE19, +// .vcc_pin = ... not connected +}; + + +/* + * NAND flash + */ +static struct mtd_partition __initdata ek_nand_partition[] = { + { + .name = "Partition 1", + .offset = 0, + .size = 64 * 1024 * 1024, + }, + { + .name = "Partition 2", + .offset = 64 * 1024 * 1024, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct mtd_partition *nand_partitions(int size, int *num_partitions) +{ + *num_partitions = ARRAY_SIZE(ek_nand_partition); + return ek_nand_partition; +} + +static struct at91_nand_data __initdata ek_nand_data = { + .ale = 21, + .cle = 22, +// .det_pin = ... not connected + .rdy_pin = AT91_PIN_PA22, + .enable_pin = AT91_PIN_PD15, + .partition_info = nand_partitions, +#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16) + .bus_width_16 = 1, +#else + .bus_width_16 = 0, +#endif +}; + + +static void __init ek_board_init(void) +{ + /* Serial */ + at91_add_device_serial(); + /* USB Host */ + at91_add_device_usbh(&ek_usbh_data); + /* USB Device */ + at91_add_device_udc(&ek_udc_data); + /* SPI */ + at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices)); + /* MMC */ + at91_add_device_mmc(1, &ek_mmc_data); + /* NAND */ + at91_add_device_nand(&ek_nand_data); +} + +MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK") + /* Maintainer: Atmel */ + .phys_io = AT91_BASE_SYS, + .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, + .boot_params = AT91_SDRAM_BASE + 0x100, + .timer = &at91sam926x_timer, + .map_io = ek_map_io, + .init_irq = ek_init_irq, + .init_machine = ek_board_init, +MACHINE_END diff --git a/arch/arm/mach-at91rm9200/clock.c b/arch/arm/mach-at91/clock.c index 36a8e4d1cc6..06c9a0507d0 100644 --- a/arch/arm/mach-at91rm9200/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/clock.c + * linux/arch/arm/mach-at91/clock.c * * Copyright (C) 2005 David Brownell * Copyright (C) 2005 Ivan Kokshaysky @@ -525,27 +525,6 @@ fail: return 0; } -/* - * Several unused clocks may be active. Turn them off. - */ -static void __init at91_periphclk_reset(void) -{ - unsigned long reg; - struct clk *clk; - - reg = at91_sys_read(AT91_PMC_PCSR); - - list_for_each_entry(clk, &clocks, node) { - if (clk->mode != pmc_periph_mode) - continue; - - if (clk->users > 0) - reg &= ~clk->pmc_mask; - } - - at91_sys_write(AT91_PMC_PCDR, reg); -} - static struct clk *const standard_pmc_clocks[] __initdata = { /* four primary clocks */ &clk32k, @@ -586,7 +565,7 @@ int __init at91_clock_init(unsigned long main_clock) pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000); /* - * USB clock init: choose 48 MHz PLLB value, turn all clocks off, + * USB clock init: choose 48 MHz PLLB value, * disable 48MHz clock during usb peripheral suspend. * * REVISIT: assumes MCK doesn't derive from PLLB! @@ -596,16 +575,10 @@ int __init at91_clock_init(unsigned long main_clock) if (cpu_is_at91rm9200()) { uhpck.pmc_mask = AT91RM9200_PMC_UHP; udpck.pmc_mask = AT91RM9200_PMC_UDP; - at91_sys_write(AT91_PMC_SCDR, AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP); at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP); - } else if (cpu_is_at91sam9260()) { + } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263()) { uhpck.pmc_mask = AT91SAM926x_PMC_UHP; udpck.pmc_mask = AT91SAM926x_PMC_UDP; - at91_sys_write(AT91_PMC_SCDR, AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP); - } else if (cpu_is_at91sam9261()) { - uhpck.pmc_mask = (AT91SAM926x_PMC_UHP | AT91_PMC_HCK0); - udpck.pmc_mask = AT91SAM926x_PMC_UDP; - at91_sys_write(AT91_PMC_SCDR, AT91SAM926x_PMC_UHP | AT91_PMC_HCK0 | AT91SAM926x_PMC_UDP); } at91_sys_write(AT91_CKGR_PLLBR, 0); @@ -634,11 +607,34 @@ int __init at91_clock_init(unsigned long main_clock) (unsigned) main_clock / 1000000, ((unsigned) main_clock % 1000000) / 1000); - /* disable all programmable clocks */ - at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK0 | AT91_PMC_PCK1 | AT91_PMC_PCK2 | AT91_PMC_PCK3); + return 0; +} + +/* + * Several unused clocks may be active. Turn them off. + */ +static int __init at91_clock_reset(void) +{ + unsigned long pcdr = 0; + unsigned long scdr = 0; + struct clk *clk; + + list_for_each_entry(clk, &clocks, node) { + if (clk->users > 0) + continue; + + if (clk->mode == pmc_periph_mode) + pcdr |= clk->pmc_mask; + + if (clk->mode == pmc_sys_mode) + scdr |= clk->pmc_mask; + + pr_debug("Clocks: disable unused %s\n", clk->name); + } - /* disable all other unused peripheral clocks */ - at91_periphclk_reset(); + at91_sys_write(AT91_PMC_PCDR, pcdr); + at91_sys_write(AT91_PMC_SCDR, scdr); return 0; } +late_initcall(at91_clock_reset); diff --git a/arch/arm/mach-at91rm9200/clock.h b/arch/arm/mach-at91/clock.h index b5c7a2eb2d1..1ba3b95ff35 100644 --- a/arch/arm/mach-at91rm9200/clock.h +++ b/arch/arm/mach-at91/clock.h @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/clock.h + * linux/arch/arm/mach-at91/clock.h * * 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 diff --git a/arch/arm/mach-at91rm9200/generic.h b/arch/arm/mach-at91/generic.h index 8c4d5a77d48..bda26221c52 100644 --- a/arch/arm/mach-at91rm9200/generic.h +++ b/arch/arm/mach-at91/generic.h @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/generic.h + * linux/arch/arm/mach-at91/generic.h * * Copyright (C) 2005 David Brownell * @@ -12,11 +12,13 @@ extern void __init at91rm9200_initialize(unsigned long main_clock, unsigned short banks); extern void __init at91sam9260_initialize(unsigned long main_clock); extern void __init at91sam9261_initialize(unsigned long main_clock); +extern void __init at91sam9263_initialize(unsigned long main_clock); /* Interrupts */ extern void __init at91rm9200_init_interrupts(unsigned int priority[]); extern void __init at91sam9260_init_interrupts(unsigned int priority[]); extern void __init at91sam9261_init_interrupts(unsigned int priority[]); +extern void __init at91sam9263_init_interrupts(unsigned int priority[]); extern void __init at91_aic_init(unsigned int priority[]); /* Timer */ diff --git a/arch/arm/mach-at91rm9200/gpio.c b/arch/arm/mach-at91/gpio.c index 15eb5b6b29f..7b87f3f101b 100644 --- a/arch/arm/mach-at91rm9200/gpio.c +++ b/arch/arm/mach-at91/gpio.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/gpio.c + * linux/arch/arm/mach-at91/gpio.c * * Copyright (C) 2005 HP Labs * diff --git a/arch/arm/mach-at91rm9200/irq.c b/arch/arm/mach-at91/irq.c index 2148daafd29..78a5cdb746d 100644 --- a/arch/arm/mach-at91rm9200/irq.c +++ b/arch/arm/mach-at91/irq.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91rm9200/irq.c + * linux/arch/arm/mach-at91/irq.c * * Copyright (C) 2004 SAN People * Copyright (C) 2004 ATMEL diff --git a/arch/arm/mach-at91rm9200/leds.c b/arch/arm/mach-at91/leds.c index 1a333730466..0d514497398 100644 --- a/arch/arm/mach-at91rm9200/leds.c +++ b/arch/arm/mach-at91/leds.c @@ -86,10 +86,6 @@ static int __init leds_init(void) if (!at91_leds_timer || !at91_leds_cpu) return -ENODEV; - /* Enable PIO to access the LEDs */ - at91_set_gpio_output(at91_leds_timer, 1); - at91_set_gpio_output(at91_leds_cpu, 1); - leds_event = at91_leds_event; leds_event(led_start); diff --git a/arch/arm/mach-at91rm9200/pm.c b/arch/arm/mach-at91/pm.c index 67aa5572a3e..b49bfda53d7 100644 --- a/arch/arm/mach-at91rm9200/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-at91rm9200/pm.c + * arch/arm/mach-at91/pm.c * AT91 Power Management * * Copyright (C) 2005 David Brownell @@ -80,6 +80,8 @@ static int at91_pm_verify_clocks(void) #warning "Check SAM9260 USB clocks" } else if (cpu_is_at91sam9261()) { #warning "Check SAM9261 USB clocks" + } else if (cpu_is_at91sam9263()) { +#warning "Check SAM9263 USB clocks" } #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig index af7904b3d0a..575a21dabd2 100644 --- a/arch/arm/mach-ep93xx/Kconfig +++ b/arch/arm/mach-ep93xx/Kconfig @@ -51,6 +51,31 @@ config MACH_GESBC9312 Say 'Y' here if you want your kernel to support the Glomation GESBC-9312-sx board. +config MACH_MICRO9 + bool + default n + +config MACH_MICRO9H + bool "Support Contec Hypercontrol Micro9-H" + select MACH_MICRO9 + help + Say 'Y' here if you want your kernel to support the + Contec Hypercontrol Micro9-H board. + +config MACH_MICRO9M + bool "Support Contec Hypercontrol Micro9-M" + select MACH_MICRO9 + help + Say 'Y' here if you want your kernel to support the + Contec Hypercontrol Micro9-M board. + +config MACH_MICRO9L + bool "Support Contec Hypercontrol Micro9-L" + select MACH_MICRO9 + help + Say 'Y' here if you want your kernel to support the + Contec Hypercontrol Micro9-L board. + config MACH_TS72XX bool "Support Technologic Systems TS-72xx SBC" help diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile index b06641dd450..0d3bf932654 100644 --- a/arch/arm/mach-ep93xx/Makefile +++ b/arch/arm/mach-ep93xx/Makefile @@ -13,4 +13,5 @@ obj-$(CONFIG_MACH_EDB9312) += edb9312.o obj-$(CONFIG_MACH_EDB9315) += edb9315.o obj-$(CONFIG_MACH_EDB9315A) += edb9315a.o obj-$(CONFIG_MACH_GESBC9312) += gesbc9312.o +obj-$(CONFIG_MACH_MICRO9) += micro9.o obj-$(CONFIG_MACH_TS72XX) += ts72xx.o diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index 08ad782c164..f174d1a3b11 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/module.h> #include <linux/string.h> #include <asm/div64.h> #include <asm/hardware.h> @@ -124,7 +125,7 @@ static unsigned long calc_pll_rate(u32 config_word) return (unsigned long)rate; } -void ep93xx_clock_init(void) +static int __init ep93xx_clock_init(void) { u32 value; @@ -153,4 +154,7 @@ void ep93xx_clock_init(void) printk(KERN_INFO "ep93xx: FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n", clk_f.rate / 1000000, clk_h.rate / 1000000, clk_p.rate / 1000000); + + return 0; } +arch_initcall(ep93xx_clock_init); diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 6b26346191c..829aed696d9 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -152,22 +152,30 @@ struct sys_timer ep93xx_timer = { /************************************************************************* * GPIO handling for EP93xx *************************************************************************/ -static unsigned char gpio_int_enable[2]; -static unsigned char gpio_int_type1[2]; -static unsigned char gpio_int_type2[2]; +static unsigned char gpio_int_unmasked[3]; +static unsigned char gpio_int_enabled[3]; +static unsigned char gpio_int_type1[3]; +static unsigned char gpio_int_type2[3]; -static void update_gpio_ab_int_params(int port) +static void update_gpio_int_params(int abf) { - if (port == 0) { + if (abf == 0) { __raw_writeb(0, EP93XX_GPIO_A_INT_ENABLE); __raw_writeb(gpio_int_type2[0], EP93XX_GPIO_A_INT_TYPE2); __raw_writeb(gpio_int_type1[0], EP93XX_GPIO_A_INT_TYPE1); - __raw_writeb(gpio_int_enable[0], EP93XX_GPIO_A_INT_ENABLE); - } else if (port == 1) { + __raw_writeb(gpio_int_unmasked[0] & gpio_int_enabled[0], EP93XX_GPIO_A_INT_ENABLE); + } else if (abf == 1) { __raw_writeb(0, EP93XX_GPIO_B_INT_ENABLE); __raw_writeb(gpio_int_type2[1], EP93XX_GPIO_B_INT_TYPE2); __raw_writeb(gpio_int_type1[1], EP93XX_GPIO_B_INT_TYPE1); - __raw_writeb(gpio_int_enable[1], EP93XX_GPIO_B_INT_ENABLE); + __raw_writeb(gpio_int_unmasked[1] & gpio_int_enabled[1], EP93XX_GPIO_B_INT_ENABLE); + } else if (abf == 2) { + __raw_writeb(0, EP93XX_GPIO_F_INT_ENABLE); + __raw_writeb(gpio_int_type2[2], EP93XX_GPIO_F_INT_TYPE2); + __raw_writeb(gpio_int_type1[2], EP93XX_GPIO_F_INT_TYPE1); + __raw_writeb(gpio_int_unmasked[2] & gpio_int_enabled[2], EP93XX_GPIO_F_INT_ENABLE); + } else { + BUG(); } } @@ -192,8 +200,13 @@ void gpio_line_config(int line, int direction) local_irq_save(flags); if (direction == GPIO_OUT) { if (line >= 0 && line < 16) { - gpio_int_enable[line >> 3] &= ~(1 << (line & 7)); - update_gpio_ab_int_params(line >> 3); + /* Port A/B. */ + gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7)); + update_gpio_int_params(line >> 3); + } else if (line >= 40 && line < 48) { + /* Port F. */ + gpio_int_unmasked[2] &= ~(1 << (line & 7)); + update_gpio_int_params(2); } v = __raw_readb(data_direction_register); @@ -244,8 +257,7 @@ EXPORT_SYMBOL(gpio_line_set); /************************************************************************* * EP93xx IRQ handling *************************************************************************/ -static void ep93xx_gpio_ab_irq_handler(unsigned int irq, - struct irq_desc *desc) +static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) { unsigned char status; int i; @@ -267,37 +279,46 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, } } -static void ep93xx_gpio_ab_irq_mask_ack(unsigned int irq) +static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + int gpio_irq = IRQ_EP93XX_GPIO(16) + (((irq + 1) & 7) ^ 4); + + desc_handle_irq(gpio_irq, irq_desc + gpio_irq); +} + +static void ep93xx_gpio_irq_mask_ack(unsigned int irq) { int line = irq - IRQ_EP93XX_GPIO(0); int port = line >> 3; - gpio_int_enable[port] &= ~(1 << (line & 7)); - update_gpio_ab_int_params(port); + gpio_int_unmasked[port] &= ~(1 << (line & 7)); + update_gpio_int_params(port); - if (line >> 3) { - __raw_writel(1 << (line & 7), EP93XX_GPIO_B_INT_ACK); - } else { + if (port == 0) { __raw_writel(1 << (line & 7), EP93XX_GPIO_A_INT_ACK); + } else if (port == 1) { + __raw_writel(1 << (line & 7), EP93XX_GPIO_B_INT_ACK); + } else if (port == 2) { + __raw_writel(1 << (line & 7), EP93XX_GPIO_F_INT_ACK); } } -static void ep93xx_gpio_ab_irq_mask(unsigned int irq) +static void ep93xx_gpio_irq_mask(unsigned int irq) { int line = irq - IRQ_EP93XX_GPIO(0); int port = line >> 3; - gpio_int_enable[port] &= ~(1 << (line & 7)); - update_gpio_ab_int_params(port); + gpio_int_unmasked[port] &= ~(1 << (line & 7)); + update_gpio_int_params(port); } -static void ep93xx_gpio_ab_irq_unmask(unsigned int irq) +static void ep93xx_gpio_irq_unmask(unsigned int irq) { int line = irq - IRQ_EP93XX_GPIO(0); int port = line >> 3; - gpio_int_enable[port] |= 1 << (line & 7); - update_gpio_ab_int_params(port); + gpio_int_unmasked[port] |= 1 << (line & 7); + update_gpio_int_params(port); } @@ -306,40 +327,51 @@ static void ep93xx_gpio_ab_irq_unmask(unsigned int irq) * edge (1) triggered, while gpio_int_type2 controls whether it * triggers on low/falling (0) or high/rising (1). */ -static int ep93xx_gpio_ab_irq_type(unsigned int irq, unsigned int type) +static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type) { int port; int line; line = irq - IRQ_EP93XX_GPIO(0); - gpio_line_config(line, GPIO_IN); + if (line >= 0 && line < 16) { + gpio_line_config(line, GPIO_IN); + } else { + gpio_line_config(EP93XX_GPIO_LINE_F(line), GPIO_IN); + } port = line >> 3; line &= 7; if (type & IRQT_RISING) { + gpio_int_enabled[port] |= 1 << line; gpio_int_type1[port] |= 1 << line; gpio_int_type2[port] |= 1 << line; } else if (type & IRQT_FALLING) { + gpio_int_enabled[port] |= 1 << line; gpio_int_type1[port] |= 1 << line; gpio_int_type2[port] &= ~(1 << line); } else if (type & IRQT_HIGH) { + gpio_int_enabled[port] |= 1 << line; gpio_int_type1[port] &= ~(1 << line); gpio_int_type2[port] |= 1 << line; } else if (type & IRQT_LOW) { + gpio_int_enabled[port] |= 1 << line; gpio_int_type1[port] &= ~(1 << line); gpio_int_type2[port] &= ~(1 << line); + } else { + gpio_int_enabled[port] &= ~(1 << line); } - update_gpio_ab_int_params(port); + update_gpio_int_params(port); return 0; } -static struct irq_chip ep93xx_gpio_ab_irq_chip = { - .ack = ep93xx_gpio_ab_irq_mask_ack, - .mask = ep93xx_gpio_ab_irq_mask, - .unmask = ep93xx_gpio_ab_irq_unmask, - .set_type = ep93xx_gpio_ab_irq_type, +static struct irq_chip ep93xx_gpio_irq_chip = { + .name = "GPIO", + .ack = ep93xx_gpio_irq_mask_ack, + .mask = ep93xx_gpio_irq_mask, + .unmask = ep93xx_gpio_irq_unmask, + .set_type = ep93xx_gpio_irq_type, }; @@ -350,12 +382,21 @@ void __init ep93xx_init_irq(void) vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK); vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK); - for (irq = IRQ_EP93XX_GPIO(0) ; irq <= IRQ_EP93XX_GPIO(15); irq++) { - set_irq_chip(irq, &ep93xx_gpio_ab_irq_chip); + for (irq = IRQ_EP93XX_GPIO(0); irq <= IRQ_EP93XX_GPIO(23); irq++) { + set_irq_chip(irq, &ep93xx_gpio_irq_chip); set_irq_handler(irq, handle_level_irq); set_irq_flags(irq, IRQF_VALID); } + set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler); + set_irq_chained_handler(IRQ_EP93XX_GPIO0MUX, ep93xx_gpio_f_irq_handler); + set_irq_chained_handler(IRQ_EP93XX_GPIO1MUX, ep93xx_gpio_f_irq_handler); + set_irq_chained_handler(IRQ_EP93XX_GPIO2MUX, ep93xx_gpio_f_irq_handler); + set_irq_chained_handler(IRQ_EP93XX_GPIO3MUX, ep93xx_gpio_f_irq_handler); + set_irq_chained_handler(IRQ_EP93XX_GPIO4MUX, ep93xx_gpio_f_irq_handler); + set_irq_chained_handler(IRQ_EP93XX_GPIO5MUX, ep93xx_gpio_f_irq_handler); + set_irq_chained_handler(IRQ_EP93XX_GPIO6MUX, ep93xx_gpio_f_irq_handler); + set_irq_chained_handler(IRQ_EP93XX_GPIO7MUX, ep93xx_gpio_f_irq_handler); } @@ -461,8 +502,6 @@ void __init ep93xx_init_devices(void) { unsigned int v; - ep93xx_clock_init(); - /* * Disallow access to MaverickCrunch initially. */ @@ -477,8 +516,4 @@ void __init ep93xx_init_devices(void) platform_device_register(&ep93xx_rtc_device); platform_device_register(&ep93xx_ohci_device); - -#ifdef CONFIG_CRUNCH - elf_hwcap |= HWCAP_CRUNCH; -#endif } diff --git a/arch/arm/mach-ep93xx/micro9.c b/arch/arm/mach-ep93xx/micro9.c new file mode 100644 index 00000000000..f28c1294cae --- /dev/null +++ b/arch/arm/mach-ep93xx/micro9.c @@ -0,0 +1,157 @@ +/* + * linux/arch/arm/mach-ep93xx/micro9.c + * + * Copyright (C) 2006 Contec Steuerungstechnik & Automation GmbH + * Manfred Gruber <manfred.gruber@contec.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/platform_device.h> +#include <linux/sched.h> + +#include <linux/mtd/physmap.h> + +#include <asm/io.h> +#include <asm/hardware.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +static struct ep93xx_eth_data micro9_eth_data = { + .phy_id = 0x1f, +}; + +static struct resource micro9_eth_resource[] = { + { + .start = EP93XX_ETHERNET_PHYS_BASE, + .end = EP93XX_ETHERNET_PHYS_BASE + 0xffff, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_EP93XX_ETHERNET, + .end = IRQ_EP93XX_ETHERNET, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device micro9_eth_device = { + .name = "ep93xx-eth", + .id = -1, + .dev = { + .platform_data = µ9_eth_data, + }, + .num_resources = ARRAY_SIZE(micro9_eth_resource), + .resource = micro9_eth_resource, +}; + +static void __init micro9_eth_init(void) +{ + memcpy(micro9_eth_data.dev_addr, + (void *)(EP93XX_ETHERNET_BASE + 0x50), 6); + platform_device_register(µ9_eth_device); +} + +static void __init micro9_init(void) +{ + micro9_eth_init(); +} + +/* + * Micro9-H + */ +#ifdef CONFIG_MACH_MICRO9H +static struct physmap_flash_data micro9h_flash_data = { + .width = 4, +}; + +static struct resource micro9h_flash_resource = { + .start = 0x10000000, + .end = 0x13ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device micro9h_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = µ9h_flash_data, + }, + .num_resources = 1, + .resource = µ9h_flash_resource, +}; + +static void __init micro9h_init(void) +{ + platform_device_register(µ9h_flash); +} + +static void __init micro9h_init_machine(void) +{ + ep93xx_init_devices(); + micro9_init(); + micro9h_init(); +} + +MACHINE_START(MICRO9, "Contec Hypercontrol Micro9-H") + /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */ + .phys_io = EP93XX_APB_PHYS_BASE, + .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = 0x00000100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .timer = &ep93xx_timer, + .init_machine = micro9h_init_machine, +MACHINE_END +#endif + +/* + * Micro9-M + */ +#ifdef CONFIG_MACH_MICRO9M +static void __init micro9m_init_machine(void) +{ + ep93xx_init_devices(); + micro9_init(); +} + +MACHINE_START(MICRO9M, "Contec Hypercontrol Micro9-M") + /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */ + .phys_io = EP93XX_APB_PHYS_BASE, + .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = 0x00000100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .timer = &ep93xx_timer, + .init_machine = micro9m_init_machine, +MACHINE_END +#endif + +/* + * Micro9-L + */ +#ifdef CONFIG_MACH_MICRO9L +static void __init micro9l_init_machine(void) +{ + ep93xx_init_devices(); + micro9_init(); +} + +MACHINE_START(MICRO9L, "Contec Hypercontrol Micro9-L") + /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */ + .phys_io = EP93XX_APB_PHYS_BASE, + .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = 0x00000100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .timer = &ep93xx_timer, + .init_machine = micro9l_init_machine, +MACHINE_END +#endif + diff --git a/arch/arm/mach-iop13xx/irq.c b/arch/arm/mach-iop13xx/irq.c index dbbc07c38b1..162b9321496 100644 --- a/arch/arm/mach-iop13xx/irq.c +++ b/arch/arm/mach-iop13xx/irq.c @@ -250,11 +250,14 @@ static struct irq_chip iop13xx_irqchip4 = { .unmask = iop13xx_irq_unmask3, }; +extern void iop_init_cp6_handler(void); + void __init iop13xx_init_irq(void) { unsigned int i; u32 cp_flags = iop13xx_cp6_save(); + iop_init_cp6_handler(); /* disable all interrupts */ write_intctl_0(0); diff --git a/arch/arm/mach-iop32x/irq.c b/arch/arm/mach-iop32x/irq.c index 3ec1cd5c4f9..8b0ac5590ae 100644 --- a/arch/arm/mach-iop32x/irq.c +++ b/arch/arm/mach-iop32x/irq.c @@ -60,6 +60,8 @@ void __init iop32x_init_irq(void) { int i; + iop_init_cp6_handler(); + intctl_write(0); intstr_write(0); if (machine_is_glantank() || diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c index 2499a7707e3..966aa51aee0 100644 --- a/arch/arm/mach-iop32x/n2100.c +++ b/arch/arm/mach-iop32x/n2100.c @@ -120,6 +120,20 @@ static struct hw_pci n2100_pci __initdata = { .map_irq = n2100_pci_map_irq, }; +/* + * Both r8169 chips on the n2100 exhibit PCI parity problems. Set + * the ->broken_parity_status flag for both ports so that the r8169 + * driver knows it should ignore error interrupts. + */ +static void n2100_fixup_r8169(struct pci_dev *dev) +{ + if (dev->bus->number == 0 && + (dev->devfn == PCI_DEVFN(1, 0) || + dev->devfn == PCI_DEVFN(2, 0))) + dev->broken_parity_status = 1; +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_REALTEK, PCI_ANY_ID, n2100_fixup_r8169); + static int __init n2100_pci_init(void) { if (machine_is_n2100()) diff --git a/arch/arm/mach-iop33x/irq.c b/arch/arm/mach-iop33x/irq.c index 00b37f32d72..effbe6b782d 100644 --- a/arch/arm/mach-iop33x/irq.c +++ b/arch/arm/mach-iop33x/irq.c @@ -110,6 +110,8 @@ void __init iop33x_init_irq(void) { int i; + iop_init_cp6_handler(); + intctl0_write(0); intctl1_write(0); intstr0_write(0); diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig index e316bd93313..8a339cdfe22 100644 --- a/arch/arm/mach-ixp4xx/Kconfig +++ b/arch/arm/mach-ixp4xx/Kconfig @@ -17,7 +17,7 @@ config MACH_NSLU2 NSLU2 NAS device. For more information on this platform, see http://www.nslu2-linux.org -config ARCH_AVILA +config MACH_AVILA bool "Avila" select PCI help @@ -25,6 +25,14 @@ config ARCH_AVILA Avila Network Platform. For more information on this platform, see <file:Documentation/arm/IXP4xx>. +config MACH_LOFT + bool "Loft" + depends on MACH_AVILA + help + Say 'Y' here if you want your kernel to support the Giant + Shoulder Inc Loft board (a minor variation on the standard + Gateworks Avila Network Platform). + config ARCH_ADI_COYOTE bool "Coyote" select PCI @@ -86,7 +94,7 @@ config MACH_NAS100D # config ARCH_IXDP4XX bool - depends on ARCH_IXDP425 || ARCH_AVILA || MACH_IXDP465 + depends on ARCH_IXDP425 || MACH_IXDP465 default y # diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile index 640315d8b96..746e297284e 100644 --- a/arch/arm/mach-ixp4xx/Makefile +++ b/arch/arm/mach-ixp4xx/Makefile @@ -6,6 +6,7 @@ obj-pci-y := obj-pci-n := obj-pci-$(CONFIG_ARCH_IXDP4XX) += ixdp425-pci.o +obj-pci-$(CONFIG_MACH_AVILA) += avila-pci.o obj-pci-$(CONFIG_MACH_IXDPG425) += ixdpg425-pci.o obj-pci-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o obj-pci-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o @@ -15,6 +16,7 @@ obj-pci-$(CONFIG_MACH_NAS100D) += nas100d-pci.o obj-y += common.o obj-$(CONFIG_ARCH_IXDP4XX) += ixdp425-setup.o +obj-$(CONFIG_MACH_AVILA) += avila-setup.o obj-$(CONFIG_MACH_IXDPG425) += coyote-setup.o obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-setup.o obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-setup.o diff --git a/arch/arm/mach-ixp4xx/avila-pci.c b/arch/arm/mach-ixp4xx/avila-pci.c new file mode 100644 index 00000000000..3f867691d9f --- /dev/null +++ b/arch/arm/mach-ixp4xx/avila-pci.c @@ -0,0 +1,78 @@ +/* + * arch/arm/mach-ixp4xx/avila-pci.c + * + * Gateworks Avila board-level PCI initialization + * + * Author: Michael-Luke Jones <mlj28@cam.ac.uk> + * + * Based on ixdp-pci.c + * Copyright (C) 2002 Intel Corporation. + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * Maintainer: Deepak Saxena <dsaxena@plexity.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/delay.h> + +#include <asm/mach/pci.h> +#include <asm/irq.h> +#include <asm/hardware.h> +#include <asm/mach-types.h> + +void __init avila_pci_preinit(void) +{ + set_irq_type(IRQ_AVILA_PCI_INTA, IRQT_LOW); + set_irq_type(IRQ_AVILA_PCI_INTB, IRQT_LOW); + set_irq_type(IRQ_AVILA_PCI_INTC, IRQT_LOW); + set_irq_type(IRQ_AVILA_PCI_INTD, IRQT_LOW); + + ixp4xx_pci_preinit(); +} + +static int __init avila_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + static int pci_irq_table[AVILA_PCI_IRQ_LINES] = { + IRQ_AVILA_PCI_INTA, + IRQ_AVILA_PCI_INTB, + IRQ_AVILA_PCI_INTC, + IRQ_AVILA_PCI_INTD + }; + + int irq = -1; + + if (slot >= 1 && + slot <= (machine_is_loft() ? LOFT_PCI_MAX_DEV : AVILA_PCI_MAX_DEV) && + pin >= 1 && pin <= AVILA_PCI_IRQ_LINES) { + irq = pci_irq_table[(slot + pin - 2) % 4]; + } + + return irq; +} + +struct hw_pci avila_pci __initdata = { + .nr_controllers = 1, + .preinit = avila_pci_preinit, + .swizzle = pci_std_swizzle, + .setup = ixp4xx_setup, + .scan = ixp4xx_scan_bus, + .map_irq = avila_map_irq, +}; + +int __init avila_pci_init(void) +{ + if (machine_is_avila() || machine_is_loft()) + pci_common_init(&avila_pci); + return 0; +} + +subsys_initcall(avila_pci_init); + diff --git a/arch/arm/mach-ixp4xx/avila-setup.c b/arch/arm/mach-ixp4xx/avila-setup.c new file mode 100644 index 00000000000..d59b8dc7dc7 --- /dev/null +++ b/arch/arm/mach-ixp4xx/avila-setup.c @@ -0,0 +1,192 @@ +/* + * arch/arm/mach-ixp4xx/avila-setup.c + * + * Gateworks Avila board-setup + * + * Author: Michael-Luke Jones <mlj28@cam.ac.uk> + * + * Based on ixdp-setup.c + * Copyright (C) 2003-2005 MontaVista Software, Inc. + * + * Author: Deepak Saxena <dsaxena@plexity.net> + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/serial.h> +#include <linux/tty.h> +#include <linux/serial_8250.h> +#include <linux/slab.h> + +#include <asm/types.h> +#include <asm/setup.h> +#include <asm/memory.h> +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/irq.h> +#include <asm/mach/arch.h> +#include <asm/mach/flash.h> + +static struct flash_platform_data avila_flash_data = { + .map_name = "cfi_probe", + .width = 2, +}; + +static struct resource avila_flash_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device avila_flash = { + .name = "IXP4XX-Flash", + .id = 0, + .dev = { + .platform_data = &avila_flash_data, + }, + .num_resources = 1, + .resource = &avila_flash_resource, +}; + +static struct ixp4xx_i2c_pins avila_i2c_gpio_pins = { + .sda_pin = AVILA_SDA_PIN, + .scl_pin = AVILA_SCL_PIN, +}; + +static struct platform_device avila_i2c_controller = { + .name = "IXP4XX-I2C", + .id = 0, + .dev = { + .platform_data = &avila_i2c_gpio_pins, + }, + .num_resources = 0 +}; + +static struct resource avila_uart_resources[] = { + { + .start = IXP4XX_UART1_BASE_PHYS, + .end = IXP4XX_UART1_BASE_PHYS + 0x0fff, + .flags = IORESOURCE_MEM + }, + { + .start = IXP4XX_UART2_BASE_PHYS, + .end = IXP4XX_UART2_BASE_PHYS + 0x0fff, + .flags = IORESOURCE_MEM + } +}; + +static struct plat_serial8250_port avila_uart_data[] = { + { + .mapbase = IXP4XX_UART1_BASE_PHYS, + .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET, + .irq = IRQ_IXP4XX_UART1, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IXP4XX_UART_XTAL, + }, + { + .mapbase = IXP4XX_UART2_BASE_PHYS, + .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET, + .irq = IRQ_IXP4XX_UART2, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IXP4XX_UART_XTAL, + }, + { }, +}; + +static struct platform_device avila_uart = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev.platform_data = avila_uart_data, + .num_resources = 2, + .resource = avila_uart_resources +}; + +static struct resource avila_pata_resources[] = { + { + .flags = IORESOURCE_MEM + }, + { + .flags = IORESOURCE_MEM, + }, + { + .name = "intrq", + .start = IRQ_IXP4XX_GPIO12, + .end = IRQ_IXP4XX_GPIO12, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct ixp4xx_pata_data avila_pata_data = { + .cs0_bits = 0xbfff0043, + .cs1_bits = 0xbfff0043, +}; + +static struct platform_device avila_pata = { + .name = "pata_ixp4xx_cf", + .id = 0, + .dev.platform_data = &avila_pata_data, + .num_resources = ARRAY_SIZE(avila_pata_resources), + .resource = avila_pata_resources, +}; + +static struct platform_device *avila_devices[] __initdata = { + &avila_i2c_controller, + &avila_flash, + &avila_uart +}; + +static void __init avila_init(void) +{ + ixp4xx_sys_init(); + + avila_flash_resource.start = IXP4XX_EXP_BUS_BASE(0); + avila_flash_resource.end = + IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; + + platform_add_devices(avila_devices, ARRAY_SIZE(avila_devices)); + + avila_pata_resources[0].start = IXP4XX_EXP_BUS_BASE(1); + avila_pata_resources[0].end = IXP4XX_EXP_BUS_END(1); + + avila_pata_resources[1].start = IXP4XX_EXP_BUS_BASE(2); + avila_pata_resources[1].end = IXP4XX_EXP_BUS_END(2); + + avila_pata_data.cs0_cfg = IXP4XX_EXP_CS1; + avila_pata_data.cs1_cfg = IXP4XX_EXP_CS2; + + platform_device_register(&avila_pata); + +} + +MACHINE_START(AVILA, "Gateworks Avila Network Platform") + /* Maintainer: Deepak Saxena <dsaxena@plexity.net> */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = ixp4xx_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x0100, + .init_machine = avila_init, +MACHINE_END + + /* + * Loft is functionally equivalent to Avila except that it has a + * different number for the maximum PCI devices. The MACHINE + * structure below is identical to Avila except for the comment. + */ +#ifdef CONFIG_MACH_LOFT +MACHINE_START(LOFT, "Giant Shoulder Inc Loft board") + /* Maintainer: Tom Billman <kernel@giantshoulderinc.com> */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = ixp4xx_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x0100, + .init_machine = avila_init, +MACHINE_END +#endif + diff --git a/arch/arm/mach-ixp4xx/ixdp425-pci.c b/arch/arm/mach-ixp4xx/ixdp425-pci.c index d5156c043f0..99c1dc8033c 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-pci.c +++ b/arch/arm/mach-ixp4xx/ixdp425-pci.c @@ -66,7 +66,7 @@ struct hw_pci ixdp425_pci __initdata = { int __init ixdp425_pci_init(void) { if (machine_is_ixdp425() || machine_is_ixcdp1100() || - machine_is_avila() || machine_is_ixdp465()) + machine_is_ixdp465()) pci_common_init(&ixdp425_pci); return 0; } diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index da72383ee30..04b1d56396a 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -156,23 +156,3 @@ MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform") .init_machine = ixdp425_init, MACHINE_END #endif - -/* - * Avila is functionally equivalent to IXDP425 except that it adds - * a CF IDE slot hanging off the expansion bus. When we have a - * driver for IXP4xx CF IDE with driver model support we'll move - * Avila to it's own setup file. - */ -#ifdef CONFIG_ARCH_AVILA -MACHINE_START(AVILA, "Gateworks Avila Network Platform") - /* Maintainer: Deepak Saxena <dsaxena@plexity.net> */ - .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, - .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, - .map_io = ixp4xx_map_io, - .init_irq = ixp4xx_init_irq, - .timer = &ixp4xx_timer, - .boot_params = 0x0100, - .init_machine = ixdp425_init, -MACHINE_END -#endif - diff --git a/arch/arm/mach-ns9xxx/Kconfig b/arch/arm/mach-ns9xxx/Kconfig new file mode 100644 index 00000000000..8175ba92a2f --- /dev/null +++ b/arch/arm/mach-ns9xxx/Kconfig @@ -0,0 +1,21 @@ +if ARCH_NS9XXX + +menu "NS9xxx Implementations" + +config MACH_CC9P9360DEV + bool "Connect Core 9P 9360 on an A9M9750 Devboard" + select PROCESSOR_NS9360 + select BOARD_A9M9750DEV + help + Say Y here if you are using the Digi Connect Core 9P 9360 + on an A9M9750 Development Board. + +config PROCESSOR_NS9360 + bool + +config BOARD_A9M9750DEV + bool + +endmenu + +endif diff --git a/arch/arm/mach-ns9xxx/Makefile b/arch/arm/mach-ns9xxx/Makefile new file mode 100644 index 00000000000..91e945f5e16 --- /dev/null +++ b/arch/arm/mach-ns9xxx/Makefile @@ -0,0 +1,5 @@ +obj-y := irq.o time.o generic.o + +obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o + +obj-$(CONFIG_BOARD_A9M9750DEV) += board-a9m9750dev.o diff --git a/arch/arm/mach-ns9xxx/Makefile.boot b/arch/arm/mach-ns9xxx/Makefile.boot new file mode 100644 index 00000000000..75ed64e90fa --- /dev/null +++ b/arch/arm/mach-ns9xxx/Makefile.boot @@ -0,0 +1,2 @@ +zreladdr-y := 0x108000 +params_phys-y := 0x100 diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.c b/arch/arm/mach-ns9xxx/board-a9m9750dev.c new file mode 100644 index 00000000000..25289884a60 --- /dev/null +++ b/arch/arm/mach-ns9xxx/board-a9m9750dev.c @@ -0,0 +1,199 @@ +/* + * arch/arm/mach-ns9xxx/board-a9m9750dev.c + * + * Copyright (C) 2006,2007 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <linux/platform_device.h> +#include <linux/serial_8250.h> +#include <linux/irq.h> + +#include <asm/mach/map.h> + +#include <asm/arch-ns9xxx/board.h> +#include <asm/arch-ns9xxx/regs-sys.h> +#include <asm/arch-ns9xxx/regs-mem.h> +#include <asm/arch-ns9xxx/regs-bbu.h> +#include <asm/arch-ns9xxx/regs-board-a9m9750dev.h> + +#include "board-a9m9750dev.h" + +static struct map_desc board_a9m9750dev_io_desc[] __initdata = { + { /* FPGA on CS0 */ + .virtual = io_p2v(NS9XXX_CSxSTAT_PHYS(0)), + .pfn = __phys_to_pfn(NS9XXX_CSxSTAT_PHYS(0)), + .length = NS9XXX_CS0STAT_LENGTH, + .type = MT_DEVICE, + }, +}; + +void __init board_a9m9750dev_map_io(void) +{ + iotable_init(board_a9m9750dev_io_desc, + ARRAY_SIZE(board_a9m9750dev_io_desc)); +} + +static void a9m9750dev_fpga_ack_irq(unsigned int irq) +{ + /* nothing */ +} + +static void a9m9750dev_fpga_mask_irq(unsigned int irq) +{ + FPGA_IER &= ~(1 << (irq - FPGA_IRQ(0))); +} + +static void a9m9750dev_fpga_maskack_irq(unsigned int irq) +{ + a9m9750dev_fpga_mask_irq(irq); + a9m9750dev_fpga_ack_irq(irq); +} + +static void a9m9750dev_fpga_unmask_irq(unsigned int irq) +{ + FPGA_IER |= 1 << (irq - FPGA_IRQ(0)); +} + +static struct irq_chip a9m9750dev_fpga_chip = { + .ack = a9m9750dev_fpga_ack_irq, + .mask = a9m9750dev_fpga_mask_irq, + .mask_ack = a9m9750dev_fpga_maskack_irq, + .unmask = a9m9750dev_fpga_unmask_irq, +}; + +static void a9m9750dev_fpga_demux_handler(unsigned int irq, + struct irq_desc *desc) +{ + int stat = FPGA_ISR; + + while (stat != 0) { + int irqno = fls(stat) - 1; + + stat &= ~(1 << irqno); + + desc = irq_desc + FPGA_IRQ(irqno); + + desc_handle_irq(irqno, desc); + } +} + +void __init board_a9m9750dev_init_irq(void) +{ + u32 reg; + int i; + + /* + * configure gpio for IRQ_EXT2 + * use GPIO 11, because GPIO 32 is used for the LCD + */ + /* XXX: proper GPIO handling */ + BBU_GC(2) &= ~0x2000; + + for (i = FPGA_IRQ(0); i <= FPGA_IRQ(7); ++i) { + set_irq_chip(i, &a9m9750dev_fpga_chip); + set_irq_handler(i, handle_level_irq); + set_irq_flags(i, IRQF_VALID); + } + + /* IRQ_EXT2: level sensitive + active low */ + reg = SYS_EIC(2); + REGSET(reg, SYS_EIC, PLTY, AL); + REGSET(reg, SYS_EIC, LVEDG, LEVEL); + SYS_EIC(2) = reg; + + set_irq_chained_handler(IRQ_EXT2, + a9m9750dev_fpga_demux_handler); +} + +static struct plat_serial8250_port board_a9m9750dev_serial8250_port[] = { + { + .iobase = FPGA_UARTA_BASE, + .membase = (unsigned char*)FPGA_UARTA_BASE, + .mapbase = FPGA_UARTA_BASE, + .irq = IRQ_FPGA_UARTA, + .iotype = UPIO_MEM, + .uartclk = 18432000, + .regshift = 0, + .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ, + }, { + .iobase = FPGA_UARTB_BASE, + .membase = (unsigned char*)FPGA_UARTB_BASE, + .mapbase = FPGA_UARTB_BASE, + .irq = IRQ_FPGA_UARTB, + .iotype = UPIO_MEM, + .uartclk = 18432000, + .regshift = 0, + .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ, + }, { + .iobase = FPGA_UARTC_BASE, + .membase = (unsigned char*)FPGA_UARTC_BASE, + .mapbase = FPGA_UARTC_BASE, + .irq = IRQ_FPGA_UARTC, + .iotype = UPIO_MEM, + .uartclk = 18432000, + .regshift = 0, + .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ, + }, { + .iobase = FPGA_UARTD_BASE, + .membase = (unsigned char*)FPGA_UARTD_BASE, + .mapbase = FPGA_UARTD_BASE, + .irq = IRQ_FPGA_UARTD, + .iotype = UPIO_MEM, + .uartclk = 18432000, + .regshift = 0, + .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ, + }, { + /* end marker */ + }, +}; + +static struct platform_device board_a9m9750dev_serial_device = { + .name = "serial8250", + .dev = { + .platform_data = board_a9m9750dev_serial8250_port, + }, +}; + +static struct platform_device *board_a9m9750dev_devices[] __initdata = { + &board_a9m9750dev_serial_device, +}; + +void __init board_a9m9750dev_init_machine(void) +{ + u32 reg; + + /* setup static CS0: memory base ... */ + REGSETIM(SYS_SMCSSMB(0), SYS_SMCSSMB, CSxB, + NS9XXX_CSxSTAT_PHYS(0) >> 12); + + /* ... and mask */ + reg = SYS_SMCSSMM(0); + REGSETIM(reg, SYS_SMCSSMM, CSxM, 0xfffff); + REGSET(reg, SYS_SMCSSMM, CSEx, EN); + SYS_SMCSSMM(0) = reg; + + /* setup static CS0: memory configuration */ + reg = MEM_SMC(0); + REGSET(reg, MEM_SMC, WSMC, OFF); + REGSET(reg, MEM_SMC, BSMC, OFF); + REGSET(reg, MEM_SMC, EW, OFF); + REGSET(reg, MEM_SMC, PB, 1); + REGSET(reg, MEM_SMC, PC, AL); + REGSET(reg, MEM_SMC, PM, DIS); + REGSET(reg, MEM_SMC, MW, 8); + MEM_SMC(0) = reg; + + /* setup static CS0: timing */ + MEM_SMWED(0) = 0x2; + MEM_SMOED(0) = 0x2; + MEM_SMRD(0) = 0x6; + MEM_SMWD(0) = 0x6; + + platform_add_devices(board_a9m9750dev_devices, + ARRAY_SIZE(board_a9m9750dev_devices)); +} + diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.h b/arch/arm/mach-ns9xxx/board-a9m9750dev.h new file mode 100644 index 00000000000..edc75abbc5d --- /dev/null +++ b/arch/arm/mach-ns9xxx/board-a9m9750dev.h @@ -0,0 +1,15 @@ +/* + * arch/arm/mach-ns9xxx/board-a9m9750dev.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <linux/init.h> + +void __init board_a9m9750dev_map_io(void); +void __init board_a9m9750dev_init_machine(void); +void __init board_a9m9750dev_init_irq(void); diff --git a/arch/arm/mach-ns9xxx/generic.c b/arch/arm/mach-ns9xxx/generic.c new file mode 100644 index 00000000000..83e2b6532b2 --- /dev/null +++ b/arch/arm/mach-ns9xxx/generic.c @@ -0,0 +1,42 @@ +/* + * arch/arm/mach-ns9xxx/generic.c + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <asm/memory.h> +#include <asm/page.h> +#include <asm/mach-types.h> +#include <asm/mach/map.h> +#include <asm/arch-ns9xxx/regs-sys.h> +#include <asm/arch-ns9xxx/regs-mem.h> +#include <asm/arch-ns9xxx/board.h> + +static struct map_desc standard_io_desc[] __initdata = { + { /* BBus */ + .virtual = io_p2v(0x90000000), + .pfn = __phys_to_pfn(0x90000000), + .length = 0x00700000, + .type = MT_DEVICE, + }, { /* AHB */ + .virtual = io_p2v(0xa0100000), + .pfn = __phys_to_pfn(0xa0100000), + .length = 0x00900000, + .type = MT_DEVICE, + }, +}; + +void __init ns9xxx_map_io(void) +{ + iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); +} + +void __init ns9xxx_init_machine(void) +{ +} diff --git a/arch/arm/mach-ns9xxx/generic.h b/arch/arm/mach-ns9xxx/generic.h new file mode 100644 index 00000000000..687e291773f --- /dev/null +++ b/arch/arm/mach-ns9xxx/generic.h @@ -0,0 +1,19 @@ +/* + * arch/arm/mach-ns9xxx/generic.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <linux/time.h> +#include <asm/mach/time.h> +#include <linux/init.h> + +void __init ns9xxx_init_irq(void); +void __init ns9xxx_map_io(void); +void __init ns9xxx_init_machine(void); + +extern struct sys_timer ns9xxx_timer; diff --git a/arch/arm/mach-ns9xxx/irq.c b/arch/arm/mach-ns9xxx/irq.c new file mode 100644 index 00000000000..83d92724a97 --- /dev/null +++ b/arch/arm/mach-ns9xxx/irq.c @@ -0,0 +1,94 @@ +/* + * arch/arm/mach-ns9xxx/irq.c + * + * Copyright (C) 2006,2007 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <linux/interrupt.h> +#include <asm/mach/irq.h> +#include <asm/mach-types.h> +#include <asm/arch-ns9xxx/regs-sys.h> +#include <asm/arch-ns9xxx/irqs.h> +#include <asm/arch-ns9xxx/board.h> + +#include "generic.h" + +static void ns9xxx_ack_irq_timer(unsigned int irq) +{ + u32 tc = SYS_TC(irq - IRQ_TIMER0); + + REGSET(tc, SYS_TCx, INTC, SET); + SYS_TC(irq - IRQ_TIMER0) = tc; + + REGSET(tc, SYS_TCx, INTC, UNSET); + SYS_TC(irq - IRQ_TIMER0) = tc; +} + +void (*ns9xxx_ack_irq_functions[NR_IRQS])(unsigned int) = { + [IRQ_TIMER0] = ns9xxx_ack_irq_timer, + [IRQ_TIMER1] = ns9xxx_ack_irq_timer, + [IRQ_TIMER2] = ns9xxx_ack_irq_timer, + [IRQ_TIMER3] = ns9xxx_ack_irq_timer, +}; + +static void ns9xxx_mask_irq(unsigned int irq) +{ + /* XXX: better use cpp symbols */ + SYS_IC(irq / 4) &= ~(1 << (7 + 8 * (3 - (irq & 3)))); +} + +static void ns9xxx_ack_irq(unsigned int irq) +{ + if (!ns9xxx_ack_irq_functions[irq]) { + printk(KERN_ERR "no ack function for irq %u\n", irq); + BUG(); + } + + ns9xxx_ack_irq_functions[irq](irq); + SYS_ISRADDR = 0; +} + +static void ns9xxx_maskack_irq(unsigned int irq) +{ + ns9xxx_mask_irq(irq); + ns9xxx_ack_irq(irq); +} + +static void ns9xxx_unmask_irq(unsigned int irq) +{ + /* XXX: better use cpp symbols */ + SYS_IC(irq / 4) |= 1 << (7 + 8 * (3 - (irq & 3))); +} + +static struct irq_chip ns9xxx_chip = { + .ack = ns9xxx_ack_irq, + .mask = ns9xxx_mask_irq, + .mask_ack = ns9xxx_maskack_irq, + .unmask = ns9xxx_unmask_irq, +}; + +void __init ns9xxx_init_irq(void) +{ + int i; + + /* disable all IRQs */ + for (i = 0; i < 8; ++i) + SYS_IC(i) = (4 * i) << 24 | (4 * i + 1) << 16 | + (4 * i + 2) << 8 | (4 * i + 3); + + /* simple interrupt prio table: + * prio(x) < prio(y) <=> x < y + */ + for (i = 0; i < 32; ++i) + SYS_IVA(i) = i; + + for (i = IRQ_WATCHDOG; i <= IRQ_EXT3; ++i) { + set_irq_chip(i, &ns9xxx_chip); + set_irq_handler(i, handle_level_irq); + set_irq_flags(i, IRQF_VALID); + } +} diff --git a/arch/arm/mach-ns9xxx/mach-cc9p9360dev.c b/arch/arm/mach-ns9xxx/mach-cc9p9360dev.c new file mode 100644 index 00000000000..a193dd93151 --- /dev/null +++ b/arch/arm/mach-ns9xxx/mach-cc9p9360dev.c @@ -0,0 +1,41 @@ +/* + * arch/arm/mach-ns9xxx/mach-cc9p9360dev.c + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include "board-a9m9750dev.h" +#include "generic.h" + +static void __init mach_cc9p9360dev_map_io(void) +{ + ns9xxx_map_io(); + board_a9m9750dev_map_io(); +} + +static void __init mach_cc9p9360dev_init_irq(void) +{ + ns9xxx_init_irq(); + board_a9m9750dev_init_irq(); +} + +static void __init mach_cc9p9360dev_init_machine(void) +{ + ns9xxx_init_machine(); + board_a9m9750dev_init_machine(); +} + +MACHINE_START(CC9P9360DEV, "Connect Core 9P 9360 on an A9M9750 Devboard") + .map_io = mach_cc9p9360dev_map_io, + .init_irq = mach_cc9p9360dev_init_irq, + .init_machine = mach_cc9p9360dev_init_machine, + .timer = &ns9xxx_timer, + .boot_params = 0x100, +MACHINE_END diff --git a/arch/arm/mach-ns9xxx/time.c b/arch/arm/mach-ns9xxx/time.c new file mode 100644 index 00000000000..eec05f18714 --- /dev/null +++ b/arch/arm/mach-ns9xxx/time.c @@ -0,0 +1,88 @@ +/* + * arch/arm/mach-ns9xxx/time.c + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <linux/jiffies.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <asm/arch-ns9xxx/regs-sys.h> +#include <asm/arch-ns9xxx/clock.h> +#include <asm/arch-ns9xxx/irqs.h> +#include <asm/arch/system.h> +#include "generic.h" + +#define TIMERCLOCKSELECT 64 + +static u32 usecs_per_tick; + +static irqreturn_t +ns9xxx_timer_interrupt(int irq, void *dev_id) +{ + write_seqlock(&xtime_lock); + timer_tick(); + write_sequnlock(&xtime_lock); + + return IRQ_HANDLED; +} + +static unsigned long ns9xxx_timer_gettimeoffset(void) +{ + /* return the microseconds which have passed since the last interrupt + * was _serviced_. That is, if an interrupt is pending or the counter + * reloads, return one periode more. */ + + u32 counter1 = SYS_TR(0); + int pending = SYS_ISR & (1 << IRQ_TIMER0); + u32 counter2 = SYS_TR(0); + u32 elapsed; + + if (pending || counter2 > counter1) + elapsed = 2 * SYS_TRC(0) - counter2; + else + elapsed = SYS_TRC(0) - counter1; + + return (elapsed * usecs_per_tick) >> 16; + +} + +static struct irqaction ns9xxx_timer_irq = { + .name = "NS9xxx Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = ns9xxx_timer_interrupt, +}; + +static void __init ns9xxx_timer_init(void) +{ + int tc; + + usecs_per_tick = + SH_DIV(1000000 * TIMERCLOCKSELECT, ns9xxx_cpuclock(), 16); + + /* disable timer */ + if ((tc = SYS_TC(0)) & SYS_TCx_TEN) + SYS_TC(0) = tc & ~SYS_TCx_TEN; + + SYS_TRC(0) = SH_DIV(ns9xxx_cpuclock(), (TIMERCLOCKSELECT * HZ), 0); + + REGSET(tc, SYS_TCx, TEN, EN); + REGSET(tc, SYS_TCx, TLCS, DIV64); /* This must match TIMERCLOCKSELECT */ + REGSET(tc, SYS_TCx, INTS, EN); + REGSET(tc, SYS_TCx, UDS, DOWN); + REGSET(tc, SYS_TCx, TDBG, STOP); + REGSET(tc, SYS_TCx, TSZ, 32); + REGSET(tc, SYS_TCx, REN, EN); + SYS_TC(0) = tc; + + setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq); +} + +struct sys_timer ns9xxx_timer = { + .init = ns9xxx_timer_init, + .offset = ns9xxx_timer_gettimeoffset, +}; diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 9de1278d234..390524c4710 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -338,6 +338,27 @@ static struct platform_device i2c_device = { .num_resources = ARRAY_SIZE(i2c_resources), }; +#ifdef CONFIG_PXA27x +static struct resource i2c_power_resources[] = { + { + .start = 0x40f00180, + .end = 0x40f001a3, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_PWRI2C, + .end = IRQ_PWRI2C, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device i2c_power_device = { + .name = "pxa2xx-i2c", + .id = 1, + .resource = i2c_power_resources, + .num_resources = ARRAY_SIZE(i2c_resources), +}; +#endif + void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info) { i2c_device.dev.platform_data = info; @@ -392,6 +413,9 @@ static struct platform_device *devices[] __initdata = { &stuart_device, &pxaficp_device, &i2c_device, +#ifdef CONFIG_PXA27x + &i2c_power_device, +#endif &i2s_device, &pxartc_device, }; diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig index 17f5f4439fe..35156ca39df 100644 --- a/arch/arm/mach-realview/Kconfig +++ b/arch/arm/mach-realview/Kconfig @@ -10,10 +10,21 @@ config MACH_REALVIEW_EB config REALVIEW_MPCORE bool "Support MPcore tile" depends on MACH_REALVIEW_EB + select CACHE_L2X0 help Enable support for the MPCore tile on the Realview platform. Since there are device address and interrupt differences, a kernel built with this option enabled is not compatible with other tiles. +config REALVIEW_MPCORE_REVB + bool "Support MPcore RevB tile" + depends on REALVIEW_MPCORE + default n + help + Enable support for the MPCore RevB tile on the Realview platform. + Since there are device address differences, a + kernel built with this option enabled is not compatible with + other tiles. + endmenu diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index b8484e15dac..fce3596f995 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -52,13 +52,14 @@ void __cpuinit platform_secondary_init(unsigned int cpu) * core (e.g. timer irq), then they will not have been enabled * for us: do so */ - gic_cpu_init(__io_address(REALVIEW_GIC_CPU_BASE)); + gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE)); /* * let the primary processor know we're out of the * pen, then head off into the C entry point */ pen_release = -1; + smp_wmb(); /* * Synchronise with the boot thread. @@ -102,6 +103,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { + smp_rmb(); if (pen_release == -1) break; diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index 9741b4d3c9c..3dba666151d 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -31,6 +31,7 @@ #include <asm/mach-types.h> #include <asm/hardware/gic.h> #include <asm/hardware/icst307.h> +#include <asm/hardware/cache-l2x0.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -57,7 +58,26 @@ static struct map_desc realview_eb_io_desc[] __initdata = { .pfn = __phys_to_pfn(REALVIEW_GIC_DIST_BASE), .length = SZ_4K, .type = MT_DEVICE, + }, +#ifdef CONFIG_REALVIEW_MPCORE + { + .virtual = IO_ADDRESS(REALVIEW_GIC1_CPU_BASE), + .pfn = __phys_to_pfn(REALVIEW_GIC1_CPU_BASE), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = IO_ADDRESS(REALVIEW_GIC1_DIST_BASE), + .pfn = __phys_to_pfn(REALVIEW_GIC1_DIST_BASE), + .length = SZ_4K, + .type = MT_DEVICE, }, { + .virtual = IO_ADDRESS(REALVIEW_MPCORE_L220_BASE), + .pfn = __phys_to_pfn(REALVIEW_MPCORE_L220_BASE), + .length = SZ_8K, + .type = MT_DEVICE, + }, +#endif + { .virtual = IO_ADDRESS(REALVIEW_SCTL_BASE), .pfn = __phys_to_pfn(REALVIEW_SCTL_BASE), .length = SZ_4K, @@ -138,19 +158,29 @@ static void __init gic_init_irq(void) #ifdef CONFIG_REALVIEW_MPCORE unsigned int pldctrl; writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK)); - pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + 0xd8); + pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + REALVIEW_MPCORE_SYS_PLD_CTRL1); pldctrl |= 0x00800000; /* New irq mode */ - writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + 0xd8); + writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + REALVIEW_MPCORE_SYS_PLD_CTRL1); writel(0x00000000, __io_address(REALVIEW_SYS_LOCK)); #endif - gic_dist_init(__io_address(REALVIEW_GIC_DIST_BASE)); - gic_cpu_init(__io_address(REALVIEW_GIC_CPU_BASE)); + gic_dist_init(0, __io_address(REALVIEW_GIC_DIST_BASE), 29); + gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE)); +#ifdef CONFIG_REALVIEW_MPCORE + gic_dist_init(1, __io_address(REALVIEW_GIC1_DIST_BASE), 64); + gic_cpu_init(1, __io_address(REALVIEW_GIC1_CPU_BASE)); + gic_cascade_irq(1, IRQ_EB_IRQ1); +#endif } static void __init realview_eb_init(void) { int i; +#ifdef CONFIG_REALVIEW_MPCORE + /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled + * Bits: .... ...0 0111 1001 0000 .... .... .... */ + l2x0_init(__io_address(REALVIEW_MPCORE_L220_BASE), 0x00790000, 0xfe000fff); +#endif clk_register(&realview_clcd_clk); platform_device_register(&realview_flash_device); diff --git a/arch/arm/mach-s3c2400/Kconfig b/arch/arm/mach-s3c2400/Kconfig new file mode 100644 index 00000000000..deab0722836 --- /dev/null +++ b/arch/arm/mach-s3c2400/Kconfig @@ -0,0 +1,13 @@ +# arch/arm/mach-s3c2400/Kconfig +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + + + +menu "S3C2400 Machines" + + +endmenu + diff --git a/arch/arm/mach-s3c2400/Makefile b/arch/arm/mach-s3c2400/Makefile new file mode 100644 index 00000000000..7e23f4e1376 --- /dev/null +++ b/arch/arm/mach-s3c2400/Makefile @@ -0,0 +1,15 @@ +# arch/arm/mach-s3c2400/Makefile +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + +obj-y := +obj-m := +obj-n := +obj- := + +obj-$(CONFIG_CPU_S3C2400) += gpio.o + +# Machine support + diff --git a/arch/arm/mach-s3c2410/s3c2400-gpio.c b/arch/arm/mach-s3c2400/gpio.c index 1576d01d5f8..758e160410e 100644 --- a/arch/arm/mach-s3c2410/s3c2400-gpio.c +++ b/arch/arm/mach-s3c2400/gpio.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2400-gpio.c +/* linux/arch/arm/mach-s3c2400/gpio.c * * Copyright (c) 2006 Lucas Correia Villa Real <lucasvr@gobolinux.org> * diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index eb4ec411312..d4b013b283c 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig @@ -1,54 +1,51 @@ -if ARCH_S3C2410 +# arch/arm/mach-s3c2410/Kconfig +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 -menu "S3C24XX Implementations" +config CPU_S3C2410 + bool + depends on ARCH_S3C2410 + select S3C2410_CLOCK + select S3C2410_GPIO + select S3C2410_PM if PM + help + Support for S3C2410 and S3C2410A family from the S3C24XX line + of Samsung Mobile CPUs. -config MACH_AML_M5900 - bool "AML M5900 Series" - select CPU_S3C2410 - select PM_SIMTEC if PM +config CPU_S3C2410_DMA + bool + depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442) + default y if CPU_S3C2410 || CPU_S3C2442 help - Say Y here if you are using the American Microsystems M5900 Series - <http://www.amltd.com> + DMA device selection for S3C2410 and compatible CPUs -config MACH_ANUBIS - bool "Simtec Electronics ANUBIS" - select CPU_S3C2440 - select PM_SIMTEC if PM +config S3C2410_PM + bool help - Say Y here if you are using the Simtec Electronics ANUBIS - development system + Power Management code common to S3C2410 and better -config MACH_OSIRIS - bool "Simtec IM2440D20 (OSIRIS) module" - select CPU_S3C2440 - select PM_SIMTEC if PM +config S3C2410_GPIO + bool help - Say Y here if you are using the Simtec IM2440D20 module, also - known as the Osiris. + GPIO code for S3C2410 and similar processors -config ARCH_BAST - bool "Simtec Electronics BAST (EB2410ITX)" - select CPU_S3C2410 - select PM_SIMTEC if PM - select ISA +config S3C2410_CLOCK + bool help - Say Y here if you are using the Simtec Electronics EB2410ITX - development board (also known as BAST) + Clock code for the S3C2410, and similar processors - Product page: <http://www.simtec.co.uk/products/EB2410ITX/>. -config BAST_PC104_IRQ - bool "BAST PC104 IRQ support" - depends on ARCH_BAST - default y - help - Say Y here to enable the PC104 IRQ routing on the - Simtec BAST (EB2410ITX) +menu "S3C2410 Machines" -config PM_H1940 - bool +config ARCH_SMDK2410 + bool "SMDK2410/A9M2410" + select CPU_S3C2410 + select MACH_SMDK help - Internal node for H1940 and related PM + Say Y here if you are using the SMDK2410 or the derived module A9M2410 + <http://www.fsforth.de> config ARCH_H1940 bool "IPAQ H1940" @@ -57,7 +54,10 @@ config ARCH_H1940 help Say Y here if you are using the HP IPAQ H1940 - <http://www.handhelds.org/projects/h1940.html>. +config PM_H1940 + bool + help + Internal node for H1940 and related PM config MACH_N30 bool "Acer N30" @@ -65,53 +65,36 @@ config MACH_N30 help Say Y here if you are using the Acer N30 - <http://zoo.weinigel.se/n30>. - -config MACH_SMDK - bool - help - Common machine code for SMDK2410 and SMDK2440 - -config ARCH_SMDK2410 - bool "SMDK2410/A9M2410" +config ARCH_BAST + bool "Simtec Electronics BAST (EB2410ITX)" select CPU_S3C2410 - select MACH_SMDK + select PM_SIMTEC if PM + select ISA help - Say Y here if you are using the SMDK2410 or the derived module A9M2410 - <http://www.fsforth.de> + Say Y here if you are using the Simtec Electronics EB2410ITX + development board (also known as BAST) -config ARCH_S3C2440 - bool "SMDK2440" - select CPU_S3C2440 - select MACH_SMDK +config MACH_OTOM + bool "NexVision OTOM Board" + select CPU_S3C2410 help - Say Y here if you are using the SMDK2440. - -config SMDK2440_CPU2440 - bool "SMDK2440 with S3C2440 CPU module" - depends on ARCH_S3C2440 - default y if ARCH_S3C2440 - select CPU_S3C2440 - -config SMDK2440_CPU2442 - bool "SMDM2440 with S3C2442 CPU module" - depends on ARCH_S3C2440 - select CPU_S3C2442 + Say Y here if you are using the Nex Vision OTOM board -config MACH_S3C2413 - bool +config MACH_AML_M5900 + bool "AML M5900 Series" + select CPU_S3C2410 + select PM_SIMTEC if PM help - Internal node for S3C2413 version of SMDK2413, so that - machine_is_s3c2413() will work when MACH_SMDK2413 is - selected + Say Y here if you are using the American Microsystems M5900 Series + <http://www.amltd.com> -config MACH_SMDK2413 - bool "SMDK2413" - select CPU_S3C2412 - select MACH_S3C2413 - select MACH_SMDK +config BAST_PC104_IRQ + bool "BAST PC104 IRQ support" + depends on ARCH_BAST + default y help - Say Y here if you are using an SMDK2413 + Say Y here to enable the PC104 IRQ routing on the + Simtec BAST (EB2410ITX) config MACH_VR1000 bool "Thorcom VR1000" @@ -120,202 +103,11 @@ config MACH_VR1000 help Say Y here if you are using the Thorcom VR1000 board. - This linux port is currently being maintained by Simtec, on behalf - of Thorcom. Any queries, please contact Thorcom first. - -config MACH_RX3715 - bool "HP iPAQ rx3715" - select CPU_S3C2440 - select PM_H1940 if PM - help - Say Y here if you are using the HP iPAQ rx3715. - - See <http://www.handhelds.org/projects/rx3715.html> for more - information on this project - -config MACH_OTOM - bool "NexVision OTOM Board" - select CPU_S3C2410 - help - Say Y here if you are using the Nex Vision OTOM board - -config MACH_NEXCODER_2440 - bool "NexVision NEXCODER 2440 Light Board" - select CPU_S3C2440 - help - Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board - -config MACH_VSTMS - bool "VMSTMS" - select CPU_S3C2412 +config MACH_QT2410 + bool "QT2410" + select CPU_S3C2410 help - Say Y here if you are using an VSTMS board + Say Y here if you are using the Armzone QT2410 endmenu -config S3C2410_CLOCK - bool - help - Clock code for the S3C2410, and similar processors - -config S3C2410_PM - bool - help - Power Management code common to S3C2410 and better - -config CPU_S3C2410_DMA - bool - depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442) - default y if CPU_S3C2410 || CPU_S3C2442 - help - DMA device selection for S3C2410 and compatible CPUs - -config CPU_S3C2410 - bool - depends on ARCH_S3C2410 - select S3C2410_CLOCK - select S3C2410_PM if PM - help - Support for S3C2410 and S3C2410A family from the S3C24XX line - of Samsung Mobile CPUs. - -# internal node to signify if we are only dealing with an S3C2412 - -config CPU_S3C2412_ONLY - bool - depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \ - !CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412 - default y if CPU_S3C2412 - -config S3C2412_PM - bool - help - Internal config node to apply S3C2412 power management - -config CPU_S3C2412 - bool - depends on ARCH_S3C2410 - select S3C2412_PM if PM - help - Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line - -config CPU_S3C244X - bool - depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442) - help - Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems. - -config CPU_S3C2440 - bool - depends on ARCH_S3C2410 - select S3C2410_CLOCK - select S3C2410_PM if PM - select CPU_S3C244X - help - Support for S3C2440 Samsung Mobile CPU based systems. - -config CPU_S3C2442 - bool - depends on ARCH_S3C2420 - select S3C2410_CLOCK - select S3C2410_PM if PM - select CPU_S3C244X - help - Support for S3C2442 Samsung Mobile CPU based systems. - -comment "S3C2410 Boot" - -config S3C2410_BOOT_WATCHDOG - bool "S3C2410 Initialisation watchdog" - depends on ARCH_S3C2410 && S3C2410_WATCHDOG - help - Say y to enable the watchdog during the kernel decompression - stage. If the kernel fails to uncompress, then the watchdog - will trigger a reset and the system should restart. - - Although this uses the same hardware unit as the kernel watchdog - driver, it is not a replacement for it. If you use this option, - you will have to use the watchdg driver to either stop the timeout - or restart it. If you do not, then your kernel will reboot after - startup. - - The driver uses a fixed timeout value, so the exact time till the - system resets depends on the value of PCLK. The timeout on an - 200MHz s3c2410 should be about 30 seconds. - -config S3C2410_BOOT_ERROR_RESET - bool "S3C2410 Reboot on decompression error" - depends on ARCH_S3C2410 - help - Say y here to use the watchdog to reset the system if the - kernel decompressor detects an error during decompression. - - -comment "S3C2410 Setup" - -config S3C2410_DMA - bool "S3C2410 DMA support" - depends on ARCH_S3C2410 - help - S3C2410 DMA support. This is needed for drivers like sound which - use the S3C2410's DMA system to move data to and from the - peripheral blocks. - -config S3C2410_DMA_DEBUG - bool "S3C2410 DMA support debug" - depends on ARCH_S3C2410 && S3C2410_DMA - help - Enable debugging output for the DMA code. This option sends info - to the kernel log, at priority KERN_DEBUG. - - Note, it is easy to create and fill the log buffer in a small - amount of time, as well as using an significant percentage of - the CPU time doing so. - - -config S3C2410_PM_DEBUG - bool "S3C2410 PM Suspend debug" - depends on ARCH_S3C2410 && PM - help - Say Y here if you want verbose debugging from the PM Suspend and - Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt> - for more information. - -config S3C2410_PM_CHECK - bool "S3C2410 PM Suspend Memory CRC" - depends on ARCH_S3C2410 && PM && CRC32 - help - Enable the PM code's memory area checksum over sleep. This option - will generate CRCs of all blocks of memory, and store them before - going to sleep. The blocks are then checked on resume for any - errors. - -config S3C2410_PM_CHECK_CHUNKSIZE - int "S3C2410 PM Suspend CRC Chunksize (KiB)" - depends on ARCH_S3C2410 && PM && S3C2410_PM_CHECK - default 64 - help - Set the chunksize in Kilobytes of the CRC for checking memory - corruption over suspend and resume. A smaller value will mean that - the CRC data block will take more memory, but wil identify any - faults with better precision. - -config PM_SIMTEC - bool - help - Common power management code for systems that are - compatible with the Simtec style of power management - -config S3C2410_LOWLEVEL_UART_PORT - int "S3C2410 UART to use for low-level messages" - default 0 - help - Choice of which UART port to use for the low-level messages, - such as the `Uncompressing...` at start time. The value of - this configuration should be between zero and two. The port - must have been initialised by the boot-loader before use. - - Note, this does not affect the port used by the debug messages, - which is a separate configuration. - -endif diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index 27663e28cc8..9a3d3d24c08 100644 --- a/arch/arm/mach-s3c2410/Makefile +++ b/arch/arm/mach-s3c2410/Makefile @@ -1,92 +1,31 @@ - +# arch/arm/mach-s3c2410/Makefile # -# Makefile for the linux kernel. +# Copyright 2007 Simtec Electronics # +# Licensed under GPLv2 -# Object file lists. - -obj-y := cpu.o irq.o time.o gpio.o clock.o devs.o -obj-m := -obj-n := -obj- := -obj-dma-y := -obj-dma-n := - -# DMA -obj-$(CONFIG_S3C2410_DMA) += dma.o - -# S3C2400 support files -obj-$(CONFIG_CPU_S3C2400) += s3c2400-gpio.o - -# S3C2410 support files +obj-y := +obj-m := +obj-n := +obj- := obj-$(CONFIG_CPU_S3C2410) += s3c2410.o -obj-$(CONFIG_CPU_S3C2410) += s3c2410-gpio.o -obj-$(CONFIG_CPU_S3C2410) += s3c2410-irq.o - -obj-$(CONFIG_S3C2410_PM) += s3c2410-pm.o s3c2410-sleep.o -obj-$(CONFIG_CPU_S3C2410_DMA) += s3c2410-dma.o - -# Power Management support - -obj-$(CONFIG_PM) += pm.o sleep.o -obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o -obj-$(CONFIG_PM_H1940) += pm-h1940.o - -# S3C2412 support -obj-$(CONFIG_CPU_S3C2412) += s3c2412.o -obj-$(CONFIG_CPU_S3C2412) += s3c2412-irq.o -obj-$(CONFIG_CPU_S3C2412) += s3c2412-clock.o -obj-dma-$(CONFIG_CPU_S3C2412) += s3c2412-dma.o - -obj-$(CONFIG_S3C2412_PM) += s3c2412-pm.o - -# -# S3C244X support - -obj-$(CONFIG_CPU_S3C244X) += s3c244x.o -obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o - -# Clock control - -obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o - -# S3C2440 support - -obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o -obj-$(CONFIG_CPU_S3C2440) += s3c2440-irq.o -obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o -obj-$(CONFIG_CPU_S3C2440) += s3c2410-gpio.o -obj-dma-$(CONFIG_CPU_S3C2440) += s3c2440-dma.o +obj-$(CONFIG_CPU_S3C2410) += irq.o +obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o +obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o +obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o +obj-$(CONFIG_S3C2410_GPIO) += gpio.o +obj-$(CONFIG_S3C2410_CLOCK) += clock.o -# S3C2442 support +# Machine support -obj-$(CONFIG_CPU_S3C2442) += s3c2442.o -obj-$(CONFIG_CPU_S3C2442) += s3c2442-clock.o - -# bast extras - -obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o - -# merge in dma objects - -obj-y += $(obj-dma-y) - -# machine specific support - -obj-$(CONFIG_MACH_AML_M5900) += mach-amlm5900.o -obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o -obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o -obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o +obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o obj-$(CONFIG_ARCH_H1940) += mach-h1940.o +obj-$(CONFIG_PM_H1940) += pm-h1940.o obj-$(CONFIG_MACH_N30) += mach-n30.o -obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o -obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o -obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o -obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o -obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o +obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o obj-$(CONFIG_MACH_OTOM) += mach-otom.o -obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o -obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o - -obj-$(CONFIG_MACH_SMDK) += common-smdk.o
\ No newline at end of file +obj-$(CONFIG_MACH_AML_M5900) += mach-amlm5900.o +obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o +obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o +obj-$(CONFIG_MACH_QT2410) += mach-qt2410.o diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c index 379efe70778..daeba427d78 100644 --- a/arch/arm/mach-s3c2410/bast-irq.c +++ b/arch/arm/mach-s3c2410/bast-irq.c @@ -39,7 +39,7 @@ #include <asm/arch/bast-map.h> #include <asm/arch/bast-irq.h> -#include "irq.h" +#include <asm/plat-s3c24xx/irq.h> #if 0 #include <asm/debug-ll.h> diff --git a/arch/arm/mach-s3c2410/bast.h b/arch/arm/mach-s3c2410/bast.h index e5d03311752..e98543742eb 100644 --- a/arch/arm/mach-s3c2410/bast.h +++ b/arch/arm/mach-s3c2410/bast.h @@ -1,2 +1,2 @@ - +/* linux/arch/arm/mach-s3c2410/bast.h extern void bast_init_irq(void); diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index e13fb677889..5b4831c4c1d 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c @@ -1,15 +1,9 @@ /* linux/arch/arm/mach-s3c2410/clock.c * - * Copyright (c) 2004-2005 Simtec Electronics + * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * - * S3C24XX Core clock control support - * - * Based on, and code from linux/arch/arm/mach-versatile/clock.c - ** - ** Copyright (C) 2004 ARM Limited. - ** Written by Deep Blue Solutions Limited. - * + * S3C2410,S3C2440,S3C2442 Clock control support * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,418 +26,251 @@ #include <linux/list.h> #include <linux/errno.h> #include <linux/err.h> -#include <linux/platform_device.h> #include <linux/sysdev.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> #include <linux/clk.h> #include <linux/mutex.h> #include <linux/delay.h> +#include <linux/serial_core.h> + +#include <asm/mach/map.h> #include <asm/hardware.h> -#include <asm/irq.h> #include <asm/io.h> +#include <asm/arch/regs-serial.h> #include <asm/arch/regs-clock.h> #include <asm/arch/regs-gpio.h> -#include "clock.h" -#include "cpu.h" - -/* clock information */ +#include <asm/plat-s3c24xx/s3c2410.h> +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/cpu.h> -static LIST_HEAD(clocks); - -DEFINE_MUTEX(clocks_mutex); - -/* enable and disable calls for use with the clk struct */ - -static int clk_null_enable(struct clk *clk, int enable) +int s3c2410_clkcon_enable(struct clk *clk, int enable) { - return 0; -} - -/* Clock API calls */ + unsigned int clocks = clk->ctrlbit; + unsigned long clkcon; -struct clk *clk_get(struct device *dev, const char *id) -{ - struct clk *p; - struct clk *clk = ERR_PTR(-ENOENT); - int idno; + clkcon = __raw_readl(S3C2410_CLKCON); - if (dev == NULL || dev->bus != &platform_bus_type) - idno = -1; + if (enable) + clkcon |= clocks; else - idno = to_platform_device(dev)->id; - - mutex_lock(&clocks_mutex); - - list_for_each_entry(p, &clocks, list) { - if (p->id == idno && - strcmp(id, p->name) == 0 && - try_module_get(p->owner)) { - clk = p; - break; - } - } - - /* check for the case where a device was supplied, but the - * clock that was being searched for is not device specific */ - - if (IS_ERR(clk)) { - list_for_each_entry(p, &clocks, list) { - if (p->id == -1 && strcmp(id, p->name) == 0 && - try_module_get(p->owner)) { - clk = p; - break; - } - } - } + clkcon &= ~clocks; - mutex_unlock(&clocks_mutex); - return clk; -} + /* ensure none of the special function bits set */ + clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER); -void clk_put(struct clk *clk) -{ - module_put(clk->owner); -} + __raw_writel(clkcon, S3C2410_CLKCON); -int clk_enable(struct clk *clk) -{ - if (IS_ERR(clk) || clk == NULL) - return -EINVAL; - - clk_enable(clk->parent); - - mutex_lock(&clocks_mutex); - - if ((clk->usage++) == 0) - (clk->enable)(clk, 1); - - mutex_unlock(&clocks_mutex); return 0; } -void clk_disable(struct clk *clk) -{ - if (IS_ERR(clk) || clk == NULL) - return; - - mutex_lock(&clocks_mutex); - - if ((--clk->usage) == 0) - (clk->enable)(clk, 0); - - mutex_unlock(&clocks_mutex); - clk_disable(clk->parent); -} - - -unsigned long clk_get_rate(struct clk *clk) -{ - if (IS_ERR(clk)) - return 0; - - if (clk->rate != 0) - return clk->rate; - - if (clk->get_rate != NULL) - return (clk->get_rate)(clk); - - if (clk->parent != NULL) - return clk_get_rate(clk->parent); - - return clk->rate; -} - -long clk_round_rate(struct clk *clk, unsigned long rate) -{ - if (!IS_ERR(clk) && clk->round_rate) - return (clk->round_rate)(clk, rate); - - return rate; -} - -int clk_set_rate(struct clk *clk, unsigned long rate) -{ - int ret; - - if (IS_ERR(clk)) - return -EINVAL; - - mutex_lock(&clocks_mutex); - ret = (clk->set_rate)(clk, rate); - mutex_unlock(&clocks_mutex); - - return ret; -} - -struct clk *clk_get_parent(struct clk *clk) +static int s3c2410_upll_enable(struct clk *clk, int enable) { - return clk->parent; -} - -int clk_set_parent(struct clk *clk, struct clk *parent) -{ - int ret = 0; - - if (IS_ERR(clk)) - return -EINVAL; - - mutex_lock(&clocks_mutex); - - if (clk->set_parent) - ret = (clk->set_parent)(clk, parent); - - mutex_unlock(&clocks_mutex); - - return ret; -} - -EXPORT_SYMBOL(clk_get); -EXPORT_SYMBOL(clk_put); -EXPORT_SYMBOL(clk_enable); -EXPORT_SYMBOL(clk_disable); -EXPORT_SYMBOL(clk_get_rate); -EXPORT_SYMBOL(clk_round_rate); -EXPORT_SYMBOL(clk_set_rate); -EXPORT_SYMBOL(clk_get_parent); -EXPORT_SYMBOL(clk_set_parent); - -/* base clocks */ - -struct clk clk_xtal = { - .name = "xtal", - .id = -1, - .rate = 0, - .parent = NULL, - .ctrlbit = 0, -}; - -struct clk clk_mpll = { - .name = "mpll", - .id = -1, -}; - -struct clk clk_upll = { - .name = "upll", - .id = -1, - .parent = NULL, - .ctrlbit = 0, -}; - -struct clk clk_f = { - .name = "fclk", - .id = -1, - .rate = 0, - .parent = &clk_mpll, - .ctrlbit = 0, -}; - -struct clk clk_h = { - .name = "hclk", - .id = -1, - .rate = 0, - .parent = NULL, - .ctrlbit = 0, -}; - -struct clk clk_p = { - .name = "pclk", - .id = -1, - .rate = 0, - .parent = NULL, - .ctrlbit = 0, -}; - -struct clk clk_usb_bus = { - .name = "usb-bus", - .id = -1, - .rate = 0, - .parent = &clk_upll, -}; - -/* clocks that could be registered by external code */ - -static int s3c24xx_dclk_enable(struct clk *clk, int enable) -{ - unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON); + unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); + unsigned long orig = clkslow; if (enable) - dclkcon |= clk->ctrlbit; + clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF; else - dclkcon &= ~clk->ctrlbit; + clkslow |= S3C2410_CLKSLOW_UCLK_OFF; - __raw_writel(dclkcon, S3C24XX_DCLKCON); + __raw_writel(clkslow, S3C2410_CLKSLOW); - return 0; -} + /* if we started the UPLL, then allow to settle */ -static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent) -{ - unsigned long dclkcon; - unsigned int uclk; - - if (parent == &clk_upll) - uclk = 1; - else if (parent == &clk_p) - uclk = 0; - else - return -EINVAL; - - clk->parent = parent; - - dclkcon = __raw_readl(S3C24XX_DCLKCON); - - if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) { - if (uclk) - dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK; - else - dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK; - } else { - if (uclk) - dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK; - else - dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK; - } - - __raw_writel(dclkcon, S3C24XX_DCLKCON); + if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF)) + udelay(200); return 0; } - -static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent) -{ - unsigned long mask; - unsigned long source; - - /* calculate the MISCCR setting for the clock */ - - if (parent == &clk_xtal) - source = S3C2410_MISCCR_CLK0_MPLL; - else if (parent == &clk_upll) - source = S3C2410_MISCCR_CLK0_UPLL; - else if (parent == &clk_f) - source = S3C2410_MISCCR_CLK0_FCLK; - else if (parent == &clk_h) - source = S3C2410_MISCCR_CLK0_HCLK; - else if (parent == &clk_p) - source = S3C2410_MISCCR_CLK0_PCLK; - else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0) - source = S3C2410_MISCCR_CLK0_DCLK0; - else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1) - source = S3C2410_MISCCR_CLK0_DCLK0; - else - return -EINVAL; - - clk->parent = parent; - - if (clk == &s3c24xx_dclk0) - mask = S3C2410_MISCCR_CLK0_MASK; - else { - source <<= 4; - mask = S3C2410_MISCCR_CLK1_MASK; +/* standard clock definitions */ + +static struct clk init_clocks_disable[] = { + { + .name = "nand", + .id = -1, + .parent = &clk_h, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_NAND, + }, { + .name = "sdi", + .id = -1, + .parent = &clk_p, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_SDI, + }, { + .name = "adc", + .id = -1, + .parent = &clk_p, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_ADC, + }, { + .name = "i2c", + .id = -1, + .parent = &clk_p, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_IIC, + }, { + .name = "iis", + .id = -1, + .parent = &clk_p, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_IIS, + }, { + .name = "spi", + .id = -1, + .parent = &clk_p, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_SPI, } - - s3c2410_modify_misccr(mask, source); - return 0; -} - -/* external clock definitions */ - -struct clk s3c24xx_dclk0 = { - .name = "dclk0", - .id = -1, - .ctrlbit = S3C2410_DCLKCON_DCLK0EN, - .enable = s3c24xx_dclk_enable, - .set_parent = s3c24xx_dclk_setparent, -}; - -struct clk s3c24xx_dclk1 = { - .name = "dclk1", - .id = -1, - .ctrlbit = S3C2410_DCLKCON_DCLK0EN, - .enable = s3c24xx_dclk_enable, - .set_parent = s3c24xx_dclk_setparent, }; -struct clk s3c24xx_clkout0 = { - .name = "clkout0", - .id = -1, - .set_parent = s3c24xx_clkout_setparent, +static struct clk init_clocks[] = { + { + .name = "lcd", + .id = -1, + .parent = &clk_h, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_LCDC, + }, { + .name = "gpio", + .id = -1, + .parent = &clk_p, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_GPIO, + }, { + .name = "usb-host", + .id = -1, + .parent = &clk_h, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_USBH, + }, { + .name = "usb-device", + .id = -1, + .parent = &clk_h, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_USBD, + }, { + .name = "timers", + .id = -1, + .parent = &clk_p, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_PWMT, + }, { + .name = "uart", + .id = 0, + .parent = &clk_p, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_UART0, + }, { + .name = "uart", + .id = 1, + .parent = &clk_p, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_UART1, + }, { + .name = "uart", + .id = 2, + .parent = &clk_p, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_UART2, + }, { + .name = "rtc", + .id = -1, + .parent = &clk_p, + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_RTC, + }, { + .name = "watchdog", + .id = -1, + .parent = &clk_p, + .ctrlbit = 0, + }, { + .name = "usb-bus-host", + .id = -1, + .parent = &clk_usb_bus, + }, { + .name = "usb-bus-gadget", + .id = -1, + .parent = &clk_usb_bus, + }, }; -struct clk s3c24xx_clkout1 = { - .name = "clkout1", - .id = -1, - .set_parent = s3c24xx_clkout_setparent, -}; - -struct clk s3c24xx_uclk = { - .name = "uclk", - .id = -1, -}; - -/* initialise the clock system */ - -int s3c24xx_register_clock(struct clk *clk) -{ - clk->owner = THIS_MODULE; - - if (clk->enable == NULL) - clk->enable = clk_null_enable; - - /* add to the list of available clocks */ - - mutex_lock(&clocks_mutex); - list_add(&clk->list, &clocks); - mutex_unlock(&clocks_mutex); - - return 0; -} - -/* initalise all the clocks */ +/* s3c2410_baseclk_add() + * + * Add all the clocks used by the s3c2410 or compatible CPUs + * such as the S3C2440 and S3C2442. + * + * We cannot use a system device as we are needed before any + * of the init-calls that initialise the devices are actually + * done. +*/ -int __init s3c24xx_setup_clocks(unsigned long xtal, - unsigned long fclk, - unsigned long hclk, - unsigned long pclk) +int __init s3c2410_baseclk_add(void) { - printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n"); + unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); + unsigned long clkcon = __raw_readl(S3C2410_CLKCON); + struct clk *clkp; + struct clk *xtal; + int ret; + int ptr; - /* initialise the main system clocks */ + clk_upll.enable = s3c2410_upll_enable; - clk_xtal.rate = xtal; - clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal); + if (s3c24xx_register_clock(&clk_usb_bus) < 0) + printk(KERN_ERR "failed to register usb bus clock\n"); - clk_mpll.rate = fclk; - clk_h.rate = hclk; - clk_p.rate = pclk; - clk_f.rate = fclk; + /* register clocks from clock array */ - /* assume uart clocks are correctly setup */ + clkp = init_clocks; + for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { + /* ensure that we note the clock state */ - /* register our clocks */ + clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0; - if (s3c24xx_register_clock(&clk_xtal) < 0) - printk(KERN_ERR "failed to register master xtal\n"); + ret = s3c24xx_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + } - if (s3c24xx_register_clock(&clk_mpll) < 0) - printk(KERN_ERR "failed to register mpll clock\n"); + /* We must be careful disabling the clocks we are not intending to + * be using at boot time, as subsytems such as the LCD which do + * their own DMA requests to the bus can cause the system to lockup + * if they where in the middle of requesting bus access. + * + * Disabling the LCD clock if the LCD is active is very dangerous, + * and therefore the bootloader should be careful to not enable + * the LCD clock if it is not needed. + */ + + /* install (and disable) the clocks we do not need immediately */ + + clkp = init_clocks_disable; + for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { + + ret = s3c24xx_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } - if (s3c24xx_register_clock(&clk_upll) < 0) - printk(KERN_ERR "failed to register upll clock\n"); + s3c2410_clkcon_enable(clkp, 0); + } - if (s3c24xx_register_clock(&clk_f) < 0) - printk(KERN_ERR "failed to register cpu fclk\n"); + /* show the clock-slow value */ - if (s3c24xx_register_clock(&clk_h) < 0) - printk(KERN_ERR "failed to register cpu hclk\n"); + xtal = clk_get(NULL, "xtal"); - if (s3c24xx_register_clock(&clk_p) < 0) - printk(KERN_ERR "failed to register cpu pclk\n"); + printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n", + print_mhz(clk_get_rate(xtal) / + ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))), + (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast", + (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on", + (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on"); return 0; } diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c index fa860e716b4..67d1ad36397 100644 --- a/arch/arm/mach-s3c2410/dma.c +++ b/arch/arm/mach-s3c2410/dma.c @@ -1,9 +1,9 @@ /* linux/arch/arm/mach-s3c2410/dma.c * - * Copyright (c) 2003-2005,2006 Simtec Electronics + * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * - * S3C2410 DMA core + * S3C2410 DMA selection * * http://armlinux.simtec.co.uk/ * @@ -12,1430 +12,170 @@ * published by the Free Software Foundation. */ - -#ifdef CONFIG_S3C2410_DMA_DEBUG -#define DEBUG -#endif - -#include <linux/module.h> +#include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> -#include <linux/spinlock.h> -#include <linux/interrupt.h> #include <linux/sysdev.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/delay.h> +#include <linux/serial_core.h> -#include <asm/system.h> -#include <asm/irq.h> -#include <asm/hardware.h> -#include <asm/io.h> #include <asm/dma.h> - -#include <asm/mach/dma.h> -#include <asm/arch/map.h> - -#include "dma.h" - -/* io map for dma */ -static void __iomem *dma_base; -static struct kmem_cache *dma_kmem; - -struct s3c24xx_dma_selection dma_sel; - -/* dma channel state information */ -struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS]; - -/* debugging functions */ - -#define BUF_MAGIC (0xcafebabe) - -#define dmawarn(fmt...) printk(KERN_DEBUG fmt) - -#define dma_regaddr(chan, reg) ((chan)->regs + (reg)) - -#if 1 -#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg)) -#else -static inline void -dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val) -{ - pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg); - writel(val, dma_regaddr(chan, reg)); -} -#endif - -#define dma_rdreg(chan, reg) readl((chan)->regs + (reg)) - -/* captured register state for debug */ - -struct s3c2410_dma_regstate { - unsigned long dcsrc; - unsigned long disrc; - unsigned long dstat; - unsigned long dcon; - unsigned long dmsktrig; +#include <asm/arch/dma.h> + +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/dma.h> + +#include <asm/arch/regs-serial.h> +#include <asm/arch/regs-gpio.h> +#include <asm/arch/regs-ac97.h> +#include <asm/arch/regs-mem.h> +#include <asm/arch/regs-lcd.h> +#include <asm/arch/regs-sdi.h> +#include <asm/arch/regs-iis.h> +#include <asm/arch/regs-spi.h> + +static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = { + [DMACH_XD0] = { + .name = "xdreq0", + .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID, + }, + [DMACH_XD1] = { + .name = "xdreq1", + .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID, + }, + [DMACH_SDI] = { + .name = "sdi", + .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID, + .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID, + .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID, + .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, + .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, + }, + [DMACH_SPI0] = { + .name = "spi0", + .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID, + .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT, + .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT, + }, + [DMACH_SPI1] = { + .name = "spi1", + .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID, + .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT, + .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT, + }, + [DMACH_UART0] = { + .name = "uart0", + .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID, + .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, + .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, + }, + [DMACH_UART1] = { + .name = "uart1", + .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID, + .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, + .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, + }, + [DMACH_UART2] = { + .name = "uart2", + .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID, + .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, + .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, + }, + [DMACH_TIMER] = { + .name = "timer", + .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID, + .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID, + .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID, + }, + [DMACH_I2S_IN] = { + .name = "i2s-sdi", + .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID, + .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID, + .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, + }, + [DMACH_I2S_OUT] = { + .name = "i2s-sdo", + .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID, + .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, + }, + [DMACH_USB_EP1] = { + .name = "usb-ep1", + .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID, + }, + [DMACH_USB_EP2] = { + .name = "usb-ep2", + .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID, + }, + [DMACH_USB_EP3] = { + .name = "usb-ep3", + .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID, + }, + [DMACH_USB_EP4] = { + .name = "usb-ep4", + .channels[3] =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID, + }, }; -#ifdef CONFIG_S3C2410_DMA_DEBUG - -/* dmadbg_showregs - * - * simple debug routine to print the current state of the dma registers -*/ - -static void -dmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs) -{ - regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC); - regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC); - regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT); - regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON); - regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); -} - -static void -dmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan, - struct s3c2410_dma_regstate *regs) -{ - printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n", - chan->number, fname, line, - regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig, - regs->dcon); -} - -static void -dmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan) -{ - struct s3c2410_dma_regstate state; - - dmadbg_capture(chan, &state); - - printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n", - chan->number, fname, line, chan->load_state, - chan->curr, chan->next, chan->end); - - dmadbg_dumpregs(fname, line, chan, &state); -} - -static void -dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan) -{ - struct s3c2410_dma_regstate state; - - dmadbg_capture(chan, &state); - dmadbg_dumpregs(fname, line, chan, &state); -} - -#define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan)) -#define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan)) -#else -#define dbg_showregs(chan) do { } while(0) -#define dbg_showchan(chan) do { } while(0) -#endif /* CONFIG_S3C2410_DMA_DEBUG */ - -static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX]; - -/* lookup_dma_channel - * - * change the dma channel number given into a real dma channel id -*/ - -static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel) -{ - if (channel & DMACH_LOW_LEVEL) - return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL]; - else - return dma_chan_map[channel]; -} - -/* s3c2410_dma_stats_timeout - * - * Update DMA stats from timeout info -*/ - -static void -s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val) +static void s3c2410_dma_select(struct s3c2410_dma_chan *chan, + struct s3c24xx_dma_map *map) { - if (stats == NULL) - return; - - if (val > stats->timeout_longest) - stats->timeout_longest = val; - if (val < stats->timeout_shortest) - stats->timeout_shortest = val; - - stats->timeout_avg += val; + chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID; } -/* s3c2410_dma_waitforload - * - * wait for the DMA engine to load a buffer, and update the state accordingly -*/ - -static int -s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line) -{ - int timeout = chan->load_timeout; - int took; - - if (chan->load_state != S3C2410_DMALOAD_1LOADED) { - printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line); - return 0; - } - - if (chan->stats != NULL) - chan->stats->loads++; - - while (--timeout > 0) { - if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) { - took = chan->load_timeout - timeout; - - s3c2410_dma_stats_timeout(chan->stats, took); - - switch (chan->load_state) { - case S3C2410_DMALOAD_1LOADED: - chan->load_state = S3C2410_DMALOAD_1RUNNING; - break; - - default: - printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state); - } - - return 1; - } - } - - if (chan->stats != NULL) { - chan->stats->timeout_failed++; - } - - return 0; -} - - - -/* s3c2410_dma_loadbuffer - * - * load a buffer, and update the channel state -*/ - -static inline int -s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan, - struct s3c2410_dma_buf *buf) -{ - unsigned long reload; - - pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n", - buf, (unsigned long)buf->data, buf->size); - - if (buf == NULL) { - dmawarn("buffer is NULL\n"); - return -EINVAL; - } - - /* check the state of the channel before we do anything */ - - if (chan->load_state == S3C2410_DMALOAD_1LOADED) { - dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n"); - } - - if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) { - dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n"); - } - - /* it would seem sensible if we are the last buffer to not bother - * with the auto-reload bit, so that the DMA engine will not try - * and load another transfer after this one has finished... - */ - if (chan->load_state == S3C2410_DMALOAD_NONE) { - pr_debug("load_state is none, checking for noreload (next=%p)\n", - buf->next); - reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0; - } else { - //pr_debug("load_state is %d => autoreload\n", chan->load_state); - reload = S3C2410_DCON_AUTORELOAD; - } - - if ((buf->data & 0xf0000000) != 0x30000000) { - dmawarn("dmaload: buffer is %p\n", (void *)buf->data); - } - - writel(buf->data, chan->addr_reg); - - dma_wrreg(chan, S3C2410_DMA_DCON, - chan->dcon | reload | (buf->size/chan->xfer_unit)); - - chan->next = buf->next; - - /* update the state of the channel */ - - switch (chan->load_state) { - case S3C2410_DMALOAD_NONE: - chan->load_state = S3C2410_DMALOAD_1LOADED; - break; - - case S3C2410_DMALOAD_1RUNNING: - chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING; - break; - - default: - dmawarn("dmaload: unknown state %d in loadbuffer\n", - chan->load_state); - break; - } - - return 0; -} - -/* s3c2410_dma_call_op - * - * small routine to call the op routine with the given op if it has been - * registered -*/ - -static void -s3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op) -{ - if (chan->op_fn != NULL) { - (chan->op_fn)(chan, op); - } -} - -/* s3c2410_dma_buffdone - * - * small wrapper to check if callback routine needs to be called, and - * if so, call it -*/ - -static inline void -s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf, - enum s3c2410_dma_buffresult result) -{ -#if 0 - pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n", - chan->callback_fn, buf, buf->id, buf->size, result); -#endif - - if (chan->callback_fn != NULL) { - (chan->callback_fn)(chan, buf->id, buf->size, result); - } -} - -/* s3c2410_dma_start - * - * start a dma channel going -*/ - -static int s3c2410_dma_start(struct s3c2410_dma_chan *chan) -{ - unsigned long tmp; - unsigned long flags; - - pr_debug("s3c2410_start_dma: channel=%d\n", chan->number); - - local_irq_save(flags); - - if (chan->state == S3C2410_DMA_RUNNING) { - pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state); - local_irq_restore(flags); - return 0; - } - - chan->state = S3C2410_DMA_RUNNING; - - /* check wether there is anything to load, and if not, see - * if we can find anything to load - */ - - if (chan->load_state == S3C2410_DMALOAD_NONE) { - if (chan->next == NULL) { - printk(KERN_ERR "dma%d: channel has nothing loaded\n", - chan->number); - chan->state = S3C2410_DMA_IDLE; - local_irq_restore(flags); - return -EINVAL; - } - - s3c2410_dma_loadbuffer(chan, chan->next); - } - - dbg_showchan(chan); - - /* enable the channel */ - - if (!chan->irq_enabled) { - enable_irq(chan->irq); - chan->irq_enabled = 1; - } - - /* start the channel going */ - - tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); - tmp &= ~S3C2410_DMASKTRIG_STOP; - tmp |= S3C2410_DMASKTRIG_ON; - dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); - - pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp); - -#if 0 - /* the dma buffer loads should take care of clearing the AUTO - * reloading feature */ - tmp = dma_rdreg(chan, S3C2410_DMA_DCON); - tmp &= ~S3C2410_DCON_NORELOAD; - dma_wrreg(chan, S3C2410_DMA_DCON, tmp); -#endif - - s3c2410_dma_call_op(chan, S3C2410_DMAOP_START); - - dbg_showchan(chan); - - /* if we've only loaded one buffer onto the channel, then chec - * to see if we have another, and if so, try and load it so when - * the first buffer is finished, the new one will be loaded onto - * the channel */ - - if (chan->next != NULL) { - if (chan->load_state == S3C2410_DMALOAD_1LOADED) { - - if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { - pr_debug("%s: buff not yet loaded, no more todo\n", - __FUNCTION__); - } else { - chan->load_state = S3C2410_DMALOAD_1RUNNING; - s3c2410_dma_loadbuffer(chan, chan->next); - } - - } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) { - s3c2410_dma_loadbuffer(chan, chan->next); - } - } - - - local_irq_restore(flags); - - return 0; -} - -/* s3c2410_dma_canload - * - * work out if we can queue another buffer into the DMA engine -*/ - -static int -s3c2410_dma_canload(struct s3c2410_dma_chan *chan) -{ - if (chan->load_state == S3C2410_DMALOAD_NONE || - chan->load_state == S3C2410_DMALOAD_1RUNNING) - return 1; - - return 0; -} - -/* s3c2410_dma_enqueue - * - * queue an given buffer for dma transfer. - * - * id the device driver's id information for this buffer - * data the physical address of the buffer data - * size the size of the buffer in bytes - * - * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART - * is checked, and if set, the channel is started. If this flag isn't set, - * then an error will be returned. - * - * It is possible to queue more than one DMA buffer onto a channel at - * once, and the code will deal with the re-loading of the next buffer - * when necessary. -*/ - -int s3c2410_dma_enqueue(unsigned int channel, void *id, - dma_addr_t data, int size) -{ - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); - struct s3c2410_dma_buf *buf; - unsigned long flags; - - if (chan == NULL) - return -EINVAL; - - pr_debug("%s: id=%p, data=%08x, size=%d\n", - __FUNCTION__, id, (unsigned int)data, size); - - buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC); - if (buf == NULL) { - pr_debug("%s: out of memory (%ld alloc)\n", - __FUNCTION__, (long)sizeof(*buf)); - return -ENOMEM; - } - - //pr_debug("%s: new buffer %p\n", __FUNCTION__, buf); - //dbg_showchan(chan); - - buf->next = NULL; - buf->data = buf->ptr = data; - buf->size = size; - buf->id = id; - buf->magic = BUF_MAGIC; - - local_irq_save(flags); - - if (chan->curr == NULL) { - /* we've got nothing loaded... */ - pr_debug("%s: buffer %p queued onto empty channel\n", - __FUNCTION__, buf); - - chan->curr = buf; - chan->end = buf; - chan->next = NULL; - } else { - pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n", - chan->number, __FUNCTION__, buf); - - if (chan->end == NULL) - pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n", - chan->number, __FUNCTION__, chan); - - chan->end->next = buf; - chan->end = buf; - } - - /* if necessary, update the next buffer field */ - if (chan->next == NULL) - chan->next = buf; - - /* check to see if we can load a buffer */ - if (chan->state == S3C2410_DMA_RUNNING) { - if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) { - if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { - printk(KERN_ERR "dma%d: loadbuffer:" - "timeout loading buffer\n", - chan->number); - dbg_showchan(chan); - local_irq_restore(flags); - return -EINVAL; - } - } - - while (s3c2410_dma_canload(chan) && chan->next != NULL) { - s3c2410_dma_loadbuffer(chan, chan->next); - } - } else if (chan->state == S3C2410_DMA_IDLE) { - if (chan->flags & S3C2410_DMAF_AUTOSTART) { - s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START); - } - } - - local_irq_restore(flags); - return 0; -} - -EXPORT_SYMBOL(s3c2410_dma_enqueue); - -static inline void -s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf) -{ - int magicok = (buf->magic == BUF_MAGIC); - - buf->magic = -1; - - if (magicok) { - kmem_cache_free(dma_kmem, buf); - } else { - printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf); - } -} - -/* s3c2410_dma_lastxfer - * - * called when the system is out of buffers, to ensure that the channel - * is prepared for shutdown. -*/ - -static inline void -s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan) -{ -#if 0 - pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n", - chan->number, chan->load_state); -#endif - - switch (chan->load_state) { - case S3C2410_DMALOAD_NONE: - break; - - case S3C2410_DMALOAD_1LOADED: - if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { - /* flag error? */ - printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n", - chan->number, __FUNCTION__); - return; - } - break; - - case S3C2410_DMALOAD_1LOADED_1RUNNING: - /* I belive in this case we do not have anything to do - * until the next buffer comes along, and we turn off the - * reload */ - return; - - default: - pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n", - chan->number, chan->load_state); - return; - - } - - /* hopefully this'll shut the damned thing up after the transfer... */ - dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD); -} - - -#define dmadbg2(x...) - -static irqreturn_t -s3c2410_dma_irq(int irq, void *devpw) -{ - struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw; - struct s3c2410_dma_buf *buf; - - buf = chan->curr; - - dbg_showchan(chan); - - /* modify the channel state */ - - switch (chan->load_state) { - case S3C2410_DMALOAD_1RUNNING: - /* TODO - if we are running only one buffer, we probably - * want to reload here, and then worry about the buffer - * callback */ - - chan->load_state = S3C2410_DMALOAD_NONE; - break; - - case S3C2410_DMALOAD_1LOADED: - /* iirc, we should go back to NONE loaded here, we - * had a buffer, and it was never verified as being - * loaded. - */ - - chan->load_state = S3C2410_DMALOAD_NONE; - break; - - case S3C2410_DMALOAD_1LOADED_1RUNNING: - /* we'll worry about checking to see if another buffer is - * ready after we've called back the owner. This should - * ensure we do not wait around too long for the DMA - * engine to start the next transfer - */ - - chan->load_state = S3C2410_DMALOAD_1LOADED; - break; - - case S3C2410_DMALOAD_NONE: - printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n", - chan->number); - break; - - default: - printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n", - chan->number, chan->load_state); - break; - } - - if (buf != NULL) { - /* update the chain to make sure that if we load any more - * buffers when we call the callback function, things should - * work properly */ - - chan->curr = buf->next; - buf->next = NULL; - - if (buf->magic != BUF_MAGIC) { - printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n", - chan->number, __FUNCTION__, buf); - return IRQ_HANDLED; - } - - s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK); - - /* free resouces */ - s3c2410_dma_freebuf(buf); - } else { - } - - /* only reload if the channel is still running... our buffer done - * routine may have altered the state by requesting the dma channel - * to stop or shutdown... */ - - /* todo: check that when the channel is shut-down from inside this - * function, we cope with unsetting reload, etc */ - - if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) { - unsigned long flags; - - switch (chan->load_state) { - case S3C2410_DMALOAD_1RUNNING: - /* don't need to do anything for this state */ - break; - - case S3C2410_DMALOAD_NONE: - /* can load buffer immediately */ - break; - - case S3C2410_DMALOAD_1LOADED: - if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { - /* flag error? */ - printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n", - chan->number, __FUNCTION__); - return IRQ_HANDLED; - } - - break; - - case S3C2410_DMALOAD_1LOADED_1RUNNING: - goto no_load; - - default: - printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n", - chan->number, chan->load_state); - return IRQ_HANDLED; - } - - local_irq_save(flags); - s3c2410_dma_loadbuffer(chan, chan->next); - local_irq_restore(flags); - } else { - s3c2410_dma_lastxfer(chan); - - /* see if we can stop this channel.. */ - if (chan->load_state == S3C2410_DMALOAD_NONE) { - pr_debug("dma%d: end of transfer, stopping channel (%ld)\n", - chan->number, jiffies); - s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL, - S3C2410_DMAOP_STOP); - } - } - - no_load: - return IRQ_HANDLED; -} - -static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel); - -/* s3c2410_request_dma - * - * get control of an dma channel -*/ - -int s3c2410_dma_request(unsigned int channel, - struct s3c2410_dma_client *client, - void *dev) -{ - struct s3c2410_dma_chan *chan; - unsigned long flags; - int err; - - pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n", - channel, client->name, dev); - - local_irq_save(flags); - - chan = s3c2410_dma_map_channel(channel); - if (chan == NULL) { - local_irq_restore(flags); - return -EBUSY; - } - - dbg_showchan(chan); - - chan->client = client; - chan->in_use = 1; - - if (!chan->irq_claimed) { - pr_debug("dma%d: %s : requesting irq %d\n", - channel, __FUNCTION__, chan->irq); - - chan->irq_claimed = 1; - local_irq_restore(flags); - - err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED, - client->name, (void *)chan); - - local_irq_save(flags); - - if (err) { - chan->in_use = 0; - chan->irq_claimed = 0; - local_irq_restore(flags); - - printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n", - client->name, chan->irq, chan->number); - return err; - } - - chan->irq_enabled = 1; - } - - local_irq_restore(flags); - - /* need to setup */ - - pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan); - - return 0; -} - -EXPORT_SYMBOL(s3c2410_dma_request); +static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = { + .select = s3c2410_dma_select, + .dcon_mask = 7 << 24, + .map = s3c2410_dma_mappings, + .map_size = ARRAY_SIZE(s3c2410_dma_mappings), +}; -/* s3c2410_dma_free - * - * release the given channel back to the system, will stop and flush - * any outstanding transfers, and ensure the channel is ready for the - * next claimant. - * - * Note, although a warning is currently printed if the freeing client - * info is not the same as the registrant's client info, the free is still - * allowed to go through. -*/ +static struct s3c24xx_dma_order __initdata s3c2410_dma_order = { + .channels = { + [DMACH_SDI] = { + .list = { + [0] = 3 | DMA_CH_VALID, + [1] = 2 | DMA_CH_VALID, + [2] = 0 | DMA_CH_VALID, + }, + }, + [DMACH_I2S_IN] = { + .list = { + [0] = 1 | DMA_CH_VALID, + [1] = 2 | DMA_CH_VALID, + }, + }, + }, +}; -int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client) +static int s3c2410_dma_add(struct sys_device *sysdev) { - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); - unsigned long flags; - - if (chan == NULL) - return -EINVAL; - - local_irq_save(flags); - - if (chan->client != client) { - printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n", - channel, chan->client, client); - } - - /* sort out stopping and freeing the channel */ - - if (chan->state != S3C2410_DMA_IDLE) { - pr_debug("%s: need to stop dma channel %p\n", - __FUNCTION__, chan); - - /* possibly flush the channel */ - s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP); - } - - chan->client = NULL; - chan->in_use = 0; - - if (chan->irq_claimed) - free_irq(chan->irq, (void *)chan); - - chan->irq_claimed = 0; - - if (!(channel & DMACH_LOW_LEVEL)) - dma_chan_map[channel] = NULL; - - local_irq_restore(flags); - - return 0; + s3c2410_dma_init(); + s3c24xx_dma_order_set(&s3c2410_dma_order); + return s3c24xx_dma_init_map(&s3c2410_dma_sel); } -EXPORT_SYMBOL(s3c2410_dma_free); - -static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan) -{ - unsigned long flags; - unsigned long tmp; - - pr_debug("%s:\n", __FUNCTION__); - - dbg_showchan(chan); - - local_irq_save(flags); - - s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP); - - tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); - tmp |= S3C2410_DMASKTRIG_STOP; - //tmp &= ~S3C2410_DMASKTRIG_ON; - dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); - -#if 0 - /* should also clear interrupts, according to WinCE BSP */ - tmp = dma_rdreg(chan, S3C2410_DMA_DCON); - tmp |= S3C2410_DCON_NORELOAD; - dma_wrreg(chan, S3C2410_DMA_DCON, tmp); -#endif - - /* should stop do this, or should we wait for flush? */ - chan->state = S3C2410_DMA_IDLE; - chan->load_state = S3C2410_DMALOAD_NONE; - - local_irq_restore(flags); - - return 0; -} +#if defined(CONFIG_CPU_S3C2410) +static struct sysdev_driver s3c2410_dma_driver = { + .add = s3c2410_dma_add, +}; -void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan) +static int __init s3c2410_dma_drvinit(void) { - unsigned long tmp; - unsigned int timeout = 0x10000; - - while (timeout-- > 0) { - tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); - - if (!(tmp & S3C2410_DMASKTRIG_ON)) - return; - } - - pr_debug("dma%d: failed to stop?\n", chan->number); + return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver); } - -/* s3c2410_dma_flush - * - * stop the channel, and remove all current and pending transfers -*/ - -static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan) -{ - struct s3c2410_dma_buf *buf, *next; - unsigned long flags; - - pr_debug("%s: chan %p (%d)\n", __FUNCTION__, chan, chan->number); - - dbg_showchan(chan); - - local_irq_save(flags); - - if (chan->state != S3C2410_DMA_IDLE) { - pr_debug("%s: stopping channel...\n", __FUNCTION__ ); - s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP); - } - - buf = chan->curr; - if (buf == NULL) - buf = chan->next; - - chan->curr = chan->next = chan->end = NULL; - - if (buf != NULL) { - for ( ; buf != NULL; buf = next) { - next = buf->next; - - pr_debug("%s: free buffer %p, next %p\n", - __FUNCTION__, buf, buf->next); - - s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT); - s3c2410_dma_freebuf(buf); - } - } - - dbg_showregs(chan); - - s3c2410_dma_waitforstop(chan); - -#if 0 - /* should also clear interrupts, according to WinCE BSP */ - { - unsigned long tmp; - - tmp = dma_rdreg(chan, S3C2410_DMA_DCON); - tmp |= S3C2410_DCON_NORELOAD; - dma_wrreg(chan, S3C2410_DMA_DCON, tmp); - } +arch_initcall(s3c2410_dma_drvinit); #endif - dbg_showregs(chan); - - local_irq_restore(flags); - - return 0; -} - -int -s3c2410_dma_started(struct s3c2410_dma_chan *chan) -{ - unsigned long flags; - - local_irq_save(flags); - - dbg_showchan(chan); - - /* if we've only loaded one buffer onto the channel, then chec - * to see if we have another, and if so, try and load it so when - * the first buffer is finished, the new one will be loaded onto - * the channel */ - - if (chan->next != NULL) { - if (chan->load_state == S3C2410_DMALOAD_1LOADED) { - - if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { - pr_debug("%s: buff not yet loaded, no more todo\n", - __FUNCTION__); - } else { - chan->load_state = S3C2410_DMALOAD_1RUNNING; - s3c2410_dma_loadbuffer(chan, chan->next); - } - - } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) { - s3c2410_dma_loadbuffer(chan, chan->next); - } - } - - - local_irq_restore(flags); - - return 0; - -} - -int -s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op) -{ - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); - - if (chan == NULL) - return -EINVAL; - - switch (op) { - case S3C2410_DMAOP_START: - return s3c2410_dma_start(chan); - - case S3C2410_DMAOP_STOP: - return s3c2410_dma_dostop(chan); - - case S3C2410_DMAOP_PAUSE: - case S3C2410_DMAOP_RESUME: - return -ENOENT; - - case S3C2410_DMAOP_FLUSH: - return s3c2410_dma_flush(chan); - - case S3C2410_DMAOP_STARTED: - return s3c2410_dma_started(chan); - - case S3C2410_DMAOP_TIMEOUT: - return 0; - - } - - return -ENOENT; /* unknown, don't bother */ -} - -EXPORT_SYMBOL(s3c2410_dma_ctrl); - -/* DMA configuration for each channel - * - * DISRCC -> source of the DMA (AHB,APB) - * DISRC -> source address of the DMA - * DIDSTC -> destination of the DMA (AHB,APD) - * DIDST -> destination address of the DMA -*/ - -/* s3c2410_dma_config - * - * xfersize: size of unit in bytes (1,2,4) - * dcon: base value of the DCONx register -*/ - -int s3c2410_dma_config(dmach_t channel, - int xferunit, - int dcon) -{ - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); - - pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n", - __FUNCTION__, channel, xferunit, dcon); - - if (chan == NULL) - return -EINVAL; - - pr_debug("%s: Initial dcon is %08x\n", __FUNCTION__, dcon); - - dcon |= chan->dcon & dma_sel.dcon_mask; - - pr_debug("%s: New dcon is %08x\n", __FUNCTION__, dcon); - - switch (xferunit) { - case 1: - dcon |= S3C2410_DCON_BYTE; - break; - - case 2: - dcon |= S3C2410_DCON_HALFWORD; - break; - - case 4: - dcon |= S3C2410_DCON_WORD; - break; - - default: - pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit); - return -EINVAL; - } - - dcon |= S3C2410_DCON_HWTRIG; - dcon |= S3C2410_DCON_INTREQ; - - pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon); - - chan->dcon = dcon; - chan->xfer_unit = xferunit; - - return 0; -} - -EXPORT_SYMBOL(s3c2410_dma_config); - -int s3c2410_dma_setflags(dmach_t channel, unsigned int flags) -{ - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); - - if (chan == NULL) - return -EINVAL; - - pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags); - - chan->flags = flags; - - return 0; -} - -EXPORT_SYMBOL(s3c2410_dma_setflags); - - -/* do we need to protect the settings of the fields from - * irq? -*/ - -int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn) -{ - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); - - if (chan == NULL) - return -EINVAL; - - pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn); - - chan->op_fn = rtn; - - return 0; -} - -EXPORT_SYMBOL(s3c2410_dma_set_opfn); - -int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn) -{ - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); - - if (chan == NULL) - return -EINVAL; - - pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn); - - chan->callback_fn = rtn; - - return 0; -} - -EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn); - -/* s3c2410_dma_devconfig - * - * configure the dma source/destination hardware type and address - * - * source: S3C2410_DMASRC_HW: source is hardware - * S3C2410_DMASRC_MEM: source is memory - * - * hwcfg: the value for xxxSTCn register, - * bit 0: 0=increment pointer, 1=leave pointer - * bit 1: 0=soucre is AHB, 1=soucre is APB - * - * devaddr: physical address of the source -*/ - -int s3c2410_dma_devconfig(int channel, - enum s3c2410_dmasrc source, - int hwcfg, - unsigned long devaddr) -{ - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); - - if (chan == NULL) - return -EINVAL; - - pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n", - __FUNCTION__, (int)source, hwcfg, devaddr); - - chan->source = source; - chan->dev_addr = devaddr; - - switch (source) { - case S3C2410_DMASRC_HW: - /* source is hardware */ - pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n", - __FUNCTION__, devaddr, hwcfg); - dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3); - dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr); - dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0)); - - chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST); - return 0; - - case S3C2410_DMASRC_MEM: - /* source is memory */ - pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n", - __FUNCTION__, devaddr, hwcfg); - dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0)); - dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr); - dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3); - - chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC); - return 0; - } - - printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source); - return -EINVAL; -} - -EXPORT_SYMBOL(s3c2410_dma_devconfig); - -/* s3c2410_dma_getposition - * - * returns the current transfer points for the dma source and destination -*/ - -int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst) -{ - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); - - if (chan == NULL) - return -EINVAL; - - if (src != NULL) - *src = dma_rdreg(chan, S3C2410_DMA_DCSRC); - - if (dst != NULL) - *dst = dma_rdreg(chan, S3C2410_DMA_DCDST); - - return 0; -} - -EXPORT_SYMBOL(s3c2410_dma_getposition); - - -/* system device class */ - -#ifdef CONFIG_PM - -static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state) -{ - struct s3c2410_dma_chan *cp = container_of(dev, struct s3c2410_dma_chan, dev); - - printk(KERN_DEBUG "suspending dma channel %d\n", cp->number); - - if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) { - /* the dma channel is still working, which is probably - * a bad thing to do over suspend/resume. We stop the - * channel and assume that the client is either going to - * retry after resume, or that it is broken. - */ - - printk(KERN_INFO "dma: stopping channel %d due to suspend\n", - cp->number); - - s3c2410_dma_dostop(cp); - } - - return 0; -} - -static int s3c2410_dma_resume(struct sys_device *dev) -{ - return 0; -} - -#else -#define s3c2410_dma_suspend NULL -#define s3c2410_dma_resume NULL -#endif /* CONFIG_PM */ - -struct sysdev_class dma_sysclass = { - set_kset_name("s3c24xx-dma"), - .suspend = s3c2410_dma_suspend, - .resume = s3c2410_dma_resume, +#if defined(CONFIG_CPU_S3C2442) +/* S3C2442 DMA contains the same selection table as the S3C2410 */ +static struct sysdev_driver s3c2442_dma_driver = { + .add = s3c2410_dma_add, }; -/* kmem cache implementation */ - -static void s3c2410_dma_cache_ctor(void *p, struct kmem_cache *c, unsigned long f) -{ - memset(p, 0, sizeof(struct s3c2410_dma_buf)); -} - -/* initialisation code */ - -static int __init s3c2410_init_dma(void) -{ - struct s3c2410_dma_chan *cp; - int channel; - int ret; - - printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n"); - - dma_base = ioremap(S3C24XX_PA_DMA, 0x200); - if (dma_base == NULL) { - printk(KERN_ERR "dma failed to remap register block\n"); - return -ENOMEM; - } - - printk("Registering sysclass\n"); - - ret = sysdev_class_register(&dma_sysclass); - if (ret != 0) { - printk(KERN_ERR "dma sysclass registration failed\n"); - goto err; - } - - dma_kmem = kmem_cache_create("dma_desc", sizeof(struct s3c2410_dma_buf), 0, - SLAB_HWCACHE_ALIGN, - s3c2410_dma_cache_ctor, NULL); - - if (dma_kmem == NULL) { - printk(KERN_ERR "dma failed to make kmem cache\n"); - ret = -ENOMEM; - goto err; - } - - for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) { - cp = &s3c2410_chans[channel]; - - memset(cp, 0, sizeof(struct s3c2410_dma_chan)); - - /* dma channel irqs are in order.. */ - cp->number = channel; - cp->irq = channel + IRQ_DMA0; - cp->regs = dma_base + (channel*0x40); - - /* point current stats somewhere */ - cp->stats = &cp->stats_store; - cp->stats_store.timeout_shortest = LONG_MAX; - - /* basic channel configuration */ - - cp->load_timeout = 1<<18; - - /* register system device */ - - cp->dev.cls = &dma_sysclass; - cp->dev.id = channel; - ret = sysdev_register(&cp->dev); - - printk("DMA channel %d at %p, irq %d\n", - cp->number, cp->regs, cp->irq); - } - - return 0; - - err: - kmem_cache_destroy(dma_kmem); - iounmap(dma_base); - dma_base = NULL; - return ret; -} - -core_initcall(s3c2410_init_dma); - -static inline int is_channel_valid(unsigned int channel) +static int __init s3c2442_dma_drvinit(void) { - return (channel & DMA_CH_VALID); + return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_dma_driver); } -/* s3c2410_dma_map_channel() - * - * turn the virtual channel number into a real, and un-used hardware - * channel. - * - * currently this code uses first-free channel from the specified harware - * map, not taking into account anything that the board setup code may - * have to say about the likely peripheral set to be in use. -*/ - -struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel) -{ - struct s3c24xx_dma_map *ch_map; - struct s3c2410_dma_chan *dmach; - int ch; - - if (dma_sel.map == NULL || channel > dma_sel.map_size) - return NULL; - - ch_map = dma_sel.map + channel; - - for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) { - if (!is_channel_valid(ch_map->channels[ch])) - continue; - - if (s3c2410_chans[ch].in_use == 0) { - printk("mapped channel %d to %d\n", channel, ch); - break; - } - } - - if (ch >= S3C2410_DMA_CHANNELS) - return NULL; - - /* update our channel mapping */ - - dmach = &s3c2410_chans[ch]; - dma_chan_map[channel] = dmach; - - /* select the channel */ - - (dma_sel.select)(dmach, ch_map); - - return dmach; -} - -static void s3c24xx_dma_show_ch(struct s3c24xx_dma_map *map, int ch) -{ - /* show the channel configuration */ - - printk("%2d: %20s, channels %c%c%c%c\n", ch, map->name, - (is_channel_valid(map->channels[0]) ? '0' : '-'), - (is_channel_valid(map->channels[1]) ? '1' : '-'), - (is_channel_valid(map->channels[2]) ? '2' : '-'), - (is_channel_valid(map->channels[3]) ? '3' : '-')); -} - -static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch) -{ - if (1) - s3c24xx_dma_show_ch(map, ch); - - return 0; -} - -int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel) -{ - struct s3c24xx_dma_map *nmap; - size_t map_sz = sizeof(*nmap) * sel->map_size; - int ptr; - - nmap = kmalloc(map_sz, GFP_KERNEL); - if (nmap == NULL) - return -ENOMEM; - - memcpy(nmap, sel->map, map_sz); - memcpy(&dma_sel, sel, sizeof(*sel)); - - dma_sel.map = nmap; - - for (ptr = 0; ptr < sel->map_size; ptr++) - s3c24xx_dma_check_entry(nmap+ptr, ptr); +arch_initcall(s3c2442_dma_drvinit); +#endif - return 0; -} diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c index f6fb215bb48..01e795d1146 100644 --- a/arch/arm/mach-s3c2410/gpio.c +++ b/arch/arm/mach-s3c2410/gpio.c @@ -1,9 +1,9 @@ /* linux/arch/arm/mach-s3c2410/gpio.c * - * Copyright (c) 2004-2005 Simtec Electronics + * Copyright (c) 2004-2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * - * S3C24XX GPIO support + * S3C2410 GPIO support * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,8 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - + */ #include <linux/kernel.h> #include <linux/init.h> @@ -33,156 +32,40 @@ #include <asm/arch/regs-gpio.h> -void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function) -{ - void __iomem *base = S3C24XX_GPIO_BASE(pin); - unsigned long mask; - unsigned long con; - unsigned long flags; - - if (pin < S3C2410_GPIO_BANKB) { - mask = 1 << S3C2410_GPIO_OFFSET(pin); - } else { - mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; - } - - switch (function) { - case S3C2410_GPIO_LEAVE: - mask = 0; - function = 0; - break; - - case S3C2410_GPIO_INPUT: - case S3C2410_GPIO_OUTPUT: - case S3C2410_GPIO_SFN2: - case S3C2410_GPIO_SFN3: - if (pin < S3C2410_GPIO_BANKB) { - function -= 1; - function &= 1; - function <<= S3C2410_GPIO_OFFSET(pin); - } else { - function &= 3; - function <<= S3C2410_GPIO_OFFSET(pin)*2; - } - } - - /* modify the specified register wwith IRQs off */ - - local_irq_save(flags); - - con = __raw_readl(base + 0x00); - con &= ~mask; - con |= function; - - __raw_writel(con, base + 0x00); - - local_irq_restore(flags); -} - -EXPORT_SYMBOL(s3c2410_gpio_cfgpin); - -unsigned int s3c2410_gpio_getcfg(unsigned int pin) -{ - void __iomem *base = S3C24XX_GPIO_BASE(pin); - unsigned long val = __raw_readl(base); - - if (pin < S3C2410_GPIO_BANKB) { - val >>= S3C2410_GPIO_OFFSET(pin); - val &= 1; - val += 1; - } else { - val >>= S3C2410_GPIO_OFFSET(pin)*2; - val &= 3; - } - - return val | S3C2410_GPIO_INPUT; -} - -EXPORT_SYMBOL(s3c2410_gpio_getcfg); - -void s3c2410_gpio_pullup(unsigned int pin, unsigned int to) +int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, + unsigned int config) { - void __iomem *base = S3C24XX_GPIO_BASE(pin); - unsigned long offs = S3C2410_GPIO_OFFSET(pin); + void __iomem *reg = S3C24XX_EINFLT0; unsigned long flags; - unsigned long up; - - if (pin < S3C2410_GPIO_BANKB) - return; - - local_irq_save(flags); - - up = __raw_readl(base + 0x08); - up &= ~(1L << offs); - up |= to << offs; - __raw_writel(up, base + 0x08); + unsigned long val; - local_irq_restore(flags); -} + if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15) + return -1; -EXPORT_SYMBOL(s3c2410_gpio_pullup); + config &= 0xff; -void s3c2410_gpio_setpin(unsigned int pin, unsigned int to) -{ - void __iomem *base = S3C24XX_GPIO_BASE(pin); - unsigned long offs = S3C2410_GPIO_OFFSET(pin); - unsigned long flags; - unsigned long dat; + pin -= S3C2410_GPG8; + reg += pin & ~3; local_irq_save(flags); - dat = __raw_readl(base + 0x04); - dat &= ~(1 << offs); - dat |= to << offs; - __raw_writel(dat, base + 0x04); - - local_irq_restore(flags); -} - -EXPORT_SYMBOL(s3c2410_gpio_setpin); - -unsigned int s3c2410_gpio_getpin(unsigned int pin) -{ - void __iomem *base = S3C24XX_GPIO_BASE(pin); - unsigned long offs = S3C2410_GPIO_OFFSET(pin); + /* update filter width and clock source */ - return __raw_readl(base + 0x04) & (1<< offs); -} + val = __raw_readl(reg); + val &= ~(0xff << ((pin & 3) * 8)); + val |= config << ((pin & 3) * 8); + __raw_writel(val, reg); -EXPORT_SYMBOL(s3c2410_gpio_getpin); + /* update filter enable */ -unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) -{ - unsigned long flags; - unsigned long misccr; + val = __raw_readl(S3C24XX_EXTINT2); + val &= ~(1 << ((pin * 4) + 3)); + val |= on << ((pin * 4) + 3); + __raw_writel(val, S3C24XX_EXTINT2); - local_irq_save(flags); - misccr = __raw_readl(S3C24XX_MISCCR); - misccr &= ~clear; - misccr ^= change; - __raw_writel(misccr, S3C24XX_MISCCR); local_irq_restore(flags); - return misccr; -} - -EXPORT_SYMBOL(s3c2410_modify_misccr); - -int s3c2410_gpio_getirq(unsigned int pin) -{ - if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15) - return -1; /* not valid interrupts */ - - if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7) - return -1; /* not valid pin */ - - if (pin < S3C2410_GPF4) - return (pin - S3C2410_GPF0) + IRQ_EINT0; - - if (pin < S3C2410_GPG0) - return (pin - S3C2410_GPF4) + IRQ_EINT4; - - return (pin - S3C2410_GPG0) + IRQ_EINT8; + return 0; } -EXPORT_SYMBOL(s3c2410_gpio_getirq); +EXPORT_SYMBOL(s3c2410_gpio_irqfilter); diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c index 3c0ed7871c5..53cbdaa43ac 100644 --- a/arch/arm/mach-s3c2410/irq.c +++ b/arch/arm/mach-s3c2410/irq.c @@ -1,6 +1,6 @@ /* linux/arch/arm/mach-s3c2410/irq.c * - * Copyright (c) 2003,2004 Simtec Electronics + * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * * This program is free software; you can redistribute it and/or modify @@ -17,37 +17,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Changelog: - * - * 22-Jul-2004 Ben Dooks <ben@simtec.co.uk> - * Fixed compile warnings - * - * 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn> - * Fixed s3c_extirq_type - * - * 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org> - * Addition of ADC/TC demux - * - * 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de> - * Fix for set_irq_type() on low EINT numbers - * - * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> - * Tidy up KF's patch and sort out new release - * - * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> - * Add support for power management controls - * - * 04-Nov-2004 Ben Dooks - * Fix standard IRQ wake for EINT0..4 and RTC - * - * 22-Feb-2005 Ben Dooks - * Fixed edge-triggering on ADC IRQ - * - * 28-Jun-2005 Ben Dooks - * Mark IRQ_LCD valid - * - * 25-Jul-2005 Ben Dooks - * Split the S3C2440 IRQ code to seperate file */ #include <linux/init.h> @@ -57,745 +26,23 @@ #include <linux/ptrace.h> #include <linux/sysdev.h> -#include <asm/hardware.h> -#include <asm/irq.h> -#include <asm/io.h> - -#include <asm/mach/irq.h> - -#include <asm/arch/regs-irq.h> -#include <asm/arch/regs-gpio.h> - -#include "cpu.h" -#include "pm.h" -#include "irq.h" - -/* wakeup irq control */ - -#ifdef CONFIG_PM - -/* state for IRQs over sleep */ - -/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources - * - * set bit to 1 in allow bitfield to enable the wakeup settings on it -*/ - -unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL; -unsigned long s3c_irqwake_intmask = 0xffffffffL; -unsigned long s3c_irqwake_eintallow = 0x0000fff0L; -unsigned long s3c_irqwake_eintmask = 0xffffffffL; - -int -s3c_irq_wake(unsigned int irqno, unsigned int state) -{ - unsigned long irqbit = 1 << (irqno - IRQ_EINT0); - - if (!(s3c_irqwake_intallow & irqbit)) - return -ENOENT; - - printk(KERN_INFO "wake %s for irq %d\n", - state ? "enabled" : "disabled", irqno); - - if (!state) - s3c_irqwake_intmask |= irqbit; - else - s3c_irqwake_intmask &= ~irqbit; - - return 0; -} - -static int -s3c_irqext_wake(unsigned int irqno, unsigned int state) -{ - unsigned long bit = 1L << (irqno - EXTINT_OFF); - - if (!(s3c_irqwake_eintallow & bit)) - return -ENOENT; - - printk(KERN_INFO "wake %s for irq %d\n", - state ? "enabled" : "disabled", irqno); - - if (!state) - s3c_irqwake_eintmask |= bit; - else - s3c_irqwake_eintmask &= ~bit; - - return 0; -} - -#else -#define s3c_irqext_wake NULL -#define s3c_irq_wake NULL -#endif - - -static void -s3c_irq_mask(unsigned int irqno) -{ - unsigned long mask; - - irqno -= IRQ_EINT0; - - mask = __raw_readl(S3C2410_INTMSK); - mask |= 1UL << irqno; - __raw_writel(mask, S3C2410_INTMSK); -} - -static inline void -s3c_irq_ack(unsigned int irqno) -{ - unsigned long bitval = 1UL << (irqno - IRQ_EINT0); - - __raw_writel(bitval, S3C2410_SRCPND); - __raw_writel(bitval, S3C2410_INTPND); -} - -static inline void -s3c_irq_maskack(unsigned int irqno) -{ - unsigned long bitval = 1UL << (irqno - IRQ_EINT0); - unsigned long mask; - - mask = __raw_readl(S3C2410_INTMSK); - __raw_writel(mask|bitval, S3C2410_INTMSK); - - __raw_writel(bitval, S3C2410_SRCPND); - __raw_writel(bitval, S3C2410_INTPND); -} - - -static void -s3c_irq_unmask(unsigned int irqno) -{ - unsigned long mask; - - if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23) - irqdbf2("s3c_irq_unmask %d\n", irqno); - - irqno -= IRQ_EINT0; - - mask = __raw_readl(S3C2410_INTMSK); - mask &= ~(1UL << irqno); - __raw_writel(mask, S3C2410_INTMSK); -} - -struct irq_chip s3c_irq_level_chip = { - .name = "s3c-level", - .ack = s3c_irq_maskack, - .mask = s3c_irq_mask, - .unmask = s3c_irq_unmask, - .set_wake = s3c_irq_wake -}; - -static struct irq_chip s3c_irq_chip = { - .name = "s3c", - .ack = s3c_irq_ack, - .mask = s3c_irq_mask, - .unmask = s3c_irq_unmask, - .set_wake = s3c_irq_wake -}; - -static void -s3c_irqext_mask(unsigned int irqno) -{ - unsigned long mask; - - irqno -= EXTINT_OFF; - - mask = __raw_readl(S3C24XX_EINTMASK); - mask |= ( 1UL << irqno); - __raw_writel(mask, S3C24XX_EINTMASK); -} - -static void -s3c_irqext_ack(unsigned int irqno) -{ - unsigned long req; - unsigned long bit; - unsigned long mask; +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/pm.h> - bit = 1UL << (irqno - EXTINT_OFF); - - mask = __raw_readl(S3C24XX_EINTMASK); - - __raw_writel(bit, S3C24XX_EINTPEND); - - req = __raw_readl(S3C24XX_EINTPEND); - req &= ~mask; - - /* not sure if we should be acking the parent irq... */ - - if (irqno <= IRQ_EINT7 ) { - if ((req & 0xf0) == 0) - s3c_irq_ack(IRQ_EINT4t7); - } else { - if ((req >> 8) == 0) - s3c_irq_ack(IRQ_EINT8t23); - } -} - -static void -s3c_irqext_unmask(unsigned int irqno) +static int s3c2410_irq_add(struct sys_device *sysdev) { - unsigned long mask; - - irqno -= EXTINT_OFF; - - mask = __raw_readl(S3C24XX_EINTMASK); - mask &= ~( 1UL << irqno); - __raw_writel(mask, S3C24XX_EINTMASK); -} - -int -s3c_irqext_type(unsigned int irq, unsigned int type) -{ - void __iomem *extint_reg; - void __iomem *gpcon_reg; - unsigned long gpcon_offset, extint_offset; - unsigned long newvalue = 0, value; - - if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3)) - { - gpcon_reg = S3C2410_GPFCON; - extint_reg = S3C24XX_EXTINT0; - gpcon_offset = (irq - IRQ_EINT0) * 2; - extint_offset = (irq - IRQ_EINT0) * 4; - } - else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7)) - { - gpcon_reg = S3C2410_GPFCON; - extint_reg = S3C24XX_EXTINT0; - gpcon_offset = (irq - (EXTINT_OFF)) * 2; - extint_offset = (irq - (EXTINT_OFF)) * 4; - } - else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15)) - { - gpcon_reg = S3C2410_GPGCON; - extint_reg = S3C24XX_EXTINT1; - gpcon_offset = (irq - IRQ_EINT8) * 2; - extint_offset = (irq - IRQ_EINT8) * 4; - } - else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23)) - { - gpcon_reg = S3C2410_GPGCON; - extint_reg = S3C24XX_EXTINT2; - gpcon_offset = (irq - IRQ_EINT8) * 2; - extint_offset = (irq - IRQ_EINT16) * 4; - } else - return -1; - - /* Set the GPIO to external interrupt mode */ - value = __raw_readl(gpcon_reg); - value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); - __raw_writel(value, gpcon_reg); - - /* Set the external interrupt to pointed trigger type */ - switch (type) - { - case IRQT_NOEDGE: - printk(KERN_WARNING "No edge setting!\n"); - break; - - case IRQT_RISING: - newvalue = S3C2410_EXTINT_RISEEDGE; - break; - - case IRQT_FALLING: - newvalue = S3C2410_EXTINT_FALLEDGE; - break; - - case IRQT_BOTHEDGE: - newvalue = S3C2410_EXTINT_BOTHEDGE; - break; - - case IRQT_LOW: - newvalue = S3C2410_EXTINT_LOWLEV; - break; - - case IRQT_HIGH: - newvalue = S3C2410_EXTINT_HILEV; - break; - - default: - printk(KERN_ERR "No such irq type %d", type); - return -1; - } - - value = __raw_readl(extint_reg); - value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); - __raw_writel(value, extint_reg); - return 0; } -static struct irq_chip s3c_irqext_chip = { - .name = "s3c-ext", - .mask = s3c_irqext_mask, - .unmask = s3c_irqext_unmask, - .ack = s3c_irqext_ack, - .set_type = s3c_irqext_type, - .set_wake = s3c_irqext_wake -}; - -static struct irq_chip s3c_irq_eint0t4 = { - .name = "s3c-ext0", - .ack = s3c_irq_ack, - .mask = s3c_irq_mask, - .unmask = s3c_irq_unmask, - .set_wake = s3c_irq_wake, - .set_type = s3c_irqext_type, -}; - -/* mask values for the parent registers for each of the interrupt types */ - -#define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0)) -#define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0)) -#define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0)) -#define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0)) - - -/* UART0 */ - -static void -s3c_irq_uart0_mask(unsigned int irqno) -{ - s3c_irqsub_mask(irqno, INTMSK_UART0, 7); -} - -static void -s3c_irq_uart0_unmask(unsigned int irqno) -{ - s3c_irqsub_unmask(irqno, INTMSK_UART0); -} - -static void -s3c_irq_uart0_ack(unsigned int irqno) -{ - s3c_irqsub_maskack(irqno, INTMSK_UART0, 7); -} - -static struct irq_chip s3c_irq_uart0 = { - .name = "s3c-uart0", - .mask = s3c_irq_uart0_mask, - .unmask = s3c_irq_uart0_unmask, - .ack = s3c_irq_uart0_ack, -}; - -/* UART1 */ - -static void -s3c_irq_uart1_mask(unsigned int irqno) -{ - s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3); -} - -static void -s3c_irq_uart1_unmask(unsigned int irqno) -{ - s3c_irqsub_unmask(irqno, INTMSK_UART1); -} - -static void -s3c_irq_uart1_ack(unsigned int irqno) -{ - s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3); -} - -static struct irq_chip s3c_irq_uart1 = { - .name = "s3c-uart1", - .mask = s3c_irq_uart1_mask, - .unmask = s3c_irq_uart1_unmask, - .ack = s3c_irq_uart1_ack, -}; - -/* UART2 */ - -static void -s3c_irq_uart2_mask(unsigned int irqno) -{ - s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6); -} - -static void -s3c_irq_uart2_unmask(unsigned int irqno) -{ - s3c_irqsub_unmask(irqno, INTMSK_UART2); -} - -static void -s3c_irq_uart2_ack(unsigned int irqno) -{ - s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6); -} - -static struct irq_chip s3c_irq_uart2 = { - .name = "s3c-uart2", - .mask = s3c_irq_uart2_mask, - .unmask = s3c_irq_uart2_unmask, - .ack = s3c_irq_uart2_ack, -}; - -/* ADC and Touchscreen */ - -static void -s3c_irq_adc_mask(unsigned int irqno) -{ - s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9); -} - -static void -s3c_irq_adc_unmask(unsigned int irqno) -{ - s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT); -} - -static void -s3c_irq_adc_ack(unsigned int irqno) -{ - s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9); -} - -static struct irq_chip s3c_irq_adc = { - .name = "s3c-adc", - .mask = s3c_irq_adc_mask, - .unmask = s3c_irq_adc_unmask, - .ack = s3c_irq_adc_ack, -}; - -/* irq demux for adc */ -static void s3c_irq_demux_adc(unsigned int irq, - struct irq_desc *desc) -{ - unsigned int subsrc, submsk; - unsigned int offset = 9; - struct irq_desc *mydesc; - - /* read the current pending interrupts, and the mask - * for what it is available */ - - subsrc = __raw_readl(S3C2410_SUBSRCPND); - submsk = __raw_readl(S3C2410_INTSUBMSK); - - subsrc &= ~submsk; - subsrc >>= offset; - subsrc &= 3; - - if (subsrc != 0) { - if (subsrc & 1) { - mydesc = irq_desc + IRQ_TC; - desc_handle_irq(IRQ_TC, mydesc); - } - if (subsrc & 2) { - mydesc = irq_desc + IRQ_ADC; - desc_handle_irq(IRQ_ADC, mydesc); - } - } -} - -static void s3c_irq_demux_uart(unsigned int start) -{ - unsigned int subsrc, submsk; - unsigned int offset = start - IRQ_S3CUART_RX0; - struct irq_desc *desc; - - /* read the current pending interrupts, and the mask - * for what it is available */ - - subsrc = __raw_readl(S3C2410_SUBSRCPND); - submsk = __raw_readl(S3C2410_INTSUBMSK); - - irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n", - start, offset, subsrc, submsk); - - subsrc &= ~submsk; - subsrc >>= offset; - subsrc &= 7; - - if (subsrc != 0) { - desc = irq_desc + start; - - if (subsrc & 1) - desc_handle_irq(start, desc); - - desc++; - - if (subsrc & 2) - desc_handle_irq(start+1, desc); - - desc++; - - if (subsrc & 4) - desc_handle_irq(start+2, desc); - } -} - -/* uart demux entry points */ - -static void -s3c_irq_demux_uart0(unsigned int irq, - struct irq_desc *desc) -{ - irq = irq; - s3c_irq_demux_uart(IRQ_S3CUART_RX0); -} - -static void -s3c_irq_demux_uart1(unsigned int irq, - struct irq_desc *desc) -{ - irq = irq; - s3c_irq_demux_uart(IRQ_S3CUART_RX1); -} - -static void -s3c_irq_demux_uart2(unsigned int irq, - struct irq_desc *desc) -{ - irq = irq; - s3c_irq_demux_uart(IRQ_S3CUART_RX2); -} - -static void -s3c_irq_demux_extint8(unsigned int irq, - struct irq_desc *desc) -{ - unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND); - unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK); - - eintpnd &= ~eintmsk; - eintpnd &= ~0xff; /* ignore lower irqs */ - - /* we may as well handle all the pending IRQs here */ - - while (eintpnd) { - irq = __ffs(eintpnd); - eintpnd &= ~(1<<irq); - - irq += (IRQ_EINT4 - 4); - desc_handle_irq(irq, irq_desc + irq); - } - -} - -static void -s3c_irq_demux_extint4t7(unsigned int irq, - struct irq_desc *desc) -{ - unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND); - unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK); - - eintpnd &= ~eintmsk; - eintpnd &= 0xff; /* only lower irqs */ - - /* we may as well handle all the pending IRQs here */ - - while (eintpnd) { - irq = __ffs(eintpnd); - eintpnd &= ~(1<<irq); - - irq += (IRQ_EINT4 - 4); - - desc_handle_irq(irq, irq_desc + irq); - } -} - -#ifdef CONFIG_PM - -static struct sleep_save irq_save[] = { - SAVE_ITEM(S3C2410_INTMSK), - SAVE_ITEM(S3C2410_INTSUBMSK), +static struct sysdev_driver s3c2410_irq_driver = { + .add = s3c2410_irq_add, + .suspend = s3c24xx_irq_suspend, + .resume = s3c24xx_irq_resume, }; -/* the extint values move between the s3c2410/s3c2440 and the s3c2412 - * so we use an array to hold them, and to calculate the address of - * the register at run-time -*/ - -static unsigned long save_extint[3]; -static unsigned long save_eintflt[4]; -static unsigned long save_eintmask; - -int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state) +static int s3c2410_irq_init(void) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(save_extint); i++) - save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4)); - - for (i = 0; i < ARRAY_SIZE(save_eintflt); i++) - save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4)); - - s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); - save_eintmask = __raw_readl(S3C24XX_EINTMASK); - - return 0; + return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver); } -int s3c24xx_irq_resume(struct sys_device *dev) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(save_extint); i++) - __raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4)); - - for (i = 0; i < ARRAY_SIZE(save_eintflt); i++) - __raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4)); - - s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); - __raw_writel(save_eintmask, S3C24XX_EINTMASK); - - return 0; -} - -#else -#define s3c24xx_irq_suspend NULL -#define s3c24xx_irq_resume NULL -#endif - -/* s3c24xx_init_irq - * - * Initialise S3C2410 IRQ system -*/ - -void __init s3c24xx_init_irq(void) -{ - unsigned long pend; - unsigned long last; - int irqno; - int i; - - irqdbf("s3c2410_init_irq: clearing interrupt status flags\n"); - - /* first, clear all interrupts pending... */ - - last = 0; - for (i = 0; i < 4; i++) { - pend = __raw_readl(S3C24XX_EINTPEND); - - if (pend == 0 || pend == last) - break; - - __raw_writel(pend, S3C24XX_EINTPEND); - printk("irq: clearing pending ext status %08x\n", (int)pend); - last = pend; - } - - last = 0; - for (i = 0; i < 4; i++) { - pend = __raw_readl(S3C2410_INTPND); - - if (pend == 0 || pend == last) - break; - - __raw_writel(pend, S3C2410_SRCPND); - __raw_writel(pend, S3C2410_INTPND); - printk("irq: clearing pending status %08x\n", (int)pend); - last = pend; - } - - last = 0; - for (i = 0; i < 4; i++) { - pend = __raw_readl(S3C2410_SUBSRCPND); - - if (pend == 0 || pend == last) - break; - - printk("irq: clearing subpending status %08x\n", (int)pend); - __raw_writel(pend, S3C2410_SUBSRCPND); - last = pend; - } - - /* register the main interrupts */ - - irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); - - for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) { - /* set all the s3c2410 internal irqs */ - - switch (irqno) { - /* deal with the special IRQs (cascaded) */ - - case IRQ_EINT4t7: - case IRQ_EINT8t23: - case IRQ_UART0: - case IRQ_UART1: - case IRQ_UART2: - case IRQ_ADCPARENT: - set_irq_chip(irqno, &s3c_irq_level_chip); - set_irq_handler(irqno, handle_level_irq); - break; - - case IRQ_RESERVED6: - case IRQ_RESERVED24: - /* no IRQ here */ - break; - - default: - //irqdbf("registering irq %d (s3c irq)\n", irqno); - set_irq_chip(irqno, &s3c_irq_chip); - set_irq_handler(irqno, handle_edge_irq); - set_irq_flags(irqno, IRQF_VALID); - } - } - - /* setup the cascade irq handlers */ - - set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7); - set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8); - - set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); - set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); - set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); - set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); - - /* external interrupts */ - - for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { - irqdbf("registering irq %d (ext int)\n", irqno); - set_irq_chip(irqno, &s3c_irq_eint0t4); - set_irq_handler(irqno, handle_edge_irq); - set_irq_flags(irqno, IRQF_VALID); - } - - for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) { - irqdbf("registering irq %d (extended s3c irq)\n", irqno); - set_irq_chip(irqno, &s3c_irqext_chip); - set_irq_handler(irqno, handle_edge_irq); - set_irq_flags(irqno, IRQF_VALID); - } - - /* register the uart interrupts */ - - irqdbf("s3c2410: registering external interrupts\n"); - - for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) { - irqdbf("registering irq %d (s3c uart0 irq)\n", irqno); - set_irq_chip(irqno, &s3c_irq_uart0); - set_irq_handler(irqno, handle_level_irq); - set_irq_flags(irqno, IRQF_VALID); - } - - for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) { - irqdbf("registering irq %d (s3c uart1 irq)\n", irqno); - set_irq_chip(irqno, &s3c_irq_uart1); - set_irq_handler(irqno, handle_level_irq); - set_irq_flags(irqno, IRQF_VALID); - } - - for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) { - irqdbf("registering irq %d (s3c uart2 irq)\n", irqno); - set_irq_chip(irqno, &s3c_irq_uart2); - set_irq_handler(irqno, handle_level_irq); - set_irq_flags(irqno, IRQF_VALID); - } - - for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) { - irqdbf("registering irq %d (s3c adc irq)\n", irqno); - set_irq_chip(irqno, &s3c_irq_adc); - set_irq_handler(irqno, handle_edge_irq); - set_irq_flags(irqno, IRQF_VALID); - } - - irqdbf("s3c2410: registered interrupt handlers\n"); -} +arch_initcall(s3c2410_irq_init); diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c2410/mach-amlm5900.c index 817e2c68441..72f2cc4fcd0 100644 --- a/arch/arm/mach-s3c2410/mach-amlm5900.c +++ b/arch/arm/mach-s3c2410/mach-amlm5900.c @@ -1,4 +1,4 @@ -/*********************************************************************** +/* linux/arch/arm/mach-s3c2410/mach-amlm5900.c * * linux/arch/arm/mach-s3c2410/mach-amlm5900.c * @@ -35,7 +35,7 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/proc_fs.h> - +#include <linux/serial_core.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -52,8 +52,8 @@ #include <asm/arch/regs-lcd.h> #include <asm/arch/regs-gpio.h> -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> #ifdef CONFIG_MTD_PARTITIONS @@ -113,12 +113,6 @@ static struct platform_device amlm5900_device_nor = { #endif static struct map_desc amlm5900_iodesc[] __initdata = { - { - .virtual = (u32)S3C24XX_VA_SPI, - .pfn = __phys_to_pfn(S3C2410_PA_SPI), - .length = SZ_1M, - .type = MT_DEVICE - } }; #define UCON S3C2410_UCON_DEFAULT diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index b8b76757ec5..7b81296427e 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c @@ -50,9 +50,9 @@ #include <linux/serial_8250.h> -#include "clock.h" -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> #include "usb-simtec.h" #define COPYRIGHT ", (c) 2004-2005 Simtec Electronics" diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c index 15b625eae49..01c60d0923c 100644 --- a/arch/arm/mach-s3c2410/mach-h1940.c +++ b/arch/arm/mach-s3c2410/mach-h1940.c @@ -25,23 +25,24 @@ #include <asm/mach/irq.h> #include <asm/hardware.h> -#include <asm/hardware/iomd.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/mach-types.h> - #include <asm/arch/regs-serial.h> #include <asm/arch/regs-lcd.h> +#include <asm/arch/regs-gpio.h> +#include <asm/arch/regs-clock.h> #include <asm/arch/h1940.h> #include <asm/arch/h1940-latch.h> #include <asm/arch/fb.h> +#include <asm/arch/udc.h> -#include "clock.h" -#include "devs.h" -#include "cpu.h" -#include "pm.h" +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/pm.h> static struct map_desc h1940_iodesc[] __initdata = { [0] = { @@ -102,6 +103,32 @@ void h1940_latch_control(unsigned int clear, unsigned int set) EXPORT_SYMBOL_GPL(h1940_latch_control); +static void h1940_udc_pullup(enum s3c2410_udc_cmd_e cmd) +{ + printk(KERN_DEBUG "udc: pullup(%d)\n",cmd); + + switch (cmd) + { + case S3C2410_UDC_P_ENABLE : + h1940_latch_control(0, H1940_LATCH_USB_DP); + break; + case S3C2410_UDC_P_DISABLE : + h1940_latch_control(H1940_LATCH_USB_DP, 0); + break; + case S3C2410_UDC_P_RESET : + break; + default: + break; + } +} + +static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = { + .udc_command = h1940_udc_pullup, + .vbus_pin = S3C2410_GPG5, + .vbus_pin_inverted = 1, +}; + + /** * Set lcd on or off @@ -146,12 +173,19 @@ static struct s3c2410fb_mach_info h1940_lcdcfg __initdata = { .bpp= {16,16,16}, }; +static struct platform_device s3c_device_leds = { + .name = "h1940-leds", + .id = -1, +}; + static struct platform_device *h1940_devices[] __initdata = { &s3c_device_usb, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c, &s3c_device_iis, + &s3c_device_usbgadget, + &s3c_device_leds, }; static struct s3c24xx_board h1940_board __initdata = { @@ -179,7 +213,23 @@ static void __init h1940_init_irq(void) static void __init h1940_init(void) { + u32 tmp; + s3c24xx_fb_set_platdata(&h1940_lcdcfg); + s3c24xx_udc_set_platdata(&h1940_udc_cfg); + + /* Turn off suspend on both USB ports, and switch the + * selectable USB port to USB device mode. */ + + s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST | + S3C2410_MISCCR_USBSUSPND0 | + S3C2410_MISCCR_USBSUSPND1, 0x0); + + tmp = ( + 0x78 << S3C2410_PLLCON_MDIVSHIFT) + | (0x02 << S3C2410_PLLCON_PDIVSHIFT) + | (0x03 << S3C2410_PLLCON_SDIVSHIFT); + writel(tmp, S3C2410_UPLLCON); } MACHINE_START(H1940, "IPAQ-H1940") @@ -189,6 +239,6 @@ MACHINE_START(H1940, "IPAQ-H1940") .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = h1940_map_io, .init_irq = h1940_init_irq, - .init_machine = h1940_init, + .init_machine = h1940_init, .timer = &s3c24xx_timer, MACHINE_END diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c index 0411e9adb54..261aa4cc077 100644 --- a/arch/arm/mach-s3c2410/mach-n30.c +++ b/arch/arm/mach-s3c2410/mach-n30.c @@ -29,7 +29,6 @@ #include <asm/mach/irq.h> #include <asm/hardware.h> -#include <asm/hardware/iomd.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/mach-types.h> @@ -38,10 +37,10 @@ #include <asm/arch/regs-gpio.h> #include <asm/arch/iic.h> -#include "s3c2410.h" -#include "clock.h" -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/s3c2410.h> +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> static struct map_desc n30_iodesc[] __initdata = { /* nothing here yet */ diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c index 2c738b375e4..c78ab75b44f 100644 --- a/arch/arm/mach-s3c2410/mach-otom.c +++ b/arch/arm/mach-s3c2410/mach-otom.c @@ -32,10 +32,10 @@ #include <asm/arch/regs-serial.h> #include <asm/arch/regs-gpio.h> -#include "s3c2410.h" -#include "clock.h" -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/s3c2410.h> +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> static struct map_desc otom11_iodesc[] __initdata = { /* Device area */ diff --git a/arch/arm/mach-s3c2410/mach-qt2410.c b/arch/arm/mach-s3c2410/mach-qt2410.c new file mode 100644 index 00000000000..c6a41593de2 --- /dev/null +++ b/arch/arm/mach-s3c2410/mach-qt2410.c @@ -0,0 +1,448 @@ +/* linux/arch/arm/mach-s3c2410/mach-qt2410.c + * + * Copyright (C) 2006 by OpenMoko, Inc. + * Author: Harald Welte <laforge@openmoko.org> + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/serial_core.h> +#include <linux/mmc/protocol.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi_bitbang.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <asm/arch/regs-gpio.h> +#include <asm/arch/leds-gpio.h> +#include <asm/arch/regs-serial.h> +#include <asm/arch/fb.h> +#include <asm/arch/nand.h> +#include <asm/arch/udc.h> +#include <asm/arch/spi.h> +#include <asm/arch/spi-gpio.h> + +#include <asm/plat-s3c24xx/common-smdk.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/pm.h> + +static struct map_desc qt2410_iodesc[] __initdata = { + { 0xe0000000, __phys_to_pfn(S3C2410_CS3+0x01000000), SZ_1M, MT_DEVICE } +}; + +#define UCON S3C2410_UCON_DEFAULT +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg smdk2410_uartcfgs[] = { + [0] = { + .hwport = 0, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, + }, + [1] = { + .hwport = 1, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, + }, + [2] = { + .hwport = 2, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, + } +}; + +/* LCD driver info */ + +/* Configuration for 640x480 SHARP LQ080V3DG01 */ +static struct s3c2410fb_mach_info qt2410_biglcd_cfg __initdata = { + .regs = { + + .lcdcon1 = S3C2410_LCDCON1_TFT16BPP | + S3C2410_LCDCON1_TFT | + S3C2410_LCDCON1_CLKVAL(0x01), /* HCLK/4 */ + + .lcdcon2 = S3C2410_LCDCON2_VBPD(18) | /* 19 */ + S3C2410_LCDCON2_LINEVAL(479) | + S3C2410_LCDCON2_VFPD(10) | /* 11 */ + S3C2410_LCDCON2_VSPW(14), /* 15 */ + + .lcdcon3 = S3C2410_LCDCON3_HBPD(43) | /* 44 */ + S3C2410_LCDCON3_HOZVAL(639) | /* 640 */ + S3C2410_LCDCON3_HFPD(115), /* 116 */ + + .lcdcon4 = S3C2410_LCDCON4_MVAL(0) | + S3C2410_LCDCON4_HSPW(95), /* 96 */ + + .lcdcon5 = S3C2410_LCDCON5_FRM565 | + S3C2410_LCDCON5_INVVLINE | + S3C2410_LCDCON5_INVVFRAME | + S3C2410_LCDCON5_PWREN | + S3C2410_LCDCON5_HWSWP, + }, + + .lpcsel = ((0xCE6) & ~7) | 1<<4, + + .width = 640, + .height = 480, + + .xres = { + .min = 640, + .max = 640, + .defval = 640, + }, + + .yres = { + .min = 480, + .max = 480, + .defval = 480, + }, + + .bpp = { + .min = 16, + .max = 16, + .defval = 16, + }, +}; + +/* Configuration for 480x640 toppoly TD028TTEC1 */ +static struct s3c2410fb_mach_info qt2410_prodlcd_cfg __initdata = { + .regs = { + + .lcdcon1 = S3C2410_LCDCON1_TFT16BPP | + S3C2410_LCDCON1_TFT | + S3C2410_LCDCON1_CLKVAL(0x01), /* HCLK/4 */ + + .lcdcon2 = S3C2410_LCDCON2_VBPD(1) | /* 2 */ + S3C2410_LCDCON2_LINEVAL(639) |/* 640 */ + S3C2410_LCDCON2_VFPD(3) | /* 4 */ + S3C2410_LCDCON2_VSPW(1), /* 2 */ + + .lcdcon3 = S3C2410_LCDCON3_HBPD(7) | /* 8 */ + S3C2410_LCDCON3_HOZVAL(479) | /* 479 */ + S3C2410_LCDCON3_HFPD(23), /* 24 */ + + .lcdcon4 = S3C2410_LCDCON4_MVAL(0) | + S3C2410_LCDCON4_HSPW(7), /* 8 */ + + .lcdcon5 = S3C2410_LCDCON5_FRM565 | + S3C2410_LCDCON5_INVVLINE | + S3C2410_LCDCON5_INVVFRAME | + S3C2410_LCDCON5_PWREN | + S3C2410_LCDCON5_HWSWP, + }, + + .lpcsel = ((0xCE6) & ~7) | 1<<4, + + .width = 480, + .height = 640, + + .xres = { + .min = 480, + .max = 480, + .defval = 480, + }, + + .yres = { + .min = 640, + .max = 640, + .defval = 640, + }, + + .bpp = { + .min = 16, + .max = 16, + .defval = 16, + }, +}; + +/* Config for 240x320 LCD */ +static struct s3c2410fb_mach_info qt2410_lcd_cfg __initdata = { + .regs = { + + .lcdcon1 = S3C2410_LCDCON1_TFT16BPP | + S3C2410_LCDCON1_TFT | + S3C2410_LCDCON1_CLKVAL(0x04), + + .lcdcon2 = S3C2410_LCDCON2_VBPD(1) | + S3C2410_LCDCON2_LINEVAL(319) | + S3C2410_LCDCON2_VFPD(6) | + S3C2410_LCDCON2_VSPW(3), + + .lcdcon3 = S3C2410_LCDCON3_HBPD(12) | + S3C2410_LCDCON3_HOZVAL(239) | + S3C2410_LCDCON3_HFPD(7), + + .lcdcon4 = S3C2410_LCDCON4_MVAL(0) | + S3C2410_LCDCON4_HSPW(3), + + .lcdcon5 = S3C2410_LCDCON5_FRM565 | + S3C2410_LCDCON5_INVVLINE | + S3C2410_LCDCON5_INVVFRAME | + S3C2410_LCDCON5_PWREN | + S3C2410_LCDCON5_HWSWP, + }, + + .lpcsel = ((0xCE6) & ~7) | 1<<4, + + .width = 240, + .height = 320, + + .xres = { + .min = 240, + .max = 240, + .defval = 240, + }, + + .yres = { + .min = 320, + .max = 320, + .defval = 320, + }, + + .bpp = { + .min = 16, + .max = 16, + .defval = 16, + }, +}; + +/* CS8900 */ + +static struct resource qt2410_cs89x0_resources[] = { + [0] = { + .start = 0x19000000, + .end = 0x19000000 + 16, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_EINT9, + .end = IRQ_EINT9, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device qt2410_cs89x0 = { + .name = "cirrus-cs89x0", + .num_resources = ARRAY_SIZE(qt2410_cs89x0_resources), + .resource = qt2410_cs89x0_resources, +}; + +/* LED */ + +static struct s3c24xx_led_platdata qt2410_pdata_led = { + .gpio = S3C2410_GPB0, + .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, + .name = "led", + .def_trigger = "timer", +}; + +static struct platform_device qt2410_led = { + .name = "s3c24xx_led", + .id = 0, + .dev = { + .platform_data = &qt2410_pdata_led, + }, +}; + +/* SPI */ + +static void spi_gpio_cs(struct s3c2410_spigpio_info *spi, int cs) +{ + switch (cs) { + case BITBANG_CS_ACTIVE: + s3c2410_gpio_setpin(S3C2410_GPB5, 0); + break; + case BITBANG_CS_INACTIVE: + s3c2410_gpio_setpin(S3C2410_GPB5, 1); + break; + } +} + +static struct s3c2410_spigpio_info spi_gpio_cfg = { + .pin_clk = S3C2410_GPG7, + .pin_mosi = S3C2410_GPG6, + .pin_miso = S3C2410_GPG5, + .chip_select = &spi_gpio_cs, +}; + + +static struct platform_device qt2410_spi = { + .name = "s3c24xx-spi-gpio", + .id = 1, + .dev = { + .platform_data = &spi_gpio_cfg, + }, +}; + +/* Board devices */ + +static struct platform_device *qt2410_devices[] __initdata = { + &s3c_device_usb, + &s3c_device_lcd, + &s3c_device_wdt, + &s3c_device_i2c, + &s3c_device_iis, + &s3c_device_sdi, + &s3c_device_usbgadget, + &qt2410_spi, + &qt2410_cs89x0, + &qt2410_led, +}; + +static struct s3c24xx_board qt2410_board __initdata = { + .devices = qt2410_devices, + .devices_count = ARRAY_SIZE(qt2410_devices) +}; + +static struct mtd_partition qt2410_nand_part[] = { + [0] = { + .name = "U-Boot", + .size = 0x30000, + .offset = 0, + }, + [1] = { + .name = "U-Boot environment", + .offset = 0x30000, + .size = 0x4000, + }, + [2] = { + .name = "kernel", + .offset = 0x34000, + .size = SZ_2M, + }, + [3] = { + .name = "initrd", + .offset = 0x234000, + .size = SZ_4M, + }, + [4] = { + .name = "jffs2", + .offset = 0x634000, + .size = 0x39cc000, + }, +}; + +static struct s3c2410_nand_set qt2410_nand_sets[] = { + [0] = { + .name = "NAND", + .nr_chips = 1, + .nr_partitions = ARRAY_SIZE(qt2410_nand_part), + .partitions = qt2410_nand_part, + }, +}; + +/* choose a set of timings which should suit most 512Mbit + * chips and beyond. + */ + +static struct s3c2410_platform_nand qt2410_nand_info = { + .tacls = 20, + .twrph0 = 60, + .twrph1 = 20, + .nr_sets = ARRAY_SIZE(qt2410_nand_sets), + .sets = qt2410_nand_sets, +}; + +/* UDC */ + +static struct s3c2410_udc_mach_info qt2410_udc_cfg = { +}; + +static char tft_type = 's'; + +static int __init qt2410_tft_setup(char *str) +{ + tft_type = str[0]; + return 1; +} + +__setup("tft=", qt2410_tft_setup); + +static void __init qt2410_map_io(void) +{ + s3c24xx_init_io(qt2410_iodesc, ARRAY_SIZE(qt2410_iodesc)); + s3c24xx_init_clocks(12*1000*1000); + s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs)); + s3c24xx_set_board(&qt2410_board); +} + +static void __init qt2410_machine_init(void) +{ + s3c_device_nand.dev.platform_data = &qt2410_nand_info; + + switch (tft_type) { + case 'p': /* production */ + s3c24xx_fb_set_platdata(&qt2410_prodlcd_cfg); + break; + case 'b': /* big */ + s3c24xx_fb_set_platdata(&qt2410_biglcd_cfg); + break; + case 's': /* small */ + default: + s3c24xx_fb_set_platdata(&qt2410_lcd_cfg); + break; + } + + s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPIO_OUTPUT); + s3c2410_gpio_setpin(S3C2410_GPB0, 1); + + s3c24xx_udc_set_platdata(&qt2410_udc_cfg); + + s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPIO_OUTPUT); + + s3c2410_pm_init(); +} + +MACHINE_START(QT2410, "QT2410") + .phys_io = S3C2410_PA_UART, + .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, + .boot_params = S3C2410_SDRAM_PA + 0x100, + .map_io = qt2410_map_io, + .init_irq = s3c24xx_init_irq, + .init_machine = qt2410_machine_init, + .timer = &s3c24xx_timer, +MACHINE_END + + diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c index 01c0c986d82..57b8a80f33d 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2410.c +++ b/arch/arm/mach-s3c2410/mach-smdk2410.c @@ -1,4 +1,4 @@ -/*********************************************************************** +/* linux/arch/arm/mach-s3c2410/mach-smdk2410.c * * linux/arch/arm/mach-s3c2410/mach-smdk2410.c * @@ -49,10 +49,10 @@ #include <asm/arch/regs-serial.h> -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> -#include "common-smdk.h" +#include <asm/plat-s3c24xx/common-smdk.h> static struct map_desc smdk2410_iodesc[] __initdata = { /* nothing here yet */ diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c index a382fc09511..c947c75bcbf 100644 --- a/arch/arm/mach-s3c2410/mach-vr1000.c +++ b/arch/arm/mach-s3c2410/mach-vr1000.c @@ -43,9 +43,9 @@ #include <asm/arch/regs-gpio.h> #include <asm/arch/leds-gpio.h> -#include "clock.h" -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> #include "usb-simtec.h" /* macros for virtual address mods for the io space entries */ diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c index ebf294dd31d..3b3a7db4e0d 100644 --- a/arch/arm/mach-s3c2410/pm.c +++ b/arch/arm/mach-s3c2410/pm.c @@ -1,11 +1,9 @@ /* linux/arch/arm/mach-s3c2410/pm.c * - * Copyright (c) 2004,2006 Simtec Electronics + * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * - * S3C24XX Power Manager (Suspend-To-RAM) support - * - * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information + * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) support * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,640 +18,139 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Parts based on arch/arm/mach-pxa/pm.c - * - * Thanks to Dimitry Andric for debugging */ #include <linux/init.h> #include <linux/suspend.h> #include <linux/errno.h> #include <linux/time.h> -#include <linux/interrupt.h> -#include <linux/crc32.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/serial_core.h> +#include <linux/sysdev.h> -#include <asm/cacheflush.h> #include <asm/hardware.h> #include <asm/io.h> -#include <asm/arch/regs-serial.h> -#include <asm/arch/regs-clock.h> -#include <asm/arch/regs-gpio.h> -#include <asm/arch/regs-mem.h> -#include <asm/arch/regs-irq.h> - -#include <asm/mach/time.h> - -#include "pm.h" - -/* for external use */ - -unsigned long s3c_pm_flags; - -#define PFX "s3c24xx-pm: " - -static struct sleep_save core_save[] = { - SAVE_ITEM(S3C2410_LOCKTIME), - SAVE_ITEM(S3C2410_CLKCON), - - /* we restore the timings here, with the proviso that the board - * brings the system up in an slower, or equal frequency setting - * to the original system. - * - * if we cannot guarantee this, then things are going to go very - * wrong here, as we modify the refresh and both pll settings. - */ - - SAVE_ITEM(S3C2410_BWSCON), - SAVE_ITEM(S3C2410_BANKCON0), - SAVE_ITEM(S3C2410_BANKCON1), - SAVE_ITEM(S3C2410_BANKCON2), - SAVE_ITEM(S3C2410_BANKCON3), - SAVE_ITEM(S3C2410_BANKCON4), - SAVE_ITEM(S3C2410_BANKCON5), - - SAVE_ITEM(S3C2410_CLKDIVN), - SAVE_ITEM(S3C2410_MPLLCON), - SAVE_ITEM(S3C2410_UPLLCON), - SAVE_ITEM(S3C2410_CLKSLOW), - SAVE_ITEM(S3C2410_REFRESH), -}; - -static struct sleep_save gpio_save[] = { - SAVE_ITEM(S3C2410_GPACON), - SAVE_ITEM(S3C2410_GPADAT), - - SAVE_ITEM(S3C2410_GPBCON), - SAVE_ITEM(S3C2410_GPBDAT), - SAVE_ITEM(S3C2410_GPBUP), - - SAVE_ITEM(S3C2410_GPCCON), - SAVE_ITEM(S3C2410_GPCDAT), - SAVE_ITEM(S3C2410_GPCUP), - - SAVE_ITEM(S3C2410_GPDCON), - SAVE_ITEM(S3C2410_GPDDAT), - SAVE_ITEM(S3C2410_GPDUP), - - SAVE_ITEM(S3C2410_GPECON), - SAVE_ITEM(S3C2410_GPEDAT), - SAVE_ITEM(S3C2410_GPEUP), - - SAVE_ITEM(S3C2410_GPFCON), - SAVE_ITEM(S3C2410_GPFDAT), - SAVE_ITEM(S3C2410_GPFUP), +#include <asm/mach-types.h> - SAVE_ITEM(S3C2410_GPGCON), - SAVE_ITEM(S3C2410_GPGDAT), - SAVE_ITEM(S3C2410_GPGUP), - - SAVE_ITEM(S3C2410_GPHCON), - SAVE_ITEM(S3C2410_GPHDAT), - SAVE_ITEM(S3C2410_GPHUP), +#include <asm/arch/regs-gpio.h> +#include <asm/arch/h1940.h> - SAVE_ITEM(S3C2410_DCLKCON), -}; +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/pm.h> #ifdef CONFIG_S3C2410_PM_DEBUG - -#define SAVE_UART(va) \ - SAVE_ITEM((va) + S3C2410_ULCON), \ - SAVE_ITEM((va) + S3C2410_UCON), \ - SAVE_ITEM((va) + S3C2410_UFCON), \ - SAVE_ITEM((va) + S3C2410_UMCON), \ - SAVE_ITEM((va) + S3C2410_UBRDIV) - -static struct sleep_save uart_save[] = { - SAVE_UART(S3C24XX_VA_UART0), - SAVE_UART(S3C24XX_VA_UART1), -#ifndef CONFIG_CPU_S3C2400 - SAVE_UART(S3C24XX_VA_UART2), -#endif -}; - -/* debug - * - * we send the debug to printascii() to allow it to be seen if the - * system never wakes up from the sleep -*/ - -extern void printascii(const char *); - -void pm_dbg(const char *fmt, ...) -{ - va_list va; - char buff[256]; - - va_start(va, fmt); - vsprintf(buff, fmt, va); - va_end(va); - - printascii(buff); -} - -static void s3c2410_pm_debug_init(void) -{ - unsigned long tmp = __raw_readl(S3C2410_CLKCON); - - /* re-start uart clocks */ - tmp |= S3C2410_CLKCON_UART0; - tmp |= S3C2410_CLKCON_UART1; - tmp |= S3C2410_CLKCON_UART2; - - __raw_writel(tmp, S3C2410_CLKCON); - udelay(10); -} - +extern void pm_dbg(const char *fmt, ...); #define DBG(fmt...) pm_dbg(fmt) #else #define DBG(fmt...) printk(KERN_DEBUG fmt) - -#define s3c2410_pm_debug_init() do { } while(0) - -static struct sleep_save uart_save[] = {}; #endif -#if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0 - -/* suspend checking code... - * - * this next area does a set of crc checks over all the installed - * memory, so the system can verify if the resume was ok. - * - * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC, - * increasing it will mean that the area corrupted will be less easy to spot, - * and reducing the size will cause the CRC save area to grow -*/ - -#define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024) - -static u32 crc_size; /* size needed for the crc block */ -static u32 *crcs; /* allocated over suspend/resume */ - -typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg); - -/* s3c2410_pm_run_res - * - * go thorugh the given resource list, and look for system ram -*/ - -static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg) -{ - while (ptr != NULL) { - if (ptr->child != NULL) - s3c2410_pm_run_res(ptr->child, fn, arg); - - if ((ptr->flags & IORESOURCE_MEM) && - strcmp(ptr->name, "System RAM") == 0) { - DBG("Found system RAM at %08lx..%08lx\n", - ptr->start, ptr->end); - arg = (fn)(ptr, arg); - } - - ptr = ptr->sibling; - } -} - -static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg) -{ - s3c2410_pm_run_res(&iomem_resource, fn, arg); -} - -static u32 *s3c2410_pm_countram(struct resource *res, u32 *val) -{ - u32 size = (u32)(res->end - res->start)+1; - - size += CHECK_CHUNKSIZE-1; - size /= CHECK_CHUNKSIZE; - - DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size); - - *val += size * sizeof(u32); - return val; -} - -/* s3c2410_pm_prepare_check - * - * prepare the necessary information for creating the CRCs. This - * must be done before the final save, as it will require memory - * allocating, and thus touching bits of the kernel we do not - * know about. -*/ - -static void s3c2410_pm_check_prepare(void) +static void s3c2410_pm_prepare(void) { - crc_size = 0; + /* ensure at least GSTATUS3 has the resume address */ - s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size); + __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3); - DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size); + DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3)); + DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4)); - crcs = kmalloc(crc_size+4, GFP_KERNEL); - if (crcs == NULL) - printk(KERN_ERR "Cannot allocated CRC save area\n"); -} + if (machine_is_h1940()) { + void *base = phys_to_virt(H1940_SUSPEND_CHECK); + unsigned long ptr; + unsigned long calc = 0; -static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val) -{ - unsigned long addr, left; + /* generate check for the bootloader to check on resume */ - for (addr = res->start; addr < res->end; - addr += CHECK_CHUNKSIZE) { - left = res->end - addr; + for (ptr = 0; ptr < 0x40000; ptr += 0x400) + calc += __raw_readl(base+ptr); - if (left > CHECK_CHUNKSIZE) - left = CHECK_CHUNKSIZE; - - *val = crc32_le(~0, phys_to_virt(addr), left); - val++; + __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM)); } - return val; -} - -/* s3c2410_pm_check_store - * - * compute the CRC values for the memory blocks before the final - * sleep. -*/ - -static void s3c2410_pm_check_store(void) -{ - if (crcs != NULL) - s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs); -} - -/* in_region - * - * return TRUE if the area defined by ptr..ptr+size contatins the - * what..what+whatsz -*/ - -static inline int in_region(void *ptr, int size, void *what, size_t whatsz) -{ - if ((what+whatsz) < ptr) - return 0; - - if (what > (ptr+size)) - return 0; - - return 1; -} - -static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val) -{ - void *save_at = phys_to_virt(s3c2410_sleep_save_phys); - unsigned long addr; - unsigned long left; - void *ptr; - u32 calc; - - for (addr = res->start; addr < res->end; - addr += CHECK_CHUNKSIZE) { - left = res->end - addr; + /* the RX3715 uses similar code and the same H1940 and the + * same offsets for resume and checksum pointers */ - if (left > CHECK_CHUNKSIZE) - left = CHECK_CHUNKSIZE; + if (machine_is_rx3715()) { + void *base = phys_to_virt(H1940_SUSPEND_CHECK); + unsigned long ptr; + unsigned long calc = 0; - ptr = phys_to_virt(addr); + /* generate check for the bootloader to check on resume */ - if (in_region(ptr, left, crcs, crc_size)) { - DBG("skipping %08lx, has crc block in\n", addr); - goto skip_check; - } + for (ptr = 0; ptr < 0x40000; ptr += 0x4) + calc += __raw_readl(base+ptr); - if (in_region(ptr, left, save_at, 32*4 )) { - DBG("skipping %08lx, has save block in\n", addr); - goto skip_check; - } - - /* calculate and check the checksum */ - - calc = crc32_le(~0, ptr, left); - if (calc != *val) { - printk(KERN_ERR PFX "Restore CRC error at " - "%08lx (%08x vs %08x)\n", addr, calc, *val); - - DBG("Restore CRC error at %08lx (%08x vs %08x)\n", - addr, calc, *val); - } - - skip_check: - val++; + __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM)); } - return val; -} + if ( machine_is_aml_m5900() ) + s3c2410_gpio_setpin(S3C2410_GPF2, 1); -/* s3c2410_pm_check_restore - * - * check the CRCs after the restore event and free the memory used - * to hold them -*/ - -static void s3c2410_pm_check_restore(void) -{ - if (crcs != NULL) { - s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs); - kfree(crcs); - crcs = NULL; - } } -#else - -#define s3c2410_pm_check_prepare() do { } while(0) -#define s3c2410_pm_check_restore() do { } while(0) -#define s3c2410_pm_check_store() do { } while(0) -#endif - -/* helper functions to save and restore register state */ - -void s3c2410_pm_do_save(struct sleep_save *ptr, int count) +static int s3c2410_pm_resume(struct sys_device *dev) { - for (; count > 0; count--, ptr++) { - ptr->val = __raw_readl(ptr->reg); - DBG("saved %p value %08lx\n", ptr->reg, ptr->val); - } -} + unsigned long tmp; -/* s3c2410_pm_do_restore - * - * restore the system from the given list of saved registers - * - * Note, we do not use DBG() in here, as the system may not have - * restore the UARTs state yet -*/ + /* unset the return-from-sleep flag, to ensure reset */ -void s3c2410_pm_do_restore(struct sleep_save *ptr, int count) -{ - for (; count > 0; count--, ptr++) { - printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n", - ptr->reg, ptr->val, __raw_readl(ptr->reg)); - - __raw_writel(ptr->val, ptr->reg); - } -} + tmp = __raw_readl(S3C2410_GSTATUS2); + tmp &= S3C2410_GSTATUS2_OFFRESET; + __raw_writel(tmp, S3C2410_GSTATUS2); -/* s3c2410_pm_do_restore_core - * - * similar to s3c2410_pm_do_restore_core - * - * WARNING: Do not put any debug in here that may effect memory or use - * peripherals, as things may be changing! -*/ + if ( machine_is_aml_m5900() ) + s3c2410_gpio_setpin(S3C2410_GPF2, 0); -static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count) -{ - for (; count > 0; count--, ptr++) { - __raw_writel(ptr->val, ptr->reg); - } + return 0; } -/* s3c2410_pm_show_resume_irqs - * - * print any IRQs asserted at resume time (ie, we woke from) -*/ - -static void s3c2410_pm_show_resume_irqs(int start, unsigned long which, - unsigned long mask) +static int s3c2410_pm_add(struct sys_device *dev) { - int i; + pm_cpu_prep = s3c2410_pm_prepare; + pm_cpu_sleep = s3c2410_cpu_suspend; - which &= ~mask; - - for (i = 0; i <= 31; i++) { - if ((which) & (1L<<i)) { - DBG("IRQ %d asserted at resume\n", start+i); - } - } + return 0; } -/* s3c2410_pm_check_resume_pin - * - * check to see if the pin is configured correctly for sleep mode, and - * make any necessary adjustments if it is not -*/ - -static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs) -{ - unsigned long irqstate; - unsigned long pinstate; - int irq = s3c2410_gpio_getirq(pin); - - if (irqoffs < 4) - irqstate = s3c_irqwake_intmask & (1L<<irqoffs); - else - irqstate = s3c_irqwake_eintmask & (1L<<irqoffs); - - pinstate = s3c2410_gpio_getcfg(pin); - - if (!irqstate) { - if (pinstate == S3C2410_GPIO_IRQ) - DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin); - } else { - if (pinstate == S3C2410_GPIO_IRQ) { - DBG("Disabling IRQ %d (pin %d)\n", irq, pin); - s3c2410_gpio_cfgpin(pin, S3C2410_GPIO_INPUT); - } - } -} +#if defined(CONFIG_CPU_S3C2410) +static struct sysdev_driver s3c2410_pm_driver = { + .add = s3c2410_pm_add, + .resume = s3c2410_pm_resume, +}; -/* s3c2410_pm_configure_extint - * - * configure all external interrupt pins -*/ +/* register ourselves */ -static void s3c2410_pm_configure_extint(void) +static int __init s3c2410_pm_drvinit(void) { - int pin; - - /* for each of the external interrupts (EINT0..EINT15) we - * need to check wether it is an external interrupt source, - * and then configure it as an input if it is not - */ - - for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) { - s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0); - } - - for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) { - s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8); - } + return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_pm_driver); } -void (*pm_cpu_prep)(void); -void (*pm_cpu_sleep)(void); - -#define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) - -/* s3c2410_pm_enter - * - * central control for sleep/resume process -*/ - -static int s3c2410_pm_enter(suspend_state_t state) -{ - unsigned long regs_save[16]; - - /* ensure the debug is initialised (if enabled) */ - - s3c2410_pm_debug_init(); - - DBG("s3c2410_pm_enter(%d)\n", state); - - if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) { - printk(KERN_ERR PFX "error: no cpu sleep functions set\n"); - return -EINVAL; - } - - if (state != PM_SUSPEND_MEM) { - printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n"); - return -EINVAL; - } - - /* check if we have anything to wake-up with... bad things seem - * to happen if you suspend with no wakeup (system will often - * require a full power-cycle) - */ - - if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && - !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { - printk(KERN_ERR PFX "No sources enabled for wake-up!\n"); - printk(KERN_ERR PFX "Aborting sleep\n"); - return -EINVAL; - } - - /* prepare check area if configured */ - - s3c2410_pm_check_prepare(); - - /* store the physical address of the register recovery block */ - - s3c2410_sleep_save_phys = virt_to_phys(regs_save); - - DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys); - - /* save all necessary core registers not covered by the drivers */ - - s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save)); - s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save)); - s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); - - /* set the irq configuration for wake */ - - s3c2410_pm_configure_extint(); - - DBG("sleep: irq wakeup masks: %08lx,%08lx\n", - s3c_irqwake_intmask, s3c_irqwake_eintmask); - - __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK); - __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); - - /* ack any outstanding external interrupts before we go to sleep */ - - __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND); - __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND); - __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND); - - /* call cpu specific preperation */ - - pm_cpu_prep(); - - /* flush cache back to ram */ - - flush_cache_all(); - - s3c2410_pm_check_store(); - - /* send the cpu to sleep... */ - - __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */ - - /* s3c2410_cpu_save will also act as our return point from when - * we resume as it saves its own register state, so use the return - * code to differentiate return from save and return from sleep */ - - if (s3c2410_cpu_save(regs_save) == 0) { - flush_cache_all(); - pm_cpu_sleep(); - } - - /* restore the cpu state */ - - cpu_init(); - - /* restore the system state */ - - s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); - s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save)); - s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); - - s3c2410_pm_debug_init(); - - /* check what irq (if any) restored the system */ - - DBG("post sleep: IRQs 0x%08x, 0x%08x\n", - __raw_readl(S3C2410_SRCPND), - __raw_readl(S3C2410_EINTPEND)); - - s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND), - s3c_irqwake_intmask); - - s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), - s3c_irqwake_eintmask); - - DBG("post sleep, preparing to return\n"); - - s3c2410_pm_check_restore(); - - /* ok, let's return from sleep */ +arch_initcall(s3c2410_pm_drvinit); +#endif - DBG("S3C2410 PM Resume (post-restore)\n"); - return 0; -} +#if defined(CONFIG_CPU_S3C2440) +static struct sysdev_driver s3c2440_pm_driver = { + .add = s3c2410_pm_add, + .resume = s3c2410_pm_resume, +}; -/* - * Called after processes are frozen, but before we shut down devices. - */ -static int s3c2410_pm_prepare(suspend_state_t state) +static int __init s3c2440_pm_drvinit(void) { - return 0; + return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_pm_driver); } -/* - * Called after devices are re-setup, but before processes are thawed. - */ -static int s3c2410_pm_finish(suspend_state_t state) -{ - return 0; -} +arch_initcall(s3c2440_pm_drvinit); +#endif -/* - * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. - */ -static struct pm_ops s3c2410_pm_ops = { - .pm_disk_mode = PM_DISK_FIRMWARE, - .prepare = s3c2410_pm_prepare, - .enter = s3c2410_pm_enter, - .finish = s3c2410_pm_finish, +#if defined(CONFIG_CPU_S3C2442) +static struct sysdev_driver s3c2442_pm_driver = { + .add = s3c2410_pm_add, + .resume = s3c2410_pm_resume, }; -/* s3c2410_pm_init - * - * Attach the power management functions. This should be called - * from the board specific initialisation if the board supports - * it. -*/ - -int __init s3c2410_pm_init(void) +static int __init s3c2442_pm_drvinit(void) { - printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n"); - - pm_set_ops(&s3c2410_pm_ops); - return 0; + return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_pm_driver); } + +arch_initcall(s3c2442_pm_drvinit); +#endif diff --git a/arch/arm/mach-s3c2410/s3c2410-clock.c b/arch/arm/mach-s3c2410/s3c2410-clock.c deleted file mode 100644 index 992cc6af230..00000000000 --- a/arch/arm/mach-s3c2410/s3c2410-clock.c +++ /dev/null @@ -1,276 +0,0 @@ -/* linux/arch/arm/mach-s3c2410/s3c2410-clock.c - * - * Copyright (c) 2006 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * S3C2410,S3C2440,S3C2442 Clock control support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/sysdev.h> -#include <linux/clk.h> -#include <linux/mutex.h> -#include <linux/delay.h> -#include <linux/serial_core.h> - -#include <asm/mach/map.h> - -#include <asm/hardware.h> -#include <asm/io.h> - -#include <asm/arch/regs-serial.h> -#include <asm/arch/regs-clock.h> -#include <asm/arch/regs-gpio.h> - -#include "s3c2410.h" -#include "clock.h" -#include "cpu.h" - -int s3c2410_clkcon_enable(struct clk *clk, int enable) -{ - unsigned int clocks = clk->ctrlbit; - unsigned long clkcon; - - clkcon = __raw_readl(S3C2410_CLKCON); - - if (enable) - clkcon |= clocks; - else - clkcon &= ~clocks; - - /* ensure none of the special function bits set */ - clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER); - - __raw_writel(clkcon, S3C2410_CLKCON); - - return 0; -} - -static int s3c2410_upll_enable(struct clk *clk, int enable) -{ - unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); - unsigned long orig = clkslow; - - if (enable) - clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF; - else - clkslow |= S3C2410_CLKSLOW_UCLK_OFF; - - __raw_writel(clkslow, S3C2410_CLKSLOW); - - /* if we started the UPLL, then allow to settle */ - - if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF)) - udelay(200); - - return 0; -} - -/* standard clock definitions */ - -static struct clk init_clocks_disable[] = { - { - .name = "nand", - .id = -1, - .parent = &clk_h, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_NAND, - }, { - .name = "sdi", - .id = -1, - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_SDI, - }, { - .name = "adc", - .id = -1, - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_ADC, - }, { - .name = "i2c", - .id = -1, - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_IIC, - }, { - .name = "iis", - .id = -1, - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_IIS, - }, { - .name = "spi", - .id = -1, - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_SPI, - } -}; - -static struct clk init_clocks[] = { - { - .name = "lcd", - .id = -1, - .parent = &clk_h, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_LCDC, - }, { - .name = "gpio", - .id = -1, - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_GPIO, - }, { - .name = "usb-host", - .id = -1, - .parent = &clk_h, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_USBH, - }, { - .name = "usb-device", - .id = -1, - .parent = &clk_h, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_USBD, - }, { - .name = "timers", - .id = -1, - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_PWMT, - }, { - .name = "uart", - .id = 0, - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_UART0, - }, { - .name = "uart", - .id = 1, - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_UART1, - }, { - .name = "uart", - .id = 2, - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_UART2, - }, { - .name = "rtc", - .id = -1, - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_RTC, - }, { - .name = "watchdog", - .id = -1, - .parent = &clk_p, - .ctrlbit = 0, - }, { - .name = "usb-bus-host", - .id = -1, - .parent = &clk_usb_bus, - }, { - .name = "usb-bus-gadget", - .id = -1, - .parent = &clk_usb_bus, - }, -}; - -/* s3c2410_baseclk_add() - * - * Add all the clocks used by the s3c2410 or compatible CPUs - * such as the S3C2440 and S3C2442. - * - * We cannot use a system device as we are needed before any - * of the init-calls that initialise the devices are actually - * done. -*/ - -int __init s3c2410_baseclk_add(void) -{ - unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); - unsigned long clkcon = __raw_readl(S3C2410_CLKCON); - struct clk *clkp; - struct clk *xtal; - int ret; - int ptr; - - clk_upll.enable = s3c2410_upll_enable; - - if (s3c24xx_register_clock(&clk_usb_bus) < 0) - printk(KERN_ERR "failed to register usb bus clock\n"); - - /* register clocks from clock array */ - - clkp = init_clocks; - for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { - /* ensure that we note the clock state */ - - clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0; - - ret = s3c24xx_register_clock(clkp); - if (ret < 0) { - printk(KERN_ERR "Failed to register clock %s (%d)\n", - clkp->name, ret); - } - } - - /* We must be careful disabling the clocks we are not intending to - * be using at boot time, as subsytems such as the LCD which do - * their own DMA requests to the bus can cause the system to lockup - * if they where in the middle of requesting bus access. - * - * Disabling the LCD clock if the LCD is active is very dangerous, - * and therefore the bootloader should be careful to not enable - * the LCD clock if it is not needed. - */ - - /* install (and disable) the clocks we do not need immediately */ - - clkp = init_clocks_disable; - for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { - - ret = s3c24xx_register_clock(clkp); - if (ret < 0) { - printk(KERN_ERR "Failed to register clock %s (%d)\n", - clkp->name, ret); - } - - s3c2410_clkcon_enable(clkp, 0); - } - - /* show the clock-slow value */ - - xtal = clk_get(NULL, "xtal"); - - printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n", - print_mhz(clk_get_rate(xtal) / - ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))), - (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast", - (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on", - (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on"); - - return 0; -} diff --git a/arch/arm/mach-s3c2410/s3c2410-dma.c b/arch/arm/mach-s3c2410/s3c2410-dma.c deleted file mode 100644 index e67ba3911f1..00000000000 --- a/arch/arm/mach-s3c2410/s3c2410-dma.c +++ /dev/null @@ -1,161 +0,0 @@ -/* linux/arch/arm/mach-s3c2410/s3c2410-dma.c - * - * Copyright (c) 2006 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * S3C2410 DMA selection - * - * http://armlinux.simtec.co.uk/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/sysdev.h> -#include <linux/serial_core.h> - -#include <asm/dma.h> -#include <asm/arch/dma.h> -#include "dma.h" - -#include "cpu.h" - -#include <asm/arch/regs-serial.h> -#include <asm/arch/regs-gpio.h> -#include <asm/arch/regs-ac97.h> -#include <asm/arch/regs-mem.h> -#include <asm/arch/regs-lcd.h> -#include <asm/arch/regs-sdi.h> -#include <asm/arch/regs-iis.h> -#include <asm/arch/regs-spi.h> - -static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = { - [DMACH_XD0] = { - .name = "xdreq0", - .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID, - }, - [DMACH_XD1] = { - .name = "xdreq1", - .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID, - }, - [DMACH_SDI] = { - .name = "sdi", - .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID, - .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID, - .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID, - .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, - .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, - }, - [DMACH_SPI0] = { - .name = "spi0", - .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID, - .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT, - .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT, - }, - [DMACH_SPI1] = { - .name = "spi1", - .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID, - .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT, - .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT, - }, - [DMACH_UART0] = { - .name = "uart0", - .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID, - .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, - .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, - }, - [DMACH_UART1] = { - .name = "uart1", - .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID, - .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, - .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, - }, - [DMACH_UART2] = { - .name = "uart2", - .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID, - .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, - .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, - }, - [DMACH_TIMER] = { - .name = "timer", - .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID, - .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID, - .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID, - }, - [DMACH_I2S_IN] = { - .name = "i2s-sdi", - .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID, - .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID, - .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, - }, - [DMACH_I2S_OUT] = { - .name = "i2s-sdo", - .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID, - .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, - }, - [DMACH_USB_EP1] = { - .name = "usb-ep1", - .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID, - }, - [DMACH_USB_EP2] = { - .name = "usb-ep2", - .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID, - }, - [DMACH_USB_EP3] = { - .name = "usb-ep3", - .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID, - }, - [DMACH_USB_EP4] = { - .name = "usb-ep4", - .channels[3] =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID, - }, -}; - -static void s3c2410_dma_select(struct s3c2410_dma_chan *chan, - struct s3c24xx_dma_map *map) -{ - chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID; -} - -static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = { - .select = s3c2410_dma_select, - .dcon_mask = 7 << 24, - .map = s3c2410_dma_mappings, - .map_size = ARRAY_SIZE(s3c2410_dma_mappings), -}; - -static int s3c2410_dma_add(struct sys_device *sysdev) -{ - return s3c24xx_dma_init_map(&s3c2410_dma_sel); -} - -#if defined(CONFIG_CPU_S3C2410) -static struct sysdev_driver s3c2410_dma_driver = { - .add = s3c2410_dma_add, -}; - -static int __init s3c2410_dma_init(void) -{ - return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver); -} - -arch_initcall(s3c2410_dma_init); -#endif - -#if defined(CONFIG_CPU_S3C2442) -/* S3C2442 DMA contains the same selection table as the S3C2410 */ -static struct sysdev_driver s3c2442_dma_driver = { - .add = s3c2410_dma_add, -}; - -static int __init s3c2442_dma_init(void) -{ - return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_dma_driver); -} - -arch_initcall(s3c2442_dma_init); -#endif - diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c deleted file mode 100644 index ec3a276cc3c..00000000000 --- a/arch/arm/mach-s3c2410/s3c2410-gpio.c +++ /dev/null @@ -1,71 +0,0 @@ -/* linux/arch/arm/mach-s3c2410/s3c2410-gpio.c - * - * Copyright (c) 2004-2006 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * S3C2410 GPIO support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> - -#include <asm/hardware.h> -#include <asm/irq.h> -#include <asm/io.h> - -#include <asm/arch/regs-gpio.h> - -int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, - unsigned int config) -{ - void __iomem *reg = S3C24XX_EINFLT0; - unsigned long flags; - unsigned long val; - - if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15) - return -1; - - config &= 0xff; - - pin -= S3C2410_GPG8; - reg += pin & ~3; - - local_irq_save(flags); - - /* update filter width and clock source */ - - val = __raw_readl(reg); - val &= ~(0xff << ((pin & 3) * 8)); - val |= config << ((pin & 3) * 8); - __raw_writel(val, reg); - - /* update filter enable */ - - val = __raw_readl(S3C24XX_EXTINT2); - val &= ~(1 << ((pin * 4) + 3)); - val |= on << ((pin * 4) + 3); - __raw_writel(val, S3C24XX_EXTINT2); - - local_irq_restore(flags); - - return 0; -} - -EXPORT_SYMBOL(s3c2410_gpio_irqfilter); diff --git a/arch/arm/mach-s3c2410/s3c2410-irq.c b/arch/arm/mach-s3c2410/s3c2410-irq.c deleted file mode 100644 index c796c9c76e7..00000000000 --- a/arch/arm/mach-s3c2410/s3c2410-irq.c +++ /dev/null @@ -1,48 +0,0 @@ -/* linux/arch/arm/mach-s3c2410/s3c2410-irq.c - * - * Copyright (c) 2006 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * -*/ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/ptrace.h> -#include <linux/sysdev.h> - -#include "cpu.h" -#include "pm.h" - -static int s3c2410_irq_add(struct sys_device *sysdev) -{ - return 0; -} - -static struct sysdev_driver s3c2410_irq_driver = { - .add = s3c2410_irq_add, - .suspend = s3c24xx_irq_suspend, - .resume = s3c24xx_irq_resume, -}; - -static int s3c2410_irq_init(void) -{ - return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver); -} - -arch_initcall(s3c2410_irq_init); diff --git a/arch/arm/mach-s3c2410/s3c2410-pm.c b/arch/arm/mach-s3c2410/s3c2410-pm.c deleted file mode 100644 index 8bb6e5e21f5..00000000000 --- a/arch/arm/mach-s3c2410/s3c2410-pm.c +++ /dev/null @@ -1,156 +0,0 @@ -/* linux/arch/arm/mach-s3c2410/s3c2410-pm.c - * - * Copyright (c) 2006 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include <linux/init.h> -#include <linux/suspend.h> -#include <linux/errno.h> -#include <linux/time.h> -#include <linux/sysdev.h> - -#include <asm/hardware.h> -#include <asm/io.h> - -#include <asm/mach-types.h> - -#include <asm/arch/regs-gpio.h> -#include <asm/arch/h1940.h> - -#include "cpu.h" -#include "pm.h" - -#ifdef CONFIG_S3C2410_PM_DEBUG -extern void pm_dbg(const char *fmt, ...); -#define DBG(fmt...) pm_dbg(fmt) -#else -#define DBG(fmt...) printk(KERN_DEBUG fmt) -#endif - -static void s3c2410_pm_prepare(void) -{ - /* ensure at least GSTATUS3 has the resume address */ - - __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3); - - DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3)); - DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4)); - - if (machine_is_h1940()) { - void *base = phys_to_virt(H1940_SUSPEND_CHECK); - unsigned long ptr; - unsigned long calc = 0; - - /* generate check for the bootloader to check on resume */ - - for (ptr = 0; ptr < 0x40000; ptr += 0x400) - calc += __raw_readl(base+ptr); - - __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM)); - } - - /* the RX3715 uses similar code and the same H1940 and the - * same offsets for resume and checksum pointers */ - - if (machine_is_rx3715()) { - void *base = phys_to_virt(H1940_SUSPEND_CHECK); - unsigned long ptr; - unsigned long calc = 0; - - /* generate check for the bootloader to check on resume */ - - for (ptr = 0; ptr < 0x40000; ptr += 0x4) - calc += __raw_readl(base+ptr); - - __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM)); - } - - if ( machine_is_aml_m5900() ) - s3c2410_gpio_setpin(S3C2410_GPF2, 1); - -} - -static int s3c2410_pm_resume(struct sys_device *dev) -{ - unsigned long tmp; - - /* unset the return-from-sleep flag, to ensure reset */ - - tmp = __raw_readl(S3C2410_GSTATUS2); - tmp &= S3C2410_GSTATUS2_OFFRESET; - __raw_writel(tmp, S3C2410_GSTATUS2); - - if ( machine_is_aml_m5900() ) - s3c2410_gpio_setpin(S3C2410_GPF2, 0); - - return 0; -} - -static int s3c2410_pm_add(struct sys_device *dev) -{ - pm_cpu_prep = s3c2410_pm_prepare; - pm_cpu_sleep = s3c2410_cpu_suspend; - - return 0; -} - -#if defined(CONFIG_CPU_S3C2410) -static struct sysdev_driver s3c2410_pm_driver = { - .add = s3c2410_pm_add, - .resume = s3c2410_pm_resume, -}; - -/* register ourselves */ - -static int __init s3c2410_pm_drvinit(void) -{ - return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_pm_driver); -} - -arch_initcall(s3c2410_pm_drvinit); -#endif - -#if defined(CONFIG_CPU_S3C2440) -static struct sysdev_driver s3c2440_pm_driver = { - .add = s3c2410_pm_add, - .resume = s3c2410_pm_resume, -}; - -static int __init s3c2440_pm_drvinit(void) -{ - return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_pm_driver); -} - -arch_initcall(s3c2440_pm_drvinit); -#endif - -#if defined(CONFIG_CPU_S3C2442) -static struct sysdev_driver s3c2442_pm_driver = { - .add = s3c2410_pm_add, - .resume = s3c2410_pm_resume, -}; - -static int __init s3c2442_pm_drvinit(void) -{ - return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_pm_driver); -} - -arch_initcall(s3c2442_pm_drvinit); -#endif diff --git a/arch/arm/mach-s3c2410/s3c2410-sleep.S b/arch/arm/mach-s3c2410/s3c2410-sleep.S deleted file mode 100644 index 9179a102458..00000000000 --- a/arch/arm/mach-s3c2410/s3c2410-sleep.S +++ /dev/null @@ -1,68 +0,0 @@ -/* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S - * - * Copyright (c) 2004 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * S3C2410 Power Manager (Suspend-To-RAM) support - * - * Based on PXA/SA1100 sleep code by: - * Nicolas Pitre, (c) 2002 Monta Vista Software Inc - * Cliff Brake, (c) 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include <linux/linkage.h> -#include <asm/assembler.h> -#include <asm/hardware.h> -#include <asm/arch/map.h> - -#include <asm/arch/regs-gpio.h> -#include <asm/arch/regs-clock.h> -#include <asm/arch/regs-mem.h> -#include <asm/arch/regs-serial.h> - - /* s3c2410_cpu_suspend - * - * put the cpu into sleep mode - */ - -ENTRY(s3c2410_cpu_suspend) - @@ prepare cpu to sleep - - ldr r4, =S3C2410_REFRESH - ldr r5, =S3C24XX_MISCCR - ldr r6, =S3C2410_CLKCON - ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB) - ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB) - ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB) - - orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command - orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals - orr r9, r9, #S3C2410_CLKCON_POWER @ power down command - - teq pc, #0 @ first as a trial-run to load cache - bl s3c2410_do_sleep - teq r0, r0 @ now do it for real - b s3c2410_do_sleep @ - - @@ align next bit of code to cache line - .align 8 -s3c2410_do_sleep: - streq r7, [ r4 ] @ SDRAM sleep command - streq r8, [ r5 ] @ SDRAM power-down config - streq r9, [ r6 ] @ CPU sleep -1: beq 1b - mov pc, r14 diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c index 4cdc0d70c19..1a86a980375 100644 --- a/arch/arm/mach-s3c2410/s3c2410.c +++ b/arch/arm/mach-s3c2410/s3c2410.c @@ -31,10 +31,10 @@ #include <asm/arch/regs-clock.h> #include <asm/arch/regs-serial.h> -#include "s3c2410.h" -#include "cpu.h" -#include "devs.h" -#include "clock.h" +#include <asm/plat-s3c24xx/s3c2410.h> +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/clock.h> /* Initial IO mappings */ @@ -110,7 +110,7 @@ static struct sys_device s3c2410_sysdev = { /* need to register class before we actually register the device, and * we also need to ensure that it has been initialised before any of the - * drivers even try to use it (even if not on an s3c2440 based system) + * drivers even try to use it (even if not on an s3c2410 based system) * as a driver which may support both 2410 and 2440 may try and use it. */ diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S index 2018c2e1dcc..637aaba6539 100644 --- a/arch/arm/mach-s3c2410/sleep.S +++ b/arch/arm/mach-s3c2410/sleep.S @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/sleep.S +/* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S * * Copyright (c) 2004 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -34,126 +34,35 @@ #include <asm/arch/regs-mem.h> #include <asm/arch/regs-serial.h> -/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not - * reset the UART configuration, only enable if you really need this! -*/ -//#define CONFIG_DEBUG_RESUME - - .text - - /* s3c2410_cpu_save - * - * save enough of the CPU state to allow us to re-start - * pm.c code. as we store items like the sp/lr, we will - * end up returning from this function when the cpu resumes - * so the return value is set to mark this. - * - * This arangement means we avoid having to flush the cache - * from this code. - * - * entry: - * r0 = pointer to save block - * - * exit: - * r0 = 0 => we stored everything - * 1 => resumed from sleep - */ - -ENTRY(s3c2410_cpu_save) - stmfd sp!, { r4 - r12, lr } - - @@ store co-processor registers - - mrc p15, 0, r4, c15, c1, 0 @ CP access register - mrc p15, 0, r5, c13, c0, 0 @ PID - mrc p15, 0, r6, c3, c0, 0 @ Domain ID - mrc p15, 0, r7, c2, c0, 0 @ translation table base address - mrc p15, 0, r8, c1, c0, 0 @ control register - - stmia r0, { r4 - r13 } - - mov r0, #0 - ldmfd sp, { r4 - r12, pc } - - @@ return to the caller, after having the MMU - @@ turned on, this restores the last bits from the - @@ stack -resume_with_mmu: - mov r0, #1 - ldmfd sp!, { r4 - r12, pc } - - .ltorg - - @@ the next bits sit in the .data segment, even though they - @@ happen to be code... the s3c2410_sleep_save_phys needs to be - @@ accessed by the resume code before it can restore the MMU. - @@ This means that the variable has to be close enough for the - @@ code to read it... since the .text segment needs to be RO, - @@ the data segment can be the only place to put this code. - - .data - - .global s3c2410_sleep_save_phys -s3c2410_sleep_save_phys: - .word 0 - - /* s3c2410_cpu_resume + /* s3c2410_cpu_suspend * - * resume code entry for bootloader to call - * - * we must put this code here in the data segment as we have no - * other way of restoring the stack pointer after sleep, and we - * must not write to the code segment (code is read-only) + * put the cpu into sleep mode */ -ENTRY(s3c2410_cpu_resume) - mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE - msr cpsr_c, r0 - - @@ load UART to allow us to print the two characters for - @@ resume debug - - mov r2, #S3C24XX_PA_UART & 0xff000000 - orr r2, r2, #S3C24XX_PA_UART & 0xff000 - -#if 0 - /* SMDK2440 LED set */ - mov r14, #S3C24XX_PA_GPIO - ldr r12, [ r14, #0x54 ] - bic r12, r12, #3<<4 - orr r12, r12, #1<<7 - str r12, [ r14, #0x54 ] -#endif - -#ifdef CONFIG_DEBUG_RESUME - mov r3, #'L' - strb r3, [ r2, #S3C2410_UTXH ] -1001: - ldrb r14, [ r3, #S3C2410_UTRSTAT ] - tst r14, #S3C2410_UTRSTAT_TXE - beq 1001b -#endif /* CONFIG_DEBUG_RESUME */ - - mov r1, #0 - mcr p15, 0, r1, c8, c7, 0 @@ invalidate I & D TLBs - mcr p15, 0, r1, c7, c7, 0 @@ invalidate I & D caches - - ldr r0, s3c2410_sleep_save_phys @ address of restore block - ldmia r0, { r4 - r13 } - - mcr p15, 0, r4, c15, c1, 0 @ CP access register - mcr p15, 0, r5, c13, c0, 0 @ PID - mcr p15, 0, r6, c3, c0, 0 @ Domain ID - mcr p15, 0, r7, c2, c0, 0 @ translation table base - -#ifdef CONFIG_DEBUG_RESUME - mov r3, #'R' - strb r3, [ r2, #S3C2410_UTXH ] -#endif - - ldr r2, =resume_with_mmu - mcr p15, 0, r8, c1, c0, 0 @ turn on MMU, etc - nop @ second-to-last before mmu - mov pc, r2 @ go back to virtual address - - .ltorg +ENTRY(s3c2410_cpu_suspend) + @@ prepare cpu to sleep + + ldr r4, =S3C2410_REFRESH + ldr r5, =S3C24XX_MISCCR + ldr r6, =S3C2410_CLKCON + ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB) + ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB) + ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB) + + orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command + orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals + orr r9, r9, #S3C2410_CLKCON_POWER @ power down command + + teq pc, #0 @ first as a trial-run to load cache + bl s3c2410_do_sleep + teq r0, r0 @ now do it for real + b s3c2410_do_sleep @ + + @@ align next bit of code to cache line + .align 5 +s3c2410_do_sleep: + streq r7, [ r4 ] @ SDRAM sleep command + streq r8, [ r5 ] @ SDRAM power-down config + streq r9, [ r6 ] @ CPU sleep +1: beq 1b + mov pc, r14 diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c index 22b0e1cdd4b..bcd562ac1d3 100644 --- a/arch/arm/mach-s3c2410/usb-simtec.c +++ b/arch/arm/mach-s3c2410/usb-simtec.c @@ -35,7 +35,7 @@ #include <asm/io.h> #include <asm/irq.h> -#include "devs.h" +#include <asm/plat-s3c24xx/devs.h> #include "usb-simtec.h" /* control power and monitor over-current events on various Simtec diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig new file mode 100644 index 00000000000..befc5fdbb61 --- /dev/null +++ b/arch/arm/mach-s3c2412/Kconfig @@ -0,0 +1,58 @@ +# arch/arm/mach-s3c2412/Kconfig +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + +config CPU_S3C2412 + bool + depends on ARCH_S3C2410 + select S3C2412_PM if PM + select S3C2412_DMA if S3C2410_DMA + help + Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line + +config CPU_S3C2412_ONLY + bool + depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \ + !CPU_S3C2440 && !CPU_S3C2442 && !CPU_S3C2443 && CPU_S3C2412 + default y if CPU_S3C2412 + +config S3C2412_DMA + bool + depends on CPU_S3C2412 + help + Internal config node for S3C2412 DMA support + +config S3C2412_PM + bool + help + Internal config node to apply S3C2412 power management + + +menu "S3C2412 Machines" + +config MACH_SMDK2413 + bool "SMDK2413" + select CPU_S3C2412 + select MACH_S3C2413 + select MACH_SMDK + help + Say Y here if you are using an SMDK2413 + +config MACH_S3C2413 + bool + help + Internal node for S3C2413 version of SMDK2413, so that + machine_is_s3c2413() will work when MACH_SMDK2413 is + selected + +config MACH_VSTMS + bool "VMSTMS" + select CPU_S3C2412 + help + Say Y here if you are using an VSTMS board + + +endmenu + diff --git a/arch/arm/mach-s3c2412/Makefile b/arch/arm/mach-s3c2412/Makefile new file mode 100644 index 00000000000..f8e011691b3 --- /dev/null +++ b/arch/arm/mach-s3c2412/Makefile @@ -0,0 +1,21 @@ +# arch/arm/mach-s3c2412/Makefile +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + +obj-y := +obj-m := +obj-n := +obj- := + +obj-$(CONFIG_CPU_S3C2412) += s3c2412.o +obj-$(CONFIG_CPU_S3C2412) += irq.o +obj-$(CONFIG_CPU_S3C2412) += clock.o +obj-$(CONFIG_S3C2412_DMA) += dma.o +obj-$(CONFIG_S3C2412_PM) += pm.o + +# Machine support + +obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o +obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o diff --git a/arch/arm/mach-s3c2410/s3c2412-clock.c b/arch/arm/mach-s3c2412/clock.c index 8f94ad83901..6a8e4448770 100644 --- a/arch/arm/mach-s3c2410/s3c2412-clock.c +++ b/arch/arm/mach-s3c2412/clock.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2412-clock.c +/* linux/arch/arm/mach-s3c2412/clock.c * * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -41,9 +41,9 @@ #include <asm/arch/regs-clock.h> #include <asm/arch/regs-gpio.h> -#include "s3c2412.h" -#include "clock.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/s3c2412.h> +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/cpu.h> /* We currently have to assume that the system is running * from the XTPll input, and that all ***REFCLKs are being diff --git a/arch/arm/mach-s3c2410/s3c2412-dma.c b/arch/arm/mach-s3c2412/dma.c index 138f726ac6b..d0f4695c09d 100644 --- a/arch/arm/mach-s3c2410/s3c2412-dma.c +++ b/arch/arm/mach-s3c2412/dma.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2412-dma.c +/* linux/arch/arm/mach-s3c2412/dma.c * * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -21,8 +21,8 @@ #include <asm/arch/dma.h> #include <asm/io.h> -#include "dma.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/dma.h> +#include <asm/plat-s3c24xx/cpu.h> #include <asm/arch/regs-serial.h> #include <asm/arch/regs-gpio.h> @@ -146,6 +146,7 @@ static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = { static int s3c2412_dma_add(struct sys_device *sysdev) { + s3c2410_dma_init(); return s3c24xx_dma_init_map(&s3c2412_dma_sel); } diff --git a/arch/arm/mach-s3c2410/s3c2412-irq.c b/arch/arm/mach-s3c2412/irq.c index ffcc30b23a8..e89dbdcb1b7 100644 --- a/arch/arm/mach-s3c2410/s3c2412-irq.c +++ b/arch/arm/mach-s3c2412/irq.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2412/s3c2412-irq.c +/* linux/arch/arm/mach-s3c2412/irq.c * * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -35,9 +35,9 @@ #include <asm/arch/regs-irq.h> #include <asm/arch/regs-gpio.h> -#include "cpu.h" -#include "irq.h" -#include "pm.h" +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/irq.h> +#include <asm/plat-s3c24xx/pm.h> /* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by * having them turn up in both the INT* and the EINT* registers. Whilst diff --git a/arch/arm/mach-s3c2410/mach-smdk2413.c b/arch/arm/mach-s3c2412/mach-smdk2413.c index 4f89abd7a6d..b5befce6c8d 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2413.c +++ b/arch/arm/mach-s3c2412/mach-smdk2413.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/mach-smdk2413.c +/* linux/arch/arm/mach-s3c2412/mach-smdk2413.c * * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -37,15 +37,16 @@ #include <asm/arch/regs-lcd.h> #include <asm/arch/idle.h> +#include <asm/arch/udc.h> #include <asm/arch/fb.h> -#include "s3c2410.h" -#include "s3c2412.h" -#include "clock.h" -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/s3c2410.h> +#include <asm/plat-s3c24xx/s3c2412.h> +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> -#include "common-smdk.h" +#include <asm/plat-s3c24xx/common-smdk.h> static struct map_desc smdk2413_iodesc[] __initdata = { }; @@ -75,12 +76,38 @@ static struct s3c2410_uartcfg smdk2413_uartcfgs[] __initdata = { } }; +static void smdk2413_udc_pullup(enum s3c2410_udc_cmd_e cmd) +{ + printk(KERN_DEBUG "udc: pullup(%d)\n",cmd); + + switch (cmd) + { + case S3C2410_UDC_P_ENABLE : + s3c2410_gpio_setpin(S3C2410_GPF2, 1); + break; + case S3C2410_UDC_P_DISABLE : + s3c2410_gpio_setpin(S3C2410_GPF2, 0); + break; + case S3C2410_UDC_P_RESET : + break; + default: + break; + } +} + + +static struct s3c2410_udc_mach_info smdk2413_udc_cfg __initdata = { + .udc_command = smdk2413_udc_pullup, +}; + + static struct platform_device *smdk2413_devices[] __initdata = { &s3c_device_usb, //&s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c, &s3c_device_iis, + &s3c_device_usbgadget, }; static struct s3c24xx_board smdk2413_board __initdata = { @@ -109,7 +136,19 @@ static void __init smdk2413_map_io(void) } static void __init smdk2413_machine_init(void) -{ +{ /* Turn off suspend on both USB ports, and switch the + * selectable USB port to USB device mode. */ + + s3c2410_gpio_setpin(S3C2410_GPF2, 0); + s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPIO_OUTPUT); + + s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST | + S3C2410_MISCCR_USBSUSPND0 | + S3C2410_MISCCR_USBSUSPND1, 0x0); + + + s3c24xx_udc_set_platdata(&smdk2413_udc_cfg); + smdk_machine_init(); } @@ -126,6 +165,19 @@ MACHINE_START(S3C2413, "S3C2413") .timer = &s3c24xx_timer, MACHINE_END +MACHINE_START(SMDK2412, "SMDK2412") + /* Maintainer: Ben Dooks <ben@fluff.org> */ + .phys_io = S3C2410_PA_UART, + .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, + .boot_params = S3C2410_SDRAM_PA + 0x100, + + .fixup = smdk2413_fixup, + .init_irq = s3c24xx_init_irq, + .map_io = smdk2413_map_io, + .init_machine = smdk2413_machine_init, + .timer = &s3c24xx_timer, +MACHINE_END + MACHINE_START(SMDK2413, "SMDK2413") /* Maintainer: Ben Dooks <ben@fluff.org> */ .phys_io = S3C2410_PA_UART, diff --git a/arch/arm/mach-s3c2410/mach-vstms.c b/arch/arm/mach-s3c2412/mach-vstms.c index 0360e1055bc..4231b549d79 100644 --- a/arch/arm/mach-s3c2410/mach-vstms.c +++ b/arch/arm/mach-s3c2412/mach-vstms.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/mach-vstms.c +/* linux/arch/arm/mach-s3c2412/mach-vstms.c * * (C) 2006 Thomas Gleixner <tglx@linutronix.de> * @@ -28,7 +28,6 @@ #include <asm/mach/irq.h> #include <asm/hardware.h> -#include <asm/hardware/iomd.h> #include <asm/setup.h> #include <asm/io.h> #include <asm/irq.h> @@ -43,11 +42,11 @@ #include <asm/arch/nand.h> -#include "s3c2410.h" -#include "s3c2412.h" -#include "clock.h" -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/s3c2410.h> +#include <asm/plat-s3c24xx/s3c2412.h> +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> static struct map_desc vstms_iodesc[] __initdata = { diff --git a/arch/arm/mach-s3c2410/s3c2412-pm.c b/arch/arm/mach-s3c2412/pm.c index 19b63322d25..8988dac388a 100644 --- a/arch/arm/mach-s3c2410/s3c2412-pm.c +++ b/arch/arm/mach-s3c2412/pm.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2412-pm.c +/* linux/arch/arm/mach-s3c2412/pm.c * * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -28,10 +28,10 @@ #include <asm/arch/regs-gpio.h> #include <asm/arch/regs-dsc.h> -#include "cpu.h" -#include "pm.h" +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/pm.h> -#include "s3c2412.h" +#include <asm/plat-s3c24xx/s3c2412.h> static void s3c2412_cpu_suspend(void) { diff --git a/arch/arm/mach-s3c2410/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c index 2f651a811ec..aafe0bc593f 100644 --- a/arch/arm/mach-s3c2410/s3c2412.c +++ b/arch/arm/mach-s3c2412/s3c2412.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2412.c +/* linux/arch/arm/mach-s3c2412/s3c2412.c * * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -38,11 +38,11 @@ #include <asm/arch/regs-gpioj.h> #include <asm/arch/regs-dsc.h> -#include "s3c2412.h" -#include "cpu.h" -#include "devs.h" -#include "clock.h" -#include "pm.h" +#include <asm/plat-s3c24xx/s3c2412.h> +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/pm.h> #ifndef CONFIG_CPU_S3C2412_ONLY void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO; diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig new file mode 100644 index 00000000000..e3bfda098c0 --- /dev/null +++ b/arch/arm/mach-s3c2440/Kconfig @@ -0,0 +1,71 @@ +# arch/arm/mach-s3c2440/Kconfig +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + +config CPU_S3C2440 + bool + depends on ARCH_S3C2410 + select S3C2410_CLOCK + select S3C2410_PM if PM + select S3C2410_GPIO + select S3C2440_DMA if S3C2410_DMA + select CPU_S3C244X + help + Support for S3C2440 Samsung Mobile CPU based systems. + +config S3C2440_DMA + bool + depends on ARCH_S3C2410 && CPU_S3C24405B + help + Support for S3C2440 specific DMA code5A + + +menu "S3C2440 Machines" + +config MACH_ANUBIS + bool "Simtec Electronics ANUBIS" + select CPU_S3C2440 + select PM_SIMTEC if PM + help + Say Y here if you are using the Simtec Electronics ANUBIS + development system + +config MACH_OSIRIS + bool "Simtec IM2440D20 (OSIRIS) module" + select CPU_S3C2440 + select PM_SIMTEC if PM + help + Say Y here if you are using the Simtec IM2440D20 module, also + known as the Osiris. + +config MACH_RX3715 + bool "HP iPAQ rx3715" + select CPU_S3C2440 + select PM_H1940 if PM + help + Say Y here if you are using the HP iPAQ rx3715. + +config ARCH_S3C2440 + bool "SMDK2440" + select CPU_S3C2440 + select MACH_SMDK + help + Say Y here if you are using the SMDK2440. + +config MACH_NEXCODER_2440 + bool "NexVision NEXCODER 2440 Light Board" + select CPU_S3C2440 + help + Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board + +config SMDK2440_CPU2440 + bool "SMDK2440 with S3C2440 CPU module" + depends on ARCH_S3C2440 + default y if ARCH_S3C2440 + select CPU_S3C2440 + + +endmenu + diff --git a/arch/arm/mach-s3c2440/Makefile b/arch/arm/mach-s3c2440/Makefile new file mode 100644 index 00000000000..c81ed6248dc --- /dev/null +++ b/arch/arm/mach-s3c2440/Makefile @@ -0,0 +1,23 @@ +# arch/arm/mach-s3c2440/Makefile +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + +obj-y := +obj-m := +obj-n := +obj- := + +obj-$(CONFIG_CPU_S3C2440) += s3c2440.o dsc.o +obj-$(CONFIG_CPU_S3C2440) += irq.o +obj-$(CONFIG_CPU_S3C2440) += clock.o +obj-$(CONFIG_S3C2440_DMA) += dma.o + +# Machine support + +obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o +obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o +obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o +obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o +obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o diff --git a/arch/arm/mach-s3c2410/s3c2440-clock.c b/arch/arm/mach-s3c2440/clock.c index ba13c1d079d..79e2ea4adaf 100644 --- a/arch/arm/mach-s3c2410/s3c2440-clock.c +++ b/arch/arm/mach-s3c2440/clock.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2440-clock.c +/* linux/arch/arm/mach-s3c2440/clock.c * * Copyright (c) 2004-2005 Simtec Electronics * http://armlinux.simtec.co.uk/ @@ -41,8 +41,8 @@ #include <asm/arch/regs-clock.h> -#include "clock.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/cpu.h> /* S3C2440 extended clock support */ diff --git a/arch/arm/mach-s3c2410/s3c2440-dma.c b/arch/arm/mach-s3c2440/dma.c index 47b861b9443..cd035a3ec87 100644 --- a/arch/arm/mach-s3c2410/s3c2440-dma.c +++ b/arch/arm/mach-s3c2440/dma.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2440-dma.c +/* linux/arch/arm/mach-s3c2440/dma.c * * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -19,9 +19,9 @@ #include <asm/dma.h> #include <asm/arch/dma.h> -#include "dma.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/dma.h> +#include <asm/plat-s3c24xx/cpu.h> #include <asm/arch/regs-serial.h> #include <asm/arch/regs-gpio.h> @@ -147,8 +147,53 @@ static struct s3c24xx_dma_selection __initdata s3c2440_dma_sel = { .map_size = ARRAY_SIZE(s3c2440_dma_mappings), }; +static struct s3c24xx_dma_order __initdata s3c2440_dma_order = { + .channels = { + [DMACH_SDI] = { + .list = { + [0] = 3 | DMA_CH_VALID, + [1] = 2 | DMA_CH_VALID, + [2] = 1 | DMA_CH_VALID, + [3] = 0 | DMA_CH_VALID, + }, + }, + [DMACH_I2S_IN] = { + .list = { + [0] = 1 | DMA_CH_VALID, + [1] = 2 | DMA_CH_VALID, + }, + }, + [DMACH_I2S_OUT] = { + .list = { + [0] = 2 | DMA_CH_VALID, + [1] = 1 | DMA_CH_VALID, + }, + }, + [DMACH_PCM_IN] = { + .list = { + [0] = 2 | DMA_CH_VALID, + [1] = 1 | DMA_CH_VALID, + }, + }, + [DMACH_PCM_OUT] = { + .list = { + [0] = 1 | DMA_CH_VALID, + [1] = 3 | DMA_CH_VALID, + }, + }, + [DMACH_MIC_IN] = { + .list = { + [0] = 3 | DMA_CH_VALID, + [1] = 2 | DMA_CH_VALID, + }, + }, + }, +}; + static int s3c2440_dma_add(struct sys_device *sysdev) { + s3c2410_dma_init(); + s3c24xx_dma_order_set(&s3c2440_dma_order); return s3c24xx_dma_init_map(&s3c2440_dma_sel); } diff --git a/arch/arm/mach-s3c2410/s3c2440-dsc.c b/arch/arm/mach-s3c2440/dsc.c index c92ea66ba45..2995ff5681b 100644 --- a/arch/arm/mach-s3c2410/s3c2440-dsc.c +++ b/arch/arm/mach-s3c2440/dsc.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2440-dsc.c +/* linux/arch/arm/mach-s3c2440/dsc.c * * Copyright (c) 2004-2005 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -27,8 +27,8 @@ #include <asm/arch/regs-gpio.h> #include <asm/arch/regs-dsc.h> -#include "cpu.h" -#include "s3c2440.h" +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/s3c2440.h> int s3c2440_set_dsc(unsigned int pin, unsigned int value) { diff --git a/arch/arm/mach-s3c2410/s3c2440-irq.c b/arch/arm/mach-s3c2440/irq.c index 1ba19b27ab0..1069d13d8c5 100644 --- a/arch/arm/mach-s3c2410/s3c2440-irq.c +++ b/arch/arm/mach-s3c2440/irq.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2440-irq.c +/* linux/arch/arm/mach-s3c2440/irq.c * * Copyright (c) 2003,2004 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -35,9 +35,9 @@ #include <asm/arch/regs-irq.h> #include <asm/arch/regs-gpio.h> -#include "cpu.h" -#include "pm.h" -#include "irq.h" +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/pm.h> +#include <asm/plat-s3c24xx/irq.h> /* WDT/AC97 */ diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c index 0fad0c2fe07..3f0288eb1ed 100644 --- a/arch/arm/mach-s3c2410/mach-anubis.c +++ b/arch/arm/mach-s3c2440/mach-anubis.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/mach-anubis.c +/* linux/arch/arm/mach-s3c2440/mach-anubis.c * * Copyright (c) 2003-2005 Simtec Electronics * http://armlinux.simtec.co.uk/ @@ -42,9 +42,9 @@ #include <linux/mtd/nand_ecc.h> #include <linux/mtd/partitions.h> -#include "clock.h" -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> #define COPYRIGHT ", (c) 2005 Simtec Electronics" diff --git a/arch/arm/mach-s3c2410/mach-nexcoder.c b/arch/arm/mach-s3c2440/mach-nexcoder.c index d6dfdad8c90..6d551d88330 100644 --- a/arch/arm/mach-s3c2410/mach-nexcoder.c +++ b/arch/arm/mach-s3c2440/mach-nexcoder.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/mach-nexcoder.c +/* linux/arch/arm/mach-s3c2440/mach-nexcoder.c * * Copyright (c) 2004 Nex Vision * Guillaume GOURAT <guillaume.gourat@nexvision.tv> @@ -38,11 +38,11 @@ #include <asm/arch/regs-gpio.h> #include <asm/arch/regs-serial.h> -#include "s3c2410.h" -#include "s3c2440.h" -#include "clock.h" -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/s3c2410.h> +#include <asm/plat-s3c24xx/s3c2440.h> +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> static struct map_desc nexcoder_iodesc[] __initdata = { /* nothing here yet */ diff --git a/arch/arm/mach-s3c2410/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c index 37b40850c9b..2ed8e51f20c 100644 --- a/arch/arm/mach-s3c2410/mach-osiris.c +++ b/arch/arm/mach-s3c2440/mach-osiris.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/mach-osiris.c +/* linux/arch/arm/mach-s3c2440/mach-osiris.c * * Copyright (c) 2005 Simtec Electronics * http://armlinux.simtec.co.uk/ @@ -41,9 +41,9 @@ #include <linux/mtd/nand_ecc.h> #include <linux/mtd/partitions.h> -#include "clock.h" -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> /* onboard perihpheral map */ diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2440/mach-rx3715.c index ecbcdf79d73..480ccde63fb 100644 --- a/arch/arm/mach-s3c2410/mach-rx3715.c +++ b/arch/arm/mach-s3c2440/mach-rx3715.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/mach-rx3715.c +/* linux/arch/arm/mach-s3c2440/mach-rx3715.c * * Copyright (c) 2003,2004 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -33,7 +33,6 @@ #include <asm/mach/irq.h> #include <asm/hardware.h> -#include <asm/hardware/iomd.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/mach-types.h> @@ -46,10 +45,10 @@ #include <asm/arch/nand.h> #include <asm/arch/fb.h> -#include "clock.h" -#include "devs.h" -#include "cpu.h" -#include "pm.h" +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/pm.h> static struct map_desc rx3715_iodesc[] __initdata = { /* dump ISA space somewhere unused */ diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2440/mach-smdk2440.c index 2b61f4ed1da..c17eb5b1f6b 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2440.c +++ b/arch/arm/mach-s3c2440/mach-smdk2440.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/mach-smdk2440.c +/* linux/arch/arm/mach-s3c2440/mach-smdk2440.c * * Copyright (c) 2004,2005 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -27,12 +27,10 @@ #include <asm/mach/irq.h> #include <asm/hardware.h> -#include <asm/hardware/iomd.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/mach-types.h> -//#include <asm/debug-ll.h> #include <asm/arch/regs-serial.h> #include <asm/arch/regs-gpio.h> #include <asm/arch/regs-lcd.h> @@ -40,13 +38,13 @@ #include <asm/arch/idle.h> #include <asm/arch/fb.h> -#include "s3c2410.h" -#include "s3c2440.h" -#include "clock.h" -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/s3c2410.h> +#include <asm/plat-s3c24xx/s3c2440.h> +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> -#include "common-smdk.h" +#include <asm/plat-s3c24xx/common-smdk.h> static struct map_desc smdk2440_iodesc[] __initdata = { /* ISA IO Space map (memory space selected by A24) */ @@ -144,6 +142,7 @@ static struct s3c2410fb_mach_info smdk2440_lcd_cfg __initdata = { #endif .lpcsel = ((0xCE6) & ~7) | 1<<4, + .type = S3C2410_LCDCON1_TFT16BPP, .width = 240, .height = 320, diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c index 344eb27cca4..90e1da61fbc 100644 --- a/arch/arm/mach-s3c2410/s3c2440.c +++ b/arch/arm/mach-s3c2440/s3c2440.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2440.c +/* linux/arch/arm/mach-s3c2440/s3c2440.c * * Copyright (c) 2004-2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -29,9 +29,9 @@ #include <asm/io.h> #include <asm/irq.h> -#include "s3c2440.h" -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/s3c2440.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> static struct sys_device s3c2440_sysdev = { .cls = &s3c2440_sysclass, diff --git a/arch/arm/mach-s3c2442/Kconfig b/arch/arm/mach-s3c2442/Kconfig new file mode 100644 index 00000000000..bf8d87abfab --- /dev/null +++ b/arch/arm/mach-s3c2442/Kconfig @@ -0,0 +1,27 @@ +# arch/arm/mach-s3c2442/Kconfig +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + +config CPU_S3C2442 + bool + depends on ARCH_S3C2420 + select S3C2410_CLOCK + select S3C2410_GPIO + select S3C2410_PM if PM + select CPU_S3C244X + help + Support for S3C2442 Samsung Mobile CPU based systems. + + +menu "S3C2442 Machines" + +config SMDK2440_CPU2442 + bool "SMDM2440 with S3C2442 CPU module" + depends on ARCH_S3C2440 + select CPU_S3C2442 + + +endmenu + diff --git a/arch/arm/mach-s3c2442/Makefile b/arch/arm/mach-s3c2442/Makefile new file mode 100644 index 00000000000..2a909c6c579 --- /dev/null +++ b/arch/arm/mach-s3c2442/Makefile @@ -0,0 +1,16 @@ +# arch/arm/mach-s3c2442/Makefile +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + +obj-y := +obj-m := +obj-n := +obj- := + +obj-$(CONFIG_CPU_S3C2442) += s3c2442.o +obj-$(CONFIG_CPU_S3C2442) += clock.o + +# Machine support + diff --git a/arch/arm/mach-s3c2410/s3c2442-clock.c b/arch/arm/mach-s3c2442/clock.c index 4e292ca7c9b..5b9e830ac4d 100644 --- a/arch/arm/mach-s3c2410/s3c2442-clock.c +++ b/arch/arm/mach-s3c2442/clock.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2442-clock.c +/* linux/arch/arm/mach-s3c2442/clock.c * * Copyright (c) 2004-2005 Simtec Electronics * http://armlinux.simtec.co.uk/ @@ -41,8 +41,8 @@ #include <asm/arch/regs-clock.h> -#include "clock.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/cpu.h> /* S3C2442 extended clock support */ diff --git a/arch/arm/mach-s3c2410/s3c2442.c b/arch/arm/mach-s3c2442/s3c2442.c index 428732ee68c..fbf8264249d 100644 --- a/arch/arm/mach-s3c2410/s3c2442.c +++ b/arch/arm/mach-s3c2442/s3c2442.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2442.c +/* linux/arch/arm/mach-s3c2442/s3c2442.c * * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -19,8 +19,8 @@ #include <linux/serial_core.h> #include <linux/sysdev.h> -#include "s3c2442.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/s3c2442.h> +#include <asm/plat-s3c24xx/cpu.h> static struct sys_device s3c2442_sysdev = { .cls = &s3c2442_sysclass, diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig new file mode 100644 index 00000000000..c649bb2e7ce --- /dev/null +++ b/arch/arm/mach-s3c2443/Kconfig @@ -0,0 +1,29 @@ +# arch/arm/mach-s3c2443/Kconfig +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + +config CPU_S3C2443 + bool + depends on ARCH_S3C2410 + select S3C2443_DMA if S3C2410_DMA + help + Support for the S3C2443 SoC from the S3C24XX line + +config S3C2443_DMA + bool + depends on CPU_S3C2443 + help + Internal config node for S3C2443 DMA support + +menu "S3C2443 Machines" + +config MACH_SMDK2443 + bool "SMDK2443" + select CPU_S3C2443 + select MACH_SMDK + help + Say Y here if you are using an SMDK2443 + +endmenu diff --git a/arch/arm/mach-s3c2443/Makefile b/arch/arm/mach-s3c2443/Makefile new file mode 100644 index 00000000000..d1843c9eb8b --- /dev/null +++ b/arch/arm/mach-s3c2443/Makefile @@ -0,0 +1,20 @@ +# arch/arm/mach-s3c2443/Makefile +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + +obj-y := +obj-m := +obj-n := +obj- := + +obj-$(CONFIG_CPU_S3C2443) += s3c2443.o +obj-$(CONFIG_CPU_S3C2443) += irq.o +obj-$(CONFIG_CPU_S3C2443) += clock.o + +obj-$(CONFIG_S3C2443_DMA) += dma.o + +# Machine support + +obj-$(CONFIG_MACH_SMDK2443) += mach-smdk2443.o diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c new file mode 100644 index 00000000000..dd2272fb113 --- /dev/null +++ b/arch/arm/mach-s3c2443/clock.c @@ -0,0 +1,1007 @@ +/* linux/arch/arm/mach-s3c2443/clock.c + * + * Copyright (c) 2007 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C2443 Clock control support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/sysdev.h> +#include <linux/clk.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/serial_core.h> + +#include <asm/mach/map.h> + +#include <asm/hardware.h> +#include <asm/io.h> + +#include <asm/arch/regs-s3c2443-clock.h> + +#include <asm/plat-s3c24xx/s3c2443.h> +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/cpu.h> + +/* We currently have to assume that the system is running + * from the XTPll input, and that all ***REFCLKs are being + * fed from it, as we cannot read the state of OM[4] from + * software. + * + * It would be possible for each board initialisation to + * set the correct muxing at initialisation +*/ + +static int s3c2443_clkcon_enable_h(struct clk *clk, int enable) +{ + unsigned int clocks = clk->ctrlbit; + unsigned long clkcon; + + clkcon = __raw_readl(S3C2443_HCLKCON); + + if (enable) + clkcon |= clocks; + else + clkcon &= ~clocks; + + __raw_writel(clkcon, S3C2443_HCLKCON); + + return 0; +} + +static int s3c2443_clkcon_enable_p(struct clk *clk, int enable) +{ + unsigned int clocks = clk->ctrlbit; + unsigned long clkcon; + + clkcon = __raw_readl(S3C2443_PCLKCON); + + if (enable) + clkcon |= clocks; + else + clkcon &= ~clocks; + + __raw_writel(clkcon, S3C2443_HCLKCON); + + return 0; +} + +static int s3c2443_clkcon_enable_s(struct clk *clk, int enable) +{ + unsigned int clocks = clk->ctrlbit; + unsigned long clkcon; + + clkcon = __raw_readl(S3C2443_SCLKCON); + + if (enable) + clkcon |= clocks; + else + clkcon &= ~clocks; + + __raw_writel(clkcon, S3C2443_SCLKCON); + + return 0; +} + +static unsigned long s3c2443_roundrate_clksrc(struct clk *clk, + unsigned long rate, + unsigned int max) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + int div; + + if (rate > parent_rate) + return parent_rate; + + /* note, we remove the +/- 1 calculations as they cancel out */ + + div = (rate / parent_rate); + + if (div < 1) + div = 1; + else if (div > max) + div = max; + + return parent_rate / div; +} + +static unsigned long s3c2443_roundrate_clksrc4(struct clk *clk, + unsigned long rate) +{ + return s3c2443_roundrate_clksrc(clk, rate, 4); +} + +static unsigned long s3c2443_roundrate_clksrc16(struct clk *clk, + unsigned long rate) +{ + return s3c2443_roundrate_clksrc(clk, rate, 16); +} + +static unsigned long s3c2443_roundrate_clksrc256(struct clk *clk, + unsigned long rate) +{ + return s3c2443_roundrate_clksrc(clk, rate, 256); +} + +/* clock selections */ + +/* CPU EXTCLK input */ +static struct clk clk_ext = { + .name = "ext", + .id = -1, +}; + +static struct clk clk_mpllref = { + .name = "mpllref", + .parent = &clk_xtal, + .id = -1, +}; + +#if 0 +static struct clk clk_mpll = { + .name = "mpll", + .parent = &clk_mpllref, + .id = -1, +}; +#endif + +static struct clk clk_epllref; + +static struct clk clk_epll = { + .name = "epll", + .parent = &clk_epllref, + .id = -1, +}; + +static struct clk clk_i2s_ext = { + .name = "i2s-ext", + .id = -1, +}; + +static int s3c2443_setparent_epllref(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); + + clksrc &= ~S3C2443_CLKSRC_EPLLREF_MASK; + + if (parent == &clk_xtal) + clksrc |= S3C2443_CLKSRC_EPLLREF_XTAL; + else if (parent == &clk_ext) + clksrc |= S3C2443_CLKSRC_EPLLREF_EXTCLK; + else if (parent != &clk_mpllref) + return -EINVAL; + + __raw_writel(clksrc, S3C2443_CLKSRC); + clk->parent = parent; + + return 0; +} + +static struct clk clk_epllref = { + .name = "epllref", + .id = -1, + .set_parent = s3c2443_setparent_epllref, +}; + +static unsigned long s3c2443_getrate_mdivclk(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2443_CLKDIV0); + + div &= S3C2443_CLKDIV0_EXTDIV_MASK; + div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */ + + return parent_rate / (div + 1); +} + +static struct clk clk_mdivclk = { + .name = "mdivclk", + .parent = &clk_mpllref, + .id = -1, + .get_rate = s3c2443_getrate_mdivclk, +}; + + +static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); + + clksrc &= ~(S3C2443_CLKSRC_MSYSCLK_MPLL | + S3C2443_CLKSRC_EXTCLK_DIV); + + if (parent == &clk_mpll) + clksrc |= S3C2443_CLKSRC_MSYSCLK_MPLL; + else if (parent == &clk_mdivclk) + clksrc |= S3C2443_CLKSRC_EXTCLK_DIV; + else if (parent != &clk_mpllref) + return -EINVAL; + + __raw_writel(clksrc, S3C2443_CLKSRC); + clk->parent = parent; + + return 0; +} + +static struct clk clk_msysclk = { + .name = "msysclk", + .parent = &clk_xtal, + .id = -1, + .set_parent = s3c2443_setparent_msysclk, +}; + + +/* esysclk + * + * this is sourced from either the EPLL or the EPLLref clock +*/ + +static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); + + if (parent == &clk_epll) + clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL; + else if (parent == &clk_epllref) + clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL; + else + return -EINVAL; + + __raw_writel(clksrc, S3C2443_CLKSRC); + clk->parent = parent; + + return 0; +} + +static struct clk clk_esysclk = { + .name = "esysclk", + .parent = &clk_epll, + .id = -1, + .set_parent = s3c2443_setparent_esysclk, +}; + +/* uartclk + * + * UART baud-rate clock sourced from esysclk via a divisor +*/ + +static unsigned long s3c2443_getrate_uart(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2443_CLKDIV1); + + div &= S3C2443_CLKDIV1_UARTDIV_MASK; + div >>= S3C2443_CLKDIV1_UARTDIV_SHIFT; + + return parent_rate / (div + 1); +} + + +static int s3c2443_setrate_uart(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); + + rate = s3c2443_roundrate_clksrc16(clk, rate); + rate = parent_rate / rate; + + clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK; + clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT; + + __raw_writel(clkdivn, S3C2443_CLKDIV1); + return 0; +} + +static struct clk clk_uart = { + .name = "uartclk", + .id = -1, + .parent = &clk_esysclk, + .get_rate = s3c2443_getrate_uart, + .set_rate = s3c2443_setrate_uart, + .round_rate = s3c2443_roundrate_clksrc16, +}; + +/* hsspi + * + * high-speed spi clock, sourced from esysclk +*/ + +static unsigned long s3c2443_getrate_hsspi(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2443_CLKDIV1); + + div &= S3C2443_CLKDIV1_HSSPIDIV_MASK; + div >>= S3C2443_CLKDIV1_HSSPIDIV_SHIFT; + + return parent_rate / (div + 1); +} + + +static int s3c2443_setrate_hsspi(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); + + rate = s3c2443_roundrate_clksrc4(clk, rate); + rate = parent_rate / rate; + + clkdivn &= ~S3C2443_CLKDIV1_HSSPIDIV_MASK; + clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSSPIDIV_SHIFT; + + __raw_writel(clkdivn, S3C2443_CLKDIV1); + return 0; +} + +static struct clk clk_hsspi = { + .name = "hsspi", + .id = -1, + .parent = &clk_esysclk, + .ctrlbit = S3C2443_SCLKCON_HSSPICLK, + .enable = s3c2443_clkcon_enable_s, + .get_rate = s3c2443_getrate_hsspi, + .set_rate = s3c2443_setrate_hsspi, + .round_rate = s3c2443_roundrate_clksrc4, +}; + +/* usbhost + * + * usb host bus-clock, usually 48MHz to provide USB bus clock timing +*/ + +static unsigned long s3c2443_getrate_usbhost(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2443_CLKDIV1); + + div &= S3C2443_CLKDIV1_USBHOSTDIV_MASK; + div >>= S3C2443_CLKDIV1_USBHOSTDIV_SHIFT; + + return parent_rate / (div + 1); +} + +static int s3c2443_setrate_usbhost(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); + + rate = s3c2443_roundrate_clksrc4(clk, rate); + rate = parent_rate / rate; + + clkdivn &= ~S3C2443_CLKDIV1_USBHOSTDIV_MASK; + clkdivn |= (rate - 1) << S3C2443_CLKDIV1_USBHOSTDIV_SHIFT; + + __raw_writel(clkdivn, S3C2443_CLKDIV1); + return 0; +} + +struct clk clk_usb_bus_host = { + .name = "usb-bus-host-parent", + .id = -1, + .parent = &clk_esysclk, + .ctrlbit = S3C2443_SCLKCON_USBHOST, + .enable = s3c2443_clkcon_enable_s, + .get_rate = s3c2443_getrate_usbhost, + .set_rate = s3c2443_setrate_usbhost, + .round_rate = s3c2443_roundrate_clksrc4, +}; + +/* clk_hsmcc_div + * + * this clock is sourced from epll, and is fed through a divider, + * to a mux controlled by sclkcon where either it or a extclk can + * be fed to the hsmmc block +*/ + +static unsigned long s3c2443_getrate_hsmmc_div(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2443_CLKDIV1); + + div &= S3C2443_CLKDIV1_HSMMCDIV_MASK; + div >>= S3C2443_CLKDIV1_HSMMCDIV_SHIFT; + + return parent_rate / (div + 1); +} + +static int s3c2443_setrate_hsmmc_div(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); + + rate = s3c2443_roundrate_clksrc4(clk, rate); + rate = parent_rate / rate; + + clkdivn &= ~S3C2443_CLKDIV1_HSMMCDIV_MASK; + clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSMMCDIV_SHIFT; + + __raw_writel(clkdivn, S3C2443_CLKDIV1); + return 0; +} + +static struct clk clk_hsmmc_div = { + .name = "hsmmc-div", + .id = -1, + .parent = &clk_esysclk, + .get_rate = s3c2443_getrate_hsmmc_div, + .set_rate = s3c2443_setrate_hsmmc_div, + .round_rate = s3c2443_roundrate_clksrc4, +}; + +static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2443_SCLKCON); + + clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT | + S3C2443_SCLKCON_HSMMCCLK_EPLL); + + if (parent == &clk_epll) + clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL; + else if (parent == &clk_ext) + clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT; + else + return -EINVAL; + + if (clk->usage > 0) { + __raw_writel(clksrc, S3C2443_SCLKCON); + } + + clk->parent = parent; + return 0; +} + +static int s3c2443_enable_hsmmc(struct clk *clk, int enable) +{ + return s3c2443_setparent_hsmmc(clk, clk->parent); +} + +static struct clk clk_hsmmc = { + .name = "hsmmc-if", + .id = -1, + .parent = &clk_hsmmc_div, + .enable = s3c2443_enable_hsmmc, + .set_parent = s3c2443_setparent_hsmmc, +}; + +/* i2s_eplldiv + * + * this clock is the output from the i2s divisor of esysclk +*/ + +static unsigned long s3c2443_getrate_i2s_eplldiv(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2443_CLKDIV1); + + div &= S3C2443_CLKDIV1_I2SDIV_MASK; + div >>= S3C2443_CLKDIV1_I2SDIV_SHIFT; + + return parent_rate / (div + 1); +} + +static int s3c2443_setrate_i2s_eplldiv(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); + + rate = s3c2443_roundrate_clksrc16(clk, rate); + rate = parent_rate / rate; + + clkdivn &= ~S3C2443_CLKDIV1_I2SDIV_MASK; + clkdivn |= (rate - 1) << S3C2443_CLKDIV1_I2SDIV_SHIFT; + + __raw_writel(clkdivn, S3C2443_CLKDIV1); + return 0; +} + +static struct clk clk_i2s_eplldiv = { + .name = "i2s-eplldiv", + .id = -1, + .parent = &clk_esysclk, + .get_rate = s3c2443_getrate_i2s_eplldiv, + .set_rate = s3c2443_setrate_i2s_eplldiv, + .round_rate = s3c2443_roundrate_clksrc16, +}; + +/* i2s-ref + * + * i2s bus reference clock, selectable from external, esysclk or epllref +*/ + +static int s3c2443_setparent_i2s(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); + + clksrc &= ~S3C2443_CLKSRC_I2S_MASK; + + if (parent == &clk_epllref) + clksrc |= S3C2443_CLKSRC_I2S_EPLLREF; + else if (parent == &clk_i2s_ext) + clksrc |= S3C2443_CLKSRC_I2S_EXT; + else if (parent != &clk_i2s_eplldiv) + return -EINVAL; + + clk->parent = parent; + __raw_writel(clksrc, S3C2443_CLKSRC); + + return 0; +} + +static struct clk clk_i2s = { + .name = "i2s-if", + .id = -1, + .parent = &clk_i2s_eplldiv, + .ctrlbit = S3C2443_SCLKCON_I2SCLK, + .enable = s3c2443_clkcon_enable_s, + .set_parent = s3c2443_setparent_i2s, +}; + +/* cam-if + * + * camera interface bus-clock, divided down from esysclk +*/ + +static unsigned long s3c2443_getrate_cam(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2443_CLKDIV1); + + div &= S3C2443_CLKDIV1_CAMDIV_MASK; + div >>= S3C2443_CLKDIV1_CAMDIV_SHIFT; + + return parent_rate / (div + 1); +} + +static int s3c2443_setrate_cam(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdiv1 = __raw_readl(S3C2443_CLKDIV1); + + rate = s3c2443_roundrate_clksrc16(clk, rate); + rate = parent_rate / rate; + + clkdiv1 &= ~S3C2443_CLKDIV1_CAMDIV_MASK; + clkdiv1 |= (rate - 1) << S3C2443_CLKDIV1_CAMDIV_SHIFT; + + __raw_writel(clkdiv1, S3C2443_CLKDIV1); + return 0; +} + +static struct clk clk_cam = { + .name = "camif-upll", /* same as 2440 name */ + .id = -1, + .parent = &clk_esysclk, + .ctrlbit = S3C2443_SCLKCON_CAMCLK, + .enable = s3c2443_clkcon_enable_s, + .get_rate = s3c2443_getrate_cam, + .set_rate = s3c2443_setrate_cam, + .round_rate = s3c2443_roundrate_clksrc16, +}; + +/* display-if + * + * display interface clock, divided from esysclk +*/ + +static unsigned long s3c2443_getrate_display(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2443_CLKDIV1); + + div &= S3C2443_CLKDIV1_DISPDIV_MASK; + div >>= S3C2443_CLKDIV1_DISPDIV_SHIFT; + + return parent_rate / (div + 1); +} + +static int s3c2443_setrate_display(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); + + rate = s3c2443_roundrate_clksrc256(clk, rate); + rate = parent_rate / rate; + + clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK; + clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT; + + __raw_writel(clkdivn, S3C2443_CLKDIV1); + return 0; +} + +static struct clk clk_display = { + .name = "display-if", + .id = -1, + .parent = &clk_esysclk, + .ctrlbit = S3C2443_SCLKCON_DISPCLK, + .enable = s3c2443_clkcon_enable_s, + .get_rate = s3c2443_getrate_display, + .set_rate = s3c2443_setrate_display, + .round_rate = s3c2443_roundrate_clksrc256, +}; + +/* standard clock definitions */ + +static struct clk init_clocks_disable[] = { + { + .name = "nand", + .id = -1, + .parent = &clk_h, + }, { + .name = "sdi", + .id = -1, + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_SDI, + }, { + .name = "adc", + .id = -1, + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_ADC, + }, { + .name = "i2c", + .id = -1, + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_IIC, + }, { + .name = "iis", + .id = -1, + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_IIS, + }, { + .name = "spi", + .id = 0, + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_SPI0, + }, { + .name = "spi", + .id = 1, + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_SPI1, + } +}; + +static struct clk init_clocks[] = { + { + .name = "dma", + .id = 0, + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_DMA0, + }, { + .name = "dma", + .id = 1, + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_DMA1, + }, { + .name = "dma", + .id = 2, + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_DMA2, + }, { + .name = "dma", + .id = 3, + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_DMA3, + }, { + .name = "dma", + .id = 4, + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_DMA4, + }, { + .name = "dma", + .id = 5, + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_DMA5, + }, { + .name = "lcd", + .id = -1, + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_LCDC, + }, { + .name = "gpio", + .id = -1, + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_GPIO, + }, { + .name = "usb-host", + .id = -1, + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_USBH, + }, { + .name = "usb-device", + .id = -1, + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_USBD, + }, { + .name = "timers", + .id = -1, + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_PWMT, + }, { + .name = "uart", + .id = 0, + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_UART0, + }, { + .name = "uart", + .id = 1, + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_UART1, + }, { + .name = "uart", + .id = 2, + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_UART2, + }, { + .name = "uart", + .id = 3, + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_UART3, + }, { + .name = "rtc", + .id = -1, + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_RTC, + }, { + .name = "watchdog", + .id = -1, + .parent = &clk_p, + .ctrlbit = S3C2443_PCLKCON_WDT, + }, { + .name = "usb-bus-host", + .id = -1, + .parent = &clk_usb_bus_host, + } +}; + +/* clocks to add where we need to check their parentage */ + +/* s3c2443_clk_initparents + * + * Initialise the parents for the clocks that we get at start-time +*/ + +static int __init clk_init_set_parent(struct clk *clk, struct clk *parent) +{ + printk(KERN_DEBUG "clock %s: parent %s\n", clk->name, parent->name); + return clk_set_parent(clk, parent); +} + +static void __init s3c2443_clk_initparents(void) +{ + unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); + struct clk *parent; + + switch (clksrc & S3C2443_CLKSRC_EPLLREF_MASK) { + case S3C2443_CLKSRC_EPLLREF_EXTCLK: + parent = &clk_ext; + break; + + case S3C2443_CLKSRC_EPLLREF_XTAL: + default: + parent = &clk_xtal; + break; + + case S3C2443_CLKSRC_EPLLREF_MPLLREF: + case S3C2443_CLKSRC_EPLLREF_MPLLREF2: + parent = &clk_mpllref; + break; + } + + clk_init_set_parent(&clk_epllref, parent); + + switch (clksrc & S3C2443_CLKSRC_I2S_MASK) { + case S3C2443_CLKSRC_I2S_EXT: + parent = &clk_i2s_ext; + break; + + case S3C2443_CLKSRC_I2S_EPLLDIV: + default: + parent = &clk_i2s_eplldiv; + break; + + case S3C2443_CLKSRC_I2S_EPLLREF: + case S3C2443_CLKSRC_I2S_EPLLREF3: + parent = &clk_epllref; + } + + clk_init_set_parent(&clk_i2s, &clk_epllref); + + /* esysclk source */ + + parent = (clksrc & S3C2443_CLKSRC_ESYSCLK_EPLL) ? + &clk_epll : &clk_epllref; + + clk_init_set_parent(&clk_esysclk, parent); + + /* msysclk source */ + + if (clksrc & S3C2443_CLKSRC_MSYSCLK_MPLL) { + parent = &clk_mpll; + } else { + parent = (clksrc & S3C2443_CLKSRC_EXTCLK_DIV) ? + &clk_mdivclk : &clk_mpllref; + } + + clk_init_set_parent(&clk_msysclk, parent); +} + +/* armdiv divisor table */ + +static unsigned int armdiv[16] = { + [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1, + [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2, + [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3, + [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4, + [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6, + [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8, + [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12, + [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16, +}; + +static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0) +{ + clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK; + + return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]; +} + +static inline unsigned long s3c2443_get_prediv(unsigned long clkcon0) +{ + clkcon0 &= S3C2443_CLKDIV0_PREDIV_MASK; + clkcon0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT; + + return clkcon0 + 1; +} + +/* clocks to add straight away */ + +static struct clk *clks[] __initdata = { + &clk_ext, + &clk_epll, + &clk_usb_bus_host, + &clk_usb_bus, + &clk_esysclk, + &clk_epllref, + &clk_mpllref, + &clk_msysclk, + &clk_uart, + &clk_display, + &clk_cam, + &clk_i2s_eplldiv, + &clk_i2s, + &clk_hsspi, + &clk_hsmmc_div, + &clk_hsmmc, +}; + +void __init s3c2443_init_clocks(int xtal) +{ + unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); + unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON); + unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); + unsigned long pll; + unsigned long fclk; + unsigned long hclk; + unsigned long pclk; + struct clk *clkp; + int ret; + int ptr; + + pll = s3c2443_get_mpll(mpllcon, xtal); + + fclk = pll / s3c2443_fclk_div(clkdiv0); + hclk = fclk / s3c2443_get_prediv(clkdiv0); + hclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_HCLK) ? 2 : 1); + pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1); + + s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); + + printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n", + (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on", + print_mhz(pll), print_mhz(fclk), + print_mhz(hclk), print_mhz(pclk)); + + s3c2443_clk_initparents(); + + for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { + clkp = clks[ptr]; + + ret = s3c24xx_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + } + + clk_epll.rate = s3c2443_get_epll(epllcon, xtal); + + clk_usb_bus.parent = &clk_usb_bus_host; + + /* ensure usb bus clock is within correct rate of 48MHz */ + + if (clk_get_rate(&clk_usb_bus_host) != (48 * 1000 * 1000)) { + printk(KERN_INFO "Warning: USB host bus not at 48MHz\n"); + clk_set_rate(&clk_usb_bus_host, 48*1000*1000); + } + + printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", + (epllcon & S3C2443_PLLCON_OFF) ? "off":"on", + print_mhz(clk_get_rate(&clk_epll)), + print_mhz(clk_get_rate(&clk_usb_bus))); + + /* register clocks from clock array */ + + clkp = init_clocks; + for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { + ret = s3c24xx_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + } + + /* We must be careful disabling the clocks we are not intending to + * be using at boot time, as subsytems such as the LCD which do + * their own DMA requests to the bus can cause the system to lockup + * if they where in the middle of requesting bus access. + * + * Disabling the LCD clock if the LCD is active is very dangerous, + * and therefore the bootloader should be careful to not enable + * the LCD clock if it is not needed. + */ + + /* install (and disable) the clocks we do not need immediately */ + + clkp = init_clocks_disable; + for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { + + ret = s3c24xx_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + + (clkp->enable)(clkp, 0); + } +} diff --git a/arch/arm/mach-s3c2443/dma.c b/arch/arm/mach-s3c2443/dma.c new file mode 100644 index 00000000000..f70e8ccffc3 --- /dev/null +++ b/arch/arm/mach-s3c2443/dma.c @@ -0,0 +1,180 @@ +/* linux/arch/arm/mach-s3c2443/dma.c + * + * Copyright (c) 2007 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C2443 DMA selection + * + * http://armlinux.simtec.co.uk/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sysdev.h> +#include <linux/serial_core.h> + +#include <asm/dma.h> +#include <asm/arch/dma.h> +#include <asm/io.h> + +#include <asm/plat-s3c24xx/dma.h> +#include <asm/plat-s3c24xx/cpu.h> + +#include <asm/arch/regs-serial.h> +#include <asm/arch/regs-gpio.h> +#include <asm/arch/regs-ac97.h> +#include <asm/arch/regs-mem.h> +#include <asm/arch/regs-lcd.h> +#include <asm/arch/regs-sdi.h> +#include <asm/arch/regs-iis.h> +#include <asm/arch/regs-spi.h> + +#define MAP(x) { \ + [0] = (x) | DMA_CH_VALID, \ + [1] = (x) | DMA_CH_VALID, \ + [2] = (x) | DMA_CH_VALID, \ + [3] = (x) | DMA_CH_VALID, \ + [4] = (x) | DMA_CH_VALID, \ + [5] = (x) | DMA_CH_VALID, \ + } + +static struct s3c24xx_dma_map __initdata s3c2443_dma_mappings[] = { + [DMACH_XD0] = { + .name = "xdreq0", + .channels = MAP(S3C2443_DMAREQSEL_XDREQ0), + }, + [DMACH_XD1] = { + .name = "xdreq1", + .channels = MAP(S3C2443_DMAREQSEL_XDREQ1), + }, + [DMACH_SDI] = { + .name = "sdi", + .channels = MAP(S3C2443_DMAREQSEL_SDI), + .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, + .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, + }, + [DMACH_SPI0] = { + .name = "spi0", + .channels = MAP(S3C2443_DMAREQSEL_SPI0TX), + .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT, + .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT, + }, + [DMACH_SPI1] = { + .name = "spi1", + .channels = MAP(S3C2443_DMAREQSEL_SPI1TX), + .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT, + .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT, + }, + [DMACH_UART0] = { + .name = "uart0", + .channels = MAP(S3C2443_DMAREQSEL_UART0_0), + .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, + .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, + }, + [DMACH_UART1] = { + .name = "uart1", + .channels = MAP(S3C2443_DMAREQSEL_UART1_0), + .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, + .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, + }, + [DMACH_UART2] = { + .name = "uart2", + .channels = MAP(S3C2443_DMAREQSEL_UART2_0), + .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, + .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, + }, + [DMACH_UART3] = { + .name = "uart3", + .channels = MAP(S3C2443_DMAREQSEL_UART3_0), + .hw_addr.to = S3C2443_PA_UART3 + S3C2410_UTXH, + .hw_addr.from = S3C2443_PA_UART3 + S3C2410_URXH, + }, + [DMACH_UART0_SRC2] = { + .name = "uart0", + .channels = MAP(S3C2443_DMAREQSEL_UART0_1), + .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, + .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, + }, + [DMACH_UART1_SRC2] = { + .name = "uart1", + .channels = MAP(S3C2443_DMAREQSEL_UART1_1), + .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, + .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, + }, + [DMACH_UART2_SRC2] = { + .name = "uart2", + .channels = MAP(S3C2443_DMAREQSEL_UART2_1), + .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, + .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, + }, + [DMACH_UART3_SRC2] = { + .name = "uart3", + .channels = MAP(S3C2443_DMAREQSEL_UART3_1), + .hw_addr.to = S3C2443_PA_UART3 + S3C2410_UTXH, + .hw_addr.from = S3C2443_PA_UART3 + S3C2410_URXH, + }, + [DMACH_TIMER] = { + .name = "timer", + .channels = MAP(S3C2443_DMAREQSEL_TIMER), + }, + [DMACH_I2S_IN] = { + .name = "i2s-sdi", + .channels = MAP(S3C2443_DMAREQSEL_I2SRX), + .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, + }, + [DMACH_I2S_OUT] = { + .name = "i2s-sdo", + .channels = MAP(S3C2443_DMAREQSEL_I2STX), + .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, + }, + [DMACH_PCM_IN] = { + .name = "pcm-in", + .channels = MAP(S3C2443_DMAREQSEL_PCMIN), + .hw_addr.from = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA, + }, + [DMACH_PCM_OUT] = { + .name = "pcm-out", + .channels = MAP(S3C2443_DMAREQSEL_PCMOUT), + .hw_addr.to = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA, + }, + [DMACH_MIC_IN] = { + .name = "mic-in", + .channels = MAP(S3C2443_DMAREQSEL_MICIN), + .hw_addr.from = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA, + }, +}; + +static void s3c2443_dma_select(struct s3c2410_dma_chan *chan, + struct s3c24xx_dma_map *map) +{ + writel(map->channels[0] | S3C2443_DMAREQSEL_HW, + chan->regs + S3C2443_DMA_DMAREQSEL); +} + +static struct s3c24xx_dma_selection __initdata s3c2443_dma_sel = { + .select = s3c2443_dma_select, + .dcon_mask = 0, + .map = s3c2443_dma_mappings, + .map_size = ARRAY_SIZE(s3c2443_dma_mappings), +}; + +static int s3c2443_dma_add(struct sys_device *sysdev) +{ + s3c24xx_dma_init(6, IRQ_S3C2443_DMA0, 0x100); + return s3c24xx_dma_init_map(&s3c2443_dma_sel); +} + +static struct sysdev_driver s3c2443_dma_driver = { + .add = s3c2443_dma_add, +}; + +static int __init s3c2443_dma_init(void) +{ + return sysdev_driver_register(&s3c2443_sysclass, &s3c2443_dma_driver); +} + +arch_initcall(s3c2443_dma_init); diff --git a/arch/arm/mach-s3c2443/irq.c b/arch/arm/mach-s3c2443/irq.c new file mode 100644 index 00000000000..7a45b6dcb73 --- /dev/null +++ b/arch/arm/mach-s3c2443/irq.c @@ -0,0 +1,290 @@ +/* linux/arch/arm/mach-s3c2443/irq.c + * + * Copyright (c) 2007 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * +*/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/ptrace.h> +#include <linux/sysdev.h> + +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/io.h> + +#include <asm/mach/irq.h> + +#include <asm/arch/regs-irq.h> +#include <asm/arch/regs-gpio.h> + +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/pm.h> +#include <asm/plat-s3c24xx/irq.h> + +#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1) + +static inline void s3c2443_irq_demux(unsigned int irq, unsigned int len) +{ + unsigned int subsrc, submsk; + unsigned int end; + struct irq_desc *mydesc; + + /* read the current pending interrupts, and the mask + * for what it is available */ + + subsrc = __raw_readl(S3C2410_SUBSRCPND); + submsk = __raw_readl(S3C2410_INTSUBMSK); + + subsrc &= ~submsk; + subsrc >>= (irq - S3C2410_IRQSUB(0)); + subsrc &= (1 << len)-1; + + end = len + irq; + mydesc = irq_desc + irq; + + for (; irq < end && subsrc; irq++) { + if (subsrc & 1) + desc_handle_irq(irq, mydesc); + + mydesc++; + subsrc >>= 1; + } +} + +/* WDT/AC97 sub interrupts */ + +static void s3c2443_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc) +{ + s3c2443_irq_demux(IRQ_S3C2443_WDT, 4); +} + +#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0)) +#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97) + +static void s3c2443_irq_wdtac97_mask(unsigned int irqno) +{ + s3c_irqsub_mask(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97); +} + +static void s3c2443_irq_wdtac97_unmask(unsigned int irqno) +{ + s3c_irqsub_unmask(irqno, INTMSK_WDTAC97); +} + +static void s3c2443_irq_wdtac97_ack(unsigned int irqno) +{ + s3c_irqsub_maskack(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97); +} + +static struct irq_chip s3c2443_irq_wdtac97 = { + .mask = s3c2443_irq_wdtac97_mask, + .unmask = s3c2443_irq_wdtac97_unmask, + .ack = s3c2443_irq_wdtac97_ack, +}; + + +/* LCD sub interrupts */ + +static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc) +{ + s3c2443_irq_demux(IRQ_S3C2443_LCD1, 4); +} + +#define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0)) +#define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4) + +static void s3c2443_irq_lcd_mask(unsigned int irqno) +{ + s3c_irqsub_mask(irqno, INTMSK_LCD, SUBMSK_LCD); +} + +static void s3c2443_irq_lcd_unmask(unsigned int irqno) +{ + s3c_irqsub_unmask(irqno, INTMSK_LCD); +} + +static void s3c2443_irq_lcd_ack(unsigned int irqno) +{ + s3c_irqsub_maskack(irqno, INTMSK_LCD, SUBMSK_LCD); +} + +static struct irq_chip s3c2443_irq_lcd = { + .mask = s3c2443_irq_lcd_mask, + .unmask = s3c2443_irq_lcd_unmask, + .ack = s3c2443_irq_lcd_ack, +}; + + +/* DMA sub interrupts */ + +static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc) +{ + s3c2443_irq_demux(IRQ_S3C2443_DMA1, 6); +} + +#define INTMSK_DMA (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0)) +#define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5) + + +static void s3c2443_irq_dma_mask(unsigned int irqno) +{ + s3c_irqsub_mask(irqno, INTMSK_DMA, SUBMSK_DMA); +} + +static void s3c2443_irq_dma_unmask(unsigned int irqno) +{ + s3c_irqsub_unmask(irqno, INTMSK_DMA); +} + +static void s3c2443_irq_dma_ack(unsigned int irqno) +{ + s3c_irqsub_maskack(irqno, INTMSK_DMA, SUBMSK_DMA); +} + +static struct irq_chip s3c2443_irq_dma = { + .mask = s3c2443_irq_dma_mask, + .unmask = s3c2443_irq_dma_unmask, + .ack = s3c2443_irq_dma_ack, +}; + + +/* UART3 sub interrupts */ + +static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc) +{ + s3c2443_irq_demux(IRQ_S3C2443_UART3, 3); +} + +#define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0)) +#define SUBMSK_UART3 (0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0))) + + +static void s3c2443_irq_uart3_mask(unsigned int irqno) +{ + s3c_irqsub_mask(irqno, INTMSK_UART3, SUBMSK_UART3); +} + +static void s3c2443_irq_uart3_unmask(unsigned int irqno) +{ + s3c_irqsub_unmask(irqno, INTMSK_UART3); +} + +static void s3c2443_irq_uart3_ack(unsigned int irqno) +{ + s3c_irqsub_maskack(irqno, INTMSK_UART3, SUBMSK_UART3); +} + +static struct irq_chip s3c2443_irq_uart3 = { + .mask = s3c2443_irq_uart3_mask, + .unmask = s3c2443_irq_uart3_unmask, + .ack = s3c2443_irq_uart3_ack, +}; + + +/* CAM sub interrupts */ + +static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc) +{ + s3c2443_irq_demux(IRQ_S3C2440_CAM_C, 4); +} + +#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0)) +#define SUBMSK_CAM INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P) + +static void s3c2443_irq_cam_mask(unsigned int irqno) +{ + s3c_irqsub_mask(irqno, INTMSK_CAM, SUBMSK_CAM); +} + +static void s3c2443_irq_cam_unmask(unsigned int irqno) +{ + s3c_irqsub_unmask(irqno, INTMSK_CAM); +} + +static void s3c2443_irq_cam_ack(unsigned int irqno) +{ + s3c_irqsub_maskack(irqno, INTMSK_CAM, SUBMSK_CAM); +} + +static struct irq_chip s3c2443_irq_cam = { + .mask = s3c2443_irq_cam_mask, + .unmask = s3c2443_irq_cam_unmask, + .ack = s3c2443_irq_cam_ack, +}; + +/* IRQ initialisation code */ + +static int __init s3c2443_add_sub(unsigned int base, + void (*demux)(unsigned int, + struct irq_desc *), + struct irq_chip *chip, + unsigned int start, unsigned int end) +{ + unsigned int irqno; + + set_irq_chip(base, &s3c_irq_level_chip); + set_irq_handler(base, handle_level_irq); + set_irq_chained_handler(base, demux); + + for (irqno = start; irqno <= end; irqno++) { + set_irq_chip(irqno, chip); + set_irq_handler(irqno, handle_level_irq); + set_irq_flags(irqno, IRQF_VALID); + } + + return 0; +} + +static int s3c2443_irq_add(struct sys_device *sysdev) +{ + printk("S3C2443: IRQ Support\n"); + + s3c2443_add_sub(IRQ_CAM, s3c2443_irq_demux_cam, &s3c2443_irq_cam, + IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P); + + s3c2443_add_sub(IRQ_LCD, s3c2443_irq_demux_lcd, &s3c2443_irq_lcd, + IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4); + + s3c2443_add_sub(IRQ_S3C2443_DMA, s3c2443_irq_demux_dma, + &s3c2443_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5); + + s3c2443_add_sub(IRQ_S3C2443_UART3, s3c2443_irq_demux_uart3, + &s3c2443_irq_uart3, + IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3); + + s3c2443_add_sub(IRQ_WDT, s3c2443_irq_demux_wdtac97, + &s3c2443_irq_wdtac97, + IRQ_S3C2443_WDT, IRQ_S3C2443_AC97); + + return 0; +} + +static struct sysdev_driver s3c2443_irq_driver = { + .add = s3c2443_irq_add, +}; + +static int s3c2443_irq_init(void) +{ + return sysdev_driver_register(&s3c2443_sysclass, &s3c2443_irq_driver); +} + +arch_initcall(s3c2443_irq_init); + diff --git a/arch/arm/mach-s3c2443/mach-smdk2443.c b/arch/arm/mach-s3c2443/mach-smdk2443.c new file mode 100644 index 00000000000..e82aaff7dee --- /dev/null +++ b/arch/arm/mach-s3c2443/mach-smdk2443.c @@ -0,0 +1,137 @@ +/* linux/arch/arm/mach-s3c2443/mach-smdk2443.c + * + * Copyright (c) 2007 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * http://www.fluff.org/ben/smdk2443/ + * + * Thanks to Samsung for the loan of an SMDK2443 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * +*/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/serial_core.h> +#include <linux/platform_device.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <asm/arch/regs-serial.h> +#include <asm/arch/regs-gpio.h> +#include <asm/arch/regs-lcd.h> + +#include <asm/arch/idle.h> +#include <asm/arch/fb.h> + +#include <asm/plat-s3c24xx/s3c2410.h> +#include <asm/plat-s3c24xx/s3c2440.h> +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> + +#include <asm/plat-s3c24xx/common-smdk.h> + +static struct map_desc smdk2443_iodesc[] __initdata = { + /* ISA IO Space map (memory space selected by A24) */ + + { + .virtual = (u32)S3C24XX_VA_ISA_WORD, + .pfn = __phys_to_pfn(S3C2410_CS2), + .length = 0x10000, + .type = MT_DEVICE, + }, { + .virtual = (u32)S3C24XX_VA_ISA_WORD + 0x10000, + .pfn = __phys_to_pfn(S3C2410_CS2 + (1<<24)), + .length = SZ_4M, + .type = MT_DEVICE, + }, { + .virtual = (u32)S3C24XX_VA_ISA_BYTE, + .pfn = __phys_to_pfn(S3C2410_CS2), + .length = 0x10000, + .type = MT_DEVICE, + }, { + .virtual = (u32)S3C24XX_VA_ISA_BYTE + 0x10000, + .pfn = __phys_to_pfn(S3C2410_CS2 + (1<<24)), + .length = SZ_4M, + .type = MT_DEVICE, + } +}; + +#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg smdk2443_uartcfgs[] __initdata = { + [0] = { + .hwport = 0, + .flags = 0, + .ucon = 0x3c5, + .ulcon = 0x03, + .ufcon = 0x51, + }, + [1] = { + .hwport = 1, + .flags = 0, + .ucon = 0x3c5, + .ulcon = 0x03, + .ufcon = 0x51, + }, + /* IR port */ + [2] = { + .hwport = 2, + .flags = 0, + .ucon = 0x3c5, + .ulcon = 0x43, + .ufcon = 0x51, + } +}; + +static struct platform_device *smdk2443_devices[] __initdata = { + &s3c_device_wdt, + &s3c_device_i2c, +}; + +static struct s3c24xx_board smdk2443_board __initdata = { + .devices = smdk2443_devices, + .devices_count = ARRAY_SIZE(smdk2443_devices) +}; + +static void __init smdk2443_map_io(void) +{ + s3c24xx_init_io(smdk2443_iodesc, ARRAY_SIZE(smdk2443_iodesc)); + s3c24xx_init_clocks(12000000); + s3c24xx_init_uarts(smdk2443_uartcfgs, ARRAY_SIZE(smdk2443_uartcfgs)); + s3c24xx_set_board(&smdk2443_board); +} + +static void __init smdk2443_machine_init(void) +{ + smdk_machine_init(); +} + +MACHINE_START(SMDK2443, "SMDK2443") + /* Maintainer: Ben Dooks <ben@fluff.org> */ + .phys_io = S3C2410_PA_UART, + .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, + .boot_params = S3C2410_SDRAM_PA + 0x100, + + .init_irq = s3c24xx_init_irq, + .map_io = smdk2443_map_io, + .init_machine = smdk2443_machine_init, + .timer = &s3c24xx_timer, +MACHINE_END diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c new file mode 100644 index 00000000000..11b1d0b310c --- /dev/null +++ b/arch/arm/mach-s3c2443/s3c2443.c @@ -0,0 +1,97 @@ +/* linux/arch/arm/mach-s3c2443/s3c2443.c + * + * Copyright (c) 2007 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Samsung S3C2443 Mobile CPU support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/serial_core.h> +#include <linux/sysdev.h> +#include <linux/clk.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> + +#include <asm/arch/regs-s3c2443-clock.h> +#include <asm/arch/reset.h> + +#include <asm/plat-s3c24xx/s3c2443.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> + +static struct map_desc s3c2443_iodesc[] __initdata = { + IODESC_ENT(WATCHDOG), + IODESC_ENT(CLKPWR), + IODESC_ENT(TIMER), +}; + +struct sysdev_class s3c2443_sysclass = { + set_kset_name("s3c2443-core"), +}; + +static struct sys_device s3c2443_sysdev = { + .cls = &s3c2443_sysclass, +}; + +static void s3c2443_hard_reset(void) +{ + __raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST); +} + +int __init s3c2443_init(void) +{ + printk("S3C2443: Initialising architecture\n"); + + s3c24xx_reset_hook = s3c2443_hard_reset; + + s3c_device_nand.name = "s3c2412-nand"; + + return sysdev_register(&s3c2443_sysdev); +} + +void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ + s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no); +} + +/* s3c2443_map_io + * + * register the standard cpu IO areas, and any passed in from the + * machine specific initialisation. + */ + +void __init s3c2443_map_io(struct map_desc *mach_desc, int mach_size) +{ + iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc)); + iotable_init(mach_desc, mach_size); +} + +/* need to register class before we actually register the device, and + * we also need to ensure that it has been initialised before any of the + * drivers even try to use it (even if not on an s3c2443 based system) + * as a driver which may support both 2443 and 2440 may try and use it. +*/ + +static int __init s3c2443_core_init(void) +{ + return sysdev_class_register(&s3c2443_sysclass); +} + +core_initcall(s3c2443_core_init); diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 3c2f97938c4..e684e9b3821 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -171,8 +171,8 @@ config CPU_ARM925T # ARM926T config CPU_ARM926T bool "Support ARM926T processor" - depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 - default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 + depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_NS9XXX + default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_NS9XXX select CPU_32v5 select CPU_ABRT_EV5TJ select CPU_CACHE_VIVT @@ -609,3 +609,10 @@ config NEEDS_SYSCALL_FOR_CMPXCHG Forget about fast user space cmpxchg support. It is just not possible. +config OUTER_CACHE + bool + default n + +config CACHE_L2X0 + bool + select OUTER_CACHE diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index d2f5672ecf6..2f8b9594777 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -66,3 +66,5 @@ obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o obj-$(CONFIG_CPU_V6) += proc-v6.o + +obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c new file mode 100644 index 00000000000..08a36f1b35d --- /dev/null +++ b/arch/arm/mm/cache-l2x0.c @@ -0,0 +1,104 @@ +/* + * arch/arm/mm/cache-l2x0.c - L210/L220 cache controller support + * + * Copyright (C) 2007 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/init.h> + +#include <asm/cacheflush.h> +#include <asm/io.h> +#include <asm/hardware/cache-l2x0.h> + +#define CACHE_LINE_SIZE 32 + +static void __iomem *l2x0_base; + +static inline void sync_writel(unsigned long val, unsigned long reg, + unsigned long complete_mask) +{ + writel(val, l2x0_base + reg); + /* wait for the operation to complete */ + while (readl(l2x0_base + reg) & complete_mask) + ; +} + +static inline void cache_sync(void) +{ + sync_writel(0, L2X0_CACHE_SYNC, 1); +} + +static inline void l2x0_inv_all(void) +{ + /* invalidate all ways */ + sync_writel(0xff, L2X0_INV_WAY, 0xff); + cache_sync(); +} + +static void l2x0_inv_range(unsigned long start, unsigned long end) +{ + unsigned long addr; + + start &= ~(CACHE_LINE_SIZE - 1); + for (addr = start; addr < end; addr += CACHE_LINE_SIZE) + sync_writel(addr, L2X0_INV_LINE_PA, 1); + cache_sync(); +} + +static void l2x0_clean_range(unsigned long start, unsigned long end) +{ + unsigned long addr; + + start &= ~(CACHE_LINE_SIZE - 1); + for (addr = start; addr < end; addr += CACHE_LINE_SIZE) + sync_writel(addr, L2X0_CLEAN_LINE_PA, 1); + cache_sync(); +} + +static void l2x0_flush_range(unsigned long start, unsigned long end) +{ + unsigned long addr; + + start &= ~(CACHE_LINE_SIZE - 1); + for (addr = start; addr < end; addr += CACHE_LINE_SIZE) + sync_writel(addr, L2X0_CLEAN_INV_LINE_PA, 1); + cache_sync(); +} + +void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) +{ + __u32 aux; + + l2x0_base = base; + + /* disable L2X0 */ + writel(0, l2x0_base + L2X0_CTRL); + + aux = readl(l2x0_base + L2X0_AUX_CTRL); + aux &= aux_mask; + aux |= aux_val; + writel(aux, l2x0_base + L2X0_AUX_CTRL); + + l2x0_inv_all(); + + /* enable L2X0 */ + writel(1, l2x0_base + L2X0_CTRL); + + outer_cache.inv_range = l2x0_inv_range; + outer_cache.clean_range = l2x0_clean_range; + outer_cache.flush_range = l2x0_flush_range; + + printk(KERN_INFO "L2X0 cache controller enabled\n"); +} diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c index 6a9c362fef5..1f9f94f9af4 100644 --- a/arch/arm/mm/consistent.c +++ b/arch/arm/mm/consistent.c @@ -205,9 +205,10 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, * kernel direct-mapped region for device DMA. */ { - unsigned long kaddr = (unsigned long)page_address(page); - memset(page_address(page), 0, size); - dmac_flush_range(kaddr, kaddr + size); + void *ptr = page_address(page); + memset(ptr, 0, size); + dmac_flush_range(ptr, ptr + size); + outer_flush_range(__pa(ptr), __pa(ptr) + size); } /* @@ -480,20 +481,24 @@ core_initcall(consistent_init); * platforms with CONFIG_DMABOUNCE. * Use the driver DMA support - see dma-mapping.h (dma_sync_*) */ -void consistent_sync(void *vaddr, size_t size, int direction) +void consistent_sync(const void *start, size_t size, int direction) { - unsigned long start = (unsigned long)vaddr; - unsigned long end = start + size; + const void *end = start + size; + + BUG_ON(!virt_addr_valid(start) || !virt_addr_valid(end - 1)); switch (direction) { case DMA_FROM_DEVICE: /* invalidate only */ dmac_inv_range(start, end); + outer_inv_range(__pa(start), __pa(end)); break; case DMA_TO_DEVICE: /* writeback only */ dmac_clean_range(start, end); + outer_clean_range(__pa(start), __pa(end)); break; case DMA_BIDIRECTIONAL: /* writeback and invalidate */ dmac_flush_range(start, end); + outer_flush_range(__pa(start), __pa(end)); break; default: BUG(); diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c index 79e80020242..9da43a0fdcd 100644 --- a/arch/arm/mm/context.c +++ b/arch/arm/mm/context.c @@ -19,7 +19,8 @@ unsigned int cpu_last_asid = { 1 << ASID_BITS }; /* * We fork()ed a process, and we need a new context for the child * to run in. We reserve version 0 for initial tasks so we will - * always allocate an ASID. + * always allocate an ASID. The ASID 0 is reserved for the TTBR + * register changing sequence. */ void __init_new_context(struct task_struct *tsk, struct mm_struct *mm) { @@ -38,8 +39,15 @@ void __new_context(struct mm_struct *mm) * If we've used up all our ASIDs, we need * to start a new version and flush the TLB. */ - if ((asid & ~ASID_MASK) == 0) + if ((asid & ~ASID_MASK) == 0) { + asid = ++cpu_last_asid; + /* set the reserved ASID before flushing the TLB */ + asm("mcr p15, 0, %0, c13, c0, 1 @ set reserved context ID\n" + : + : "r" (0)); + isb(); flush_tlb_all(); + } mm->context.id = asid; } diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index cf95c5d0ce4..44558d5f931 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -119,8 +119,6 @@ make_coherent(struct address_space *mapping, struct vm_area_struct *vma, unsigne flush_cache_page(vma, addr, pfn); } -void __flush_dcache_page(struct address_space *mapping, struct page *page); - /* * Take care of architecture specific things when placing a new PTE into * a page table, or changing an existing PTE. Basically, there are two diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 655c8376f0b..94fd4bf5cb9 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -49,8 +49,10 @@ pmd_t *top_pmd; static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK; static unsigned int ecc_mask __initdata = 0; +pgprot_t pgprot_user; pgprot_t pgprot_kernel; +EXPORT_SYMBOL(pgprot_user); EXPORT_SYMBOL(pgprot_kernel); struct cachepolicy { @@ -345,6 +347,7 @@ static void __init build_mem_type_table(void) mem_types[MT_MINICLEAN].prot_sect &= ~PMD_SECT_TEX(1); } + pgprot_user = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | user_pgprot); pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | L_PTE_EXEC | kern_pgprot); diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index 7b1843befb9..eb42e5b9486 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -14,10 +14,13 @@ #include <asm/assembler.h> #include <asm/asm-offsets.h> #include <asm/elf.h> -#include <asm/hardware/arm_scu.h> #include <asm/pgtable-hwdef.h> #include <asm/pgtable.h> +#ifdef CONFIG_SMP +#include <asm/hardware/arm_scu.h> +#endif + #include "proc-macros.S" #define D_CACHE_LINE_SIZE 32 @@ -30,6 +33,12 @@ #define TTB_RGN_WT (2 << 3) #define TTB_RGN_WB (3 << 3) +#ifndef CONFIG_SMP +#define TTB_FLAGS TTB_RGN_WBWA +#else +#define TTB_FLAGS TTB_RGN_WBWA|TTB_S +#endif + ENTRY(cpu_v6_proc_init) mov pc, lr @@ -92,9 +101,7 @@ ENTRY(cpu_v6_switch_mm) #ifdef CONFIG_MMU mov r2, #0 ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id -#ifdef CONFIG_SMP - orr r0, r0, #TTB_RGN_WBWA|TTB_S @ mark PTWs shared, outer cacheable -#endif + orr r0, r0, #TTB_FLAGS mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB mcr p15, 0, r2, c7, c10, 4 @ drain write buffer mcr p15, 0, r0, c2, c0, 0 @ set TTB 0 @@ -183,8 +190,7 @@ __v6_setup: /* Set up the SCU on core 0 only */ mrc p15, 0, r0, c0, c0, 5 @ CPU core number ands r0, r0, #15 - moveq r0, #0x10000000 @ SCU_BASE - orreq r0, r0, #0x00100000 + ldreq r0, =SCU_BASE ldreq r5, [r0, #SCU_CTRL] orreq r5, r5, #1 streq r5, [r0, #SCU_CTRL] @@ -204,9 +210,7 @@ __v6_setup: #ifdef CONFIG_MMU mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs mcr p15, 0, r0, c2, c0, 2 @ TTB control register -#ifdef CONFIG_SMP - orr r4, r4, #TTB_RGN_WBWA|TTB_S @ mark PTWs shared, outer cacheable -#endif + orr r4, r4, #TTB_FLAGS mcr p15, 0, r4, c2, c0, 1 @ load TTB1 #endif /* CONFIG_MMU */ adr r5, v6_crval diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index 94a58455f34..d95921a2ab9 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -5,23 +5,23 @@ * Current Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> * * Copyright 2004 (C) Intel Corp. - * Copyright 2005 (c) MontaVista Software, Inc. + * Copyright 2005 (C) MontaVista Software, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * MMU functions for the Intel XScale3 Core (XSC3). The XSC3 core is an - * extension to Intel's original XScale core that adds the following + * MMU functions for the Intel XScale3 Core (XSC3). The XSC3 core is + * an extension to Intel's original XScale core that adds the following * features: * * - ARMv6 Supersections * - Low Locality Reference pages (replaces mini-cache) * - 36-bit addressing * - L2 cache - * - Cache-coherency if chipset supports it + * - Cache coherency if chipset supports it * - * Based on orignal XScale code by Nicolas Pitre + * Based on original XScale code by Nicolas Pitre. */ #include <linux/linkage.h> @@ -42,12 +42,12 @@ #define MAX_AREA_SIZE 32768 /* - * The cache line size of the I and D cache. + * The cache line size of the L1 I, L1 D and unified L2 cache. */ #define CACHELINESIZE 32 /* - * The size of the data cache. + * The size of the L1 D cache. */ #define CACHESIZE 32768 @@ -57,9 +57,9 @@ #define L2_CACHE_ENABLE 1 /* - * This macro is used to wait for a CP15 write and is needed - * when we have to ensure that the last operation to the co-pro - * was completed before continuing with operation. + * This macro is used to wait for a CP15 write and is needed when we + * have to ensure that the last operation to the coprocessor was + * completed before continuing with operation. */ .macro cpwait_ret, lr, rd mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15 @@ -68,13 +68,13 @@ .endm /* - * This macro cleans & invalidates the entire xsc3 dcache by set & way. + * This macro cleans and invalidates the entire L1 D cache. */ .macro clean_d_cache rd, rs mov \rd, #0x1f00 orr \rd, \rd, #0x00e0 -1: mcr p15, 0, \rd, c7, c14, 2 @ clean/inv set/way +1: mcr p15, 0, \rd, c7, c14, 2 @ clean/invalidate L1 D line adds \rd, \rd, #0x40000000 bcc 1b subs \rd, \rd, #0x20 @@ -119,15 +119,15 @@ ENTRY(cpu_xsc3_reset) mov r1, #PSR_F_BIT|PSR_I_BIT|SVC_MODE msr cpsr_c, r1 @ reset CPSR mrc p15, 0, r1, c1, c0, 0 @ ctrl register - bic r1, r1, #0x0086 @ ........B....CA. bic r1, r1, #0x3900 @ ..VIZ..S........ + bic r1, r1, #0x0086 @ ........B....CA. mcr p15, 0, r1, c1, c0, 0 @ ctrl register - mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches & BTB + mcr p15, 0, ip, c7, c7, 0 @ invalidate L1 caches and BTB bic r1, r1, #0x0001 @ ...............M mcr p15, 0, r1, c1, c0, 0 @ ctrl register @ CAUTION: MMU turned off from this point. We count on the pipeline @ already containing those two last instructions to survive. - mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mcr p15, 0, ip, c8, c7, 0 @ invalidate I and D TLBs mov pc, r0 /* @@ -139,14 +139,12 @@ ENTRY(cpu_xsc3_reset) * * XScale supports clock switching, but using idle mode support * allows external hardware to react to system state changes. - - MMG: Come back to this one. */ .align 5 ENTRY(cpu_xsc3_do_idle) mov r0, #1 - mcr p14, 0, r0, c7, c0, 0 @ Go to IDLE + mcr p14, 0, r0, c7, c0, 0 @ go to idle mov pc, lr /* ================================= CACHE ================================ */ @@ -171,9 +169,9 @@ ENTRY(xsc3_flush_kern_cache_all) __flush_whole_cache: clean_d_cache r0, r1 tst r2, #VM_EXEC - mcrne p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB - mcrne p15, 0, ip, c7, c10, 4 @ Drain Write Buffer - mcrne p15, 0, ip, c7, c5, 4 @ Prefetch Flush + mcrne p15, 0, ip, c7, c5, 0 @ invalidate L1 I cache and BTB + mcrne p15, 0, ip, c7, c10, 4 @ data write barrier + mcrne p15, 0, ip, c7, c5, 4 @ prefetch flush mov pc, lr /* @@ -194,21 +192,21 @@ ENTRY(xsc3_flush_user_cache_range) bhs __flush_whole_cache 1: tst r2, #VM_EXEC - mcrne p15, 0, r0, c7, c5, 1 @ Invalidate I cache line - mcr p15, 0, r0, c7, c14, 1 @ Clean/invalidate D cache line + mcrne p15, 0, r0, c7, c5, 1 @ invalidate L1 I line + mcr p15, 0, r0, c7, c14, 1 @ clean/invalidate L1 D line add r0, r0, #CACHELINESIZE cmp r0, r1 blo 1b tst r2, #VM_EXEC - mcrne p15, 0, ip, c7, c5, 6 @ Invalidate BTB - mcrne p15, 0, ip, c7, c10, 4 @ Drain Write Buffer - mcrne p15, 0, ip, c7, c5, 4 @ Prefetch Flush + mcrne p15, 0, ip, c7, c5, 6 @ invalidate BTB + mcrne p15, 0, ip, c7, c10, 4 @ data write barrier + mcrne p15, 0, ip, c7, c5, 4 @ prefetch flush mov pc, lr /* * coherent_kern_range(start, end) * - * Ensure coherency between the Icache and the Dcache in the + * Ensure coherency between the I cache and the D cache in the * region described by start. If you have non-snooping * Harvard caches, you need to implement this function. * @@ -222,34 +220,34 @@ ENTRY(xsc3_coherent_kern_range) /* FALLTHROUGH */ ENTRY(xsc3_coherent_user_range) bic r0, r0, #CACHELINESIZE - 1 -1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry +1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line add r0, r0, #CACHELINESIZE cmp r0, r1 blo 1b mov r0, #0 - mcr p15, 0, r0, c7, c5, 0 @ Invalidate I cache & BTB - mcr p15, 0, r0, c7, c10, 4 @ Drain Write Buffer - mcr p15, 0, r0, c7, c5, 4 @ Prefetch Flush + mcr p15, 0, r0, c7, c5, 0 @ invalidate L1 I cache and BTB + mcr p15, 0, r0, c7, c10, 4 @ data write barrier + mcr p15, 0, r0, c7, c5, 4 @ prefetch flush mov pc, lr /* * flush_kern_dcache_page(void *page) * * Ensure no D cache aliasing occurs, either with itself or - * the I cache + * the I cache. * * - addr - page aligned address */ ENTRY(xsc3_flush_kern_dcache_page) add r1, r0, #PAGE_SZ -1: mcr p15, 0, r0, c7, c14, 1 @ Clean/Invalidate D Cache line +1: mcr p15, 0, r0, c7, c14, 1 @ clean/invalidate L1 D line add r0, r0, #CACHELINESIZE cmp r0, r1 blo 1b mov r0, #0 - mcr p15, 0, r0, c7, c5, 0 @ Invalidate I cache & BTB - mcr p15, 0, r0, c7, c10, 4 @ Drain Write Buffer - mcr p15, 0, r0, c7, c5, 4 @ Prefetch Flush + mcr p15, 0, r0, c7, c5, 0 @ invalidate L1 I cache and BTB + mcr p15, 0, r0, c7, c10, 4 @ data write barrier + mcr p15, 0, r0, c7, c5, 4 @ prefetch flush mov pc, lr /* @@ -266,17 +264,17 @@ ENTRY(xsc3_flush_kern_dcache_page) ENTRY(xsc3_dma_inv_range) tst r0, #CACHELINESIZE - 1 bic r0, r0, #CACHELINESIZE - 1 - mcrne p15, 0, r0, c7, c10, 1 @ clean L1 D entry - mcrne p15, 1, r0, c7, c11, 1 @ clean L2 D entry + mcrne p15, 0, r0, c7, c10, 1 @ clean L1 D line + mcrne p15, 1, r0, c7, c11, 1 @ clean L2 line tst r1, #CACHELINESIZE - 1 - mcrne p15, 0, r1, c7, c10, 1 @ clean L1 D entry - mcrne p15, 1, r1, c7, c11, 1 @ clean L2 D entry -1: mcr p15, 0, r0, c7, c6, 1 @ invalidate L1 D entry - mcr p15, 1, r0, c7, c7, 1 @ Invalidate L2 D cache line + mcrne p15, 0, r1, c7, c10, 1 @ clean L1 D line + mcrne p15, 1, r1, c7, c11, 1 @ clean L2 line +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate L1 D line + mcr p15, 1, r0, c7, c7, 1 @ invalidate L2 line add r0, r0, #CACHELINESIZE cmp r0, r1 blo 1b - mcr p15, 0, r0, c7, c10, 4 @ Drain Write Buffer + mcr p15, 0, r0, c7, c10, 4 @ data write barrier mov pc, lr /* @@ -289,12 +287,12 @@ ENTRY(xsc3_dma_inv_range) */ ENTRY(xsc3_dma_clean_range) bic r0, r0, #CACHELINESIZE - 1 -1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D entry - mcr p15, 1, r0, c7, c11, 1 @ clean L2 D entry +1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line + mcr p15, 1, r0, c7, c11, 1 @ clean L2 line add r0, r0, #CACHELINESIZE cmp r0, r1 blo 1b - mcr p15, 0, r0, c7, c10, 4 @ Drain Write Buffer + mcr p15, 0, r0, c7, c10, 4 @ data write barrier mov pc, lr /* @@ -307,13 +305,13 @@ ENTRY(xsc3_dma_clean_range) */ ENTRY(xsc3_dma_flush_range) bic r0, r0, #CACHELINESIZE - 1 -1: mcr p15, 0, r0, c7, c14, 1 @ Clean/invalidate L1 D cache line - mcr p15, 1, r0, c7, c11, 1 @ Clean L2 D cache line - mcr p15, 1, r0, c7, c7, 1 @ Invalidate L2 D cache line +1: mcr p15, 0, r0, c7, c14, 1 @ clean/invalidate L1 D line + mcr p15, 1, r0, c7, c11, 1 @ clean L2 line + mcr p15, 1, r0, c7, c7, 1 @ invalidate L2 line add r0, r0, #CACHELINESIZE cmp r0, r1 blo 1b - mcr p15, 0, r0, c7, c10, 4 @ Drain Write Buffer + mcr p15, 0, r0, c7, c10, 4 @ data write barrier mov pc, lr ENTRY(xsc3_cache_fns) @@ -328,7 +326,7 @@ ENTRY(xsc3_cache_fns) .long xsc3_dma_flush_range ENTRY(cpu_xsc3_dcache_clean_area) -1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry +1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line add r0, r0, #CACHELINESIZE subs r1, r1, #CACHELINESIZE bhi 1b @@ -346,14 +344,14 @@ ENTRY(cpu_xsc3_dcache_clean_area) .align 5 ENTRY(cpu_xsc3_switch_mm) clean_d_cache r1, r2 - mcr p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB - mcr p15, 0, ip, c7, c10, 4 @ Drain Write Buffer - mcr p15, 0, ip, c7, c5, 4 @ Prefetch Flush + mcr p15, 0, ip, c7, c5, 0 @ invalidate L1 I cache and BTB + mcr p15, 0, ip, c7, c10, 4 @ data write barrier + mcr p15, 0, ip, c7, c5, 4 @ prefetch flush #ifdef L2_CACHE_ENABLE orr r0, r0, #0x18 @ cache the page table in L2 #endif mcr p15, 0, r0, c2, c0, 0 @ load page table pointer - mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mcr p15, 0, ip, c8, c7, 0 @ invalidate I and D TLBs cpwait_ret lr, ip /* @@ -366,34 +364,34 @@ ENTRY(cpu_xsc3_switch_mm) ENTRY(cpu_xsc3_set_pte_ext) str r1, [r0], #-2048 @ linux version - bic r2, r1, #0xff0 @ Keep C, B bits + bic r2, r1, #0xff0 @ keep C, B bits orr r2, r2, #PTE_TYPE_EXT @ extended page - tst r1, #L_PTE_SHARED @ Shared? + tst r1, #L_PTE_SHARED @ shared? orrne r2, r2, #0x200 eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY - tst r3, #L_PTE_USER @ User? + tst r3, #L_PTE_USER @ user? orrne r2, r2, #PTE_EXT_AP_URO_SRW @ yes -> user r/o, system r/w - tst r3, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty? + tst r3, #L_PTE_WRITE | L_PTE_DIRTY @ write and dirty? orreq r2, r2, #PTE_EXT_AP_UNO_SRW @ yes -> user n/a, system r/w @ combined with user -> user r/w #if L2_CACHE_ENABLE - @ If its cacheable it needs to be in L2 also. + @ If it's cacheable, it needs to be in L2 also. eor ip, r1, #L_PTE_CACHEABLE tst ip, #L_PTE_CACHEABLE orreq r2, r2, #PTE_EXT_TEX(0x5) #endif - tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young? + tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ present and young? movne r2, #0 @ no -> fault str r2, [r0] @ hardware version mov ip, #0 - mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line mcr - mcr p15, 0, ip, c7, c10, 4 @ Drain Write Buffer + mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line + mcr p15, 0, ip, c7, c10, 4 @ data write barrier mov pc, lr .ltorg @@ -406,17 +404,18 @@ ENTRY(cpu_xsc3_set_pte_ext) __xsc3_setup: mov r0, #PSR_F_BIT|PSR_I_BIT|SVC_MODE msr cpsr_c, r0 - mcr p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB - mcr p15, 0, ip, c7, c10, 4 @ Drain Write Buffer - mcr p15, 0, ip, c7, c5, 4 @ Prefetch Flush - mcr p15, 0, ip, c8, c7, 0 @ invalidate I, D TLBs + mcr p15, 0, ip, c7, c7, 0 @ invalidate L1 caches and BTB + mcr p15, 0, ip, c7, c10, 4 @ data write barrier + mcr p15, 0, ip, c7, c5, 4 @ prefetch flush + mcr p15, 0, ip, c8, c7, 0 @ invalidate I and D TLBs #if L2_CACHE_ENABLE orr r4, r4, #0x18 @ cache the page table in L2 #endif mcr p15, 0, r4, c2, c0, 0 @ load page table pointer - mov r0, #1 @ Allow access to CP0 and CP13 - orr r0, r0, #1 << 13 @ Its undefined whether this - mcr p15, 0, r0, c15, c1, 0 @ affects USR or SVC modes + + mov r0, #0 @ don't allow CP access + mcr p15, 0, r0, c15, c1, 0 @ write CP access register + mrc p15, 0, r0, c1, c0, 1 @ get auxiliary control reg and r0, r0, #2 @ preserve bit P bit setting #if L2_CACHE_ENABLE @@ -427,9 +426,9 @@ __xsc3_setup: adr r5, xsc3_crval ldmia r5, {r5, r6} mrc p15, 0, r0, c1, c0, 0 @ get control register - bic r0, r0, r5 @ .... .... .... ..A. - orr r0, r0, r6 @ .... .... .... .C.M - orr r0, r0, #0x00000800 @ ..VI Z..S .... .... + bic r0, r0, r5 @ ..V. ..R. .... ..A. + orr r0, r0, r6 @ ..VI Z..S .... .C.M (mmu) + @ ...I Z..S .... .... (uc) #if L2_CACHE_ENABLE orr r0, r0, #0x04000000 @ L2 enable #endif @@ -439,7 +438,7 @@ __xsc3_setup: .type xsc3_crval, #object xsc3_crval: - crval clear=0x04003b02, mmuset=0x00003105, ucset=0x00001100 + crval clear=0x04002202, mmuset=0x00003905, ucset=0x00001900 __INITDATA @@ -474,7 +473,7 @@ cpu_elf_name: .type cpu_xsc3_name, #object cpu_xsc3_name: - .asciz "XScale-Core3" + .asciz "XScale-V3 based processor" .size cpu_xsc3_name, . - cpu_xsc3_name .align @@ -490,7 +489,7 @@ __xsc3_proc_info: PMD_SECT_CACHEABLE | \ PMD_SECT_AP_WRITE | \ PMD_SECT_AP_READ - .long PMD_TYPE_SECT | \ + .long PMD_TYPE_SECT | \ PMD_SECT_AP_WRITE | \ PMD_SECT_AP_READ b __xsc3_setup diff --git a/arch/arm/mm/tlb-v6.S b/arch/arm/mm/tlb-v6.S index fd6adde3909..20f84bbaa9b 100644 --- a/arch/arm/mm/tlb-v6.S +++ b/arch/arm/mm/tlb-v6.S @@ -53,6 +53,8 @@ ENTRY(v6wbi_flush_user_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b + mcr p15, 0, ip, c7, c5, 6 @ flush BTAC/BTB + mcr p15, 0, ip, c7, c10, 4 @ data synchronization barrier mov pc, lr /* @@ -80,7 +82,9 @@ ENTRY(v6wbi_flush_kern_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b + mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB mcr p15, 0, r2, c7, c10, 4 @ data synchronization barrier + mcr p15, 0, r2, c7, c5, 4 @ prefetch flush mov pc, lr .section ".text.init", #alloc, #execinstr diff --git a/arch/arm/oprofile/Kconfig b/arch/arm/oprofile/Kconfig index 19d37730b66..afd93ad02fe 100644 --- a/arch/arm/oprofile/Kconfig +++ b/arch/arm/oprofile/Kconfig @@ -19,5 +19,24 @@ config OPROFILE If unsure, say N. +if OPROFILE + +config OPROFILE_ARMV6 + bool + depends on CPU_V6 && !SMP + default y + select OPROFILE_ARM11_CORE + +config OPROFILE_MPCORE + bool + depends on CPU_V6 && SMP + default y + select OPROFILE_ARM11_CORE + +config OPROFILE_ARM11_CORE + bool + +endif + endmenu diff --git a/arch/arm/oprofile/Makefile b/arch/arm/oprofile/Makefile index 6a94e54848f..e61d0cc520b 100644 --- a/arch/arm/oprofile/Makefile +++ b/arch/arm/oprofile/Makefile @@ -8,4 +8,6 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ oprofile-y := $(DRIVER_OBJS) common.o backtrace.o oprofile-$(CONFIG_CPU_XSCALE) += op_model_xscale.o - +oprofile-$(CONFIG_OPROFILE_ARM11_CORE) += op_model_arm11_core.o +oprofile-$(CONFIG_OPROFILE_ARMV6) += op_model_v6.o +oprofile-$(CONFIG_OPROFILE_MPCORE) += op_model_mpcore.o diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c index 6f833358cd0..0a007b931f6 100644 --- a/arch/arm/oprofile/common.c +++ b/arch/arm/oprofile/common.c @@ -135,6 +135,14 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) spec = &op_xscale_spec; #endif +#ifdef CONFIG_OPROFILE_ARMV6 + spec = &op_armv6_spec; +#endif + +#ifdef CONFIG_OPROFILE_MPCORE + spec = &op_mpcore_spec; +#endif + if (spec) { ret = spec->init(); if (ret < 0) diff --git a/arch/arm/oprofile/op_arm_model.h b/arch/arm/oprofile/op_arm_model.h index 38c6ad15854..4899c629aa0 100644 --- a/arch/arm/oprofile/op_arm_model.h +++ b/arch/arm/oprofile/op_arm_model.h @@ -24,6 +24,9 @@ struct op_arm_model_spec { extern struct op_arm_model_spec op_xscale_spec; #endif +extern struct op_arm_model_spec op_armv6_spec; +extern struct op_arm_model_spec op_mpcore_spec; + extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth); extern int __init op_arm_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec); diff --git a/arch/arm/oprofile/op_model_arm11_core.c b/arch/arm/oprofile/op_model_arm11_core.c new file mode 100644 index 00000000000..ad80752cb9f --- /dev/null +++ b/arch/arm/oprofile/op_model_arm11_core.c @@ -0,0 +1,162 @@ +/** + * @file op_model_arm11_core.c + * ARM11 Event Monitor Driver + * @remark Copyright 2004 ARM SMP Development Team + */ +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/oprofile.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/smp.h> + +#include "op_counter.h" +#include "op_arm_model.h" +#include "op_model_arm11_core.h" + +/* + * ARM11 PMU support + */ +static inline void arm11_write_pmnc(u32 val) +{ + /* upper 4bits and 7, 11 are write-as-0 */ + val &= 0x0ffff77f; + asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val)); +} + +static inline u32 arm11_read_pmnc(void) +{ + u32 val; + asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val)); + return val; +} + +static void arm11_reset_counter(unsigned int cnt) +{ + u32 val = -(u32)counter_config[CPU_COUNTER(smp_processor_id(), cnt)].count; + switch (cnt) { + case CCNT: + asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val)); + break; + + case PMN0: + asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val)); + break; + + case PMN1: + asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val)); + break; + } +} + +int arm11_setup_pmu(void) +{ + unsigned int cnt; + u32 pmnc; + + if (arm11_read_pmnc() & PMCR_E) { + printk(KERN_ERR "oprofile: CPU%u PMU still enabled when setup new event counter.\n", smp_processor_id()); + return -EBUSY; + } + + /* initialize PMNC, reset overflow, D bit, C bit and P bit. */ + arm11_write_pmnc(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT | + PMCR_C | PMCR_P); + + for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) { + unsigned long event; + + if (!counter_config[CPU_COUNTER(smp_processor_id(), cnt)].enabled) + continue; + + event = counter_config[CPU_COUNTER(smp_processor_id(), cnt)].event & 255; + + /* + * Set event (if destined for PMNx counters) + */ + if (cnt == PMN0) { + pmnc |= event << 20; + } else if (cnt == PMN1) { + pmnc |= event << 12; + } + + /* + * We don't need to set the event if it's a cycle count + * Enable interrupt for this counter + */ + pmnc |= PMCR_IEN_PMN0 << cnt; + arm11_reset_counter(cnt); + } + arm11_write_pmnc(pmnc); + + return 0; +} + +int arm11_start_pmu(void) +{ + arm11_write_pmnc(arm11_read_pmnc() | PMCR_E); + return 0; +} + +int arm11_stop_pmu(void) +{ + unsigned int cnt; + + arm11_write_pmnc(arm11_read_pmnc() & ~PMCR_E); + + for (cnt = PMN0; cnt <= CCNT; cnt++) + arm11_reset_counter(cnt); + + return 0; +} + +/* + * CPU counters' IRQ handler (one IRQ per CPU) + */ +static irqreturn_t arm11_pmu_interrupt(int irq, void *arg) +{ + struct pt_regs *regs = get_irq_regs(); + unsigned int cnt; + u32 pmnc; + + pmnc = arm11_read_pmnc(); + + for (cnt = PMN0; cnt <= CCNT; cnt++) { + if ((pmnc & (PMCR_OFL_PMN0 << cnt)) && (pmnc & (PMCR_IEN_PMN0 << cnt))) { + arm11_reset_counter(cnt); + oprofile_add_sample(regs, CPU_COUNTER(smp_processor_id(), cnt)); + } + } + /* Clear counter flag(s) */ + arm11_write_pmnc(pmnc); + return IRQ_HANDLED; +} + +int arm11_request_interrupts(int *irqs, int nr) +{ + unsigned int i; + int ret = 0; + + for(i = 0; i < nr; i++) { + ret = request_irq(irqs[i], arm11_pmu_interrupt, IRQF_DISABLED, "CP15 PMU", NULL); + if (ret != 0) { + printk(KERN_ERR "oprofile: unable to request IRQ%u for MPCORE-EM\n", + irqs[i]); + break; + } + } + + if (i != nr) + while (i-- != 0) + free_irq(irqs[i], NULL); + + return ret; +} + +void arm11_release_interrupts(int *irqs, int nr) +{ + unsigned int i; + + for (i = 0; i < nr; i++) + free_irq(irqs[i], NULL); +} diff --git a/arch/arm/oprofile/op_model_arm11_core.h b/arch/arm/oprofile/op_model_arm11_core.h new file mode 100644 index 00000000000..6f8538e5a96 --- /dev/null +++ b/arch/arm/oprofile/op_model_arm11_core.h @@ -0,0 +1,45 @@ +/** + * @file op_model_arm11_core.h + * ARM11 Event Monitor Driver + * @remark Copyright 2004 ARM SMP Development Team + * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com> + * @remark Copyright 2000-2004 MontaVista Software Inc + * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com> + * @remark Copyright 2004 Intel Corporation + * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk> + * @remark Copyright 2004 Oprofile Authors + * + * @remark Read the file COPYING + * + * @author Zwane Mwaikambo + */ +#ifndef OP_MODEL_ARM11_CORE_H +#define OP_MODEL_ARM11_CORE_H + +/* + * Per-CPU PMCR + */ +#define PMCR_E (1 << 0) /* Enable */ +#define PMCR_P (1 << 1) /* Count reset */ +#define PMCR_C (1 << 2) /* Cycle counter reset */ +#define PMCR_D (1 << 3) /* Cycle counter counts every 64th cpu cycle */ +#define PMCR_IEN_PMN0 (1 << 4) /* Interrupt enable count reg 0 */ +#define PMCR_IEN_PMN1 (1 << 5) /* Interrupt enable count reg 1 */ +#define PMCR_IEN_CCNT (1 << 6) /* Interrupt enable cycle counter */ +#define PMCR_OFL_PMN0 (1 << 8) /* Count reg 0 overflow */ +#define PMCR_OFL_PMN1 (1 << 9) /* Count reg 1 overflow */ +#define PMCR_OFL_CCNT (1 << 10) /* Cycle counter overflow */ + +#define PMN0 0 +#define PMN1 1 +#define CCNT 2 + +#define CPU_COUNTER(cpu, counter) ((cpu) * 3 + (counter)) + +int arm11_setup_pmu(void); +int arm11_start_pmu(void); +int arm11_stop_pmu(void); +int arm11_request_interrupts(int *, int); +void arm11_release_interrupts(int *, int); + +#endif diff --git a/arch/arm/oprofile/op_model_mpcore.c b/arch/arm/oprofile/op_model_mpcore.c new file mode 100644 index 00000000000..89850071824 --- /dev/null +++ b/arch/arm/oprofile/op_model_mpcore.c @@ -0,0 +1,296 @@ +/** + * @file op_model_mpcore.c + * MPCORE Event Monitor Driver + * @remark Copyright 2004 ARM SMP Development Team + * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com> + * @remark Copyright 2000-2004 MontaVista Software Inc + * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com> + * @remark Copyright 2004 Intel Corporation + * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk> + * @remark Copyright 2004 Oprofile Authors + * + * @remark Read the file COPYING + * + * @author Zwane Mwaikambo + * + * Counters: + * 0: PMN0 on CPU0, per-cpu configurable event counter + * 1: PMN1 on CPU0, per-cpu configurable event counter + * 2: CCNT on CPU0 + * 3: PMN0 on CPU1 + * 4: PMN1 on CPU1 + * 5: CCNT on CPU1 + * 6: PMN0 on CPU1 + * 7: PMN1 on CPU1 + * 8: CCNT on CPU1 + * 9: PMN0 on CPU1 + * 10: PMN1 on CPU1 + * 11: CCNT on CPU1 + * 12-19: configurable SCU event counters + */ + +/* #define DEBUG */ +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/oprofile.h> +#include <linux/interrupt.h> +#include <linux/smp.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/mach/irq.h> +#include <asm/hardware.h> +#include <asm/system.h> + +#include "op_counter.h" +#include "op_arm_model.h" +#include "op_model_arm11_core.h" +#include "op_model_mpcore.h" + +/* + * MPCore SCU event monitor support + */ +#define SCU_EVENTMONITORS_VA_BASE __io_address(REALVIEW_MPCORE_SCU_BASE + 0x10) + +/* + * Bitmask of used SCU counters + */ +static unsigned int scu_em_used; + +/* + * 2 helper fns take a counter number from 0-7 (not the userspace-visible counter number) + */ +static inline void scu_reset_counter(struct eventmonitor __iomem *emc, unsigned int n) +{ + writel(-(u32)counter_config[SCU_COUNTER(n)].count, &emc->MC[n]); +} + +static inline void scu_set_event(struct eventmonitor __iomem *emc, unsigned int n, u32 event) +{ + event &= 0xff; + writeb(event, &emc->MCEB[n]); +} + +/* + * SCU counters' IRQ handler (one IRQ per counter => 2 IRQs per CPU) + */ +static irqreturn_t scu_em_interrupt(int irq, void *arg) +{ + struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE; + unsigned int cnt; + + cnt = irq - IRQ_PMU_SCU0; + oprofile_add_sample(get_irq_regs(), SCU_COUNTER(cnt)); + scu_reset_counter(emc, cnt); + + /* Clear overflow flag for this counter */ + writel(1 << (cnt + 16), &emc->PMCR); + + return IRQ_HANDLED; +} + +/* Configure just the SCU counters that the user has requested */ +static void scu_setup(void) +{ + struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE; + unsigned int i; + + scu_em_used = 0; + + for (i = 0; i < NUM_SCU_COUNTERS; i++) { + if (counter_config[SCU_COUNTER(i)].enabled && + counter_config[SCU_COUNTER(i)].event) { + scu_set_event(emc, i, 0); /* disable counter for now */ + scu_em_used |= 1 << i; + } + } +} + +static int scu_start(void) +{ + struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE; + unsigned int temp, i; + unsigned long event; + int ret = 0; + + /* + * request the SCU counter interrupts that we need + */ + for (i = 0; i < NUM_SCU_COUNTERS; i++) { + if (scu_em_used & (1 << i)) { + ret = request_irq(IRQ_PMU_SCU0 + i, scu_em_interrupt, IRQF_DISABLED, "SCU PMU", NULL); + if (ret) { + printk(KERN_ERR "oprofile: unable to request IRQ%u for SCU Event Monitor\n", + IRQ_PMU_SCU0 + i); + goto err_free_scu; + } + } + } + + /* + * clear overflow and enable interrupt for all used counters + */ + temp = readl(&emc->PMCR); + for (i = 0; i < NUM_SCU_COUNTERS; i++) { + if (scu_em_used & (1 << i)) { + scu_reset_counter(emc, i); + event = counter_config[SCU_COUNTER(i)].event; + scu_set_event(emc, i, event); + + /* clear overflow/interrupt */ + temp |= 1 << (i + 16); + /* enable interrupt*/ + temp |= 1 << (i + 8); + } + } + + /* Enable all 8 counters */ + temp |= PMCR_E; + writel(temp, &emc->PMCR); + + return 0; + + err_free_scu: + while (i--) + free_irq(IRQ_PMU_SCU0 + i, NULL); + return ret; +} + +static void scu_stop(void) +{ + struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE; + unsigned int temp, i; + + /* Disable counter interrupts */ + /* Don't disable all 8 counters (with the E bit) as they may be in use */ + temp = readl(&emc->PMCR); + for (i = 0; i < NUM_SCU_COUNTERS; i++) { + if (scu_em_used & (1 << i)) + temp &= ~(1 << (i + 8)); + } + writel(temp, &emc->PMCR); + + /* Free counter interrupts and reset counters */ + for (i = 0; i < NUM_SCU_COUNTERS; i++) { + if (scu_em_used & (1 << i)) { + scu_reset_counter(emc, i); + free_irq(IRQ_PMU_SCU0 + i, NULL); + } + } +} + +struct em_function_data { + int (*fn)(void); + int ret; +}; + +static void em_func(void *data) +{ + struct em_function_data *d = data; + int ret = d->fn(); + if (ret) + d->ret = ret; +} + +static int em_call_function(int (*fn)(void)) +{ + struct em_function_data data; + + data.fn = fn; + data.ret = 0; + + smp_call_function(em_func, &data, 1, 1); + em_func(&data); + + return data.ret; +} + +/* + * Glue to stick the individual ARM11 PMUs and the SCU + * into the oprofile framework. + */ +static int em_setup_ctrs(void) +{ + int ret; + + /* Configure CPU counters by cross-calling to the other CPUs */ + ret = em_call_function(arm11_setup_pmu); + if (ret == 0) + scu_setup(); + + return 0; +} + +static int arm11_irqs[] = { + [0] = IRQ_PMU_CPU0, + [1] = IRQ_PMU_CPU1, + [2] = IRQ_PMU_CPU2, + [3] = IRQ_PMU_CPU3 +}; + +static int em_start(void) +{ + int ret; + + ret = arm11_request_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs)); + if (ret == 0) { + em_call_function(arm11_start_pmu); + + ret = scu_start(); + if (ret) + arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs)); + } + return ret; +} + +static void em_stop(void) +{ + em_call_function(arm11_stop_pmu); + arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs)); + scu_stop(); +} + +/* + * Why isn't there a function to route an IRQ to a specific CPU in + * genirq? + */ +static void em_route_irq(int irq, unsigned int cpu) +{ + irq_desc[irq].affinity = cpumask_of_cpu(cpu); + irq_desc[irq].chip->set_affinity(irq, cpumask_of_cpu(cpu)); +} + +static int em_setup(void) +{ + /* + * Send SCU PMU interrupts to the "owner" CPU. + */ + em_route_irq(IRQ_PMU_SCU0, 0); + em_route_irq(IRQ_PMU_SCU1, 0); + em_route_irq(IRQ_PMU_SCU2, 1); + em_route_irq(IRQ_PMU_SCU3, 1); + em_route_irq(IRQ_PMU_SCU4, 2); + em_route_irq(IRQ_PMU_SCU5, 2); + em_route_irq(IRQ_PMU_SCU6, 3); + em_route_irq(IRQ_PMU_SCU7, 3); + + /* + * Send CP15 PMU interrupts to the owner CPU. + */ + em_route_irq(IRQ_PMU_CPU0, 0); + em_route_irq(IRQ_PMU_CPU1, 1); + em_route_irq(IRQ_PMU_CPU2, 2); + em_route_irq(IRQ_PMU_CPU3, 3); + + return 0; +} + +struct op_arm_model_spec op_mpcore_spec = { + .init = em_setup, + .num_counters = MPCORE_NUM_COUNTERS, + .setup_ctrs = em_setup_ctrs, + .start = em_start, + .stop = em_stop, + .name = "arm/mpcore", +}; diff --git a/arch/arm/oprofile/op_model_mpcore.h b/arch/arm/oprofile/op_model_mpcore.h new file mode 100644 index 00000000000..73d81102368 --- /dev/null +++ b/arch/arm/oprofile/op_model_mpcore.h @@ -0,0 +1,61 @@ +/** + * @file op_model_mpcore.c + * MPCORE Event Monitor Driver + * @remark Copyright 2004 ARM SMP Development Team + * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com> + * @remark Copyright 2000-2004 MontaVista Software Inc + * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com> + * @remark Copyright 2004 Intel Corporation + * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk> + * @remark Copyright 2004 Oprofile Authors + * + * @remark Read the file COPYING + * + * @author Zwane Mwaikambo + */ +#ifndef OP_MODEL_MPCORE_H +#define OP_MODEL_MPCORE_H + +struct eventmonitor { + unsigned long PMCR; + unsigned char MCEB[8]; + unsigned long MC[8]; +}; + +/* + * List of userspace counter numbers: note that the structure is important. + * The code relies on CPUn's counters being CPU0's counters + 3n + * and on CPU0's counters starting at 0 + */ + +#define COUNTER_CPU0_PMN0 0 +#define COUNTER_CPU0_PMN1 1 +#define COUNTER_CPU0_CCNT 2 + +#define COUNTER_CPU1_PMN0 3 +#define COUNTER_CPU1_PMN1 4 +#define COUNTER_CPU1_CCNT 5 + +#define COUNTER_CPU2_PMN0 6 +#define COUNTER_CPU2_PMN1 7 +#define COUNTER_CPU2_CCNT 8 + +#define COUNTER_CPU3_PMN0 9 +#define COUNTER_CPU3_PMN1 10 +#define COUNTER_CPU3_CCNT 11 + +#define COUNTER_SCU_MN0 12 +#define COUNTER_SCU_MN1 13 +#define COUNTER_SCU_MN2 14 +#define COUNTER_SCU_MN3 15 +#define COUNTER_SCU_MN4 16 +#define COUNTER_SCU_MN5 17 +#define COUNTER_SCU_MN6 18 +#define COUNTER_SCU_MN7 19 +#define NUM_SCU_COUNTERS 8 + +#define SCU_COUNTER(number) ((number) + COUNTER_SCU_MN0) + +#define MPCORE_NUM_COUNTERS SCU_COUNTER(NUM_SCU_COUNTERS) + +#endif diff --git a/arch/arm/oprofile/op_model_v6.c b/arch/arm/oprofile/op_model_v6.c new file mode 100644 index 00000000000..fe581383d3e --- /dev/null +++ b/arch/arm/oprofile/op_model_v6.c @@ -0,0 +1,67 @@ +/** + * @file op_model_v6.c + * ARM11 Performance Monitor Driver + * + * Based on op_model_xscale.c + * + * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com> + * @remark Copyright 2000-2004 MontaVista Software Inc + * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com> + * @remark Copyright 2004 Intel Corporation + * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk> + * @remark Copyright 2004 OProfile Authors + * + * @remark Read the file COPYING + * + * @author Tony Lindgren <tony@atomide.com> + */ + +/* #define DEBUG */ +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/oprofile.h> +#include <linux/interrupt.h> +#include <asm/irq.h> +#include <asm/system.h> + +#include "op_counter.h" +#include "op_arm_model.h" +#include "op_model_arm11_core.h" + +static int irqs[] = { +#ifdef CONFIG_ARCH_OMAP2 + 3, +#endif +}; + +static void armv6_pmu_stop(void) +{ + arm11_stop_pmu(); + arm11_release_interrupts(irqs, ARRAY_SIZE(irqs)); +} + +static int armv6_pmu_start(void) +{ + int ret; + + ret = arm11_request_interrupts(irqs, ARRAY_SIZE(irqs)); + if (ret >= 0) + ret = arm11_start_pmu(); + + return ret; +} + +static int armv6_detect_pmu(void) +{ + return 0; +} + +struct op_arm_model_spec op_armv6_spec = { + .init = armv6_detect_pmu, + .num_counters = 3, + .setup_ctrs = arm11_setup_pmu, + .start = armv6_pmu_start, + .stop = armv6_pmu_stop, + .name = "arm/armv6", +}; diff --git a/arch/arm/plat-iop/Makefile b/arch/arm/plat-iop/Makefile index 23da00b1151..3250d732a17 100644 --- a/arch/arm/plat-iop/Makefile +++ b/arch/arm/plat-iop/Makefile @@ -2,7 +2,29 @@ # Makefile for the linux kernel. # -obj-y := gpio.o i2c.o pci.o setup.o time.o -obj-m := -obj-n := -obj- := +obj-y := + +# IOP32X +obj-$(CONFIG_ARCH_IOP32X) += gpio.o +obj-$(CONFIG_ARCH_IOP32X) += i2c.o +obj-$(CONFIG_ARCH_IOP32X) += pci.o +obj-$(CONFIG_ARCH_IOP32X) += setup.o +obj-$(CONFIG_ARCH_IOP32X) += time.o +obj-$(CONFIG_ARCH_IOP32X) += io.o +obj-$(CONFIG_ARCH_IOP32X) += cp6.o + +# IOP33X +obj-$(CONFIG_ARCH_IOP33X) += gpio.o +obj-$(CONFIG_ARCH_IOP33X) += i2c.o +obj-$(CONFIG_ARCH_IOP33X) += pci.o +obj-$(CONFIG_ARCH_IOP33X) += setup.o +obj-$(CONFIG_ARCH_IOP33X) += time.o +obj-$(CONFIG_ARCH_IOP33X) += io.o +obj-$(CONFIG_ARCH_IOP33X) += cp6.o + +# IOP13XX +obj-$(CONFIG_ARCH_IOP13XX) += cp6.o + +obj-m := +obj-n := +obj- := diff --git a/arch/arm/plat-iop/cp6.c b/arch/arm/plat-iop/cp6.c new file mode 100644 index 00000000000..9612a87e2a8 --- /dev/null +++ b/arch/arm/plat-iop/cp6.c @@ -0,0 +1,50 @@ +/* + * IOP Coprocessor-6 access handler + * Copyright (c) 2006, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ +#include <linux/init.h> +#include <asm/traps.h> + +static int cp6_trap(struct pt_regs *regs, unsigned int instr) +{ + u32 temp; + + /* enable cp6 access */ + asm volatile ( + "mrc p15, 0, %0, c15, c1, 0\n\t" + "orr %0, %0, #(1 << 6)\n\t" + "mcr p15, 0, %0, c15, c1, 0\n\t" + : "=r"(temp)); + + return 0; +} + +/* permit kernel space cp6 access + * deny user space cp6 access + */ +static struct undef_hook cp6_hook = { + .instr_mask = 0x0f000ff0, + .instr_val = 0x0e000610, + .cpsr_mask = MODE_MASK, + .cpsr_val = SVC_MODE, + .fn = cp6_trap, +}; + +void __init iop_init_cp6_handler(void) +{ + register_undef_hook(&cp6_hook); +} diff --git a/arch/arm/plat-iop/io.c b/arch/arm/plat-iop/io.c new file mode 100644 index 00000000000..f7eccecf2e4 --- /dev/null +++ b/arch/arm/plat-iop/io.c @@ -0,0 +1,58 @@ +/* + * iop3xx custom ioremap implementation + * Copyright (c) 2006, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <asm/hardware.h> +#include <asm/io.h> + +void * __iomem __iop3xx_ioremap(unsigned long cookie, size_t size, + unsigned long flags) +{ + void __iomem * retval; + + switch (cookie) { + case IOP3XX_PCI_LOWER_IO_PA ... IOP3XX_PCI_UPPER_IO_PA: + retval = (void *) IOP3XX_PCI_IO_PHYS_TO_VIRT(cookie); + break; + case IOP3XX_PERIPHERAL_PHYS_BASE ... IOP3XX_PERIPHERAL_UPPER_PA: + retval = (void *) IOP3XX_PMMR_PHYS_TO_VIRT(cookie); + break; + default: + retval = __ioremap(cookie, size, flags); + } + + return retval; +} +EXPORT_SYMBOL(__iop3xx_ioremap); + +void __iop3xx_iounmap(void __iomem *addr) +{ + extern void __iounmap(volatile void __iomem *addr); + + switch ((u32) addr) { + case IOP3XX_PCI_LOWER_IO_VA ... IOP3XX_PCI_UPPER_IO_VA: + case IOP3XX_PERIPHERAL_VIRT_BASE ... IOP3XX_PERIPHERAL_UPPER_VA: + goto skip; + } + __iounmap(addr); + +skip: + return; +} +EXPORT_SYMBOL(__iop3xx_iounmap); diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/plat-iop/pci.c index e647812654f..b5f6ec35aaf 100644 --- a/arch/arm/plat-iop/pci.c +++ b/arch/arm/plat-iop/pci.c @@ -196,8 +196,8 @@ int iop3xx_pci_setup(int nr, struct pci_sys_data *sys) if (!res) panic("PCI: unable to alloc resources"); - res[0].start = IOP3XX_PCI_LOWER_IO_VA; - res[0].end = IOP3XX_PCI_LOWER_IO_VA + IOP3XX_PCI_IO_WINDOW_SIZE - 1; + res[0].start = IOP3XX_PCI_LOWER_IO_PA; + res[0].end = IOP3XX_PCI_LOWER_IO_PA + IOP3XX_PCI_IO_WINDOW_SIZE - 1; res[0].name = "IOP3XX PCI I/O Space"; res[0].flags = IORESOURCE_IO; request_resource(&ioport_resource, &res[0]); @@ -209,7 +209,7 @@ int iop3xx_pci_setup(int nr, struct pci_sys_data *sys) request_resource(&iomem_resource, &res[1]); sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - IOP3XX_PCI_LOWER_MEM_BA; - sys->io_offset = IOP3XX_PCI_LOWER_IO_VA - IOP3XX_PCI_LOWER_IO_BA; + sys->io_offset = IOP3XX_PCI_LOWER_IO_PA - IOP3XX_PCI_LOWER_IO_BA; sys->resource[0] = &res[0]; sys->resource[1] = &res[1]; diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig new file mode 100644 index 00000000000..e2234316063 --- /dev/null +++ b/arch/arm/plat-s3c24xx/Kconfig @@ -0,0 +1,99 @@ +# arch/arm/plat-s3c24xx/Kconfig +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + +config PLAT_S3C24XX + bool + depends on ARCH_S3C2410 + default y if ARCH_S3C2410 + help + Base platform code for any Samsung S3C device + +if PLAT_S3C24XX + +config CPU_S3C244X + bool + depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442) + help + Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems. + +config PM_SIMTEC + bool + help + Common power management code for systems that are + compatible with the Simtec style of power management + +config S3C2410_BOOT_WATCHDOG + bool "S3C2410 Initialisation watchdog" + depends on ARCH_S3C2410 && S3C2410_WATCHDOG + help + Say y to enable the watchdog during the kernel decompression + stage. If the kernel fails to uncompress, then the watchdog + will trigger a reset and the system should restart. + +config S3C2410_BOOT_ERROR_RESET + bool "S3C2410 Reboot on decompression error" + depends on ARCH_S3C2410 + help + Say y here to use the watchdog to reset the system if the + kernel decompressor detects an error during decompression. + +config S3C2410_PM_DEBUG + bool "S3C2410 PM Suspend debug" + depends on ARCH_S3C2410 && PM + help + Say Y here if you want verbose debugging from the PM Suspend and + Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt> + for more information. + +config S3C2410_PM_CHECK + bool "S3C2410 PM Suspend Memory CRC" + depends on ARCH_S3C2410 && PM && CRC32 + help + Enable the PM code's memory area checksum over sleep. This option + will generate CRCs of all blocks of memory, and store them before + going to sleep. The blocks are then checked on resume for any + errors. + +config S3C2410_PM_CHECK_CHUNKSIZE + int "S3C2410 PM Suspend CRC Chunksize (KiB)" + depends on ARCH_S3C2410 && PM && S3C2410_PM_CHECK + default 64 + help + Set the chunksize in Kilobytes of the CRC for checking memory + corruption over suspend and resume. A smaller value will mean that + the CRC data block will take more memory, but wil identify any + faults with better precision. + +config S3C2410_LOWLEVEL_UART_PORT + int "S3C2410 UART to use for low-level messages" + default 0 + help + Choice of which UART port to use for the low-level messages, + such as the `Uncompressing...` at start time. The value of + this configuration should be between zero and two. The port + must have been initialised by the boot-loader before use. + +config S3C2410_DMA + bool "S3C2410 DMA support" + depends on ARCH_S3C2410 + help + S3C2410 DMA support. This is needed for drivers like sound which + use the S3C2410's DMA system to move data to and from the + peripheral blocks. + +config S3C2410_DMA_DEBUG + bool "S3C2410 DMA support debug" + depends on ARCH_S3C2410 && S3C2410_DMA + help + Enable debugging output for the DMA code. This option sends info + to the kernel log, at priority KERN_DEBUG. + +config MACH_SMDK + bool + help + Common machine code for SMDK2410 and SMDK2440 + +endif diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile new file mode 100644 index 00000000000..8e5ccaa1f03 --- /dev/null +++ b/arch/arm/plat-s3c24xx/Makefile @@ -0,0 +1,30 @@ +# arch/arm/plat-s3c24xx/Makefile +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + +obj-y := +obj-m := +obj-n := +obj- := + + +# Core files + +obj-y += cpu.o +obj-y += irq.o +obj-y += devs.o +obj-y += gpio.o +obj-y += time.o +obj-y += clock.o + +# Architecture dependant builds + +obj-$(CONFIG_CPU_S3C244X) += s3c244x.o +obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o +obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o +obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_PM) += sleep.o +obj-$(CONFIG_S3C2410_DMA) += dma.o +obj-$(CONFIG_MACH_SMDK) += common-smdk.o diff --git a/arch/arm/plat-s3c24xx/clock.c b/arch/arm/plat-s3c24xx/clock.c new file mode 100644 index 00000000000..d3dc03a7383 --- /dev/null +++ b/arch/arm/plat-s3c24xx/clock.c @@ -0,0 +1,449 @@ +/* linux/arch/arm/plat-s3c24xx/clock.c + * + * Copyright (c) 2004-2005 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C24XX Core clock control support + * + * Based on, and code from linux/arch/arm/mach-versatile/clock.c + ** + ** Copyright (C) 2004 ARM Limited. + ** Written by Deep Blue Solutions Limited. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/sysdev.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/clk.h> +#include <linux/mutex.h> +#include <linux/delay.h> + +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/io.h> + +#include <asm/arch/regs-clock.h> +#include <asm/arch/regs-gpio.h> + +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/cpu.h> + +/* clock information */ + +static LIST_HEAD(clocks); + +DEFINE_MUTEX(clocks_mutex); + +/* enable and disable calls for use with the clk struct */ + +static int clk_null_enable(struct clk *clk, int enable) +{ + return 0; +} + +/* Clock API calls */ + +struct clk *clk_get(struct device *dev, const char *id) +{ + struct clk *p; + struct clk *clk = ERR_PTR(-ENOENT); + int idno; + + if (dev == NULL || dev->bus != &platform_bus_type) + idno = -1; + else + idno = to_platform_device(dev)->id; + + mutex_lock(&clocks_mutex); + + list_for_each_entry(p, &clocks, list) { + if (p->id == idno && + strcmp(id, p->name) == 0 && + try_module_get(p->owner)) { + clk = p; + break; + } + } + + /* check for the case where a device was supplied, but the + * clock that was being searched for is not device specific */ + + if (IS_ERR(clk)) { + list_for_each_entry(p, &clocks, list) { + if (p->id == -1 && strcmp(id, p->name) == 0 && + try_module_get(p->owner)) { + clk = p; + break; + } + } + } + + mutex_unlock(&clocks_mutex); + return clk; +} + +void clk_put(struct clk *clk) +{ + module_put(clk->owner); +} + +int clk_enable(struct clk *clk) +{ + if (IS_ERR(clk) || clk == NULL) + return -EINVAL; + + clk_enable(clk->parent); + + mutex_lock(&clocks_mutex); + + if ((clk->usage++) == 0) + (clk->enable)(clk, 1); + + mutex_unlock(&clocks_mutex); + return 0; +} + +void clk_disable(struct clk *clk) +{ + if (IS_ERR(clk) || clk == NULL) + return; + + mutex_lock(&clocks_mutex); + + if ((--clk->usage) == 0) + (clk->enable)(clk, 0); + + mutex_unlock(&clocks_mutex); + clk_disable(clk->parent); +} + + +unsigned long clk_get_rate(struct clk *clk) +{ + if (IS_ERR(clk)) + return 0; + + if (clk->rate != 0) + return clk->rate; + + if (clk->get_rate != NULL) + return (clk->get_rate)(clk); + + if (clk->parent != NULL) + return clk_get_rate(clk->parent); + + return clk->rate; +} + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (!IS_ERR(clk) && clk->round_rate) + return (clk->round_rate)(clk, rate); + + return rate; +} + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + int ret; + + if (IS_ERR(clk)) + return -EINVAL; + + mutex_lock(&clocks_mutex); + ret = (clk->set_rate)(clk, rate); + mutex_unlock(&clocks_mutex); + + return ret; +} + +struct clk *clk_get_parent(struct clk *clk) +{ + return clk->parent; +} + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + int ret = 0; + + if (IS_ERR(clk)) + return -EINVAL; + + mutex_lock(&clocks_mutex); + + if (clk->set_parent) + ret = (clk->set_parent)(clk, parent); + + mutex_unlock(&clocks_mutex); + + return ret; +} + +EXPORT_SYMBOL(clk_get); +EXPORT_SYMBOL(clk_put); +EXPORT_SYMBOL(clk_enable); +EXPORT_SYMBOL(clk_disable); +EXPORT_SYMBOL(clk_get_rate); +EXPORT_SYMBOL(clk_round_rate); +EXPORT_SYMBOL(clk_set_rate); +EXPORT_SYMBOL(clk_get_parent); +EXPORT_SYMBOL(clk_set_parent); + +/* base clocks */ + +struct clk clk_xtal = { + .name = "xtal", + .id = -1, + .rate = 0, + .parent = NULL, + .ctrlbit = 0, +}; + +struct clk clk_mpll = { + .name = "mpll", + .id = -1, +}; + +struct clk clk_upll = { + .name = "upll", + .id = -1, + .parent = NULL, + .ctrlbit = 0, +}; + +struct clk clk_f = { + .name = "fclk", + .id = -1, + .rate = 0, + .parent = &clk_mpll, + .ctrlbit = 0, +}; + +struct clk clk_h = { + .name = "hclk", + .id = -1, + .rate = 0, + .parent = NULL, + .ctrlbit = 0, +}; + +struct clk clk_p = { + .name = "pclk", + .id = -1, + .rate = 0, + .parent = NULL, + .ctrlbit = 0, +}; + +struct clk clk_usb_bus = { + .name = "usb-bus", + .id = -1, + .rate = 0, + .parent = &clk_upll, +}; + +/* clocks that could be registered by external code */ + +static int s3c24xx_dclk_enable(struct clk *clk, int enable) +{ + unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON); + + if (enable) + dclkcon |= clk->ctrlbit; + else + dclkcon &= ~clk->ctrlbit; + + __raw_writel(dclkcon, S3C24XX_DCLKCON); + + return 0; +} + +static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent) +{ + unsigned long dclkcon; + unsigned int uclk; + + if (parent == &clk_upll) + uclk = 1; + else if (parent == &clk_p) + uclk = 0; + else + return -EINVAL; + + clk->parent = parent; + + dclkcon = __raw_readl(S3C24XX_DCLKCON); + + if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) { + if (uclk) + dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK; + else + dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK; + } else { + if (uclk) + dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK; + else + dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK; + } + + __raw_writel(dclkcon, S3C24XX_DCLKCON); + + return 0; +} + + +static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent) +{ + unsigned long mask; + unsigned long source; + + /* calculate the MISCCR setting for the clock */ + + if (parent == &clk_xtal) + source = S3C2410_MISCCR_CLK0_MPLL; + else if (parent == &clk_upll) + source = S3C2410_MISCCR_CLK0_UPLL; + else if (parent == &clk_f) + source = S3C2410_MISCCR_CLK0_FCLK; + else if (parent == &clk_h) + source = S3C2410_MISCCR_CLK0_HCLK; + else if (parent == &clk_p) + source = S3C2410_MISCCR_CLK0_PCLK; + else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0) + source = S3C2410_MISCCR_CLK0_DCLK0; + else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1) + source = S3C2410_MISCCR_CLK0_DCLK0; + else + return -EINVAL; + + clk->parent = parent; + + if (clk == &s3c24xx_dclk0) + mask = S3C2410_MISCCR_CLK0_MASK; + else { + source <<= 4; + mask = S3C2410_MISCCR_CLK1_MASK; + } + + s3c2410_modify_misccr(mask, source); + return 0; +} + +/* external clock definitions */ + +struct clk s3c24xx_dclk0 = { + .name = "dclk0", + .id = -1, + .ctrlbit = S3C2410_DCLKCON_DCLK0EN, + .enable = s3c24xx_dclk_enable, + .set_parent = s3c24xx_dclk_setparent, +}; + +struct clk s3c24xx_dclk1 = { + .name = "dclk1", + .id = -1, + .ctrlbit = S3C2410_DCLKCON_DCLK0EN, + .enable = s3c24xx_dclk_enable, + .set_parent = s3c24xx_dclk_setparent, +}; + +struct clk s3c24xx_clkout0 = { + .name = "clkout0", + .id = -1, + .set_parent = s3c24xx_clkout_setparent, +}; + +struct clk s3c24xx_clkout1 = { + .name = "clkout1", + .id = -1, + .set_parent = s3c24xx_clkout_setparent, +}; + +struct clk s3c24xx_uclk = { + .name = "uclk", + .id = -1, +}; + +/* initialise the clock system */ + +int s3c24xx_register_clock(struct clk *clk) +{ + clk->owner = THIS_MODULE; + + if (clk->enable == NULL) + clk->enable = clk_null_enable; + + /* add to the list of available clocks */ + + mutex_lock(&clocks_mutex); + list_add(&clk->list, &clocks); + mutex_unlock(&clocks_mutex); + + return 0; +} + +/* initalise all the clocks */ + +int __init s3c24xx_setup_clocks(unsigned long xtal, + unsigned long fclk, + unsigned long hclk, + unsigned long pclk) +{ + printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n"); + + /* initialise the main system clocks */ + + clk_xtal.rate = xtal; + clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal); + + clk_mpll.rate = fclk; + clk_h.rate = hclk; + clk_p.rate = pclk; + clk_f.rate = fclk; + + /* assume uart clocks are correctly setup */ + + /* register our clocks */ + + if (s3c24xx_register_clock(&clk_xtal) < 0) + printk(KERN_ERR "failed to register master xtal\n"); + + if (s3c24xx_register_clock(&clk_mpll) < 0) + printk(KERN_ERR "failed to register mpll clock\n"); + + if (s3c24xx_register_clock(&clk_upll) < 0) + printk(KERN_ERR "failed to register upll clock\n"); + + if (s3c24xx_register_clock(&clk_f) < 0) + printk(KERN_ERR "failed to register cpu fclk\n"); + + if (s3c24xx_register_clock(&clk_h) < 0) + printk(KERN_ERR "failed to register cpu hclk\n"); + + if (s3c24xx_register_clock(&clk_p) < 0) + printk(KERN_ERR "failed to register cpu pclk\n"); + + return 0; +} diff --git a/arch/arm/mach-s3c2410/common-smdk.c b/arch/arm/plat-s3c24xx/common-smdk.c index a40eaa65617..908efa7d745 100644 --- a/arch/arm/mach-s3c2410/common-smdk.c +++ b/arch/arm/plat-s3c24xx/common-smdk.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/common-smdk.c +/* linux/arch/arm/plat-s3c24xx/common-smdk.c * * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -38,9 +38,9 @@ #include <asm/arch/nand.h> -#include "common-smdk.h" -#include "devs.h" -#include "pm.h" +#include <asm/plat-s3c24xx/common-smdk.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/pm.h> /* LED devices */ diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/plat-s3c24xx/cpu.c index ae1f5bb63f7..6a2d1070e5a 100644 --- a/arch/arm/mach-s3c2410/cpu.c +++ b/arch/arm/plat-s3c24xx/cpu.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/cpu.c +/* linux/arch/arm/plat-s3c24xx/cpu.c * * Copyright (c) 2004-2005 Simtec Electronics * http://www.simtec.co.uk/products/SWLINUX/ @@ -40,15 +40,16 @@ #include <asm/arch/regs-gpio.h> #include <asm/arch/regs-serial.h> -#include "cpu.h" -#include "devs.h" -#include "clock.h" -#include "s3c2400.h" -#include "s3c2410.h" -#include "s3c2412.h" +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/s3c2400.h> +#include <asm/plat-s3c24xx/s3c2410.h> +#include <asm/plat-s3c24xx/s3c2412.h> #include "s3c244x.h" -#include "s3c2440.h" -#include "s3c2442.h" +#include <asm/plat-s3c24xx/s3c2440.h> +#include <asm/plat-s3c24xx/s3c2442.h> +#include <asm/plat-s3c24xx/s3c2443.h> struct cpu_table { unsigned long idcode; @@ -67,6 +68,7 @@ static const char name_s3c2410[] = "S3C2410"; static const char name_s3c2412[] = "S3C2412"; static const char name_s3c2440[] = "S3C2440"; static const char name_s3c2442[] = "S3C2442"; +static const char name_s3c2443[] = "S3C2443"; static const char name_s3c2410a[] = "S3C2410A"; static const char name_s3c2440a[] = "S3C2440A"; @@ -135,6 +137,15 @@ static struct cpu_table cpu_ids[] __initdata = { .name = name_s3c2412, }, { + .idcode = 0x32443001, + .idmask = 0xffffffff, + .map_io = s3c2443_map_io, + .init_clocks = s3c2443_init_clocks, + .init_uarts = s3c2443_init_uarts, + .init = s3c2443_init, + .name = name_s3c2443, + }, + { .idcode = 0x0, /* S3C2400 doesn't have an idcode */ .idmask = 0xffffffff, .map_io = s3c2400_map_io, diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/plat-s3c24xx/devs.c index faccde2092d..0fe53b39cb2 100644 --- a/arch/arm/mach-s3c2410/devs.c +++ b/arch/arm/plat-s3c24xx/devs.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/devs.c +/* linux/arch/arm/plat-s3c24xx/devs.c * * Copyright (c) 2004 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -29,9 +29,10 @@ #include <asm/irq.h> #include <asm/arch/regs-serial.h> +#include <asm/arch/udc.h> -#include "devs.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> /* Serial port registrations */ @@ -230,6 +231,20 @@ struct platform_device s3c_device_usbgadget = { EXPORT_SYMBOL(s3c_device_usbgadget); +void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *pd) +{ + struct s3c2410_udc_mach_info *npd; + + npd = kmalloc(sizeof(*npd), GFP_KERNEL); + if (npd) { + memcpy(npd, pd, sizeof(*npd)); + s3c_device_usbgadget.dev.platform_data = npd; + } else { + printk(KERN_ERR "no memory for udc platform data\n"); + } +} + + /* Watchdog */ static struct resource s3c_wdt_resource[] = { diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c new file mode 100644 index 00000000000..4540a806f52 --- /dev/null +++ b/arch/arm/plat-s3c24xx/dma.c @@ -0,0 +1,1499 @@ +/* linux/arch/arm/plat-s3c24xx/dma.c + * + * Copyright (c) 2003-2005,2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 DMA core + * + * http://armlinux.simtec.co.uk/ + * + * 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. +*/ + + +#ifdef CONFIG_S3C2410_DMA_DEBUG +#define DEBUG +#endif + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/sysdev.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/delay.h> + +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/dma.h> + +#include <asm/mach/dma.h> +#include <asm/arch/map.h> + +#include <asm/plat-s3c24xx/dma.h> + +/* io map for dma */ +static void __iomem *dma_base; +static struct kmem_cache *dma_kmem; + +static int dma_channels; + +struct s3c24xx_dma_selection dma_sel; + +/* dma channel state information */ +struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS]; + +/* debugging functions */ + +#define BUF_MAGIC (0xcafebabe) + +#define dmawarn(fmt...) printk(KERN_DEBUG fmt) + +#define dma_regaddr(chan, reg) ((chan)->regs + (reg)) + +#if 1 +#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg)) +#else +static inline void +dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val) +{ + pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg); + writel(val, dma_regaddr(chan, reg)); +} +#endif + +#define dma_rdreg(chan, reg) readl((chan)->regs + (reg)) + +/* captured register state for debug */ + +struct s3c2410_dma_regstate { + unsigned long dcsrc; + unsigned long disrc; + unsigned long dstat; + unsigned long dcon; + unsigned long dmsktrig; +}; + +#ifdef CONFIG_S3C2410_DMA_DEBUG + +/* dmadbg_showregs + * + * simple debug routine to print the current state of the dma registers +*/ + +static void +dmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs) +{ + regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC); + regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC); + regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT); + regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON); + regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); +} + +static void +dmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan, + struct s3c2410_dma_regstate *regs) +{ + printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n", + chan->number, fname, line, + regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig, + regs->dcon); +} + +static void +dmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan) +{ + struct s3c2410_dma_regstate state; + + dmadbg_capture(chan, &state); + + printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n", + chan->number, fname, line, chan->load_state, + chan->curr, chan->next, chan->end); + + dmadbg_dumpregs(fname, line, chan, &state); +} + +static void +dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan) +{ + struct s3c2410_dma_regstate state; + + dmadbg_capture(chan, &state); + dmadbg_dumpregs(fname, line, chan, &state); +} + +#define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan)) +#define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan)) +#else +#define dbg_showregs(chan) do { } while(0) +#define dbg_showchan(chan) do { } while(0) +#endif /* CONFIG_S3C2410_DMA_DEBUG */ + +static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX]; + +/* lookup_dma_channel + * + * change the dma channel number given into a real dma channel id +*/ + +static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel) +{ + if (channel & DMACH_LOW_LEVEL) + return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL]; + else + return dma_chan_map[channel]; +} + +/* s3c2410_dma_stats_timeout + * + * Update DMA stats from timeout info +*/ + +static void +s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val) +{ + if (stats == NULL) + return; + + if (val > stats->timeout_longest) + stats->timeout_longest = val; + if (val < stats->timeout_shortest) + stats->timeout_shortest = val; + + stats->timeout_avg += val; +} + +/* s3c2410_dma_waitforload + * + * wait for the DMA engine to load a buffer, and update the state accordingly +*/ + +static int +s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line) +{ + int timeout = chan->load_timeout; + int took; + + if (chan->load_state != S3C2410_DMALOAD_1LOADED) { + printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line); + return 0; + } + + if (chan->stats != NULL) + chan->stats->loads++; + + while (--timeout > 0) { + if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) { + took = chan->load_timeout - timeout; + + s3c2410_dma_stats_timeout(chan->stats, took); + + switch (chan->load_state) { + case S3C2410_DMALOAD_1LOADED: + chan->load_state = S3C2410_DMALOAD_1RUNNING; + break; + + default: + printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state); + } + + return 1; + } + } + + if (chan->stats != NULL) { + chan->stats->timeout_failed++; + } + + return 0; +} + + + +/* s3c2410_dma_loadbuffer + * + * load a buffer, and update the channel state +*/ + +static inline int +s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan, + struct s3c2410_dma_buf *buf) +{ + unsigned long reload; + + pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n", + buf, (unsigned long)buf->data, buf->size); + + if (buf == NULL) { + dmawarn("buffer is NULL\n"); + return -EINVAL; + } + + /* check the state of the channel before we do anything */ + + if (chan->load_state == S3C2410_DMALOAD_1LOADED) { + dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n"); + } + + if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) { + dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n"); + } + + /* it would seem sensible if we are the last buffer to not bother + * with the auto-reload bit, so that the DMA engine will not try + * and load another transfer after this one has finished... + */ + if (chan->load_state == S3C2410_DMALOAD_NONE) { + pr_debug("load_state is none, checking for noreload (next=%p)\n", + buf->next); + reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0; + } else { + //pr_debug("load_state is %d => autoreload\n", chan->load_state); + reload = S3C2410_DCON_AUTORELOAD; + } + + if ((buf->data & 0xf0000000) != 0x30000000) { + dmawarn("dmaload: buffer is %p\n", (void *)buf->data); + } + + writel(buf->data, chan->addr_reg); + + dma_wrreg(chan, S3C2410_DMA_DCON, + chan->dcon | reload | (buf->size/chan->xfer_unit)); + + chan->next = buf->next; + + /* update the state of the channel */ + + switch (chan->load_state) { + case S3C2410_DMALOAD_NONE: + chan->load_state = S3C2410_DMALOAD_1LOADED; + break; + + case S3C2410_DMALOAD_1RUNNING: + chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING; + break; + + default: + dmawarn("dmaload: unknown state %d in loadbuffer\n", + chan->load_state); + break; + } + + return 0; +} + +/* s3c2410_dma_call_op + * + * small routine to call the op routine with the given op if it has been + * registered +*/ + +static void +s3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op) +{ + if (chan->op_fn != NULL) { + (chan->op_fn)(chan, op); + } +} + +/* s3c2410_dma_buffdone + * + * small wrapper to check if callback routine needs to be called, and + * if so, call it +*/ + +static inline void +s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf, + enum s3c2410_dma_buffresult result) +{ +#if 0 + pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n", + chan->callback_fn, buf, buf->id, buf->size, result); +#endif + + if (chan->callback_fn != NULL) { + (chan->callback_fn)(chan, buf->id, buf->size, result); + } +} + +/* s3c2410_dma_start + * + * start a dma channel going +*/ + +static int s3c2410_dma_start(struct s3c2410_dma_chan *chan) +{ + unsigned long tmp; + unsigned long flags; + + pr_debug("s3c2410_start_dma: channel=%d\n", chan->number); + + local_irq_save(flags); + + if (chan->state == S3C2410_DMA_RUNNING) { + pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state); + local_irq_restore(flags); + return 0; + } + + chan->state = S3C2410_DMA_RUNNING; + + /* check wether there is anything to load, and if not, see + * if we can find anything to load + */ + + if (chan->load_state == S3C2410_DMALOAD_NONE) { + if (chan->next == NULL) { + printk(KERN_ERR "dma%d: channel has nothing loaded\n", + chan->number); + chan->state = S3C2410_DMA_IDLE; + local_irq_restore(flags); + return -EINVAL; + } + + s3c2410_dma_loadbuffer(chan, chan->next); + } + + dbg_showchan(chan); + + /* enable the channel */ + + if (!chan->irq_enabled) { + enable_irq(chan->irq); + chan->irq_enabled = 1; + } + + /* start the channel going */ + + tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); + tmp &= ~S3C2410_DMASKTRIG_STOP; + tmp |= S3C2410_DMASKTRIG_ON; + dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); + + pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp); + +#if 0 + /* the dma buffer loads should take care of clearing the AUTO + * reloading feature */ + tmp = dma_rdreg(chan, S3C2410_DMA_DCON); + tmp &= ~S3C2410_DCON_NORELOAD; + dma_wrreg(chan, S3C2410_DMA_DCON, tmp); +#endif + + s3c2410_dma_call_op(chan, S3C2410_DMAOP_START); + + dbg_showchan(chan); + + /* if we've only loaded one buffer onto the channel, then chec + * to see if we have another, and if so, try and load it so when + * the first buffer is finished, the new one will be loaded onto + * the channel */ + + if (chan->next != NULL) { + if (chan->load_state == S3C2410_DMALOAD_1LOADED) { + + if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { + pr_debug("%s: buff not yet loaded, no more todo\n", + __FUNCTION__); + } else { + chan->load_state = S3C2410_DMALOAD_1RUNNING; + s3c2410_dma_loadbuffer(chan, chan->next); + } + + } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) { + s3c2410_dma_loadbuffer(chan, chan->next); + } + } + + + local_irq_restore(flags); + + return 0; +} + +/* s3c2410_dma_canload + * + * work out if we can queue another buffer into the DMA engine +*/ + +static int +s3c2410_dma_canload(struct s3c2410_dma_chan *chan) +{ + if (chan->load_state == S3C2410_DMALOAD_NONE || + chan->load_state == S3C2410_DMALOAD_1RUNNING) + return 1; + + return 0; +} + +/* s3c2410_dma_enqueue + * + * queue an given buffer for dma transfer. + * + * id the device driver's id information for this buffer + * data the physical address of the buffer data + * size the size of the buffer in bytes + * + * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART + * is checked, and if set, the channel is started. If this flag isn't set, + * then an error will be returned. + * + * It is possible to queue more than one DMA buffer onto a channel at + * once, and the code will deal with the re-loading of the next buffer + * when necessary. +*/ + +int s3c2410_dma_enqueue(unsigned int channel, void *id, + dma_addr_t data, int size) +{ + struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + struct s3c2410_dma_buf *buf; + unsigned long flags; + + if (chan == NULL) + return -EINVAL; + + pr_debug("%s: id=%p, data=%08x, size=%d\n", + __FUNCTION__, id, (unsigned int)data, size); + + buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC); + if (buf == NULL) { + pr_debug("%s: out of memory (%ld alloc)\n", + __FUNCTION__, (long)sizeof(*buf)); + return -ENOMEM; + } + + //pr_debug("%s: new buffer %p\n", __FUNCTION__, buf); + //dbg_showchan(chan); + + buf->next = NULL; + buf->data = buf->ptr = data; + buf->size = size; + buf->id = id; + buf->magic = BUF_MAGIC; + + local_irq_save(flags); + + if (chan->curr == NULL) { + /* we've got nothing loaded... */ + pr_debug("%s: buffer %p queued onto empty channel\n", + __FUNCTION__, buf); + + chan->curr = buf; + chan->end = buf; + chan->next = NULL; + } else { + pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n", + chan->number, __FUNCTION__, buf); + + if (chan->end == NULL) + pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n", + chan->number, __FUNCTION__, chan); + + chan->end->next = buf; + chan->end = buf; + } + + /* if necessary, update the next buffer field */ + if (chan->next == NULL) + chan->next = buf; + + /* check to see if we can load a buffer */ + if (chan->state == S3C2410_DMA_RUNNING) { + if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) { + if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { + printk(KERN_ERR "dma%d: loadbuffer:" + "timeout loading buffer\n", + chan->number); + dbg_showchan(chan); + local_irq_restore(flags); + return -EINVAL; + } + } + + while (s3c2410_dma_canload(chan) && chan->next != NULL) { + s3c2410_dma_loadbuffer(chan, chan->next); + } + } else if (chan->state == S3C2410_DMA_IDLE) { + if (chan->flags & S3C2410_DMAF_AUTOSTART) { + s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START); + } + } + + local_irq_restore(flags); + return 0; +} + +EXPORT_SYMBOL(s3c2410_dma_enqueue); + +static inline void +s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf) +{ + int magicok = (buf->magic == BUF_MAGIC); + + buf->magic = -1; + + if (magicok) { + kmem_cache_free(dma_kmem, buf); + } else { + printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf); + } +} + +/* s3c2410_dma_lastxfer + * + * called when the system is out of buffers, to ensure that the channel + * is prepared for shutdown. +*/ + +static inline void +s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan) +{ +#if 0 + pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n", + chan->number, chan->load_state); +#endif + + switch (chan->load_state) { + case S3C2410_DMALOAD_NONE: + break; + + case S3C2410_DMALOAD_1LOADED: + if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { + /* flag error? */ + printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n", + chan->number, __FUNCTION__); + return; + } + break; + + case S3C2410_DMALOAD_1LOADED_1RUNNING: + /* I belive in this case we do not have anything to do + * until the next buffer comes along, and we turn off the + * reload */ + return; + + default: + pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n", + chan->number, chan->load_state); + return; + + } + + /* hopefully this'll shut the damned thing up after the transfer... */ + dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD); +} + + +#define dmadbg2(x...) + +static irqreturn_t +s3c2410_dma_irq(int irq, void *devpw) +{ + struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw; + struct s3c2410_dma_buf *buf; + + buf = chan->curr; + + dbg_showchan(chan); + + /* modify the channel state */ + + switch (chan->load_state) { + case S3C2410_DMALOAD_1RUNNING: + /* TODO - if we are running only one buffer, we probably + * want to reload here, and then worry about the buffer + * callback */ + + chan->load_state = S3C2410_DMALOAD_NONE; + break; + + case S3C2410_DMALOAD_1LOADED: + /* iirc, we should go back to NONE loaded here, we + * had a buffer, and it was never verified as being + * loaded. + */ + + chan->load_state = S3C2410_DMALOAD_NONE; + break; + + case S3C2410_DMALOAD_1LOADED_1RUNNING: + /* we'll worry about checking to see if another buffer is + * ready after we've called back the owner. This should + * ensure we do not wait around too long for the DMA + * engine to start the next transfer + */ + + chan->load_state = S3C2410_DMALOAD_1LOADED; + break; + + case S3C2410_DMALOAD_NONE: + printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n", + chan->number); + break; + + default: + printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n", + chan->number, chan->load_state); + break; + } + + if (buf != NULL) { + /* update the chain to make sure that if we load any more + * buffers when we call the callback function, things should + * work properly */ + + chan->curr = buf->next; + buf->next = NULL; + + if (buf->magic != BUF_MAGIC) { + printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n", + chan->number, __FUNCTION__, buf); + return IRQ_HANDLED; + } + + s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK); + + /* free resouces */ + s3c2410_dma_freebuf(buf); + } else { + } + + /* only reload if the channel is still running... our buffer done + * routine may have altered the state by requesting the dma channel + * to stop or shutdown... */ + + /* todo: check that when the channel is shut-down from inside this + * function, we cope with unsetting reload, etc */ + + if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) { + unsigned long flags; + + switch (chan->load_state) { + case S3C2410_DMALOAD_1RUNNING: + /* don't need to do anything for this state */ + break; + + case S3C2410_DMALOAD_NONE: + /* can load buffer immediately */ + break; + + case S3C2410_DMALOAD_1LOADED: + if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { + /* flag error? */ + printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n", + chan->number, __FUNCTION__); + return IRQ_HANDLED; + } + + break; + + case S3C2410_DMALOAD_1LOADED_1RUNNING: + goto no_load; + + default: + printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n", + chan->number, chan->load_state); + return IRQ_HANDLED; + } + + local_irq_save(flags); + s3c2410_dma_loadbuffer(chan, chan->next); + local_irq_restore(flags); + } else { + s3c2410_dma_lastxfer(chan); + + /* see if we can stop this channel.. */ + if (chan->load_state == S3C2410_DMALOAD_NONE) { + pr_debug("dma%d: end of transfer, stopping channel (%ld)\n", + chan->number, jiffies); + s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL, + S3C2410_DMAOP_STOP); + } + } + + no_load: + return IRQ_HANDLED; +} + +static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel); + +/* s3c2410_request_dma + * + * get control of an dma channel +*/ + +int s3c2410_dma_request(unsigned int channel, + struct s3c2410_dma_client *client, + void *dev) +{ + struct s3c2410_dma_chan *chan; + unsigned long flags; + int err; + + pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n", + channel, client->name, dev); + + local_irq_save(flags); + + chan = s3c2410_dma_map_channel(channel); + if (chan == NULL) { + local_irq_restore(flags); + return -EBUSY; + } + + dbg_showchan(chan); + + chan->client = client; + chan->in_use = 1; + + if (!chan->irq_claimed) { + pr_debug("dma%d: %s : requesting irq %d\n", + channel, __FUNCTION__, chan->irq); + + chan->irq_claimed = 1; + local_irq_restore(flags); + + err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED, + client->name, (void *)chan); + + local_irq_save(flags); + + if (err) { + chan->in_use = 0; + chan->irq_claimed = 0; + local_irq_restore(flags); + + printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n", + client->name, chan->irq, chan->number); + return err; + } + + chan->irq_enabled = 1; + } + + local_irq_restore(flags); + + /* need to setup */ + + pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan); + + return 0; +} + +EXPORT_SYMBOL(s3c2410_dma_request); + +/* s3c2410_dma_free + * + * release the given channel back to the system, will stop and flush + * any outstanding transfers, and ensure the channel is ready for the + * next claimant. + * + * Note, although a warning is currently printed if the freeing client + * info is not the same as the registrant's client info, the free is still + * allowed to go through. +*/ + +int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client) +{ + struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + unsigned long flags; + + if (chan == NULL) + return -EINVAL; + + local_irq_save(flags); + + if (chan->client != client) { + printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n", + channel, chan->client, client); + } + + /* sort out stopping and freeing the channel */ + + if (chan->state != S3C2410_DMA_IDLE) { + pr_debug("%s: need to stop dma channel %p\n", + __FUNCTION__, chan); + + /* possibly flush the channel */ + s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP); + } + + chan->client = NULL; + chan->in_use = 0; + + if (chan->irq_claimed) + free_irq(chan->irq, (void *)chan); + + chan->irq_claimed = 0; + + if (!(channel & DMACH_LOW_LEVEL)) + dma_chan_map[channel] = NULL; + + local_irq_restore(flags); + + return 0; +} + +EXPORT_SYMBOL(s3c2410_dma_free); + +static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan) +{ + unsigned long flags; + unsigned long tmp; + + pr_debug("%s:\n", __FUNCTION__); + + dbg_showchan(chan); + + local_irq_save(flags); + + s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP); + + tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); + tmp |= S3C2410_DMASKTRIG_STOP; + //tmp &= ~S3C2410_DMASKTRIG_ON; + dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); + +#if 0 + /* should also clear interrupts, according to WinCE BSP */ + tmp = dma_rdreg(chan, S3C2410_DMA_DCON); + tmp |= S3C2410_DCON_NORELOAD; + dma_wrreg(chan, S3C2410_DMA_DCON, tmp); +#endif + + /* should stop do this, or should we wait for flush? */ + chan->state = S3C2410_DMA_IDLE; + chan->load_state = S3C2410_DMALOAD_NONE; + + local_irq_restore(flags); + + return 0; +} + +void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan) +{ + unsigned long tmp; + unsigned int timeout = 0x10000; + + while (timeout-- > 0) { + tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); + + if (!(tmp & S3C2410_DMASKTRIG_ON)) + return; + } + + pr_debug("dma%d: failed to stop?\n", chan->number); +} + + +/* s3c2410_dma_flush + * + * stop the channel, and remove all current and pending transfers +*/ + +static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan) +{ + struct s3c2410_dma_buf *buf, *next; + unsigned long flags; + + pr_debug("%s: chan %p (%d)\n", __FUNCTION__, chan, chan->number); + + dbg_showchan(chan); + + local_irq_save(flags); + + if (chan->state != S3C2410_DMA_IDLE) { + pr_debug("%s: stopping channel...\n", __FUNCTION__ ); + s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP); + } + + buf = chan->curr; + if (buf == NULL) + buf = chan->next; + + chan->curr = chan->next = chan->end = NULL; + + if (buf != NULL) { + for ( ; buf != NULL; buf = next) { + next = buf->next; + + pr_debug("%s: free buffer %p, next %p\n", + __FUNCTION__, buf, buf->next); + + s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT); + s3c2410_dma_freebuf(buf); + } + } + + dbg_showregs(chan); + + s3c2410_dma_waitforstop(chan); + +#if 0 + /* should also clear interrupts, according to WinCE BSP */ + { + unsigned long tmp; + + tmp = dma_rdreg(chan, S3C2410_DMA_DCON); + tmp |= S3C2410_DCON_NORELOAD; + dma_wrreg(chan, S3C2410_DMA_DCON, tmp); + } +#endif + + dbg_showregs(chan); + + local_irq_restore(flags); + + return 0; +} + +int +s3c2410_dma_started(struct s3c2410_dma_chan *chan) +{ + unsigned long flags; + + local_irq_save(flags); + + dbg_showchan(chan); + + /* if we've only loaded one buffer onto the channel, then chec + * to see if we have another, and if so, try and load it so when + * the first buffer is finished, the new one will be loaded onto + * the channel */ + + if (chan->next != NULL) { + if (chan->load_state == S3C2410_DMALOAD_1LOADED) { + + if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { + pr_debug("%s: buff not yet loaded, no more todo\n", + __FUNCTION__); + } else { + chan->load_state = S3C2410_DMALOAD_1RUNNING; + s3c2410_dma_loadbuffer(chan, chan->next); + } + + } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) { + s3c2410_dma_loadbuffer(chan, chan->next); + } + } + + + local_irq_restore(flags); + + return 0; + +} + +int +s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op) +{ + struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + + if (chan == NULL) + return -EINVAL; + + switch (op) { + case S3C2410_DMAOP_START: + return s3c2410_dma_start(chan); + + case S3C2410_DMAOP_STOP: + return s3c2410_dma_dostop(chan); + + case S3C2410_DMAOP_PAUSE: + case S3C2410_DMAOP_RESUME: + return -ENOENT; + + case S3C2410_DMAOP_FLUSH: + return s3c2410_dma_flush(chan); + + case S3C2410_DMAOP_STARTED: + return s3c2410_dma_started(chan); + + case S3C2410_DMAOP_TIMEOUT: + return 0; + + } + + return -ENOENT; /* unknown, don't bother */ +} + +EXPORT_SYMBOL(s3c2410_dma_ctrl); + +/* DMA configuration for each channel + * + * DISRCC -> source of the DMA (AHB,APB) + * DISRC -> source address of the DMA + * DIDSTC -> destination of the DMA (AHB,APD) + * DIDST -> destination address of the DMA +*/ + +/* s3c2410_dma_config + * + * xfersize: size of unit in bytes (1,2,4) + * dcon: base value of the DCONx register +*/ + +int s3c2410_dma_config(dmach_t channel, + int xferunit, + int dcon) +{ + struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + + pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n", + __FUNCTION__, channel, xferunit, dcon); + + if (chan == NULL) + return -EINVAL; + + pr_debug("%s: Initial dcon is %08x\n", __FUNCTION__, dcon); + + dcon |= chan->dcon & dma_sel.dcon_mask; + + pr_debug("%s: New dcon is %08x\n", __FUNCTION__, dcon); + + switch (xferunit) { + case 1: + dcon |= S3C2410_DCON_BYTE; + break; + + case 2: + dcon |= S3C2410_DCON_HALFWORD; + break; + + case 4: + dcon |= S3C2410_DCON_WORD; + break; + + default: + pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit); + return -EINVAL; + } + + dcon |= S3C2410_DCON_HWTRIG; + dcon |= S3C2410_DCON_INTREQ; + + pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon); + + chan->dcon = dcon; + chan->xfer_unit = xferunit; + + return 0; +} + +EXPORT_SYMBOL(s3c2410_dma_config); + +int s3c2410_dma_setflags(dmach_t channel, unsigned int flags) +{ + struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + + if (chan == NULL) + return -EINVAL; + + pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags); + + chan->flags = flags; + + return 0; +} + +EXPORT_SYMBOL(s3c2410_dma_setflags); + + +/* do we need to protect the settings of the fields from + * irq? +*/ + +int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn) +{ + struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + + if (chan == NULL) + return -EINVAL; + + pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn); + + chan->op_fn = rtn; + + return 0; +} + +EXPORT_SYMBOL(s3c2410_dma_set_opfn); + +int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn) +{ + struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + + if (chan == NULL) + return -EINVAL; + + pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn); + + chan->callback_fn = rtn; + + return 0; +} + +EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn); + +/* s3c2410_dma_devconfig + * + * configure the dma source/destination hardware type and address + * + * source: S3C2410_DMASRC_HW: source is hardware + * S3C2410_DMASRC_MEM: source is memory + * + * hwcfg: the value for xxxSTCn register, + * bit 0: 0=increment pointer, 1=leave pointer + * bit 1: 0=soucre is AHB, 1=soucre is APB + * + * devaddr: physical address of the source +*/ + +int s3c2410_dma_devconfig(int channel, + enum s3c2410_dmasrc source, + int hwcfg, + unsigned long devaddr) +{ + struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + + if (chan == NULL) + return -EINVAL; + + pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n", + __FUNCTION__, (int)source, hwcfg, devaddr); + + chan->source = source; + chan->dev_addr = devaddr; + + switch (source) { + case S3C2410_DMASRC_HW: + /* source is hardware */ + pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n", + __FUNCTION__, devaddr, hwcfg); + dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3); + dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr); + dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0)); + + chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST); + return 0; + + case S3C2410_DMASRC_MEM: + /* source is memory */ + pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n", + __FUNCTION__, devaddr, hwcfg); + dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0)); + dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr); + dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3); + + chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC); + return 0; + } + + printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source); + return -EINVAL; +} + +EXPORT_SYMBOL(s3c2410_dma_devconfig); + +/* s3c2410_dma_getposition + * + * returns the current transfer points for the dma source and destination +*/ + +int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst) +{ + struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + + if (chan == NULL) + return -EINVAL; + + if (src != NULL) + *src = dma_rdreg(chan, S3C2410_DMA_DCSRC); + + if (dst != NULL) + *dst = dma_rdreg(chan, S3C2410_DMA_DCDST); + + return 0; +} + +EXPORT_SYMBOL(s3c2410_dma_getposition); + + +/* system device class */ + +#ifdef CONFIG_PM + +static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state) +{ + struct s3c2410_dma_chan *cp = container_of(dev, struct s3c2410_dma_chan, dev); + + printk(KERN_DEBUG "suspending dma channel %d\n", cp->number); + + if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) { + /* the dma channel is still working, which is probably + * a bad thing to do over suspend/resume. We stop the + * channel and assume that the client is either going to + * retry after resume, or that it is broken. + */ + + printk(KERN_INFO "dma: stopping channel %d due to suspend\n", + cp->number); + + s3c2410_dma_dostop(cp); + } + + return 0; +} + +static int s3c2410_dma_resume(struct sys_device *dev) +{ + return 0; +} + +#else +#define s3c2410_dma_suspend NULL +#define s3c2410_dma_resume NULL +#endif /* CONFIG_PM */ + +struct sysdev_class dma_sysclass = { + set_kset_name("s3c24xx-dma"), + .suspend = s3c2410_dma_suspend, + .resume = s3c2410_dma_resume, +}; + +/* kmem cache implementation */ + +static void s3c2410_dma_cache_ctor(void *p, struct kmem_cache *c, unsigned long f) +{ + memset(p, 0, sizeof(struct s3c2410_dma_buf)); +} + +/* initialisation code */ + +int __init s3c24xx_dma_sysclass_init(void) +{ + int ret = sysdev_class_register(&dma_sysclass); + + if (ret != 0) + printk(KERN_ERR "dma sysclass registration failed\n"); + + return ret; +} + +core_initcall(s3c24xx_dma_sysclass_init); + +int __init s3c24xx_dma_sysdev_register(void) +{ + struct s3c2410_dma_chan *cp = s3c2410_chans; + int channel, ret; + + for (channel = 0; channel < dma_channels; cp++, channel++) { + cp->dev.cls = &dma_sysclass; + cp->dev.id = channel; + ret = sysdev_register(&cp->dev); + + if (ret) { + printk(KERN_ERR "error registering dev for dma %d\n", + channel); + return ret; + } + } + + return 0; +} + +late_initcall(s3c24xx_dma_sysdev_register); + +int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq, + unsigned int stride) +{ + struct s3c2410_dma_chan *cp; + int channel; + int ret; + + printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n"); + + dma_channels = channels; + + dma_base = ioremap(S3C24XX_PA_DMA, stride * channels); + if (dma_base == NULL) { + printk(KERN_ERR "dma failed to remap register block\n"); + return -ENOMEM; + } + + dma_kmem = kmem_cache_create("dma_desc", + sizeof(struct s3c2410_dma_buf), 0, + SLAB_HWCACHE_ALIGN, + s3c2410_dma_cache_ctor, NULL); + + if (dma_kmem == NULL) { + printk(KERN_ERR "dma failed to make kmem cache\n"); + ret = -ENOMEM; + goto err; + } + + for (channel = 0; channel < channels; channel++) { + cp = &s3c2410_chans[channel]; + + memset(cp, 0, sizeof(struct s3c2410_dma_chan)); + + /* dma channel irqs are in order.. */ + cp->number = channel; + cp->irq = channel + irq; + cp->regs = dma_base + (channel * stride); + + /* point current stats somewhere */ + cp->stats = &cp->stats_store; + cp->stats_store.timeout_shortest = LONG_MAX; + + /* basic channel configuration */ + + cp->load_timeout = 1<<18; + + printk("DMA channel %d at %p, irq %d\n", + cp->number, cp->regs, cp->irq); + } + + return 0; + + err: + kmem_cache_destroy(dma_kmem); + iounmap(dma_base); + dma_base = NULL; + return ret; +} + +int s3c2410_dma_init(void) +{ + return s3c24xx_dma_init(4, IRQ_DMA0, 0x40); +} + +static inline int is_channel_valid(unsigned int channel) +{ + return (channel & DMA_CH_VALID); +} + +static struct s3c24xx_dma_order *dma_order; + + +/* s3c2410_dma_map_channel() + * + * turn the virtual channel number into a real, and un-used hardware + * channel. + * + * first, try the dma ordering given to us by either the relevant + * dma code, or the board. Then just find the first usable free + * channel +*/ + +struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel) +{ + struct s3c24xx_dma_order_ch *ord = NULL; + struct s3c24xx_dma_map *ch_map; + struct s3c2410_dma_chan *dmach; + int ch; + + if (dma_sel.map == NULL || channel > dma_sel.map_size) + return NULL; + + ch_map = dma_sel.map + channel; + + /* first, try the board mapping */ + + if (dma_order) { + ord = &dma_order->channels[channel]; + + for (ch = 0; ch < dma_channels; ch++) { + if (!is_channel_valid(ord->list[ch])) + continue; + + if (s3c2410_chans[ord->list[ch]].in_use == 0) { + ch = ord->list[ch] & ~DMA_CH_VALID; + goto found; + } + } + + if (ord->flags & DMA_CH_NEVER) + return NULL; + } + + /* second, search the channel map for first free */ + + for (ch = 0; ch < dma_channels; ch++) { + if (!is_channel_valid(ch_map->channels[ch])) + continue; + + if (s3c2410_chans[ch].in_use == 0) { + printk("mapped channel %d to %d\n", channel, ch); + break; + } + } + + if (ch >= dma_channels) + return NULL; + + /* update our channel mapping */ + + found: + dmach = &s3c2410_chans[ch]; + dma_chan_map[channel] = dmach; + + /* select the channel */ + + (dma_sel.select)(dmach, ch_map); + + return dmach; +} + +static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch) +{ + return 0; +} + +int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel) +{ + struct s3c24xx_dma_map *nmap; + size_t map_sz = sizeof(*nmap) * sel->map_size; + int ptr; + + nmap = kmalloc(map_sz, GFP_KERNEL); + if (nmap == NULL) + return -ENOMEM; + + memcpy(nmap, sel->map, map_sz); + memcpy(&dma_sel, sel, sizeof(*sel)); + + dma_sel.map = nmap; + + for (ptr = 0; ptr < sel->map_size; ptr++) + s3c24xx_dma_check_entry(nmap+ptr, ptr); + + return 0; +} + +int __init s3c24xx_dma_order_set(struct s3c24xx_dma_order *ord) +{ + struct s3c24xx_dma_order *nord = dma_order; + + if (nord == NULL) + nord = kmalloc(sizeof(struct s3c24xx_dma_order), GFP_KERNEL); + + if (nord == NULL) { + printk(KERN_ERR "no memory to store dma channel order\n"); + return -ENOMEM; + } + + dma_order = nord; + memcpy(nord, ord, sizeof(struct s3c24xx_dma_order)); + return 0; +} diff --git a/arch/arm/plat-s3c24xx/gpio.c b/arch/arm/plat-s3c24xx/gpio.c new file mode 100644 index 00000000000..ec3a09c4d18 --- /dev/null +++ b/arch/arm/plat-s3c24xx/gpio.c @@ -0,0 +1,188 @@ +/* linux/arch/arm/plat-s3c24xx/gpio.c + * + * Copyright (c) 2004-2005 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C24XX GPIO support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> + +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/io.h> + +#include <asm/arch/regs-gpio.h> + +void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function) +{ + void __iomem *base = S3C24XX_GPIO_BASE(pin); + unsigned long mask; + unsigned long con; + unsigned long flags; + + if (pin < S3C2410_GPIO_BANKB) { + mask = 1 << S3C2410_GPIO_OFFSET(pin); + } else { + mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; + } + + switch (function) { + case S3C2410_GPIO_LEAVE: + mask = 0; + function = 0; + break; + + case S3C2410_GPIO_INPUT: + case S3C2410_GPIO_OUTPUT: + case S3C2410_GPIO_SFN2: + case S3C2410_GPIO_SFN3: + if (pin < S3C2410_GPIO_BANKB) { + function -= 1; + function &= 1; + function <<= S3C2410_GPIO_OFFSET(pin); + } else { + function &= 3; + function <<= S3C2410_GPIO_OFFSET(pin)*2; + } + } + + /* modify the specified register wwith IRQs off */ + + local_irq_save(flags); + + con = __raw_readl(base + 0x00); + con &= ~mask; + con |= function; + + __raw_writel(con, base + 0x00); + + local_irq_restore(flags); +} + +EXPORT_SYMBOL(s3c2410_gpio_cfgpin); + +unsigned int s3c2410_gpio_getcfg(unsigned int pin) +{ + void __iomem *base = S3C24XX_GPIO_BASE(pin); + unsigned long val = __raw_readl(base); + + if (pin < S3C2410_GPIO_BANKB) { + val >>= S3C2410_GPIO_OFFSET(pin); + val &= 1; + val += 1; + } else { + val >>= S3C2410_GPIO_OFFSET(pin)*2; + val &= 3; + } + + return val | S3C2410_GPIO_INPUT; +} + +EXPORT_SYMBOL(s3c2410_gpio_getcfg); + +void s3c2410_gpio_pullup(unsigned int pin, unsigned int to) +{ + void __iomem *base = S3C24XX_GPIO_BASE(pin); + unsigned long offs = S3C2410_GPIO_OFFSET(pin); + unsigned long flags; + unsigned long up; + + if (pin < S3C2410_GPIO_BANKB) + return; + + local_irq_save(flags); + + up = __raw_readl(base + 0x08); + up &= ~(1L << offs); + up |= to << offs; + __raw_writel(up, base + 0x08); + + local_irq_restore(flags); +} + +EXPORT_SYMBOL(s3c2410_gpio_pullup); + +void s3c2410_gpio_setpin(unsigned int pin, unsigned int to) +{ + void __iomem *base = S3C24XX_GPIO_BASE(pin); + unsigned long offs = S3C2410_GPIO_OFFSET(pin); + unsigned long flags; + unsigned long dat; + + local_irq_save(flags); + + dat = __raw_readl(base + 0x04); + dat &= ~(1 << offs); + dat |= to << offs; + __raw_writel(dat, base + 0x04); + + local_irq_restore(flags); +} + +EXPORT_SYMBOL(s3c2410_gpio_setpin); + +unsigned int s3c2410_gpio_getpin(unsigned int pin) +{ + void __iomem *base = S3C24XX_GPIO_BASE(pin); + unsigned long offs = S3C2410_GPIO_OFFSET(pin); + + return __raw_readl(base + 0x04) & (1<< offs); +} + +EXPORT_SYMBOL(s3c2410_gpio_getpin); + +unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) +{ + unsigned long flags; + unsigned long misccr; + + local_irq_save(flags); + misccr = __raw_readl(S3C24XX_MISCCR); + misccr &= ~clear; + misccr ^= change; + __raw_writel(misccr, S3C24XX_MISCCR); + local_irq_restore(flags); + + return misccr; +} + +EXPORT_SYMBOL(s3c2410_modify_misccr); + +int s3c2410_gpio_getirq(unsigned int pin) +{ + if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15) + return -1; /* not valid interrupts */ + + if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7) + return -1; /* not valid pin */ + + if (pin < S3C2410_GPF4) + return (pin - S3C2410_GPF0) + IRQ_EINT0; + + if (pin < S3C2410_GPG0) + return (pin - S3C2410_GPF4) + IRQ_EINT4; + + return (pin - S3C2410_GPG0) + IRQ_EINT8; +} + +EXPORT_SYMBOL(s3c2410_gpio_getirq); diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c new file mode 100644 index 00000000000..ce186398e3f --- /dev/null +++ b/arch/arm/plat-s3c24xx/irq.c @@ -0,0 +1,801 @@ +/* linux/arch/arm/plat-s3c24xx/irq.c + * + * Copyright (c) 2003,2004 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Changelog: + * + * 22-Jul-2004 Ben Dooks <ben@simtec.co.uk> + * Fixed compile warnings + * + * 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn> + * Fixed s3c_extirq_type + * + * 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org> + * Addition of ADC/TC demux + * + * 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de> + * Fix for set_irq_type() on low EINT numbers + * + * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> + * Tidy up KF's patch and sort out new release + * + * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> + * Add support for power management controls + * + * 04-Nov-2004 Ben Dooks + * Fix standard IRQ wake for EINT0..4 and RTC + * + * 22-Feb-2005 Ben Dooks + * Fixed edge-triggering on ADC IRQ + * + * 28-Jun-2005 Ben Dooks + * Mark IRQ_LCD valid + * + * 25-Jul-2005 Ben Dooks + * Split the S3C2440 IRQ code to seperate file +*/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/ptrace.h> +#include <linux/sysdev.h> + +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/io.h> + +#include <asm/mach/irq.h> + +#include <asm/arch/regs-irq.h> +#include <asm/arch/regs-gpio.h> + +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/pm.h> +#include <asm/plat-s3c24xx/irq.h> + +/* wakeup irq control */ + +#ifdef CONFIG_PM + +/* state for IRQs over sleep */ + +/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources + * + * set bit to 1 in allow bitfield to enable the wakeup settings on it +*/ + +unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL; +unsigned long s3c_irqwake_intmask = 0xffffffffL; +unsigned long s3c_irqwake_eintallow = 0x0000fff0L; +unsigned long s3c_irqwake_eintmask = 0xffffffffL; + +int +s3c_irq_wake(unsigned int irqno, unsigned int state) +{ + unsigned long irqbit = 1 << (irqno - IRQ_EINT0); + + if (!(s3c_irqwake_intallow & irqbit)) + return -ENOENT; + + printk(KERN_INFO "wake %s for irq %d\n", + state ? "enabled" : "disabled", irqno); + + if (!state) + s3c_irqwake_intmask |= irqbit; + else + s3c_irqwake_intmask &= ~irqbit; + + return 0; +} + +static int +s3c_irqext_wake(unsigned int irqno, unsigned int state) +{ + unsigned long bit = 1L << (irqno - EXTINT_OFF); + + if (!(s3c_irqwake_eintallow & bit)) + return -ENOENT; + + printk(KERN_INFO "wake %s for irq %d\n", + state ? "enabled" : "disabled", irqno); + + if (!state) + s3c_irqwake_eintmask |= bit; + else + s3c_irqwake_eintmask &= ~bit; + + return 0; +} + +#else +#define s3c_irqext_wake NULL +#define s3c_irq_wake NULL +#endif + + +static void +s3c_irq_mask(unsigned int irqno) +{ + unsigned long mask; + + irqno -= IRQ_EINT0; + + mask = __raw_readl(S3C2410_INTMSK); + mask |= 1UL << irqno; + __raw_writel(mask, S3C2410_INTMSK); +} + +static inline void +s3c_irq_ack(unsigned int irqno) +{ + unsigned long bitval = 1UL << (irqno - IRQ_EINT0); + + __raw_writel(bitval, S3C2410_SRCPND); + __raw_writel(bitval, S3C2410_INTPND); +} + +static inline void +s3c_irq_maskack(unsigned int irqno) +{ + unsigned long bitval = 1UL << (irqno - IRQ_EINT0); + unsigned long mask; + + mask = __raw_readl(S3C2410_INTMSK); + __raw_writel(mask|bitval, S3C2410_INTMSK); + + __raw_writel(bitval, S3C2410_SRCPND); + __raw_writel(bitval, S3C2410_INTPND); +} + + +static void +s3c_irq_unmask(unsigned int irqno) +{ + unsigned long mask; + + if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23) + irqdbf2("s3c_irq_unmask %d\n", irqno); + + irqno -= IRQ_EINT0; + + mask = __raw_readl(S3C2410_INTMSK); + mask &= ~(1UL << irqno); + __raw_writel(mask, S3C2410_INTMSK); +} + +struct irq_chip s3c_irq_level_chip = { + .name = "s3c-level", + .ack = s3c_irq_maskack, + .mask = s3c_irq_mask, + .unmask = s3c_irq_unmask, + .set_wake = s3c_irq_wake +}; + +static struct irq_chip s3c_irq_chip = { + .name = "s3c", + .ack = s3c_irq_ack, + .mask = s3c_irq_mask, + .unmask = s3c_irq_unmask, + .set_wake = s3c_irq_wake +}; + +static void +s3c_irqext_mask(unsigned int irqno) +{ + unsigned long mask; + + irqno -= EXTINT_OFF; + + mask = __raw_readl(S3C24XX_EINTMASK); + mask |= ( 1UL << irqno); + __raw_writel(mask, S3C24XX_EINTMASK); +} + +static void +s3c_irqext_ack(unsigned int irqno) +{ + unsigned long req; + unsigned long bit; + unsigned long mask; + + bit = 1UL << (irqno - EXTINT_OFF); + + mask = __raw_readl(S3C24XX_EINTMASK); + + __raw_writel(bit, S3C24XX_EINTPEND); + + req = __raw_readl(S3C24XX_EINTPEND); + req &= ~mask; + + /* not sure if we should be acking the parent irq... */ + + if (irqno <= IRQ_EINT7 ) { + if ((req & 0xf0) == 0) + s3c_irq_ack(IRQ_EINT4t7); + } else { + if ((req >> 8) == 0) + s3c_irq_ack(IRQ_EINT8t23); + } +} + +static void +s3c_irqext_unmask(unsigned int irqno) +{ + unsigned long mask; + + irqno -= EXTINT_OFF; + + mask = __raw_readl(S3C24XX_EINTMASK); + mask &= ~( 1UL << irqno); + __raw_writel(mask, S3C24XX_EINTMASK); +} + +int +s3c_irqext_type(unsigned int irq, unsigned int type) +{ + void __iomem *extint_reg; + void __iomem *gpcon_reg; + unsigned long gpcon_offset, extint_offset; + unsigned long newvalue = 0, value; + + if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3)) + { + gpcon_reg = S3C2410_GPFCON; + extint_reg = S3C24XX_EXTINT0; + gpcon_offset = (irq - IRQ_EINT0) * 2; + extint_offset = (irq - IRQ_EINT0) * 4; + } + else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7)) + { + gpcon_reg = S3C2410_GPFCON; + extint_reg = S3C24XX_EXTINT0; + gpcon_offset = (irq - (EXTINT_OFF)) * 2; + extint_offset = (irq - (EXTINT_OFF)) * 4; + } + else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15)) + { + gpcon_reg = S3C2410_GPGCON; + extint_reg = S3C24XX_EXTINT1; + gpcon_offset = (irq - IRQ_EINT8) * 2; + extint_offset = (irq - IRQ_EINT8) * 4; + } + else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23)) + { + gpcon_reg = S3C2410_GPGCON; + extint_reg = S3C24XX_EXTINT2; + gpcon_offset = (irq - IRQ_EINT8) * 2; + extint_offset = (irq - IRQ_EINT16) * 4; + } else + return -1; + + /* Set the GPIO to external interrupt mode */ + value = __raw_readl(gpcon_reg); + value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); + __raw_writel(value, gpcon_reg); + + /* Set the external interrupt to pointed trigger type */ + switch (type) + { + case IRQT_NOEDGE: + printk(KERN_WARNING "No edge setting!\n"); + break; + + case IRQT_RISING: + newvalue = S3C2410_EXTINT_RISEEDGE; + break; + + case IRQT_FALLING: + newvalue = S3C2410_EXTINT_FALLEDGE; + break; + + case IRQT_BOTHEDGE: + newvalue = S3C2410_EXTINT_BOTHEDGE; + break; + + case IRQT_LOW: + newvalue = S3C2410_EXTINT_LOWLEV; + break; + + case IRQT_HIGH: + newvalue = S3C2410_EXTINT_HILEV; + break; + + default: + printk(KERN_ERR "No such irq type %d", type); + return -1; + } + + value = __raw_readl(extint_reg); + value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); + __raw_writel(value, extint_reg); + + return 0; +} + +static struct irq_chip s3c_irqext_chip = { + .name = "s3c-ext", + .mask = s3c_irqext_mask, + .unmask = s3c_irqext_unmask, + .ack = s3c_irqext_ack, + .set_type = s3c_irqext_type, + .set_wake = s3c_irqext_wake +}; + +static struct irq_chip s3c_irq_eint0t4 = { + .name = "s3c-ext0", + .ack = s3c_irq_ack, + .mask = s3c_irq_mask, + .unmask = s3c_irq_unmask, + .set_wake = s3c_irq_wake, + .set_type = s3c_irqext_type, +}; + +/* mask values for the parent registers for each of the interrupt types */ + +#define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0)) +#define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0)) +#define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0)) +#define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0)) + + +/* UART0 */ + +static void +s3c_irq_uart0_mask(unsigned int irqno) +{ + s3c_irqsub_mask(irqno, INTMSK_UART0, 7); +} + +static void +s3c_irq_uart0_unmask(unsigned int irqno) +{ + s3c_irqsub_unmask(irqno, INTMSK_UART0); +} + +static void +s3c_irq_uart0_ack(unsigned int irqno) +{ + s3c_irqsub_maskack(irqno, INTMSK_UART0, 7); +} + +static struct irq_chip s3c_irq_uart0 = { + .name = "s3c-uart0", + .mask = s3c_irq_uart0_mask, + .unmask = s3c_irq_uart0_unmask, + .ack = s3c_irq_uart0_ack, +}; + +/* UART1 */ + +static void +s3c_irq_uart1_mask(unsigned int irqno) +{ + s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3); +} + +static void +s3c_irq_uart1_unmask(unsigned int irqno) +{ + s3c_irqsub_unmask(irqno, INTMSK_UART1); +} + +static void +s3c_irq_uart1_ack(unsigned int irqno) +{ + s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3); +} + +static struct irq_chip s3c_irq_uart1 = { + .name = "s3c-uart1", + .mask = s3c_irq_uart1_mask, + .unmask = s3c_irq_uart1_unmask, + .ack = s3c_irq_uart1_ack, +}; + +/* UART2 */ + +static void +s3c_irq_uart2_mask(unsigned int irqno) +{ + s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6); +} + +static void +s3c_irq_uart2_unmask(unsigned int irqno) +{ + s3c_irqsub_unmask(irqno, INTMSK_UART2); +} + +static void +s3c_irq_uart2_ack(unsigned int irqno) +{ + s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6); +} + +static struct irq_chip s3c_irq_uart2 = { + .name = "s3c-uart2", + .mask = s3c_irq_uart2_mask, + .unmask = s3c_irq_uart2_unmask, + .ack = s3c_irq_uart2_ack, +}; + +/* ADC and Touchscreen */ + +static void +s3c_irq_adc_mask(unsigned int irqno) +{ + s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9); +} + +static void +s3c_irq_adc_unmask(unsigned int irqno) +{ + s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT); +} + +static void +s3c_irq_adc_ack(unsigned int irqno) +{ + s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9); +} + +static struct irq_chip s3c_irq_adc = { + .name = "s3c-adc", + .mask = s3c_irq_adc_mask, + .unmask = s3c_irq_adc_unmask, + .ack = s3c_irq_adc_ack, +}; + +/* irq demux for adc */ +static void s3c_irq_demux_adc(unsigned int irq, + struct irq_desc *desc) +{ + unsigned int subsrc, submsk; + unsigned int offset = 9; + struct irq_desc *mydesc; + + /* read the current pending interrupts, and the mask + * for what it is available */ + + subsrc = __raw_readl(S3C2410_SUBSRCPND); + submsk = __raw_readl(S3C2410_INTSUBMSK); + + subsrc &= ~submsk; + subsrc >>= offset; + subsrc &= 3; + + if (subsrc != 0) { + if (subsrc & 1) { + mydesc = irq_desc + IRQ_TC; + desc_handle_irq(IRQ_TC, mydesc); + } + if (subsrc & 2) { + mydesc = irq_desc + IRQ_ADC; + desc_handle_irq(IRQ_ADC, mydesc); + } + } +} + +static void s3c_irq_demux_uart(unsigned int start) +{ + unsigned int subsrc, submsk; + unsigned int offset = start - IRQ_S3CUART_RX0; + struct irq_desc *desc; + + /* read the current pending interrupts, and the mask + * for what it is available */ + + subsrc = __raw_readl(S3C2410_SUBSRCPND); + submsk = __raw_readl(S3C2410_INTSUBMSK); + + irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n", + start, offset, subsrc, submsk); + + subsrc &= ~submsk; + subsrc >>= offset; + subsrc &= 7; + + if (subsrc != 0) { + desc = irq_desc + start; + + if (subsrc & 1) + desc_handle_irq(start, desc); + + desc++; + + if (subsrc & 2) + desc_handle_irq(start+1, desc); + + desc++; + + if (subsrc & 4) + desc_handle_irq(start+2, desc); + } +} + +/* uart demux entry points */ + +static void +s3c_irq_demux_uart0(unsigned int irq, + struct irq_desc *desc) +{ + irq = irq; + s3c_irq_demux_uart(IRQ_S3CUART_RX0); +} + +static void +s3c_irq_demux_uart1(unsigned int irq, + struct irq_desc *desc) +{ + irq = irq; + s3c_irq_demux_uart(IRQ_S3CUART_RX1); +} + +static void +s3c_irq_demux_uart2(unsigned int irq, + struct irq_desc *desc) +{ + irq = irq; + s3c_irq_demux_uart(IRQ_S3CUART_RX2); +} + +static void +s3c_irq_demux_extint8(unsigned int irq, + struct irq_desc *desc) +{ + unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND); + unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK); + + eintpnd &= ~eintmsk; + eintpnd &= ~0xff; /* ignore lower irqs */ + + /* we may as well handle all the pending IRQs here */ + + while (eintpnd) { + irq = __ffs(eintpnd); + eintpnd &= ~(1<<irq); + + irq += (IRQ_EINT4 - 4); + desc_handle_irq(irq, irq_desc + irq); + } + +} + +static void +s3c_irq_demux_extint4t7(unsigned int irq, + struct irq_desc *desc) +{ + unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND); + unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK); + + eintpnd &= ~eintmsk; + eintpnd &= 0xff; /* only lower irqs */ + + /* we may as well handle all the pending IRQs here */ + + while (eintpnd) { + irq = __ffs(eintpnd); + eintpnd &= ~(1<<irq); + + irq += (IRQ_EINT4 - 4); + + desc_handle_irq(irq, irq_desc + irq); + } +} + +#ifdef CONFIG_PM + +static struct sleep_save irq_save[] = { + SAVE_ITEM(S3C2410_INTMSK), + SAVE_ITEM(S3C2410_INTSUBMSK), +}; + +/* the extint values move between the s3c2410/s3c2440 and the s3c2412 + * so we use an array to hold them, and to calculate the address of + * the register at run-time +*/ + +static unsigned long save_extint[3]; +static unsigned long save_eintflt[4]; +static unsigned long save_eintmask; + +int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(save_extint); i++) + save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4)); + + for (i = 0; i < ARRAY_SIZE(save_eintflt); i++) + save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4)); + + s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); + save_eintmask = __raw_readl(S3C24XX_EINTMASK); + + return 0; +} + +int s3c24xx_irq_resume(struct sys_device *dev) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(save_extint); i++) + __raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4)); + + for (i = 0; i < ARRAY_SIZE(save_eintflt); i++) + __raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4)); + + s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); + __raw_writel(save_eintmask, S3C24XX_EINTMASK); + + return 0; +} + +#else +#define s3c24xx_irq_suspend NULL +#define s3c24xx_irq_resume NULL +#endif + +/* s3c24xx_init_irq + * + * Initialise S3C2410 IRQ system +*/ + +void __init s3c24xx_init_irq(void) +{ + unsigned long pend; + unsigned long last; + int irqno; + int i; + + irqdbf("s3c2410_init_irq: clearing interrupt status flags\n"); + + /* first, clear all interrupts pending... */ + + last = 0; + for (i = 0; i < 4; i++) { + pend = __raw_readl(S3C24XX_EINTPEND); + + if (pend == 0 || pend == last) + break; + + __raw_writel(pend, S3C24XX_EINTPEND); + printk("irq: clearing pending ext status %08x\n", (int)pend); + last = pend; + } + + last = 0; + for (i = 0; i < 4; i++) { + pend = __raw_readl(S3C2410_INTPND); + + if (pend == 0 || pend == last) + break; + + __raw_writel(pend, S3C2410_SRCPND); + __raw_writel(pend, S3C2410_INTPND); + printk("irq: clearing pending status %08x\n", (int)pend); + last = pend; + } + + last = 0; + for (i = 0; i < 4; i++) { + pend = __raw_readl(S3C2410_SUBSRCPND); + + if (pend == 0 || pend == last) + break; + + printk("irq: clearing subpending status %08x\n", (int)pend); + __raw_writel(pend, S3C2410_SUBSRCPND); + last = pend; + } + + /* register the main interrupts */ + + irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); + + for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) { + /* set all the s3c2410 internal irqs */ + + switch (irqno) { + /* deal with the special IRQs (cascaded) */ + + case IRQ_EINT4t7: + case IRQ_EINT8t23: + case IRQ_UART0: + case IRQ_UART1: + case IRQ_UART2: + case IRQ_ADCPARENT: + set_irq_chip(irqno, &s3c_irq_level_chip); + set_irq_handler(irqno, handle_level_irq); + break; + + case IRQ_RESERVED6: + case IRQ_RESERVED24: + /* no IRQ here */ + break; + + default: + //irqdbf("registering irq %d (s3c irq)\n", irqno); + set_irq_chip(irqno, &s3c_irq_chip); + set_irq_handler(irqno, handle_edge_irq); + set_irq_flags(irqno, IRQF_VALID); + } + } + + /* setup the cascade irq handlers */ + + set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7); + set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8); + + set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); + set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); + set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); + set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); + + /* external interrupts */ + + for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { + irqdbf("registering irq %d (ext int)\n", irqno); + set_irq_chip(irqno, &s3c_irq_eint0t4); + set_irq_handler(irqno, handle_edge_irq); + set_irq_flags(irqno, IRQF_VALID); + } + + for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) { + irqdbf("registering irq %d (extended s3c irq)\n", irqno); + set_irq_chip(irqno, &s3c_irqext_chip); + set_irq_handler(irqno, handle_edge_irq); + set_irq_flags(irqno, IRQF_VALID); + } + + /* register the uart interrupts */ + + irqdbf("s3c2410: registering external interrupts\n"); + + for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) { + irqdbf("registering irq %d (s3c uart0 irq)\n", irqno); + set_irq_chip(irqno, &s3c_irq_uart0); + set_irq_handler(irqno, handle_level_irq); + set_irq_flags(irqno, IRQF_VALID); + } + + for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) { + irqdbf("registering irq %d (s3c uart1 irq)\n", irqno); + set_irq_chip(irqno, &s3c_irq_uart1); + set_irq_handler(irqno, handle_level_irq); + set_irq_flags(irqno, IRQF_VALID); + } + + for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) { + irqdbf("registering irq %d (s3c uart2 irq)\n", irqno); + set_irq_chip(irqno, &s3c_irq_uart2); + set_irq_handler(irqno, handle_level_irq); + set_irq_flags(irqno, IRQF_VALID); + } + + for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) { + irqdbf("registering irq %d (s3c adc irq)\n", irqno); + set_irq_chip(irqno, &s3c_irq_adc); + set_irq_handler(irqno, handle_edge_irq); + set_irq_flags(irqno, IRQF_VALID); + } + + irqdbf("s3c2410: registered interrupt handlers\n"); +} diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/plat-s3c24xx/pm-simtec.c index 619133eb716..bd965f2feec 100644 --- a/arch/arm/mach-s3c2410/pm-simtec.c +++ b/arch/arm/plat-s3c24xx/pm-simtec.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/pm-simtec.c +/* linux/arch/arm/plat-s3c24xx/pm-simtec.c * * Copyright (c) 2004 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -32,7 +32,7 @@ #include <asm/mach-types.h> -#include "pm.h" +#include <asm/plat-s3c24xx/pm.h> #define COPYRIGHT ", (c) 2005 Simtec Electronics" diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c new file mode 100644 index 00000000000..ecf68d61190 --- /dev/null +++ b/arch/arm/plat-s3c24xx/pm.c @@ -0,0 +1,659 @@ +/* linux/arch/arm/plat-s3c24xx/pm.c + * + * Copyright (c) 2004,2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C24XX Power Manager (Suspend-To-RAM) support + * + * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Parts based on arch/arm/mach-pxa/pm.c + * + * Thanks to Dimitry Andric for debugging +*/ + +#include <linux/init.h> +#include <linux/suspend.h> +#include <linux/errno.h> +#include <linux/time.h> +#include <linux/interrupt.h> +#include <linux/crc32.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/serial_core.h> + +#include <asm/cacheflush.h> +#include <asm/hardware.h> +#include <asm/io.h> + +#include <asm/arch/regs-serial.h> +#include <asm/arch/regs-clock.h> +#include <asm/arch/regs-gpio.h> +#include <asm/arch/regs-mem.h> +#include <asm/arch/regs-irq.h> + +#include <asm/mach/time.h> + +#include <asm/plat-s3c24xx/pm.h> + +/* for external use */ + +unsigned long s3c_pm_flags; + +#define PFX "s3c24xx-pm: " + +static struct sleep_save core_save[] = { + SAVE_ITEM(S3C2410_LOCKTIME), + SAVE_ITEM(S3C2410_CLKCON), + + /* we restore the timings here, with the proviso that the board + * brings the system up in an slower, or equal frequency setting + * to the original system. + * + * if we cannot guarantee this, then things are going to go very + * wrong here, as we modify the refresh and both pll settings. + */ + + SAVE_ITEM(S3C2410_BWSCON), + SAVE_ITEM(S3C2410_BANKCON0), + SAVE_ITEM(S3C2410_BANKCON1), + SAVE_ITEM(S3C2410_BANKCON2), + SAVE_ITEM(S3C2410_BANKCON3), + SAVE_ITEM(S3C2410_BANKCON4), + SAVE_ITEM(S3C2410_BANKCON5), + + SAVE_ITEM(S3C2410_CLKDIVN), + SAVE_ITEM(S3C2410_MPLLCON), + SAVE_ITEM(S3C2410_UPLLCON), + SAVE_ITEM(S3C2410_CLKSLOW), + SAVE_ITEM(S3C2410_REFRESH), +}; + +static struct sleep_save gpio_save[] = { + SAVE_ITEM(S3C2410_GPACON), + SAVE_ITEM(S3C2410_GPADAT), + + SAVE_ITEM(S3C2410_GPBCON), + SAVE_ITEM(S3C2410_GPBDAT), + SAVE_ITEM(S3C2410_GPBUP), + + SAVE_ITEM(S3C2410_GPCCON), + SAVE_ITEM(S3C2410_GPCDAT), + SAVE_ITEM(S3C2410_GPCUP), + + SAVE_ITEM(S3C2410_GPDCON), + SAVE_ITEM(S3C2410_GPDDAT), + SAVE_ITEM(S3C2410_GPDUP), + + SAVE_ITEM(S3C2410_GPECON), + SAVE_ITEM(S3C2410_GPEDAT), + SAVE_ITEM(S3C2410_GPEUP), + + SAVE_ITEM(S3C2410_GPFCON), + SAVE_ITEM(S3C2410_GPFDAT), + SAVE_ITEM(S3C2410_GPFUP), + + SAVE_ITEM(S3C2410_GPGCON), + SAVE_ITEM(S3C2410_GPGDAT), + SAVE_ITEM(S3C2410_GPGUP), + + SAVE_ITEM(S3C2410_GPHCON), + SAVE_ITEM(S3C2410_GPHDAT), + SAVE_ITEM(S3C2410_GPHUP), + + SAVE_ITEM(S3C2410_DCLKCON), +}; + +#ifdef CONFIG_S3C2410_PM_DEBUG + +#define SAVE_UART(va) \ + SAVE_ITEM((va) + S3C2410_ULCON), \ + SAVE_ITEM((va) + S3C2410_UCON), \ + SAVE_ITEM((va) + S3C2410_UFCON), \ + SAVE_ITEM((va) + S3C2410_UMCON), \ + SAVE_ITEM((va) + S3C2410_UBRDIV) + +static struct sleep_save uart_save[] = { + SAVE_UART(S3C24XX_VA_UART0), + SAVE_UART(S3C24XX_VA_UART1), +#ifndef CONFIG_CPU_S3C2400 + SAVE_UART(S3C24XX_VA_UART2), +#endif +}; + +/* debug + * + * we send the debug to printascii() to allow it to be seen if the + * system never wakes up from the sleep +*/ + +extern void printascii(const char *); + +void pm_dbg(const char *fmt, ...) +{ + va_list va; + char buff[256]; + + va_start(va, fmt); + vsprintf(buff, fmt, va); + va_end(va); + + printascii(buff); +} + +static void s3c2410_pm_debug_init(void) +{ + unsigned long tmp = __raw_readl(S3C2410_CLKCON); + + /* re-start uart clocks */ + tmp |= S3C2410_CLKCON_UART0; + tmp |= S3C2410_CLKCON_UART1; + tmp |= S3C2410_CLKCON_UART2; + + __raw_writel(tmp, S3C2410_CLKCON); + udelay(10); +} + +#define DBG(fmt...) pm_dbg(fmt) +#else +#define DBG(fmt...) printk(KERN_DEBUG fmt) + +#define s3c2410_pm_debug_init() do { } while(0) + +static struct sleep_save uart_save[] = {}; +#endif + +#if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0 + +/* suspend checking code... + * + * this next area does a set of crc checks over all the installed + * memory, so the system can verify if the resume was ok. + * + * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC, + * increasing it will mean that the area corrupted will be less easy to spot, + * and reducing the size will cause the CRC save area to grow +*/ + +#define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024) + +static u32 crc_size; /* size needed for the crc block */ +static u32 *crcs; /* allocated over suspend/resume */ + +typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg); + +/* s3c2410_pm_run_res + * + * go thorugh the given resource list, and look for system ram +*/ + +static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg) +{ + while (ptr != NULL) { + if (ptr->child != NULL) + s3c2410_pm_run_res(ptr->child, fn, arg); + + if ((ptr->flags & IORESOURCE_MEM) && + strcmp(ptr->name, "System RAM") == 0) { + DBG("Found system RAM at %08lx..%08lx\n", + ptr->start, ptr->end); + arg = (fn)(ptr, arg); + } + + ptr = ptr->sibling; + } +} + +static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg) +{ + s3c2410_pm_run_res(&iomem_resource, fn, arg); +} + +static u32 *s3c2410_pm_countram(struct resource *res, u32 *val) +{ + u32 size = (u32)(res->end - res->start)+1; + + size += CHECK_CHUNKSIZE-1; + size /= CHECK_CHUNKSIZE; + + DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size); + + *val += size * sizeof(u32); + return val; +} + +/* s3c2410_pm_prepare_check + * + * prepare the necessary information for creating the CRCs. This + * must be done before the final save, as it will require memory + * allocating, and thus touching bits of the kernel we do not + * know about. +*/ + +static void s3c2410_pm_check_prepare(void) +{ + crc_size = 0; + + s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size); + + DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size); + + crcs = kmalloc(crc_size+4, GFP_KERNEL); + if (crcs == NULL) + printk(KERN_ERR "Cannot allocated CRC save area\n"); +} + +static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val) +{ + unsigned long addr, left; + + for (addr = res->start; addr < res->end; + addr += CHECK_CHUNKSIZE) { + left = res->end - addr; + + if (left > CHECK_CHUNKSIZE) + left = CHECK_CHUNKSIZE; + + *val = crc32_le(~0, phys_to_virt(addr), left); + val++; + } + + return val; +} + +/* s3c2410_pm_check_store + * + * compute the CRC values for the memory blocks before the final + * sleep. +*/ + +static void s3c2410_pm_check_store(void) +{ + if (crcs != NULL) + s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs); +} + +/* in_region + * + * return TRUE if the area defined by ptr..ptr+size contatins the + * what..what+whatsz +*/ + +static inline int in_region(void *ptr, int size, void *what, size_t whatsz) +{ + if ((what+whatsz) < ptr) + return 0; + + if (what > (ptr+size)) + return 0; + + return 1; +} + +static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val) +{ + void *save_at = phys_to_virt(s3c2410_sleep_save_phys); + unsigned long addr; + unsigned long left; + void *ptr; + u32 calc; + + for (addr = res->start; addr < res->end; + addr += CHECK_CHUNKSIZE) { + left = res->end - addr; + + if (left > CHECK_CHUNKSIZE) + left = CHECK_CHUNKSIZE; + + ptr = phys_to_virt(addr); + + if (in_region(ptr, left, crcs, crc_size)) { + DBG("skipping %08lx, has crc block in\n", addr); + goto skip_check; + } + + if (in_region(ptr, left, save_at, 32*4 )) { + DBG("skipping %08lx, has save block in\n", addr); + goto skip_check; + } + + /* calculate and check the checksum */ + + calc = crc32_le(~0, ptr, left); + if (calc != *val) { + printk(KERN_ERR PFX "Restore CRC error at " + "%08lx (%08x vs %08x)\n", addr, calc, *val); + + DBG("Restore CRC error at %08lx (%08x vs %08x)\n", + addr, calc, *val); + } + + skip_check: + val++; + } + + return val; +} + +/* s3c2410_pm_check_restore + * + * check the CRCs after the restore event and free the memory used + * to hold them +*/ + +static void s3c2410_pm_check_restore(void) +{ + if (crcs != NULL) { + s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs); + kfree(crcs); + crcs = NULL; + } +} + +#else + +#define s3c2410_pm_check_prepare() do { } while(0) +#define s3c2410_pm_check_restore() do { } while(0) +#define s3c2410_pm_check_store() do { } while(0) +#endif + +/* helper functions to save and restore register state */ + +void s3c2410_pm_do_save(struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) { + ptr->val = __raw_readl(ptr->reg); + DBG("saved %p value %08lx\n", ptr->reg, ptr->val); + } +} + +/* s3c2410_pm_do_restore + * + * restore the system from the given list of saved registers + * + * Note, we do not use DBG() in here, as the system may not have + * restore the UARTs state yet +*/ + +void s3c2410_pm_do_restore(struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) { + printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n", + ptr->reg, ptr->val, __raw_readl(ptr->reg)); + + __raw_writel(ptr->val, ptr->reg); + } +} + +/* s3c2410_pm_do_restore_core + * + * similar to s3c2410_pm_do_restore_core + * + * WARNING: Do not put any debug in here that may effect memory or use + * peripherals, as things may be changing! +*/ + +static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) { + __raw_writel(ptr->val, ptr->reg); + } +} + +/* s3c2410_pm_show_resume_irqs + * + * print any IRQs asserted at resume time (ie, we woke from) +*/ + +static void s3c2410_pm_show_resume_irqs(int start, unsigned long which, + unsigned long mask) +{ + int i; + + which &= ~mask; + + for (i = 0; i <= 31; i++) { + if ((which) & (1L<<i)) { + DBG("IRQ %d asserted at resume\n", start+i); + } + } +} + +/* s3c2410_pm_check_resume_pin + * + * check to see if the pin is configured correctly for sleep mode, and + * make any necessary adjustments if it is not +*/ + +static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs) +{ + unsigned long irqstate; + unsigned long pinstate; + int irq = s3c2410_gpio_getirq(pin); + + if (irqoffs < 4) + irqstate = s3c_irqwake_intmask & (1L<<irqoffs); + else + irqstate = s3c_irqwake_eintmask & (1L<<irqoffs); + + pinstate = s3c2410_gpio_getcfg(pin); + + if (!irqstate) { + if (pinstate == S3C2410_GPIO_IRQ) + DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin); + } else { + if (pinstate == S3C2410_GPIO_IRQ) { + DBG("Disabling IRQ %d (pin %d)\n", irq, pin); + s3c2410_gpio_cfgpin(pin, S3C2410_GPIO_INPUT); + } + } +} + +/* s3c2410_pm_configure_extint + * + * configure all external interrupt pins +*/ + +static void s3c2410_pm_configure_extint(void) +{ + int pin; + + /* for each of the external interrupts (EINT0..EINT15) we + * need to check wether it is an external interrupt source, + * and then configure it as an input if it is not + */ + + for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) { + s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0); + } + + for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) { + s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8); + } +} + +void (*pm_cpu_prep)(void); +void (*pm_cpu_sleep)(void); + +#define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) + +/* s3c2410_pm_enter + * + * central control for sleep/resume process +*/ + +static int s3c2410_pm_enter(suspend_state_t state) +{ + unsigned long regs_save[16]; + + /* ensure the debug is initialised (if enabled) */ + + s3c2410_pm_debug_init(); + + DBG("s3c2410_pm_enter(%d)\n", state); + + if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) { + printk(KERN_ERR PFX "error: no cpu sleep functions set\n"); + return -EINVAL; + } + + if (state != PM_SUSPEND_MEM) { + printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n"); + return -EINVAL; + } + + /* check if we have anything to wake-up with... bad things seem + * to happen if you suspend with no wakeup (system will often + * require a full power-cycle) + */ + + if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && + !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { + printk(KERN_ERR PFX "No sources enabled for wake-up!\n"); + printk(KERN_ERR PFX "Aborting sleep\n"); + return -EINVAL; + } + + /* prepare check area if configured */ + + s3c2410_pm_check_prepare(); + + /* store the physical address of the register recovery block */ + + s3c2410_sleep_save_phys = virt_to_phys(regs_save); + + DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys); + + /* save all necessary core registers not covered by the drivers */ + + s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save)); + s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save)); + s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); + + /* set the irq configuration for wake */ + + s3c2410_pm_configure_extint(); + + DBG("sleep: irq wakeup masks: %08lx,%08lx\n", + s3c_irqwake_intmask, s3c_irqwake_eintmask); + + __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK); + __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); + + /* ack any outstanding external interrupts before we go to sleep */ + + __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND); + __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND); + __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND); + + /* call cpu specific preperation */ + + pm_cpu_prep(); + + /* flush cache back to ram */ + + flush_cache_all(); + + s3c2410_pm_check_store(); + + /* send the cpu to sleep... */ + + __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */ + + /* s3c2410_cpu_save will also act as our return point from when + * we resume as it saves its own register state, so use the return + * code to differentiate return from save and return from sleep */ + + if (s3c2410_cpu_save(regs_save) == 0) { + flush_cache_all(); + pm_cpu_sleep(); + } + + /* restore the cpu state */ + + cpu_init(); + + /* restore the system state */ + + s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); + s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save)); + s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); + + s3c2410_pm_debug_init(); + + /* check what irq (if any) restored the system */ + + DBG("post sleep: IRQs 0x%08x, 0x%08x\n", + __raw_readl(S3C2410_SRCPND), + __raw_readl(S3C2410_EINTPEND)); + + s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND), + s3c_irqwake_intmask); + + s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), + s3c_irqwake_eintmask); + + DBG("post sleep, preparing to return\n"); + + s3c2410_pm_check_restore(); + + /* ok, let's return from sleep */ + + DBG("S3C2410 PM Resume (post-restore)\n"); + return 0; +} + +/* + * Called after processes are frozen, but before we shut down devices. + */ +static int s3c2410_pm_prepare(suspend_state_t state) +{ + return 0; +} + +/* + * Called after devices are re-setup, but before processes are thawed. + */ +static int s3c2410_pm_finish(suspend_state_t state) +{ + return 0; +} + +/* + * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. + */ +static struct pm_ops s3c2410_pm_ops = { + .pm_disk_mode = PM_DISK_FIRMWARE, + .prepare = s3c2410_pm_prepare, + .enter = s3c2410_pm_enter, + .finish = s3c2410_pm_finish, +}; + +/* s3c2410_pm_init + * + * Attach the power management functions. This should be called + * from the board specific initialisation if the board supports + * it. +*/ + +int __init s3c2410_pm_init(void) +{ + printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n"); + + pm_set_ops(&s3c2410_pm_ops); + return 0; +} diff --git a/arch/arm/mach-s3c2410/s3c244x-irq.c b/arch/arm/plat-s3c24xx/s3c244x-irq.c index ede94636a72..a0e39d89401 100644 --- a/arch/arm/mach-s3c2410/s3c244x-irq.c +++ b/arch/arm/plat-s3c24xx/s3c244x-irq.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c244x-irq.c +/* linux/arch/arm/plat-s3c24xx/s3c244x-irq.c * * Copyright (c) 2003,2004 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -35,9 +35,9 @@ #include <asm/arch/regs-irq.h> #include <asm/arch/regs-gpio.h> -#include "cpu.h" -#include "pm.h" -#include "irq.h" +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/pm.h> +#include <asm/plat-s3c24xx/irq.h> /* camera irq */ diff --git a/arch/arm/mach-s3c2410/s3c244x.c b/arch/arm/plat-s3c24xx/s3c244x.c index 23c7494ad10..767f2e9a3a5 100644 --- a/arch/arm/mach-s3c2410/s3c244x.c +++ b/arch/arm/plat-s3c24xx/s3c244x.c @@ -1,9 +1,9 @@ -/* linux/arch/arm/mach-s3c2410/s3c244x.c +/* linux/arch/arm/plat-s3c24xx/s3c244x.c * * Copyright (c) 2004-2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * - * Samsung S3C2440 and S3C2442 Mobile CPU support + * Samsung S3C2440 and S3C2442 Mobile CPU support (not S3C2443) * * 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 @@ -35,13 +35,13 @@ #include <asm/arch/regs-gpioj.h> #include <asm/arch/regs-dsc.h> -#include "s3c2410.h" -#include "s3c2440.h" +#include <asm/plat-s3c24xx/s3c2410.h> +#include <asm/plat-s3c24xx/s3c2440.h> #include "s3c244x.h" -#include "clock.h" -#include "devs.h" -#include "cpu.h" -#include "pm.h" +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/devs.h> +#include <asm/plat-s3c24xx/cpu.h> +#include <asm/plat-s3c24xx/pm.h> static struct map_desc s3c244x_iodesc[] __initdata = { IODESC_ENT(CLKPWR), diff --git a/arch/arm/mach-s3c2410/s3c244x.h b/arch/arm/plat-s3c24xx/s3c244x.h index 1488c1eb37e..f8ed17676a3 100644 --- a/arch/arm/mach-s3c2410/s3c244x.h +++ b/arch/arm/plat-s3c24xx/s3c244x.h @@ -1,4 +1,4 @@ -/* arch/arm/mach-s3c2410/s3c244x.h +/* linux/arch/arm/plat-s3c24xx/s3c244x.h * * Copyright (c) 2004-2005 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> diff --git a/arch/arm/plat-s3c24xx/sleep.S b/arch/arm/plat-s3c24xx/sleep.S new file mode 100644 index 00000000000..435349dc324 --- /dev/null +++ b/arch/arm/plat-s3c24xx/sleep.S @@ -0,0 +1,157 @@ +/* linux/arch/arm/mach-s3c2410/sleep.S + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 Power Manager (Suspend-To-RAM) support + * + * Based on PXA/SA1100 sleep code by: + * Nicolas Pitre, (c) 2002 Monta Vista Software Inc + * Cliff Brake, (c) 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> +#include <asm/arch/map.h> + +#include <asm/arch/regs-gpio.h> +#include <asm/arch/regs-clock.h> +#include <asm/arch/regs-mem.h> +#include <asm/arch/regs-serial.h> + +/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not + * reset the UART configuration, only enable if you really need this! +*/ +//#define CONFIG_DEBUG_RESUME + + .text + + /* s3c2410_cpu_save + * + * save enough of the CPU state to allow us to re-start + * pm.c code. as we store items like the sp/lr, we will + * end up returning from this function when the cpu resumes + * so the return value is set to mark this. + * + * This arangement means we avoid having to flush the cache + * from this code. + * + * entry: + * r0 = pointer to save block + * + * exit: + * r0 = 0 => we stored everything + * 1 => resumed from sleep + */ + +ENTRY(s3c2410_cpu_save) + stmfd sp!, { r4 - r12, lr } + + @@ store co-processor registers + + mrc p15, 0, r4, c13, c0, 0 @ PID + mrc p15, 0, r5, c3, c0, 0 @ Domain ID + mrc p15, 0, r6, c2, c0, 0 @ translation table base address + mrc p15, 0, r7, c1, c0, 0 @ control register + + stmia r0, { r4 - r13 } + + mov r0, #0 + ldmfd sp, { r4 - r12, pc } + + @@ return to the caller, after having the MMU + @@ turned on, this restores the last bits from the + @@ stack +resume_with_mmu: + mov r0, #1 + ldmfd sp!, { r4 - r12, pc } + + .ltorg + + @@ the next bits sit in the .data segment, even though they + @@ happen to be code... the s3c2410_sleep_save_phys needs to be + @@ accessed by the resume code before it can restore the MMU. + @@ This means that the variable has to be close enough for the + @@ code to read it... since the .text segment needs to be RO, + @@ the data segment can be the only place to put this code. + + .data + + .global s3c2410_sleep_save_phys +s3c2410_sleep_save_phys: + .word 0 + + /* s3c2410_cpu_resume + * + * resume code entry for bootloader to call + * + * we must put this code here in the data segment as we have no + * other way of restoring the stack pointer after sleep, and we + * must not write to the code segment (code is read-only) + */ + +ENTRY(s3c2410_cpu_resume) + mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE + msr cpsr_c, r0 + + @@ load UART to allow us to print the two characters for + @@ resume debug + + mov r2, #S3C24XX_PA_UART & 0xff000000 + orr r2, r2, #S3C24XX_PA_UART & 0xff000 + +#if 0 + /* SMDK2440 LED set */ + mov r14, #S3C24XX_PA_GPIO + ldr r12, [ r14, #0x54 ] + bic r12, r12, #3<<4 + orr r12, r12, #1<<7 + str r12, [ r14, #0x54 ] +#endif + +#ifdef CONFIG_DEBUG_RESUME + mov r3, #'L' + strb r3, [ r2, #S3C2410_UTXH ] +1001: + ldrb r14, [ r3, #S3C2410_UTRSTAT ] + tst r14, #S3C2410_UTRSTAT_TXE + beq 1001b +#endif /* CONFIG_DEBUG_RESUME */ + + mov r1, #0 + mcr p15, 0, r1, c8, c7, 0 @@ invalidate I & D TLBs + mcr p15, 0, r1, c7, c7, 0 @@ invalidate I & D caches + + ldr r0, s3c2410_sleep_save_phys @ address of restore block + ldmia r0, { r4 - r13 } + + mcr p15, 0, r4, c13, c0, 0 @ PID + mcr p15, 0, r5, c3, c0, 0 @ Domain ID + mcr p15, 0, r6, c2, c0, 0 @ translation table base + +#ifdef CONFIG_DEBUG_RESUME + mov r3, #'R' + strb r3, [ r2, #S3C2410_UTXH ] +#endif + + ldr r2, =resume_with_mmu + mcr p15, 0, r7, c1, c0, 0 @ turn on MMU, etc + nop @ second-to-last before mmu + mov pc, r2 @ go back to virtual address + + .ltorg diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/plat-s3c24xx/time.c index 9910bf0f2ce..c523d1c9cce 100644 --- a/arch/arm/mach-s3c2410/time.c +++ b/arch/arm/plat-s3c24xx/time.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/time.c +/* linux/arch/arm/plat-s3c24xx/time.c * * Copyright (C) 2003-2005 Simtec Electronics * Ben Dooks, <ben@simtec.co.uk> @@ -37,8 +37,8 @@ #include <asm/arch/regs-irq.h> #include <asm/mach/time.h> -#include "clock.h" -#include "cpu.h" +#include <asm/plat-s3c24xx/clock.h> +#include <asm/plat-s3c24xx/cpu.h> static unsigned long timer_startval; static unsigned long timer_usec_ticks; diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c index 49e7b12fe71..00c435452d7 100644 --- a/arch/avr32/mach-at32ap/clock.c +++ b/arch/avr32/mach-at32ap/clock.c @@ -3,7 +3,7 @@ * * Copyright (C) 2006 Atmel Corporation * - * Based on arch/arm/mach-at91rm9200/clock.c + * Based on arch/arm/mach-at91/clock.c * Copyright (C) 2005 David Brownell * Copyright (C) 2005 Ivan Kokshaysky * diff --git a/arch/avr32/mach-at32ap/clock.h b/arch/avr32/mach-at32ap/clock.h index f953f044ba4..bb8e1f29583 100644 --- a/arch/avr32/mach-at32ap/clock.h +++ b/arch/avr32/mach-at32ap/clock.h @@ -3,7 +3,7 @@ * * Copyright (C) 2006 Atmel Corporation * - * Based on arch/arm/mach-at91rm9200/clock.c + * Based on arch/arm/mach-at91/clock.c * Copyright (C) 2005 David Brownell * Copyright (C) 2005 Ivan Kokshaysky * diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index fb3e72328a5..e5eb97a910e 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -850,10 +850,9 @@ static inline int acpi_parse_madt_ioapic_entries(void) static void __init acpi_process_madt(void) { #ifdef CONFIG_X86_LOCAL_APIC - int count, error; + int error; - count = acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt); - if (count >= 1) { + if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) { /* * Parse MADT LAPIC entries diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c index 53ca6e89798..1bb06937214 100644 --- a/arch/i386/pci/common.c +++ b/arch/i386/pci/common.c @@ -191,6 +191,94 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"), }, }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL20p G3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G3"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL20p G4", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G4"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL30p G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL30p G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL25p G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL25p G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL35p G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL35p G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL45p G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL45p G2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G2"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL460c G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL460c G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL465c G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL465c G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL480c G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL480c G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL685c G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL685c G1"), + }, + }, {} }; diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 9197d7b361b..3549c94467b 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -651,7 +651,7 @@ int __init acpi_boot_init(void) * information -- the successor to MPS tables. */ - if (acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt) < 1) { + if (acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) { printk(KERN_ERR PREFIX "Can't find MADT\n"); goto skip_madt; } @@ -702,7 +702,7 @@ int __init acpi_boot_init(void) * gets interrupts such as power and sleep buttons. If it's not * on a Legacy interrupt, it needs to be setup. */ - if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt) < 1) + if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt)) printk(KERN_ERR PREFIX "Can't find FADT\n"); #ifdef CONFIG_SMP diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 340d9beab6d..6dfbd52694a 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -620,6 +620,15 @@ config RTAS_FLASH tristate "Firmware flash interface" depends on PPC64 && RTAS_PROC +config PPC_PMI + tristate "Support for PMI" + depends PPC_IBM_CELL_BLADE + help + PMI (Platform Management Interrupt) is a way to + communicate with the BMC (Baseboard Mangement Controller). + It is used in some IBM Cell blades. + default m + config MMIO_NVRAM bool default n diff --git a/arch/powerpc/boot/dts/kuroboxHD.dts b/arch/powerpc/boot/dts/kuroboxHD.dts index 096e94ac415..b89791802e8 100644 --- a/arch/powerpc/boot/dts/kuroboxHD.dts +++ b/arch/powerpc/boot/dts/kuroboxHD.dts @@ -35,7 +35,6 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHD.dtb -V 16 kuroboxHD.dts" PowerPC,603e { /* Really 8241 */ linux,phandle = <2100>; - linux,boot-cpu; device_type = "cpu"; reg = <0>; clock-frequency = <bebc200>; /* Fixed by bootwrapper */ diff --git a/arch/powerpc/boot/dts/kuroboxHG.dts b/arch/powerpc/boot/dts/kuroboxHG.dts index d06b0b01889..753102752d8 100644 --- a/arch/powerpc/boot/dts/kuroboxHG.dts +++ b/arch/powerpc/boot/dts/kuroboxHG.dts @@ -35,7 +35,6 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHG.dtb -V 16 kuroboxHG.dts" PowerPC,603e { /* Really 8241 */ linux,phandle = <2100>; - linux,boot-cpu; device_type = "cpu"; reg = <0>; clock-frequency = <fdad680>; /* Fixed by bootwrapper */ diff --git a/arch/powerpc/boot/dts/mpc7448hpc2.dts b/arch/powerpc/boot/dts/mpc7448hpc2.dts index c4d9562cbaa..41d0720c590 100644 --- a/arch/powerpc/boot/dts/mpc7448hpc2.dts +++ b/arch/powerpc/boot/dts/mpc7448hpc2.dts @@ -36,7 +36,6 @@ bus-frequency = <0>; // From U-Boot 32-bit; linux,phandle = <201>; - linux,boot-cpu; }; }; diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts index 26b44f7513d..260b2e44777 100644 --- a/arch/powerpc/boot/dts/mpc8272ads.dts +++ b/arch/powerpc/boot/dts/mpc8272ads.dts @@ -34,7 +34,6 @@ clock-frequency = <0>; 32-bit; linux,phandle = <201>; - linux,boot-cpu; }; }; diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts index 3d2f5a06df3..6d721900d00 100644 --- a/arch/powerpc/boot/dts/mpc8313erdb.dts +++ b/arch/powerpc/boot/dts/mpc8313erdb.dts @@ -11,7 +11,7 @@ / { model = "MPC8313ERDB"; - compatible = "MPC83xx"; + compatible = "MPC8313ERDB", "MPC831xRDB", "MPC83xxRDB"; #address-cells = <1>; #size-cells = <1>; @@ -59,7 +59,7 @@ compatible = "fsl-i2c"; reg = <3000 100>; interrupts = <e 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; dfsrr; }; @@ -68,7 +68,7 @@ compatible = "fsl-i2c"; reg = <3100 100>; interrupts = <f 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; dfsrr; }; @@ -77,7 +77,7 @@ compatible = "mpc83xx_spi"; reg = <7000 1000>; interrupts = <10 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; mode = <0>; }; @@ -88,8 +88,8 @@ reg = <23000 1000>; #address-cells = <1>; #size-cells = <0>; - interrupt-parent = <700>; - interrupts = <26 2>; + interrupt-parent = < &ipic >; + interrupts = <26 8>; phy_type = "utmi_wide"; }; @@ -99,18 +99,15 @@ reg = <24520 20>; #address-cells = <1>; #size-cells = <0>; - linux,phandle = <24520>; - ethernet-phy@1 { - linux,phandle = <2452001>; - interrupt-parent = <700>; - interrupts = <13 2>; + phy1: ethernet-phy@1 { + interrupt-parent = < &ipic >; + interrupts = <13 8>; reg = <1>; device_type = "ethernet-phy"; }; - ethernet-phy@4 { - linux,phandle = <2452004>; - interrupt-parent = <700>; - interrupts = <14 2>; + phy4: ethernet-phy@4 { + interrupt-parent = < &ipic >; + interrupts = <14 8>; reg = <4>; device_type = "ethernet-phy"; }; @@ -123,8 +120,8 @@ reg = <24000 1000>; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <25 8 24 8 23 8>; - interrupt-parent = <700>; - phy-handle = <2452001>; + interrupt-parent = < &ipic >; + phy-handle = < &phy1 >; }; ethernet@25000 { @@ -134,8 +131,8 @@ reg = <25000 1000>; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <22 8 21 8 20 8>; - interrupt-parent = <700>; - phy-handle = <2452004>; + interrupt-parent = < &ipic >; + phy-handle = < &phy4 >; }; serial@4500 { @@ -144,7 +141,7 @@ reg = <4500 100>; clock-frequency = <0>; interrupts = <9 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; serial@4600 { @@ -153,7 +150,7 @@ reg = <4600 100>; clock-frequency = <0>; interrupts = <a 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; pci@8500 { @@ -161,17 +158,17 @@ interrupt-map = < /* IDSEL 0x0E -mini PCI */ - 7000 0 0 1 700 12 8 - 7000 0 0 2 700 12 8 - 7000 0 0 3 700 12 8 - 7000 0 0 4 700 12 8 + 7000 0 0 1 &ipic 12 8 + 7000 0 0 2 &ipic 12 8 + 7000 0 0 3 &ipic 12 8 + 7000 0 0 4 &ipic 12 8 /* IDSEL 0x0F - PCI slot */ - 7800 0 0 1 700 11 8 - 7800 0 0 2 700 12 8 - 7800 0 0 3 700 11 8 - 7800 0 0 4 700 12 8>; - interrupt-parent = <700>; + 7800 0 0 1 &ipic 11 8 + 7800 0 0 2 &ipic 12 8 + 7800 0 0 3 &ipic 11 8 + 7800 0 0 4 &ipic 12 8>; + interrupt-parent = < &ipic >; interrupts = <42 8>; bus-range = <0 0>; ranges = <02000000 0 90000000 90000000 0 10000000 @@ -192,7 +189,7 @@ compatible = "talitos"; reg = <30000 7000>; interrupts = <b 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; /* Rev. 2.2 */ num-channels = <1>; channel-fifo-len = <18>; @@ -206,8 +203,7 @@ * sense == 8: Level, low assertion * sense == 2: Edge, high-to-low change */ - pic@700 { - linux,phandle = <700>; + ipic: pic@700 { interrupt-controller; #address-cells = <0>; #interrupt-cells = <2>; diff --git a/arch/powerpc/boot/dts/mpc8323emds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts index fa7ef24d205..06b310698a0 100644 --- a/arch/powerpc/boot/dts/mpc8323emds.dts +++ b/arch/powerpc/boot/dts/mpc832x_mds.dts @@ -11,16 +11,14 @@ / { model = "MPC8323EMDS"; - compatible = "MPC83xx"; + compatible = "MPC8323EMDS", "MPC832xMDS", "MPC83xxMDS"; #address-cells = <1>; #size-cells = <1>; - linux,phandle = <100>; cpus { #cpus = <1>; #address-cells = <1>; #size-cells = <0>; - linux,phandle = <200>; PowerPC,8323@0 { device_type = "cpu"; @@ -33,14 +31,11 @@ bus-frequency = <0>; clock-frequency = <0>; 32-bit; - linux,phandle = <201>; - linux,boot-cpu; }; }; memory { device_type = "memory"; - linux,phandle = <300>; reg = <00000000 08000000>; }; @@ -69,7 +64,7 @@ compatible = "fsl-i2c"; reg = <3000 100>; interrupts = <e 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; dfsrr; }; @@ -79,7 +74,7 @@ reg = <4500 100>; clock-frequency = <0>; interrupts = <9 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; serial@4600 { @@ -88,7 +83,7 @@ reg = <4600 100>; clock-frequency = <0>; interrupts = <a 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; crypto@30000 { @@ -97,7 +92,7 @@ compatible = "talitos"; reg = <30000 7000>; interrupts = <b 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; /* Rev. 2.2 */ num-channels = <1>; channel-fifo-len = <18>; @@ -106,51 +101,50 @@ }; pci@8500 { - linux,phandle = <8500>; interrupt-map-mask = <f800 0 0 7>; interrupt-map = < /* IDSEL 0x11 AD17 */ - 8800 0 0 1 700 14 8 - 8800 0 0 2 700 15 8 - 8800 0 0 3 700 16 8 - 8800 0 0 4 700 17 8 + 8800 0 0 1 &ipic 14 8 + 8800 0 0 2 &ipic 15 8 + 8800 0 0 3 &ipic 16 8 + 8800 0 0 4 &ipic 17 8 /* IDSEL 0x12 AD18 */ - 9000 0 0 1 700 16 8 - 9000 0 0 2 700 17 8 - 9000 0 0 3 700 14 8 - 9000 0 0 4 700 15 8 + 9000 0 0 1 &ipic 16 8 + 9000 0 0 2 &ipic 17 8 + 9000 0 0 3 &ipic 14 8 + 9000 0 0 4 &ipic 15 8 /* IDSEL 0x13 AD19 */ - 9800 0 0 1 700 17 8 - 9800 0 0 2 700 14 8 - 9800 0 0 3 700 15 8 - 9800 0 0 4 700 16 8 + 9800 0 0 1 &ipic 17 8 + 9800 0 0 2 &ipic 14 8 + 9800 0 0 3 &ipic 15 8 + 9800 0 0 4 &ipic 16 8 /* IDSEL 0x15 AD21*/ - a800 0 0 1 700 14 8 - a800 0 0 2 700 15 8 - a800 0 0 3 700 16 8 - a800 0 0 4 700 17 8 + a800 0 0 1 &ipic 14 8 + a800 0 0 2 &ipic 15 8 + a800 0 0 3 &ipic 16 8 + a800 0 0 4 &ipic 17 8 /* IDSEL 0x16 AD22*/ - b000 0 0 1 700 17 8 - b000 0 0 2 700 14 8 - b000 0 0 3 700 15 8 - b000 0 0 4 700 16 8 + b000 0 0 1 &ipic 17 8 + b000 0 0 2 &ipic 14 8 + b000 0 0 3 &ipic 15 8 + b000 0 0 4 &ipic 16 8 /* IDSEL 0x17 AD23*/ - b800 0 0 1 700 16 8 - b800 0 0 2 700 17 8 - b800 0 0 3 700 14 8 - b800 0 0 4 700 15 8 + b800 0 0 1 &ipic 16 8 + b800 0 0 2 &ipic 17 8 + b800 0 0 3 &ipic 14 8 + b800 0 0 4 &ipic 15 8 /* IDSEL 0x18 AD24*/ - c000 0 0 1 700 15 8 - c000 0 0 2 700 16 8 - c000 0 0 3 700 17 8 - c000 0 0 4 700 14 8>; - interrupt-parent = <700>; + c000 0 0 1 &ipic 15 8 + c000 0 0 2 &ipic 16 8 + c000 0 0 3 &ipic 17 8 + c000 0 0 4 &ipic 14 8>; + interrupt-parent = < &ipic >; interrupts = <42 8>; bus-range = <0 0>; ranges = <02000000 0 a0000000 90000000 0 10000000 @@ -165,8 +159,7 @@ device_type = "pci"; }; - pic@700 { - linux,phandle = <700>; + ipic: pic@700 { interrupt-controller; #address-cells = <0>; #interrupt-cells = <2>; @@ -180,8 +173,7 @@ device_type = "par_io"; num-ports = <7>; - ucc_pin@03 { - linux,phandle = <140003>; + pio3: ucc_pin@03 { pio-map = < /* port pin dir open_drain assignment has_irq */ 3 4 3 0 2 0 /* MDIO */ @@ -204,8 +196,7 @@ 1 c 1 0 1 0 /* TX_EN */ 1 d 2 0 1 0>;/* CRS */ }; - ucc_pin@04 { - linux,phandle = <140004>; + pio4: ucc_pin@04 { pio-map = < /* port pin dir open_drain assignment has_irq */ 3 1f 2 0 1 0 /* RX_CLK (CLK7) */ @@ -252,7 +243,7 @@ compatible = "fsl_spi"; reg = <4c0 40>; interrupts = <2>; - interrupt-parent = <80>; + interrupt-parent = < &qeic >; mode = "cpu"; }; @@ -261,7 +252,7 @@ compatible = "fsl_spi"; reg = <500 40>; interrupts = <1>; - interrupt-parent = <80>; + interrupt-parent = < &qeic >; mode = "cpu"; }; @@ -270,7 +261,7 @@ compatible = "qe_udc"; reg = <6c0 40 8B00 100>; interrupts = <b>; - interrupt-parent = <80>; + interrupt-parent = < &qeic >; mode = "slave"; }; @@ -281,12 +272,12 @@ device-id = <3>; reg = <2200 200>; interrupts = <22>; - interrupt-parent = <80>; + interrupt-parent = < &qeic >; mac-address = [ 00 04 9f 00 23 23 ]; rx-clock = <19>; tx-clock = <1a>; - phy-handle = <212003>; - pio-handle = <140003>; + phy-handle = < &phy3 >; + pio-handle = < &pio3 >; }; ucc@3200 { @@ -296,12 +287,12 @@ device-id = <4>; reg = <3000 200>; interrupts = <23>; - interrupt-parent = <80>; + interrupt-parent = < &qeic >; mac-address = [ 00 11 22 33 44 55 ]; rx-clock = <17>; tx-clock = <18>; - phy-handle = <212004>; - pio-handle = <140004>; + phy-handle = < &phy4 >; + pio-handle = < &pio4 >; }; mdio@2320 { @@ -311,26 +302,23 @@ device_type = "mdio"; compatible = "ucc_geth_phy"; - ethernet-phy@03 { - linux,phandle = <212003>; - interrupt-parent = <700>; - interrupts = <11 2>; + phy3: ethernet-phy@03 { + interrupt-parent = < &ipic >; + interrupts = <11 8>; reg = <3>; device_type = "ethernet-phy"; interface = <3>; //ENET_100_MII }; - ethernet-phy@04 { - linux,phandle = <212004>; - interrupt-parent = <700>; - interrupts = <12 2>; + phy4: ethernet-phy@04 { + interrupt-parent = < &ipic >; + interrupts = <12 8>; reg = <4>; device_type = "ethernet-phy"; interface = <3>; }; }; - qeic@80 { - linux,phandle = <80>; + qeic: qeic@80 { interrupt-controller; device_type = "qeic"; #address-cells = <0>; @@ -339,7 +327,7 @@ built-in; big-endian; interrupts = <20 8 21 8>; //high:32 low:33 - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; }; }; diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts index 27807fc4588..61b550bf164 100644 --- a/arch/powerpc/boot/dts/mpc8349emitx.dts +++ b/arch/powerpc/boot/dts/mpc8349emitx.dts @@ -10,7 +10,7 @@ */ / { model = "MPC8349EMITX"; - compatible = "MPC834xMITX"; + compatible = "MPC8349EMITX", "MPC834xMITX", "MPC83xxMITX"; #address-cells = <1>; #size-cells = <1>; @@ -58,7 +58,7 @@ compatible = "fsl-i2c"; reg = <3000 100>; interrupts = <e 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; dfsrr; }; @@ -67,7 +67,7 @@ compatible = "fsl-i2c"; reg = <3100 100>; interrupts = <f 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; dfsrr; }; @@ -76,7 +76,7 @@ compatible = "mpc83xx_spi"; reg = <7000 1000>; interrupts = <10 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; mode = <0>; }; @@ -86,8 +86,8 @@ reg = <22000 1000>; #address-cells = <1>; #size-cells = <0>; - interrupt-parent = <700>; - interrupts = <27 2>; + interrupt-parent = < &ipic >; + interrupts = <27 8>; phy_type = "ulpi"; port1; }; @@ -98,8 +98,8 @@ reg = <23000 1000>; #address-cells = <1>; #size-cells = <0>; - interrupt-parent = <700>; - interrupts = <26 2>; + interrupt-parent = < &ipic >; + interrupts = <26 8>; phy_type = "ulpi"; }; @@ -109,22 +109,19 @@ reg = <24520 20>; #address-cells = <1>; #size-cells = <0>; - linux,phandle = <24520>; /* Vitesse 8201 */ - ethernet-phy@1c { - linux,phandle = <245201c>; - interrupt-parent = <700>; - interrupts = <12 2>; + phy1c: ethernet-phy@1c { + interrupt-parent = < &ipic >; + interrupts = <12 8>; reg = <1c>; device_type = "ethernet-phy"; }; /* Vitesse 7385 */ - ethernet-phy@1f { - linux,phandle = <245201f>; - interrupt-parent = <700>; - interrupts = <12 2>; + phy1f: ethernet-phy@1f { + interrupt-parent = < &ipic >; + interrupts = <12 8>; reg = <1f>; device_type = "ethernet-phy"; }; @@ -138,8 +135,8 @@ address = [ 00 00 00 00 00 00 ]; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <20 8 21 8 22 8>; - interrupt-parent = <700>; - phy-handle = <245201c>; + interrupt-parent = < &ipic >; + phy-handle = < &phy1c >; }; ethernet@25000 { @@ -152,8 +149,8 @@ address = [ 00 00 00 00 00 00 ]; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <23 8 24 8 25 8>; - interrupt-parent = <700>; - phy-handle = <245201f>; + interrupt-parent = < &ipic >; + phy-handle = < &phy1f >; }; serial@4500 { @@ -162,7 +159,7 @@ reg = <4500 100>; clock-frequency = <0>; // from bootloader interrupts = <9 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; serial@4600 { @@ -171,16 +168,16 @@ reg = <4600 100>; clock-frequency = <0>; // from bootloader interrupts = <a 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; pci@8500 { interrupt-map-mask = <f800 0 0 7>; interrupt-map = < /* IDSEL 0x10 - SATA */ - 8000 0 0 1 700 16 8 /* SATA_INTA */ + 8000 0 0 1 &ipic 16 8 /* SATA_INTA */ >; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; interrupts = <42 8>; bus-range = <0 0>; ranges = <42000000 0 80000000 80000000 0 10000000 @@ -199,13 +196,13 @@ interrupt-map-mask = <f800 0 0 7>; interrupt-map = < /* IDSEL 0x0E - MiniPCI Slot */ - 7000 0 0 1 700 15 8 /* PCI_INTA */ + 7000 0 0 1 &ipic 15 8 /* PCI_INTA */ /* IDSEL 0x0F - PCI Slot */ - 7800 0 0 1 700 14 8 /* PCI_INTA */ - 7800 0 0 2 700 15 8 /* PCI_INTB */ + 7800 0 0 1 &ipic 14 8 /* PCI_INTA */ + 7800 0 0 2 &ipic 15 8 /* PCI_INTB */ >; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; interrupts = <43 8>; bus-range = <1 1>; ranges = <42000000 0 a0000000 a0000000 0 10000000 @@ -226,15 +223,14 @@ compatible = "talitos"; reg = <30000 10000>; interrupts = <b 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; num-channels = <4>; channel-fifo-len = <18>; exec-units-mask = <0000007e>; descriptor-types-mask = <01010ebf>; }; - pic@700 { - linux,phandle = <700>; + ipic: pic@700 { interrupt-controller; #address-cells = <0>; #interrupt-cells = <2>; diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts index 3190774de1d..b2e1a5ec377 100644 --- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts +++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts @@ -10,7 +10,7 @@ */ / { model = "MPC8349EMITXGP"; - compatible = "MPC834xMITXGP"; + compatible = "MPC8349EMITXGP", "MPC834xMITX", "MPC83xxMITX"; #address-cells = <1>; #size-cells = <1>; @@ -58,7 +58,7 @@ compatible = "fsl-i2c"; reg = <3000 100>; interrupts = <e 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; dfsrr; }; @@ -67,7 +67,7 @@ compatible = "fsl-i2c"; reg = <3100 100>; interrupts = <f 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; dfsrr; }; @@ -76,7 +76,7 @@ compatible = "mpc83xx_spi"; reg = <7000 1000>; interrupts = <10 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; mode = <0>; }; @@ -86,8 +86,8 @@ reg = <23000 1000>; #address-cells = <1>; #size-cells = <0>; - interrupt-parent = <700>; - interrupts = <26 2>; + interrupt-parent = < &ipic >; + interrupts = <26 8>; dr_mode = "otg"; phy_type = "ulpi"; }; @@ -98,13 +98,11 @@ reg = <24520 20>; #address-cells = <1>; #size-cells = <0>; - linux,phandle = <24520>; /* Vitesse 8201 */ - ethernet-phy@1c { - linux,phandle = <245201c>; - interrupt-parent = <700>; - interrupts = <12 2>; + phy1c: ethernet-phy@1c { + interrupt-parent = < &ipic >; + interrupts = <12 8>; reg = <1c>; device_type = "ethernet-phy"; }; @@ -117,8 +115,8 @@ reg = <24000 1000>; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <20 8 21 8 22 8>; - interrupt-parent = <700>; - phy-handle = <245201c>; + interrupt-parent = < &ipic >; + phy-handle = < &phy1c >; }; serial@4500 { @@ -127,7 +125,7 @@ reg = <4500 100>; clock-frequency = <0>; // from bootloader interrupts = <9 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; serial@4600 { @@ -136,17 +134,17 @@ reg = <4600 100>; clock-frequency = <0>; // from bootloader interrupts = <a 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; pci@8600 { interrupt-map-mask = <f800 0 0 7>; interrupt-map = < /* IDSEL 0x0F - PCI Slot */ - 7800 0 0 1 700 14 8 /* PCI_INTA */ - 7800 0 0 2 700 15 8 /* PCI_INTB */ + 7800 0 0 1 &ipic 14 8 /* PCI_INTA */ + 7800 0 0 2 &ipic 15 8 /* PCI_INTB */ >; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; interrupts = <43 8>; bus-range = <1 1>; ranges = <42000000 0 a0000000 a0000000 0 10000000 @@ -167,15 +165,14 @@ compatible = "talitos"; reg = <30000 10000>; interrupts = <b 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; num-channels = <4>; channel-fifo-len = <18>; exec-units-mask = <0000007e>; descriptor-types-mask = <01010ebf>; }; - pic@700 { - linux,phandle = <700>; + ipic: pic@700 { interrupt-controller; #address-cells = <0>; #interrupt-cells = <2>; diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts index dc121b3cb4a..e4b43c24bc0 100644 --- a/arch/powerpc/boot/dts/mpc834x_mds.dts +++ b/arch/powerpc/boot/dts/mpc834x_mds.dts @@ -11,7 +11,7 @@ / { model = "MPC8349EMDS"; - compatible = "MPC834xMDS"; + compatible = "MPC8349EMDS", "MPC834xMDS", "MPC83xxMDS"; #address-cells = <1>; #size-cells = <1>; @@ -64,7 +64,7 @@ compatible = "fsl-i2c"; reg = <3000 100>; interrupts = <e 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; dfsrr; }; @@ -73,7 +73,7 @@ compatible = "fsl-i2c"; reg = <3100 100>; interrupts = <f 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; dfsrr; }; @@ -82,7 +82,7 @@ compatible = "mpc83xx_spi"; reg = <7000 1000>; interrupts = <10 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; mode = <0>; }; @@ -94,8 +94,8 @@ reg = <22000 1000>; #address-cells = <1>; #size-cells = <0>; - interrupt-parent = <700>; - interrupts = <27 2>; + interrupt-parent = < &ipic >; + interrupts = <27 8>; phy_type = "ulpi"; port1; }; @@ -106,8 +106,8 @@ reg = <23000 1000>; #address-cells = <1>; #size-cells = <0>; - interrupt-parent = <700>; - interrupts = <26 2>; + interrupt-parent = < &ipic >; + interrupts = <26 8>; dr_mode = "otg"; phy_type = "ulpi"; }; @@ -118,18 +118,15 @@ reg = <24520 20>; #address-cells = <1>; #size-cells = <0>; - linux,phandle = <24520>; - ethernet-phy@0 { - linux,phandle = <2452000>; - interrupt-parent = <700>; - interrupts = <11 2>; + phy0: ethernet-phy@0 { + interrupt-parent = < &ipic >; + interrupts = <11 8>; reg = <0>; device_type = "ethernet-phy"; }; - ethernet-phy@1 { - linux,phandle = <2452001>; - interrupt-parent = <700>; - interrupts = <12 2>; + phy1: ethernet-phy@1 { + interrupt-parent = < &ipic >; + interrupts = <12 8>; reg = <1>; device_type = "ethernet-phy"; }; @@ -143,8 +140,8 @@ address = [ 00 00 00 00 00 00 ]; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <20 8 21 8 22 8>; - interrupt-parent = <700>; - phy-handle = <2452000>; + interrupt-parent = < &ipic >; + phy-handle = < &phy0 >; }; ethernet@25000 { @@ -157,8 +154,8 @@ address = [ 00 00 00 00 00 00 ]; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <23 8 24 8 25 8>; - interrupt-parent = <700>; - phy-handle = <2452001>; + interrupt-parent = < &ipic >; + phy-handle = < &phy1 >; }; serial@4500 { @@ -167,7 +164,7 @@ reg = <4500 100>; clock-frequency = <0>; interrupts = <9 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; serial@4600 { @@ -176,7 +173,7 @@ reg = <4600 100>; clock-frequency = <0>; interrupts = <a 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; pci@8500 { @@ -184,47 +181,47 @@ interrupt-map = < /* IDSEL 0x11 */ - 8800 0 0 1 700 14 8 - 8800 0 0 2 700 15 8 - 8800 0 0 3 700 16 8 - 8800 0 0 4 700 17 8 + 8800 0 0 1 &ipic 14 8 + 8800 0 0 2 &ipic 15 8 + 8800 0 0 3 &ipic 16 8 + 8800 0 0 4 &ipic 17 8 /* IDSEL 0x12 */ - 9000 0 0 1 700 16 8 - 9000 0 0 2 700 17 8 - 9000 0 0 3 700 14 8 - 9000 0 0 4 700 15 8 + 9000 0 0 1 &ipic 16 8 + 9000 0 0 2 &ipic 17 8 + 9000 0 0 3 &ipic 14 8 + 9000 0 0 4 &ipic 15 8 /* IDSEL 0x13 */ - 9800 0 0 1 700 17 8 - 9800 0 0 2 700 14 8 - 9800 0 0 3 700 15 8 - 9800 0 0 4 700 16 8 + 9800 0 0 1 &ipic 17 8 + 9800 0 0 2 &ipic 14 8 + 9800 0 0 3 &ipic 15 8 + 9800 0 0 4 &ipic 16 8 /* IDSEL 0x15 */ - a800 0 0 1 700 14 8 - a800 0 0 2 700 15 8 - a800 0 0 3 700 16 8 - a800 0 0 4 700 17 8 + a800 0 0 1 &ipic 14 8 + a800 0 0 2 &ipic 15 8 + a800 0 0 3 &ipic 16 8 + a800 0 0 4 &ipic 17 8 /* IDSEL 0x16 */ - b000 0 0 1 700 17 8 - b000 0 0 2 700 14 8 - b000 0 0 3 700 15 8 - b000 0 0 4 700 16 8 + b000 0 0 1 &ipic 17 8 + b000 0 0 2 &ipic 14 8 + b000 0 0 3 &ipic 15 8 + b000 0 0 4 &ipic 16 8 /* IDSEL 0x17 */ - b800 0 0 1 700 16 8 - b800 0 0 2 700 17 8 - b800 0 0 3 700 14 8 - b800 0 0 4 700 15 8 + b800 0 0 1 &ipic 16 8 + b800 0 0 2 &ipic 17 8 + b800 0 0 3 &ipic 14 8 + b800 0 0 4 &ipic 15 8 /* IDSEL 0x18 */ - c000 0 0 1 700 15 8 - c000 0 0 2 700 16 8 - c000 0 0 3 700 17 8 - c000 0 0 4 700 14 8>; - interrupt-parent = <700>; + c000 0 0 1 &ipic 15 8 + c000 0 0 2 &ipic 16 8 + c000 0 0 3 &ipic 17 8 + c000 0 0 4 &ipic 14 8>; + interrupt-parent = < &ipic >; interrupts = <42 8>; bus-range = <0 0>; ranges = <02000000 0 a0000000 a0000000 0 10000000 @@ -244,47 +241,47 @@ interrupt-map = < /* IDSEL 0x11 */ - 8800 0 0 1 700 14 8 - 8800 0 0 2 700 15 8 - 8800 0 0 3 700 16 8 - 8800 0 0 4 700 17 8 + 8800 0 0 1 &ipic 14 8 + 8800 0 0 2 &ipic 15 8 + 8800 0 0 3 &ipic 16 8 + 8800 0 0 4 &ipic 17 8 /* IDSEL 0x12 */ - 9000 0 0 1 700 16 8 - 9000 0 0 2 700 17 8 - 9000 0 0 3 700 14 8 - 9000 0 0 4 700 15 8 + 9000 0 0 1 &ipic 16 8 + 9000 0 0 2 &ipic 17 8 + 9000 0 0 3 &ipic 14 8 + 9000 0 0 4 &ipic 15 8 /* IDSEL 0x13 */ - 9800 0 0 1 700 17 8 - 9800 0 0 2 700 14 8 - 9800 0 0 3 700 15 8 - 9800 0 0 4 700 16 8 + 9800 0 0 1 &ipic 17 8 + 9800 0 0 2 &ipic 14 8 + 9800 0 0 3 &ipic 15 8 + 9800 0 0 4 &ipic 16 8 /* IDSEL 0x15 */ - a800 0 0 1 700 14 8 - a800 0 0 2 700 15 8 - a800 0 0 3 700 16 8 - a800 0 0 4 700 17 8 + a800 0 0 1 &ipic 14 8 + a800 0 0 2 &ipic 15 8 + a800 0 0 3 &ipic 16 8 + a800 0 0 4 &ipic 17 8 /* IDSEL 0x16 */ - b000 0 0 1 700 17 8 - b000 0 0 2 700 14 8 - b000 0 0 3 700 15 8 - b000 0 0 4 700 16 8 + b000 0 0 1 &ipic 17 8 + b000 0 0 2 &ipic 14 8 + b000 0 0 3 &ipic 15 8 + b000 0 0 4 &ipic 16 8 /* IDSEL 0x17 */ - b800 0 0 1 700 16 8 - b800 0 0 2 700 17 8 - b800 0 0 3 700 14 8 - b800 0 0 4 700 15 8 + b800 0 0 1 &ipic 16 8 + b800 0 0 2 &ipic 17 8 + b800 0 0 3 &ipic 14 8 + b800 0 0 4 &ipic 15 8 /* IDSEL 0x18 */ - c000 0 0 1 700 15 8 - c000 0 0 2 700 16 8 - c000 0 0 3 700 17 8 - c000 0 0 4 700 14 8>; - interrupt-parent = <700>; + c000 0 0 1 &ipic 15 8 + c000 0 0 2 &ipic 16 8 + c000 0 0 3 &ipic 17 8 + c000 0 0 4 &ipic 14 8>; + interrupt-parent = < &ipic >; interrupts = <42 8>; bus-range = <0 0>; ranges = <02000000 0 b0000000 b0000000 0 10000000 @@ -306,7 +303,7 @@ compatible = "talitos"; reg = <30000 10000>; interrupts = <b 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; num-channels = <4>; channel-fifo-len = <18>; exec-units-mask = <0000007e>; @@ -321,8 +318,7 @@ * sense == 8: Level, low assertion * sense == 2: Edge, high-to-low change */ - pic@700 { - linux,phandle = <700>; + ipic: pic@700 { interrupt-controller; #address-cells = <0>; #interrupt-cells = <2>; diff --git a/arch/powerpc/boot/dts/mpc8360emds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts index 9022192155b..4fe45c02184 100644 --- a/arch/powerpc/boot/dts/mpc8360emds.dts +++ b/arch/powerpc/boot/dts/mpc836x_mds.dts @@ -15,17 +15,15 @@ */ / { - model = "MPC8360EPB"; - compatible = "MPC83xx"; + model = "MPC8360MDS"; + compatible = "MPC8360EMDS", "MPC836xMDS", "MPC83xxMDS"; #address-cells = <1>; #size-cells = <1>; - linux,phandle = <100>; cpus { #cpus = <1>; #address-cells = <1>; #size-cells = <0>; - linux,phandle = <200>; PowerPC,8360@0 { device_type = "cpu"; @@ -38,14 +36,11 @@ bus-frequency = <FBC5200>; clock-frequency = <1F78A400>; 32-bit; - linux,phandle = <201>; - linux,boot-cpu; }; }; memory { device_type = "memory"; - linux,phandle = <300>; reg = <00000000 10000000>; }; @@ -74,7 +69,7 @@ compatible = "fsl-i2c"; reg = <3000 100>; interrupts = <e 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; dfsrr; }; @@ -83,7 +78,7 @@ compatible = "fsl-i2c"; reg = <3100 100>; interrupts = <f 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; dfsrr; }; @@ -93,7 +88,7 @@ reg = <4500 100>; clock-frequency = <FBC5200>; interrupts = <9 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; serial@4600 { @@ -102,7 +97,7 @@ reg = <4600 100>; clock-frequency = <FBC5200>; interrupts = <a 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; crypto@30000 { @@ -111,7 +106,7 @@ compatible = "talitos"; reg = <30000 10000>; interrupts = <b 8>; - interrupt-parent = <700>; + interrupt-parent = < &ipic >; num-channels = <4>; channel-fifo-len = <18>; exec-units-mask = <0000007e>; @@ -120,52 +115,51 @@ }; pci@8500 { - linux,phandle = <8500>; interrupt-map-mask = <f800 0 0 7>; interrupt-map = < /* IDSEL 0x11 AD17 */ - 8800 0 0 1 700 14 8 - 8800 0 0 2 700 15 8 - 8800 0 0 3 700 16 8 - 8800 0 0 4 700 17 8 + 8800 0 0 1 &ipic 14 8 + 8800 0 0 2 &ipic 15 8 + 8800 0 0 3 &ipic 16 8 + 8800 0 0 4 &ipic 17 8 /* IDSEL 0x12 AD18 */ - 9000 0 0 1 700 16 8 - 9000 0 0 2 700 17 8 - 9000 0 0 3 700 14 8 - 9000 0 0 4 700 15 8 + 9000 0 0 1 &ipic 16 8 + 9000 0 0 2 &ipic 17 8 + 9000 0 0 3 &ipic 14 8 + 9000 0 0 4 &ipic 15 8 /* IDSEL 0x13 AD19 */ - 9800 0 0 1 700 17 8 - 9800 0 0 2 700 14 8 - 9800 0 0 3 700 15 8 - 9800 0 0 4 700 16 8 + 9800 0 0 1 &ipic 17 8 + 9800 0 0 2 &ipic 14 8 + 9800 0 0 3 &ipic 15 8 + 9800 0 0 4 &ipic 16 8 /* IDSEL 0x15 AD21*/ - a800 0 0 1 700 14 8 - a800 0 0 2 700 15 8 - a800 0 0 3 700 16 8 - a800 0 0 4 700 17 8 + a800 0 0 1 &ipic 14 8 + a800 0 0 2 &ipic 15 8 + a800 0 0 3 &ipic 16 8 + a800 0 0 4 &ipic 17 8 /* IDSEL 0x16 AD22*/ - b000 0 0 1 700 17 8 - b000 0 0 2 700 14 8 - b000 0 0 3 700 15 8 - b000 0 0 4 700 16 8 + b000 0 0 1 &ipic 17 8 + b000 0 0 2 &ipic 14 8 + b000 0 0 3 &ipic 15 8 + b000 0 0 4 &ipic 16 8 /* IDSEL 0x17 AD23*/ - b800 0 0 1 700 16 8 - b800 0 0 2 700 17 8 - b800 0 0 3 700 14 8 - b800 0 0 4 700 15 8 + b800 0 0 1 &ipic 16 8 + b800 0 0 2 &ipic 17 8 + b800 0 0 3 &ipic 14 8 + b800 0 0 4 &ipic 15 8 /* IDSEL 0x18 AD24*/ - c000 0 0 1 700 15 8 - c000 0 0 2 700 16 8 - c000 0 0 3 700 17 8 - c000 0 0 4 700 14 8>; - interrupt-parent = <700>; + c000 0 0 1 &ipic 15 8 + c000 0 0 2 &ipic 16 8 + c000 0 0 3 &ipic 17 8 + c000 0 0 4 &ipic 14 8>; + interrupt-parent = < &ipic >; interrupts = <42 8>; bus-range = <0 0>; ranges = <02000000 0 a0000000 a0000000 0 10000000 @@ -180,8 +174,7 @@ device_type = "pci"; }; - pic@700 { - linux,phandle = <700>; + ipic: pic@700 { interrupt-controller; #address-cells = <0>; #interrupt-cells = <2>; @@ -195,8 +188,7 @@ device_type = "par_io"; num-ports = <7>; - ucc_pin@01 { - linux,phandle = <140001>; + pio1: ucc_pin@01 { pio-map = < /* port pin dir open_drain assignment has_irq */ 0 3 1 0 1 0 /* TxD0 */ @@ -223,8 +215,7 @@ 2 9 1 0 3 0 /* GTX_CLK - CLK10 */ 2 8 2 0 1 0>; /* GTX125 - CLK9 */ }; - ucc_pin@02 { - linux,phandle = <140002>; + pio2: ucc_pin@02 { pio-map = < /* port pin dir open_drain assignment has_irq */ 0 11 1 0 1 0 /* TxD0 */ @@ -281,7 +272,7 @@ compatible = "fsl_spi"; reg = <4c0 40>; interrupts = <2>; - interrupt-parent = <80>; + interrupt-parent = < &qeic >; mode = "cpu"; }; @@ -290,7 +281,7 @@ compatible = "fsl_spi"; reg = <500 40>; interrupts = <1>; - interrupt-parent = <80>; + interrupt-parent = < &qeic >; mode = "cpu"; }; @@ -299,7 +290,7 @@ compatible = "qe_udc"; reg = <6c0 40 8B00 100>; interrupts = <b>; - interrupt-parent = <80>; + interrupt-parent = < &qeic >; mode = "slave"; }; @@ -310,12 +301,12 @@ device-id = <1>; reg = <2000 200>; interrupts = <20>; - interrupt-parent = <80>; + interrupt-parent = < &qeic >; mac-address = [ 00 04 9f 00 23 23 ]; rx-clock = <0>; tx-clock = <19>; - phy-handle = <212000>; - pio-handle = <140001>; + phy-handle = < &phy0 >; + pio-handle = < &pio1 >; }; ucc@3000 { @@ -325,12 +316,12 @@ device-id = <2>; reg = <3000 200>; interrupts = <21>; - interrupt-parent = <80>; + interrupt-parent = < &qeic >; mac-address = [ 00 11 22 33 44 55 ]; rx-clock = <0>; tx-clock = <14>; - phy-handle = <212001>; - pio-handle = <140002>; + phy-handle = < &phy1 >; + pio-handle = < &pio2 >; }; mdio@2120 { @@ -340,26 +331,23 @@ device_type = "mdio"; compatible = "ucc_geth_phy"; - ethernet-phy@00 { - linux,phandle = <212000>; - interrupt-parent = <700>; - interrupts = <11 2>; + phy0: ethernet-phy@00 { + interrupt-parent = < &ipic >; + interrupts = <11 8>; reg = <0>; device_type = "ethernet-phy"; interface = <6>; //ENET_1000_GMII }; - ethernet-phy@01 { - linux,phandle = <212001>; - interrupt-parent = <700>; - interrupts = <12 2>; + phy1: ethernet-phy@01 { + interrupt-parent = < &ipic >; + interrupts = <12 8>; reg = <1>; device_type = "ethernet-phy"; interface = <6>; }; }; - qeic@80 { - linux,phandle = <80>; + qeic: qeic@80 { interrupt-controller; device_type = "qeic"; #address-cells = <0>; @@ -368,7 +356,7 @@ built-in; big-endian; interrupts = <20 8 21 8>; //high:32 low:33 - interrupt-parent = <700>; + interrupt-parent = < &ipic >; }; }; diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts index 5f41c1f7a5f..3c0917fa791 100644 --- a/arch/powerpc/boot/dts/mpc8540ads.dts +++ b/arch/powerpc/boot/dts/mpc8540ads.dts @@ -12,16 +12,14 @@ / { model = "MPC8540ADS"; - compatible = "MPC85xxADS"; + compatible = "MPC8540ADS", "MPC85xxADS"; #address-cells = <1>; #size-cells = <1>; - linux,phandle = <100>; cpus { #cpus = <1>; #address-cells = <1>; #size-cells = <0>; - linux,phandle = <200>; PowerPC,8540@0 { device_type = "cpu"; @@ -34,13 +32,11 @@ bus-frequency = <0>; // 166 MHz clock-frequency = <0>; // 825 MHz, from uboot 32-bit; - linux,phandle = <201>; }; }; memory { device_type = "memory"; - linux,phandle = <300>; reg = <00000000 08000000>; // 128M at 0x0 }; @@ -58,7 +54,7 @@ compatible = "fsl-i2c"; reg = <3000 100>; interrupts = <1b 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; dfsrr; }; @@ -68,24 +64,20 @@ device_type = "mdio"; compatible = "gianfar"; reg = <24520 20>; - linux,phandle = <24520>; - ethernet-phy@0 { - linux,phandle = <2452000>; - interrupt-parent = <40000>; + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; interrupts = <35 1>; reg = <0>; device_type = "ethernet-phy"; }; - ethernet-phy@1 { - linux,phandle = <2452001>; - interrupt-parent = <40000>; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; interrupts = <35 1>; reg = <1>; device_type = "ethernet-phy"; }; - ethernet-phy@3 { - linux,phandle = <2452003>; - interrupt-parent = <40000>; + phy3: ethernet-phy@3 { + interrupt-parent = <&mpic>; interrupts = <37 1>; reg = <3>; device_type = "ethernet-phy"; @@ -102,8 +94,8 @@ address = [ 00 E0 0C 00 73 00 ]; local-mac-address = [ 00 E0 0C 00 73 00 ]; interrupts = <d 2 e 2 12 2>; - interrupt-parent = <40000>; - phy-handle = <2452000>; + interrupt-parent = <&mpic>; + phy-handle = <&phy0>; }; ethernet@25000 { @@ -116,8 +108,8 @@ address = [ 00 E0 0C 00 73 01 ]; local-mac-address = [ 00 E0 0C 00 73 01 ]; interrupts = <13 2 14 2 18 2>; - interrupt-parent = <40000>; - phy-handle = <2452001>; + interrupt-parent = <&mpic>; + phy-handle = <&phy1>; }; ethernet@26000 { @@ -130,8 +122,8 @@ address = [ 00 E0 0C 00 73 02 ]; local-mac-address = [ 00 E0 0C 00 73 02 ]; interrupts = <19 2>; - interrupt-parent = <40000>; - phy-handle = <2452003>; + interrupt-parent = <&mpic>; + phy-handle = <&phy3>; }; serial@4500 { @@ -140,7 +132,7 @@ reg = <4500 100>; // reg base, size clock-frequency = <0>; // should we fill in in uboot? interrupts = <1a 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; serial@4600 { @@ -149,85 +141,84 @@ reg = <4600 100>; // reg base, size clock-frequency = <0>; // should we fill in in uboot? interrupts = <1a 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; pci@8000 { - linux,phandle = <8000>; interrupt-map-mask = <f800 0 0 7>; interrupt-map = < /* IDSEL 0x02 */ - 1000 0 0 1 40000 31 1 - 1000 0 0 2 40000 32 1 - 1000 0 0 3 40000 33 1 - 1000 0 0 4 40000 34 1 + 1000 0 0 1 &mpic 31 1 + 1000 0 0 2 &mpic 32 1 + 1000 0 0 3 &mpic 33 1 + 1000 0 0 4 &mpic 34 1 /* IDSEL 0x03 */ - 1800 0 0 1 40000 34 1 - 1800 0 0 2 40000 31 1 - 1800 0 0 3 40000 32 1 - 1800 0 0 4 40000 33 1 + 1800 0 0 1 &mpic 34 1 + 1800 0 0 2 &mpic 31 1 + 1800 0 0 3 &mpic 32 1 + 1800 0 0 4 &mpic 33 1 /* IDSEL 0x04 */ - 2000 0 0 1 40000 33 1 - 2000 0 0 2 40000 34 1 - 2000 0 0 3 40000 31 1 - 2000 0 0 4 40000 32 1 + 2000 0 0 1 &mpic 33 1 + 2000 0 0 2 &mpic 34 1 + 2000 0 0 3 &mpic 31 1 + 2000 0 0 4 &mpic 32 1 /* IDSEL 0x05 */ - 2800 0 0 1 40000 32 1 - 2800 0 0 2 40000 33 1 - 2800 0 0 3 40000 34 1 - 2800 0 0 4 40000 31 1 + 2800 0 0 1 &mpic 32 1 + 2800 0 0 2 &mpic 33 1 + 2800 0 0 3 &mpic 34 1 + 2800 0 0 4 &mpic 31 1 /* IDSEL 0x0c */ - 6000 0 0 1 40000 31 1 - 6000 0 0 2 40000 32 1 - 6000 0 0 3 40000 33 1 - 6000 0 0 4 40000 34 1 + 6000 0 0 1 &mpic 31 1 + 6000 0 0 2 &mpic 32 1 + 6000 0 0 3 &mpic 33 1 + 6000 0 0 4 &mpic 34 1 /* IDSEL 0x0d */ - 6800 0 0 1 40000 34 1 - 6800 0 0 2 40000 31 1 - 6800 0 0 3 40000 32 1 - 6800 0 0 4 40000 33 1 + 6800 0 0 1 &mpic 34 1 + 6800 0 0 2 &mpic 31 1 + 6800 0 0 3 &mpic 32 1 + 6800 0 0 4 &mpic 33 1 /* IDSEL 0x0e */ - 7000 0 0 1 40000 33 1 - 7000 0 0 2 40000 34 1 - 7000 0 0 3 40000 31 1 - 7000 0 0 4 40000 32 1 + 7000 0 0 1 &mpic 33 1 + 7000 0 0 2 &mpic 34 1 + 7000 0 0 3 &mpic 31 1 + 7000 0 0 4 &mpic 32 1 /* IDSEL 0x0f */ - 7800 0 0 1 40000 32 1 - 7800 0 0 2 40000 33 1 - 7800 0 0 3 40000 34 1 - 7800 0 0 4 40000 31 1 + 7800 0 0 1 &mpic 32 1 + 7800 0 0 2 &mpic 33 1 + 7800 0 0 3 &mpic 34 1 + 7800 0 0 4 &mpic 31 1 /* IDSEL 0x12 */ - 9000 0 0 1 40000 31 1 - 9000 0 0 2 40000 32 1 - 9000 0 0 3 40000 33 1 - 9000 0 0 4 40000 34 1 + 9000 0 0 1 &mpic 31 1 + 9000 0 0 2 &mpic 32 1 + 9000 0 0 3 &mpic 33 1 + 9000 0 0 4 &mpic 34 1 /* IDSEL 0x13 */ - 9800 0 0 1 40000 34 1 - 9800 0 0 2 40000 31 1 - 9800 0 0 3 40000 32 1 - 9800 0 0 4 40000 33 1 + 9800 0 0 1 &mpic 34 1 + 9800 0 0 2 &mpic 31 1 + 9800 0 0 3 &mpic 32 1 + 9800 0 0 4 &mpic 33 1 /* IDSEL 0x14 */ - a000 0 0 1 40000 33 1 - a000 0 0 2 40000 34 1 - a000 0 0 3 40000 31 1 - a000 0 0 4 40000 32 1 + a000 0 0 1 &mpic 33 1 + a000 0 0 2 &mpic 34 1 + a000 0 0 3 &mpic 31 1 + a000 0 0 4 &mpic 32 1 /* IDSEL 0x15 */ - a800 0 0 1 40000 32 1 - a800 0 0 2 40000 33 1 - a800 0 0 3 40000 34 1 - a800 0 0 4 40000 31 1>; - interrupt-parent = <40000>; + a800 0 0 1 &mpic 32 1 + a800 0 0 2 &mpic 33 1 + a800 0 0 3 &mpic 34 1 + a800 0 0 4 &mpic 31 1>; + interrupt-parent = <&mpic>; interrupts = <08 2>; bus-range = <0 0>; ranges = <02000000 0 80000000 80000000 0 20000000 @@ -241,8 +232,7 @@ device_type = "pci"; }; - pic@40000 { - linux,phandle = <40000>; + mpic: pic@40000 { clock-frequency = <0>; interrupt-controller; #address-cells = <0>; diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts index 7be0bc659e1..2a1ae760ab3 100644 --- a/arch/powerpc/boot/dts/mpc8541cds.dts +++ b/arch/powerpc/boot/dts/mpc8541cds.dts @@ -12,16 +12,14 @@ / { model = "MPC8541CDS"; - compatible = "MPC85xxCDS"; + compatible = "MPC8541CDS", "MPC85xxCDS"; #address-cells = <1>; #size-cells = <1>; - linux,phandle = <100>; cpus { #cpus = <1>; #address-cells = <1>; #size-cells = <0>; - linux,phandle = <200>; PowerPC,8541@0 { device_type = "cpu"; @@ -34,13 +32,11 @@ bus-frequency = <0>; // 166 MHz clock-frequency = <0>; // 825 MHz, from uboot 32-bit; - linux,phandle = <201>; }; }; memory { device_type = "memory"; - linux,phandle = <300>; reg = <00000000 08000000>; // 128M at 0x0 }; @@ -58,7 +54,7 @@ compatible = "fsl-i2c"; reg = <3000 100>; interrupts = <1b 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; dfsrr; }; @@ -68,17 +64,14 @@ device_type = "mdio"; compatible = "gianfar"; reg = <24520 20>; - linux,phandle = <24520>; - ethernet-phy@0 { - linux,phandle = <2452000>; - interrupt-parent = <40000>; + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; interrupts = <35 0>; reg = <0>; device_type = "ethernet-phy"; }; - ethernet-phy@1 { - linux,phandle = <2452001>; - interrupt-parent = <40000>; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; interrupts = <35 0>; reg = <1>; device_type = "ethernet-phy"; @@ -94,8 +87,8 @@ reg = <24000 1000>; local-mac-address = [ 00 E0 0C 00 73 00 ]; interrupts = <d 2 e 2 12 2>; - interrupt-parent = <40000>; - phy-handle = <2452000>; + interrupt-parent = <&mpic>; + phy-handle = <&phy0>; }; ethernet@25000 { @@ -107,8 +100,8 @@ reg = <25000 1000>; local-mac-address = [ 00 E0 0C 00 73 01 ]; interrupts = <13 2 14 2 18 2>; - interrupt-parent = <40000>; - phy-handle = <2452001>; + interrupt-parent = <&mpic>; + phy-handle = <&phy1>; }; serial@4500 { @@ -117,7 +110,7 @@ reg = <4500 100>; // reg base, size clock-frequency = <0>; // should we fill in in uboot? interrupts = <1a 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; serial@4600 { @@ -126,57 +119,56 @@ reg = <4600 100>; // reg base, size clock-frequency = <0>; // should we fill in in uboot? interrupts = <1a 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; - pci@8000 { - linux,phandle = <8000>; + pci1: pci@8000 { interrupt-map-mask = <1f800 0 0 7>; interrupt-map = < /* IDSEL 0x10 */ - 08000 0 0 1 40000 30 1 - 08000 0 0 2 40000 31 1 - 08000 0 0 3 40000 32 1 - 08000 0 0 4 40000 33 1 + 08000 0 0 1 &mpic 30 1 + 08000 0 0 2 &mpic 31 1 + 08000 0 0 3 &mpic 32 1 + 08000 0 0 4 &mpic 33 1 /* IDSEL 0x11 */ - 08800 0 0 1 40000 30 1 - 08800 0 0 2 40000 31 1 - 08800 0 0 3 40000 32 1 - 08800 0 0 4 40000 33 1 + 08800 0 0 1 &mpic 30 1 + 08800 0 0 2 &mpic 31 1 + 08800 0 0 3 &mpic 32 1 + 08800 0 0 4 &mpic 33 1 /* IDSEL 0x12 (Slot 1) */ - 09000 0 0 1 40000 30 1 - 09000 0 0 2 40000 31 1 - 09000 0 0 3 40000 32 1 - 09000 0 0 4 40000 33 1 + 09000 0 0 1 &mpic 30 1 + 09000 0 0 2 &mpic 31 1 + 09000 0 0 3 &mpic 32 1 + 09000 0 0 4 &mpic 33 1 /* IDSEL 0x13 (Slot 2) */ - 09800 0 0 1 40000 31 1 - 09800 0 0 2 40000 32 1 - 09800 0 0 3 40000 33 1 - 09800 0 0 4 40000 30 1 + 09800 0 0 1 &mpic 31 1 + 09800 0 0 2 &mpic 32 1 + 09800 0 0 3 &mpic 33 1 + 09800 0 0 4 &mpic 30 1 /* IDSEL 0x14 (Slot 3) */ - 0a000 0 0 1 40000 32 1 - 0a000 0 0 2 40000 33 1 - 0a000 0 0 3 40000 30 1 - 0a000 0 0 4 40000 31 1 + 0a000 0 0 1 &mpic 32 1 + 0a000 0 0 2 &mpic 33 1 + 0a000 0 0 3 &mpic 30 1 + 0a000 0 0 4 &mpic 31 1 /* IDSEL 0x15 (Slot 4) */ - 0a800 0 0 1 40000 33 1 - 0a800 0 0 2 40000 30 1 - 0a800 0 0 3 40000 31 1 - 0a800 0 0 4 40000 32 1 + 0a800 0 0 1 &mpic 33 1 + 0a800 0 0 2 &mpic 30 1 + 0a800 0 0 3 &mpic 31 1 + 0a800 0 0 4 &mpic 32 1 /* Bus 1 (Tundra Bridge) */ /* IDSEL 0x12 (ISA bridge) */ - 19000 0 0 1 40000 30 1 - 19000 0 0 2 40000 31 1 - 19000 0 0 3 40000 32 1 - 19000 0 0 4 40000 33 1>; - interrupt-parent = <40000>; + 19000 0 0 1 &mpic 30 1 + 19000 0 0 2 &mpic 31 1 + 19000 0 0 3 &mpic 32 1 + 19000 0 0 4 &mpic 33 1>; + interrupt-parent = <&mpic>; interrupts = <08 2>; bus-range = <0 0>; ranges = <02000000 0 80000000 80000000 0 20000000 @@ -200,21 +192,20 @@ compatible = "chrp,iic"; big-endian; interrupts = <1>; - interrupt-parent = <8000>; + interrupt-parent = <&pci1>; }; }; pci@9000 { - linux,phandle = <9000>; interrupt-map-mask = <f800 0 0 7>; interrupt-map = < /* IDSEL 0x15 */ - a800 0 0 1 40000 3b 1 - a800 0 0 2 40000 3b 1 - a800 0 0 3 40000 3b 1 - a800 0 0 4 40000 3b 1>; - interrupt-parent = <40000>; + a800 0 0 1 &mpic 3b 1 + a800 0 0 2 &mpic 3b 1 + a800 0 0 3 &mpic 3b 1 + a800 0 0 4 &mpic 3b 1>; + interrupt-parent = <&mpic>; interrupts = <09 2>; bus-range = <0 0>; ranges = <02000000 0 a0000000 a0000000 0 20000000 @@ -228,8 +219,7 @@ device_type = "pci"; }; - pic@40000 { - linux,phandle = <40000>; + mpic: pic@40000 { clock-frequency = <0>; interrupt-controller; #address-cells = <0>; diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts index 893d7957c17..7eb5d81d5ee 100644 --- a/arch/powerpc/boot/dts/mpc8548cds.dts +++ b/arch/powerpc/boot/dts/mpc8548cds.dts @@ -12,16 +12,14 @@ / { model = "MPC8548CDS"; - compatible = "MPC85xxCDS"; + compatible = "MPC8548CDS", "MPC85xxCDS"; #address-cells = <1>; #size-cells = <1>; - linux,phandle = <100>; cpus { #cpus = <1>; #address-cells = <1>; #size-cells = <0>; - linux,phandle = <200>; PowerPC,8548@0 { device_type = "cpu"; @@ -34,13 +32,11 @@ bus-frequency = <0>; // 166 MHz clock-frequency = <0>; // 825 MHz, from uboot 32-bit; - linux,phandle = <201>; }; }; memory { device_type = "memory"; - linux,phandle = <300>; reg = <00000000 08000000>; // 128M at 0x0 }; @@ -58,7 +54,7 @@ compatible = "fsl-i2c"; reg = <3000 100>; interrupts = <1b 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; dfsrr; }; @@ -68,32 +64,26 @@ device_type = "mdio"; compatible = "gianfar"; reg = <24520 20>; - linux,phandle = <24520>; - ethernet-phy@0 { - linux,phandle = <2452000>; - interrupt-parent = <40000>; + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; interrupts = <35 0>; reg = <0>; device_type = "ethernet-phy"; }; - ethernet-phy@1 { - linux,phandle = <2452001>; - interrupt-parent = <40000>; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; interrupts = <35 0>; reg = <1>; device_type = "ethernet-phy"; }; - - ethernet-phy@2 { - linux,phandle = <2452002>; - interrupt-parent = <40000>; + phy2: ethernet-phy@2 { + interrupt-parent = <&mpic>; interrupts = <35 0>; reg = <2>; device_type = "ethernet-phy"; }; - ethernet-phy@3 { - linux,phandle = <2452003>; - interrupt-parent = <40000>; + phy3: ethernet-phy@3 { + interrupt-parent = <&mpic>; interrupts = <35 0>; reg = <3>; device_type = "ethernet-phy"; @@ -109,8 +99,8 @@ reg = <24000 1000>; local-mac-address = [ 00 E0 0C 00 73 00 ]; interrupts = <d 2 e 2 12 2>; - interrupt-parent = <40000>; - phy-handle = <2452000>; + interrupt-parent = <&mpic>; + phy-handle = <&phy0>; }; ethernet@25000 { @@ -122,10 +112,11 @@ reg = <25000 1000>; local-mac-address = [ 00 E0 0C 00 73 01 ]; interrupts = <13 2 14 2 18 2>; - interrupt-parent = <40000>; - phy-handle = <2452001>; + interrupt-parent = <&mpic>; + phy-handle = <&phy1>; }; +/* eTSEC 3/4 are currently broken ethernet@26000 { #address-cells = <1>; #size-cells = <0>; @@ -135,11 +126,10 @@ reg = <26000 1000>; local-mac-address = [ 00 E0 0C 00 73 02 ]; interrupts = <f 2 10 2 11 2>; - interrupt-parent = <40000>; - phy-handle = <2452001>; + interrupt-parent = <&mpic>; + phy-handle = <&phy2>; }; -/* eTSEC 4 is currently broken ethernet@27000 { #address-cells = <1>; #size-cells = <0>; @@ -149,8 +139,8 @@ reg = <27000 1000>; local-mac-address = [ 00 E0 0C 00 73 03 ]; interrupts = <15 2 16 2 17 2>; - interrupt-parent = <40000>; - phy-handle = <2452001>; + interrupt-parent = <&mpic>; + phy-handle = <&phy3>; }; */ @@ -160,7 +150,7 @@ reg = <4500 100>; // reg base, size clock-frequency = <0>; // should we fill in in uboot? interrupts = <1a 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; serial@4600 { @@ -169,57 +159,56 @@ reg = <4600 100>; // reg base, size clock-frequency = <0>; // should we fill in in uboot? interrupts = <1a 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; - pci@8000 { - linux,phandle = <8000>; + pci1: pci@8000 { interrupt-map-mask = <1f800 0 0 7>; interrupt-map = < /* IDSEL 0x10 */ - 08000 0 0 1 40000 30 1 - 08000 0 0 2 40000 31 1 - 08000 0 0 3 40000 32 1 - 08000 0 0 4 40000 33 1 + 08000 0 0 1 &mpic 30 1 + 08000 0 0 2 &mpic 31 1 + 08000 0 0 3 &mpic 32 1 + 08000 0 0 4 &mpic 33 1 /* IDSEL 0x11 */ - 08800 0 0 1 40000 30 1 - 08800 0 0 2 40000 31 1 - 08800 0 0 3 40000 32 1 - 08800 0 0 4 40000 33 1 + 08800 0 0 1 &mpic 30 1 + 08800 0 0 2 &mpic 31 1 + 08800 0 0 3 &mpic 32 1 + 08800 0 0 4 &mpic 33 1 /* IDSEL 0x12 (Slot 1) */ - 09000 0 0 1 40000 30 1 - 09000 0 0 2 40000 31 1 - 09000 0 0 3 40000 32 1 - 09000 0 0 4 40000 33 1 + 09000 0 0 1 &mpic 30 1 + 09000 0 0 2 &mpic 31 1 + 09000 0 0 3 &mpic 32 1 + 09000 0 0 4 &mpic 33 1 /* IDSEL 0x13 (Slot 2) */ - 09800 0 0 1 40000 31 1 - 09800 0 0 2 40000 32 1 - 09800 0 0 3 40000 33 1 - 09800 0 0 4 40000 30 1 + 09800 0 0 1 &mpic 31 1 + 09800 0 0 2 &mpic 32 1 + 09800 0 0 3 &mpic 33 1 + 09800 0 0 4 &mpic 30 1 /* IDSEL 0x14 (Slot 3) */ - 0a000 0 0 1 40000 32 1 - 0a000 0 0 2 40000 33 1 - 0a000 0 0 3 40000 30 1 - 0a000 0 0 4 40000 31 1 + 0a000 0 0 1 &mpic 32 1 + 0a000 0 0 2 &mpic 33 1 + 0a000 0 0 3 &mpic 30 1 + 0a000 0 0 4 &mpic 31 1 /* IDSEL 0x15 (Slot 4) */ - 0a800 0 0 1 40000 33 1 - 0a800 0 0 2 40000 30 1 - 0a800 0 0 3 40000 31 1 - 0a800 0 0 4 40000 32 1 + 0a800 0 0 1 &mpic 33 1 + 0a800 0 0 2 &mpic 30 1 + 0a800 0 0 3 &mpic 31 1 + 0a800 0 0 4 &mpic 32 1 /* Bus 1 (Tundra Bridge) */ /* IDSEL 0x12 (ISA bridge) */ - 19000 0 0 1 40000 30 1 - 19000 0 0 2 40000 31 1 - 19000 0 0 3 40000 32 1 - 19000 0 0 4 40000 33 1>; - interrupt-parent = <40000>; + 19000 0 0 1 &mpic 30 1 + 19000 0 0 2 &mpic 31 1 + 19000 0 0 3 &mpic 32 1 + 19000 0 0 4 &mpic 33 1>; + interrupt-parent = <&mpic>; interrupts = <08 2>; bus-range = <0 0>; ranges = <02000000 0 80000000 80000000 0 20000000 @@ -243,21 +232,20 @@ compatible = "chrp,iic"; big-endian; interrupts = <1>; - interrupt-parent = <8000>; + interrupt-parent = <&pci1>; }; }; pci@9000 { - linux,phandle = <9000>; interrupt-map-mask = <f800 0 0 7>; interrupt-map = < /* IDSEL 0x15 */ - a800 0 0 1 40000 3b 1 - a800 0 0 2 40000 3b 1 - a800 0 0 3 40000 3b 1 - a800 0 0 4 40000 3b 1>; - interrupt-parent = <40000>; + a800 0 0 1 &mpic 3b 1 + a800 0 0 2 &mpic 3b 1 + a800 0 0 3 &mpic 3b 1 + a800 0 0 4 &mpic 3b 1>; + interrupt-parent = <&mpic>; interrupts = <09 2>; bus-range = <0 0>; ranges = <02000000 0 a0000000 a0000000 0 20000000 @@ -271,8 +259,7 @@ device_type = "pci"; }; - pic@40000 { - linux,phandle = <40000>; + mpic: pic@40000 { clock-frequency = <0>; interrupt-controller; #address-cells = <0>; diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts index 118f5a88765..5f9c102a0ab 100644 --- a/arch/powerpc/boot/dts/mpc8555cds.dts +++ b/arch/powerpc/boot/dts/mpc8555cds.dts @@ -12,16 +12,14 @@ / { model = "MPC8555CDS"; - compatible = "MPC85xxCDS"; + compatible = "MPC8555CDS", "MPC85xxCDS"; #address-cells = <1>; #size-cells = <1>; - linux,phandle = <100>; cpus { #cpus = <1>; #address-cells = <1>; #size-cells = <0>; - linux,phandle = <200>; PowerPC,8555@0 { device_type = "cpu"; @@ -34,13 +32,11 @@ bus-frequency = <0>; // 166 MHz clock-frequency = <0>; // 825 MHz, from uboot 32-bit; - linux,phandle = <201>; }; }; memory { device_type = "memory"; - linux,phandle = <300>; reg = <00000000 08000000>; // 128M at 0x0 }; @@ -58,7 +54,7 @@ compatible = "fsl-i2c"; reg = <3000 100>; interrupts = <1b 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; dfsrr; }; @@ -68,17 +64,14 @@ device_type = "mdio"; compatible = "gianfar"; reg = <24520 20>; - linux,phandle = <24520>; - ethernet-phy@0 { - linux,phandle = <2452000>; - interrupt-parent = <40000>; + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; interrupts = <35 0>; reg = <0>; device_type = "ethernet-phy"; }; - ethernet-phy@1 { - linux,phandle = <2452001>; - interrupt-parent = <40000>; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; interrupts = <35 0>; reg = <1>; device_type = "ethernet-phy"; @@ -94,8 +87,8 @@ reg = <24000 1000>; local-mac-address = [ 00 E0 0C 00 73 00 ]; interrupts = <0d 2 0e 2 12 2>; - interrupt-parent = <40000>; - phy-handle = <2452000>; + interrupt-parent = <&mpic>; + phy-handle = <&phy0>; }; ethernet@25000 { @@ -107,8 +100,8 @@ reg = <25000 1000>; local-mac-address = [ 00 E0 0C 00 73 01 ]; interrupts = <13 2 14 2 18 2>; - interrupt-parent = <40000>; - phy-handle = <2452001>; + interrupt-parent = <&mpic>; + phy-handle = <&phy1>; }; serial@4500 { @@ -117,7 +110,7 @@ reg = <4500 100>; // reg base, size clock-frequency = <0>; // should we fill in in uboot? interrupts = <1a 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; serial@4600 { @@ -126,57 +119,56 @@ reg = <4600 100>; // reg base, size clock-frequency = <0>; // should we fill in in uboot? interrupts = <1a 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; - pci@8000 { - linux,phandle = <8000>; + pci1: pci@8000 { interrupt-map-mask = <1f800 0 0 7>; interrupt-map = < /* IDSEL 0x10 */ - 08000 0 0 1 40000 30 1 - 08000 0 0 2 40000 31 1 - 08000 0 0 3 40000 32 1 - 08000 0 0 4 40000 33 1 + 08000 0 0 1 &mpic 30 1 + 08000 0 0 2 &mpic 31 1 + 08000 0 0 3 &mpic 32 1 + 08000 0 0 4 &mpic 33 1 /* IDSEL 0x11 */ - 08800 0 0 1 40000 30 1 - 08800 0 0 2 40000 31 1 - 08800 0 0 3 40000 32 1 - 08800 0 0 4 40000 33 1 + 08800 0 0 1 &mpic 30 1 + 08800 0 0 2 &mpic 31 1 + 08800 0 0 3 &mpic 32 1 + 08800 0 0 4 &mpic 33 1 /* IDSEL 0x12 (Slot 1) */ - 09000 0 0 1 40000 30 1 - 09000 0 0 2 40000 31 1 - 09000 0 0 3 40000 32 1 - 09000 0 0 4 40000 33 1 + 09000 0 0 1 &mpic 30 1 + 09000 0 0 2 &mpic 31 1 + 09000 0 0 3 &mpic 32 1 + 09000 0 0 4 &mpic 33 1 /* IDSEL 0x13 (Slot 2) */ - 09800 0 0 1 40000 31 1 - 09800 0 0 2 40000 32 1 - 09800 0 0 3 40000 33 1 - 09800 0 0 4 40000 30 1 + 09800 0 0 1 &mpic 31 1 + 09800 0 0 2 &mpic 32 1 + 09800 0 0 3 &mpic 33 1 + 09800 0 0 4 &mpic 30 1 /* IDSEL 0x14 (Slot 3) */ - 0a000 0 0 1 40000 32 1 - 0a000 0 0 2 40000 33 1 - 0a000 0 0 3 40000 30 1 - 0a000 0 0 4 40000 31 1 + 0a000 0 0 1 &mpic 32 1 + 0a000 0 0 2 &mpic 33 1 + 0a000 0 0 3 &mpic 30 1 + 0a000 0 0 4 &mpic 31 1 /* IDSEL 0x15 (Slot 4) */ - 0a800 0 0 1 40000 33 1 - 0a800 0 0 2 40000 30 1 - 0a800 0 0 3 40000 31 1 - 0a800 0 0 4 40000 32 1 + 0a800 0 0 1 &mpic 33 1 + 0a800 0 0 2 &mpic 30 1 + 0a800 0 0 3 &mpic 31 1 + 0a800 0 0 4 &mpic 32 1 /* Bus 1 (Tundra Bridge) */ /* IDSEL 0x12 (ISA bridge) */ - 19000 0 0 1 40000 30 1 - 19000 0 0 2 40000 31 1 - 19000 0 0 3 40000 32 1 - 19000 0 0 4 40000 33 1>; - interrupt-parent = <40000>; + 19000 0 0 1 &mpic 30 1 + 19000 0 0 2 &mpic 31 1 + 19000 0 0 3 &mpic 32 1 + 19000 0 0 4 &mpic 33 1>; + interrupt-parent = <&mpic>; interrupts = <08 2>; bus-range = <0 0>; ranges = <02000000 0 80000000 80000000 0 20000000 @@ -200,21 +192,20 @@ compatible = "chrp,iic"; big-endian; interrupts = <1>; - interrupt-parent = <8000>; + interrupt-parent = <&pci1>; }; }; pci@9000 { - linux,phandle = <9000>; interrupt-map-mask = <f800 0 0 7>; interrupt-map = < /* IDSEL 0x15 */ - a800 0 0 1 40000 3b 1 - a800 0 0 2 40000 3b 1 - a800 0 0 3 40000 3b 1 - a800 0 0 4 40000 3b 1>; - interrupt-parent = <40000>; + a800 0 0 1 &mpic 3b 1 + a800 0 0 2 &mpic 3b 1 + a800 0 0 3 &mpic 3b 1 + a800 0 0 4 &mpic 3b 1>; + interrupt-parent = <&mpic>; interrupts = <09 2>; bus-range = <0 0>; ranges = <02000000 0 a0000000 a0000000 0 20000000 @@ -228,8 +219,7 @@ device_type = "pci"; }; - pic@40000 { - linux,phandle = <40000>; + mpic: pic@40000 { clock-frequency = <0>; interrupt-controller; #address-cells = <0>; diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts index 119bd5d3a83..10502638b0e 100644 --- a/arch/powerpc/boot/dts/mpc8560ads.dts +++ b/arch/powerpc/boot/dts/mpc8560ads.dts @@ -12,16 +12,14 @@ / { model = "MPC8560ADS"; - compatible = "MPC85xxADS"; + compatible = "MPC8560ADS", "MPC85xxADS"; #address-cells = <1>; #size-cells = <1>; - linux,phandle = <100>; cpus { #cpus = <1>; #address-cells = <1>; #size-cells = <0>; - linux,phandle = <200>; PowerPC,8560@0 { device_type = "cpu"; @@ -34,14 +32,11 @@ bus-frequency = <13ab6680>; clock-frequency = <312c8040>; 32-bit; - linux,phandle = <201>; - linux,boot-cpu; }; }; memory { device_type = "memory"; - linux,phandle = <300>; reg = <00000000 10000000>; }; @@ -58,33 +53,28 @@ device_type = "mdio"; compatible = "gianfar"; reg = <24520 20>; - linux,phandle = <24520>; #address-cells = <1>; #size-cells = <0>; - ethernet-phy@0 { - linux,phandle = <2452000>; - interrupt-parent = <40000>; + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; interrupts = <35 1>; reg = <0>; device_type = "ethernet-phy"; }; - ethernet-phy@1 { - linux,phandle = <2452001>; - interrupt-parent = <40000>; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; interrupts = <35 1>; reg = <1>; device_type = "ethernet-phy"; }; - ethernet-phy@2 { - linux,phandle = <2452002>; - interrupt-parent = <40000>; + phy2: ethernet-phy@2 { + interrupt-parent = <&mpic>; interrupts = <37 1>; reg = <2>; device_type = "ethernet-phy"; }; - ethernet-phy@3 { - linux,phandle = <2452003>; - interrupt-parent = <40000>; + phy3: ethernet-phy@3 { + interrupt-parent = <&mpic>; interrupts = <37 1>; reg = <3>; device_type = "ethernet-phy"; @@ -98,8 +88,8 @@ reg = <24000 1000>; address = [ 00 00 0C 00 00 FD ]; interrupts = <d 2 e 2 12 2>; - interrupt-parent = <40000>; - phy-handle = <2452000>; + interrupt-parent = <&mpic>; + phy-handle = <&phy0>; }; ethernet@25000 { @@ -111,12 +101,11 @@ reg = <25000 1000>; address = [ 00 00 0C 00 01 FD ]; interrupts = <13 2 14 2 18 2>; - interrupt-parent = <40000>; - phy-handle = <2452001>; + interrupt-parent = <&mpic>; + phy-handle = <&phy1>; }; pci@8000 { - linux,phandle = <8000>; #interrupt-cells = <1>; #size-cells = <2>; #address-cells = <3>; @@ -128,96 +117,94 @@ interrupt-map = < /* IDSEL 0x2 */ - 1000 0 0 1 40000 31 1 - 1000 0 0 2 40000 32 1 - 1000 0 0 3 40000 33 1 - 1000 0 0 4 40000 34 1 + 1000 0 0 1 &mpic 31 1 + 1000 0 0 2 &mpic 32 1 + 1000 0 0 3 &mpic 33 1 + 1000 0 0 4 &mpic 34 1 /* IDSEL 0x3 */ - 1800 0 0 1 40000 34 1 - 1800 0 0 2 40000 31 1 - 1800 0 0 3 40000 32 1 - 1800 0 0 4 40000 33 1 + 1800 0 0 1 &mpic 34 1 + 1800 0 0 2 &mpic 31 1 + 1800 0 0 3 &mpic 32 1 + 1800 0 0 4 &mpic 33 1 /* IDSEL 0x4 */ - 2000 0 0 1 40000 33 1 - 2000 0 0 2 40000 34 1 - 2000 0 0 3 40000 31 1 - 2000 0 0 4 40000 32 1 + 2000 0 0 1 &mpic 33 1 + 2000 0 0 2 &mpic 34 1 + 2000 0 0 3 &mpic 31 1 + 2000 0 0 4 &mpic 32 1 /* IDSEL 0x5 */ - 2800 0 0 1 40000 32 1 - 2800 0 0 2 40000 33 1 - 2800 0 0 3 40000 34 1 - 2800 0 0 4 40000 31 1 + 2800 0 0 1 &mpic 32 1 + 2800 0 0 2 &mpic 33 1 + 2800 0 0 3 &mpic 34 1 + 2800 0 0 4 &mpic 31 1 /* IDSEL 12 */ - 6000 0 0 1 40000 31 1 - 6000 0 0 2 40000 32 1 - 6000 0 0 3 40000 33 1 - 6000 0 0 4 40000 34 1 + 6000 0 0 1 &mpic 31 1 + 6000 0 0 2 &mpic 32 1 + 6000 0 0 3 &mpic 33 1 + 6000 0 0 4 &mpic 34 1 /* IDSEL 13 */ - 6800 0 0 1 40000 34 1 - 6800 0 0 2 40000 31 1 - 6800 0 0 3 40000 32 1 - 6800 0 0 4 40000 33 1 + 6800 0 0 1 &mpic 34 1 + 6800 0 0 2 &mpic 31 1 + 6800 0 0 3 &mpic 32 1 + 6800 0 0 4 &mpic 33 1 /* IDSEL 14*/ - 7000 0 0 1 40000 33 1 - 7000 0 0 2 40000 34 1 - 7000 0 0 3 40000 31 1 - 7000 0 0 4 40000 32 1 + 7000 0 0 1 &mpic 33 1 + 7000 0 0 2 &mpic 34 1 + 7000 0 0 3 &mpic 31 1 + 7000 0 0 4 &mpic 32 1 /* IDSEL 15 */ - 7800 0 0 1 40000 32 1 - 7800 0 0 2 40000 33 1 - 7800 0 0 3 40000 34 1 - 7800 0 0 4 40000 31 1 + 7800 0 0 1 &mpic 32 1 + 7800 0 0 2 &mpic 33 1 + 7800 0 0 3 &mpic 34 1 + 7800 0 0 4 &mpic 31 1 /* IDSEL 18 */ - 9000 0 0 1 40000 31 1 - 9000 0 0 2 40000 32 1 - 9000 0 0 3 40000 33 1 - 9000 0 0 4 40000 34 1 + 9000 0 0 1 &mpic 31 1 + 9000 0 0 2 &mpic 32 1 + 9000 0 0 3 &mpic 33 1 + 9000 0 0 4 &mpic 34 1 /* IDSEL 19 */ - 9800 0 0 1 40000 34 1 - 9800 0 0 2 40000 31 1 - 9800 0 0 3 40000 32 1 - 9800 0 0 4 40000 33 1 + 9800 0 0 1 &mpic 34 1 + 9800 0 0 2 &mpic 31 1 + 9800 0 0 3 &mpic 32 1 + 9800 0 0 4 &mpic 33 1 /* IDSEL 20 */ - a000 0 0 1 40000 33 1 - a000 0 0 2 40000 34 1 - a000 0 0 3 40000 31 1 - a000 0 0 4 40000 32 1 + a000 0 0 1 &mpic 33 1 + a000 0 0 2 &mpic 34 1 + a000 0 0 3 &mpic 31 1 + a000 0 0 4 &mpic 32 1 /* IDSEL 21 */ - a800 0 0 1 40000 32 1 - a800 0 0 2 40000 33 1 - a800 0 0 3 40000 34 1 - a800 0 0 4 40000 31 1>; + a800 0 0 1 &mpic 32 1 + a800 0 0 2 &mpic 33 1 + a800 0 0 3 &mpic 34 1 + a800 0 0 4 &mpic 31 1>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; interrupts = <8 0>; bus-range = <0 0>; ranges = <02000000 0 80000000 80000000 0 20000000 01000000 0 00000000 e2000000 0 01000000>; }; - pic@40000 { - linux,phandle = <40000>; + mpic: pic@40000 { interrupt-controller; #address-cells = <0>; #interrupt-cells = <2>; - reg = <40000 20100>; + reg = <40000 40000>; built-in; device_type = "open-pic"; }; cpm@e0000000 { - linux,phandle = <e0000000>; #address-cells = <1>; #size-cells = <1>; #interrupt-cells = <2>; @@ -228,13 +215,12 @@ command-proc = <919c0>; brg-frequency = <9d5b340>; - pic@90c00 { - linux,phandle = <90c00>; + cpmpic: pic@90c00 { interrupt-controller; #address-cells = <0>; #interrupt-cells = <2>; interrupts = <1e 0>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; reg = <90c00 80>; built-in; device_type = "cpm-pic"; @@ -251,7 +237,7 @@ tx-clock = <1>; current-speed = <1c200>; interrupts = <28 8>; - interrupt-parent = <90c00>; + interrupt-parent = <&cpmpic>; }; scc@91a20 { @@ -265,7 +251,7 @@ tx-clock = <2>; current-speed = <1c200>; interrupts = <29 8>; - interrupt-parent = <90c00>; + interrupt-parent = <&cpmpic>; }; fcc@91320 { @@ -279,8 +265,8 @@ rx-clock = <15>; tx-clock = <16>; interrupts = <21 8>; - interrupt-parent = <90c00>; - phy-handle = <2452002>; + interrupt-parent = <&cpmpic>; + phy-handle = <&phy2>; }; fcc@91340 { @@ -294,8 +280,8 @@ rx-clock = <17>; tx-clock = <18>; interrupts = <22 8>; - interrupt-parent = <90c00>; - phy-handle = <2452003>; + interrupt-parent = <&cpmpic>; + phy-handle = <&phy3>; }; }; }; diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts index 06d24653e42..bf49d8c997b 100644 --- a/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/arch/powerpc/boot/dts/mpc8568mds.dts @@ -16,16 +16,14 @@ / { model = "MPC8568EMDS"; - compatible = "MPC85xxMDS"; + compatible = "MPC8568EMDS", "MPC85xxMDS"; #address-cells = <1>; #size-cells = <1>; - linux,phandle = <100>; cpus { #cpus = <1>; #address-cells = <1>; #size-cells = <0>; - linux,phandle = <200>; PowerPC,8568@0 { device_type = "cpu"; @@ -38,13 +36,11 @@ bus-frequency = <0>; clock-frequency = <0>; 32-bit; - linux,phandle = <201>; }; }; memory { device_type = "memory"; - linux,phandle = <300>; reg = <00000000 10000000>; }; @@ -67,7 +63,7 @@ compatible = "fsl-i2c"; reg = <3000 100>; interrupts = <1b 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; dfsrr; }; @@ -76,7 +72,7 @@ compatible = "fsl-i2c"; reg = <3100 100>; interrupts = <1b 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; dfsrr; }; @@ -86,32 +82,26 @@ device_type = "mdio"; compatible = "gianfar"; reg = <24520 20>; - linux,phandle = <24520>; - ethernet-phy@0 { - linux,phandle = <2452000>; - interrupt-parent = <40000>; + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; interrupts = <31 1>; reg = <0>; device_type = "ethernet-phy"; }; - ethernet-phy@1 { - linux,phandle = <2452001>; - interrupt-parent = <40000>; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; interrupts = <32 1>; reg = <1>; device_type = "ethernet-phy"; }; - - ethernet-phy@2 { - linux,phandle = <2452002>; - interrupt-parent = <40000>; + phy2: ethernet-phy@2 { + interrupt-parent = <&mpic>; interrupts = <31 1>; reg = <2>; device_type = "ethernet-phy"; }; - ethernet-phy@3 { - linux,phandle = <2452003>; - interrupt-parent = <40000>; + phy3: ethernet-phy@3 { + interrupt-parent = <&mpic>; interrupts = <32 1>; reg = <3>; device_type = "ethernet-phy"; @@ -127,8 +117,8 @@ reg = <24000 1000>; mac-address = [ 00 00 00 00 00 00 ]; interrupts = <d 2 e 2 12 2>; - interrupt-parent = <40000>; - phy-handle = <2452002>; + interrupt-parent = <&mpic>; + phy-handle = <&phy2>; }; ethernet@25000 { @@ -140,8 +130,8 @@ reg = <25000 1000>; mac-address = [ 00 00 00 00 00 00]; interrupts = <13 2 14 2 18 2>; - interrupt-parent = <40000>; - phy-handle = <2452003>; + interrupt-parent = <&mpic>; + phy-handle = <&phy3>; }; serial@4500 { @@ -150,7 +140,7 @@ reg = <4500 100>; clock-frequency = <0>; interrupts = <1a 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; serial@4600 { @@ -159,7 +149,7 @@ reg = <4600 100>; clock-frequency = <0>; interrupts = <1a 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; crypto@30000 { @@ -168,15 +158,14 @@ compatible = "talitos"; reg = <30000 f000>; interrupts = <1d 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; num-channels = <4>; channel-fifo-len = <18>; exec-units-mask = <000000fe>; descriptor-types-mask = <012b0ebf>; }; - pic@40000 { - linux,phandle = <40000>; + mpic: pic@40000 { clock-frequency = <0>; interrupt-controller; #address-cells = <0>; @@ -192,8 +181,7 @@ device_type = "par_io"; num-ports = <7>; - ucc_pin@01 { - linux,phandle = <e010001>; + pio1: ucc_pin@01 { pio-map = < /* port pin dir open_drain assignment has_irq */ 4 0a 1 0 2 0 /* TxD0 */ @@ -220,8 +208,7 @@ 4 13 1 0 2 0 /* GTX_CLK */ 1 1f 2 0 3 0>; /* GTX125 */ }; - ucc_pin@02 { - linux,phandle = <e010002>; + pio2: ucc_pin@02 { pio-map = < /* port pin dir open_drain assignment has_irq */ 5 0a 1 0 2 0 /* TxD0 */ @@ -277,7 +264,7 @@ compatible = "fsl_spi"; reg = <4c0 40>; interrupts = <2>; - interrupt-parent = <80>; + interrupt-parent = <&qeic>; mode = "cpu"; }; @@ -286,7 +273,7 @@ compatible = "fsl_spi"; reg = <500 40>; interrupts = <1>; - interrupt-parent = <80>; + interrupt-parent = <&qeic>; mode = "cpu"; }; @@ -297,12 +284,12 @@ device-id = <1>; reg = <2000 200>; interrupts = <20>; - interrupt-parent = <80>; + interrupt-parent = <&qeic>; mac-address = [ 00 04 9f 00 23 23 ]; rx-clock = <0>; tx-clock = <19>; - phy-handle = <212000>; - pio-handle = <e010001>; + phy-handle = <&qe_phy0>; + pio-handle = <&pio1>; }; ucc@3000 { @@ -312,12 +299,12 @@ device-id = <2>; reg = <3000 200>; interrupts = <21>; - interrupt-parent = <80>; + interrupt-parent = <&qeic>; mac-address = [ 00 11 22 33 44 55 ]; rx-clock = <0>; tx-clock = <14>; - phy-handle = <212001>; - pio-handle = <e010002>; + phy-handle = <&qe_phy1>; + pio-handle = <&pio2>; }; mdio@2120 { @@ -329,33 +316,29 @@ /* These are the same PHYs as on * gianfar's MDIO bus */ - ethernet-phy@00 { - linux,phandle = <212000>; - interrupt-parent = <40000>; + qe_phy0: ethernet-phy@00 { + interrupt-parent = <&mpic>; interrupts = <31 1>; reg = <0>; device_type = "ethernet-phy"; interface = <6>; //ENET_1000_GMII }; - ethernet-phy@01 { - linux,phandle = <212001>; - interrupt-parent = <40000>; + qe_phy1: ethernet-phy@01 { + interrupt-parent = <&mpic>; interrupts = <32 1>; reg = <1>; device_type = "ethernet-phy"; interface = <6>; }; - ethernet-phy@02 { - linux,phandle = <212002>; - interrupt-parent = <40000>; + qe_phy2: ethernet-phy@02 { + interrupt-parent = <&mpic>; interrupts = <31 1>; reg = <2>; device_type = "ethernet-phy"; interface = <6>; //ENET_1000_GMII }; - ethernet-phy@03 { - linux,phandle = <212003>; - interrupt-parent = <40000>; + qe_phy3: ethernet-phy@03 { + interrupt-parent = <&mpic>; interrupts = <32 1>; reg = <3>; device_type = "ethernet-phy"; @@ -363,8 +346,7 @@ }; }; - qeic@80 { - linux,phandle = <80>; + qeic: qeic@80 { interrupt-controller; device_type = "qeic"; #address-cells = <0>; @@ -373,7 +355,7 @@ built-in; big-endian; interrupts = <1e 2 1e 2>; //high:30 low:30 - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; }; diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts index f0c7731743e..8a4995a85ba 100644 --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts @@ -32,7 +32,6 @@ bus-frequency = <0>; // From uboot clock-frequency = <0>; // From uboot 32-bit; - linux,boot-cpu; }; PowerPC,8641@1 { device_type = "cpu"; @@ -67,7 +66,7 @@ compatible = "fsl-i2c"; reg = <3000 100>; interrupts = <2b 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; dfsrr; }; @@ -76,7 +75,7 @@ compatible = "fsl-i2c"; reg = <3100 100>; interrupts = <2b 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; dfsrr; }; @@ -86,31 +85,26 @@ device_type = "mdio"; compatible = "gianfar"; reg = <24520 20>; - linux,phandle = <24520>; - ethernet-phy@0 { - linux,phandle = <2452000>; - interrupt-parent = <40000>; + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; interrupts = <4a 1>; reg = <0>; device_type = "ethernet-phy"; }; - ethernet-phy@1 { - linux,phandle = <2452001>; - interrupt-parent = <40000>; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; interrupts = <4a 1>; reg = <1>; device_type = "ethernet-phy"; }; - ethernet-phy@2 { - linux,phandle = <2452002>; - interrupt-parent = <40000>; + phy2: ethernet-phy@2 { + interrupt-parent = <&mpic>; interrupts = <4a 1>; reg = <2>; device_type = "ethernet-phy"; }; - ethernet-phy@3 { - linux,phandle = <2452003>; - interrupt-parent = <40000>; + phy3: ethernet-phy@3 { + interrupt-parent = <&mpic>; interrupts = <4a 1>; reg = <3>; device_type = "ethernet-phy"; @@ -126,8 +120,8 @@ reg = <24000 1000>; mac-address = [ 00 E0 0C 00 73 00 ]; interrupts = <1d 2 1e 2 22 2>; - interrupt-parent = <40000>; - phy-handle = <2452000>; + interrupt-parent = <&mpic>; + phy-handle = <&phy0>; }; ethernet@25000 { @@ -139,8 +133,8 @@ reg = <25000 1000>; mac-address = [ 00 E0 0C 00 73 01 ]; interrupts = <23 2 24 2 28 2>; - interrupt-parent = <40000>; - phy-handle = <2452001>; + interrupt-parent = <&mpic>; + phy-handle = <&phy1>; }; ethernet@26000 { @@ -152,8 +146,8 @@ reg = <26000 1000>; mac-address = [ 00 E0 0C 00 02 FD ]; interrupts = <1F 2 20 2 21 2>; - interrupt-parent = <40000>; - phy-handle = <2452002>; + interrupt-parent = <&mpic>; + phy-handle = <&phy2>; }; ethernet@27000 { @@ -165,8 +159,8 @@ reg = <27000 1000>; mac-address = [ 00 E0 0C 00 03 FD ]; interrupts = <25 2 26 2 27 2>; - interrupt-parent = <40000>; - phy-handle = <2452003>; + interrupt-parent = <&mpic>; + phy-handle = <&phy3>; }; serial@4500 { device_type = "serial"; @@ -174,7 +168,7 @@ reg = <4500 100>; clock-frequency = <0>; interrupts = <2a 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; serial@4600 { @@ -183,7 +177,7 @@ reg = <4600 100>; clock-frequency = <0>; interrupts = <1c 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; pci@8000 { @@ -197,103 +191,102 @@ ranges = <02000000 0 80000000 80000000 0 20000000 01000000 0 00000000 e2000000 0 00100000>; clock-frequency = <1fca055>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; interrupts = <18 2>; interrupt-map-mask = <f800 0 0 7>; interrupt-map = < /* IDSEL 0x11 */ - 8800 0 0 1 4d0 3 2 - 8800 0 0 2 4d0 4 2 - 8800 0 0 3 4d0 5 2 - 8800 0 0 4 4d0 6 2 + 8800 0 0 1 &i8259 3 2 + 8800 0 0 2 &i8259 4 2 + 8800 0 0 3 &i8259 5 2 + 8800 0 0 4 &i8259 6 2 /* IDSEL 0x12 */ - 9000 0 0 1 4d0 4 2 - 9000 0 0 2 4d0 5 2 - 9000 0 0 3 4d0 6 2 - 9000 0 0 4 4d0 3 2 + 9000 0 0 1 &i8259 4 2 + 9000 0 0 2 &i8259 5 2 + 9000 0 0 3 &i8259 6 2 + 9000 0 0 4 &i8259 3 2 /* IDSEL 0x13 */ - 9800 0 0 1 4d0 0 0 - 9800 0 0 2 4d0 0 0 - 9800 0 0 3 4d0 0 0 - 9800 0 0 4 4d0 0 0 + 9800 0 0 1 &i8259 0 0 + 9800 0 0 2 &i8259 0 0 + 9800 0 0 3 &i8259 0 0 + 9800 0 0 4 &i8259 0 0 /* IDSEL 0x14 */ - a000 0 0 1 4d0 0 0 - a000 0 0 2 4d0 0 0 - a000 0 0 3 4d0 0 0 - a000 0 0 4 4d0 0 0 + a000 0 0 1 &i8259 0 0 + a000 0 0 2 &i8259 0 0 + a000 0 0 3 &i8259 0 0 + a000 0 0 4 &i8259 0 0 /* IDSEL 0x15 */ - a800 0 0 1 4d0 0 0 - a800 0 0 2 4d0 0 0 - a800 0 0 3 4d0 0 0 - a800 0 0 4 4d0 0 0 + a800 0 0 1 &i8259 0 0 + a800 0 0 2 &i8259 0 0 + a800 0 0 3 &i8259 0 0 + a800 0 0 4 &i8259 0 0 /* IDSEL 0x16 */ - b000 0 0 1 4d0 0 0 - b000 0 0 2 4d0 0 0 - b000 0 0 3 4d0 0 0 - b000 0 0 4 4d0 0 0 + b000 0 0 1 &i8259 0 0 + b000 0 0 2 &i8259 0 0 + b000 0 0 3 &i8259 0 0 + b000 0 0 4 &i8259 0 0 /* IDSEL 0x17 */ - b800 0 0 1 4d0 0 0 - b800 0 0 2 4d0 0 0 - b800 0 0 3 4d0 0 0 - b800 0 0 4 4d0 0 0 + b800 0 0 1 &i8259 0 0 + b800 0 0 2 &i8259 0 0 + b800 0 0 3 &i8259 0 0 + b800 0 0 4 &i8259 0 0 /* IDSEL 0x18 */ - c000 0 0 1 4d0 0 0 - c000 0 0 2 4d0 0 0 - c000 0 0 3 4d0 0 0 - c000 0 0 4 4d0 0 0 + c000 0 0 1 &i8259 0 0 + c000 0 0 2 &i8259 0 0 + c000 0 0 3 &i8259 0 0 + c000 0 0 4 &i8259 0 0 /* IDSEL 0x19 */ - c800 0 0 1 4d0 0 0 - c800 0 0 2 4d0 0 0 - c800 0 0 3 4d0 0 0 - c800 0 0 4 4d0 0 0 + c800 0 0 1 &i8259 0 0 + c800 0 0 2 &i8259 0 0 + c800 0 0 3 &i8259 0 0 + c800 0 0 4 &i8259 0 0 /* IDSEL 0x1a */ - d000 0 0 1 4d0 6 2 - d000 0 0 2 4d0 3 2 - d000 0 0 3 4d0 4 2 - d000 0 0 4 4d0 5 2 + d000 0 0 1 &i8259 6 2 + d000 0 0 2 &i8259 3 2 + d000 0 0 3 &i8259 4 2 + d000 0 0 4 &i8259 5 2 /* IDSEL 0x1b */ - d800 0 0 1 4d0 5 2 - d800 0 0 2 4d0 0 0 - d800 0 0 3 4d0 0 0 - d800 0 0 4 4d0 0 0 + d800 0 0 1 &i8259 5 2 + d800 0 0 2 &i8259 0 0 + d800 0 0 3 &i8259 0 0 + d800 0 0 4 &i8259 0 0 /* IDSEL 0x1c */ - e000 0 0 1 4d0 9 2 - e000 0 0 2 4d0 a 2 - e000 0 0 3 4d0 c 2 - e000 0 0 4 4d0 7 2 + e000 0 0 1 &i8259 9 2 + e000 0 0 2 &i8259 a 2 + e000 0 0 3 &i8259 c 2 + e000 0 0 4 &i8259 7 2 /* IDSEL 0x1d */ - e800 0 0 1 4d0 9 2 - e800 0 0 2 4d0 a 2 - e800 0 0 3 4d0 b 2 - e800 0 0 4 4d0 0 0 + e800 0 0 1 &i8259 9 2 + e800 0 0 2 &i8259 a 2 + e800 0 0 3 &i8259 b 2 + e800 0 0 4 &i8259 0 0 /* IDSEL 0x1e */ - f000 0 0 1 4d0 c 2 - f000 0 0 2 4d0 0 0 - f000 0 0 3 4d0 0 0 - f000 0 0 4 4d0 0 0 + f000 0 0 1 &i8259 c 2 + f000 0 0 2 &i8259 0 0 + f000 0 0 3 &i8259 0 0 + f000 0 0 4 &i8259 0 0 /* IDSEL 0x1f */ - f800 0 0 1 4d0 6 2 - f800 0 0 2 4d0 0 0 - f800 0 0 3 4d0 0 0 - f800 0 0 4 4d0 0 0 + f800 0 0 1 &i8259 6 2 + f800 0 0 2 &i8259 0 0 + f800 0 0 3 &i8259 0 0 + f800 0 0 4 &i8259 0 0 >; - i8259@4d0 { - linux,phandle = <4d0>; + i8259: i8259@4d0 { clock-frequency = <0>; interrupt-controller; device_type = "interrupt-controller"; @@ -303,12 +296,11 @@ compatible = "chrp,iic"; big-endian; interrupts = <49 2>; - interrupt-parent = <40000>; + interrupt-parent = <&mpic>; }; }; - pic@40000 { - linux,phandle = <40000>; + mpic: pic@40000 { clock-frequency = <0>; interrupt-controller; #address-cells = <0>; @@ -317,23 +309,7 @@ built-in; compatible = "chrp,open-pic"; device_type = "open-pic"; - big-endian; - interrupts = < - 10 2 11 2 12 2 13 2 - 14 2 15 2 16 2 17 2 - 18 2 19 2 1a 2 1b 2 - 1c 2 1d 2 1e 2 1f 2 - 20 2 21 2 22 2 23 2 - 24 2 25 2 26 2 27 2 - 28 2 29 2 2a 2 2b 2 - 2c 2 2d 2 2e 2 2f 2 - 30 2 31 2 32 2 33 2 - 34 2 35 2 36 2 37 2 - 38 2 39 2 2a 2 3b 2 - 3c 2 3d 2 3e 2 3f 2 - 48 1 49 2 4a 1 - >; - interrupt-parent = <40000>; + big-endian; }; }; }; diff --git a/arch/powerpc/boot/dts/mpc866ads.dts b/arch/powerpc/boot/dts/mpc866ads.dts index 5d4005239b8..2b56b5df451 100644 --- a/arch/powerpc/boot/dts/mpc866ads.dts +++ b/arch/powerpc/boot/dts/mpc866ads.dts @@ -37,7 +37,6 @@ interrupts = <f 2>; // decrementer interrupt interrupt-parent = <ff000000>; linux,phandle = <201>; - linux,boot-cpu; }; }; diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts index cf1a19f962c..faecd08c54d 100644 --- a/arch/powerpc/boot/dts/mpc885ads.dts +++ b/arch/powerpc/boot/dts/mpc885ads.dts @@ -37,7 +37,6 @@ interrupts = <f 2>; // decrementer interrupt interrupt-parent = <ff000000>; linux,phandle = <201>; - linux,boot-cpu; }; }; diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig index e956548da00..24367319ce2 100644 --- a/arch/powerpc/configs/cell_defconfig +++ b/arch/powerpc/configs/cell_defconfig @@ -147,6 +147,7 @@ CONFIG_PPC_RTAS=y # CONFIG_RTAS_ERROR_LOGGING is not set CONFIG_RTAS_PROC=y CONFIG_RTAS_FLASH=y +CONFIG_PPC_PMI=m CONFIG_MMIO_NVRAM=y # CONFIG_PPC_MPC106 is not set # CONFIG_PPC_970_NAP is not set diff --git a/arch/powerpc/configs/mpc832xemds_defconfig b/arch/powerpc/configs/mpc832x_mds_defconfig index e1b36de6b38..e1b36de6b38 100644 --- a/arch/powerpc/configs/mpc832xemds_defconfig +++ b/arch/powerpc/configs/mpc832x_mds_defconfig diff --git a/arch/powerpc/configs/mpc8360emds_defconfig b/arch/powerpc/configs/mpc836x_mds_defconfig index bbe38ccc3d8..8eb475cd0df 100644 --- a/arch/powerpc/configs/mpc8360emds_defconfig +++ b/arch/powerpc/configs/mpc836x_mds_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20-rc5 -# Fri Jan 26 00:19:45 2007 +# Linux kernel version: 2.6.20 +# Sat Feb 17 10:09:26 2007 # # CONFIG_PPC64 is not set CONFIG_PPC32=y @@ -34,9 +34,9 @@ CONFIG_DEFAULT_UIMAGE=y CONFIG_PPC_83xx=y # CONFIG_PPC_85xx is not set # CONFIG_PPC_86xx is not set +# CONFIG_PPC_8xx is not set # CONFIG_40x is not set # CONFIG_44x is not set -# CONFIG_8xx is not set # CONFIG_E200 is not set CONFIG_6xx=y CONFIG_83xx=y @@ -63,6 +63,7 @@ CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y # CONFIG_IPC_NS is not set +CONFIG_SYSVIPC_SYSCTL=y # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set @@ -129,10 +130,11 @@ CONFIG_PPC_GEN550=y # # Platform support # +# CONFIG_MPC8313_RDB is not set # CONFIG_MPC832x_MDS is not set -# CONFIG_MPC834x_SYS is not set +# CONFIG_MPC834x_MDS is not set # CONFIG_MPC834x_ITX is not set -CONFIG_MPC8360E_PB=y +CONFIG_MPC836x_MDS=y CONFIG_PPC_MPC836x=y # CONFIG_MPIC is not set @@ -162,6 +164,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 CONFIG_PROC_DEVICETREE=y # CONFIG_CMDLINE_BOOL is not set # CONFIG_PM is not set @@ -171,6 +174,7 @@ CONFIG_ISA_DMA_API=y # # Bus options # +CONFIG_ZONE_DMA=y CONFIG_GENERIC_ISA_DMA=y # CONFIG_MPIC_WEIRD is not set # CONFIG_PPC_I8259 is not set @@ -219,6 +223,7 @@ CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set # CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set # CONFIG_NET_KEY is not set CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -528,6 +533,7 @@ CONFIG_UCC_GETH=y # Ethernet (10000 Mbit) # # CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set # CONFIG_MYRI10GE is not set @@ -620,6 +626,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4 CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_OF_PLATFORM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -690,6 +697,7 @@ CONFIG_I2C_MPC=y # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_OCORES is not set # CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PASEMI is not set # CONFIG_I2C_PROSAVAGE is not set # CONFIG_I2C_SAVAGE4 is not set # CONFIG_I2C_SIS5595 is not set @@ -804,6 +812,7 @@ CONFIG_FIRMWARE_EDID=y # HID Devices # CONFIG_HID=y +# CONFIG_HID_DEBUG is not set # # USB support @@ -868,6 +877,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y # # +# Auxiliary Display support +# + +# # Virtualization # @@ -1011,7 +1024,8 @@ CONFIG_BITREVERSE=y CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_PLIST=y -CONFIG_IOMAP_COPY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y # # Instrumentation Support @@ -1060,8 +1074,10 @@ CONFIG_CRYPTO_MD5=y # CONFIG_CRYPTO_GF128MUL is not set CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_LRW is not set CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set # CONFIG_CRYPTO_SERPENT is not set @@ -1075,6 +1091,7 @@ CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_DEFLATE is not set # CONFIG_CRYPTO_MICHAEL_MIC is not set # CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set # CONFIG_CRYPTO_TEST is not set # diff --git a/arch/powerpc/configs/mpc8568mds_defconfig b/arch/powerpc/configs/mpc8568mds_defconfig index 058e06d88bc..7b3800674cb 100644 --- a/arch/powerpc/configs/mpc8568mds_defconfig +++ b/arch/powerpc/configs/mpc8568mds_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20-rc5 -# Wed Feb 7 23:54:25 2007 +# Linux kernel version: 2.6.20 +# Sat Feb 17 16:26:53 2007 # # CONFIG_PPC64 is not set CONFIG_PPC32=y @@ -34,9 +34,9 @@ CONFIG_DEFAULT_UIMAGE=y # CONFIG_PPC_83xx is not set CONFIG_PPC_85xx=y # CONFIG_PPC_86xx is not set +# CONFIG_PPC_8xx is not set # CONFIG_40x is not set # CONFIG_44x is not set -# CONFIG_8xx is not set # CONFIG_E200 is not set CONFIG_85xx=y CONFIG_E500=y @@ -63,6 +63,7 @@ CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y # CONFIG_IPC_NS is not set +CONFIG_SYSVIPC_SYSCTL=y # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set @@ -130,7 +131,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_MPC8540_ADS is not set # CONFIG_MPC8560_ADS is not set # CONFIG_MPC85xx_CDS is not set -CONFIG_MPC8568_MDS=y +CONFIG_MPC85xx_MDS=y CONFIG_MPC85xx=y CONFIG_PPC_INDIRECT_PCI_BE=y CONFIG_MPIC=y @@ -162,6 +163,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 CONFIG_PROC_DEVICETREE=y # CONFIG_CMDLINE_BOOL is not set # CONFIG_PM is not set @@ -171,6 +173,7 @@ CONFIG_ISA_DMA_API=y # # Bus options # +CONFIG_ZONE_DMA=y # CONFIG_MPIC_WEIRD is not set # CONFIG_PPC_I8259 is not set CONFIG_PPC_INDIRECT_PCI=y @@ -216,6 +219,7 @@ CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set # CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set # CONFIG_NET_KEY is not set CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -301,6 +305,7 @@ CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set # CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set # @@ -341,7 +346,6 @@ CONFIG_BLK_DEV_INITRD=y # # Misc devices # -# CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support @@ -543,6 +547,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4 # CONFIG_SERIAL_UARTLITE is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_OF_PLATFORM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -698,6 +703,7 @@ CONFIG_FIRMWARE_EDID=y # HID Devices # CONFIG_HID=y +# CONFIG_HID_DEBUG is not set # # USB support @@ -760,6 +766,10 @@ CONFIG_HID=y # # +# Auxiliary Display support +# + +# # Virtualization # @@ -896,7 +906,8 @@ CONFIG_BITREVERSE=y CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_PLIST=y -CONFIG_IOMAP_COPY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y # # Instrumentation Support @@ -914,6 +925,7 @@ CONFIG_ENABLE_MUST_CHECK=y # CONFIG_DEBUG_FS is not set # CONFIG_HEADERS_CHECK is not set CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set CONFIG_LOG_BUF_SHIFT=14 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set @@ -922,7 +934,6 @@ CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_RWSEMS is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set @@ -932,6 +943,8 @@ CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_DEBUG_LIST is not set CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set CONFIG_DEBUGGER=y # CONFIG_XMON is not set # CONFIG_BDI_SWITCH is not set @@ -943,6 +956,8 @@ CONFIG_PPC_EARLY_DEBUG=y # CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set # CONFIG_PPC_EARLY_DEBUG_MAPLE is not set # CONFIG_PPC_EARLY_DEBUG_ISERIES is not set +# CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE is not set +# CONFIG_PPC_EARLY_DEBUG_BEAT is not set # # Security options @@ -970,8 +985,10 @@ CONFIG_CRYPTO_MD5=y # CONFIG_CRYPTO_GF128MUL is not set CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_LRW is not set CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set # CONFIG_CRYPTO_SERPENT is not set @@ -985,6 +1002,7 @@ CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_DEFLATE is not set # CONFIG_CRYPTO_MICHAEL_MIC is not set # CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set # CONFIG_CRYPTO_TEST is not set # diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index debac66e825..a8da0aea3b8 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -500,7 +500,7 @@ CONFIG_BLK_DEV_AMD74XX=y # CONFIG_BLK_DEV_PDC202XX_NEW is not set # CONFIG_BLK_DEV_SVWKS is not set # CONFIG_BLK_DEV_SIIMAGE is not set -CONFIG_BLK_DEV_SL82C105=y +# CONFIG_BLK_DEV_SL82C105 is not set # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set @@ -646,7 +646,7 @@ CONFIG_SATA_SVW=y # CONFIG_PATA_SIL680 is not set # CONFIG_PATA_SIS is not set # CONFIG_PATA_VIA is not set -# CONFIG_PATA_WINBOND is not set +CONFIG_PATA_WINBOND=y # # Multi-device support (RAID and LVM) diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 1c794fe718f..6e96e50c362 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -483,7 +483,7 @@ CONFIG_BLK_DEV_AMD74XX=y # CONFIG_BLK_DEV_PDC202XX_NEW is not set # CONFIG_BLK_DEV_SVWKS is not set # CONFIG_BLK_DEV_SIIMAGE is not set -CONFIG_BLK_DEV_SL82C105=y +# CONFIG_BLK_DEV_SL82C105 is not set # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set @@ -628,7 +628,7 @@ CONFIG_ATA=y # CONFIG_PATA_SIL680 is not set # CONFIG_PATA_SIS is not set # CONFIG_PATA_VIA is not set -# CONFIG_PATA_WINBOND is not set +CONFIG_PATA_WINBOND=y # # Multi-device support (RAID and LVM) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 3e86e6e0f77..8d52b23348b 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -1599,6 +1599,7 @@ struct property *of_find_property(const struct device_node *np, return pp; } +EXPORT_SYMBOL(of_find_property); /* * Find a property with a given name for a given node diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 12c51e4ad2b..ea6fd552c7e 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -5,6 +5,7 @@ #include <linux/pci_regs.h> #include <linux/module.h> #include <linux/ioport.h> +#include <linux/etherdevice.h> #include <asm/prom.h> #include <asm/pci-bridge.h> @@ -1003,3 +1004,42 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq return res; } EXPORT_SYMBOL_GPL(of_irq_map_one); + +/** + * Search the device tree for the best MAC address to use. 'mac-address' is + * checked first, because that is supposed to contain to "most recent" MAC + * address. If that isn't set, then 'local-mac-address' is checked next, + * because that is the default address. If that isn't set, then the obsolete + * 'address' is checked, just in case we're using an old device tree. + * + * Note that the 'address' property is supposed to contain a virtual address of + * the register set, but some DTS files have redefined that property to be the + * MAC address. + * + * All-zero MAC addresses are rejected, because those could be properties that + * exist in the device tree, but were not set by U-Boot. For example, the + * DTS could define 'mac-address' and 'local-mac-address', with zero MAC + * addresses. Some older U-Boots only initialized 'local-mac-address'. In + * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists + * but is all zeros. +*/ +const void *of_get_mac_address(struct device_node *np) +{ + struct property *pp; + + pp = of_find_property(np, "mac-address", NULL); + if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) + return pp->value; + + pp = of_find_property(np, "local-mac-address", NULL); + if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) + return pp->value; + + pp = of_find_property(np, "address", NULL); + if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) + return pp->value; + + return NULL; +} +EXPORT_SYMBOL(of_get_mac_address); + diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 16e4ee1c231..1d443407423 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -103,7 +103,7 @@ static int map_io_page(unsigned long ea, unsigned long pa, int flags) * */ if (htab_bolt_mapping(ea, ea + PAGE_SIZE, pa, flags, - mmu_virtual_psize)) { + mmu_io_psize)) { printk(KERN_ERR "Failed to do bolted mapping IO " "memory at %016lx !\n", pa); return -ENOMEM; diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index 1aea1e69ff3..713b31a16ce 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig @@ -38,12 +38,12 @@ config MPC834x_ITX Be aware that PCI initialization is the bootloader's responsibility. -config MPC8360E_PB - bool "Freescale MPC8360E PB" +config MPC836x_MDS + bool "Freescale MPC836x MDS" select DEFAULT_UIMAGE select QUICC_ENGINE help - This option enables support for the MPC836x EMDS Processor Board. + This option enables support for the MPC836x MDS Processor Board. endchoice @@ -69,6 +69,6 @@ config PPC_MPC836x bool select PPC_UDBG_16550 select PPC_INDIRECT_PCI - default y if MPC8360E_PB + default y if MPC836x_MDS endmenu diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile index 6c8199c4c38..dfc970d0df1 100644 --- a/arch/powerpc/platforms/83xx/Makefile +++ b/arch/powerpc/platforms/83xx/Makefile @@ -6,5 +6,5 @@ obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_MPC8313_RDB) += mpc8313_rdb.o obj-$(CONFIG_MPC834x_MDS) += mpc834x_mds.o obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o -obj-$(CONFIG_MPC8360E_PB) += mpc8360e_pb.o +obj-$(CONFIG_MPC836x_MDS) += mpc836x_mds.o obj-$(CONFIG_MPC832x_MDS) += mpc832x_mds.o diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c index c3b98c34eb6..32e9e949284 100644 --- a/arch/powerpc/platforms/83xx/mpc8313_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c @@ -74,16 +74,9 @@ void __init mpc8313_rdb_init_IRQ(void) */ static int __init mpc8313_rdb_probe(void) { - char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), - "model", NULL); - if (model == NULL) - return 0; - if (strcmp(model, "MPC8313ERDB")) - return 0; + unsigned long root = of_get_flat_dt_root(); - DBG("MPC8313 RDB found\n"); - - return 1; + return of_flat_dt_is_compatible(root, "MPC8313ERDB"); } define_machine(mpc8313_rdb) { diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index 3ecb55f8a6e..17e3a3c6d8b 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -57,11 +57,6 @@ unsigned long isa_mem_base = 0; static u8 *bcsr_regs = NULL; -u8 *get_bcsr(void) -{ - return bcsr_regs; -} - /* ************************************************************************ * * Setup the architecture @@ -74,17 +69,6 @@ static void __init mpc832x_sys_setup_arch(void) if (ppc_md.progress) ppc_md.progress("mpc832x_sys_setup_arch()", 0); - np = of_find_node_by_type(NULL, "cpu"); - if (np != 0) { - unsigned int *fp = - (int *)get_property(np, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(np); - } - /* Map BCSR area */ np = of_find_node_by_name(NULL, "bcsr"); if (np != 0) { @@ -121,34 +105,23 @@ static void __init mpc832x_sys_setup_arch(void) iounmap(bcsr_regs); of_node_put(np); } - #endif /* CONFIG_QUICC_ENGINE */ - -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_HDA1; -#endif } +static struct of_device_id mpc832x_ids[] = { + { .type = "soc", }, + { .compatible = "soc", }, + { .type = "qe", }, + {}, +}; + static int __init mpc832x_declare_of_platform_devices(void) { - struct device_node *np; - - for (np = NULL; (np = of_find_compatible_node(np, "network", - "ucc_geth")) != NULL;) { - int ucc_num; - char bus_id[BUS_ID_SIZE]; + if (!machine_is(mpc832x_mds)) + return 0; - ucc_num = *((uint *) get_property(np, "device-id", NULL)) - 1; - snprintf(bus_id, BUS_ID_SIZE, "ucc_geth.%u", ucc_num); - of_platform_device_create(np, bus_id, NULL); - } + /* Publish the QE devices */ + of_platform_bus_probe(NULL, mpc832x_ids, NULL); return 0; } @@ -156,7 +129,6 @@ device_initcall(mpc832x_declare_of_platform_devices); static void __init mpc832x_sys_init_IRQ(void) { - struct device_node *np; np = of_find_node_by_type(NULL, "ipic"); @@ -189,6 +161,9 @@ static int __init mpc832x_rtc_hookup(void) { struct timespec tv; + if (!machine_is(mpc832x_mds)) + return 0; + ppc_md.get_rtc_time = ds1374_get_rtc_time; ppc_md.set_rtc_time = ds1374_set_rtc_time; @@ -207,17 +182,9 @@ late_initcall(mpc832x_rtc_hookup); */ static int __init mpc832x_sys_probe(void) { - char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), - "model", NULL); - - if (model == NULL) - return 0; - if (strcmp(model, "MPC8323EMDS")) - return 0; - - DBG("%s found\n", model); + unsigned long root = of_get_flat_dt_root(); - return 1; + return of_flat_dt_is_compatible(root, "MPC832xMDS"); } define_machine(mpc832x_mds) { diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 443a3172f37..3c009f6d4a4 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -55,28 +55,12 @@ static void __init mpc834x_itx_setup_arch(void) if (ppc_md.progress) ppc_md.progress("mpc834x_itx_setup_arch()", 0); - np = of_find_node_by_type(NULL, "cpu"); - if (np != 0) { - const unsigned int *fp = - get_property(np, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(np); - } #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) add_bridge(np); ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif - -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_HDA1; -#endif } static void __init mpc834x_itx_init_IRQ(void) @@ -100,10 +84,9 @@ static void __init mpc834x_itx_init_IRQ(void) */ static int __init mpc834x_itx_probe(void) { - /* We always match for now, eventually we should look at the flat - dev tree to ensure this is the board we are suppose to run on - */ - return 1; + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "MPC834xMITX"); } define_machine(mpc834x_itx) { diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index d2736da76c4..e5d81916687 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -125,17 +125,6 @@ static void __init mpc834x_mds_setup_arch(void) if (ppc_md.progress) ppc_md.progress("mpc834x_mds_setup_arch()", 0); - np = of_find_node_by_type(NULL, "cpu"); - if (np != 0) { - const unsigned int *fp = - get_property(np, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(np); - } - #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) add_bridge(np); @@ -144,12 +133,6 @@ static void __init mpc834x_mds_setup_arch(void) #endif mpc834x_usb_cfg(); - -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_HDA1; -#endif } static void __init mpc834x_mds_init_IRQ(void) @@ -176,6 +159,9 @@ static int __init mpc834x_rtc_hookup(void) { struct timespec tv; + if (!machine_is(mpc834x_mds)) + return 0; + ppc_md.get_rtc_time = ds1374_get_rtc_time; ppc_md.set_rtc_time = ds1374_set_rtc_time; @@ -194,10 +180,9 @@ late_initcall(mpc834x_rtc_hookup); */ static int __init mpc834x_mds_probe(void) { - /* We always match for now, eventually we should look at the flat - dev tree to ensure this is the board we are suppose to run on - */ - return 1; + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "MPC834xMDS"); } define_machine(mpc834x_mds) { diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index ccce2f9f283..526ed090a44 100644 --- a/arch/powerpc/platforms/83xx/mpc8360e_pb.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -5,12 +5,12 @@ * Yin Olivia <Hong-hua.Yin@freescale.com> * * Description: - * MPC8360E MDS PB board specific routines. + * MPC8360E MDS board specific routines. * * Changelog: * Jun 21, 2006 Initial version * - * This program is free software; you can redistribute it and/or modify it + * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. @@ -62,33 +62,17 @@ unsigned long isa_mem_base = 0; static u8 *bcsr_regs = NULL; -u8 *get_bcsr(void) -{ - return bcsr_regs; -} - /* ************************************************************************ * * Setup the architecture * */ -static void __init mpc8360_sys_setup_arch(void) +static void __init mpc836x_mds_setup_arch(void) { struct device_node *np; if (ppc_md.progress) - ppc_md.progress("mpc8360_sys_setup_arch()", 0); - - np = of_find_node_by_type(NULL, "cpu"); - if (np != 0) { - const unsigned int *fp = - get_property(np, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(np); - } + ppc_md.progress("mpc836x_mds_setup_arch()", 0); /* Map BCSR area */ np = of_find_node_by_name(NULL, "bcsr"); @@ -128,40 +112,29 @@ static void __init mpc8360_sys_setup_arch(void) } #endif /* CONFIG_QUICC_ENGINE */ - -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_HDA1; -#endif } -static int __init mpc8360_declare_of_platform_devices(void) -{ - struct device_node *np; +static struct of_device_id mpc836x_ids[] = { + { .type = "soc", }, + { .compatible = "soc", }, + { .type = "qe", }, + {}, +}; - for (np = NULL; (np = of_find_compatible_node(np, "network", - "ucc_geth")) != NULL;) { - int ucc_num; - char bus_id[BUS_ID_SIZE]; +static int __init mpc836x_declare_of_platform_devices(void) +{ + if (!machine_is(mpc836x_mds)) + return 0; - ucc_num = *((uint *) get_property(np, "device-id", NULL)) - 1; - snprintf(bus_id, BUS_ID_SIZE, "ucc_geth.%u", ucc_num); - of_platform_device_create(np, bus_id, NULL); - } + /* Publish the QE devices */ + of_platform_bus_probe(NULL, mpc836x_ids, NULL); return 0; } -device_initcall(mpc8360_declare_of_platform_devices); +device_initcall(mpc836x_declare_of_platform_devices); -static void __init mpc8360_sys_init_IRQ(void) +static void __init mpc836x_mds_init_IRQ(void) { - struct device_node *np; np = of_find_node_by_type(NULL, "ipic"); @@ -194,6 +167,9 @@ static int __init mpc8360_rtc_hookup(void) { struct timespec tv; + if (!machine_is(mpc836x_mds)) + return 0; + ppc_md.get_rtc_time = ds1374_get_rtc_time; ppc_md.set_rtc_time = ds1374_set_rtc_time; @@ -210,28 +186,21 @@ late_initcall(mpc8360_rtc_hookup); /* * Called very early, MMU is off, device-tree isn't unflattened */ -static int __init mpc8360_sys_probe(void) +static int __init mpc836x_mds_probe(void) { - char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), - "model", NULL); - if (model == NULL) - return 0; - if (strcmp(model, "MPC8360EPB")) - return 0; - - DBG("MPC8360EMDS-PB found\n"); + unsigned long root = of_get_flat_dt_root(); - return 1; + return of_flat_dt_is_compatible(root, "MPC836xMDS"); } -define_machine(mpc8360_sys) { - .name = "MPC8360E PB", - .probe = mpc8360_sys_probe, - .setup_arch = mpc8360_sys_setup_arch, - .init_IRQ = mpc8360_sys_init_IRQ, - .get_irq = ipic_get_irq, - .restart = mpc83xx_restart, - .time_init = mpc83xx_time_init, +define_machine(mpc836x_mds) { + .name = "MPC836x MDS", + .probe = mpc836x_mds_probe, + .setup_arch = mpc836x_mds_setup_arch, + .init_IRQ = mpc836x_mds_init_IRQ, + .get_irq = ipic_get_irq, + .restart = mpc83xx_restart, + .time_init = mpc83xx_time_init, .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, + .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index 0efdd2f1bab..eb661ccf2da 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -23,12 +23,12 @@ config MPC85xx_CDS help This option enables support for the MPC85xx CDS board -config MPC8568_MDS - bool "Freescale MPC8568 MDS" +config MPC85xx_MDS + bool "Freescale MPC85xx MDS" select DEFAULT_UIMAGE # select QUICC_ENGINE help - This option enables support for the MPC8568 MDS board + This option enables support for the MPC85xx MDS board endchoice @@ -47,7 +47,7 @@ config MPC85xx bool select PPC_UDBG_16550 select PPC_INDIRECT_PCI - default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS || MPC8568_MDS + default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS || MPC85xx_MDS config PPC_INDIRECT_PCI_BE bool diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index e40e521816b..4e63917ada9 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -5,4 +5,4 @@ obj-$(CONFIG_PPC_85xx) += misc.o pci.o obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o -obj-$(CONFIG_MPC8568_MDS) += mpc8568_mds.o +obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index c56fce57621..8ed034aeca5 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -17,7 +17,6 @@ #include <linux/kdev_t.h> #include <linux/delay.h> #include <linux/seq_file.h> -#include <linux/root_dev.h> #include <asm/system.h> #include <asm/time.h> @@ -245,12 +244,6 @@ static void __init mpc85xx_ads_setup_arch(void) add_bridge(np); ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif - -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_HDA1; -#endif } static void mpc85xx_ads_show_cpuinfo(struct seq_file *m) @@ -279,10 +272,9 @@ static void mpc85xx_ads_show_cpuinfo(struct seq_file *m) */ static int __init mpc85xx_ads_probe(void) { - /* We always match for now, eventually we should look at the flat - dev tree to ensure this is the board we are suppose to run on - */ - return 1; + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "MPC85xxADS"); } define_machine(mpc85xx_ads) { diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index abc0aca6de4..4232686be44 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -22,7 +22,6 @@ #include <linux/console.h> #include <linux/delay.h> #include <linux/seq_file.h> -#include <linux/root_dev.h> #include <linux/initrd.h> #include <linux/module.h> #include <linux/fsl_devices.h> @@ -263,12 +262,6 @@ static void __init mpc85xx_cds_setup_arch(void) ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup; ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif - -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_HDA1; -#endif } static void mpc85xx_cds_show_cpuinfo(struct seq_file *m) @@ -298,11 +291,9 @@ static void mpc85xx_cds_show_cpuinfo(struct seq_file *m) */ static int __init mpc85xx_cds_probe(void) { - /* We always match for now, eventually we should look at - * the flat dev tree to ensure this is the board we are - * supposed to run on - */ - return 1; + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "MPC85xxCDS"); } define_machine(mpc85xx_cds) { diff --git a/arch/powerpc/platforms/85xx/mpc8568_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 0861d1107bc..81144d2ae45 100644 --- a/arch/powerpc/platforms/85xx/mpc8568_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -8,7 +8,7 @@ * Yin Olivia <Hong-hua.Yin@freescale.com> * * Description: - * MPC8568E MDS PB board specific routines. + * MPC85xx MDS board specific routines. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -27,7 +27,6 @@ #include <linux/console.h> #include <linux/delay.h> #include <linux/seq_file.h> -#include <linux/root_dev.h> #include <linux/initrd.h> #include <linux/module.h> #include <linux/fsl_devices.h> @@ -70,14 +69,13 @@ unsigned long isa_mem_base = 0; * Setup the architecture * */ -static void __init mpc8568_mds_setup_arch(void) +static void __init mpc85xx_mds_setup_arch(void) { struct device_node *np; static u8 *bcsr_regs = NULL; - if (ppc_md.progress) - ppc_md.progress("mpc8568_mds_setup_arch()", 0); + ppc_md.progress("mpc85xx_mds_setup_arch()", 0); np = of_find_node_by_type(NULL, "cpu"); if (np != NULL) { @@ -145,26 +143,26 @@ static void __init mpc8568_mds_setup_arch(void) #endif /* CONFIG_QUICC_ENGINE */ } -static struct of_device_id mpc8568_ids[] = { +static struct of_device_id mpc85xx_ids[] = { { .type = "soc", }, { .compatible = "soc", }, { .type = "qe", }, {}, }; -static int __init mpc8568_publish_devices(void) +static int __init mpc85xx_publish_devices(void) { - if (!machine_is(mpc8568_mds)) + if (!machine_is(mpc85xx_mds)) return 0; /* Publish the QE devices */ - of_platform_bus_probe(NULL,mpc8568_ids,NULL); + of_platform_bus_probe(NULL,mpc85xx_ids,NULL); return 0; } -device_initcall(mpc8568_publish_devices); +device_initcall(mpc85xx_publish_devices); -static void __init mpc8568_mds_pic_init(void) +static void __init mpc85xx_mds_pic_init(void) { struct mpic *mpic; struct resource r; @@ -207,7 +205,6 @@ static void __init mpc8568_mds_pic_init(void) mpic_init(mpic); - #ifdef CONFIG_QUICC_ENGINE np = of_find_node_by_type(NULL, "qeic"); if (!np) @@ -218,27 +215,18 @@ static void __init mpc8568_mds_pic_init(void) #endif /* CONFIG_QUICC_ENGINE */ } - -static int __init mpc8568_mds_probe(void) +static int __init mpc85xx_mds_probe(void) { - char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), - "model", NULL); - if (model == NULL) - return 0; - if (strcmp(model, "MPC8568EMDS")) - return 0; - - DBG("MPC8568EMDS found\n"); + unsigned long root = of_get_flat_dt_root(); - return 1; + return of_flat_dt_is_compatible(root, "MPC85xxMDS"); } - -define_machine(mpc8568_mds) { - .name = "MPC8568E MDS", - .probe = mpc8568_mds_probe, - .setup_arch = mpc8568_mds_setup_arch, - .init_IRQ = mpc8568_mds_pic_init, +define_machine(mpc85xx_mds) { + .name = "MPC85xx MDS", + .probe = mpc85xx_mds_probe, + .setup_arch = mpc85xx_mds_setup_arch, + .init_IRQ = mpc85xx_mds_pic_init, .get_irq = mpic_get_irq, .restart = mpc85xx_restart, .calibrate_decr = generic_calibrate_decr, diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index f4dd5f2f8a2..f42f801cf84 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -18,7 +18,6 @@ #include <linux/kdev_t.h> #include <linux/delay.h> #include <linux/seq_file.h> -#include <linux/root_dev.h> #include <asm/system.h> #include <asm/time.h> @@ -120,6 +119,8 @@ mpc86xx_hpcn_init_irq(void) DBG("mpc86xxhpcn: cascade mapped to irq %d\n", cascade_irq); i8259_init(cascade_node, 0); + of_node_put(cascade_node); + set_irq_chained_handler(cascade_irq, mpc86xx_8259_cascade); #endif } @@ -365,12 +366,6 @@ mpc86xx_hpcn_setup_arch(void) printk("MPC86xx HPCN board from Freescale Semiconductor\n"); -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_HDA1; -#endif - #ifdef CONFIG_SMP mpc86xx_smp_init(); #endif diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile index 3baf658ac54..f4f82520dc4 100644 --- a/arch/powerpc/platforms/celleb/Makefile +++ b/arch/powerpc/platforms/celleb/Makefile @@ -1,9 +1,8 @@ obj-y += interrupt.o iommu.o setup.o \ htab.o beat.o pci.o \ - scc_epci.o hvCall.o + scc_epci.o scc_uhc.o hvCall.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o -obj-$(CONFIG_USB) += scc_uhc.o obj-$(CONFIG_HAS_TXX9_SERIAL) += scc_sio.o obj-$(CONFIG_SPU_BASE) += spu_priv1.o diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c index 1de63acfda8..5f4d0d93323 100644 --- a/arch/powerpc/platforms/celleb/setup.c +++ b/arch/powerpc/platforms/celleb/setup.c @@ -137,10 +137,12 @@ static int celleb_check_legacy_ioport(unsigned int baseport) return -ENODEV; } +#ifdef CONFIG_KEXEC static void celleb_kexec_cpu_down(int crash, int secondary) { beatic_deinit_IRQ(); } +#endif static struct of_device_id celleb_bus_ids[] = { { .type = "scc", }, diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index 4be3943d1c0..d270a1e374d 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -62,4 +62,14 @@ config PS3_PS3AV This support is required for graphics and sound. In general, all users will say Y or M. +config PS3_SYS_MANAGER + bool "PS3 System Manager driver" + select PS3_VUART + default y + help + Include support for the PS3 System Manager. + + This support is required for system control. In + general, all users will say Y. + endmenu diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 13d669a8eca..ac5df9688dc 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -42,6 +42,10 @@ #define DBG(fmt...) do{if(0)printk(fmt);}while(0) #endif +#if !defined(CONFIG_SMP) +static void smp_send_stop(void) {} +#endif + int ps3_get_firmware_version(union ps3_firmware_version *v) { int result = lv1_get_version_info(&v->raw); @@ -66,22 +70,35 @@ static void ps3_power_save(void) lv1_pause(0); } +static void ps3_restart(char *cmd) +{ + DBG("%s:%d cmd '%s'\n", __func__, __LINE__, cmd); + + smp_send_stop(); + ps3_sys_manager_restart(); /* never returns */ +} + +static void ps3_power_off(void) +{ + DBG("%s:%d\n", __func__, __LINE__); + + smp_send_stop(); + ps3_sys_manager_power_off(); /* never returns */ +} + static void ps3_panic(char *str) { DBG("%s:%d %s\n", __func__, __LINE__, str); -#ifdef CONFIG_SMP smp_send_stop(); -#endif printk("\n"); printk(" System does not reboot automatically.\n"); printk(" Please press POWER button.\n"); printk("\n"); - for (;;) ; + while(1); } - static void prealloc(struct ps3_prealloc *p) { if (!p->size) @@ -219,6 +236,8 @@ define_machine(ps3) { .get_rtc_time = ps3_get_rtc_time, .calibrate_decr = ps3_calibrate_decr, .progress = ps3_progress, + .restart = ps3_restart, + .power_off = ps3_power_off, #if defined(CONFIG_KEXEC) .kexec_cpu_down = ps3_kexec_cpu_down, .machine_kexec = ps3_machine_kexec, diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index dc0583bdbc6..2dfd05095a2 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -4,7 +4,7 @@ endif obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ setup.o iommu.o ras.o rtasd.o pci_dlpar.o \ - firmware.o + firmware.o power.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_SCANLOG) += scanlog.o diff --git a/arch/powerpc/platforms/pseries/power.c b/arch/powerpc/platforms/pseries/power.c new file mode 100644 index 00000000000..2624b71df73 --- /dev/null +++ b/arch/powerpc/platforms/pseries/power.c @@ -0,0 +1,87 @@ +/* + * Interface for power-management for ppc64 compliant platform + * + * Manish Ahuja <mahuja@us.ibm.com> + * + * Feb 2007 + * + * Copyright (C) 2007 IBM Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kobject.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/init.h> + +unsigned long rtas_poweron_auto; /* default and normal state is 0 */ + +static ssize_t auto_poweron_show(struct subsystem *subsys, char *buf) +{ + return sprintf(buf, "%lu\n", rtas_poweron_auto); +} + +static ssize_t +auto_poweron_store(struct subsystem *subsys, const char *buf, size_t n) +{ + int ret; + unsigned long ups_restart; + ret = sscanf(buf, "%lu", &ups_restart); + + if ((ret == 1) && ((ups_restart == 1) || (ups_restart == 0))){ + rtas_poweron_auto = ups_restart; + return n; + } + return -EINVAL; +} + +static struct subsys_attribute auto_poweron_attr = { + .attr = { + .name = __stringify(auto_poweron), + .mode = 0644, + }, + .show = auto_poweron_show, + .store = auto_poweron_store, +}; + +#ifndef CONFIG_PM +decl_subsys(power,NULL,NULL); + +static struct attribute *g[] = { + &auto_poweron_attr.attr, + NULL, +}; + +static struct attribute_group attr_group = { + .attrs = g, +}; + +static int __init pm_init(void) +{ + int error = subsystem_register(&power_subsys); + if (!error) + error = sysfs_create_group(&power_subsys.kset.kobj,&attr_group); + return error; +} +core_initcall(pm_init); +#else +extern struct subsystem power_subsys; + +static int __init apo_pm_init(void) +{ + return (subsys_create_file(&power_subsys, &auto_poweron_attr)); +} +__initcall(apo_pm_init); +#endif diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index b43f1397a5b..22bc0198974 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -29,8 +29,11 @@ static inline smp_init_pseries_xics(void) { }; extern void setup_kexec_cpu_down_xics(void); extern void setup_kexec_cpu_down_mpic(void); #else -static inline setup_kexec_cpu_down_xics(void) { }; -static inline setup_kexec_cpu_down_mpic(void) { }; +static inline void setup_kexec_cpu_down_xics(void) { } +static inline void setup_kexec_cpu_down_mpic(void) { } #endif +/* Poweron flag used for enabling auto ups restart */ +extern unsigned long rtas_poweron_auto; + #endif /* _PSERIES_PSERIES_H */ diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 435a0459652..34aff47b1f5 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -486,6 +486,34 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus) return PCI_PROBE_NORMAL; } +/** + * pSeries_power_off - tell firmware about how to power off the system. + * + * This function calls either the power-off rtas token in normal cases + * or the ibm,power-off-ups token (if present & requested) in case of + * a power failure. If power-off token is used, power on will only be + * possible with power button press. If ibm,power-off-ups token is used + * it will allow auto poweron after power is restored. + */ +void pSeries_power_off(void) +{ + int rc; + int rtas_poweroff_ups_token = rtas_token("ibm,power-off-ups"); + + if (rtas_flash_term_hook) + rtas_flash_term_hook(SYS_POWER_OFF); + + if (rtas_poweron_auto == 0 || + rtas_poweroff_ups_token == RTAS_UNKNOWN_SERVICE) { + rc = rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1); + printk(KERN_INFO "RTAS power-off returned %d\n", rc); + } else { + rc = rtas_call(rtas_poweroff_ups_token, 0, 1, NULL); + printk(KERN_INFO "RTAS ibm,power-off-ups returned %d\n", rc); + } + for (;;); +} + define_machine(pseries) { .name = "pSeries", .probe = pSeries_probe, @@ -496,7 +524,7 @@ define_machine(pseries) { .pcibios_fixup = pSeries_final_fixup, .pci_probe_mode = pSeries_pci_probe_mode, .restart = rtas_restart, - .power_off = rtas_power_off, + .power_off = pSeries_power_off, .halt = rtas_halt, .panic = rtas_os_term, .get_boot_time = rtas_get_boot_time, diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 85dcdf17841..26ca3ffbc1d 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o obj-$(CONFIG_PPC_MPC106) += grackle.o obj-$(CONFIG_PPC_DCR) += dcr.o obj-$(CONFIG_PPC_DCR_NATIVE) += dcr-low.o +obj-$(CONFIG_PPC_PMI) += pmi.o obj-$(CONFIG_U3_DART) += dart_iommu.o obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o obj-$(CONFIG_FSL_SOC) += fsl_soc.o diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 34161bc5a02..d20f02927f7 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -233,14 +233,7 @@ static int __init gfar_of_init(void) goto err; } - mac_addr = get_property(np, "local-mac-address", NULL); - if (mac_addr == NULL) - mac_addr = get_property(np, "mac-address", NULL); - if (mac_addr == NULL) { - /* Obsolete */ - mac_addr = get_property(np, "address", NULL); - } - + mac_addr = of_get_mac_address(np); if (mac_addr) memcpy(gfar_data.mac_addr, mac_addr, 6); @@ -646,8 +639,9 @@ static int __init fs_enet_of_init(void) goto unreg; } - mac_addr = get_property(np, "mac-address", NULL); - memcpy(fs_enet_data.macaddr, mac_addr, 6); + mac_addr = of_get_mac_address(np); + if (mac_addr) + memcpy(fs_enet_data.macaddr, mac_addr, 6); ph = get_property(np, "phy-handle", NULL); phy = of_find_node_by_phandle(*ph); @@ -931,8 +925,9 @@ static int __init fs_enet_of_init(void) goto err; r[0].name = enet_regs; - mac_addr = (void *)get_property(np, "mac-address", NULL); - memcpy(fs_enet_data.macaddr, mac_addr, 6); + mac_addr = of_get_mac_address(np); + if (mac_addr) + memcpy(fs_enet_data.macaddr, mac_addr, 6); ph = (phandle *) get_property(np, "phy-handle", NULL); if (ph != NULL) diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 4e54a09dd33..bcfb900481f 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1370,7 +1370,7 @@ void mpic_request_ipis(void) printk(KERN_ERR "Failed to map IPI %d\n", i); break; } - request_irq(vipi, mpic_ipi_action, IRQF_DISABLED, + request_irq(vipi, mpic_ipi_action, IRQF_DISABLED|IRQF_PERCPU, ipi_names[i], mpic); } } diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c new file mode 100644 index 00000000000..a5282011d39 --- /dev/null +++ b/arch/powerpc/sysdev/pmi.c @@ -0,0 +1,305 @@ +/* + * pmi driver + * + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * + * PMI (Platform Management Interrupt) is a way to communicate + * with the BMC (Baseboard Management Controller) via interrupts. + * Unlike IPMI it is bidirectional and has a low latency. + * + * Author: Christian Krafft <krafft@de.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/interrupt.h> +#include <linux/completion.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> + +#include <asm/of_device.h> +#include <asm/of_platform.h> +#include <asm/io.h> +#include <asm/pmi.h> + + +struct pmi_data { + struct list_head handler; + spinlock_t handler_spinlock; + spinlock_t pmi_spinlock; + struct mutex msg_mutex; + pmi_message_t msg; + struct completion *completion; + struct of_device *dev; + int irq; + u8 __iomem *pmi_reg; + struct work_struct work; +}; + + + +static void __iomem *of_iomap(struct device_node *np) +{ + struct resource res; + + if (of_address_to_resource(np, 0, &res)) + return NULL; + + pr_debug("Resource start: 0x%lx\n", res.start); + pr_debug("Resource end: 0x%lx\n", res.end); + + return ioremap(res.start, 1 + res.end - res.start); +} + + +static int pmi_irq_handler(int irq, void *dev_id) +{ + struct pmi_data *data; + u8 type; + int rc; + + data = dev_id; + + spin_lock(&data->pmi_spinlock); + + type = ioread8(data->pmi_reg + PMI_READ_TYPE); + pr_debug("pmi: got message of type %d\n", type); + + if (type & PMI_ACK && !data->completion) { + printk(KERN_WARNING "pmi: got unexpected ACK message.\n"); + rc = -EIO; + goto unlock; + } + + if (data->completion && !(type & PMI_ACK)) { + printk(KERN_WARNING "pmi: expected ACK, but got %d\n", type); + rc = -EIO; + goto unlock; + } + + data->msg.type = type; + data->msg.data0 = ioread8(data->pmi_reg + PMI_READ_DATA0); + data->msg.data1 = ioread8(data->pmi_reg + PMI_READ_DATA1); + data->msg.data2 = ioread8(data->pmi_reg + PMI_READ_DATA2); + rc = 0; +unlock: + spin_unlock(&data->pmi_spinlock); + + if (rc == -EIO) { + rc = IRQ_HANDLED; + goto out; + } + + if (data->msg.type & PMI_ACK) { + complete(data->completion); + rc = IRQ_HANDLED; + goto out; + } + + schedule_work(&data->work); + + rc = IRQ_HANDLED; +out: + return rc; +} + + +static struct of_device_id pmi_match[] = { + { .type = "ibm,pmi", .name = "ibm,pmi" }, + {}, +}; + +MODULE_DEVICE_TABLE(of, pmi_match); + +static void pmi_notify_handlers(struct work_struct *work) +{ + struct pmi_data *data; + struct pmi_handler *handler; + + data = container_of(work, struct pmi_data, work); + + spin_lock(&data->handler_spinlock); + list_for_each_entry(handler, &data->handler, node) { + pr_debug(KERN_INFO "pmi: notifying handler %p\n", handler); + if (handler->type == data->msg.type) + handler->handle_pmi_message(data->dev, data->msg); + } + spin_unlock(&data->handler_spinlock); +} + +static int pmi_of_probe(struct of_device *dev, + const struct of_device_id *match) +{ + struct device_node *np = dev->node; + struct pmi_data *data; + int rc; + + data = kzalloc(sizeof(struct pmi_data), GFP_KERNEL); + if (!data) { + printk(KERN_ERR "pmi: could not allocate memory.\n"); + rc = -ENOMEM; + goto out; + } + + data->pmi_reg = of_iomap(np); + if (!data->pmi_reg) { + printk(KERN_ERR "pmi: invalid register address.\n"); + rc = -EFAULT; + goto error_cleanup_data; + } + + INIT_LIST_HEAD(&data->handler); + + mutex_init(&data->msg_mutex); + spin_lock_init(&data->pmi_spinlock); + spin_lock_init(&data->handler_spinlock); + + INIT_WORK(&data->work, pmi_notify_handlers); + + dev->dev.driver_data = data; + data->dev = dev; + + data->irq = irq_of_parse_and_map(np, 0); + if (data->irq == NO_IRQ) { + printk(KERN_ERR "pmi: invalid interrupt.\n"); + rc = -EFAULT; + goto error_cleanup_iomap; + } + + rc = request_irq(data->irq, pmi_irq_handler, 0, "pmi", data); + if (rc) { + printk(KERN_ERR "pmi: can't request IRQ %d: returned %d\n", + data->irq, rc); + goto error_cleanup_iomap; + } + + printk(KERN_INFO "pmi: found pmi device at addr %p.\n", data->pmi_reg); + + goto out; + +error_cleanup_iomap: + iounmap(data->pmi_reg); + +error_cleanup_data: + kfree(data); + +out: + return rc; +} + +static int pmi_of_remove(struct of_device *dev) +{ + struct pmi_data *data; + struct pmi_handler *handler, *tmp; + + data = dev->dev.driver_data; + + free_irq(data->irq, data); + iounmap(data->pmi_reg); + + spin_lock(&data->handler_spinlock); + + list_for_each_entry_safe(handler, tmp, &data->handler, node) + list_del(&handler->node); + + spin_unlock(&data->handler_spinlock); + + kfree(dev->dev.driver_data); + + return 0; +} + +static struct of_platform_driver pmi_of_platform_driver = { + .name = "pmi", + .match_table = pmi_match, + .probe = pmi_of_probe, + .remove = pmi_of_remove +}; + +static int __init pmi_module_init(void) +{ + return of_register_platform_driver(&pmi_of_platform_driver); +} +module_init(pmi_module_init); + +static void __exit pmi_module_exit(void) +{ + of_unregister_platform_driver(&pmi_of_platform_driver); +} +module_exit(pmi_module_exit); + +void pmi_send_message(struct of_device *device, pmi_message_t msg) +{ + struct pmi_data *data; + unsigned long flags; + DECLARE_COMPLETION_ONSTACK(completion); + + data = device->dev.driver_data; + + mutex_lock(&data->msg_mutex); + + data->msg = msg; + pr_debug("pmi_send_message: msg is %08x\n", *(u32*)&msg); + + data->completion = &completion; + + spin_lock_irqsave(&data->pmi_spinlock, flags); + iowrite8(msg.data0, data->pmi_reg + PMI_WRITE_DATA0); + iowrite8(msg.data1, data->pmi_reg + PMI_WRITE_DATA1); + iowrite8(msg.data2, data->pmi_reg + PMI_WRITE_DATA2); + iowrite8(msg.type, data->pmi_reg + PMI_WRITE_TYPE); + spin_unlock_irqrestore(&data->pmi_spinlock, flags); + + pr_debug("pmi_send_message: wait for completion\n"); + + wait_for_completion_interruptible_timeout(data->completion, + PMI_TIMEOUT); + + data->completion = NULL; + + mutex_unlock(&data->msg_mutex); +} +EXPORT_SYMBOL_GPL(pmi_send_message); + +void pmi_register_handler(struct of_device *device, + struct pmi_handler *handler) +{ + struct pmi_data *data; + data = device->dev.driver_data; + + spin_lock(&data->handler_spinlock); + list_add_tail(&handler->node, &data->handler); + spin_unlock(&data->handler_spinlock); +} +EXPORT_SYMBOL_GPL(pmi_register_handler); + +void pmi_unregister_handler(struct of_device *device, + struct pmi_handler *handler) +{ + struct pmi_data *data; + + pr_debug("pmi: unregistering handler %p\n", handler); + + data = device->dev.driver_data; + + spin_lock(&data->handler_spinlock); + list_del(&handler->node); + spin_unlock(&data->handler_spinlock); +} +EXPORT_SYMBOL_GPL(pmi_unregister_handler); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>"); +MODULE_DESCRIPTION("IBM Platform Management Interrupt driver"); diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c index e657559bea9..a457ac1c663 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c @@ -1,13 +1,12 @@ /* - * arch/powerpc/sysdev/qe_lib/ucc_fast.c - * - * QE UCC Fast API Set - UCC Fast specific routines implementations. - * * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. * * Authors: Shlomi Gridish <gridish@freescale.com> * Li Yang <leoli@freescale.com> * + * Description: + * QE UCC Fast API Set - UCC Fast specific routines implementations. + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -27,79 +26,61 @@ #include <asm/ucc.h> #include <asm/ucc_fast.h> -#define uccf_printk(level, format, arg...) \ - printk(level format "\n", ## arg) - -#define uccf_dbg(format, arg...) \ - uccf_printk(KERN_DEBUG , format , ## arg) -#define uccf_err(format, arg...) \ - uccf_printk(KERN_ERR , format , ## arg) -#define uccf_info(format, arg...) \ - uccf_printk(KERN_INFO , format , ## arg) -#define uccf_warn(format, arg...) \ - uccf_printk(KERN_WARNING , format , ## arg) - -#ifdef UCCF_VERBOSE_DEBUG -#define uccf_vdbg uccf_dbg -#else -#define uccf_vdbg(fmt, args...) do { } while (0) -#endif /* UCCF_VERBOSE_DEBUG */ - void ucc_fast_dump_regs(struct ucc_fast_private * uccf) { - uccf_info("UCC%d Fast registers:", uccf->uf_info->ucc_num); - uccf_info("Base address: 0x%08x", (u32) uccf->uf_regs); + printk(KERN_INFO "UCC%d Fast registers:", uccf->uf_info->ucc_num); + printk(KERN_INFO "Base address: 0x%08x", (u32) uccf->uf_regs); - uccf_info("gumr : addr - 0x%08x, val - 0x%08x", + printk(KERN_INFO "gumr : addr - 0x%08x, val - 0x%08x", (u32) & uccf->uf_regs->gumr, in_be32(&uccf->uf_regs->gumr)); - uccf_info("upsmr : addr - 0x%08x, val - 0x%08x", + printk(KERN_INFO "upsmr : addr - 0x%08x, val - 0x%08x", (u32) & uccf->uf_regs->upsmr, in_be32(&uccf->uf_regs->upsmr)); - uccf_info("utodr : addr - 0x%08x, val - 0x%04x", + printk(KERN_INFO "utodr : addr - 0x%08x, val - 0x%04x", (u32) & uccf->uf_regs->utodr, in_be16(&uccf->uf_regs->utodr)); - uccf_info("udsr : addr - 0x%08x, val - 0x%04x", + printk(KERN_INFO "udsr : addr - 0x%08x, val - 0x%04x", (u32) & uccf->uf_regs->udsr, in_be16(&uccf->uf_regs->udsr)); - uccf_info("ucce : addr - 0x%08x, val - 0x%08x", + printk(KERN_INFO "ucce : addr - 0x%08x, val - 0x%08x", (u32) & uccf->uf_regs->ucce, in_be32(&uccf->uf_regs->ucce)); - uccf_info("uccm : addr - 0x%08x, val - 0x%08x", + printk(KERN_INFO "uccm : addr - 0x%08x, val - 0x%08x", (u32) & uccf->uf_regs->uccm, in_be32(&uccf->uf_regs->uccm)); - uccf_info("uccs : addr - 0x%08x, val - 0x%02x", + printk(KERN_INFO "uccs : addr - 0x%08x, val - 0x%02x", (u32) & uccf->uf_regs->uccs, uccf->uf_regs->uccs); - uccf_info("urfb : addr - 0x%08x, val - 0x%08x", + printk(KERN_INFO "urfb : addr - 0x%08x, val - 0x%08x", (u32) & uccf->uf_regs->urfb, in_be32(&uccf->uf_regs->urfb)); - uccf_info("urfs : addr - 0x%08x, val - 0x%04x", + printk(KERN_INFO "urfs : addr - 0x%08x, val - 0x%04x", (u32) & uccf->uf_regs->urfs, in_be16(&uccf->uf_regs->urfs)); - uccf_info("urfet : addr - 0x%08x, val - 0x%04x", + printk(KERN_INFO "urfet : addr - 0x%08x, val - 0x%04x", (u32) & uccf->uf_regs->urfet, in_be16(&uccf->uf_regs->urfet)); - uccf_info("urfset: addr - 0x%08x, val - 0x%04x", + printk(KERN_INFO "urfset: addr - 0x%08x, val - 0x%04x", (u32) & uccf->uf_regs->urfset, in_be16(&uccf->uf_regs->urfset)); - uccf_info("utfb : addr - 0x%08x, val - 0x%08x", + printk(KERN_INFO "utfb : addr - 0x%08x, val - 0x%08x", (u32) & uccf->uf_regs->utfb, in_be32(&uccf->uf_regs->utfb)); - uccf_info("utfs : addr - 0x%08x, val - 0x%04x", + printk(KERN_INFO "utfs : addr - 0x%08x, val - 0x%04x", (u32) & uccf->uf_regs->utfs, in_be16(&uccf->uf_regs->utfs)); - uccf_info("utfet : addr - 0x%08x, val - 0x%04x", + printk(KERN_INFO "utfet : addr - 0x%08x, val - 0x%04x", (u32) & uccf->uf_regs->utfet, in_be16(&uccf->uf_regs->utfet)); - uccf_info("utftt : addr - 0x%08x, val - 0x%04x", + printk(KERN_INFO "utftt : addr - 0x%08x, val - 0x%04x", (u32) & uccf->uf_regs->utftt, in_be16(&uccf->uf_regs->utftt)); - uccf_info("utpt : addr - 0x%08x, val - 0x%04x", + printk(KERN_INFO "utpt : addr - 0x%08x, val - 0x%04x", (u32) & uccf->uf_regs->utpt, in_be16(&uccf->uf_regs->utpt)); - uccf_info("urtry : addr - 0x%08x, val - 0x%08x", + printk(KERN_INFO "urtry : addr - 0x%08x, val - 0x%08x", (u32) & uccf->uf_regs->urtry, in_be32(&uccf->uf_regs->urtry)); - uccf_info("guemr : addr - 0x%08x, val - 0x%02x", + printk(KERN_INFO "guemr : addr - 0x%08x, val - 0x%02x", (u32) & uccf->uf_regs->guemr, uccf->uf_regs->guemr); } u32 ucc_fast_get_qe_cr_subblock(int uccf_num) { switch (uccf_num) { - case 0: return QE_CR_SUBBLOCK_UCCFAST1; + case 0: return QE_CR_SUBBLOCK_UCCFAST1; case 1: return QE_CR_SUBBLOCK_UCCFAST2; case 2: return QE_CR_SUBBLOCK_UCCFAST3; case 3: return QE_CR_SUBBLOCK_UCCFAST4; case 4: return QE_CR_SUBBLOCK_UCCFAST5; case 5: return QE_CR_SUBBLOCK_UCCFAST6; case 6: return QE_CR_SUBBLOCK_UCCFAST7; - case 7: return QE_CR_SUBBLOCK_UCCFAST8; + case 7: return QE_CR_SUBBLOCK_UCCFAST8; default: return QE_CR_SUBBLOCK_INVALID; } } @@ -153,84 +134,72 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc { struct ucc_fast_private *uccf; struct ucc_fast *uf_regs; - u32 gumr = 0; + u32 gumr; int ret; - uccf_vdbg("%s: IN", __FUNCTION__); - if (!uf_info) return -EINVAL; /* check if the UCC port number is in range. */ if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM - 1)) { - uccf_err("ucc_fast_init: Illegal UCC number!"); + printk(KERN_ERR "%s: illegal UCC number", __FUNCTION__); return -EINVAL; } /* Check that 'max_rx_buf_length' is properly aligned (4). */ if (uf_info->max_rx_buf_length & (UCC_FAST_MRBLR_ALIGNMENT - 1)) { - uccf_err("ucc_fast_init: max_rx_buf_length not aligned."); + printk(KERN_ERR "%s: max_rx_buf_length not aligned", __FUNCTION__); return -EINVAL; } /* Validate Virtual Fifo register values */ if (uf_info->urfs < UCC_FAST_URFS_MIN_VAL) { - uccf_err - ("ucc_fast_init: Virtual Fifo register urfs too small."); + printk(KERN_ERR "%s: urfs is too small", __FUNCTION__); return -EINVAL; } if (uf_info->urfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - uccf_err - ("ucc_fast_init: Virtual Fifo register urfs not aligned."); + printk(KERN_ERR "%s: urfs is not aligned", __FUNCTION__); return -EINVAL; } if (uf_info->urfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - uccf_err - ("ucc_fast_init: Virtual Fifo register urfet not aligned."); + printk(KERN_ERR "%s: urfet is not aligned.", __FUNCTION__); return -EINVAL; } if (uf_info->urfset & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - uccf_err - ("ucc_fast_init: Virtual Fifo register urfset not aligned."); + printk(KERN_ERR "%s: urfset is not aligned", __FUNCTION__); return -EINVAL; } if (uf_info->utfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - uccf_err - ("ucc_fast_init: Virtual Fifo register utfs not aligned."); + printk(KERN_ERR "%s: utfs is not aligned", __FUNCTION__); return -EINVAL; } if (uf_info->utfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - uccf_err - ("ucc_fast_init: Virtual Fifo register utfet not aligned."); + printk(KERN_ERR "%s: utfet is not aligned", __FUNCTION__); return -EINVAL; } if (uf_info->utftt & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - uccf_err - ("ucc_fast_init: Virtual Fifo register utftt not aligned."); + printk(KERN_ERR "%s: utftt is not aligned", __FUNCTION__); return -EINVAL; } uccf = kzalloc(sizeof(struct ucc_fast_private), GFP_KERNEL); if (!uccf) { - uccf_err - ("ucc_fast_init: No memory for UCC slow data structure!"); + printk(KERN_ERR "%s: Cannot allocate private data", __FUNCTION__); return -ENOMEM; } /* Fill fast UCC structure */ uccf->uf_info = uf_info; /* Set the PHY base address */ - uccf->uf_regs = - (struct ucc_fast *) ioremap(uf_info->regs, sizeof(struct ucc_fast)); + uccf->uf_regs = ioremap(uf_info->regs, sizeof(struct ucc_fast)); if (uccf->uf_regs == NULL) { - uccf_err - ("ucc_fast_init: No memory map for UCC slow controller!"); + printk(KERN_ERR "%s: Cannot map UCC registers", __FUNCTION__); return -ENOMEM; } @@ -249,7 +218,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc /* Init Guemr register */ if ((ret = ucc_init_guemr((struct ucc_common *) (uf_regs)))) { - uccf_err("ucc_fast_init: Could not init the guemr register."); + printk(KERN_ERR "%s: cannot init GUEMR", __FUNCTION__); ucc_fast_free(uccf); return ret; } @@ -258,7 +227,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc if ((ret = ucc_set_type(uf_info->ucc_num, (struct ucc_common *) (uf_regs), UCC_SPEED_TYPE_FAST))) { - uccf_err("ucc_fast_init: Could not set type to fast."); + printk(KERN_ERR "%s: cannot set UCC type", __FUNCTION__); ucc_fast_free(uccf); return ret; } @@ -267,10 +236,9 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc /* Set GUMR */ /* For more details see the hardware spec. */ - /* gumr starts as zero. */ + gumr = uf_info->ttx_trx; if (uf_info->tci) gumr |= UCC_FAST_GUMR_TCI; - gumr |= uf_info->ttx_trx; if (uf_info->cdp) gumr |= UCC_FAST_GUMR_CDP; if (uf_info->ctsp) @@ -298,9 +266,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc uccf->ucc_fast_tx_virtual_fifo_base_offset = qe_muram_alloc(uf_info->utfs, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); if (IS_MURAM_ERR(uccf->ucc_fast_tx_virtual_fifo_base_offset)) { - uccf_err - ("ucc_fast_init: Can not allocate MURAM memory for " - "struct ucc_fastx_virtual_fifo_base_offset."); + printk(KERN_ERR "%s: cannot allocate MURAM for TX FIFO", __FUNCTION__); uccf->ucc_fast_tx_virtual_fifo_base_offset = 0; ucc_fast_free(uccf); return -ENOMEM; @@ -308,14 +274,11 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc /* Allocate memory for Rx Virtual Fifo */ uccf->ucc_fast_rx_virtual_fifo_base_offset = - qe_muram_alloc(uf_info->urfs + - (u32) + qe_muram_alloc(uf_info->urfs + UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); if (IS_MURAM_ERR(uccf->ucc_fast_rx_virtual_fifo_base_offset)) { - uccf_err - ("ucc_fast_init: Can not allocate MURAM memory for " - "ucc_fast_rx_virtual_fifo_base_offset."); + printk(KERN_ERR "%s: cannot allocate MURAM for RX FIFO", __FUNCTION__); uccf->ucc_fast_rx_virtual_fifo_base_offset = 0; ucc_fast_free(uccf); return -ENOMEM; @@ -342,26 +305,22 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc /* If NMSI (not Tsa), set Tx and Rx clock. */ if (!uf_info->tsa) { /* Rx clock routing */ - if (uf_info->rx_clock != QE_CLK_NONE) { - if (ucc_set_qe_mux_rxtx - (uf_info->ucc_num, uf_info->rx_clock, - COMM_DIR_RX)) { - uccf_err - ("ucc_fast_init: Illegal value for parameter 'RxClock'."); - ucc_fast_free(uccf); - return -EINVAL; - } + if ((uf_info->rx_clock != QE_CLK_NONE) && + ucc_set_qe_mux_rxtx(uf_info->ucc_num, uf_info->rx_clock, + COMM_DIR_RX)) { + printk(KERN_ERR "%s: illegal value for RX clock", + __FUNCTION__); + ucc_fast_free(uccf); + return -EINVAL; } /* Tx clock routing */ - if (uf_info->tx_clock != QE_CLK_NONE) { - if (ucc_set_qe_mux_rxtx - (uf_info->ucc_num, uf_info->tx_clock, - COMM_DIR_TX)) { - uccf_err - ("ucc_fast_init: Illegal value for parameter 'TxClock'."); - ucc_fast_free(uccf); - return -EINVAL; - } + if ((uf_info->tx_clock != QE_CLK_NONE) && + ucc_set_qe_mux_rxtx(uf_info->ucc_num, uf_info->tx_clock, + COMM_DIR_TX)) { + printk(KERN_ERR "%s: illegal value for TX clock", + __FUNCTION__); + ucc_fast_free(uccf); + return -EINVAL; } } @@ -370,9 +329,9 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc /* First, clear anything pending at UCC level, * otherwise, old garbage may come through - * as soon as the dam is opened - * Writing '1' clears - */ + * as soon as the dam is opened. */ + + /* Writing '1' clears */ out_be32(&uf_regs->ucce, 0xffffffff); *uccf_ret = uccf; diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c index 0e97e5c94f8..817df73ecf5 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c @@ -19,7 +19,6 @@ #include <linux/stddef.h> #include <linux/interrupt.h> -#include <asm/irq.h> #include <asm/io.h> #include <asm/immap_qe.h> #include <asm/qe.h> @@ -27,24 +26,6 @@ #include <asm/ucc.h> #include <asm/ucc_slow.h> -#define uccs_printk(level, format, arg...) \ - printk(level format "\n", ## arg) - -#define uccs_dbg(format, arg...) \ - uccs_printk(KERN_DEBUG , format , ## arg) -#define uccs_err(format, arg...) \ - uccs_printk(KERN_ERR , format , ## arg) -#define uccs_info(format, arg...) \ - uccs_printk(KERN_INFO , format , ## arg) -#define uccs_warn(format, arg...) \ - uccs_printk(KERN_WARNING , format , ## arg) - -#ifdef UCCS_VERBOSE_DEBUG -#define uccs_vdbg uccs_dbg -#else -#define uccs_vdbg(fmt, args...) do { } while (0) -#endif /* UCCS_VERBOSE_DEBUG */ - u32 ucc_slow_get_qe_cr_subblock(int uccs_num) { switch (uccs_num) { @@ -135,51 +116,53 @@ void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode) int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret) { + struct ucc_slow_private *uccs; u32 i; struct ucc_slow *us_regs; u32 gumr; - u8 function_code = 0; - u8 *bd; - struct ucc_slow_private *uccs; + struct qe_bd *bd; u32 id; u32 command; - int ret; - - uccs_vdbg("%s: IN", __FUNCTION__); + int ret = 0; if (!us_info) return -EINVAL; /* check if the UCC port number is in range. */ if ((us_info->ucc_num < 0) || (us_info->ucc_num > UCC_MAX_NUM - 1)) { - uccs_err("ucc_slow_init: Illegal UCC number!"); + printk(KERN_ERR "%s: illegal UCC number", __FUNCTION__); return -EINVAL; } /* * Set mrblr * Check that 'max_rx_buf_length' is properly aligned (4), unless - * rfw is 1, meaning that QE accepts one byte at a time, unlike normal + * rfw is 1, meaning that QE accepts one byte at a time, unlike normal * case when QE accepts 32 bits at a time. */ if ((!us_info->rfw) && (us_info->max_rx_buf_length & (UCC_SLOW_MRBLR_ALIGNMENT - 1))) { - uccs_err("max_rx_buf_length not aligned."); + printk(KERN_ERR "max_rx_buf_length not aligned."); return -EINVAL; } uccs = kzalloc(sizeof(struct ucc_slow_private), GFP_KERNEL); if (!uccs) { - uccs_err - ("ucc_slow_init: No memory for UCC slow data structure!"); + printk(KERN_ERR "%s: Cannot allocate private data", __FUNCTION__); return -ENOMEM; } /* Fill slow UCC structure */ uccs->us_info = us_info; + /* Set the PHY base address */ + uccs->us_regs = ioremap(us_info->regs, sizeof(struct ucc_slow)); + if (uccs->us_regs == NULL) { + printk(KERN_ERR "%s: Cannot map UCC registers", __FUNCTION__); + return -ENOMEM; + } + uccs->saved_uccm = 0; uccs->p_rx_frame = 0; - uccs->us_regs = us_info->regs; us_regs = uccs->us_regs; uccs->p_ucce = (u16 *) & (us_regs->ucce); uccs->p_uccm = (u16 *) & (us_regs->uccm); @@ -190,24 +173,22 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc #endif /* STATISTICS */ /* Get PRAM base */ - uccs->us_pram_offset = qe_muram_alloc(UCC_SLOW_PRAM_SIZE, - ALIGNMENT_OF_UCC_SLOW_PRAM); + uccs->us_pram_offset = + qe_muram_alloc(UCC_SLOW_PRAM_SIZE, ALIGNMENT_OF_UCC_SLOW_PRAM); if (IS_MURAM_ERR(uccs->us_pram_offset)) { - uccs_err - ("ucc_slow_init: Can not allocate MURAM memory " - "for Slow UCC."); + printk(KERN_ERR "%s: cannot allocate MURAM for PRAM", __FUNCTION__); ucc_slow_free(uccs); return -ENOMEM; } id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, id, QE_CR_PROTOCOL_UNSPECIFIED, - (u32) uccs->us_pram_offset); + uccs->us_pram_offset); uccs->us_pram = qe_muram_addr(uccs->us_pram_offset); /* Init Guemr register */ if ((ret = ucc_init_guemr((struct ucc_common *) (us_info->regs)))) { - uccs_err("ucc_slow_init: Could not init the guemr register."); + printk(KERN_ERR "%s: cannot init GUEMR", __FUNCTION__); ucc_slow_free(uccs); return ret; } @@ -216,7 +197,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc if ((ret = ucc_set_type(us_info->ucc_num, (struct ucc_common *) (us_info->regs), UCC_SPEED_TYPE_SLOW))) { - uccs_err("ucc_slow_init: Could not init the guemr register."); + printk(KERN_ERR "%s: cannot set UCC type", __FUNCTION__); ucc_slow_free(uccs); return ret; } @@ -230,7 +211,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc qe_muram_alloc(us_info->rx_bd_ring_len * sizeof(struct qe_bd), QE_ALIGNMENT_OF_BD); if (IS_MURAM_ERR(uccs->rx_base_offset)) { - uccs_err("ucc_slow_init: No memory for Rx BD's."); + printk(KERN_ERR "%s: cannot allocate RX BDs", __FUNCTION__); uccs->rx_base_offset = 0; ucc_slow_free(uccs); return -ENOMEM; @@ -240,7 +221,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc qe_muram_alloc(us_info->tx_bd_ring_len * sizeof(struct qe_bd), QE_ALIGNMENT_OF_BD); if (IS_MURAM_ERR(uccs->tx_base_offset)) { - uccs_err("ucc_slow_init: No memory for Tx BD's."); + printk(KERN_ERR "%s: cannot allocate TX BDs", __FUNCTION__); uccs->tx_base_offset = 0; ucc_slow_free(uccs); return -ENOMEM; @@ -248,34 +229,33 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* Init Tx bds */ bd = uccs->confBd = uccs->tx_bd = qe_muram_addr(uccs->tx_base_offset); - for (i = 0; i < us_info->tx_bd_ring_len; i++) { + for (i = 0; i < us_info->tx_bd_ring_len - 1; i++) { /* clear bd buffer */ - out_be32(&(((struct qe_bd *)bd)->buf), 0); + out_be32(&bd->buf, 0); /* set bd status and length */ - out_be32((u32*)bd, 0); - bd += sizeof(struct qe_bd); + out_be32((u32 *) bd, 0); + bd++; } - bd -= sizeof(struct qe_bd); - /* set bd status and length */ - out_be32((u32*)bd, T_W); /* for last BD set Wrap bit */ + /* for last BD set Wrap bit */ + out_be32(&bd->buf, 0); + out_be32((u32 *) bd, cpu_to_be32(T_W)); /* Init Rx bds */ bd = uccs->rx_bd = qe_muram_addr(uccs->rx_base_offset); - for (i = 0; i < us_info->rx_bd_ring_len; i++) { + for (i = 0; i < us_info->rx_bd_ring_len - 1; i++) { /* set bd status and length */ out_be32((u32*)bd, 0); /* clear bd buffer */ - out_be32(&(((struct qe_bd *)bd)->buf), 0); - bd += sizeof(struct qe_bd); + out_be32(&bd->buf, 0); + bd++; } - bd -= sizeof(struct qe_bd); - /* set bd status and length */ - out_be32((u32*)bd, R_W); /* for last BD set Wrap bit */ + /* for last BD set Wrap bit */ + out_be32((u32*)bd, cpu_to_be32(R_W)); + out_be32(&bd->buf, 0); /* Set GUMR (For more details see the hardware spec.). */ /* gumr_h */ - gumr = 0; - gumr |= us_info->tcrc; + gumr = us_info->tcrc; if (us_info->cdp) gumr |= UCC_SLOW_GUMR_H_CDP; if (us_info->ctsp) @@ -295,7 +275,8 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc out_be32(&us_regs->gumr_h, gumr); /* gumr_l */ - gumr = 0; + gumr = us_info->tdcr | us_info->rdcr | us_info->tenc | us_info->renc | + us_info->diag | us_info->mode; if (us_info->tci) gumr |= UCC_SLOW_GUMR_L_TCI; if (us_info->rinv) @@ -304,23 +285,14 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc gumr |= UCC_SLOW_GUMR_L_TINV; if (us_info->tend) gumr |= UCC_SLOW_GUMR_L_TEND; - gumr |= us_info->tdcr; - gumr |= us_info->rdcr; - gumr |= us_info->tenc; - gumr |= us_info->renc; - gumr |= us_info->diag; - gumr |= us_info->mode; out_be32(&us_regs->gumr_l, gumr); /* Function code registers */ - /* function_code has initial value 0 */ /* if the data is in cachable memory, the 'global' */ /* in the function code should be set. */ - function_code |= us_info->data_mem_part; - function_code |= QE_BMR_BYTE_ORDER_BO_MOT; /* Required for QE */ - uccs->us_pram->tfcr = function_code; - uccs->us_pram->rfcr = function_code; + uccs->us_pram->tfcr = uccs->us_pram->rfcr = + us_info->data_mem_part | QE_BMR_BYTE_ORDER_BO_MOT; /* rbase, tbase are offsets from MURAM base */ out_be16(&uccs->us_pram->rbase, uccs->us_pram_offset); @@ -336,34 +308,29 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* If NMSI (not Tsa), set Tx and Rx clock. */ if (!us_info->tsa) { /* Rx clock routing */ - if (ucc_set_qe_mux_rxtx - (us_info->ucc_num, us_info->rx_clock, COMM_DIR_RX)) { - uccs_err - ("ucc_slow_init: Illegal value for parameter" - " 'RxClock'."); + if (ucc_set_qe_mux_rxtx(us_info->ucc_num, us_info->rx_clock, + COMM_DIR_RX)) { + printk(KERN_ERR "%s: illegal value for RX clock", + __FUNCTION__); ucc_slow_free(uccs); return -EINVAL; } /* Tx clock routing */ - if (ucc_set_qe_mux_rxtx(us_info->ucc_num, - us_info->tx_clock, COMM_DIR_TX)) { - uccs_err - ("ucc_slow_init: Illegal value for parameter " - "'TxClock'."); + if (ucc_set_qe_mux_rxtx(us_info->ucc_num, us_info->tx_clock, + COMM_DIR_TX)) { + printk(KERN_ERR "%s: illegal value for TX clock", + __FUNCTION__); ucc_slow_free(uccs); return -EINVAL; } } - /* - * INTERRUPTS - */ /* Set interrupt mask register at UCC level. */ out_be16(&us_regs->uccm, us_info->uccm_mask); - /* First, clear anything pending at UCC level, */ - /* otherwise, old garbage may come through */ - /* as soon as the dam is opened. */ + /* First, clear anything pending at UCC level, + * otherwise, old garbage may come through + * as soon as the dam is opened. */ /* Writing '1' clears */ out_be16(&us_regs->ucce, 0xffff); @@ -400,3 +367,5 @@ void ucc_slow_free(struct ucc_slow_private * uccs) kfree(uccs); } + + diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c index bd30d138113..8047ea8c2ab 100644 --- a/arch/x86_64/kernel/early-quirks.c +++ b/arch/x86_64/kernel/early-quirks.c @@ -53,7 +53,9 @@ static void nvidia_bugs(void) return; nvidia_hpet_detected = 0; - acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check); + if (acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check)) + return; + if (nvidia_hpet_detected == 0) { acpi_skip_timer_override = 1; printk(KERN_INFO "Nvidia board " diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 20eacc2c9e0..e942ffe8b57 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -13,6 +13,7 @@ config ACPI depends on IA64 || X86 depends on PCI depends on PM + select PNP default y ---help--- Advanced Configuration and Power Interface (ACPI) support for @@ -132,15 +133,6 @@ config ACPI_VIDEO Note that this is an ref. implementation only. It may or may not work for your integrated video device. -config ACPI_HOTKEY - tristate "Generic Hotkey (EXPERIMENTAL)" - depends on EXPERIMENTAL - depends on X86 - default n - help - Experimental consolidated hotkey driver. - If you are unsure, say N. - config ACPI_FAN tristate "Fan" default y diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 856c32bccac..5956e9f64a8 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -46,7 +46,6 @@ obj-$(CONFIG_ACPI_FAN) += fan.o obj-$(CONFIG_ACPI_DOCK) += dock.o obj-$(CONFIG_ACPI_BAY) += bay.o obj-$(CONFIG_ACPI_VIDEO) += video.o -obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o obj-$(CONFIG_ACPI_POWER) += power.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 6daeace796a..37c7dc4f9fe 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -35,7 +35,6 @@ #define ACPI_AC_COMPONENT 0x00020000 #define ACPI_AC_CLASS "ac_adapter" #define ACPI_AC_HID "ACPI0003" -#define ACPI_AC_DRIVER_NAME "ACPI AC Adapter Driver" #define ACPI_AC_DEVICE_NAME "AC Adapter" #define ACPI_AC_FILE_STATE "state" #define ACPI_AC_NOTIFY_STATUS 0x80 @@ -44,10 +43,10 @@ #define ACPI_AC_STATUS_UNKNOWN 0xFF #define _COMPONENT ACPI_AC_COMPONENT -ACPI_MODULE_NAME("acpi_ac") +ACPI_MODULE_NAME("ac"); - MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME); +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION("ACPI AC Adapter Driver"); MODULE_LICENSE("GPL"); extern struct proc_dir_entry *acpi_lock_ac_dir(void); @@ -58,7 +57,7 @@ static int acpi_ac_remove(struct acpi_device *device, int type); static int acpi_ac_open_fs(struct inode *inode, struct file *file); static struct acpi_driver acpi_ac_driver = { - .name = ACPI_AC_DRIVER_NAME, + .name = "ac", .class = ACPI_AC_CLASS, .ids = ACPI_AC_HID, .ops = { diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index cd946ed192d..c26172671fd 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -35,14 +35,13 @@ #define ACPI_MEMORY_DEVICE_COMPONENT 0x08000000UL #define ACPI_MEMORY_DEVICE_CLASS "memory" #define ACPI_MEMORY_DEVICE_HID "PNP0C80" -#define ACPI_MEMORY_DEVICE_DRIVER_NAME "Hotplug Mem Driver" #define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device" #define _COMPONENT ACPI_MEMORY_DEVICE_COMPONENT -ACPI_MODULE_NAME("acpi_memory") - MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>"); -MODULE_DESCRIPTION(ACPI_MEMORY_DEVICE_DRIVER_NAME); +ACPI_MODULE_NAME("acpi_memhotplug"); +MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>"); +MODULE_DESCRIPTION("Hotplug Mem Driver"); MODULE_LICENSE("GPL"); /* ACPI _STA method values */ @@ -60,7 +59,7 @@ static int acpi_memory_device_remove(struct acpi_device *device, int type); static int acpi_memory_device_start(struct acpi_device *device); static struct acpi_driver acpi_memory_device_driver = { - .name = ACPI_MEMORY_DEVICE_DRIVER_NAME, + .name = "acpi_memhotplug", .class = ACPI_MEMORY_DEVICE_CLASS, .ids = ACPI_MEMORY_DEVICE_HID, .ops = { diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index 31ad70a6e22..772299fb5f9 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -141,6 +141,7 @@ struct asus_hotk { W5A, //W5A W3V, //W3030V xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N + A4S, //Z81sp //(Centrino) END_MODEL } model; //Models currently supported @@ -397,7 +398,16 @@ static struct model_data model_conf[END_MODEL] = { .brightness_set = "SPLV", .brightness_get = "GPLV", .display_set = "SDSP", - .display_get = "\\ADVG"} + .display_get = "\\ADVG"}, + + { + .name = "A4S", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .mt_bt_switch = "BLED", + .mt_wled = "WLED" + } + }; /* procdir we use */ @@ -421,7 +431,7 @@ static struct asus_hotk *hotk; static int asus_hotk_add(struct acpi_device *device); static int asus_hotk_remove(struct acpi_device *device, int type); static struct acpi_driver asus_hotk_driver = { - .name = ACPI_HOTK_NAME, + .name = "asus_acpi", .class = ACPI_HOTK_CLASS, .ids = ACPI_HOTK_HID, .ops = { @@ -1117,6 +1127,8 @@ static int asus_model_match(char *model) return W3V; else if (strncmp(model, "W5A", 3) == 0) return W5A; + else if (strncmp(model, "A4S", 3) == 0) + return A4S; else return END_MODEL; } @@ -1365,10 +1377,6 @@ static int __init asus_acpi_init(void) if (acpi_disabled) return -ENODEV; - if (!acpi_specific_hotkey_enabled) { - printk(KERN_ERR "Using generic hotkey driver\n"); - return -ENODEV; - } asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); if (!asus_proc_dir) { printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 2f4521a48fe..e64c76c8b72 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -42,7 +42,6 @@ #define ACPI_BATTERY_COMPONENT 0x00040000 #define ACPI_BATTERY_CLASS "battery" #define ACPI_BATTERY_HID "PNP0C0A" -#define ACPI_BATTERY_DRIVER_NAME "ACPI Battery Driver" #define ACPI_BATTERY_DEVICE_NAME "Battery" #define ACPI_BATTERY_FILE_INFO "info" #define ACPI_BATTERY_FILE_STATUS "state" @@ -53,10 +52,10 @@ #define ACPI_BATTERY_UNITS_AMPS "mA" #define _COMPONENT ACPI_BATTERY_COMPONENT -ACPI_MODULE_NAME("acpi_battery") +ACPI_MODULE_NAME("battery"); - MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME); +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION("ACPI Battery Driver"); MODULE_LICENSE("GPL"); extern struct proc_dir_entry *acpi_lock_battery_dir(void); @@ -67,7 +66,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type); static int acpi_battery_resume(struct acpi_device *device); static struct acpi_driver acpi_battery_driver = { - .name = ACPI_BATTERY_DRIVER_NAME, + .name = "battery", .class = ACPI_BATTERY_CLASS, .ids = ACPI_BATTERY_HID, .ops = { @@ -324,6 +323,13 @@ static int acpi_battery_check(struct acpi_battery *battery) return result; } +static void acpi_battery_check_present(struct acpi_battery *battery) +{ + if (!battery->flags.present) { + acpi_battery_check(battery); + } +} + /* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ @@ -340,6 +346,8 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset) if (!battery) goto end; + acpi_battery_check_present(battery); + if (battery->flags.present) seq_printf(seq, "present: yes\n"); else { @@ -424,6 +432,8 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) if (!battery) goto end; + acpi_battery_check_present(battery); + if (battery->flags.present) seq_printf(seq, "present: yes\n"); else { @@ -499,6 +509,8 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) if (!battery) goto end; + acpi_battery_check_present(battery); + if (!battery->flags.present) { seq_printf(seq, "present: no\n"); goto end; @@ -536,6 +548,8 @@ acpi_battery_write_alarm(struct file *file, if (!battery || (count > sizeof(alarm_string) - 1)) return -EINVAL; + acpi_battery_check_present(battery); + if (!battery->flags.present) return -ENODEV; diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c index 91082ce6f5d..fb3f31b5e69 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c @@ -32,11 +32,9 @@ #include <asm/uaccess.h> #include <linux/platform_device.h> -#define ACPI_BAY_DRIVER_NAME "ACPI Removable Drive Bay Driver" - -ACPI_MODULE_NAME("bay") +ACPI_MODULE_NAME("bay"); MODULE_AUTHOR("Kristen Carlson Accardi"); -MODULE_DESCRIPTION(ACPI_BAY_DRIVER_NAME); +MODULE_DESCRIPTION("ACPI Removable Drive Bay Driver"); MODULE_LICENSE("GPL"); #define ACPI_BAY_CLASS "bay" #define ACPI_BAY_COMPONENT 0x10000000 @@ -47,18 +45,6 @@ MODULE_LICENSE("GPL"); acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\ printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); } static void bay_notify(acpi_handle handle, u32 event, void *data); -static int acpi_bay_add(struct acpi_device *device); -static int acpi_bay_remove(struct acpi_device *device, int type); - -static struct acpi_driver acpi_bay_driver = { - .name = ACPI_BAY_DRIVER_NAME, - .class = ACPI_BAY_CLASS, - .ids = ACPI_BAY_HID, - .ops = { - .add = acpi_bay_add, - .remove = acpi_bay_remove, - }, -}; struct bay { acpi_handle handle; @@ -234,14 +220,6 @@ int eject_removable_drive(struct device *dev) } EXPORT_SYMBOL_GPL(eject_removable_drive); -static int acpi_bay_add(struct acpi_device *device) -{ - bay_dprintk(device->handle, "adding bay device"); - strcpy(acpi_device_name(device), "Dockable Bay"); - strcpy(acpi_device_class(device), "bay"); - return 0; -} - static int acpi_bay_add_fs(struct bay *bay) { int ret; @@ -303,7 +281,7 @@ static int bay_add(acpi_handle handle, int id) /* initialize platform device stuff */ pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0); - if (pdev == NULL) { + if (IS_ERR(pdev)) { printk(KERN_ERR PREFIX "Error registering bay device\n"); goto bay_add_err; } @@ -339,52 +317,6 @@ bay_add_err: return -ENODEV; } -static int acpi_bay_remove(struct acpi_device *device, int type) -{ - /*** FIXME: do something here */ - return 0; -} - -/** - * bay_create_acpi_device - add new devices to acpi - * @handle - handle of the device to add - * - * This function will create a new acpi_device for the given - * handle if one does not exist already. This should cause - * acpi to scan for drivers for the given devices, and call - * matching driver's add routine. - * - * Returns a pointer to the acpi_device corresponding to the handle. - */ -static struct acpi_device * bay_create_acpi_device(acpi_handle handle) -{ - struct acpi_device *device = NULL; - struct acpi_device *parent_device; - acpi_handle parent; - int ret; - - bay_dprintk(handle, "Trying to get device"); - if (acpi_bus_get_device(handle, &device)) { - /* - * no device created for this object, - * so we should create one. - */ - bay_dprintk(handle, "No device for handle"); - acpi_get_parent(handle, &parent); - if (acpi_bus_get_device(parent, &parent_device)) - parent_device = NULL; - - ret = acpi_bus_add(&device, parent_device, handle, - ACPI_BUS_TYPE_DEVICE); - if (ret) { - pr_debug("error adding bus, %x\n", - -ret); - return NULL; - } - } - return device; -} - /** * bay_notify - act upon an acpi bay notification * @handle: the bay handle @@ -394,38 +326,19 @@ static struct acpi_device * bay_create_acpi_device(acpi_handle handle) */ static void bay_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_device *dev; + struct bay *bay_dev = (struct bay *)data; + struct device *dev = &bay_dev->pdev->dev; bay_dprintk(handle, "Bay event"); switch(event) { case ACPI_NOTIFY_BUS_CHECK: - printk("Bus Check\n"); case ACPI_NOTIFY_DEVICE_CHECK: - printk("Device Check\n"); - dev = bay_create_acpi_device(handle); - if (dev) - acpi_bus_generate_event(dev, event, 0); - else - printk("No device for generating event\n"); - /* wouldn't it be a good idea to just rescan SATA - * right here? - */ - break; case ACPI_NOTIFY_EJECT_REQUEST: - printk("Eject request\n"); - dev = bay_create_acpi_device(handle); - if (dev) - acpi_bus_generate_event(dev, event, 0); - else - printk("No device for generating eventn"); - - /* wouldn't it be a good idea to just call the - * eject_device here if we were a SATA device? - */ + kobject_uevent(&dev->kobj, KOBJ_CHANGE); break; default: - printk("unknown event %d\n", event); + printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event); } } @@ -457,10 +370,6 @@ static int __init bay_init(void) acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, find_bay, &bays, NULL); - if (bays) - if ((acpi_bus_register_driver(&acpi_bay_driver) < 0)) - printk(KERN_ERR "Unable to register bay driver\n"); - if (!bays) return -ENODEV; @@ -481,8 +390,6 @@ static void __exit bay_exit(void) kfree(bay->name); kfree(bay); } - - acpi_bus_unregister_driver(&acpi_bay_driver); } postcore_initcall(bay_init); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index c26468da429..dd49ea0d0ed 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -39,7 +39,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_BUS_COMPONENT -ACPI_MODULE_NAME("acpi_bus") +ACPI_MODULE_NAME("bus"); #ifdef CONFIG_X86 extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger); #endif @@ -147,7 +147,7 @@ int acpi_bus_get_power(acpi_handle handle, int *state) *state = ACPI_STATE_D0; } else { /* - * Get the device's power state either directly (via _PSC) or + * Get the device's power state either directly (via _PSC) or * indirectly (via power resources). */ if (device->power.flags.explicit_get) { @@ -199,15 +199,14 @@ int acpi_bus_set_power(acpi_handle handle, int state) * Get device's current power state if it's unknown * This means device power state isn't initialized or previous setting failed */ - if (!device->flags.force_power_state) { - if (device->power.state == ACPI_STATE_UNKNOWN) - acpi_bus_get_power(device->handle, &device->power.state); - if (state == device->power.state) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", - state)); - return 0; - } + if ((device->power.state == ACPI_STATE_UNKNOWN) || device->flags.force_power_state) + acpi_bus_get_power(device->handle, &device->power.state); + if ((state == device->power.state) && !device->flags.force_power_state) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", + state)); + return 0; } + if (!device->power.states[state].flags.valid) { printk(KERN_WARNING PREFIX "Device does not support D%d\n", state); return -ENODEV; @@ -462,7 +461,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) "Received BUS CHECK notification for device [%s]\n", device->pnp.bus_id)); result = acpi_bus_check_scope(device); - /* + /* * TBD: We'll need to outsource certain events to non-ACPI * drivers via the device manager (device.c). */ @@ -473,7 +472,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) "Received DEVICE CHECK notification for device [%s]\n", device->pnp.bus_id)); result = acpi_bus_check_device(device, NULL); - /* + /* * TBD: We'll need to outsource certain events to non-ACPI * drivers via the device manager (device.c). */ @@ -543,7 +542,7 @@ static int __init acpi_bus_init_irq(void) char *message = NULL; - /* + /* * Let the system know what interrupt model we are using by * evaluating the \_PIC object, if exists. */ @@ -684,7 +683,7 @@ static int __init acpi_bus_init(void) * the EC device is found in the namespace (i.e. before acpi_initialize_objects() * is called). * - * This is accomplished by looking for the ECDT table, and getting + * This is accomplished by looking for the ECDT table, and getting * the EC parameters out of that. */ status = acpi_ec_ecdt_probe(); @@ -699,6 +698,9 @@ static int __init acpi_bus_init(void) printk(KERN_INFO PREFIX "Interpreter enabled\n"); + /* Initialize sleep structures */ + acpi_sleep_init(); + /* * Get the system interrupt model and evaluate \_PIC. */ diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index c726612fafb..cb4110b50cd 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -34,7 +34,6 @@ #include <acpi/acpi_drivers.h> #define ACPI_BUTTON_COMPONENT 0x00080000 -#define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver" #define ACPI_BUTTON_CLASS "button" #define ACPI_BUTTON_FILE_INFO "info" #define ACPI_BUTTON_FILE_STATE "state" @@ -61,10 +60,10 @@ #define ACPI_BUTTON_TYPE_LID 0x05 #define _COMPONENT ACPI_BUTTON_COMPONENT -ACPI_MODULE_NAME("acpi_button") +ACPI_MODULE_NAME("button"); MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME); +MODULE_DESCRIPTION("ACPI Button Driver"); MODULE_LICENSE("GPL"); static int acpi_button_add(struct acpi_device *device); @@ -73,7 +72,7 @@ static int acpi_button_info_open_fs(struct inode *inode, struct file *file); static int acpi_button_state_open_fs(struct inode *inode, struct file *file); static struct acpi_driver acpi_button_driver = { - .name = ACPI_BUTTON_DRIVER_NAME, + .name = "button", .class = ACPI_BUTTON_CLASS, .ids = "button_power,button_sleep,PNP0C0D,PNP0C0C,PNP0C0E", .ops = { diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c index 4a9b7bf6f44..f9db4f444bd 100644 --- a/drivers/acpi/cm_sbs.c +++ b/drivers/acpi/cm_sbs.c @@ -31,7 +31,7 @@ #include <acpi/actypes.h> #include <acpi/acutils.h> -ACPI_MODULE_NAME("cm_sbs") +ACPI_MODULE_NAME("cm_sbs"); #define ACPI_AC_CLASS "ac_adapter" #define ACPI_BATTERY_CLASS "battery" #define ACPI_SBS_COMPONENT 0x00080000 diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 69a68fd394c..0930d9413df 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -35,7 +35,6 @@ #include <acpi/acpi_drivers.h> #include <acpi/container.h> -#define ACPI_CONTAINER_DRIVER_NAME "ACPI container driver" #define ACPI_CONTAINER_DEVICE_NAME "ACPI container device" #define ACPI_CONTAINER_CLASS "container" @@ -44,10 +43,10 @@ #define ACPI_CONTAINER_COMPONENT 0x01000000 #define _COMPONENT ACPI_CONTAINER_COMPONENT -ACPI_MODULE_NAME("acpi_container") +ACPI_MODULE_NAME("container"); - MODULE_AUTHOR("Anil S Keshavamurthy"); -MODULE_DESCRIPTION(ACPI_CONTAINER_DRIVER_NAME); +MODULE_AUTHOR("Anil S Keshavamurthy"); +MODULE_DESCRIPTION("ACPI container driver"); MODULE_LICENSE("GPL"); #define ACPI_STA_PRESENT (0x00000001) @@ -56,7 +55,7 @@ static int acpi_container_add(struct acpi_device *device); static int acpi_container_remove(struct acpi_device *device, int type); static struct acpi_driver acpi_container_driver = { - .name = ACPI_CONTAINER_DRIVER_NAME, + .name = "container", .class = ACPI_CONTAINER_CLASS, .ids = "ACPI0004,PNP0A05,PNP0A06", .ops = { diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c index d48f65a8f65..bf513e07b77 100644 --- a/drivers/acpi/debug.c +++ b/drivers/acpi/debug.c @@ -12,7 +12,7 @@ #include <acpi/acglobal.h> #define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME("debug") +ACPI_MODULE_NAME("debug"); #ifdef MODULE_PARAM_PREFIX #undef MODULE_PARAM_PREFIX diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index 1cbe6190582..1683e5c5b94 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -231,10 +231,8 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, * Obtain the method mutex if necessary. Do not acquire mutex for a * recursive call. */ - if (!walk_state || - !obj_desc->method.mutex->mutex.owner_thread || - (walk_state->thread != - obj_desc->method.mutex->mutex.owner_thread)) { + if (acpi_os_get_thread_id() != + obj_desc->method.mutex->mutex.owner_thread_id) { /* * Acquire the method mutex. This releases the interpreter if we * block (and reacquires it before it returns) @@ -248,14 +246,14 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, } /* Update the mutex and walk info and save the original sync_level */ + obj_desc->method.mutex->mutex.owner_thread_id = + acpi_os_get_thread_id(); if (walk_state) { obj_desc->method.mutex->mutex. original_sync_level = walk_state->thread->current_sync_level; - obj_desc->method.mutex->mutex.owner_thread = - walk_state->thread; walk_state->thread->current_sync_level = obj_desc->method.sync_level; } else { @@ -569,7 +567,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, acpi_os_release_mutex(method_desc->method.mutex->mutex. os_mutex); - method_desc->method.mutex->mutex.owner_thread = NULL; + method_desc->method.mutex->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED; } } diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 688e83a1690..54a697f9aa1 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -32,11 +32,11 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> -#define ACPI_DOCK_DRIVER_NAME "ACPI Dock Station Driver" +#define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver" -ACPI_MODULE_NAME("dock") +ACPI_MODULE_NAME("dock"); MODULE_AUTHOR("Kristen Carlson Accardi"); -MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME); +MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); MODULE_LICENSE("GPL"); static struct atomic_notifier_head dock_notifier_list; @@ -741,7 +741,7 @@ static int dock_add(acpi_handle handle) goto dock_add_err; } - printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_NAME); + printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_DESCRIPTION); return 0; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 743ce27fa0b..ab688837379 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -38,11 +38,10 @@ #include <acpi/actypes.h> #define _COMPONENT ACPI_EC_COMPONENT -ACPI_MODULE_NAME("acpi_ec") +ACPI_MODULE_NAME("ec"); #define ACPI_EC_COMPONENT 0x00100000 #define ACPI_EC_CLASS "embedded_controller" #define ACPI_EC_HID "PNP0C09" -#define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" #define ACPI_EC_DEVICE_NAME "Embedded Controller" #define ACPI_EC_FILE_INFO "info" #undef PREFIX @@ -80,7 +79,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type); static int acpi_ec_add(struct acpi_device *device); static struct acpi_driver acpi_ec_driver = { - .name = ACPI_EC_DRIVER_NAME, + .name = "ec", .class = ACPI_EC_CLASS, .ids = ACPI_EC_HID, .ops = { @@ -280,8 +279,10 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, mutex_lock(&ec->lock); if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { + mutex_unlock(&ec->lock); return -ENODEV; + } } /* Make sure GPE is enabled before doing transaction */ diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index 959a893c8d1..3b23562e6f9 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -13,7 +13,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME("event") +ACPI_MODULE_NAME("event"); /* Global vars for handling event proc entry */ static DEFINE_SPINLOCK(acpi_system_event_lock); diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index dfac3ecc596..635ba449ebc 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -636,17 +636,6 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) } } - if (!acpi_gbl_system_awake_and_running) { - /* - * We just woke up because of a wake GPE. Disable any further GPEs - * until we are fully up and running (Only wake GPEs should be enabled - * at this time, but we just brute-force disable them all.) - * 1) We must disable this particular wake GPE so it won't fire again - * 2) We want to disable all wake GPEs, since we are now awake - */ - (void)acpi_hw_disable_all_gpes(); - } - /* * Dispatch the GPE to either an installed handler, or the control method * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index 1b784ffe54c..d572700197f 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -196,12 +196,11 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, notify_info->notify.value = (u16) notify_value; notify_info->notify.handler_obj = handler_obj; - status = - acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch, - notify_info); - if (ACPI_FAILURE(status)) { - acpi_ut_delete_generic_state(notify_info); - } + acpi_ex_relinquish_interpreter(); + + acpi_ev_notify_dispatch(notify_info); + + acpi_ex_reacquire_interpreter(); } if (!handler_obj) { diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c index 68d283fd60e..1a73c14df2c 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/executer/exdump.c @@ -134,7 +134,7 @@ static struct acpi_exdump_info acpi_ex_dump_method[8] = { static struct acpi_exdump_info acpi_ex_dump_mutex[5] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"}, - {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread_id), "Owner Thread"}, {ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth), "Acquire Depth"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"} diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index 5101bad5baf..4eb883bda6a 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -66,10 +66,9 @@ acpi_ex_link_mutex(union acpi_operand_object *obj_desc, * ******************************************************************************/ -void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc) +void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc, + struct acpi_thread_state *thread) { - struct acpi_thread_state *thread = obj_desc->mutex.owner_thread; - if (!thread) { return; } @@ -174,16 +173,13 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, /* Support for multiple acquires by the owning thread */ - if (obj_desc->mutex.owner_thread) { - if (obj_desc->mutex.owner_thread->thread_id == - walk_state->thread->thread_id) { - /* - * The mutex is already owned by this thread, just increment the - * acquisition depth - */ - obj_desc->mutex.acquisition_depth++; - return_ACPI_STATUS(AE_OK); - } + if (obj_desc->mutex.owner_thread_id == acpi_os_get_thread_id()) { + /* + * The mutex is already owned by this thread, just increment the + * acquisition depth + */ + obj_desc->mutex.acquisition_depth++; + return_ACPI_STATUS(AE_OK); } /* Acquire the mutex, wait if necessary. Special case for Global Lock */ @@ -206,7 +202,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, /* Have the mutex: update mutex and walk info and save the sync_level */ - obj_desc->mutex.owner_thread = walk_state->thread; + obj_desc->mutex.owner_thread_id = acpi_os_get_thread_id(); obj_desc->mutex.acquisition_depth = 1; obj_desc->mutex.original_sync_level = walk_state->thread->current_sync_level; @@ -246,7 +242,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, /* The mutex must have been previously acquired in order to release it */ - if (!obj_desc->mutex.owner_thread) { + if (!obj_desc->mutex.owner_thread_id) { ACPI_ERROR((AE_INFO, "Cannot release Mutex [%4.4s], not acquired", acpi_ut_get_node_name(obj_desc->mutex.node))); @@ -266,14 +262,14 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, * The Mutex is owned, but this thread must be the owner. * Special case for Global Lock, any thread can release */ - if ((obj_desc->mutex.owner_thread->thread_id != + if ((obj_desc->mutex.owner_thread_id != walk_state->thread->thread_id) && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) { ACPI_ERROR((AE_INFO, "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", (unsigned long)walk_state->thread->thread_id, acpi_ut_get_node_name(obj_desc->mutex.node), - (unsigned long)obj_desc->mutex.owner_thread->thread_id)); + (unsigned long)obj_desc->mutex.owner_thread_id)); return_ACPI_STATUS(AE_AML_NOT_OWNER); } @@ -300,7 +296,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, /* Unlink the mutex from the owner's list */ - acpi_ex_unlink_mutex(obj_desc); + acpi_ex_unlink_mutex(obj_desc, walk_state->thread); /* Release the mutex, special case for Global Lock */ @@ -312,7 +308,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, /* Update the mutex and restore sync_level */ - obj_desc->mutex.owner_thread = NULL; + obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED; walk_state->thread->current_sync_level = obj_desc->mutex.original_sync_level; @@ -367,7 +363,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) /* Mark mutex unowned */ - obj_desc->mutex.owner_thread = NULL; + obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED; /* Update Thread sync_level (Last mutex is the important one) */ diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index af22fdf7341..ec655c53949 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -36,14 +36,13 @@ #define ACPI_FAN_COMPONENT 0x00200000 #define ACPI_FAN_CLASS "fan" -#define ACPI_FAN_DRIVER_NAME "ACPI Fan Driver" #define ACPI_FAN_FILE_STATE "state" #define _COMPONENT ACPI_FAN_COMPONENT -ACPI_MODULE_NAME("acpi_fan") +ACPI_MODULE_NAME("fan"); - MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_FAN_DRIVER_NAME); +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION("ACPI Fan Driver"); MODULE_LICENSE("GPL"); static int acpi_fan_add(struct acpi_device *device); @@ -52,7 +51,7 @@ static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state); static int acpi_fan_resume(struct acpi_device *device); static struct acpi_driver acpi_fan_driver = { - .name = ACPI_FAN_DRIVER_NAME, + .name = "fan", .class = ACPI_FAN_CLASS, .ids = "PNP0C0B", .ops = { diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 7b6c9ff9beb..4334c208841 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -241,3 +241,65 @@ static int __init init_acpi_device_notify(void) } arch_initcall(init_acpi_device_notify); + + +#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) + +/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find + * its device node and pass extra config data. This helps its driver use + * capabilities that the now-obsolete mc146818 didn't have, and informs it + * that this board's RTC is wakeup-capable (per ACPI spec). + */ +#include <linux/mc146818rtc.h> + +static struct cmos_rtc_board_info rtc_info; + + +/* PNP devices are registered in a subsys_initcall(); + * ACPI specifies the PNP IDs to use. + */ +#include <linux/pnp.h> + +static int __init pnp_match(struct device *dev, void *data) +{ + static const char *ids[] = { "PNP0b00", "PNP0b01", "PNP0b02", }; + struct pnp_dev *pnp = to_pnp_dev(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(ids); i++) { + if (compare_pnp_id(pnp->id, ids[i]) != 0) + return 1; + } + return 0; +} + +static struct device *__init get_rtc_dev(void) +{ + return bus_find_device(&pnp_bus_type, NULL, NULL, pnp_match); +} + +static int __init acpi_rtc_init(void) +{ + struct device *dev = get_rtc_dev(); + + if (dev) { + rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm; + rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm; + rtc_info.rtc_century = acpi_gbl_FADT.century; + + /* NOTE: acpi_gbl_FADT->rtcs4 is NOT currently useful */ + + dev->platform_data = &rtc_info; + + /* RTC always wakes from S1/S2/S3, and often S4/STD */ + device_init_wakeup(dev, 1); + + put_device(dev); + } else + pr_debug("ACPI: RTC unavailable?\n"); + return 0; +} +/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */ +fs_initcall(acpi_rtc_init); + +#endif diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 57901ca3ade..8fa93125fd4 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -235,6 +235,14 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) "While executing method _SST")); } + /* + * 1) Disable/Clear all GPEs + */ + status = acpi_hw_disable_all_gpes(); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + return_ACPI_STATUS(AE_OK); } @@ -290,13 +298,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) } /* - * 1) Disable/Clear all GPEs * 2) Enable all wakeup GPEs */ - status = acpi_hw_disable_all_gpes(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } acpi_gbl_system_awake_and_running = FALSE; status = acpi_hw_enable_all_wakeup_gpes(); diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c deleted file mode 100644 index 8edfb92f7ed..00000000000 --- a/drivers/acpi/hotkey.c +++ /dev/null @@ -1,1042 +0,0 @@ -/* - * hotkey.c - ACPI Hotkey Driver ($Revision: 0.2 $) - * - * Copyright (C) 2004 Luming Yu <luming.yu@intel.com> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/sched.h> -#include <linux/kmod.h> -#include <linux/seq_file.h> -#include <acpi/acpi_drivers.h> -#include <acpi/acpi_bus.h> -#include <asm/uaccess.h> - -#define HOTKEY_ACPI_VERSION "0.1" - -#define HOTKEY_PROC "hotkey" -#define HOTKEY_EV_CONFIG "event_config" -#define HOTKEY_PL_CONFIG "poll_config" -#define HOTKEY_ACTION "action" -#define HOTKEY_INFO "info" - -#define ACPI_HOTK_NAME "Generic Hotkey Driver" -#define ACPI_HOTK_CLASS "Hotkey" -#define ACPI_HOTK_DEVICE_NAME "Hotkey" -#define ACPI_HOTK_HID "Unknown?" -#define ACPI_HOTKEY_COMPONENT 0x20000000 - -#define ACPI_HOTKEY_EVENT 0x1 -#define ACPI_HOTKEY_POLLING 0x2 -#define ACPI_UNDEFINED_EVENT 0xf - -#define RESULT_STR_LEN 80 - -#define ACTION_METHOD 0 -#define POLL_METHOD 1 - -#define IS_EVENT(e) ((e) <= 10000 && (e) >0) -#define IS_POLL(e) ((e) > 10000) -#define IS_OTHERS(e) ((e)<=0 || (e)>=20000) -#define _COMPONENT ACPI_HOTKEY_COMPONENT -ACPI_MODULE_NAME("acpi_hotkey") - - MODULE_AUTHOR("luming.yu@intel.com"); -MODULE_DESCRIPTION(ACPI_HOTK_NAME); -MODULE_LICENSE("GPL"); - -/* standardized internal hotkey number/event */ -enum { - /* Video Extension event */ - HK_EVENT_CYCLE_OUTPUT_DEVICE = 0x80, - HK_EVENT_OUTPUT_DEVICE_STATUS_CHANGE, - HK_EVENT_CYCLE_DISPLAY_OUTPUT, - HK_EVENT_NEXT_DISPLAY_OUTPUT, - HK_EVENT_PREVIOUS_DISPLAY_OUTPUT, - HK_EVENT_CYCLE_BRIGHTNESS, - HK_EVENT_INCREASE_BRIGHTNESS, - HK_EVENT_DECREASE_BRIGHTNESS, - HK_EVENT_ZERO_BRIGHTNESS, - HK_EVENT_DISPLAY_DEVICE_OFF, - - /* Snd Card event */ - HK_EVENT_VOLUME_MUTE, - HK_EVENT_VOLUME_INCLREASE, - HK_EVENT_VOLUME_DECREASE, - - /* running state control */ - HK_EVENT_ENTERRING_S3, - HK_EVENT_ENTERRING_S4, - HK_EVENT_ENTERRING_S5, -}; - -enum conf_entry_enum { - bus_handle = 0, - bus_method = 1, - action_handle = 2, - method = 3, - LAST_CONF_ENTRY -}; - -/* procdir we use */ -static struct proc_dir_entry *hotkey_proc_dir; -static struct proc_dir_entry *hotkey_config; -static struct proc_dir_entry *hotkey_poll_config; -static struct proc_dir_entry *hotkey_action; -static struct proc_dir_entry *hotkey_info; - -/* linkage for all type of hotkey */ -struct acpi_hotkey_link { - struct list_head entries; - int hotkey_type; /* event or polling based hotkey */ - int hotkey_standard_num; /* standardized hotkey(event) number */ -}; - -/* event based hotkey */ -struct acpi_event_hotkey { - struct acpi_hotkey_link hotkey_link; - int flag; - acpi_handle bus_handle; /* bus to install notify handler */ - int external_hotkey_num; /* external hotkey/event number */ - acpi_handle action_handle; /* acpi handle attached aml action method */ - char *action_method; /* action method */ -}; - -/* - * There are two ways to poll status - * 1. directy call read_xxx method, without any arguments passed in - * 2. call write_xxx method, with arguments passed in, you need - * the result is saved in acpi_polling_hotkey.poll_result. - * anthoer read command through polling interface. - * - */ - -/* polling based hotkey */ -struct acpi_polling_hotkey { - struct acpi_hotkey_link hotkey_link; - int flag; - acpi_handle poll_handle; /* acpi handle attached polling method */ - char *poll_method; /* poll method */ - acpi_handle action_handle; /* acpi handle attached action method */ - char *action_method; /* action method */ - union acpi_object *poll_result; /* polling_result */ - struct proc_dir_entry *proc; -}; - -/* hotkey object union */ -union acpi_hotkey { - struct list_head entries; - struct acpi_hotkey_link link; - struct acpi_event_hotkey event_hotkey; - struct acpi_polling_hotkey poll_hotkey; -}; - -/* hotkey object list */ -struct acpi_hotkey_list { - struct list_head *entries; - int count; -}; - -static int auto_hotkey_add(struct acpi_device *device); -static int auto_hotkey_remove(struct acpi_device *device, int type); - -static struct acpi_driver hotkey_driver = { - .name = ACPI_HOTK_NAME, - .class = ACPI_HOTK_CLASS, - .ids = ACPI_HOTK_HID, - .ops = { - .add = auto_hotkey_add, - .remove = auto_hotkey_remove, - }, -}; - -static void free_hotkey_device(union acpi_hotkey *key); -static void free_hotkey_buffer(union acpi_hotkey *key); -static void free_poll_hotkey_buffer(union acpi_hotkey *key); -static int hotkey_open_config(struct inode *inode, struct file *file); -static int hotkey_poll_open_config(struct inode *inode, struct file *file); -static ssize_t hotkey_write_config(struct file *file, - const char __user * buffer, - size_t count, loff_t * data); -static int hotkey_info_open_fs(struct inode *inode, struct file *file); -static int hotkey_action_open_fs(struct inode *inode, struct file *file); -static ssize_t hotkey_execute_aml_method(struct file *file, - const char __user * buffer, - size_t count, loff_t * data); -static int hotkey_config_seq_show(struct seq_file *seq, void *offset); -static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset); -static int hotkey_polling_open_fs(struct inode *inode, struct file *file); -static union acpi_hotkey *get_hotkey_by_event(struct - acpi_hotkey_list - *hotkey_list, int event); - -/* event based config */ -static const struct file_operations hotkey_config_fops = { - .open = hotkey_open_config, - .read = seq_read, - .write = hotkey_write_config, - .llseek = seq_lseek, - .release = single_release, -}; - -/* polling based config */ -static const struct file_operations hotkey_poll_config_fops = { - .open = hotkey_poll_open_config, - .read = seq_read, - .write = hotkey_write_config, - .llseek = seq_lseek, - .release = single_release, -}; - -/* hotkey driver info */ -static const struct file_operations hotkey_info_fops = { - .open = hotkey_info_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/* action */ -static const struct file_operations hotkey_action_fops = { - .open = hotkey_action_open_fs, - .read = seq_read, - .write = hotkey_execute_aml_method, - .llseek = seq_lseek, - .release = single_release, -}; - -/* polling results */ -static const struct file_operations hotkey_polling_fops = { - .open = hotkey_polling_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -struct acpi_hotkey_list global_hotkey_list; /* link all ev or pl hotkey */ -struct list_head hotkey_entries; /* head of the list of hotkey_list */ - -static int hotkey_info_seq_show(struct seq_file *seq, void *offset) -{ - - seq_printf(seq, "Hotkey generic driver ver: %s\n", HOTKEY_ACPI_VERSION); - - return 0; -} - -static int hotkey_info_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, hotkey_info_seq_show, PDE(inode)->data); -} - -static char *format_result(union acpi_object *object) -{ - char *buf; - - buf = kzalloc(RESULT_STR_LEN, GFP_KERNEL); - if (!buf) - return NULL; - /* Now, just support integer type */ - if (object->type == ACPI_TYPE_INTEGER) - sprintf(buf, "%d\n", (u32) object->integer.value); - return buf; -} - -static int hotkey_polling_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_polling_hotkey *poll_hotkey = seq->private; - char *buf; - - - if (poll_hotkey->poll_result) { - buf = format_result(poll_hotkey->poll_result); - if (buf) - seq_printf(seq, "%s", buf); - kfree(buf); - } - return 0; -} - -static int hotkey_polling_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, hotkey_polling_seq_show, PDE(inode)->data); -} - -static int hotkey_action_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, hotkey_info_seq_show, PDE(inode)->data); -} - -/* Mapping external hotkey number to standardized hotkey event num */ -static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list) -{ - struct list_head *entries; - int val = -1; - - - list_for_each(entries, list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT - && key->event_hotkey.external_hotkey_num == event) { - val = key->link.hotkey_standard_num; - break; - } - } - - return val; -} - -static void -acpi_hotkey_notify_handler(acpi_handle handle, u32 event, void *data) -{ - struct acpi_device *device = NULL; - u32 internal_event; - - - if (acpi_bus_get_device(handle, &device)) - return; - - internal_event = hotkey_get_internal_event(event, &global_hotkey_list); - acpi_bus_generate_event(device, internal_event, 0); - - return; -} - -/* Need to invent automatically hotkey add method */ -static int auto_hotkey_add(struct acpi_device *device) -{ - /* Implement me */ - return 0; -} - -/* Need to invent automatically hotkey remove method */ -static int auto_hotkey_remove(struct acpi_device *device, int type) -{ - /* Implement me */ - return 0; -} - -/* Create a proc file for each polling method */ -static int create_polling_proc(union acpi_hotkey *device) -{ - struct proc_dir_entry *proc; - char proc_name[80]; - mode_t mode; - - mode = S_IFREG | S_IRUGO | S_IWUGO; - - sprintf(proc_name, "%d", device->link.hotkey_standard_num); - /* - strcat(proc_name, device->poll_hotkey.poll_method); - */ - proc = create_proc_entry(proc_name, mode, hotkey_proc_dir); - - if (!proc) { - return -ENODEV; - } else { - proc->proc_fops = &hotkey_polling_fops; - proc->owner = THIS_MODULE; - proc->data = device; - proc->uid = 0; - proc->gid = 0; - device->poll_hotkey.proc = proc; - } - return 0; -} - -static int hotkey_add(union acpi_hotkey *device) -{ - int status = 0; - struct acpi_device *dev = NULL; - - - if (device->link.hotkey_type == ACPI_HOTKEY_EVENT) { - acpi_bus_get_device(device->event_hotkey.bus_handle, &dev); - status = acpi_install_notify_handler(dev->handle, - ACPI_DEVICE_NOTIFY, - acpi_hotkey_notify_handler, - dev); - } else /* Add polling hotkey */ - create_polling_proc(device); - - global_hotkey_list.count++; - - list_add_tail(&device->link.entries, global_hotkey_list.entries); - - return status; -} - -static int hotkey_remove(union acpi_hotkey *device) -{ - struct list_head *entries, *next; - - - list_for_each_safe(entries, next, global_hotkey_list.entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_standard_num == - device->link.hotkey_standard_num) { - list_del(&key->link.entries); - free_hotkey_device(key); - global_hotkey_list.count--; - break; - } - } - kfree(device); - return 0; -} - -static int hotkey_update(union acpi_hotkey *key) -{ - struct list_head *entries; - - - list_for_each(entries, global_hotkey_list.entries) { - union acpi_hotkey *tmp = - container_of(entries, union acpi_hotkey, entries); - if (tmp->link.hotkey_standard_num == - key->link.hotkey_standard_num) { - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { - free_hotkey_buffer(tmp); - tmp->event_hotkey.bus_handle = - key->event_hotkey.bus_handle; - tmp->event_hotkey.external_hotkey_num = - key->event_hotkey.external_hotkey_num; - tmp->event_hotkey.action_handle = - key->event_hotkey.action_handle; - tmp->event_hotkey.action_method = - key->event_hotkey.action_method; - kfree(key); - } else { - /* - char proc_name[80]; - - sprintf(proc_name, "%d", tmp->link.hotkey_standard_num); - strcat(proc_name, tmp->poll_hotkey.poll_method); - remove_proc_entry(proc_name,hotkey_proc_dir); - */ - free_poll_hotkey_buffer(tmp); - tmp->poll_hotkey.poll_handle = - key->poll_hotkey.poll_handle; - tmp->poll_hotkey.poll_method = - key->poll_hotkey.poll_method; - tmp->poll_hotkey.action_handle = - key->poll_hotkey.action_handle; - tmp->poll_hotkey.action_method = - key->poll_hotkey.action_method; - tmp->poll_hotkey.poll_result = - key->poll_hotkey.poll_result; - /* - create_polling_proc(tmp); - */ - kfree(key); - } - return 0; - break; - } - } - - return -ENODEV; -} - -static void free_hotkey_device(union acpi_hotkey *key) -{ - struct acpi_device *dev; - - - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { - acpi_bus_get_device(key->event_hotkey.bus_handle, &dev); - if (dev->handle) - acpi_remove_notify_handler(dev->handle, - ACPI_DEVICE_NOTIFY, - acpi_hotkey_notify_handler); - free_hotkey_buffer(key); - } else { - char proc_name[80]; - - sprintf(proc_name, "%d", key->link.hotkey_standard_num); - /* - strcat(proc_name, key->poll_hotkey.poll_method); - */ - remove_proc_entry(proc_name, hotkey_proc_dir); - free_poll_hotkey_buffer(key); - } - kfree(key); - return; -} - -static void free_hotkey_buffer(union acpi_hotkey *key) -{ - /* key would never be null, action method could be */ - kfree(key->event_hotkey.action_method); -} - -static void free_poll_hotkey_buffer(union acpi_hotkey *key) -{ - /* key would never be null, others could be*/ - kfree(key->poll_hotkey.action_method); - kfree(key->poll_hotkey.poll_method); - kfree(key->poll_hotkey.poll_result); -} -static int -init_hotkey_device(union acpi_hotkey *key, char **config_entry, - int std_num, int external_num) -{ - acpi_handle tmp_handle; - acpi_status status = AE_OK; - - if (std_num < 0 || IS_POLL(std_num) || !key) - goto do_fail; - - if (!config_entry[bus_handle] || !config_entry[action_handle] - || !config_entry[method]) - goto do_fail; - - key->link.hotkey_type = ACPI_HOTKEY_EVENT; - key->link.hotkey_standard_num = std_num; - key->event_hotkey.flag = 0; - key->event_hotkey.action_method = config_entry[method]; - - status = acpi_get_handle(NULL, config_entry[bus_handle], - &(key->event_hotkey.bus_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - key->event_hotkey.external_hotkey_num = external_num; - status = acpi_get_handle(NULL, config_entry[action_handle], - &(key->event_hotkey.action_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = acpi_get_handle(key->event_hotkey.action_handle, - config_entry[method], &tmp_handle); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - return AE_OK; -do_fail_zero: - key->event_hotkey.action_method = NULL; -do_fail: - return -ENODEV; -} - -static int -init_poll_hotkey_device(union acpi_hotkey *key, char **config_entry, - int std_num) -{ - acpi_status status = AE_OK; - acpi_handle tmp_handle; - - if (std_num < 0 || IS_EVENT(std_num) || !key) - goto do_fail; - if (!config_entry[bus_handle] ||!config_entry[bus_method] || - !config_entry[action_handle] || !config_entry[method]) - goto do_fail; - - key->link.hotkey_type = ACPI_HOTKEY_POLLING; - key->link.hotkey_standard_num = std_num; - key->poll_hotkey.flag = 0; - key->poll_hotkey.poll_method = config_entry[bus_method]; - key->poll_hotkey.action_method = config_entry[method]; - - status = acpi_get_handle(NULL, config_entry[bus_handle], - &(key->poll_hotkey.poll_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = acpi_get_handle(key->poll_hotkey.poll_handle, - config_entry[bus_method], &tmp_handle); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = - acpi_get_handle(NULL, config_entry[action_handle], - &(key->poll_hotkey.action_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = acpi_get_handle(key->poll_hotkey.action_handle, - config_entry[method], &tmp_handle); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - key->poll_hotkey.poll_result = - kmalloc(sizeof(union acpi_object), GFP_KERNEL); - if (!key->poll_hotkey.poll_result) - goto do_fail_zero; - return AE_OK; - -do_fail_zero: - key->poll_hotkey.poll_method = NULL; - key->poll_hotkey.action_method = NULL; -do_fail: - return -ENODEV; -} - -static int hotkey_open_config(struct inode *inode, struct file *file) -{ - return (single_open - (file, hotkey_config_seq_show, PDE(inode)->data)); -} - -static int hotkey_poll_open_config(struct inode *inode, struct file *file) -{ - return (single_open - (file, hotkey_poll_config_seq_show, PDE(inode)->data)); -} - -static int hotkey_config_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; - struct list_head *entries; - char bus_name[ACPI_PATHNAME_MAX] = { 0 }; - char action_name[ACPI_PATHNAME_MAX] = { 0 }; - struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name }; - struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name }; - - - list_for_each(entries, hotkey_list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { - acpi_get_name(key->event_hotkey.bus_handle, - ACPI_NAME_TYPE_MAX, &bus); - acpi_get_name(key->event_hotkey.action_handle, - ACPI_NAME_TYPE_MAX, &act); - seq_printf(seq, "%s:%s:%s:%d:%d\n", bus_name, - action_name, - key->event_hotkey.action_method, - key->link.hotkey_standard_num, - key->event_hotkey.external_hotkey_num); - } - } - seq_puts(seq, "\n"); - return 0; -} - -static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; - struct list_head *entries; - char bus_name[ACPI_PATHNAME_MAX] = { 0 }; - char action_name[ACPI_PATHNAME_MAX] = { 0 }; - struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name }; - struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name }; - - - list_for_each(entries, hotkey_list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_type == ACPI_HOTKEY_POLLING) { - acpi_get_name(key->poll_hotkey.poll_handle, - ACPI_NAME_TYPE_MAX, &bus); - acpi_get_name(key->poll_hotkey.action_handle, - ACPI_NAME_TYPE_MAX, &act); - seq_printf(seq, "%s:%s:%s:%s:%d\n", bus_name, - key->poll_hotkey.poll_method, - action_name, - key->poll_hotkey.action_method, - key->link.hotkey_standard_num); - } - } - seq_puts(seq, "\n"); - return 0; -} - -static int -get_parms(char *config_record, int *cmd, char **config_entry, - int *internal_event_num, int *external_event_num) -{ -/* the format of *config_record = - * "1:\d+:*" : "cmd:internal_event_num" - * "\d+:\w+:\w+:\w+:\w+:\d+:\d+" : - * "cmd:bus_handle:bus_method:action_handle:method:internal_event_num:external_event_num" - */ - char *tmp, *tmp1, count; - int i; - - sscanf(config_record, "%d", cmd); - if (*cmd == 1) { - if (sscanf(config_record, "%d:%d", cmd, internal_event_num) != - 2) - goto do_fail; - else - return (6); - } - tmp = strchr(config_record, ':'); - if (!tmp) - goto do_fail; - tmp++; - for (i = 0; i < LAST_CONF_ENTRY; i++) { - tmp1 = strchr(tmp, ':'); - if (!tmp1) { - goto do_fail; - } - count = tmp1 - tmp; - config_entry[i] = kzalloc(count + 1, GFP_KERNEL); - if (!config_entry[i]) - goto handle_failure; - strncpy(config_entry[i], tmp, count); - tmp = tmp1 + 1; - } - if (sscanf(tmp, "%d:%d", internal_event_num, external_event_num) <= 0) - goto handle_failure; - if (!IS_OTHERS(*internal_event_num)) { - return 6; - } -handle_failure: - while (i-- > 0) - kfree(config_entry[i]); -do_fail: - return -1; -} - -/* count is length for one input record */ -static ssize_t hotkey_write_config(struct file *file, - const char __user * buffer, - size_t count, loff_t * data) -{ - char *config_record = NULL; - char *config_entry[LAST_CONF_ENTRY]; - int cmd, internal_event_num, external_event_num; - int ret = 0; - union acpi_hotkey *key = kzalloc(sizeof(union acpi_hotkey), GFP_KERNEL); - - if (!key) - return -ENOMEM; - - config_record = kzalloc(count + 1, GFP_KERNEL); - if (!config_record) { - kfree(key); - return -ENOMEM; - } - - if (copy_from_user(config_record, buffer, count)) { - kfree(config_record); - kfree(key); - printk(KERN_ERR PREFIX "Invalid data\n"); - return -EINVAL; - } - ret = get_parms(config_record, &cmd, config_entry, - &internal_event_num, &external_event_num); - kfree(config_record); - if (ret != 6) { - printk(KERN_ERR PREFIX "Invalid data format ret=%d\n", ret); - return -EINVAL; - } - - if (cmd == 1) { - union acpi_hotkey *tmp = NULL; - tmp = get_hotkey_by_event(&global_hotkey_list, - internal_event_num); - if (!tmp) - printk(KERN_ERR PREFIX "Invalid key\n"); - else - memcpy(key, tmp, sizeof(union acpi_hotkey)); - goto cont_cmd; - } - if (IS_EVENT(internal_event_num)) { - if (init_hotkey_device(key, config_entry, - internal_event_num, external_event_num)) - goto init_hotkey_fail; - } else { - if (init_poll_hotkey_device(key, config_entry, - internal_event_num)) - goto init_poll_hotkey_fail; - } -cont_cmd: - switch (cmd) { - case 0: - if (get_hotkey_by_event(&global_hotkey_list, - key->link.hotkey_standard_num)) - goto fail_out; - else - hotkey_add(key); - break; - case 1: - hotkey_remove(key); - break; - case 2: - /* key is kfree()ed if matched*/ - if (hotkey_update(key)) - goto fail_out; - break; - default: - goto fail_out; - break; - } - return count; - -init_poll_hotkey_fail: /* failed init_poll_hotkey_device */ - kfree(config_entry[bus_method]); - config_entry[bus_method] = NULL; -init_hotkey_fail: /* failed init_hotkey_device */ - kfree(config_entry[method]); -fail_out: - kfree(config_entry[bus_handle]); - kfree(config_entry[action_handle]); - /* No double free since elements =NULL for error cases */ - if (IS_EVENT(internal_event_num)) { - if (config_entry[bus_method]) - kfree(config_entry[bus_method]); - free_hotkey_buffer(key); /* frees [method] */ - } else - free_poll_hotkey_buffer(key); /* frees [bus_method]+[method] */ - kfree(key); - printk(KERN_ERR PREFIX "invalid key\n"); - return -EINVAL; -} - -/* - * This function evaluates an ACPI method, given an int as parameter, the - * method is searched within the scope of the handle, can be NULL. The output - * of the method is written is output, which can also be NULL - * - * returns 1 if write is successful, 0 else. - */ -static int write_acpi_int(acpi_handle handle, const char *method, int val, - struct acpi_buffer *output) -{ - struct acpi_object_list params; /* list of input parameters (an int here) */ - union acpi_object in_obj; /* the only param we use */ - acpi_status status; - - params.count = 1; - params.pointer = &in_obj; - in_obj.type = ACPI_TYPE_INTEGER; - in_obj.integer.value = val; - - status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); - - return (status == AE_OK); -} - -static int read_acpi_int(acpi_handle handle, const char *method, - union acpi_object *val) -{ - struct acpi_buffer output; - union acpi_object out_obj; - acpi_status status; - - output.length = sizeof(out_obj); - output.pointer = &out_obj; - - status = acpi_evaluate_object(handle, (char *)method, NULL, &output); - if (val) { - val->integer.value = out_obj.integer.value; - val->type = out_obj.type; - } else - printk(KERN_ERR PREFIX "null val pointer\n"); - return ((status == AE_OK) - && (out_obj.type == ACPI_TYPE_INTEGER)); -} - -static union acpi_hotkey *get_hotkey_by_event(struct - acpi_hotkey_list - *hotkey_list, int event) -{ - struct list_head *entries; - - list_for_each(entries, hotkey_list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_standard_num == event) { - return (key); - } - } - return (NULL); -} - -/* - * user call AML method interface: - * Call convention: - * echo "event_num: arg type : value" - * example: echo "1:1:30" > /proc/acpi/action - * Just support 1 integer arg passing to AML method - */ - -static ssize_t hotkey_execute_aml_method(struct file *file, - const char __user * buffer, - size_t count, loff_t * data) -{ - struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; - char *arg; - int event, method_type, type, value; - union acpi_hotkey *key; - - - arg = kzalloc(count + 1, GFP_KERNEL); - if (!arg) - return -ENOMEM; - - if (copy_from_user(arg, buffer, count)) { - kfree(arg); - printk(KERN_ERR PREFIX "Invalid argument 2\n"); - return -EINVAL; - } - - if (sscanf(arg, "%d:%d:%d:%d", &event, &method_type, &type, &value) != - 4) { - kfree(arg); - printk(KERN_ERR PREFIX "Invalid argument 3\n"); - return -EINVAL; - } - kfree(arg); - if (type == ACPI_TYPE_INTEGER) { - key = get_hotkey_by_event(hotkey_list, event); - if (!key) - goto do_fail; - if (IS_EVENT(event)) - write_acpi_int(key->event_hotkey.action_handle, - key->event_hotkey.action_method, value, - NULL); - else if (IS_POLL(event)) { - if (method_type == POLL_METHOD) - read_acpi_int(key->poll_hotkey.poll_handle, - key->poll_hotkey.poll_method, - key->poll_hotkey.poll_result); - else if (method_type == ACTION_METHOD) - write_acpi_int(key->poll_hotkey.action_handle, - key->poll_hotkey.action_method, - value, NULL); - else - goto do_fail; - - } - } else { - printk(KERN_WARNING "Not supported\n"); - return -EINVAL; - } - return count; - do_fail: - return -EINVAL; - -} - -static int __init hotkey_init(void) -{ - int result; - mode_t mode = S_IFREG | S_IRUGO | S_IWUGO; - - - if (acpi_disabled) - return -ENODEV; - - if (acpi_specific_hotkey_enabled) { - printk("Using specific hotkey driver\n"); - return -ENODEV; - } - - hotkey_proc_dir = proc_mkdir(HOTKEY_PROC, acpi_root_dir); - if (!hotkey_proc_dir) { - return (-ENODEV); - } - hotkey_proc_dir->owner = THIS_MODULE; - - hotkey_config = - create_proc_entry(HOTKEY_EV_CONFIG, mode, hotkey_proc_dir); - if (!hotkey_config) { - goto do_fail1; - } else { - hotkey_config->proc_fops = &hotkey_config_fops; - hotkey_config->data = &global_hotkey_list; - hotkey_config->owner = THIS_MODULE; - hotkey_config->uid = 0; - hotkey_config->gid = 0; - } - - hotkey_poll_config = - create_proc_entry(HOTKEY_PL_CONFIG, mode, hotkey_proc_dir); - if (!hotkey_poll_config) { - goto do_fail2; - } else { - hotkey_poll_config->proc_fops = &hotkey_poll_config_fops; - hotkey_poll_config->data = &global_hotkey_list; - hotkey_poll_config->owner = THIS_MODULE; - hotkey_poll_config->uid = 0; - hotkey_poll_config->gid = 0; - } - - hotkey_action = create_proc_entry(HOTKEY_ACTION, mode, hotkey_proc_dir); - if (!hotkey_action) { - goto do_fail3; - } else { - hotkey_action->proc_fops = &hotkey_action_fops; - hotkey_action->owner = THIS_MODULE; - hotkey_action->uid = 0; - hotkey_action->gid = 0; - } - - hotkey_info = create_proc_entry(HOTKEY_INFO, mode, hotkey_proc_dir); - if (!hotkey_info) { - goto do_fail4; - } else { - hotkey_info->proc_fops = &hotkey_info_fops; - hotkey_info->owner = THIS_MODULE; - hotkey_info->uid = 0; - hotkey_info->gid = 0; - } - - result = acpi_bus_register_driver(&hotkey_driver); - if (result < 0) - goto do_fail5; - global_hotkey_list.count = 0; - global_hotkey_list.entries = &hotkey_entries; - - INIT_LIST_HEAD(&hotkey_entries); - - return (0); - - do_fail5: - remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir); - do_fail4: - remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir); - do_fail3: - remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir); - do_fail2: - remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir); - do_fail1: - remove_proc_entry(HOTKEY_PROC, acpi_root_dir); - return (-ENODEV); -} - -static void __exit hotkey_exit(void) -{ - struct list_head *entries, *next; - - - list_for_each_safe(entries, next, global_hotkey_list.entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - - acpi_os_wait_events_complete(NULL); - list_del(&key->link.entries); - global_hotkey_list.count--; - free_hotkey_device(key); - } - acpi_bus_unregister_driver(&hotkey_driver); - remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir); - remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir); - remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir); - remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir); - remove_proc_entry(HOTKEY_PROC, acpi_root_dir); - return; -} - -module_init(hotkey_init); -module_exit(hotkey_exit); diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c index 76ec8b63e69..acab4a48189 100644 --- a/drivers/acpi/i2c_ec.c +++ b/drivers/acpi/i2c_ec.c @@ -27,18 +27,17 @@ #define ACPI_EC_HC_COMPONENT 0x00080000 #define ACPI_EC_HC_CLASS "ec_hc_smbus" #define ACPI_EC_HC_HID "ACPI0001" -#define ACPI_EC_HC_DRIVER_NAME "ACPI EC HC smbus driver" #define ACPI_EC_HC_DEVICE_NAME "EC HC smbus" #define _COMPONENT ACPI_EC_HC_COMPONENT -ACPI_MODULE_NAME("acpi_smbus") +ACPI_MODULE_NAME("i2c_ec"); static int acpi_ec_hc_add(struct acpi_device *device); static int acpi_ec_hc_remove(struct acpi_device *device, int type); static struct acpi_driver acpi_ec_hc_driver = { - .name = ACPI_EC_HC_DRIVER_NAME, + .name = "i2c_ec", .class = ACPI_EC_HC_CLASS, .ids = ACPI_EC_HC_HID, .ops = { diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index c6144ca6663..1a0ed3dc409 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c @@ -496,6 +496,10 @@ static int ibm_acpi_driver_init(void) printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); printk(IBM_INFO "%s\n", IBM_URL); + if (ibm_thinkpad_ec_found) + printk(IBM_INFO "ThinkPad EC firmware %s\n", + ibm_thinkpad_ec_found); + return 0; } @@ -2617,7 +2621,7 @@ static void __init ibm_handle_init(char *name, ibm_handle_init(#object, &object##_handle, *object##_parent, \ object##_paths, ARRAY_SIZE(object##_paths), &object##_path) -static int set_ibm_param(const char *val, struct kernel_param *kp) +static int __init set_ibm_param(const char *val, struct kernel_param *kp) { unsigned int i; @@ -2659,7 +2663,8 @@ static void acpi_ibm_exit(void) for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--) ibm_exit(&ibms[i]); - remove_proc_entry(IBM_DIR, acpi_root_dir); + if (proc_dir) + remove_proc_entry(IBM_DIR, acpi_root_dir); if (ibm_thinkpad_ec_found) kfree(ibm_thinkpad_ec_found); @@ -2696,11 +2701,6 @@ static int __init acpi_ibm_init(void) if (acpi_disabled) return -ENODEV; - if (!acpi_specific_hotkey_enabled) { - printk(IBM_ERR "using generic hotkey driver\n"); - return -ENODEV; - } - /* ec is required because many other handles are relative to it */ IBM_HANDLE_INIT(ec); if (!ec_handle) { @@ -2710,9 +2710,6 @@ static int __init acpi_ibm_init(void) /* Models with newer firmware report the EC in DMI */ ibm_thinkpad_ec_found = check_dmi_for_ec(); - if (ibm_thinkpad_ec_found) - printk(IBM_INFO "ThinkPad EC firmware %s\n", - ibm_thinkpad_ec_found); /* these handles are not required */ IBM_HANDLE_INIT(vid); @@ -2742,6 +2739,7 @@ static int __init acpi_ibm_init(void) proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir); if (!proc_dir) { printk(IBM_ERR "unable to create proc dir %s", IBM_DIR); + acpi_ibm_exit(); return -ENODEV; } proc_dir->owner = THIS_MODULE; diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 4a9faff4c01..8fcd6a15517 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -33,7 +33,7 @@ #define ACPI_NUMA 0x80000000 #define _COMPONENT ACPI_NUMA -ACPI_MODULE_NAME("numa") +ACPI_MODULE_NAME("numa"); static nodemask_t nodes_found_map = NODE_MASK_NONE; #define PXM_INVAL -1 @@ -45,12 +45,6 @@ int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS] int __cpuinitdata node_to_pxm_map[MAX_NUMNODES] = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; -extern int __init acpi_table_parse_madt_family(char *id, - unsigned long madt_size, - int entry_id, - acpi_madt_entry_handler handler, - unsigned int max_entries); - int __cpuinit pxm_to_node(int pxm) { if (pxm < 0) @@ -208,9 +202,9 @@ static int __init acpi_parse_srat(struct acpi_table_header *table) int __init acpi_table_parse_srat(enum acpi_srat_type id, - acpi_madt_entry_handler handler, unsigned int max_entries) + acpi_table_entry_handler handler, unsigned int max_entries) { - return acpi_table_parse_madt_family(ACPI_SIG_SRAT, + return acpi_table_parse_entries(ACPI_SIG_SRAT, sizeof(struct acpi_table_srat), id, handler, max_entries); } @@ -220,9 +214,7 @@ int __init acpi_numa_init(void) int result; /* SRAT: Static Resource Affinity Table */ - result = acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat); - - if (result > 0) { + if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) { result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY, acpi_parse_processor_affinity, NR_CPUS); @@ -230,7 +222,7 @@ int __init acpi_numa_init(void) } /* SLIT: System Locality Information Table */ - result = acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); + acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); acpi_numa_arch_fixup(); return 0; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 0f6f3bcbc8e..971eca4864f 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -46,7 +46,7 @@ #include <linux/efi.h> #define _COMPONENT ACPI_OS_SERVICES -ACPI_MODULE_NAME("osl") +ACPI_MODULE_NAME("osl"); #define PREFIX "ACPI: " struct acpi_os_dpc { acpi_osd_exec_callback function; @@ -68,9 +68,6 @@ EXPORT_SYMBOL(acpi_in_debugger); extern char line_buf[80]; #endif /*ENABLE_DEBUGGER */ -int acpi_specific_hotkey_enabled = TRUE; -EXPORT_SYMBOL(acpi_specific_hotkey_enabled); - static unsigned int acpi_irq_irq; static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; @@ -205,7 +202,7 @@ void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size) { if (phys > ULONG_MAX) { printk(KERN_ERR PREFIX "Cannot map memory that high\n"); - return 0; + return NULL; } if (acpi_gbl_permanent_mmap) /* @@ -890,26 +887,6 @@ u32 acpi_os_get_line(char *buffer) } #endif /* ACPI_FUTURE_USAGE */ -/* Assumes no unreadable holes inbetween */ -u8 acpi_os_readable(void *ptr, acpi_size len) -{ -#if defined(__i386__) || defined(__x86_64__) - char tmp; - return !__get_user(tmp, (char __user *)ptr) - && !__get_user(tmp, (char __user *)ptr + len - 1); -#endif - return 1; -} - -#ifdef ACPI_FUTURE_USAGE -u8 acpi_os_writable(void *ptr, acpi_size len) -{ - /* could do dummy write (racy) or a kernel page table lookup. - The later may be difficult at early boot when kmap doesn't work yet. */ - return 1; -} -#endif - acpi_status acpi_os_signal(u32 function, void *info) { switch (function) { @@ -1012,14 +989,6 @@ static int __init acpi_wake_gpes_always_on_setup(char *str) __setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); -static int __init acpi_hotkey_setup(char *str) -{ - acpi_specific_hotkey_enabled = FALSE; - return 1; -} - -__setup("acpi_generic_hotkey", acpi_hotkey_setup); - /* * max_cstate is defined in the base kernel so modules can * change it w/o depending on the state of the processor module. diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index 55f57a61c55..028969370bb 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -36,7 +36,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_bind") +ACPI_MODULE_NAME("pci_bind"); struct acpi_pci_data { struct acpi_pci_id id; diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index fe7d007833a..dd3186abe07 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -38,7 +38,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_irq") +ACPI_MODULE_NAME("pci_irq"); static struct acpi_prt_list acpi_prt; static DEFINE_SPINLOCK(acpi_prt_lock); diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 0f683c8c6fb..acc59477137 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -44,10 +44,9 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_link") +ACPI_MODULE_NAME("pci_link"); #define ACPI_PCI_LINK_CLASS "pci_irq_routing" #define ACPI_PCI_LINK_HID "PNP0C0F" -#define ACPI_PCI_LINK_DRIVER_NAME "ACPI PCI Interrupt Link Driver" #define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link" #define ACPI_PCI_LINK_FILE_INFO "info" #define ACPI_PCI_LINK_FILE_STATUS "state" @@ -56,7 +55,7 @@ static int acpi_pci_link_add(struct acpi_device *device); static int acpi_pci_link_remove(struct acpi_device *device, int type); static struct acpi_driver acpi_pci_link_driver = { - .name = ACPI_PCI_LINK_DRIVER_NAME, + .name = "pci_link", .class = ACPI_PCI_LINK_CLASS, .ids = ACPI_PCI_LINK_HID, .ops = { diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 4ecf701687e..ad4145a3778 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -36,17 +36,16 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_root") +ACPI_MODULE_NAME("pci_root"); #define ACPI_PCI_ROOT_CLASS "pci_bridge" #define ACPI_PCI_ROOT_HID "PNP0A03" -#define ACPI_PCI_ROOT_DRIVER_NAME "ACPI PCI Root Bridge Driver" #define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" static int acpi_pci_root_add(struct acpi_device *device); static int acpi_pci_root_remove(struct acpi_device *device, int type); static int acpi_pci_root_start(struct acpi_device *device); static struct acpi_driver acpi_pci_root_driver = { - .name = ACPI_PCI_ROOT_DRIVER_NAME, + .name = "pci_root", .class = ACPI_PCI_ROOT_CLASS, .ids = ACPI_PCI_ROOT_HID, .ops = { diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 0ba7dfbbb2e..1ef338545df 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -45,10 +45,9 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_POWER_COMPONENT -ACPI_MODULE_NAME("acpi_power") +ACPI_MODULE_NAME("power"); #define ACPI_POWER_COMPONENT 0x00800000 #define ACPI_POWER_CLASS "power_resource" -#define ACPI_POWER_DRIVER_NAME "ACPI Power Resource Driver" #define ACPI_POWER_DEVICE_NAME "Power Resource" #define ACPI_POWER_FILE_INFO "info" #define ACPI_POWER_FILE_STATUS "state" @@ -57,25 +56,33 @@ ACPI_MODULE_NAME("acpi_power") #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF static int acpi_power_add(struct acpi_device *device); static int acpi_power_remove(struct acpi_device *device, int type); +static int acpi_power_resume(struct acpi_device *device); static int acpi_power_open_fs(struct inode *inode, struct file *file); static struct acpi_driver acpi_power_driver = { - .name = ACPI_POWER_DRIVER_NAME, + .name = "power", .class = ACPI_POWER_CLASS, .ids = ACPI_POWER_HID, .ops = { .add = acpi_power_add, .remove = acpi_power_remove, + .resume = acpi_power_resume, }, }; +struct acpi_power_reference { + struct list_head node; + struct acpi_device *device; +}; + struct acpi_power_resource { struct acpi_device * device; acpi_bus_id name; u32 system_level; u32 order; int state; - int references; + struct mutex resource_lock; + struct list_head reference; }; static struct list_head acpi_power_resource_list; @@ -171,22 +178,47 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) return result; } -static int acpi_power_on(acpi_handle handle) +static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) { int result = 0; + int found = 0; acpi_status status = AE_OK; - struct acpi_device *device = NULL; struct acpi_power_resource *resource = NULL; + struct list_head *node, *next; + struct acpi_power_reference *ref; result = acpi_power_get_context(handle, &resource); if (result) return result; - resource->references++; + mutex_lock(&resource->resource_lock); + list_for_each_safe(node, next, &resource->reference) { + ref = container_of(node, struct acpi_power_reference, node); + if (dev->handle == ref->device->handle) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already referenced by resource [%s]\n", + dev->pnp.bus_id, resource->name)); + found = 1; + break; + } + } + + if (!found) { + ref = kmalloc(sizeof (struct acpi_power_reference), + irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); + if (!ref) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "kmalloc() failed\n")); + mutex_unlock(&resource->resource_lock); + return -ENOMEM; + } + list_add_tail(&ref->node, &resource->reference); + ref->device = dev; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] added to resource [%s] references\n", + dev->pnp.bus_id, resource->name)); + } + mutex_unlock(&resource->resource_lock); - if ((resource->references > 1) - || (resource->state == ACPI_POWER_RESOURCE_STATE_ON)) { + if (resource->state == ACPI_POWER_RESOURCE_STATE_ON) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already on\n", resource->name)); return 0; @@ -203,38 +235,49 @@ static int acpi_power_on(acpi_handle handle) return -ENOEXEC; /* Update the power resource's _device_ power state */ - device = resource->device; resource->device->power.state = ACPI_STATE_D0; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned on\n", resource->name)); - return 0; } -static int acpi_power_off_device(acpi_handle handle) +static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev) { int result = 0; acpi_status status = AE_OK; struct acpi_power_resource *resource = NULL; + struct list_head *node, *next; + struct acpi_power_reference *ref; + result = acpi_power_get_context(handle, &resource); if (result) return result; - if (resource->references) - resource->references--; + mutex_lock(&resource->resource_lock); + list_for_each_safe(node, next, &resource->reference) { + ref = container_of(node, struct acpi_power_reference, node); + if (dev->handle == ref->device->handle) { + list_del(&ref->node); + kfree(ref); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] removed from resource [%s] references\n", + dev->pnp.bus_id, resource->name)); + break; + } + } - if (resource->references) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Resource [%s] is still in use, dereferencing\n", - resource->device->pnp.bus_id)); + if (!list_empty(&resource->reference)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cannot turn resource [%s] off - resource is in use\n", + resource->name)); + mutex_unlock(&resource->resource_lock); return 0; } + mutex_unlock(&resource->resource_lock); if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n", - resource->device->pnp.bus_id)); + resource->name)); return 0; } @@ -276,7 +319,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev) arg.integer.value = 1; /* Open power resource */ for (i = 0; i < dev->wakeup.resources.count; i++) { - ret = acpi_power_on(dev->wakeup.resources.handles[i]); + ret = acpi_power_on(dev->wakeup.resources.handles[i], dev); if (ret) { printk(KERN_ERR PREFIX "Transition power state\n"); dev->wakeup.flags.valid = 0; @@ -323,7 +366,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) /* Close power resource */ for (i = 0; i < dev->wakeup.resources.count; i++) { - ret = acpi_power_off_device(dev->wakeup.resources.handles[i]); + ret = acpi_power_off_device(dev->wakeup.resources.handles[i], dev); if (ret) { printk(KERN_ERR PREFIX "Transition power state\n"); dev->wakeup.flags.valid = 0; @@ -407,16 +450,20 @@ int acpi_power_transition(struct acpi_device *device, int state) * (e.g. so the device doesn't lose power while transitioning). */ for (i = 0; i < tl->count; i++) { - result = acpi_power_on(tl->handles[i]); + result = acpi_power_on(tl->handles[i], device); if (result) goto end; } + if (device->power.state == state) { + goto end; + } + /* * Then we dereference all power resources used in the current list. */ for (i = 0; i < cl->count; i++) { - result = acpi_power_off_device(cl->handles[i]); + result = acpi_power_off_device(cl->handles[i], device); if (result) goto end; } @@ -439,7 +486,11 @@ static struct proc_dir_entry *acpi_power_dir; static int acpi_power_seq_show(struct seq_file *seq, void *offset) { + int count = 0; + int result = 0; struct acpi_power_resource *resource = NULL; + struct list_head *node, *next; + struct acpi_power_reference *ref; resource = seq->private; @@ -447,6 +498,10 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset) if (!resource) goto end; + result = acpi_power_get_state(resource); + if (result) + goto end; + seq_puts(seq, "state: "); switch (resource->state) { case ACPI_POWER_RESOURCE_STATE_ON: @@ -460,11 +515,18 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset) break; } + mutex_lock(&resource->resource_lock); + list_for_each_safe(node, next, &resource->reference) { + ref = container_of(node, struct acpi_power_reference, node); + count++; + } + mutex_unlock(&resource->resource_lock); + seq_printf(seq, "system level: S%d\n" "order: %d\n" "reference count: %d\n", resource->system_level, - resource->order, resource->references); + resource->order, count); end: return 0; @@ -537,6 +599,8 @@ static int acpi_power_add(struct acpi_device *device) return -ENOMEM; resource->device = device; + mutex_init(&resource->resource_lock); + INIT_LIST_HEAD(&resource->reference); strcpy(resource->name, device->pnp.bus_id); strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_POWER_CLASS); @@ -584,6 +648,7 @@ static int acpi_power_add(struct acpi_device *device) static int acpi_power_remove(struct acpi_device *device, int type) { struct acpi_power_resource *resource = NULL; + struct list_head *node, *next; if (!device || !acpi_driver_data(device)) @@ -593,11 +658,54 @@ static int acpi_power_remove(struct acpi_device *device, int type) acpi_power_remove_fs(device); + mutex_lock(&resource->resource_lock); + list_for_each_safe(node, next, &resource->reference) { + struct acpi_power_reference *ref = container_of(node, struct acpi_power_reference, node); + list_del(&ref->node); + kfree(ref); + } + mutex_unlock(&resource->resource_lock); + kfree(resource); return 0; } +static int acpi_power_resume(struct acpi_device *device) +{ + int result = 0; + struct acpi_power_resource *resource = NULL; + struct acpi_power_reference *ref; + + if (!device || !acpi_driver_data(device)) + return -EINVAL; + + resource = (struct acpi_power_resource *)acpi_driver_data(device); + + result = acpi_power_get_state(resource); + if (result) + return result; + + mutex_lock(&resource->resource_lock); + if ((resource->state == ACPI_POWER_RESOURCE_STATE_ON) && + list_empty(&resource->reference)) { + mutex_unlock(&resource->resource_lock); + result = acpi_power_off_device(device->handle, NULL); + return result; + } + + if ((resource->state == ACPI_POWER_RESOURCE_STATE_OFF) && + !list_empty(&resource->reference)) { + ref = container_of(resource->reference.next, struct acpi_power_reference, node); + mutex_unlock(&resource->resource_lock); + result = acpi_power_on(device->handle, ref->device); + return result; + } + + mutex_unlock(&resource->resource_lock); + return 0; +} + static int __init acpi_power_init(void) { int result = 0; diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 0079bc51082..99d1516d1e7 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -60,7 +60,6 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define ACPI_PROCESSOR_DEVICE_NAME "Processor" #define ACPI_PROCESSOR_FILE_INFO "info" #define ACPI_PROCESSOR_FILE_THROTTLING "throttling" @@ -74,10 +73,10 @@ #define ACPI_STA_PRESENT 0x00000001 #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_core"); - MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME); +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION("ACPI Processor Driver"); MODULE_LICENSE("GPL"); static int acpi_processor_add(struct acpi_device *device); @@ -89,7 +88,7 @@ static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); static int acpi_processor_handle_eject(struct acpi_processor *pr); static struct acpi_driver acpi_processor_driver = { - .name = ACPI_PROCESSOR_DRIVER_NAME, + .name = "processor", .class = ACPI_PROCESSOR_CLASS, .ids = ACPI_PROCESSOR_HID, .ops = { @@ -404,7 +403,7 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, if (lsapic->lapic_flags & ACPI_MADT_ENABLED) { /* First check against id */ if (lsapic->processor_id == acpi_id) { - *apic_id = lsapic->id; + *apic_id = (lsapic->id << 8) | lsapic->eid; return 1; /* Check against optional uid */ } else if (entry->length >= 16 && @@ -1005,7 +1004,7 @@ static int __init acpi_processor_init(void) #ifdef CONFIG_SMP if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, (struct acpi_table_header **)&madt))) - madt = 0; + madt = NULL; #endif acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 8206fc1ecc5..60773005b8a 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -51,6 +51,14 @@ #include <asm/apic.h> #endif +/* + * Include the apic definitions for x86 to have the APIC timer related defines + * available also for UP (on SMP it gets magically included via linux/smp.h). + */ +#ifdef CONFIG_X86 +#include <asm/apic.h> +#endif + #include <asm/io.h> #include <asm/uaccess.h> @@ -59,9 +67,8 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_idle"); #define ACPI_PROCESSOR_FILE_POWER "power" #define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000) #define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */ diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 058f13cf3b7..2f2e7964226 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -44,10 +44,9 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_perflib"); static DEFINE_MUTEX(performance_mutex); diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 40fecd67ad8..06e6f3fb882 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -41,9 +41,8 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_thermal"); /* -------------------------------------------------------------------------- Limit Interface diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 89dff3639ab..b33486009f4 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -41,9 +41,8 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_throttling"); /* -------------------------------------------------------------------------- Throttling Control diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index f58fc7447ab..59640d9a0ac 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -59,7 +59,6 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); #define ACPI_AC_CLASS "ac_adapter" #define ACPI_BATTERY_CLASS "battery" #define ACPI_SBS_HID "ACPI0002" -#define ACPI_SBS_DRIVER_NAME "ACPI Smart Battery System Driver" #define ACPI_SBS_DEVICE_NAME "Smart Battery System" #define ACPI_SBS_FILE_INFO "info" #define ACPI_SBS_FILE_STATE "state" @@ -78,7 +77,7 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); #define MAX_SBS_BAT 4 #define MAX_SMBUS_ERR 1 -ACPI_MODULE_NAME("acpi_sbs"); +ACPI_MODULE_NAME("sbs"); MODULE_AUTHOR("Rich Townsend"); MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); @@ -110,7 +109,7 @@ static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus); static void acpi_sbs_update_queue(void *data); static struct acpi_driver acpi_sbs_driver = { - .name = ACPI_SBS_DRIVER_NAME, + .name = "sbs", .class = ACPI_SBS_CLASS, .ids = ACPI_SBS_HID, .ops = { @@ -1034,21 +1033,19 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) } else { seq_printf(seq, "capacity state: ok\n"); } + + foo = (s16) battery->state.amperage * battery->info.ipscale; + if (battery->info.capacity_mode) { + foo = foo * battery->info.design_voltage / 1000; + } if (battery->state.amperage < 0) { seq_printf(seq, "charging state: discharging\n"); - foo = battery->state.remaining_capacity * cscale * 60 / - (battery->state.average_time_to_empty == 0 ? 1 : - battery->state.average_time_to_empty); - seq_printf(seq, "present rate: %i%s\n", - foo, battery->info.capacity_mode ? "0 mW" : " mA"); + seq_printf(seq, "present rate: %d %s\n", + -foo, battery->info.capacity_mode ? "mW" : "mA"); } else if (battery->state.amperage > 0) { seq_printf(seq, "charging state: charging\n"); - foo = (battery->info.full_charge_capacity - - battery->state.remaining_capacity) * cscale * 60 / - (battery->state.average_time_to_full == 0 ? 1 : - battery->state.average_time_to_full); - seq_printf(seq, "present rate: %i%s\n", - foo, battery->info.capacity_mode ? "0 mW" : " mA"); + seq_printf(seq, "present rate: %d %s\n", + foo, battery->info.capacity_mode ? "mW" : "mA"); } else { seq_printf(seq, "charging state: charged\n"); seq_printf(seq, "present rate: 0 %s\n", diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 64f26db10c8..bb0e0da39fb 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -11,13 +11,12 @@ #include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */ #define _COMPONENT ACPI_BUS_COMPONENT -ACPI_MODULE_NAME("scan") +ACPI_MODULE_NAME("scan"); #define STRUCT_TO_INT(s) (*((int*)&s)) extern struct acpi_device *acpi_root; #define ACPI_BUS_CLASS "system_bus" #define ACPI_BUS_HID "ACPI_BUS" -#define ACPI_BUS_DRIVER_NAME "ACPI Bus Driver" #define ACPI_BUS_DEVICE_NAME "System Bus" static LIST_HEAD(acpi_device_list); diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 62ce87d7165..37a0930fc0a 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -200,7 +200,7 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { {}, }; -static int __init acpi_sleep_init(void) +int __init acpi_sleep_init(void) { int i = 0; @@ -229,4 +229,3 @@ static int __init acpi_sleep_init(void) return 0; } -late_initcall(acpi_sleep_init); diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 7147b0bdab0..83a8d309790 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -31,14 +31,13 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME("acpi_system") +ACPI_MODULE_NAME("system"); #ifdef MODULE_PARAM_PREFIX #undef MODULE_PARAM_PREFIX #endif #define MODULE_PARAM_PREFIX "acpi." #define ACPI_SYSTEM_CLASS "system" -#define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver" #define ACPI_SYSTEM_DEVICE_NAME "System" #define ACPI_SYSTEM_FILE_INFO "info" #define ACPI_SYSTEM_FILE_EVENT "event" diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 45bd17313c4..849e2c36180 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -169,40 +169,40 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header * header) int __init -acpi_table_parse_madt_family(char *id, - unsigned long madt_size, +acpi_table_parse_entries(char *id, + unsigned long table_size, int entry_id, - acpi_madt_entry_handler handler, + acpi_table_entry_handler handler, unsigned int max_entries) { - struct acpi_table_header *madt = NULL; + struct acpi_table_header *table_header = NULL; struct acpi_subtable_header *entry; unsigned int count = 0; - unsigned long madt_end; + unsigned long table_end; if (!handler) return -EINVAL; - /* Locate the MADT (if exists). There should only be one. */ - acpi_get_table(id, 0, &madt); + /* Locate the table (if exists). There should only be one. */ + acpi_get_table(id, 0, &table_header); - if (!madt) { + if (!table_header) { printk(KERN_WARNING PREFIX "%4.4s not present\n", id); return -ENODEV; } - madt_end = (unsigned long)madt + madt->length; + table_end = (unsigned long)table_header + table_header->length; /* Parse all entries looking for a match. */ entry = (struct acpi_subtable_header *) - ((unsigned long)madt + madt_size); + ((unsigned long)table_header + table_size); while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < - madt_end) { + table_end) { if (entry->type == entry_id && (!max_entries || count++ < max_entries)) - if (handler(entry, madt_end)) + if (handler(entry, table_end)) return -EINVAL; entry = (struct acpi_subtable_header *) @@ -218,13 +218,22 @@ acpi_table_parse_madt_family(char *id, int __init acpi_table_parse_madt(enum acpi_madt_type id, - acpi_madt_entry_handler handler, unsigned int max_entries) + acpi_table_entry_handler handler, unsigned int max_entries) { - return acpi_table_parse_madt_family(ACPI_SIG_MADT, + return acpi_table_parse_entries(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), id, handler, max_entries); } +/** + * acpi_table_parse - find table with @id, run @handler on it + * + * @id: table id to find + * @handler: handler to run + * + * Scan the ACPI System Descriptor Table (STD) for a table matching @id, + * run @handler on it. Return 0 if table found, return on if not. + */ int __init acpi_table_parse(char *id, acpi_table_handler handler) { struct acpi_table_header *table = NULL; @@ -234,9 +243,9 @@ int __init acpi_table_parse(char *id, acpi_table_handler handler) acpi_get_table(id, 0, &table); if (table) { handler(table); - return 1; - } else return 0; + } else + return 1; } /* diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 807978d5381..417ef5fa766 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -338,9 +338,9 @@ acpi_status acpi_unload_table_id(acpi_owner_id id) int i; acpi_status status = AE_NOT_EXIST; - ACPI_FUNCTION_TRACE(acpi_unload_table); + ACPI_FUNCTION_TRACE(acpi_unload_table_id); - /* Find table from the requested type list */ + /* Find table in the global table list */ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { if (id != acpi_gbl_root_table_list.tables[i].owner_id) { continue; @@ -352,8 +352,9 @@ acpi_status acpi_unload_table_id(acpi_owner_id id) * simply a position within the hierarchy */ acpi_tb_delete_namespace_by_owner(i); - acpi_tb_release_owner_id(i); + status = acpi_tb_release_owner_id(i); acpi_tb_set_table_loaded_flag(i, FALSE); + break; } return_ACPI_STATUS(status); } @@ -408,7 +409,7 @@ acpi_get_table(char *signature, } if (!acpi_gbl_permanent_mmap) { - acpi_gbl_root_table_list.tables[i].pointer = 0; + acpi_gbl_root_table_list.tables[i].pointer = NULL; } return (status); diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 986afd470a1..0ae8b9310cb 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -47,7 +47,6 @@ #define ACPI_THERMAL_COMPONENT 0x04000000 #define ACPI_THERMAL_CLASS "thermal_zone" -#define ACPI_THERMAL_DRIVER_NAME "ACPI Thermal Zone Driver" #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone" #define ACPI_THERMAL_FILE_STATE "state" #define ACPI_THERMAL_FILE_TEMPERATURE "temperature" @@ -71,10 +70,10 @@ #define CELSIUS_TO_KELVIN(t) ((t+273)*10) #define _COMPONENT ACPI_THERMAL_COMPONENT -ACPI_MODULE_NAME("acpi_thermal") +ACPI_MODULE_NAME("thermal"); MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_THERMAL_DRIVER_NAME); +MODULE_DESCRIPTION("ACPI Thermal Zone Driver"); MODULE_LICENSE("GPL"); static int tzp; @@ -99,7 +98,7 @@ static ssize_t acpi_thermal_write_polling(struct file *, const char __user *, size_t, loff_t *); static struct acpi_driver acpi_thermal_driver = { - .name = ACPI_THERMAL_DRIVER_NAME, + .name = "thermal", .class = ACPI_THERMAL_CLASS, .ids = ACPI_THERMAL_HID, .ops = { @@ -270,7 +269,7 @@ static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency set to %lu seconds\n", - tz->polling_frequency)); + tz->polling_frequency/10)); return 0; } @@ -1357,28 +1356,32 @@ static int acpi_thermal_remove(struct acpi_device *device, int type) static int acpi_thermal_resume(struct acpi_device *device) { struct acpi_thermal *tz = NULL; - int i; + int i, j, power_state, result; + if (!device || !acpi_driver_data(device)) return -EINVAL; tz = acpi_driver_data(device); - acpi_thermal_get_temperature(tz); - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { - if (tz->trips.active[i].flags.valid) { - tz->temperature = tz->trips.active[i].temperature; - tz->trips.active[i].flags.enabled = 0; - - acpi_thermal_active(tz); - - tz->state.active |= tz->trips.active[i].flags.enabled; - tz->state.active_index = i; + if (!(&tz->trips.active[i])) + break; + if (!tz->trips.active[i].flags.valid) + break; + tz->trips.active[i].flags.enabled = 1; + for (j = 0; j < tz->trips.active[i].devices.count; j++) { + result = acpi_bus_get_power(tz->trips.active[i].devices. + handles[j], &power_state); + if (result || (power_state != ACPI_STATE_D0)) { + tz->trips.active[i].flags.enabled = 0; + break; + } } + tz->state.active |= tz->trips.active[i].flags.enabled; } - acpi_thermal_check(tz); + acpi_thermal_check(tz); return AE_OK; } diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index d9b651ffcdc..faf8a5232d8 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -125,7 +125,7 @@ static int write_acpi_int(const char *methodName, int val) union acpi_object in_objs[1]; acpi_status status; - params.count = sizeof(in_objs) / sizeof(in_objs[0]); + params.count = ARRAY_SIZE(in_objs); params.pointer = in_objs; in_objs[0].type = ACPI_TYPE_INTEGER; in_objs[0].integer.value = val; @@ -561,10 +561,6 @@ static int __init toshiba_acpi_init(void) if (acpi_disabled) return -ENODEV; - if (!acpi_specific_hotkey_enabled) { - printk(MY_INFO "Using generic hotkey driver\n"); - return -ENODEV; - } /* simple device detection: look for HCI method */ if (is_valid_acpi_path(METHOD_HCI_1)) method_hci = METHOD_HCI_1; diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index f777cebdc46..673a0caa407 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -170,7 +170,6 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) acpi_os_delete_mutex(object->mutex.os_mutex); acpi_gbl_global_lock_mutex = NULL; } else { - acpi_ex_unlink_mutex(object); acpi_os_delete_mutex(object->mutex.os_mutex); } break; diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 68a809fa7b1..34f15757108 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -31,7 +31,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_BUS_COMPONENT -ACPI_MODULE_NAME("acpi_utils") +ACPI_MODULE_NAME("utils"); /* -------------------------------------------------------------------------- Object Evaluation Helpers diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index e0b97add8c6..bf525cca3b6 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -40,7 +40,6 @@ #define ACPI_VIDEO_COMPONENT 0x08000000 #define ACPI_VIDEO_CLASS "video" -#define ACPI_VIDEO_DRIVER_NAME "ACPI Video Driver" #define ACPI_VIDEO_BUS_NAME "Video Bus" #define ACPI_VIDEO_DEVICE_NAME "Video Device" #define ACPI_VIDEO_NOTIFY_SWITCH 0x80 @@ -65,17 +64,17 @@ #define ACPI_VIDEO_DISPLAY_LCD 4 #define _COMPONENT ACPI_VIDEO_COMPONENT -ACPI_MODULE_NAME("acpi_video") +ACPI_MODULE_NAME("video"); - MODULE_AUTHOR("Bruno Ducrot"); -MODULE_DESCRIPTION(ACPI_VIDEO_DRIVER_NAME); +MODULE_AUTHOR("Bruno Ducrot"); +MODULE_DESCRIPTION("ACPI Video Driver"); MODULE_LICENSE("GPL"); static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device, int type); static struct acpi_driver acpi_video_bus = { - .name = ACPI_VIDEO_DRIVER_NAME, + .name = "video", .class = ACPI_VIDEO_CLASS, .ids = ACPI_VIDEO_HID, .ops = { diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 3747457fee7..4af0a4bb578 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -161,6 +161,19 @@ config SATA_INTEL_COMBINED depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX) default y +config SATA_ACPI + bool + depends on ACPI && PCI + default y + help + This option adds support for SATA-related ACPI objects. + These ACPI objects add the ability to retrieve taskfiles + from the ACPI BIOS and write them to the disk controller. + These objects may be related to performance, security, + power management, or other areas. + You can disable this at kernel boot time by using the + option libata.noacpi=1 + config PATA_ALI tristate "ALi PATA support (Experimental)" depends on PCI && EXPERIMENTAL diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index cd096f0c78a..74298afbbaa 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -66,4 +66,4 @@ obj-$(CONFIG_ATA_GENERIC) += ata_generic.o obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o - +libata-$(CONFIG_SATA_ACPI) += libata-acpi.o diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c new file mode 100644 index 00000000000..b4e8be5d292 --- /dev/null +++ b/drivers/ata/libata-acpi.c @@ -0,0 +1,698 @@ +/* + * libata-acpi.c + * Provides ACPI support for PATA/SATA. + * + * Copyright (C) 2006 Intel Corp. + * Copyright (C) 2006 Randy Dunlap + */ + +#include <linux/ata.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/acpi.h> +#include <linux/libata.h> +#include <linux/pci.h> +#include "libata.h" + +#include <acpi/acpi_bus.h> +#include <acpi/acnames.h> +#include <acpi/acnamesp.h> +#include <acpi/acparser.h> +#include <acpi/acexcep.h> +#include <acpi/acmacros.h> +#include <acpi/actypes.h> + +#define SATA_ROOT_PORT(x) (((x) >> 16) & 0xffff) +#define SATA_PORT_NUMBER(x) ((x) & 0xffff) /* or NO_PORT_MULT */ +#define NO_PORT_MULT 0xffff +#define SATA_ADR_RSVD 0xffffffff + +#define REGS_PER_GTF 7 +struct taskfile_array { + u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ +}; + + +/** + * sata_get_dev_handle - finds acpi_handle and PCI device.function + * @dev: device to locate + * @handle: returned acpi_handle for @dev + * @pcidevfn: return PCI device.func for @dev + * + * This function is somewhat SATA-specific. Or at least the + * PATA & SATA versions of this function are different, + * so it's not entirely generic code. + * + * Returns 0 on success, <0 on error. + */ +static int sata_get_dev_handle(struct device *dev, acpi_handle *handle, + acpi_integer *pcidevfn) +{ + struct pci_dev *pci_dev; + acpi_integer addr; + + pci_dev = to_pci_dev(dev); /* NOTE: PCI-specific */ + /* Please refer to the ACPI spec for the syntax of _ADR. */ + addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); + *pcidevfn = addr; + *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr); + if (!*handle) + return -ENODEV; + return 0; +} + +/** + * pata_get_dev_handle - finds acpi_handle and PCI device.function + * @dev: device to locate + * @handle: returned acpi_handle for @dev + * @pcidevfn: return PCI device.func for @dev + * + * The PATA and SATA versions of this function are different. + * + * Returns 0 on success, <0 on error. + */ +static int pata_get_dev_handle(struct device *dev, acpi_handle *handle, + acpi_integer *pcidevfn) +{ + unsigned int bus, devnum, func; + acpi_integer addr; + acpi_handle dev_handle, parent_handle; + struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER, + .pointer = NULL}; + acpi_status status; + struct acpi_device_info *dinfo = NULL; + int ret = -ENODEV; + struct pci_dev *pdev = to_pci_dev(dev); + + bus = pdev->bus->number; + devnum = PCI_SLOT(pdev->devfn); + func = PCI_FUNC(pdev->devfn); + + dev_handle = DEVICE_ACPI_HANDLE(dev); + parent_handle = DEVICE_ACPI_HANDLE(dev->parent); + + status = acpi_get_object_info(parent_handle, &buffer); + if (ACPI_FAILURE(status)) + goto err; + + dinfo = buffer.pointer; + if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && + dinfo->address == bus) { + /* ACPI spec for _ADR for PCI bus: */ + addr = (acpi_integer)(devnum << 16 | func); + *pcidevfn = addr; + *handle = dev_handle; + } else { + goto err; + } + + if (!*handle) + goto err; + ret = 0; +err: + kfree(dinfo); + return ret; +} + +struct walk_info { /* can be trimmed some */ + struct device *dev; + struct acpi_device *adev; + acpi_handle handle; + acpi_integer pcidevfn; + unsigned int drivenum; + acpi_handle obj_handle; + struct ata_port *ataport; + struct ata_device *atadev; + u32 sata_adr; + int status; + char basepath[ACPI_PATHNAME_MAX]; + int basepath_len; +}; + +static acpi_status get_devices(acpi_handle handle, + u32 level, void *context, void **return_value) +{ + acpi_status status; + struct walk_info *winfo = context; + struct acpi_buffer namebuf = {ACPI_ALLOCATE_BUFFER, NULL}; + char *pathname; + struct acpi_buffer buffer; + struct acpi_device_info *dinfo; + + status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &namebuf); + if (status) + goto ret; + pathname = namebuf.pointer; + + buffer.length = ACPI_ALLOCATE_BUFFER; + buffer.pointer = NULL; + status = acpi_get_object_info(handle, &buffer); + if (ACPI_FAILURE(status)) + goto out2; + + dinfo = buffer.pointer; + + /* find full device path name for pcidevfn */ + if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && + dinfo->address == winfo->pcidevfn) { + if (ata_msg_probe(winfo->ataport)) + ata_dev_printk(winfo->atadev, KERN_DEBUG, + ":%s: matches pcidevfn (0x%llx)\n", + pathname, winfo->pcidevfn); + strlcpy(winfo->basepath, pathname, + sizeof(winfo->basepath)); + winfo->basepath_len = strlen(pathname); + goto out; + } + + /* if basepath is not yet known, ignore this object */ + if (!winfo->basepath_len) + goto out; + + /* if this object is in scope of basepath, maybe use it */ + if (strncmp(pathname, winfo->basepath, + winfo->basepath_len) == 0) { + if (!(dinfo->valid & ACPI_VALID_ADR)) + goto out; + if (ata_msg_probe(winfo->ataport)) + ata_dev_printk(winfo->atadev, KERN_DEBUG, + "GOT ONE: (%s) root_port = 0x%llx," + " port_num = 0x%llx\n", pathname, + SATA_ROOT_PORT(dinfo->address), + SATA_PORT_NUMBER(dinfo->address)); + /* heuristics: */ + if (SATA_PORT_NUMBER(dinfo->address) != NO_PORT_MULT) + if (ata_msg_probe(winfo->ataport)) + ata_dev_printk(winfo->atadev, + KERN_DEBUG, "warning: don't" + " know how to handle SATA port" + " multiplier\n"); + if (SATA_ROOT_PORT(dinfo->address) == + winfo->ataport->port_no && + SATA_PORT_NUMBER(dinfo->address) == NO_PORT_MULT) { + if (ata_msg_probe(winfo->ataport)) + ata_dev_printk(winfo->atadev, + KERN_DEBUG, + "THIS ^^^^^ is the requested" + " SATA drive (handle = 0x%p)\n", + handle); + winfo->sata_adr = dinfo->address; + winfo->obj_handle = handle; + } + } +out: + kfree(dinfo); +out2: + kfree(pathname); + +ret: + return status; +} + +/* Get the SATA drive _ADR object. */ +static int get_sata_adr(struct device *dev, acpi_handle handle, + acpi_integer pcidevfn, unsigned int drive, + struct ata_port *ap, + struct ata_device *atadev, u32 *dev_adr) +{ + acpi_status status; + struct walk_info *winfo; + int err = -ENOMEM; + + winfo = kzalloc(sizeof(struct walk_info), GFP_KERNEL); + if (!winfo) + goto out; + + winfo->dev = dev; + winfo->atadev = atadev; + winfo->ataport = ap; + if (acpi_bus_get_device(handle, &winfo->adev) < 0) + if (ata_msg_probe(ap)) + ata_dev_printk(winfo->atadev, KERN_DEBUG, + "acpi_bus_get_device failed\n"); + winfo->handle = handle; + winfo->pcidevfn = pcidevfn; + winfo->drivenum = drive; + + status = acpi_get_devices(NULL, get_devices, winfo, NULL); + if (ACPI_FAILURE(status)) { + if (ata_msg_probe(ap)) + ata_dev_printk(winfo->atadev, KERN_DEBUG, + "%s: acpi_get_devices failed\n", + __FUNCTION__); + err = -ENODEV; + } else { + *dev_adr = winfo->sata_adr; + atadev->obj_handle = winfo->obj_handle; + err = 0; + } + kfree(winfo); +out: + return err; +} + +/** + * do_drive_get_GTF - get the drive bootup default taskfile settings + * @ap: the ata_port for the drive + * @ix: target ata_device (drive) index + * @gtf_length: number of bytes of _GTF data returned at @gtf_address + * @gtf_address: buffer containing _GTF taskfile arrays + * + * This applies to both PATA and SATA drives. + * + * The _GTF method has no input parameters. + * It returns a variable number of register set values (registers + * hex 1F1..1F7, taskfiles). + * The <variable number> is not known in advance, so have ACPI-CA + * allocate the buffer as needed and return it, then free it later. + * + * The returned @gtf_length and @gtf_address are only valid if the + * function return value is 0. + */ +static int do_drive_get_GTF(struct ata_port *ap, int ix, + unsigned int *gtf_length, unsigned long *gtf_address, + unsigned long *obj_loc) +{ + acpi_status status; + acpi_handle dev_handle = NULL; + acpi_handle chan_handle, drive_handle; + acpi_integer pcidevfn = 0; + u32 dev_adr; + struct acpi_buffer output; + union acpi_object *out_obj; + struct device *dev = ap->host->dev; + struct ata_device *atadev = &ap->device[ix]; + int err = -ENODEV; + + *gtf_length = 0; + *gtf_address = 0UL; + *obj_loc = 0UL; + + if (noacpi) + return 0; + + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: ENTER: ap->id: %d, port#: %d\n", + __FUNCTION__, ap->id, ap->port_no); + + if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED)) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: ERR: " + "ata_dev_present: %d, PORT_DISABLED: %lu\n", + __FUNCTION__, ata_dev_enabled(atadev), + ap->flags & ATA_FLAG_DISABLED); + goto out; + } + + /* Don't continue if device has no _ADR method. + * _GTF is intended for known motherboard devices. */ + if (!(ap->cbl == ATA_CBL_SATA)) { + err = pata_get_dev_handle(dev, &dev_handle, &pcidevfn); + if (err < 0) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: pata_get_dev_handle failed (%d)\n", + __FUNCTION__, err); + goto out; + } + } else { + err = sata_get_dev_handle(dev, &dev_handle, &pcidevfn); + if (err < 0) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: sata_get_dev_handle failed (%d\n", + __FUNCTION__, err); + goto out; + } + } + + /* Get this drive's _ADR info. if not already known. */ + if (!atadev->obj_handle) { + if (!(ap->cbl == ATA_CBL_SATA)) { + /* get child objects of dev_handle == channel objects, + * + _their_ children == drive objects */ + /* channel is ap->port_no */ + chan_handle = acpi_get_child(dev_handle, + ap->port_no); + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: chan adr=%d: chan_handle=0x%p\n", + __FUNCTION__, ap->port_no, + chan_handle); + if (!chan_handle) { + err = -ENODEV; + goto out; + } + /* TBD: could also check ACPI object VALID bits */ + drive_handle = acpi_get_child(chan_handle, ix); + if (!drive_handle) { + err = -ENODEV; + goto out; + } + dev_adr = ix; + atadev->obj_handle = drive_handle; + } else { /* for SATA mode */ + dev_adr = SATA_ADR_RSVD; + err = get_sata_adr(dev, dev_handle, pcidevfn, 0, + ap, atadev, &dev_adr); + } + if (err < 0 || dev_adr == SATA_ADR_RSVD || + !atadev->obj_handle) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: get_sata/pata_adr failed: " + "err=%d, dev_adr=%u, obj_handle=0x%p\n", + __FUNCTION__, err, dev_adr, + atadev->obj_handle); + goto out; + } + } + + /* Setting up output buffer */ + output.length = ACPI_ALLOCATE_BUFFER; + output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ + + /* _GTF has no input parameters */ + err = -EIO; + status = acpi_evaluate_object(atadev->obj_handle, "_GTF", + NULL, &output); + if (ACPI_FAILURE(status)) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: Run _GTF error: status = 0x%x\n", + __FUNCTION__, status); + goto out; + } + + if (!output.length || !output.pointer) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: Run _GTF: " + "length or ptr is NULL (0x%llx, 0x%p)\n", + __FUNCTION__, + (unsigned long long)output.length, + output.pointer); + kfree(output.pointer); + goto out; + } + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) { + kfree(output.pointer); + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: Run _GTF: " + "error: expected object type of " + " ACPI_TYPE_BUFFER, got 0x%x\n", + __FUNCTION__, out_obj->type); + err = -ENOENT; + goto out; + } + + if (!out_obj->buffer.length || !out_obj->buffer.pointer || + out_obj->buffer.length % REGS_PER_GTF) { + if (ata_msg_drv(ap)) + ata_dev_printk(atadev, KERN_ERR, + "%s: unexpected GTF length (%d) or addr (0x%p)\n", + __FUNCTION__, out_obj->buffer.length, + out_obj->buffer.pointer); + err = -ENOENT; + goto out; + } + + *gtf_length = out_obj->buffer.length; + *gtf_address = (unsigned long)out_obj->buffer.pointer; + *obj_loc = (unsigned long)out_obj; + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: returning " + "gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n", + __FUNCTION__, *gtf_length, *gtf_address, *obj_loc); + err = 0; +out: + return err; +} + +/** + * taskfile_load_raw - send taskfile registers to host controller + * @ap: Port to which output is sent + * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) + * + * Outputs ATA taskfile to standard ATA host controller using MMIO + * or PIO as indicated by the ATA_FLAG_MMIO flag. + * Writes the control, feature, nsect, lbal, lbam, and lbah registers. + * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect, + * hob_lbal, hob_lbam, and hob_lbah. + * + * This function waits for idle (!BUSY and !DRQ) after writing + * registers. If the control register has a new value, this + * function also waits for idle after writing control and before + * writing the remaining registers. + * + * LOCKING: TBD: + * Inherited from caller. + */ +static void taskfile_load_raw(struct ata_port *ap, + struct ata_device *atadev, + const struct taskfile_array *gtf) +{ + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: (0x1f1-1f7): hex: " + "%02x %02x %02x %02x %02x %02x %02x\n", + __FUNCTION__, + gtf->tfa[0], gtf->tfa[1], gtf->tfa[2], + gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]); + + if ((gtf->tfa[0] == 0) && (gtf->tfa[1] == 0) && (gtf->tfa[2] == 0) + && (gtf->tfa[3] == 0) && (gtf->tfa[4] == 0) && (gtf->tfa[5] == 0) + && (gtf->tfa[6] == 0)) + return; + + if (ap->ops->qc_issue) { + struct ata_taskfile tf; + unsigned int err; + + ata_tf_init(atadev, &tf); + + /* convert gtf to tf */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ + tf.protocol = atadev->class == ATA_DEV_ATAPI ? + ATA_PROT_ATAPI_NODATA : ATA_PROT_NODATA; + tf.feature = gtf->tfa[0]; /* 0x1f1 */ + tf.nsect = gtf->tfa[1]; /* 0x1f2 */ + tf.lbal = gtf->tfa[2]; /* 0x1f3 */ + tf.lbam = gtf->tfa[3]; /* 0x1f4 */ + tf.lbah = gtf->tfa[4]; /* 0x1f5 */ + tf.device = gtf->tfa[5]; /* 0x1f6 */ + tf.command = gtf->tfa[6]; /* 0x1f7 */ + + err = ata_exec_internal(atadev, &tf, NULL, DMA_NONE, NULL, 0); + if (err && ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_ERR, + "%s: ata_exec_internal failed: %u\n", + __FUNCTION__, err); + } else + if (ata_msg_warn(ap)) + ata_dev_printk(atadev, KERN_WARNING, + "%s: SATA driver is missing qc_issue function" + " entry points\n", + __FUNCTION__); +} + +/** + * do_drive_set_taskfiles - write the drive taskfile settings from _GTF + * @ap: the ata_port for the drive + * @atadev: target ata_device + * @gtf_length: total number of bytes of _GTF taskfiles + * @gtf_address: location of _GTF taskfile arrays + * + * This applies to both PATA and SATA drives. + * + * Write {gtf_address, length gtf_length} in groups of + * REGS_PER_GTF bytes. + */ +static int do_drive_set_taskfiles(struct ata_port *ap, + struct ata_device *atadev, unsigned int gtf_length, + unsigned long gtf_address) +{ + int err = -ENODEV; + int gtf_count = gtf_length / REGS_PER_GTF; + int ix; + struct taskfile_array *gtf; + + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: ENTER: ap->id: %d, port#: %d\n", + __FUNCTION__, ap->id, ap->port_no); + + if (noacpi || !(ap->cbl == ATA_CBL_SATA)) + return 0; + + if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED)) + goto out; + if (!gtf_count) /* shouldn't be here */ + goto out; + + if (gtf_length % REGS_PER_GTF) { + if (ata_msg_drv(ap)) + ata_dev_printk(atadev, KERN_ERR, + "%s: unexpected GTF length (%d)\n", + __FUNCTION__, gtf_length); + goto out; + } + + for (ix = 0; ix < gtf_count; ix++) { + gtf = (struct taskfile_array *) + (gtf_address + ix * REGS_PER_GTF); + + /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ + taskfile_load_raw(ap, atadev, gtf); + } + + err = 0; +out: + return err; +} + +/** + * ata_acpi_exec_tfs - get then write drive taskfile settings + * @ap: the ata_port for the drive + * + * This applies to both PATA and SATA drives. + */ +int ata_acpi_exec_tfs(struct ata_port *ap) +{ + int ix; + int ret =0; + unsigned int gtf_length; + unsigned long gtf_address; + unsigned long obj_loc; + + if (noacpi) + return 0; + + for (ix = 0; ix < ATA_MAX_DEVICES; ix++) { + if (!ata_dev_enabled(&ap->device[ix])) + continue; + + ret = do_drive_get_GTF(ap, ix, + >f_length, >f_address, &obj_loc); + if (ret < 0) { + if (ata_msg_probe(ap)) + ata_port_printk(ap, KERN_DEBUG, + "%s: get_GTF error (%d)\n", + __FUNCTION__, ret); + break; + } + + ret = do_drive_set_taskfiles(ap, &ap->device[ix], + gtf_length, gtf_address); + kfree((void *)obj_loc); + if (ret < 0) { + if (ata_msg_probe(ap)) + ata_port_printk(ap, KERN_DEBUG, + "%s: set_taskfiles error (%d)\n", + __FUNCTION__, ret); + break; + } + } + + return ret; +} + +/** + * ata_acpi_push_id - send Identify data to drive + * @ap: the ata_port for the drive + * @ix: drive index + * + * _SDD ACPI object: for SATA mode only + * Must be after Identify (Packet) Device -- uses its data + * ATM this function never returns a failure. It is an optional + * method and if it fails for whatever reason, we should still + * just keep going. + */ +int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) +{ + acpi_handle handle; + acpi_integer pcidevfn; + int err; + struct device *dev = ap->host->dev; + struct ata_device *atadev = &ap->device[ix]; + u32 dev_adr; + acpi_status status; + struct acpi_object_list input; + union acpi_object in_params[1]; + + if (noacpi) + return 0; + + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: ap->id: %d, ix = %d, port#: %d\n", + __FUNCTION__, ap->id, ix, ap->port_no); + + /* Don't continue if not a SATA device. */ + if (!(ap->cbl == ATA_CBL_SATA)) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: Not a SATA device\n", __FUNCTION__); + goto out; + } + + /* Don't continue if device has no _ADR method. + * _SDD is intended for known motherboard devices. */ + err = sata_get_dev_handle(dev, &handle, &pcidevfn); + if (err < 0) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: sata_get_dev_handle failed (%d\n", + __FUNCTION__, err); + goto out; + } + + /* Get this drive's _ADR info, if not already known */ + if (!atadev->obj_handle) { + dev_adr = SATA_ADR_RSVD; + err = get_sata_adr(dev, handle, pcidevfn, ix, ap, atadev, + &dev_adr); + if (err < 0 || dev_adr == SATA_ADR_RSVD || + !atadev->obj_handle) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: get_sata_adr failed: " + "err=%d, dev_adr=%u, obj_handle=0x%p\n", + __FUNCTION__, err, dev_adr, + atadev->obj_handle); + goto out; + } + } + + /* Give the drive Identify data to the drive via the _SDD method */ + /* _SDD: set up input parameters */ + input.count = 1; + input.pointer = in_params; + in_params[0].type = ACPI_TYPE_BUFFER; + in_params[0].buffer.length = sizeof(atadev->id[0]) * ATA_ID_WORDS; + in_params[0].buffer.pointer = (u8 *)atadev->id; + /* Output buffer: _SDD has no output */ + + /* It's OK for _SDD to be missing too. */ + swap_buf_le16(atadev->id, ATA_ID_WORDS); + status = acpi_evaluate_object(atadev->obj_handle, "_SDD", &input, NULL); + swap_buf_le16(atadev->id, ATA_ID_WORDS); + + err = ACPI_FAILURE(status) ? -EIO : 0; + if (err < 0) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "ata%u(%u): %s _SDD error: status = 0x%x\n", + ap->id, ap->device->devno, + __FUNCTION__, status); + } + + /* always return success */ +out: + return 0; +} + + diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 2cf8251728d..e900c5edefc 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -93,6 +93,10 @@ static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ; module_param(ata_probe_timeout, int, 0444); MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)"); +int noacpi; +module_param(noacpi, int, 0444); +MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in suspend/resume when set"); + MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("Library module for ATA devices"); MODULE_LICENSE("GPL"); @@ -1564,6 +1568,16 @@ int ata_dev_configure(struct ata_device *dev) ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n", __FUNCTION__, ap->id, dev->devno); + /* set _SDD */ + rc = ata_acpi_push_id(ap, dev->devno); + if (rc) { + ata_dev_printk(dev, KERN_WARNING, "failed to set _SDD(%d)\n", + rc); + } + + /* retrieve and execute the ATA task file of _GTF */ + ata_acpi_exec_tfs(ap); + /* print device capabilities */ if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 06ccf230e3c..0ad7781d72a 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -47,6 +47,7 @@ extern struct workqueue_struct *ata_aux_wq; extern int atapi_enabled; extern int atapi_dmadir; extern int libata_fua; +extern int noacpi; extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, u64 block, u32 n_block, unsigned int tf_flags, @@ -87,6 +88,20 @@ extern void ata_port_init(struct ata_port *ap, struct ata_host *host, extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port); +/* libata-acpi.c */ +#ifdef CONFIG_SATA_ACPI +extern int ata_acpi_exec_tfs(struct ata_port *ap); +extern int ata_acpi_push_id(struct ata_port *ap, unsigned int ix); +#else +static inline int ata_acpi_exec_tfs(struct ata_port *ap) +{ + return 0; +} +static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) +{ + return 0; +} +#endif /* libata-scsi.c */ extern struct scsi_transport_template ata_scsi_transport_template; diff --git a/drivers/atm/he.c b/drivers/atm/he.c index db33f6f4dd2..8510026b690 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -3017,7 +3017,7 @@ read_prom_byte(struct he_dev *he_dev, int addr) he_writel(he_dev, val, HOST_CNTL); /* Send READ instruction */ - for (i = 0; i < sizeof(readtab)/sizeof(readtab[0]); i++) { + for (i = 0; i < ARRAY_SIZE(readtab); i++) { he_writel(he_dev, val | readtab[i], HOST_CNTL); udelay(EEPROM_DELAY); } diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index f4078612194..b4b80140c39 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -388,7 +388,7 @@ idt77252_eeprom_read_status(struct idt77252_dev *card) gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); - for (i = 0; i < sizeof(rdsrtab)/sizeof(rdsrtab[0]); i++) { + for (i = 0; i < ARRAY_SIZE(rdsrtab); i++) { idt77252_write_gp(card, gp | rdsrtab[i]); udelay(5); } @@ -422,7 +422,7 @@ idt77252_eeprom_read_byte(struct idt77252_dev *card, u8 offset) gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); - for (i = 0; i < sizeof(rdtab)/sizeof(rdtab[0]); i++) { + for (i = 0; i < ARRAY_SIZE(rdtab); i++) { idt77252_write_gp(card, gp | rdtab[i]); udelay(5); } @@ -469,14 +469,14 @@ idt77252_eeprom_write_byte(struct idt77252_dev *card, u8 offset, u8 data) gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); - for (i = 0; i < sizeof(wrentab)/sizeof(wrentab[0]); i++) { + for (i = 0; i < ARRAY_SIZE(wrentab); i++) { idt77252_write_gp(card, gp | wrentab[i]); udelay(5); } idt77252_write_gp(card, gp | SAR_GP_EECS); udelay(5); - for (i = 0; i < sizeof(wrtab)/sizeof(wrtab[0]); i++) { + for (i = 0; i < ARRAY_SIZE(wrtab); i++) { idt77252_write_gp(card, gp | wrtab[i]); udelay(5); } diff --git a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c index 2c5e3ae7750..480947f4e01 100644 --- a/drivers/atm/nicstarmac.c +++ b/drivers/atm/nicstarmac.c @@ -7,6 +7,8 @@ * Read this ForeRunner's MAC address from eprom/eeprom */ +#include <linux/kernel.h> + typedef void __iomem *virt_addr_t; #define CYCLE_DELAY 5 @@ -176,7 +178,7 @@ read_eprom_byte(virt_addr_t base, u_int8_t offset) val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0; /* Send READ instruction */ - for (i=0; i<sizeof readtab/sizeof readtab[0]; i++) + for (i=0; i<ARRAY_SIZE(readtab); i++) { NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, (val | readtab[i]) ); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 472810f8e6e..253868e03c7 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -324,27 +324,25 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, return error; } -static int device_add_attrs(struct bus_type * bus, struct device * dev) +static int device_add_attrs(struct bus_type *bus, struct device *dev) { int error = 0; int i; - if (bus->dev_attrs) { - for (i = 0; attr_name(bus->dev_attrs[i]); i++) { - error = device_create_file(dev,&bus->dev_attrs[i]); - if (error) - goto Err; + if (!bus->dev_attrs) + return 0; + + for (i = 0; attr_name(bus->dev_attrs[i]); i++) { + error = device_create_file(dev,&bus->dev_attrs[i]); + if (error) { + while (--i >= 0) + device_remove_file(dev, &bus->dev_attrs[i]); + break; } } - Done: return error; - Err: - while (--i >= 0) - device_remove_file(dev,&bus->dev_attrs[i]); - goto Done; } - static void device_remove_attrs(struct bus_type * bus, struct device * dev) { int i; diff --git a/drivers/base/class.c b/drivers/base/class.c index 96def1ddba1..1417e5cd4c6 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -163,8 +163,7 @@ int class_register(struct class * cls) void class_unregister(struct class * cls) { pr_debug("device class '%s': unregistering\n", cls->name); - if (cls->virtual_dir) - kobject_unregister(cls->virtual_dir); + kobject_unregister(cls->virtual_dir); remove_class_attrs(cls); subsystem_unregister(&cls->subsys); } diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 20ee4f7c53a..90e2d9350c1 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -83,7 +83,7 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap) * Every time unit enable is asserted, GPOD needs to be cleared * on IOP3XX to avoid data corruption on the bus. */ -#ifdef CONFIG_PLAT_IOP +#if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X) if (iop3xx_adap->id == 0) { gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW); gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW); diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index c3b1567c852..14e83d0aac8 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -34,6 +34,7 @@ #include <asm/hardware.h> #include <asm/irq.h> +#include <asm/io.h> #include <asm/arch/i2c.h> #include <asm/arch/pxa-regs.h> @@ -54,8 +55,21 @@ struct pxa_i2c { unsigned int irqlogidx; u32 isrlog[32]; u32 icrlog[32]; + + void __iomem *reg_base; + + unsigned long iobase; + unsigned long iosize; + + int irq; }; +#define _IBMR(i2c) ((i2c)->reg_base + 0) +#define _IDBR(i2c) ((i2c)->reg_base + 8) +#define _ICR(i2c) ((i2c)->reg_base + 0x10) +#define _ISR(i2c) ((i2c)->reg_base + 0x18) +#define _ISAR(i2c) ((i2c)->reg_base + 0x20) + /* * I2C Slave mode address */ @@ -130,7 +144,8 @@ static unsigned int i2c_debug = DEBUG; static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname) { - dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno, ISR, ICR, IBMR); + dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno, + readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c))); } #define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __FUNCTION__) @@ -153,7 +168,7 @@ static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why) printk("i2c: msg_num: %d msg_idx: %d msg_ptr: %d\n", i2c->msg_num, i2c->msg_idx, i2c->msg_ptr); printk("i2c: ICR: %08x ISR: %08x\n" - "i2c: log: ", ICR, ISR); + "i2c: log: ", readl(_ICR(i2c)), readl(_ISR(i2c))); for (i = 0; i < i2c->irqlogidx; i++) printk("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]); printk("\n"); @@ -161,7 +176,7 @@ static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why) static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c) { - return !(ICR & ICR_SCLE); + return !(readl(_ICR(i2c)) & ICR_SCLE); } static void i2c_pxa_abort(struct pxa_i2c *i2c) @@ -173,28 +188,29 @@ static void i2c_pxa_abort(struct pxa_i2c *i2c) return; } - while (time_before(jiffies, timeout) && (IBMR & 0x1) == 0) { - unsigned long icr = ICR; + while (time_before(jiffies, timeout) && (readl(_IBMR(i2c)) & 0x1) == 0) { + unsigned long icr = readl(_ICR(i2c)); icr &= ~ICR_START; icr |= ICR_ACKNAK | ICR_STOP | ICR_TB; - ICR = icr; + writel(icr, _ICR(i2c)); show_state(i2c); msleep(1); } - ICR &= ~(ICR_MA | ICR_START | ICR_STOP); + writel(readl(_ICR(i2c)) & ~(ICR_MA | ICR_START | ICR_STOP), + _ICR(i2c)); } static int i2c_pxa_wait_bus_not_busy(struct pxa_i2c *i2c) { int timeout = DEF_TIMEOUT; - while (timeout-- && ISR & (ISR_IBB | ISR_UB)) { - if ((ISR & ISR_SAD) != 0) + while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) { + if ((readl(_ISR(i2c)) & ISR_SAD) != 0) timeout += 4; msleep(2); @@ -214,9 +230,9 @@ static int i2c_pxa_wait_master(struct pxa_i2c *i2c) while (time_before(jiffies, timeout)) { if (i2c_debug > 1) dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n", - __func__, (long)jiffies, ISR, ICR, IBMR); + __func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c))); - if (ISR & ISR_SAD) { + if (readl(_ISR(i2c)) & ISR_SAD) { if (i2c_debug > 0) dev_dbg(&i2c->adap.dev, "%s: Slave detected\n", __func__); goto out; @@ -226,7 +242,7 @@ static int i2c_pxa_wait_master(struct pxa_i2c *i2c) * quick check of the i2c lines themselves to ensure they've * gone high... */ - if ((ISR & (ISR_UB | ISR_IBB)) == 0 && IBMR == 3) { + if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) == 0 && readl(_IBMR(i2c)) == 3) { if (i2c_debug > 0) dev_dbg(&i2c->adap.dev, "%s: done\n", __func__); return 1; @@ -246,7 +262,7 @@ static int i2c_pxa_set_master(struct pxa_i2c *i2c) if (i2c_debug) dev_dbg(&i2c->adap.dev, "setting to bus master\n"); - if ((ISR & (ISR_UB | ISR_IBB)) != 0) { + if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) != 0) { dev_dbg(&i2c->adap.dev, "%s: unit is busy\n", __func__); if (!i2c_pxa_wait_master(i2c)) { dev_dbg(&i2c->adap.dev, "%s: error: unit busy\n", __func__); @@ -254,7 +270,7 @@ static int i2c_pxa_set_master(struct pxa_i2c *i2c) } } - ICR |= ICR_SCLE; + writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c)); return 0; } @@ -270,11 +286,11 @@ static int i2c_pxa_wait_slave(struct pxa_i2c *i2c) while (time_before(jiffies, timeout)) { if (i2c_debug > 1) dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n", - __func__, (long)jiffies, ISR, ICR, IBMR); + __func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c))); - if ((ISR & (ISR_UB|ISR_IBB)) == 0 || - (ISR & ISR_SAD) != 0 || - (ICR & ICR_SCLE) == 0) { + if ((readl(_ISR(i2c)) & (ISR_UB|ISR_IBB)) == 0 || + (readl(_ISR(i2c)) & ISR_SAD) != 0 || + (readl(_ICR(i2c)) & ICR_SCLE) == 0) { if (i2c_debug > 1) dev_dbg(&i2c->adap.dev, "%s: done\n", __func__); return 1; @@ -302,9 +318,9 @@ static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode) /* we need to wait for the stop condition to end */ /* if we where in stop, then clear... */ - if (ICR & ICR_STOP) { + if (readl(_ICR(i2c)) & ICR_STOP) { udelay(100); - ICR &= ~ICR_STOP; + writel(readl(_ICR(i2c)) & ~ICR_STOP, _ICR(i2c)); } if (!i2c_pxa_wait_slave(i2c)) { @@ -314,12 +330,12 @@ static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode) } } - ICR &= ~(ICR_STOP|ICR_ACKNAK|ICR_MA); - ICR &= ~ICR_SCLE; + writel(readl(_ICR(i2c)) & ~(ICR_STOP|ICR_ACKNAK|ICR_MA), _ICR(i2c)); + writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c)); if (i2c_debug) { - dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", ICR, ISR); - decode_ICR(ICR); + dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", readl(_ICR(i2c)), readl(_ISR(i2c))); + decode_ICR(readl(_ICR(i2c))); } } #else @@ -334,24 +350,24 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c) i2c_pxa_abort(i2c); /* reset according to 9.8 */ - ICR = ICR_UR; - ISR = I2C_ISR_INIT; - ICR &= ~ICR_UR; + writel(ICR_UR, _ICR(i2c)); + writel(I2C_ISR_INIT, _ISR(i2c)); + writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c)); - ISAR = i2c->slave_addr; + writel(i2c->slave_addr, _ISAR(i2c)); /* set control register values */ - ICR = I2C_ICR_INIT; + writel(I2C_ICR_INIT, _ICR(i2c)); #ifdef CONFIG_I2C_PXA_SLAVE dev_info(&i2c->adap.dev, "Enabling slave mode\n"); - ICR |= ICR_SADIE | ICR_ALDIE | ICR_SSDIE; + writel(readl(_ICR(i2c)) | ICR_SADIE | ICR_ALDIE | ICR_SSDIE, _ICR(i2c)); #endif i2c_pxa_set_slave(i2c, 0); /* enable unit */ - ICR |= ICR_IUE; + writel(readl(_ICR(i2c)) | ICR_IUE, _ICR(i2c)); udelay(100); } @@ -371,19 +387,19 @@ static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr) if (i2c->slave != NULL) ret = i2c->slave->read(i2c->slave->data); - IDBR = ret; - ICR |= ICR_TB; /* allow next byte */ + writel(ret, _IDBR(i2c)); + writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c)); /* allow next byte */ } } static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr) { - unsigned int byte = IDBR; + unsigned int byte = readl(_IDBR(i2c)); if (i2c->slave != NULL) i2c->slave->write(i2c->slave->data, byte); - ICR |= ICR_TB; + writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c)); } static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) @@ -403,13 +419,13 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) * start condition... if this happens, we'd better back off * and stop holding the poor thing up */ - ICR &= ~(ICR_START|ICR_STOP); - ICR |= ICR_TB; + writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c)); + writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c)); timeout = 0x10000; while (1) { - if ((IBMR & 2) == 2) + if ((readl(_IBMR(i2c)) & 2) == 2) break; timeout--; @@ -420,7 +436,7 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) } } - ICR &= ~ICR_SCLE; + writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c)); } static void i2c_pxa_slave_stop(struct pxa_i2c *i2c) @@ -447,14 +463,14 @@ static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr) if (isr & ISR_BED) { /* what should we do here? */ } else { - IDBR = 0; - ICR |= ICR_TB; + writel(0, _IDBR(i2c)); + writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c)); } } static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr) { - ICR |= ICR_TB | ICR_ACKNAK; + writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c)); } static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) @@ -466,13 +482,13 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) * start condition... if this happens, we'd better back off * and stop holding the poor thing up */ - ICR &= ~(ICR_START|ICR_STOP); - ICR |= ICR_TB | ICR_ACKNAK; + writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c)); + writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c)); timeout = 0x10000; while (1) { - if ((IBMR & 2) == 2) + if ((readl(_IBMR(i2c)) & 2) == 2) break; timeout--; @@ -483,7 +499,7 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) } } - ICR &= ~ICR_SCLE; + writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c)); } static void i2c_pxa_slave_stop(struct pxa_i2c *i2c) @@ -514,13 +530,13 @@ static inline void i2c_pxa_start_message(struct pxa_i2c *i2c) /* * Step 1: target slave address into IDBR */ - IDBR = i2c_pxa_addr_byte(i2c->msg); + writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c)); /* * Step 2: initiate the write. */ - icr = ICR & ~(ICR_STOP | ICR_ALDIE); - ICR = icr | ICR_START | ICR_TB; + icr = readl(_ICR(i2c)) & ~(ICR_STOP | ICR_ALDIE); + writel(icr | ICR_START | ICR_TB, _ICR(i2c)); } /* @@ -594,7 +610,7 @@ static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret) static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) { - u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB); + u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB); again: /* @@ -645,7 +661,7 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) /* * Write mode. Write the next data byte. */ - IDBR = i2c->msg->buf[i2c->msg_ptr++]; + writel(i2c->msg->buf[i2c->msg_ptr++], _IDBR(i2c)); icr |= ICR_ALDIE | ICR_TB; @@ -675,7 +691,7 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) /* * Write the next address. */ - IDBR = i2c_pxa_addr_byte(i2c->msg); + writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c)); /* * And trigger a repeated start, and send the byte. @@ -696,18 +712,18 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) i2c->icrlog[i2c->irqlogidx-1] = icr; - ICR = icr; + writel(icr, _ICR(i2c)); show_state(i2c); } static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr) { - u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB); + u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB); /* * Read the byte. */ - i2c->msg->buf[i2c->msg_ptr++] = IDBR; + i2c->msg->buf[i2c->msg_ptr++] = readl(_IDBR(i2c)); if (i2c->msg_ptr < i2c->msg->len) { /* @@ -724,17 +740,17 @@ static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr) i2c->icrlog[i2c->irqlogidx-1] = icr; - ICR = icr; + writel(icr, _ICR(i2c)); } static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id) { struct pxa_i2c *i2c = dev_id; - u32 isr = ISR; + u32 isr = readl(_ISR(i2c)); if (i2c_debug > 2 && 0) { dev_dbg(&i2c->adap.dev, "%s: ISR=%08x, ICR=%08x, IBMR=%02x\n", - __func__, isr, ICR, IBMR); + __func__, isr, readl(_ICR(i2c)), readl(_IBMR(i2c))); decode_ISR(isr); } @@ -746,7 +762,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id) /* * Always clear all pending IRQs. */ - ISR = isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED); + writel(isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED), _ISR(i2c)); if (isr & ISR_SAD) i2c_pxa_slave_start(i2c, isr); @@ -779,7 +795,7 @@ static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num /* If the I2C controller is disabled we need to reset it (probably due to a suspend/resume destroying state). We do this here as we can then avoid worrying about resuming the controller before its users. */ - if (!(ICR & ICR_IUE)) + if (!(readl(_ICR(i2c)) & ICR_IUE)) i2c_pxa_reset(i2c); for (i = adap->retries; i >= 0; i--) { @@ -810,28 +826,53 @@ static const struct i2c_algorithm i2c_pxa_algorithm = { static struct pxa_i2c i2c_pxa = { .lock = SPIN_LOCK_UNLOCKED, - .wait = __WAIT_QUEUE_HEAD_INITIALIZER(i2c_pxa.wait), .adap = { .owner = THIS_MODULE, .algo = &i2c_pxa_algorithm, - .name = "pxa2xx-i2c", + .name = "pxa2xx-i2c.0", .retries = 5, }, }; +#define res_len(r) ((r)->end - (r)->start + 1) static int i2c_pxa_probe(struct platform_device *dev) { struct pxa_i2c *i2c = &i2c_pxa; + struct resource *res; #ifdef CONFIG_I2C_PXA_SLAVE struct i2c_pxa_platform_data *plat = dev->dev.platform_data; #endif int ret; + int irq; -#ifdef CONFIG_PXA27x - pxa_gpio_mode(GPIO117_I2CSCL_MD); - pxa_gpio_mode(GPIO118_I2CSDA_MD); - udelay(100); -#endif + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + irq = platform_get_irq(dev, 0); + if (res == NULL || irq < 0) + return -ENODEV; + + if (!request_mem_region(res->start, res_len(res), res->name)) + return -ENOMEM; + + i2c = kmalloc(sizeof(struct pxa_i2c), GFP_KERNEL); + if (!i2c) { + ret = -ENOMEM; + goto emalloc; + } + + memcpy(i2c, &i2c_pxa, sizeof(struct pxa_i2c)); + init_waitqueue_head(&i2c->wait); + i2c->adap.name[strlen(i2c->adap.name) - 1] = '0' + dev->id % 10; + + i2c->reg_base = ioremap(res->start, res_len(res)); + if (!i2c->reg_base) { + ret = -EIO; + goto eremap; + } + + i2c->iobase = res->start; + i2c->iosize = res_len(res); + + i2c->irq = irq; i2c->slave_addr = I2C_PXA_SLAVE_ADDR; @@ -842,11 +883,28 @@ static int i2c_pxa_probe(struct platform_device *dev) } #endif - pxa_set_cken(CKEN14_I2C, 1); - ret = request_irq(IRQ_I2C, i2c_pxa_handler, IRQF_DISABLED, - "pxa2xx-i2c", i2c); + switch (dev->id) { + case 0: +#ifdef CONFIG_PXA27x + pxa_gpio_mode(GPIO117_I2CSCL_MD); + pxa_gpio_mode(GPIO118_I2CSDA_MD); +#endif + pxa_set_cken(CKEN14_I2C, 1); + break; +#ifdef CONFIG_PXA27x + case 1: + local_irq_disable(); + PCFR |= PCFR_PI2CEN; + local_irq_enable(); + pxa_set_cken(CKEN15_PWRI2C, 1); +#endif + } + + ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED, + i2c->adap.name, i2c); if (ret) - goto out; + goto ereqirq; + i2c_pxa_reset(i2c); @@ -856,7 +914,7 @@ static int i2c_pxa_probe(struct platform_device *dev) ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { printk(KERN_INFO "I2C: Failed to add bus\n"); - goto err_irq; + goto eadapt; } platform_set_drvdata(dev, i2c); @@ -870,9 +928,25 @@ static int i2c_pxa_probe(struct platform_device *dev) #endif return 0; - err_irq: - free_irq(IRQ_I2C, i2c); - out: +eadapt: + free_irq(irq, i2c); +ereqirq: + switch (dev->id) { + case 0: + pxa_set_cken(CKEN14_I2C, 0); + break; +#ifdef CONFIG_PXA27x + case 1: + pxa_set_cken(CKEN15_PWRI2C, 0); + local_irq_disable(); + PCFR &= ~PCFR_PI2CEN; + local_irq_enable(); +#endif + } +eremap: + kfree(i2c); +emalloc: + release_mem_region(res->start, res_len(res)); return ret; } @@ -883,8 +957,21 @@ static int i2c_pxa_remove(struct platform_device *dev) platform_set_drvdata(dev, NULL); i2c_del_adapter(&i2c->adap); - free_irq(IRQ_I2C, i2c); - pxa_set_cken(CKEN14_I2C, 0); + free_irq(i2c->irq, i2c); + switch (dev->id) { + case 0: + pxa_set_cken(CKEN14_I2C, 0); + break; +#ifdef CONFIG_PXA27x + case 1: + pxa_set_cken(CKEN15_PWRI2C, 0); + local_irq_disable(); + PCFR &= ~PCFR_PI2CEN; + local_irq_enable(); +#endif + } + release_mem_region(i2c->iobase, i2c->iosize); + kfree(i2c); return 0; } diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 6adf8649764..49234e32fd1 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -800,6 +800,14 @@ config BLK_DEV_IDEDMA_PMAC to transfer data to and from memory. Saying Y is safe and improves performance. +config BLK_DEV_IDE_CELLEB + bool "Toshiba's Cell Reference Set IDE support" + depends on PPC_CELLEB + help + This driver provides support for the built-in IDE controller on + Toshiba Cell Reference Board. + If unsure, say Y. + config BLK_DEV_IDE_SWARM tristate "IDE for Sibyte evaluation boards" depends on SIBYTE_SB1xxx_SOC diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index d9f029e8ff7..28feedfbd21 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -37,6 +37,7 @@ ide-core-$(CONFIG_BLK_DEV_Q40IDE) += legacy/q40ide.o # built-in only drivers from ppc/ ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE) += ppc/mpc8xx.o ide-core-$(CONFIG_BLK_DEV_IDE_PMAC) += ppc/pmac.o +ide-core-$(CONFIG_BLK_DEV_IDE_CELLEB) += ppc/scc_pata.o # built-in only drivers from h8300/ ide-core-$(CONFIG_H8300) += h8300/ide-h8300.o diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 8a1c27f2869..40e5c66b81c 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -307,26 +307,24 @@ static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode) return on; } -static int icside_dma_host_off(ide_drive_t *drive) +static void icside_dma_host_off(ide_drive_t *drive) { - return 0; } -static int icside_dma_off_quietly(ide_drive_t *drive) +static void icside_dma_off_quietly(ide_drive_t *drive) { drive->using_dma = 0; - return icside_dma_host_off(drive); } -static int icside_dma_host_on(ide_drive_t *drive) +static void icside_dma_host_on(ide_drive_t *drive) { - return 0; } static int icside_dma_on(ide_drive_t *drive) { drive->using_dma = 1; - return icside_dma_host_on(drive); + + return 0; } static int icside_dma_check(ide_drive_t *drive) @@ -365,10 +363,7 @@ static int icside_dma_check(ide_drive_t *drive) out: on = icside_set_speed(drive, xfer_mode); - if (on) - return icside_dma_on(drive); - else - return icside_dma_off_quietly(drive); + return on ? 0 : -1; } static int icside_dma_end(ide_drive_t *drive) @@ -497,9 +492,9 @@ static void icside_dma_init(ide_hwif_t *hwif) hwif->autodma = autodma; hwif->ide_dma_check = icside_dma_check; - hwif->ide_dma_host_off = icside_dma_host_off; - hwif->ide_dma_off_quietly = icside_dma_off_quietly; - hwif->ide_dma_host_on = icside_dma_host_on; + hwif->dma_host_off = icside_dma_host_off; + hwif->dma_off_quietly = icside_dma_off_quietly; + hwif->dma_host_on = icside_dma_host_on; hwif->ide_dma_on = icside_dma_on; hwif->dma_setup = icside_dma_setup; hwif->dma_exec_cmd = icside_dma_exec_cmd; @@ -556,7 +551,7 @@ icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *e * Ensure we're using MMIO */ default_hwif_mmiops(hwif); - hwif->mmio = 2; + hwif->mmio = 1; for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { hwif->hw.io_ports[i] = port; diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c index 3058217767d..9c6c49fdd2b 100644 --- a/drivers/ide/arm/rapide.c +++ b/drivers/ide/arm/rapide.c @@ -46,7 +46,7 @@ rapide_locate_hwif(void __iomem *base, void __iomem *ctrl, unsigned int sz, int hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl; hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl; hwif->hw.irq = hwif->irq = irq; - hwif->mmio = 2; + hwif->mmio = 1; default_hwif_mmiops(hwif); return hwif; diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 5797e0b5a13..6b2d152351b 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -682,9 +682,12 @@ static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int); static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int); static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int); static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int); -static int cris_dma_off (ide_drive_t *drive); static int cris_dma_on (ide_drive_t *drive); +static void cris_dma_off(ide_drive_t *drive) +{ +} + static void tune_cris_ide(ide_drive_t *drive, u8 pio) { int setup, strobe, hold; @@ -795,7 +798,7 @@ init_e100_ide (void) 0, 0, cris_ide_ack_intr, ide_default_irq(0)); ide_register_hw(&hw, &hwif); - hwif->mmio = 2; + hwif->mmio = 1; hwif->chipset = ide_etrax100; hwif->tuneproc = &tune_cris_ide; hwif->speedproc = &speed_cris_ide; @@ -814,13 +817,16 @@ init_e100_ide (void) hwif->OUTBSYNC = &cris_ide_outbsync; hwif->INB = &cris_ide_inb; hwif->INW = &cris_ide_inw; - hwif->ide_dma_host_off = &cris_dma_off; - hwif->ide_dma_host_on = &cris_dma_on; - hwif->ide_dma_off_quietly = &cris_dma_off; + hwif->dma_host_off = &cris_dma_off; + hwif->dma_host_on = &cris_dma_on; + hwif->dma_off_quietly = &cris_dma_off; hwif->udma_four = 0; hwif->ultra_mask = cris_ultra_mask; hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */ hwif->swdma_mask = 0x07; /* Singleword DMA 0-2 */ + hwif->autodma = 1; + hwif->drives[0].autodma = 1; + hwif->drives[1].autodma = 1; } /* Reset pulse */ @@ -835,11 +841,6 @@ init_e100_ide (void) cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0); } -static int cris_dma_off (ide_drive_t *drive) -{ - return 0; -} - static int cris_dma_on (ide_drive_t *drive) { return 0; @@ -1045,17 +1046,10 @@ static ide_startstop_t cris_dma_intr (ide_drive_t *drive) static int cris_dma_check(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; - struct hd_driveid* id = drive->id; - - if (id && (id->capability & 1)) { - if (ide_use_dma(drive)) { - if (cris_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - } + if (ide_use_dma(drive) && cris_config_drive_for_dma(drive)) + return 0; - return hwif->ide_dma_off_quietly(drive); + return -1; } static int cris_dma_end(ide_drive_t *drive) diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c index 608ca871744..88750a30033 100644 --- a/drivers/ide/h8300/ide-h8300.c +++ b/drivers/ide/h8300/ide-h8300.c @@ -76,13 +76,11 @@ static inline void hwif_setup(ide_hwif_t *hwif) { default_hwif_iops(hwif); - hwif->mmio = 2; + hwif->mmio = 1; hwif->OUTW = mm_outw; hwif->OUTSW = mm_outsw; hwif->INW = mm_inw; hwif->INSW = mm_insw; - hwif->OUTL = NULL; - hwif->INL = NULL; hwif->OUTSL = NULL; hwif->INSL = NULL; } diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 5969cec58dc..45a928c058c 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -687,15 +687,8 @@ static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 sta static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) { struct request *rq = HWGROUP(drive)->rq; - ide_hwif_t *hwif = HWIF(drive); int stat, err, sense_key; - /* We may have bogus DMA interrupts in PIO state here */ - if (HWIF(drive)->dma_status && hwif->atapi_irq_bogon) { - stat = hwif->INB(hwif->dma_status); - /* Should we force the bit as well ? */ - hwif->OUTB(stat, hwif->dma_status); - } /* Check for errors. */ stat = HWIF(drive)->INB(IDE_STATUS_REG); if (stat_ret) @@ -930,6 +923,10 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { + /* waiting for CDB interrupt, not DMA yet. */ + if (info->dma) + drive->waiting_for_dma = 0; + /* packet command */ ide_execute_command(drive, WIN_PACKETCMD, handler, ATAPI_WAIT_PC, cdrom_timer_expiry); return ide_started; @@ -972,6 +969,10 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, /* Check for errors. */ if (cdrom_decode_status(drive, DRQ_STAT, NULL)) return ide_stopped; + + /* Ok, next interrupt will be DMA interrupt. */ + if (info->dma) + drive->waiting_for_dma = 1; } else { /* Otherwise, we must wait for DRQ to get set. */ if (ide_wait_stat(&startstop, drive, DRQ_STAT, @@ -1103,7 +1104,7 @@ static ide_startstop_t cdrom_read_intr (ide_drive_t *drive) if (dma) { info->dma = 0; if ((dma_error = HWIF(drive)->ide_dma_end(drive))) - __ide_dma_off(drive); + ide_dma_off(drive); } if (cdrom_decode_status(drive, 0, &stat)) @@ -1699,7 +1700,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) if (dma) { if (dma_error) { printk(KERN_ERR "ide-cd: dma error\n"); - __ide_dma_off(drive); + ide_dma_off(drive); return ide_error(drive, "dma error", stat); } @@ -1825,7 +1826,7 @@ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive) info->dma = 0; if ((dma_error = HWIF(drive)->ide_dma_end(drive))) { printk(KERN_ERR "ide-cd: write dma error\n"); - __ide_dma_off(drive); + ide_dma_off(drive); } } @@ -3254,14 +3255,6 @@ int ide_cdrom_setup (ide_drive_t *drive) if (drive->autotune == IDE_TUNE_DEFAULT || drive->autotune == IDE_TUNE_AUTO) drive->dsc_overlap = (drive->next != drive); -#if 0 - drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1; - if (HWIF(drive)->no_dsc) { - printk(KERN_INFO "ide-cd: %s: disabling DSC overlap\n", - drive->name); - drive->dsc_overlap = 0; - } -#endif if (ide_cdrom_register(drive, nslots)) { printk (KERN_ERR "%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name); @@ -3360,21 +3353,16 @@ static int idecd_open(struct inode * inode, struct file * file) { struct gendisk *disk = inode->i_bdev->bd_disk; struct cdrom_info *info; - ide_drive_t *drive; int rc = -ENOMEM; if (!(info = ide_cd_get(disk))) return -ENXIO; - drive = info->drive; - - drive->usage++; - if (!info->buffer) - info->buffer = kmalloc(SECTOR_BUFFER_SIZE, - GFP_KERNEL|__GFP_REPEAT); - if (!info->buffer || (rc = cdrom_open(&info->devinfo, inode, file))) - drive->usage--; + info->buffer = kmalloc(SECTOR_BUFFER_SIZE, GFP_KERNEL|__GFP_REPEAT); + + if (info->buffer) + rc = cdrom_open(&info->devinfo, inode, file); if (rc < 0) ide_cd_put(info); @@ -3386,10 +3374,8 @@ static int idecd_release(struct inode * inode, struct file * file) { struct gendisk *disk = inode->i_bdev->bd_disk; struct cdrom_info *info = ide_cd_g(disk); - ide_drive_t *drive = info->drive; cdrom_release (&info->devinfo, file); - drive->usage--; ide_cd_put(info); diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 0a05a377d66..e2cea1889c4 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -77,6 +77,7 @@ struct ide_disk_obj { ide_driver_t *driver; struct gendisk *disk; struct kref kref; + unsigned int openers; /* protected by BKL for now */ }; static DEFINE_MUTEX(idedisk_ref_mutex); @@ -1081,8 +1082,9 @@ static int idedisk_open(struct inode *inode, struct file *filp) drive = idkp->drive; - drive->usage++; - if (drive->removable && drive->usage == 1) { + idkp->openers++; + + if (drive->removable && idkp->openers == 1) { ide_task_t args; memset(&args, 0, sizeof(ide_task_t)); args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK; @@ -1106,9 +1108,10 @@ static int idedisk_release(struct inode *inode, struct file *filp) struct ide_disk_obj *idkp = ide_disk_g(disk); ide_drive_t *drive = idkp->drive; - if (drive->usage == 1) + if (idkp->openers == 1) ide_cacheflush_p(drive); - if (drive->removable && drive->usage == 1) { + + if (drive->removable && idkp->openers == 1) { ide_task_t args; memset(&args, 0, sizeof(ide_task_t)); args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK; @@ -1117,7 +1120,8 @@ static int idedisk_release(struct inode *inode, struct file *filp) if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL)) drive->doorlocking = 0; } - drive->usage--; + + idkp->openers--; ide_disk_put(idkp); diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 56efed6742d..08e7cd043bc 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -348,15 +348,14 @@ EXPORT_SYMBOL_GPL(ide_destroy_dmatable); static int config_drive_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - if ((id->capability & 1) && hwif->autodma) { + if ((id->capability & 1) && drive->hwif->autodma) { /* * Enable DMA on any drive that has * UltraDMA (mode 0/1/2/3/4/5/6) enabled */ if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f)) - return hwif->ide_dma_on(drive); + return 0; /* * Enable DMA on any drive that has mode2 DMA * (multi or single) enabled @@ -364,14 +363,14 @@ static int config_drive_for_dma (ide_drive_t *drive) if (id->field_valid & 2) /* regular DMA */ if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) - return hwif->ide_dma_on(drive); + return 0; /* Consult the list of known "good" drives */ if (__ide_dma_good_drive(drive)) - return hwif->ide_dma_on(drive); + return 0; } -// if (hwif->tuneproc != NULL) hwif->tuneproc(drive, 255); - return hwif->ide_dma_off_quietly(drive); + + return -1; } /** @@ -415,72 +414,68 @@ static int dma_timer_expiry (ide_drive_t *drive) } /** - * __ide_dma_host_off - Generic DMA kill + * ide_dma_host_off - Generic DMA kill * @drive: drive to control * * Perform the generic IDE controller DMA off operation. This * works for most IDE bus mastering controllers */ -int __ide_dma_host_off (ide_drive_t *drive) +void ide_dma_host_off(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); u8 unit = (drive->select.b.unit & 0x01); u8 dma_stat = hwif->INB(hwif->dma_status); hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status); - return 0; } -EXPORT_SYMBOL(__ide_dma_host_off); +EXPORT_SYMBOL(ide_dma_host_off); /** - * __ide_dma_host_off_quietly - Generic DMA kill + * ide_dma_off_quietly - Generic DMA kill * @drive: drive to control * * Turn off the current DMA on this IDE controller. */ -int __ide_dma_off_quietly (ide_drive_t *drive) +void ide_dma_off_quietly(ide_drive_t *drive) { drive->using_dma = 0; ide_toggle_bounce(drive, 0); - if (HWIF(drive)->ide_dma_host_off(drive)) - return 1; - - return 0; + drive->hwif->dma_host_off(drive); } -EXPORT_SYMBOL(__ide_dma_off_quietly); +EXPORT_SYMBOL(ide_dma_off_quietly); #endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ /** - * __ide_dma_off - disable DMA on a device + * ide_dma_off - disable DMA on a device * @drive: drive to disable DMA on * * Disable IDE DMA for a device on this IDE controller. * Inform the user that DMA has been disabled. */ -int __ide_dma_off (ide_drive_t *drive) +void ide_dma_off(ide_drive_t *drive) { printk(KERN_INFO "%s: DMA disabled\n", drive->name); - return HWIF(drive)->ide_dma_off_quietly(drive); + drive->hwif->dma_off_quietly(drive); } -EXPORT_SYMBOL(__ide_dma_off); +EXPORT_SYMBOL(ide_dma_off); #ifdef CONFIG_BLK_DEV_IDEDMA_PCI /** - * __ide_dma_host_on - Enable DMA on a host + * ide_dma_host_on - Enable DMA on a host * @drive: drive to enable for DMA * * Enable DMA on an IDE controller following generic bus mastering * IDE controller behaviour */ - -int __ide_dma_host_on (ide_drive_t *drive) + +void ide_dma_host_on(ide_drive_t *drive) { if (drive->using_dma) { ide_hwif_t *hwif = HWIF(drive); @@ -488,12 +483,10 @@ int __ide_dma_host_on (ide_drive_t *drive) u8 dma_stat = hwif->INB(hwif->dma_status); hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status); - return 0; } - return 1; } -EXPORT_SYMBOL(__ide_dma_host_on); +EXPORT_SYMBOL(ide_dma_host_on); /** * __ide_dma_on - Enable DMA on a device @@ -511,8 +504,7 @@ int __ide_dma_on (ide_drive_t *drive) drive->using_dma = 1; ide_toggle_bounce(drive, 1); - if (HWIF(drive)->ide_dma_host_on(drive)) - return 1; + drive->hwif->dma_host_on(drive); return 0; } @@ -565,7 +557,10 @@ int ide_dma_setup(ide_drive_t *drive) } /* PRD table */ - hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable); + if (hwif->mmio) + writel(hwif->dmatable_dma, (void __iomem *)hwif->dma_prdtable); + else + outl(hwif->dmatable_dma, hwif->dma_prdtable); /* specify r/w */ hwif->OUTB(reading, hwif->dma_command); @@ -680,6 +675,9 @@ int ide_use_dma(ide_drive_t *drive) struct hd_driveid *id = drive->id; ide_hwif_t *hwif = drive->hwif; + if ((id->capability & 1) == 0 || drive->autodma == 0) + return 0; + /* consult the list of known "bad" drives */ if (__ide_dma_bad_drive(drive)) return 0; @@ -753,12 +751,37 @@ void ide_dma_verbose(ide_drive_t *drive) return; bug_dma_off: printk(", BUG DMA OFF"); - hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); return; } EXPORT_SYMBOL(ide_dma_verbose); +int ide_set_dma(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + int rc; + + rc = hwif->ide_dma_check(drive); + + switch(rc) { + case -1: /* DMA needs to be disabled */ + hwif->dma_off_quietly(drive); + return 0; + case 0: /* DMA needs to be enabled */ + return hwif->ide_dma_on(drive); + case 1: /* DMA setting cannot be changed */ + break; + default: + BUG(); + break; + } + + return rc; +} + +EXPORT_SYMBOL_GPL(ide_set_dma); + #ifdef CONFIG_BLK_DEV_IDEDMA_PCI int __ide_dma_lostirq (ide_drive_t *drive) { @@ -809,7 +832,7 @@ int ide_release_dma(ide_hwif_t *hwif) { ide_release_dma_engine(hwif); - if (hwif->mmio == 2) + if (hwif->mmio) return 1; else return ide_release_iomio_dma(hwif); @@ -878,9 +901,9 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base, unsigned int ports) { - if (hwif->mmio == 2) + if (hwif->mmio) return ide_mapped_mmio_dma(hwif, base,ports); - BUG_ON(hwif->mmio == 1); + return ide_iomio_dma(hwif, base, ports); } @@ -908,14 +931,14 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p if (!(hwif->dma_prdtable)) hwif->dma_prdtable = (hwif->dma_base + 4); - if (!hwif->ide_dma_off_quietly) - hwif->ide_dma_off_quietly = &__ide_dma_off_quietly; - if (!hwif->ide_dma_host_off) - hwif->ide_dma_host_off = &__ide_dma_host_off; + if (!hwif->dma_off_quietly) + hwif->dma_off_quietly = &ide_dma_off_quietly; + if (!hwif->dma_host_off) + hwif->dma_host_off = &ide_dma_host_off; if (!hwif->ide_dma_on) hwif->ide_dma_on = &__ide_dma_on; - if (!hwif->ide_dma_host_on) - hwif->ide_dma_host_on = &__ide_dma_host_on; + if (!hwif->dma_host_on) + hwif->dma_host_on = &ide_dma_host_on; if (!hwif->ide_dma_check) hwif->ide_dma_check = &__ide_dma_check; if (!hwif->dma_setup) diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index d33717c8afd..57cd21c5b2c 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -279,6 +279,7 @@ typedef struct ide_floppy_obj { ide_driver_t *driver; struct gendisk *disk; struct kref kref; + unsigned int openers; /* protected by BKL for now */ /* Current packet command */ idefloppy_pc_t *pc; @@ -866,7 +867,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { printk(KERN_ERR "ide-floppy: The floppy wants to issue " "more interrupts in DMA mode\n"); - (void)__ide_dma_off(drive); + ide_dma_off(drive); return ide_do_reset(drive); } @@ -1096,9 +1097,9 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p pc->current_position = pc->buffer; bcount.all = min(pc->request_transfer, 63 * 1024); - if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) { - (void)__ide_dma_off(drive); - } + if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) + ide_dma_off(drive); + feature.all = 0; if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) @@ -1433,7 +1434,8 @@ static int idefloppy_get_capacity (ide_drive_t *drive) drive->bios_cyl = 0; drive->bios_head = drive->bios_sect = 0; - floppy->blocks = floppy->bs_factor = 0; + floppy->blocks = 0; + floppy->bs_factor = 1; set_capacity(floppy->disk, 0); idefloppy_create_read_capacity_cmd(&pc); @@ -1949,9 +1951,9 @@ static int idefloppy_open(struct inode *inode, struct file *filp) drive = floppy->drive; - drive->usage++; + floppy->openers++; - if (drive->usage == 1) { + if (floppy->openers == 1) { clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags); /* Just in case */ @@ -1969,13 +1971,11 @@ static int idefloppy_open(struct inode *inode, struct file *filp) ** capacity of the drive or begin the format - Sam */ ) { - drive->usage--; ret = -EIO; goto out_put_floppy; } if (floppy->wp && (filp->f_mode & 2)) { - drive->usage--; ret = -EROFS; goto out_put_floppy; } @@ -1987,13 +1987,13 @@ static int idefloppy_open(struct inode *inode, struct file *filp) } check_disk_change(inode->i_bdev); } else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) { - drive->usage--; ret = -EBUSY; goto out_put_floppy; } return 0; out_put_floppy: + floppy->openers--; ide_floppy_put(floppy); return ret; } @@ -2007,7 +2007,7 @@ static int idefloppy_release(struct inode *inode, struct file *filp) debug_log(KERN_INFO "Reached idefloppy_release\n"); - if (drive->usage == 1) { + if (floppy->openers == 1) { /* IOMEGA Clik! drives do not support lock/unlock commands */ if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) { idefloppy_create_prevent_cmd(&pc, 0); @@ -2016,7 +2016,8 @@ static int idefloppy_release(struct inode *inode, struct file *filp) clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags); } - drive->usage--; + + floppy->openers--; ide_floppy_put(floppy); @@ -2050,7 +2051,7 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file, prevent = 0; /* fall through */ case CDROM_LOCKDOOR: - if (drive->usage > 1) + if (floppy->openers > 1) return -EBUSY; /* The IOMEGA Clik! Drive doesn't support this command - no room for an eject mechanism */ @@ -2072,7 +2073,7 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file, if (!(file->f_mode & 2)) return -EPERM; - if (drive->usage > 1) { + if (floppy->openers > 1) { /* Don't format if someone is using the disk */ clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 2614f41b507..c193553f6fe 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -226,7 +226,7 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request * break; if (drive->hwif->ide_dma_check == NULL) break; - drive->hwif->ide_dma_check(drive); + ide_set_dma(drive); break; } pm->pm_step = ide_pm_state_completed; @@ -1351,7 +1351,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) */ drive->retry_pio++; drive->state = DMA_PIO_RETRY; - (void) hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); /* * un-busy drive etc (hwgroup->busy is cleared on return) and @@ -1646,6 +1646,17 @@ irqreturn_t ide_intr (int irq, void *dev_id) del_timer(&hwgroup->timer); spin_unlock(&ide_lock); + /* Some controllers might set DMA INTR no matter DMA or PIO; + * bmdma status might need to be cleared even for + * PIO interrupts to prevent spurious/lost irq. + */ + if (hwif->ide_dma_clear_irq && !(drive->waiting_for_dma)) + /* ide_dma_end() needs bmdma status for error checking. + * So, skip clearing bmdma status here and leave it + * to ide_dma_end() if this is dma interrupt. + */ + hwif->ide_dma_clear_irq(drive); + if (drive->unmask) local_irq_enable_in_hardirq(); /* service this interrupt, may set handler for next interrupt */ diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index badde633177..c67b3b1e6f4 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -49,11 +49,6 @@ static void ide_insw (unsigned long port, void *addr, u32 count) insw(port, addr, count); } -static u32 ide_inl (unsigned long port) -{ - return (u32) inl(port); -} - static void ide_insl (unsigned long port, void *addr, u32 count) { insl(port, addr, count); @@ -79,11 +74,6 @@ static void ide_outsw (unsigned long port, void *addr, u32 count) outsw(port, addr, count); } -static void ide_outl (u32 val, unsigned long port) -{ - outl(val, port); -} - static void ide_outsl (unsigned long port, void *addr, u32 count) { outsl(port, addr, count); @@ -94,12 +84,10 @@ void default_hwif_iops (ide_hwif_t *hwif) hwif->OUTB = ide_outb; hwif->OUTBSYNC = ide_outbsync; hwif->OUTW = ide_outw; - hwif->OUTL = ide_outl; hwif->OUTSW = ide_outsw; hwif->OUTSL = ide_outsl; hwif->INB = ide_inb; hwif->INW = ide_inw; - hwif->INL = ide_inl; hwif->INSW = ide_insw; hwif->INSL = ide_insl; } @@ -123,11 +111,6 @@ static void ide_mm_insw (unsigned long port, void *addr, u32 count) __ide_mm_insw((void __iomem *) port, addr, count); } -static u32 ide_mm_inl (unsigned long port) -{ - return (u32) readl((void __iomem *) port); -} - static void ide_mm_insl (unsigned long port, void *addr, u32 count) { __ide_mm_insl((void __iomem *) port, addr, count); @@ -153,11 +136,6 @@ static void ide_mm_outsw (unsigned long port, void *addr, u32 count) __ide_mm_outsw((void __iomem *) port, addr, count); } -static void ide_mm_outl (u32 value, unsigned long port) -{ - writel(value, (void __iomem *) port); -} - static void ide_mm_outsl (unsigned long port, void *addr, u32 count) { __ide_mm_outsl((void __iomem *) port, addr, count); @@ -170,12 +148,10 @@ void default_hwif_mmiops (ide_hwif_t *hwif) this one is controller specific! */ hwif->OUTBSYNC = ide_mm_outbsync; hwif->OUTW = ide_mm_outw; - hwif->OUTL = ide_mm_outl; hwif->OUTSW = ide_mm_outsw; hwif->OUTSL = ide_mm_outsl; hwif->INB = ide_mm_inb; hwif->INW = ide_mm_inw; - hwif->INL = ide_mm_inl; hwif->INSW = ide_mm_insw; hwif->INSL = ide_mm_insl; } @@ -777,7 +753,7 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed) #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->ide_dma_check) /* check if host supports DMA */ - hwif->ide_dma_host_off(drive); + hwif->dma_host_off(drive); #endif /* @@ -854,9 +830,9 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed) #ifdef CONFIG_BLK_DEV_IDEDMA if (speed >= XFER_SW_DMA_0) - hwif->ide_dma_host_on(drive); + hwif->dma_host_on(drive); else if (hwif->ide_dma_check) /* check if host supports DMA */ - hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); #endif switch(speed) { @@ -1066,12 +1042,12 @@ static void check_dma_crc(ide_drive_t *drive) { #ifdef CONFIG_BLK_DEV_IDEDMA if (drive->crc_count) { - (void) HWIF(drive)->ide_dma_off_quietly(drive); + drive->hwif->dma_off_quietly(drive); ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive)); if (drive->current_speed >= XFER_SW_DMA_0) (void) HWIF(drive)->ide_dma_on(drive); } else - (void)__ide_dma_off(drive); + ide_dma_off(drive); #endif } diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 8237d89eec6..8afce4ceea3 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -205,6 +205,21 @@ int ide_dma_enable (ide_drive_t *drive) EXPORT_SYMBOL(ide_dma_enable); +int ide_use_fast_pio(ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + + if ((id->capability & 1) && drive->autodma) + return 1; + + if ((id->capability & 8) || (id->field_valid & 2)) + return 1; + + return 0; +} + +EXPORT_SYMBOL_GPL(ide_use_fast_pio); + /* * Standard (generic) timings for PIO modes, from ATA2 specification. * These timings are for access to the IDE data port register *only*. @@ -349,7 +364,6 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p int use_iordy = 0; struct hd_driveid* id = drive->id; int overridden = 0; - int blacklisted = 0; if (mode_wanted != 255) { pio_mode = mode_wanted; @@ -357,7 +371,6 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p pio_mode = 0; } else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) { overridden = 1; - blacklisted = 1; use_iordy = (pio_mode > 2); } else { pio_mode = id->tPIO; @@ -409,7 +422,6 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time; d->use_iordy = use_iordy; d->overridden = overridden; - d->blacklisted = blacklisted; } return pio_mode; } @@ -462,8 +474,6 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) return -1; } -EXPORT_SYMBOL_GPL(ide_set_xfer_rate); - static void ide_dump_opcode(ide_drive_t *drive) { struct request *rq; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 176bbc850d6..8afbd6cb94b 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -853,11 +853,11 @@ static void probe_hwif(ide_hwif_t *hwif) * things, if not checked and cleared. * PARANOIA!!! */ - hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); #ifdef CONFIG_IDEDMA_ONLYDISK if (drive->media == ide_disk) #endif - hwif->ide_dma_check(drive); + ide_set_dma(drive); } } } diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index c6eec0413a6..4e59239fef7 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -1970,7 +1970,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) printk(KERN_ERR "ide-tape: The tape wants to issue more " "interrupts in DMA mode\n"); printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n"); - (void)__ide_dma_off(drive); + ide_dma_off(drive); return ide_do_reset(drive); } /* Get the number of bytes to transfer on this interrupt. */ @@ -2176,7 +2176,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) { printk(KERN_WARNING "ide-tape: DMA disabled, " "reverting to PIO\n"); - (void)__ide_dma_off(drive); + ide_dma_off(drive); } if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) dma_ok = !hwif->dma_setup(drive); @@ -4792,15 +4792,10 @@ static int idetape_open(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; struct ide_tape_obj *tape; - ide_drive_t *drive; if (!(tape = ide_tape_get(disk))) return -ENXIO; - drive = tape->drive; - - drive->usage++; - return 0; } @@ -4808,9 +4803,6 @@ static int idetape_release(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; struct ide_tape_obj *tape = ide_tape_g(disk); - ide_drive_t *drive = tape->drive; - - drive->usage--; ide_tape_put(tape); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index c750f6ce770..b3c0818c5c6 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -389,9 +389,8 @@ int ide_hwif_request_regions(ide_hwif_t *hwif) unsigned long addr; unsigned int i; - if (hwif->mmio == 2) + if (hwif->mmio) return 0; - BUG_ON(hwif->mmio == 1); addr = hwif->io_ports[IDE_CONTROL_OFFSET]; if (addr && !hwif_request_region(hwif, addr, 1)) goto control_region_busy; @@ -438,7 +437,7 @@ void ide_hwif_release_regions(ide_hwif_t *hwif) { u32 i = 0; - if (hwif->mmio == 2) + if (hwif->mmio) return; if (hwif->io_ports[IDE_CONTROL_OFFSET]) release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); @@ -507,23 +506,22 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->ide_dma_end = tmp_hwif->ide_dma_end; hwif->ide_dma_check = tmp_hwif->ide_dma_check; hwif->ide_dma_on = tmp_hwif->ide_dma_on; - hwif->ide_dma_off_quietly = tmp_hwif->ide_dma_off_quietly; + hwif->dma_off_quietly = tmp_hwif->dma_off_quietly; hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq; - hwif->ide_dma_host_on = tmp_hwif->ide_dma_host_on; - hwif->ide_dma_host_off = tmp_hwif->ide_dma_host_off; + hwif->ide_dma_clear_irq = tmp_hwif->ide_dma_clear_irq; + hwif->dma_host_on = tmp_hwif->dma_host_on; + hwif->dma_host_off = tmp_hwif->dma_host_off; hwif->ide_dma_lostirq = tmp_hwif->ide_dma_lostirq; hwif->ide_dma_timeout = tmp_hwif->ide_dma_timeout; hwif->OUTB = tmp_hwif->OUTB; hwif->OUTBSYNC = tmp_hwif->OUTBSYNC; hwif->OUTW = tmp_hwif->OUTW; - hwif->OUTL = tmp_hwif->OUTL; hwif->OUTSW = tmp_hwif->OUTSW; hwif->OUTSL = tmp_hwif->OUTSL; hwif->INB = tmp_hwif->INB; hwif->INW = tmp_hwif->INW; - hwif->INL = tmp_hwif->INL; hwif->INSW = tmp_hwif->INSW; hwif->INSL = tmp_hwif->INSL; @@ -551,7 +549,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->extra_ports = tmp_hwif->extra_ports; hwif->autodma = tmp_hwif->autodma; hwif->udma_four = tmp_hwif->udma_four; - hwif->no_dsc = tmp_hwif->no_dsc; hwif->hwif_data = tmp_hwif->hwif_data; } @@ -1138,12 +1135,11 @@ static int set_using_dma (ide_drive_t *drive, int arg) if (HWIF(drive)->ide_dma_check == NULL) return -EPERM; if (arg) { - if (HWIF(drive)->ide_dma_check(drive)) return -EIO; - if (HWIF(drive)->ide_dma_on(drive)) return -EIO; - } else { - if (__ide_dma_off(drive)) + if (ide_set_dma(drive)) return -EIO; - } + if (HWIF(drive)->ide_dma_on(drive)) return -EIO; + } else + ide_dma_off(drive); return 0; #else return -EPERM; diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c index 0391a312287..1ed224a01f7 100644 --- a/drivers/ide/legacy/buddha.c +++ b/drivers/ide/legacy/buddha.c @@ -215,7 +215,7 @@ fail_base2: index = ide_register_hw(&hw, &hwif); if (index != -1) { - hwif->mmio = 2; + hwif->mmio = 1; printk("ide%d: ", index); switch(type) { case BOARD_BUDDHA: diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c index 64d42619ab0..dcfadbbf55d 100644 --- a/drivers/ide/legacy/gayle.c +++ b/drivers/ide/legacy/gayle.c @@ -167,7 +167,7 @@ found: index = ide_register_hw(&hw, &hwif); if (index != -1) { - hwif->mmio = 2; + hwif->mmio = 1; switch (i) { case 0: printk("ide%d: Gayle IDE interface (A%d style)\n", index, diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c index c48e87e512d..19ccd006f20 100644 --- a/drivers/ide/legacy/ht6560b.c +++ b/drivers/ide/legacy/ht6560b.c @@ -143,16 +143,16 @@ static void ht6560b_selectproc (ide_drive_t *drive) current_timing = timing; if (drive->media != ide_disk || !drive->present) select |= HT_PREFETCH_MODE; - (void) HWIF(drive)->INB(HT_CONFIG_PORT); - (void) HWIF(drive)->INB(HT_CONFIG_PORT); - (void) HWIF(drive)->INB(HT_CONFIG_PORT); - (void) HWIF(drive)->INB(HT_CONFIG_PORT); - HWIF(drive)->OUTB(select, HT_CONFIG_PORT); + (void)inb(HT_CONFIG_PORT); + (void)inb(HT_CONFIG_PORT); + (void)inb(HT_CONFIG_PORT); + (void)inb(HT_CONFIG_PORT); + outb(select, HT_CONFIG_PORT); /* * Set timing for this drive: */ - HWIF(drive)->OUTB(timing, IDE_SELECT_REG); - (void) HWIF(drive)->INB(IDE_STATUS_REG); + outb(timing, IDE_SELECT_REG); + (void)inb(IDE_STATUS_REG); #ifdef DEBUG printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing); diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c index b1730d7e414..4c0079ad52a 100644 --- a/drivers/ide/legacy/macide.c +++ b/drivers/ide/legacy/macide.c @@ -141,7 +141,7 @@ void macide_init(void) } if (index != -1) { - hwif->mmio = 2; + hwif->mmio = 1; if (macintosh_config->ide_type == MAC_IDE_QUADRA) printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index); else if (macintosh_config->ide_type == MAC_IDE_PB) diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c index 434a94faa3b..74f08124eab 100644 --- a/drivers/ide/legacy/q40ide.c +++ b/drivers/ide/legacy/q40ide.c @@ -145,7 +145,7 @@ void q40ide_init(void) index = ide_register_hw(&hw, &hwif); // **FIXME** if (index != -1) - hwif->mmio = 2; + hwif->mmio = 1; } } diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index c7854ea57b5..0a59d5ef159 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -181,12 +181,6 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed) { int mem_sttime; int mem_stcfg; - unsigned long mode; - -#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - if (ide_use_dma(drive)) - mode = ide_dma_speed(drive, 0); -#endif mem_sttime = 0; mem_stcfg = au_readl(MEM_STCFG2); @@ -195,7 +189,7 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed) auide_tune_drive(drive, speed - XFER_PIO_0); return 0; } - + switch(speed) { #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA case XFER_MW_DMA_2: @@ -207,7 +201,6 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed) mem_stcfg &= ~TOECS_MASK; mem_stcfg |= SBC_IDE_MDMA2_TCSOE | SBC_IDE_MDMA2_TOECS; - mode = XFER_MW_DMA_2; break; case XFER_MW_DMA_1: mem_sttime = SBC_IDE_TIMING(MDMA1); @@ -218,7 +211,6 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed) mem_stcfg &= ~TOECS_MASK; mem_stcfg |= SBC_IDE_MDMA1_TCSOE | SBC_IDE_MDMA1_TOECS; - mode = XFER_MW_DMA_1; break; case XFER_MW_DMA_0: mem_sttime = SBC_IDE_TIMING(MDMA0); @@ -229,14 +221,13 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed) mem_stcfg &= ~TOECS_MASK; mem_stcfg |= SBC_IDE_MDMA0_TCSOE | SBC_IDE_MDMA0_TOECS; - mode = XFER_MW_DMA_0; break; #endif default: return 1; } - - if (ide_config_drive_speed(drive, mode)) + + if (ide_config_drive_speed(drive, speed)) return 1; au_writel(mem_sttime,MEM_STTIME2); @@ -423,9 +414,9 @@ static int auide_dma_check(ide_drive_t *drive) speed = ide_find_best_mode(drive, XFER_PIO | XFER_MWDMA); if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) - return HWIF(drive)->ide_dma_on(drive); + return 0; - return HWIF(drive)->ide_dma_off_quietly(drive); + return -1; } static int auide_dma_test_irq(ide_drive_t *drive) @@ -447,27 +438,24 @@ static int auide_dma_test_irq(ide_drive_t *drive) return 0; } -static int auide_dma_host_on(ide_drive_t *drive) +static void auide_dma_host_on(ide_drive_t *drive) { - return 0; } static int auide_dma_on(ide_drive_t *drive) { drive->using_dma = 1; - return auide_dma_host_on(drive); -} + return 0; +} -static int auide_dma_host_off(ide_drive_t *drive) +static void auide_dma_host_off(ide_drive_t *drive) { - return 0; } -static int auide_dma_off_quietly(ide_drive_t *drive) +static void auide_dma_off_quietly(ide_drive_t *drive) { drive->using_dma = 0; - return auide_dma_host_off(drive); } static int auide_dma_lostirq(ide_drive_t *drive) @@ -717,7 +705,8 @@ static int au_ide_probe(struct device *dev) /* hold should be on in all cases */ hwif->hold = 1; - hwif->mmio = 2; + + hwif->mmio = 1; /* If the user has selected DDMA assisted copies, then set up a few local I/O function entry points @@ -732,7 +721,7 @@ static int au_ide_probe(struct device *dev) hwif->speedproc = &auide_tune_chipset; #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - hwif->ide_dma_off_quietly = &auide_dma_off_quietly; + hwif->dma_off_quietly = &auide_dma_off_quietly; hwif->ide_dma_timeout = &auide_dma_timeout; hwif->ide_dma_check = &auide_dma_check; @@ -741,8 +730,8 @@ static int au_ide_probe(struct device *dev) hwif->ide_dma_end = &auide_dma_end; hwif->dma_setup = &auide_dma_setup; hwif->ide_dma_test_irq = &auide_dma_test_irq; - hwif->ide_dma_host_off = &auide_dma_host_off; - hwif->ide_dma_host_on = &auide_dma_host_on; + hwif->dma_host_off = &auide_dma_host_off; + hwif->dma_host_on = &auide_dma_host_on; hwif->ide_dma_lostirq = &auide_dma_lostirq; hwif->ide_dma_on = &auide_dma_on; diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c index 09c9e7936b0..81fa06851b2 100644 --- a/drivers/ide/mips/swarm.c +++ b/drivers/ide/mips/swarm.c @@ -115,7 +115,7 @@ static int __devinit swarm_ide_probe(struct device *dev) /* Setup MMIO ops. */ default_hwif_mmiops(hwif); /* Prevent resource map manipulation. */ - hwif->mmio = 2; + hwif->mmio = 1; hwif->noprobe = 0; for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index d261bfbad22..990eafe5ea1 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -94,9 +94,9 @@ static u8 aec62xx_ratemask (ide_drive_t *drive) switch(hwif->pci_dev->device) { case PCI_DEVICE_ID_ARTOP_ATP865: case PCI_DEVICE_ID_ARTOP_ATP865R: - mode = (hwif->INB(((hwif->channel) ? - hwif->mate->dma_status : - hwif->dma_status)) & 0x10) ? 4 : 3; + mode = (inb(hwif->channel ? + hwif->mate->dma_status : + hwif->dma_status) & 0x10) ? 4 : 3; break; case PCI_DEVICE_ID_ARTOP_ATP860: case PCI_DEVICE_ID_ARTOP_ATP860R: @@ -209,25 +209,13 @@ static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio) static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) aec62xx_tune_drive(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + + return -1; } static int aec62xx_irq_timeout (ide_drive_t *drive) @@ -286,10 +274,8 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif) hwif->tuneproc = &aec62xx_tune_drive; hwif->speedproc = &aec62xx_tune_chipset; - if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) { + if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) hwif->serialized = hwif->channel; - hwif->no_dsc = 1; - } if (hwif->mate) hwif->mate->serialized = hwif->serialized; diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 68df77ec502..4debd18d52f 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -507,17 +507,15 @@ static int config_chipset_for_dma (ide_drive_t *drive) * * Configure a drive for DMA operation. If DMA is not possible we * drop the drive into PIO mode instead. - * - * FIXME: exactly what are we trying to return here */ - + static int ali15x3_config_drive_for_dma(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); struct hd_driveid *id = drive->id; if ((m5229_revision<=0x20) && (drive->media!=ide_disk)) - return hwif->ide_dma_off_quietly(drive); + goto no_dma_set; drive->init_speed = 0; @@ -552,9 +550,10 @@ try_dma_modes: ata_pio: hwif->tuneproc(drive, 255); no_dma_set: - return hwif->ide_dma_off_quietly(drive); + return -1; } - return hwif->ide_dma_on(drive); + + return 0; } /** @@ -852,8 +851,8 @@ static void __devinit init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase) { if (m5229_revision < 0x20) return; - if (!(hwif->channel)) - hwif->OUTB(hwif->INB(dmabase+2) & 0x60, dmabase+2); + if (!hwif->channel) + outb(inb(dmabase + 2) & 0x60, dmabase + 2); ide_setup_dma(hwif, dmabase, 8); } diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index a4336995a41..7989bdd842a 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -304,8 +304,9 @@ static int amd74xx_ide_dma_check(ide_drive_t *drive) amd_set_drive(drive, speed); if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) - return HWIF(drive)->ide_dma_on(drive); - return HWIF(drive)->ide_dma_off_quietly(drive); + return 0; + + return -1; } /* diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index 982ac31fa99..2d48af32e3f 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -101,7 +101,7 @@ static u8 atiixp_dma_2_pio(u8 xfer_rate) { } } -static int atiixp_ide_dma_host_on(ide_drive_t *drive) +static void atiixp_dma_host_on(ide_drive_t *drive) { struct pci_dev *dev = drive->hwif->pci_dev; unsigned long flags; @@ -118,10 +118,10 @@ static int atiixp_ide_dma_host_on(ide_drive_t *drive) spin_unlock_irqrestore(&atiixp_lock, flags); - return __ide_dma_host_on(drive); + ide_dma_host_on(drive); } -static int atiixp_ide_dma_host_off(ide_drive_t *drive) +static void atiixp_dma_host_off(ide_drive_t *drive) { struct pci_dev *dev = drive->hwif->pci_dev; unsigned long flags; @@ -135,7 +135,7 @@ static int atiixp_ide_dma_host_off(ide_drive_t *drive) spin_unlock_irqrestore(&atiixp_lock, flags); - return __ide_dma_host_off(drive); + ide_dma_host_off(drive); } /** @@ -235,11 +235,8 @@ static int atiixp_config_drive_for_dma(ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, atiixp_ratemask(drive)); - /* If no DMA speed was available then disable DMA and use PIO. */ - if (!speed) { - u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); - speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0; - } + if (!speed) + return 0; (void) atiixp_speedproc(drive, speed); return ide_dma_enable(drive); @@ -255,30 +252,20 @@ static int atiixp_config_drive_for_dma(ide_drive_t *drive) static int atiixp_dma_check(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; u8 tspeed, speed; drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (atiixp_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && atiixp_config_drive_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) { tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0; - hwif->speedproc(drive, speed); - return hwif->ide_dma_off_quietly(drive); + atiixp_speedproc(drive, speed); } - /* IORDY not supported */ - return 0; + + return -1; } /** @@ -318,8 +305,8 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif) else hwif->udma_four = 0; - hwif->ide_dma_host_on = &atiixp_ide_dma_host_on; - hwif->ide_dma_host_off = &atiixp_ide_dma_host_off; + hwif->dma_host_on = &atiixp_dma_host_on; + hwif->dma_host_off = &atiixp_dma_host_off; hwif->ide_dma_check = &atiixp_dma_check; if (!noautodma) hwif->autodma = 1; diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index aee947e8fc3..49df27513da 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -466,36 +466,21 @@ static int config_chipset_for_dma (ide_drive_t *drive) if (!speed) return 0; - if(ide_set_xfer_rate(drive, speed)) - return 0; - - if (!drive->init_speed) - drive->init_speed = speed; + if (cmd64x_tune_chipset(drive, speed)) + return 0; return ide_dma_enable(drive); } static int cmd64x_config_drive_for_dma (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) config_chipset_for_pio(drive, 1); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + + return -1; } static int cmd64x_alt_dma_status (struct pci_dev *dev) @@ -518,13 +503,13 @@ static int cmd64x_ide_dma_end (ide_drive_t *drive) drive->waiting_for_dma = 0; /* read DMA command state */ - dma_cmd = hwif->INB(hwif->dma_command); + dma_cmd = inb(hwif->dma_command); /* stop DMA */ - hwif->OUTB((dma_cmd & ~1), hwif->dma_command); + outb(dma_cmd & ~1, hwif->dma_command); /* get DMA status */ - dma_stat = hwif->INB(hwif->dma_status); + dma_stat = inb(hwif->dma_status); /* clear the INTR & ERROR bits */ - hwif->OUTB(dma_stat|6, hwif->dma_status); + outb(dma_stat | 6, hwif->dma_status); if (cmd64x_alt_dma_status(dev)) { u8 dma_intr = 0; u8 dma_mask = (hwif->channel) ? ARTTIM23_INTR_CH1 : @@ -546,7 +531,7 @@ static int cmd64x_ide_dma_test_irq (ide_drive_t *drive) struct pci_dev *dev = hwif->pci_dev; u8 dma_alt_stat = 0, mask = (hwif->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; - u8 dma_stat = hwif->INB(hwif->dma_status); + u8 dma_stat = inb(hwif->dma_status); (void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat); #ifdef DEBUG @@ -576,13 +561,13 @@ static int cmd646_1_ide_dma_end (ide_drive_t *drive) drive->waiting_for_dma = 0; /* get DMA status */ - dma_stat = hwif->INB(hwif->dma_status); + dma_stat = inb(hwif->dma_status); /* read DMA command state */ - dma_cmd = hwif->INB(hwif->dma_command); + dma_cmd = inb(hwif->dma_command); /* stop DMA */ - hwif->OUTB((dma_cmd & ~1), hwif->dma_command); + outb(dma_cmd & ~1, hwif->dma_command); /* clear the INTR & ERROR bits */ - hwif->OUTB(dma_stat|6, hwif->dma_status); + outb(dma_stat | 6, hwif->dma_status); /* and free any DMA resources */ ide_destroy_dmatable(drive); /* verify good DMA status */ diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index ba6786aabf3..400859a839f 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -132,12 +132,11 @@ static void cs5520_tune_drive(ide_drive_t *drive, u8 pio) static int cs5520_config_drive_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - /* Tune the drive for PIO modes up to PIO 4 */ cs5520_tune_drive(drive, 4); + /* Then tell the core to use DMA operations */ - return hwif->ide_dma_on(drive); + return 0; } /* diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index 9bf5fdfc5b1..b2d7c132ef4 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -81,8 +81,8 @@ static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autot pio = ide_get_best_pio_mode(drive, pio, 4, NULL); if (!cs5530_set_xfer_mode(drive, modes[pio])) { - format = (hwif->INL(basereg+4) >> 31) & 1; - hwif->OUTL(cs5530_pio_timings[format][pio], + format = (inl(basereg + 4) >> 31) & 1; + outl(cs5530_pio_timings[format][pio], basereg+(drive->select.b.unit<<3)); } } @@ -103,16 +103,13 @@ static int cs5530_config_dma (ide_drive_t *drive) int unit = drive->select.b.unit; ide_drive_t *mate = &hwif->drives[unit^1]; struct hd_driveid *id = drive->id; - unsigned int reg, timings; + unsigned int reg, timings = 0; unsigned long basereg; /* * Default to DMA-off in case we run into trouble here. */ - hwif->ide_dma_off_quietly(drive); - /* turn off DMA while we fiddle */ - hwif->ide_dma_host_off(drive); - /* clear DMA_capable bit */ + hwif->dma_off_quietly(drive); /* * The CS5530 specifies that two drives sharing a cable cannot @@ -182,30 +179,24 @@ static int cs5530_config_dma (ide_drive_t *drive) case XFER_MW_DMA_1: timings = 0x00012121; break; case XFER_MW_DMA_2: timings = 0x00002020; break; default: - printk(KERN_ERR "%s: cs5530_config_dma: huh? mode=%02x\n", - drive->name, mode); - return 1; /* failure */ + BUG(); + break; } basereg = CS5530_BASEREG(hwif); - reg = hwif->INL(basereg+4); /* get drive0 config register */ + reg = inl(basereg + 4); /* get drive0 config register */ timings |= reg & 0x80000000; /* preserve PIO format bit */ if (unit == 0) { /* are we configuring drive0? */ - hwif->OUTL(timings, basereg+4); /* write drive0 config register */ + outl(timings, basereg + 4); /* write drive0 config register */ } else { if (timings & 0x00100000) reg |= 0x00100000; /* enable UDMA timings for both drives */ else reg &= ~0x00100000; /* disable UDMA timings for both drives */ - hwif->OUTL(reg, basereg+4); /* write drive0 config register */ - hwif->OUTL(timings, basereg+12); /* write drive1 config register */ + outl(reg, basereg + 4); /* write drive0 config register */ + outl(timings, basereg + 12); /* write drive1 config register */ } - (void) hwif->ide_dma_host_on(drive); - /* set DMA_capable bit */ - /* - * Finally, turn DMA on in software, and exit. - */ - return hwif->ide_dma_on(drive); /* success */ + return 0; /* success */ } /** @@ -321,17 +312,17 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif) hwif->tuneproc = &cs5530_tuneproc; basereg = CS5530_BASEREG(hwif); - d0_timings = hwif->INL(basereg+0); + d0_timings = inl(basereg + 0); if (CS5530_BAD_PIO(d0_timings)) { /* PIO timings not initialized? */ - hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0); + outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 0); if (!hwif->drives[0].autotune) hwif->drives[0].autotune = 1; /* needs autotuning later */ } - if (CS5530_BAD_PIO(hwif->INL(basereg+8))) { - /* PIO timings not initialized? */ - hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8); + if (CS5530_BAD_PIO(inl(basereg + 8))) { + /* PIO timings not initialized? */ + outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 8); if (!hwif->drives[1].autotune) hwif->drives[1].autotune = 1; /* needs autotuning later */ diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c index 5c5aec28e67..45f43efbf92 100644 --- a/drivers/ide/pci/cs5535.c +++ b/drivers/ide/pci/cs5535.c @@ -195,28 +195,19 @@ static int cs5535_config_drive_for_dma(ide_drive_t *drive) static int cs5535_dma_check(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; - struct hd_driveid *id = drive->id; u8 speed; drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - if (ide_use_dma(drive)) { - if (cs5535_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && cs5535_config_drive_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) { speed = ide_get_best_pio_mode(drive, 255, 4, NULL); cs5535_set_drive(drive, speed); - return hwif->ide_dma_off_quietly(drive); } - /* IORDY not supported */ - return 0; + + return -1; } static u8 __devinit cs5535_cable_detect(struct pci_dev *dev) diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c index 9eafcbf444f..103b9db9785 100644 --- a/drivers/ide/pci/cy82c693.c +++ b/drivers/ide/pci/cy82c693.c @@ -197,8 +197,8 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) #if CY82C693_DEBUG_LOGS /* for debug let's show the previous values */ - HWIF(drive)->OUTB(index, CY82_INDEX_PORT); - data = HWIF(drive)->INB(CY82_DATA_PORT); + outb(index, CY82_INDEX_PORT); + data = inb(CY82_DATA_PORT); printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, @@ -207,8 +207,8 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) data = (u8)mode|(u8)(single<<2); - HWIF(drive)->OUTB(index, CY82_INDEX_PORT); - HWIF(drive)->OUTB(data, CY82_DATA_PORT); + outb(index, CY82_INDEX_PORT); + outb(data, CY82_DATA_PORT); #if CY82C693_DEBUG_INFO printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", @@ -227,8 +227,8 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) */ data = BUSMASTER_TIMEOUT; - HWIF(drive)->OUTB(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT); - HWIF(drive)->OUTB(data, CY82_DATA_PORT); + outb(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT); + outb(data, CY82_DATA_PORT); #if CY82C693_DEBUG_INFO printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n", @@ -478,21 +478,18 @@ static void __devinit init_iops_cy82c693(ide_hwif_t *hwif) } } -static ide_pci_device_t cy82c693_chipsets[] __devinitdata = { - { /* 0 */ - .name = "CY82C693", - .init_chipset = init_chipset_cy82c693, - .init_iops = init_iops_cy82c693, - .init_hwif = init_hwif_cy82c693, - .channels = 1, - .autodma = AUTODMA, - .bootable = ON_BOARD, - } +static ide_pci_device_t cy82c693_chipset __devinitdata = { + .name = "CY82C693", + .init_chipset = init_chipset_cy82c693, + .init_iops = init_iops_cy82c693, + .init_hwif = init_hwif_cy82c693, + .channels = 1, + .autodma = AUTODMA, + .bootable = ON_BOARD, }; static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_pci_device_t *d = &cy82c693_chipsets[id->driver_data]; struct pci_dev *dev2; int ret = -ENODEV; @@ -501,7 +498,7 @@ static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_dev if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && PCI_FUNC(dev->devfn) == 1) { dev2 = pci_get_slot(dev->bus, dev->devfn + 1); - ret = ide_setup_pci_devices(dev, dev2, d); + ret = ide_setup_pci_devices(dev, dev2, &cy82c693_chipset); /* We leak pci refs here but thats ok - we can't be unloaded */ } return ret; diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c index ce7b08f08a0..924eaa3a570 100644 --- a/drivers/ide/pci/hpt34x.c +++ b/drivers/ide/pci/hpt34x.c @@ -48,19 +48,6 @@ static u8 hpt34x_ratemask (ide_drive_t *drive) return 1; } -static void hpt34x_clear_chipset (ide_drive_t *drive) -{ - struct pci_dev *dev = HWIF(drive)->pci_dev; - u32 reg1 = 0, tmp1 = 0, reg2 = 0, tmp2 = 0; - - pci_read_config_dword(dev, 0x44, ®1); - pci_read_config_dword(dev, 0x48, ®2); - tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn)))); - tmp2 = (reg2 & ~(0x11 << drive->dn)); - pci_write_config_dword(dev, 0x44, tmp1); - pci_write_config_dword(dev, 0x48, tmp2); -} - static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed) { struct pci_dev *dev = HWIF(drive)->pci_dev; @@ -81,7 +68,7 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed) pci_read_config_dword(dev, 0x44, ®1); pci_read_config_dword(dev, 0x48, ®2); tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn)))); - tmp2 = ((hi_speed << drive->dn) | reg2); + tmp2 = ((hi_speed << drive->dn) | (reg2 & ~(0x11 << drive->dn))); pci_write_config_dword(dev, 0x44, tmp1); pci_write_config_dword(dev, 0x48, tmp2); @@ -99,7 +86,6 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed) static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio) { pio = ide_get_best_pio_mode(drive, pio, 5, NULL); - hpt34x_clear_chipset(drive); (void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio)); } @@ -117,38 +103,25 @@ static int config_chipset_for_dma (ide_drive_t *drive) if (!(speed)) return 0; - hpt34x_clear_chipset(drive); (void) hpt34x_tune_chipset(drive, speed); return ide_dma_enable(drive); } static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if (id && (id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) #ifndef CONFIG_HPT34X_AUTODMA - return hwif->ide_dma_off_quietly(drive); + return -1; #else - return hwif->ide_dma_on(drive); + return 0; #endif - } - - goto fast_ata_pio; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) hpt34x_tune_drive(drive, 255); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + + return -1; } /* @@ -209,7 +182,6 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif) hwif->tuneproc = &hpt34x_tune_drive; hwif->speedproc = &hpt34x_tune_chipset; - hwif->no_dsc = 1; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 05be8fadda7..60ecdc258c7 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -736,24 +736,15 @@ static void hpt3xx_maskproc(ide_drive_t *drive, int mask) static int hpt366_config_drive_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - if (ide_use_dma(drive) && config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) hpt3xx_tune_drive(drive, 255); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + + return -1; } /* @@ -841,7 +832,7 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive) return 0; } - dma_stat = hwif->INB(hwif->dma_status); + dma_stat = inb(hwif->dma_status); /* return 1 if INTR asserted */ if (dma_stat & 4) return 1; @@ -1391,9 +1382,6 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase) u8 dma_new = 0, dma_old = 0; unsigned long flags; - if (!dmabase) - return; - dma_old = hwif->INB(dmabase + 2); local_irq_save(flags); diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index 63248b6909f..424f00bb160 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -244,17 +244,15 @@ static int config_chipset_for_dma (ide_drive_t *drive) static int it8213_config_drive_for_dma (ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; + u8 pio; - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - hwif->speedproc(drive, XFER_PIO_0 - + ide_get_best_pio_mode(drive, 255, 4, NULL)); + pio = ide_get_best_pio_mode(drive, 255, 4, NULL); + it8213_tune_chipset(drive, XFER_PIO_0 + pio); - return hwif->ide_dma_off_quietly(drive); + return -1; } /** diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index e9bad185968..a132767f7d9 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -520,14 +520,12 @@ static int config_chipset_for_dma (ide_drive_t *drive) static int it821x_config_drive_for_dma (ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } config_it821x_chipset_for_pio(drive, 1); - return hwif->ide_dma_off_quietly(drive); + + return -1; } /** @@ -608,11 +606,11 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif) printk(".\n"); /* Now the core code will have wrongly decided no DMA so we need to fix this */ - hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); #ifdef CONFIG_IDEDMA_ONLYDISK if (drive->media == ide_disk) #endif - hwif->ide_dma_check(drive); + ide_set_dma(drive); } else { /* Non RAID volume. Fixups to stop the core code doing unsupported things */ diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c index f07bbbed177..53f25500c22 100644 --- a/drivers/ide/pci/jmicron.c +++ b/drivers/ide/pci/jmicron.c @@ -147,7 +147,9 @@ static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, jmicron_ratemask(drive)); - config_jmicron_chipset_for_pio(drive, !speed); + if (!speed) + return 0; + jmicron_tune_chipset(drive, speed); return ide_dma_enable(drive); } @@ -162,14 +164,12 @@ static int config_chipset_for_dma (ide_drive_t *drive) static int jmicron_config_drive_for_dma (ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } config_jmicron_chipset_for_pio(drive, 1); - return hwif->ide_dma_off_quietly(drive); + + return -1; } /** diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c index 8aaea4ea554..b310c4f5107 100644 --- a/drivers/ide/pci/ns87415.c +++ b/drivers/ide/pci/ns87415.c @@ -166,10 +166,10 @@ static int ns87415_ide_dma_end (ide_drive_t *drive) /* get dma command mode */ dma_cmd = hwif->INB(hwif->dma_command); /* stop DMA */ - hwif->OUTB(dma_cmd & ~1, hwif->dma_command); + outb(dma_cmd & ~1, hwif->dma_command); /* from ERRATA: clear the INTR & ERROR bits */ dma_cmd = hwif->INB(hwif->dma_command); - hwif->OUTB(dma_cmd|6, hwif->dma_command); + outb(dma_cmd | 6, hwif->dma_command); /* and free any DMA resources */ ide_destroy_dmatable(drive); /* verify good DMA status */ @@ -190,7 +190,8 @@ static int ns87415_ide_dma_setup(ide_drive_t *drive) static int ns87415_ide_dma_check (ide_drive_t *drive) { if (drive->media != ide_disk) - return HWIF(drive)->ide_dma_off_quietly(drive); + return -1; + return __ide_dma_check(drive); } @@ -243,9 +244,9 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) * to SELECT_DRIVE() properly during first probe_hwif(). */ timeout = 10000; - hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]); + outb(12, hwif->io_ports[IDE_CONTROL_OFFSET]); udelay(10); - hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]); + outb(8, hwif->io_ports[IDE_CONTROL_OFFSET]); do { udelay(50); stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]); @@ -263,7 +264,7 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) if (!hwif->dma_base) return; - hwif->OUTB(0x60, hwif->dma_status); + outb(0x60, hwif->dma_status); hwif->dma_setup = &ns87415_ide_dma_setup; hwif->ide_dma_check = &ns87415_ide_dma_check; hwif->ide_dma_end = &ns87415_ide_dma_end; diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index 22bbf613f94..9ca60dd2185 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -176,34 +176,35 @@ static int cmpt_clk(int time, int bus_speed) return ((time*bus_speed+999)/1000); } -static void write_reg(ide_hwif_t *hwif, u8 value, int reg) /* Write value to register reg, base of register * is at reg_base (0x1f0 primary, 0x170 secondary, * if not changed by PCI configuration). * This is from setupvic.exe program. */ +static void write_reg(u8 value, int reg) { - hwif->INW(reg_base+1); - hwif->INW(reg_base+1); - hwif->OUTB(3, reg_base+2); - hwif->OUTB(value, reg_base+reg); - hwif->OUTB(0x83, reg_base+2); + inw(reg_base + 1); + inw(reg_base + 1); + outb(3, reg_base + 2); + outb(value, reg_base + reg); + outb(0x83, reg_base + 2); } -static u8 read_reg(ide_hwif_t *hwif, int reg) /* Read value from register reg, base of register * is at reg_base (0x1f0 primary, 0x170 secondary, * if not changed by PCI configuration). * This is from setupvic.exe program. */ +static u8 read_reg(int reg) { u8 ret = 0; - hwif->INW(reg_base+1); - hwif->INW(reg_base+1); - hwif->OUTB(3, reg_base+2); - ret = hwif->INB(reg_base+reg); - hwif->OUTB(0x83, reg_base+2); + inw(reg_base + 1); + inw(reg_base + 1); + outb(3, reg_base + 2); + ret = inb(reg_base + reg); + outb(0x83, reg_base + 2); + return ret; } @@ -286,39 +287,39 @@ static void opti621_tune_drive (ide_drive_t *drive, u8 pio) reg_base = hwif->io_ports[IDE_DATA_OFFSET]; /* allow Register-B */ - hwif->OUTB(0xc0, reg_base+CNTRL_REG); + outb(0xc0, reg_base + CNTRL_REG); /* hmm, setupvic.exe does this ;-) */ - hwif->OUTB(0xff, reg_base+5); + outb(0xff, reg_base + 5); /* if reads 0xff, adapter not exist? */ - (void) hwif->INB(reg_base+CNTRL_REG); + (void)inb(reg_base + CNTRL_REG); /* if reads 0xc0, no interface exist? */ - read_reg(hwif, CNTRL_REG); + read_reg(CNTRL_REG); /* read version, probably 0 */ - read_reg(hwif, STRAP_REG); + read_reg(STRAP_REG); /* program primary drive */ - /* select Index-0 for Register-A */ - write_reg(hwif, 0, MISC_REG); - /* set read cycle timings */ - write_reg(hwif, cycle1, READ_REG); - /* set write cycle timings */ - write_reg(hwif, cycle1, WRITE_REG); + /* select Index-0 for Register-A */ + write_reg(0, MISC_REG); + /* set read cycle timings */ + write_reg(cycle1, READ_REG); + /* set write cycle timings */ + write_reg(cycle1, WRITE_REG); /* program secondary drive */ - /* select Index-1 for Register-B */ - write_reg(hwif, 1, MISC_REG); - /* set read cycle timings */ - write_reg(hwif, cycle2, READ_REG); - /* set write cycle timings */ - write_reg(hwif, cycle2, WRITE_REG); + /* select Index-1 for Register-B */ + write_reg(1, MISC_REG); + /* set read cycle timings */ + write_reg(cycle2, READ_REG); + /* set write cycle timings */ + write_reg(cycle2, WRITE_REG); /* use Register-A for drive 0 */ /* use Register-B for drive 1 */ - write_reg(hwif, 0x85, CNTRL_REG); + write_reg(0x85, CNTRL_REG); /* set address setup, DRDY timings, */ /* and read prefetch for both drives */ - write_reg(hwif, misc, MISC_REG); + write_reg(misc, MISC_REG); spin_unlock_irqrestore(&ide_lock, flags); } diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 236a03144a2..6ceb25bc5a7 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -101,8 +101,8 @@ static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index) { u8 value; - hwif->OUTB(index, hwif->dma_vendor1); - value = hwif->INB(hwif->dma_vendor3); + outb(index, hwif->dma_vendor1); + value = inb(hwif->dma_vendor3); DBG("index[%02X] value[%02X]\n", index, value); return value; @@ -115,8 +115,8 @@ static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index) */ static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value) { - hwif->OUTB(index, hwif->dma_vendor1); - hwif->OUTB(value, hwif->dma_vendor3); + outb(index, hwif->dma_vendor1); + outb(value, hwif->dma_vendor3); DBG("index[%02X] value[%02X]\n", index, value); } @@ -281,25 +281,15 @@ static int config_chipset_for_dma(ide_drive_t *drive) static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive) && config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - goto fast_ata_pio; + if (ide_use_fast_pio(drive)) + pdcnew_tune_drive(drive, 255); - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - hwif->tuneproc(drive, 255); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + return -1; } static int pdcnew_quirkproc(ide_drive_t *drive) diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index 730e8d1ec2f..a7a639fe1ea 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -2,6 +2,7 @@ * linux/drivers/ide/pci/pdc202xx_old.c Version 0.36 Sept 11, 2002 * * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2006-2007 MontaVista Software, Inc. * * Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this * compiled into the kernel if you have more than one card installed. @@ -216,21 +217,10 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed) } -/* 0 1 2 3 4 5 6 7 8 - * 960, 480, 390, 300, 240, 180, 120, 90, 60 - * 180, 150, 120, 90, 60 - * DMA_Speed - * 180, 120, 90, 90, 90, 60, 30 - * 11, 5, 4, 3, 2, 1, 0 - */ -static void config_chipset_for_pio (ide_drive_t *drive, u8 pio) +static void pdc202xx_tune_drive(ide_drive_t *drive, u8 pio) { - u8 speed = 0; - - if (pio == 5) pio = 4; - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL); - - pdc202xx_tune_chipset(drive, speed); + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + pdc202xx_tune_chipset(drive, XFER_PIO_0 + pio); } static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif) @@ -250,17 +240,17 @@ static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif) static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif) { unsigned long clock_reg = hwif->dma_master + 0x11; - u8 clock = hwif->INB(clock_reg); + u8 clock = inb(clock_reg); - hwif->OUTB(clock | (hwif->channel ? 0x08 : 0x02), clock_reg); + outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg); } static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif) { unsigned long clock_reg = hwif->dma_master + 0x11; - u8 clock = hwif->INB(clock_reg); + u8 clock = inb(clock_reg); - hwif->OUTB(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg); + outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg); } static int config_chipset_for_dma (ide_drive_t *drive) @@ -332,27 +322,15 @@ chipset_is_set: static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if (id && (id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - goto fast_ata_pio; + if (ide_use_fast_pio(drive)) + pdc202xx_tune_drive(drive, 255); - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - hwif->tuneproc(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + return -1; } static int pdc202xx_quirkproc (ide_drive_t *drive) @@ -375,14 +353,14 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive) unsigned long high_16 = hwif->dma_master; unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); u32 word_count = 0; - u8 clock = hwif->INB(high_16 + 0x11); + u8 clock = inb(high_16 + 0x11); - hwif->OUTB(clock|(hwif->channel ? 0x08 : 0x02), high_16+0x11); + outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11); word_count = (rq->nr_sectors << 8); word_count = (rq_data_dir(rq) == READ) ? word_count | 0x05000000 : word_count | 0x06000000; - hwif->OUTL(word_count, atapi_reg); + outl(word_count, atapi_reg); } ide_dma_start(drive); } @@ -395,9 +373,9 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive) unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); u8 clock = 0; - hwif->OUTL(0, atapi_reg); /* zero out extra */ - clock = hwif->INB(high_16 + 0x11); - hwif->OUTB(clock & ~(hwif->channel ? 0x08:0x02), high_16+0x11); + outl(0, atapi_reg); /* zero out extra */ + clock = inb(high_16 + 0x11); + outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11); } if (drive->current_speed > XFER_UDMA_2) pdc_old_disable_66MHz_clock(drive->hwif); @@ -408,8 +386,8 @@ static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); unsigned long high_16 = hwif->dma_master; - u8 dma_stat = hwif->INB(hwif->dma_status); - u8 sc1d = hwif->INB((high_16 + 0x001d)); + u8 dma_stat = inb(hwif->dma_status); + u8 sc1d = inb(high_16 + 0x001d); if (hwif->channel) { /* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */ @@ -445,11 +423,11 @@ static int pdc202xx_ide_dma_timeout(ide_drive_t *drive) static void pdc202xx_reset_host (ide_hwif_t *hwif) { unsigned long high_16 = hwif->dma_master; - u8 udma_speed_flag = hwif->INB(high_16|0x001f); + u8 udma_speed_flag = inb(high_16 | 0x001f); - hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f)); + outb(udma_speed_flag | 0x10, high_16 | 0x001f); mdelay(100); - hwif->OUTB((udma_speed_flag & ~0x10), (high_16|0x001f)); + outb(udma_speed_flag & ~0x10, high_16 | 0x001f); mdelay(2000); /* 2 seconds ?! */ printk(KERN_WARNING "PDC202XX: %s channel reset.\n", @@ -463,7 +441,7 @@ static void pdc202xx_reset (ide_drive_t *drive) pdc202xx_reset_host(hwif); pdc202xx_reset_host(mate); - hwif->tuneproc(drive, 5); + pdc202xx_tune_drive(drive, 255); } static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, @@ -490,7 +468,7 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif) hwif->rqsize = 256; hwif->autodma = 0; - hwif->tuneproc = &config_chipset_for_pio; + hwif->tuneproc = &pdc202xx_tune_drive; hwif->quirkproc = &pdc202xx_quirkproc; if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) @@ -537,9 +515,9 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase) return; } - udma_speed_flag = hwif->INB((dmabase|0x1f)); - primary_mode = hwif->INB((dmabase|0x1a)); - secondary_mode = hwif->INB((dmabase|0x1b)); + udma_speed_flag = inb(dmabase | 0x1f); + primary_mode = inb(dmabase | 0x1a); + secondary_mode = inb(dmabase | 0x1b); printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \ "Primary %s Mode " \ "Secondary %s Mode.\n", hwif->cds->name, @@ -552,30 +530,10 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase) printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ", hwif->cds->name, udma_speed_flag, (udma_speed_flag|1)); - hwif->OUTB(udma_speed_flag|1,(dmabase|0x1f)); - printk("%sACTIVE\n", - (hwif->INB(dmabase|0x1f)&1) ? "":"IN"); + outb(udma_speed_flag | 1, dmabase | 0x1f); + printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN"); } #endif /* CONFIG_PDC202XX_BURST */ -#ifdef CONFIG_PDC202XX_MASTER - if (!(primary_mode & 1)) { - printk(KERN_INFO "%s: FORCING PRIMARY MODE BIT " - "0x%02x -> 0x%02x ", hwif->cds->name, - primary_mode, (primary_mode|1)); - hwif->OUTB(primary_mode|1, (dmabase|0x1a)); - printk("%s\n", - (hwif->INB((dmabase|0x1a)) & 1) ? "MASTER" : "PCI"); - } - - if (!(secondary_mode & 1)) { - printk(KERN_INFO "%s: FORCING SECONDARY MODE BIT " - "0x%02x -> 0x%02x ", hwif->cds->name, - secondary_mode, (secondary_mode|1)); - hwif->OUTB(secondary_mode|1, (dmabase|0x1b)); - printk("%s\n", - (hwif->INB((dmabase|0x1b)) & 1) ? "MASTER" : "PCI"); - } -#endif /* CONFIG_PDC202XX_MASTER */ ide_setup_dma(hwif, dmabase, 8); } diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 52cfc2ac22c..569822f4cf5 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -369,7 +369,7 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) * If no DMA speed was available or the chipset has DMA bugs * then disable DMA and use PIO */ - if (!speed || no_piix_dma) + if (!speed) return 0; (void) piix_tune_chipset(drive, speed); @@ -386,41 +386,28 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) static int piix_config_drive_xfer_rate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive) && piix_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - - goto fast_ata_pio; + if (ide_use_dma(drive) && piix_config_drive_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) /* Find best PIO mode. */ - (void) hwif->speedproc(drive, XFER_PIO_0 + - ide_get_best_pio_mode(drive, 255, 4, NULL)); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + piix_tune_chipset(drive, XFER_PIO_0 + + ide_get_best_pio_mode(drive, 255, 4, NULL)); + + return -1; } /** - * init_chipset_piix - set up the PIIX chipset - * @dev: PCI device to set up - * @name: Name of the device + * piix_is_ichx - check if ICHx + * @dev: PCI device to check * - * Initialize the PCI device as required. For the PIIX this turns - * out to be nice and simple + * returns 1 if ICHx, 0 otherwise. */ - -static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name) +static int piix_is_ichx(struct pci_dev *dev) { - switch(dev->device) { + switch (dev->device) { case PCI_DEVICE_ID_INTEL_82801EB_1: case PCI_DEVICE_ID_INTEL_82801AA_1: case PCI_DEVICE_ID_INTEL_82801AB_1: @@ -438,19 +425,61 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char case PCI_DEVICE_ID_INTEL_ICH7_21: case PCI_DEVICE_ID_INTEL_ESB2_18: case PCI_DEVICE_ID_INTEL_ICH8_6: - { - unsigned int extra = 0; - pci_read_config_dword(dev, 0x54, &extra); - pci_write_config_dword(dev, 0x54, extra|0x400); - } - default: - break; + return 1; } return 0; } /** + * init_chipset_piix - set up the PIIX chipset + * @dev: PCI device to set up + * @name: Name of the device + * + * Initialize the PCI device as required. For the PIIX this turns + * out to be nice and simple + */ + +static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name) +{ + if (piix_is_ichx(dev)) { + unsigned int extra = 0; + pci_read_config_dword(dev, 0x54, &extra); + pci_write_config_dword(dev, 0x54, extra|0x400); + } + + return 0; +} + +/** + * piix_dma_clear_irq - clear BMDMA status + * @drive: IDE drive to clear + * + * Called from ide_intr() for PIO interrupts + * to clear BMDMA status as needed by ICHx + */ +static void piix_dma_clear_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + u8 dma_stat; + + /* clear the INTR & ERROR bits */ + dma_stat = hwif->INB(hwif->dma_status); + /* Should we force the bit as well ? */ + hwif->OUTB(dma_stat, hwif->dma_status); +} + +static int __devinit piix_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *dev = hwif->pci_dev; + u8 reg54h = 0, mask = hwif->channel ? 0xc0 : 0x30; + + pci_read_config_byte(dev, 0x54, ®54h); + + return (reg54h & mask) ? 1 : 0; +} + +/** * init_hwif_piix - fill in the hwif for the PIIX * @hwif: IDE interface * @@ -460,9 +489,6 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char static void __devinit init_hwif_piix(ide_hwif_t *hwif) { - u8 reg54h = 0, reg55h = 0, ata66 = 0; - u8 mask = hwif->channel ? 0xc0 : 0x30; - #ifndef CONFIG_IA64 if (!hwif->irq) hwif->irq = hwif->channel ? 15 : 14; @@ -472,10 +498,6 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif) /* This is a painful system best to let it self tune for now */ return; } - /* ESB2 appears to generate spurious DMA interrupts in PIO mode - when in native mode */ - if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_ESB2_18) - hwif->atapi_irq_bogon = 1; hwif->autodma = 0; hwif->tuneproc = &piix_tune_drive; @@ -486,15 +508,16 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif) if (!hwif->dma_base) return; + /* ICHx need to clear the bmdma status for all interrupts */ + if (piix_is_ichx(hwif->pci_dev)) + hwif->ide_dma_clear_irq = &piix_dma_clear_irq; + hwif->atapi_dma = 1; hwif->ultra_mask = 0x3f; hwif->mwdma_mask = 0x06; hwif->swdma_mask = 0x04; switch(hwif->pci_dev->device) { - case PCI_DEVICE_ID_INTEL_82371MX: - hwif->mwdma_mask = 0x80; - hwif->swdma_mask = 0x80; case PCI_DEVICE_ID_INTEL_82371FB_0: case PCI_DEVICE_ID_INTEL_82371FB_1: case PCI_DEVICE_ID_INTEL_82371SB_1: @@ -507,14 +530,14 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif) hwif->ultra_mask = 0x07; break; default: - pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); - pci_read_config_byte(hwif->pci_dev, 0x55, ®55h); - ata66 = (reg54h & mask) ? 1 : 0; + if (!hwif->udma_four) + hwif->udma_four = piix_cable_detect(hwif); break; } - if (!(hwif->udma_four)) - hwif->udma_four = ata66; + if (no_piix_dma) + hwif->ultra_mask = hwif->mwdma_mask = hwif->swdma_mask = 0; + hwif->ide_dma_check = &piix_config_drive_xfer_rate; if (!noautodma) hwif->autodma = 1; diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index 8d762d323f8..b5ae0c50e21 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -161,7 +161,7 @@ static int sc1200_config_dma2 (ide_drive_t *drive, int mode) /* * Default to DMA-off in case we run into trouble here. */ - hwif->ide_dma_off_quietly(drive); /* turn off DMA while we fiddle */ + hwif->dma_off_quietly(drive); /* turn off DMA while we fiddle */ outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */ /* @@ -241,10 +241,7 @@ static int sc1200_config_dma2 (ide_drive_t *drive, int mode) outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2); /* set DMA_capable bit */ - /* - * Finally, turn DMA on in software, and exit. - */ - return hwif->ide_dma_on(drive); /* success */ + return 0; /* success */ } /* @@ -442,10 +439,10 @@ static int sc1200_resume (struct pci_dev *dev) ide_drive_t *drive = &(hwif->drives[d]); if (drive->present && !__ide_dma_bad_drive(drive)) { int was_using_dma = drive->using_dma; - hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); sc1200_config_dma(drive); if (!was_using_dma && drive->using_dma) { - hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); } } } diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index ea9a28a4585..dbcd37a0c65 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -160,7 +160,7 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed) if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) { if (!drive->init_speed) { - u8 dma_stat = hwif->INB(hwif->dma_status); + u8 dma_stat = inb(hwif->dma_status); dma_pio: if (((ultra_enable << (7-drive->dn) & 0x80) == 0x80) && @@ -315,35 +315,15 @@ static int config_chipset_for_dma (ide_drive_t *drive) static int svwks_config_drive_xfer_rate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) config_chipset_for_pio(drive); - // hwif->tuneproc(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -/* This can go soon */ -static int svwks_ide_dma_end (ide_drive_t *drive) -{ - return __ide_dma_end(drive); + return -1; } static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const char *name) @@ -537,35 +517,20 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif) } hwif->ide_dma_check = &svwks_config_drive_xfer_rate; - if (hwif->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) - hwif->ide_dma_end = &svwks_ide_dma_end; - else if (!(hwif->udma_four)) - hwif->udma_four = ata66_svwks(hwif); + if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { + if (!hwif->udma_four) + hwif->udma_four = ata66_svwks(hwif); + } if (!noautodma) hwif->autodma = 1; - dma_stat = hwif->INB(hwif->dma_status); + dma_stat = inb(hwif->dma_status); hwif->drives[0].autodma = (dma_stat & 0x20); hwif->drives[1].autodma = (dma_stat & 0x40); hwif->drives[0].autotune = (!(dma_stat & 0x20)); hwif->drives[1].autotune = (!(dma_stat & 0x40)); } -/* - * We allow the BM-DMA driver to only work on enabled interfaces. - */ -static void __devinit init_dma_svwks (ide_hwif_t *hwif, unsigned long dmabase) -{ - struct pci_dev *dev = hwif->pci_dev; - - if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || - (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) && - (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel)) - return; - - ide_setup_dma(hwif, dmabase, 8); -} - static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d) { return ide_setup_pci_device(dev, d); @@ -600,7 +565,6 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = { .init_setup = init_setup_svwks, .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .init_dma = init_dma_svwks, .channels = 2, .autodma = AUTODMA, .bootable = ON_BOARD, @@ -609,7 +573,6 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = { .init_setup = init_setup_csb6, .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .init_dma = init_dma_svwks, .channels = 2, .autodma = AUTODMA, .bootable = ON_BOARD, @@ -618,7 +581,6 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = { .init_setup = init_setup_csb6, .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .init_dma = init_dma_svwks, .channels = 1, /* 2 */ .autodma = AUTODMA, .bootable = ON_BOARD, @@ -627,7 +589,6 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = { .init_setup = init_setup_svwks, .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .init_dma = init_dma_svwks, .channels = 1, /* 2 */ .autodma = AUTODMA, .bootable = ON_BOARD, diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index b0bf0180927..fd09b295a69 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -110,24 +110,24 @@ sgiioc4_init_hwif_ports(hw_regs_t * hw, unsigned long data_port, static void sgiioc4_maskproc(ide_drive_t * drive, int mask) { - ide_hwif_t *hwif = HWIF(drive); - hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2), - IDE_CONTROL_REG); + writeb(mask ? (drive->ctl | 2) : (drive->ctl & ~2), + (void __iomem *)IDE_CONTROL_REG); } static int sgiioc4_checkirq(ide_hwif_t * hwif) { - u8 intr_reg = - hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + IOC4_INTR_REG * 4); + unsigned long intr_addr = + hwif->io_ports[IDE_IRQ_OFFSET] + IOC4_INTR_REG * 4; - if (intr_reg & 0x03) + if ((u8)readl((void __iomem *)intr_addr) & 0x03) return 1; return 0; } +static u8 sgiioc4_INB(unsigned long); static int sgiioc4_clearirq(ide_drive_t * drive) @@ -138,21 +138,21 @@ sgiioc4_clearirq(ide_drive_t * drive) hwif->io_ports[IDE_IRQ_OFFSET] + (IOC4_INTR_REG << 2); /* Code to check for PCI error conditions */ - intr_reg = hwif->INL(other_ir); + intr_reg = readl((void __iomem *)other_ir); if (intr_reg & 0x03) { /* Valid IOC4-IDE interrupt */ /* - * Using hwif->INB to read the IDE_STATUS_REG has a side effect + * Using sgiioc4_INB to read the IDE_STATUS_REG has a side effect * of clearing the interrupt. The first read should clear it * if it is set. The second read should return a "clear" status * if it got cleared. If not, then spin for a bit trying to * clear it. */ - u8 stat = hwif->INB(IDE_STATUS_REG); + u8 stat = sgiioc4_INB(IDE_STATUS_REG); int count = 0; - stat = hwif->INB(IDE_STATUS_REG); + stat = sgiioc4_INB(IDE_STATUS_REG); while ((stat & 0x80) && (count++ < 100)) { udelay(1); - stat = hwif->INB(IDE_STATUS_REG); + stat = sgiioc4_INB(IDE_STATUS_REG); } if (intr_reg & 0x02) { @@ -161,9 +161,9 @@ sgiioc4_clearirq(ide_drive_t * drive) pci_stat_cmd_reg; pci_err_addr_low = - hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET]); + readl((void __iomem *)hwif->io_ports[IDE_IRQ_OFFSET]); pci_err_addr_high = - hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + 4); + readl((void __iomem *)(hwif->io_ports[IDE_IRQ_OFFSET] + 4)); pci_read_config_dword(hwif->pci_dev, PCI_COMMAND, &pci_stat_cmd_reg); printk(KERN_ERR @@ -180,9 +180,9 @@ sgiioc4_clearirq(ide_drive_t * drive) } /* Clear the Interrupt, Error bits on the IOC4 */ - hwif->OUTL(0x03, other_ir); + writel(0x03, (void __iomem *)other_ir); - intr_reg = hwif->INL(other_ir); + intr_reg = readl((void __iomem *)other_ir); } return intr_reg & 3; @@ -191,23 +191,25 @@ sgiioc4_clearirq(ide_drive_t * drive) static void sgiioc4_ide_dma_start(ide_drive_t * drive) { ide_hwif_t *hwif = HWIF(drive); - unsigned int reg = hwif->INL(hwif->dma_base + IOC4_DMA_CTRL * 4); + unsigned long ioc4_dma_addr = hwif->dma_base + IOC4_DMA_CTRL * 4; + unsigned int reg = readl((void __iomem *)ioc4_dma_addr); unsigned int temp_reg = reg | IOC4_S_DMA_START; - hwif->OUTL(temp_reg, hwif->dma_base + IOC4_DMA_CTRL * 4); + writel(temp_reg, (void __iomem *)ioc4_dma_addr); } static u32 sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base) { + unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4; u32 ioc4_dma; int count; count = 0; - ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4); + ioc4_dma = readl((void __iomem *)ioc4_dma_addr); while ((ioc4_dma & IOC4_S_DMA_STOP) && (count++ < 200)) { udelay(1); - ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4); + ioc4_dma = readl((void __iomem *)ioc4_dma_addr); } return ioc4_dma; } @@ -218,11 +220,11 @@ sgiioc4_ide_dma_end(ide_drive_t * drive) { u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0; ide_hwif_t *hwif = HWIF(drive); - u64 dma_base = hwif->dma_base; + unsigned long dma_base = hwif->dma_base; int dma_stat = 0; unsigned long *ending_dma = ide_get_hwifdata(hwif); - hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4); + writel(IOC4_S_DMA_STOP, (void __iomem *)(dma_base + IOC4_DMA_CTRL * 4)); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); @@ -254,8 +256,8 @@ sgiioc4_ide_dma_end(ide_drive_t * drive) dma_stat = 1; } - bc_dev = hwif->INL(dma_base + IOC4_BC_DEV * 4); - bc_mem = hwif->INL(dma_base + IOC4_BC_MEM * 4); + bc_dev = readl((void __iomem *)(dma_base + IOC4_BC_DEV * 4)); + bc_mem = readl((void __iomem *)(dma_base + IOC4_BC_MEM * 4)); if ((bc_dev & 0x01FF) || (bc_mem & 0x1FF)) { if (bc_dev > bc_mem + 8) { @@ -273,34 +275,29 @@ sgiioc4_ide_dma_end(ide_drive_t * drive) } static int -sgiioc4_ide_dma_check(ide_drive_t * drive) +sgiioc4_ide_dma_on(ide_drive_t * drive) { - if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) { - printk(KERN_INFO - "Couldnot set %s in Multimode-2 DMA mode | " - "Drive %s using PIO instead\n", - drive->name, drive->name); - drive->using_dma = 0; - } else - drive->using_dma = 1; + drive->using_dma = 1; return 0; } -static int -sgiioc4_ide_dma_on(ide_drive_t * drive) +static void sgiioc4_dma_off_quietly(ide_drive_t *drive) { - drive->using_dma = 1; + drive->using_dma = 0; - return HWIF(drive)->ide_dma_host_on(drive); + drive->hwif->dma_host_off(drive); } -static int -sgiioc4_ide_dma_off_quietly(ide_drive_t * drive) +static int sgiioc4_ide_dma_check(ide_drive_t *drive) { - drive->using_dma = 0; - - return HWIF(drive)->ide_dma_host_off(drive); + /* FIXME: check for available DMA modes */ + if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) { + printk(KERN_WARNING "%s: couldn't set MWDMA2 mode, " + "using PIO instead\n", drive->name); + return -1; + } else + return 0; } /* returns 1 if dma irq issued, 0 otherwise */ @@ -310,21 +307,13 @@ sgiioc4_ide_dma_test_irq(ide_drive_t * drive) return sgiioc4_checkirq(HWIF(drive)); } -static int -sgiioc4_ide_dma_host_on(ide_drive_t * drive) +static void sgiioc4_dma_host_on(ide_drive_t * drive) { - if (drive->using_dma) - return 0; - - return 1; } -static int -sgiioc4_ide_dma_host_off(ide_drive_t * drive) +static void sgiioc4_dma_host_off(ide_drive_t * drive) { sgiioc4_clearirq(drive); - - return 0; } static int @@ -436,16 +425,17 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) { u32 ioc4_dma; ide_hwif_t *hwif = HWIF(drive); - u64 dma_base = hwif->dma_base; + unsigned long dma_base = hwif->dma_base; + unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4; u32 dma_addr, ending_dma_addr; - ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4); + ioc4_dma = readl((void __iomem *)ioc4_dma_addr); if (ioc4_dma & IOC4_S_DMA_ACTIVE) { printk(KERN_WARNING "%s(%s):Warning!! DMA from previous transfer was still active\n", __FUNCTION__, drive->name); - hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4); + writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); if (ioc4_dma & IOC4_S_DMA_STOP) @@ -454,13 +444,13 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) __FUNCTION__, drive->name); } - ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4); + ioc4_dma = readl((void __iomem *)ioc4_dma_addr); if (ioc4_dma & IOC4_S_DMA_ERROR) { printk(KERN_WARNING "%s(%s) : Warning!! - DMA Error during Previous" " transfer | status 0x%x\n", __FUNCTION__, drive->name, ioc4_dma); - hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4); + writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); if (ioc4_dma & IOC4_S_DMA_STOP) @@ -471,14 +461,14 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) /* Address of the Scatter Gather List */ dma_addr = cpu_to_le32(hwif->dmatable_dma); - hwif->OUTL(dma_addr, dma_base + IOC4_DMA_PTR_L * 4); + writel(dma_addr, (void __iomem *)(dma_base + IOC4_DMA_PTR_L * 4)); /* Address of the Ending DMA */ memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE); ending_dma_addr = cpu_to_le32(hwif->dma_status); - hwif->OUTL(ending_dma_addr, dma_base + IOC4_DMA_END_ADDR * 4); + writel(ending_dma_addr, (void __iomem *)(dma_base + IOC4_DMA_END_ADDR * 4)); - hwif->OUTL(dma_direction, dma_base + IOC4_DMA_CTRL * 4); + writel(dma_direction, (void __iomem *)ioc4_dma_addr); drive->waiting_for_dma = 1; } @@ -590,7 +580,7 @@ static int sgiioc4_ide_dma_setup(ide_drive_t *drive) static void __devinit ide_init_sgiioc4(ide_hwif_t * hwif) { - hwif->mmio = 2; + hwif->mmio = 1; hwif->autodma = 1; hwif->atapi_dma = 1; hwif->ultra_mask = 0x0; /* Disable Ultra DMA */ @@ -613,10 +603,10 @@ ide_init_sgiioc4(ide_hwif_t * hwif) hwif->ide_dma_end = &sgiioc4_ide_dma_end; hwif->ide_dma_check = &sgiioc4_ide_dma_check; hwif->ide_dma_on = &sgiioc4_ide_dma_on; - hwif->ide_dma_off_quietly = &sgiioc4_ide_dma_off_quietly; + hwif->dma_off_quietly = &sgiioc4_dma_off_quietly; hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq; - hwif->ide_dma_host_on = &sgiioc4_ide_dma_host_on; - hwif->ide_dma_host_off = &sgiioc4_ide_dma_host_off; + hwif->dma_host_on = &sgiioc4_dma_host_on; + hwif->dma_host_off = &sgiioc4_dma_host_off; hwif->ide_dma_lostirq = &sgiioc4_ide_dma_lostirq; hwif->ide_dma_timeout = &__ide_dma_timeout; @@ -688,7 +678,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) default_hwif_mmiops(hwif); /* Initializing chipset IRQ Registers */ - hwif->OUTL(0x03, irqport + IOC4_INTR_SET * 4); + writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4)); ide_init_sgiioc4(hwif); @@ -729,8 +719,7 @@ out: return ret; } -static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = { - { +static ide_pci_device_t sgiioc4_chipset __devinitdata = { /* Channel 0 */ .name = "SGIIOC4", .init_hwif = ide_init_sgiioc4, @@ -739,7 +728,6 @@ static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = { .autodma = AUTODMA, /* SGI IOC4 doesn't have enablebits. */ .bootable = ON_BOARD, - } }; int @@ -751,8 +739,7 @@ ioc4_ide_attach_one(struct ioc4_driver_data *idd) if (idd->idd_variant == IOC4_VARIANT_PCI_RT) return 0; - return pci_init_sgiioc4(idd->idd_pdev, - &sgiioc4_chipsets[idd->idd_pci_id->driver_data]); + return pci_init_sgiioc4(idd->idd_pdev, &sgiioc4_chipset); } static struct ioc4_submodule ioc4_ide_submodule = { diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 4ff89c7d990..7b4c189a9d9 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -1,8 +1,9 @@ /* - * linux/drivers/ide/pci/siimage.c Version 1.07 Nov 30, 2003 + * linux/drivers/ide/pci/siimage.c Version 1.11 Jan 27, 2007 * * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2003 Red Hat <alan@redhat.com> + * Copyright (C) 2007 MontaVista Software, Inc. * * May be copied or modified under the terms of the GNU General Public License * @@ -205,41 +206,39 @@ static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted) unsigned long tfaddr = siimage_selreg(hwif, 0x02); /* cheat for now and use the docs */ - switch(mode_wanted) { - case 4: - speedp = 0x10c1; - speedt = 0x10c1; - break; - case 3: - speedp = 0x10C3; - speedt = 0x10C3; - break; - case 2: - speedp = 0x1104; - speedt = 0x1281; - break; - case 1: - speedp = 0x2283; - speedt = 0x1281; - break; - case 0: - default: - speedp = 0x328A; - speedt = 0x328A; - break; + switch (mode_wanted) { + case 4: + speedp = 0x10c1; + speedt = 0x10c1; + break; + case 3: + speedp = 0x10c3; + speedt = 0x10c3; + break; + case 2: + speedp = 0x1104; + speedt = 0x1281; + break; + case 1: + speedp = 0x2283; + speedt = 0x2283; + break; + case 0: + default: + speedp = 0x328a; + speedt = 0x328a; + break; } - if (hwif->mmio) - { - hwif->OUTW(speedt, addr); - hwif->OUTW(speedp, tfaddr); + + if (hwif->mmio) { + hwif->OUTW(speedp, addr); + hwif->OUTW(speedt, tfaddr); /* Now set up IORDY */ if(mode_wanted == 3 || mode_wanted == 4) hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2); else hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2); - } - else - { + } else { pci_write_config_word(hwif->pci_dev, addr, speedp); pci_write_config_word(hwif->pci_dev, tfaddr, speedt); pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp); @@ -397,12 +396,9 @@ static int config_chipset_for_dma (ide_drive_t *drive) if (!speed) return 0; - if (ide_set_xfer_rate(drive, speed)) + if (siimage_tune_chipset(drive, speed)) return 0; - if (!drive->init_speed) - drive->init_speed = speed; - return ide_dma_enable(drive); } @@ -418,25 +414,13 @@ static int config_chipset_for_dma (ide_drive_t *drive) static int siimage_config_drive_for_dma (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id->capability & 1) != 0 && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) config_chipset_for_pio(drive, 1); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + + return -1; } /* returns 1 if dma irq issued, 0 otherwise */ @@ -472,11 +456,11 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive) unsigned long addr = siimage_selreg(hwif, 0x1); if (SATA_ERROR_REG) { - u32 ext_stat = hwif->INL(base + 0x10); + u32 ext_stat = readl((void __iomem *)(base + 0x10)); u8 watchdog = 0; if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) { - u32 sata_error = hwif->INL(SATA_ERROR_REG); - hwif->OUTL(sata_error, SATA_ERROR_REG); + u32 sata_error = readl((void __iomem *)SATA_ERROR_REG); + writel(sata_error, (void __iomem *)SATA_ERROR_REG); watchdog = (sata_error & 0x00680000) ? 1 : 0; printk(KERN_WARNING "%s: sata_error = 0x%08x, " "watchdog = %d, %s\n", @@ -493,11 +477,11 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive) } /* return 1 if INTR asserted */ - if ((hwif->INB(hwif->dma_status) & 0x04) == 0x04) + if ((readb((void __iomem *)hwif->dma_status) & 0x04) == 0x04) return 1; /* return 1 if Device INTR asserted */ - if ((hwif->INB(addr) & 8) == 8) + if ((readb((void __iomem *)addr) & 8) == 8) return 0; //return 1; return 0; @@ -519,9 +503,9 @@ static int siimage_busproc (ide_drive_t * drive, int state) u32 stat_config = 0; unsigned long addr = siimage_selreg(hwif, 0); - if (hwif->mmio) { - stat_config = hwif->INL(addr); - } else + if (hwif->mmio) + stat_config = readl((void __iomem *)addr); + else pci_read_config_dword(hwif->pci_dev, addr, &stat_config); switch (state) { @@ -557,9 +541,10 @@ static int siimage_reset_poll (ide_drive_t *drive) if (SATA_STATUS_REG) { ide_hwif_t *hwif = HWIF(drive); - if ((hwif->INL(SATA_STATUS_REG) & 0x03) != 0x03) { + /* SATA_STATUS_REG is valid only when in MMIO mode */ + if ((readl((void __iomem *)SATA_STATUS_REG) & 0x03) != 0x03) { printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n", - hwif->name, hwif->INL(SATA_STATUS_REG)); + hwif->name, readl((void __iomem *)SATA_STATUS_REG)); HWGROUP(drive)->polling = 0; return ide_started; } @@ -619,7 +604,8 @@ static void siimage_reset (ide_drive_t *drive) } if (SATA_STATUS_REG) { - u32 sata_stat = hwif->INL(SATA_STATUS_REG); + /* SATA_STATUS_REG is valid only when in MMIO mode */ + u32 sata_stat = readl((void __iomem *)SATA_STATUS_REG); printk(KERN_WARNING "%s: reset phy, status=0x%08x, %s\n", hwif->name, sata_stat, __FUNCTION__); if (!(sata_stat)) { @@ -898,7 +884,8 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif) base = (unsigned long) addr; hwif->dma_base = base + (ch ? 0x08 : 0x00); - hwif->mmio = 2; + + hwif->mmio = 1; } static int is_dev_seagate_sata(ide_drive_t *drive) diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 1afff659ab5..2ba0669f36a 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -667,67 +667,20 @@ static int config_chipset_for_dma (ide_drive_t *drive) return ide_dma_enable(drive); } -static int sis5513_config_drive_xfer_rate (ide_drive_t *drive) +static int sis5513_config_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; + config_art_rwp_pio(drive, 5); drive->init_speed = 0; - if (id && (id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) sis5513_tune_drive(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -/* initiates/aborts (U)DMA read/write operations on a drive. */ -static int sis5513_config_xfer_rate (ide_drive_t *drive) -{ - config_drive_art_rwp(drive); - config_art_rwp_pio(drive, 5); - return sis5513_config_drive_xfer_rate(drive); -} - -/* - Future simpler config_xfer_rate : - When ide_find_best_mode is made bad-drive aware - - remove config_drive_xfer_rate and config_chipset_for_dma, - - replace config_xfer_rate with the following - -static int sis5513_config_xfer_rate (ide_drive_t *drive) -{ - u16 w80 = HWIF(drive)->udma_four; - u16 speed; - - config_drive_art_rwp(drive); - config_art_rwp_pio(drive, 5); - - speed = ide_find_best_mode(drive, - XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA | - (chipset_family >= ATA_33 ? XFER_UDMA : 0) | - (w80 && chipset_family >= ATA_66 ? XFER_UDMA_66 : 0) | - (w80 && chipset_family >= ATA_100a ? XFER_UDMA_100 : 0) | - (w80 && chipset_family >= ATA_133a ? XFER_UDMA_133 : 0)); - - sis5513_tune_chipset(drive, speed); - if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) - return HWIF(drive)->ide_dma_on(drive); - return HWIF(drive)->ide_dma_off_quietly(drive); + return -1; } -*/ /* Chip detection and general config */ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const char *name) diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index 170a2619905..3a8a76fc78c 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -161,14 +161,14 @@ static int sl82c105_check_drive (ide_drive_t *drive) if (id->field_valid & 2) { if ((id->dma_mword & hwif->mwdma_mask) || (id->dma_1word & hwif->swdma_mask)) - return hwif->ide_dma_on(drive); + return 0; } - if (__ide_dma_good_drive(drive)) - return hwif->ide_dma_on(drive); + if (__ide_dma_good_drive(drive) && id->eide_dma_time < 150) + return 0; } while (0); - return hwif->ide_dma_off_quietly(drive); + return -1; } /* @@ -215,7 +215,7 @@ static int sl82c105_ide_dma_lost_irq(ide_drive_t *drive) * Was DMA enabled? If so, disable it - we're resetting the * host. The IDE layer will be handling the drive for us. */ - val = hwif->INB(dma_base); + val = inb(dma_base); if (val & 1) { outb(val & ~1, dma_base); printk("sl82c105: DMA was enabled\n"); @@ -259,28 +259,22 @@ static int sl82c105_ide_dma_on (ide_drive_t *drive) { DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name)); - if (config_for_dma(drive)) { - config_for_pio(drive, 4, 0, 0); - return HWIF(drive)->ide_dma_off_quietly(drive); - } + if (config_for_dma(drive)) + return 1; printk(KERN_INFO "%s: DMA enabled\n", drive->name); return __ide_dma_on(drive); } -static int sl82c105_ide_dma_off_quietly (ide_drive_t *drive) +static void sl82c105_dma_off_quietly(ide_drive_t *drive) { u8 speed = XFER_PIO_0; - int rc; - - DBG(("sl82c105_ide_dma_off_quietly(drive:%s)\n", drive->name)); - rc = __ide_dma_off_quietly(drive); + DBG(("sl82c105_dma_off_quietly(drive:%s)\n", drive->name)); + + ide_dma_off_quietly(drive); if (drive->pio_speed) speed = drive->pio_speed - XFER_PIO_0; config_for_pio(drive, speed, 0, 1); - drive->current_speed = drive->pio_speed; - - return rc; } /* @@ -401,11 +395,9 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c /* * Initialise the chip */ - static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) { unsigned int rev; - u8 dma_state; DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index)); @@ -431,7 +423,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) if (!hwif->dma_base) return; - dma_state = hwif->INB(hwif->dma_base + 2) & ~0x60; rev = sl82c105_bridge_revision(hwif->pci_dev); if (rev <= 5) { /* @@ -441,15 +432,12 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n", hwif->name, rev); } else { - dma_state |= 0x60; - hwif->atapi_dma = 1; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; + hwif->mwdma_mask = 0x04; hwif->ide_dma_check = &sl82c105_check_drive; hwif->ide_dma_on = &sl82c105_ide_dma_on; - hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly; + hwif->dma_off_quietly = &sl82c105_dma_off_quietly; hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq; hwif->dma_start = &sl82c105_ide_dma_start; hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout; @@ -462,7 +450,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) if (hwif->mate) hwif->serialized = hwif->mate->serialized = 1; } - hwif->OUTB(dma_state, hwif->dma_base + 2); } static ide_pci_device_t sl82c105_chipset __devinitdata = { diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 2663ddbd9b6..ae7eb58d961 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -179,26 +179,16 @@ static int slc90e66_config_drive_for_dma (ide_drive_t *drive) static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); + if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive)) + return 0; - goto fast_ata_pio; + if (ide_use_fast_pio(drive)) + (void)slc90e66_tune_chipset(drive, XFER_PIO_0 + + ide_get_best_pio_mode(drive, 255, 4, NULL)); - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - (void) hwif->speedproc(drive, XFER_PIO_0 + - ide_get_best_pio_mode(drive, 255, 4, NULL)); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + return -1; } static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif) diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c index 2ad72bbda34..0b6d81d6ce4 100644 --- a/drivers/ide/pci/tc86c001.c +++ b/drivers/ide/pci/tc86c001.c @@ -45,7 +45,7 @@ static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed) scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f; scr |= mode; - hwif->OUTW(scr, scr_port); + outw(scr, scr_port); return ide_config_drive_speed(drive, speed); } @@ -89,15 +89,15 @@ static int tc86c001_timer_expiry(ide_drive_t *drive) "attempting recovery...\n", drive->name); /* Stop DMA */ - hwif->OUTB(dma_cmd & ~0x01, hwif->dma_command); + outb(dma_cmd & ~0x01, hwif->dma_command); /* Setup the dummy DMA transfer */ - hwif->OUTW(0, sc_base + 0x0a); /* Sector Count */ - hwif->OUTW(0, twcr_port); /* Transfer Word Count 1 or 2 */ + outw(0, sc_base + 0x0a); /* Sector Count */ + outw(0, twcr_port); /* Transfer Word Count 1 or 2 */ /* Start the dummy DMA transfer */ - hwif->OUTB(0x00, hwif->dma_command); /* clear R_OR_WCTR for write */ - hwif->OUTB(0x01, hwif->dma_command); /* set START_STOPBM */ + outb(0x00, hwif->dma_command); /* clear R_OR_WCTR for write */ + outb(0x01, hwif->dma_command); /* set START_STOPBM */ /* * If an interrupt was pending, it should come thru shortly. @@ -128,8 +128,8 @@ static void tc86c001_dma_start(ide_drive_t *drive) * the appropriate system control registers for DMA to work * with LBA48 and ATAPI devices... */ - hwif->OUTW(nsectors, sc_base + 0x0a); /* Sector Count */ - hwif->OUTW(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */ + outw(nsectors, sc_base + 0x0a); /* Sector Count */ + outw(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */ /* Install our timeout expiry hook, saving the current handler... */ ide_set_hwifdata(hwif, hwgroup->expiry); @@ -168,7 +168,7 @@ static int tc86c001_busproc(ide_drive_t *drive, int state) } /* System Control 1 Register bit 11 (ATA Hard Reset) write */ - hwif->OUTW(scr1, sc_base + 0x00); + outw(scr1, sc_base + 0x00); return 0; } @@ -185,23 +185,13 @@ static int config_chipset_for_dma(ide_drive_t *drive) static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive) && config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) tc86c001_tune_drive(drive, 255); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + + return -1; } static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif) @@ -210,13 +200,13 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif) u16 scr1 = hwif->INW(sc_base + 0x00);; /* System Control 1 Register bit 15 (Soft Reset) set */ - hwif->OUTW(scr1 | 0x8000, sc_base + 0x00); + outw(scr1 | 0x8000, sc_base + 0x00); /* System Control 1 Register bit 14 (FIFO Reset) set */ - hwif->OUTW(scr1 | 0x4000, sc_base + 0x00); + outw(scr1 | 0x4000, sc_base + 0x00); /* System Control 1 Register: reset clear */ - hwif->OUTW(scr1 & ~0xc000, sc_base + 0x00); + outw(scr1 & ~0xc000, sc_base + 0x00); /* Store the system control register base for convenience... */ hwif->config_data = sc_base; @@ -234,7 +224,7 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif) * Sector Count Control Register bits 0 and 1 set: * software sets Sector Count Register for master and slave device */ - hwif->OUTW(0x0003, sc_base + 0x0c); + outw(0x0003, sc_base + 0x0c); /* Sector Count Register limit */ hwif->rqsize = 0xffff; diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c index b13cce1fd1a..5e06179c346 100644 --- a/drivers/ide/pci/triflex.c +++ b/drivers/ide/pci/triflex.c @@ -104,29 +104,21 @@ static int triflex_config_drive_for_dma(ide_drive_t *drive) { int speed = ide_dma_speed(drive, 0); /* No ultra speeds */ - if (!speed) { - u8 pspeed = ide_get_best_pio_mode(drive, 255, 4, NULL); - speed = XFER_PIO_0 + pspeed; - } - + if (!speed) + return 0; + (void) triflex_tune_chipset(drive, speed); return ide_dma_enable(drive); } static int triflex_config_drive_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id->capability & 1) && drive->autodma) { - if (ide_use_dma(drive)) { - if (triflex_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - } + if (ide_use_dma(drive) && triflex_config_drive_for_dma(drive)) + return 0; + + triflex_tune_drive(drive, 255); - hwif->tuneproc(drive, 255); - return hwif->ide_dma_off_quietly(drive); + return -1; } static void __devinit init_hwif_triflex(ide_hwif_t *hwif) diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c index 174b88c4780..cbb1b11119a 100644 --- a/drivers/ide/pci/trm290.c +++ b/drivers/ide/pci/trm290.c @@ -157,16 +157,16 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) if (reg != hwif->select_data) { hwif->select_data = reg; /* set PIO/DMA */ - hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1); - hwif->OUTW(reg & 0xff, hwif->config_data); + outb(0x51 | (hwif->channel << 3), hwif->config_data + 1); + outw(reg & 0xff, hwif->config_data); } /* enable IRQ if not probing */ if (drive->present) { - reg = hwif->INW(hwif->config_data + 3); + reg = inw(hwif->config_data + 3); reg &= 0x13; reg &= ~(1 << hwif->channel); - hwif->OUTW(reg, hwif->config_data+3); + outw(reg, hwif->config_data + 3); } local_irq_restore(flags); @@ -177,15 +177,12 @@ static void trm290_selectproc (ide_drive_t *drive) trm290_prepare_drive(drive, drive->using_dma); } -#ifdef CONFIG_BLK_DEV_IDEDMA static void trm290_ide_dma_exec_cmd(ide_drive_t *drive, u8 command) { - ide_hwif_t *hwif = HWIF(drive); - BUG_ON(HWGROUP(drive)->handler != NULL); /* paranoia check */ ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */ - hwif->OUTB(command, IDE_COMMAND_REG); + outb(command, IDE_COMMAND_REG); } static int trm290_ide_dma_setup(ide_drive_t *drive) @@ -211,10 +208,10 @@ static int trm290_ide_dma_setup(ide_drive_t *drive) } /* select DMA xfer */ trm290_prepare_drive(drive, 1); - hwif->OUTL(hwif->dmatable_dma|rw, hwif->dma_command); + outl(hwif->dmatable_dma | rw, hwif->dma_command); drive->waiting_for_dma = 1; /* start DMA */ - hwif->OUTW((count * 2) - 1, hwif->dma_status); + outw((count * 2) - 1, hwif->dma_status); return 0; } @@ -230,7 +227,7 @@ static int trm290_ide_dma_end (ide_drive_t *drive) drive->waiting_for_dma = 0; /* purge DMA mappings */ ide_destroy_dmatable(drive); - status = hwif->INW(hwif->dma_status); + status = inw(hwif->dma_status); return (status != 0x00ff); } @@ -239,10 +236,9 @@ static int trm290_ide_dma_test_irq (ide_drive_t *drive) ide_hwif_t *hwif = HWIF(drive); u16 status = 0; - status = hwif->INW(hwif->dma_status); + status = inw(hwif->dma_status); return (status == 0x00ff); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * Invoked from ide-dma.c at boot time. @@ -269,15 +265,15 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif) local_irq_save(flags); /* put config reg into first byte of hwif->select_data */ - hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1); + outb(0x51 | (hwif->channel << 3), hwif->config_data + 1); /* select PIO as default */ hwif->select_data = 0x21; - hwif->OUTB(hwif->select_data, hwif->config_data); + outb(hwif->select_data, hwif->config_data); /* get IRQ info */ - reg = hwif->INB(hwif->config_data+3); + reg = inb(hwif->config_data + 3); /* mask IRQs for both ports */ reg = (reg & 0x10) | 0x03; - hwif->OUTB(reg, hwif->config_data+3); + outb(reg, hwif->config_data + 3); local_irq_restore(flags); if ((reg & 0x10)) @@ -289,13 +285,11 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif) ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3); -#ifdef CONFIG_BLK_DEV_IDEDMA hwif->dma_setup = &trm290_ide_dma_setup; hwif->dma_exec_cmd = &trm290_ide_dma_exec_cmd; hwif->dma_start = &trm290_ide_dma_start; hwif->ide_dma_end = &trm290_ide_dma_end; hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq; -#endif /* CONFIG_BLK_DEV_IDEDMA */ hwif->selectproc = &trm290_selectproc; hwif->autodma = 0; /* play it safe for now */ @@ -312,16 +306,16 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif) static u16 next_offset = 0; u8 old_mask; - hwif->OUTB(0x54|(hwif->channel<<3), hwif->config_data+1); - old = hwif->INW(hwif->config_data); + outb(0x54 | (hwif->channel << 3), hwif->config_data + 1); + old = inw(hwif->config_data); old &= ~1; - old_mask = hwif->INB(old+2); + old_mask = inb(old + 2); if (old != compat && old_mask == 0xff) { /* leave lower 10 bits untouched */ compat += (next_offset += 0x400); hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2; - hwif->OUTW(compat|1, hwif->config_data); - new = hwif->INW(hwif->config_data); + outw(compat | 1, hwif->config_data); + new = inw(hwif->config_data); printk(KERN_INFO "%s: control basereg workaround: " "old=0x%04x, new=0x%04x\n", hwif->name, old, new & ~1); diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index 6fb6e50b823..a508550c409 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -240,8 +240,9 @@ static int via82cxxx_ide_dma_check (ide_drive_t *drive) via_set_drive(drive, speed); if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) - return hwif->ide_dma_on(drive); - return hwif->ide_dma_off_quietly(drive); + return 0; + + return -1; } static struct via_isa_bridge *via_config_find(struct pci_dev **isa) diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index d8ea23710bf..395d35253d5 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1237,7 +1237,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) hwif->OUTBSYNC = pmac_outbsync; /* Tell common code _not_ to mess with resources */ - hwif->mmio = 2; + hwif->mmio = 1; hwif->hwif_data = pmif; pmac_ide_init_hwif_ports(&hwif->hw, pmif->regbase, 0, &hwif->irq); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); @@ -1979,16 +1979,12 @@ pmac_ide_dma_test_irq (ide_drive_t *drive) return 1; } -static int -pmac_ide_dma_host_off (ide_drive_t *drive) +static void pmac_ide_dma_host_off(ide_drive_t *drive) { - return 0; } -static int -pmac_ide_dma_host_on (ide_drive_t *drive) +static int pmac_ide_dma_host_on(ide_drive_t *drive) { - return 0; } static int @@ -2034,7 +2030,7 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) return; } - hwif->ide_dma_off_quietly = &__ide_dma_off_quietly; + hwif->dma_off_quietly = &ide_dma_off_quietly; hwif->ide_dma_on = &__ide_dma_on; hwif->ide_dma_check = &pmac_ide_dma_check; hwif->dma_setup = &pmac_ide_dma_setup; @@ -2042,8 +2038,8 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) hwif->dma_start = &pmac_ide_dma_start; hwif->ide_dma_end = &pmac_ide_dma_end; hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq; - hwif->ide_dma_host_off = &pmac_ide_dma_host_off; - hwif->ide_dma_host_on = &pmac_ide_dma_host_on; + hwif->dma_host_off = &pmac_ide_dma_host_off; + hwif->dma_host_on = &pmac_ide_dma_host_on; hwif->ide_dma_timeout = &__ide_dma_timeout; hwif->ide_dma_lostirq = &pmac_ide_dma_lostirq; diff --git a/drivers/ide/ppc/scc_pata.c b/drivers/ide/ppc/scc_pata.c new file mode 100644 index 00000000000..de64b022478 --- /dev/null +++ b/drivers/ide/ppc/scc_pata.c @@ -0,0 +1,831 @@ +/* + * Support for IDE interfaces on Celleb platform + * + * (C) Copyright 2006 TOSHIBA CORPORATION + * + * This code is based on drivers/ide/pci/siimage.c: + * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2003 Red Hat <alan@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/hdreg.h> +#include <linux/ide.h> +#include <linux/init.h> + +#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4 + +#define SCC_PATA_NAME "scc IDE" + +#define TDVHSEL_MASTER 0x00000001 +#define TDVHSEL_SLAVE 0x00000004 + +#define MODE_JCUSFEN 0x00000080 + +#define CCKCTRL_ATARESET 0x00040000 +#define CCKCTRL_BUFCNT 0x00020000 +#define CCKCTRL_CRST 0x00010000 +#define CCKCTRL_OCLKEN 0x00000100 +#define CCKCTRL_ATACLKOEN 0x00000002 +#define CCKCTRL_LCLKEN 0x00000001 + +#define QCHCD_IOS_SS 0x00000001 + +#define QCHSD_STPDIAG 0x00020000 + +#define INTMASK_MSK 0xD1000012 +#define INTSTS_SERROR 0x80000000 +#define INTSTS_PRERR 0x40000000 +#define INTSTS_RERR 0x10000000 +#define INTSTS_ICERR 0x01000000 +#define INTSTS_BMSINT 0x00000010 +#define INTSTS_BMHE 0x00000008 +#define INTSTS_IOIRQS 0x00000004 +#define INTSTS_INTRQ 0x00000002 +#define INTSTS_ACTEINT 0x00000001 + +#define ECMODE_VALUE 0x01 + +static struct scc_ports { + unsigned long ctl, dma; + unsigned char hwif_id; /* for removing hwif from system */ +} scc_ports[MAX_HWIFS]; + +/* PIO transfer mode table */ +/* JCHST */ +static unsigned long JCHSTtbl[2][7] = { + {0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00}, /* 100MHz */ + {0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00} /* 133MHz */ +}; + +/* JCHHT */ +static unsigned long JCHHTtbl[2][7] = { + {0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00}, /* 100MHz */ + {0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00} /* 133MHz */ +}; + +/* JCHCT */ +static unsigned long JCHCTtbl[2][7] = { + {0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00}, /* 100MHz */ + {0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00} /* 133MHz */ +}; + + +/* DMA transfer mode table */ +/* JCHDCTM/JCHDCTS */ +static unsigned long JCHDCTxtbl[2][7] = { + {0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00}, /* 100MHz */ + {0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00} /* 133MHz */ +}; + +/* JCSTWTM/JCSTWTS */ +static unsigned long JCSTWTxtbl[2][7] = { + {0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00}, /* 100MHz */ + {0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02} /* 133MHz */ +}; + +/* JCTSS */ +static unsigned long JCTSStbl[2][7] = { + {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00}, /* 100MHz */ + {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05} /* 133MHz */ +}; + +/* JCENVT */ +static unsigned long JCENVTtbl[2][7] = { + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00}, /* 100MHz */ + {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02} /* 133MHz */ +}; + +/* JCACTSELS/JCACTSELM */ +static unsigned long JCACTSELtbl[2][7] = { + {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00}, /* 100MHz */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} /* 133MHz */ +}; + + +static u8 scc_ide_inb(unsigned long port) +{ + u32 data = in_be32((void*)port); + return (u8)data; +} + +static u16 scc_ide_inw(unsigned long port) +{ + u32 data = in_be32((void*)port); + return (u16)data; +} + +static void scc_ide_insw(unsigned long port, void *addr, u32 count) +{ + u16 *ptr = (u16 *)addr; + while (count--) { + *ptr++ = le16_to_cpu(in_be32((void*)port)); + } +} + +static void scc_ide_insl(unsigned long port, void *addr, u32 count) +{ + u16 *ptr = (u16 *)addr; + while (count--) { + *ptr++ = le16_to_cpu(in_be32((void*)port)); + *ptr++ = le16_to_cpu(in_be32((void*)port)); + } +} + +static void scc_ide_outb(u8 addr, unsigned long port) +{ + out_be32((void*)port, addr); +} + +static void scc_ide_outw(u16 addr, unsigned long port) +{ + out_be32((void*)port, addr); +} + +static void +scc_ide_outbsync(ide_drive_t * drive, u8 addr, unsigned long port) +{ + ide_hwif_t *hwif = HWIF(drive); + + out_be32((void*)port, addr); + __asm__ __volatile__("eieio":::"memory"); + in_be32((void*)(hwif->dma_base + 0x01c)); + __asm__ __volatile__("eieio":::"memory"); +} + +static void +scc_ide_outsw(unsigned long port, void *addr, u32 count) +{ + u16 *ptr = (u16 *)addr; + while (count--) { + out_be32((void*)port, cpu_to_le16(*ptr++)); + } +} + +static void +scc_ide_outsl(unsigned long port, void *addr, u32 count) +{ + u16 *ptr = (u16 *)addr; + while (count--) { + out_be32((void*)port, cpu_to_le16(*ptr++)); + out_be32((void*)port, cpu_to_le16(*ptr++)); + } +} + +/** + * scc_ratemask - Compute available modes + * @drive: IDE drive + * + * Compute the available speeds for the devices on the interface. + * Enforce UDMA33 as a limit if there is no 80pin cable present. + */ + +static u8 scc_ratemask(ide_drive_t *drive) +{ + u8 mode = 4; + + if (!eighty_ninty_three(drive)) + mode = min(mode, (u8)1); + return mode; +} + +/** + * scc_tuneproc - tune a drive PIO mode + * @drive: drive to tune + * @mode_wanted: the target operating mode + * + * Load the timing settings for this device mode into the + * controller. + */ + +static void scc_tuneproc(ide_drive_t *drive, byte mode_wanted) +{ + ide_hwif_t *hwif = HWIF(drive); + struct scc_ports *ports = ide_get_hwifdata(hwif); + unsigned long ctl_base = ports->ctl; + unsigned long cckctrl_port = ctl_base + 0xff0; + unsigned long piosht_port = ctl_base + 0x000; + unsigned long pioct_port = ctl_base + 0x004; + unsigned long reg; + unsigned char speed = XFER_PIO_0; + int offset; + + mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 4, NULL); + switch (mode_wanted) { + case 4: + speed = XFER_PIO_4; + break; + case 3: + speed = XFER_PIO_3; + break; + case 2: + speed = XFER_PIO_2; + break; + case 1: + speed = XFER_PIO_1; + break; + case 0: + default: + speed = XFER_PIO_0; + break; + } + + reg = in_be32((void __iomem *)cckctrl_port); + if (reg & CCKCTRL_ATACLKOEN) { + offset = 1; /* 133MHz */ + } else { + offset = 0; /* 100MHz */ + } + reg = JCHSTtbl[offset][mode_wanted] << 16 | JCHHTtbl[offset][mode_wanted]; + out_be32((void __iomem *)piosht_port, reg); + reg = JCHCTtbl[offset][mode_wanted]; + out_be32((void __iomem *)pioct_port, reg); + + ide_config_drive_speed(drive, speed); +} + +/** + * scc_tune_chipset - tune a drive DMA mode + * @drive: Drive to set up + * @xferspeed: speed we want to achieve + * + * Load the timing settings for this device mode into the + * controller. + */ + +static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed) +{ + ide_hwif_t *hwif = HWIF(drive); + u8 speed = ide_rate_filter(scc_ratemask(drive), xferspeed); + struct scc_ports *ports = ide_get_hwifdata(hwif); + unsigned long ctl_base = ports->ctl; + unsigned long cckctrl_port = ctl_base + 0xff0; + unsigned long mdmact_port = ctl_base + 0x008; + unsigned long mcrcst_port = ctl_base + 0x00c; + unsigned long sdmact_port = ctl_base + 0x010; + unsigned long scrcst_port = ctl_base + 0x014; + unsigned long udenvt_port = ctl_base + 0x018; + unsigned long tdvhsel_port = ctl_base + 0x020; + int is_slave = (&hwif->drives[1] == drive); + int offset, idx; + unsigned long reg; + unsigned long jcactsel; + + reg = in_be32((void __iomem *)cckctrl_port); + if (reg & CCKCTRL_ATACLKOEN) { + offset = 1; /* 133MHz */ + } else { + offset = 0; /* 100MHz */ + } + + switch (speed) { + case XFER_UDMA_6: + idx = 6; + break; + case XFER_UDMA_5: + idx = 5; + break; + case XFER_UDMA_4: + idx = 4; + break; + case XFER_UDMA_3: + idx = 3; + break; + case XFER_UDMA_2: + idx = 2; + break; + case XFER_UDMA_1: + idx = 1; + break; + case XFER_UDMA_0: + idx = 0; + break; + default: + return 1; + } + + jcactsel = JCACTSELtbl[offset][idx]; + if (is_slave) { + out_be32((void __iomem *)sdmact_port, JCHDCTxtbl[offset][idx]); + out_be32((void __iomem *)scrcst_port, JCSTWTxtbl[offset][idx]); + jcactsel = jcactsel << 2; + out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_SLAVE) | jcactsel); + } else { + out_be32((void __iomem *)mdmact_port, JCHDCTxtbl[offset][idx]); + out_be32((void __iomem *)mcrcst_port, JCSTWTxtbl[offset][idx]); + out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_MASTER) | jcactsel); + } + reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]; + out_be32((void __iomem *)udenvt_port, reg); + + return ide_config_drive_speed(drive, speed); +} + +/** + * scc_config_chipset_for_dma - configure for DMA + * @drive: drive to configure + * + * Called by scc_config_drive_for_dma(). + */ + +static int scc_config_chipset_for_dma(ide_drive_t *drive) +{ + u8 speed = ide_dma_speed(drive, scc_ratemask(drive)); + + if (!speed) + return 0; + + if (scc_tune_chipset(drive, speed)) + return 0; + + return ide_dma_enable(drive); +} + +/** + * scc_configure_drive_for_dma - set up for DMA transfers + * @drive: drive we are going to set up + * + * Set up the drive for DMA, tune the controller and drive as + * required. + * If the drive isn't suitable for DMA or we hit other problems + * then we will drop down to PIO and set up PIO appropriately. + * (return 1) + */ + +static int scc_config_drive_for_dma(ide_drive_t *drive) +{ + if (ide_use_dma(drive) && scc_config_chipset_for_dma(drive)) + return 0; + + if (ide_use_fast_pio(drive)) + scc_tuneproc(drive, 4); + + return -1; +} + +/** + * scc_ide_dma_setup - begin a DMA phase + * @drive: target device + * + * Build an IDE DMA PRD (IDE speak for scatter gather table) + * and then set up the DMA transfer registers. + * + * Returns 0 on success. If a PIO fallback is required then 1 + * is returned. + */ + +static int scc_dma_setup(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct request *rq = HWGROUP(drive)->rq; + unsigned int reading; + u8 dma_stat; + + if (rq_data_dir(rq)) + reading = 0; + else + reading = 1 << 3; + + /* fall back to pio! */ + if (!ide_build_dmatable(drive, rq)) { + ide_map_sg(drive, rq); + return 1; + } + + /* PRD table */ + out_be32((void __iomem *)hwif->dma_prdtable, hwif->dmatable_dma); + + /* specify r/w */ + out_be32((void __iomem *)hwif->dma_command, reading); + + /* read dma_status for INTR & ERROR flags */ + dma_stat = in_be32((void __iomem *)hwif->dma_status); + + /* clear INTR & ERROR flags */ + out_be32((void __iomem *)hwif->dma_status, dma_stat|6); + drive->waiting_for_dma = 1; + return 0; +} + + +/** + * scc_ide_dma_end - Stop DMA + * @drive: IDE drive + * + * Check and clear INT Status register. + * Then call __ide_dma_end(). + */ + +static int scc_ide_dma_end(ide_drive_t * drive) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long intsts_port = hwif->dma_base + 0x014; + u32 reg; + + while (1) { + reg = in_be32((void __iomem *)intsts_port); + + if (reg & INTSTS_SERROR) { + printk(KERN_WARNING "%s: SERROR\n", SCC_PATA_NAME); + out_be32((void __iomem *)intsts_port, INTSTS_SERROR|INTSTS_BMSINT); + + out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS); + continue; + } + + if (reg & INTSTS_PRERR) { + u32 maea0, maec0; + unsigned long ctl_base = hwif->config_data; + + maea0 = in_be32((void __iomem *)(ctl_base + 0xF50)); + maec0 = in_be32((void __iomem *)(ctl_base + 0xF54)); + + printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", SCC_PATA_NAME, maea0, maec0); + + out_be32((void __iomem *)intsts_port, INTSTS_PRERR|INTSTS_BMSINT); + + out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS); + continue; + } + + if (reg & INTSTS_RERR) { + printk(KERN_WARNING "%s: Response Error\n", SCC_PATA_NAME); + out_be32((void __iomem *)intsts_port, INTSTS_RERR|INTSTS_BMSINT); + + out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS); + continue; + } + + if (reg & INTSTS_ICERR) { + out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS); + + printk(KERN_WARNING "%s: Illegal Configuration\n", SCC_PATA_NAME); + out_be32((void __iomem *)intsts_port, INTSTS_ICERR|INTSTS_BMSINT); + continue; + } + + if (reg & INTSTS_BMSINT) { + printk(KERN_WARNING "%s: Internal Bus Error\n", SCC_PATA_NAME); + out_be32((void __iomem *)intsts_port, INTSTS_BMSINT); + + ide_do_reset(drive); + continue; + } + + if (reg & INTSTS_BMHE) { + out_be32((void __iomem *)intsts_port, INTSTS_BMHE); + continue; + } + + if (reg & INTSTS_ACTEINT) { + out_be32((void __iomem *)intsts_port, INTSTS_ACTEINT); + continue; + } + + if (reg & INTSTS_IOIRQS) { + out_be32((void __iomem *)intsts_port, INTSTS_IOIRQS); + continue; + } + break; + } + + return __ide_dma_end(drive); +} + +/** + * setup_mmio_scc - map CTRL/BMID region + * @dev: PCI device we are configuring + * @name: device name + * + */ + +static int setup_mmio_scc (struct pci_dev *dev, const char *name) +{ + unsigned long ctl_base = pci_resource_start(dev, 0); + unsigned long dma_base = pci_resource_start(dev, 1); + unsigned long ctl_size = pci_resource_len(dev, 0); + unsigned long dma_size = pci_resource_len(dev, 1); + void *ctl_addr; + void *dma_addr; + int i; + + for (i = 0; i < MAX_HWIFS; i++) { + if (scc_ports[i].ctl == 0) + break; + } + if (i >= MAX_HWIFS) + return -ENOMEM; + + if (!request_mem_region(ctl_base, ctl_size, name)) { + printk(KERN_WARNING "%s: IDE controller MMIO ports not available.\n", SCC_PATA_NAME); + goto fail_0; + } + + if (!request_mem_region(dma_base, dma_size, name)) { + printk(KERN_WARNING "%s: IDE controller MMIO ports not available.\n", SCC_PATA_NAME); + goto fail_1; + } + + if ((ctl_addr = ioremap(ctl_base, ctl_size)) == NULL) + goto fail_2; + + if ((dma_addr = ioremap(dma_base, dma_size)) == NULL) + goto fail_3; + + pci_set_master(dev); + scc_ports[i].ctl = (unsigned long)ctl_addr; + scc_ports[i].dma = (unsigned long)dma_addr; + pci_set_drvdata(dev, (void *) &scc_ports[i]); + + return 1; + + fail_3: + iounmap(ctl_addr); + fail_2: + release_mem_region(dma_base, dma_size); + fail_1: + release_mem_region(ctl_base, ctl_size); + fail_0: + return -ENOMEM; +} + +/** + * init_setup_scc - set up an SCC PATA Controller + * @dev: PCI device + * @d: IDE PCI device + * + * Perform the initial set up for this device. + */ + +static int __devinit init_setup_scc(struct pci_dev *dev, ide_pci_device_t *d) +{ + unsigned long ctl_base; + unsigned long dma_base; + unsigned long cckctrl_port; + unsigned long intmask_port; + unsigned long mode_port; + unsigned long ecmode_port; + unsigned long dma_status_port; + u32 reg = 0; + struct scc_ports *ports; + int rc; + + rc = setup_mmio_scc(dev, d->name); + if (rc < 0) { + return rc; + } + + ports = pci_get_drvdata(dev); + ctl_base = ports->ctl; + dma_base = ports->dma; + cckctrl_port = ctl_base + 0xff0; + intmask_port = dma_base + 0x010; + mode_port = ctl_base + 0x024; + ecmode_port = ctl_base + 0xf00; + dma_status_port = dma_base + 0x004; + + /* controller initialization */ + reg = 0; + out_be32((void*)cckctrl_port, reg); + reg |= CCKCTRL_ATACLKOEN; + out_be32((void*)cckctrl_port, reg); + reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN; + out_be32((void*)cckctrl_port, reg); + reg |= CCKCTRL_CRST; + out_be32((void*)cckctrl_port, reg); + + for (;;) { + reg = in_be32((void*)cckctrl_port); + if (reg & CCKCTRL_CRST) + break; + udelay(5000); + } + + reg |= CCKCTRL_ATARESET; + out_be32((void*)cckctrl_port, reg); + + out_be32((void*)ecmode_port, ECMODE_VALUE); + out_be32((void*)mode_port, MODE_JCUSFEN); + out_be32((void*)intmask_port, INTMASK_MSK); + + return ide_setup_pci_device(dev, d); +} + +/** + * init_mmio_iops_scc - set up the iops for MMIO + * @hwif: interface to set up + * + */ + +static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif) +{ + struct pci_dev *dev = hwif->pci_dev; + struct scc_ports *ports = pci_get_drvdata(dev); + unsigned long dma_base = ports->dma; + + ide_set_hwifdata(hwif, ports); + + hwif->INB = scc_ide_inb; + hwif->INW = scc_ide_inw; + hwif->INSW = scc_ide_insw; + hwif->INSL = scc_ide_insl; + hwif->OUTB = scc_ide_outb; + hwif->OUTBSYNC = scc_ide_outbsync; + hwif->OUTW = scc_ide_outw; + hwif->OUTSW = scc_ide_outsw; + hwif->OUTSL = scc_ide_outsl; + + hwif->io_ports[IDE_DATA_OFFSET] = dma_base + 0x20; + hwif->io_ports[IDE_ERROR_OFFSET] = dma_base + 0x24; + hwif->io_ports[IDE_NSECTOR_OFFSET] = dma_base + 0x28; + hwif->io_ports[IDE_SECTOR_OFFSET] = dma_base + 0x2c; + hwif->io_ports[IDE_LCYL_OFFSET] = dma_base + 0x30; + hwif->io_ports[IDE_HCYL_OFFSET] = dma_base + 0x34; + hwif->io_ports[IDE_SELECT_OFFSET] = dma_base + 0x38; + hwif->io_ports[IDE_STATUS_OFFSET] = dma_base + 0x3c; + hwif->io_ports[IDE_CONTROL_OFFSET] = dma_base + 0x40; + + hwif->irq = hwif->pci_dev->irq; + hwif->dma_base = dma_base; + hwif->config_data = ports->ctl; + hwif->mmio = 1; +} + +/** + * init_iops_scc - set up iops + * @hwif: interface to set up + * + * Do the basic setup for the SCC hardware interface + * and then do the MMIO setup. + */ + +static void __devinit init_iops_scc(ide_hwif_t *hwif) +{ + struct pci_dev *dev = hwif->pci_dev; + hwif->hwif_data = NULL; + if (pci_get_drvdata(dev) == NULL) + return; + init_mmio_iops_scc(hwif); +} + +/** + * init_hwif_scc - set up hwif + * @hwif: interface to set up + * + * We do the basic set up of the interface structure. The SCC + * requires several custom handlers so we override the default + * ide DMA handlers appropriately. + */ + +static void __devinit init_hwif_scc(ide_hwif_t *hwif) +{ + struct scc_ports *ports = ide_get_hwifdata(hwif); + + ports->hwif_id = hwif->index; + + hwif->dma_command = hwif->dma_base; + hwif->dma_status = hwif->dma_base + 0x04; + hwif->dma_prdtable = hwif->dma_base + 0x08; + + /* PTERADD */ + out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma); + + hwif->dma_setup = scc_dma_setup; + hwif->ide_dma_end = scc_ide_dma_end; + hwif->speedproc = scc_tune_chipset; + hwif->tuneproc = scc_tuneproc; + hwif->ide_dma_check = scc_config_drive_for_dma; + + hwif->drives[0].autotune = IDE_TUNE_AUTO; + hwif->drives[1].autotune = IDE_TUNE_AUTO; + + if (in_be32((void __iomem *)(hwif->config_data + 0xff0)) & CCKCTRL_ATACLKOEN) { + hwif->ultra_mask = 0x7f; /* 133MHz */ + } else { + hwif->ultra_mask = 0x3f; /* 100MHz */ + } + hwif->mwdma_mask = 0x00; + hwif->swdma_mask = 0x00; + hwif->atapi_dma = 1; + + /* we support 80c cable only. */ + hwif->udma_four = 1; + + hwif->autodma = 0; + if (!noautodma) + hwif->autodma = 1; + hwif->drives[0].autodma = hwif->autodma; + hwif->drives[1].autodma = hwif->autodma; +} + +#define DECLARE_SCC_DEV(name_str) \ + { \ + .name = name_str, \ + .init_setup = init_setup_scc, \ + .init_iops = init_iops_scc, \ + .init_hwif = init_hwif_scc, \ + .channels = 1, \ + .autodma = AUTODMA, \ + .bootable = ON_BOARD, \ + } + +static ide_pci_device_t scc_chipsets[] __devinitdata = { + /* 0 */ DECLARE_SCC_DEV("sccIDE"), +}; + +/** + * scc_init_one - pci layer discovery entry + * @dev: PCI device + * @id: ident table entry + * + * Called by the PCI code when it finds an SCC PATA controller. + * We then use the IDE PCI generic helper to do most of the work. + */ + +static int __devinit scc_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + ide_pci_device_t *d = &scc_chipsets[id->driver_data]; + return d->init_setup(dev, d); +} + +/** + * scc_remove - pci layer remove entry + * @dev: PCI device + * + * Called by the PCI code when it removes an SCC PATA controller. + */ + +static void __devexit scc_remove(struct pci_dev *dev) +{ + struct scc_ports *ports = pci_get_drvdata(dev); + ide_hwif_t *hwif = &ide_hwifs[ports->hwif_id]; + unsigned long ctl_base = pci_resource_start(dev, 0); + unsigned long dma_base = pci_resource_start(dev, 1); + unsigned long ctl_size = pci_resource_len(dev, 0); + unsigned long dma_size = pci_resource_len(dev, 1); + + if (hwif->dmatable_cpu) { + pci_free_consistent(hwif->pci_dev, + PRD_ENTRIES * PRD_BYTES, + hwif->dmatable_cpu, + hwif->dmatable_dma); + hwif->dmatable_cpu = NULL; + } + + ide_unregister(hwif->index); + + hwif->chipset = ide_unknown; + iounmap((void*)ports->dma); + iounmap((void*)ports->ctl); + release_mem_region(dma_base, dma_size); + release_mem_region(ctl_base, ctl_size); + memset(ports, 0, sizeof(*ports)); +} + +static struct pci_device_id scc_pci_tbl[] = { + { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, scc_pci_tbl); + +static struct pci_driver driver = { + .name = "SCC IDE", + .id_table = scc_pci_tbl, + .probe = scc_init_one, + .remove = scc_remove, +}; + +static int scc_ide_init(void) +{ + return ide_pci_register_driver(&driver); +} + +module_init(scc_ide_init); +/* -- No exit code? +static void scc_ide_exit(void) +{ + ide_pci_unregister_driver(&driver); +} +module_exit(scc_ide_exit); + */ + + +MODULE_DESCRIPTION("PCI driver module for Toshiba SCC IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ieee1394/ieee1394-ioctl.h b/drivers/ieee1394/ieee1394-ioctl.h index 8f207508ed1..46878fef136 100644 --- a/drivers/ieee1394/ieee1394-ioctl.h +++ b/drivers/ieee1394/ieee1394-ioctl.h @@ -100,5 +100,7 @@ _IO ('#', 0x28) #define RAW1394_IOC_ISO_RECV_FLUSH \ _IO ('#', 0x29) +#define RAW1394_IOC_GET_CYCLE_TIMER \ + _IOR ('#', 0x30, struct raw1394_cycle_timer) #endif /* __IEEE1394_IOCTL_H */ diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 1521e57e124..d791d08c743 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -33,7 +33,10 @@ #include <linux/skbuff.h> #include <linux/suspend.h> #include <linux/kthread.h> +#include <linux/preempt.h> +#include <linux/time.h> +#include <asm/system.h> #include <asm/byteorder.h> #include "ieee1394_types.h" @@ -186,6 +189,45 @@ int hpsb_reset_bus(struct hpsb_host *host, int type) } } +/** + * hpsb_read_cycle_timer - read cycle timer register and system time + * @host: host whose isochronous cycle timer register is read + * @cycle_timer: address of bitfield to return the register contents + * @local_time: address to return the system time + * + * The format of * @cycle_timer, is described in OHCI 1.1 clause 5.13. This + * format is also read from non-OHCI controllers. * @local_time contains the + * system time in microseconds since the Epoch, read at the moment when the + * cycle timer was read. + * + * Return value: 0 for success or error number otherwise. + */ +int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer, + u64 *local_time) +{ + int ctr; + struct timeval tv; + unsigned long flags; + + if (!host || !cycle_timer || !local_time) + return -EINVAL; + + preempt_disable(); + local_irq_save(flags); + + ctr = host->driver->devctl(host, GET_CYCLE_COUNTER, 0); + if (ctr) + do_gettimeofday(&tv); + + local_irq_restore(flags); + preempt_enable(); + + if (!ctr) + return -EIO; + *cycle_timer = ctr; + *local_time = tv.tv_sec * 1000000ULL + tv.tv_usec; + return 0; +} int hpsb_bus_reset(struct hpsb_host *host) { @@ -1190,6 +1232,7 @@ EXPORT_SYMBOL(hpsb_alloc_packet); EXPORT_SYMBOL(hpsb_free_packet); EXPORT_SYMBOL(hpsb_send_packet); EXPORT_SYMBOL(hpsb_reset_bus); +EXPORT_SYMBOL(hpsb_read_cycle_timer); EXPORT_SYMBOL(hpsb_bus_reset); EXPORT_SYMBOL(hpsb_selfid_received); EXPORT_SYMBOL(hpsb_selfid_complete); diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h index 536ba3f580f..bd29d8ef5bb 100644 --- a/drivers/ieee1394/ieee1394_core.h +++ b/drivers/ieee1394/ieee1394_core.h @@ -127,6 +127,9 @@ int hpsb_send_packet_and_wait(struct hpsb_packet *packet); * progress, 0 otherwise. */ int hpsb_reset_bus(struct hpsb_host *host, int type); +int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer, + u64 *local_time); + /* * The following functions are exported for host driver module usage. All of * them are safe to use in interrupt contexts, although some are quite diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index ba9faeff479..c5ace190bfe 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -1681,7 +1681,8 @@ static int nodemgr_host_thread(void *__hi) for (;;) { /* Sleep until next bus reset */ set_current_state(TASK_INTERRUPTIBLE); - if (get_hpsb_generation(host) == generation) + if (get_hpsb_generation(host) == generation && + !kthread_should_stop()) schedule(); __set_current_state(TASK_RUNNING); diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index aa9ca8385ec..bb897a37d9f 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -2669,6 +2669,18 @@ static void raw1394_iso_shutdown(struct file_info *fi) fi->iso_state = RAW1394_ISO_INACTIVE; } +static int raw1394_read_cycle_timer(struct file_info *fi, void __user * uaddr) +{ + struct raw1394_cycle_timer ct; + int err; + + err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time); + if (!err) + if (copy_to_user(uaddr, &ct, sizeof(ct))) + err = -EFAULT; + return err; +} + /* mmap the rawiso xmit/recv buffer */ static int raw1394_mmap(struct file *file, struct vm_area_struct *vma) { @@ -2777,6 +2789,14 @@ static int raw1394_ioctl(struct inode *inode, struct file *file, break; } + /* state-independent commands */ + switch(cmd) { + case RAW1394_IOC_GET_CYCLE_TIMER: + return raw1394_read_cycle_timer(fi, argp); + default: + break; + } + return -EINVAL; } diff --git a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h index 35bfc38f013..7bd22ee1afb 100644 --- a/drivers/ieee1394/raw1394.h +++ b/drivers/ieee1394/raw1394.h @@ -178,4 +178,14 @@ struct raw1394_iso_status { __s16 xmit_cycle; }; +/* argument to RAW1394_IOC_GET_CYCLE_TIMER ioctl */ +struct raw1394_cycle_timer { + /* contents of Isochronous Cycle Timer register, + as in OHCI 1.1 clause 5.13 (also with non-OHCI hosts) */ + __u32 cycle_timer; + + /* local time in microseconds since Epoch, + simultaneously read with cycle timer */ + __u64 local_time; +}; #endif /* IEEE1394_RAW1394_H */ diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index 50fb1cd447b..189e5d4b9b1 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile @@ -12,7 +12,7 @@ ib_core-y := packer.o ud_header.o verbs.o sysfs.o \ ib_mad-y := mad.o smi.o agent.o mad_rmpp.o -ib_sa-y := sa_query.o +ib_sa-y := sa_query.o multicast.o ib_cm-y := cm.o diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index db88e609bf4..f8d69b3fa30 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -71,6 +71,7 @@ static struct workqueue_struct *cma_wq; static DEFINE_IDR(sdp_ps); static DEFINE_IDR(tcp_ps); static DEFINE_IDR(udp_ps); +static DEFINE_IDR(ipoib_ps); static int next_port; struct cma_device { @@ -116,6 +117,7 @@ struct rdma_id_private { struct list_head list; struct list_head listen_list; struct cma_device *cma_dev; + struct list_head mc_list; enum cma_state state; spinlock_t lock; @@ -134,10 +136,23 @@ struct rdma_id_private { } cm_id; u32 seq_num; + u32 qkey; u32 qp_num; u8 srq; }; +struct cma_multicast { + struct rdma_id_private *id_priv; + union { + struct ib_sa_multicast *ib; + } multicast; + struct list_head list; + void *context; + struct sockaddr addr; + u8 pad[sizeof(struct sockaddr_in6) - + sizeof(struct sockaddr)]; +}; + struct cma_work { struct work_struct work; struct rdma_id_private *id; @@ -243,6 +258,11 @@ static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver) hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF); } +static inline int cma_is_ud_ps(enum rdma_port_space ps) +{ + return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB); +} + static void cma_attach_to_dev(struct rdma_id_private *id_priv, struct cma_device *cma_dev) { @@ -265,19 +285,41 @@ static void cma_detach_from_dev(struct rdma_id_private *id_priv) id_priv->cma_dev = NULL; } +static int cma_set_qkey(struct ib_device *device, u8 port_num, + enum rdma_port_space ps, + struct rdma_dev_addr *dev_addr, u32 *qkey) +{ + struct ib_sa_mcmember_rec rec; + int ret = 0; + + switch (ps) { + case RDMA_PS_UDP: + *qkey = RDMA_UDP_QKEY; + break; + case RDMA_PS_IPOIB: + ib_addr_get_mgid(dev_addr, &rec.mgid); + ret = ib_sa_get_mcmember_rec(device, port_num, &rec.mgid, &rec); + *qkey = be32_to_cpu(rec.qkey); + break; + default: + break; + } + return ret; +} + static int cma_acquire_dev(struct rdma_id_private *id_priv) { - enum rdma_node_type dev_type = id_priv->id.route.addr.dev_addr.dev_type; + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; struct cma_device *cma_dev; union ib_gid gid; int ret = -ENODEV; - switch (rdma_node_get_transport(dev_type)) { + switch (rdma_node_get_transport(dev_addr->dev_type)) { case RDMA_TRANSPORT_IB: - ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); + ib_addr_get_sgid(dev_addr, &gid); break; case RDMA_TRANSPORT_IWARP: - iw_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); + iw_addr_get_sgid(dev_addr, &gid); break; default: return -ENODEV; @@ -287,7 +329,12 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv) ret = ib_find_cached_gid(cma_dev->device, &gid, &id_priv->id.port_num, NULL); if (!ret) { - cma_attach_to_dev(id_priv, cma_dev); + ret = cma_set_qkey(cma_dev->device, + id_priv->id.port_num, + id_priv->id.ps, dev_addr, + &id_priv->qkey); + if (!ret) + cma_attach_to_dev(id_priv, cma_dev); break; } } @@ -325,40 +372,50 @@ struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, init_waitqueue_head(&id_priv->wait_remove); atomic_set(&id_priv->dev_remove, 0); INIT_LIST_HEAD(&id_priv->listen_list); + INIT_LIST_HEAD(&id_priv->mc_list); get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); return &id_priv->id; } EXPORT_SYMBOL(rdma_create_id); -static int cma_init_ib_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) +static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) { struct ib_qp_attr qp_attr; - struct rdma_dev_addr *dev_addr; - int ret; + int qp_attr_mask, ret; - dev_addr = &id_priv->id.route.addr.dev_addr; - ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, - ib_addr_get_pkey(dev_addr), - &qp_attr.pkey_index); + qp_attr.qp_state = IB_QPS_INIT; + ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); if (ret) return ret; - qp_attr.qp_state = IB_QPS_INIT; - qp_attr.qp_access_flags = 0; - qp_attr.port_num = id_priv->id.port_num; - return ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS | - IB_QP_PKEY_INDEX | IB_QP_PORT); + ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); + if (ret) + return ret; + + qp_attr.qp_state = IB_QPS_RTR; + ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); + if (ret) + return ret; + + qp_attr.qp_state = IB_QPS_RTS; + qp_attr.sq_psn = 0; + ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); + + return ret; } -static int cma_init_iw_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) +static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) { struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; qp_attr.qp_state = IB_QPS_INIT; - qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE; + ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); + if (ret) + return ret; - return ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS); + return ib_modify_qp(qp, &qp_attr, qp_attr_mask); } int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, @@ -376,18 +433,10 @@ int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, if (IS_ERR(qp)) return PTR_ERR(qp); - switch (rdma_node_get_transport(id->device->node_type)) { - case RDMA_TRANSPORT_IB: - ret = cma_init_ib_qp(id_priv, qp); - break; - case RDMA_TRANSPORT_IWARP: - ret = cma_init_iw_qp(id_priv, qp); - break; - default: - ret = -ENOSYS; - break; - } - + if (cma_is_ud_ps(id_priv->id.ps)) + ret = cma_init_ud_qp(id_priv, qp); + else + ret = cma_init_conn_qp(id_priv, qp); if (ret) goto err; @@ -460,23 +509,55 @@ static int cma_modify_qp_err(struct rdma_cm_id *id) return ib_modify_qp(id->qp, &qp_attr, IB_QP_STATE); } +static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, + struct ib_qp_attr *qp_attr, int *qp_attr_mask) +{ + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + int ret; + + ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, + ib_addr_get_pkey(dev_addr), + &qp_attr->pkey_index); + if (ret) + return ret; + + qp_attr->port_num = id_priv->id.port_num; + *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; + + if (cma_is_ud_ps(id_priv->id.ps)) { + qp_attr->qkey = id_priv->qkey; + *qp_attr_mask |= IB_QP_QKEY; + } else { + qp_attr->qp_access_flags = 0; + *qp_attr_mask |= IB_QP_ACCESS_FLAGS; + } + return 0; +} + int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, int *qp_attr_mask) { struct rdma_id_private *id_priv; - int ret; + int ret = 0; id_priv = container_of(id, struct rdma_id_private, id); switch (rdma_node_get_transport(id_priv->id.device->node_type)) { case RDMA_TRANSPORT_IB: - ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, - qp_attr_mask); + if (!id_priv->cm_id.ib || cma_is_ud_ps(id_priv->id.ps)) + ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask); + else + ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, + qp_attr_mask); if (qp_attr->qp_state == IB_QPS_RTR) qp_attr->rq_psn = id_priv->seq_num; break; case RDMA_TRANSPORT_IWARP: - ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, - qp_attr_mask); + if (!id_priv->cm_id.iw) { + qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE; + *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; + } else + ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, + qp_attr_mask); break; default: ret = -ENOSYS; @@ -698,6 +779,19 @@ static void cma_release_port(struct rdma_id_private *id_priv) mutex_unlock(&lock); } +static void cma_leave_mc_groups(struct rdma_id_private *id_priv) +{ + struct cma_multicast *mc; + + while (!list_empty(&id_priv->mc_list)) { + mc = container_of(id_priv->mc_list.next, + struct cma_multicast, list); + list_del(&mc->list); + ib_sa_free_multicast(mc->multicast.ib); + kfree(mc); + } +} + void rdma_destroy_id(struct rdma_cm_id *id) { struct rdma_id_private *id_priv; @@ -722,6 +816,7 @@ void rdma_destroy_id(struct rdma_cm_id *id) default: break; } + cma_leave_mc_groups(id_priv); mutex_lock(&lock); cma_detach_from_dev(id_priv); } @@ -972,7 +1067,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) memset(&event, 0, sizeof event); offset = cma_user_data_offset(listen_id->id.ps); event.event = RDMA_CM_EVENT_CONNECT_REQUEST; - if (listen_id->id.ps == RDMA_PS_UDP) { + if (cma_is_ud_ps(listen_id->id.ps)) { conn_id = cma_new_udp_id(&listen_id->id, ib_event); event.param.ud.private_data = ib_event->private_data + offset; event.param.ud.private_data_len = @@ -1725,7 +1820,7 @@ static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, struct rdma_bind_list *bind_list; int port, ret; - bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); + bind_list = kmalloc(sizeof *bind_list, GFP_KERNEL); if (!bind_list) return -ENOMEM; @@ -1847,6 +1942,9 @@ static int cma_get_port(struct rdma_id_private *id_priv) case RDMA_PS_UDP: ps = &udp_ps; break; + case RDMA_PS_IPOIB: + ps = &ipoib_ps; + break; default: return -EPROTONOSUPPORT; } @@ -1961,7 +2059,7 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id, event.status = ib_event->param.sidr_rep_rcvd.status; break; } - if (rep->qkey != RDMA_UD_QKEY) { + if (id_priv->qkey != rep->qkey) { event.event = RDMA_CM_EVENT_UNREACHABLE; event.status = -EINVAL; break; @@ -2160,7 +2258,7 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) switch (rdma_node_get_transport(id->device->node_type)) { case RDMA_TRANSPORT_IB: - if (id->ps == RDMA_PS_UDP) + if (cma_is_ud_ps(id->ps)) ret = cma_resolve_ib_udp(id_priv, conn_param); else ret = cma_connect_ib(id_priv, conn_param); @@ -2256,7 +2354,7 @@ static int cma_send_sidr_rep(struct rdma_id_private *id_priv, rep.status = status; if (status == IB_SIDR_SUCCESS) { rep.qp_num = id_priv->qp_num; - rep.qkey = RDMA_UD_QKEY; + rep.qkey = id_priv->qkey; } rep.private_data = private_data; rep.private_data_len = private_data_len; @@ -2280,7 +2378,7 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) switch (rdma_node_get_transport(id->device->node_type)) { case RDMA_TRANSPORT_IB: - if (id->ps == RDMA_PS_UDP) + if (cma_is_ud_ps(id->ps)) ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, conn_param->private_data, conn_param->private_data_len); @@ -2341,7 +2439,7 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data, switch (rdma_node_get_transport(id->device->node_type)) { case RDMA_TRANSPORT_IB: - if (id->ps == RDMA_PS_UDP) + if (cma_is_ud_ps(id->ps)) ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, private_data, private_data_len); else @@ -2392,6 +2490,178 @@ out: } EXPORT_SYMBOL(rdma_disconnect); +static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) +{ + struct rdma_id_private *id_priv; + struct cma_multicast *mc = multicast->context; + struct rdma_cm_event event; + int ret; + + id_priv = mc->id_priv; + atomic_inc(&id_priv->dev_remove); + if (!cma_comp(id_priv, CMA_ADDR_BOUND) && + !cma_comp(id_priv, CMA_ADDR_RESOLVED)) + goto out; + + if (!status && id_priv->id.qp) + status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid, + multicast->rec.mlid); + + memset(&event, 0, sizeof event); + event.status = status; + event.param.ud.private_data = mc->context; + if (!status) { + event.event = RDMA_CM_EVENT_MULTICAST_JOIN; + ib_init_ah_from_mcmember(id_priv->id.device, + id_priv->id.port_num, &multicast->rec, + &event.param.ud.ah_attr); + event.param.ud.qp_num = 0xFFFFFF; + event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey); + } else + event.event = RDMA_CM_EVENT_MULTICAST_ERROR; + + ret = id_priv->id.event_handler(&id_priv->id, &event); + if (ret) { + cma_exch(id_priv, CMA_DESTROYING); + cma_release_remove(id_priv); + rdma_destroy_id(&id_priv->id); + return 0; + } +out: + cma_release_remove(id_priv); + return 0; +} + +static void cma_set_mgid(struct rdma_id_private *id_priv, + struct sockaddr *addr, union ib_gid *mgid) +{ + unsigned char mc_map[MAX_ADDR_LEN]; + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + struct sockaddr_in *sin = (struct sockaddr_in *) addr; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; + + if (cma_any_addr(addr)) { + memset(mgid, 0, sizeof *mgid); + } else if ((addr->sa_family == AF_INET6) && + ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFF10A01B) == + 0xFF10A01B)) { + /* IPv6 address is an SA assigned MGID. */ + memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); + } else { + ip_ib_mc_map(sin->sin_addr.s_addr, mc_map); + if (id_priv->id.ps == RDMA_PS_UDP) + mc_map[7] = 0x01; /* Use RDMA CM signature */ + mc_map[8] = ib_addr_get_pkey(dev_addr) >> 8; + mc_map[9] = (unsigned char) ib_addr_get_pkey(dev_addr); + *mgid = *(union ib_gid *) (mc_map + 4); + } +} + +static int cma_join_ib_multicast(struct rdma_id_private *id_priv, + struct cma_multicast *mc) +{ + struct ib_sa_mcmember_rec rec; + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + ib_sa_comp_mask comp_mask; + int ret; + + ib_addr_get_mgid(dev_addr, &rec.mgid); + ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num, + &rec.mgid, &rec); + if (ret) + return ret; + + cma_set_mgid(id_priv, &mc->addr, &rec.mgid); + if (id_priv->id.ps == RDMA_PS_UDP) + rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); + ib_addr_get_sgid(dev_addr, &rec.port_gid); + rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); + rec.join_state = 1; + + comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | + IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE | + IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL | + IB_SA_MCMEMBER_REC_FLOW_LABEL | + IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; + + mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device, + id_priv->id.port_num, &rec, + comp_mask, GFP_KERNEL, + cma_ib_mc_handler, mc); + if (IS_ERR(mc->multicast.ib)) + return PTR_ERR(mc->multicast.ib); + + return 0; +} + +int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, + void *context) +{ + struct rdma_id_private *id_priv; + struct cma_multicast *mc; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp(id_priv, CMA_ADDR_BOUND) && + !cma_comp(id_priv, CMA_ADDR_RESOLVED)) + return -EINVAL; + + mc = kmalloc(sizeof *mc, GFP_KERNEL); + if (!mc) + return -ENOMEM; + + memcpy(&mc->addr, addr, ip_addr_size(addr)); + mc->context = context; + mc->id_priv = id_priv; + + spin_lock(&id_priv->lock); + list_add(&mc->list, &id_priv->mc_list); + spin_unlock(&id_priv->lock); + + switch (rdma_node_get_transport(id->device->node_type)) { + case RDMA_TRANSPORT_IB: + ret = cma_join_ib_multicast(id_priv, mc); + break; + default: + ret = -ENOSYS; + break; + } + + if (ret) { + spin_lock_irq(&id_priv->lock); + list_del(&mc->list); + spin_unlock_irq(&id_priv->lock); + kfree(mc); + } + return ret; +} +EXPORT_SYMBOL(rdma_join_multicast); + +void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) +{ + struct rdma_id_private *id_priv; + struct cma_multicast *mc; + + id_priv = container_of(id, struct rdma_id_private, id); + spin_lock_irq(&id_priv->lock); + list_for_each_entry(mc, &id_priv->mc_list, list) { + if (!memcmp(&mc->addr, addr, ip_addr_size(addr))) { + list_del(&mc->list); + spin_unlock_irq(&id_priv->lock); + + if (id->qp) + ib_detach_mcast(id->qp, + &mc->multicast.ib->rec.mgid, + mc->multicast.ib->rec.mlid); + ib_sa_free_multicast(mc->multicast.ib); + kfree(mc); + return; + } + } + spin_unlock_irq(&id_priv->lock); +} +EXPORT_SYMBOL(rdma_leave_multicast); + static void cma_add_one(struct ib_device *device) { struct cma_device *cma_dev; @@ -2522,6 +2792,7 @@ static void cma_cleanup(void) idr_destroy(&sdp_ps); idr_destroy(&tcp_ps); idr_destroy(&udp_ps); + idr_destroy(&ipoib_ps); } module_init(cma_init); diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c index 8926a2bd4a8..1d796e7c819 100644 --- a/drivers/infiniband/core/fmr_pool.c +++ b/drivers/infiniband/core/fmr_pool.c @@ -301,7 +301,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, { struct ib_pool_fmr *fmr; - struct ib_fmr_attr attr = { + struct ib_fmr_attr fmr_attr = { .max_pages = params->max_pages_per_fmr, .max_maps = pool->max_remaps, .page_shift = params->page_shift @@ -321,7 +321,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, fmr->ref_count = 0; INIT_HLIST_NODE(&fmr->cache_node); - fmr->fmr = ib_alloc_fmr(pd, params->access, &attr); + fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr); if (IS_ERR(fmr->fmr)) { printk(KERN_WARNING "fmr_create failed for FMR %d", i); kfree(fmr); diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index 1039ad57d53..891d1fa7b2e 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -146,6 +146,12 @@ static int copy_private_data(struct iw_cm_event *event) return 0; } +static void free_cm_id(struct iwcm_id_private *cm_id_priv) +{ + dealloc_work_entries(cm_id_priv); + kfree(cm_id_priv); +} + /* * Release a reference on cm_id. If the last reference is being * released, enable the waiting thread (in iw_destroy_cm_id) to @@ -153,21 +159,14 @@ static int copy_private_data(struct iw_cm_event *event) */ static int iwcm_deref_id(struct iwcm_id_private *cm_id_priv) { - int ret = 0; - BUG_ON(atomic_read(&cm_id_priv->refcount)==0); if (atomic_dec_and_test(&cm_id_priv->refcount)) { BUG_ON(!list_empty(&cm_id_priv->work_list)); - if (waitqueue_active(&cm_id_priv->destroy_comp.wait)) { - BUG_ON(cm_id_priv->state != IW_CM_STATE_DESTROYING); - BUG_ON(test_bit(IWCM_F_CALLBACK_DESTROY, - &cm_id_priv->flags)); - ret = 1; - } complete(&cm_id_priv->destroy_comp); + return 1; } - return ret; + return 0; } static void add_ref(struct iw_cm_id *cm_id) @@ -181,7 +180,11 @@ static void rem_ref(struct iw_cm_id *cm_id) { struct iwcm_id_private *cm_id_priv; cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); - iwcm_deref_id(cm_id_priv); + if (iwcm_deref_id(cm_id_priv) && + test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags)) { + BUG_ON(!list_empty(&cm_id_priv->work_list)); + free_cm_id(cm_id_priv); + } } static int cm_event_handler(struct iw_cm_id *cm_id, struct iw_cm_event *event); @@ -355,7 +358,9 @@ static void destroy_cm_id(struct iw_cm_id *cm_id) case IW_CM_STATE_CONN_RECV: /* * App called destroy before/without calling accept after - * receiving connection request event notification. + * receiving connection request event notification or + * returned non zero from the event callback function. + * In either case, must tell the provider to reject. */ cm_id_priv->state = IW_CM_STATE_DESTROYING; break; @@ -391,9 +396,7 @@ void iw_destroy_cm_id(struct iw_cm_id *cm_id) wait_for_completion(&cm_id_priv->destroy_comp); - dealloc_work_entries(cm_id_priv); - - kfree(cm_id_priv); + free_cm_id(cm_id_priv); } EXPORT_SYMBOL(iw_destroy_cm_id); @@ -647,10 +650,11 @@ static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv, /* Call the client CM handler */ ret = cm_id->cm_handler(cm_id, iw_event); if (ret) { + iw_cm_reject(cm_id, NULL, 0); set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags); destroy_cm_id(cm_id); if (atomic_read(&cm_id_priv->refcount)==0) - kfree(cm_id); + free_cm_id(cm_id_priv); } out: @@ -854,13 +858,12 @@ static void cm_work_handler(struct work_struct *_work) destroy_cm_id(&cm_id_priv->id); } BUG_ON(atomic_read(&cm_id_priv->refcount)==0); - if (iwcm_deref_id(cm_id_priv)) - return; - - if (atomic_read(&cm_id_priv->refcount)==0 && - test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags)) { - dealloc_work_entries(cm_id_priv); - kfree(cm_id_priv); + if (iwcm_deref_id(cm_id_priv)) { + if (test_bit(IWCM_F_CALLBACK_DESTROY, + &cm_id_priv->flags)) { + BUG_ON(!list_empty(&cm_id_priv->work_list)); + free_cm_id(cm_id_priv); + } return; } spin_lock_irqsave(&cm_id_priv->lock, flags); diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c new file mode 100644 index 00000000000..4a579b3a1c9 --- /dev/null +++ b/drivers/infiniband/core/multicast.c @@ -0,0 +1,837 @@ +/* + * Copyright (c) 2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/completion.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/bitops.h> +#include <linux/random.h> + +#include <rdma/ib_cache.h> +#include "sa.h" + +static void mcast_add_one(struct ib_device *device); +static void mcast_remove_one(struct ib_device *device); + +static struct ib_client mcast_client = { + .name = "ib_multicast", + .add = mcast_add_one, + .remove = mcast_remove_one +}; + +static struct ib_sa_client sa_client; +static struct workqueue_struct *mcast_wq; +static union ib_gid mgid0; + +struct mcast_device; + +struct mcast_port { + struct mcast_device *dev; + spinlock_t lock; + struct rb_root table; + atomic_t refcount; + struct completion comp; + u8 port_num; +}; + +struct mcast_device { + struct ib_device *device; + struct ib_event_handler event_handler; + int start_port; + int end_port; + struct mcast_port port[0]; +}; + +enum mcast_state { + MCAST_IDLE, + MCAST_JOINING, + MCAST_MEMBER, + MCAST_BUSY, + MCAST_ERROR +}; + +struct mcast_member; + +struct mcast_group { + struct ib_sa_mcmember_rec rec; + struct rb_node node; + struct mcast_port *port; + spinlock_t lock; + struct work_struct work; + struct list_head pending_list; + struct list_head active_list; + struct mcast_member *last_join; + int members[3]; + atomic_t refcount; + enum mcast_state state; + struct ib_sa_query *query; + int query_id; +}; + +struct mcast_member { + struct ib_sa_multicast multicast; + struct ib_sa_client *client; + struct mcast_group *group; + struct list_head list; + enum mcast_state state; + atomic_t refcount; + struct completion comp; +}; + +static void join_handler(int status, struct ib_sa_mcmember_rec *rec, + void *context); +static void leave_handler(int status, struct ib_sa_mcmember_rec *rec, + void *context); + +static struct mcast_group *mcast_find(struct mcast_port *port, + union ib_gid *mgid) +{ + struct rb_node *node = port->table.rb_node; + struct mcast_group *group; + int ret; + + while (node) { + group = rb_entry(node, struct mcast_group, node); + ret = memcmp(mgid->raw, group->rec.mgid.raw, sizeof *mgid); + if (!ret) + return group; + + if (ret < 0) + node = node->rb_left; + else + node = node->rb_right; + } + return NULL; +} + +static struct mcast_group *mcast_insert(struct mcast_port *port, + struct mcast_group *group, + int allow_duplicates) +{ + struct rb_node **link = &port->table.rb_node; + struct rb_node *parent = NULL; + struct mcast_group *cur_group; + int ret; + + while (*link) { + parent = *link; + cur_group = rb_entry(parent, struct mcast_group, node); + + ret = memcmp(group->rec.mgid.raw, cur_group->rec.mgid.raw, + sizeof group->rec.mgid); + if (ret < 0) + link = &(*link)->rb_left; + else if (ret > 0) + link = &(*link)->rb_right; + else if (allow_duplicates) + link = &(*link)->rb_left; + else + return cur_group; + } + rb_link_node(&group->node, parent, link); + rb_insert_color(&group->node, &port->table); + return NULL; +} + +static void deref_port(struct mcast_port *port) +{ + if (atomic_dec_and_test(&port->refcount)) + complete(&port->comp); +} + +static void release_group(struct mcast_group *group) +{ + struct mcast_port *port = group->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (atomic_dec_and_test(&group->refcount)) { + rb_erase(&group->node, &port->table); + spin_unlock_irqrestore(&port->lock, flags); + kfree(group); + deref_port(port); + } else + spin_unlock_irqrestore(&port->lock, flags); +} + +static void deref_member(struct mcast_member *member) +{ + if (atomic_dec_and_test(&member->refcount)) + complete(&member->comp); +} + +static void queue_join(struct mcast_member *member) +{ + struct mcast_group *group = member->group; + unsigned long flags; + + spin_lock_irqsave(&group->lock, flags); + list_add(&member->list, &group->pending_list); + if (group->state == MCAST_IDLE) { + group->state = MCAST_BUSY; + atomic_inc(&group->refcount); + queue_work(mcast_wq, &group->work); + } + spin_unlock_irqrestore(&group->lock, flags); +} + +/* + * A multicast group has three types of members: full member, non member, and + * send only member. We need to keep track of the number of members of each + * type based on their join state. Adjust the number of members the belong to + * the specified join states. + */ +static void adjust_membership(struct mcast_group *group, u8 join_state, int inc) +{ + int i; + + for (i = 0; i < 3; i++, join_state >>= 1) + if (join_state & 0x1) + group->members[i] += inc; +} + +/* + * If a multicast group has zero members left for a particular join state, but + * the group is still a member with the SA, we need to leave that join state. + * Determine which join states we still belong to, but that do not have any + * active members. + */ +static u8 get_leave_state(struct mcast_group *group) +{ + u8 leave_state = 0; + int i; + + for (i = 0; i < 3; i++) + if (!group->members[i]) + leave_state |= (0x1 << i); + + return leave_state & group->rec.join_state; +} + +static int check_selector(ib_sa_comp_mask comp_mask, + ib_sa_comp_mask selector_mask, + ib_sa_comp_mask value_mask, + u8 selector, u8 src_value, u8 dst_value) +{ + int err; + + if (!(comp_mask & selector_mask) || !(comp_mask & value_mask)) + return 0; + + switch (selector) { + case IB_SA_GT: + err = (src_value <= dst_value); + break; + case IB_SA_LT: + err = (src_value >= dst_value); + break; + case IB_SA_EQ: + err = (src_value != dst_value); + break; + default: + err = 0; + break; + } + + return err; +} + +static int cmp_rec(struct ib_sa_mcmember_rec *src, + struct ib_sa_mcmember_rec *dst, ib_sa_comp_mask comp_mask) +{ + /* MGID must already match */ + + if (comp_mask & IB_SA_MCMEMBER_REC_PORT_GID && + memcmp(&src->port_gid, &dst->port_gid, sizeof src->port_gid)) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_QKEY && src->qkey != dst->qkey) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_MLID && src->mlid != dst->mlid) + return -EINVAL; + if (check_selector(comp_mask, IB_SA_MCMEMBER_REC_MTU_SELECTOR, + IB_SA_MCMEMBER_REC_MTU, dst->mtu_selector, + src->mtu, dst->mtu)) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_TRAFFIC_CLASS && + src->traffic_class != dst->traffic_class) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_PKEY && src->pkey != dst->pkey) + return -EINVAL; + if (check_selector(comp_mask, IB_SA_MCMEMBER_REC_RATE_SELECTOR, + IB_SA_MCMEMBER_REC_RATE, dst->rate_selector, + src->rate, dst->rate)) + return -EINVAL; + if (check_selector(comp_mask, + IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR, + IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME, + dst->packet_life_time_selector, + src->packet_life_time, dst->packet_life_time)) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_SL && src->sl != dst->sl) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_FLOW_LABEL && + src->flow_label != dst->flow_label) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_HOP_LIMIT && + src->hop_limit != dst->hop_limit) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_SCOPE && src->scope != dst->scope) + return -EINVAL; + + /* join_state checked separately, proxy_join ignored */ + + return 0; +} + +static int send_join(struct mcast_group *group, struct mcast_member *member) +{ + struct mcast_port *port = group->port; + int ret; + + group->last_join = member; + ret = ib_sa_mcmember_rec_query(&sa_client, port->dev->device, + port->port_num, IB_MGMT_METHOD_SET, + &member->multicast.rec, + member->multicast.comp_mask, + 3000, GFP_KERNEL, join_handler, group, + &group->query); + if (ret >= 0) { + group->query_id = ret; + ret = 0; + } + return ret; +} + +static int send_leave(struct mcast_group *group, u8 leave_state) +{ + struct mcast_port *port = group->port; + struct ib_sa_mcmember_rec rec; + int ret; + + rec = group->rec; + rec.join_state = leave_state; + + ret = ib_sa_mcmember_rec_query(&sa_client, port->dev->device, + port->port_num, IB_SA_METHOD_DELETE, &rec, + IB_SA_MCMEMBER_REC_MGID | + IB_SA_MCMEMBER_REC_PORT_GID | + IB_SA_MCMEMBER_REC_JOIN_STATE, + 3000, GFP_KERNEL, leave_handler, + group, &group->query); + if (ret >= 0) { + group->query_id = ret; + ret = 0; + } + return ret; +} + +static void join_group(struct mcast_group *group, struct mcast_member *member, + u8 join_state) +{ + member->state = MCAST_MEMBER; + adjust_membership(group, join_state, 1); + group->rec.join_state |= join_state; + member->multicast.rec = group->rec; + member->multicast.rec.join_state = join_state; + list_move(&member->list, &group->active_list); +} + +static int fail_join(struct mcast_group *group, struct mcast_member *member, + int status) +{ + spin_lock_irq(&group->lock); + list_del_init(&member->list); + spin_unlock_irq(&group->lock); + return member->multicast.callback(status, &member->multicast); +} + +static void process_group_error(struct mcast_group *group) +{ + struct mcast_member *member; + int ret; + + spin_lock_irq(&group->lock); + while (!list_empty(&group->active_list)) { + member = list_entry(group->active_list.next, + struct mcast_member, list); + atomic_inc(&member->refcount); + list_del_init(&member->list); + adjust_membership(group, member->multicast.rec.join_state, -1); + member->state = MCAST_ERROR; + spin_unlock_irq(&group->lock); + + ret = member->multicast.callback(-ENETRESET, + &member->multicast); + deref_member(member); + if (ret) + ib_sa_free_multicast(&member->multicast); + spin_lock_irq(&group->lock); + } + + group->rec.join_state = 0; + group->state = MCAST_BUSY; + spin_unlock_irq(&group->lock); +} + +static void mcast_work_handler(struct work_struct *work) +{ + struct mcast_group *group; + struct mcast_member *member; + struct ib_sa_multicast *multicast; + int status, ret; + u8 join_state; + + group = container_of(work, typeof(*group), work); +retest: + spin_lock_irq(&group->lock); + while (!list_empty(&group->pending_list) || + (group->state == MCAST_ERROR)) { + + if (group->state == MCAST_ERROR) { + spin_unlock_irq(&group->lock); + process_group_error(group); + goto retest; + } + + member = list_entry(group->pending_list.next, + struct mcast_member, list); + multicast = &member->multicast; + join_state = multicast->rec.join_state; + atomic_inc(&member->refcount); + + if (join_state == (group->rec.join_state & join_state)) { + status = cmp_rec(&group->rec, &multicast->rec, + multicast->comp_mask); + if (!status) + join_group(group, member, join_state); + else + list_del_init(&member->list); + spin_unlock_irq(&group->lock); + ret = multicast->callback(status, multicast); + } else { + spin_unlock_irq(&group->lock); + status = send_join(group, member); + if (!status) { + deref_member(member); + return; + } + ret = fail_join(group, member, status); + } + + deref_member(member); + if (ret) + ib_sa_free_multicast(&member->multicast); + spin_lock_irq(&group->lock); + } + + join_state = get_leave_state(group); + if (join_state) { + group->rec.join_state &= ~join_state; + spin_unlock_irq(&group->lock); + if (send_leave(group, join_state)) + goto retest; + } else { + group->state = MCAST_IDLE; + spin_unlock_irq(&group->lock); + release_group(group); + } +} + +/* + * Fail a join request if it is still active - at the head of the pending queue. + */ +static void process_join_error(struct mcast_group *group, int status) +{ + struct mcast_member *member; + int ret; + + spin_lock_irq(&group->lock); + member = list_entry(group->pending_list.next, + struct mcast_member, list); + if (group->last_join == member) { + atomic_inc(&member->refcount); + list_del_init(&member->list); + spin_unlock_irq(&group->lock); + ret = member->multicast.callback(status, &member->multicast); + deref_member(member); + if (ret) + ib_sa_free_multicast(&member->multicast); + } else + spin_unlock_irq(&group->lock); +} + +static void join_handler(int status, struct ib_sa_mcmember_rec *rec, + void *context) +{ + struct mcast_group *group = context; + + if (status) + process_join_error(group, status); + else { + spin_lock_irq(&group->port->lock); + group->rec = *rec; + if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) { + rb_erase(&group->node, &group->port->table); + mcast_insert(group->port, group, 1); + } + spin_unlock_irq(&group->port->lock); + } + mcast_work_handler(&group->work); +} + +static void leave_handler(int status, struct ib_sa_mcmember_rec *rec, + void *context) +{ + struct mcast_group *group = context; + + mcast_work_handler(&group->work); +} + +static struct mcast_group *acquire_group(struct mcast_port *port, + union ib_gid *mgid, gfp_t gfp_mask) +{ + struct mcast_group *group, *cur_group; + unsigned long flags; + int is_mgid0; + + is_mgid0 = !memcmp(&mgid0, mgid, sizeof mgid0); + if (!is_mgid0) { + spin_lock_irqsave(&port->lock, flags); + group = mcast_find(port, mgid); + if (group) + goto found; + spin_unlock_irqrestore(&port->lock, flags); + } + + group = kzalloc(sizeof *group, gfp_mask); + if (!group) + return NULL; + + group->port = port; + group->rec.mgid = *mgid; + INIT_LIST_HEAD(&group->pending_list); + INIT_LIST_HEAD(&group->active_list); + INIT_WORK(&group->work, mcast_work_handler); + spin_lock_init(&group->lock); + + spin_lock_irqsave(&port->lock, flags); + cur_group = mcast_insert(port, group, is_mgid0); + if (cur_group) { + kfree(group); + group = cur_group; + } else + atomic_inc(&port->refcount); +found: + atomic_inc(&group->refcount); + spin_unlock_irqrestore(&port->lock, flags); + return group; +} + +/* + * We serialize all join requests to a single group to make our lives much + * easier. Otherwise, two users could try to join the same group + * simultaneously, with different configurations, one could leave while the + * join is in progress, etc., which makes locking around error recovery + * difficult. + */ +struct ib_sa_multicast * +ib_sa_join_multicast(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + struct ib_sa_mcmember_rec *rec, + ib_sa_comp_mask comp_mask, gfp_t gfp_mask, + int (*callback)(int status, + struct ib_sa_multicast *multicast), + void *context) +{ + struct mcast_device *dev; + struct mcast_member *member; + struct ib_sa_multicast *multicast; + int ret; + + dev = ib_get_client_data(device, &mcast_client); + if (!dev) + return ERR_PTR(-ENODEV); + + member = kmalloc(sizeof *member, gfp_mask); + if (!member) + return ERR_PTR(-ENOMEM); + + ib_sa_client_get(client); + member->client = client; + member->multicast.rec = *rec; + member->multicast.comp_mask = comp_mask; + member->multicast.callback = callback; + member->multicast.context = context; + init_completion(&member->comp); + atomic_set(&member->refcount, 1); + member->state = MCAST_JOINING; + + member->group = acquire_group(&dev->port[port_num - dev->start_port], + &rec->mgid, gfp_mask); + if (!member->group) { + ret = -ENOMEM; + goto err; + } + + /* + * The user will get the multicast structure in their callback. They + * could then free the multicast structure before we can return from + * this routine. So we save the pointer to return before queuing + * any callback. + */ + multicast = &member->multicast; + queue_join(member); + return multicast; + +err: + ib_sa_client_put(client); + kfree(member); + return ERR_PTR(ret); +} +EXPORT_SYMBOL(ib_sa_join_multicast); + +void ib_sa_free_multicast(struct ib_sa_multicast *multicast) +{ + struct mcast_member *member; + struct mcast_group *group; + + member = container_of(multicast, struct mcast_member, multicast); + group = member->group; + + spin_lock_irq(&group->lock); + if (member->state == MCAST_MEMBER) + adjust_membership(group, multicast->rec.join_state, -1); + + list_del_init(&member->list); + + if (group->state == MCAST_IDLE) { + group->state = MCAST_BUSY; + spin_unlock_irq(&group->lock); + /* Continue to hold reference on group until callback */ + queue_work(mcast_wq, &group->work); + } else { + spin_unlock_irq(&group->lock); + release_group(group); + } + + deref_member(member); + wait_for_completion(&member->comp); + ib_sa_client_put(member->client); + kfree(member); +} +EXPORT_SYMBOL(ib_sa_free_multicast); + +int ib_sa_get_mcmember_rec(struct ib_device *device, u8 port_num, + union ib_gid *mgid, struct ib_sa_mcmember_rec *rec) +{ + struct mcast_device *dev; + struct mcast_port *port; + struct mcast_group *group; + unsigned long flags; + int ret = 0; + + dev = ib_get_client_data(device, &mcast_client); + if (!dev) + return -ENODEV; + + port = &dev->port[port_num - dev->start_port]; + spin_lock_irqsave(&port->lock, flags); + group = mcast_find(port, mgid); + if (group) + *rec = group->rec; + else + ret = -EADDRNOTAVAIL; + spin_unlock_irqrestore(&port->lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_sa_get_mcmember_rec); + +int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num, + struct ib_sa_mcmember_rec *rec, + struct ib_ah_attr *ah_attr) +{ + int ret; + u16 gid_index; + u8 p; + + ret = ib_find_cached_gid(device, &rec->port_gid, &p, &gid_index); + if (ret) + return ret; + + memset(ah_attr, 0, sizeof *ah_attr); + ah_attr->dlid = be16_to_cpu(rec->mlid); + ah_attr->sl = rec->sl; + ah_attr->port_num = port_num; + ah_attr->static_rate = rec->rate; + + ah_attr->ah_flags = IB_AH_GRH; + ah_attr->grh.dgid = rec->mgid; + + ah_attr->grh.sgid_index = (u8) gid_index; + ah_attr->grh.flow_label = be32_to_cpu(rec->flow_label); + ah_attr->grh.hop_limit = rec->hop_limit; + ah_attr->grh.traffic_class = rec->traffic_class; + + return 0; +} +EXPORT_SYMBOL(ib_init_ah_from_mcmember); + +static void mcast_groups_lost(struct mcast_port *port) +{ + struct mcast_group *group; + struct rb_node *node; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + for (node = rb_first(&port->table); node; node = rb_next(node)) { + group = rb_entry(node, struct mcast_group, node); + spin_lock(&group->lock); + if (group->state == MCAST_IDLE) { + atomic_inc(&group->refcount); + queue_work(mcast_wq, &group->work); + } + group->state = MCAST_ERROR; + spin_unlock(&group->lock); + } + spin_unlock_irqrestore(&port->lock, flags); +} + +static void mcast_event_handler(struct ib_event_handler *handler, + struct ib_event *event) +{ + struct mcast_device *dev; + + dev = container_of(handler, struct mcast_device, event_handler); + + switch (event->event) { + case IB_EVENT_PORT_ERR: + case IB_EVENT_LID_CHANGE: + case IB_EVENT_SM_CHANGE: + case IB_EVENT_CLIENT_REREGISTER: + mcast_groups_lost(&dev->port[event->element.port_num - + dev->start_port]); + break; + default: + break; + } +} + +static void mcast_add_one(struct ib_device *device) +{ + struct mcast_device *dev; + struct mcast_port *port; + int i; + + if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) + return; + + dev = kmalloc(sizeof *dev + device->phys_port_cnt * sizeof *port, + GFP_KERNEL); + if (!dev) + return; + + if (device->node_type == RDMA_NODE_IB_SWITCH) + dev->start_port = dev->end_port = 0; + else { + dev->start_port = 1; + dev->end_port = device->phys_port_cnt; + } + + for (i = 0; i <= dev->end_port - dev->start_port; i++) { + port = &dev->port[i]; + port->dev = dev; + port->port_num = dev->start_port + i; + spin_lock_init(&port->lock); + port->table = RB_ROOT; + init_completion(&port->comp); + atomic_set(&port->refcount, 1); + } + + dev->device = device; + ib_set_client_data(device, &mcast_client, dev); + + INIT_IB_EVENT_HANDLER(&dev->event_handler, device, mcast_event_handler); + ib_register_event_handler(&dev->event_handler); +} + +static void mcast_remove_one(struct ib_device *device) +{ + struct mcast_device *dev; + struct mcast_port *port; + int i; + + dev = ib_get_client_data(device, &mcast_client); + if (!dev) + return; + + ib_unregister_event_handler(&dev->event_handler); + flush_workqueue(mcast_wq); + + for (i = 0; i <= dev->end_port - dev->start_port; i++) { + port = &dev->port[i]; + deref_port(port); + wait_for_completion(&port->comp); + } + + kfree(dev); +} + +int mcast_init(void) +{ + int ret; + + mcast_wq = create_singlethread_workqueue("ib_mcast"); + if (!mcast_wq) + return -ENOMEM; + + ib_sa_register_client(&sa_client); + + ret = ib_register_client(&mcast_client); + if (ret) + goto err; + return 0; + +err: + ib_sa_unregister_client(&sa_client); + destroy_workqueue(mcast_wq); + return ret; +} + +void mcast_cleanup(void) +{ + ib_unregister_client(&mcast_client); + ib_sa_unregister_client(&sa_client); + destroy_workqueue(mcast_wq); +} diff --git a/drivers/infiniband/core/sa.h b/drivers/infiniband/core/sa.h new file mode 100644 index 00000000000..24c93fd320f --- /dev/null +++ b/drivers/infiniband/core/sa.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef SA_H +#define SA_H + +#include <rdma/ib_sa.h> + +static inline void ib_sa_client_get(struct ib_sa_client *client) +{ + atomic_inc(&client->users); +} + +static inline void ib_sa_client_put(struct ib_sa_client *client) +{ + if (atomic_dec_and_test(&client->users)) + complete(&client->comp); +} + +int ib_sa_mcmember_rec_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + u8 method, + struct ib_sa_mcmember_rec *rec, + ib_sa_comp_mask comp_mask, + int timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct ib_sa_mcmember_rec *resp, + void *context), + void *context, + struct ib_sa_query **sa_query); + +int mcast_init(void); +void mcast_cleanup(void); + +#endif /* SA_H */ diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index e45afba7534..68db633711c 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -47,8 +47,8 @@ #include <linux/workqueue.h> #include <rdma/ib_pack.h> -#include <rdma/ib_sa.h> #include <rdma/ib_cache.h> +#include "sa.h" MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("InfiniBand subnet administration query support"); @@ -425,17 +425,6 @@ void ib_sa_register_client(struct ib_sa_client *client) } EXPORT_SYMBOL(ib_sa_register_client); -static inline void ib_sa_client_get(struct ib_sa_client *client) -{ - atomic_inc(&client->users); -} - -static inline void ib_sa_client_put(struct ib_sa_client *client) -{ - if (atomic_dec_and_test(&client->users)) - complete(&client->comp); -} - void ib_sa_unregister_client(struct ib_sa_client *client) { ib_sa_client_put(client); @@ -482,6 +471,7 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num, ah_attr->sl = rec->sl; ah_attr->src_path_bits = be16_to_cpu(rec->slid) & 0x7f; ah_attr->port_num = port_num; + ah_attr->static_rate = rec->rate; if (rec->hop_limit > 1) { ah_attr->ah_flags = IB_AH_GRH; @@ -901,7 +891,6 @@ err1: kfree(query); return ret; } -EXPORT_SYMBOL(ib_sa_mcmember_rec_query); static void send_handler(struct ib_mad_agent *agent, struct ib_mad_send_wc *mad_send_wc) @@ -1053,14 +1042,27 @@ static int __init ib_sa_init(void) get_random_bytes(&tid, sizeof tid); ret = ib_register_client(&sa_client); - if (ret) + if (ret) { printk(KERN_ERR "Couldn't register ib_sa client\n"); + goto err1; + } + + ret = mcast_init(); + if (ret) { + printk(KERN_ERR "Couldn't initialize multicast handling\n"); + goto err2; + } + return 0; +err2: + ib_unregister_client(&sa_client); +err1: return ret; } static void __exit ib_sa_cleanup(void) { + mcast_cleanup(); ib_unregister_client(&sa_client); idr_destroy(&query_idr); } diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 709323c14c5..000c086bf2e 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -714,8 +714,6 @@ int ib_device_register_sysfs(struct ib_device *device) if (ret) goto err_put; } else { - int i; - for (i = 1; i <= device->phys_port_cnt; ++i) { ret = add_port(device, i); if (ret) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 6b81b98961c..b516b93b855 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -70,10 +70,24 @@ struct ucma_context { u64 uid; struct list_head list; + struct list_head mc_list; +}; + +struct ucma_multicast { + struct ucma_context *ctx; + int id; + int events_reported; + + u64 uid; + struct list_head list; + struct sockaddr addr; + u8 pad[sizeof(struct sockaddr_in6) - + sizeof(struct sockaddr)]; }; struct ucma_event { struct ucma_context *ctx; + struct ucma_multicast *mc; struct list_head list; struct rdma_cm_id *cm_id; struct rdma_ucm_event_resp resp; @@ -81,6 +95,7 @@ struct ucma_event { static DEFINE_MUTEX(mut); static DEFINE_IDR(ctx_idr); +static DEFINE_IDR(multicast_idr); static inline struct ucma_context *_ucma_find_context(int id, struct ucma_file *file) @@ -124,6 +139,7 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file) atomic_set(&ctx->ref, 1); init_completion(&ctx->comp); + INIT_LIST_HEAD(&ctx->mc_list); ctx->file = file; do { @@ -147,6 +163,37 @@ error: return NULL; } +static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx) +{ + struct ucma_multicast *mc; + int ret; + + mc = kzalloc(sizeof(*mc), GFP_KERNEL); + if (!mc) + return NULL; + + do { + ret = idr_pre_get(&multicast_idr, GFP_KERNEL); + if (!ret) + goto error; + + mutex_lock(&mut); + ret = idr_get_new(&multicast_idr, mc, &mc->id); + mutex_unlock(&mut); + } while (ret == -EAGAIN); + + if (ret) + goto error; + + mc->ctx = ctx; + list_add_tail(&mc->list, &ctx->mc_list); + return mc; + +error: + kfree(mc); + return NULL; +} + static void ucma_copy_conn_event(struct rdma_ucm_conn_param *dst, struct rdma_conn_param *src) { @@ -180,8 +227,19 @@ static void ucma_set_event_context(struct ucma_context *ctx, struct ucma_event *uevent) { uevent->ctx = ctx; - uevent->resp.uid = ctx->uid; - uevent->resp.id = ctx->id; + switch (event->event) { + case RDMA_CM_EVENT_MULTICAST_JOIN: + case RDMA_CM_EVENT_MULTICAST_ERROR: + uevent->mc = (struct ucma_multicast *) + event->param.ud.private_data; + uevent->resp.uid = uevent->mc->uid; + uevent->resp.id = uevent->mc->id; + break; + default: + uevent->resp.uid = ctx->uid; + uevent->resp.id = ctx->id; + break; + } } static int ucma_event_handler(struct rdma_cm_id *cm_id, @@ -199,7 +257,7 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id, ucma_set_event_context(ctx, event, uevent); uevent->resp.event = event->event; uevent->resp.status = event->status; - if (cm_id->ps == RDMA_PS_UDP) + if (cm_id->ps == RDMA_PS_UDP || cm_id->ps == RDMA_PS_IPOIB) ucma_copy_ud_event(&uevent->resp.param.ud, &event->param.ud); else ucma_copy_conn_event(&uevent->resp.param.conn, @@ -290,6 +348,8 @@ static ssize_t ucma_get_event(struct ucma_file *file, const char __user *inbuf, list_del(&uevent->list); uevent->ctx->events_reported++; + if (uevent->mc) + uevent->mc->events_reported++; kfree(uevent); done: mutex_unlock(&file->mut); @@ -342,6 +402,19 @@ err1: return ret; } +static void ucma_cleanup_multicast(struct ucma_context *ctx) +{ + struct ucma_multicast *mc, *tmp; + + mutex_lock(&mut); + list_for_each_entry_safe(mc, tmp, &ctx->mc_list, list) { + list_del(&mc->list); + idr_remove(&multicast_idr, mc->id); + kfree(mc); + } + mutex_unlock(&mut); +} + static void ucma_cleanup_events(struct ucma_context *ctx) { struct ucma_event *uevent, *tmp; @@ -360,6 +433,19 @@ static void ucma_cleanup_events(struct ucma_context *ctx) } } +static void ucma_cleanup_mc_events(struct ucma_multicast *mc) +{ + struct ucma_event *uevent, *tmp; + + list_for_each_entry_safe(uevent, tmp, &mc->ctx->file->event_list, list) { + if (uevent->mc != mc) + continue; + + list_del(&uevent->list); + kfree(uevent); + } +} + static int ucma_free_ctx(struct ucma_context *ctx) { int events_reported; @@ -367,6 +453,8 @@ static int ucma_free_ctx(struct ucma_context *ctx) /* No new events will be generated after destroying the id. */ rdma_destroy_id(ctx->cm_id); + ucma_cleanup_multicast(ctx); + /* Cleanup events not yet reported to the user. */ mutex_lock(&ctx->file->mut); ucma_cleanup_events(ctx); @@ -731,6 +819,114 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf, return ret; } +static ssize_t ucma_join_multicast(struct ucma_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_join_mcast cmd; + struct rdma_ucm_create_id_resp resp; + struct ucma_context *ctx; + struct ucma_multicast *mc; + int ret; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + mutex_lock(&file->mut); + mc = ucma_alloc_multicast(ctx); + if (IS_ERR(mc)) { + ret = PTR_ERR(mc); + goto err1; + } + + mc->uid = cmd.uid; + memcpy(&mc->addr, &cmd.addr, sizeof cmd.addr); + ret = rdma_join_multicast(ctx->cm_id, &mc->addr, mc); + if (ret) + goto err2; + + resp.id = mc->id; + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) { + ret = -EFAULT; + goto err3; + } + + mutex_unlock(&file->mut); + ucma_put_ctx(ctx); + return 0; + +err3: + rdma_leave_multicast(ctx->cm_id, &mc->addr); + ucma_cleanup_mc_events(mc); +err2: + mutex_lock(&mut); + idr_remove(&multicast_idr, mc->id); + mutex_unlock(&mut); + list_del(&mc->list); + kfree(mc); +err1: + mutex_unlock(&file->mut); + ucma_put_ctx(ctx); + return ret; +} + +static ssize_t ucma_leave_multicast(struct ucma_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_destroy_id cmd; + struct rdma_ucm_destroy_id_resp resp; + struct ucma_multicast *mc; + int ret = 0; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + mutex_lock(&mut); + mc = idr_find(&multicast_idr, cmd.id); + if (!mc) + mc = ERR_PTR(-ENOENT); + else if (mc->ctx->file != file) + mc = ERR_PTR(-EINVAL); + else { + idr_remove(&multicast_idr, mc->id); + atomic_inc(&mc->ctx->ref); + } + mutex_unlock(&mut); + + if (IS_ERR(mc)) { + ret = PTR_ERR(mc); + goto out; + } + + rdma_leave_multicast(mc->ctx->cm_id, &mc->addr); + mutex_lock(&mc->ctx->file->mut); + ucma_cleanup_mc_events(mc); + list_del(&mc->list); + mutex_unlock(&mc->ctx->file->mut); + + ucma_put_ctx(mc->ctx); + resp.events_reported = mc->events_reported; + kfree(mc); + + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) + ret = -EFAULT; +out: + return ret; +} + static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, const char __user *inbuf, int in_len, int out_len) = { @@ -750,6 +946,8 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, [RDMA_USER_CM_CMD_GET_OPTION] = NULL, [RDMA_USER_CM_CMD_SET_OPTION] = NULL, [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify, + [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast, + [RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast, }; static ssize_t ucma_write(struct file *filp, const char __user *buf, diff --git a/drivers/infiniband/hw/cxgb3/cxio_dbg.c b/drivers/infiniband/hw/cxgb3/cxio_dbg.c index 5a7306f5efa..75f7b16a271 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_dbg.c +++ b/drivers/infiniband/hw/cxgb3/cxio_dbg.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 82fa7204198..114ac3b775d 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h index 1b97e80b878..8ab04a7c6f6 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.h +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.c b/drivers/infiniband/hw/cxgb3/cxio_resource.c index 997aa32cbf0..65bf577311a 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_resource.c +++ b/drivers/infiniband/hw/cxgb3/cxio_resource.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.h b/drivers/infiniband/hw/cxgb3/cxio_resource.h index a6bbe8370d8..a2703a3d882 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_resource.h +++ b/drivers/infiniband/hw/cxgb3/cxio_resource.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h index 103fc42d697..90d7b8972cb 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index 4611afa5222..0315c9d9fce 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch.h b/drivers/infiniband/hw/cxgb3/iwch.h index 6517ef85026..caf4e6007a4 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.h +++ b/drivers/infiniband/hw/cxgb3/iwch.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index a522b1baa3b..e5442e34b78 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h index 7c810d90427..0c6f281bd4a 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.h +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_cq.c b/drivers/infiniband/hw/cxgb3/iwch_cq.c index 98b3bdb5de9..d7624c170ee 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cq.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cq.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_ev.c b/drivers/infiniband/hw/cxgb3/iwch_ev.c index a6efa8fe15d..54362afbf72 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_ev.c +++ b/drivers/infiniband/hw/cxgb3/iwch_ev.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_mem.c b/drivers/infiniband/hw/cxgb3/iwch_mem.c index 2b6cd53bb3f..a6c2c4ba29e 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_mem.c +++ b/drivers/infiniband/hw/cxgb3/iwch_mem.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index 6861087d776..2aef122f995 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h index 61e3278fd7a..2af3e93b607 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.h +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index e066727504b..4dda2f6da2d 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -846,6 +845,8 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, break; case IWCH_QP_STATE_TERMINATE: qhp->attr.state = IWCH_QP_STATE_TERMINATE; + if (t3b_device(qhp->rhp)) + cxio_set_wq_in_error(&qhp->wq); if (!internal) terminate = 1; break; diff --git a/drivers/infiniband/hw/cxgb3/iwch_user.h b/drivers/infiniband/hw/cxgb3/iwch_user.h index c4e7fbea8bb..cb7086f558c 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_user.h +++ b/drivers/infiniband/hw/cxgb3/iwch_user.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/ehca/Kconfig b/drivers/infiniband/hw/ehca/Kconfig index 727b10d8968..1a854598e0e 100644 --- a/drivers/infiniband/hw/ehca/Kconfig +++ b/drivers/infiniband/hw/ehca/Kconfig @@ -7,11 +7,3 @@ config INFINIBAND_EHCA To compile the driver as a module, choose M here. The module will be called ib_ehca. -config INFINIBAND_EHCA_SCALING - bool "Scaling support (EXPERIMENTAL)" - depends on IBMEBUS && INFINIBAND_EHCA && HOTPLUG_CPU && EXPERIMENTAL - default y - ---help--- - eHCA scaling support schedules the CQ callbacks to different CPUs. - - To enable this feature choose Y here. diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index cf95ee474b0..40404c9e281 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -42,8 +42,6 @@ #ifndef __EHCA_CLASSES_H__ #define __EHCA_CLASSES_H__ -#include "ehca_classes.h" -#include "ipz_pt_fn.h" struct ehca_module; struct ehca_qp; @@ -54,14 +52,22 @@ struct ehca_mw; struct ehca_pd; struct ehca_av; +#include <rdma/ib_verbs.h> +#include <rdma/ib_user_verbs.h> + #ifdef CONFIG_PPC64 #include "ehca_classes_pSeries.h" #endif +#include "ipz_pt_fn.h" +#include "ehca_qes.h" +#include "ehca_irq.h" -#include <rdma/ib_verbs.h> -#include <rdma/ib_user_verbs.h> +#define EHCA_EQE_CACHE_SIZE 20 -#include "ehca_irq.h" +struct ehca_eqe_cache_entry { + struct ehca_eqe *eqe; + struct ehca_cq *cq; +}; struct ehca_eq { u32 length; @@ -74,6 +80,8 @@ struct ehca_eq { spinlock_t spinlock; struct tasklet_struct interrupt_task; u32 ist; + spinlock_t irq_spinlock; + struct ehca_eqe_cache_entry eqe_cache[EHCA_EQE_CACHE_SIZE]; }; struct ehca_sport { @@ -269,6 +277,7 @@ extern struct idr ehca_cq_idr; extern int ehca_static_rate; extern int ehca_port_act_time; extern int ehca_use_hp_mr; +extern int ehca_scaling_code; struct ipzu_queue_resp { u32 qe_size; /* queue entry size */ diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c index 24ceab0bae4..4961eb88827 100644 --- a/drivers/infiniband/hw/ehca/ehca_eq.c +++ b/drivers/infiniband/hw/ehca/ehca_eq.c @@ -61,6 +61,7 @@ int ehca_create_eq(struct ehca_shca *shca, struct ib_device *ib_dev = &shca->ib_device; spin_lock_init(&eq->spinlock); + spin_lock_init(&eq->irq_spinlock); eq->is_initialized = 0; if (type != EHCA_EQ && type != EHCA_NEQ) { diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c index b7be950ab47..30eb45df9f0 100644 --- a/drivers/infiniband/hw/ehca/ehca_hca.c +++ b/drivers/infiniband/hw/ehca/ehca_hca.c @@ -162,6 +162,9 @@ int ehca_query_port(struct ib_device *ibdev, props->active_width = IB_WIDTH_12X; props->active_speed = 0x1; + /* at the moment (logical) link state is always LINK_UP */ + props->phys_state = 0x5; + query_port1: ehca_free_fw_ctrlblock(rblock); diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index 6c4f9f91b15..3ec53c687d0 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -63,15 +63,11 @@ #define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63) #define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7) -#ifdef CONFIG_INFINIBAND_EHCA_SCALING - static void queue_comp_task(struct ehca_cq *__cq); static struct ehca_comp_pool* pool; static struct notifier_block comp_pool_callback_nb; -#endif - static inline void comp_event_callback(struct ehca_cq *cq) { if (!cq->ib_cq.comp_handler) @@ -206,7 +202,7 @@ static void qp_event_callback(struct ehca_shca *shca, } static void cq_event_callback(struct ehca_shca *shca, - u64 eqe) + u64 eqe) { struct ehca_cq *cq; unsigned long flags; @@ -318,7 +314,7 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe) "disruptive port %x configuration change", port); ehca_info(&shca->ib_device, - "port %x is inactive.", port); + "port %x is inactive.", port); event.device = &shca->ib_device; event.event = IB_EVENT_PORT_ERR; event.element.port_num = port; @@ -326,7 +322,7 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe) ib_dispatch_event(&event); ehca_info(&shca->ib_device, - "port %x is active.", port); + "port %x is active.", port); event.device = &shca->ib_device; event.event = IB_EVENT_PORT_ACTIVE; event.element.port_num = port; @@ -401,115 +397,170 @@ irqreturn_t ehca_interrupt_eq(int irq, void *dev_id) return IRQ_HANDLED; } -void ehca_tasklet_eq(unsigned long data) -{ - struct ehca_shca *shca = (struct ehca_shca*)data; - struct ehca_eqe *eqe; - int int_state; - int query_cnt = 0; - do { - eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq); +static inline void process_eqe(struct ehca_shca *shca, struct ehca_eqe *eqe) +{ + u64 eqe_value; + u32 token; + unsigned long flags; + struct ehca_cq *cq; + eqe_value = eqe->entry; + ehca_dbg(&shca->ib_device, "eqe_value=%lx", eqe_value); + if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) { + ehca_dbg(&shca->ib_device, "... completion event"); + token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value); + spin_lock_irqsave(&ehca_cq_idr_lock, flags); + cq = idr_find(&ehca_cq_idr, token); + if (cq == NULL) { + spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); + ehca_err(&shca->ib_device, + "Invalid eqe for non-existing cq token=%x", + token); + return; + } + reset_eq_pending(cq); + if (ehca_scaling_code) { + queue_comp_task(cq); + spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); + } else { + spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); + comp_event_callback(cq); + } + } else { + ehca_dbg(&shca->ib_device, + "Got non completion event"); + parse_identifier(shca, eqe_value); + } +} - if ((shca->hw_level >= 2) && eqe) - int_state = 1; - else - int_state = 0; - - while ((int_state == 1) || eqe) { - while (eqe) { - u64 eqe_value = eqe->entry; - - ehca_dbg(&shca->ib_device, - "eqe_value=%lx", eqe_value); - - /* TODO: better structure */ - if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, - eqe_value)) { - unsigned long flags; - u32 token; - struct ehca_cq *cq; - - ehca_dbg(&shca->ib_device, - "... completion event"); - token = - EHCA_BMASK_GET(EQE_CQ_TOKEN, - eqe_value); - spin_lock_irqsave(&ehca_cq_idr_lock, - flags); - cq = idr_find(&ehca_cq_idr, token); - - if (cq == NULL) { - spin_unlock_irqrestore(&ehca_cq_idr_lock, - flags); - break; - } - - reset_eq_pending(cq); -#ifdef CONFIG_INFINIBAND_EHCA_SCALING - queue_comp_task(cq); - spin_unlock_irqrestore(&ehca_cq_idr_lock, - flags); -#else - spin_unlock_irqrestore(&ehca_cq_idr_lock, - flags); - comp_event_callback(cq); -#endif - } else { - ehca_dbg(&shca->ib_device, - "... non completion event"); - parse_identifier(shca, eqe_value); - } - eqe = - (struct ehca_eqe *)ehca_poll_eq(shca, - &shca->eq); - } +void ehca_process_eq(struct ehca_shca *shca, int is_irq) +{ + struct ehca_eq *eq = &shca->eq; + struct ehca_eqe_cache_entry *eqe_cache = eq->eqe_cache; + u64 eqe_value; + unsigned long flags; + int eqe_cnt, i; + int eq_empty = 0; + + spin_lock_irqsave(&eq->irq_spinlock, flags); + if (is_irq) { + const int max_query_cnt = 100; + int query_cnt = 0; + int int_state = 1; + do { + int_state = hipz_h_query_int_state( + shca->ipz_hca_handle, eq->ist); + query_cnt++; + iosync(); + } while (int_state && query_cnt < max_query_cnt); + if (unlikely((query_cnt == max_query_cnt))) + ehca_dbg(&shca->ib_device, "int_state=%x query_cnt=%x", + int_state, query_cnt); + } - if (shca->hw_level >= 2) { - int_state = - hipz_h_query_int_state(shca->ipz_hca_handle, - shca->eq.ist); - query_cnt++; - iosync(); - if (query_cnt >= 100) { - query_cnt = 0; - int_state = 0; - } + /* read out all eqes */ + eqe_cnt = 0; + do { + u32 token; + eqe_cache[eqe_cnt].eqe = + (struct ehca_eqe *)ehca_poll_eq(shca, eq); + if (!eqe_cache[eqe_cnt].eqe) + break; + eqe_value = eqe_cache[eqe_cnt].eqe->entry; + if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) { + token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value); + spin_lock(&ehca_cq_idr_lock); + eqe_cache[eqe_cnt].cq = idr_find(&ehca_cq_idr, token); + if (!eqe_cache[eqe_cnt].cq) { + spin_unlock(&ehca_cq_idr_lock); + ehca_err(&shca->ib_device, + "Invalid eqe for non-existing cq " + "token=%x", token); + continue; } - eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq); - + spin_unlock(&ehca_cq_idr_lock); + } else + eqe_cache[eqe_cnt].cq = NULL; + eqe_cnt++; + } while (eqe_cnt < EHCA_EQE_CACHE_SIZE); + if (!eqe_cnt) { + if (is_irq) + ehca_dbg(&shca->ib_device, + "No eqe found for irq event"); + goto unlock_irq_spinlock; + } else if (!is_irq) + ehca_dbg(&shca->ib_device, "deadman found %x eqe", eqe_cnt); + if (unlikely(eqe_cnt == EHCA_EQE_CACHE_SIZE)) + ehca_dbg(&shca->ib_device, "too many eqes for one irq event"); + /* enable irq for new packets */ + for (i = 0; i < eqe_cnt; i++) { + if (eq->eqe_cache[i].cq) + reset_eq_pending(eq->eqe_cache[i].cq); + } + /* check eq */ + spin_lock(&eq->spinlock); + eq_empty = (!ipz_eqit_eq_peek_valid(&shca->eq.ipz_queue)); + spin_unlock(&eq->spinlock); + /* call completion handler for cached eqes */ + for (i = 0; i < eqe_cnt; i++) + if (eq->eqe_cache[i].cq) { + if (ehca_scaling_code) { + spin_lock(&ehca_cq_idr_lock); + queue_comp_task(eq->eqe_cache[i].cq); + spin_unlock(&ehca_cq_idr_lock); + } else + comp_event_callback(eq->eqe_cache[i].cq); + } else { + ehca_dbg(&shca->ib_device, "Got non completion event"); + parse_identifier(shca, eq->eqe_cache[i].eqe->entry); } - } while (int_state != 0); - - return; + /* poll eq if not empty */ + if (eq_empty) + goto unlock_irq_spinlock; + do { + struct ehca_eqe *eqe; + eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq); + if (!eqe) + break; + process_eqe(shca, eqe); + eqe_cnt++; + } while (1); + +unlock_irq_spinlock: + spin_unlock_irqrestore(&eq->irq_spinlock, flags); } -#ifdef CONFIG_INFINIBAND_EHCA_SCALING +void ehca_tasklet_eq(unsigned long data) +{ + ehca_process_eq((struct ehca_shca*)data, 1); +} static inline int find_next_online_cpu(struct ehca_comp_pool* pool) { - unsigned long flags_last_cpu; + int cpu; + unsigned long flags; + WARN_ON_ONCE(!in_interrupt()); if (ehca_debug_level) ehca_dmp(&cpu_online_map, sizeof(cpumask_t), ""); - spin_lock_irqsave(&pool->last_cpu_lock, flags_last_cpu); - pool->last_cpu = next_cpu(pool->last_cpu, cpu_online_map); - if (pool->last_cpu == NR_CPUS) - pool->last_cpu = first_cpu(cpu_online_map); - spin_unlock_irqrestore(&pool->last_cpu_lock, flags_last_cpu); + spin_lock_irqsave(&pool->last_cpu_lock, flags); + cpu = next_cpu(pool->last_cpu, cpu_online_map); + if (cpu == NR_CPUS) + cpu = first_cpu(cpu_online_map); + pool->last_cpu = cpu; + spin_unlock_irqrestore(&pool->last_cpu_lock, flags); - return pool->last_cpu; + return cpu; } static void __queue_comp_task(struct ehca_cq *__cq, struct ehca_cpu_comp_task *cct) { - unsigned long flags_cct; - unsigned long flags_cq; + unsigned long flags; - spin_lock_irqsave(&cct->task_lock, flags_cct); - spin_lock_irqsave(&__cq->task_lock, flags_cq); + spin_lock_irqsave(&cct->task_lock, flags); + spin_lock(&__cq->task_lock); if (__cq->nr_callbacks == 0) { __cq->nr_callbacks++; @@ -520,8 +571,8 @@ static void __queue_comp_task(struct ehca_cq *__cq, else __cq->nr_callbacks++; - spin_unlock_irqrestore(&__cq->task_lock, flags_cq); - spin_unlock_irqrestore(&cct->task_lock, flags_cct); + spin_unlock(&__cq->task_lock); + spin_unlock_irqrestore(&cct->task_lock, flags); } static void queue_comp_task(struct ehca_cq *__cq) @@ -532,69 +583,69 @@ static void queue_comp_task(struct ehca_cq *__cq) cpu = get_cpu(); cpu_id = find_next_online_cpu(pool); - BUG_ON(!cpu_online(cpu_id)); cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id); + BUG_ON(!cct); if (cct->cq_jobs > 0) { cpu_id = find_next_online_cpu(pool); cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id); + BUG_ON(!cct); } __queue_comp_task(__cq, cct); - - put_cpu(); - - return; } static void run_comp_task(struct ehca_cpu_comp_task* cct) { struct ehca_cq *cq; - unsigned long flags_cct; - unsigned long flags_cq; + unsigned long flags; - spin_lock_irqsave(&cct->task_lock, flags_cct); + spin_lock_irqsave(&cct->task_lock, flags); while (!list_empty(&cct->cq_list)) { cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); - spin_unlock_irqrestore(&cct->task_lock, flags_cct); + spin_unlock_irqrestore(&cct->task_lock, flags); comp_event_callback(cq); - spin_lock_irqsave(&cct->task_lock, flags_cct); + spin_lock_irqsave(&cct->task_lock, flags); - spin_lock_irqsave(&cq->task_lock, flags_cq); + spin_lock(&cq->task_lock); cq->nr_callbacks--; if (cq->nr_callbacks == 0) { list_del_init(cct->cq_list.next); cct->cq_jobs--; } - spin_unlock_irqrestore(&cq->task_lock, flags_cq); - + spin_unlock(&cq->task_lock); } - spin_unlock_irqrestore(&cct->task_lock, flags_cct); - - return; + spin_unlock_irqrestore(&cct->task_lock, flags); } static int comp_task(void *__cct) { struct ehca_cpu_comp_task* cct = __cct; + int cql_empty; DECLARE_WAITQUEUE(wait, current); set_current_state(TASK_INTERRUPTIBLE); while(!kthread_should_stop()) { add_wait_queue(&cct->wait_queue, &wait); - if (list_empty(&cct->cq_list)) + spin_lock_irq(&cct->task_lock); + cql_empty = list_empty(&cct->cq_list); + spin_unlock_irq(&cct->task_lock); + if (cql_empty) schedule(); else __set_current_state(TASK_RUNNING); remove_wait_queue(&cct->wait_queue, &wait); - if (!list_empty(&cct->cq_list)) + spin_lock_irq(&cct->task_lock); + cql_empty = list_empty(&cct->cq_list); + spin_unlock_irq(&cct->task_lock); + if (!cql_empty) run_comp_task(__cct); set_current_state(TASK_INTERRUPTIBLE); @@ -637,8 +688,6 @@ static void destroy_comp_task(struct ehca_comp_pool *pool, if (task) kthread_stop(task); - - return; } static void take_over_work(struct ehca_comp_pool *pool, @@ -654,11 +703,11 @@ static void take_over_work(struct ehca_comp_pool *pool, list_splice_init(&cct->cq_list, &list); while(!list_empty(&list)) { - cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); + cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); - list_del(&cq->entry); - __queue_comp_task(cq, per_cpu_ptr(pool->cpu_comp_tasks, - smp_processor_id())); + list_del(&cq->entry); + __queue_comp_task(cq, per_cpu_ptr(pool->cpu_comp_tasks, + smp_processor_id())); } spin_unlock_irqrestore(&cct->task_lock, flags_cct); @@ -708,14 +757,14 @@ static int comp_pool_callback(struct notifier_block *nfb, return NOTIFY_OK; } -#endif - int ehca_create_comp_pool(void) { -#ifdef CONFIG_INFINIBAND_EHCA_SCALING int cpu; struct task_struct *task; + if (!ehca_scaling_code) + return 0; + pool = kzalloc(sizeof(struct ehca_comp_pool), GFP_KERNEL); if (pool == NULL) return -ENOMEM; @@ -740,16 +789,19 @@ int ehca_create_comp_pool(void) comp_pool_callback_nb.notifier_call = comp_pool_callback; comp_pool_callback_nb.priority =0; register_cpu_notifier(&comp_pool_callback_nb); -#endif + + printk(KERN_INFO "eHCA scaling code enabled\n"); return 0; } void ehca_destroy_comp_pool(void) { -#ifdef CONFIG_INFINIBAND_EHCA_SCALING int i; + if (!ehca_scaling_code) + return; + unregister_cpu_notifier(&comp_pool_callback_nb); for (i = 0; i < NR_CPUS; i++) { @@ -758,7 +810,4 @@ void ehca_destroy_comp_pool(void) } free_percpu(pool->cpu_comp_tasks); kfree(pool); -#endif - - return; } diff --git a/drivers/infiniband/hw/ehca/ehca_irq.h b/drivers/infiniband/hw/ehca/ehca_irq.h index be579cc0adf..6ed06ee033e 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.h +++ b/drivers/infiniband/hw/ehca/ehca_irq.h @@ -56,6 +56,7 @@ void ehca_tasklet_neq(unsigned long data); irqreturn_t ehca_interrupt_eq(int irq, void *dev_id); void ehca_tasklet_eq(unsigned long data); +void ehca_process_eq(struct ehca_shca *shca, int is_irq); struct ehca_cpu_comp_task { wait_queue_head_t wait_queue; diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 1155bcf4821..c1835121a82 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -52,7 +52,7 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>"); MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver"); -MODULE_VERSION("SVNEHCA_0020"); +MODULE_VERSION("SVNEHCA_0021"); int ehca_open_aqp1 = 0; int ehca_debug_level = 0; @@ -62,6 +62,7 @@ int ehca_use_hp_mr = 0; int ehca_port_act_time = 30; int ehca_poll_all_eqs = 1; int ehca_static_rate = -1; +int ehca_scaling_code = 1; module_param_named(open_aqp1, ehca_open_aqp1, int, 0); module_param_named(debug_level, ehca_debug_level, int, 0); @@ -71,6 +72,7 @@ module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0); module_param_named(port_act_time, ehca_port_act_time, int, 0); module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0); module_param_named(static_rate, ehca_static_rate, int, 0); +module_param_named(scaling_code, ehca_scaling_code, int, 0); MODULE_PARM_DESC(open_aqp1, "AQP1 on startup (0: no (default), 1: yes)"); @@ -91,6 +93,8 @@ MODULE_PARM_DESC(poll_all_eqs, " (0: no, 1: yes (default))"); MODULE_PARM_DESC(static_rate, "set permanent static rate (default: disabled)"); +MODULE_PARM_DESC(scaling_code, + "set scaling code (0: disabled, 1: enabled/default)"); spinlock_t ehca_qp_idr_lock; spinlock_t ehca_cq_idr_lock; @@ -432,8 +436,8 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport) static ssize_t ehca_show_debug_level(struct device_driver *ddp, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", - ehca_debug_level); + return snprintf(buf, PAGE_SIZE, "%d\n", + ehca_debug_level); } static ssize_t ehca_store_debug_level(struct device_driver *ddp, @@ -778,8 +782,24 @@ void ehca_poll_eqs(unsigned long data) spin_lock(&shca_list_lock); list_for_each_entry(shca, &shca_list, shca_list) { - if (shca->eq.is_initialized) - ehca_tasklet_eq((unsigned long)(void*)shca); + if (shca->eq.is_initialized) { + /* call deadman proc only if eq ptr does not change */ + struct ehca_eq *eq = &shca->eq; + int max = 3; + volatile u64 q_ofs, q_ofs2; + u64 flags; + spin_lock_irqsave(&eq->spinlock, flags); + q_ofs = eq->ipz_queue.current_q_offset; + spin_unlock_irqrestore(&eq->spinlock, flags); + do { + spin_lock_irqsave(&eq->spinlock, flags); + q_ofs2 = eq->ipz_queue.current_q_offset; + spin_unlock_irqrestore(&eq->spinlock, flags); + max--; + } while (q_ofs == q_ofs2 && max > 0); + if (q_ofs == q_ofs2) + ehca_process_eq(shca, 0); + } } mod_timer(&poll_eqs_timer, jiffies + HZ); spin_unlock(&shca_list_lock); @@ -790,7 +810,7 @@ int __init ehca_module_init(void) int ret; printk(KERN_INFO "eHCA Infiniband Device Driver " - "(Rel.: SVNEHCA_0020)\n"); + "(Rel.: SVNEHCA_0021)\n"); idr_init(&ehca_qp_idr); idr_init(&ehca_cq_idr); spin_lock_init(&ehca_qp_idr_lock); diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h index dc3bda2634b..8199c45768a 100644 --- a/drivers/infiniband/hw/ehca/ipz_pt_fn.h +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h @@ -79,7 +79,7 @@ static inline void *ipz_qeit_calc(struct ipz_queue *queue, u64 q_offset) if (q_offset >= queue->queue_length) return NULL; current_page = (queue->queue_pages)[q_offset >> EHCA_PAGESHIFT]; - return ¤t_page->entries[q_offset & (EHCA_PAGESIZE - 1)]; + return ¤t_page->entries[q_offset & (EHCA_PAGESIZE - 1)]; } /* @@ -247,6 +247,15 @@ static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue) return ret; } +static inline void *ipz_eqit_eq_peek_valid(struct ipz_queue *queue) +{ + void *ret = ipz_qeit_get(queue); + u32 qe = *(u8 *) ret; + if ((qe >> 7) != (queue->toggle_state & 1)) + return NULL; + return ret; +} + /* returns address (GX) of first queue entry */ static inline u64 ipz_qpt_get_firstpage(struct ipz_qpt *qpt) { diff --git a/drivers/infiniband/hw/ipath/ipath_dma.c b/drivers/infiniband/hw/ipath/ipath_dma.c index 6e0f2b8918c..f6f94904082 100644 --- a/drivers/infiniband/hw/ipath/ipath_dma.c +++ b/drivers/infiniband/hw/ipath/ipath_dma.c @@ -96,8 +96,8 @@ static void ipath_dma_unmap_page(struct ib_device *dev, BUG_ON(!valid_dma_direction(direction)); } -int ipath_map_sg(struct ib_device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) +static int ipath_map_sg(struct ib_device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) { u64 addr; int i; diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 0b9d053a599..48f7c65e9ae 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -175,7 +175,9 @@ struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, if (!ret) { ++chunk->npages; - if (!coherent && chunk->npages == MTHCA_ICM_CHUNK_LEN) { + if (coherent) + ++chunk->nsg; + else if (chunk->npages == MTHCA_ICM_CHUNK_LEN) { chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 224c93dd29e..71dc84bd425 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -573,6 +573,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, goto out; } + if (cur_state == new_state && cur_state == IB_QPS_RESET) { + err = 0; + goto out; + } + if ((attr_mask & IB_QP_PKEY_INDEX) && attr->pkey_index >= dev->limits.pkey_table_len) { mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n", diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 2d483874a58..4d59682f7d4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -145,7 +145,7 @@ partial_error: for (; i >= 0; --i) ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE); - kfree_skb(skb); + dev_kfree_skb_any(skb); return -ENOMEM; } @@ -1138,7 +1138,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, return -EINVAL; } -static DEVICE_ATTR(mode, S_IWUGO | S_IRUGO, show_mode, set_mode); +static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, show_mode, set_mode); int ipoib_cm_add_mode_attr(struct net_device *dev) { diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index fea737f520f..b303ce6bc21 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -60,14 +60,11 @@ static DEFINE_MUTEX(mcast_mutex); /* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */ struct ipoib_mcast { struct ib_sa_mcmember_rec mcmember; + struct ib_sa_multicast *mc; struct ipoib_ah *ah; struct rb_node rb_node; struct list_head list; - struct completion done; - - int query_id; - struct ib_sa_query *query; unsigned long created; unsigned long backoff; @@ -299,18 +296,22 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, return 0; } -static void +static int ipoib_mcast_sendonly_join_complete(int status, - struct ib_sa_mcmember_rec *mcmember, - void *mcast_ptr) + struct ib_sa_multicast *multicast) { - struct ipoib_mcast *mcast = mcast_ptr; + struct ipoib_mcast *mcast = multicast->context; struct net_device *dev = mcast->dev; struct ipoib_dev_priv *priv = netdev_priv(dev); + /* We trap for port events ourselves. */ + if (status == -ENETRESET) + return 0; + if (!status) - ipoib_mcast_join_finish(mcast, mcmember); - else { + status = ipoib_mcast_join_finish(mcast, &multicast->rec); + + if (status) { if (mcast->logcount++ < 20) ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for " IPOIB_GID_FMT ", status %d\n", @@ -325,11 +326,10 @@ ipoib_mcast_sendonly_join_complete(int status, spin_unlock_irq(&priv->tx_lock); /* Clear the busy flag so we try again */ - clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); - mcast->query = NULL; + status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, + &mcast->flags); } - - complete(&mcast->done); + return status; } static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) @@ -359,35 +359,33 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) rec.port_gid = priv->local_gid; rec.pkey = cpu_to_be16(priv->pkey); - init_completion(&mcast->done); - - ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port, &rec, - IB_SA_MCMEMBER_REC_MGID | - IB_SA_MCMEMBER_REC_PORT_GID | - IB_SA_MCMEMBER_REC_PKEY | - IB_SA_MCMEMBER_REC_JOIN_STATE, - 1000, GFP_ATOMIC, - ipoib_mcast_sendonly_join_complete, - mcast, &mcast->query); - if (ret < 0) { - ipoib_warn(priv, "ib_sa_mcmember_rec_set failed (ret = %d)\n", + mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, + priv->port, &rec, + IB_SA_MCMEMBER_REC_MGID | + IB_SA_MCMEMBER_REC_PORT_GID | + IB_SA_MCMEMBER_REC_PKEY | + IB_SA_MCMEMBER_REC_JOIN_STATE, + GFP_ATOMIC, + ipoib_mcast_sendonly_join_complete, + mcast); + if (IS_ERR(mcast->mc)) { + ret = PTR_ERR(mcast->mc); + clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + ipoib_warn(priv, "ib_sa_join_multicast failed (ret = %d)\n", ret); } else { ipoib_dbg_mcast(priv, "no multicast record for " IPOIB_GID_FMT ", starting join\n", IPOIB_GID_ARG(mcast->mcmember.mgid)); - - mcast->query_id = ret; } return ret; } -static void ipoib_mcast_join_complete(int status, - struct ib_sa_mcmember_rec *mcmember, - void *mcast_ptr) +static int ipoib_mcast_join_complete(int status, + struct ib_sa_multicast *multicast) { - struct ipoib_mcast *mcast = mcast_ptr; + struct ipoib_mcast *mcast = multicast->context; struct net_device *dev = mcast->dev; struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -395,24 +393,25 @@ static void ipoib_mcast_join_complete(int status, " (status %d)\n", IPOIB_GID_ARG(mcast->mcmember.mgid), status); - if (!status && !ipoib_mcast_join_finish(mcast, mcmember)) { + /* We trap for port events ourselves. */ + if (status == -ENETRESET) + return 0; + + if (!status) + status = ipoib_mcast_join_finish(mcast, &multicast->rec); + + if (!status) { mcast->backoff = 1; mutex_lock(&mcast_mutex); if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) queue_delayed_work(ipoib_workqueue, &priv->mcast_task, 0); mutex_unlock(&mcast_mutex); - complete(&mcast->done); - return; - } - - if (status == -EINTR) { - complete(&mcast->done); - return; + return 0; } - if (status && mcast->logcount++ < 20) { - if (status == -ETIMEDOUT || status == -EINTR) { + if (mcast->logcount++ < 20) { + if (status == -ETIMEDOUT) { ipoib_dbg_mcast(priv, "multicast join failed for " IPOIB_GID_FMT ", status %d\n", IPOIB_GID_ARG(mcast->mcmember.mgid), @@ -429,24 +428,18 @@ static void ipoib_mcast_join_complete(int status, if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS; - mutex_lock(&mcast_mutex); + /* Clear the busy flag so we try again */ + status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + mutex_lock(&mcast_mutex); spin_lock_irq(&priv->lock); - mcast->query = NULL; - - if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) { - if (status == -ETIMEDOUT) - queue_delayed_work(ipoib_workqueue, &priv->mcast_task, - 0); - else - queue_delayed_work(ipoib_workqueue, &priv->mcast_task, - mcast->backoff * HZ); - } else - complete(&mcast->done); + if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) + queue_delayed_work(ipoib_workqueue, &priv->mcast_task, + mcast->backoff * HZ); spin_unlock_irq(&priv->lock); mutex_unlock(&mcast_mutex); - return; + return status; } static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, @@ -495,15 +488,14 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, rec.hop_limit = priv->broadcast->mcmember.hop_limit; } - init_completion(&mcast->done); - - ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port, - &rec, comp_mask, mcast->backoff * 1000, - GFP_ATOMIC, ipoib_mcast_join_complete, - mcast, &mcast->query); - - if (ret < 0) { - ipoib_warn(priv, "ib_sa_mcmember_rec_set failed, status %d\n", ret); + set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port, + &rec, comp_mask, GFP_KERNEL, + ipoib_mcast_join_complete, mcast); + if (IS_ERR(mcast->mc)) { + clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + ret = PTR_ERR(mcast->mc); + ipoib_warn(priv, "ib_sa_join_multicast failed, status %d\n", ret); mcast->backoff *= 2; if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) @@ -515,8 +507,7 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, &priv->mcast_task, mcast->backoff * HZ); mutex_unlock(&mcast_mutex); - } else - mcast->query_id = ret; + } } void ipoib_mcast_join_task(struct work_struct *work) @@ -541,7 +532,7 @@ void ipoib_mcast_join_task(struct work_struct *work) priv->local_rate = attr.active_speed * ib_width_enum_to_int(attr.active_width); } else - ipoib_warn(priv, "ib_query_port failed\n"); + ipoib_warn(priv, "ib_query_port failed\n"); } if (!priv->broadcast) { @@ -568,7 +559,8 @@ void ipoib_mcast_join_task(struct work_struct *work) } if (!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { - ipoib_mcast_join(dev, priv->broadcast, 0); + if (!test_bit(IPOIB_MCAST_FLAG_BUSY, &priv->broadcast->flags)) + ipoib_mcast_join(dev, priv->broadcast, 0); return; } @@ -625,26 +617,9 @@ int ipoib_mcast_start_thread(struct net_device *dev) return 0; } -static void wait_for_mcast_join(struct ipoib_dev_priv *priv, - struct ipoib_mcast *mcast) -{ - spin_lock_irq(&priv->lock); - if (mcast && mcast->query) { - ib_sa_cancel_query(mcast->query_id, mcast->query); - mcast->query = NULL; - spin_unlock_irq(&priv->lock); - ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); - wait_for_completion(&mcast->done); - } - else - spin_unlock_irq(&priv->lock); -} - int ipoib_mcast_stop_thread(struct net_device *dev, int flush) { struct ipoib_dev_priv *priv = netdev_priv(dev); - struct ipoib_mcast *mcast; ipoib_dbg_mcast(priv, "stopping multicast thread\n"); @@ -660,52 +635,27 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush) if (flush) flush_workqueue(ipoib_workqueue); - wait_for_mcast_join(priv, priv->broadcast); - - list_for_each_entry(mcast, &priv->multicast_list, list) - wait_for_mcast_join(priv, mcast); - return 0; } static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast) { struct ipoib_dev_priv *priv = netdev_priv(dev); - struct ib_sa_mcmember_rec rec = { - .join_state = 1 - }; int ret = 0; - if (!test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) - return 0; - - ipoib_dbg_mcast(priv, "leaving MGID " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); - - rec.mgid = mcast->mcmember.mgid; - rec.port_gid = priv->local_gid; - rec.pkey = cpu_to_be16(priv->pkey); + if (test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { + ipoib_dbg_mcast(priv, "leaving MGID " IPOIB_GID_FMT "\n", + IPOIB_GID_ARG(mcast->mcmember.mgid)); - /* Remove ourselves from the multicast group */ - ret = ipoib_mcast_detach(dev, be16_to_cpu(mcast->mcmember.mlid), - &mcast->mcmember.mgid); - if (ret) - ipoib_warn(priv, "ipoib_mcast_detach failed (result = %d)\n", ret); + /* Remove ourselves from the multicast group */ + ret = ipoib_mcast_detach(dev, be16_to_cpu(mcast->mcmember.mlid), + &mcast->mcmember.mgid); + if (ret) + ipoib_warn(priv, "ipoib_mcast_detach failed (result = %d)\n", ret); + } - /* - * Just make one shot at leaving and don't wait for a reply; - * if we fail, too bad. - */ - ret = ib_sa_mcmember_rec_delete(&ipoib_sa_client, priv->ca, priv->port, &rec, - IB_SA_MCMEMBER_REC_MGID | - IB_SA_MCMEMBER_REC_PORT_GID | - IB_SA_MCMEMBER_REC_PKEY | - IB_SA_MCMEMBER_REC_JOIN_STATE, - 0, GFP_ATOMIC, NULL, - mcast, &mcast->query); - if (ret < 0) - ipoib_warn(priv, "ib_sa_mcmember_rec_delete failed " - "for leave (result = %d)\n", ret); + if (test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) + ib_sa_free_multicast(mcast->mc); return 0; } @@ -758,7 +708,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) dev_kfree_skb_any(skb); } - if (mcast->query) + if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) ipoib_dbg_mcast(priv, "no address vector, " "but multicast join already started\n"); else if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) @@ -916,7 +866,6 @@ void ipoib_mcast_restart_task(struct work_struct *work) /* We have to cancel outside of the spinlock */ list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { - wait_for_mcast_join(priv, mcast); ipoib_mcast_leave(mcast->dev, mcast); ipoib_mcast_free(mcast); } diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index bedae4ad3f7..80b199fa0aa 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -107,4 +107,19 @@ config MSI_LAPTOP If you have an MSI S270 laptop, say Y or M here. +config SONY_LAPTOP + tristate "Sony Laptop Extras" + depends on X86 && ACPI + select BACKLIGHT_CLASS_DEVICE + ---help--- + This mini-driver drives the SNC device present in the ACPI BIOS of + the Sony Vaio laptops. + + It gives access to some extra laptop functionalities. In its current + form, this driver let the user set or query the screen brightness + through the backlight subsystem and remove/apply power to some + devices. + + Read <file:Documentation/sony-laptop.txt> for more information. + endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 35da53c409c..7793ccd7904 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_SGI_IOC4) += ioc4.o +obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index 861c39935f9..e4e2b707a35 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c @@ -1088,11 +1088,6 @@ static int __init asus_laptop_init(void) if (acpi_disabled) return -ENODEV; - if (!acpi_specific_hotkey_enabled) { - printk(ASUS_ERR "Using generic hotkey driver\n"); - return -ENODEV; - } - result = acpi_bus_register_driver(&asus_hotk_driver); if (result < 0) return result; diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c new file mode 100644 index 00000000000..cabbed0015e --- /dev/null +++ b/drivers/misc/sony-laptop.c @@ -0,0 +1,562 @@ +/* + * ACPI Sony Notebook Control Driver (SNC) + * + * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net> + * Copyright (C) 2007 Mattia Dongili <malattia@linux.it> + * + * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c + * which are copyrighted by their respective authors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/backlight.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <acpi/acpi_drivers.h> +#include <acpi/acpi_bus.h> +#include <asm/uaccess.h> + +#define ACPI_SNC_CLASS "sony" +#define ACPI_SNC_HID "SNY5001" +#define ACPI_SNC_DRIVER_NAME "ACPI Sony Notebook Control Driver v0.4" + +/* the device uses 1-based values, while the backlight subsystem uses + 0-based values */ +#define SONY_MAX_BRIGHTNESS 8 + +#define LOG_PFX KERN_WARNING "sony-laptop: " + +MODULE_AUTHOR("Stelian Pop, Mattia Dongili"); +MODULE_DESCRIPTION(ACPI_SNC_DRIVER_NAME); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help " + "the development of this driver"); + +static ssize_t sony_acpi_show(struct device *, struct device_attribute *, + char *); +static ssize_t sony_acpi_store(struct device *, struct device_attribute *, + const char *, size_t); +static int boolean_validate(const int, const int); +static int brightness_default_validate(const int, const int); + +#define SNC_VALIDATE_IN 0 +#define SNC_VALIDATE_OUT 1 + +struct sony_acpi_value { + char *name; /* name of the entry */ + char **acpiget; /* names of the ACPI get function */ + char **acpiset; /* names of the ACPI set function */ + int (*validate)(const int, const int); /* input/output validation */ + int value; /* current setting */ + int valid; /* Has ever been set */ + int debug; /* active only in debug mode ? */ + struct device_attribute devattr; /* sysfs atribute */ +}; + +#define HANDLE_NAMES(_name, _values...) \ + static char *snc_##_name[] = { _values, NULL } + +#define SONY_ACPI_VALUE(_name, _getters, _setters, _validate, _debug) \ + { \ + .name = __stringify(_name), \ + .acpiget = _getters, \ + .acpiset = _setters, \ + .validate = _validate, \ + .debug = _debug, \ + .devattr = __ATTR(_name, 0, sony_acpi_show, sony_acpi_store), \ + } + +#define SONY_ACPI_VALUE_NULL { .name = NULL } + +HANDLE_NAMES(fnkey_get, "GHKE"); + +HANDLE_NAMES(brightness_def_get, "GPBR"); +HANDLE_NAMES(brightness_def_set, "SPBR"); + +HANDLE_NAMES(cdpower_get, "GCDP"); +HANDLE_NAMES(cdpower_set, "SCDP", "CDPW"); + +HANDLE_NAMES(audiopower_get, "GAZP"); +HANDLE_NAMES(audiopower_set, "AZPW"); + +HANDLE_NAMES(lanpower_get, "GLNP"); +HANDLE_NAMES(lanpower_set, "LNPW"); + +HANDLE_NAMES(PID_get, "GPID"); + +HANDLE_NAMES(CTR_get, "GCTR"); +HANDLE_NAMES(CTR_set, "SCTR"); + +HANDLE_NAMES(PCR_get, "GPCR"); +HANDLE_NAMES(PCR_set, "SPCR"); + +HANDLE_NAMES(CMI_get, "GCMI"); +HANDLE_NAMES(CMI_set, "SCMI"); + +static struct sony_acpi_value sony_acpi_values[] = { + SONY_ACPI_VALUE(brightness_default, snc_brightness_def_get, + snc_brightness_def_set, brightness_default_validate, 0), + SONY_ACPI_VALUE(fnkey, snc_fnkey_get, NULL, NULL, 0), + SONY_ACPI_VALUE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0), + SONY_ACPI_VALUE(audiopower, snc_audiopower_get, snc_audiopower_set, + boolean_validate, 0), + SONY_ACPI_VALUE(lanpower, snc_lanpower_get, snc_lanpower_set, + boolean_validate, 1), + /* unknown methods */ + SONY_ACPI_VALUE(PID, snc_PID_get, NULL, NULL, 1), + SONY_ACPI_VALUE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), + SONY_ACPI_VALUE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1), + SONY_ACPI_VALUE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1), + SONY_ACPI_VALUE_NULL +}; + +static acpi_handle sony_acpi_handle; +static struct acpi_device *sony_acpi_acpi_device = NULL; + +/* + * acpi_evaluate_object wrappers + */ +static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) +{ + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, name, NULL, &output); + if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) { + *result = out_obj.integer.value; + return 0; + } + + printk(LOG_PFX "acpi_callreadfunc failed\n"); + + return -1; +} + +static int acpi_callsetfunc(acpi_handle handle, char *name, int value, + int *result) +{ + struct acpi_object_list params; + union acpi_object in_obj; + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = value; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, name, ¶ms, &output); + if (status == AE_OK) { + if (result != NULL) { + if (out_obj.type != ACPI_TYPE_INTEGER) { + printk(LOG_PFX "acpi_evaluate_object bad " + "return type\n"); + return -1; + } + *result = out_obj.integer.value; + } + return 0; + } + + printk(LOG_PFX "acpi_evaluate_object failed\n"); + + return -1; +} + +/* + * sony_acpi_values input/output validate functions + */ + +/* brightness_default_validate: + * + * manipulate input output values to keep consistency with the + * backlight framework for which brightness values are 0-based. + */ +static int brightness_default_validate(const int direction, const int value) +{ + switch (direction) { + case SNC_VALIDATE_OUT: + return value - 1; + case SNC_VALIDATE_IN: + if (value >= 0 && value < SONY_MAX_BRIGHTNESS) + return value + 1; + } + return -EINVAL; +} + +/* boolean_validate: + * + * on input validate boolean values 0/1, on output just pass the + * received value. + */ +static int boolean_validate(const int direction, const int value) +{ + if (direction == SNC_VALIDATE_IN) { + if (value != 0 && value != 1) + return -EINVAL; + } + return value; +} + +/* + * Sysfs show/store common to all sony_acpi_values + */ +static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr, + char *buffer) +{ + int value; + struct sony_acpi_value *item = + container_of(attr, struct sony_acpi_value, devattr); + + if (!*item->acpiget) + return -EIO; + + if (acpi_callgetfunc(sony_acpi_handle, *item->acpiget, &value) < 0) + return -EIO; + + if (item->validate) + value = item->validate(SNC_VALIDATE_OUT, value); + + return snprintf(buffer, PAGE_SIZE, "%d\n", value); +} + +static ssize_t sony_acpi_store(struct device *dev, + struct device_attribute *attr, + const char *buffer, size_t count) +{ + int value; + struct sony_acpi_value *item = + container_of(attr, struct sony_acpi_value, devattr); + + if (!item->acpiset) + return -EIO; + + if (count > 31) + return -EINVAL; + + value = simple_strtoul(buffer, NULL, 10); + + if (item->validate) + value = item->validate(SNC_VALIDATE_IN, value); + + if (value < 0) + return value; + + if (acpi_callsetfunc(sony_acpi_handle, *item->acpiset, value, NULL) < 0) + return -EIO; + item->value = value; + item->valid = 1; + return count; +} + +/* + * Platform device + */ +static struct platform_driver sncpf_driver = { + .driver = { + .name = "sony-laptop", + .owner = THIS_MODULE, + } +}; +static struct platform_device *sncpf_device; + +static int sony_snc_pf_add(void) +{ + acpi_handle handle; + struct sony_acpi_value *item; + int ret = 0; + + ret = platform_driver_register(&sncpf_driver); + if (ret) + goto out; + + sncpf_device = platform_device_alloc("sony-laptop", -1); + if (!sncpf_device) { + ret = -ENOMEM; + goto out_platform_registered; + } + + ret = platform_device_add(sncpf_device); + if (ret) + goto out_platform_alloced; + + for (item = sony_acpi_values; item->name; ++item) { + + if (!debug && item->debug) + continue; + + /* find the available acpiget as described in the DSDT */ + for (; item->acpiget && *item->acpiget; ++item->acpiget) { + if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, + *item->acpiget, + &handle))) { + if (debug) + printk(LOG_PFX "Found %s getter: %s\n", + item->name, *item->acpiget); + item->devattr.attr.mode |= S_IRUGO; + break; + } + } + + /* find the available acpiset as described in the DSDT */ + for (; item->acpiset && *item->acpiset; ++item->acpiset) { + if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, + *item->acpiset, + &handle))) { + if (debug) + printk(LOG_PFX "Found %s setter: %s\n", + item->name, *item->acpiset); + item->devattr.attr.mode |= S_IWUSR; + break; + } + } + + if (item->devattr.attr.mode != 0) { + ret = + device_create_file(&sncpf_device->dev, + &item->devattr); + if (ret) + goto out_sysfs; + } + } + + return 0; + + out_sysfs: + for (item = sony_acpi_values; item->name; ++item) { + device_remove_file(&sncpf_device->dev, &item->devattr); + } + platform_device_del(sncpf_device); + out_platform_alloced: + platform_device_put(sncpf_device); + out_platform_registered: + platform_driver_unregister(&sncpf_driver); + out: + return ret; +} + +static void sony_snc_pf_remove(void) +{ + struct sony_acpi_value *item; + + for (item = sony_acpi_values; item->name; ++item) { + device_remove_file(&sncpf_device->dev, &item->devattr); + } + + platform_device_del(sncpf_device); + platform_device_put(sncpf_device); + platform_driver_unregister(&sncpf_driver); +} + +/* + * Backlight device + */ +static int sony_backlight_update_status(struct backlight_device *bd) +{ + return acpi_callsetfunc(sony_acpi_handle, "SBRT", + bd->props->brightness + 1, NULL); +} + +static int sony_backlight_get_brightness(struct backlight_device *bd) +{ + int value; + + if (acpi_callgetfunc(sony_acpi_handle, "GBRT", &value)) + return 0; + /* brightness levels are 1-based, while backlight ones are 0-based */ + return value - 1; +} + +static struct backlight_device *sony_backlight_device; +static struct backlight_properties sony_backlight_properties = { + .owner = THIS_MODULE, + .update_status = sony_backlight_update_status, + .get_brightness = sony_backlight_get_brightness, + .max_brightness = SONY_MAX_BRIGHTNESS - 1, +}; + +/* + * ACPI callbacks + */ +static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) +{ + if (debug) + printk(LOG_PFX "sony_acpi_notify, event: %d\n", event); + acpi_bus_generate_event(sony_acpi_acpi_device, 1, event); +} + +static acpi_status sony_walk_callback(acpi_handle handle, u32 level, + void *context, void **return_value) +{ + struct acpi_namespace_node *node; + union acpi_operand_object *operand; + + node = (struct acpi_namespace_node *)handle; + operand = (union acpi_operand_object *)node->object; + + printk(LOG_PFX "method: name: %4.4s, args %X\n", node->name.ascii, + (u32) operand->method.param_count); + + return AE_OK; +} + +/* + * ACPI device + */ +static int sony_acpi_resume(struct acpi_device *device) +{ + struct sony_acpi_value *item; + + for (item = sony_acpi_values; item->name; item++) { + int ret; + + if (!item->valid) + continue; + ret = acpi_callsetfunc(sony_acpi_handle, *item->acpiset, + item->value, NULL); + if (ret < 0) { + printk("%s: %d\n", __FUNCTION__, ret); + break; + } + } + return 0; +} + +static int sony_acpi_add(struct acpi_device *device) +{ + acpi_status status; + int result; + acpi_handle handle; + + sony_acpi_acpi_device = device; + + sony_acpi_handle = device->handle; + + if (debug) { + status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_acpi_handle, + 1, sony_walk_callback, NULL, NULL); + if (ACPI_FAILURE(status)) { + printk(LOG_PFX "unable to walk acpi resources\n"); + result = -ENODEV; + goto outwalk; + } + } + + status = acpi_install_notify_handler(sony_acpi_handle, + ACPI_DEVICE_NOTIFY, + sony_acpi_notify, NULL); + if (ACPI_FAILURE(status)) { + printk(LOG_PFX "unable to install notify handler\n"); + result = -ENODEV; + goto outwalk; + } + + if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, "GBRT", &handle))) { + sony_backlight_device = backlight_device_register("sony", NULL, + NULL, + &sony_backlight_properties); + + if (IS_ERR(sony_backlight_device)) { + printk(LOG_PFX "unable to register backlight device\n"); + sony_backlight_device = NULL; + } else + sony_backlight_properties.brightness = + sony_backlight_get_brightness + (sony_backlight_device); + } + + if (sony_snc_pf_add()) + goto outbacklight; + + printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully installed\n"); + + return 0; + + outbacklight: + if (sony_backlight_device) + backlight_device_unregister(sony_backlight_device); + + status = acpi_remove_notify_handler(sony_acpi_handle, + ACPI_DEVICE_NOTIFY, + sony_acpi_notify); + if (ACPI_FAILURE(status)) + printk(LOG_PFX "unable to remove notify handler\n"); + outwalk: + return result; +} + +static int sony_acpi_remove(struct acpi_device *device, int type) +{ + acpi_status status; + + if (sony_backlight_device) + backlight_device_unregister(sony_backlight_device); + + sony_acpi_acpi_device = NULL; + + status = acpi_remove_notify_handler(sony_acpi_handle, + ACPI_DEVICE_NOTIFY, + sony_acpi_notify); + if (ACPI_FAILURE(status)) + printk(LOG_PFX "unable to remove notify handler\n"); + + sony_snc_pf_remove(); + + printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully removed\n"); + + return 0; +} + +static struct acpi_driver sony_acpi_driver = { + .name = ACPI_SNC_DRIVER_NAME, + .class = ACPI_SNC_CLASS, + .ids = ACPI_SNC_HID, + .ops = { + .add = sony_acpi_add, + .remove = sony_acpi_remove, + .resume = sony_acpi_resume, + }, +}; + +static int __init sony_acpi_init(void) +{ + return acpi_bus_register_driver(&sony_acpi_driver); +} + +static void __exit sony_acpi_exit(void) +{ + acpi_bus_unregister_driver(&sony_acpi_driver); +} + +module_init(sony_acpi_init); +module_exit(sony_acpi_exit); diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index 2ce50f38e3c..459f4b4fede 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -64,6 +64,7 @@ #include <linux/err.h> #include <linux/dma-mapping.h> #include <linux/clk.h> +#include <linux/atmel_pdc.h> #include <linux/mmc/host.h> #include <linux/mmc/protocol.h> @@ -75,7 +76,6 @@ #include <asm/arch/cpu.h> #include <asm/arch/gpio.h> #include <asm/arch/at91_mci.h> -#include <asm/arch/at91_pdc.h> #define DRIVER_NAME "at91_mci" @@ -211,13 +211,13 @@ static void at91mci_pre_dma_read(struct at91mci_host *host) /* Check to see if this needs filling */ if (i == 0) { - if (at91_mci_read(host, AT91_PDC_RCR) != 0) { + if (at91_mci_read(host, ATMEL_PDC_RCR) != 0) { pr_debug("Transfer active in current\n"); continue; } } else { - if (at91_mci_read(host, AT91_PDC_RNCR) != 0) { + if (at91_mci_read(host, ATMEL_PDC_RNCR) != 0) { pr_debug("Transfer active in next\n"); continue; } @@ -234,12 +234,12 @@ static void at91mci_pre_dma_read(struct at91mci_host *host) pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length); if (i == 0) { - at91_mci_write(host, AT91_PDC_RPR, sg->dma_address); - at91_mci_write(host, AT91_PDC_RCR, sg->length / 4); + at91_mci_write(host, ATMEL_PDC_RPR, sg->dma_address); + at91_mci_write(host, ATMEL_PDC_RCR, sg->length / 4); } else { - at91_mci_write(host, AT91_PDC_RNPR, sg->dma_address); - at91_mci_write(host, AT91_PDC_RNCR, sg->length / 4); + at91_mci_write(host, ATMEL_PDC_RNPR, sg->dma_address); + at91_mci_write(host, ATMEL_PDC_RNCR, sg->length / 4); } } @@ -303,7 +303,7 @@ static void at91mci_post_dma_read(struct at91mci_host *host) at91mci_pre_dma_read(host); else { at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF); - at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); } pr_debug("post dma read done\n"); @@ -320,7 +320,7 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host) pr_debug("Handling the transmit\n"); /* Disable the transfer */ - at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); /* Now wait for cmd ready */ at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE); @@ -431,15 +431,15 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR)); if (!data) { - at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS); - at91_mci_write(host, AT91_PDC_RPR, 0); - at91_mci_write(host, AT91_PDC_RCR, 0); - at91_mci_write(host, AT91_PDC_RNPR, 0); - at91_mci_write(host, AT91_PDC_RNCR, 0); - at91_mci_write(host, AT91_PDC_TPR, 0); - at91_mci_write(host, AT91_PDC_TCR, 0); - at91_mci_write(host, AT91_PDC_TNPR, 0); - at91_mci_write(host, AT91_PDC_TNCR, 0); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS); + at91_mci_write(host, ATMEL_PDC_RPR, 0); + at91_mci_write(host, ATMEL_PDC_RCR, 0); + at91_mci_write(host, ATMEL_PDC_RNPR, 0); + at91_mci_write(host, ATMEL_PDC_RNCR, 0); + at91_mci_write(host, ATMEL_PDC_TPR, 0); + at91_mci_write(host, ATMEL_PDC_TCR, 0); + at91_mci_write(host, ATMEL_PDC_TNPR, 0); + at91_mci_write(host, ATMEL_PDC_TNCR, 0); at91_mci_write(host, AT91_MCI_ARGR, cmd->arg); at91_mci_write(host, AT91_MCI_CMDR, cmdr); @@ -452,7 +452,7 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ /* * Disable the PDC controller */ - at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); if (cmdr & AT91_MCI_TRCMD_START) { data->bytes_xfered = 0; @@ -481,8 +481,8 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ pr_debug("Transmitting %d bytes\n", host->total_length); - at91_mci_write(host, AT91_PDC_TPR, host->physical_address); - at91_mci_write(host, AT91_PDC_TCR, host->total_length / 4); + at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address); + at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4); ier = AT91_MCI_TXBUFE; } } @@ -497,9 +497,9 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ if (cmdr & AT91_MCI_TRCMD_START) { if (cmdr & AT91_MCI_TRDIR) - at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTEN); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); else - at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTEN); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); } return ier; } diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 38f41a593b1..d9400ef8719 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1284,8 +1284,8 @@ config PCNET32 will be called pcnet32. config PCNET32_NAPI - bool "Use RX polling (NAPI) (EXPERIMENTAL)" - depends on PCNET32 && EXPERIMENTAL + bool "Use RX polling (NAPI)" + depends on PCNET32 help NAPI is a new driver API designed to reduce CPU and interrupt load when the driver is receiving lots of packets from the card. It is @@ -2125,14 +2125,16 @@ config SKY2 will be called sky2. This is recommended. config SK98LIN - tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support" + tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support (DEPRECATED)" depends on PCI ---help--- Say Y here if you have a Marvell Yukon or SysKonnect SK-98xx/SK-95xx compliant Gigabit Ethernet Adapter. - This driver supports the original Yukon chipset. A cleaner driver is - also available (skge) which seems to work better than this one. + This driver supports the original Yukon chipset. This driver is + deprecated and will be removed from the kernel in the near future, + it has been replaced by the skge driver. skge is cleaner and + seems to work better. This driver does not support the newer Yukon2 chipset. A separate driver, sky2, is provided to support Yukon2-based adapters. @@ -2337,7 +2339,7 @@ config QLA3XXX config ATL1 tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)" - depends on NET_PCI && PCI && EXPERIMENTAL + depends on PCI && EXPERIMENTAL select CRC32 select MII help diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c index e7555d4e6ff..6318814a11a 100644 --- a/drivers/net/arcnet/arc-rawmode.c +++ b/drivers/net/arcnet/arc-rawmode.c @@ -94,7 +94,7 @@ static void rx(struct net_device *dev, int bufnum, BUGMSG(D_DURING, "it's a raw packet (length=%d)\n", length); - if (length >= MinTU) + if (length > MTU) ofs = 512 - length; else ofs = 256 - length; @@ -183,7 +183,7 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, length, XMTU); length = XMTU; } - if (length > MinTU) { + if (length >= MinTU) { hard->offset[0] = 0; hard->offset[1] = ofs = 512 - length; } else if (length > MTU) { diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 4e91dab1f17..83004fdab0a 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -41,7 +41,7 @@ * <jojo@repas.de> */ -#define VERSION "arcnet: v3.93 BETA 2000/04/29 - by Avery Pennarun et al.\n" +#define VERSION "arcnet: v3.94 BETA 2007/02/08 - by Avery Pennarun et al.\n" #include <linux/module.h> #include <linux/types.h> diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 98d326b23c9..b8c0fa6d401 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -155,6 +155,7 @@ static struct pci_device_id com20020pci_id_table[] = { { 0x1571, 0xa00b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, { 0x1571, 0xa00c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, { 0x1571, 0xa00d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, + { 0x1571, 0xa00e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, { 0x1571, 0xa201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, { 0x1571, 0xa202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, { 0x1571, 0xa203, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, @@ -163,6 +164,8 @@ static struct pci_device_id com20020pci_id_table[] = { { 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, { 0x10B5, 0x9030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, { 0x10B5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, + { 0x14BA, 0x6000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, + { 0x10B5, 0x2200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, {0,} }; diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index 4218075c8aa..7cf0a251169 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -104,7 +104,7 @@ int com20020_check(struct net_device *dev) SET_SUBADR(SUB_SETUP1); outb(lp->setup, _XREG); - if (lp->card_flags & ARC_CAN_10MBIT) + if (lp->clockm != 0) { SET_SUBADR(SUB_SETUP2); outb(lp->setup2, _XREG); diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c index 08b2d785469..314dbaabb64 100644 --- a/drivers/net/atl1/atl1_hw.c +++ b/drivers/net/atl1/atl1_hw.c @@ -243,14 +243,8 @@ static int atl1_get_permanent_address(struct atl1_hw *hw) i += 4; } -/* - * The following 2 lines are the Attansic originals. Saving for posterity. - * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]); - * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]); - */ - *(u32 *) & eth_addr[2] = swab32(addr[0]); - *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]); - + *(u32 *) ð_addr[2] = swab32(addr[0]); + *(u16 *) ð_addr[0] = swab16(*(u16 *) &addr[1]); if (is_valid_ether_addr(eth_addr)) { memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); return 0; @@ -281,17 +275,28 @@ static int atl1_get_permanent_address(struct atl1_hw *hw) i += 4; } -/* - * The following 2 lines are the Attansic originals. Saving for posterity. - * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]); - * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]); - */ - *(u32 *) & eth_addr[2] = swab32(addr[0]); - *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]); + *(u32 *) ð_addr[2] = swab32(addr[0]); + *(u16 *) ð_addr[0] = swab16(*(u16 *) &addr[1]); if (is_valid_ether_addr(eth_addr)) { memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); return 0; } + + /* + * On some motherboards, the MAC address is written by the + * BIOS directly to the MAC register during POST, and is + * not stored in eeprom. If all else thus far has failed + * to fetch the permanent MAC address, try reading it directly. + */ + addr[0] = ioread32(hw->hw_addr + REG_MAC_STA_ADDR); + addr[1] = ioread16(hw->hw_addr + (REG_MAC_STA_ADDR + 4)); + *(u32 *) ð_addr[2] = swab32(addr[0]); + *(u16 *) ð_addr[0] = swab16(*(u16 *) &addr[1]); + if (is_valid_ether_addr(eth_addr)) { + memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); + return 0; + } + return 1; } @@ -357,7 +362,7 @@ void atl1_hash_set(struct atl1_hw *hw, u32 hash_value) */ hash_reg = (hash_value >> 31) & 0x1; hash_bit = (hash_value >> 26) & 0x1F; - mta = ioread32((hw + REG_RX_HASH_TABLE) + (hash_reg << 2)); + mta = ioread32((hw->hw_addr + REG_RX_HASH_TABLE) + (hash_reg << 2)); mta |= (1 << hash_bit); iowrite32(mta, (hw->hw_addr + REG_RX_HASH_TABLE) + (hash_reg << 2)); } diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index 6655640eb4c..65673485bb6 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -82,8 +82,7 @@ #include "atl1.h" -#define RUN_REALTIME 0 -#define DRIVER_VERSION "2.0.6" +#define DRIVER_VERSION "2.0.7" char atl1_driver_name[] = "atl1"; static const char atl1_driver_string[] = "Attansic L1 Ethernet Network Driver"; @@ -100,7 +99,7 @@ MODULE_VERSION(DRIVER_VERSION); * atl1_pci_tbl - PCI Device ID Table */ static const struct pci_device_id atl1_pci_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1048)}, + {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1)}, /* required last entry */ {0,} }; diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 5ff7882297d..aaada572732 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -59,7 +59,6 @@ #define B44_DEF_TX_RING_PENDING (B44_TX_RING_SIZE - 1) #define B44_TX_RING_BYTES (sizeof(struct dma_desc) * \ B44_TX_RING_SIZE) -#define B44_DMA_MASK 0x3fffffff #define TX_RING_GAP(BP) \ (B44_TX_RING_SIZE - (BP)->tx_pending) @@ -665,7 +664,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) /* Hardware bug work-around, the chip is unable to do PCI DMA to/from anything above 1GB :-( */ if (dma_mapping_error(mapping) || - mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) { + mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { /* Sigh... */ if (!dma_mapping_error(mapping)) pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); @@ -677,7 +676,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) RX_PKT_BUF_SZ, PCI_DMA_FROMDEVICE); if (dma_mapping_error(mapping) || - mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) { + mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { if (!dma_mapping_error(mapping)) pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); dev_kfree_skb_any(skb); @@ -988,7 +987,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) } mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE); - if (dma_mapping_error(mapping) || mapping + len > B44_DMA_MASK) { + if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { /* Chip can't handle DMA to/from >1GB, use bounce buffer */ if (!dma_mapping_error(mapping)) pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE); @@ -1000,7 +999,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) mapping = pci_map_single(bp->pdev, bounce_skb->data, len, PCI_DMA_TODEVICE); - if (dma_mapping_error(mapping) || mapping + len > B44_DMA_MASK) { + if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { if (!dma_mapping_error(mapping)) pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE); @@ -1227,7 +1226,7 @@ static int b44_alloc_consistent(struct b44 *bp) DMA_BIDIRECTIONAL); if (dma_mapping_error(rx_ring_dma) || - rx_ring_dma + size > B44_DMA_MASK) { + rx_ring_dma + size > DMA_30BIT_MASK) { kfree(rx_ring); goto out_err; } @@ -1254,7 +1253,7 @@ static int b44_alloc_consistent(struct b44 *bp) DMA_TO_DEVICE); if (dma_mapping_error(tx_ring_dma) || - tx_ring_dma + size > B44_DMA_MASK) { + tx_ring_dma + size > DMA_30BIT_MASK) { kfree(tx_ring); goto out_err; } @@ -1289,7 +1288,7 @@ static void b44_chip_reset(struct b44 *bp) if (ssb_is_core_up(bp)) { bw32(bp, B44_RCV_LAZY, 0); bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE); - b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 100, 1); + b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1); bw32(bp, B44_DMATX_CTRL, 0); bp->tx_prod = bp->tx_cons = 0; if (br32(bp, B44_DMARX_STAT) & DMARX_STAT_EMASK) { @@ -2151,13 +2150,13 @@ static int __devinit b44_init_one(struct pci_dev *pdev, pci_set_master(pdev); - err = pci_set_dma_mask(pdev, (u64) B44_DMA_MASK); + err = pci_set_dma_mask(pdev, (u64) DMA_30BIT_MASK); if (err) { dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n"); goto err_out_free_res; } - err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK); + err = pci_set_consistent_dma_mask(pdev, (u64) DMA_30BIT_MASK); if (err) { dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n"); goto err_out_free_res; diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h index 16e004990c5..e14862b43d1 100644 --- a/drivers/net/cxgb3/cxgb3_defs.h +++ b/drivers/net/cxgb3/cxgb3_defs.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index c6b72664318..b2cf5f6feb4 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h index 0e6beb69ba1..f15446a32ef 100644 --- a/drivers/net/cxgb3/cxgb3_offload.h +++ b/drivers/net/cxgb3/cxgb3_offload.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c index 3c0cb855705..d660af74606 100644 --- a/drivers/net/cxgb3/l2t.c +++ b/drivers/net/cxgb3/l2t.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h index ba5d2cbd724..d79001336cf 100644 --- a/drivers/net/cxgb3/l2t.h +++ b/drivers/net/cxgb3/l2t.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h index 9af3bcd64b3..fa4099bc041 100644 --- a/drivers/net/cxgb3/t3cdev.h +++ b/drivers/net/cxgb3/t3cdev.h @@ -1,6 +1,5 @@ /* * Copyright (C) 2006-2007 Chelsio Communications. All rights reserved. - * Copyright (C) 2006-2007 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 689f158a469..dd4b728ac4b 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -337,7 +337,6 @@ struct e1000_adapter { struct e1000_rx_ring test_rx_ring; - uint32_t *config_space; int msg_enable; #ifdef CONFIG_PCI_MSI boolean_t have_msi; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 44ebc72962d..6777887295f 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -166,7 +166,7 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->transceiver = XCVR_EXTERNAL; } - if (netif_carrier_ok(adapter->netdev)) { + if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { e1000_get_speed_and_duplex(hw, &adapter->link_speed, &adapter->link_duplex); diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 619c89218b4..a71023741c3 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1417,10 +1417,6 @@ e1000_open(struct net_device *netdev) if ((err = e1000_setup_all_rx_resources(adapter))) goto err_setup_rx; - err = e1000_request_irq(adapter); - if (err) - goto err_req_irq; - e1000_power_up_phy(adapter); if ((err = e1000_up(adapter))) @@ -1431,6 +1427,10 @@ e1000_open(struct net_device *netdev) e1000_update_mng_vlan(adapter); } + err = e1000_request_irq(adapter); + if (err) + goto err_req_irq; + /* If AMT is enabled, let the firmware know that the network * interface is now open */ if (adapter->hw.mac_type == e1000_82573 && @@ -1439,10 +1439,10 @@ e1000_open(struct net_device *netdev) return E1000_SUCCESS; +err_req_irq: + e1000_down(adapter); err_up: e1000_power_down_phy(adapter); - e1000_free_irq(adapter); -err_req_irq: e1000_free_all_rx_resources(adapter); err_setup_rx: e1000_free_all_tx_resources(adapter); @@ -5071,58 +5071,6 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx) return 0; } -#ifdef CONFIG_PM -/* Save/restore 16 or 64 dwords of PCI config space depending on which - * bus we're on (PCI(X) vs. PCI-E) - */ -#define PCIE_CONFIG_SPACE_LEN 256 -#define PCI_CONFIG_SPACE_LEN 64 -static int -e1000_pci_save_state(struct e1000_adapter *adapter) -{ - struct pci_dev *dev = adapter->pdev; - int size; - int i; - - if (adapter->hw.mac_type >= e1000_82571) - size = PCIE_CONFIG_SPACE_LEN; - else - size = PCI_CONFIG_SPACE_LEN; - - WARN_ON(adapter->config_space != NULL); - - adapter->config_space = kmalloc(size, GFP_KERNEL); - if (!adapter->config_space) { - DPRINTK(PROBE, ERR, "unable to allocate %d bytes\n", size); - return -ENOMEM; - } - for (i = 0; i < (size / 4); i++) - pci_read_config_dword(dev, i * 4, &adapter->config_space[i]); - return 0; -} - -static void -e1000_pci_restore_state(struct e1000_adapter *adapter) -{ - struct pci_dev *dev = adapter->pdev; - int size; - int i; - - if (adapter->config_space == NULL) - return; - - if (adapter->hw.mac_type >= e1000_82571) - size = PCIE_CONFIG_SPACE_LEN; - else - size = PCI_CONFIG_SPACE_LEN; - for (i = 0; i < (size / 4); i++) - pci_write_config_dword(dev, i * 4, adapter->config_space[i]); - kfree(adapter->config_space); - adapter->config_space = NULL; - return; -} -#endif /* CONFIG_PM */ - static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) { @@ -5142,9 +5090,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) } #ifdef CONFIG_PM - /* Implement our own version of pci_save_state(pdev) because pci- - * express adapters have 256-byte config spaces. */ - retval = e1000_pci_save_state(adapter); + retval = pci_save_state(pdev); if (retval) return retval; #endif @@ -5231,7 +5177,7 @@ e1000_resume(struct pci_dev *pdev) uint32_t err; pci_set_power_state(pdev, PCI_D0); - e1000_pci_restore_state(adapter); + pci_restore_state(pdev); if ((err = pci_enable_device(pdev))) { printk(KERN_ERR "e1000: Cannot enable PCI device from suspend\n"); return err; diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 272e1ec51aa..42295d61ecd 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -39,7 +39,7 @@ #include <asm/io.h> #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0045" +#define DRV_VERSION "EHEA_0046" #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 38b2fa424b2..88ad1c8bcee 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -76,7 +76,7 @@ void ehea_dump(void *adr, int len, char *msg) { int x; unsigned char *deb = adr; for (x = 0; x < len; x += 16) { - printk(DRV_NAME "%s adr=%p ofs=%04x %016lx %016lx\n", msg, + printk(DRV_NAME " %s adr=%p ofs=%04x %016lx %016lx\n", msg, deb, x, *((u64*)&deb[0]), *((u64*)&deb[8])); deb += 16; } @@ -555,6 +555,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) { struct ehea_port *port = param; struct ehea_eqe *eqe; + struct ehea_qp *qp; u32 qp_token; eqe = ehea_poll_eq(port->qp_eq); @@ -563,9 +564,14 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry); ehea_error("QP aff_err: entry=0x%lx, token=0x%x", eqe->entry, qp_token); + + qp = port->port_res[qp_token].qp; + ehea_error_data(port->adapter, qp->fw_handle); eqe = ehea_poll_eq(port->qp_eq); } + queue_work(port->adapter->ehea_wq, &port->reset_task); + return IRQ_HANDLED; } diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c index 37716e05e80..bc3c0054726 100644 --- a/drivers/net/ehea/ehea_phyp.c +++ b/drivers/net/ehea/ehea_phyp.c @@ -612,3 +612,13 @@ u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle, event_mask, /* R6 */ 0, 0, 0, 0); /* R7-R12 */ } + +u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle, + void *rblock) +{ + return ehea_plpar_hcall_norets(H_ERROR_DATA, + adapter_handle, /* R4 */ + ressource_handle, /* R5 */ + virt_to_abs(rblock), /* R6 */ + 0, 0, 0, 0); /* R7-R12 */ +} diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h index 919f94b7593..90acddb068a 100644 --- a/drivers/net/ehea/ehea_phyp.h +++ b/drivers/net/ehea/ehea_phyp.h @@ -454,4 +454,7 @@ u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num, u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle, const u64 event_mask); +u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle, + void *rblock); + #endif /* __EHEA_PHYP_H__ */ diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index f143e13b229..96ff3b67999 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -486,6 +486,7 @@ int ehea_destroy_qp(struct ehea_qp *qp) if (!qp) return 0; + ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle); hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle); if (hret != H_SUCCESS) { ehea_error("destroy_qp failed"); @@ -581,4 +582,45 @@ out: return ret; } +void print_error_data(u64 *data) +{ + int length; + u64 type = EHEA_BMASK_GET(ERROR_DATA_TYPE, data[2]); + u64 resource = data[1]; + + length = EHEA_BMASK_GET(ERROR_DATA_LENGTH, data[0]); + + if (length > EHEA_PAGESIZE) + length = EHEA_PAGESIZE; + + if (type == 0x8) /* Queue Pair */ + ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, " + "port=%lX", resource, data[6], data[12], data[22]); + + ehea_dump(data, length, "error data"); +} + +void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle) +{ + unsigned long ret; + u64 *rblock; + + rblock = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!rblock) { + ehea_error("Cannot allocate rblock memory."); + return; + } + ret = ehea_h_error_data(adapter->handle, + res_handle, + rblock); + + if (ret == H_R_STATE) + ehea_error("No error data is available: %lX.", res_handle); + else if (ret == H_SUCCESS) + print_error_data(rblock); + else + ehea_error("Error data could not be fetched: %lX", res_handle); + + kfree(rblock); +} diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h index 7efdc96919c..1ff60983504 100644 --- a/drivers/net/ehea/ehea_qmr.h +++ b/drivers/net/ehea/ehea_qmr.h @@ -180,6 +180,9 @@ struct ehea_eqe { u64 entry; }; +#define ERROR_DATA_LENGTH EHEA_BMASK_IBM(52,63) +#define ERROR_DATA_TYPE EHEA_BMASK_IBM(0,7) + static inline void *hw_qeit_calc(struct hw_queue *queue, u64 q_offset) { struct ehea_page *current_page; @@ -355,4 +358,6 @@ int ehea_destroy_qp(struct ehea_qp *qp); int ehea_reg_mr_adapter(struct ehea_adapter *adapter); +void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); + #endif /* __EHEA_QMR_H__ */ diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 1be4a84dce0..1f83988a6a6 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -10,6 +10,7 @@ * Maintainer: Kumar Gala * * Copyright (c) 2002-2006 Freescale Semiconductor, Inc. + * Copyright (c) 2007 MontaVista Software, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -1612,71 +1613,17 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id) /* Save ievent for future reference */ u32 events = gfar_read(&priv->regs->ievent); - /* Clear IEVENT */ - gfar_write(&priv->regs->ievent, events); - /* Check for reception */ - if ((events & IEVENT_RXF0) || (events & IEVENT_RXB0)) + if (events & IEVENT_RX_MASK) gfar_receive(irq, dev_id); /* Check for transmit completion */ - if ((events & IEVENT_TXF) || (events & IEVENT_TXB)) + if (events & IEVENT_TX_MASK) gfar_transmit(irq, dev_id); - /* Update error statistics */ - if (events & IEVENT_TXE) { - priv->stats.tx_errors++; - - if (events & IEVENT_LC) - priv->stats.tx_window_errors++; - if (events & IEVENT_CRL) - priv->stats.tx_aborted_errors++; - if (events & IEVENT_XFUN) { - if (netif_msg_tx_err(priv)) - printk(KERN_WARNING "%s: tx underrun. dropped packet\n", dev->name); - priv->stats.tx_dropped++; - priv->extra_stats.tx_underrun++; - - /* Reactivate the Tx Queues */ - gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); - } - } - if (events & IEVENT_BSY) { - priv->stats.rx_errors++; - priv->extra_stats.rx_bsy++; - - gfar_receive(irq, dev_id); - -#ifndef CONFIG_GFAR_NAPI - /* Clear the halt bit in RSTAT */ - gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); -#endif - - if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", - dev->name, - gfar_read(&priv->regs->rstat)); - } - if (events & IEVENT_BABR) { - priv->stats.rx_errors++; - priv->extra_stats.rx_babr++; - - if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: babbling error\n", dev->name); - } - if (events & IEVENT_EBERR) { - priv->extra_stats.eberr++; - if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: EBERR\n", dev->name); - } - if ((events & IEVENT_RXC) && (netif_msg_rx_err(priv))) - printk(KERN_DEBUG "%s: control frame\n", dev->name); - - if (events & IEVENT_BABT) { - priv->extra_stats.tx_babt++; - if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: babt error\n", dev->name); - } + /* Check for errors */ + if (events & IEVENT_ERR_MASK) + gfar_error(irq, dev_id); return IRQ_HANDLED; } @@ -1938,7 +1885,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id) /* Hmm... */ if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv)) printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n", - dev->name, events, gfar_read(&priv->regs->imask)); + dev->name, events, gfar_read(&priv->regs->imask)); /* Update the error counters */ if (events & IEVENT_TXE) { @@ -1950,8 +1897,8 @@ static irqreturn_t gfar_error(int irq, void *dev_id) priv->stats.tx_aborted_errors++; if (events & IEVENT_XFUN) { if (netif_msg_tx_err(priv)) - printk(KERN_DEBUG "%s: underrun. packet dropped.\n", - dev->name); + printk(KERN_DEBUG "%s: TX FIFO underrun, " + "packet dropped.\n", dev->name); priv->stats.tx_dropped++; priv->extra_stats.tx_underrun++; @@ -1973,30 +1920,28 @@ static irqreturn_t gfar_error(int irq, void *dev_id) #endif if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", - dev->name, - gfar_read(&priv->regs->rstat)); + printk(KERN_DEBUG "%s: busy error (rstat: %x)\n", + dev->name, gfar_read(&priv->regs->rstat)); } if (events & IEVENT_BABR) { priv->stats.rx_errors++; priv->extra_stats.rx_babr++; if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: babbling error\n", dev->name); + printk(KERN_DEBUG "%s: babbling RX error\n", dev->name); } if (events & IEVENT_EBERR) { priv->extra_stats.eberr++; if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: EBERR\n", dev->name); + printk(KERN_DEBUG "%s: bus error\n", dev->name); } if ((events & IEVENT_RXC) && netif_msg_rx_status(priv)) - if (netif_msg_rx_status(priv)) - printk(KERN_DEBUG "%s: control frame\n", dev->name); + printk(KERN_DEBUG "%s: control frame\n", dev->name); if (events & IEVENT_BABT) { priv->extra_stats.tx_babt++; if (netif_msg_tx_err(priv)) - printk(KERN_DEBUG "%s: babt error\n", dev->name); + printk(KERN_DEBUG "%s: babbling TX error\n", dev->name); } return IRQ_HANDLED; } diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c index 45ffb5d0ca3..aec9ab17a9a 100644 --- a/drivers/net/gianfar_sysfs.c +++ b/drivers/net/gianfar_sysfs.c @@ -38,13 +38,15 @@ #include "gianfar.h" #define GFAR_ATTR(_name) \ -static ssize_t gfar_show_##_name(struct class_device *cdev, char *buf); \ -static ssize_t gfar_set_##_name(struct class_device *cdev, \ +static ssize_t gfar_show_##_name(struct device *dev, \ + struct device_attribute *attr, char *buf); \ +static ssize_t gfar_set_##_name(struct device *dev, \ + struct device_attribute *attr, \ const char *buf, size_t count); \ -static CLASS_DEVICE_ATTR(_name, 0644, gfar_show_##_name, gfar_set_##_name) +static DEVICE_ATTR(_name, 0644, gfar_show_##_name, gfar_set_##_name) #define GFAR_CREATE_FILE(_dev, _name) \ - class_device_create_file(&_dev->class_dev, &class_device_attr_##_name) + device_create_file(&_dev->dev, &dev_attr_##_name) GFAR_ATTR(bd_stash); GFAR_ATTR(rx_stash_size); @@ -53,29 +55,28 @@ GFAR_ATTR(fifo_threshold); GFAR_ATTR(fifo_starve); GFAR_ATTR(fifo_starve_off); -#define to_net_dev(cd) container_of(cd, struct net_device, class_dev) - -static ssize_t gfar_show_bd_stash(struct class_device *cdev, char *buf) +static ssize_t gfar_show_bd_stash(struct device *dev, + struct device_attribute *attr, char *buf) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - return sprintf(buf, "%s\n", priv->bd_stash_en? "on" : "off"); + return sprintf(buf, "%s\n", priv->bd_stash_en ? "on" : "off"); } -static ssize_t gfar_set_bd_stash(struct class_device *cdev, - const char *buf, size_t count) +static ssize_t gfar_set_bd_stash(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); int new_setting = 0; u32 temp; unsigned long flags; /* Find out the new setting */ - if (!strncmp("on", buf, count-1) || !strncmp("1", buf, count-1)) + if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1)) new_setting = 1; - else if (!strncmp("off", buf, count-1) || !strncmp("0", buf, count-1)) + else if (!strncmp("off", buf, count - 1) + || !strncmp("0", buf, count - 1)) new_setting = 0; else return count; @@ -99,19 +100,19 @@ static ssize_t gfar_set_bd_stash(struct class_device *cdev, return count; } -static ssize_t gfar_show_rx_stash_size(struct class_device *cdev, char *buf) +static ssize_t gfar_show_rx_stash_size(struct device *dev, + struct device_attribute *attr, char *buf) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); return sprintf(buf, "%d\n", priv->rx_stash_size); } -static ssize_t gfar_set_rx_stash_size(struct class_device *cdev, - const char *buf, size_t count) +static ssize_t gfar_set_rx_stash_size(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); unsigned int length = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -145,21 +146,21 @@ static ssize_t gfar_set_rx_stash_size(struct class_device *cdev, return count; } - /* Stashing will only be enabled when rx_stash_size != 0 */ -static ssize_t gfar_show_rx_stash_index(struct class_device *cdev, char *buf) +static ssize_t gfar_show_rx_stash_index(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); return sprintf(buf, "%d\n", priv->rx_stash_index); } -static ssize_t gfar_set_rx_stash_index(struct class_device *cdev, - const char *buf, size_t count) +static ssize_t gfar_set_rx_stash_index(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); unsigned short index = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -183,19 +184,20 @@ static ssize_t gfar_set_rx_stash_index(struct class_device *cdev, return count; } -static ssize_t gfar_show_fifo_threshold(struct class_device *cdev, char *buf) +static ssize_t gfar_show_fifo_threshold(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); return sprintf(buf, "%d\n", priv->fifo_threshold); } -static ssize_t gfar_set_fifo_threshold(struct class_device *cdev, - const char *buf, size_t count) +static ssize_t gfar_set_fifo_threshold(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); unsigned int length = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -217,20 +219,19 @@ static ssize_t gfar_set_fifo_threshold(struct class_device *cdev, return count; } -static ssize_t gfar_show_fifo_starve(struct class_device *cdev, char *buf) +static ssize_t gfar_show_fifo_starve(struct device *dev, + struct device_attribute *attr, char *buf) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); return sprintf(buf, "%d\n", priv->fifo_starve); } - -static ssize_t gfar_set_fifo_starve(struct class_device *cdev, - const char *buf, size_t count) +static ssize_t gfar_set_fifo_starve(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); unsigned int num = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -252,19 +253,20 @@ static ssize_t gfar_set_fifo_starve(struct class_device *cdev, return count; } -static ssize_t gfar_show_fifo_starve_off(struct class_device *cdev, char *buf) +static ssize_t gfar_show_fifo_starve_off(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); return sprintf(buf, "%d\n", priv->fifo_starve_off); } -static ssize_t gfar_set_fifo_starve_off(struct class_device *cdev, - const char *buf, size_t count) +static ssize_t gfar_set_fifo_starve_off(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); unsigned int num = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index f0d30cf67b5..4ad780719a8 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -836,13 +836,17 @@ static int ioc3_mii_init(struct ioc3_private *ip) } ip->mii.phy_id = i; + +out: + return res; +} + +static void ioc3_mii_start(struct ioc3_private *ip) +{ ip->ioc3_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */ ip->ioc3_timer.data = (unsigned long) ip; ip->ioc3_timer.function = &ioc3_timer; add_timer(&ip->ioc3_timer); - -out: - return res; } static inline void ioc3_clean_rx_ring(struct ioc3_private *ip) @@ -1071,6 +1075,7 @@ static int ioc3_open(struct net_device *dev) ip->ehar_h = 0; ip->ehar_l = 0; ioc3_init(dev); + ioc3_mii_start(ip); netif_start_queue(dev); return 0; @@ -1274,6 +1279,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_stop; } + ioc3_mii_start(ip); ioc3_ssram_disc(ip); ioc3_get_eaddr(ip); @@ -1314,6 +1320,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) out_stop: ioc3_stop(ip); + del_timer_sync(&ip->ioc3_timer); ioc3_free_rings(ip); out_res: pci_release_regions(pdev); @@ -1335,6 +1342,8 @@ static void __devexit ioc3_remove_one (struct pci_dev *pdev) struct ioc3 *ioc3 = ip->regs; unregister_netdev(dev); + del_timer_sync(&ip->ioc3_timer); + iounmap(ioc3); pci_release_regions(pdev); free_netdev(dev); @@ -1492,6 +1501,7 @@ static void ioc3_timeout(struct net_device *dev) ioc3_stop(ip); ioc3_init(dev); ioc3_mii_init(ip); + ioc3_mii_start(ip); spin_unlock_irq(&ip->ioc3_lock); diff --git a/drivers/net/macb.c b/drivers/net/macb.c index a41418b3c51..2e9571bf073 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -881,27 +881,15 @@ static struct net_device_stats *macb_get_stats(struct net_device *dev) static int macb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct macb *bp = netdev_priv(dev); - int ret; - unsigned long flags; - - spin_lock_irqsave(&bp->lock, flags); - ret = mii_ethtool_gset(&bp->mii, cmd); - spin_unlock_irqrestore(&bp->lock, flags); - return ret; + return mii_ethtool_gset(&bp->mii, cmd); } static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct macb *bp = netdev_priv(dev); - int ret; - unsigned long flags; - - spin_lock_irqsave(&bp->lock, flags); - ret = mii_ethtool_sset(&bp->mii, cmd); - spin_unlock_irqrestore(&bp->lock, flags); - return ret; + return mii_ethtool_sset(&bp->mii, cmd); } static void macb_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) @@ -930,17 +918,11 @@ static struct ethtool_ops macb_ethtool_ops = { static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct macb *bp = netdev_priv(dev); - int ret; - unsigned long flags; if (!netif_running(dev)) return -EINVAL; - spin_lock_irqsave(&bp->lock, flags); - ret = generic_mii_ioctl(&bp->mii, if_mii(rq), cmd, NULL); - spin_unlock_irqrestore(&bp->lock, flags); - - return ret; + return generic_mii_ioctl(&bp->mii, if_mii(rq), cmd, NULL); } static ssize_t macb_mii_show(const struct device *_dev, char *buf, diff --git a/drivers/net/meth.c b/drivers/net/meth.c index d38b7c72362..7e69ca6edd9 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -170,7 +170,7 @@ static int mdio_probe(struct meth_private *priv) static void meth_check_link(struct net_device *dev) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); unsigned long mii_advertising = mdio_read(priv, 4); unsigned long mii_partner = mdio_read(priv, 5); unsigned long negotiated = mii_advertising & mii_partner; @@ -268,7 +268,7 @@ static void meth_free_rx_ring(struct meth_private *priv) int meth_reset(struct net_device *dev) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); /* Reset card */ mace->eth.mac_ctrl = SGI_MAC_RESET; @@ -310,7 +310,7 @@ int meth_reset(struct net_device *dev) */ static int meth_open(struct net_device *dev) { - struct meth_private *priv = dev->priv; + struct meth_private *priv = netdev_priv(dev); int ret; priv->phy_addr = -1; /* No PHY is known yet... */ @@ -354,7 +354,7 @@ out_free_tx_ring: static int meth_release(struct net_device *dev) { - struct meth_private *priv = dev->priv; + struct meth_private *priv = netdev_priv(dev); DPRINTK("Stopping queue\n"); netif_stop_queue(dev); /* can't transmit any more */ @@ -376,7 +376,7 @@ static void meth_rx(struct net_device* dev, unsigned long int_status) { struct sk_buff *skb; unsigned long status; - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); unsigned long fifo_rptr = (int_status & METH_INT_RX_RPTR_MASK) >> 8; spin_lock(&priv->meth_lock); @@ -466,14 +466,14 @@ static void meth_rx(struct net_device* dev, unsigned long int_status) static int meth_tx_full(struct net_device *dev) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); return (priv->tx_count >= TX_RING_ENTRIES - 1); } static void meth_tx_cleanup(struct net_device* dev, unsigned long int_status) { - struct meth_private *priv = dev->priv; + struct meth_private *priv = netdev_priv(dev); unsigned long status; struct sk_buff *skb; unsigned long rptr = (int_status&TX_INFO_RPTR) >> 16; @@ -536,7 +536,7 @@ static void meth_tx_cleanup(struct net_device* dev, unsigned long int_status) static void meth_error(struct net_device* dev, unsigned status) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); printk(KERN_WARNING "meth: error status: 0x%08x\n",status); /* check for errors too... */ @@ -570,7 +570,7 @@ static void meth_error(struct net_device* dev, unsigned status) static irqreturn_t meth_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); unsigned long status; status = mace->eth.int_stat; @@ -695,7 +695,7 @@ static void meth_add_to_tx_ring(struct meth_private *priv, struct sk_buff *skb) */ static int meth_tx(struct sk_buff *skb, struct net_device *dev) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&priv->meth_lock, flags); @@ -726,7 +726,7 @@ static int meth_tx(struct sk_buff *skb, struct net_device *dev) */ static void meth_tx_timeout(struct net_device *dev) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); unsigned long flags; printk(KERN_WARNING "%s: transmit timed out\n", dev->name); @@ -778,7 +778,7 @@ static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) */ static struct net_device_stats *meth_stats(struct net_device *dev) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); return &priv->stats; } @@ -807,7 +807,7 @@ static struct net_device *meth_init(void) dev->irq = MACE_ETHERNET_IRQ; dev->base_addr = (unsigned long)&mace->eth; - priv = (struct meth_private *) dev->priv; + priv = netdev_priv(dev); spin_lock_init(&priv->meth_lock); ret = register_netdev(dev); diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 3f3896e9887..2807ef400fb 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -252,7 +252,7 @@ typedef u32 netxen_ctx_msg; #define netxen_set_msg_ctxid(config_word, val) \ ((config_word) &= ~(0x3ff<<18), (config_word) |= (val & 0x3ff) << 18) #define netxen_set_msg_opcode(config_word, val) \ - ((config_word) &= ~(0xf<<24), (config_word) |= (val & 0xf) << 24) + ((config_word) &= ~(0xf<<28), (config_word) |= (val & 0xf) << 28) struct netxen_rcv_context { __le64 rcv_ring_addr; @@ -303,14 +303,14 @@ struct netxen_ring_ctx { (cmd_desc)->flags_opcode |= cpu_to_le16((val) & 0x7f)) #define netxen_set_cmd_desc_opcode(cmd_desc, val) \ ((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x3f<<7), \ - (cmd_desc)->flags_opcode |= cpu_to_le16((val) & (0x3f<<7))) + (cmd_desc)->flags_opcode |= cpu_to_le16(((val & 0x3f)<<7))) #define netxen_set_cmd_desc_num_of_buff(cmd_desc, val) \ ((cmd_desc)->num_of_buffers_total_length &= ~cpu_to_le32(0xff), \ (cmd_desc)->num_of_buffers_total_length |= cpu_to_le32((val) & 0xff)) #define netxen_set_cmd_desc_totallength(cmd_desc, val) \ - ((cmd_desc)->num_of_buffers_total_length &= cpu_to_le32(0xff), \ - (cmd_desc)->num_of_buffers_total_length |= cpu_to_le32(val << 24)) + ((cmd_desc)->num_of_buffers_total_length &= ~cpu_to_le32(0xffffff00), \ + (cmd_desc)->num_of_buffers_total_length |= cpu_to_le32(val << 8)) #define netxen_get_cmd_desc_opcode(cmd_desc) \ ((le16_to_cpu((cmd_desc)->flags_opcode) >> 7) & 0x003F) @@ -1040,6 +1040,7 @@ int netxen_flash_unlock(struct netxen_adapter *adapter); int netxen_backup_crbinit(struct netxen_adapter *adapter); int netxen_flash_erase_secondary(struct netxen_adapter *adapter); int netxen_flash_erase_primary(struct netxen_adapter *adapter); +void netxen_halt_pegs(struct netxen_adapter *adapter); int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data); int netxen_rom_se(struct netxen_adapter *adapter, int addr); diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index cc0efe213e0..6252e9a8727 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -402,7 +402,7 @@ netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) wol->wolopts = 0; } -static u32 netxen_nic_get_link(struct net_device *dev) +static u32 netxen_nic_test_link(struct net_device *dev) { struct netxen_port *port = netdev_priv(dev); struct netxen_adapter *adapter = port->adapter; @@ -459,6 +459,7 @@ netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, int ret; if (flash_start == 0) { + netxen_halt_pegs(adapter); ret = netxen_flash_unlock(adapter); if (ret < 0) { printk(KERN_ERR "%s: Flash unlock failed.\n", @@ -712,7 +713,7 @@ netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, { if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* offline tests */ /* link test */ - if (!(data[4] = (u64) netxen_nic_get_link(dev))) + if (!(data[4] = (u64) netxen_nic_test_link(dev))) eth_test->flags |= ETH_TEST_FL_FAILED; if (netif_running(dev)) @@ -727,7 +728,7 @@ netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, dev->open(dev); } else { /* online tests */ /* link test */ - if (!(data[4] = (u64) netxen_nic_get_link(dev))) + if (!(data[4] = (u64) netxen_nic_test_link(dev))) eth_test->flags |= ETH_TEST_FL_FAILED; /* other tests pass by default */ @@ -783,7 +784,7 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .get_regs_len = netxen_nic_get_regs_len, .get_regs = netxen_nic_get_regs, .get_wol = netxen_nic_get_wol, - .get_link = netxen_nic_get_link, + .get_link = ethtool_op_get_link, .get_eeprom_len = netxen_nic_get_eeprom_len, .get_eeprom = netxen_nic_get_eeprom, .set_eeprom = netxen_nic_set_eeprom, diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index f263232f499..7195af3e8f3 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -420,6 +420,7 @@ static int netxen_get_flash_block(struct netxen_adapter *adapter, int base, for (i = 0; i < size / sizeof(u32); i++) { if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) return -1; + *ptr32 = cpu_to_le32(*ptr32); ptr32++; addr += sizeof(u32); } @@ -428,6 +429,7 @@ static int netxen_get_flash_block(struct netxen_adapter *adapter, int base, if (netxen_rom_fast_read(adapter, addr, &local) == -1) return -1; + local = cpu_to_le32(local); memcpy(ptr32, &local, (char *)buf + size - (char *)ptr32); } diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index f7bb8c90537..2f324366784 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -717,6 +717,14 @@ netxen_flash_erase_primary(struct netxen_adapter *adapter) return ret; } +void netxen_halt_pegs(struct netxen_adapter *adapter) +{ + netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_0 + 0x3c, 1); + netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_1 + 0x3c, 1); + netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_2 + 0x3c, 1); + netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_3 + 0x3c, 1); +} + int netxen_flash_unlock(struct netxen_adapter *adapter) { int ret = 0; @@ -1246,7 +1254,7 @@ int netxen_process_cmd_ring(unsigned long data) * the netdev which is associated with that device. */ - consumer = *(adapter->cmd_consumer); + consumer = le32_to_cpu(*(adapter->cmd_consumer)); if (last_consumer == consumer) { /* Ring is empty */ DPRINTK(INFO, "last_consumer %d == consumer %d\n", last_consumer, consumer); @@ -1340,7 +1348,7 @@ int netxen_process_cmd_ring(unsigned long data) if (adapter->last_cmd_consumer == consumer && (((adapter->cmd_producer + 1) % adapter->max_tx_desc_count) == adapter->last_cmd_consumer)) { - consumer = *(adapter->cmd_consumer); + consumer = le32_to_cpu(*(adapter->cmd_consumer)); } done = (adapter->last_cmd_consumer == consumer); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 36ba6a1aa36..225ff55527c 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -434,12 +434,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->port_count++; adapter->port[i] = port; } - +#ifndef CONFIG_PPC64 writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); netxen_pinit_from_rom(adapter, 0); udelay(500); netxen_load_firmware(adapter); netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); +#endif /* * delay a while to ensure that the Pegs are up & running. * Otherwise, we might see some flaky behaviour. diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 40d7003a371..d5d95074e56 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -458,7 +458,7 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) { - long reg = 0, ret = 0; + u32 reg = 0, ret = 0; if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) { netxen_crb_writelit_adapter(adapter, diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 448bf4a7801..c7bd9c1c7f3 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -915,7 +915,7 @@ static void media_check(unsigned long arg) if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + Timer) == 0xff)) { if (!lp->fast_poll) printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); - el3_interrupt(dev->irq, lp); + el3_interrupt(dev->irq, dev); lp->fast_poll = HZ; } if (lp->fast_poll) { diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 530df8883fe..2561f76033e 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1927,7 +1927,7 @@ static void media_check(u_long arg) if (smc->watchdog++ && ((i>>8) & i)) { if (!smc->fast_poll) printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); - smc_interrupt(dev->irq, smc); + smc_interrupt(dev->irq, dev); smc->fast_poll = HZ; } if (smc->fast_poll) { diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index f4d4eb659ca..22aec5cce68 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -42,6 +42,19 @@ #define MII_M1011_IMASK_INIT 0x6400 #define MII_M1011_IMASK_CLEAR 0x0000 +#define MII_M1011_PHY_SCR 0x10 +#define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060 + +#define MII_M1145_PHY_EXT_CR 0x14 +#define MII_M1145_RGMII_RX_DELAY 0x0080 +#define MII_M1145_RGMII_TX_DELAY 0x0002 + +#define M1145_DEV_FLAGS_RESISTANCE 0x00000001 + +#define MII_M1111_PHY_LED_CONTROL 0x18 +#define MII_M1111_PHY_LED_DIRECT 0x4100 +#define MII_M1111_PHY_LED_COMBINE 0x411c + MODULE_DESCRIPTION("Marvell PHY driver"); MODULE_AUTHOR("Andy Fleming"); MODULE_LICENSE("GPL"); @@ -63,7 +76,7 @@ static int marvell_config_intr(struct phy_device *phydev) { int err; - if(phydev->interrupts == PHY_INTERRUPT_ENABLED) + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); else err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); @@ -103,34 +116,153 @@ static int marvell_config_aneg(struct phy_device *phydev) if (err < 0) return err; + err = phy_write(phydev, MII_M1011_PHY_SCR, + MII_M1011_PHY_SCR_AUTO_CROSS); + if (err < 0) + return err; + + err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, + MII_M1111_PHY_LED_DIRECT); + if (err < 0) + return err; err = genphy_config_aneg(phydev); return err; } +static int m88e1145_config_init(struct phy_device *phydev) +{ + int err; + + /* Take care of errata E0 & E1 */ + err = phy_write(phydev, 0x1d, 0x001b); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0x418f); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1d, 0x0016); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0xa2da); + if (err < 0) + return err; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { + int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); + if (temp < 0) + return temp; + + temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY); + + err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp); + if (err < 0) + return err; + + if (phydev->dev_flags & M1145_DEV_FLAGS_RESISTANCE) { + err = phy_write(phydev, 0x1d, 0x0012); + if (err < 0) + return err; + + temp = phy_read(phydev, 0x1e); + if (temp < 0) + return temp; + + temp &= 0xf03f; + temp |= 2 << 9; /* 36 ohm */ + temp |= 2 << 6; /* 39 ohm */ + + err = phy_write(phydev, 0x1e, temp); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1d, 0x3); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0x8000); + if (err < 0) + return err; + } + } + + return 0; +} static struct phy_driver m88e1101_driver = { - .phy_id = 0x01410c00, - .phy_id_mask = 0xffffff00, - .name = "Marvell 88E1101", - .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_INTERRUPT, - .config_aneg = &marvell_config_aneg, - .read_status = &genphy_read_status, - .ack_interrupt = &marvell_ack_interrupt, - .config_intr = &marvell_config_intr, - .driver = { .owner = THIS_MODULE,}, + .phy_id = 0x01410c60, + .phy_id_mask = 0xfffffff0, + .name = "Marvell 88E1101", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &marvell_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, + .driver = {.owner = THIS_MODULE,}, +}; + +static struct phy_driver m88e1111s_driver = { + .phy_id = 0x01410cc0, + .phy_id_mask = 0xfffffff0, + .name = "Marvell 88E1111", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &marvell_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, + .driver = {.owner = THIS_MODULE,}, +}; + +static struct phy_driver m88e1145_driver = { + .phy_id = 0x01410cd0, + .phy_id_mask = 0xfffffff0, + .name = "Marvell 88E1145", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_init = &m88e1145_config_init, + .config_aneg = &marvell_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, + .driver = {.owner = THIS_MODULE,}, }; static int __init marvell_init(void) { - return phy_driver_register(&m88e1101_driver); + int ret; + + ret = phy_driver_register(&m88e1101_driver); + if (ret) + return ret; + + ret = phy_driver_register(&m88e1111s_driver); + if (ret) + goto err1111s; + + ret = phy_driver_register(&m88e1145_driver); + if (ret) + goto err1145; + + return 0; + + err1145: + phy_driver_unregister(&m88e1111s_driver); + err1111s: + phy_driver_unregister(&m88e1101_driver); + return ret; } static void __exit marvell_exit(void) { phy_driver_unregister(&m88e1101_driver); + phy_driver_unregister(&m88e1111s_driver); + phy_driver_unregister(&m88e1145_driver); } module_init(marvell_init); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index fdf45fdb673..7d5b6d1838c 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -138,7 +138,7 @@ void phy_prepare_link(struct phy_device *phydev, */ struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, void (*handler)(struct net_device *), u32 flags, - u32 interface) + phy_interface_t interface) { struct phy_device *phydev; @@ -187,7 +187,7 @@ static int phy_compare_id(struct device *dev, void *data) } struct phy_device *phy_attach(struct net_device *dev, - const char *phy_id, u32 flags, u32 interface) + const char *phy_id, u32 flags, phy_interface_t interface) { struct bus_type *bus = &mdio_bus_type; struct phy_device *phydev; diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 92d11b961db..e94ab256b54 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -5188,6 +5188,9 @@ static struct pci_driver skge_driver = { static int __init skge_init(void) { + printk(KERN_NOTICE "sk98lin: driver has been replaced by the skge driver" + " and is scheduled for removal\n"); + return pci_register_driver(&skge_driver); } diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index f2ab3d56e56..52edbd7ac17 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -49,7 +49,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.12" +#define DRV_VERSION "1.13" #define PFX DRV_NAME " " /* @@ -1742,13 +1742,6 @@ static void sky2_link_down(struct sky2_port *sky2) reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); gma_write16(hw, port, GM_GP_CTRL, reg); - if (sky2->flow_status == FC_RX) { - /* restore Asymmetric Pause bit */ - gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, - gm_phy_read(hw, port, PHY_MARV_AUNE_ADV) - | PHY_M_AN_ASP); - } - netif_carrier_off(sky2->netdev); netif_stop_queue(sky2->netdev); @@ -1773,10 +1766,10 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) { struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; - u16 lpa; + u16 advert, lpa; + advert = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV); lpa = gm_phy_read(hw, port, PHY_MARV_AUNE_LP); - if (lpa & PHY_M_AN_RF) { printk(KERN_ERR PFX "%s: remote fault", sky2->netdev->name); return -1; @@ -1791,20 +1784,40 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) sky2->speed = sky2_phy_speed(hw, aux); sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF; - /* Pause bits are offset (9..8) */ - if (hw->chip_id == CHIP_ID_YUKON_XL - || hw->chip_id == CHIP_ID_YUKON_EC_U - || hw->chip_id == CHIP_ID_YUKON_EX) - aux >>= 6; - - sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN, - aux & PHY_M_PS_TX_P_EN); + /* Since the pause result bits seem to in different positions on + * different chips. look at registers. + */ + if (!sky2_is_copper(hw)) { + /* Shift for bits in fiber PHY */ + advert &= ~(ADVERTISE_PAUSE_CAP|ADVERTISE_PAUSE_ASYM); + lpa &= ~(LPA_PAUSE_CAP|LPA_PAUSE_ASYM); + + if (advert & ADVERTISE_1000XPAUSE) + advert |= ADVERTISE_PAUSE_CAP; + if (advert & ADVERTISE_1000XPSE_ASYM) + advert |= ADVERTISE_PAUSE_ASYM; + if (lpa & LPA_1000XPAUSE) + lpa |= LPA_PAUSE_CAP; + if (lpa & LPA_1000XPAUSE_ASYM) + lpa |= LPA_PAUSE_ASYM; + } + + sky2->flow_status = FC_NONE; + if (advert & ADVERTISE_PAUSE_CAP) { + if (lpa & LPA_PAUSE_CAP) + sky2->flow_status = FC_BOTH; + else if (advert & ADVERTISE_PAUSE_ASYM) + sky2->flow_status = FC_RX; + } else if (advert & ADVERTISE_PAUSE_ASYM) { + if ((lpa & LPA_PAUSE_CAP) && (lpa & LPA_PAUSE_ASYM)) + sky2->flow_status = FC_TX; + } if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000 && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)) sky2->flow_status = FC_NONE; - if (aux & PHY_M_PS_RX_P_EN) + if (sky2->flow_status & FC_TX) sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); else sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); @@ -1853,16 +1866,13 @@ out: spin_unlock(&sky2->phy_lock); } - /* Transmit timeout is only called if we are running, carrier is up * and tx queue is full (stopped). - * Called with netif_tx_lock held. */ static void sky2_tx_timeout(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; - u32 imask; if (netif_msg_timer(sky2)) printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); @@ -1872,19 +1882,8 @@ static void sky2_tx_timeout(struct net_device *dev) sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX), sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE))); - imask = sky2_read32(hw, B0_IMSK); /* block IRQ in hw */ - sky2_write32(hw, B0_IMSK, 0); - sky2_read32(hw, B0_IMSK); - - netif_poll_disable(hw->dev[0]); /* stop NAPI poll */ - synchronize_irq(hw->pdev->irq); - - netif_start_queue(dev); /* don't wakeup during flush */ - sky2_tx_complete(sky2, sky2->tx_prod); /* Flush transmit queue */ - - sky2_write32(hw, B0_IMSK, imask); - - sky2_phy_reinit(sky2); /* this clears flow control etc */ + /* can't restart safely under softirq */ + schedule_work(&hw->restart_work); } static int sky2_change_mtu(struct net_device *dev, int new_mtu) @@ -2057,9 +2056,6 @@ static struct sk_buff *sky2_receive(struct net_device *dev, if (!(status & GMR_FS_RX_OK)) goto resubmit; - if (length > dev->mtu + ETH_HLEN) - goto oversize; - if (length < copybreak) skb = receive_copy(sky2, re, length); else @@ -2069,14 +2065,10 @@ resubmit: return skb; -oversize: - ++sky2->net_stats.rx_over_errors; - goto resubmit; - error: ++sky2->net_stats.rx_errors; if (status & GMR_FS_RX_FF_OV) { - sky2->net_stats.rx_fifo_errors++; + sky2->net_stats.rx_over_errors++; goto resubmit; } @@ -2638,6 +2630,49 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); } +static void sky2_restart(struct work_struct *work) +{ + struct sky2_hw *hw = container_of(work, struct sky2_hw, restart_work); + struct net_device *dev; + int i, err; + + dev_dbg(&hw->pdev->dev, "restarting\n"); + + del_timer_sync(&hw->idle_timer); + + rtnl_lock(); + sky2_write32(hw, B0_IMSK, 0); + sky2_read32(hw, B0_IMSK); + + netif_poll_disable(hw->dev[0]); + + for (i = 0; i < hw->ports; i++) { + dev = hw->dev[i]; + if (netif_running(dev)) + sky2_down(dev); + } + + sky2_reset(hw); + sky2_write32(hw, B0_IMSK, Y2_IS_BASE); + netif_poll_enable(hw->dev[0]); + + for (i = 0; i < hw->ports; i++) { + dev = hw->dev[i]; + if (netif_running(dev)) { + err = sky2_up(dev); + if (err) { + printk(KERN_INFO PFX "%s: could not restart %d\n", + dev->name, err); + dev_close(dev); + } + } + } + + sky2_idle_start(hw); + + rtnl_unlock(); +} + static inline u8 sky2_wol_supported(const struct sky2_hw *hw) { return sky2_is_copper(hw) ? (WAKE_PHY | WAKE_MAGIC) : 0; @@ -3600,6 +3635,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev, } setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw); + INIT_WORK(&hw->restart_work, sky2_restart); + sky2_idle_start(hw); pci_set_drvdata(pdev, hw); @@ -3636,6 +3673,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev) del_timer_sync(&hw->idle_timer); + flush_scheduled_work(); + sky2_write32(hw, B0_IMSK, 0); synchronize_irq(hw->pdev->irq); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 3b0189569d5..ac24bdc4297 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1589,7 +1589,7 @@ enum { GMR_FS_ANY_ERR = GMR_FS_RX_FF_OV | GMR_FS_CRC_ERR | GMR_FS_FRAGMENT | GMR_FS_LONG_ERR | - GMR_FS_MII_ERR | GMR_FS_GOOD_FC | GMR_FS_BAD_FC | + GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_UN_SIZE | GMR_FS_JABBER, }; @@ -1933,6 +1933,7 @@ struct sky2_hw { dma_addr_t st_dma; struct timer_list idle_timer; + struct work_struct restart_work; int msi; wait_queue_head_t msi_wait; }; diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 61708cf4c85..8897f538a7c 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -26,7 +26,7 @@ config WAN # There is no way to detect a comtrol sv11 - force it modular for now. config HOSTESS_SV11 tristate "Comtrol Hostess SV-11 support" - depends on WAN && ISA && m && ISA_DMA_API + depends on WAN && ISA && m && ISA_DMA_API && INET help Driver for Comtrol Hostess SV-11 network card which operates on low speed synchronous serial links at up to diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c index bc156b51678..aff05dba720 100644 --- a/drivers/net/wan/pc300too.c +++ b/drivers/net/wan/pc300too.c @@ -542,7 +542,7 @@ static int __init pc300_init_module(void) CLOCK_BASE = use_crystal_clock ? 24576000 : pci_clock_freq; - return pci_module_init(&pc300_pci_driver); + return pci_register_driver(&pc300_pci_driver); } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 3a064def162..0e790efae68 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -771,6 +771,7 @@ struct bcm43xx_private { * This is currently always BCM43xx_BUSTYPE_PCI */ u8 bustype; + u64 dma_mask; u16 board_vendor; u16 board_type; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index 978ed099e28..6e0dc76400e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -145,16 +145,14 @@ dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring, int tx) { dma_addr_t dmaaddr; + int direction = PCI_DMA_FROMDEVICE; - if (tx) { - dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, - buf, len, - DMA_TO_DEVICE); - } else { - dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, + if (tx) + direction = PCI_DMA_TODEVICE; + + dmaaddr = pci_map_single(ring->bcm->pci_dev, buf, len, - DMA_FROM_DEVICE); - } + direction); return dmaaddr; } @@ -166,13 +164,13 @@ void unmap_descbuffer(struct bcm43xx_dmaring *ring, int tx) { if (tx) { - dma_unmap_single(&ring->bcm->pci_dev->dev, + pci_unmap_single(ring->bcm->pci_dev, addr, len, - DMA_TO_DEVICE); + PCI_DMA_TODEVICE); } else { - dma_unmap_single(&ring->bcm->pci_dev->dev, + pci_unmap_single(ring->bcm->pci_dev, addr, len, - DMA_FROM_DEVICE); + PCI_DMA_FROMDEVICE); } } @@ -183,8 +181,8 @@ void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring, { assert(!ring->tx); - dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev, - addr, len, DMA_FROM_DEVICE); + pci_dma_sync_single_for_cpu(ring->bcm->pci_dev, + addr, len, PCI_DMA_FROMDEVICE); } static inline @@ -194,8 +192,8 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring, { assert(!ring->tx); - dma_sync_single_for_device(&ring->bcm->pci_dev->dev, - addr, len, DMA_FROM_DEVICE); + pci_dma_sync_single_for_cpu(ring->bcm->pci_dev, + addr, len, PCI_DMA_TODEVICE); } /* Unmap and free a descriptor buffer. */ @@ -214,17 +212,53 @@ void free_descriptor_buffer(struct bcm43xx_dmaring *ring, static int alloc_ringmemory(struct bcm43xx_dmaring *ring) { - struct device *dev = &(ring->bcm->pci_dev->dev); - - ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, - &(ring->dmabase), GFP_KERNEL); + ring->descbase = pci_alloc_consistent(ring->bcm->pci_dev, BCM43xx_DMA_RINGMEMSIZE, + &(ring->dmabase)); if (!ring->descbase) { - printk(KERN_ERR PFX "DMA ringmemory allocation failed\n"); - return -ENOMEM; + /* Allocation may have failed due to pci_alloc_consistent + insisting on use of GFP_DMA, which is more restrictive + than necessary... */ + struct dma_desc *rx_ring; + dma_addr_t rx_ring_dma; + + rx_ring = kzalloc(BCM43xx_DMA_RINGMEMSIZE, GFP_KERNEL); + if (!rx_ring) + goto out_err; + + rx_ring_dma = pci_map_single(ring->bcm->pci_dev, rx_ring, + BCM43xx_DMA_RINGMEMSIZE, + PCI_DMA_BIDIRECTIONAL); + + if (pci_dma_mapping_error(rx_ring_dma) || + rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) { + /* Sigh... */ + if (!pci_dma_mapping_error(rx_ring_dma)) + pci_unmap_single(ring->bcm->pci_dev, + rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE, + PCI_DMA_BIDIRECTIONAL); + rx_ring_dma = pci_map_single(ring->bcm->pci_dev, + rx_ring, BCM43xx_DMA_RINGMEMSIZE, + PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(rx_ring_dma) || + rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) { + assert(0); + if (!pci_dma_mapping_error(rx_ring_dma)) + pci_unmap_single(ring->bcm->pci_dev, + rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE, + PCI_DMA_BIDIRECTIONAL); + goto out_err; + } + } + + ring->descbase = rx_ring; + ring->dmabase = rx_ring_dma; } memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE); return 0; +out_err: + printk(KERN_ERR PFX "DMA ringmemory allocation failed\n"); + return -ENOMEM; } static void free_ringmemory(struct bcm43xx_dmaring *ring) @@ -407,6 +441,29 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, if (unlikely(!skb)) return -ENOMEM; dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); + /* This hardware bug work-around adapted from the b44 driver. + The chip may be unable to do PCI DMA to/from anything above 1GB */ + if (pci_dma_mapping_error(dmaaddr) || + dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) { + /* This one has 30-bit addressing... */ + if (!pci_dma_mapping_error(dmaaddr)) + pci_unmap_single(ring->bcm->pci_dev, + dmaaddr, ring->rx_buffersize, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); + skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA); + if (skb == NULL) + return -ENOMEM; + dmaaddr = pci_map_single(ring->bcm->pci_dev, + skb->data, ring->rx_buffersize, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(dmaaddr) || + dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) { + assert(0); + dev_kfree_skb_any(skb); + return -ENOMEM; + } + } meta->skb = skb; meta->dmaaddr = dmaaddr; skb->dev = ring->bcm->net_dev; @@ -636,8 +693,10 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm, err = dmacontroller_setup(ring); if (err) goto err_free_ringmemory; + return ring; out: + printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n"); return ring; err_free_ringmemory: @@ -705,30 +764,16 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm) struct bcm43xx_dmaring *ring; int err = -ENOMEM; int dma64 = 0; - u64 mask = bcm43xx_get_supported_dma_mask(bcm); - int nobits; - if (mask == DMA_64BIT_MASK) { + bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm); + if (bcm->dma_mask == DMA_64BIT_MASK) dma64 = 1; - nobits = 64; - } else if (mask == DMA_32BIT_MASK) - nobits = 32; - else - nobits = 30; - err = pci_set_dma_mask(bcm->pci_dev, mask); - err |= pci_set_consistent_dma_mask(bcm->pci_dev, mask); - if (err) { -#ifdef CONFIG_BCM43XX_PIO - printk(KERN_WARNING PFX "DMA not supported on this device." - " Falling back to PIO.\n"); - bcm->__using_pio = 1; - return -ENOSYS; -#else - printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " - "Please recompile the driver with PIO support.\n"); - return -ENODEV; -#endif /* CONFIG_BCM43XX_PIO */ - } + err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask); + if (err) + goto no_dma; + err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask); + if (err) + goto no_dma; /* setup TX DMA channels. */ ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64); @@ -774,7 +819,9 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm) dma->rx_ring3 = ring; } - dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits); + dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", + (bcm->dma_mask == DMA_64BIT_MASK) ? 64 : + (bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30); err = 0; out: return err; @@ -800,7 +847,17 @@ err_destroy_tx1: err_destroy_tx0: bcm43xx_destroy_dmaring(dma->tx_ring0); dma->tx_ring0 = NULL; - goto out; +no_dma: +#ifdef CONFIG_BCM43XX_PIO + printk(KERN_WARNING PFX "DMA not supported on this device." + " Falling back to PIO.\n"); + bcm->__using_pio = 1; + return -ENOSYS; +#else + printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " + "Please recompile the driver with PIO support.\n"); + return -ENODEV; +#endif /* CONFIG_BCM43XX_PIO */ } /* Generate a cookie for the TX header. */ @@ -905,6 +962,7 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring, struct bcm43xx_dmadesc_generic *desc; struct bcm43xx_dmadesc_meta *meta; dma_addr_t dmaaddr; + struct sk_buff *bounce_skb; assert(skb_shinfo(skb)->nr_frags == 0); @@ -924,9 +982,28 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring, skb->len - sizeof(struct bcm43xx_txhdr), (cur_frag == 0), generate_cookie(ring, slot)); + dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) { + /* chip cannot handle DMA to/from > 1GB, use bounce buffer (copied from b44 driver) */ + if (!dma_mapping_error(dmaaddr)) + unmap_descbuffer(ring, dmaaddr, skb->len, 1); + bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC|GFP_DMA); + if (!bounce_skb) + return; + dmaaddr = map_descbuffer(ring, bounce_skb->data, bounce_skb->len, 1); + if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) { + if (!dma_mapping_error(dmaaddr)) + unmap_descbuffer(ring, dmaaddr, skb->len, 1); + dev_kfree_skb_any(bounce_skb); + assert(0); + return; + } + memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); + dev_kfree_skb_any(skb); + skb = bounce_skb; + } meta->skb = skb; - dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); meta->dmaaddr = dmaaddr; fill_descriptor(ring, desc, dmaaddr, diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 23aaf1ed854..2e400aacc43 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -95,13 +95,9 @@ static int modparam_noleds; module_param_named(noleds, modparam_noleds, int, 0444); MODULE_PARM_DESC(noleds, "Turn off all LED activity"); -#ifdef CONFIG_BCM43XX_DEBUG static char modparam_fwpostfix[64]; module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444); -MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging."); -#else -# define modparam_fwpostfix "" -#endif /* CONFIG_BCM43XX_DEBUG*/ +MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple firmware image versions."); /* If you want to debug with just a single device, enable this, @@ -2983,8 +2979,10 @@ static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm) err = bcm43xx_pctl_set_crystal(bcm, 1); if (err) goto out; - bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status); - bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT); + err = bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status); + if (err) + goto out; + err = bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT); out: return err; @@ -3796,12 +3794,18 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) } net_dev->base_addr = (unsigned long)bcm->mmio_addr; - bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, + err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, &bcm->board_vendor); - bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID, + if (err) + goto err_iounmap; + err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID, &bcm->board_type); - bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID, + if (err) + goto err_iounmap; + err = bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID, &bcm->board_revision); + if (err) + goto err_iounmap; err = bcm43xx_chipset_attach(bcm); if (err) @@ -3892,6 +3896,7 @@ err_pci_release: pci_release_regions(pci_dev); err_pci_disable: pci_disable_device(pci_dev); + printk(KERN_ERR PFX "Unable to attach board\n"); goto out; } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index d2ca949174f..7b665e2386a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -260,22 +260,22 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, if (phy->type == BCM43xx_PHYTYPE_A || phy->type == BCM43xx_PHYTYPE_G) { range->num_bitrates = 8; - range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB * 500000; } if (phy->type == BCM43xx_PHYTYPE_B || phy->type == BCM43xx_PHYTYPE_G) { range->num_bitrates += 4; - range->bitrate[i++] = IEEE80211_CCK_RATE_1MB; - range->bitrate[i++] = IEEE80211_CCK_RATE_2MB; - range->bitrate[i++] = IEEE80211_CCK_RATE_5MB; - range->bitrate[i++] = IEEE80211_CCK_RATE_11MB; + range->bitrate[i++] = IEEE80211_CCK_RATE_1MB * 500000; + range->bitrate[i++] = IEEE80211_CCK_RATE_2MB * 500000; + range->bitrate[i++] = IEEE80211_CCK_RATE_5MB * 500000; + range->bitrate[i++] = IEEE80211_CCK_RATE_11MB * 500000; } geo = ieee80211_get_geo(bcm->ieee); @@ -285,7 +285,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, if (j == IW_MAX_FREQUENCIES) break; range->freq[j].i = j + 1; - range->freq[j].m = geo->a[i].freq;//FIXME? + range->freq[j].m = geo->a[i].freq * 100000; range->freq[j].e = 1; j++; } @@ -293,7 +293,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, if (j == IW_MAX_FREQUENCIES) break; range->freq[j].i = j + 1; - range->freq[j].m = geo->bg[i].freq;//FIXME? + range->freq[j].m = geo->bg[i].freq * 100000; range->freq[j].e = 1; j++; } diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index b85857a8487..d0639a45cd2 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -175,7 +175,7 @@ that only one external action is invoked at a time. /* Debugging stuff */ #ifdef CONFIG_IPW2100_DEBUG -#define CONFIG_IPW2100_RX_DEBUG /* Reception debugging */ +#define IPW2100_RX_DEBUG /* Reception debugging */ #endif MODULE_DESCRIPTION(DRV_DESCRIPTION); @@ -2239,7 +2239,7 @@ static void ipw2100_snapshot_free(struct ipw2100_priv *priv) priv->snapshot[0] = NULL; } -#ifdef CONFIG_IPW2100_DEBUG_C3 +#ifdef IPW2100_DEBUG_C3 static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv) { int i; @@ -2314,13 +2314,13 @@ static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf, * The size of the constructed ethernet * */ -#ifdef CONFIG_IPW2100_RX_DEBUG +#ifdef IPW2100_RX_DEBUG static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH]; #endif static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i) { -#ifdef CONFIG_IPW2100_DEBUG_C3 +#ifdef IPW2100_DEBUG_C3 struct ipw2100_status *status = &priv->status_queue.drv[i]; u32 match, reg; int j; @@ -2342,7 +2342,7 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i) } #endif -#ifdef CONFIG_IPW2100_DEBUG_C3 +#ifdef IPW2100_DEBUG_C3 /* Halt the fimrware so we can get a good image */ write_register(priv->net_dev, IPW_REG_RESET_REG, IPW_AUX_HOST_RESET_REG_STOP_MASTER); @@ -2413,7 +2413,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i, skb_put(packet->skb, status->frame_size); -#ifdef CONFIG_IPW2100_RX_DEBUG +#ifdef IPW2100_RX_DEBUG /* Make a copy of the frame so we can dump it to the logs if * ieee80211_rx fails */ memcpy(packet_data, packet->skb->data, @@ -2421,7 +2421,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i, #endif if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { -#ifdef CONFIG_IPW2100_RX_DEBUG +#ifdef IPW2100_RX_DEBUG IPW_DEBUG_DROP("%s: Non consumed packet:\n", priv->net_dev->name); printk_buf(IPW_DL_DROP, packet_data, status->frame_size); @@ -4912,7 +4912,7 @@ static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level) else priv->power_mode = IPW_POWER_ENABLED | power_level; -#ifdef CONFIG_IPW2100_TX_POWER +#ifdef IPW2100_TX_POWER if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) { /* Set beacon interval */ cmd.host_command = TX_POWER_INDEX; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index a08524191b5..4c5f78eac34 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -156,7 +156,7 @@ void zd_mac_clear(struct zd_mac *mac) static int reset_mode(struct zd_mac *mac) { struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - struct zd_ioreq32 ioreqs[3] = { + struct zd_ioreq32 ioreqs[] = { { CR_RX_FILTER, STA_RX_FILTER }, { CR_SNIFFER_ON, 0U }, }; @@ -164,10 +164,9 @@ static int reset_mode(struct zd_mac *mac) if (ieee->iw_mode == IW_MODE_MONITOR) { ioreqs[0].value = 0xffffffff; ioreqs[1].value = 0x1; - ioreqs[2].value = ENC_SNIFFER; } - return zd_iowrite32a(&mac->chip, ioreqs, 3); + return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs)); } int zd_mac_open(struct net_device *netdev) @@ -904,16 +903,21 @@ static int fill_ctrlset(struct zd_mac *mac, static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri) { int i, r; + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); for (i = 0; i < txb->nr_frags; i++) { struct sk_buff *skb = txb->fragments[i]; r = fill_ctrlset(mac, txb, i); - if (r) + if (r) { + ieee->stats.tx_dropped++; return r; + } r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len); - if (r) + if (r) { + ieee->stats.tx_dropped++; return r; + } } /* FIXME: shouldn't this be handled by the upper layers? */ @@ -1063,9 +1067,23 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats, *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status)); if (status->frame_status & ZD_RX_ERROR) { - /* FIXME: update? */ + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + ieee->stats.rx_errors++; + if (status->frame_status & ZD_RX_TIMEOUT_ERROR) + ieee->stats.rx_missed_errors++; + else if (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR) + ieee->stats.rx_fifo_errors++; + else if (status->frame_status & ZD_RX_DECRYPTION_ERROR) + ieee->ieee_stats.rx_discards_undecryptable++; + else if (status->frame_status & ZD_RX_CRC32_ERROR) { + ieee->stats.rx_crc_errors++; + ieee->ieee_stats.rx_fcs_errors++; + } + else if (status->frame_status & ZD_RX_CRC16_ERROR) + ieee->stats.rx_crc_errors++; return -EINVAL; } + memset(stats, 0, sizeof(struct ieee80211_rx_stats)); stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN + + sizeof(struct rx_status)); @@ -1094,14 +1112,16 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb) if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN + IEEE80211_FCS_LEN + sizeof(struct rx_status)) { - dev_dbg_f(zd_mac_dev(mac), "Packet with length %u to small.\n", - skb->len); + ieee->stats.rx_errors++; + ieee->stats.rx_length_errors++; goto free_skb; } r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len); if (r) { - /* Only packets with rx errors are included here. */ + /* Only packets with rx errors are included here. + * The error stats have already been set in fill_rx_stats. + */ goto free_skb; } @@ -1114,8 +1134,10 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb) r = filter_rx(ieee, skb->data, skb->len, &stats); if (r <= 0) { - if (r < 0) + if (r < 0) { + ieee->stats.rx_errors++; dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n"); + } goto free_skb; } @@ -1146,7 +1168,9 @@ int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length) skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length); if (!skb) { + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n"); + ieee->stats.rx_dropped++; return -ENOMEM; } skb_reserve(skb, sizeof(struct zd_rt_hdr)); diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 75ef55624d7..aac8a1c5ba0 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -313,6 +313,12 @@ out: static inline void handle_retry_failed_int(struct urb *urb) { + struct zd_usb *usb = urb->context; + struct zd_mac *mac = zd_usb_to_mac(usb); + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + + ieee->stats.tx_errors++; + ieee->ieee_stats.tx_retry_limit_exceeded++; dev_dbg_f(urb_dev(urb), "retry failed interrupt\n"); } @@ -487,6 +493,9 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, if (length < sizeof(struct rx_length_info)) { /* It's not a complete packet anyhow. */ + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + ieee->stats.rx_errors++; + ieee->stats.rx_length_errors++; return; } length_info = (struct rx_length_info *) @@ -923,6 +932,8 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id) goto error; } + usb_reset_device(interface_to_usbdev(intf)); + netdev = zd_netdev_alloc(intf); if (netdev == NULL) { r = -ENOMEM; @@ -1024,6 +1035,7 @@ static int __init usb_init(void) r = usb_register(&driver); if (r) { + destroy_workqueue(zd_workqueue); printk(KERN_ERR "%s usb_register() failed. Error number %d\n", driver.name, r); return r; diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 4438ae1ede4..a3c1755b2f2 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -415,6 +415,7 @@ static struct kobj_type pci_driver_kobj_type = { * __pci_register_driver - register a new pci driver * @drv: the driver structure to register * @owner: owner module of drv + * @mod_name: module name string * * Adds the driver structure to the list of registered drivers. * Returns a negative value on error, otherwise 0. diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 7a94076752d..cd913a2a416 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -143,6 +143,14 @@ static ssize_t is_enabled_show(struct device *dev, return sprintf (buf, "%u\n", atomic_read(&pdev->enable_cnt)); } +#ifdef CONFIG_NUMA +static ssize_t +numa_node_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf (buf, "%d\n", dev->numa_node); +} +#endif + static ssize_t msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -194,6 +202,9 @@ struct device_attribute pci_dev_attrs[] = { __ATTR_RO(irq), __ATTR_RO(local_cpus), __ATTR_RO(modalias), +#ifdef CONFIG_NUMA + __ATTR_RO(numa_node), +#endif __ATTR(enable, 0600, is_enabled_show, is_enabled_store), __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), broken_parity_status_show,broken_parity_status_store), diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8b44cff2c17..1e74e1ee8bd 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -21,6 +21,12 @@ unsigned int pci_pm_d3_delay = 10; +#define DEFAULT_CARDBUS_IO_SIZE (256) +#define DEFAULT_CARDBUS_MEM_SIZE (64*1024*1024) +/* pci=cbmemsize=nnM,cbiosize=nn can override this */ +unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE; +unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; + /** * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children * @bus: pointer to PCI bus structure to search @@ -1300,7 +1306,7 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) /** * pci_select_bars - Make BAR mask from the type of resource - * @pdev: the PCI device for which BAR mask is made + * @dev: the PCI device for which BAR mask is made * @flags: resource type mask to be selected * * This helper routine makes bar mask from the type of resource. @@ -1333,6 +1339,10 @@ static int __devinit pci_setup(char *str) if (*str && (str = pcibios_setup(str)) && *str) { if (!strcmp(str, "nomsi")) { pci_no_msi(); + } else if (!strncmp(str, "cbiosize=", 9)) { + pci_cardbus_io_size = memparse(str + 9, &str); + } else if (!strncmp(str, "cbmemsize=", 10)) { + pci_cardbus_mem_size = memparse(str + 10, &str); } else { printk(KERN_ERR "PCI: Unknown option `%s'\n", str); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 89f3036f0de..3554f394881 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -36,13 +36,6 @@ #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) -/* - * FIXME: IO should be max 256 bytes. However, since we may - * have a P2P bridge below a cardbus bridge, we need 4K. - */ -#define CARDBUS_IO_SIZE (256) -#define CARDBUS_MEM_SIZE (64*1024*1024) - static void __devinit pbus_assign_resources_sorted(struct pci_bus *bus) { @@ -415,12 +408,12 @@ pci_bus_size_cardbus(struct pci_bus *bus) * Reserve some resources for CardBus. We reserve * a fixed amount of bus space for CardBus bridges. */ - b_res[0].start = CARDBUS_IO_SIZE; - b_res[0].end = b_res[0].start + CARDBUS_IO_SIZE - 1; + b_res[0].start = pci_cardbus_io_size; + b_res[0].end = b_res[0].start + pci_cardbus_io_size - 1; b_res[0].flags |= IORESOURCE_IO; - b_res[1].start = CARDBUS_IO_SIZE; - b_res[1].end = b_res[1].start + CARDBUS_IO_SIZE - 1; + b_res[1].start = pci_cardbus_io_size; + b_res[1].end = b_res[1].start + pci_cardbus_io_size - 1; b_res[1].flags |= IORESOURCE_IO; /* @@ -440,16 +433,16 @@ pci_bus_size_cardbus(struct pci_bus *bus) * twice the size. */ if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) { - b_res[2].start = CARDBUS_MEM_SIZE; - b_res[2].end = b_res[2].start + CARDBUS_MEM_SIZE - 1; + b_res[2].start = pci_cardbus_mem_size; + b_res[2].end = b_res[2].start + pci_cardbus_mem_size - 1; b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; - b_res[3].start = CARDBUS_MEM_SIZE; - b_res[3].end = b_res[3].start + CARDBUS_MEM_SIZE - 1; + b_res[3].start = pci_cardbus_mem_size; + b_res[3].end = b_res[3].start + pci_cardbus_mem_size - 1; b_res[3].flags |= IORESOURCE_MEM; } else { - b_res[3].start = CARDBUS_MEM_SIZE * 2; - b_res[3].end = b_res[3].start + CARDBUS_MEM_SIZE * 2 - 1; + b_res[3].start = pci_cardbus_mem_size * 2; + b_res[3].end = b_res[3].start + pci_cardbus_mem_size * 2 - 1; b_res[3].flags |= IORESOURCE_MEM; } } diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index a251289c995..568f1877315 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -24,7 +24,7 @@ pdev_fixup_irq(struct pci_dev *dev, int (*map_irq)(struct pci_dev *, u8, u8)) { u8 pin, slot; - int irq; + int irq = 0; /* If this device is not on the primary bus, we need to figure out which interrupt pin it will come in on. We know which slot it @@ -33,16 +33,18 @@ pdev_fixup_irq(struct pci_dev *dev, apply the swizzle function. */ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - /* Cope with 0 and illegal. */ - if (pin == 0 || pin > 4) + /* Cope with illegal. */ + if (pin > 4) pin = 1; - /* Follow the chain of bridges, swizzling as we go. */ - slot = (*swizzle)(dev, &pin); + if (pin != 0) { + /* Follow the chain of bridges, swizzling as we go. */ + slot = (*swizzle)(dev, &pin); - irq = (*map_irq)(dev, slot, pin); - if (irq == -1) - irq = 0; + irq = (*map_irq)(dev, slot, pin); + if (irq == -1) + irq = 0; + } dev->irq = irq; pr_debug("PCI: fixup irq: (%s) got %d\n", diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index b3186283753..99baabc2359 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c @@ -277,7 +277,7 @@ static int __init at91_cf_probe(struct platform_device *pdev) board->det_pin, board->irq_pin); cf->socket.owner = THIS_MODULE; - cf->socket.dev.dev = &pdev->dev; + cf->socket.dev.parent = &pdev->dev; cf->socket.ops = &at91_cf_ops; cf->socket.resource_ops = &pccard_static_ops; cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index d2a3bea55de..aa7779d8975 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -478,7 +478,7 @@ dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, i * * Returns: the number of characters added to the buffer */ -static ssize_t show_status(struct device *dev, char *buf) +static ssize_t show_status(struct device *dev, struct device_attribute *attr, char *buf) { struct soc_pcmcia_socket *skt = container_of(dev, struct soc_pcmcia_socket, socket.dev); @@ -501,7 +501,7 @@ static ssize_t show_status(struct device *dev, char *buf) return p-buf; } -static CLASS_DEVICE_ATTR(status, S_IRUGO, show_status, NULL); +static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); static struct pccard_operations soc_common_pcmcia_operations = { @@ -660,7 +660,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops skt->socket.ops = &soc_common_pcmcia_operations; skt->socket.owner = ops->owner; - skt->socket.dev.dev = dev; + skt->socket.dev.parent = dev; init_timer(&skt->poll_timer); skt->poll_timer.function = soc_common_pcmcia_poll_event; @@ -747,7 +747,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops add_timer(&skt->poll_timer); - device_create_file(&skt->socket.dev, &device_attr_status); + device_create_file(&skt->socket.dev, &dev_attr_status); } dev_set_drvdata(dev, sinfo); diff --git a/drivers/pnp/pnpacpi/Kconfig b/drivers/pnp/pnpacpi/Kconfig index ad27e5e0101..b04767ce273 100644 --- a/drivers/pnp/pnpacpi/Kconfig +++ b/drivers/pnp/pnpacpi/Kconfig @@ -2,17 +2,5 @@ # Plug and Play ACPI configuration # config PNPACPI - bool "Plug and Play ACPI support" - depends on PNP && ACPI - default y - ---help--- - Linux uses the PNPACPI to autodetect built-in - mainboard resources (e.g. parallel port resources). - - Some features (e.g. real hotplug) are not currently - implemented. - - If you would like the kernel to detect and allocate resources to - your mainboard devices (on some systems they are disabled by the - BIOS) say Y here. Also the PNPACPI can help prevent resource - conflicts between mainboard devices and other bus devices. + bool + default (PNP && ACPI) diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile index 96958c03cf6..e251d1c1171 100644 --- a/drivers/ps3/Makefile +++ b/drivers/ps3/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_PS3_VUART) += vuart.o obj-$(CONFIG_PS3_PS3AV) += ps3av.o ps3av_cmd.o +obj-$(CONFIG_PS3_SYS_MANAGER) += sys-manager.o diff --git a/drivers/ps3/sys-manager.c b/drivers/ps3/sys-manager.c new file mode 100644 index 00000000000..0fc30be8b81 --- /dev/null +++ b/drivers/ps3/sys-manager.c @@ -0,0 +1,604 @@ +/* + * PS3 System Manager. + * + * Copyright (C) 2007 Sony Computer Entertainment Inc. + * Copyright 2007 Sony Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/workqueue.h> +#include <linux/reboot.h> +#include <asm/ps3.h> +#include "vuart.h" + +MODULE_AUTHOR("Sony Corporation"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("PS3 System Manager"); + +/** + * ps3_sys_manager - PS3 system manager driver. + * + * The system manager provides an asyncronous system event notification + * mechanism for reporting events like thermal alert and button presses to + * guests. It also provides support to control system shutdown and startup. + * + * The actual system manager is implemented as an application running in the + * system policy module in lpar_1. Guests communicate with the system manager + * through port 2 of the vuart using a simple packet message protocol. + * Messages are comprised of a fixed field header followed by a message + * specific payload. + */ + +/** + * struct ps3_sys_manager_header - System manager message header. + * @version: Header version, currently 1. + * @size: Header size in bytes, curently 16. + * @payload_size: Message payload size in bytes. + * @service_id: Message type, one of enum ps3_sys_manager_service_id. + */ + +struct ps3_sys_manager_header { + /* version 1 */ + u8 version; + u8 size; + u16 reserved_1; + u32 payload_size; + u16 service_id; + u16 reserved_2[3]; +}; + +/** + * @PS3_SM_RX_MSG_LEN - System manager received message length. + * + * Currently all messages received from the system manager are the same length + * (16 bytes header + 16 bytes payload = 32 bytes). This knowlege is used to + * simplify the logic. + */ + +enum { + PS3_SM_RX_MSG_LEN = 32, +}; + +/** + * enum ps3_sys_manager_service_id - Message header service_id. + * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager. + * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager. + * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager. + * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager. + * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager. + * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager. + */ + +enum ps3_sys_manager_service_id { + /* version 1 */ + PS3_SM_SERVICE_ID_REQUEST = 1, + PS3_SM_SERVICE_ID_RESPONSE = 2, + PS3_SM_SERVICE_ID_COMMAND = 3, + PS3_SM_SERVICE_ID_EXTERN_EVENT = 4, + PS3_SM_SERVICE_ID_SET_NEXT_OP = 5, + PS3_SM_SERVICE_ID_SET_ATTR = 8, +}; + +/** + * enum ps3_sys_manager_attr - Notification attribute (bit position mask). + * @PS3_SM_ATTR_POWER: Power button. + * @PS3_SM_ATTR_RESET: Reset button, not available on retail console. + * @PS3_SM_ATTR_THERMAL: Sytem thermal alert. + * @PS3_SM_ATTR_CONTROLLER: Remote controller event. + * @PS3_SM_ATTR_ALL: Logical OR of all. + * + * The guest tells the system manager which events it is interested in receiving + * notice of by sending the system manager a logical OR of notification + * attributes via the ps3_sys_manager_send_attr() routine. + */ + +enum ps3_sys_manager_attr { + /* version 1 */ + PS3_SM_ATTR_POWER = 1, + PS3_SM_ATTR_RESET = 2, + PS3_SM_ATTR_THERMAL = 4, + PS3_SM_ATTR_CONTROLLER = 8, /* bogus? */ + PS3_SM_ATTR_ALL = 0x0f, +}; + +/** + * enum ps3_sys_manager_event - External event type, reported by system manager. + * @PS3_SM_EVENT_POWER_PRESSED: payload.value not used. + * @PS3_SM_EVENT_POWER_RELEASED: payload.value = time pressed in millisec. + * @PS3_SM_EVENT_RESET_PRESSED: payload.value not used. + * @PS3_SM_EVENT_RESET_RELEASED: payload.value = time pressed in millisec. + * @PS3_SM_EVENT_THERMAL_ALERT: payload.value = thermal zone id. + * @PS3_SM_EVENT_THERMAL_CLEARED: payload.value = thermal zone id. + */ + +enum ps3_sys_manager_event { + /* version 1 */ + PS3_SM_EVENT_POWER_PRESSED = 3, + PS3_SM_EVENT_POWER_RELEASED = 4, + PS3_SM_EVENT_RESET_PRESSED = 5, + PS3_SM_EVENT_RESET_RELEASED = 6, + PS3_SM_EVENT_THERMAL_ALERT = 7, + PS3_SM_EVENT_THERMAL_CLEARED = 8, + /* no info on controller events */ +}; + +/** + * enum ps3_sys_manager_next_op - Operation to perform after lpar is destroyed. + */ + +enum ps3_sys_manager_next_op { + /* version 3 */ + PS3_SM_NEXT_OP_SYS_SHUTDOWN = 1, + PS3_SM_NEXT_OP_SYS_REBOOT = 2, + PS3_SM_NEXT_OP_LPAR_REBOOT = 0x82, +}; + +/** + * enum ps3_sys_manager_wake_source - Next-op wakeup source (bit position mask). + * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button, IR + * controller, and bluetooth controller. + * @PS3_SM_WAKE_RTC: + * @PS3_SM_WAKE_RTC_ERROR: + * @PS3_SM_WAKE_P_O_R: Power on reset. + * + * Additional wakeup sources when specifying PS3_SM_NEXT_OP_SYS_SHUTDOWN. + * System will always wake from the PS3_SM_WAKE_DEFAULT sources. + */ + +enum ps3_sys_manager_wake_source { + /* version 3 */ + PS3_SM_WAKE_DEFAULT = 0, + PS3_SM_WAKE_RTC = 0x00000040, + PS3_SM_WAKE_RTC_ERROR = 0x00000080, + PS3_SM_WAKE_P_O_R = 0x10000000, +}; + +/** + * enum ps3_sys_manager_cmd - Command from system manager to guest. + * + * The guest completes the actions needed, then acks or naks the command via + * ps3_sys_manager_send_response(). In the case of @PS3_SM_CMD_SHUTDOWN, + * the guest must be fully prepared for a system poweroff prior to acking the + * command. + */ + +enum ps3_sys_manager_cmd { + /* version 1 */ + PS3_SM_CMD_SHUTDOWN = 1, /* shutdown guest OS */ +}; + +/** + * ps3_sys_manager_write - Helper to write a two part message to the vuart. + * + */ + +static int ps3_sys_manager_write(struct ps3_vuart_port_device *dev, + const struct ps3_sys_manager_header *header, const void *payload) +{ + int result; + + BUG_ON(header->version != 1); + BUG_ON(header->size != 16); + BUG_ON(header->payload_size != 8 && header->payload_size != 16); + BUG_ON(header->service_id > 8); + + result = ps3_vuart_write(dev, header, + sizeof(struct ps3_sys_manager_header)); + + if (!result) + result = ps3_vuart_write(dev, payload, header->payload_size); + + return result; +} + +/** + * ps3_sys_manager_send_attr - Send a 'set attribute' to the system manager. + * + */ + +static int ps3_sys_manager_send_attr(struct ps3_vuart_port_device *dev, + enum ps3_sys_manager_attr attr) +{ + static const struct ps3_sys_manager_header header = { + .version = 1, + .size = 16, + .payload_size = 16, + .service_id = PS3_SM_SERVICE_ID_SET_ATTR, + }; + struct { + u8 version; + u8 reserved_1[3]; + u32 attribute; + } payload; + + BUILD_BUG_ON(sizeof(payload) != 8); + + dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr); + + memset(&payload, 0, sizeof(payload)); + payload.version = 1; + payload.attribute = attr; + + return ps3_sys_manager_write(dev, &header, &payload); +} + +/** + * ps3_sys_manager_send_next_op - Send a 'set next op' to the system manager. + * + * Tell the system manager what to do after this lpar is destroyed. + */ + +static int ps3_sys_manager_send_next_op(struct ps3_vuart_port_device *dev, + enum ps3_sys_manager_next_op op, + enum ps3_sys_manager_wake_source wake_source) +{ + static const struct ps3_sys_manager_header header = { + .version = 1, + .size = 16, + .payload_size = 16, + .service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP, + }; + struct { + u8 version; + u8 type; + u8 gos_id; + u8 reserved_1; + u32 wake_source; + u8 reserved_2[8]; + } payload; + + BUILD_BUG_ON(sizeof(payload) != 16); + + dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op); + + memset(&payload, 0, sizeof(payload)); + payload.version = 3; + payload.type = op; + payload.gos_id = 3; /* other os */ + payload.wake_source = wake_source; + + return ps3_sys_manager_write(dev, &header, &payload); +} + +/** + * ps3_sys_manager_send_request_shutdown - Send 'request' to the system manager. + * + * The guest sends this message to request an operation or action of the system + * manager. The reply is a command message from the system manager. In the + * command handler the guest performs the requested operation. The result of + * the command is then communicated back to the system manager with a response + * message. + * + * Currently, the only supported request it the 'shutdown self' request. + */ + +static int ps3_sys_manager_send_request_shutdown(struct ps3_vuart_port_device *dev) +{ + static const struct ps3_sys_manager_header header = { + .version = 1, + .size = 16, + .payload_size = 16, + .service_id = PS3_SM_SERVICE_ID_REQUEST, + }; + struct { + u8 version; + u8 type; + u8 gos_id; + u8 reserved_1[13]; + } static const payload = { + .version = 1, + .type = 1, /* shutdown */ + .gos_id = 0, /* self */ + }; + + BUILD_BUG_ON(sizeof(payload) != 16); + + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); + + return ps3_sys_manager_write(dev, &header, &payload); +} + +/** + * ps3_sys_manager_send_response - Send a 'response' to the system manager. + * @status: zero = success, others fail. + * + * The guest sends this message to the system manager to acnowledge success or + * failure of a command sent by the system manager. + */ + +static int ps3_sys_manager_send_response(struct ps3_vuart_port_device *dev, + u64 status) +{ + static const struct ps3_sys_manager_header header = { + .version = 1, + .size = 16, + .payload_size = 16, + .service_id = PS3_SM_SERVICE_ID_RESPONSE, + }; + struct { + u8 version; + u8 reserved_1[3]; + u8 status; + u8 reserved_2[11]; + } payload; + + BUILD_BUG_ON(sizeof(payload) != 16); + + dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, + (status ? "nak" : "ack")); + + memset(&payload, 0, sizeof(payload)); + payload.version = 1; + payload.status = status; + + return ps3_sys_manager_write(dev, &header, &payload); +} + +/** + * ps3_sys_manager_handle_event - Second stage event msg handler. + * + */ + +static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev) +{ + int result; + struct { + u8 version; + u8 type; + u8 reserved_1[2]; + u32 value; + u8 reserved_2[8]; + } event; + + BUILD_BUG_ON(sizeof(event) != 16); + + result = ps3_vuart_read(dev, &event, sizeof(event)); + BUG_ON(result); + + if (event.version != 1) { + dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n", + __func__, __LINE__, event.version); + return -EIO; + } + + switch (event.type) { + case PS3_SM_EVENT_POWER_PRESSED: + dev_dbg(&dev->core, "%s:%d: POWER_PRESSED\n", + __func__, __LINE__); + break; + case PS3_SM_EVENT_POWER_RELEASED: + dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n", + __func__, __LINE__, event.value); + kill_cad_pid(SIGINT, 1); + break; + case PS3_SM_EVENT_THERMAL_ALERT: + dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n", + __func__, __LINE__, event.value); + printk(KERN_INFO "PS3 Thermal Alert Zone %u\n", event.value); + break; + case PS3_SM_EVENT_THERMAL_CLEARED: + dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n", + __func__, __LINE__, event.value); + break; + default: + dev_dbg(&dev->core, "%s:%d: unknown event (%u)\n", + __func__, __LINE__, event.type); + return -EIO; + } + + return 0; +} +/** + * ps3_sys_manager_handle_cmd - Second stage command msg handler. + * + * The system manager sends this in reply to a 'request' message from the guest. + */ + +static int ps3_sys_manager_handle_cmd(struct ps3_vuart_port_device *dev) +{ + int result; + struct { + u8 version; + u8 type; + u8 reserved_1[14]; + } cmd; + + BUILD_BUG_ON(sizeof(cmd) != 16); + + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); + + result = ps3_vuart_read(dev, &cmd, sizeof(cmd)); + + if(result) + return result; + + if (cmd.version != 1) { + dev_dbg(&dev->core, "%s:%d: unsupported cmd version (%u)\n", + __func__, __LINE__, cmd.version); + return -EIO; + } + + if (cmd.type != PS3_SM_CMD_SHUTDOWN) { + dev_dbg(&dev->core, "%s:%d: unknown cmd (%u)\n", + __func__, __LINE__, cmd.type); + return -EIO; + } + + ps3_sys_manager_send_response(dev, 0); + return 0; +} + +/** + * ps3_sys_manager_handle_msg - First stage msg handler. + * + */ + +static int ps3_sys_manager_handle_msg(struct ps3_vuart_port_device *dev) +{ + int result; + struct ps3_sys_manager_header header; + + result = ps3_vuart_read(dev, &header, + sizeof(struct ps3_sys_manager_header)); + + if(result) + return result; + + if (header.version != 1) { + dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n", + __func__, __LINE__, header.version); + goto fail_header; + } + + BUILD_BUG_ON(sizeof(header) != 16); + BUG_ON(header.size != 16); + BUG_ON(header.payload_size != 16); + + switch (header.service_id) { + case PS3_SM_SERVICE_ID_EXTERN_EVENT: + dev_dbg(&dev->core, "%s:%d: EVENT\n", __func__, __LINE__); + return ps3_sys_manager_handle_event(dev); + case PS3_SM_SERVICE_ID_COMMAND: + dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__); + return ps3_sys_manager_handle_cmd(dev); + default: + dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n", + __func__, __LINE__, header.service_id); + break; + } + goto fail_id; + +fail_header: + ps3_vuart_clear_rx_bytes(dev, 0); + return -EIO; +fail_id: + ps3_vuart_clear_rx_bytes(dev, header.payload_size); + return -EIO; +} + +/** + * ps3_sys_manager_work - Asyncronous read handler. + * + * Signaled when a complete message arrives at the vuart port. + */ + +static void ps3_sys_manager_work(struct work_struct *work) +{ + struct ps3_vuart_port_device *dev = ps3_vuart_work_to_port_device(work); + + ps3_sys_manager_handle_msg(dev); + ps3_vuart_read_async(dev, ps3_sys_manager_work, PS3_SM_RX_MSG_LEN); +} + +struct { + struct ps3_vuart_port_device *dev; +} static drv_priv; + +/** + * ps3_sys_manager_restart - The final platform machine_restart routine. + * + * This routine never returns. The routine disables asyncronous vuart reads + * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge + * the shutdown command sent from the system manager. Soon after the + * acknowledgement is sent the lpar is destroyed by the HV. This routine + * should only be called from ps3_restart(). + */ + +void ps3_sys_manager_restart(void) +{ + struct ps3_vuart_port_device *dev = drv_priv.dev; + + BUG_ON(!drv_priv.dev); + + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); + + ps3_vuart_cancel_async(dev); + + ps3_sys_manager_send_attr(dev, 0); + ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT, + PS3_SM_WAKE_DEFAULT); + ps3_sys_manager_send_request_shutdown(dev); + + printk(KERN_EMERG "System Halted, OK to turn off power\n"); + + while(1) + ps3_sys_manager_handle_msg(dev); +} + +/** + * ps3_sys_manager_power_off - The final platform machine_power_off routine. + * + * This routine never returns. The routine disables asyncronous vuart reads + * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge + * the shutdown command sent from the system manager. Soon after the + * acknowledgement is sent the lpar is destroyed by the HV. This routine + * should only be called from ps3_power_off(). + */ + +void ps3_sys_manager_power_off(void) +{ + struct ps3_vuart_port_device *dev = drv_priv.dev; + + BUG_ON(!drv_priv.dev); + + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); + + ps3_vuart_cancel_async(dev); + + ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN, + PS3_SM_WAKE_DEFAULT); + ps3_sys_manager_send_request_shutdown(dev); + + printk(KERN_EMERG "System Halted, OK to turn off power\n"); + + while(1) + ps3_sys_manager_handle_msg(dev); +} + +static int ps3_sys_manager_probe(struct ps3_vuart_port_device *dev) +{ + int result; + + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); + + BUG_ON(drv_priv.dev); + drv_priv.dev = dev; + + result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL); + BUG_ON(result); + + result = ps3_vuart_read_async(dev, ps3_sys_manager_work, + PS3_SM_RX_MSG_LEN); + BUG_ON(result); + + return result; +} + +static struct ps3_vuart_port_driver ps3_sys_manager = { + .match_id = PS3_MATCH_ID_SYSTEM_MANAGER, + .core = { + .name = "ps3_sys_manager", + }, + .probe = ps3_sys_manager_probe, +}; + +static int __init ps3_sys_manager_init(void) +{ + return ps3_vuart_port_driver_register(&ps3_sys_manager); +} + +module_init(ps3_sys_manager_init); diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c index ef8fd4c3087..746298107d6 100644 --- a/drivers/ps3/vuart.c +++ b/drivers/ps3/vuart.c @@ -21,8 +21,10 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <linux/workqueue.h> #include <asm/ps3.h> +#include <asm/firmware.h> #include <asm/lv1call.h> #include <asm/bitops.h> @@ -30,7 +32,7 @@ MODULE_AUTHOR("Sony Corporation"); MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("ps3 vuart"); +MODULE_DESCRIPTION("PS3 vuart"); /** * vuart - An inter-partition data link service. @@ -157,7 +159,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, unsigned long size; unsigned long val; - result = lv1_get_virtual_uart_param(dev->port_number, + result = lv1_get_virtual_uart_param(dev->priv->port_number, PARAM_TX_TRIGGER, &trig->tx); if (result) { @@ -166,7 +168,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, return result; } - result = lv1_get_virtual_uart_param(dev->port_number, + result = lv1_get_virtual_uart_param(dev->priv->port_number, PARAM_RX_BUF_SIZE, &size); if (result) { @@ -175,7 +177,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, return result; } - result = lv1_get_virtual_uart_param(dev->port_number, + result = lv1_get_virtual_uart_param(dev->priv->port_number, PARAM_RX_TRIGGER, &val); if (result) { @@ -198,7 +200,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, int result; unsigned long size; - result = lv1_set_virtual_uart_param(dev->port_number, + result = lv1_set_virtual_uart_param(dev->priv->port_number, PARAM_TX_TRIGGER, tx); if (result) { @@ -207,7 +209,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, return result; } - result = lv1_get_virtual_uart_param(dev->port_number, + result = lv1_get_virtual_uart_param(dev->priv->port_number, PARAM_RX_BUF_SIZE, &size); if (result) { @@ -216,7 +218,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, return result; } - result = lv1_set_virtual_uart_param(dev->port_number, + result = lv1_set_virtual_uart_param(dev->priv->port_number, PARAM_RX_TRIGGER, size - rx); if (result) { @@ -232,9 +234,9 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, } static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev, - unsigned long *bytes_waiting) + u64 *bytes_waiting) { - int result = lv1_get_virtual_uart_param(dev->port_number, + int result = lv1_get_virtual_uart_param(dev->priv->port_number, PARAM_RX_BYTES, bytes_waiting); if (result) @@ -253,10 +255,10 @@ static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev, dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask); - dev->interrupt_mask = mask; + dev->priv->interrupt_mask = mask; - result = lv1_set_virtual_uart_param(dev->port_number, - PARAM_INTERRUPT_MASK, dev->interrupt_mask); + result = lv1_set_virtual_uart_param(dev->priv->port_number, + PARAM_INTERRUPT_MASK, dev->priv->interrupt_mask); if (result) dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n", @@ -265,62 +267,64 @@ static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev, return result; } -static int ps3_vuart_get_interrupt_mask(struct ps3_vuart_port_device *dev, +static int ps3_vuart_get_interrupt_status(struct ps3_vuart_port_device *dev, unsigned long *status) { - int result = lv1_get_virtual_uart_param(dev->port_number, - PARAM_INTERRUPT_STATUS, status); + u64 tmp; + int result = lv1_get_virtual_uart_param(dev->priv->port_number, + PARAM_INTERRUPT_STATUS, &tmp); if (result) dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n", __func__, __LINE__, ps3_result(result)); + *status = tmp & dev->priv->interrupt_mask; + dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n", - __func__, __LINE__, dev->interrupt_mask, *status, - dev->interrupt_mask & *status); + __func__, __LINE__, dev->priv->interrupt_mask, tmp, *status); return result; } int ps3_vuart_enable_interrupt_tx(struct ps3_vuart_port_device *dev) { - return (dev->interrupt_mask & INTERRUPT_MASK_TX) ? 0 - : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask + return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX) ? 0 + : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | INTERRUPT_MASK_TX); } int ps3_vuart_enable_interrupt_rx(struct ps3_vuart_port_device *dev) { - return (dev->interrupt_mask & INTERRUPT_MASK_RX) ? 0 - : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask + return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX) ? 0 + : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | INTERRUPT_MASK_RX); } int ps3_vuart_enable_interrupt_disconnect(struct ps3_vuart_port_device *dev) { - return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0 - : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask + return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0 + : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | INTERRUPT_MASK_DISCONNECT); } int ps3_vuart_disable_interrupt_tx(struct ps3_vuart_port_device *dev) { - return (dev->interrupt_mask & INTERRUPT_MASK_TX) - ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask + return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX) + ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask & ~INTERRUPT_MASK_TX) : 0; } int ps3_vuart_disable_interrupt_rx(struct ps3_vuart_port_device *dev) { - return (dev->interrupt_mask & INTERRUPT_MASK_RX) - ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask + return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX) + ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask & ~INTERRUPT_MASK_RX) : 0; } int ps3_vuart_disable_interrupt_disconnect(struct ps3_vuart_port_device *dev) { - return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT) - ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask + return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) + ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask & ~INTERRUPT_MASK_DISCONNECT) : 0; } @@ -335,9 +339,7 @@ static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev, { int result; - dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes); - - result = lv1_write_virtual_uart(dev->port_number, + result = lv1_write_virtual_uart(dev->priv->port_number, ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written); if (result) { @@ -346,10 +348,10 @@ static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev, return result; } - dev->stats.bytes_written += *bytes_written; + dev->priv->stats.bytes_written += *bytes_written; - dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__, - __LINE__, *bytes_written, bytes, dev->stats.bytes_written); + dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__, __LINE__, + *bytes_written, bytes, dev->priv->stats.bytes_written); return result; } @@ -367,7 +369,7 @@ static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf, dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes); - result = lv1_read_virtual_uart(dev->port_number, + result = lv1_read_virtual_uart(dev->priv->port_number, ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read); if (result) { @@ -376,15 +378,58 @@ static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf, return result; } - dev->stats.bytes_read += *bytes_read; + dev->priv->stats.bytes_read += *bytes_read; dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__, - *bytes_read, bytes, dev->stats.bytes_read); + *bytes_read, bytes, dev->priv->stats.bytes_read); return result; } /** + * ps3_vuart_clear_rx_bytes - Discard bytes received. + * @bytes: Max byte count to discard, zero = all pending. + * + * Used to clear pending rx interrupt source. Will not block. + */ + +void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev, + unsigned int bytes) +{ + int result; + u64 bytes_waiting; + void* tmp; + + result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes_waiting); + + BUG_ON(result); + + bytes = bytes ? min(bytes, (unsigned int)bytes_waiting) : bytes_waiting; + + dev_dbg(&dev->core, "%s:%d: %u\n", __func__, __LINE__, bytes); + + if (!bytes) + return; + + /* Add some extra space for recently arrived data. */ + + bytes += 128; + + tmp = kmalloc(bytes, GFP_KERNEL); + + if (!tmp) + return; + + ps3_vuart_raw_read(dev, tmp, bytes, &bytes_waiting); + + kfree(tmp); + + /* Don't include these bytes in the stats. */ + + dev->priv->stats.bytes_read -= bytes_waiting; +} + +/** * struct list_buffer - An element for a port device fifo buffer list. */ @@ -416,14 +461,14 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, bytes, bytes); - spin_lock_irqsave(&dev->tx_list.lock, flags); + spin_lock_irqsave(&dev->priv->tx_list.lock, flags); - if (list_empty(&dev->tx_list.head)) { + if (list_empty(&dev->priv->tx_list.head)) { unsigned long bytes_written; result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written); - spin_unlock_irqrestore(&dev->tx_list.lock, flags); + spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); if (result) { dev_dbg(&dev->core, @@ -441,7 +486,7 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, bytes -= bytes_written; buf += bytes_written; } else - spin_unlock_irqrestore(&dev->tx_list.lock, flags); + spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL); @@ -454,10 +499,10 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, lb->tail = lb->data + bytes; lb->dbg_number = ++dbg_number; - spin_lock_irqsave(&dev->tx_list.lock, flags); - list_add_tail(&lb->link, &dev->tx_list.head); + spin_lock_irqsave(&dev->priv->tx_list.lock, flags); + list_add_tail(&lb->link, &dev->priv->tx_list.head); ps3_vuart_enable_interrupt_tx(dev); - spin_unlock_irqrestore(&dev->tx_list.lock, flags); + spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n", __func__, __LINE__, lb->dbg_number, bytes); @@ -484,47 +529,83 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, bytes, bytes); - spin_lock_irqsave(&dev->rx_list.lock, flags); + spin_lock_irqsave(&dev->priv->rx_list.lock, flags); - if (dev->rx_list.bytes_held < bytes) { - spin_unlock_irqrestore(&dev->rx_list.lock, flags); + if (dev->priv->rx_list.bytes_held < bytes) { + spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n", - __func__, __LINE__, bytes - dev->rx_list.bytes_held); + __func__, __LINE__, + bytes - dev->priv->rx_list.bytes_held); return -EAGAIN; } - list_for_each_entry_safe(lb, n, &dev->rx_list.head, link) { + list_for_each_entry_safe(lb, n, &dev->priv->rx_list.head, link) { bytes_read = min((unsigned int)(lb->tail - lb->head), bytes); memcpy(buf, lb->head, bytes_read); buf += bytes_read; bytes -= bytes_read; - dev->rx_list.bytes_held -= bytes_read; + dev->priv->rx_list.bytes_held -= bytes_read; if (bytes_read < lb->tail - lb->head) { lb->head += bytes_read; - spin_unlock_irqrestore(&dev->rx_list.lock, flags); - - dev_dbg(&dev->core, - "%s:%d: dequeued buf_%lu, %lxh bytes\n", - __func__, __LINE__, lb->dbg_number, bytes_read); + dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh " + "bytes\n", __func__, __LINE__, lb->dbg_number, + bytes_read); + spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); return 0; } - dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__, - lb->dbg_number); + dev_dbg(&dev->core, "%s:%d: buf_%lu: free, dequeued %lxh " + "bytes\n", __func__, __LINE__, lb->dbg_number, + bytes_read); list_del(&lb->link); kfree(lb); } - spin_unlock_irqrestore(&dev->rx_list.lock, flags); - dev_dbg(&dev->core, "%s:%d: dequeued buf_%lu, %xh bytes\n", - __func__, __LINE__, lb->dbg_number, bytes); + spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); + return 0; +} + +int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, + unsigned int bytes) +{ + unsigned long flags; + + if(dev->priv->work.trigger) { + dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n", + __func__, __LINE__); + return -EAGAIN; + } + + BUG_ON(!bytes); + + PREPARE_WORK(&dev->priv->work.work, func); + + spin_lock_irqsave(&dev->priv->work.lock, flags); + if(dev->priv->rx_list.bytes_held >= bytes) { + dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n", + __func__, __LINE__, bytes); + schedule_work(&dev->priv->work.work); + spin_unlock_irqrestore(&dev->priv->work.lock, flags); + return 0; + } + + dev->priv->work.trigger = bytes; + spin_unlock_irqrestore(&dev->priv->work.lock, flags); + + dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__, + __LINE__, bytes, bytes); return 0; } +void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev) +{ + dev->priv->work.trigger = 0; +} + /** * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler * @@ -542,9 +623,9 @@ static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev) dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); - spin_lock_irqsave(&dev->tx_list.lock, flags); + spin_lock_irqsave(&dev->priv->tx_list.lock, flags); - list_for_each_entry_safe(lb, n, &dev->tx_list.head, link) { + list_for_each_entry_safe(lb, n, &dev->priv->tx_list.head, link) { unsigned long bytes_written; @@ -578,7 +659,7 @@ static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev) ps3_vuart_disable_interrupt_tx(dev); port_full: - spin_unlock_irqrestore(&dev->tx_list.lock, flags); + spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n", __func__, __LINE__, bytes_total); return result; @@ -609,7 +690,7 @@ static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev) BUG_ON(!bytes); - /* add some extra space for recently arrived data */ + /* Add some extra space for recently arrived data. */ bytes += 128; @@ -624,14 +705,23 @@ static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev) lb->tail = lb->data + bytes; lb->dbg_number = ++dbg_number; - spin_lock_irqsave(&dev->rx_list.lock, flags); - list_add_tail(&lb->link, &dev->rx_list.head); - dev->rx_list.bytes_held += bytes; - spin_unlock_irqrestore(&dev->rx_list.lock, flags); + spin_lock_irqsave(&dev->priv->rx_list.lock, flags); + list_add_tail(&lb->link, &dev->priv->rx_list.head); + dev->priv->rx_list.bytes_held += bytes; + spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); - dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %lxh bytes\n", + dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n", __func__, __LINE__, lb->dbg_number, bytes); + spin_lock_irqsave(&dev->priv->work.lock, flags); + if(dev->priv->work.trigger + && dev->priv->rx_list.bytes_held >= dev->priv->work.trigger) { + dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n", + __func__, __LINE__, dev->priv->work.trigger); + dev->priv->work.trigger = 0; + schedule_work(&dev->priv->work.work); + } + spin_unlock_irqrestore(&dev->priv->work.lock, flags); return 0; } @@ -656,7 +746,7 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) int result; unsigned long status; - result = ps3_vuart_get_interrupt_mask(dev, &status); + result = ps3_vuart_get_interrupt_status(dev, &status); if (result) return result; @@ -665,21 +755,21 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) status); if (status & INTERRUPT_MASK_DISCONNECT) { - dev->stats.disconnect_interrupts++; + dev->priv->stats.disconnect_interrupts++; result = ps3_vuart_handle_interrupt_disconnect(dev); if (result) ps3_vuart_disable_interrupt_disconnect(dev); } if (status & INTERRUPT_MASK_TX) { - dev->stats.tx_interrupts++; + dev->priv->stats.tx_interrupts++; result = ps3_vuart_handle_interrupt_tx(dev); if (result) ps3_vuart_disable_interrupt_tx(dev); } if (status & INTERRUPT_MASK_RX) { - dev->stats.rx_interrupts++; + dev->priv->stats.rx_interrupts++; result = ps3_vuart_handle_interrupt_rx(dev); if (result) ps3_vuart_disable_interrupt_rx(dev); @@ -688,12 +778,13 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) return 0; } -struct vuart_private { - unsigned int in_use; +struct vuart_bus_priv { + const struct ports_bmp bmp; unsigned int virq; + struct semaphore probe_mutex; + int use_count; struct ps3_vuart_port_device *devices[PORT_COUNT]; - const struct ports_bmp bmp; -}; +} static vuart_bus_priv; /** * ps3_vuart_irq_handler - first stage interrupt handler @@ -705,25 +796,25 @@ struct vuart_private { static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private) { - struct vuart_private *private; + struct vuart_bus_priv *bus_priv; BUG_ON(!_private); - private = (struct vuart_private *)_private; + bus_priv = (struct vuart_bus_priv *)_private; while (1) { unsigned int port; - dump_ports_bmp(&private->bmp); + dump_ports_bmp(&bus_priv->bmp); - port = (BITS_PER_LONG - 1) - __ilog2(private->bmp.status); + port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp.status); if (port == BITS_PER_LONG) break; BUG_ON(port >= PORT_COUNT); - BUG_ON(!private->devices[port]); + BUG_ON(!bus_priv->devices[port]); - ps3_vuart_handle_port_interrupt(private->devices[port]); + ps3_vuart_handle_port_interrupt(bus_priv->devices[port]); } return IRQ_HANDLED; @@ -744,12 +835,10 @@ static int ps3_vuart_match(struct device *_dev, struct device_driver *_drv) return result; } -static struct vuart_private vuart_private; - static int ps3_vuart_probe(struct device *_dev) { int result; - unsigned long tmp; + unsigned int port_number; struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); struct ps3_vuart_port_driver *drv = to_ps3_vuart_port_driver(_dev->driver); @@ -758,7 +847,12 @@ static int ps3_vuart_probe(struct device *_dev) BUG_ON(!drv); - result = ps3_vuart_match_id_to_port(dev->match_id, &dev->port_number); + down(&vuart_bus_priv.probe_mutex); + + /* Setup vuart_bus_priv.devices[]. */ + + result = ps3_vuart_match_id_to_port(dev->match_id, + &port_number); if (result) { dev_dbg(&dev->core, "%s:%d: unknown match_id (%d)\n", @@ -767,24 +861,41 @@ static int ps3_vuart_probe(struct device *_dev) goto fail_match; } - if (vuart_private.devices[dev->port_number]) { + if (vuart_bus_priv.devices[port_number]) { dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__, - __LINE__, dev->port_number); + __LINE__, port_number); result = -EBUSY; goto fail_match; } - vuart_private.devices[dev->port_number] = dev; + vuart_bus_priv.devices[port_number] = dev; + + /* Setup dev->priv. */ + + dev->priv = kzalloc(sizeof(struct ps3_vuart_port_priv), GFP_KERNEL); + + if (!dev->priv) { + result = -ENOMEM; + goto fail_alloc; + } - INIT_LIST_HEAD(&dev->tx_list.head); - spin_lock_init(&dev->tx_list.lock); - INIT_LIST_HEAD(&dev->rx_list.head); - spin_lock_init(&dev->rx_list.lock); + dev->priv->port_number = port_number; + + INIT_LIST_HEAD(&dev->priv->tx_list.head); + spin_lock_init(&dev->priv->tx_list.lock); + + INIT_LIST_HEAD(&dev->priv->rx_list.head); + spin_lock_init(&dev->priv->rx_list.lock); + + INIT_WORK(&dev->priv->work.work, NULL); + spin_lock_init(&dev->priv->work.lock); + dev->priv->work.trigger = 0; + dev->priv->work.dev = dev; + + if (++vuart_bus_priv.use_count == 1) { - vuart_private.in_use++; - if (vuart_private.in_use == 1) { result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY, - (void*)&vuart_private.bmp.status, &vuart_private.virq); + (void*)&vuart_bus_priv.bmp.status, &vuart_bus_priv.virq); if (result) { dev_dbg(&dev->core, @@ -794,8 +905,8 @@ static int ps3_vuart_probe(struct device *_dev) goto fail_alloc_irq; } - result = request_irq(vuart_private.virq, ps3_vuart_irq_handler, - IRQF_DISABLED, "vuart", &vuart_private); + result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler, + IRQF_DISABLED, "vuart", &vuart_bus_priv); if (result) { dev_info(&dev->core, "%s:%d: request_irq failed (%d)\n", @@ -804,10 +915,11 @@ static int ps3_vuart_probe(struct device *_dev) } } - ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX); - /* clear stale pending interrupts */ - ps3_vuart_get_interrupt_mask(dev, &tmp); + + ps3_vuart_clear_rx_bytes(dev, 0); + + ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX); ps3_vuart_set_triggers(dev, 1, 1); @@ -822,20 +934,27 @@ static int ps3_vuart_probe(struct device *_dev) if (result) { dev_dbg(&dev->core, "%s:%d: drv->probe failed\n", __func__, __LINE__); + down(&vuart_bus_priv.probe_mutex); goto fail_probe; } + up(&vuart_bus_priv.probe_mutex); + return result; fail_probe: + ps3_vuart_set_interrupt_mask(dev, 0); fail_request_irq: - vuart_private.in_use--; - if (!vuart_private.in_use) { - ps3_free_vuart_irq(vuart_private.virq); - vuart_private.virq = NO_IRQ; - } + ps3_free_vuart_irq(vuart_bus_priv.virq); + vuart_bus_priv.virq = NO_IRQ; fail_alloc_irq: + --vuart_bus_priv.use_count; + kfree(dev->priv); + dev->priv = NULL; +fail_alloc: + vuart_bus_priv.devices[port_number] = 0; fail_match: + up(&vuart_bus_priv.probe_mutex); dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__); return result; } @@ -846,10 +965,12 @@ static int ps3_vuart_remove(struct device *_dev) struct ps3_vuart_port_driver *drv = to_ps3_vuart_port_driver(_dev->driver); + down(&vuart_bus_priv.probe_mutex); + dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); - BUG_ON(vuart_private.in_use < 1); + BUG_ON(vuart_bus_priv.use_count < 1); if (drv->remove) drv->remove(dev); @@ -857,13 +978,19 @@ static int ps3_vuart_remove(struct device *_dev) dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__, __LINE__, dev->core.bus_id); - vuart_private.in_use--; + vuart_bus_priv.devices[dev->priv->port_number] = 0; - if (!vuart_private.in_use) { - free_irq(vuart_private.virq, &vuart_private); - ps3_free_vuart_irq(vuart_private.virq); - vuart_private.virq = NO_IRQ; + if (--vuart_bus_priv.use_count == 0) { + BUG(); + free_irq(vuart_bus_priv.virq, &vuart_bus_priv); + ps3_free_vuart_irq(vuart_bus_priv.virq); + vuart_bus_priv.virq = NO_IRQ; } + + kfree(dev->priv); + dev->priv = NULL; + + up(&vuart_bus_priv.probe_mutex); return 0; } @@ -884,12 +1011,12 @@ static void ps3_vuart_shutdown(struct device *_dev) } /** - * ps3_vuart - The vuart instance. + * ps3_vuart_bus - The vuart bus instance. * * The vuart is managed as a bus that port devices connect to. */ -struct bus_type ps3_vuart = { +struct bus_type ps3_vuart_bus = { .name = "ps3_vuart", .match = ps3_vuart_match, .probe = ps3_vuart_probe, @@ -897,24 +1024,30 @@ struct bus_type ps3_vuart = { .shutdown = ps3_vuart_shutdown, }; -int __init ps3_vuart_init(void) +int __init ps3_vuart_bus_init(void) { int result; pr_debug("%s:%d:\n", __func__, __LINE__); - result = bus_register(&ps3_vuart); + + if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) + return 0; + + init_MUTEX(&vuart_bus_priv.probe_mutex); + result = bus_register(&ps3_vuart_bus); BUG_ON(result); + return result; } -void __exit ps3_vuart_exit(void) +void __exit ps3_vuart_bus_exit(void) { pr_debug("%s:%d:\n", __func__, __LINE__); - bus_unregister(&ps3_vuart); + bus_unregister(&ps3_vuart_bus); } -core_initcall(ps3_vuart_init); -module_exit(ps3_vuart_exit); +core_initcall(ps3_vuart_bus_init); +module_exit(ps3_vuart_bus_exit); /** * ps3_vuart_port_release_device - Remove a vuart port device. @@ -922,11 +1055,14 @@ module_exit(ps3_vuart_exit); static void ps3_vuart_port_release_device(struct device *_dev) { - struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); #if defined(DEBUG) - memset(dev, 0xad, sizeof(struct ps3_vuart_port_device)); + struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); + + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); + + BUG_ON(dev->priv && "forgot to free"); + memset(&dev->core, 0, sizeof(dev->core)); #endif - kfree(dev); } /** @@ -935,11 +1071,12 @@ static void ps3_vuart_port_release_device(struct device *_dev) int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev) { - int result; static unsigned int dev_count = 1; + BUG_ON(dev->priv && "forgot to free"); + dev->core.parent = NULL; - dev->core.bus = &ps3_vuart; + dev->core.bus = &ps3_vuart_bus; dev->core.release = ps3_vuart_port_release_device; snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x", @@ -947,9 +1084,7 @@ int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev) dev_dbg(&dev->core, "%s:%d register\n", __func__, __LINE__); - result = device_register(&dev->core); - - return result; + return device_register(&dev->core); } EXPORT_SYMBOL_GPL(ps3_vuart_port_device_register); @@ -963,7 +1098,7 @@ int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv) int result; pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name); - drv->core.bus = &ps3_vuart; + drv->core.bus = &ps3_vuart_bus; result = driver_register(&drv->core); return result; } @@ -976,6 +1111,7 @@ EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register); void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv) { + pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name); driver_unregister(&drv->core); } diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h index 2cbf728a3a0..1be992d568c 100644 --- a/drivers/ps3/vuart.h +++ b/drivers/ps3/vuart.h @@ -21,6 +21,44 @@ #if !defined(_PS3_VUART_H) #define _PS3_VUART_H +#include <asm/ps3.h> + +struct ps3_vuart_stats { + unsigned long bytes_written; + unsigned long bytes_read; + unsigned long tx_interrupts; + unsigned long rx_interrupts; + unsigned long disconnect_interrupts; +}; + +struct ps3_vuart_work { + struct work_struct work; + unsigned long trigger; + spinlock_t lock; + struct ps3_vuart_port_device* dev; /* to convert work to device */ +}; + +/** + * struct ps3_vuart_port_priv - private vuart device data. + */ + +struct ps3_vuart_port_priv { + unsigned int port_number; + u64 interrupt_mask; + + struct { + spinlock_t lock; + struct list_head head; + } tx_list; + struct { + unsigned long bytes_held; + spinlock_t lock; + struct list_head head; + } rx_list; + struct ps3_vuart_stats stats; + struct ps3_vuart_work work; +}; + /** * struct ps3_vuart_port_driver - a driver for a device on a vuart port */ @@ -41,10 +79,6 @@ struct ps3_vuart_port_driver { int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv); void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv); -int ps3_vuart_write(struct ps3_vuart_port_device *dev, - const void* buf, unsigned int bytes); -int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, - unsigned int bytes); static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver( struct device_driver *_drv) { @@ -55,5 +89,22 @@ static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device( { return container_of(_dev, struct ps3_vuart_port_device, core); } +static inline struct ps3_vuart_port_device *ps3_vuart_work_to_port_device( + struct work_struct *_work) +{ + struct ps3_vuart_work *vw = container_of(_work, struct ps3_vuart_work, + work); + return vw->dev; +} + +int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, + unsigned int bytes); +int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, + unsigned int bytes); +int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, + unsigned int bytes); +void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev); +void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev, + unsigned int bytes); #endif diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 8f6b5bf580f..2b5b8a93bc1 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -801,15 +801,10 @@ static int idescsi_ide_open(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; struct ide_scsi_obj *scsi; - ide_drive_t *drive; if (!(scsi = ide_scsi_get(disk))) return -ENXIO; - drive = scsi->drive; - - drive->usage++; - return 0; } @@ -817,9 +812,6 @@ static int idescsi_ide_release(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; struct ide_scsi_obj *scsi = ide_scsi_g(disk); - ide_drive_t *drive = scsi->drive; - - drive->usage--; ide_scsi_put(scsi); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3f048bd6326..5a8f55fea5f 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1269,9 +1269,18 @@ repeat: /* Some devices return the total number of sectors, not the * highest sector number. Make the necessary adjustment. */ - if (sdp->fix_capacity) + if (sdp->fix_capacity) { --sdkp->capacity; + /* Some devices have version which report the correct sizes + * and others which do not. We guess size according to a heuristic + * and err on the side of lowering the capacity. */ + } else { + if (sdp->guess_capacity) + if (sdkp->capacity & 0x01) /* odd sizes are odd */ + --sdkp->capacity; + } + got_data: if (sector_size == 0) { sector_size = 512; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index e8dd71df916..ad9f321968e 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -262,7 +262,8 @@ config SERIAL_AMBA_PL010 select SERIAL_CORE help This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have - an Integrator/AP or Integrator/PP2 platform, say Y or M here. + an Integrator/AP or Integrator/PP2 platform, or if you have a + Cirrus Logic EP93xx CPU, say Y or M here. If unsure, say N. diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index df45a7ac773..935f48fa501 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -33,12 +33,13 @@ #include <linux/sysrq.h> #include <linux/tty_flip.h> #include <linux/platform_device.h> +#include <linux/atmel_pdc.h> #include <asm/io.h> #include <asm/mach/serial_at91.h> #include <asm/arch/board.h> -#include <asm/arch/at91_pdc.h> + #ifdef CONFIG_ARM #include <asm/arch/cpu.h> #include <asm/arch/gpio.h> diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index 787a8f13467..fa455996ad8 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -285,7 +285,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo) int __init cpm_uart_init_portdesc(void) { #if defined(CONFIG_SERIAL_CPM_SMC1) || defined(CONFIG_SERIAL_CPM_SMC2) - u32 addr; + u16 *addr; #endif pr_debug("CPM uart[-]:init portdesc\n"); diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index e216dcf2937..04cc88cc528 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -154,7 +154,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport) { struct circ_buf *xmit = &sport->port.info->xmit; - do { + while (!(UTS((u32)sport->port.membase) & UTS_TXFULL)) { /* send xmit->buf[xmit->tail] * out the port here */ URTX0((u32)sport->port.membase) = xmit->buf[xmit->tail]; @@ -163,7 +163,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport) sport->port.icount.tx++; if (uart_circ_empty(xmit)) break; - } while (!(UTS((u32)sport->port.membase) & UTS_TXFULL)); + } if (uart_circ_empty(xmit)) imx_stop_tx(&sport->port); @@ -178,8 +178,7 @@ static void imx_start_tx(struct uart_port *port) UCR1((u32)sport->port.membase) |= UCR1_TXMPTYEN; - if(UTS((u32)sport->port.membase) & UTS_TXEMPTY) - imx_transmit_buffer(sport); + imx_transmit_buffer(sport); } static irqreturn_t imx_rtsint(int irq, void *dev_id) @@ -404,7 +403,8 @@ static int imx_startup(struct uart_port *port) if (retval) goto error_out2; retval = request_irq(sport->rtsirq, imx_rtsint, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + (sport->rtsirq < IMX_IRQS) ? 0 : + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, DRIVER_NAME, sport); if (retval) goto error_out3; @@ -678,7 +678,7 @@ static struct imx_port imx_ports[] = { .mapbase = IMX_UART1_BASE, /* FIXME */ .irq = UART1_MINT_RX, .uartclk = 16000000, - .fifosize = 8, + .fifosize = 32, .flags = UPF_BOOT_AUTOCONF, .ops = &imx_pops, .line = 0, @@ -694,7 +694,7 @@ static struct imx_port imx_ports[] = { .mapbase = IMX_UART2_BASE, /* FIXME */ .irq = UART2_MINT_RX, .uartclk = 16000000, - .fifosize = 8, + .fifosize = 32, .flags = UPF_BOOT_AUTOCONF, .ops = &imx_pops, .line = 1, diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 955bbd653e2..8d24cd52105 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -995,8 +995,10 @@ mpc52xx_uart_of_remove(struct of_device *op) struct uart_port *port = dev_get_drvdata(&op->dev); dev_set_drvdata(&op->dev, NULL); - if (port) + if (port) { uart_remove_one_port(&mpc52xx_uart_driver, port); + irq_dispose_mapping(port->irq); + } return 0; } diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index c2f1012449d..6b76babc7fb 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -248,6 +248,10 @@ static const struct serial_quirk quirks[] = { .multi = 2, }, { .manfid = MANFID_QUATECH, + .prodid = PRODID_QUATECH_DUAL_RS232_G, + .multi = 2, + }, { + .manfid = MANFID_QUATECH, .prodid = PRODID_QUATECH_QUAD_RS232, .multi = 4, }, { @@ -891,6 +895,7 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a), PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab), PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f), + PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "PCMLM28.cis"), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "PCMLM28.cis"), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "PCMLM28.cis"), diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 825bf884537..8b7ff467d26 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB_ADUTUX) += misc/ obj-$(CONFIG_USB_APPLEDISPLAY) += misc/ obj-$(CONFIG_USB_AUERSWALD) += misc/ +obj-$(CONFIG_USB_BERRY_CHARGE) += misc/ obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/ obj-$(CONFIG_USB_CYTHERM) += misc/ obj-$(CONFIG_USB_EMI26) += misc/ diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index dae4ef1e8fe..4973e147bc7 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -61,6 +61,7 @@ #include <linux/usb.h> #include <linux/firmware.h> #include <linux/ctype.h> +#include <linux/sched.h> #include <linux/kthread.h> #include <linux/version.h> #include <linux/mutex.h> diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 98199628e39..d38a25f36ea 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -326,10 +326,16 @@ static void acm_rx_tasklet(unsigned long _acm) struct tty_struct *tty = acm->tty; struct acm_ru *rcv; unsigned long flags; - int i = 0; + unsigned char throttled; dbg("Entering acm_rx_tasklet"); - if (!ACM_READY(acm) || acm->throttle) + if (!ACM_READY(acm)) + return; + + spin_lock(&acm->throttle_lock); + throttled = acm->throttle; + spin_unlock(&acm->throttle_lock); + if (throttled) return; next_buffer: @@ -346,22 +352,20 @@ next_buffer: dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); tty_buffer_request_room(tty, buf->size); - if (!acm->throttle) + spin_lock(&acm->throttle_lock); + throttled = acm->throttle; + spin_unlock(&acm->throttle_lock); + if (!throttled) tty_insert_flip_string(tty, buf->base, buf->size); tty_flip_buffer_push(tty); - spin_lock(&acm->throttle_lock); - if (acm->throttle) { - dbg("Throtteling noticed"); - memmove(buf->base, buf->base + i, buf->size - i); - buf->size -= i; - spin_unlock(&acm->throttle_lock); + if (throttled) { + dbg("Throttling noticed"); spin_lock_irqsave(&acm->read_lock, flags); list_add(&buf->list, &acm->filled_read_bufs); spin_unlock_irqrestore(&acm->read_lock, flags); return; } - spin_unlock(&acm->throttle_lock); spin_lock_irqsave(&acm->read_lock, flags); list_add(&buf->list, &acm->spare_read_bufs); @@ -467,7 +471,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) goto bail_out; } - if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS)) + if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && + (acm->ctrl_caps & USB_CDC_CAP_LINE)) goto full_bailout; INIT_LIST_HEAD(&acm->spare_read_urbs); @@ -480,6 +485,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) list_add(&(acm->rb[i].list), &acm->spare_read_bufs); } + acm->throttle = 0; + tasklet_schedule(&acm->urb_task); done: @@ -1092,6 +1099,10 @@ static struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */ .driver_info = SINGLE_RX_URB, /* firmware bug */ }, + { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, + /* control interfaces with various AT-command sets */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_ACM_PROTO_AT_V25TER) }, diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index a47c30b2d76..aefc7987120 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -604,10 +604,6 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct lock_kernel(); if (!st) { st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL); - if (!st) { - unlock_kernel(); - return POLLIN; - } /* we may have dropped BKL - need to check for having lost the race */ if (file->private_data) { @@ -615,6 +611,11 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct st = file->private_data; goto lost_race; } + /* we haven't lost - check for allocation failure now */ + if (!st) { + unlock_kernel(); + return POLLIN; + } /* * need to prevent the module from being unloaded, since diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 2087766f9e8..274f14f1633 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -857,11 +857,11 @@ static int proc_setintf(struct dev_state *ps, void __user *arg) static int proc_setconfig(struct dev_state *ps, void __user *arg) { - unsigned int u; + int u; int status = 0; struct usb_host_config *actconfig; - if (get_user(u, (unsigned int __user *)arg)) + if (get_user(u, (int __user *)arg)) return -EFAULT; actconfig = ps->dev->actconfig; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 600d1bc8272..2aded261f42 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -743,6 +743,7 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver); * usb_register_driver - register a USB interface driver * @new_driver: USB operations for the interface driver * @owner: module owner of this driver. + * @mod_name: module name string * * Registers a USB interface driver with the USB core. The list of * unattached interfaces will be rescanned whenever a new driver is diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 5e628ae3aec..e0ec7045e86 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -229,7 +229,7 @@ static int init_endpoint_class(void) kref_init(&ep_class->kref); ep_class->class = class_create(THIS_MODULE, "usb_endpoint"); if (IS_ERR(ep_class->class)) { - result = IS_ERR(ep_class->class); + result = PTR_ERR(ep_class->class); goto class_create_error; } diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index b531a4fd30c..9bbcb20e2d9 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -184,7 +184,7 @@ static void generic_disconnect(struct usb_device *udev) /* if this is only an unbind, not a physical disconnect, then * unconfigure the device */ if (udev->actconfig) - usb_set_configuration(udev, 0); + usb_set_configuration(udev, -1); usb_remove_sysfs_dev_files(udev); } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 590ec82d051..50c0db15304 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -44,6 +44,7 @@ struct usb_hub { struct usb_hub_status hub; struct usb_port_status port; } *status; /* buffer for status reports */ + struct mutex status_mutex; /* for the status buffer */ int error; /* last reported error */ int nerrors; /* track consecutive errors */ @@ -535,6 +536,7 @@ static int hub_hub_status(struct usb_hub *hub, { int ret; + mutex_lock(&hub->status_mutex); ret = get_hub_status(hub->hdev, &hub->status->hub); if (ret < 0) dev_err (hub->intfdev, @@ -544,6 +546,7 @@ static int hub_hub_status(struct usb_hub *hub, *change = le16_to_cpu(hub->status->hub.wHubChange); ret = 0; } + mutex_unlock(&hub->status_mutex); return ret; } @@ -617,6 +620,7 @@ static int hub_configure(struct usb_hub *hub, ret = -ENOMEM; goto fail; } + mutex_init(&hub->status_mutex); hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); if (!hub->descriptor) { @@ -1396,6 +1400,7 @@ static int hub_port_status(struct usb_hub *hub, int port1, { int ret; + mutex_lock(&hub->status_mutex); ret = get_port_status(hub->hdev, port1, &hub->status->port); if (ret < 4) { dev_err (hub->intfdev, @@ -1407,6 +1412,7 @@ static int hub_port_status(struct usb_hub *hub, int port1, *change = le16_to_cpu(hub->status->port.wPortChange); ret = 0; } + mutex_unlock(&hub->status_mutex); return ret; } @@ -1904,6 +1910,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_hub *hub = usb_get_intfdata (intf); struct usb_device *hdev = hub->hdev; unsigned port1; + int status = 0; /* fail if children aren't already suspended */ for (port1 = 1; port1 <= hdev->maxchild; port1++) { @@ -1927,24 +1934,18 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) dev_dbg(&intf->dev, "%s\n", __FUNCTION__); + /* stop khubd and related activity */ + hub_quiesce(hub); + /* "global suspend" of the downstream HC-to-USB interface */ if (!hdev->parent) { - struct usb_bus *bus = hdev->bus; - if (bus) { - int status = hcd_bus_suspend (bus); - - if (status != 0) { - dev_dbg(&hdev->dev, "'global' suspend %d\n", - status); - return status; - } - } else - return -EOPNOTSUPP; + status = hcd_bus_suspend(hdev->bus); + if (status != 0) { + dev_dbg(&hdev->dev, "'global' suspend %d\n", status); + hub_activate(hub); + } } - - /* stop khubd and related activity */ - hub_quiesce(hub); - return 0; + return status; } static int hub_resume(struct usb_interface *intf) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 8aca3574c2b..74edaea5665 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1316,6 +1316,14 @@ static void release_interface(struct device *dev) * use this kind of configurability; many devices only have one * configuration. * + * @configuration is the value of the configuration to be installed. + * According to the USB spec (e.g. section 9.1.1.5), configuration values + * must be non-zero; a value of zero indicates that the device in + * unconfigured. However some devices erroneously use 0 as one of their + * configuration values. To help manage such devices, this routine will + * accept @configuration = -1 as indicating the device should be put in + * an unconfigured state. + * * USB device configurations may affect Linux interoperability, * power consumption and the functionality available. For example, * the default configuration is limited to using 100mA of bus power, @@ -1347,10 +1355,15 @@ int usb_set_configuration(struct usb_device *dev, int configuration) struct usb_interface **new_interfaces = NULL; int n, nintf; - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { - if (dev->config[i].desc.bConfigurationValue == configuration) { - cp = &dev->config[i]; - break; + if (configuration == -1) + configuration = 0; + else { + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { + if (dev->config[i].desc.bConfigurationValue == + configuration) { + cp = &dev->config[i]; + break; + } } } if ((!cp && configuration != 0)) @@ -1359,6 +1372,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) /* The USB spec says configuration 0 means unconfigured. * But if a device includes a configuration numbered 0, * we will accept it as a correctly configured state. + * Use -1 if you really want to unconfigure the device. */ if (cp && configuration == 0) dev_warn(&dev->dev, "config 0 descriptor??\n"); diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h index 627a5a2fc9c..7f31a495a25 100644 --- a/drivers/usb/core/otg_whitelist.h +++ b/drivers/usb/core/otg_whitelist.h @@ -31,7 +31,7 @@ static struct usb_device_id whitelist_table [] = { { USB_DEVICE_INFO(7, 1, 3) }, #endif -#ifdef CONFIG_USB_CDCETHER +#ifdef CONFIG_USB_NET_CDCETHER /* Linux-USB CDC Ethernet gadget */ { USB_DEVICE(0x0525, 0xa4a1), }, /* Linux-USB CDC Ethernet + RNDIS gadget */ diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 4eaa0ee8e72..0edfbafd702 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -63,7 +63,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr, struct usb_device *udev = to_usb_device(dev); int config, value; - if (sscanf(buf, "%u", &config) != 1 || config > 255) + if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255) return -EINVAL; usb_lock_device(udev); value = usb_set_configuration(udev, config); diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 36b36e0175f..a4677802fb2 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -784,7 +784,7 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value) return status; } -static struct usb_ep_ops at91_ep_ops = { +static const struct usb_ep_ops at91_ep_ops = { .enable = at91_ep_enable, .disable = at91_ep_disable, .alloc_request = at91_ep_alloc_request, @@ -912,7 +912,7 @@ static void pullup(struct at91_udc *udc, int is_on) at91_udp_write(udc, AT91_UDP_TXVC, 0); if (cpu_is_at91rm9200()) at91_set_gpio_value(udc->board.pullup_pin, 1); - else if (cpu_is_at91sam9260()) { + else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) { u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); txvc |= AT91_UDP_TXVC_PUON; @@ -929,7 +929,7 @@ static void pullup(struct at91_udc *udc, int is_on) at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); if (cpu_is_at91rm9200()) at91_set_gpio_value(udc->board.pullup_pin, 0); - else if (cpu_is_at91sam9260()) { + else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) { u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); txvc &= ~AT91_UDP_TXVC_PUON; @@ -1651,7 +1651,7 @@ static void at91udc_shutdown(struct platform_device *dev) pullup(platform_get_drvdata(dev), 0); } -static int __devinit at91udc_probe(struct platform_device *pdev) +static int __init at91udc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct at91_udc *udc; @@ -1762,7 +1762,7 @@ fail0: return retval; } -static int __devexit at91udc_remove(struct platform_device *pdev) +static int __exit at91udc_remove(struct platform_device *pdev) { struct at91_udc *udc = platform_get_drvdata(pdev); struct resource *res; @@ -1836,8 +1836,7 @@ static int at91udc_resume(struct platform_device *pdev) #endif static struct platform_driver at91_udc = { - .probe = at91udc_probe, - .remove = __devexit_p(at91udc_remove), + .remove = __exit_p(at91udc_remove), .shutdown = at91udc_shutdown, .suspend = at91udc_suspend, .resume = at91udc_resume, @@ -1847,13 +1846,13 @@ static struct platform_driver at91_udc = { }, }; -static int __devinit udc_init_module(void) +static int __init udc_init_module(void) { - return platform_driver_register(&at91_udc); + return platform_driver_probe(&at91_udc, at91udc_probe); } module_init(udc_init_module); -static void __devexit udc_exit_module(void) +static void __exit udc_exit_module(void) { platform_driver_unregister(&at91_udc); } diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 27904a56494..f01890dc875 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -155,7 +155,7 @@ static int is_vbus_present(void) struct pxa2xx_udc_mach_info *mach = the_controller->mach; if (mach->gpio_vbus) - return pxa_gpio_get(mach->gpio_vbus); + return udc_gpio_get(mach->gpio_vbus); if (mach->udc_is_connected) return mach->udc_is_connected(); return 1; @@ -167,7 +167,7 @@ static void pullup_off(void) struct pxa2xx_udc_mach_info *mach = the_controller->mach; if (mach->gpio_pullup) - pxa_gpio_set(mach->gpio_pullup, 0); + udc_gpio_set(mach->gpio_pullup, 0); else if (mach->udc_command) mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); } @@ -177,7 +177,7 @@ static void pullup_on(void) struct pxa2xx_udc_mach_info *mach = the_controller->mach; if (mach->gpio_pullup) - pxa_gpio_set(mach->gpio_pullup, 1); + udc_gpio_set(mach->gpio_pullup, 1); else if (mach->udc_command) mach->udc_command(PXA2XX_UDC_CMD_CONNECT); } @@ -1755,7 +1755,7 @@ lubbock_vbus_irq(int irq, void *_dev) static irqreturn_t udc_vbus_irq(int irq, void *_dev) { struct pxa2xx_udc *dev = _dev; - int vbus = pxa_gpio_get(dev->mach->gpio_vbus); + int vbus = udc_gpio_get(dev->mach->gpio_vbus); pxa2xx_udc_vbus_session(&dev->gadget, vbus); return IRQ_HANDLED; @@ -2545,15 +2545,13 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) dev->dev = &pdev->dev; dev->mach = pdev->dev.platform_data; if (dev->mach->gpio_vbus) { - vbus_irq = IRQ_GPIO(dev->mach->gpio_vbus & GPIO_MD_MASK_NR); - pxa_gpio_mode((dev->mach->gpio_vbus & GPIO_MD_MASK_NR) - | GPIO_IN); + udc_gpio_init_vbus(dev->mach->gpio_vbus); + vbus_irq = udc_gpio_to_irq(dev->mach->gpio_vbus); set_irq_type(vbus_irq, IRQT_BOTHEDGE); } else vbus_irq = 0; if (dev->mach->gpio_pullup) - pxa_gpio_mode((dev->mach->gpio_pullup & GPIO_MD_MASK_NR) - | GPIO_OUT | GPIO_DFLT_LOW); + udc_gpio_init_pullup(dev->mach->gpio_pullup); init_timer(&dev->timer); dev->timer.function = udc_watchdog; diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index 8e598c8bf4e..773e549aff3 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -177,21 +177,6 @@ struct pxa2xx_udc { static struct pxa2xx_udc *the_controller; -static inline int pxa_gpio_get(unsigned gpio) -{ - return (GPLR(gpio) & GPIO_bit(gpio)) != 0; -} - -static inline void pxa_gpio_set(unsigned gpio, int is_on) -{ - int mask = GPIO_bit(gpio); - - if (is_on) - GPSR(gpio) = mask; - else - GPCR(gpio) = mask; -} - /*-------------------------------------------------------------------------*/ /* diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index e6c19aa4bef..e552668d36b 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -1699,6 +1699,7 @@ static int gs_setup_class(struct usb_gadget *gadget, memcpy(&port->port_line_coding, req->buf, ret); spin_unlock(&port->port_lock); } + ret = 0; break; case USB_CDC_REQ_GET_LINE_CODING: diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 185721dba42..a7405648823 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -42,6 +42,9 @@ #include <asm/irq.h> #include <asm/system.h> #include <asm/unaligned.h> +#ifdef CONFIG_PPC_PS3 +#include <asm/firmware.h> +#endif /*-------------------------------------------------------------------------*/ @@ -299,6 +302,19 @@ static void ehci_watchdog (unsigned long param) spin_unlock_irqrestore (&ehci->lock, flags); } +/* On some systems, leaving remote wakeup enabled prevents system shutdown. + * The firmware seems to think that powering off is a wakeup event! + * This routine turns off remote wakeup and everything else, on all ports. + */ +static void ehci_turn_off_all_ports(struct ehci_hcd *ehci) +{ + int port = HCS_N_PORTS(ehci->hcs_params); + + while (port--) + ehci_writel(ehci, PORT_RWC_BITS, + &ehci->regs->port_status[port]); +} + /* ehci_shutdown kick in for silicon on any bus (not just pci, etc). * This forcibly disables dma and IRQs, helping kexec and other cases * where the next system software may expect clean state. @@ -310,9 +326,13 @@ ehci_shutdown (struct usb_hcd *hcd) ehci = hcd_to_ehci (hcd); (void) ehci_halt (ehci); + ehci_turn_off_all_ports(ehci); /* make BIOS/etc use companion controller during reboot */ ehci_writel(ehci, 0, &ehci->regs->configured_flag); + + /* unblock posted writes */ + ehci_readl(ehci, &ehci->regs->configured_flag); } static void ehci_port_power (struct ehci_hcd *ehci, int is_on) @@ -951,15 +971,18 @@ static int __init ehci_hcd_init(void) #endif #ifdef PS3_SYSTEM_BUS_DRIVER - retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER); - if (retval < 0) { + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { + retval = ps3_system_bus_driver_register( + &PS3_SYSTEM_BUS_DRIVER); + if (retval < 0) { #ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); + platform_driver_unregister(&PLATFORM_DRIVER); #endif #ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); + pci_unregister_driver(&PCI_DRIVER); #endif - return retval; + return retval; + } } #endif @@ -976,7 +999,8 @@ static void __exit ehci_hcd_cleanup(void) pci_unregister_driver(&PCI_DRIVER); #endif #ifdef PS3_SYSTEM_BUS_DRIVER - ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif } module_exit(ehci_hcd_cleanup); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 0d83c6df1a3..9af529d22b3 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -36,6 +36,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) int port; int mask; + ehci_dbg(ehci, "suspend root hub\n"); + if (time_before (jiffies, ehci->next_statechange)) msleep(5); diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 2718b5dc4ec..46873f2534b 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1577,7 +1577,7 @@ static int isp116x_remove(struct platform_device *pdev) #define resource_len(r) (((r)->end - (r)->start) + 1) -static int __init isp116x_probe(struct platform_device *pdev) +static int __devinit isp116x_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct isp116x *isp116x; diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 93034648727..d849c809acb 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -18,19 +18,38 @@ #include <asm/mach-types.h> #include <asm/hardware.h> #include <asm/arch/board.h> +#include <asm/arch/cpu.h> #ifndef CONFIG_ARCH_AT91 #error "CONFIG_ARCH_AT91 must be defined." #endif -/* interface and function clocks */ -static struct clk *iclk, *fclk; +/* interface and function clocks; sometimes also an AHB clock */ +static struct clk *iclk, *fclk, *hclk; static int clocked; extern int usb_disabled(void); /*-------------------------------------------------------------------------*/ +static void at91_start_clock(void) +{ + if (cpu_is_at91sam9261()) + clk_enable(hclk); + clk_enable(iclk); + clk_enable(fclk); + clocked = 1; +} + +static void at91_stop_clock(void) +{ + clk_disable(fclk); + clk_disable(iclk); + if (cpu_is_at91sam9261()) + clk_disable(hclk); + clocked = 0; +} + static void at91_start_hc(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); @@ -41,9 +60,7 @@ static void at91_start_hc(struct platform_device *pdev) /* * Start the USB clocks. */ - clk_enable(iclk); - clk_enable(fclk); - clocked = 1; + at91_start_clock(); /* * The USB host controller must remain in reset. @@ -66,9 +83,7 @@ static void at91_stop_hc(struct platform_device *pdev) /* * Stop the USB clocks. */ - clk_disable(fclk); - clk_disable(iclk); - clocked = 0; + at91_stop_clock(); } @@ -126,6 +141,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, iclk = clk_get(&pdev->dev, "ohci_clk"); fclk = clk_get(&pdev->dev, "uhpck"); + if (cpu_is_at91sam9261()) + hclk = clk_get(&pdev->dev, "hck0"); at91_start_hc(pdev); ohci_hcd_init(hcd_to_ohci(hcd)); @@ -137,6 +154,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, /* Error handling */ at91_stop_hc(pdev); + if (cpu_is_at91sam9261()) + clk_put(hclk); clk_put(fclk); clk_put(iclk); @@ -171,9 +190,11 @@ static int usb_hcd_at91_remove(struct usb_hcd *hcd, iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + if (cpu_is_at91sam9261()) + clk_put(hclk); clk_put(fclk); clk_put(iclk); - fclk = iclk = NULL; + fclk = iclk = hclk = NULL; dev_set_drvdata(&pdev->dev, NULL); return 0; @@ -280,9 +301,7 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg) */ if (at91_suspend_entering_slow_clock()) { ohci_usb_reset (ohci); - clk_disable(fclk); - clk_disable(iclk); - clocked = 0; + at91_stop_clock(); } return 0; @@ -295,11 +314,8 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) if (device_may_wakeup(&pdev->dev)) disable_irq_wake(hcd->irq); - if (!clocked) { - clk_enable(iclk); - clk_enable(fclk); - clocked = 1; - } + if (!clocked) + at91_start_clock(); return 0; } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index fa6a7ceaa0d..f0d29eda3c6 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -42,6 +42,9 @@ #include <asm/system.h> #include <asm/unaligned.h> #include <asm/byteorder.h> +#ifdef CONFIG_PPC_PS3 +#include <asm/firmware.h> +#endif #include "../core/hcd.h" @@ -944,9 +947,12 @@ static int __init ohci_hcd_mod_init(void) sizeof (struct ed), sizeof (struct td)); #ifdef PS3_SYSTEM_BUS_DRIVER - retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER); - if (retval < 0) - goto error_ps3; + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { + retval = ps3_system_bus_driver_register( + &PS3_SYSTEM_BUS_DRIVER); + if (retval < 0) + goto error_ps3; + } #endif #ifdef PLATFORM_DRIVER @@ -992,7 +998,8 @@ static int __init ohci_hcd_mod_init(void) error_platform: #endif #ifdef PS3_SYSTEM_BUS_DRIVER - ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); error_ps3: #endif return retval; @@ -1014,7 +1021,8 @@ static void __exit ohci_hcd_mod_exit(void) platform_driver_unregister(&PLATFORM_DRIVER); #endif #ifdef PS3_SYSTEM_BUS_DRIVER - ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif } module_exit(ohci_hcd_mod_exit); diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 4d8ed3d71a1..ef09952f203 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -515,6 +515,7 @@ void usbhid_close(struct hid_device *hid) #define USB_VENDOR_ID_TURBOX 0x062a #define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 +#define USB_VENDOR_ID_CIDC 0x1677 /* * Initialize all reports @@ -548,7 +549,6 @@ void usbhid_init_reports(struct hid_device *hid) } #define USB_VENDOR_ID_GTCO 0x078c -#define USB_VENDOR_ID_GTCO_IPANEL_2 0x5543 #define USB_DEVICE_ID_GTCO_90 0x0090 #define USB_DEVICE_ID_GTCO_100 0x0100 #define USB_DEVICE_ID_GTCO_101 0x0101 @@ -594,8 +594,6 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_GTCO_1004 0x1004 #define USB_DEVICE_ID_GTCO_1005 0x1005 #define USB_DEVICE_ID_GTCO_1006 0x1006 -#define USB_DEVICE_ID_GTCO_8 0x0008 -#define USB_DEVICE_ID_GTCO_d 0x000d #define USB_VENDOR_ID_WACOM 0x056a @@ -854,8 +852,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_8, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_d, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE }, @@ -953,6 +949,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER }, + { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE }, + { 0, 0 } }; diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index a74bf8617e7..4907e8b8007 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -88,6 +88,17 @@ config USB_LCD To compile this driver as a module, choose M here: the module will be called usblcd. +config USB_BERRY_CHARGE + tristate "USB BlackBerry recharge support" + depends on USB + help + Say Y here if you want to connect a BlackBerry device to your + computer's USB port and have it automatically switch to "recharge" + mode. + + To compile this driver as a module, choose M here: the + module will be called berry_charge. + config USB_LED tristate "USB LED driver support" depends on USB diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 2cba07d3197..dac2d5b7156 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_USB_ADUTUX) += adutux.o obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o obj-$(CONFIG_USB_AUERSWALD) += auerswald.o +obj-$(CONFIG_USB_BERRY_CHARGE) += berry_charge.o obj-$(CONFIG_USB_CYPRESS_CY7C63)+= cypress_cy7c63.o obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 32f0e3a5b02..e573c8ba978 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -281,8 +281,8 @@ static int appledisplay_probe(struct usb_interface *iface, /* Register backlight device */ snprintf(bl_name, sizeof(bl_name), "appledisplay%d", atomic_inc_return(&count_displays) - 1); - pdata->bd = backlight_device_register(bl_name, NULL, - pdata, &appledisplay_bl_data); + pdata->bd = backlight_device_register(bl_name, NULL, pdata, + &appledisplay_bl_data); if (IS_ERR(pdata->bd)) { err("appledisplay: Backlight registration failed"); goto error; diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c new file mode 100644 index 00000000000..60893c6c822 --- /dev/null +++ b/drivers/usb/misc/berry_charge.c @@ -0,0 +1,140 @@ +/* + * USB BlackBerry charging module + * + * Copyright (C) 2007 Greg Kroah-Hartman <gregkh@suse.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + * Information on how to switch configs was taken by the bcharge.cc file + * created by the barry.sf.net project. + * + * bcharge.cc has the following copyright: + * Copyright (C) 2006, Net Direct Inc. (http://www.netdirect.ca/) + * and is released under the GPLv2. + * + * + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/usb.h> + +#define RIM_VENDOR 0x0fca +#define BLACKBERRY 0x0001 + +static int debug; + +#ifdef dbg +#undef dbg +#endif +#define dbg(dev, format, arg...) \ + if (debug) \ + dev_printk(KERN_DEBUG , dev , format , ## arg) + +static struct usb_device_id id_table [] = { + { USB_DEVICE(RIM_VENDOR, BLACKBERRY) }, + { }, /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static int magic_charge(struct usb_device *udev) +{ + char *dummy_buffer = kzalloc(2, GFP_KERNEL); + int retval; + + if (!dummy_buffer) + return -ENOMEM; + + /* send two magic commands and then set the configuration. The device + * will then reset itself with the new power usage and should start + * charging. */ + + /* Note, with testing, it only seems that the first message is really + * needed (at least for the 8700c), but to be safe, we emulate what + * other operating systems seem to be sending to their device. We + * really need to get some specs for this device to be sure about what + * is going on here. + */ + dbg(&udev->dev, "Sending first magic command\n"); + retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0xa5, 0xc0, 0, 1, dummy_buffer, 2, 100); + if (retval != 2) { + dev_err(&udev->dev, "First magic command failed: %d.\n", + retval); + return retval; + } + + dbg(&udev->dev, "Sending first magic command\n"); + retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0xa2, 0x40, 0, 1, dummy_buffer, 0, 100); + if (retval != 0) { + dev_err(&udev->dev, "Second magic command failed: %d.\n", + retval); + return retval; + } + + dbg(&udev->dev, "Calling set_configuration\n"); + retval = usb_driver_set_configuration(udev, 1); + if (retval) + dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); + + return retval; +} + +static int berry_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + + dbg(&udev->dev, "Power is set to %dmA\n", + udev->actconfig->desc.bMaxPower * 2); + + /* check the power usage so we don't try to enable something that is + * already enabled */ + if ((udev->actconfig->desc.bMaxPower * 2) == 500) { + dbg(&udev->dev, "device is already charging, power is " + "set to %dmA\n", udev->actconfig->desc.bMaxPower * 2); + return -ENODEV; + } + + /* turn the power on */ + magic_charge(udev); + + /* we don't really want to bind to the device, userspace programs can + * handle the syncing just fine, so get outta here. */ + return -ENODEV; +} + +static void berry_disconnect(struct usb_interface *intf) +{ +} + +static struct usb_driver berry_driver = { + .name = "berry_charge", + .probe = berry_probe, + .disconnect = berry_disconnect, + .id_table = id_table, +}; + +static int __init berry_init(void) +{ + return usb_register(&berry_driver); +} + +static void __exit berry_exit(void) +{ + usb_deregister(&berry_driver); +} + +module_init(berry_init); +module_exit(berry_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>"); +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index a2b94ef512b..0f3d7dbb537 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -84,6 +84,7 @@ config USB_PEGASUS config USB_RTL8150 tristate "USB RTL8150 based ethernet device support (EXPERIMENTAL)" depends on EXPERIMENTAL + select MII help Say Y here if you have RTL8150 based usb-ethernet adapter. Send me <petkan@users.sourceforge.net> any comments you may have. @@ -98,7 +99,7 @@ config USB_USBNET_MII config USB_USBNET tristate "Multi-purpose USB Networking Framework" - select MII if USBNET_MII != n + select MII if USB_USBNET_MII != n ---help--- This driver supports several kinds of network links over USB, with "minidrivers" built around a common network driver core @@ -239,6 +240,7 @@ config USB_NET_RNDIS_HOST config USB_NET_CDC_SUBSET tristate "Simple USB Network Links (CDC Ethernet subset)" depends on USB_USBNET + default y help This driver module supports USB network devices that can work without any device-specific information. Select it if you have @@ -298,6 +300,13 @@ config USB_EPSON2888 Choose this option to support the usb networking links used by some sample firmware from Epson. +config USB_KC2190 + boolean "KT Technology KC2190 based cables (InstaNet)" + depends on USB_NET_CDC_SUBSET && EXPERIMENTAL + help + Choose this option if you're using a host-to-host cable + with one of these chips. + config USB_NET_ZAURUS tristate "Sharp Zaurus (stock ROMs) and compatible" depends on USB_USBNET diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index bd357e178e5..7ef2e4b5e39 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -351,9 +351,11 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, skb_push(skb, 4); packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); + cpu_to_le32s(&packet_len); memcpy(skb->data, &packet_len, sizeof(packet_len)); if ((skb->len % 512) == 0) { + cpu_to_le32s(&padbytes); memcpy( skb->tail, &padbytes, sizeof(padbytes)); skb_put(skb, sizeof(padbytes)); } diff --git a/drivers/usb/net/cdc_subset.c b/drivers/usb/net/cdc_subset.c index ae8fb06cf38..bc62b012602 100644 --- a/drivers/usb/net/cdc_subset.c +++ b/drivers/usb/net/cdc_subset.c @@ -79,13 +79,19 @@ static int always_connected (struct usbnet *dev) * * ALi M5632 driver ... does high speed * + * NOTE that the MS-Windows drivers for this chip use some funky and + * (naturally) undocumented 7-byte prefix to each packet, so this is a + * case where we don't currently interoperate. Also, once you unplug + * one end of the cable, you need to replug the other end too ... since + * chip docs are unavailable, there's no way to reset the relevant state + * short of a power cycle. + * *-------------------------------------------------------------------------*/ static const struct driver_info ali_m5632_info = { .description = "ALi M5632", }; - #endif @@ -159,6 +165,11 @@ static const struct driver_info epson2888_info = { #endif /* CONFIG_USB_EPSON2888 */ +/*------------------------------------------------------------------------- + * + * info from Jonathan McDowell <noodles@earth.li> + * + *-------------------------------------------------------------------------*/ #ifdef CONFIG_USB_KC2190 #define HAVE_HARDWARE static const struct driver_info kc2190_info = { @@ -223,6 +234,10 @@ static const struct usb_device_id products [] = { USB_DEVICE (0x0402, 0x5632), // ALi defaults .driver_info = (unsigned long) &ali_m5632_info, }, +{ + USB_DEVICE (0x182d,0x207c), // SiteCom CN-124 + .driver_info = (unsigned long) &ali_m5632_info, +}, #endif #ifdef CONFIG_USB_AN2720 @@ -314,13 +329,13 @@ static struct usb_driver cdc_subset_driver = { static int __init cdc_subset_init(void) { - return usb_register(&cdc_subset_driver); + return usb_register(&cdc_subset_driver); } module_init(cdc_subset_init); static void __exit cdc_subset_exit(void) { - usb_deregister(&cdc_subset_driver); + usb_deregister(&cdc_subset_driver); } module_exit(cdc_subset_exit); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 43ba61abfcc..de69b183bd2 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -147,7 +147,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) if (tmp < 0) return tmp; } - + dev->in = usb_rcvbulkpipe (dev->udev, in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->out = usb_sndbulkpipe (dev->udev, @@ -327,7 +327,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) if (netif_running (dev->net) && netif_device_present (dev->net) && !test_bit (EVENT_RX_HALT, &dev->flags)) { - switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ + switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ case -EPIPE: usbnet_defer_kevent (dev, EVENT_RX_HALT); break; @@ -443,7 +443,7 @@ block: case -EOVERFLOW: dev->stats.rx_over_errors++; // FALLTHROUGH - + default: entry->state = rx_cleanup; dev->stats.rx_errors++; @@ -560,7 +560,7 @@ static int usbnet_stop (struct net_device *net) if (netif_msg_ifdown (dev)) devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld", - dev->stats.rx_packets, dev->stats.tx_packets, + dev->stats.rx_packets, dev->stats.tx_packets, dev->stats.rx_errors, dev->stats.tx_errors ); @@ -578,7 +578,7 @@ static int usbnet_stop (struct net_device *net) devdbg (dev, "waited for %d urb completions", temp); } dev->wait = NULL; - remove_wait_queue (&unlink_wakeup, &wait); + remove_wait_queue (&unlink_wakeup, &wait); usb_kill_urb(dev->interrupt); @@ -834,7 +834,7 @@ kevent (struct work_struct *work) } if (test_bit (EVENT_LINK_RESET, &dev->flags)) { - struct driver_info *info = dev->driver_info; + struct driver_info *info = dev->driver_info; int retval = 0; clear_bit (EVENT_LINK_RESET, &dev->flags); @@ -1066,7 +1066,7 @@ static void usbnet_bh (unsigned long param) * USB Device Driver support * *-------------------------------------------------------------------------*/ - + // precondition: never called in_interrupt void usbnet_disconnect (struct usb_interface *intf) @@ -1087,7 +1087,7 @@ void usbnet_disconnect (struct usb_interface *intf) intf->dev.driver->name, xdev->bus->bus_name, xdev->devpath, dev->driver_info->description); - + net = dev->net; unregister_netdev (net); @@ -1111,7 +1111,7 @@ int usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) { struct usbnet *dev; - struct net_device *net; + struct net_device *net; struct usb_host_interface *interface; struct driver_info *info; struct usb_device *xdev; @@ -1181,6 +1181,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) // NOTE net->name still not usable ... if (info->bind) { status = info->bind (dev, udev); + if (status < 0) + goto out1; + // heuristic: "usb%d" for links we know are two-host, // else "eth%d" when there's reasonable doubt. userspace // can rename the link if it knows better. @@ -1207,12 +1210,12 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) if (status == 0 && dev->status) status = init_status (dev, udev); if (status < 0) - goto out1; + goto out3; if (!dev->rx_urb_size) dev->rx_urb_size = dev->hard_mtu; dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); - + SET_NETDEV_DEV(net, &udev->dev); status = register_netdev (net); if (status) @@ -1255,7 +1258,7 @@ EXPORT_SYMBOL_GPL(usbnet_probe); int usbnet_suspend (struct usb_interface *intf, pm_message_t message) { struct usbnet *dev = usb_get_intfdata(intf); - + /* accelerate emptying of the rx and queues, to avoid * having everything error out. */ @@ -1286,7 +1289,7 @@ static int __init usbnet_init(void) < sizeof (struct skb_data)); random_ether_addr(node_id); - return 0; + return 0; } module_init(usbnet_init); diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 0af42e32fa0..18816bf96a4 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -58,11 +58,6 @@ static void airprime_read_bulk_callback(struct urb *urb) if (urb->status) { dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); - /* something happened, so free up the memory for this urb */ - if (urb->transfer_buffer) { - kfree (urb->transfer_buffer); - urb->transfer_buffer = NULL; - } return; } usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); @@ -146,6 +141,8 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp) airprime_read_bulk_callback, port); result = usb_submit_urb(urb, GFP_KERNEL); if (result) { + usb_free_urb(urb); + kfree(buffer); dev_err(&port->dev, "%s - failed submitting read urb %d for port %d, error %d\n", __FUNCTION__, i, port->number, result); @@ -160,27 +157,12 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp) /* some error happened, cancel any submitted urbs and clean up anything that got allocated successfully */ - for ( ; i >= 0; --i) { + while (i-- != 0) { urb = priv->read_urbp[i]; - if (urb) { - /* This urb was submitted successfully. So we have to - cancel it. - Unlinking the urb will invoke read_bulk_callback() - with an error status, so its transfer buffer will - be freed there */ - if (usb_unlink_urb (urb) != -EINPROGRESS) { - /* comments in drivers/usb/core/urb.c say this - can only happen if the urb was never submitted, - or has completed already. - Either way we may have to free the transfer - buffer here. */ - if (urb->transfer_buffer) { - kfree (urb->transfer_buffer); - urb->transfer_buffer = NULL; - } - } - usb_free_urb (urb); - } + buffer = urb->transfer_buffer; + usb_kill_urb (urb); + usb_free_urb (urb); + kfree (buffer); } out: @@ -194,10 +176,9 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp) dbg("%s - port %d", __FUNCTION__, port->number); - /* killing the urb will invoke read_bulk_callback() with an error status, - so the transfer buffer will be freed there */ for (i = 0; i < NUM_READ_URBS; ++i) { usb_kill_urb (priv->read_urbp[i]); + kfree (priv->read_urbp[i]->transfer_buffer); usb_free_urb (priv->read_urbp[i]); } diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 3ec24870bca..db623e75489 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -69,6 +69,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */ { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { } /* Terminating Entry */ diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 601e0648dec..53baeec8f26 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -66,6 +66,8 @@ struct usb_serial_driver usb_serial_generic_device = { .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, .shutdown = usb_serial_generic_shutdown, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, }; static int generic_probe(struct usb_interface *interface, @@ -115,6 +117,7 @@ int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; int result = 0; + unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); @@ -124,7 +127,13 @@ int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp) if (port->tty) port->tty->low_latency = 1; - /* if we have a bulk interrupt, start reading from it */ + /* clear the throttle flags */ + spin_lock_irqsave(&port->lock, flags); + port->throttled = 0; + port->throttle_req = 0; + spin_unlock_irqrestore(&port->lock, flags); + + /* if we have a bulk endpoint, start reading from it */ if (serial->num_bulk_in) { /* Start reading from the device */ usb_fill_bulk_urb (port->read_urb, serial->dev, @@ -253,31 +262,22 @@ int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port) return (chars); } -void usb_serial_generic_read_bulk_callback (struct urb *urb) +/* Push data to tty layer and resubmit the bulk read URB */ +static void flush_and_resubmit_read_urb (struct usb_serial_port *port) { - struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = port->serial; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; + struct urb *urb = port->read_urb; + struct tty_struct *tty = port->tty; int result; - dbg("%s - port %d", __FUNCTION__, port->number); - - if (urb->status) { - dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); - return; - } - - usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); - - tty = port->tty; + /* Push data to tty */ if (tty && urb->actual_length) { tty_buffer_request_room(tty, urb->actual_length); - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); + tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length); + tty_flip_buffer_push(tty); /* is this allowed from an URB callback ? */ } - /* Continue trying to always read */ + /* Continue reading from device */ usb_fill_bulk_urb (port->read_urb, serial->dev, usb_rcvbulkpipe (serial->dev, port->bulk_in_endpointAddress), @@ -290,6 +290,40 @@ void usb_serial_generic_read_bulk_callback (struct urb *urb) if (result) dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); } + +void usb_serial_generic_read_bulk_callback (struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + unsigned char *data = urb->transfer_buffer; + int is_throttled; + unsigned long flags; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (urb->status) { + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); + return; + } + + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); + + /* Throttle the device if requested by tty */ + if (urb->actual_length) { + spin_lock_irqsave(&port->lock, flags); + is_throttled = port->throttled = port->throttle_req; + spin_unlock_irqrestore(&port->lock, flags); + if (is_throttled) { + /* Let the received data linger in the read URB; + * usb_serial_generic_unthrottle() will pick it + * up later. */ + dbg("%s - throttling device", __FUNCTION__); + return; + } + } + + /* Handle data and continue reading from device */ + flush_and_resubmit_read_urb(port); +} EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); void usb_serial_generic_write_bulk_callback (struct urb *urb) @@ -308,6 +342,38 @@ void usb_serial_generic_write_bulk_callback (struct urb *urb) } EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); +void usb_serial_generic_throttle (struct usb_serial_port *port) +{ + unsigned long flags; + + dbg("%s - port %d", __FUNCTION__, port->number); + + /* Set the throttle request flag. It will be picked up + * by usb_serial_generic_read_bulk_callback(). */ + spin_lock_irqsave(&port->lock, flags); + port->throttle_req = 1; + spin_unlock_irqrestore(&port->lock, flags); +} + +void usb_serial_generic_unthrottle (struct usb_serial_port *port) +{ + int was_throttled; + unsigned long flags; + + dbg("%s - port %d", __FUNCTION__, port->number); + + /* Clear the throttle flags */ + spin_lock_irqsave(&port->lock, flags); + was_throttled = port->throttled; + port->throttled = port->throttle_req = 0; + spin_unlock_irqrestore(&port->lock, flags); + + if (was_throttled) { + /* Handle pending data and resume reading from device */ + flush_and_resubmit_read_urb(port); + } +} + void usb_serial_generic_shutdown (struct usb_serial *serial) { int i; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index ced9f32b29d..9963a8b7584 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -69,7 +69,6 @@ static int option_send_setup(struct usb_serial_port *port); /* Vendor and product IDs */ #define OPTION_VENDOR_ID 0x0AF0 #define HUAWEI_VENDOR_ID 0x12D1 -#define AUDIOVOX_VENDOR_ID 0x0F3D #define NOVATELWIRELESS_VENDOR_ID 0x1410 #define ANYDATA_VENDOR_ID 0x16d5 @@ -81,7 +80,6 @@ static int option_send_setup(struct usb_serial_port *port); #define OPTION_PRODUCT_GTMAX36 0x6701 #define HUAWEI_PRODUCT_E600 0x1001 #define HUAWEI_PRODUCT_E220 0x1003 -#define AUDIOVOX_PRODUCT_AIRCARD 0x0112 #define NOVATELWIRELESS_PRODUCT_U740 0x1400 #define ANYDATA_PRODUCT_ID 0x6501 @@ -94,7 +92,6 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) }, - { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, { } /* Terminating entry */ @@ -109,7 +106,6 @@ static struct usb_device_id option_ids1[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) }, - { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, { } /* Terminating entry */ diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 6c083d4e2c9..83dfae93a45 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -83,6 +83,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) }, + { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 65a5039665e..f9a71d0c102 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -97,3 +97,8 @@ /* Huawei E620 UMTS/HSDPA card (ID: 12d1:1001) */ #define HUAWEI_VENDOR_ID 0x12d1 #define HUAWEI_PRODUCT_ID 0x1001 + +/* Willcom WS002IN Data Driver (by NetIndex Inc.) */ +#define WS002IN_VENDOR_ID 0x11f6 +#define WS002IN_PRODUCT_ID 0x2001 + diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 70234f5dbee..e227f64d564 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -153,6 +153,12 @@ static int slave_configure(struct scsi_device *sdev) if (us->flags & US_FL_FIX_CAPACITY) sdev->fix_capacity = 1; + /* A few disks have two indistinguishable version, one of + * which reports the correct capacity and the other does not. + * The sd driver has to guess which is the case. */ + if (us->flags & US_FL_CAPACITY_HEURISTICS) + sdev->guess_capacity = 1; + /* Some devices report a SCSI revision level above 2 but are * unable to handle the REPORT LUNS command (for which * support is mandatory at level 3). Since we already have diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index f49a62fc32d..9644a8ea4aa 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1101,6 +1101,15 @@ UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN), +/* Submitted by Dylan Taft <d13f00l@gmail.com> + * US_FL_IGNORE_RESIDUE Needed + */ +UNUSUAL_DEV( 0x08ca, 0x3103, 0x0100, 0x0100, + "AIPTEK", + "Aiptek USB Keychain MP3 Player", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE), + /* Entry needed for flags. Moreover, all devices with this ID use * bulk-only transport, but _some_ falsely report Control/Bulk instead. * One example is "Trumpion Digital Research MYMP3". @@ -1311,12 +1320,13 @@ UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_NO_WP_DETECT ), -/* Reported by Jan Mate <mate@fiit.stuba.sk> */ +/* Reported by Jan Mate <mate@fiit.stuba.sk> + * and by Soeren Sonnenburg <kernel@nn7.de> */ UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, "Sony Ericsson", "P990i", US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), + US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ), /* Reported by Emmanuel Vasilakis <evas@forthnet.gr> */ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000, @@ -1385,6 +1395,16 @@ UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Thomas Baechler <thomas@archlinux.org> + * Fixes I/O errors with Teac HD-35PU devices + */ + +UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201, + "Super Top", + "USB 2.0 IDE DEVICE", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE), + /* patch submitted by Davide Perini <perini.davide@dpsoftware.org> * and Renato Perini <rperini@email.it> */ @@ -1423,7 +1443,7 @@ UNUSUAL_DEV( 0xed06, 0x4500, 0x0001, 0x0001, "DataStor", "USB4500 FW1.04", US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY), + US_FL_CAPACITY_HEURISTICS), /* Control/Bulk transport for all SubClass values */ USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR), diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 296b091cf16..46929a1b6f2 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -90,13 +90,15 @@ static int skel_open(struct inode *inode, struct file *file) goto exit; } + /* increment our usage count for the device */ + kref_get(&dev->kref); + /* prevent the device from being autosuspended */ retval = usb_autopm_get_interface(interface); - if (retval) + if (retval) { + kref_put(&dev->kref, skel_delete); goto exit; - - /* increment our usage count for the device */ - kref_get(&dev->kref); + } /* save our object in the file's private structure */ file->private_data = dev; diff --git a/fs/Kconfig b/fs/Kconfig index a722b5a3f75..3c4886b849f 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1189,32 +1189,6 @@ config EFS_FS To compile the EFS file system support as a module, choose M here: the module will be called efs. -config JFFS_FS - tristate "Journalling Flash File System (JFFS) support" - depends on MTD && BLOCK && BROKEN - help - JFFS is the Journalling Flash File System developed by Axis - Communications in Sweden, aimed at providing a crash/powerdown-safe - file system for disk-less embedded devices. Further information is - available at (<http://developer.axis.com/software/jffs/>). - - NOTE: This filesystem is deprecated and is scheduled for removal in - 2.6.21. See Documentation/feature-removal-schedule.txt - -config JFFS_FS_VERBOSE - int "JFFS debugging verbosity (0 = quiet, 3 = noisy)" - depends on JFFS_FS - default "0" - help - Determines the verbosity level of the JFFS debugging messages. - -config JFFS_PROC_FS - bool "JFFS stats available in /proc filesystem" - depends on JFFS_FS && PROC_FS - help - Enabling this option will cause statistics from mounted JFFS file systems - to be made available to the user in the /proc/fs/jffs/ directory. - config JFFS2_FS tristate "Journalling Flash File System v2 (JFFS2) support" select CRC32 diff --git a/fs/Makefile b/fs/Makefile index b9ffa63f77f..9edf4112bee 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -94,7 +94,6 @@ obj-$(CONFIG_HPFS_FS) += hpfs/ obj-$(CONFIG_NTFS_FS) += ntfs/ obj-$(CONFIG_UFS_FS) += ufs/ obj-$(CONFIG_EFS_FS) += efs/ -obj-$(CONFIG_JFFS_FS) += jffs/ obj-$(CONFIG_JFFS2_FS) += jffs2/ obj-$(CONFIG_AFFS_FS) += affs/ obj-$(CONFIG_ROMFS_FS) += romfs/ diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 8d130cc8532..682f928b7f4 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -16,6 +16,7 @@ #include <linux/module.h> #include <linux/fs.h> #include <linux/pagemap.h> +#include <linux/namei.h> #include <linux/debugfs.h> static ssize_t default_read_file(struct file *file, char __user *buf, @@ -44,6 +45,17 @@ const struct file_operations debugfs_file_operations = { .open = default_open, }; +static void *debugfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + nd_set_link(nd, dentry->d_inode->i_private); + return NULL; +} + +const struct inode_operations debugfs_link_operations = { + .readlink = generic_readlink, + .follow_link = debugfs_follow_link, +}; + static void debugfs_u8_set(void *data, u64 val) { *(u8 *)data = val; diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index c692487346e..7b324cfebcb 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -25,11 +25,13 @@ #include <linux/namei.h> #include <linux/debugfs.h> #include <linux/fsnotify.h> +#include <linux/string.h> #define DEBUGFS_MAGIC 0x64626720 /* declared over in file.c */ extern struct file_operations debugfs_file_operations; +extern struct inode_operations debugfs_link_operations; static struct vfsmount *debugfs_mount; static int debugfs_mount_count; @@ -51,6 +53,9 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d case S_IFREG: inode->i_fop = &debugfs_file_operations; break; + case S_IFLNK: + inode->i_op = &debugfs_link_operations; + break; case S_IFDIR: inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; @@ -96,6 +101,12 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) return res; } +static int debugfs_link(struct inode *dir, struct dentry *dentry, int mode) +{ + mode = (mode & S_IALLUGO) | S_IFLNK; + return debugfs_mknod(dir, dentry, mode, 0); +} + static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode) { int res; @@ -158,10 +169,17 @@ static int debugfs_create_by_name(const char *name, mode_t mode, mutex_lock(&parent->d_inode->i_mutex); *dentry = lookup_one_len(name, parent, strlen(name)); if (!IS_ERR(*dentry)) { - if ((mode & S_IFMT) == S_IFDIR) + switch (mode & S_IFMT) { + case S_IFDIR: error = debugfs_mkdir(parent->d_inode, *dentry, mode); - else + break; + case S_IFLNK: + error = debugfs_link(parent->d_inode, *dentry, mode); + break; + default: error = debugfs_create(parent->d_inode, *dentry, mode); + break; + } dput(*dentry); } else error = PTR_ERR(*dentry); @@ -194,9 +212,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode, * you are responsible here.) If an error occurs, %NULL will be returned. * * If debugfs is not enabled in the kernel, the value -%ENODEV will be - * returned. It is not wise to check for this value, but rather, check for - * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling - * code. + * returned. */ struct dentry *debugfs_create_file(const char *name, mode_t mode, struct dentry *parent, void *data, @@ -246,9 +262,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_file); * you are responsible here.) If an error occurs, %NULL will be returned. * * If debugfs is not enabled in the kernel, the value -%ENODEV will be - * returned. It is not wise to check for this value, but rather, check for - * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling - * code. + * returned. */ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent) { @@ -259,6 +273,47 @@ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent) EXPORT_SYMBOL_GPL(debugfs_create_dir); /** + * debugfs_create_symlink- create a symbolic link in the debugfs filesystem + * @name: a pointer to a string containing the name of the symbolic link to + * create. + * @parent: a pointer to the parent dentry for this symbolic link. This + * should be a directory dentry if set. If this paramater is NULL, + * then the symbolic link will be created in the root of the debugfs + * filesystem. + * @target: a pointer to a string containing the path to the target of the + * symbolic link. + * + * This function creates a symbolic link with the given name in debugfs that + * links to the given target path. + * + * This function will return a pointer to a dentry if it succeeds. This + * pointer must be passed to the debugfs_remove() function when the symbolic + * link is to be removed (no automatic cleanup happens if your module is + * unloaded, you are responsible here.) If an error occurs, %NULL will be + * returned. + * + * If debugfs is not enabled in the kernel, the value -%ENODEV will be + * returned. + */ +struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, + const char *target) +{ + struct dentry *result; + char *link; + + link = kstrdup(target, GFP_KERNEL); + if (!link) + return NULL; + + result = debugfs_create_file(name, S_IFLNK | S_IRWXUGO, parent, link, + NULL); + if (!result) + kfree(link); + return result; +} +EXPORT_SYMBOL_GPL(debugfs_create_symlink); + +/** * debugfs_remove - removes a file or directory from the debugfs filesystem * @dentry: a pointer to a the dentry of the file or directory to be * removed. @@ -287,15 +342,22 @@ void debugfs_remove(struct dentry *dentry) if (debugfs_positive(dentry)) { if (dentry->d_inode) { dget(dentry); - if (S_ISDIR(dentry->d_inode->i_mode)) { + switch (dentry->d_inode->i_mode & S_IFMT) { + case S_IFDIR: ret = simple_rmdir(parent->d_inode, dentry); if (ret) printk(KERN_ERR "DebugFS rmdir on %s failed : " "directory not empty.\n", dentry->d_name.name); - } else + break; + case S_IFLNK: + kfree(dentry->d_inode->i_private); + /* fall through */ + default: simple_unlink(parent->d_inode, dentry); + break; + } if (!ret) d_delete(dentry); dput(dentry); diff --git a/fs/jffs/Makefile b/fs/jffs/Makefile deleted file mode 100644 index 9c1c0bb5969..00000000000 --- a/fs/jffs/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for the linux Journalling Flash FileSystem (JFFS) routines. -# -# $Id: Makefile,v 1.11 2001/09/25 20:59:41 dwmw2 Exp $ -# - -obj-$(CONFIG_JFFS_FS) += jffs.o - -jffs-y := jffs_fm.o intrep.o inode-v23.o -jffs-$(CONFIG_JFFS_PROC_FS) += jffs_proc.o -jffs-objs := $(jffs-y) diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c deleted file mode 100644 index 9602b925da0..00000000000 --- a/fs/jffs/inode-v23.c +++ /dev/null @@ -1,1847 +0,0 @@ -/* - * JFFS -- Journalling Flash File System, Linux implementation. - * - * Copyright (C) 1999, 2000 Axis Communications AB. - * - * Created by Finn Hakansson <finn@axis.com>. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * $Id: inode-v23.c,v 1.70 2001/10/02 09:16:02 dwmw2 Exp $ - * - * Ported to Linux 2.3.x and MTD: - * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB - * - * Copyright 2000, 2001 Red Hat, Inc. - */ - -/* inode.c -- Contains the code that is called from the VFS. */ - -/* TODO-ALEX: - * uid and gid are just 16 bit. - * jffs_file_write reads from user-space pointers without xx_from_user - * maybe other stuff do to. - */ - -#include <linux/time.h> - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/jffs.h> -#include <linux/fs.h> -#include <linux/smp_lock.h> -#include <linux/ioctl.h> -#include <linux/stat.h> -#include <linux/blkdev.h> -#include <linux/quotaops.h> -#include <linux/highmem.h> -#include <linux/vfs.h> -#include <linux/mutex.h> -#include <asm/byteorder.h> -#include <asm/uaccess.h> - -#include "jffs_fm.h" -#include "intrep.h" -#ifdef CONFIG_JFFS_PROC_FS -#include "jffs_proc.h" -#endif - -static int jffs_remove(struct inode *dir, struct dentry *dentry, int type); - -static const struct super_operations jffs_ops; -static const struct file_operations jffs_file_operations; -static const struct inode_operations jffs_file_inode_operations; -static const struct file_operations jffs_dir_operations; -static const struct inode_operations jffs_dir_inode_operations; -static const struct address_space_operations jffs_address_operations; - -struct kmem_cache *node_cache = NULL; -struct kmem_cache *fm_cache = NULL; - -/* Called by the VFS at mount time to initialize the whole file system. */ -static int jffs_fill_super(struct super_block *sb, void *data, int silent) -{ - struct inode *root_inode; - struct jffs_control *c; - - sb->s_flags |= MS_NODIRATIME; - - D1(printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n", - sb->s_id)); - - if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) { - printk(KERN_WARNING "JFFS: Trying to mount a " - "non-mtd device.\n"); - return -EINVAL; - } - - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_fs_info = (void *) 0; - sb->s_maxbytes = 0xFFFFFFFF; - - /* Build the file system. */ - if (jffs_build_fs(sb) < 0) { - goto jffs_sb_err1; - } - - /* - * set up enough so that we can read an inode - */ - sb->s_magic = JFFS_MAGIC_SB_BITMASK; - sb->s_op = &jffs_ops; - - root_inode = iget(sb, JFFS_MIN_INO); - if (!root_inode) - goto jffs_sb_err2; - - /* Get the root directory of this file system. */ - if (!(sb->s_root = d_alloc_root(root_inode))) { - goto jffs_sb_err3; - } - - c = (struct jffs_control *) sb->s_fs_info; - -#ifdef CONFIG_JFFS_PROC_FS - /* Set up the jffs proc file system. */ - if (jffs_register_jffs_proc_dir(MINOR(sb->s_dev), c) < 0) { - printk(KERN_WARNING "JFFS: Failed to initialize the JFFS " - "proc file system for device %s.\n", - sb->s_id); - } -#endif - - /* Set the Garbage Collection thresholds */ - - /* GC if free space goes below 5% of the total size */ - c->gc_minfree_threshold = c->fmc->flash_size / 20; - - if (c->gc_minfree_threshold < c->fmc->sector_size) - c->gc_minfree_threshold = c->fmc->sector_size; - - /* GC if dirty space exceeds 33% of the total size. */ - c->gc_maxdirty_threshold = c->fmc->flash_size / 3; - - if (c->gc_maxdirty_threshold < c->fmc->sector_size) - c->gc_maxdirty_threshold = c->fmc->sector_size; - - - c->thread_pid = kernel_thread (jffs_garbage_collect_thread, - (void *) c, - CLONE_KERNEL); - D1(printk(KERN_NOTICE "JFFS: GC thread pid=%d.\n", (int) c->thread_pid)); - - D1(printk(KERN_NOTICE "JFFS: Successfully mounted device %s.\n", - sb->s_id)); - return 0; - -jffs_sb_err3: - iput(root_inode); -jffs_sb_err2: - jffs_cleanup_control((struct jffs_control *)sb->s_fs_info); -jffs_sb_err1: - printk(KERN_WARNING "JFFS: Failed to mount device %s.\n", - sb->s_id); - return -EINVAL; -} - - -/* This function is called when the file system is umounted. */ -static void -jffs_put_super(struct super_block *sb) -{ - struct jffs_control *c = (struct jffs_control *) sb->s_fs_info; - - D2(printk("jffs_put_super()\n")); - -#ifdef CONFIG_JFFS_PROC_FS - jffs_unregister_jffs_proc_dir(c); -#endif - - if (c->gc_task) { - D1(printk (KERN_NOTICE "jffs_put_super(): Telling gc thread to die.\n")); - send_sig(SIGKILL, c->gc_task, 1); - } - wait_for_completion(&c->gc_thread_comp); - - D1(printk (KERN_NOTICE "jffs_put_super(): Successfully waited on thread.\n")); - - jffs_cleanup_control((struct jffs_control *)sb->s_fs_info); - D1(printk(KERN_NOTICE "JFFS: Successfully unmounted device %s.\n", - sb->s_id)); -} - - -/* This function is called when user commands like chmod, chgrp and - chown are executed. System calls like trunc() results in a call - to this function. */ -static int -jffs_setattr(struct dentry *dentry, struct iattr *iattr) -{ - struct inode *inode = dentry->d_inode; - struct jffs_raw_inode raw_inode; - struct jffs_control *c; - struct jffs_fmcontrol *fmc; - struct jffs_file *f; - struct jffs_node *new_node; - int update_all; - int res = 0; - int recoverable = 0; - - lock_kernel(); - - if ((res = inode_change_ok(inode, iattr))) - goto out; - - c = (struct jffs_control *)inode->i_sb->s_fs_info; - fmc = c->fmc; - - D3(printk (KERN_NOTICE "notify_change(): down biglock\n")); - mutex_lock(&fmc->biglock); - - f = jffs_find_file(c, inode->i_ino); - - ASSERT(if (!f) { - printk("jffs_setattr(): Invalid inode number: %lu\n", - inode->i_ino); - D3(printk (KERN_NOTICE "notify_change(): up biglock\n")); - mutex_unlock(&fmc->biglock); - res = -EINVAL; - goto out; - }); - - D1(printk("***jffs_setattr(): file: \"%s\", ino: %u\n", - f->name, f->ino)); - - update_all = iattr->ia_valid & ATTR_FORCE; - - if ( (update_all || iattr->ia_valid & ATTR_SIZE) - && (iattr->ia_size + 128 < f->size) ) { - /* We're shrinking the file by more than 128 bytes. - We'll be able to GC and recover this space, so - allow it to go into the reserved space. */ - recoverable = 1; - } - - if (!(new_node = jffs_alloc_node())) { - D(printk("jffs_setattr(): Allocation failed!\n")); - D3(printk (KERN_NOTICE "notify_change(): up biglock\n")); - mutex_unlock(&fmc->biglock); - res = -ENOMEM; - goto out; - } - - new_node->data_offset = 0; - new_node->removed_size = 0; - raw_inode.magic = JFFS_MAGIC_BITMASK; - raw_inode.ino = f->ino; - raw_inode.pino = f->pino; - raw_inode.mode = f->mode; - raw_inode.uid = f->uid; - raw_inode.gid = f->gid; - raw_inode.atime = f->atime; - raw_inode.mtime = f->mtime; - raw_inode.ctime = f->ctime; - raw_inode.dsize = 0; - raw_inode.offset = 0; - raw_inode.rsize = 0; - raw_inode.dsize = 0; - raw_inode.nsize = f->nsize; - raw_inode.nlink = f->nlink; - raw_inode.spare = 0; - raw_inode.rename = 0; - raw_inode.deleted = 0; - - if (update_all || iattr->ia_valid & ATTR_MODE) { - raw_inode.mode = iattr->ia_mode; - inode->i_mode = iattr->ia_mode; - } - if (update_all || iattr->ia_valid & ATTR_UID) { - raw_inode.uid = iattr->ia_uid; - inode->i_uid = iattr->ia_uid; - } - if (update_all || iattr->ia_valid & ATTR_GID) { - raw_inode.gid = iattr->ia_gid; - inode->i_gid = iattr->ia_gid; - } - if (update_all || iattr->ia_valid & ATTR_SIZE) { - int len; - D1(printk("jffs_notify_change(): Changing size " - "to %lu bytes!\n", (long)iattr->ia_size)); - raw_inode.offset = iattr->ia_size; - - /* Calculate how many bytes need to be removed from - the end. */ - if (f->size < iattr->ia_size) { - len = 0; - } - else { - len = f->size - iattr->ia_size; - } - - raw_inode.rsize = len; - - /* The updated node will be a removal node, with - base at the new size and size of the nbr of bytes - to be removed. */ - new_node->data_offset = iattr->ia_size; - new_node->removed_size = len; - inode->i_size = iattr->ia_size; - inode->i_blocks = (inode->i_size + 511) >> 9; - - if (len) { - invalidate_mapping_pages(inode->i_mapping, 0, -1); - } - inode->i_ctime = CURRENT_TIME_SEC; - inode->i_mtime = inode->i_ctime; - } - if (update_all || iattr->ia_valid & ATTR_ATIME) { - raw_inode.atime = iattr->ia_atime.tv_sec; - inode->i_atime = iattr->ia_atime; - } - if (update_all || iattr->ia_valid & ATTR_MTIME) { - raw_inode.mtime = iattr->ia_mtime.tv_sec; - inode->i_mtime = iattr->ia_mtime; - } - if (update_all || iattr->ia_valid & ATTR_CTIME) { - raw_inode.ctime = iattr->ia_ctime.tv_sec; - inode->i_ctime = iattr->ia_ctime; - } - - /* Write this node to the flash. */ - if ((res = jffs_write_node(c, new_node, &raw_inode, f->name, NULL, recoverable, f)) < 0) { - D(printk("jffs_notify_change(): The write failed!\n")); - jffs_free_node(new_node); - D3(printk (KERN_NOTICE "n_c(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - goto out; - } - - jffs_insert_node(c, f, &raw_inode, NULL, new_node); - - mark_inode_dirty(inode); - D3(printk (KERN_NOTICE "n_c(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); -out: - unlock_kernel(); - return res; -} /* jffs_notify_change() */ - - -static struct inode * -jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode, - int * err) -{ - struct super_block * sb; - struct inode * inode; - struct jffs_control *c; - struct jffs_file *f; - - sb = dir->i_sb; - inode = new_inode(sb); - if (!inode) { - *err = -ENOMEM; - return NULL; - } - - c = (struct jffs_control *)sb->s_fs_info; - - inode->i_ino = raw_inode->ino; - inode->i_mode = raw_inode->mode; - inode->i_nlink = raw_inode->nlink; - inode->i_uid = raw_inode->uid; - inode->i_gid = raw_inode->gid; - inode->i_size = raw_inode->dsize; - inode->i_atime.tv_sec = raw_inode->atime; - inode->i_mtime.tv_sec = raw_inode->mtime; - inode->i_ctime.tv_sec = raw_inode->ctime; - inode->i_ctime.tv_nsec = 0; - inode->i_mtime.tv_nsec = 0; - inode->i_atime.tv_nsec = 0; - inode->i_blocks = (inode->i_size + 511) >> 9; - - f = jffs_find_file(c, raw_inode->ino); - - inode->i_private = (void *)f; - insert_inode_hash(inode); - - return inode; -} - -/* Get statistics of the file system. */ -static int -jffs_statfs(struct dentry *dentry, struct kstatfs *buf) -{ - struct jffs_control *c = (struct jffs_control *) dentry->d_sb->s_fs_info; - struct jffs_fmcontrol *fmc; - - lock_kernel(); - - fmc = c->fmc; - - D2(printk("jffs_statfs()\n")); - - buf->f_type = JFFS_MAGIC_SB_BITMASK; - buf->f_bsize = PAGE_CACHE_SIZE; - buf->f_blocks = (fmc->flash_size / PAGE_CACHE_SIZE) - - (fmc->min_free_size / PAGE_CACHE_SIZE); - buf->f_bfree = (jffs_free_size1(fmc) + jffs_free_size2(fmc) + - fmc->dirty_size - fmc->min_free_size) - >> PAGE_CACHE_SHIFT; - buf->f_bavail = buf->f_bfree; - - /* Find out how many files there are in the filesystem. */ - buf->f_files = jffs_foreach_file(c, jffs_file_count); - buf->f_ffree = buf->f_bfree; - /* buf->f_fsid = 0; */ - buf->f_namelen = JFFS_MAX_NAME_LEN; - - unlock_kernel(); - - return 0; -} - - -/* Rename a file. */ -static int -jffs_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) -{ - struct jffs_raw_inode raw_inode; - struct jffs_control *c; - struct jffs_file *old_dir_f; - struct jffs_file *new_dir_f; - struct jffs_file *del_f; - struct jffs_file *f; - struct jffs_node *node; - struct inode *inode; - int result = 0; - __u32 rename_data = 0; - - D2(printk("***jffs_rename()\n")); - - D(printk("jffs_rename(): old_dir: 0x%p, old name: 0x%p, " - "new_dir: 0x%p, new name: 0x%p\n", - old_dir, old_dentry->d_name.name, - new_dir, new_dentry->d_name.name)); - - lock_kernel(); - c = (struct jffs_control *)old_dir->i_sb->s_fs_info; - ASSERT(if (!c) { - printk(KERN_ERR "jffs_rename(): The old_dir inode " - "didn't have a reference to a jffs_file struct\n"); - unlock_kernel(); - return -EIO; - }); - - result = -ENOTDIR; - if (!(old_dir_f = old_dir->i_private)) { - D(printk("jffs_rename(): Old dir invalid.\n")); - goto jffs_rename_end; - } - - /* Try to find the file to move. */ - result = -ENOENT; - if (!(f = jffs_find_child(old_dir_f, old_dentry->d_name.name, - old_dentry->d_name.len))) { - goto jffs_rename_end; - } - - /* Find the new directory. */ - result = -ENOTDIR; - if (!(new_dir_f = new_dir->i_private)) { - D(printk("jffs_rename(): New dir invalid.\n")); - goto jffs_rename_end; - } - D3(printk (KERN_NOTICE "rename(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - /* Create a node and initialize as much as needed. */ - result = -ENOMEM; - if (!(node = jffs_alloc_node())) { - D(printk("jffs_rename(): Allocation failed: node == 0\n")); - goto jffs_rename_end; - } - node->data_offset = 0; - node->removed_size = 0; - - /* Initialize the raw inode. */ - raw_inode.magic = JFFS_MAGIC_BITMASK; - raw_inode.ino = f->ino; - raw_inode.pino = new_dir_f->ino; -/* raw_inode.version = f->highest_version + 1; */ - raw_inode.mode = f->mode; - raw_inode.uid = current->fsuid; - raw_inode.gid = current->fsgid; -#if 0 - raw_inode.uid = f->uid; - raw_inode.gid = f->gid; -#endif - raw_inode.atime = get_seconds(); - raw_inode.mtime = raw_inode.atime; - raw_inode.ctime = f->ctime; - raw_inode.offset = 0; - raw_inode.dsize = 0; - raw_inode.rsize = 0; - raw_inode.nsize = new_dentry->d_name.len; - raw_inode.nlink = f->nlink; - raw_inode.spare = 0; - raw_inode.rename = 0; - raw_inode.deleted = 0; - - /* See if there already exists a file with the same name as - new_name. */ - if ((del_f = jffs_find_child(new_dir_f, new_dentry->d_name.name, - new_dentry->d_name.len))) { - raw_inode.rename = 1; - raw_inode.dsize = sizeof(__u32); - rename_data = del_f->ino; - } - - /* Write the new node to the flash memory. */ - if ((result = jffs_write_node(c, node, &raw_inode, - new_dentry->d_name.name, - (unsigned char*)&rename_data, 0, f)) < 0) { - D(printk("jffs_rename(): Failed to write node to flash.\n")); - jffs_free_node(node); - goto jffs_rename_end; - } - raw_inode.dsize = 0; - - if (raw_inode.rename) { - /* The file with the same name must be deleted. */ - //FIXME deadlock down(&c->fmc->gclock); - if ((result = jffs_remove(new_dir, new_dentry, - del_f->mode)) < 0) { - /* This is really bad. */ - printk(KERN_ERR "JFFS: An error occurred in " - "rename().\n"); - } - // up(&c->fmc->gclock); - } - - if (old_dir_f != new_dir_f) { - /* Remove the file from its old position in the - filesystem tree. */ - jffs_unlink_file_from_tree(f); - } - - /* Insert the new node into the file system. */ - if ((result = jffs_insert_node(c, f, &raw_inode, - new_dentry->d_name.name, node)) < 0) { - D(printk(KERN_ERR "jffs_rename(): jffs_insert_node() " - "failed!\n")); - } - - if (old_dir_f != new_dir_f) { - /* Insert the file to its new position in the - file system. */ - jffs_insert_file_into_tree(f); - } - - /* This is a kind of update of the inode we're about to make - here. This is what they do in ext2fs. Kind of. */ - if ((inode = iget(new_dir->i_sb, f->ino))) { - inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); - iput(inode); - } - -jffs_rename_end: - D3(printk (KERN_NOTICE "rename(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - unlock_kernel(); - return result; -} /* jffs_rename() */ - - -/* Read the contents of a directory. Used by programs like `ls' - for instance. */ -static int -jffs_readdir(struct file *filp, void *dirent, filldir_t filldir) -{ - struct jffs_file *f; - struct dentry *dentry = filp->f_path.dentry; - struct inode *inode = dentry->d_inode; - struct jffs_control *c = (struct jffs_control *)inode->i_sb->s_fs_info; - int j; - int ddino; - lock_kernel(); - D3(printk (KERN_NOTICE "readdir(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - - D2(printk("jffs_readdir(): inode: 0x%p, filp: 0x%p\n", inode, filp)); - if (filp->f_pos == 0) { - D3(printk("jffs_readdir(): \".\" %lu\n", inode->i_ino)); - if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) { - D3(printk (KERN_NOTICE "readdir(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - unlock_kernel(); - return 0; - } - filp->f_pos = 1; - } - if (filp->f_pos == 1) { - if (inode->i_ino == JFFS_MIN_INO) { - ddino = JFFS_MIN_INO; - } - else { - ddino = ((struct jffs_file *) - inode->i_private)->pino; - } - D3(printk("jffs_readdir(): \"..\" %u\n", ddino)); - if (filldir(dirent, "..", 2, filp->f_pos, ddino, DT_DIR) < 0) { - D3(printk (KERN_NOTICE "readdir(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - unlock_kernel(); - return 0; - } - filp->f_pos++; - } - f = ((struct jffs_file *)inode->i_private)->children; - - j = 2; - while(f && (f->deleted || j++ < filp->f_pos )) { - f = f->sibling_next; - } - - while (f) { - D3(printk("jffs_readdir(): \"%s\" ino: %u\n", - (f->name ? f->name : ""), f->ino)); - if (filldir(dirent, f->name, f->nsize, - filp->f_pos , f->ino, DT_UNKNOWN) < 0) { - D3(printk (KERN_NOTICE "readdir(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - unlock_kernel(); - return 0; - } - filp->f_pos++; - do { - f = f->sibling_next; - } while(f && f->deleted); - } - D3(printk (KERN_NOTICE "readdir(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - unlock_kernel(); - return filp->f_pos; -} /* jffs_readdir() */ - - -/* Find a file in a directory. If the file exists, return its - corresponding dentry. */ -static struct dentry * -jffs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) -{ - struct jffs_file *d; - struct jffs_file *f; - struct jffs_control *c = (struct jffs_control *)dir->i_sb->s_fs_info; - int len; - int r = 0; - const char *name; - struct inode *inode = NULL; - - len = dentry->d_name.len; - name = dentry->d_name.name; - - lock_kernel(); - - D3({ - char *s = kmalloc(len + 1, GFP_KERNEL); - memcpy(s, name, len); - s[len] = '\0'; - printk("jffs_lookup(): dir: 0x%p, name: \"%s\"\n", dir, s); - kfree(s); - }); - - D3(printk (KERN_NOTICE "lookup(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - - r = -ENAMETOOLONG; - if (len > JFFS_MAX_NAME_LEN) { - goto jffs_lookup_end; - } - - r = -EACCES; - if (!(d = (struct jffs_file *)dir->i_private)) { - D(printk("jffs_lookup(): No such inode! (%lu)\n", - dir->i_ino)); - goto jffs_lookup_end; - } - - /* Get the corresponding inode to the file. */ - - /* iget calls jffs_read_inode, so we need to drop the biglock - before calling iget. Unfortunately, the GC has a tendency - to sneak in here, because iget sometimes calls schedule (). - */ - - if ((len == 1) && (name[0] == '.')) { - D3(printk (KERN_NOTICE "lookup(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - if (!(inode = iget(dir->i_sb, d->ino))) { - D(printk("jffs_lookup(): . iget() ==> NULL\n")); - goto jffs_lookup_end_no_biglock; - } - D3(printk (KERN_NOTICE "lookup(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - } else if ((len == 2) && (name[0] == '.') && (name[1] == '.')) { - D3(printk (KERN_NOTICE "lookup(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - if (!(inode = iget(dir->i_sb, d->pino))) { - D(printk("jffs_lookup(): .. iget() ==> NULL\n")); - goto jffs_lookup_end_no_biglock; - } - D3(printk (KERN_NOTICE "lookup(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - } else if ((f = jffs_find_child(d, name, len))) { - D3(printk (KERN_NOTICE "lookup(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - if (!(inode = iget(dir->i_sb, f->ino))) { - D(printk("jffs_lookup(): iget() ==> NULL\n")); - goto jffs_lookup_end_no_biglock; - } - D3(printk (KERN_NOTICE "lookup(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - } else { - D3(printk("jffs_lookup(): Couldn't find the file. " - "f = 0x%p, name = \"%s\", d = 0x%p, d->ino = %u\n", - f, name, d, d->ino)); - inode = NULL; - } - - d_add(dentry, inode); - D3(printk (KERN_NOTICE "lookup(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - unlock_kernel(); - return NULL; - -jffs_lookup_end: - D3(printk (KERN_NOTICE "lookup(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - -jffs_lookup_end_no_biglock: - unlock_kernel(); - return ERR_PTR(r); -} /* jffs_lookup() */ - - -/* Try to read a page of data from a file. */ -static int -jffs_do_readpage_nolock(struct file *file, struct page *page) -{ - void *buf; - unsigned long read_len; - int result; - struct inode *inode = (struct inode*)page->mapping->host; - struct jffs_file *f = (struct jffs_file *)inode->i_private; - struct jffs_control *c = (struct jffs_control *)inode->i_sb->s_fs_info; - int r; - loff_t offset; - - D2(printk("***jffs_readpage(): file = \"%s\", page->index = %lu\n", - (f->name ? f->name : ""), (long)page->index)); - - get_page(page); - /* Don't SetPageLocked(page), should be locked already */ - ClearPageUptodate(page); - ClearPageError(page); - - D3(printk (KERN_NOTICE "readpage(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - - read_len = 0; - result = 0; - offset = page_offset(page); - - kmap(page); - buf = page_address(page); - if (offset < inode->i_size) { - read_len = min_t(long, inode->i_size - offset, PAGE_SIZE); - r = jffs_read_data(f, buf, offset, read_len); - if (r != read_len) { - result = -EIO; - D( - printk("***jffs_readpage(): Read error! " - "Wanted to read %lu bytes but only " - "read %d bytes.\n", read_len, r); - ); - } - - } - - /* This handles the case of partial or no read in above */ - if(read_len < PAGE_SIZE) - memset(buf + read_len, 0, PAGE_SIZE - read_len); - flush_dcache_page(page); - kunmap(page); - - D3(printk (KERN_NOTICE "readpage(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - - if (result) { - SetPageError(page); - }else { - SetPageUptodate(page); - } - - page_cache_release(page); - - D3(printk("jffs_readpage(): Leaving...\n")); - - return result; -} /* jffs_do_readpage_nolock() */ - -static int jffs_readpage(struct file *file, struct page *page) -{ - int ret = jffs_do_readpage_nolock(file, page); - unlock_page(page); - return ret; -} - -/* Create a new directory. */ -static int -jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) -{ - struct jffs_raw_inode raw_inode; - struct jffs_control *c; - struct jffs_node *node; - struct jffs_file *dir_f; - struct inode *inode; - int dir_mode; - int result = 0; - int err; - - D1({ - int len = dentry->d_name.len; - char *_name = kmalloc(len + 1, GFP_KERNEL); - memcpy(_name, dentry->d_name.name, len); - _name[len] = '\0'; - printk("***jffs_mkdir(): dir = 0x%p, name = \"%s\", " - "len = %d, mode = 0x%08x\n", dir, _name, len, mode); - kfree(_name); - }); - - lock_kernel(); - dir_f = dir->i_private; - - ASSERT(if (!dir_f) { - printk(KERN_ERR "jffs_mkdir(): No reference to a " - "jffs_file struct in inode.\n"); - unlock_kernel(); - return -EIO; - }); - - c = dir_f->c; - D3(printk (KERN_NOTICE "mkdir(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - - dir_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) - & ~current->fs->umask); - if (dir->i_mode & S_ISGID) { - dir_mode |= S_ISGID; - } - - /* Create a node and initialize it as much as needed. */ - if (!(node = jffs_alloc_node())) { - D(printk("jffs_mkdir(): Allocation failed: node == 0\n")); - result = -ENOMEM; - goto jffs_mkdir_end; - } - node->data_offset = 0; - node->removed_size = 0; - - /* Initialize the raw inode. */ - raw_inode.magic = JFFS_MAGIC_BITMASK; - raw_inode.ino = c->next_ino++; - raw_inode.pino = dir_f->ino; - raw_inode.version = 1; - raw_inode.mode = dir_mode; - raw_inode.uid = current->fsuid; - raw_inode.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; - /* raw_inode.gid = current->fsgid; */ - raw_inode.atime = get_seconds(); - raw_inode.mtime = raw_inode.atime; - raw_inode.ctime = raw_inode.atime; - raw_inode.offset = 0; - raw_inode.dsize = 0; - raw_inode.rsize = 0; - raw_inode.nsize = dentry->d_name.len; - raw_inode.nlink = 1; - raw_inode.spare = 0; - raw_inode.rename = 0; - raw_inode.deleted = 0; - - /* Write the new node to the flash. */ - if ((result = jffs_write_node(c, node, &raw_inode, - dentry->d_name.name, NULL, 0, NULL)) < 0) { - D(printk("jffs_mkdir(): jffs_write_node() failed.\n")); - jffs_free_node(node); - goto jffs_mkdir_end; - } - - /* Insert the new node into the file system. */ - if ((result = jffs_insert_node(c, NULL, &raw_inode, dentry->d_name.name, - node)) < 0) { - goto jffs_mkdir_end; - } - - inode = jffs_new_inode(dir, &raw_inode, &err); - if (inode == NULL) { - result = err; - goto jffs_mkdir_end; - } - - inode->i_op = &jffs_dir_inode_operations; - inode->i_fop = &jffs_dir_operations; - - mark_inode_dirty(dir); - d_instantiate(dentry, inode); - - result = 0; -jffs_mkdir_end: - D3(printk (KERN_NOTICE "mkdir(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - unlock_kernel(); - return result; -} /* jffs_mkdir() */ - - -/* Remove a directory. */ -static int -jffs_rmdir(struct inode *dir, struct dentry *dentry) -{ - struct jffs_control *c = (struct jffs_control *)dir->i_sb->s_fs_info; - int ret; - D3(printk("***jffs_rmdir()\n")); - D3(printk (KERN_NOTICE "rmdir(): down biglock\n")); - lock_kernel(); - mutex_lock(&c->fmc->biglock); - ret = jffs_remove(dir, dentry, S_IFDIR); - D3(printk (KERN_NOTICE "rmdir(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - unlock_kernel(); - return ret; -} - - -/* Remove any kind of file except for directories. */ -static int -jffs_unlink(struct inode *dir, struct dentry *dentry) -{ - struct jffs_control *c = (struct jffs_control *)dir->i_sb->s_fs_info; - int ret; - - lock_kernel(); - D3(printk("***jffs_unlink()\n")); - D3(printk (KERN_NOTICE "unlink(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - ret = jffs_remove(dir, dentry, 0); - D3(printk (KERN_NOTICE "unlink(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - unlock_kernel(); - return ret; -} - - -/* Remove a JFFS entry, i.e. plain files, directories, etc. Here we - shouldn't test for free space on the device. */ -static int -jffs_remove(struct inode *dir, struct dentry *dentry, int type) -{ - struct jffs_raw_inode raw_inode; - struct jffs_control *c; - struct jffs_file *dir_f; /* The file-to-remove's parent. */ - struct jffs_file *del_f; /* The file to remove. */ - struct jffs_node *del_node; - struct inode *inode = NULL; - int result = 0; - - D1({ - int len = dentry->d_name.len; - const char *name = dentry->d_name.name; - char *_name = kmalloc(len + 1, GFP_KERNEL); - memcpy(_name, name, len); - _name[len] = '\0'; - printk("***jffs_remove(): file = \"%s\", ino = %ld\n", _name, dentry->d_inode->i_ino); - kfree(_name); - }); - - dir_f = dir->i_private; - c = dir_f->c; - - result = -ENOENT; - if (!(del_f = jffs_find_child(dir_f, dentry->d_name.name, - dentry->d_name.len))) { - D(printk("jffs_remove(): jffs_find_child() failed.\n")); - goto jffs_remove_end; - } - - if (S_ISDIR(type)) { - struct jffs_file *child = del_f->children; - while(child) { - if( !child->deleted ) { - result = -ENOTEMPTY; - goto jffs_remove_end; - } - child = child->sibling_next; - } - } - else if (S_ISDIR(del_f->mode)) { - D(printk("jffs_remove(): node is a directory " - "but it shouldn't be.\n")); - result = -EPERM; - goto jffs_remove_end; - } - - inode = dentry->d_inode; - - result = -EIO; - if (del_f->ino != inode->i_ino) - goto jffs_remove_end; - - if (!inode->i_nlink) { - printk("Deleting nonexistent file inode: %lu, nlink: %d\n", - inode->i_ino, inode->i_nlink); - inode->i_nlink=1; - } - - /* Create a node for the deletion. */ - result = -ENOMEM; - if (!(del_node = jffs_alloc_node())) { - D(printk("jffs_remove(): Allocation failed!\n")); - goto jffs_remove_end; - } - del_node->data_offset = 0; - del_node->removed_size = 0; - - /* Initialize the raw inode. */ - raw_inode.magic = JFFS_MAGIC_BITMASK; - raw_inode.ino = del_f->ino; - raw_inode.pino = del_f->pino; -/* raw_inode.version = del_f->highest_version + 1; */ - raw_inode.mode = del_f->mode; - raw_inode.uid = current->fsuid; - raw_inode.gid = current->fsgid; - raw_inode.atime = get_seconds(); - raw_inode.mtime = del_f->mtime; - raw_inode.ctime = raw_inode.atime; - raw_inode.offset = 0; - raw_inode.dsize = 0; - raw_inode.rsize = 0; - raw_inode.nsize = 0; - raw_inode.nlink = del_f->nlink; - raw_inode.spare = 0; - raw_inode.rename = 0; - raw_inode.deleted = 1; - - /* Write the new node to the flash memory. */ - if (jffs_write_node(c, del_node, &raw_inode, NULL, NULL, 1, del_f) < 0) { - jffs_free_node(del_node); - result = -EIO; - goto jffs_remove_end; - } - - /* Update the file. This operation will make the file disappear - from the in-memory file system structures. */ - jffs_insert_node(c, del_f, &raw_inode, NULL, del_node); - - dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; - mark_inode_dirty(dir); - inode->i_ctime = dir->i_ctime; - inode_dec_link_count(inode); - - d_delete(dentry); /* This also frees the inode */ - - result = 0; -jffs_remove_end: - return result; -} /* jffs_remove() */ - - -static int -jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) -{ - struct jffs_raw_inode raw_inode; - struct jffs_file *dir_f; - struct jffs_node *node = NULL; - struct jffs_control *c; - struct inode *inode; - int result = 0; - u16 data = old_encode_dev(rdev); - int err; - - D1(printk("***jffs_mknod()\n")); - - if (!old_valid_dev(rdev)) - return -EINVAL; - lock_kernel(); - dir_f = dir->i_private; - c = dir_f->c; - - D3(printk (KERN_NOTICE "mknod(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - - /* Create and initialize a new node. */ - if (!(node = jffs_alloc_node())) { - D(printk("jffs_mknod(): Allocation failed!\n")); - result = -ENOMEM; - goto jffs_mknod_err; - } - node->data_offset = 0; - node->removed_size = 0; - - /* Initialize the raw inode. */ - raw_inode.magic = JFFS_MAGIC_BITMASK; - raw_inode.ino = c->next_ino++; - raw_inode.pino = dir_f->ino; - raw_inode.version = 1; - raw_inode.mode = mode; - raw_inode.uid = current->fsuid; - raw_inode.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; - /* raw_inode.gid = current->fsgid; */ - raw_inode.atime = get_seconds(); - raw_inode.mtime = raw_inode.atime; - raw_inode.ctime = raw_inode.atime; - raw_inode.offset = 0; - raw_inode.dsize = 2; - raw_inode.rsize = 0; - raw_inode.nsize = dentry->d_name.len; - raw_inode.nlink = 1; - raw_inode.spare = 0; - raw_inode.rename = 0; - raw_inode.deleted = 0; - - /* Write the new node to the flash. */ - if ((err = jffs_write_node(c, node, &raw_inode, dentry->d_name.name, - (unsigned char *)&data, 0, NULL)) < 0) { - D(printk("jffs_mknod(): jffs_write_node() failed.\n")); - result = err; - goto jffs_mknod_err; - } - - /* Insert the new node into the file system. */ - if ((err = jffs_insert_node(c, NULL, &raw_inode, dentry->d_name.name, - node)) < 0) { - result = err; - goto jffs_mknod_end; - } - - inode = jffs_new_inode(dir, &raw_inode, &err); - if (inode == NULL) { - result = err; - goto jffs_mknod_end; - } - - init_special_inode(inode, mode, rdev); - - d_instantiate(dentry, inode); - - goto jffs_mknod_end; - -jffs_mknod_err: - if (node) { - jffs_free_node(node); - } - -jffs_mknod_end: - D3(printk (KERN_NOTICE "mknod(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - unlock_kernel(); - return result; -} /* jffs_mknod() */ - - -static int -jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) -{ - struct jffs_raw_inode raw_inode; - struct jffs_control *c; - struct jffs_file *dir_f; - struct jffs_node *node; - struct inode *inode; - - int symname_len = strlen(symname); - int err; - - lock_kernel(); - D1({ - int len = dentry->d_name.len; - char *_name = kmalloc(len + 1, GFP_KERNEL); - char *_symname = kmalloc(symname_len + 1, GFP_KERNEL); - memcpy(_name, dentry->d_name.name, len); - _name[len] = '\0'; - memcpy(_symname, symname, symname_len); - _symname[symname_len] = '\0'; - printk("***jffs_symlink(): dir = 0x%p, " - "dentry->dname.name = \"%s\", " - "symname = \"%s\"\n", dir, _name, _symname); - kfree(_name); - kfree(_symname); - }); - - dir_f = dir->i_private; - ASSERT(if (!dir_f) { - printk(KERN_ERR "jffs_symlink(): No reference to a " - "jffs_file struct in inode.\n"); - unlock_kernel(); - return -EIO; - }); - - c = dir_f->c; - - /* Create a node and initialize it as much as needed. */ - if (!(node = jffs_alloc_node())) { - D(printk("jffs_symlink(): Allocation failed: node = NULL\n")); - unlock_kernel(); - return -ENOMEM; - } - D3(printk (KERN_NOTICE "symlink(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - - node->data_offset = 0; - node->removed_size = 0; - - /* Initialize the raw inode. */ - raw_inode.magic = JFFS_MAGIC_BITMASK; - raw_inode.ino = c->next_ino++; - raw_inode.pino = dir_f->ino; - raw_inode.version = 1; - raw_inode.mode = S_IFLNK | S_IRWXUGO; - raw_inode.uid = current->fsuid; - raw_inode.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; - raw_inode.atime = get_seconds(); - raw_inode.mtime = raw_inode.atime; - raw_inode.ctime = raw_inode.atime; - raw_inode.offset = 0; - raw_inode.dsize = symname_len; - raw_inode.rsize = 0; - raw_inode.nsize = dentry->d_name.len; - raw_inode.nlink = 1; - raw_inode.spare = 0; - raw_inode.rename = 0; - raw_inode.deleted = 0; - - /* Write the new node to the flash. */ - if ((err = jffs_write_node(c, node, &raw_inode, dentry->d_name.name, - (const unsigned char *)symname, 0, NULL)) < 0) { - D(printk("jffs_symlink(): jffs_write_node() failed.\n")); - jffs_free_node(node); - goto jffs_symlink_end; - } - - /* Insert the new node into the file system. */ - if ((err = jffs_insert_node(c, NULL, &raw_inode, dentry->d_name.name, - node)) < 0) { - goto jffs_symlink_end; - } - - inode = jffs_new_inode(dir, &raw_inode, &err); - if (inode == NULL) { - goto jffs_symlink_end; - } - err = 0; - inode->i_op = &page_symlink_inode_operations; - inode->i_mapping->a_ops = &jffs_address_operations; - - d_instantiate(dentry, inode); - jffs_symlink_end: - D3(printk (KERN_NOTICE "symlink(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - unlock_kernel(); - return err; -} /* jffs_symlink() */ - - -/* Create an inode inside a JFFS directory (dir) and return it. - * - * By the time this is called, we already have created - * the directory cache entry for the new file, but it - * is so far negative - it has no inode. - * - * If the create succeeds, we fill in the inode information - * with d_instantiate(). - */ -static int -jffs_create(struct inode *dir, struct dentry *dentry, int mode, - struct nameidata *nd) -{ - struct jffs_raw_inode raw_inode; - struct jffs_control *c; - struct jffs_node *node; - struct jffs_file *dir_f; /* JFFS representation of the directory. */ - struct inode *inode; - int err; - - lock_kernel(); - D1({ - int len = dentry->d_name.len; - char *s = kmalloc(len + 1, GFP_KERNEL); - memcpy(s, dentry->d_name.name, len); - s[len] = '\0'; - printk("jffs_create(): dir: 0x%p, name: \"%s\"\n", dir, s); - kfree(s); - }); - - dir_f = dir->i_private; - ASSERT(if (!dir_f) { - printk(KERN_ERR "jffs_create(): No reference to a " - "jffs_file struct in inode.\n"); - unlock_kernel(); - return -EIO; - }); - - c = dir_f->c; - - /* Create a node and initialize as much as needed. */ - if (!(node = jffs_alloc_node())) { - D(printk("jffs_create(): Allocation failed: node == 0\n")); - unlock_kernel(); - return -ENOMEM; - } - D3(printk (KERN_NOTICE "create(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - - node->data_offset = 0; - node->removed_size = 0; - - /* Initialize the raw inode. */ - raw_inode.magic = JFFS_MAGIC_BITMASK; - raw_inode.ino = c->next_ino++; - raw_inode.pino = dir_f->ino; - raw_inode.version = 1; - raw_inode.mode = mode; - raw_inode.uid = current->fsuid; - raw_inode.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; - raw_inode.atime = get_seconds(); - raw_inode.mtime = raw_inode.atime; - raw_inode.ctime = raw_inode.atime; - raw_inode.offset = 0; - raw_inode.dsize = 0; - raw_inode.rsize = 0; - raw_inode.nsize = dentry->d_name.len; - raw_inode.nlink = 1; - raw_inode.spare = 0; - raw_inode.rename = 0; - raw_inode.deleted = 0; - - /* Write the new node to the flash. */ - if ((err = jffs_write_node(c, node, &raw_inode, - dentry->d_name.name, NULL, 0, NULL)) < 0) { - D(printk("jffs_create(): jffs_write_node() failed.\n")); - jffs_free_node(node); - goto jffs_create_end; - } - - /* Insert the new node into the file system. */ - if ((err = jffs_insert_node(c, NULL, &raw_inode, dentry->d_name.name, - node)) < 0) { - goto jffs_create_end; - } - - /* Initialize an inode. */ - inode = jffs_new_inode(dir, &raw_inode, &err); - if (inode == NULL) { - goto jffs_create_end; - } - err = 0; - inode->i_op = &jffs_file_inode_operations; - inode->i_fop = &jffs_file_operations; - inode->i_mapping->a_ops = &jffs_address_operations; - inode->i_mapping->nrpages = 0; - - d_instantiate(dentry, inode); - jffs_create_end: - D3(printk (KERN_NOTICE "create(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - unlock_kernel(); - return err; -} /* jffs_create() */ - - -/* Write, append or rewrite data to an existing file. */ -static ssize_t -jffs_file_write(struct file *filp, const char *buf, size_t count, - loff_t *ppos) -{ - struct jffs_raw_inode raw_inode; - struct jffs_control *c; - struct jffs_file *f; - struct jffs_node *node; - struct dentry *dentry = filp->f_path.dentry; - struct inode *inode = dentry->d_inode; - int recoverable = 0; - size_t written = 0; - __u32 thiscount = count; - loff_t pos = *ppos; - int err; - - inode = filp->f_path.dentry->d_inode; - - D2(printk("***jffs_file_write(): inode: 0x%p (ino: %lu), " - "filp: 0x%p, buf: 0x%p, count: %d\n", - inode, inode->i_ino, filp, buf, count)); - -#if 0 - if (inode->i_sb->s_flags & MS_RDONLY) { - D(printk("jffs_file_write(): MS_RDONLY\n")); - err = -EROFS; - goto out_isem; - } -#endif - err = -EINVAL; - - if (!S_ISREG(inode->i_mode)) { - D(printk("jffs_file_write(): inode->i_mode == 0x%08x\n", - inode->i_mode)); - goto out_isem; - } - - if (!(f = inode->i_private)) { - D(printk("jffs_file_write(): inode->i_private = 0x%p\n", - inode->i_private)); - goto out_isem; - } - - c = f->c; - - /* - * This will never trigger with sane page sizes. leave it in - * anyway, since I'm thinking about how to merge larger writes - * (the current idea is to poke a thread that does the actual - * I/O and starts by doing a mutex_lock(&inode->i_mutex). then we - * would need to get the page cache pages and have a list of - * I/O requests and do write-merging here. - * -- prumpf - */ - thiscount = min(c->fmc->max_chunk_size - sizeof(struct jffs_raw_inode), count); - - D3(printk (KERN_NOTICE "file_write(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - - /* Urgh. POSIX says we can do short writes if we feel like it. - * In practice, we can't. Nothing will cope. So we loop until - * we're done. - * - * <_Anarchy_> posix and reality are not interconnected on this issue - */ - while (count) { - /* Things are going to be written so we could allocate and - initialize the necessary data structures now. */ - if (!(node = jffs_alloc_node())) { - D(printk("jffs_file_write(): node == 0\n")); - err = -ENOMEM; - goto out; - } - - node->data_offset = pos; - node->removed_size = 0; - - /* Initialize the raw inode. */ - raw_inode.magic = JFFS_MAGIC_BITMASK; - raw_inode.ino = f->ino; - raw_inode.pino = f->pino; - - raw_inode.mode = f->mode; - - raw_inode.uid = f->uid; - raw_inode.gid = f->gid; - raw_inode.atime = get_seconds(); - raw_inode.mtime = raw_inode.atime; - raw_inode.ctime = f->ctime; - raw_inode.offset = pos; - raw_inode.dsize = thiscount; - raw_inode.rsize = 0; - raw_inode.nsize = f->nsize; - raw_inode.nlink = f->nlink; - raw_inode.spare = 0; - raw_inode.rename = 0; - raw_inode.deleted = 0; - - if (pos < f->size) { - node->removed_size = raw_inode.rsize = min(thiscount, (__u32)(f->size - pos)); - - /* If this node is going entirely over the top of old data, - we can allow it to go into the reserved space, because - we know that GC can reclaim the space later. - */ - if (pos + thiscount < f->size) { - /* If all the data we're overwriting are _real_, - not just holes, then: - recoverable = 1; - */ - } - } - - /* Write the new node to the flash. */ - /* NOTE: We would be quite happy if jffs_write_node() wrote a - smaller node than we were expecting. There's no need for it - to waste the space at the end of the flash just because it's - a little smaller than what we asked for. But that's a whole - new can of worms which I'm not going to open this week. - -- dwmw2. - */ - if ((err = jffs_write_node(c, node, &raw_inode, f->name, - (const unsigned char *)buf, - recoverable, f)) < 0) { - D(printk("jffs_file_write(): jffs_write_node() failed.\n")); - jffs_free_node(node); - goto out; - } - - written += err; - buf += err; - count -= err; - pos += err; - - /* Insert the new node into the file system. */ - if ((err = jffs_insert_node(c, f, &raw_inode, NULL, node)) < 0) { - goto out; - } - - D3(printk("jffs_file_write(): new f_pos %ld.\n", (long)pos)); - - thiscount = min(c->fmc->max_chunk_size - sizeof(struct jffs_raw_inode), count); - } - out: - D3(printk (KERN_NOTICE "file_write(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - - /* Fix things in the real inode. */ - if (pos > inode->i_size) { - inode->i_size = pos; - inode->i_blocks = (inode->i_size + 511) >> 9; - } - inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); - invalidate_mapping_pages(inode->i_mapping, 0, -1); - - out_isem: - return err; -} /* jffs_file_write() */ - -static int -jffs_prepare_write(struct file *filp, struct page *page, - unsigned from, unsigned to) -{ - /* FIXME: we should detect some error conditions here */ - - /* Bugger that. We should make sure the page is uptodate */ - if (!PageUptodate(page) && (from || to < PAGE_CACHE_SIZE)) - return jffs_do_readpage_nolock(filp, page); - - return 0; -} /* jffs_prepare_write() */ - -static int -jffs_commit_write(struct file *filp, struct page *page, - unsigned from, unsigned to) -{ - void *addr = page_address(page) + from; - /* XXX: PAGE_CACHE_SHIFT or PAGE_SHIFT */ - loff_t pos = page_offset(page) + from; - - return jffs_file_write(filp, addr, to-from, &pos); -} /* jffs_commit_write() */ - -/* This is our ioctl() routine. */ -static int -jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct jffs_control *c; - int ret = 0; - - D2(printk("***jffs_ioctl(): cmd = 0x%08x, arg = 0x%08lx\n", - cmd, arg)); - - if (!(c = (struct jffs_control *)inode->i_sb->s_fs_info)) { - printk(KERN_ERR "JFFS: Bad inode in ioctl() call. " - "(cmd = 0x%08x)\n", cmd); - return -EIO; - } - D3(printk (KERN_NOTICE "ioctl(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - - switch (cmd) { - case JFFS_PRINT_HASH: - jffs_print_hash_table(c); - break; - case JFFS_PRINT_TREE: - jffs_print_tree(c->root, 0); - break; - case JFFS_GET_STATUS: - { - struct jffs_flash_status fst; - struct jffs_fmcontrol *fmc = c->fmc; - printk("Flash status -- "); - if (!access_ok(VERIFY_WRITE, - (struct jffs_flash_status __user *)arg, - sizeof(struct jffs_flash_status))) { - D(printk("jffs_ioctl(): Bad arg in " - "JFFS_GET_STATUS ioctl!\n")); - ret = -EFAULT; - break; - } - fst.size = fmc->flash_size; - fst.used = fmc->used_size; - fst.dirty = fmc->dirty_size; - fst.begin = fmc->head->offset; - fst.end = fmc->tail->offset + fmc->tail->size; - printk("size: %d, used: %d, dirty: %d, " - "begin: %d, end: %d\n", - fst.size, fst.used, fst.dirty, - fst.begin, fst.end); - if (copy_to_user((struct jffs_flash_status __user *)arg, - &fst, - sizeof(struct jffs_flash_status))) { - ret = -EFAULT; - } - } - break; - default: - ret = -ENOTTY; - } - D3(printk (KERN_NOTICE "ioctl(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - return ret; -} /* jffs_ioctl() */ - - -static const struct address_space_operations jffs_address_operations = { - .readpage = jffs_readpage, - .prepare_write = jffs_prepare_write, - .commit_write = jffs_commit_write, -}; - -static int jffs_fsync(struct file *f, struct dentry *d, int datasync) -{ - /* We currently have O_SYNC operations at all times. - Do nothing. - */ - return 0; -} - - -static const struct file_operations jffs_file_operations = -{ - .open = generic_file_open, - .llseek = generic_file_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = generic_file_aio_write, - .ioctl = jffs_ioctl, - .mmap = generic_file_readonly_mmap, - .fsync = jffs_fsync, - .sendfile = generic_file_sendfile, -}; - - -static const struct inode_operations jffs_file_inode_operations = -{ - .lookup = jffs_lookup, /* lookup */ - .setattr = jffs_setattr, -}; - - -static const struct file_operations jffs_dir_operations = -{ - .readdir = jffs_readdir, -}; - - -static const struct inode_operations jffs_dir_inode_operations = -{ - .create = jffs_create, - .lookup = jffs_lookup, - .unlink = jffs_unlink, - .symlink = jffs_symlink, - .mkdir = jffs_mkdir, - .rmdir = jffs_rmdir, - .mknod = jffs_mknod, - .rename = jffs_rename, - .setattr = jffs_setattr, -}; - - -/* Initialize an inode for the VFS. */ -static void -jffs_read_inode(struct inode *inode) -{ - struct jffs_file *f; - struct jffs_control *c; - - D3(printk("jffs_read_inode(): inode->i_ino == %lu\n", inode->i_ino)); - - if (!inode->i_sb) { - D(printk("jffs_read_inode(): !inode->i_sb ==> " - "No super block!\n")); - return; - } - c = (struct jffs_control *)inode->i_sb->s_fs_info; - D3(printk (KERN_NOTICE "read_inode(): down biglock\n")); - mutex_lock(&c->fmc->biglock); - if (!(f = jffs_find_file(c, inode->i_ino))) { - D(printk("jffs_read_inode(): No such inode (%lu).\n", - inode->i_ino)); - D3(printk (KERN_NOTICE "read_inode(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); - return; - } - inode->i_private = f; - inode->i_mode = f->mode; - inode->i_nlink = f->nlink; - inode->i_uid = f->uid; - inode->i_gid = f->gid; - inode->i_size = f->size; - inode->i_atime.tv_sec = f->atime; - inode->i_mtime.tv_sec = f->mtime; - inode->i_ctime.tv_sec = f->ctime; - inode->i_atime.tv_nsec = - inode->i_mtime.tv_nsec = - inode->i_ctime.tv_nsec = 0; - - inode->i_blocks = (inode->i_size + 511) >> 9; - if (S_ISREG(inode->i_mode)) { - inode->i_op = &jffs_file_inode_operations; - inode->i_fop = &jffs_file_operations; - inode->i_mapping->a_ops = &jffs_address_operations; - } - else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &jffs_dir_inode_operations; - inode->i_fop = &jffs_dir_operations; - } - else if (S_ISLNK(inode->i_mode)) { - inode->i_op = &page_symlink_inode_operations; - inode->i_mapping->a_ops = &jffs_address_operations; - } - else { - /* If the node is a device of some sort, then the number of - the device should be read from the flash memory and then - added to the inode's i_rdev member. */ - u16 val; - jffs_read_data(f, (char *)&val, 0, 2); - init_special_inode(inode, inode->i_mode, - old_decode_dev(val)); - } - - D3(printk (KERN_NOTICE "read_inode(): up biglock\n")); - mutex_unlock(&c->fmc->biglock); -} - - -static void -jffs_delete_inode(struct inode *inode) -{ - struct jffs_file *f; - struct jffs_control *c; - D3(printk("jffs_delete_inode(): inode->i_ino == %lu\n", - inode->i_ino)); - - truncate_inode_pages(&inode->i_data, 0); - lock_kernel(); - inode->i_size = 0; - inode->i_blocks = 0; - inode->i_private = NULL; - clear_inode(inode); - if (inode->i_nlink == 0) { - c = (struct jffs_control *) inode->i_sb->s_fs_info; - f = (struct jffs_file *) jffs_find_file (c, inode->i_ino); - jffs_possibly_delete_file(f); - } - - unlock_kernel(); -} - - -static void -jffs_write_super(struct super_block *sb) -{ - struct jffs_control *c = (struct jffs_control *)sb->s_fs_info; - lock_kernel(); - jffs_garbage_collect_trigger(c); - unlock_kernel(); -} - -static int jffs_remount(struct super_block *sb, int *flags, char *data) -{ - *flags |= MS_NODIRATIME; - return 0; -} - -static const struct super_operations jffs_ops = -{ - .read_inode = jffs_read_inode, - .delete_inode = jffs_delete_inode, - .put_super = jffs_put_super, - .write_super = jffs_write_super, - .statfs = jffs_statfs, - .remount_fs = jffs_remount, -}; - -static int jffs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) -{ - return get_sb_bdev(fs_type, flags, dev_name, data, jffs_fill_super, - mnt); -} - -static struct file_system_type jffs_fs_type = { - .owner = THIS_MODULE, - .name = "jffs", - .get_sb = jffs_get_sb, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; - -static int __init -init_jffs_fs(void) -{ - printk(KERN_INFO "JFFS version " JFFS_VERSION_STRING - ", (C) 1999, 2000 Axis Communications AB\n"); - -#ifdef CONFIG_JFFS_PROC_FS - jffs_proc_root = proc_mkdir("jffs", proc_root_fs); - if (!jffs_proc_root) { - printk(KERN_WARNING "cannot create /proc/jffs entry\n"); - } -#endif - fm_cache = kmem_cache_create("jffs_fm", sizeof(struct jffs_fm), - 0, - SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, - NULL, NULL); - if (!fm_cache) { - return -ENOMEM; - } - - node_cache = kmem_cache_create("jffs_node",sizeof(struct jffs_node), - 0, - SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, - NULL, NULL); - if (!node_cache) { - kmem_cache_destroy(fm_cache); - return -ENOMEM; - } - - return register_filesystem(&jffs_fs_type); -} - -static void __exit -exit_jffs_fs(void) -{ - unregister_filesystem(&jffs_fs_type); - kmem_cache_destroy(fm_cache); - kmem_cache_destroy(node_cache); -} - -module_init(init_jffs_fs) -module_exit(exit_jffs_fs) - -MODULE_DESCRIPTION("The Journalling Flash File System"); -MODULE_AUTHOR("Axis Communications AB."); -MODULE_LICENSE("GPL"); diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c deleted file mode 100644 index 6dd18911b44..00000000000 --- a/fs/jffs/intrep.c +++ /dev/null @@ -1,3449 +0,0 @@ -/* - * JFFS -- Journaling Flash File System, Linux implementation. - * - * Copyright (C) 1999, 2000 Axis Communications, Inc. - * - * Created by Finn Hakansson <finn@axis.com>. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * $Id: intrep.c,v 1.102 2001/09/23 23:28:36 dwmw2 Exp $ - * - * Ported to Linux 2.3.x and MTD: - * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB - * - */ - -/* This file contains the code for the internal structure of the - Journaling Flash File System, JFFS. */ - -/* - * Todo list: - * - * memcpy_to_flash() and memcpy_from_flash() functions. - * - * Implementation of hard links. - * - * Organize the source code in a better way. Against the VFS we could - * have jffs_ext.c, and against the block device jffs_int.c. - * A better file-internal organization too. - * - * A better checksum algorithm. - * - * Consider endianness stuff. ntohl() etc. - * - * Are we handling the atime, mtime, ctime members of the inode right? - * - * Remove some duplicated code. Take a look at jffs_write_node() and - * jffs_rewrite_data() for instance. - * - * Implement more meaning of the nlink member in various data structures. - * nlink could be used in conjunction with hard links for instance. - * - * Better memory management. Allocate data structures in larger chunks - * if possible. - * - * If too much meta data is stored, a garbage collect should be issued. - * We have experienced problems with too much meta data with for instance - * log files. - * - * Improve the calls to jffs_ioctl(). We would like to retrieve more - * information to be able to debug (or to supervise) JFFS during run-time. - * - */ - -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/jffs.h> -#include <linux/fs.h> -#include <linux/stat.h> -#include <linux/pagemap.h> -#include <linux/mutex.h> -#include <asm/byteorder.h> -#include <linux/smp_lock.h> -#include <linux/time.h> -#include <linux/ctype.h> -#include <linux/freezer.h> - -#include "intrep.h" -#include "jffs_fm.h" - -long no_jffs_node = 0; -static long no_jffs_file = 0; -#if defined(JFFS_MEMORY_DEBUG) && JFFS_MEMORY_DEBUG -long no_jffs_control = 0; -long no_jffs_raw_inode = 0; -long no_jffs_node_ref = 0; -long no_jffs_fm = 0; -long no_jffs_fmcontrol = 0; -long no_hash = 0; -long no_name = 0; -#endif - -static int jffs_scan_flash(struct jffs_control *c); -static int jffs_update_file(struct jffs_file *f, struct jffs_node *node); -static int jffs_build_file(struct jffs_file *f); -static int jffs_free_file(struct jffs_file *f); -static int jffs_free_node_list(struct jffs_file *f); -static int jffs_garbage_collect_now(struct jffs_control *c); -static int jffs_insert_file_into_hash(struct jffs_file *f); -static int jffs_remove_redundant_nodes(struct jffs_file *f); - -/* Is there enough space on the flash? */ -static inline int JFFS_ENOUGH_SPACE(struct jffs_control *c, __u32 space) -{ - struct jffs_fmcontrol *fmc = c->fmc; - - while (1) { - if ((fmc->flash_size - (fmc->used_size + fmc->dirty_size)) - >= fmc->min_free_size + space) { - return 1; - } - if (fmc->dirty_size < fmc->sector_size) - return 0; - - if (jffs_garbage_collect_now(c)) { - D1(printk("JFFS_ENOUGH_SPACE: jffs_garbage_collect_now() failed.\n")); - return 0; - } - } -} - -#if CONFIG_JFFS_FS_VERBOSE > 0 -static __u8 -flash_read_u8(struct mtd_info *mtd, loff_t from) -{ - size_t retlen; - __u8 ret; - int res; - - res = MTD_READ(mtd, from, 1, &retlen, &ret); - if (retlen != 1) { - printk("Didn't read a byte in flash_read_u8(). Returned %d\n", res); - return 0; - } - - return ret; -} - -static void -jffs_hexdump(struct mtd_info *mtd, loff_t pos, int size) -{ - char line[16]; - int j = 0; - - while (size > 0) { - int i; - - printk("%ld:", (long) pos); - for (j = 0; j < 16; j++) { - line[j] = flash_read_u8(mtd, pos++); - } - for (i = 0; i < j; i++) { - if (!(i & 1)) { - printk(" %.2x", line[i] & 0xff); - } - else { - printk("%.2x", line[i] & 0xff); - } - } - - /* Print empty space */ - for (; i < 16; i++) { - if (!(i & 1)) { - printk(" "); - } - else { - printk(" "); - } - } - printk(" "); - - for (i = 0; i < j; i++) { - if (isgraph(line[i])) { - printk("%c", line[i]); - } - else { - printk("."); - } - } - printk("\n"); - size -= 16; - } -} - -/* Print the contents of a node. */ -static void -jffs_print_node(struct jffs_node *n) -{ - D(printk("jffs_node: 0x%p\n", n)); - D(printk("{\n")); - D(printk(" 0x%08x, /* version */\n", n->version)); - D(printk(" 0x%08x, /* data_offset */\n", n->data_offset)); - D(printk(" 0x%08x, /* data_size */\n", n->data_size)); - D(printk(" 0x%08x, /* removed_size */\n", n->removed_size)); - D(printk(" 0x%08x, /* fm_offset */\n", n->fm_offset)); - D(printk(" 0x%02x, /* name_size */\n", n->name_size)); - D(printk(" 0x%p, /* fm, fm->offset: %u */\n", - n->fm, (n->fm ? n->fm->offset : 0))); - D(printk(" 0x%p, /* version_prev */\n", n->version_prev)); - D(printk(" 0x%p, /* version_next */\n", n->version_next)); - D(printk(" 0x%p, /* range_prev */\n", n->range_prev)); - D(printk(" 0x%p, /* range_next */\n", n->range_next)); - D(printk("}\n")); -} - -#endif - -/* Print the contents of a raw inode. */ -static void -jffs_print_raw_inode(struct jffs_raw_inode *raw_inode) -{ - D(printk("jffs_raw_inode: inode number: %u\n", raw_inode->ino)); - D(printk("{\n")); - D(printk(" 0x%08x, /* magic */\n", raw_inode->magic)); - D(printk(" 0x%08x, /* ino */\n", raw_inode->ino)); - D(printk(" 0x%08x, /* pino */\n", raw_inode->pino)); - D(printk(" 0x%08x, /* version */\n", raw_inode->version)); - D(printk(" 0x%08x, /* mode */\n", raw_inode->mode)); - D(printk(" 0x%04x, /* uid */\n", raw_inode->uid)); - D(printk(" 0x%04x, /* gid */\n", raw_inode->gid)); - D(printk(" 0x%08x, /* atime */\n", raw_inode->atime)); - D(printk(" 0x%08x, /* mtime */\n", raw_inode->mtime)); - D(printk(" 0x%08x, /* ctime */\n", raw_inode->ctime)); - D(printk(" 0x%08x, /* offset */\n", raw_inode->offset)); - D(printk(" 0x%08x, /* dsize */\n", raw_inode->dsize)); - D(printk(" 0x%08x, /* rsize */\n", raw_inode->rsize)); - D(printk(" 0x%02x, /* nsize */\n", raw_inode->nsize)); - D(printk(" 0x%02x, /* nlink */\n", raw_inode->nlink)); - D(printk(" 0x%02x, /* spare */\n", - raw_inode->spare)); - D(printk(" %u, /* rename */\n", - raw_inode->rename)); - D(printk(" %u, /* deleted */\n", - raw_inode->deleted)); - D(printk(" 0x%02x, /* accurate */\n", - raw_inode->accurate)); - D(printk(" 0x%08x, /* dchksum */\n", raw_inode->dchksum)); - D(printk(" 0x%04x, /* nchksum */\n", raw_inode->nchksum)); - D(printk(" 0x%04x, /* chksum */\n", raw_inode->chksum)); - D(printk("}\n")); -} - -#define flash_safe_acquire(arg) -#define flash_safe_release(arg) - - -static int -flash_safe_read(struct mtd_info *mtd, loff_t from, - u_char *buf, size_t count) -{ - size_t retlen; - int res; - - D3(printk(KERN_NOTICE "flash_safe_read(%p, %08x, %p, %08x)\n", - mtd, (unsigned int) from, buf, count)); - - res = mtd->read(mtd, from, count, &retlen, buf); - if (retlen != count) { - panic("Didn't read all bytes in flash_safe_read(). Returned %d\n", res); - } - return res?res:retlen; -} - - -static __u32 -flash_read_u32(struct mtd_info *mtd, loff_t from) -{ - size_t retlen; - __u32 ret; - int res; - - res = mtd->read(mtd, from, 4, &retlen, (unsigned char *)&ret); - if (retlen != 4) { - printk("Didn't read all bytes in flash_read_u32(). Returned %d\n", res); - return 0; - } - - return ret; -} - - -static int -flash_safe_write(struct mtd_info *mtd, loff_t to, - const u_char *buf, size_t count) -{ - size_t retlen; - int res; - - D3(printk(KERN_NOTICE "flash_safe_write(%p, %08x, %p, %08x)\n", - mtd, (unsigned int) to, buf, count)); - - res = mtd->write(mtd, to, count, &retlen, buf); - if (retlen != count) { - printk("Didn't write all bytes in flash_safe_write(). Returned %d\n", res); - } - return res?res:retlen; -} - - -static int -flash_safe_writev(struct mtd_info *mtd, const struct kvec *vecs, - unsigned long iovec_cnt, loff_t to) -{ - size_t retlen, retlen_a; - int i; - int res; - - D3(printk(KERN_NOTICE "flash_safe_writev(%p, %08x, %p)\n", - mtd, (unsigned int) to, vecs)); - - if (mtd->writev) { - res = mtd->writev(mtd, vecs, iovec_cnt, to, &retlen); - return res ? res : retlen; - } - /* Not implemented writev. Repeatedly use write - on the not so - unreasonable assumption that the mtd driver doesn't care how - many write cycles we use. */ - res=0; - retlen=0; - - for (i=0; !res && i<iovec_cnt; i++) { - res = mtd->write(mtd, to, vecs[i].iov_len, &retlen_a, - vecs[i].iov_base); - if (retlen_a != vecs[i].iov_len) { - printk("Didn't write all bytes in flash_safe_writev(). Returned %d\n", res); - if (i != iovec_cnt-1) - return -EIO; - } - /* If res is non-zero, retlen_a is undefined, but we don't - care because in that case it's not going to be - returned anyway. - */ - to += retlen_a; - retlen += retlen_a; - } - return res?res:retlen; -} - - -static int -flash_memset(struct mtd_info *mtd, loff_t to, - const u_char c, size_t size) -{ - static unsigned char pattern[64]; - int i; - - /* fill up pattern */ - - for(i = 0; i < 64; i++) - pattern[i] = c; - - /* write as many 64-byte chunks as we can */ - - while (size >= 64) { - flash_safe_write(mtd, to, pattern, 64); - size -= 64; - to += 64; - } - - /* and the rest */ - - if(size) - flash_safe_write(mtd, to, pattern, size); - - return size; -} - - -static void -intrep_erase_callback(struct erase_info *done) -{ - wait_queue_head_t *wait_q; - - wait_q = (wait_queue_head_t *)done->priv; - - wake_up(wait_q); -} - - -static int -flash_erase_region(struct mtd_info *mtd, loff_t start, - size_t size) -{ - struct erase_info *erase; - DECLARE_WAITQUEUE(wait, current); - wait_queue_head_t wait_q; - - erase = kmalloc(sizeof(struct erase_info), GFP_KERNEL); - if (!erase) - return -ENOMEM; - - init_waitqueue_head(&wait_q); - - erase->mtd = mtd; - erase->callback = intrep_erase_callback; - erase->addr = start; - erase->len = size; - erase->priv = (u_long)&wait_q; - - /* FIXME: Use TASK_INTERRUPTIBLE and deal with being interrupted */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&wait_q, &wait); - - if (mtd->erase(mtd, erase) < 0) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&wait_q, &wait); - kfree(erase); - - printk(KERN_WARNING "flash: erase of region [0x%lx, 0x%lx] " - "totally failed\n", (long)start, (long)start + size); - - return -1; - } - - schedule(); /* Wait for flash to finish. */ - remove_wait_queue(&wait_q, &wait); - - kfree(erase); - - return 0; -} - -/* This routine calculates checksums in JFFS. */ -static __u32 -jffs_checksum(const void *data, int size) -{ - __u32 sum = 0; - __u8 *ptr = (__u8 *)data; - while (size-- > 0) { - sum += *ptr++; - } - D3(printk(", result: 0x%08x\n", sum)); - return sum; -} - - -static int -jffs_checksum_flash(struct mtd_info *mtd, loff_t start, int size, __u32 *result) -{ - __u32 sum = 0; - loff_t ptr = start; - __u8 *read_buf; - int i, length; - - /* Allocate read buffer */ - read_buf = kmalloc(sizeof(__u8) * 4096, GFP_KERNEL); - if (!read_buf) { - printk(KERN_NOTICE "kmalloc failed in jffs_checksum_flash()\n"); - return -ENOMEM; - } - /* Loop until checksum done */ - while (size) { - /* Get amount of data to read */ - if (size < 4096) - length = size; - else - length = 4096; - - /* Perform flash read */ - D3(printk(KERN_NOTICE "jffs_checksum_flash\n")); - flash_safe_read(mtd, ptr, &read_buf[0], length); - - /* Compute checksum */ - for (i=0; i < length ; i++) - sum += read_buf[i]; - - /* Update pointer and size */ - size -= length; - ptr += length; - } - - /* Free read buffer */ - kfree(read_buf); - - /* Return result */ - D3(printk("checksum result: 0x%08x\n", sum)); - *result = sum; - return 0; -} - -static __inline__ void jffs_fm_write_lock(struct jffs_fmcontrol *fmc) -{ - // down(&fmc->wlock); -} - -static __inline__ void jffs_fm_write_unlock(struct jffs_fmcontrol *fmc) -{ - // up(&fmc->wlock); -} - - -/* Create and initialize a new struct jffs_file. */ -static struct jffs_file * -jffs_create_file(struct jffs_control *c, - const struct jffs_raw_inode *raw_inode) -{ - struct jffs_file *f; - - if (!(f = kzalloc(sizeof(*f), GFP_KERNEL))) { - D(printk("jffs_create_file(): Failed!\n")); - return NULL; - } - no_jffs_file++; - f->ino = raw_inode->ino; - f->pino = raw_inode->pino; - f->nlink = raw_inode->nlink; - f->deleted = raw_inode->deleted; - f->c = c; - - return f; -} - - -/* Build a control block for the file system. */ -static struct jffs_control * -jffs_create_control(struct super_block *sb) -{ - struct jffs_control *c; - register int s = sizeof(struct jffs_control); - int i; - D(char *t = 0); - - D2(printk("jffs_create_control()\n")); - - if (!(c = kmalloc(s, GFP_KERNEL))) { - goto fail_control; - } - DJM(no_jffs_control++); - c->root = NULL; - c->gc_task = NULL; - c->hash_len = JFFS_HASH_SIZE; - s = sizeof(struct list_head) * c->hash_len; - if (!(c->hash = kmalloc(s, GFP_KERNEL))) { - goto fail_hash; - } - DJM(no_hash++); - for (i = 0; i < c->hash_len; i++) - INIT_LIST_HEAD(&c->hash[i]); - if (!(c->fmc = jffs_build_begin(c, MINOR(sb->s_dev)))) { - goto fail_fminit; - } - c->next_ino = JFFS_MIN_INO + 1; - c->delete_list = (struct jffs_delete_list *) 0; - return c; - -fail_fminit: - D(t = "c->fmc"); -fail_hash: - kfree(c); - DJM(no_jffs_control--); - D(t = t ? t : "c->hash"); -fail_control: - D(t = t ? t : "control"); - D(printk("jffs_create_control(): Allocation failed: (%s)\n", t)); - return (struct jffs_control *)0; -} - - -/* Clean up all data structures associated with the file system. */ -void -jffs_cleanup_control(struct jffs_control *c) -{ - D2(printk("jffs_cleanup_control()\n")); - - if (!c) { - D(printk("jffs_cleanup_control(): c == NULL !!!\n")); - return; - } - - while (c->delete_list) { - struct jffs_delete_list *delete_list_element; - delete_list_element = c->delete_list; - c->delete_list = c->delete_list->next; - kfree(delete_list_element); - } - - /* Free all files and nodes. */ - if (c->hash) { - jffs_foreach_file(c, jffs_free_node_list); - jffs_foreach_file(c, jffs_free_file); - kfree(c->hash); - DJM(no_hash--); - } - jffs_cleanup_fmcontrol(c->fmc); - kfree(c); - DJM(no_jffs_control--); - D3(printk("jffs_cleanup_control(): Leaving...\n")); -} - - -/* This function adds a virtual root node to the in-RAM representation. - Called by jffs_build_fs(). */ -static int -jffs_add_virtual_root(struct jffs_control *c) -{ - struct jffs_file *root; - struct jffs_node *node; - - D2(printk("jffs_add_virtual_root(): " - "Creating a virtual root directory.\n")); - - if (!(root = kzalloc(sizeof(struct jffs_file), GFP_KERNEL))) { - return -ENOMEM; - } - no_jffs_file++; - if (!(node = jffs_alloc_node())) { - kfree(root); - no_jffs_file--; - return -ENOMEM; - } - DJM(no_jffs_node++); - memset(node, 0, sizeof(struct jffs_node)); - node->ino = JFFS_MIN_INO; - root->ino = JFFS_MIN_INO; - root->mode = S_IFDIR | S_IRWXU | S_IRGRP - | S_IXGRP | S_IROTH | S_IXOTH; - root->atime = root->mtime = root->ctime = get_seconds(); - root->nlink = 1; - root->c = c; - root->version_head = root->version_tail = node; - jffs_insert_file_into_hash(root); - return 0; -} - - -/* This is where the file system is built and initialized. */ -int -jffs_build_fs(struct super_block *sb) -{ - struct jffs_control *c; - int err = 0; - - D2(printk("jffs_build_fs()\n")); - - if (!(c = jffs_create_control(sb))) { - return -ENOMEM; - } - c->building_fs = 1; - c->sb = sb; - if ((err = jffs_scan_flash(c)) < 0) { - if(err == -EAGAIN){ - /* scan_flash() wants us to try once more. A flipping - bits sector was detect in the middle of the scan flash. - Clean up old allocated memory before going in. - */ - D1(printk("jffs_build_fs: Cleaning up all control structures," - " reallocating them and trying mount again.\n")); - jffs_cleanup_control(c); - if (!(c = jffs_create_control(sb))) { - return -ENOMEM; - } - c->building_fs = 1; - c->sb = sb; - - if ((err = jffs_scan_flash(c)) < 0) { - goto jffs_build_fs_fail; - } - }else{ - goto jffs_build_fs_fail; - } - } - - /* Add a virtual root node if no one exists. */ - if (!jffs_find_file(c, JFFS_MIN_INO)) { - if ((err = jffs_add_virtual_root(c)) < 0) { - goto jffs_build_fs_fail; - } - } - - while (c->delete_list) { - struct jffs_file *f; - struct jffs_delete_list *delete_list_element; - - if ((f = jffs_find_file(c, c->delete_list->ino))) { - f->deleted = 1; - } - delete_list_element = c->delete_list; - c->delete_list = c->delete_list->next; - kfree(delete_list_element); - } - - /* Remove deleted nodes. */ - if ((err = jffs_foreach_file(c, jffs_possibly_delete_file)) < 0) { - printk(KERN_ERR "JFFS: Failed to remove deleted nodes.\n"); - goto jffs_build_fs_fail; - } - /* Remove redundant nodes. (We are not interested in the - return value in this case.) */ - jffs_foreach_file(c, jffs_remove_redundant_nodes); - /* Try to build a tree from all the nodes. */ - if ((err = jffs_foreach_file(c, jffs_insert_file_into_tree)) < 0) { - printk("JFFS: Failed to build tree.\n"); - goto jffs_build_fs_fail; - } - /* Compute the sizes of all files in the filesystem. Adjust if - necessary. */ - if ((err = jffs_foreach_file(c, jffs_build_file)) < 0) { - printk("JFFS: Failed to build file system.\n"); - goto jffs_build_fs_fail; - } - sb->s_fs_info = (void *)c; - c->building_fs = 0; - - D1(jffs_print_hash_table(c)); - D1(jffs_print_tree(c->root, 0)); - - return 0; - -jffs_build_fs_fail: - jffs_cleanup_control(c); - return err; -} /* jffs_build_fs() */ - - -/* - This checks for sectors that were being erased in their previous - lifetimes and for some reason or the other (power fail etc.), - the erase cycles never completed. - As the flash array would have reverted back to read status, - these sectors are detected by the symptom of the "flipping bits", - i.e. bits being read back differently from the same location in - flash if read multiple times. - The only solution to this is to re-erase the entire - sector. - Unfortunately detecting "flipping bits" is not a simple exercise - as a bit may be read back at 1 or 0 depending on the alignment - of the stars in the universe. - The level of confidence is in direct proportion to the number of - scans done. By power fail testing I (Vipin) have been able to - proove that reading twice is not enough. - Maybe 4 times? Change NUM_REREADS to a higher number if you want - a (even) higher degree of confidence in your mount process. - A higher number would of course slow down your mount. -*/ -static int check_partly_erased_sectors(struct jffs_fmcontrol *fmc){ - -#define NUM_REREADS 4 /* see note above */ -#define READ_AHEAD_BYTES 4096 /* must be a multiple of 4, - usually set to kernel page size */ - - __u8 *read_buf1; - __u8 *read_buf2; - - int err = 0; - int retlen; - int i; - int cnt; - __u32 offset; - loff_t pos = 0; - loff_t end = fmc->flash_size; - - - /* Allocate read buffers */ - read_buf1 = kmalloc(sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL); - if (!read_buf1) - return -ENOMEM; - - read_buf2 = kmalloc(sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL); - if (!read_buf2) { - kfree(read_buf1); - return -ENOMEM; - } - - CHECK_NEXT: - while(pos < end){ - - D1(printk("check_partly_erased_sector():checking sector which contains" - " offset 0x%x for flipping bits..\n", (__u32)pos)); - - retlen = flash_safe_read(fmc->mtd, pos, - &read_buf1[0], READ_AHEAD_BYTES); - retlen &= ~3; - - for(cnt = 0; cnt < NUM_REREADS; cnt++){ - (void)flash_safe_read(fmc->mtd, pos, - &read_buf2[0], READ_AHEAD_BYTES); - - for (i=0 ; i < retlen ; i+=4) { - /* buffers MUST match, double word for word! */ - if(*((__u32 *) &read_buf1[i]) != - *((__u32 *) &read_buf2[i]) - ){ - /* flipping bits detected, time to erase sector */ - /* This will help us log some statistics etc. */ - D1(printk("Flipping bits detected in re-read round:%i of %i\n", - cnt, NUM_REREADS)); - D1(printk("check_partly_erased_sectors:flipping bits detected" - " @offset:0x%x(0x%x!=0x%x)\n", - (__u32)pos+i, *((__u32 *) &read_buf1[i]), - *((__u32 *) &read_buf2[i]))); - - /* calculate start of present sector */ - offset = (((__u32)pos+i)/(__u32)fmc->sector_size) * (__u32)fmc->sector_size; - - D1(printk("check_partly_erased_sector():erasing sector starting 0x%x.\n", - offset)); - - if (flash_erase_region(fmc->mtd, - offset, fmc->sector_size) < 0) { - printk(KERN_ERR "JFFS: Erase of flash failed. " - "offset = %u, erase_size = %d\n", - offset , fmc->sector_size); - - err = -EIO; - goto returnBack; - - }else{ - D1(printk("JFFS: Erase of flash sector @0x%x successful.\n", - offset)); - /* skip ahead to the next sector */ - pos = (((__u32)pos+i)/(__u32)fmc->sector_size) * (__u32)fmc->sector_size; - pos += fmc->sector_size; - goto CHECK_NEXT; - } - } - } - } - pos += READ_AHEAD_BYTES; - } - - returnBack: - kfree(read_buf1); - kfree(read_buf2); - - D2(printk("check_partly_erased_sector():Done checking all sectors till offset 0x%x for flipping bits.\n", - (__u32)pos)); - - return err; - -}/* end check_partly_erased_sectors() */ - - - -/* Scan the whole flash memory in order to find all nodes in the - file systems. */ -static int -jffs_scan_flash(struct jffs_control *c) -{ - char name[JFFS_MAX_NAME_LEN + 2]; - struct jffs_raw_inode raw_inode; - struct jffs_node *node = NULL; - struct jffs_fmcontrol *fmc = c->fmc; - __u32 checksum; - __u8 tmp_accurate; - __u16 tmp_chksum; - __u32 deleted_file; - loff_t pos = 0; - loff_t start; - loff_t test_start; - loff_t end = fmc->flash_size; - __u8 *read_buf; - int i, len, retlen; - __u32 offset; - - __u32 free_chunk_size1; - __u32 free_chunk_size2; - - -#define NUMFREEALLOWED 2 /* 2 chunks of at least erase size space allowed */ - int num_free_space = 0; /* Flag err if more than TWO - free blocks found. This is NOT allowed - by the current jffs design. - */ - int num_free_spc_not_accp = 0; /* For debugging purposed keep count - of how much free space was rejected and - marked dirty - */ - - D1(printk("jffs_scan_flash(): start pos = 0x%lx, end = 0x%lx\n", - (long)pos, (long)end)); - - flash_safe_acquire(fmc->mtd); - - /* - check and make sure that any sector does not suffer - from the "partly erased, bit flipping syndrome" (TM Vipin :) - If so, offending sectors will be erased. - */ - if(check_partly_erased_sectors(fmc) < 0){ - - flash_safe_release(fmc->mtd); - return -EIO; /* bad, bad, bad error. Cannot continue.*/ - } - - /* Allocate read buffer */ - read_buf = kmalloc(sizeof(__u8) * 4096, GFP_KERNEL); - if (!read_buf) { - flash_safe_release(fmc->mtd); - return -ENOMEM; - } - - /* Start the scan. */ - while (pos < end) { - deleted_file = 0; - - /* Remember the position from where we started this scan. */ - start = pos; - - switch (flash_read_u32(fmc->mtd, pos)) { - case JFFS_EMPTY_BITMASK: - /* We have found 0xffffffff at this position. We have to - scan the rest of the flash till the end or till - something else than 0xffffffff is found. - Keep going till we do not find JFFS_EMPTY_BITMASK - anymore */ - - D1(printk("jffs_scan_flash(): 0xffffffff at pos 0x%lx.\n", - (long)pos)); - - while(pos < end){ - - len = end - pos < 4096 ? end - pos : 4096; - - retlen = flash_safe_read(fmc->mtd, pos, - &read_buf[0], len); - - retlen &= ~3; - - for (i=0 ; i < retlen ; i+=4, pos += 4) { - if(*((__u32 *) &read_buf[i]) != - JFFS_EMPTY_BITMASK) - break; - } - if (i == retlen) - continue; - else - break; - } - - D1(printk("jffs_scan_flash():0xffffffff ended at pos 0x%lx.\n", - (long)pos)); - - /* If some free space ends in the middle of a sector, - treat it as dirty rather than clean. - This is to handle the case where one thread - allocated space for a node, but didn't get to - actually _write_ it before power was lost, leaving - a gap in the log. Shifting all node writes into - a single kernel thread will fix the original problem. - */ - if ((__u32) pos % fmc->sector_size) { - /* If there was free space in previous - sectors, don't mark that dirty too - - only from the beginning of this sector - (or from start) - */ - - test_start = pos & ~(fmc->sector_size-1); /* end of last sector */ - - if (start < test_start) { - - /* free space started in the previous sector! */ - - if((num_free_space < NUMFREEALLOWED) && - ((unsigned int)(test_start - start) >= fmc->sector_size)){ - - /* - Count it in if we are still under NUMFREEALLOWED *and* it is - at least 1 erase sector in length. This will keep us from - picking any little ole' space as "free". - */ - - D1(printk("Reducing end of free space to 0x%x from 0x%x\n", - (unsigned int)test_start, (unsigned int)pos)); - - D1(printk("Free space accepted: Starting 0x%x for 0x%x bytes\n", - (unsigned int) start, - (unsigned int)(test_start - start))); - - /* below, space from "start" to "pos" will be marked dirty. */ - start = test_start; - - /* Being in here means that we have found at least an entire - erase sector size of free space ending on a sector boundary. - Keep track of free spaces accepted. - */ - num_free_space++; - }else{ - num_free_spc_not_accp++; - D1(printk("Free space (#%i) found but *Not* accepted: Starting" - " 0x%x for 0x%x bytes\n", - num_free_spc_not_accp, (unsigned int)start, - (unsigned int)((unsigned int)(pos & ~(fmc->sector_size-1)) - (unsigned int)start))); - - } - - } - if((((__u32)(pos - start)) != 0)){ - - D1(printk("Dirty space: Starting 0x%x for 0x%x bytes\n", - (unsigned int) start, (unsigned int) (pos - start))); - jffs_fmalloced(fmc, (__u32) start, - (__u32) (pos - start), NULL); - }else{ - /* "Flipping bits" detected. This means that our scan for them - did not catch this offset. See check_partly_erased_sectors() for - more info. - */ - - D1(printk("jffs_scan_flash():wants to allocate dirty flash " - "space for 0 bytes.\n")); - D1(printk("jffs_scan_flash(): Flipping bits! We will free " - "all allocated memory, erase this sector and remount\n")); - - /* calculate start of present sector */ - offset = (((__u32)pos)/(__u32)fmc->sector_size) * (__u32)fmc->sector_size; - - D1(printk("jffs_scan_flash():erasing sector starting 0x%x.\n", - offset)); - - if (flash_erase_region(fmc->mtd, - offset, fmc->sector_size) < 0) { - printk(KERN_ERR "JFFS: Erase of flash failed. " - "offset = %u, erase_size = %d\n", - offset , fmc->sector_size); - - flash_safe_release(fmc->mtd); - kfree(read_buf); - return -1; /* bad, bad, bad! */ - - } - flash_safe_release(fmc->mtd); - kfree(read_buf); - - return -EAGAIN; /* erased offending sector. Try mount one more time please. */ - } - }else{ - /* Being in here means that we have found free space that ends on an erase sector - boundary. - Count it in if we are still under NUMFREEALLOWED *and* it is at least 1 erase - sector in length. This will keep us from picking any little ole' space as "free". - */ - if((num_free_space < NUMFREEALLOWED) && - ((unsigned int)(pos - start) >= fmc->sector_size)){ - /* We really don't do anything to mark space as free, except *not* - mark it dirty and just advance the "pos" location pointer. - It will automatically be picked up as free space. - */ - num_free_space++; - D1(printk("Free space accepted: Starting 0x%x for 0x%x bytes\n", - (unsigned int) start, (unsigned int) (pos - start))); - }else{ - num_free_spc_not_accp++; - D1(printk("Free space (#%i) found but *Not* accepted: Starting " - "0x%x for 0x%x bytes\n", num_free_spc_not_accp, - (unsigned int) start, - (unsigned int) (pos - start))); - - /* Mark this space as dirty. We already have our free space. */ - D1(printk("Dirty space: Starting 0x%x for 0x%x bytes\n", - (unsigned int) start, (unsigned int) (pos - start))); - jffs_fmalloced(fmc, (__u32) start, - (__u32) (pos - start), NULL); - } - - } - if(num_free_space > NUMFREEALLOWED){ - printk(KERN_WARNING "jffs_scan_flash(): Found free space " - "number %i. Only %i free space is allowed.\n", - num_free_space, NUMFREEALLOWED); - } - continue; - - case JFFS_DIRTY_BITMASK: - /* We have found 0x00000000 at this position. Scan as far - as possible to find out how much is dirty. */ - D1(printk("jffs_scan_flash(): 0x00000000 at pos 0x%lx.\n", - (long)pos)); - for (; pos < end - && JFFS_DIRTY_BITMASK == flash_read_u32(fmc->mtd, pos); - pos += 4); - D1(printk("jffs_scan_flash(): 0x00 ended at " - "pos 0x%lx.\n", (long)pos)); - jffs_fmalloced(fmc, (__u32) start, - (__u32) (pos - start), NULL); - continue; - - case JFFS_MAGIC_BITMASK: - /* We have probably found a new raw inode. */ - break; - - default: - bad_inode: - /* We're f*cked. This is not solved yet. We have - to scan for the magic pattern. */ - D1(printk("*************** Dirty flash memory or " - "bad inode: " - "hexdump(pos = 0x%lx, len = 128):\n", - (long)pos)); - D1(jffs_hexdump(fmc->mtd, pos, 128)); - - for (pos += 4; pos < end; pos += 4) { - switch (flash_read_u32(fmc->mtd, pos)) { - case JFFS_MAGIC_BITMASK: - case JFFS_EMPTY_BITMASK: - /* handle these in the main switch() loop */ - goto cont_scan; - - default: - break; - } - } - - cont_scan: - /* First, mark as dirty the region - which really does contain crap. */ - jffs_fmalloced(fmc, (__u32) start, - (__u32) (pos - start), - NULL); - - continue; - }/* switch */ - - /* We have found the beginning of an inode. Create a - node for it unless there already is one available. */ - if (!node) { - if (!(node = jffs_alloc_node())) { - /* Free read buffer */ - kfree(read_buf); - - /* Release the flash device */ - flash_safe_release(fmc->mtd); - - return -ENOMEM; - } - DJM(no_jffs_node++); - } - - /* Read the next raw inode. */ - - flash_safe_read(fmc->mtd, pos, (u_char *) &raw_inode, - sizeof(struct jffs_raw_inode)); - - /* When we compute the checksum for the inode, we never - count the 'accurate' or the 'checksum' fields. */ - tmp_accurate = raw_inode.accurate; - tmp_chksum = raw_inode.chksum; - raw_inode.accurate = 0; - raw_inode.chksum = 0; - checksum = jffs_checksum(&raw_inode, - sizeof(struct jffs_raw_inode)); - raw_inode.accurate = tmp_accurate; - raw_inode.chksum = tmp_chksum; - - D3(printk("*** We have found this raw inode at pos 0x%lx " - "on the flash:\n", (long)pos)); - D3(jffs_print_raw_inode(&raw_inode)); - - if (checksum != raw_inode.chksum) { - D1(printk("jffs_scan_flash(): Bad checksum: " - "checksum = %u, " - "raw_inode.chksum = %u\n", - checksum, raw_inode.chksum)); - pos += sizeof(struct jffs_raw_inode); - jffs_fmalloced(fmc, (__u32) start, - (__u32) (pos - start), NULL); - /* Reuse this unused struct jffs_node. */ - continue; - } - - /* Check the raw inode read so far. Start with the - maximum length of the filename. */ - if (raw_inode.nsize > JFFS_MAX_NAME_LEN) { - printk(KERN_WARNING "jffs_scan_flash: Found a " - "JFFS node with name too large\n"); - goto bad_inode; - } - - if (raw_inode.rename && raw_inode.dsize != sizeof(__u32)) { - printk(KERN_WARNING "jffs_scan_flash: Found a " - "rename node with dsize %u.\n", - raw_inode.dsize); - jffs_print_raw_inode(&raw_inode); - goto bad_inode; - } - - /* The node's data segment should not exceed a - certain length. */ - if (raw_inode.dsize > fmc->max_chunk_size) { - printk(KERN_WARNING "jffs_scan_flash: Found a " - "JFFS node with dsize (0x%x) > max_chunk_size (0x%x)\n", - raw_inode.dsize, fmc->max_chunk_size); - goto bad_inode; - } - - pos += sizeof(struct jffs_raw_inode); - - /* This shouldn't be necessary because a node that - violates the flash boundaries shouldn't be written - in the first place. */ - if (pos >= end) { - goto check_node; - } - - /* Read the name. */ - *name = 0; - if (raw_inode.nsize) { - flash_safe_read(fmc->mtd, pos, name, raw_inode.nsize); - name[raw_inode.nsize] = '\0'; - pos += raw_inode.nsize - + JFFS_GET_PAD_BYTES(raw_inode.nsize); - D3(printk("name == \"%s\"\n", name)); - checksum = jffs_checksum(name, raw_inode.nsize); - if (checksum != raw_inode.nchksum) { - D1(printk("jffs_scan_flash(): Bad checksum: " - "checksum = %u, " - "raw_inode.nchksum = %u\n", - checksum, raw_inode.nchksum)); - jffs_fmalloced(fmc, (__u32) start, - (__u32) (pos - start), NULL); - /* Reuse this unused struct jffs_node. */ - continue; - } - if (pos >= end) { - goto check_node; - } - } - - /* Read the data, if it exists, in order to be sure it - matches the checksum. */ - if (raw_inode.dsize) { - if (raw_inode.rename) { - deleted_file = flash_read_u32(fmc->mtd, pos); - } - if (jffs_checksum_flash(fmc->mtd, pos, raw_inode.dsize, &checksum)) { - printk("jffs_checksum_flash() failed to calculate a checksum\n"); - jffs_fmalloced(fmc, (__u32) start, - (__u32) (pos - start), NULL); - /* Reuse this unused struct jffs_node. */ - continue; - } - pos += raw_inode.dsize - + JFFS_GET_PAD_BYTES(raw_inode.dsize); - - if (checksum != raw_inode.dchksum) { - D1(printk("jffs_scan_flash(): Bad checksum: " - "checksum = %u, " - "raw_inode.dchksum = %u\n", - checksum, raw_inode.dchksum)); - jffs_fmalloced(fmc, (__u32) start, - (__u32) (pos - start), NULL); - /* Reuse this unused struct jffs_node. */ - continue; - } - } - - check_node: - - /* Remember the highest inode number in the whole file - system. This information will be used when assigning - new files new inode numbers. */ - if (c->next_ino <= raw_inode.ino) { - c->next_ino = raw_inode.ino + 1; - } - - if (raw_inode.accurate) { - int err; - node->data_offset = raw_inode.offset; - node->data_size = raw_inode.dsize; - node->removed_size = raw_inode.rsize; - /* Compute the offset to the actual data in the - on-flash node. */ - node->fm_offset - = sizeof(struct jffs_raw_inode) - + raw_inode.nsize - + JFFS_GET_PAD_BYTES(raw_inode.nsize); - node->fm = jffs_fmalloced(fmc, (__u32) start, - (__u32) (pos - start), - node); - if (!node->fm) { - D(printk("jffs_scan_flash(): !node->fm\n")); - jffs_free_node(node); - DJM(no_jffs_node--); - - /* Free read buffer */ - kfree(read_buf); - - /* Release the flash device */ - flash_safe_release(fmc->mtd); - - return -ENOMEM; - } - if ((err = jffs_insert_node(c, NULL, &raw_inode, - name, node)) < 0) { - printk("JFFS: Failed to handle raw inode. " - "(err = %d)\n", err); - break; - } - if (raw_inode.rename) { - struct jffs_delete_list *dl - = (struct jffs_delete_list *) - kmalloc(sizeof(struct jffs_delete_list), - GFP_KERNEL); - if (!dl) { - D(printk("jffs_scan_flash: !dl\n")); - jffs_free_node(node); - DJM(no_jffs_node--); - - /* Release the flash device */ - flash_safe_release(fmc->flash_part); - - /* Free read buffer */ - kfree(read_buf); - - return -ENOMEM; - } - dl->ino = deleted_file; - dl->next = c->delete_list; - c->delete_list = dl; - node->data_size = 0; - } - D3(jffs_print_node(node)); - node = NULL; /* Don't free the node! */ - } - else { - jffs_fmalloced(fmc, (__u32) start, - (__u32) (pos - start), NULL); - D3(printk("jffs_scan_flash(): Just found an obsolete " - "raw_inode. Continuing the scan...\n")); - /* Reuse this unused struct jffs_node. */ - } - } - - if (node) { - jffs_free_node(node); - DJM(no_jffs_node--); - } - jffs_build_end(fmc); - - /* Free read buffer */ - kfree(read_buf); - - if(!num_free_space){ - printk(KERN_WARNING "jffs_scan_flash(): Did not find even a single " - "chunk of free space. This is BAD!\n"); - } - - /* Return happy */ - D3(printk("jffs_scan_flash(): Leaving...\n")); - flash_safe_release(fmc->mtd); - - /* This is to trap the "free size accounting screwed error. */ - free_chunk_size1 = jffs_free_size1(fmc); - free_chunk_size2 = jffs_free_size2(fmc); - - if (free_chunk_size1 + free_chunk_size2 != fmc->free_size) { - - printk(KERN_WARNING "jffs_scan_falsh():Free size accounting screwed\n"); - printk(KERN_WARNING "jfffs_scan_flash():free_chunk_size1 == 0x%x, " - "free_chunk_size2 == 0x%x, fmc->free_size == 0x%x\n", - free_chunk_size1, free_chunk_size2, fmc->free_size); - - return -1; /* Do NOT mount f/s so that we can inspect what happened. - Mounting this screwed up f/s will screw us up anyway. - */ - } - - return 0; /* as far as we are concerned, we are happy! */ -} /* jffs_scan_flash() */ - - -/* Insert any kind of node into the file system. Take care of data - insertions and deletions. Also remove redundant information. The - memory allocated for the `name' is regarded as "given away" in the - caller's perspective. */ -int -jffs_insert_node(struct jffs_control *c, struct jffs_file *f, - const struct jffs_raw_inode *raw_inode, - const char *name, struct jffs_node *node) -{ - int update_name = 0; - int insert_into_tree = 0; - - D2(printk("jffs_insert_node(): ino = %u, version = %u, " - "name = \"%s\", deleted = %d\n", - raw_inode->ino, raw_inode->version, - ((name && *name) ? name : ""), raw_inode->deleted)); - - /* If there doesn't exist an associated jffs_file, then - create, initialize and insert one into the file system. */ - if (!f && !(f = jffs_find_file(c, raw_inode->ino))) { - if (!(f = jffs_create_file(c, raw_inode))) { - return -ENOMEM; - } - jffs_insert_file_into_hash(f); - insert_into_tree = 1; - } - node->ino = raw_inode->ino; - node->version = raw_inode->version; - node->data_size = raw_inode->dsize; - node->fm_offset = sizeof(struct jffs_raw_inode) + raw_inode->nsize - + JFFS_GET_PAD_BYTES(raw_inode->nsize); - node->name_size = raw_inode->nsize; - - /* Now insert the node at the correct position into the file's - version list. */ - if (!f->version_head) { - /* This is the first node. */ - f->version_head = node; - f->version_tail = node; - node->version_prev = NULL; - node->version_next = NULL; - f->highest_version = node->version; - update_name = 1; - f->mode = raw_inode->mode; - f->uid = raw_inode->uid; - f->gid = raw_inode->gid; - f->atime = raw_inode->atime; - f->mtime = raw_inode->mtime; - f->ctime = raw_inode->ctime; - } - else if ((f->highest_version < node->version) - || (node->version == 0)) { - /* Insert at the end of the list. I.e. this node is the - newest one so far. */ - node->version_prev = f->version_tail; - node->version_next = NULL; - f->version_tail->version_next = node; - f->version_tail = node; - f->highest_version = node->version; - update_name = 1; - f->pino = raw_inode->pino; - f->mode = raw_inode->mode; - f->uid = raw_inode->uid; - f->gid = raw_inode->gid; - f->atime = raw_inode->atime; - f->mtime = raw_inode->mtime; - f->ctime = raw_inode->ctime; - } - else if (f->version_head->version > node->version) { - /* Insert at the bottom of the list. */ - node->version_prev = NULL; - node->version_next = f->version_head; - f->version_head->version_prev = node; - f->version_head = node; - if (!f->name) { - update_name = 1; - } - } - else { - struct jffs_node *n; - int newer_name = 0; - /* Search for the insertion position starting from - the tail (newest node). */ - for (n = f->version_tail; n; n = n->version_prev) { - if (n->version < node->version) { - node->version_prev = n; - node->version_next = n->version_next; - node->version_next->version_prev = node; - n->version_next = node; - if (!newer_name) { - update_name = 1; - } - break; - } - if (n->name_size) { - newer_name = 1; - } - } - } - - /* Deletion is irreversible. If any 'deleted' node is ever - written, the file is deleted */ - if (raw_inode->deleted) - f->deleted = raw_inode->deleted; - - /* Perhaps update the name. */ - if (raw_inode->nsize && update_name && name && *name && (name != f->name)) { - if (f->name) { - kfree(f->name); - DJM(no_name--); - } - if (!(f->name = kmalloc(raw_inode->nsize + 1, - GFP_KERNEL))) { - return -ENOMEM; - } - DJM(no_name++); - memcpy(f->name, name, raw_inode->nsize); - f->name[raw_inode->nsize] = '\0'; - f->nsize = raw_inode->nsize; - D3(printk("jffs_insert_node(): Updated the name of " - "the file to \"%s\".\n", name)); - } - - if (!c->building_fs) { - D3(printk("jffs_insert_node(): ---------------------------" - "------------------------------------------- 1\n")); - if (insert_into_tree) { - jffs_insert_file_into_tree(f); - } - /* Once upon a time, we would call jffs_possibly_delete_file() - here. That causes an oops if someone's still got the file - open, so now we only do it in jffs_delete_inode() - -- dwmw2 - */ - if (node->data_size || node->removed_size) { - jffs_update_file(f, node); - } - jffs_remove_redundant_nodes(f); - - jffs_garbage_collect_trigger(c); - - D3(printk("jffs_insert_node(): ---------------------------" - "------------------------------------------- 2\n")); - } - - return 0; -} /* jffs_insert_node() */ - - -/* Unlink a jffs_node from the version list it is in. */ -static inline void -jffs_unlink_node_from_version_list(struct jffs_file *f, - struct jffs_node *node) -{ - if (node->version_prev) { - node->version_prev->version_next = node->version_next; - } else { - f->version_head = node->version_next; - } - if (node->version_next) { - node->version_next->version_prev = node->version_prev; - } else { - f->version_tail = node->version_prev; - } -} - - -/* Unlink a jffs_node from the range list it is in. */ -static inline void -jffs_unlink_node_from_range_list(struct jffs_file *f, struct jffs_node *node) -{ - if (node->range_prev) { - node->range_prev->range_next = node->range_next; - } - else { - f->range_head = node->range_next; - } - if (node->range_next) { - node->range_next->range_prev = node->range_prev; - } - else { - f->range_tail = node->range_prev; - } -} - - -/* Function used by jffs_remove_redundant_nodes() below. This function - classifies what kind of information a node adds to a file. */ -static inline __u8 -jffs_classify_node(struct jffs_node *node) -{ - __u8 mod_type = JFFS_MODIFY_INODE; - - if (node->name_size) { - mod_type |= JFFS_MODIFY_NAME; - } - if (node->data_size || node->removed_size) { - mod_type |= JFFS_MODIFY_DATA; - } - return mod_type; -} - - -/* Remove redundant nodes from a file. Mark the on-flash memory - as dirty. */ -static int -jffs_remove_redundant_nodes(struct jffs_file *f) -{ - struct jffs_node *newest_node; - struct jffs_node *cur; - struct jffs_node *prev; - __u8 newest_type; - __u8 mod_type; - __u8 node_with_name_later = 0; - - if (!(newest_node = f->version_tail)) { - return 0; - } - - /* What does the `newest_node' modify? */ - newest_type = jffs_classify_node(newest_node); - node_with_name_later = newest_type & JFFS_MODIFY_NAME; - - D3(printk("jffs_remove_redundant_nodes(): ino: %u, name: \"%s\", " - "newest_type: %u\n", f->ino, (f->name ? f->name : ""), - newest_type)); - - /* Traverse the file's nodes and determine which of them that are - superfluous. Yeah, this might look very complex at first - glance but it is actually very simple. */ - for (cur = newest_node->version_prev; cur; cur = prev) { - prev = cur->version_prev; - mod_type = jffs_classify_node(cur); - if ((mod_type <= JFFS_MODIFY_INODE) - || ((newest_type & JFFS_MODIFY_NAME) - && (mod_type - <= (JFFS_MODIFY_INODE + JFFS_MODIFY_NAME))) - || (cur->data_size == 0 && cur->removed_size - && !cur->version_prev && node_with_name_later)) { - /* Yes, this node is redundant. Remove it. */ - D2(printk("jffs_remove_redundant_nodes(): " - "Removing node: ino: %u, version: %u, " - "mod_type: %u\n", cur->ino, cur->version, - mod_type)); - jffs_unlink_node_from_version_list(f, cur); - jffs_fmfree(f->c->fmc, cur->fm, cur); - jffs_free_node(cur); - DJM(no_jffs_node--); - } - else { - node_with_name_later |= (mod_type & JFFS_MODIFY_NAME); - } - } - - return 0; -} - - -/* Insert a file into the hash table. */ -static int -jffs_insert_file_into_hash(struct jffs_file *f) -{ - int i = f->ino % f->c->hash_len; - - D3(printk("jffs_insert_file_into_hash(): f->ino: %u\n", f->ino)); - - list_add(&f->hash, &f->c->hash[i]); - return 0; -} - - -/* Insert a file into the file system tree. */ -int -jffs_insert_file_into_tree(struct jffs_file *f) -{ - struct jffs_file *parent; - - D3(printk("jffs_insert_file_into_tree(): name: \"%s\"\n", - (f->name ? f->name : ""))); - - if (!(parent = jffs_find_file(f->c, f->pino))) { - if (f->pino == 0) { - f->c->root = f; - f->parent = NULL; - f->sibling_prev = NULL; - f->sibling_next = NULL; - return 0; - } - else { - D1(printk("jffs_insert_file_into_tree(): Found " - "inode with no parent and pino == %u\n", - f->pino)); - return -1; - } - } - f->parent = parent; - f->sibling_next = parent->children; - if (f->sibling_next) { - f->sibling_next->sibling_prev = f; - } - f->sibling_prev = NULL; - parent->children = f; - return 0; -} - - -/* Remove a file from the hash table. */ -static int -jffs_unlink_file_from_hash(struct jffs_file *f) -{ - D3(printk("jffs_unlink_file_from_hash(): f: 0x%p, " - "ino %u\n", f, f->ino)); - - list_del(&f->hash); - return 0; -} - - -/* Just remove the file from the parent's children. Don't free - any memory. */ -int -jffs_unlink_file_from_tree(struct jffs_file *f) -{ - D3(printk("jffs_unlink_file_from_tree(): ino: %d, pino: %d, name: " - "\"%s\"\n", f->ino, f->pino, (f->name ? f->name : ""))); - - if (f->sibling_prev) { - f->sibling_prev->sibling_next = f->sibling_next; - } - else if (f->parent) { - D3(printk("f->parent=%p\n", f->parent)); - f->parent->children = f->sibling_next; - } - if (f->sibling_next) { - f->sibling_next->sibling_prev = f->sibling_prev; - } - return 0; -} - - -/* Find a file with its inode number. */ -struct jffs_file * -jffs_find_file(struct jffs_control *c, __u32 ino) -{ - struct jffs_file *f; - int i = ino % c->hash_len; - - D3(printk("jffs_find_file(): ino: %u\n", ino)); - - list_for_each_entry(f, &c->hash[i], hash) { - if (ino != f->ino) - continue; - D3(printk("jffs_find_file(): Found file with ino " - "%u. (name: \"%s\")\n", - ino, (f->name ? f->name : "")); - ); - return f; - } - D3(printk("jffs_find_file(): Didn't find file " - "with ino %u.\n", ino); - ); - return NULL; -} - - -/* Find a file in a directory. We are comparing the names. */ -struct jffs_file * -jffs_find_child(struct jffs_file *dir, const char *name, int len) -{ - struct jffs_file *f; - - D3(printk("jffs_find_child()\n")); - - for (f = dir->children; f; f = f->sibling_next) { - if (!f->deleted && f->name - && !strncmp(f->name, name, len) - && f->name[len] == '\0') { - break; - } - } - - D3(if (f) { - printk("jffs_find_child(): Found \"%s\".\n", f->name); - } - else { - char *copy = kmalloc(len + 1, GFP_KERNEL); - if (copy) { - memcpy(copy, name, len); - copy[len] = '\0'; - } - printk("jffs_find_child(): Didn't find the file \"%s\".\n", - (copy ? copy : "")); - kfree(copy); - }); - - return f; -} - - -/* Write a raw inode that takes up a certain amount of space in the flash - memory. At the end of the flash device, there is often space that is - impossible to use. At these times we want to mark this space as not - used. In the cases when the amount of space is greater or equal than - a struct jffs_raw_inode, we write a "dummy node" that takes up this - space. The space after the raw inode, if it exists, is left as it is. - Since this space after the raw inode contains JFFS_EMPTY_BITMASK bytes, - we can compute the checksum of it; we don't have to manipulate it any - further. - - If the space left on the device is less than the size of a struct - jffs_raw_inode, this space is filled with JFFS_DIRTY_BITMASK bytes. - No raw inode is written this time. */ -static int -jffs_write_dummy_node(struct jffs_control *c, struct jffs_fm *dirty_fm) -{ - struct jffs_fmcontrol *fmc = c->fmc; - int err; - - D1(printk("jffs_write_dummy_node(): dirty_fm->offset = 0x%08x, " - "dirty_fm->size = %u\n", - dirty_fm->offset, dirty_fm->size)); - - if (dirty_fm->size >= sizeof(struct jffs_raw_inode)) { - struct jffs_raw_inode raw_inode; - memset(&raw_inode, 0, sizeof(struct jffs_raw_inode)); - raw_inode.magic = JFFS_MAGIC_BITMASK; - raw_inode.dsize = dirty_fm->size - - sizeof(struct jffs_raw_inode); - raw_inode.dchksum = raw_inode.dsize * 0xff; - raw_inode.chksum - = jffs_checksum(&raw_inode, sizeof(struct jffs_raw_inode)); - - if ((err = flash_safe_write(fmc->mtd, - dirty_fm->offset, - (u_char *)&raw_inode, - sizeof(struct jffs_raw_inode))) - < 0) { - printk(KERN_ERR "JFFS: jffs_write_dummy_node: " - "flash_safe_write failed!\n"); - return err; - } - } - else { - flash_safe_acquire(fmc->mtd); - flash_memset(fmc->mtd, dirty_fm->offset, 0, dirty_fm->size); - flash_safe_release(fmc->mtd); - } - - D3(printk("jffs_write_dummy_node(): Leaving...\n")); - return 0; -} - - -/* Write a raw inode, possibly its name and possibly some data. */ -int -jffs_write_node(struct jffs_control *c, struct jffs_node *node, - struct jffs_raw_inode *raw_inode, - const char *name, const unsigned char *data, - int recoverable, - struct jffs_file *f) -{ - struct jffs_fmcontrol *fmc = c->fmc; - struct jffs_fm *fm; - struct kvec node_iovec[4]; - unsigned long iovec_cnt; - - __u32 pos; - int err; - __u32 slack = 0; - - __u32 total_name_size = raw_inode->nsize - + JFFS_GET_PAD_BYTES(raw_inode->nsize); - __u32 total_data_size = raw_inode->dsize - + JFFS_GET_PAD_BYTES(raw_inode->dsize); - __u32 total_size = sizeof(struct jffs_raw_inode) - + total_name_size + total_data_size; - - /* If this node isn't something that will eventually let - GC free even more space, then don't allow it unless - there's at least max_chunk_size space still available - */ - if (!recoverable) - slack = fmc->max_chunk_size; - - - /* Fire the retrorockets and shoot the fruiton torpedoes, sir! */ - - ASSERT(if (!node) { - printk("jffs_write_node(): node == NULL\n"); - return -EINVAL; - }); - ASSERT(if (raw_inode && raw_inode->nsize && !name) { - printk("*** jffs_write_node(): nsize = %u but name == NULL\n", - raw_inode->nsize); - return -EINVAL; - }); - - D1(printk("jffs_write_node(): filename = \"%s\", ino = %u, " - "total_size = %u\n", - (name ? name : ""), raw_inode->ino, - total_size)); - - jffs_fm_write_lock(fmc); - -retry: - fm = NULL; - err = 0; - while (!fm) { - - /* Deadlocks suck. */ - while(fmc->free_size < fmc->min_free_size + total_size + slack) { - jffs_fm_write_unlock(fmc); - if (!JFFS_ENOUGH_SPACE(c, total_size + slack)) - return -ENOSPC; - jffs_fm_write_lock(fmc); - } - - /* First try to allocate some flash memory. */ - err = jffs_fmalloc(fmc, total_size, node, &fm); - - if (err == -ENOSPC) { - /* Just out of space. GC and try again */ - if (fmc->dirty_size < fmc->sector_size) { - D(printk("jffs_write_node(): jffs_fmalloc(0x%p, %u) " - "failed, no dirty space to GC\n", fmc, - total_size)); - return err; - } - - D1(printk(KERN_INFO "jffs_write_node(): Calling jffs_garbage_collect_now()\n")); - jffs_fm_write_unlock(fmc); - if ((err = jffs_garbage_collect_now(c))) { - D(printk("jffs_write_node(): jffs_garbage_collect_now() failed\n")); - return err; - } - jffs_fm_write_lock(fmc); - continue; - } - - if (err < 0) { - jffs_fm_write_unlock(fmc); - - D(printk("jffs_write_node(): jffs_fmalloc(0x%p, %u) " - "failed!\n", fmc, total_size)); - return err; - } - - if (!fm->nodes) { - /* The jffs_fm struct that we got is not good enough. - Make that space dirty and try again */ - if ((err = jffs_write_dummy_node(c, fm)) < 0) { - kfree(fm); - DJM(no_jffs_fm--); - jffs_fm_write_unlock(fmc); - D(printk("jffs_write_node(): " - "jffs_write_dummy_node(): Failed!\n")); - return err; - } - fm = NULL; - } - } /* while(!fm) */ - node->fm = fm; - - ASSERT(if (fm->nodes == 0) { - printk(KERN_ERR "jffs_write_node(): fm->nodes == 0\n"); - }); - - pos = node->fm->offset; - - /* Increment the version number here. We can't let the caller - set it beforehand, because we might have had to do GC on a node - of this file - and we'd end up reusing version numbers. - */ - if (f) { - raw_inode->version = f->highest_version + 1; - D1(printk (KERN_NOTICE "jffs_write_node(): setting version of %s to %d\n", f->name, raw_inode->version)); - - /* if the file was deleted, set the deleted bit in the raw inode */ - if (f->deleted) - raw_inode->deleted = 1; - } - - /* Compute the checksum for the data and name chunks. */ - raw_inode->dchksum = jffs_checksum(data, raw_inode->dsize); - raw_inode->nchksum = jffs_checksum(name, raw_inode->nsize); - - /* The checksum is calculated without the chksum and accurate - fields so set them to zero first. */ - raw_inode->accurate = 0; - raw_inode->chksum = 0; - raw_inode->chksum = jffs_checksum(raw_inode, - sizeof(struct jffs_raw_inode)); - raw_inode->accurate = 0xff; - - D3(printk("jffs_write_node(): About to write this raw inode to the " - "flash at pos 0x%lx:\n", (long)pos)); - D3(jffs_print_raw_inode(raw_inode)); - - /* The actual raw JFFS node */ - node_iovec[0].iov_base = (void *) raw_inode; - node_iovec[0].iov_len = (size_t) sizeof(struct jffs_raw_inode); - iovec_cnt = 1; - - /* Get name and size if there is one */ - if (raw_inode->nsize) { - node_iovec[iovec_cnt].iov_base = (void *) name; - node_iovec[iovec_cnt].iov_len = (size_t) raw_inode->nsize; - iovec_cnt++; - - if (JFFS_GET_PAD_BYTES(raw_inode->nsize)) { - static unsigned char allff[3]={255,255,255}; - /* Add some extra padding if necessary */ - node_iovec[iovec_cnt].iov_base = allff; - node_iovec[iovec_cnt].iov_len = - JFFS_GET_PAD_BYTES(raw_inode->nsize); - iovec_cnt++; - } - } - - /* Get data and size if there is any */ - if (raw_inode->dsize) { - node_iovec[iovec_cnt].iov_base = (void *) data; - node_iovec[iovec_cnt].iov_len = (size_t) raw_inode->dsize; - iovec_cnt++; - /* No need to pad this because we're not actually putting - anything after it. - */ - } - - if ((err = flash_safe_writev(fmc->mtd, node_iovec, iovec_cnt, - pos)) < 0) { - jffs_fmfree_partly(fmc, fm, 0); - jffs_fm_write_unlock(fmc); - printk(KERN_ERR "JFFS: jffs_write_node: Failed to write, " - "requested %i, wrote %i\n", total_size, err); - goto retry; - } - if (raw_inode->deleted) - f->deleted = 1; - - jffs_fm_write_unlock(fmc); - D3(printk("jffs_write_node(): Leaving...\n")); - return raw_inode->dsize; -} /* jffs_write_node() */ - - -/* Read data from the node and write it to the buffer. 'node_offset' - is how much we have read from this particular node before and which - shouldn't be read again. 'max_size' is how much space there is in - the buffer. */ -static int -jffs_get_node_data(struct jffs_file *f, struct jffs_node *node, - unsigned char *buf,__u32 node_offset, __u32 max_size) -{ - struct jffs_fmcontrol *fmc = f->c->fmc; - __u32 pos = node->fm->offset + node->fm_offset + node_offset; - __u32 avail = node->data_size - node_offset; - __u32 r; - - D2(printk(" jffs_get_node_data(): file: \"%s\", ino: %u, " - "version: %u, node_offset: %u\n", - f->name, node->ino, node->version, node_offset)); - - r = min(avail, max_size); - D3(printk(KERN_NOTICE "jffs_get_node_data\n")); - flash_safe_read(fmc->mtd, pos, buf, r); - - D3(printk(" jffs_get_node_data(): Read %u byte%s.\n", - r, (r == 1 ? "" : "s"))); - - return r; -} - - -/* Read data from the file's nodes. Write the data to the buffer - 'buf'. 'read_offset' tells how much data we should skip. */ -int -jffs_read_data(struct jffs_file *f, unsigned char *buf, __u32 read_offset, - __u32 size) -{ - struct jffs_node *node; - __u32 read_data = 0; /* Total amount of read data. */ - __u32 node_offset = 0; - __u32 pos = 0; /* Number of bytes traversed. */ - - D2(printk("jffs_read_data(): file = \"%s\", read_offset = %d, " - "size = %u\n", - (f->name ? f->name : ""), read_offset, size)); - - if (read_offset >= f->size) { - D(printk(" f->size: %d\n", f->size)); - return 0; - } - - /* First find the node to read data from. */ - node = f->range_head; - while (pos <= read_offset) { - node_offset = read_offset - pos; - if (node_offset >= node->data_size) { - pos += node->data_size; - node = node->range_next; - } - else { - break; - } - } - - /* "Cats are living proof that not everything in nature - has to be useful." - - Garrison Keilor ('97) */ - - /* Fill the buffer. */ - while (node && (read_data < size)) { - int r; - if (!node->fm) { - /* This node does not refer to real data. */ - r = min(size - read_data, - node->data_size - node_offset); - memset(&buf[read_data], 0, r); - } - else if ((r = jffs_get_node_data(f, node, &buf[read_data], - node_offset, - size - read_data)) < 0) { - return r; - } - read_data += r; - node_offset = 0; - node = node->range_next; - } - D3(printk(" jffs_read_data(): Read %u bytes.\n", read_data)); - return read_data; -} - - -/* Used for traversing all nodes in the hash table. */ -int -jffs_foreach_file(struct jffs_control *c, int (*func)(struct jffs_file *)) -{ - int pos; - int r; - int result = 0; - - for (pos = 0; pos < c->hash_len; pos++) { - struct jffs_file *f, *next; - - /* We must do _safe, because 'func' might remove the - current file 'f' from the list. */ - list_for_each_entry_safe(f, next, &c->hash[pos], hash) { - r = func(f); - if (r < 0) - return r; - result += r; - } - } - - return result; -} - - -/* Free all nodes associated with a file. */ -static int -jffs_free_node_list(struct jffs_file *f) -{ - struct jffs_node *node; - struct jffs_node *p; - - D3(printk("jffs_free_node_list(): f #%u, \"%s\"\n", - f->ino, (f->name ? f->name : ""))); - node = f->version_head; - while (node) { - p = node; - node = node->version_next; - jffs_free_node(p); - DJM(no_jffs_node--); - } - return 0; -} - - -/* Free a file and its name. */ -static int -jffs_free_file(struct jffs_file *f) -{ - D3(printk("jffs_free_file: f #%u, \"%s\"\n", - f->ino, (f->name ? f->name : ""))); - - if (f->name) { - kfree(f->name); - DJM(no_name--); - } - kfree(f); - no_jffs_file--; - return 0; -} - -static long -jffs_get_file_count(void) -{ - return no_jffs_file; -} - -/* See if a file is deleted. If so, mark that file's nodes as obsolete. */ -int -jffs_possibly_delete_file(struct jffs_file *f) -{ - struct jffs_node *n; - - D3(printk("jffs_possibly_delete_file(): ino: %u\n", - f->ino)); - - ASSERT(if (!f) { - printk(KERN_ERR "jffs_possibly_delete_file(): f == NULL\n"); - return -1; - }); - - if (f->deleted) { - /* First try to remove all older versions. Commence with - the oldest node. */ - for (n = f->version_head; n; n = n->version_next) { - if (!n->fm) { - continue; - } - if (jffs_fmfree(f->c->fmc, n->fm, n) < 0) { - break; - } - } - /* Unlink the file from the filesystem. */ - if (!f->c->building_fs) { - jffs_unlink_file_from_tree(f); - } - jffs_unlink_file_from_hash(f); - jffs_free_node_list(f); - jffs_free_file(f); - } - return 0; -} - - -/* Used in conjunction with jffs_foreach_file() to count the number - of files in the file system. */ -int -jffs_file_count(struct jffs_file *f) -{ - return 1; -} - - -/* Build up a file's range list from scratch by going through the - version list. */ -static int -jffs_build_file(struct jffs_file *f) -{ - struct jffs_node *n; - - D3(printk("jffs_build_file(): ino: %u, name: \"%s\"\n", - f->ino, (f->name ? f->name : ""))); - - for (n = f->version_head; n; n = n->version_next) { - jffs_update_file(f, n); - } - return 0; -} - - -/* Remove an amount of data from a file. If this amount of data is - zero, that could mean that a node should be split in two parts. - We remove or change the appropriate nodes in the lists. - - Starting offset of area to be removed is node->data_offset, - and the length of the area is in node->removed_size. */ -static int -jffs_delete_data(struct jffs_file *f, struct jffs_node *node) -{ - struct jffs_node *n; - __u32 offset = node->data_offset; - __u32 remove_size = node->removed_size; - - D3(printk("jffs_delete_data(): offset = %u, remove_size = %u\n", - offset, remove_size)); - - if (remove_size == 0 - && f->range_tail - && f->range_tail->data_offset + f->range_tail->data_size - == offset) { - /* A simple append; nothing to remove or no node to split. */ - return 0; - } - - /* Find the node where we should begin the removal. */ - for (n = f->range_head; n; n = n->range_next) { - if (n->data_offset + n->data_size > offset) { - break; - } - } - if (!n) { - /* If there's no data in the file there's no data to - remove either. */ - return 0; - } - - if (n->data_offset > offset) { - /* XXX: Not implemented yet. */ - printk(KERN_WARNING "JFFS: An unexpected situation " - "occurred in jffs_delete_data.\n"); - } - else if (n->data_offset < offset) { - /* See if the node has to be split into two parts. */ - if (n->data_offset + n->data_size > offset + remove_size) { - /* Do the split. */ - struct jffs_node *new_node; - D3(printk("jffs_delete_data(): Split node with " - "version number %u.\n", n->version)); - - if (!(new_node = jffs_alloc_node())) { - D(printk("jffs_delete_data(): -ENOMEM\n")); - return -ENOMEM; - } - DJM(no_jffs_node++); - - new_node->ino = n->ino; - new_node->version = n->version; - new_node->data_offset = offset; - new_node->data_size = n->data_size - (remove_size + (offset - n->data_offset)); - new_node->fm_offset = n->fm_offset + (remove_size + (offset - n->data_offset)); - new_node->name_size = n->name_size; - new_node->fm = n->fm; - new_node->version_prev = n; - new_node->version_next = n->version_next; - if (new_node->version_next) { - new_node->version_next->version_prev - = new_node; - } - else { - f->version_tail = new_node; - } - n->version_next = new_node; - new_node->range_prev = n; - new_node->range_next = n->range_next; - if (new_node->range_next) { - new_node->range_next->range_prev = new_node; - } - else { - f->range_tail = new_node; - } - /* A very interesting can of worms. */ - n->range_next = new_node; - n->data_size = offset - n->data_offset; - if (new_node->fm) - jffs_add_node(new_node); - else { - D1(printk(KERN_WARNING "jffs_delete_data(): Splitting an empty node (file hold).\n!")); - D1(printk(KERN_WARNING "FIXME: Did dwmw2 do the right thing here?\n")); - } - n = new_node->range_next; - remove_size = 0; - } - else { - /* No. No need to split the node. Just remove - the end of the node. */ - int r = min(n->data_offset + n->data_size - - offset, remove_size); - n->data_size -= r; - remove_size -= r; - n = n->range_next; - } - } - - /* Remove as many nodes as necessary. */ - while (n && remove_size) { - if (n->data_size <= remove_size) { - struct jffs_node *p = n; - remove_size -= n->data_size; - n = n->range_next; - D3(printk("jffs_delete_data(): Removing node: " - "ino: %u, version: %u%s\n", - p->ino, p->version, - (p->fm ? "" : " (virtual)"))); - if (p->fm) { - jffs_fmfree(f->c->fmc, p->fm, p); - } - jffs_unlink_node_from_range_list(f, p); - jffs_unlink_node_from_version_list(f, p); - jffs_free_node(p); - DJM(no_jffs_node--); - } - else { - n->data_size -= remove_size; - n->fm_offset += remove_size; - n->data_offset -= (node->removed_size - remove_size); - n = n->range_next; - break; - } - } - - /* Adjust the following nodes' information about offsets etc. */ - while (n && node->removed_size) { - n->data_offset -= node->removed_size; - n = n->range_next; - } - - if (node->removed_size > (f->size - node->data_offset)) { - /* It's possible that the removed_size is in fact - * greater than the amount of data we actually thought - * were present in the first place - some of the nodes - * which this node originally obsoleted may already have - * been deleted from the flash by subsequent garbage - * collection. - * - * If this is the case, don't let f->size go negative. - * Bad things would happen :) - */ - f->size = node->data_offset; - } else { - f->size -= node->removed_size; - } - D3(printk("jffs_delete_data(): f->size = %d\n", f->size)); - return 0; -} /* jffs_delete_data() */ - - -/* Insert some data into a file. Prior to the call to this function, - jffs_delete_data should be called. */ -static int -jffs_insert_data(struct jffs_file *f, struct jffs_node *node) -{ - D3(printk("jffs_insert_data(): node->data_offset = %u, " - "node->data_size = %u, f->size = %u\n", - node->data_offset, node->data_size, f->size)); - - /* Find the position where we should insert data. */ - retry: - if (node->data_offset == f->size) { - /* A simple append. This is the most common operation. */ - node->range_next = NULL; - node->range_prev = f->range_tail; - if (node->range_prev) { - node->range_prev->range_next = node; - } - f->range_tail = node; - f->size += node->data_size; - if (!f->range_head) { - f->range_head = node; - } - } - else if (node->data_offset < f->size) { - /* Trying to insert data into the middle of the file. This - means no problem because jffs_delete_data() has already - prepared the range list for us. */ - struct jffs_node *n; - - /* Find the correct place for the insertion and then insert - the node. */ - for (n = f->range_head; n; n = n->range_next) { - D2(printk("Cool stuff's happening!\n")); - - if (n->data_offset == node->data_offset) { - node->range_prev = n->range_prev; - if (node->range_prev) { - node->range_prev->range_next = node; - } - else { - f->range_head = node; - } - node->range_next = n; - n->range_prev = node; - break; - } - ASSERT(else if (n->data_offset + n->data_size > - node->data_offset) { - printk(KERN_ERR "jffs_insert_data(): " - "Couldn't find a place to insert " - "the data!\n"); - return -1; - }); - } - - /* Adjust later nodes' offsets etc. */ - n = node->range_next; - while (n) { - n->data_offset += node->data_size; - n = n->range_next; - } - f->size += node->data_size; - } - else if (node->data_offset > f->size) { - /* Okay. This is tricky. This means that we want to insert - data at a place that is beyond the limits of the file as - it is constructed right now. This is actually a common - event that for instance could occur during the mounting - of the file system if a large file have been truncated, - rewritten and then only partially garbage collected. */ - - struct jffs_node *n; - - /* We need a place holder for the data that is missing in - front of this insertion. This "virtual node" will not - be associated with any space on the flash device. */ - struct jffs_node *virtual_node; - if (!(virtual_node = jffs_alloc_node())) { - return -ENOMEM; - } - - D(printk("jffs_insert_data: Inserting a virtual node.\n")); - D(printk(" node->data_offset = %u\n", node->data_offset)); - D(printk(" f->size = %u\n", f->size)); - - virtual_node->ino = node->ino; - virtual_node->version = node->version; - virtual_node->removed_size = 0; - virtual_node->fm_offset = 0; - virtual_node->name_size = 0; - virtual_node->fm = NULL; /* This is a virtual data holder. */ - virtual_node->version_prev = NULL; - virtual_node->version_next = NULL; - virtual_node->range_next = NULL; - - /* Are there any data at all in the file yet? */ - if (f->range_head) { - virtual_node->data_offset - = f->range_tail->data_offset - + f->range_tail->data_size; - virtual_node->data_size - = node->data_offset - virtual_node->data_offset; - virtual_node->range_prev = f->range_tail; - f->range_tail->range_next = virtual_node; - } - else { - virtual_node->data_offset = 0; - virtual_node->data_size = node->data_offset; - virtual_node->range_prev = NULL; - f->range_head = virtual_node; - } - - f->range_tail = virtual_node; - f->size += virtual_node->data_size; - - /* Insert this virtual node in the version list as well. */ - for (n = f->version_head; n ; n = n->version_next) { - if (n->version == virtual_node->version) { - virtual_node->version_prev = n->version_prev; - n->version_prev = virtual_node; - if (virtual_node->version_prev) { - virtual_node->version_prev - ->version_next = virtual_node; - } - else { - f->version_head = virtual_node; - } - virtual_node->version_next = n; - break; - } - } - - D(jffs_print_node(virtual_node)); - - /* Make a new try to insert the node. */ - goto retry; - } - - D3(printk("jffs_insert_data(): f->size = %d\n", f->size)); - return 0; -} - - -/* A new node (with data) has been added to the file and now the range - list has to be modified. */ -static int -jffs_update_file(struct jffs_file *f, struct jffs_node *node) -{ - int err; - - D3(printk("jffs_update_file(): ino: %u, version: %u\n", - f->ino, node->version)); - - if (node->data_size == 0) { - if (node->removed_size == 0) { - /* data_offset == X */ - /* data_size == 0 */ - /* remove_size == 0 */ - } - else { - /* data_offset == X */ - /* data_size == 0 */ - /* remove_size != 0 */ - if ((err = jffs_delete_data(f, node)) < 0) { - return err; - } - } - } - else { - /* data_offset == X */ - /* data_size != 0 */ - /* remove_size == Y */ - if ((err = jffs_delete_data(f, node)) < 0) { - return err; - } - if ((err = jffs_insert_data(f, node)) < 0) { - return err; - } - } - return 0; -} - -/* Print the contents of a file. */ -#if 0 -int -jffs_print_file(struct jffs_file *f) -{ - D(int i); - D(printk("jffs_file: 0x%p\n", f)); - D(printk("{\n")); - D(printk(" 0x%08x, /* ino */\n", f->ino)); - D(printk(" 0x%08x, /* pino */\n", f->pino)); - D(printk(" 0x%08x, /* mode */\n", f->mode)); - D(printk(" 0x%04x, /* uid */\n", f->uid)); - D(printk(" 0x%04x, /* gid */\n", f->gid)); - D(printk(" 0x%08x, /* atime */\n", f->atime)); - D(printk(" 0x%08x, /* mtime */\n", f->mtime)); - D(printk(" 0x%08x, /* ctime */\n", f->ctime)); - D(printk(" 0x%02x, /* nsize */\n", f->nsize)); - D(printk(" 0x%02x, /* nlink */\n", f->nlink)); - D(printk(" 0x%02x, /* deleted */\n", f->deleted)); - D(printk(" \"%s\", ", (f->name ? f->name : ""))); - D(for (i = strlen(f->name ? f->name : ""); i < 8; ++i) { - printk(" "); - }); - D(printk("/* name */\n")); - D(printk(" 0x%08x, /* size */\n", f->size)); - D(printk(" 0x%08x, /* highest_version */\n", - f->highest_version)); - D(printk(" 0x%p, /* c */\n", f->c)); - D(printk(" 0x%p, /* parent */\n", f->parent)); - D(printk(" 0x%p, /* children */\n", f->children)); - D(printk(" 0x%p, /* sibling_prev */\n", f->sibling_prev)); - D(printk(" 0x%p, /* sibling_next */\n", f->sibling_next)); - D(printk(" 0x%p, /* hash_prev */\n", f->hash.prev)); - D(printk(" 0x%p, /* hash_next */\n", f->hash.next)); - D(printk(" 0x%p, /* range_head */\n", f->range_head)); - D(printk(" 0x%p, /* range_tail */\n", f->range_tail)); - D(printk(" 0x%p, /* version_head */\n", f->version_head)); - D(printk(" 0x%p, /* version_tail */\n", f->version_tail)); - D(printk("}\n")); - return 0; -} -#endif /* 0 */ - -void -jffs_print_hash_table(struct jffs_control *c) -{ - int i; - - printk("JFFS: Dumping the file system's hash table...\n"); - for (i = 0; i < c->hash_len; i++) { - struct jffs_file *f; - list_for_each_entry(f, &c->hash[i], hash) { - printk("*** c->hash[%u]: \"%s\" " - "(ino: %u, pino: %u)\n", - i, (f->name ? f->name : ""), - f->ino, f->pino); - } - } -} - - -void -jffs_print_tree(struct jffs_file *first_file, int indent) -{ - struct jffs_file *f; - char *space; - int dir; - - if (!first_file) { - return; - } - - if (!(space = kmalloc(indent + 1, GFP_KERNEL))) { - printk("jffs_print_tree(): Out of memory!\n"); - return; - } - - memset(space, ' ', indent); - space[indent] = '\0'; - - for (f = first_file; f; f = f->sibling_next) { - dir = S_ISDIR(f->mode); - printk("%s%s%s (ino: %u, highest_version: %u, size: %u)\n", - space, (f->name ? f->name : ""), (dir ? "/" : ""), - f->ino, f->highest_version, f->size); - if (dir) { - jffs_print_tree(f->children, indent + 2); - } - } - - kfree(space); -} - - -#if defined(JFFS_MEMORY_DEBUG) && JFFS_MEMORY_DEBUG -void -jffs_print_memory_allocation_statistics(void) -{ - static long printout; - printk("________ Memory printout #%ld ________\n", ++printout); - printk("no_jffs_file = %ld\n", no_jffs_file); - printk("no_jffs_node = %ld\n", no_jffs_node); - printk("no_jffs_control = %ld\n", no_jffs_control); - printk("no_jffs_raw_inode = %ld\n", no_jffs_raw_inode); - printk("no_jffs_node_ref = %ld\n", no_jffs_node_ref); - printk("no_jffs_fm = %ld\n", no_jffs_fm); - printk("no_jffs_fmcontrol = %ld\n", no_jffs_fmcontrol); - printk("no_hash = %ld\n", no_hash); - printk("no_name = %ld\n", no_name); - printk("\n"); -} -#endif - - -/* Rewrite `size' bytes, and begin at `node'. */ -static int -jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, __u32 size) -{ - struct jffs_control *c = f->c; - struct jffs_fmcontrol *fmc = c->fmc; - struct jffs_raw_inode raw_inode; - struct jffs_node *new_node; - struct jffs_fm *fm; - __u32 pos; - __u32 pos_dchksum; - __u32 total_name_size; - __u32 total_data_size; - __u32 total_size; - int err; - - D1(printk("***jffs_rewrite_data(): node: %u, name: \"%s\", size: %u\n", - f->ino, (f->name ? f->name : "(null)"), size)); - - /* Create and initialize the new node. */ - if (!(new_node = jffs_alloc_node())) { - D(printk("jffs_rewrite_data(): " - "Failed to allocate node.\n")); - return -ENOMEM; - } - DJM(no_jffs_node++); - new_node->data_offset = node->data_offset; - new_node->removed_size = size; - total_name_size = JFFS_PAD(f->nsize); - total_data_size = JFFS_PAD(size); - total_size = sizeof(struct jffs_raw_inode) - + total_name_size + total_data_size; - new_node->fm_offset = sizeof(struct jffs_raw_inode) - + total_name_size; - -retry: - jffs_fm_write_lock(fmc); - err = 0; - - if ((err = jffs_fmalloc(fmc, total_size, new_node, &fm)) < 0) { - DJM(no_jffs_node--); - jffs_fm_write_unlock(fmc); - D(printk("jffs_rewrite_data(): Failed to allocate fm.\n")); - jffs_free_node(new_node); - return err; - } - else if (!fm->nodes) { - /* The jffs_fm struct that we got is not big enough. */ - /* This should never happen, because we deal with this case - in jffs_garbage_collect_next().*/ - printk(KERN_WARNING "jffs_rewrite_data(): Allocated node is too small (%d bytes of %d)\n", fm->size, total_size); - if ((err = jffs_write_dummy_node(c, fm)) < 0) { - D(printk("jffs_rewrite_data(): " - "jffs_write_dummy_node() Failed!\n")); - } else { - err = -ENOSPC; - } - DJM(no_jffs_fm--); - jffs_fm_write_unlock(fmc); - kfree(fm); - - return err; - } - new_node->fm = fm; - - /* Initialize the raw inode. */ - raw_inode.magic = JFFS_MAGIC_BITMASK; - raw_inode.ino = f->ino; - raw_inode.pino = f->pino; - raw_inode.version = f->highest_version + 1; - raw_inode.mode = f->mode; - raw_inode.uid = f->uid; - raw_inode.gid = f->gid; - raw_inode.atime = f->atime; - raw_inode.mtime = f->mtime; - raw_inode.ctime = f->ctime; - raw_inode.offset = node->data_offset; - raw_inode.dsize = size; - raw_inode.rsize = size; - raw_inode.nsize = f->nsize; - raw_inode.nlink = f->nlink; - raw_inode.spare = 0; - raw_inode.rename = 0; - raw_inode.deleted = f->deleted; - raw_inode.accurate = 0xff; - raw_inode.dchksum = 0; - raw_inode.nchksum = 0; - - pos = new_node->fm->offset; - pos_dchksum = pos +JFFS_RAW_INODE_DCHKSUM_OFFSET; - - D3(printk("jffs_rewrite_data(): Writing this raw inode " - "to pos 0x%ul.\n", pos)); - D3(jffs_print_raw_inode(&raw_inode)); - - if ((err = flash_safe_write(fmc->mtd, pos, - (u_char *) &raw_inode, - sizeof(struct jffs_raw_inode) - - sizeof(__u32) - - sizeof(__u16) - sizeof(__u16))) < 0) { - jffs_fmfree_partly(fmc, fm, - total_name_size + total_data_size); - jffs_fm_write_unlock(fmc); - printk(KERN_ERR "JFFS: jffs_rewrite_data: Write error during " - "rewrite. (raw inode)\n"); - printk(KERN_ERR "JFFS: jffs_rewrite_data: Now retrying " - "rewrite. (raw inode)\n"); - goto retry; - } - pos += sizeof(struct jffs_raw_inode); - - /* Write the name to the flash memory. */ - if (f->nsize) { - D3(printk("jffs_rewrite_data(): Writing name \"%s\" to " - "pos 0x%ul.\n", f->name, (unsigned int) pos)); - if ((err = flash_safe_write(fmc->mtd, pos, - (u_char *)f->name, - f->nsize)) < 0) { - jffs_fmfree_partly(fmc, fm, total_data_size); - jffs_fm_write_unlock(fmc); - printk(KERN_ERR "JFFS: jffs_rewrite_data: Write " - "error during rewrite. (name)\n"); - printk(KERN_ERR "JFFS: jffs_rewrite_data: Now retrying " - "rewrite. (name)\n"); - goto retry; - } - pos += total_name_size; - raw_inode.nchksum = jffs_checksum(f->name, f->nsize); - } - - /* Write the data. */ - if (size) { - int r; - unsigned char *page; - __u32 offset = node->data_offset; - - if (!(page = (unsigned char *)__get_free_page(GFP_KERNEL))) { - jffs_fmfree_partly(fmc, fm, 0); - return -1; - } - - while (size) { - __u32 s = min(size, (__u32)PAGE_SIZE); - if ((r = jffs_read_data(f, (char *)page, - offset, s)) < s) { - free_page((unsigned long)page); - jffs_fmfree_partly(fmc, fm, 0); - jffs_fm_write_unlock(fmc); - printk(KERN_ERR "JFFS: jffs_rewrite_data: " - "jffs_read_data() " - "failed! (r = %d)\n", r); - return -1; - } - if ((err = flash_safe_write(fmc->mtd, - pos, page, r)) < 0) { - free_page((unsigned long)page); - jffs_fmfree_partly(fmc, fm, 0); - jffs_fm_write_unlock(fmc); - printk(KERN_ERR "JFFS: jffs_rewrite_data: " - "Write error during rewrite. " - "(data)\n"); - goto retry; - } - pos += r; - size -= r; - offset += r; - raw_inode.dchksum += jffs_checksum(page, r); - } - - free_page((unsigned long)page); - } - - raw_inode.accurate = 0; - raw_inode.chksum = jffs_checksum(&raw_inode, - sizeof(struct jffs_raw_inode) - - sizeof(__u16)); - - /* Add the checksum. */ - if ((err - = flash_safe_write(fmc->mtd, pos_dchksum, - &((u_char *) - &raw_inode)[JFFS_RAW_INODE_DCHKSUM_OFFSET], - sizeof(__u32) + sizeof(__u16) - + sizeof(__u16))) < 0) { - jffs_fmfree_partly(fmc, fm, 0); - jffs_fm_write_unlock(fmc); - printk(KERN_ERR "JFFS: jffs_rewrite_data: Write error during " - "rewrite. (checksum)\n"); - goto retry; - } - - /* Now make the file system aware of the newly written node. */ - jffs_insert_node(c, f, &raw_inode, f->name, new_node); - jffs_fm_write_unlock(fmc); - - D3(printk("jffs_rewrite_data(): Leaving...\n")); - return 0; -} /* jffs_rewrite_data() */ - - -/* jffs_garbage_collect_next implements one step in the garbage collect - process and is often called multiple times at each occasion of a - garbage collect. */ - -static int -jffs_garbage_collect_next(struct jffs_control *c) -{ - struct jffs_fmcontrol *fmc = c->fmc; - struct jffs_node *node; - struct jffs_file *f; - int err = 0; - __u32 size; - __u32 data_size; - __u32 total_name_size; - __u32 extra_available; - __u32 space_needed; - __u32 free_chunk_size1 = jffs_free_size1(fmc); - D2(__u32 free_chunk_size2 = jffs_free_size2(fmc)); - - /* Get the oldest node in the flash. */ - node = jffs_get_oldest_node(fmc); - ASSERT(if (!node) { - printk(KERN_ERR "JFFS: jffs_garbage_collect_next: " - "No oldest node found!\n"); - err = -1; - goto jffs_garbage_collect_next_end; - - - }); - - /* Find its corresponding file too. */ - f = jffs_find_file(c, node->ino); - - if (!f) { - printk (KERN_ERR "JFFS: jffs_garbage_collect_next: " - "No file to garbage collect! " - "(ino = 0x%08x)\n", node->ino); - /* FIXME: Free the offending node and recover. */ - err = -1; - goto jffs_garbage_collect_next_end; - } - - /* We always write out the name. Theoretically, we don't need - to, but for now it's easier - because otherwise we'd have - to keep track of how many times the current name exists on - the flash and make sure it never reaches zero. - - The current approach means that would be possible to cause - the GC to end up eating its tail by writing lots of nodes - with no name for it to garbage-collect. Hence the change in - inode.c to write names with _every_ node. - - It sucks, but it _should_ work. - */ - total_name_size = JFFS_PAD(f->nsize); - - D1(printk("jffs_garbage_collect_next(): \"%s\", " - "ino: %u, version: %u, location 0x%x, dsize %u\n", - (f->name ? f->name : ""), node->ino, node->version, - node->fm->offset, node->data_size)); - - /* Compute how many data it's possible to rewrite at the moment. */ - data_size = f->size - node->data_offset; - - /* And from that, the total size of the chunk we want to write */ - size = sizeof(struct jffs_raw_inode) + total_name_size - + data_size + JFFS_GET_PAD_BYTES(data_size); - - /* If that's more than max_chunk_size, reduce it accordingly */ - if (size > fmc->max_chunk_size) { - size = fmc->max_chunk_size; - data_size = size - sizeof(struct jffs_raw_inode) - - total_name_size; - } - - /* If we're asking to take up more space than free_chunk_size1 - but we _could_ fit in it, shrink accordingly. - */ - if (size > free_chunk_size1) { - - if (free_chunk_size1 < - (sizeof(struct jffs_raw_inode) + total_name_size + BLOCK_SIZE)){ - /* The space left is too small to be of any - use really. */ - struct jffs_fm *dirty_fm - = jffs_fmalloced(fmc, - fmc->tail->offset + fmc->tail->size, - free_chunk_size1, NULL); - if (!dirty_fm) { - printk(KERN_ERR "JFFS: " - "jffs_garbage_collect_next: " - "Failed to allocate `dirty' " - "flash memory!\n"); - err = -1; - goto jffs_garbage_collect_next_end; - } - D1(printk("Dirtying end of flash - too small\n")); - jffs_write_dummy_node(c, dirty_fm); - err = 0; - goto jffs_garbage_collect_next_end; - } - D1(printk("Reducing size of new node from %d to %d to avoid " - " exceeding free_chunk_size1\n", - size, free_chunk_size1)); - - size = free_chunk_size1; - data_size = size - sizeof(struct jffs_raw_inode) - - total_name_size; - } - - - /* Calculate the amount of space needed to hold the nodes - which are remaining in the tail */ - space_needed = fmc->min_free_size - (node->fm->offset % fmc->sector_size); - - /* From that, calculate how much 'extra' space we can use to - increase the size of the node we're writing from the size - of the node we're obsoleting - */ - if (space_needed > fmc->free_size) { - /* If we've gone below min_free_size for some reason, - don't fuck up. This is why we have - min_free_size > sector_size. Whinge about it though, - just so I can convince myself my maths is right. - */ - D1(printk(KERN_WARNING "jffs_garbage_collect_next(): " - "space_needed %d exceeded free_size %d\n", - space_needed, fmc->free_size)); - extra_available = 0; - } else { - extra_available = fmc->free_size - space_needed; - } - - /* Check that we don't use up any more 'extra' space than - what's available */ - if (size > JFFS_PAD(node->data_size) + total_name_size + - sizeof(struct jffs_raw_inode) + extra_available) { - D1(printk("Reducing size of new node from %d to %ld to avoid " - "catching our tail\n", size, - (long) (JFFS_PAD(node->data_size) + JFFS_PAD(node->name_size) + - sizeof(struct jffs_raw_inode) + extra_available))); - D1(printk("space_needed = %d, extra_available = %d\n", - space_needed, extra_available)); - - size = JFFS_PAD(node->data_size) + total_name_size + - sizeof(struct jffs_raw_inode) + extra_available; - data_size = size - sizeof(struct jffs_raw_inode) - - total_name_size; - }; - - D2(printk(" total_name_size: %u\n", total_name_size)); - D2(printk(" data_size: %u\n", data_size)); - D2(printk(" size: %u\n", size)); - D2(printk(" f->nsize: %u\n", f->nsize)); - D2(printk(" f->size: %u\n", f->size)); - D2(printk(" node->data_offset: %u\n", node->data_offset)); - D2(printk(" free_chunk_size1: %u\n", free_chunk_size1)); - D2(printk(" free_chunk_size2: %u\n", free_chunk_size2)); - D2(printk(" node->fm->offset: 0x%08x\n", node->fm->offset)); - - if ((err = jffs_rewrite_data(f, node, data_size))) { - printk(KERN_WARNING "jffs_rewrite_data() failed: %d\n", err); - return err; - } - -jffs_garbage_collect_next_end: - D3(printk("jffs_garbage_collect_next: Leaving...\n")); - return err; -} /* jffs_garbage_collect_next */ - - -/* If an obsolete node is partly going to be erased due to garbage - collection, the part that isn't going to be erased must be filled - with zeroes so that the scan of the flash will work smoothly next - time. (The data in the file could for instance be a JFFS image - which could cause enormous confusion during a scan of the flash - device if we didn't do this.) - There are two phases in this procedure: First, the clearing of - the name and data parts of the node. Second, possibly also clearing - a part of the raw inode as well. If the box is power cycled during - the first phase, only the checksum of this node-to-be-cleared-at- - the-end will be wrong. If the box is power cycled during, or after, - the clearing of the raw inode, the information like the length of - the name and data parts are zeroed. The next time the box is - powered up, the scanning algorithm manages this faulty data too - because: - - - The checksum is invalid and thus the raw inode must be discarded - in any case. - - If the lengths of the data part or the name part are zeroed, the - scanning just continues after the raw inode. But after the inode - the scanning procedure just finds zeroes which is the same as - dirt. - - So, in the end, this could never fail. :-) Even if it does fail, - the scanning algorithm should manage that too. */ - -static int -jffs_clear_end_of_node(struct jffs_control *c, __u32 erase_size) -{ - struct jffs_fm *fm; - struct jffs_fmcontrol *fmc = c->fmc; - __u32 zero_offset; - __u32 zero_size; - __u32 zero_offset_data; - __u32 zero_size_data; - __u32 cutting_raw_inode = 0; - - if (!(fm = jffs_cut_node(fmc, erase_size))) { - D3(printk("jffs_clear_end_of_node(): fm == NULL\n")); - return 0; - } - - /* Where and how much shall we clear? */ - zero_offset = fmc->head->offset + erase_size; - zero_size = fm->offset + fm->size - zero_offset; - - /* Do we have to clear the raw_inode explicitly? */ - if (fm->size - zero_size < sizeof(struct jffs_raw_inode)) { - cutting_raw_inode = sizeof(struct jffs_raw_inode) - - (fm->size - zero_size); - } - - /* First, clear the name and data fields. */ - zero_offset_data = zero_offset + cutting_raw_inode; - zero_size_data = zero_size - cutting_raw_inode; - flash_safe_acquire(fmc->mtd); - flash_memset(fmc->mtd, zero_offset_data, 0, zero_size_data); - flash_safe_release(fmc->mtd); - - /* Should we clear a part of the raw inode? */ - if (cutting_raw_inode) { - /* I guess it is ok to clear the raw inode in this order. */ - flash_safe_acquire(fmc->mtd); - flash_memset(fmc->mtd, zero_offset, 0, - cutting_raw_inode); - flash_safe_release(fmc->mtd); - } - - return 0; -} /* jffs_clear_end_of_node() */ - -/* Try to erase as much as possible of the dirt in the flash memory. */ -static long -jffs_try_to_erase(struct jffs_control *c) -{ - struct jffs_fmcontrol *fmc = c->fmc; - long erase_size; - int err; - __u32 offset; - - D3(printk("jffs_try_to_erase()\n")); - - erase_size = jffs_erasable_size(fmc); - - D2(printk("jffs_try_to_erase(): erase_size = %ld\n", erase_size)); - - if (erase_size == 0) { - return 0; - } - else if (erase_size < 0) { - printk(KERN_ERR "JFFS: jffs_try_to_erase: " - "jffs_erasable_size returned %ld.\n", erase_size); - return erase_size; - } - - if ((err = jffs_clear_end_of_node(c, erase_size)) < 0) { - printk(KERN_ERR "JFFS: jffs_try_to_erase: " - "Clearing of node failed.\n"); - return err; - } - - offset = fmc->head->offset; - - /* Now, let's try to do the erase. */ - if ((err = flash_erase_region(fmc->mtd, - offset, erase_size)) < 0) { - printk(KERN_ERR "JFFS: Erase of flash failed. " - "offset = %u, erase_size = %ld\n", - offset, erase_size); - /* XXX: Here we should allocate this area as dirty - with jffs_fmalloced or something similar. Now - we just report the error. */ - return err; - } - -#if 0 - /* Check if the erased sectors really got erased. */ - { - __u32 pos; - __u32 end; - - pos = (__u32)flash_get_direct_pointer(to_kdev_t(c->sb->s_dev), offset); - end = pos + erase_size; - - D2(printk("JFFS: Checking erased sector(s)...\n")); - - flash_safe_acquire(fmc->mtd); - - for (; pos < end; pos += 4) { - if (*(__u32 *)pos != JFFS_EMPTY_BITMASK) { - printk("JFFS: Erase failed! pos = 0x%lx\n", - (long)pos); - jffs_hexdump(fmc->mtd, pos, - jffs_min(256, end - pos)); - err = -1; - break; - } - } - - flash_safe_release(fmc->mtd); - - if (!err) { - D2(printk("JFFS: Erase succeeded.\n")); - } - else { - /* XXX: Here we should allocate the memory - with jffs_fmalloced() in order to prevent - JFFS from using this area accidentally. */ - return err; - } - } -#endif - - /* Update the flash memory data structures. */ - jffs_sync_erase(fmc, erase_size); - - return erase_size; -} - - -/* There are different criteria that should trigger a garbage collect: - - 1. There is too much dirt in the memory. - 2. The free space is becoming small. - 3. There are many versions of a node. - - The garbage collect should always be done in a manner that guarantees - that future garbage collects cannot be locked. E.g. Rewritten chunks - should not be too large (span more than one sector in the flash memory - for exemple). Of course there is a limit on how intelligent this garbage - collection can be. */ - - -static int -jffs_garbage_collect_now(struct jffs_control *c) -{ - struct jffs_fmcontrol *fmc = c->fmc; - long erased = 0; - int result = 0; - D1(int i = 1); - D2(printk("***jffs_garbage_collect_now(): fmc->dirty_size = %u, fmc->free_size = 0x%x\n, fcs1=0x%x, fcs2=0x%x", - fmc->dirty_size, fmc->free_size, jffs_free_size1(fmc), jffs_free_size2(fmc))); - D2(jffs_print_fmcontrol(fmc)); - - // down(&fmc->gclock); - - /* If it is possible to garbage collect, do so. */ - - while (erased == 0) { - D1(printk("***jffs_garbage_collect_now(): round #%u, " - "fmc->dirty_size = %u\n", i++, fmc->dirty_size)); - D2(jffs_print_fmcontrol(fmc)); - - if ((erased = jffs_try_to_erase(c)) < 0) { - printk(KERN_WARNING "JFFS: Error in " - "garbage collector.\n"); - result = erased; - goto gc_end; - } - if (erased) - break; - - if (fmc->free_size == 0) { - /* Argh */ - printk(KERN_ERR "jffs_garbage_collect_now(): free_size == 0. This is BAD.\n"); - result = -ENOSPC; - break; - } - - if (fmc->dirty_size < fmc->sector_size) { - /* Actually, we _may_ have been able to free some, - * if there are many overlapping nodes which aren't - * actually marked dirty because they still have - * some valid data in each. - */ - result = -ENOSPC; - break; - } - - /* Let's dare to make a garbage collect. */ - if ((result = jffs_garbage_collect_next(c)) < 0) { - printk(KERN_ERR "JFFS: Something " - "has gone seriously wrong " - "with a garbage collect.\n"); - goto gc_end; - } - - D1(printk(" jffs_garbage_collect_now(): erased: %ld\n", erased)); - DJM(jffs_print_memory_allocation_statistics()); - } - -gc_end: - // up(&fmc->gclock); - - D3(printk(" jffs_garbage_collect_now(): Leaving...\n")); - D1(if (erased) { - printk("jffs_g_c_now(): erased = %ld\n", erased); - jffs_print_fmcontrol(fmc); - }); - - if (!erased && !result) - return -ENOSPC; - - return result; -} /* jffs_garbage_collect_now() */ - - -/* Determine if it is reasonable to start garbage collection. - We start a gc pass if either: - - The number of free bytes < MIN_FREE_BYTES && at least one - block is dirty, OR - - The number of dirty bytes > MAX_DIRTY_BYTES -*/ -static inline int thread_should_wake (struct jffs_control *c) -{ - D1(printk (KERN_NOTICE "thread_should_wake(): free=%d, dirty=%d, blocksize=%d.\n", - c->fmc->free_size, c->fmc->dirty_size, c->fmc->sector_size)); - - /* If there's not enough dirty space to free a block, there's no point. */ - if (c->fmc->dirty_size < c->fmc->sector_size) { - D2(printk(KERN_NOTICE "thread_should_wake(): Not waking. Insufficient dirty space\n")); - return 0; - } -#if 1 - /* If there is too much RAM used by the various structures, GC */ - if (jffs_get_node_inuse() > (c->fmc->used_size/c->fmc->max_chunk_size * 5 + jffs_get_file_count() * 2 + 50)) { - /* FIXME: Provide proof that this test can be satisfied. We - don't want a filesystem doing endless GC just because this - condition cannot ever be false. - */ - D2(printk(KERN_NOTICE "thread_should_wake(): Waking due to number of nodes\n")); - return 1; - } -#endif - /* If there are fewer free bytes than the threshold, GC */ - if (c->fmc->free_size < c->gc_minfree_threshold) { - D2(printk(KERN_NOTICE "thread_should_wake(): Waking due to insufficent free space\n")); - return 1; - } - /* If there are more dirty bytes than the threshold, GC */ - if (c->fmc->dirty_size > c->gc_maxdirty_threshold) { - D2(printk(KERN_NOTICE "thread_should_wake(): Waking due to excessive dirty space\n")); - return 1; - } - /* FIXME: What about the "There are many versions of a node" condition? */ - - return 0; -} - - -void jffs_garbage_collect_trigger(struct jffs_control *c) -{ - /* NOTE: We rely on the fact that we have the BKL here. - * Otherwise, the gc_task could go away between the check - * and the wake_up_process() - */ - if (c->gc_task && thread_should_wake(c)) - send_sig(SIGHUP, c->gc_task, 1); -} - - -/* Kernel threads take (void *) as arguments. Thus we pass - the jffs_control data as a (void *) and then cast it. */ -int -jffs_garbage_collect_thread(void *ptr) -{ - struct jffs_control *c = (struct jffs_control *) ptr; - struct jffs_fmcontrol *fmc = c->fmc; - long erased; - int result = 0; - D1(int i = 1); - - daemonize("jffs_gcd"); - - c->gc_task = current; - - lock_kernel(); - init_completion(&c->gc_thread_comp); /* barrier */ - spin_lock_irq(¤t->sighand->siglock); - siginitsetinv (¤t->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT)); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - D1(printk (KERN_NOTICE "jffs_garbage_collect_thread(): Starting infinite loop.\n")); - - for (;;) { - - /* See if we need to start gc. If we don't, go to sleep. - - Current implementation is a BAD THING(tm). If we try - to unmount the FS, the unmount operation will sleep waiting - for this thread to exit. We need to arrange to send it a - sig before the umount process sleeps. - */ - - if (!thread_should_wake(c)) - set_current_state (TASK_INTERRUPTIBLE); - - schedule(); /* Yes, we do this even if we want to go - on immediately - we're a low priority - background task. */ - - /* Put_super will send a SIGKILL and then wait on the sem. - */ - while (signal_pending(current)) { - siginfo_t info; - unsigned long signr = 0; - - if (try_to_freeze()) - continue; - - spin_lock_irq(¤t->sighand->siglock); - signr = dequeue_signal(current, ¤t->blocked, &info); - spin_unlock_irq(¤t->sighand->siglock); - - switch(signr) { - case SIGSTOP: - D1(printk("jffs_garbage_collect_thread(): SIGSTOP received.\n")); - set_current_state(TASK_STOPPED); - schedule(); - break; - - case SIGKILL: - D1(printk("jffs_garbage_collect_thread(): SIGKILL received.\n")); - c->gc_task = NULL; - complete_and_exit(&c->gc_thread_comp, 0); - } - } - - - D1(printk (KERN_NOTICE "jffs_garbage_collect_thread(): collecting.\n")); - - D3(printk (KERN_NOTICE "g_c_thread(): down biglock\n")); - mutex_lock(&fmc->biglock); - - D1(printk("***jffs_garbage_collect_thread(): round #%u, " - "fmc->dirty_size = %u\n", i++, fmc->dirty_size)); - D2(jffs_print_fmcontrol(fmc)); - - if ((erased = jffs_try_to_erase(c)) < 0) { - printk(KERN_WARNING "JFFS: Error in " - "garbage collector: %ld.\n", erased); - } - - if (erased) - goto gc_end; - - if (fmc->free_size == 0) { - /* Argh. Might as well commit suicide. */ - printk(KERN_ERR "jffs_garbage_collect_thread(): free_size == 0. This is BAD.\n"); - send_sig(SIGQUIT, c->gc_task, 1); - // panic() - goto gc_end; - } - - /* Let's dare to make a garbage collect. */ - if ((result = jffs_garbage_collect_next(c)) < 0) { - printk(KERN_ERR "JFFS: Something " - "has gone seriously wrong " - "with a garbage collect: %d\n", result); - } - - gc_end: - D3(printk (KERN_NOTICE "g_c_thread(): up biglock\n")); - mutex_unlock(&fmc->biglock); - } /* for (;;) */ -} /* jffs_garbage_collect_thread() */ diff --git a/fs/jffs/intrep.h b/fs/jffs/intrep.h deleted file mode 100644 index 5c7abe0e269..00000000000 --- a/fs/jffs/intrep.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * JFFS -- Journaling Flash File System, Linux implementation. - * - * Copyright (C) 1999, 2000 Axis Communications AB. - * - * Created by Finn Hakansson <finn@axis.com>. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * $Id: intrep.h,v 1.14 2001/09/23 23:28:37 dwmw2 Exp $ - * - */ - -#ifndef __LINUX_JFFS_INTREP_H__ -#define __LINUX_JFFS_INTREP_H__ -#include "jffs_fm.h" -struct jffs_node *jffs_alloc_node(void); -void jffs_free_node(struct jffs_node *n); -int jffs_get_node_inuse(void); - -void jffs_cleanup_control(struct jffs_control *c); -int jffs_build_fs(struct super_block *sb); - -int jffs_insert_node(struct jffs_control *c, struct jffs_file *f, - const struct jffs_raw_inode *raw_inode, - const char *name, struct jffs_node *node); -struct jffs_file *jffs_find_file(struct jffs_control *c, __u32 ino); -struct jffs_file *jffs_find_child(struct jffs_file *dir, const char *name, int len); - -void jffs_free_node(struct jffs_node *node); - -int jffs_foreach_file(struct jffs_control *c, int (*func)(struct jffs_file *)); -int jffs_possibly_delete_file(struct jffs_file *f); -int jffs_insert_file_into_tree(struct jffs_file *f); -int jffs_unlink_file_from_tree(struct jffs_file *f); -int jffs_file_count(struct jffs_file *f); - -int jffs_write_node(struct jffs_control *c, struct jffs_node *node, - struct jffs_raw_inode *raw_inode, - const char *name, const unsigned char *buf, - int recoverable, struct jffs_file *f); -int jffs_read_data(struct jffs_file *f, unsigned char *buf, __u32 read_offset, __u32 size); - -/* Garbage collection stuff. */ -int jffs_garbage_collect_thread(void *c); -void jffs_garbage_collect_trigger(struct jffs_control *c); - -/* For debugging purposes. */ -#if 0 -int jffs_print_file(struct jffs_file *f); -#endif /* 0 */ -void jffs_print_hash_table(struct jffs_control *c); -void jffs_print_tree(struct jffs_file *first_file, int indent); - -#endif /* __LINUX_JFFS_INTREP_H__ */ diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c deleted file mode 100644 index 5a95fbdd6fd..00000000000 --- a/fs/jffs/jffs_fm.c +++ /dev/null @@ -1,798 +0,0 @@ -/* - * JFFS -- Journaling Flash File System, Linux implementation. - * - * Copyright (C) 1999, 2000 Axis Communications AB. - * - * Created by Finn Hakansson <finn@axis.com>. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * $Id: jffs_fm.c,v 1.27 2001/09/20 12:29:47 dwmw2 Exp $ - * - * Ported to Linux 2.3.x and MTD: - * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB - * - */ -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/blkdev.h> -#include <linux/jffs.h> -#include "jffs_fm.h" -#include "intrep.h" - -#if defined(JFFS_MARK_OBSOLETE) && JFFS_MARK_OBSOLETE -static int jffs_mark_obsolete(struct jffs_fmcontrol *fmc, __u32 fm_offset); -#endif - -static struct jffs_fm *jffs_alloc_fm(void); -static void jffs_free_fm(struct jffs_fm *n); - -extern struct kmem_cache *fm_cache; -extern struct kmem_cache *node_cache; - -#if CONFIG_JFFS_FS_VERBOSE > 0 -void -jffs_print_fmcontrol(struct jffs_fmcontrol *fmc) -{ - D(printk("struct jffs_fmcontrol: 0x%p\n", fmc)); - D(printk("{\n")); - D(printk(" %u, /* flash_size */\n", fmc->flash_size)); - D(printk(" %u, /* used_size */\n", fmc->used_size)); - D(printk(" %u, /* dirty_size */\n", fmc->dirty_size)); - D(printk(" %u, /* free_size */\n", fmc->free_size)); - D(printk(" %u, /* sector_size */\n", fmc->sector_size)); - D(printk(" %u, /* min_free_size */\n", fmc->min_free_size)); - D(printk(" %u, /* max_chunk_size */\n", fmc->max_chunk_size)); - D(printk(" 0x%p, /* mtd */\n", fmc->mtd)); - D(printk(" 0x%p, /* head */ " - "(head->offset = 0x%08x)\n", - fmc->head, (fmc->head ? fmc->head->offset : 0))); - D(printk(" 0x%p, /* tail */ " - "(tail->offset + tail->size = 0x%08x)\n", - fmc->tail, - (fmc->tail ? fmc->tail->offset + fmc->tail->size : 0))); - D(printk(" 0x%p, /* head_extra */\n", fmc->head_extra)); - D(printk(" 0x%p, /* tail_extra */\n", fmc->tail_extra)); - D(printk("}\n")); -} -#endif /* CONFIG_JFFS_FS_VERBOSE > 0 */ - -#if CONFIG_JFFS_FS_VERBOSE > 2 -static void -jffs_print_fm(struct jffs_fm *fm) -{ - D(printk("struct jffs_fm: 0x%p\n", fm)); - D(printk("{\n")); - D(printk(" 0x%08x, /* offset */\n", fm->offset)); - D(printk(" %u, /* size */\n", fm->size)); - D(printk(" 0x%p, /* prev */\n", fm->prev)); - D(printk(" 0x%p, /* next */\n", fm->next)); - D(printk(" 0x%p, /* nodes */\n", fm->nodes)); - D(printk("}\n")); -} -#endif /* CONFIG_JFFS_FS_VERBOSE > 2 */ - -#if 0 -void -jffs_print_node_ref(struct jffs_node_ref *ref) -{ - D(printk("struct jffs_node_ref: 0x%p\n", ref)); - D(printk("{\n")); - D(printk(" 0x%p, /* node */\n", ref->node)); - D(printk(" 0x%p, /* next */\n", ref->next)); - D(printk("}\n")); -} -#endif /* 0 */ - -/* This function creates a new shiny flash memory control structure. */ -struct jffs_fmcontrol * -jffs_build_begin(struct jffs_control *c, int unit) -{ - struct jffs_fmcontrol *fmc; - struct mtd_info *mtd; - - D3(printk("jffs_build_begin()\n")); - fmc = kmalloc(sizeof(*fmc), GFP_KERNEL); - if (!fmc) { - D(printk("jffs_build_begin(): Allocation of " - "struct jffs_fmcontrol failed!\n")); - return (struct jffs_fmcontrol *)0; - } - DJM(no_jffs_fmcontrol++); - - mtd = get_mtd_device(NULL, unit); - - if (IS_ERR(mtd)) { - kfree(fmc); - DJM(no_jffs_fmcontrol--); - return NULL; - } - - /* Retrieve the size of the flash memory. */ - fmc->flash_size = mtd->size; - D3(printk(" fmc->flash_size = %d bytes\n", fmc->flash_size)); - - fmc->used_size = 0; - fmc->dirty_size = 0; - fmc->free_size = mtd->size; - fmc->sector_size = mtd->erasesize; - fmc->max_chunk_size = fmc->sector_size >> 1; - /* min_free_size: - 1 sector, obviously. - + 1 x max_chunk_size, for when a nodes overlaps the end of a sector - + 1 x max_chunk_size again, which ought to be enough to handle - the case where a rename causes a name to grow, and GC has - to write out larger nodes than the ones it's obsoleting. - We should fix it so it doesn't have to write the name - _every_ time. Later. - + another 2 sectors because people keep getting GC stuck and - we don't know why. This scares me - I want formal proof - of correctness of whatever number we put here. dwmw2. - */ - fmc->min_free_size = fmc->sector_size << 2; - fmc->mtd = mtd; - fmc->c = c; - fmc->head = NULL; - fmc->tail = NULL; - fmc->head_extra = NULL; - fmc->tail_extra = NULL; - mutex_init(&fmc->biglock); - return fmc; -} - - -/* When the flash memory scan has completed, this function should be called - before use of the control structure. */ -void -jffs_build_end(struct jffs_fmcontrol *fmc) -{ - D3(printk("jffs_build_end()\n")); - - if (!fmc->head) { - fmc->head = fmc->head_extra; - fmc->tail = fmc->tail_extra; - } - else if (fmc->head_extra) { - fmc->tail_extra->next = fmc->head; - fmc->head->prev = fmc->tail_extra; - fmc->head = fmc->head_extra; - } - fmc->head_extra = NULL; /* These two instructions should be omitted. */ - fmc->tail_extra = NULL; - D3(jffs_print_fmcontrol(fmc)); -} - - -/* Call this function when the file system is unmounted. This function - frees all memory used by this module. */ -void -jffs_cleanup_fmcontrol(struct jffs_fmcontrol *fmc) -{ - if (fmc) { - struct jffs_fm *next = fmc->head; - while (next) { - struct jffs_fm *cur = next; - next = next->next; - jffs_free_fm(cur); - } - put_mtd_device(fmc->mtd); - kfree(fmc); - DJM(no_jffs_fmcontrol--); - } -} - - -/* This function returns the size of the first chunk of free space on the - flash memory. This function will return something nonzero if the flash - memory contains any free space. */ -__u32 -jffs_free_size1(struct jffs_fmcontrol *fmc) -{ - __u32 head; - __u32 tail; - __u32 end = fmc->flash_size; - - if (!fmc->head) { - /* There is nothing on the flash. */ - return fmc->flash_size; - } - - /* Compute the beginning and ending of the contents of the flash. */ - head = fmc->head->offset; - tail = fmc->tail->offset + fmc->tail->size; - if (tail == end) { - tail = 0; - } - ASSERT(else if (tail > end) { - printk(KERN_WARNING "jffs_free_size1(): tail > end\n"); - tail = 0; - }); - - if (head <= tail) { - return end - tail; - } - else { - return head - tail; - } -} - -/* This function will return something nonzero in case there are two free - areas on the flash. Like this: - - +----------------+------------------+----------------+ - | FREE 1 | USED / DIRTY | FREE 2 | - +----------------+------------------+----------------+ - fmc->head -----^ - fmc->tail ------------------------^ - - The value returned, will be the size of the first empty area on the - flash, in this case marked "FREE 1". */ -__u32 -jffs_free_size2(struct jffs_fmcontrol *fmc) -{ - if (fmc->head) { - __u32 head = fmc->head->offset; - __u32 tail = fmc->tail->offset + fmc->tail->size; - if (tail == fmc->flash_size) { - tail = 0; - } - - if (tail >= head) { - return head; - } - } - return 0; -} - - -/* Allocate a chunk of flash memory. If there is enough space on the - device, a reference to the associated node is stored in the jffs_fm - struct. */ -int -jffs_fmalloc(struct jffs_fmcontrol *fmc, __u32 size, struct jffs_node *node, - struct jffs_fm **result) -{ - struct jffs_fm *fm; - __u32 free_chunk_size1; - __u32 free_chunk_size2; - - D2(printk("jffs_fmalloc(): fmc = 0x%p, size = %d, " - "node = 0x%p\n", fmc, size, node)); - - *result = NULL; - - if (!(fm = jffs_alloc_fm())) { - D(printk("jffs_fmalloc(): kmalloc() failed! (fm)\n")); - return -ENOMEM; - } - - free_chunk_size1 = jffs_free_size1(fmc); - free_chunk_size2 = jffs_free_size2(fmc); - if (free_chunk_size1 + free_chunk_size2 != fmc->free_size) { - printk(KERN_WARNING "Free size accounting screwed\n"); - printk(KERN_WARNING "free_chunk_size1 == 0x%x, free_chunk_size2 == 0x%x, fmc->free_size == 0x%x\n", free_chunk_size1, free_chunk_size2, fmc->free_size); - } - - D3(printk("jffs_fmalloc(): free_chunk_size1 = %u, " - "free_chunk_size2 = %u\n", - free_chunk_size1, free_chunk_size2)); - - if (size <= free_chunk_size1) { - if (!(fm->nodes = (struct jffs_node_ref *) - kmalloc(sizeof(struct jffs_node_ref), - GFP_KERNEL))) { - D(printk("jffs_fmalloc(): kmalloc() failed! " - "(node_ref)\n")); - jffs_free_fm(fm); - return -ENOMEM; - } - DJM(no_jffs_node_ref++); - fm->nodes->node = node; - fm->nodes->next = NULL; - if (fmc->tail) { - fm->offset = fmc->tail->offset + fmc->tail->size; - if (fm->offset == fmc->flash_size) { - fm->offset = 0; - } - ASSERT(else if (fm->offset > fmc->flash_size) { - printk(KERN_WARNING "jffs_fmalloc(): " - "offset > flash_end\n"); - fm->offset = 0; - }); - } - else { - /* There don't have to be files in the file - system yet. */ - fm->offset = 0; - } - fm->size = size; - fmc->free_size -= size; - fmc->used_size += size; - } - else if (size > free_chunk_size2) { - printk(KERN_WARNING "JFFS: Tried to allocate a too " - "large flash memory chunk. (size = %u)\n", size); - jffs_free_fm(fm); - return -ENOSPC; - } - else { - fm->offset = fmc->tail->offset + fmc->tail->size; - fm->size = free_chunk_size1; - fm->nodes = NULL; - fmc->free_size -= fm->size; - fmc->dirty_size += fm->size; /* Changed by simonk. This seemingly fixes a - bug that caused infinite garbage collection. - It previously set fmc->dirty_size to size (which is the - size of the requested chunk). - */ - } - - fm->next = NULL; - if (!fmc->head) { - fm->prev = NULL; - fmc->head = fm; - fmc->tail = fm; - } - else { - fm->prev = fmc->tail; - fmc->tail->next = fm; - fmc->tail = fm; - } - - D3(jffs_print_fmcontrol(fmc)); - D3(jffs_print_fm(fm)); - *result = fm; - return 0; -} - - -/* The on-flash space is not needed anymore by the passed node. Remove - the reference to the node from the node list. If the data chunk in - the flash memory isn't used by any more nodes anymore (fm->nodes == 0), - then mark that chunk as dirty. */ -int -jffs_fmfree(struct jffs_fmcontrol *fmc, struct jffs_fm *fm, struct jffs_node *node) -{ - struct jffs_node_ref *ref; - struct jffs_node_ref *prev; - ASSERT(int del = 0); - - D2(printk("jffs_fmfree(): node->ino = %u, node->version = %u\n", - node->ino, node->version)); - - ASSERT(if (!fmc || !fm || !fm->nodes) { - printk(KERN_ERR "jffs_fmfree(): fmc: 0x%p, fm: 0x%p, " - "fm->nodes: 0x%p\n", - fmc, fm, (fm ? fm->nodes : NULL)); - return -1; - }); - - /* Find the reference to the node that is going to be removed - and remove it. */ - for (ref = fm->nodes, prev = NULL; ref; ref = ref->next) { - if (ref->node == node) { - if (prev) { - prev->next = ref->next; - } - else { - fm->nodes = ref->next; - } - kfree(ref); - DJM(no_jffs_node_ref--); - ASSERT(del = 1); - break; - } - prev = ref; - } - - /* If the data chunk in the flash memory isn't used anymore - just mark it as obsolete. */ - if (!fm->nodes) { - /* No node uses this chunk so let's remove it. */ - fmc->used_size -= fm->size; - fmc->dirty_size += fm->size; -#if defined(JFFS_MARK_OBSOLETE) && JFFS_MARK_OBSOLETE - if (jffs_mark_obsolete(fmc, fm->offset) < 0) { - D1(printk("jffs_fmfree(): Failed to mark an on-flash " - "node obsolete!\n")); - return -1; - } -#endif - } - - ASSERT(if (!del) { - printk(KERN_WARNING "***jffs_fmfree(): " - "Didn't delete any node reference!\n"); - }); - - return 0; -} - - -/* This allocation function is used during the initialization of - the file system. */ -struct jffs_fm * -jffs_fmalloced(struct jffs_fmcontrol *fmc, __u32 offset, __u32 size, - struct jffs_node *node) -{ - struct jffs_fm *fm; - - D3(printk("jffs_fmalloced()\n")); - - if (!(fm = jffs_alloc_fm())) { - D(printk("jffs_fmalloced(0x%p, %u, %u, 0x%p): failed!\n", - fmc, offset, size, node)); - return NULL; - } - fm->offset = offset; - fm->size = size; - fm->prev = NULL; - fm->next = NULL; - fm->nodes = NULL; - if (node) { - /* `node' exists and it should be associated with the - jffs_fm structure `fm'. */ - if (!(fm->nodes = (struct jffs_node_ref *) - kmalloc(sizeof(struct jffs_node_ref), - GFP_KERNEL))) { - D(printk("jffs_fmalloced(): !fm->nodes\n")); - jffs_free_fm(fm); - return NULL; - } - DJM(no_jffs_node_ref++); - fm->nodes->node = node; - fm->nodes->next = NULL; - fmc->used_size += size; - fmc->free_size -= size; - } - else { - /* If there is no node, then this is just a chunk of dirt. */ - fmc->dirty_size += size; - fmc->free_size -= size; - } - - if (fmc->head_extra) { - fm->prev = fmc->tail_extra; - fmc->tail_extra->next = fm; - fmc->tail_extra = fm; - } - else if (!fmc->head) { - fmc->head = fm; - fmc->tail = fm; - } - else if (fmc->tail->offset + fmc->tail->size < offset) { - fmc->head_extra = fm; - fmc->tail_extra = fm; - } - else { - fm->prev = fmc->tail; - fmc->tail->next = fm; - fmc->tail = fm; - } - D3(jffs_print_fmcontrol(fmc)); - D3(jffs_print_fm(fm)); - return fm; -} - - -/* Add a new node to an already existing jffs_fm struct. */ -int -jffs_add_node(struct jffs_node *node) -{ - struct jffs_node_ref *ref; - - D3(printk("jffs_add_node(): ino = %u\n", node->ino)); - - ref = kmalloc(sizeof(*ref), GFP_KERNEL); - if (!ref) - return -ENOMEM; - - DJM(no_jffs_node_ref++); - ref->node = node; - ref->next = node->fm->nodes; - node->fm->nodes = ref; - return 0; -} - - -/* Free a part of some allocated space. */ -void -jffs_fmfree_partly(struct jffs_fmcontrol *fmc, struct jffs_fm *fm, __u32 size) -{ - D1(printk("***jffs_fmfree_partly(): fm = 0x%p, fm->nodes = 0x%p, " - "fm->nodes->node->ino = %u, size = %u\n", - fm, (fm ? fm->nodes : 0), - (!fm ? 0 : (!fm->nodes ? 0 : fm->nodes->node->ino)), size)); - - if (fm->nodes) { - kfree(fm->nodes); - DJM(no_jffs_node_ref--); - fm->nodes = NULL; - } - fmc->used_size -= fm->size; - if (fm == fmc->tail) { - fm->size -= size; - fmc->free_size += size; - } - fmc->dirty_size += fm->size; -} - - -/* Find the jffs_fm struct that contains the end of the data chunk that - begins at the logical beginning of the flash memory and spans `size' - bytes. If we want to erase a sector of the flash memory, we use this - function to find where the sector limit cuts a chunk of data. */ -struct jffs_fm * -jffs_cut_node(struct jffs_fmcontrol *fmc, __u32 size) -{ - struct jffs_fm *fm; - __u32 pos = 0; - - if (size == 0) { - return NULL; - } - - ASSERT(if (!fmc) { - printk(KERN_ERR "jffs_cut_node(): fmc == NULL\n"); - return NULL; - }); - - fm = fmc->head; - - while (fm) { - pos += fm->size; - if (pos < size) { - fm = fm->next; - } - else if (pos > size) { - break; - } - else { - fm = NULL; - break; - } - } - - return fm; -} - - -/* Move the head of the fmc structures and delete the obsolete parts. */ -void -jffs_sync_erase(struct jffs_fmcontrol *fmc, int erased_size) -{ - struct jffs_fm *fm; - struct jffs_fm *del; - - ASSERT(if (!fmc) { - printk(KERN_ERR "jffs_sync_erase(): fmc == NULL\n"); - return; - }); - - fmc->dirty_size -= erased_size; - fmc->free_size += erased_size; - - for (fm = fmc->head; fm && (erased_size > 0);) { - if (erased_size >= fm->size) { - erased_size -= fm->size; - del = fm; - fm = fm->next; - fm->prev = NULL; - fmc->head = fm; - jffs_free_fm(del); - } - else { - fm->size -= erased_size; - fm->offset += erased_size; - break; - } - } -} - - -/* Return the oldest used node in the flash memory. */ -struct jffs_node * -jffs_get_oldest_node(struct jffs_fmcontrol *fmc) -{ - struct jffs_fm *fm; - struct jffs_node_ref *nref; - struct jffs_node *node = NULL; - - ASSERT(if (!fmc) { - printk(KERN_ERR "jffs_get_oldest_node(): fmc == NULL\n"); - return NULL; - }); - - for (fm = fmc->head; fm && !fm->nodes; fm = fm->next); - - if (!fm) { - return NULL; - } - - /* The oldest node is the last one in the reference list. This list - shouldn't be too long; just one or perhaps two elements. */ - for (nref = fm->nodes; nref; nref = nref->next) { - node = nref->node; - } - - D2(printk("jffs_get_oldest_node(): ino = %u, version = %u\n", - (node ? node->ino : 0), (node ? node->version : 0))); - - return node; -} - - -#if defined(JFFS_MARK_OBSOLETE) && JFFS_MARK_OBSOLETE - -/* Mark an on-flash node as obsolete. - - Note that this is just an optimization that isn't necessary for the - filesystem to work. */ - -static int -jffs_mark_obsolete(struct jffs_fmcontrol *fmc, __u32 fm_offset) -{ - /* The `accurate_pos' holds the position of the accurate byte - in the jffs_raw_inode structure that we are going to mark - as obsolete. */ - __u32 accurate_pos = fm_offset + JFFS_RAW_INODE_ACCURATE_OFFSET; - unsigned char zero = 0x00; - size_t len; - - D3(printk("jffs_mark_obsolete(): accurate_pos = %u\n", accurate_pos)); - ASSERT(if (!fmc) { - printk(KERN_ERR "jffs_mark_obsolete(): fmc == NULL\n"); - return -1; - }); - - /* Write 0x00 to the raw inode's accurate member. Don't care - about the return value. */ - MTD_WRITE(fmc->mtd, accurate_pos, 1, &len, &zero); - return 0; -} - -#endif /* JFFS_MARK_OBSOLETE */ - -/* check if it's possible to erase the wanted range, and if not, return - * the range that IS erasable, or a negative error code. - */ -static long -jffs_flash_erasable_size(struct mtd_info *mtd, __u32 offset, __u32 size) -{ - u_long ssize; - - /* assume that sector size for a partition is constant even - * if it spans more than one chip (you usually put the same - * type of chips in a system) - */ - - ssize = mtd->erasesize; - - if (offset % ssize) { - printk(KERN_WARNING "jffs_flash_erasable_size() given non-aligned offset %x (erasesize %lx)\n", offset, ssize); - /* The offset is not sector size aligned. */ - return -1; - } - else if (offset > mtd->size) { - printk(KERN_WARNING "jffs_flash_erasable_size given offset off the end of device (%x > %x)\n", offset, mtd->size); - return -2; - } - else if (offset + size > mtd->size) { - printk(KERN_WARNING "jffs_flash_erasable_size() given length which runs off the end of device (ofs %x + len %x = %x, > %x)\n", offset,size, offset+size, mtd->size); - return -3; - } - - return (size / ssize) * ssize; -} - - -/* How much dirty flash memory is possible to erase at the moment? */ -long -jffs_erasable_size(struct jffs_fmcontrol *fmc) -{ - struct jffs_fm *fm; - __u32 size = 0; - long ret; - - ASSERT(if (!fmc) { - printk(KERN_ERR "jffs_erasable_size(): fmc = NULL\n"); - return -1; - }); - - if (!fmc->head) { - /* The flash memory is totally empty. No nodes. No dirt. - Just return. */ - return 0; - } - - /* Calculate how much space that is dirty. */ - for (fm = fmc->head; fm && !fm->nodes; fm = fm->next) { - if (size && fm->offset == 0) { - /* We have reached the beginning of the flash. */ - break; - } - size += fm->size; - } - - /* Someone's signature contained this: - There's a fine line between fishing and just standing on - the shore like an idiot... */ - ret = jffs_flash_erasable_size(fmc->mtd, fmc->head->offset, size); - - ASSERT(if (ret < 0) { - printk("jffs_erasable_size: flash_erasable_size() " - "returned something less than zero (%ld).\n", ret); - printk("jffs_erasable_size: offset = 0x%08x\n", - fmc->head->offset); - }); - - /* If there is dirt on the flash (which is the reason to why - this function was called in the first place) but no space is - possible to erase right now, the initial part of the list of - jffs_fm structs, that hold place for dirty space, could perhaps - be shortened. The list's initial "dirty" elements are merged - into just one large dirty jffs_fm struct. This operation must - only be performed if nothing is possible to erase. Otherwise, - jffs_clear_end_of_node() won't work as expected. */ - if (ret == 0) { - struct jffs_fm *head = fmc->head; - struct jffs_fm *del; - /* While there are two dirty nodes beside each other.*/ - while (head->nodes == 0 - && head->next - && head->next->nodes == 0) { - del = head->next; - head->size += del->size; - head->next = del->next; - if (del->next) { - del->next->prev = head; - } - jffs_free_fm(del); - } - } - - return (ret >= 0 ? ret : 0); -} - -static struct jffs_fm *jffs_alloc_fm(void) -{ - struct jffs_fm *fm; - - fm = kmem_cache_alloc(fm_cache,GFP_KERNEL); - DJM(if (fm) no_jffs_fm++;); - - return fm; -} - -static void jffs_free_fm(struct jffs_fm *n) -{ - kmem_cache_free(fm_cache,n); - DJM(no_jffs_fm--); -} - - - -struct jffs_node *jffs_alloc_node(void) -{ - struct jffs_node *n; - - n = (struct jffs_node *)kmem_cache_alloc(node_cache,GFP_KERNEL); - if(n != NULL) - no_jffs_node++; - return n; -} - -void jffs_free_node(struct jffs_node *n) -{ - kmem_cache_free(node_cache,n); - no_jffs_node--; -} - - -int jffs_get_node_inuse(void) -{ - return no_jffs_node; -} diff --git a/fs/jffs/jffs_fm.h b/fs/jffs/jffs_fm.h deleted file mode 100644 index 9ee6ad29eff..00000000000 --- a/fs/jffs/jffs_fm.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * JFFS -- Journaling Flash File System, Linux implementation. - * - * Copyright (C) 1999, 2000 Axis Communications AB. - * - * Created by Finn Hakansson <finn@axis.com>. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * $Id: jffs_fm.h,v 1.13 2001/01/11 12:03:25 dwmw2 Exp $ - * - * Ported to Linux 2.3.x and MTD: - * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB - * - */ - -#ifndef __LINUX_JFFS_FM_H__ -#define __LINUX_JFFS_FM_H__ - -#include <linux/types.h> -#include <linux/jffs.h> -#include <linux/mtd/mtd.h> -#include <linux/mutex.h> - -/* The alignment between two nodes in the flash memory. */ -#define JFFS_ALIGN_SIZE 4 - -/* Mark the on-flash space as obsolete when appropriate. */ -#define JFFS_MARK_OBSOLETE 0 - -#ifndef CONFIG_JFFS_FS_VERBOSE -#define CONFIG_JFFS_FS_VERBOSE 1 -#endif - -#if CONFIG_JFFS_FS_VERBOSE > 0 -#define D(x) x -#define D1(x) D(x) -#else -#define D(x) -#define D1(x) -#endif - -#if CONFIG_JFFS_FS_VERBOSE > 1 -#define D2(x) D(x) -#else -#define D2(x) -#endif - -#if CONFIG_JFFS_FS_VERBOSE > 2 -#define D3(x) D(x) -#else -#define D3(x) -#endif - -#define ASSERT(x) x - -/* How many padding bytes should be inserted between two chunks of data - on the flash? */ -#define JFFS_GET_PAD_BYTES(size) ( (JFFS_ALIGN_SIZE-1) & -(__u32)(size) ) -#define JFFS_PAD(size) ( (size + (JFFS_ALIGN_SIZE-1)) & ~(JFFS_ALIGN_SIZE-1) ) - - - -struct jffs_node_ref -{ - struct jffs_node *node; - struct jffs_node_ref *next; -}; - - -/* The struct jffs_fm represents a chunk of data in the flash memory. */ -struct jffs_fm -{ - __u32 offset; - __u32 size; - struct jffs_fm *prev; - struct jffs_fm *next; - struct jffs_node_ref *nodes; /* USED if != 0. */ -}; - -struct jffs_fmcontrol -{ - __u32 flash_size; - __u32 used_size; - __u32 dirty_size; - __u32 free_size; - __u32 sector_size; - __u32 min_free_size; /* The minimum free space needed to be able - to perform garbage collections. */ - __u32 max_chunk_size; /* The maximum size of a chunk of data. */ - struct mtd_info *mtd; - struct jffs_control *c; - struct jffs_fm *head; - struct jffs_fm *tail; - struct jffs_fm *head_extra; - struct jffs_fm *tail_extra; - struct mutex biglock; -}; - -/* Notice the two members head_extra and tail_extra in the jffs_control - structure above. Those are only used during the scanning of the flash - memory; while the file system is being built. If the data in the flash - memory is organized like - - +----------------+------------------+----------------+ - | USED / DIRTY | FREE | USED / DIRTY | - +----------------+------------------+----------------+ - - then the scan is split in two parts. The first scanned part of the - flash memory is organized through the members head and tail. The - second scanned part is organized with head_extra and tail_extra. When - the scan is completed, the two lists are merged together. The jffs_fm - struct that head_extra references is the logical beginning of the - flash memory so it will be referenced by the head member. */ - - - -struct jffs_fmcontrol *jffs_build_begin(struct jffs_control *c, int unit); -void jffs_build_end(struct jffs_fmcontrol *fmc); -void jffs_cleanup_fmcontrol(struct jffs_fmcontrol *fmc); - -int jffs_fmalloc(struct jffs_fmcontrol *fmc, __u32 size, - struct jffs_node *node, struct jffs_fm **result); -int jffs_fmfree(struct jffs_fmcontrol *fmc, struct jffs_fm *fm, - struct jffs_node *node); - -__u32 jffs_free_size1(struct jffs_fmcontrol *fmc); -__u32 jffs_free_size2(struct jffs_fmcontrol *fmc); -void jffs_sync_erase(struct jffs_fmcontrol *fmc, int erased_size); -struct jffs_fm *jffs_cut_node(struct jffs_fmcontrol *fmc, __u32 size); -struct jffs_node *jffs_get_oldest_node(struct jffs_fmcontrol *fmc); -long jffs_erasable_size(struct jffs_fmcontrol *fmc); -struct jffs_fm *jffs_fmalloced(struct jffs_fmcontrol *fmc, __u32 offset, - __u32 size, struct jffs_node *node); -int jffs_add_node(struct jffs_node *node); -void jffs_fmfree_partly(struct jffs_fmcontrol *fmc, struct jffs_fm *fm, - __u32 size); - -#if CONFIG_JFFS_FS_VERBOSE > 0 -void jffs_print_fmcontrol(struct jffs_fmcontrol *fmc); -#endif -#if 0 -void jffs_print_node_ref(struct jffs_node_ref *ref); -#endif /* 0 */ - -#endif /* __LINUX_JFFS_FM_H__ */ diff --git a/fs/jffs/jffs_proc.c b/fs/jffs/jffs_proc.c deleted file mode 100644 index 9bdd99a557c..00000000000 --- a/fs/jffs/jffs_proc.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * JFFS -- Journaling Flash File System, Linux implementation. - * - * Copyright (C) 2000 Axis Communications AB. - * - * Created by Simon Kagstrom <simonk@axis.com>. - * - * $Id: jffs_proc.c,v 1.5 2001/06/02 14:34:55 dwmw2 Exp $ - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Overview: - * This file defines JFFS partition entries in the proc file system. - * - * TODO: - * Create some more proc files for different kinds of info, i.e. statistics - * about written and read bytes, number of calls to different routines, - * reports about failures. - */ - -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/jffs.h> -#include <linux/slab.h> -#include <linux/proc_fs.h> -#include <linux/time.h> -#include <linux/types.h> -#include "jffs_fm.h" -#include "jffs_proc.h" - -/* - * Structure for a JFFS partition in the system - */ -struct jffs_partition_dir { - struct jffs_control *c; - struct proc_dir_entry *part_root; - struct proc_dir_entry *part_info; - struct proc_dir_entry *part_layout; - struct jffs_partition_dir *next; -}; - -/* - * Structure for top-level entry in '/proc/fs' directory - */ -struct proc_dir_entry *jffs_proc_root; - -/* - * Linked list of 'jffs_partition_dirs' to help us track - * the mounted JFFS partitions in the system - */ -static struct jffs_partition_dir *jffs_part_dirs; - -/* - * Read functions for entries - */ -static int jffs_proc_info_read(char *page, char **start, off_t off, - int count, int *eof, void *data); -static int jffs_proc_layout_read (char *page, char **start, off_t off, - int count, int *eof, void *data); - - -/* - * Register a JFFS partition directory (called upon mount) - */ -int jffs_register_jffs_proc_dir(int mtd, struct jffs_control *c) -{ - struct jffs_partition_dir *part_dir; - struct proc_dir_entry *part_info = NULL; - struct proc_dir_entry *part_layout = NULL; - struct proc_dir_entry *part_root = NULL; - char name[10]; - - sprintf(name, "%d", mtd); - /* Allocate structure for local JFFS partition table */ - part_dir = (struct jffs_partition_dir *) - kmalloc(sizeof (struct jffs_partition_dir), GFP_KERNEL); - if (!part_dir) - goto out; - - /* Create entry for this partition */ - part_root = proc_mkdir(name, jffs_proc_root); - if (!part_root) - goto out1; - - /* Create entry for 'info' file */ - part_info = create_proc_entry ("info", 0, part_root); - if (!part_info) - goto out2; - part_info->read_proc = jffs_proc_info_read; - part_info->data = (void *) c; - - /* Create entry for 'layout' file */ - part_layout = create_proc_entry ("layout", 0, part_root); - if (!part_layout) - goto out3; - part_layout->read_proc = jffs_proc_layout_read; - part_layout->data = (void *) c; - - /* Fill in structure for table and insert in the list */ - part_dir->c = c; - part_dir->part_root = part_root; - part_dir->part_info = part_info; - part_dir->part_layout = part_layout; - part_dir->next = jffs_part_dirs; - jffs_part_dirs = part_dir; - - /* Return happy */ - return 0; - -out3: - remove_proc_entry("info", part_root); -out2: - remove_proc_entry(name, jffs_proc_root); -out1: - kfree(part_dir); -out: - return -ENOMEM; -} - - -/* - * Unregister a JFFS partition directory (called at umount) - */ -int jffs_unregister_jffs_proc_dir(struct jffs_control *c) -{ - struct jffs_partition_dir *part_dir = jffs_part_dirs; - struct jffs_partition_dir *prev_part_dir = NULL; - - while (part_dir) { - if (part_dir->c == c) { - /* Remove entries for partition */ - remove_proc_entry (part_dir->part_info->name, - part_dir->part_root); - remove_proc_entry (part_dir->part_layout->name, - part_dir->part_root); - remove_proc_entry (part_dir->part_root->name, - jffs_proc_root); - - /* Remove entry from list */ - if (prev_part_dir) - prev_part_dir->next = part_dir->next; - else - jffs_part_dirs = part_dir->next; - - /* - * Check to see if this is the last one - * and remove the entry from '/proc/fs' - * if it is. - */ - if (jffs_part_dirs == part_dir->next) - remove_proc_entry ("jffs", proc_root_fs); - - /* Free memory for entry */ - kfree(part_dir); - - /* Return happy */ - return 0; - } - - /* Move to next entry */ - prev_part_dir = part_dir; - part_dir = part_dir->next; - } - - /* Return unhappy */ - return -1; -} - - -/* - * Read a JFFS partition's `info' file - */ -static int jffs_proc_info_read (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct jffs_control *c = (struct jffs_control *) data; - int len = 0; - - /* Get information on the parition */ - len += sprintf (page, - "partition size: %08lX (%u)\n" - "sector size: %08lX (%u)\n" - "used size: %08lX (%u)\n" - "dirty size: %08lX (%u)\n" - "free size: %08lX (%u)\n\n", - (unsigned long) c->fmc->flash_size, c->fmc->flash_size, - (unsigned long) c->fmc->sector_size, c->fmc->sector_size, - (unsigned long) c->fmc->used_size, c->fmc->used_size, - (unsigned long) c->fmc->dirty_size, c->fmc->dirty_size, - (unsigned long) (c->fmc->flash_size - - (c->fmc->used_size + c->fmc->dirty_size)), - c->fmc->flash_size - (c->fmc->used_size + c->fmc->dirty_size)); - - /* We're done */ - *eof = 1; - - /* Return length */ - return len; -} - - -/* - * Read a JFFS partition's `layout' file - */ -static int jffs_proc_layout_read (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct jffs_control *c = (struct jffs_control *) data; - struct jffs_fm *fm = NULL; - struct jffs_fm *last_fm = NULL; - int len = 0; - - /* Get the first item in the list */ - fm = c->fmc->head; - - /* Print free space */ - if (fm && fm->offset) { - len += sprintf (page, "00000000 %08lX free\n", - (unsigned long) fm->offset); - } - - /* Loop through all of the flash control structures */ - while (fm && (len < (off + count))) { - if (fm->nodes) { - len += sprintf (page + len, - "%08lX %08lX ino=%08lX, ver=%08lX\n", - (unsigned long) fm->offset, - (unsigned long) fm->size, - (unsigned long) fm->nodes->node->ino, - (unsigned long) fm->nodes->node->version); - } - else { - len += sprintf (page + len, - "%08lX %08lX dirty\n", - (unsigned long) fm->offset, - (unsigned long) fm->size); - } - last_fm = fm; - fm = fm->next; - } - - /* Print free space */ - if ((len < (off + count)) && last_fm - && (last_fm->offset < c->fmc->flash_size)) { - len += sprintf (page + len, - "%08lX %08lX free\n", - (unsigned long) last_fm->offset + - last_fm->size, - (unsigned long) (c->fmc->flash_size - - (last_fm->offset + last_fm->size))); - } - - /* We're done */ - *eof = 1; - - /* Return length */ - return len; -} diff --git a/fs/jffs/jffs_proc.h b/fs/jffs/jffs_proc.h deleted file mode 100644 index 39a1c5d162b..00000000000 --- a/fs/jffs/jffs_proc.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * JFFS -- Journaling Flash File System, Linux implementation. - * - * Copyright (C) 2000 Axis Communications AB. - * - * Created by Simon Kagstrom <simonk@axis.com>. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * $Id: jffs_proc.h,v 1.2 2000/11/15 22:04:12 sjhill Exp $ - */ - -/* jffs_proc.h defines a structure for inclusion in the proc-file system. */ -#ifndef __LINUX_JFFS_PROC_H__ -#define __LINUX_JFFS_PROC_H__ - -#include <linux/proc_fs.h> - -/* The proc_dir_entry for jffs (defined in jffs_proc.c). */ -extern struct proc_dir_entry *jffs_proc_root; - -int jffs_register_jffs_proc_dir(int mtd, struct jffs_control *c); -int jffs_unregister_jffs_proc_dir(struct jffs_control *c); - -#endif /* __LINUX_JFFS_PROC_H__ */ diff --git a/fs/partitions/check.c b/fs/partitions/check.c index ac32a2e8540..22d38ffc9ef 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -358,8 +358,7 @@ void delete_partition(struct gendisk *disk, int part) p->ios[0] = p->ios[1] = 0; p->sectors[0] = p->sectors[1] = 0; sysfs_remove_link(&p->kobj, "subsystem"); - if (p->holder_dir) - kobject_unregister(p->holder_dir); + kobject_unregister(p->holder_dir); kobject_uevent(&p->kobj, KOBJ_REMOVE); kobject_del(&p->kobj); kobject_put(&p->kobj); @@ -603,10 +602,8 @@ void del_gendisk(struct gendisk *disk) disk->stamp = 0; kobject_uevent(&disk->kobj, KOBJ_REMOVE); - if (disk->holder_dir) - kobject_unregister(disk->holder_dir); - if (disk->slave_dir) - kobject_unregister(disk->slave_dir); + kobject_unregister(disk->holder_dir); + kobject_unregister(disk->slave_dir); if (disk->driverfs_dev) { char *disk_name = make_block_name(disk); sysfs_remove_link(&disk->kobj, "device"); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index c0e117649a4..98b0910ad80 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -54,7 +54,7 @@ static struct sysfs_ops subsys_sysfs_ops = { /** * add_to_collection - add buffer to a collection * @buffer: buffer to be added - * @node inode of set to add to + * @node: inode of set to add to */ static inline void diff --git a/include/acpi/acinterp.h b/include/acpi/acinterp.h index ce7c9d65391..73967c8152d 100644 --- a/include/acpi/acinterp.h +++ b/include/acpi/acinterp.h @@ -253,7 +253,8 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread); -void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc); +void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc, + struct acpi_thread_state *thread); /* * exprep - ACPI AML execution - prep utilities diff --git a/include/acpi/acobject.h b/include/acpi/acobject.h index 04e9735a674..5206d61d74a 100644 --- a/include/acpi/acobject.h +++ b/include/acpi/acobject.h @@ -155,7 +155,7 @@ struct acpi_object_event { struct acpi_object_mutex { ACPI_OBJECT_COMMON_HEADER u8 sync_level; /* 0-15, specified in Mutex() call */ u16 acquisition_depth; /* Allow multiple Acquires, same thread */ - struct acpi_thread_state *owner_thread; /* Current owner of the mutex */ + acpi_thread_id owner_thread_id; /* Current owner of the mutex */ acpi_mutex os_mutex; /* Actual OS synchronization object */ union acpi_operand_object *prev; /* Link for list of acquired mutexes */ union acpi_operand_object *next; /* Link for list of acquired mutexes */ diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 4dc8a5043ef..f6275b0e66d 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -105,12 +105,6 @@ int acpi_ec_ecdt_probe(void); int acpi_processor_set_thermal_limit(acpi_handle handle, int type); -/* -------------------------------------------------------------------------- - Hot Keys - -------------------------------------------------------------------------- */ - -extern int acpi_specific_hotkey_enabled; - /*-------------------------------------------------------------------------- Dock Station -------------------------------------------------------------------------- */ @@ -122,10 +116,34 @@ extern int register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler, void *context); extern void unregister_hotplug_dock_device(acpi_handle handle); #else -#define is_dock_device(h) (0) -#define register_dock_notifier(nb) (-ENODEV) -#define unregister_dock_notifier(nb) do { } while(0) -#define register_hotplug_dock_device(h1, h2, c) (-ENODEV) -#define unregister_hotplug_dock_device(h) do { } while(0) +static inline int is_dock_device(acpi_handle handle) +{ + return 0; +} +static inline int register_dock_notifier(struct notifier_block *nb) +{ + return -ENODEV; +} +static inline void unregister_dock_notifier(struct notifier_block *nb) +{ +} +static inline int register_hotplug_dock_device(acpi_handle handle, + acpi_notify_handler handler, void *context) +{ + return -ENODEV; +} +static inline void unregister_hotplug_dock_device(acpi_handle handle) +{ +} +#endif + +/*-------------------------------------------------------------------------- + Suspend/Resume + -------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_SLEEP +extern int acpi_sleep_init(void); +#else +#define acpi_sleep_init() do {} while (0) #endif + #endif /*__ACPI_DRIVERS_H__*/ diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 781394b9efe..2785058c82a 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -240,12 +240,6 @@ acpi_status acpi_os_validate_address(u8 space_id, acpi_physical_address address, acpi_size length); -u8 acpi_os_readable(void *pointer, acpi_size length); - -#ifdef ACPI_FUTURE_USAGE -u8 acpi_os_writable(void *pointer, acpi_size length); -#endif - u64 acpi_os_get_timer(void); acpi_status acpi_os_signal(u32 function, void *info); diff --git a/include/asm-arm/.gitignore b/include/asm-arm/.gitignore new file mode 100644 index 00000000000..e02c15d158f --- /dev/null +++ b/include/asm-arm/.gitignore @@ -0,0 +1,2 @@ +arch +mach-types.h diff --git a/include/asm-arm/arch-at91rm9200/at91_aic.h b/include/asm-arm/arch-at91/at91_aic.h index 267e69812e2..df44c12a12d 100644 --- a/include/asm-arm/arch-at91rm9200/at91_aic.h +++ b/include/asm-arm/arch-at91/at91_aic.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_aic.h + * include/asm-arm/arch-at91/at91_aic.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People diff --git a/include/asm-arm/arch-at91rm9200/at91_dbgu.h b/include/asm-arm/arch-at91/at91_dbgu.h index e4b8b27acfc..b0369e176f7 100644 --- a/include/asm-arm/arch-at91rm9200/at91_dbgu.h +++ b/include/asm-arm/arch-at91/at91_dbgu.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_dbgu.h + * include/asm-arm/arch-at91/at91_dbgu.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People @@ -35,6 +35,20 @@ #define AT91_CIDR_NVPSIZ (0xf << 8) /* Nonvolatile Program Memory Size */ #define AT91_CIDR_NVPSIZ2 (0xf << 12) /* Second Nonvolatile Program Memory Size */ #define AT91_CIDR_SRAMSIZ (0xf << 16) /* Internal SRAM Size */ +#define AT91_CIDR_SRAMSIZ_1K (1 << 16) +#define AT91_CIDR_SRAMSIZ_2K (2 << 16) +#define AT91_CIDR_SRAMSIZ_112K (4 << 16) +#define AT91_CIDR_SRAMSIZ_4K (5 << 16) +#define AT91_CIDR_SRAMSIZ_80K (6 << 16) +#define AT91_CIDR_SRAMSIZ_160K (7 << 16) +#define AT91_CIDR_SRAMSIZ_8K (8 << 16) +#define AT91_CIDR_SRAMSIZ_16K (9 << 16) +#define AT91_CIDR_SRAMSIZ_32K (10 << 16) +#define AT91_CIDR_SRAMSIZ_64K (11 << 16) +#define AT91_CIDR_SRAMSIZ_128K (12 << 16) +#define AT91_CIDR_SRAMSIZ_256K (13 << 16) +#define AT91_CIDR_SRAMSIZ_96K (14 << 16) +#define AT91_CIDR_SRAMSIZ_512K (15 << 16) #define AT91_CIDR_ARCH (0xff << 20) /* Architecture Identifier */ #define AT91_CIDR_NVPTYP (7 << 28) /* Nonvolatile Program Memory Type */ #define AT91_CIDR_EXT (1 << 31) /* Extension Flag */ diff --git a/include/asm-arm/arch-at91rm9200/at91_ecc.h b/include/asm-arm/arch-at91/at91_ecc.h index 5c564ede5c5..ff93df516d6 100644 --- a/include/asm-arm/arch-at91rm9200/at91_ecc.h +++ b/include/asm-arm/arch-at91/at91_ecc.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_ecc.h + * include/asm-arm/arch-at91/at91_ecc.h * * Error Corrected Code Controller (ECC) - System peripherals regsters. * Based on AT91SAM9260 datasheet revision B. diff --git a/include/asm-arm/arch-at91rm9200/at91_lcdc.h b/include/asm-arm/arch-at91/at91_lcdc.h index 9cbfcdd3c47..ab040a40d37 100644 --- a/include/asm-arm/arch-at91rm9200/at91_lcdc.h +++ b/include/asm-arm/arch-at91/at91_lcdc.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_lcdc.h + * include/asm-arm/arch-at91/at91_lcdc.h * * LCD Controller (LCDC). * Based on AT91SAM9261 datasheet revision E. diff --git a/include/asm-arm/arch-at91rm9200/at91_mci.h b/include/asm-arm/arch-at91/at91_mci.h index 9a552cb743c..40a9876b661 100644 --- a/include/asm-arm/arch-at91rm9200/at91_mci.h +++ b/include/asm-arm/arch-at91/at91_mci.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_mci.h + * include/asm-arm/arch-at91/at91_mci.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People diff --git a/include/asm-arm/arch-at91rm9200/at91_pio.h b/include/asm-arm/arch-at91/at91_pio.h index 680eaa1f591..84c3866d309 100644 --- a/include/asm-arm/arch-at91rm9200/at91_pio.h +++ b/include/asm-arm/arch-at91/at91_pio.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_pio.h + * include/asm-arm/arch-at91/at91_pio.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People diff --git a/include/asm-arm/arch-at91rm9200/at91_pit.h b/include/asm-arm/arch-at91/at91_pit.h index 4a30d009c58..5026325a5ae 100644 --- a/include/asm-arm/arch-at91rm9200/at91_pit.h +++ b/include/asm-arm/arch-at91/at91_pit.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_pit.h + * include/asm-arm/arch-at91/at91_pit.h * * Periodic Interval Timer (PIT) - System peripherals regsters. * Based on AT91SAM9261 datasheet revision D. diff --git a/include/asm-arm/arch-at91rm9200/at91_pmc.h b/include/asm-arm/arch-at91/at91_pmc.h index c3b489d09b6..33ff5b6798e 100644 --- a/include/asm-arm/arch-at91rm9200/at91_pmc.h +++ b/include/asm-arm/arch-at91/at91_pmc.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_pmc.h + * include/asm-arm/arch-at91/at91_pmc.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People diff --git a/include/asm-arm/arch-at91rm9200/at91_rstc.h b/include/asm-arm/arch-at91/at91_rstc.h index 237d3c40b31..fb8d1618a23 100644 --- a/include/asm-arm/arch-at91rm9200/at91_rstc.h +++ b/include/asm-arm/arch-at91/at91_rstc.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_rstc.h + * include/asm-arm/arch-at91/at91_rstc.h * * Reset Controller (RSTC) - System peripherals regsters. * Based on AT91SAM9261 datasheet revision D. @@ -17,7 +17,7 @@ #define AT91_RSTC_PROCRST (1 << 0) /* Processor Reset */ #define AT91_RSTC_PERRST (1 << 2) /* Peripheral Reset */ #define AT91_RSTC_EXTRST (1 << 3) /* External Reset */ -#define AT91_RSTC_KEY (0xff << 24) /* KEY Password */ +#define AT91_RSTC_KEY (0xa5 << 24) /* KEY Password */ #define AT91_RSTC_SR (AT91_RSTC + 0x04) /* Reset Controller Status Register */ #define AT91_RSTC_URSTS (1 << 0) /* User Reset Status */ @@ -34,6 +34,5 @@ #define AT91_RSTC_URSTEN (1 << 0) /* User Reset Enable */ #define AT91_RSTC_URSTIEN (1 << 4) /* User Reset Interrupt Enable */ #define AT91_RSTC_ERSTL (0xf << 8) /* External Reset Length */ -#define AT91_RSTC_KEY (0xff << 24) /* KEY Password */ #endif diff --git a/include/asm-arm/arch-at91rm9200/at91_rtc.h b/include/asm-arm/arch-at91/at91_rtc.h index 095fe088310..af9bd28174c 100644 --- a/include/asm-arm/arch-at91rm9200/at91_rtc.h +++ b/include/asm-arm/arch-at91/at91_rtc.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_rtc.h + * include/asm-arm/arch-at91/at91_rtc.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People diff --git a/include/asm-arm/arch-at91rm9200/at91_rtt.h b/include/asm-arm/arch-at91/at91_rtt.h index c6751ba3ccc..bae1103fbbb 100644 --- a/include/asm-arm/arch-at91rm9200/at91_rtt.h +++ b/include/asm-arm/arch-at91/at91_rtt.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_rtt.h + * include/asm-arm/arch-at91/at91_rtt.h * * Real-time Timer (RTT) - System peripherals regsters. * Based on AT91SAM9261 datasheet revision D. diff --git a/include/asm-arm/arch-at91rm9200/at91_shdwc.h b/include/asm-arm/arch-at91/at91_shdwc.h index 0439250553c..795fcc26622 100644 --- a/include/asm-arm/arch-at91rm9200/at91_shdwc.h +++ b/include/asm-arm/arch-at91/at91_shdwc.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_shdwc.h + * include/asm-arm/arch-at91/at91_shdwc.h * * Shutdown Controller (SHDWC) - System peripherals regsters. * Based on AT91SAM9261 datasheet revision D. diff --git a/include/asm-arm/arch-at91rm9200/at91_spi.h b/include/asm-arm/arch-at91/at91_spi.h index bec48ca89bb..f9b9a846499 100644 --- a/include/asm-arm/arch-at91rm9200/at91_spi.h +++ b/include/asm-arm/arch-at91/at91_spi.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_spi.h + * include/asm-arm/arch-at91/at91_spi.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People diff --git a/include/asm-arm/arch-at91rm9200/at91_ssc.h b/include/asm-arm/arch-at91/at91_ssc.h index 694bcaa8f7c..0ecc73460b5 100644 --- a/include/asm-arm/arch-at91rm9200/at91_ssc.h +++ b/include/asm-arm/arch-at91/at91_ssc.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_ssc.h + * include/asm-arm/arch-at91/at91_ssc.h * * Copyright (C) SAN People * diff --git a/include/asm-arm/arch-at91rm9200/at91_st.h b/include/asm-arm/arch-at91/at91_st.h index 2432ddfc6c4..30446e2ea77 100644 --- a/include/asm-arm/arch-at91rm9200/at91_st.h +++ b/include/asm-arm/arch-at91/at91_st.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_st.h + * include/asm-arm/arch-at91/at91_st.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People diff --git a/include/asm-arm/arch-at91rm9200/at91_tc.h b/include/asm-arm/arch-at91/at91_tc.h index 8d06eb078e1..b85d3faeef5 100644 --- a/include/asm-arm/arch-at91rm9200/at91_tc.h +++ b/include/asm-arm/arch-at91/at91_tc.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_tc.h + * include/asm-arm/arch-at91/at91_tc.h * * Copyright (C) SAN People * diff --git a/include/asm-arm/arch-at91rm9200/at91_twi.h b/include/asm-arm/arch-at91/at91_twi.h index cda914f1e74..ca9a9073345 100644 --- a/include/asm-arm/arch-at91rm9200/at91_twi.h +++ b/include/asm-arm/arch-at91/at91_twi.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_twi.h + * include/asm-arm/arch-at91/at91_twi.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People diff --git a/include/asm-arm/arch-at91rm9200/at91_wdt.h b/include/asm-arm/arch-at91/at91_wdt.h index ac63e775772..7251a344c74 100644 --- a/include/asm-arm/arch-at91rm9200/at91_wdt.h +++ b/include/asm-arm/arch-at91/at91_wdt.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91_wdt.h + * include/asm-arm/arch-at91/at91_wdt.h * * Watchdog Timer (WDT) - System peripherals regsters. * Based on AT91SAM9261 datasheet revision D. diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200.h b/include/asm-arm/arch-at91/at91rm9200.h index c569b6a21a4..a12ac8ab2ad 100644 --- a/include/asm-arm/arch-at91rm9200/at91rm9200.h +++ b/include/asm-arm/arch-at91/at91rm9200.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91rm9200.h + * include/asm-arm/arch-at91/at91rm9200.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_emac.h b/include/asm-arm/arch-at91/at91rm9200_emac.h index fbc091e61e2..0c417af5fe7 100644 --- a/include/asm-arm/arch-at91rm9200/at91rm9200_emac.h +++ b/include/asm-arm/arch-at91/at91rm9200_emac.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91rm9200_emac.h + * include/asm-arm/arch-at91/at91rm9200_emac.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_mc.h b/include/asm-arm/arch-at91/at91rm9200_mc.h index 0c0d81480b3..24d012939cc 100644 --- a/include/asm-arm/arch-at91rm9200/at91rm9200_mc.h +++ b/include/asm-arm/arch-at91/at91rm9200_mc.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91rm9200_mc.h + * include/asm-arm/arch-at91/at91rm9200_mc.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People diff --git a/include/asm-arm/arch-at91rm9200/at91sam9260.h b/include/asm-arm/arch-at91/at91sam9260.h index 46f4dd65c03..2cadebc36af 100644 --- a/include/asm-arm/arch-at91rm9200/at91sam9260.h +++ b/include/asm-arm/arch-at91/at91sam9260.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91sam9260.h + * include/asm-arm/arch-at91/at91sam9260.h * * (C) 2006 Andrew Victor * @@ -113,6 +113,10 @@ #define AT91SAM9260_UHP_BASE 0x00500000 /* USB Host controller */ +#define AT91SAM9XE_FLASH_BASE 0x00200000 /* Internal FLASH base address */ +#define AT91SAM9XE_SRAM_BASE 0x00300000 /* Internal SRAM base address */ + + #if 0 /* * PIO pin definitions (peripheral A/B multiplexing). diff --git a/include/asm-arm/arch-at91rm9200/at91sam9260_matrix.h b/include/asm-arm/arch-at91/at91sam9260_matrix.h index 78f6b4917b8..aacb1e97642 100644 --- a/include/asm-arm/arch-at91rm9200/at91sam9260_matrix.h +++ b/include/asm-arm/arch-at91/at91sam9260_matrix.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91sam9260_matrix.h + * include/asm-arm/arch-at91/at91sam9260_matrix.h * * Memory Controllers (MATRIX, EBI) - System peripherals registers. * Based on AT91SAM9260 datasheet revision B. @@ -18,7 +18,7 @@ #define AT91_MATRIX_MCFG2 (AT91_MATRIX + 0x08) /* Master Configuration Register 2 */ #define AT91_MATRIX_MCFG3 (AT91_MATRIX + 0x0C) /* Master Configuration Register 3 */ #define AT91_MATRIX_MCFG4 (AT91_MATRIX + 0x10) /* Master Configuration Register 4 */ -#define AT91_MATRIX_MCFG5 (AT91_MATRIX + 0x04) /* Master Configuration Register 5 */ +#define AT91_MATRIX_MCFG5 (AT91_MATRIX + 0x14) /* Master Configuration Register 5 */ #define AT91_MATRIX_ULBT (7 << 0) /* Undefined Length Burst Type */ #define AT91_MATRIX_ULBT_INFINITE (0 << 0) #define AT91_MATRIX_ULBT_SINGLE (1 << 0) diff --git a/include/asm-arm/arch-at91rm9200/at91sam9261.h b/include/asm-arm/arch-at91/at91sam9261.h index 8d39672d5b8..01b58ffe2e2 100644 --- a/include/asm-arm/arch-at91rm9200/at91sam9261.h +++ b/include/asm-arm/arch-at91/at91sam9261.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91sam9261.h + * include/asm-arm/arch-at91/at91sam9261.h * * Copyright (C) SAN People * diff --git a/include/asm-arm/arch-at91rm9200/at91sam9261_matrix.h b/include/asm-arm/arch-at91/at91sam9261_matrix.h index ec88efabbe6..6f072421be5 100644 --- a/include/asm-arm/arch-at91rm9200/at91sam9261_matrix.h +++ b/include/asm-arm/arch-at91/at91sam9261_matrix.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91sam9261_matrix.h + * include/asm-arm/arch-at91/at91sam9261_matrix.h * * Memory Controllers (MATRIX, EBI) - System peripherals registers. * Based on AT91SAM9261 datasheet revision D. diff --git a/include/asm-arm/arch-at91/at91sam9263.h b/include/asm-arm/arch-at91/at91sam9263.h new file mode 100644 index 00000000000..f4af68ae0ea --- /dev/null +++ b/include/asm-arm/arch-at91/at91sam9263.h @@ -0,0 +1,131 @@ +/* + * include/asm-arm/arch-at91/at91sam9263.h + * + * (C) 2007 Atmel Corporation. + * + * Common definitions. + * Based on AT91SAM9263 datasheet revision B (Preliminary). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef AT91SAM9263_H +#define AT91SAM9263_H + +/* + * Peripheral identifiers/interrupts. + */ +#define AT91_ID_FIQ 0 /* Advanced Interrupt Controller (FIQ) */ +#define AT91_ID_SYS 1 /* System Peripherals */ +#define AT91SAM9263_ID_PIOA 2 /* Parallel IO Controller A */ +#define AT91SAM9263_ID_PIOB 3 /* Parallel IO Controller B */ +#define AT91SAM9263_ID_PIOCDE 4 /* Parallel IO Controller C, D and E */ +#define AT91SAM9263_ID_US0 7 /* USART 0 */ +#define AT91SAM9263_ID_US1 8 /* USART 1 */ +#define AT91SAM9263_ID_US2 9 /* USART 2 */ +#define AT91SAM9263_ID_MCI0 10 /* Multimedia Card Interface 0 */ +#define AT91SAM9263_ID_MCI1 11 /* Multimedia Card Interface 1 */ +#define AT91SAM9263_ID_CAN 12 /* CAN */ +#define AT91SAM9263_ID_TWI 13 /* Two-Wire Interface */ +#define AT91SAM9263_ID_SPI0 14 /* Serial Peripheral Interface 0 */ +#define AT91SAM9263_ID_SPI1 15 /* Serial Peripheral Interface 1 */ +#define AT91SAM9263_ID_SSC0 16 /* Serial Synchronous Controller 0 */ +#define AT91SAM9263_ID_SSC1 17 /* Serial Synchronous Controller 1 */ +#define AT91SAM9263_ID_AC97C 18 /* AC97 Controller */ +#define AT91SAM9263_ID_TCB 19 /* Timer Counter 0, 1 and 2 */ +#define AT91SAM9263_ID_PWMC 20 /* Pulse Width Modulation Controller */ +#define AT91SAM9263_ID_EMAC 21 /* Ethernet */ +#define AT91SAM9263_ID_2DGE 23 /* 2D Graphic Engine */ +#define AT91SAM9263_ID_UDP 24 /* USB Device Port */ +#define AT91SAM9263_ID_ISI 25 /* Image Sensor Interface */ +#define AT91SAM9263_ID_LCDC 26 /* LCD Controller */ +#define AT91SAM9263_ID_DMA 27 /* DMA Controller */ +#define AT91SAM9263_ID_UHP 29 /* USB Host port */ +#define AT91SAM9263_ID_IRQ0 30 /* Advanced Interrupt Controller (IRQ0) */ +#define AT91SAM9263_ID_IRQ1 31 /* Advanced Interrupt Controller (IRQ1) */ + + +/* + * User Peripheral physical base addresses. + */ +#define AT91SAM9263_BASE_UDP 0xfff78000 +#define AT91SAM9263_BASE_TCB0 0xfff7c000 +#define AT91SAM9263_BASE_TC0 0xfff7c000 +#define AT91SAM9263_BASE_TC1 0xfff7c040 +#define AT91SAM9263_BASE_TC2 0xfff7c080 +#define AT91SAM9263_BASE_MCI0 0xfff80000 +#define AT91SAM9263_BASE_MCI1 0xfff84000 +#define AT91SAM9263_BASE_TWI 0xfff88000 +#define AT91SAM9263_BASE_US0 0xfff8c000 +#define AT91SAM9263_BASE_US1 0xfff90000 +#define AT91SAM9263_BASE_US2 0xfff94000 +#define AT91SAM9263_BASE_SSC0 0xfff98000 +#define AT91SAM9263_BASE_SSC1 0xfff9c000 +#define AT91SAM9263_BASE_AC97C 0xfffa0000 +#define AT91SAM9263_BASE_SPI0 0xfffa4000 +#define AT91SAM9263_BASE_SPI1 0xfffa8000 +#define AT91SAM9263_BASE_CAN 0xfffac000 +#define AT91SAM9263_BASE_PWMC 0xfffb8000 +#define AT91SAM9263_BASE_EMAC 0xfffbc000 +#define AT91SAM9263_BASE_ISI 0xfffc4000 +#define AT91SAM9263_BASE_2DGE 0xfffc8000 +#define AT91_BASE_SYS 0xffffe000 + +/* + * System Peripherals (offset from AT91_BASE_SYS) + */ +#define AT91_ECC0 (0xffffe000 - AT91_BASE_SYS) +#define AT91_SDRAMC0 (0xffffe200 - AT91_BASE_SYS) +#define AT91_SMC0 (0xffffe400 - AT91_BASE_SYS) +#define AT91_ECC1 (0xffffe600 - AT91_BASE_SYS) +#define AT91_SDRAMC1 (0xffffe800 - AT91_BASE_SYS) +#define AT91_SMC1 (0xffffea00 - AT91_BASE_SYS) +#define AT91_MATRIX (0xffffec00 - AT91_BASE_SYS) +#define AT91_CCFG (0xffffed10 - AT91_BASE_SYS) +#define AT91_DBGU (0xffffee00 - AT91_BASE_SYS) +#define AT91_AIC (0xfffff000 - AT91_BASE_SYS) +#define AT91_PIOA (0xfffff200 - AT91_BASE_SYS) +#define AT91_PIOB (0xfffff400 - AT91_BASE_SYS) +#define AT91_PIOC (0xfffff600 - AT91_BASE_SYS) +#define AT91_PIOD (0xfffff800 - AT91_BASE_SYS) +#define AT91_PIOE (0xfffffa00 - AT91_BASE_SYS) +#define AT91_PMC (0xfffffc00 - AT91_BASE_SYS) +#define AT91_RSTC (0xfffffd00 - AT91_BASE_SYS) +#define AT91_SHDWC (0xfffffd10 - AT91_BASE_SYS) +#define AT91_RTT0 (0xfffffd20 - AT91_BASE_SYS) +#define AT91_PIT (0xfffffd30 - AT91_BASE_SYS) +#define AT91_WDT (0xfffffd40 - AT91_BASE_SYS) +#define AT91_RTT1 (0xfffffd50 - AT91_BASE_SYS) +#define AT91_GPBR (0xfffffd60 - AT91_BASE_SYS) + +#define AT91_SMC AT91_SMC0 + +/* + * Internal Memory. + */ +#define AT91SAM9263_SRAM0_BASE 0x00300000 /* Internal SRAM 0 base address */ +#define AT91SAM9263_SRAM0_SIZE (80 * SZ_1K) /* Internal SRAM 0 size (80Kb) */ + +#define AT91SAM9263_ROM_BASE 0x00400000 /* Internal ROM base address */ +#define AT91SAM9263_ROM_SIZE SZ_128K /* Internal ROM size (128Kb) */ + +#define AT91SAM9263_SRAM1_BASE 0x00500000 /* Internal SRAM 1 base address */ +#define AT91SAM9263_SRAM1_SIZE SZ_16K /* Internal SRAM 1 size (16Kb) */ + +#define AT91SAM9263_LCDC_BASE 0x00700000 /* LCD Controller */ +#define AT91SAM9263_DMAC_BASE 0x00800000 /* DMA Controller */ +#define AT91SAM9263_UHP_BASE 0x00a00000 /* USB Host controller */ + +#if 0 +/* + * PIO pin definitions (peripheral A/B multiplexing). + */ + +// TODO: Add + +#endif + +#endif diff --git a/include/asm-arm/arch-at91/at91sam9263_matrix.h b/include/asm-arm/arch-at91/at91sam9263_matrix.h new file mode 100644 index 00000000000..6fc6e4be624 --- /dev/null +++ b/include/asm-arm/arch-at91/at91sam9263_matrix.h @@ -0,0 +1,129 @@ +/* + * include/asm-arm/arch-at91/at91sam9263_matrix.h + * + * Copyright (C) 2006 Atmel Corporation. + * + * Memory Controllers (MATRIX, EBI) - System peripherals registers. + * Based on AT91SAM9263 datasheet revision B (Preliminary). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef AT91SAM9263_MATRIX_H +#define AT91SAM9263_MATRIX_H + +#define AT91_MATRIX_MCFG0 (AT91_MATRIX + 0x00) /* Master Configuration Register 0 */ +#define AT91_MATRIX_MCFG1 (AT91_MATRIX + 0x04) /* Master Configuration Register 1 */ +#define AT91_MATRIX_MCFG2 (AT91_MATRIX + 0x08) /* Master Configuration Register 2 */ +#define AT91_MATRIX_MCFG3 (AT91_MATRIX + 0x0C) /* Master Configuration Register 3 */ +#define AT91_MATRIX_MCFG4 (AT91_MATRIX + 0x10) /* Master Configuration Register 4 */ +#define AT91_MATRIX_MCFG5 (AT91_MATRIX + 0x14) /* Master Configuration Register 5 */ +#define AT91_MATRIX_MCFG6 (AT91_MATRIX + 0x18) /* Master Configuration Register 6 */ +#define AT91_MATRIX_MCFG7 (AT91_MATRIX + 0x1C) /* Master Configuration Register 7 */ +#define AT91_MATRIX_MCFG8 (AT91_MATRIX + 0x20) /* Master Configuration Register 8 */ +#define AT91_MATRIX_ULBT (7 << 0) /* Undefined Length Burst Type */ +#define AT91_MATRIX_ULBT_INFINITE (0 << 0) +#define AT91_MATRIX_ULBT_SINGLE (1 << 0) +#define AT91_MATRIX_ULBT_FOUR (2 << 0) +#define AT91_MATRIX_ULBT_EIGHT (3 << 0) +#define AT91_MATRIX_ULBT_SIXTEEN (4 << 0) + +#define AT91_MATRIX_SCFG0 (AT91_MATRIX + 0x40) /* Slave Configuration Register 0 */ +#define AT91_MATRIX_SCFG1 (AT91_MATRIX + 0x44) /* Slave Configuration Register 1 */ +#define AT91_MATRIX_SCFG2 (AT91_MATRIX + 0x48) /* Slave Configuration Register 2 */ +#define AT91_MATRIX_SCFG3 (AT91_MATRIX + 0x4C) /* Slave Configuration Register 3 */ +#define AT91_MATRIX_SCFG4 (AT91_MATRIX + 0x50) /* Slave Configuration Register 4 */ +#define AT91_MATRIX_SCFG5 (AT91_MATRIX + 0x54) /* Slave Configuration Register 5 */ +#define AT91_MATRIX_SCFG6 (AT91_MATRIX + 0x58) /* Slave Configuration Register 6 */ +#define AT91_MATRIX_SCFG7 (AT91_MATRIX + 0x5C) /* Slave Configuration Register 7 */ +#define AT91_MATRIX_SLOT_CYCLE (0xff << 0) /* Maximum Number of Allowed Cycles for a Burst */ +#define AT91_MATRIX_DEFMSTR_TYPE (3 << 16) /* Default Master Type */ +#define AT91_MATRIX_DEFMSTR_TYPE_NONE (0 << 16) +#define AT91_MATRIX_DEFMSTR_TYPE_LAST (1 << 16) +#define AT91_MATRIX_DEFMSTR_TYPE_FIXED (2 << 16) +#define AT91_MATRIX_FIXED_DEFMSTR (7 << 18) /* Fixed Index of Default Master */ +#define AT91_MATRIX_ARBT (3 << 24) /* Arbitration Type */ +#define AT91_MATRIX_ARBT_ROUND_ROBIN (0 << 24) +#define AT91_MATRIX_ARBT_FIXED_PRIORITY (1 << 24) + +#define AT91_MATRIX_PRAS0 (AT91_MATRIX + 0x80) /* Priority Register A for Slave 0 */ +#define AT91_MATRIX_PRBS0 (AT91_MATRIX + 0x84) /* Priority Register B for Slave 0 */ +#define AT91_MATRIX_PRAS1 (AT91_MATRIX + 0x88) /* Priority Register A for Slave 1 */ +#define AT91_MATRIX_PRBS1 (AT91_MATRIX + 0x8C) /* Priority Register B for Slave 1 */ +#define AT91_MATRIX_PRAS2 (AT91_MATRIX + 0x90) /* Priority Register A for Slave 2 */ +#define AT91_MATRIX_PRBS2 (AT91_MATRIX + 0x94) /* Priority Register B for Slave 2 */ +#define AT91_MATRIX_PRAS3 (AT91_MATRIX + 0x98) /* Priority Register A for Slave 3 */ +#define AT91_MATRIX_PRBS3 (AT91_MATRIX + 0x9C) /* Priority Register B for Slave 3 */ +#define AT91_MATRIX_PRAS4 (AT91_MATRIX + 0xA0) /* Priority Register A for Slave 4 */ +#define AT91_MATRIX_PRBS4 (AT91_MATRIX + 0xA4) /* Priority Register B for Slave 4 */ +#define AT91_MATRIX_PRAS5 (AT91_MATRIX + 0xA8) /* Priority Register A for Slave 5 */ +#define AT91_MATRIX_PRBS5 (AT91_MATRIX + 0xAC) /* Priority Register B for Slave 5 */ +#define AT91_MATRIX_PRAS6 (AT91_MATRIX + 0xB0) /* Priority Register A for Slave 6 */ +#define AT91_MATRIX_PRBS6 (AT91_MATRIX + 0xB4) /* Priority Register B for Slave 6 */ +#define AT91_MATRIX_PRAS7 (AT91_MATRIX + 0xB8) /* Priority Register A for Slave 7 */ +#define AT91_MATRIX_PRBS7 (AT91_MATRIX + 0xBC) /* Priority Register B for Slave 7 */ +#define AT91_MATRIX_M0PR (3 << 0) /* Master 0 Priority */ +#define AT91_MATRIX_M1PR (3 << 4) /* Master 1 Priority */ +#define AT91_MATRIX_M2PR (3 << 8) /* Master 2 Priority */ +#define AT91_MATRIX_M3PR (3 << 12) /* Master 3 Priority */ +#define AT91_MATRIX_M4PR (3 << 16) /* Master 4 Priority */ +#define AT91_MATRIX_M5PR (3 << 20) /* Master 5 Priority */ +#define AT91_MATRIX_M6PR (3 << 24) /* Master 6 Priority */ +#define AT91_MATRIX_M7PR (3 << 28) /* Master 7 Priority */ +#define AT91_MATRIX_M8PR (3 << 0) /* Master 8 Priority (in Register B) */ + +#define AT91_MATRIX_MRCR (AT91_MATRIX + 0x100) /* Master Remap Control Register */ +#define AT91_MATRIX_RCB0 (1 << 0) /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */ +#define AT91_MATRIX_RCB1 (1 << 1) /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */ +#define AT91_MATRIX_RCB2 (1 << 2) +#define AT91_MATRIX_RCB3 (1 << 3) +#define AT91_MATRIX_RCB4 (1 << 4) +#define AT91_MATRIX_RCB5 (1 << 5) +#define AT91_MATRIX_RCB6 (1 << 6) +#define AT91_MATRIX_RCB7 (1 << 7) +#define AT91_MATRIX_RCB8 (1 << 8) + +#define AT91_MATRIX_TCMR (AT91_MATRIX + 0x114) /* TCM Configuration Register */ +#define AT91_MATRIX_ITCM_SIZE (0xf << 0) /* Size of ITCM enabled memory block */ +#define AT91_MATRIX_ITCM_0 (0 << 0) +#define AT91_MATRIX_ITCM_16 (5 << 0) +#define AT91_MATRIX_ITCM_32 (6 << 0) +#define AT91_MATRIX_DTCM_SIZE (0xf << 4) /* Size of DTCM enabled memory block */ +#define AT91_MATRIX_DTCM_0 (0 << 4) +#define AT91_MATRIX_DTCM_16 (5 << 4) +#define AT91_MATRIX_DTCM_32 (6 << 4) + +#define AT91_MATRIX_EBI0CSA (AT91_MATRIX + 0x120) /* EBI0 Chip Select Assignment Register */ +#define AT91_MATRIX_EBI0_CS1A (1 << 1) /* Chip Select 1 Assignment */ +#define AT91_MATRIX_EBI0_CS1A_SMC (0 << 1) +#define AT91_MATRIX_EBI0_CS1A_SDRAMC (1 << 1) +#define AT91_MATRIX_EBI0_CS3A (1 << 3) /* Chip Select 3 Assignment */ +#define AT91_MATRIX_EBI0_CS3A_SMC (0 << 3) +#define AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA (1 << 3) +#define AT91_MATRIX_EBI0_CS4A (1 << 4) /* Chip Select 4 Assignment */ +#define AT91_MATRIX_EBI0_CS4A_SMC (0 << 4) +#define AT91_MATRIX_EBI0_CS4A_SMC_CF1 (1 << 4) +#define AT91_MATRIX_EBI0_CS5A (1 << 5) /* Chip Select 5 Assignment */ +#define AT91_MATRIX_EBI0_CS5A_SMC (0 << 5) +#define AT91_MATRIX_EBI0_CS5A_SMC_CF2 (1 << 5) +#define AT91_MATRIX_EBI0_DBPUC (1 << 8) /* Data Bus Pull-up Configuration */ +#define AT91_MATRIX_EBI0_VDDIOMSEL (1 << 16) /* Memory voltage selection */ +#define AT91_MATRIX_EBI0_VDDIOMSEL_1_8V (0 << 16) +#define AT91_MATRIX_EBI0_VDDIOMSEL_3_3V (1 << 16) + +#define AT91_MATRIX_EBI1CSA (AT91_MATRIX + 0x124) /* EBI1 Chip Select Assignment Register */ +#define AT91_MATRIX_EBI1_CS1A (1 << 1) /* Chip Select 1 Assignment */ +#define AT91_MATRIX_EBI1_CS1A_SMC (0 << 1) +#define AT91_MATRIX_EBI1_CS1A_SDRAMC (1 << 1) +#define AT91_MATRIX_EBI1_CS2A (1 << 3) /* Chip Select 3 Assignment */ +#define AT91_MATRIX_EBI1_CS2A_SMC (0 << 3) +#define AT91_MATRIX_EBI1_CS2A_SMC_SMARTMEDIA (1 << 3) +#define AT91_MATRIX_EBI1_DBPUC (1 << 8) /* Data Bus Pull-up Configuration */ +#define AT91_MATRIX_EBI1_VDDIOMSEL (1 << 16) /* Memory voltage selection */ +#define AT91_MATRIX_EBI1_VDDIOMSEL_1_8V (0 << 16) +#define AT91_MATRIX_EBI1_VDDIOMSEL_3_3V (1 << 16) + +#endif diff --git a/include/asm-arm/arch-at91rm9200/at91sam926x_mc.h b/include/asm-arm/arch-at91/at91sam926x_mc.h index 972e7531c7f..d82631c251f 100644 --- a/include/asm-arm/arch-at91rm9200/at91sam926x_mc.h +++ b/include/asm-arm/arch-at91/at91sam926x_mc.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91sam926x_mc.h + * include/asm-arm/arch-at91/at91sam926x_mc.h * * Memory Controllers (SMC, SDRAMC) - System peripherals registers. * Based on AT91SAM9261 datasheet revision D. @@ -131,4 +131,11 @@ #define AT91_SMC_PS_16 (2 << 28) #define AT91_SMC_PS_32 (3 << 28) +#if defined(AT91_SMC1) /* The AT91SAM9263 has 2 Static Memory contollers */ +#define AT91_SMC1_SETUP(n) (AT91_SMC1 + 0x00 + ((n)*0x10)) /* Setup Register for CS n */ +#define AT91_SMC1_PULSE(n) (AT91_SMC1 + 0x04 + ((n)*0x10)) /* Pulse Register for CS n */ +#define AT91_SMC1_CYCLE(n) (AT91_SMC1 + 0x08 + ((n)*0x10)) /* Cycle Register for CS n */ +#define AT91_SMC1_MODE(n) (AT91_SMC1 + 0x0c + ((n)*0x10)) /* Mode Register for CS n */ +#endif + #endif diff --git a/include/asm-arm/arch-at91rm9200/board.h b/include/asm-arm/arch-at91/board.h index 768e0fc6aa2..7b9903c2c44 100644 --- a/include/asm-arm/arch-at91rm9200/board.h +++ b/include/asm-arm/arch-at91/board.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/board.h + * include/asm-arm/arch-at91/board.h * * Copyright (C) 2005 HP Labs * @@ -60,7 +60,7 @@ struct at91_mmc_data { u8 wp_pin; /* (SD) writeprotect detect */ u8 vcc_pin; /* power switching (high == on) */ }; -extern void __init at91_add_device_mmc(struct at91_mmc_data *data); +extern void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data); /* Ethernet */ struct at91_eth_data { @@ -69,9 +69,14 @@ struct at91_eth_data { }; extern void __init at91_add_device_eth(struct at91_eth_data *data); +#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263) +#define eth_platform_data at91_eth_data +#endif + /* USB Host */ struct at91_usbh_data { u8 ports; /* number of ports on root hub */ + u8 vbus_pin[]; /* port power-control pin */ }; extern void __init at91_add_device_usbh(struct at91_usbh_data *data); diff --git a/include/asm-arm/arch-at91rm9200/cpu.h b/include/asm-arm/arch-at91/cpu.h index 6f8d09b0869..d464ca58cdb 100644 --- a/include/asm-arm/arch-at91rm9200/cpu.h +++ b/include/asm-arm/arch-at91/cpu.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/cpu.h + * include/asm-arm/arch-at91/cpu.h * * Copyright (C) 2006 SAN People * @@ -20,7 +20,11 @@ #define ARCH_ID_AT91RM9200 0x09290780 #define ARCH_ID_AT91SAM9260 0x019803a0 #define ARCH_ID_AT91SAM9261 0x019703a0 +#define ARCH_ID_AT91SAM9263 0x019607a0 +#define ARCH_ID_AT91SAM9XE128 0x329973a0 +#define ARCH_ID_AT91SAM9XE256 0x329a93a0 +#define ARCH_ID_AT91SAM9XE512 0x329aa3a0 static inline unsigned long at91_cpu_identify(void) { @@ -28,6 +32,16 @@ static inline unsigned long at91_cpu_identify(void) } +#define ARCH_FAMILY_AT91X92 0x09200000 +#define ARCH_FAMILY_AT91SAM9 0x01900000 +#define ARCH_FAMILY_AT91SAM9XE 0x02900000 + +static inline unsigned long at91_arch_identify(void) +{ + return (at91_sys_read(AT91_DBGU_CIDR) & AT91_CIDR_ARCH); +} + + #ifdef CONFIG_ARCH_AT91RM9200 #define cpu_is_at91rm9200() (at91_cpu_identify() == ARCH_ID_AT91RM9200) #else @@ -35,8 +49,10 @@ static inline unsigned long at91_cpu_identify(void) #endif #ifdef CONFIG_ARCH_AT91SAM9260 -#define cpu_is_at91sam9260() (at91_cpu_identify() == ARCH_ID_AT91SAM9260) +#define cpu_is_at91sam9xe() (at91_arch_identify() == ARCH_FAMILY_AT91SAM9XE) +#define cpu_is_at91sam9260() ((at91_cpu_identify() == ARCH_ID_AT91SAM9260) || cpu_is_at91sam9xe()) #else +#define cpu_is_at91sam9xe() (0) #define cpu_is_at91sam9260() (0) #endif @@ -46,4 +62,10 @@ static inline unsigned long at91_cpu_identify(void) #define cpu_is_at91sam9261() (0) #endif +#ifdef CONFIG_ARCH_AT91SAM9263 +#define cpu_is_at91sam9263() (at91_cpu_identify() == ARCH_ID_AT91SAM9263) +#else +#define cpu_is_at91sam9263() (0) +#endif + #endif diff --git a/include/asm-arm/arch-at91/debug-macro.S b/include/asm-arm/arch-at91/debug-macro.S new file mode 100644 index 00000000000..13e9f5e1d4f --- /dev/null +++ b/include/asm-arm/arch-at91/debug-macro.S @@ -0,0 +1,39 @@ +/* + * include/asm-arm/arch-at91/debug-macro.S + * + * Copyright (C) 2003-2005 SAN People + * + * Debugging macro include header + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * +*/ + +#include <asm/hardware.h> +#include <asm/arch/at91_dbgu.h> + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + ldreq \rx, =(AT91_BASE_SYS + AT91_DBGU) @ System peripherals (phys address) + ldrne \rx, =(AT91_VA_BASE_SYS + AT91_DBGU) @ System peripherals (virt address) + .endm + + .macro senduart,rd,rx + strb \rd, [\rx, #(AT91_DBGU_THR - AT91_DBGU)] @ Write to Transmitter Holding Register + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #(AT91_DBGU_SR - AT91_DBGU)] @ Read Status Register + tst \rd, #AT91_DBGU_TXRDY @ DBGU_TXRDY = 1 when ready to transmit + beq 1001b + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #(AT91_DBGU_SR - AT91_DBGU)] @ Read Status Register + tst \rd, #AT91_DBGU_TXEMPTY @ DBGU_TXEMPTY = 1 when transmission complete + beq 1001b + .endm + diff --git a/include/asm-arm/arch-at91rm9200/dma.h b/include/asm-arm/arch-at91/dma.h index 22c1dfdd8da..774565412be 100644 --- a/include/asm-arm/arch-at91rm9200/dma.h +++ b/include/asm-arm/arch-at91/dma.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/dma.h + * include/asm-arm/arch-at91/dma.h * * Copyright (C) 2003 SAN People * diff --git a/include/asm-arm/arch-at91/entry-macro.S b/include/asm-arm/arch-at91/entry-macro.S new file mode 100644 index 00000000000..76c8cccf73a --- /dev/null +++ b/include/asm-arm/arch-at91/entry-macro.S @@ -0,0 +1,26 @@ +/* + * include/asm-arm/arch-at91/entry-macro.S + * + * Copyright (C) 2003-2005 SAN People + * + * Low-level IRQ helper macros for AT91RM9200 platforms + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <asm/hardware.h> +#include <asm/arch/at91_aic.h> + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \base, =(AT91_VA_BASE_SYS + AT91_AIC) @ base virtual address of AIC peripheral + ldr \irqnr, [\base, #(AT91_AIC_IVR - AT91_AIC)] @ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt) + ldr \irqstat, [\base, #(AT91_AIC_ISR - AT91_AIC)] @ read interrupt source number + teq \irqstat, #0 @ ISR is 0 when no current interrupt, or spurious interrupt + streq \tmp, [\base, #(AT91_AIC_EOICR - AT91_AIC)] @ not going to be handled further, then ACK it now. + .endm + diff --git a/include/asm-arm/arch-at91rm9200/gpio.h b/include/asm-arm/arch-at91/gpio.h index e09d6528fad..98ad2114f43 100644 --- a/include/asm-arm/arch-at91rm9200/gpio.h +++ b/include/asm-arm/arch-at91/gpio.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/gpio.h + * include/asm-arm/arch-at91/gpio.h * * Copyright (C) 2005 HP Labs * @@ -17,7 +17,7 @@ #define PIN_BASE NR_AIC_IRQS -#define MAX_GPIO_BANKS 4 +#define MAX_GPIO_BANKS 5 /* these pin numbers double as IRQ numbers, like AT91xxx_ID_* values */ @@ -26,37 +26,31 @@ #define AT91_PIN_PA2 (PIN_BASE + 0x00 + 2) #define AT91_PIN_PA3 (PIN_BASE + 0x00 + 3) #define AT91_PIN_PA4 (PIN_BASE + 0x00 + 4) - #define AT91_PIN_PA5 (PIN_BASE + 0x00 + 5) #define AT91_PIN_PA6 (PIN_BASE + 0x00 + 6) #define AT91_PIN_PA7 (PIN_BASE + 0x00 + 7) #define AT91_PIN_PA8 (PIN_BASE + 0x00 + 8) #define AT91_PIN_PA9 (PIN_BASE + 0x00 + 9) - #define AT91_PIN_PA10 (PIN_BASE + 0x00 + 10) #define AT91_PIN_PA11 (PIN_BASE + 0x00 + 11) #define AT91_PIN_PA12 (PIN_BASE + 0x00 + 12) #define AT91_PIN_PA13 (PIN_BASE + 0x00 + 13) #define AT91_PIN_PA14 (PIN_BASE + 0x00 + 14) - #define AT91_PIN_PA15 (PIN_BASE + 0x00 + 15) #define AT91_PIN_PA16 (PIN_BASE + 0x00 + 16) #define AT91_PIN_PA17 (PIN_BASE + 0x00 + 17) #define AT91_PIN_PA18 (PIN_BASE + 0x00 + 18) #define AT91_PIN_PA19 (PIN_BASE + 0x00 + 19) - #define AT91_PIN_PA20 (PIN_BASE + 0x00 + 20) #define AT91_PIN_PA21 (PIN_BASE + 0x00 + 21) #define AT91_PIN_PA22 (PIN_BASE + 0x00 + 22) #define AT91_PIN_PA23 (PIN_BASE + 0x00 + 23) #define AT91_PIN_PA24 (PIN_BASE + 0x00 + 24) - #define AT91_PIN_PA25 (PIN_BASE + 0x00 + 25) #define AT91_PIN_PA26 (PIN_BASE + 0x00 + 26) #define AT91_PIN_PA27 (PIN_BASE + 0x00 + 27) #define AT91_PIN_PA28 (PIN_BASE + 0x00 + 28) #define AT91_PIN_PA29 (PIN_BASE + 0x00 + 29) - #define AT91_PIN_PA30 (PIN_BASE + 0x00 + 30) #define AT91_PIN_PA31 (PIN_BASE + 0x00 + 31) @@ -65,37 +59,31 @@ #define AT91_PIN_PB2 (PIN_BASE + 0x20 + 2) #define AT91_PIN_PB3 (PIN_BASE + 0x20 + 3) #define AT91_PIN_PB4 (PIN_BASE + 0x20 + 4) - #define AT91_PIN_PB5 (PIN_BASE + 0x20 + 5) #define AT91_PIN_PB6 (PIN_BASE + 0x20 + 6) #define AT91_PIN_PB7 (PIN_BASE + 0x20 + 7) #define AT91_PIN_PB8 (PIN_BASE + 0x20 + 8) #define AT91_PIN_PB9 (PIN_BASE + 0x20 + 9) - #define AT91_PIN_PB10 (PIN_BASE + 0x20 + 10) #define AT91_PIN_PB11 (PIN_BASE + 0x20 + 11) #define AT91_PIN_PB12 (PIN_BASE + 0x20 + 12) #define AT91_PIN_PB13 (PIN_BASE + 0x20 + 13) #define AT91_PIN_PB14 (PIN_BASE + 0x20 + 14) - #define AT91_PIN_PB15 (PIN_BASE + 0x20 + 15) #define AT91_PIN_PB16 (PIN_BASE + 0x20 + 16) #define AT91_PIN_PB17 (PIN_BASE + 0x20 + 17) #define AT91_PIN_PB18 (PIN_BASE + 0x20 + 18) #define AT91_PIN_PB19 (PIN_BASE + 0x20 + 19) - #define AT91_PIN_PB20 (PIN_BASE + 0x20 + 20) #define AT91_PIN_PB21 (PIN_BASE + 0x20 + 21) #define AT91_PIN_PB22 (PIN_BASE + 0x20 + 22) #define AT91_PIN_PB23 (PIN_BASE + 0x20 + 23) #define AT91_PIN_PB24 (PIN_BASE + 0x20 + 24) - #define AT91_PIN_PB25 (PIN_BASE + 0x20 + 25) #define AT91_PIN_PB26 (PIN_BASE + 0x20 + 26) #define AT91_PIN_PB27 (PIN_BASE + 0x20 + 27) #define AT91_PIN_PB28 (PIN_BASE + 0x20 + 28) #define AT91_PIN_PB29 (PIN_BASE + 0x20 + 29) - #define AT91_PIN_PB30 (PIN_BASE + 0x20 + 30) #define AT91_PIN_PB31 (PIN_BASE + 0x20 + 31) @@ -104,37 +92,31 @@ #define AT91_PIN_PC2 (PIN_BASE + 0x40 + 2) #define AT91_PIN_PC3 (PIN_BASE + 0x40 + 3) #define AT91_PIN_PC4 (PIN_BASE + 0x40 + 4) - #define AT91_PIN_PC5 (PIN_BASE + 0x40 + 5) #define AT91_PIN_PC6 (PIN_BASE + 0x40 + 6) #define AT91_PIN_PC7 (PIN_BASE + 0x40 + 7) #define AT91_PIN_PC8 (PIN_BASE + 0x40 + 8) #define AT91_PIN_PC9 (PIN_BASE + 0x40 + 9) - #define AT91_PIN_PC10 (PIN_BASE + 0x40 + 10) #define AT91_PIN_PC11 (PIN_BASE + 0x40 + 11) #define AT91_PIN_PC12 (PIN_BASE + 0x40 + 12) #define AT91_PIN_PC13 (PIN_BASE + 0x40 + 13) #define AT91_PIN_PC14 (PIN_BASE + 0x40 + 14) - #define AT91_PIN_PC15 (PIN_BASE + 0x40 + 15) #define AT91_PIN_PC16 (PIN_BASE + 0x40 + 16) #define AT91_PIN_PC17 (PIN_BASE + 0x40 + 17) #define AT91_PIN_PC18 (PIN_BASE + 0x40 + 18) #define AT91_PIN_PC19 (PIN_BASE + 0x40 + 19) - #define AT91_PIN_PC20 (PIN_BASE + 0x40 + 20) #define AT91_PIN_PC21 (PIN_BASE + 0x40 + 21) #define AT91_PIN_PC22 (PIN_BASE + 0x40 + 22) #define AT91_PIN_PC23 (PIN_BASE + 0x40 + 23) #define AT91_PIN_PC24 (PIN_BASE + 0x40 + 24) - #define AT91_PIN_PC25 (PIN_BASE + 0x40 + 25) #define AT91_PIN_PC26 (PIN_BASE + 0x40 + 26) #define AT91_PIN_PC27 (PIN_BASE + 0x40 + 27) #define AT91_PIN_PC28 (PIN_BASE + 0x40 + 28) #define AT91_PIN_PC29 (PIN_BASE + 0x40 + 29) - #define AT91_PIN_PC30 (PIN_BASE + 0x40 + 30) #define AT91_PIN_PC31 (PIN_BASE + 0x40 + 31) @@ -143,40 +125,67 @@ #define AT91_PIN_PD2 (PIN_BASE + 0x60 + 2) #define AT91_PIN_PD3 (PIN_BASE + 0x60 + 3) #define AT91_PIN_PD4 (PIN_BASE + 0x60 + 4) - #define AT91_PIN_PD5 (PIN_BASE + 0x60 + 5) #define AT91_PIN_PD6 (PIN_BASE + 0x60 + 6) #define AT91_PIN_PD7 (PIN_BASE + 0x60 + 7) #define AT91_PIN_PD8 (PIN_BASE + 0x60 + 8) #define AT91_PIN_PD9 (PIN_BASE + 0x60 + 9) - #define AT91_PIN_PD10 (PIN_BASE + 0x60 + 10) #define AT91_PIN_PD11 (PIN_BASE + 0x60 + 11) #define AT91_PIN_PD12 (PIN_BASE + 0x60 + 12) #define AT91_PIN_PD13 (PIN_BASE + 0x60 + 13) #define AT91_PIN_PD14 (PIN_BASE + 0x60 + 14) - #define AT91_PIN_PD15 (PIN_BASE + 0x60 + 15) #define AT91_PIN_PD16 (PIN_BASE + 0x60 + 16) #define AT91_PIN_PD17 (PIN_BASE + 0x60 + 17) #define AT91_PIN_PD18 (PIN_BASE + 0x60 + 18) #define AT91_PIN_PD19 (PIN_BASE + 0x60 + 19) - #define AT91_PIN_PD20 (PIN_BASE + 0x60 + 20) #define AT91_PIN_PD21 (PIN_BASE + 0x60 + 21) #define AT91_PIN_PD22 (PIN_BASE + 0x60 + 22) #define AT91_PIN_PD23 (PIN_BASE + 0x60 + 23) #define AT91_PIN_PD24 (PIN_BASE + 0x60 + 24) - #define AT91_PIN_PD25 (PIN_BASE + 0x60 + 25) #define AT91_PIN_PD26 (PIN_BASE + 0x60 + 26) #define AT91_PIN_PD27 (PIN_BASE + 0x60 + 27) #define AT91_PIN_PD28 (PIN_BASE + 0x60 + 28) #define AT91_PIN_PD29 (PIN_BASE + 0x60 + 29) - #define AT91_PIN_PD30 (PIN_BASE + 0x60 + 30) #define AT91_PIN_PD31 (PIN_BASE + 0x60 + 31) +#define AT91_PIN_PE0 (PIN_BASE + 0x80 + 0) +#define AT91_PIN_PE1 (PIN_BASE + 0x80 + 1) +#define AT91_PIN_PE2 (PIN_BASE + 0x80 + 2) +#define AT91_PIN_PE3 (PIN_BASE + 0x80 + 3) +#define AT91_PIN_PE4 (PIN_BASE + 0x80 + 4) +#define AT91_PIN_PE5 (PIN_BASE + 0x80 + 5) +#define AT91_PIN_PE6 (PIN_BASE + 0x80 + 6) +#define AT91_PIN_PE7 (PIN_BASE + 0x80 + 7) +#define AT91_PIN_PE8 (PIN_BASE + 0x80 + 8) +#define AT91_PIN_PE9 (PIN_BASE + 0x80 + 9) +#define AT91_PIN_PE10 (PIN_BASE + 0x80 + 10) +#define AT91_PIN_PE11 (PIN_BASE + 0x80 + 11) +#define AT91_PIN_PE12 (PIN_BASE + 0x80 + 12) +#define AT91_PIN_PE13 (PIN_BASE + 0x80 + 13) +#define AT91_PIN_PE14 (PIN_BASE + 0x80 + 14) +#define AT91_PIN_PE15 (PIN_BASE + 0x80 + 15) +#define AT91_PIN_PE16 (PIN_BASE + 0x80 + 16) +#define AT91_PIN_PE17 (PIN_BASE + 0x80 + 17) +#define AT91_PIN_PE18 (PIN_BASE + 0x80 + 18) +#define AT91_PIN_PE19 (PIN_BASE + 0x80 + 19) +#define AT91_PIN_PE20 (PIN_BASE + 0x80 + 20) +#define AT91_PIN_PE21 (PIN_BASE + 0x80 + 21) +#define AT91_PIN_PE22 (PIN_BASE + 0x80 + 22) +#define AT91_PIN_PE23 (PIN_BASE + 0x80 + 23) +#define AT91_PIN_PE24 (PIN_BASE + 0x80 + 24) +#define AT91_PIN_PE25 (PIN_BASE + 0x80 + 25) +#define AT91_PIN_PE26 (PIN_BASE + 0x80 + 26) +#define AT91_PIN_PE27 (PIN_BASE + 0x80 + 27) +#define AT91_PIN_PE28 (PIN_BASE + 0x80 + 28) +#define AT91_PIN_PE29 (PIN_BASE + 0x80 + 29) +#define AT91_PIN_PE30 (PIN_BASE + 0x80 + 30) +#define AT91_PIN_PE31 (PIN_BASE + 0x80 + 31) + #ifndef __ASSEMBLY__ /* setup setup routines, called from board init or driver probe() */ extern int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup); diff --git a/include/asm-arm/arch-at91rm9200/hardware.h b/include/asm-arm/arch-at91/hardware.h index 9ea5bfe0632..eaaf1c12b75 100644 --- a/include/asm-arm/arch-at91rm9200/hardware.h +++ b/include/asm-arm/arch-at91/hardware.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/hardware.h + * include/asm-arm/arch-at91/hardware.h * * Copyright (C) 2003 SAN People * Copyright (C) 2003 ATMEL @@ -22,21 +22,23 @@ #include <asm/arch/at91sam9260.h> #elif defined(CONFIG_ARCH_AT91SAM9261) #include <asm/arch/at91sam9261.h> +#elif defined(CONFIG_ARCH_AT91SAM9263) +#include <asm/arch/at91sam9263.h> #else #error "Unsupported AT91 processor" #endif /* - * Remap the peripherals from address 0xFFFA0000 .. 0xFFFFFFFF - * to 0xFEFA0000 .. 0xFF000000. (384Kb) + * Remap the peripherals from address 0xFFF78000 .. 0xFFFFFFFF + * to 0xFEF78000 .. 0xFF000000. (5444Kb) */ -#define AT91_IO_PHYS_BASE 0xFFFA0000 +#define AT91_IO_PHYS_BASE 0xFFF78000 #define AT91_IO_SIZE (0xFFFFFFFF - AT91_IO_PHYS_BASE + 1) #define AT91_IO_VIRT_BASE (0xFF000000 - AT91_IO_SIZE) /* Convert a physical IO address to virtual IO address */ -#define AT91_IO_P2V(x) ((x) - AT91_IO_PHYS_BASE + AT91_IO_VIRT_BASE) +#define AT91_IO_P2V(x) ((x) - AT91_IO_PHYS_BASE + AT91_IO_VIRT_BASE) /* * Virtual to Physical Address mapping for IO devices. diff --git a/include/asm-arm/arch-at91rm9200/io.h b/include/asm-arm/arch-at91/io.h index 88fd1bebcef..401f327ec04 100644 --- a/include/asm-arm/arch-at91rm9200/io.h +++ b/include/asm-arm/arch-at91/io.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/io.h + * include/asm-arm/arch-at91/io.h * * Copyright (C) 2003 SAN People * diff --git a/include/asm-arm/arch-at91rm9200/irqs.h b/include/asm-arm/arch-at91/irqs.h index c0679eaefaf..1ffa3bb9a9c 100644 --- a/include/asm-arm/arch-at91rm9200/irqs.h +++ b/include/asm-arm/arch-at91/irqs.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/irqs.h + * include/asm-arm/arch-at91/irqs.h * * Copyright (C) 2004 SAN People * @@ -37,8 +37,8 @@ * IRQ interrupt symbols are the AT91xxx_ID_* symbols * for IRQs handled directly through the AIC, or else the AT91_PIN_* * symbols in gpio.h for ones handled indirectly as GPIOs. - * We make provision for 4 banks of GPIO. + * We make provision for 5 banks of GPIO. */ -#define NR_IRQS (NR_AIC_IRQS + (4 * 32)) +#define NR_IRQS (NR_AIC_IRQS + (5 * 32)) #endif diff --git a/include/asm-arm/arch-at91rm9200/memory.h b/include/asm-arm/arch-at91/memory.h index f985069e6d0..4835d678450 100644 --- a/include/asm-arm/arch-at91rm9200/memory.h +++ b/include/asm-arm/arch-at91/memory.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/memory.h + * include/asm-arm/arch-at91/memory.h * * Copyright (C) 2004 SAN People * diff --git a/include/asm-arm/arch-at91rm9200/system.h b/include/asm-arm/arch-at91/system.h index 9c67130603b..6bf846098ea 100644 --- a/include/asm-arm/arch-at91rm9200/system.h +++ b/include/asm-arm/arch-at91/system.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/system.h + * include/asm-arm/arch-at91/system.h * * Copyright (C) 2003 SAN People * diff --git a/include/asm-arm/arch-at91rm9200/timex.h b/include/asm-arm/arch-at91/timex.h index faeca45a8d4..f41636d607a 100644 --- a/include/asm-arm/arch-at91rm9200/timex.h +++ b/include/asm-arm/arch-at91/timex.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/timex.h + * include/asm-arm/arch-at91/timex.h * * Copyright (C) 2003 SAN People * @@ -32,6 +32,11 @@ #define AT91SAM9_MASTER_CLOCK 99300000 #define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16) +#elif defined(CONFIG_ARCH_AT91SAM9263) + +#define AT91SAM9_MASTER_CLOCK 99959500 +#define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16) + #endif #endif diff --git a/include/asm-arm/arch-at91rm9200/uncompress.h b/include/asm-arm/arch-at91/uncompress.h index 34b4b93fa01..a193d28304b 100644 --- a/include/asm-arm/arch-at91rm9200/uncompress.h +++ b/include/asm-arm/arch-at91/uncompress.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/uncompress.h + * include/asm-arm/arch-at91/uncompress.h * * Copyright (C) 2003 SAN People * diff --git a/include/asm-arm/arch-at91rm9200/vmalloc.h b/include/asm-arm/arch-at91/vmalloc.h index 0a23b8c562b..bb05e70e932 100644 --- a/include/asm-arm/arch-at91rm9200/vmalloc.h +++ b/include/asm-arm/arch-at91/vmalloc.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/vmalloc.h + * include/asm-arm/arch-at91/vmalloc.h * * Copyright (C) 2003 SAN People * diff --git a/include/asm-arm/arch-at91rm9200/at91_pdc.h b/include/asm-arm/arch-at91rm9200/at91_pdc.h deleted file mode 100644 index 79d6e02fa45..00000000000 --- a/include/asm-arm/arch-at91rm9200/at91_pdc.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * include/asm-arm/arch-at91rm9200/at91_pdc.h - * - * Copyright (C) 2005 Ivan Kokshaysky - * Copyright (C) SAN People - * - * Peripheral Data Controller (PDC) registers. - * Based on AT91RM9200 datasheet revision E. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef AT91_PDC_H -#define AT91_PDC_H - -#define AT91_PDC_RPR 0x100 /* Receive Pointer Register */ -#define AT91_PDC_RCR 0x104 /* Receive Counter Register */ -#define AT91_PDC_TPR 0x108 /* Transmit Pointer Register */ -#define AT91_PDC_TCR 0x10c /* Transmit Counter Register */ -#define AT91_PDC_RNPR 0x110 /* Receive Next Pointer Register */ -#define AT91_PDC_RNCR 0x114 /* Receive Next Counter Register */ -#define AT91_PDC_TNPR 0x118 /* Transmit Next Pointer Register */ -#define AT91_PDC_TNCR 0x11c /* Transmit Next Counter Register */ - -#define AT91_PDC_PTCR 0x120 /* Transfer Control Register */ -#define AT91_PDC_RXTEN (1 << 0) /* Receiver Transfer Enable */ -#define AT91_PDC_RXTDIS (1 << 1) /* Receiver Transfer Disable */ -#define AT91_PDC_TXTEN (1 << 8) /* Transmitter Transfer Enable */ -#define AT91_PDC_TXTDIS (1 << 9) /* Transmitter Transfer Disable */ - -#define AT91_PDC_PTSR 0x124 /* Transfer Status Register */ - -#endif diff --git a/include/asm-arm/arch-at91rm9200/debug-macro.S b/include/asm-arm/arch-at91rm9200/debug-macro.S deleted file mode 100644 index 85cdadf2663..00000000000 --- a/include/asm-arm/arch-at91rm9200/debug-macro.S +++ /dev/null @@ -1,39 +0,0 @@ -/* - * include/asm-arm/arch-at91rm9200/debug-macro.S - * - * Copyright (C) 2003-2005 SAN People - * - * Debugging macro include header - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * -*/ - -#include <asm/hardware.h> -#include <asm/arch/at91_dbgu.h> - - .macro addruart,rx - mrc p15, 0, \rx, c1, c0 - tst \rx, #1 @ MMU enabled? - ldreq \rx, =AT91_BASE_SYS @ System peripherals (phys address) - ldrne \rx, =AT91_VA_BASE_SYS @ System peripherals (virt address) - .endm - - .macro senduart,rd,rx - strb \rd, [\rx, #AT91_DBGU_THR] @ Write to Transmitter Holding Register - .endm - - .macro waituart,rd,rx -1001: ldr \rd, [\rx, #AT91_DBGU_SR] @ Read Status Register - tst \rd, #AT91_DBGU_TXRDY @ DBGU_TXRDY = 1 when ready to transmit - beq 1001b - .endm - - .macro busyuart,rd,rx -1001: ldr \rd, [\rx, #AT91_DBGU_SR] @ Read Status Register - tst \rd, #AT91_DBGU_TXEMPTY @ DBGU_TXEMPTY = 1 when transmission complete - beq 1001b - .endm - diff --git a/include/asm-arm/arch-at91rm9200/entry-macro.S b/include/asm-arm/arch-at91rm9200/entry-macro.S deleted file mode 100644 index 57248a79647..00000000000 --- a/include/asm-arm/arch-at91rm9200/entry-macro.S +++ /dev/null @@ -1,26 +0,0 @@ -/* - * include/asm-arm/arch-at91rm9200/entry-macro.S - * - * Copyright (C) 2003-2005 SAN People - * - * Low-level IRQ helper macros for AT91RM9200 platforms - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <asm/hardware.h> -#include <asm/arch/at91_aic.h> - - .macro disable_fiq - .endm - - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - ldr \base, =(AT91_VA_BASE_SYS) @ base virtual address of SYS peripherals - ldr \irqnr, [\base, #AT91_AIC_IVR] @ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt) - ldr \irqstat, [\base, #AT91_AIC_ISR] @ read interrupt source number - teq \irqstat, #0 @ ISR is 0 when no current interrupt, or spurious interrupt - streq \tmp, [\base, #AT91_AIC_EOICR] @ not going to be handled further, then ACK it now. - .endm - diff --git a/include/asm-arm/arch-ep93xx/ep93xx-regs.h b/include/asm-arm/arch-ep93xx/ep93xx-regs.h index 593f562f85c..625c6f0abc0 100644 --- a/include/asm-arm/arch-ep93xx/ep93xx-regs.h +++ b/include/asm-arm/arch-ep93xx/ep93xx-regs.h @@ -73,6 +73,11 @@ #define EP93XX_GPIO_BASE (EP93XX_APB_VIRT_BASE + 0x00040000) #define EP93XX_GPIO_REG(x) (EP93XX_GPIO_BASE + (x)) +#define EP93XX_GPIO_F_INT_TYPE1 EP93XX_GPIO_REG(0x4c) +#define EP93XX_GPIO_F_INT_TYPE2 EP93XX_GPIO_REG(0x50) +#define EP93XX_GPIO_F_INT_ACK EP93XX_GPIO_REG(0x54) +#define EP93XX_GPIO_F_INT_ENABLE EP93XX_GPIO_REG(0x58) +#define EP93XX_GPIO_F_INT_STATUS EP93XX_GPIO_REG(0x5c) #define EP93XX_GPIO_A_INT_TYPE1 EP93XX_GPIO_REG(0x90) #define EP93XX_GPIO_A_INT_TYPE2 EP93XX_GPIO_REG(0x94) #define EP93XX_GPIO_A_INT_ACK EP93XX_GPIO_REG(0x98) diff --git a/include/asm-arm/arch-ep93xx/irqs.h b/include/asm-arm/arch-ep93xx/irqs.h index ae532e304bf..2a8c63638c5 100644 --- a/include/asm-arm/arch-ep93xx/irqs.h +++ b/include/asm-arm/arch-ep93xx/irqs.h @@ -67,9 +67,13 @@ #define IRQ_EP93XX_SAI 60 #define EP93XX_VIC2_VALID_IRQ_MASK 0x1fffffff -#define IRQ_EP93XX_GPIO(x) (64 + (x)) +/* + * Map GPIO A0..A7 to irq 64..71, B0..B7 to 72..79, and + * F0..F7 to 80..87. + */ +#define IRQ_EP93XX_GPIO(x) (64 + (((x) + (((x) >> 2) & 8)) & 0x1f)) -#define NR_EP93XX_IRQS IRQ_EP93XX_GPIO(16) +#define NR_EP93XX_IRQS (64 + 24) #define EP93XX_BOARD_IRQ(x) (NR_EP93XX_IRQS + (x)) #define EP93XX_BOARD_IRQS 32 diff --git a/include/asm-arm/arch-ep93xx/platform.h b/include/asm-arm/arch-ep93xx/platform.h index b4a8deb8bde..44eccec2cba 100644 --- a/include/asm-arm/arch-ep93xx/platform.h +++ b/include/asm-arm/arch-ep93xx/platform.h @@ -8,7 +8,6 @@ void ep93xx_map_io(void); void ep93xx_init_irq(void); void ep93xx_init_time(unsigned long); void ep93xx_init_devices(void); -void ep93xx_clock_init(void); extern struct sys_timer ep93xx_timer; struct ep93xx_eth_data diff --git a/include/asm-arm/arch-imx/entry-macro.S b/include/asm-arm/arch-imx/entry-macro.S index 3b9ef691462..61bb0bdc1b1 100644 --- a/include/asm-arm/arch-imx/entry-macro.S +++ b/include/asm-arm/arch-imx/entry-macro.S @@ -13,19 +13,13 @@ .endm #define AITC_NIVECSR 0x40 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - ldr \irqstat, =IO_ADDRESS(IMX_AITC_BASE) + ldr \base, =IO_ADDRESS(IMX_AITC_BASE) @ Load offset & priority of the highest priority @ interrupt pending. - ldr \irqnr, [\irqstat, #AITC_NIVECSR] + ldr \irqstat, [\base, #AITC_NIVECSR] @ Shift off the priority leaving the offset or - @ "interrupt number" - mov \irqnr, \irqnr, lsr #16 - ldr \irqstat, =1 @ dummy compare - ldr \base, =0xFFFF // invalid interrupt - cmp \irqnr, \base - bne 1001f - ldr \irqstat, =0 -1001: - tst \irqstat, #1 @ to make the condition code = TRUE + @ "interrupt number", use arithmetic shift to + @ transform illegal source (0xffff) as -1 + mov \irqnr, \irqstat, asr #16 + adds \tmp, \irqnr, #1 .endm - diff --git a/include/asm-arm/arch-iop32x/io.h b/include/asm-arm/arch-iop32x/io.h index 12d9ee02cde..5f570a598a3 100644 --- a/include/asm-arm/arch-iop32x/io.h +++ b/include/asm-arm/arch-iop32x/io.h @@ -13,10 +13,16 @@ #include <asm/hardware.h> -#define IO_SPACE_LIMIT 0xffffffff +extern void __iomem * __ioremap(unsigned long, size_t, unsigned long); +extern void __iomem *__iop3xx_ioremap(unsigned long cookie, size_t size, + unsigned long flags); +extern void __iop3xx_iounmap(void __iomem *addr); -#define __io(p) ((void __iomem *)(p)) +#define IO_SPACE_LIMIT 0xffffffff +#define __io(p) ((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p)) #define __mem_pci(a) (a) +#define __arch_ioremap(a, s, f) __iop3xx_ioremap(a, s, f) +#define __arch_iounmap(a) __iop3xx_iounmap(a) #endif diff --git a/include/asm-arm/arch-iop33x/io.h b/include/asm-arm/arch-iop33x/io.h index c017402bab9..1bb5071e1fa 100644 --- a/include/asm-arm/arch-iop33x/io.h +++ b/include/asm-arm/arch-iop33x/io.h @@ -13,9 +13,16 @@ #include <asm/hardware.h> +extern void __iomem * __ioremap(unsigned long, size_t, unsigned long); +extern void __iomem *__iop3xx_ioremap(unsigned long cookie, size_t size, + unsigned long flags); +extern void __iop3xx_iounmap(void __iomem *addr); + #define IO_SPACE_LIMIT 0xffffffff -#define __io(p) ((void __iomem *)(p)) +#define __io(p) ((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p)) #define __mem_pci(a) (a) +#define __arch_ioremap(a, s, f) __iop3xx_ioremap(a, s, f) +#define __arch_iounmap(a) __iop3xx_iounmap(a) #endif diff --git a/include/asm-arm/arch-ixp4xx/avila.h b/include/asm-arm/arch-ixp4xx/avila.h new file mode 100644 index 00000000000..0dfea0ccd6b --- /dev/null +++ b/include/asm-arm/arch-ixp4xx/avila.h @@ -0,0 +1,39 @@ +/* + * include/asm-arm/arch-ixp4xx/avila.h + * + * Gateworks Avila platform specific definitions + * + * Author: Michael-Luke Jones <mlj28@cam.ac.uk> + * + * Based on ixdp425.h + * Author: Deepak Saxena <dsaxena@plexity.net> + * + * Copyright 2004 (c) MontaVista, Software, Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __ASM_ARCH_HARDWARE_H__ +#error "Do not include this directly, instead #include <asm/hardware.h>" +#endif + +#define AVILA_SDA_PIN 7 +#define AVILA_SCL_PIN 6 + +/* + * AVILA PCI IRQs + */ +#define AVILA_PCI_MAX_DEV 4 +#define LOFT_PCI_MAX_DEV 6 +#define AVILA_PCI_IRQ_LINES 4 + + +/* PCI controller GPIO to IRQ pin mappings */ +#define AVILA_PCI_INTA_PIN 11 +#define AVILA_PCI_INTB_PIN 10 +#define AVILA_PCI_INTC_PIN 9 +#define AVILA_PCI_INTD_PIN 8 + + diff --git a/include/asm-arm/arch-ixp4xx/hardware.h b/include/asm-arm/arch-ixp4xx/hardware.h index 6acb69c95ef..88fd0877dcc 100644 --- a/include/asm-arm/arch-ixp4xx/hardware.h +++ b/include/asm-arm/arch-ixp4xx/hardware.h @@ -42,6 +42,7 @@ extern unsigned int processor_id; /* Platform specific details */ #include "ixdp425.h" +#include "avila.h" #include "coyote.h" #include "prpmc1100.h" #include "nslu2.h" diff --git a/include/asm-arm/arch-ixp4xx/irqs.h b/include/asm-arm/arch-ixp4xx/irqs.h index f24b763ca18..e44a563d00f 100644 --- a/include/asm-arm/arch-ixp4xx/irqs.h +++ b/include/asm-arm/arch-ixp4xx/irqs.h @@ -79,6 +79,15 @@ #define IRQ_IXDP425_PCI_INTD IRQ_IXP4XX_GPIO8 /* + * Gateworks Avila board IRQs + */ +#define IRQ_AVILA_PCI_INTA IRQ_IXP4XX_GPIO11 +#define IRQ_AVILA_PCI_INTB IRQ_IXP4XX_GPIO10 +#define IRQ_AVILA_PCI_INTC IRQ_IXP4XX_GPIO9 +#define IRQ_AVILA_PCI_INTD IRQ_IXP4XX_GPIO8 + + +/* * PrPMC1100 Board IRQs */ #define IRQ_PRPMC1100_PCI_INTA IRQ_IXP4XX_GPIO11 diff --git a/include/asm-arm/arch-ixp4xx/udc.h b/include/asm-arm/arch-ixp4xx/udc.h index dbdec36ff0d..79b850a3be4 100644 --- a/include/asm-arm/arch-ixp4xx/udc.h +++ b/include/asm-arm/arch-ixp4xx/udc.h @@ -6,3 +6,25 @@ extern void ixp4xx_set_udc_info(struct pxa2xx_udc_mach_info *info); +static inline int udc_gpio_to_irq(unsigned gpio) +{ + return 0; +} + +static inline void udc_gpio_init_vbus(unsigned gpio) +{ +} + +static inline void udc_gpio_init_pullup(unsigned gpio) +{ +} + +static inline int udc_gpio_get(unsigned gpio) +{ + return 0; +} + +static inline void udc_gpio_set(unsigned gpio, int is_on) +{ +} + diff --git a/include/asm-arm/arch-ns9xxx/board.h b/include/asm-arm/arch-ns9xxx/board.h new file mode 100644 index 00000000000..91dc8fb1027 --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/board.h @@ -0,0 +1,18 @@ +/* + * include/asm-arm/arch-ns9xxx/board.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_BOARD_H +#define __ASM_ARCH_BOARD_H + +#include <asm/mach-types.h> + +#define board_is_a9m9750dev() (machine_is_cc9p9360dev()) + +#endif /* ifndef __ASM_ARCH_BOARD_H */ diff --git a/include/asm-arm/arch-ns9xxx/clock.h b/include/asm-arm/arch-ns9xxx/clock.h new file mode 100644 index 00000000000..4371a485db4 --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/clock.h @@ -0,0 +1,37 @@ +/* + * include/asm-arm/arch-ns9xxx/clock.h + * + * Copyright (C) 2007 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_CLOCK_H +#define __ASM_ARCH_CLOCK_H + +static inline u32 ns9xxx_systemclock(void) +{ + /* + * This should be a multiple of HZ * TIMERCLOCKSELECT (in time.c) + */ + return 353894400; +} + +static inline const u32 ns9xxx_cpuclock(void) +{ + return ns9xxx_systemclock() / 2; +} + +static inline const u32 ns9xxx_ahbclock(void) +{ + return ns9xxx_systemclock() / 4; +} + +static inline const u32 ns9xxx_bbusclock(void) +{ + return ns9xxx_systemclock() / 8; +} + +#endif /* ifndef __ASM_ARCH_CLOCK_H */ diff --git a/include/asm-arm/arch-ns9xxx/debug-macro.S b/include/asm-arm/arch-ns9xxx/debug-macro.S new file mode 100644 index 00000000000..b21b93eb2db --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/debug-macro.S @@ -0,0 +1,22 @@ +/* + * include/asm-arm/arch-ns9xxx/debug-macro.S + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <asm/hardware.h> + +#include <asm/arch-ns9xxx/regs-board-a9m9750dev.h> + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 + ldreq \rx, =NS9XXX_CSxSTAT_PHYS(0) + ldrne \rx, =io_p2v(NS9XXX_CSxSTAT_PHYS(0)) + .endm + +#define UART_SHIFT 2 +#include <asm/hardware/debug-8250.S> diff --git a/include/asm-arm/arch-ns9xxx/dma.h b/include/asm-arm/arch-ns9xxx/dma.h new file mode 100644 index 00000000000..a67cbbe009c --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/dma.h @@ -0,0 +1,14 @@ +/* + * include/asm-arm/arch-ns9xxx/dma.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#endif /* ifndef __ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-ns9xxx/entry-macro.S b/include/asm-arm/arch-ns9xxx/entry-macro.S new file mode 100644 index 00000000000..467a1986d25 --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/entry-macro.S @@ -0,0 +1,22 @@ +/* + * include/asm-arm/arch-ns9xxx/entry-macro.S + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <asm/hardware.h> +#include <asm/arch-ns9xxx/regs-sys.h> + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \base, =SYS_ISRADDR + ldr \irqstat, [\base, #(SYS_ISA - SYS_ISRADDR)] + cmp \irqstat, #0 + ldrne \irqnr, [\base] + .endm + + .macro disable_fiq + .endm diff --git a/include/asm-arm/arch-ns9xxx/hardware.h b/include/asm-arm/arch-ns9xxx/hardware.h new file mode 100644 index 00000000000..6819da7c48d --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/hardware.h @@ -0,0 +1,67 @@ +/* + * include/asm-arm/arch-ns9xxx/hardware.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include <asm/memory.h> + +/* + * NetSilicon NS9xxx internal mapping: + * + * physical <--> virtual + * 0x90000000 - 0x906fffff <--> 0xf9000000 - 0xf96fffff + * 0xa0100000 - 0xa0afffff <--> 0xfa100000 - 0xfaafffff + */ +#define io_p2v(x) (0xf0000000 \ + + (((x) & 0xf0000000) >> 4) \ + + ((x) & 0x00ffffff)) + +#define io_v2p(x) ((((x) & 0x0f000000) << 4) \ + + ((x) & 0x00ffffff)) + +#define __REGBIT(bit) ((u32)1 << (bit)) +#define __REGBITS(hbit, lbit) ((((u32)1 << ((hbit) - (lbit) + 1)) - 1) << (lbit)) +#define __REGVAL(mask, value) (((value) * ((mask) & (-(mask))) & (mask))) + +#ifndef __ASSEMBLY__ + +# define __REG(x) (*((volatile u32 *)io_p2v((x)))) +# define __REG2(x, y) (*((volatile u32 *)io_p2v((x)) + (y))) + +# define __REGB(x) (*((volatile u8 *)io_p2v((x)))) +# define __REGB2(x) (*((volatile u8 *)io_p2v((x)) + (y))) + +# define REGSET(var, reg, field, value) \ + ((var) = (((var) \ + & ~(reg ## _ ## field & \ + ~ reg ## _ ## field ## _ ## value)) \ + | (reg ## _ ## field ## _ ## value))) + +# define REGSETIM(var, reg, field, value) \ + ((var) = (((var) \ + & ~(reg ## _ ## field & \ + ~(__REGVAL(reg ## _ ## field, value)))) \ + | (__REGVAL(reg ## _ ## field, value)))) + +# define REGGET(reg, field) \ + ((reg & (reg ## _ ## field)) / (field & (-field))) + +#else + +# define __REG(x) io_p2v(x) +# define __REG2(x, y) io_p2v((x) + (y)) + +# define __REGB(x) __REG((x)) +# define __REGB2(x, y) __REG2((x), (y)) + +#endif + +#endif /* ifndef __ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-ns9xxx/io.h b/include/asm-arm/arch-ns9xxx/io.h new file mode 100644 index 00000000000..6f82d28af12 --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/io.h @@ -0,0 +1,20 @@ +/* + * include/asm-arm/arch-ns9xxx/io.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_IO_H +#define __ASM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff /* XXX */ + +#define __io(a) ((void __iomem *)(a)) +#define __mem_pci(a) (a) +#define __mem_isa(a) (IO_BASE + (a)) + +#endif /* ifndef __ASM_ARCH_IO_H */ diff --git a/include/asm-arm/arch-ns9xxx/irqs.h b/include/asm-arm/arch-ns9xxx/irqs.h new file mode 100644 index 00000000000..25d8d28b27f --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/irqs.h @@ -0,0 +1,85 @@ +/* + * include/asm-arm/arch-ns9xxx/irqs.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_IRQS_H +#define __ASM_ARCH_IRQS_H + +#define IRQ_WATCHDOG 0 +#define IRQ_AHBBUSERR 1 +#define IRQ_BBUSAGG 2 +/* irq 3 is reserved for NS9360 */ +#define IRQ_ETHRX 4 +#define IRQ_ETHTX 5 +#define IRQ_ETHPHY 6 +#define IRQ_LCD 7 +#define IRQ_SERBRX 8 +#define IRQ_SERBTX 9 +#define IRQ_SERARX 10 +#define IRQ_SERATX 11 +#define IRQ_SERCRX 12 +#define IRQ_SERCTX 13 +#define IRQ_I2C 14 +#define IRQ_BBUSDMA 15 +#define IRQ_TIMER0 16 +#define IRQ_TIMER1 17 +#define IRQ_TIMER2 18 +#define IRQ_TIMER3 19 +#define IRQ_TIMER4 20 +#define IRQ_TIMER5 21 +#define IRQ_TIMER6 22 +#define IRQ_TIMER7 23 +#define IRQ_RTC 24 +#define IRQ_USBHOST 25 +#define IRQ_USBDEVICE 26 +#define IRQ_IEEE1284 27 +#define IRQ_EXT0 28 +#define IRQ_EXT1 29 +#define IRQ_EXT2 30 +#define IRQ_EXT3 31 + +#define BBUS_IRQ(irq) (32 + irq) + +#define IRQ_BBUS_DMA BBUS_IRQ(0) +#define IRQ_BBUS_SERBRX BBUS_IRQ(2) +#define IRQ_BBUS_SERBTX BBUS_IRQ(3) +#define IRQ_BBUS_SERARX BBUS_IRQ(4) +#define IRQ_BBUS_SERATX BBUS_IRQ(5) +#define IRQ_BBUS_SERCRX BBUS_IRQ(6) +#define IRQ_BBUS_SERCTX BBUS_IRQ(7) +#define IRQ_BBUS_SERDRX BBUS_IRQ(8) +#define IRQ_BBUS_SERDTX BBUS_IRQ(9) +#define IRQ_BBUS_I2C BBUS_IRQ(10) +#define IRQ_BBUS_1284 BBUS_IRQ(11) +#define IRQ_BBUS_UTIL BBUS_IRQ(12) +#define IRQ_BBUS_RTC BBUS_IRQ(13) +#define IRQ_BBUS_USBHST BBUS_IRQ(14) +#define IRQ_BBUS_USBDEV BBUS_IRQ(15) +#define IRQ_BBUS_AHBDMA1 BBUS_IRQ(24) +#define IRQ_BBUS_AHBDMA2 BBUS_IRQ(25) + +/* + * these Interrupts are specific for the a9m9750dev board. + * They are generated by an FPGA that interrupts the CPU on + * IRQ_EXT2 + */ +#define FPGA_IRQ(irq) (64 + irq) + +#define IRQ_FPGA_UARTA FPGA_IRQ(0) +#define IRQ_FPGA_UARTB FPGA_IRQ(1) +#define IRQ_FPGA_UARTC FPGA_IRQ(2) +#define IRQ_FPGA_UARTD FPGA_IRQ(3) +#define IRQ_FPGA_TOUCH FPGA_IRQ(4) +#define IRQ_FPGA_CF FPGA_IRQ(5) +#define IRQ_FPGA_CAN0 FPGA_IRQ(6) +#define IRQ_FPGA_CAN1 FPGA_IRQ(7) + +#define NR_IRQS 72 + +#endif /* __ASM_ARCH_IRQS_H */ diff --git a/include/asm-arm/arch-ns9xxx/memory.h b/include/asm-arm/arch-ns9xxx/memory.h new file mode 100644 index 00000000000..ce1343e593e --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/memory.h @@ -0,0 +1,27 @@ +/* + * include/asm-arm/arch-ns9xxx/memory.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. +*/ +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +/* x in [0..3] */ +#define NS9XXX_CSxSTAT_PHYS(x) UL(((x) + 4) << 28) + +#define NS9XXX_CS0STAT_LENGTH UL(0x1000) +#define NS9XXX_CS1STAT_LENGTH UL(0x1000) +#define NS9XXX_CS2STAT_LENGTH UL(0x1000) +#define NS9XXX_CS3STAT_LENGTH UL(0x1000) + +#define PHYS_OFFSET UL(0x00000000) + +#define __virt_to_bus(x) __virt_to_phys(x) +#define __bus_to_virt(x) __phys_to_virt(x) + +#endif diff --git a/include/asm-arm/arch-ns9xxx/processor.h b/include/asm-arm/arch-ns9xxx/processor.h new file mode 100644 index 00000000000..716c106ac0b --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/processor.h @@ -0,0 +1,18 @@ +/* + * include/asm-arm/arch-ns9xxx/processor.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_PROCESSOR_H +#define __ASM_ARCH_PROCESSOR_H + +#include <asm/mach-types.h> + +#define processor_is_ns9360() (machine_is_cc9p9360dev()) + +#endif /* ifndef __ASM_ARCH_PROCESSOR_H */ diff --git a/include/asm-arm/arch-ns9xxx/regs-bbu.h b/include/asm-arm/arch-ns9xxx/regs-bbu.h new file mode 100644 index 00000000000..e2626954624 --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/regs-bbu.h @@ -0,0 +1,21 @@ +/* + * include/asm-arm/arch-ns9xxx/regs-bbu.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_REGSBBU_H +#define __ASM_ARCH_REGSBBU_H + +#include <asm/hardware.h> + +/* BBus Utility */ + +/* GPIO Configuration Register */ +#define BBU_GC(x) __REG2(0x9060000c, (x)) + +#endif /* ifndef __ASM_ARCH_REGSBBU_H */ diff --git a/include/asm-arm/arch-ns9xxx/regs-board-a9m9750dev.h b/include/asm-arm/arch-ns9xxx/regs-board-a9m9750dev.h new file mode 100644 index 00000000000..c3dc532dd20 --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/regs-board-a9m9750dev.h @@ -0,0 +1,24 @@ +/* + * include/asm-arm/arch-ns9xxx/regs-board-a9m9750dev.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_REGSBOARDA9M9750_H +#define __ASM_ARCH_REGSBOARDA9M9750_H + +#include <asm/hardware.h> + +#define FPGA_UARTA_BASE io_p2v(NS9XXX_CSxSTAT_PHYS(0)) +#define FPGA_UARTB_BASE io_p2v(NS9XXX_CSxSTAT_PHYS(0) + 0x08) +#define FPGA_UARTC_BASE io_p2v(NS9XXX_CSxSTAT_PHYS(0) + 0x10) +#define FPGA_UARTD_BASE io_p2v(NS9XXX_CSxSTAT_PHYS(0) + 0x18) + +#define FPGA_IER __REGB(NS9XXX_CSxSTAT_PHYS(0) + 0x50) +#define FPGA_ISR __REGB(NS9XXX_CSxSTAT_PHYS(0) + 0x60) + +#endif /* ifndef __ASM_ARCH_REGSBOARDA9M9750_H */ diff --git a/include/asm-arm/arch-ns9xxx/regs-mem.h b/include/asm-arm/arch-ns9xxx/regs-mem.h new file mode 100644 index 00000000000..8ed8448767b --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/regs-mem.h @@ -0,0 +1,135 @@ +/* + * include/asm-arm/arch-ns9xxx/regs-mem.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_REGSMEM_H +#define __ASM_ARCH_REGSMEM_H + +#include <asm/hardware.h> + +/* Memory Module */ + +/* Control register */ +#define MEM_CTRL __REG(0xa0700000) + +/* Status register */ +#define MEM_STAT __REG(0xa0700004) + +/* Configuration register */ +#define MEM_CONF __REG(0xa0700008) + +/* Dynamic Memory Control register */ +#define MEM_DMCTRL __REG(0xa0700020) + +/* Dynamic Memory Refresh Timer */ +#define MEM_DMRT __REG(0xa0700024) + +/* Dynamic Memory Read Configuration register */ +#define MEM_DMRC __REG(0xa0700028) + +/* Dynamic Memory Precharge Command Period (tRP) */ +#define MEM_DMPCP __REG(0xa0700030) + +/* Dynamic Memory Active to Precharge Command Period (tRAS) */ +#define MEM_DMAPCP __REG(0xa0700034) + +/* Dynamic Memory Self-Refresh Exit Time (tSREX) */ +#define MEM_DMSRET __REG(0xa0700038) + +/* Dynamic Memory Last Data Out to Active Time (tAPR) */ +#define MEM_DMLDOAT __REG(0xa070003c) + +/* Dynamic Memory Data-in to Active Command Time (tDAL or TAPW) */ +#define MEM_DMDIACT __REG(0xa0700040) + +/* Dynamic Memory Write Recovery Time (tWR, tDPL, tRWL, tRDL) */ +#define MEM_DMWRT __REG(0xa0700044) + +/* Dynamic Memory Active to Active Command Period (tRC) */ +#define MEM_DMAACP __REG(0xa0700048) + +/* Dynamic Memory Auto Refresh Period, and Auto Refresh to Active Command Period (tRFC) */ +#define MEM_DMARP __REG(0xa070004c) + +/* Dynamic Memory Exit Self-Refresh to Active Command (tXSR) */ +#define MEM_DMESRAC __REG(0xa0700050) + +/* Dynamic Memory Active Bank A to Active B Time (tRRD) */ +#define MEM_DMABAABT __REG(0xa0700054) + +/* Dynamic Memory Load Mode register to Active Command Time (tMRD) */ +#define MEM_DMLMACT __REG(0xa0700058) + +/* Static Memory Extended Wait */ +#define MEM_SMEW __REG(0xa0700080) + +/* Dynamic Memory Configuration Register x */ +#define MEM_DMCONF(x) __REG2(0xa0700100, (x) << 3) + +/* Dynamic Memory RAS and CAS Delay x */ +#define MEM_DMRCD(x) __REG2(0xa0700104, (x) << 3) + +/* Static Memory Configuration Register x */ +#define MEM_SMC(x) __REG2(0xa0700200, (x) << 3) + +/* Static Memory Configuration Register x: Write protect */ +#define MEM_SMC_WSMC __REGBIT(20) +#define MEM_SMC_WSMC_OFF __REGVAL(MEM_SMC_WSMC, 0) +#define MEM_SMC_WSMC_ON __REGVAL(MEM_SMC_WSMC, 1) + +/* Static Memory Configuration Register x: Buffer enable */ +#define MEM_SMC_BSMC __REGBIT(19) +#define MEM_SMC_BSMC_OFF __REGVAL(MEM_SMC_BSMC, 0) +#define MEM_SMC_BSMC_ON __REGVAL(MEM_SMC_BSMC, 1) + +/* Static Memory Configuration Register x: Extended Wait */ +#define MEM_SMC_EW __REGBIT(8) +#define MEM_SMC_EW_OFF __REGVAL(MEM_SMC_EW, 0) +#define MEM_SMC_EW_ON __REGVAL(MEM_SMC_EW, 1) + +/* Static Memory Configuration Register x: Byte lane state */ +#define MEM_SMC_PB __REGBIT(7) +#define MEM_SMC_PB_0 __REGVAL(MEM_SMC_PB, 0) +#define MEM_SMC_PB_1 __REGVAL(MEM_SMC_PB, 1) + +/* Static Memory Configuration Register x: Chip select polarity */ +#define MEM_SMC_PC __REGBIT(6) +#define MEM_SMC_PC_AL __REGVAL(MEM_SMC_PC, 0) +#define MEM_SMC_PC_AH __REGVAL(MEM_SMC_PC, 1) + +/* static memory configuration register x: page mode*/ +#define MEM_SMC_PM __REGBIT(3) +#define MEM_SMC_PM_DIS __REGVAL(MEM_SMC_PM, 0) +#define MEM_SMC_PM_ASYNC __REGVAL(MEM_SMC_PM, 1) + +/* static memory configuration register x: Memory width */ +#define MEM_SMC_MW __REGBITS(1, 0) +#define MEM_SMC_MW_8 __REGVAL(MEM_SMC_MW, 0) +#define MEM_SMC_MW_16 __REGVAL(MEM_SMC_MW, 1) +#define MEM_SMC_MW_32 __REGVAL(MEM_SMC_MW, 2) + +/* Static Memory Write Enable Delay x */ +#define MEM_SMWED(x) __REG2(0xa0700204, (x) << 3) + +/* Static Memory Output Enable Delay x */ +#define MEM_SMOED(x) __REG2(0xa0700208, (x) << 3) + +/* Static Memory Read Delay x */ +#define MEM_SMRD(x) __REG2(0xa070020c, (x) << 3) + +/* Static Memory Page Mode Read Delay 0 */ +#define MEM_SMPMRD(x) __REG2(0xa0700210, (x) << 3) + +/* Static Memory Write Delay */ +#define MEM_SMWD(x) __REG2(0xa0700214, (x) << 3) + +/* Static Memory Turn Round Delay x */ +#define MEM_SWT(x) __REG2(0xa0700218, (x) << 3) + +#endif /* ifndef __ASM_ARCH_REGSMEM_H */ diff --git a/include/asm-arm/arch-ns9xxx/regs-sys.h b/include/asm-arm/arch-ns9xxx/regs-sys.h new file mode 100644 index 00000000000..8162a50bb27 --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/regs-sys.h @@ -0,0 +1,157 @@ +/* + * include/asm-arm/arch-ns9xxx/regs-sys.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_REGSSYS_H +#define __ASM_ARCH_REGSSYS_H + +#include <asm/hardware.h> + +/* System Control Module */ + +/* AHB Arbiter Gen Configuration */ +#define SYS_AHBAGENCONF __REG(0xa0900000) + +/* BRC */ +#define SYS_BRC(x) __REG2(0xa0900004, (x)) + +/* Timer x Reload Count register */ +#define SYS_TRC(x) __REG2(0xa0900044, (x)) + +/* Timer x Read register */ +#define SYS_TR(x) __REG2(0xa0900084, (x)) + +/* Interrupt Vector Address Register Level x */ +#define SYS_IVA(x) __REG2(0xa09000c4, (x)) + +/* Interrupt Configuration registers */ +#define SYS_IC(x) __REG2(0xa0900144, (x)) + +/* ISRADDR */ +#define SYS_ISRADDR __REG(0xa0900164) + +/* Interrupt Status Active */ +#define SYS_ISA __REG(0xa0900168) + +/* Interrupt Status Raw */ +#define SYS_ISR __REG(0xa090016c) + +/* Timer Interrupt Status register */ +#define SYS_TIS __REG(0xa0900170) + +/* PLL Configuration register */ +#define SYS_PLL __REG(0xa0900188) + +/* PLL Configuration register: PLL SW change */ +#define SYS_PLL_SWC __REGBIT(15) +#define SYS_PLL_SWC_NO __REGVAL(SYS_PLL_SWC, 0) +#define SYS_PLL_SWC_YES __REGVAL(SYS_PLL_SWC, 1) + +/* Timer x Control register */ +#define SYS_TC(x) __REG2(0xa0900190, (x)) + +/* Timer x Control register: Timer enable */ +#define SYS_TCx_TEN __REGBIT(15) +#define SYS_TCx_TEN_DIS __REGVAL(SYS_TCx_TEN, 1) +#define SYS_TCx_TEN_EN __REGVAL(SYS_TCx_TEN, 1) + +/* Timer x Control register: CPU debug mode */ +#define SYS_TCx_TDBG __REGBIT(10) +#define SYS_TCx_TDBG_CONT __REGVAL(SYS_TCx_TDBG, 0) +#define SYS_TCx_TDBG_STOP __REGVAL(SYS_TCx_TDBG, 1) + +/* Timer x Control register: Interrupt clear */ +#define SYS_TCx_INTC __REGBIT(9) +#define SYS_TCx_INTC_UNSET __REGVAL(SYS_TCx_INTC, 0) +#define SYS_TCx_INTC_SET __REGVAL(SYS_TCx_INTC, 1) + +/* Timer x Control register: Timer clock select */ +#define SYS_TCx_TLCS __REGBITS(8, 6) +#define SYS_TCx_TLCS_CPU __REGVAL(SYS_TCx_TLCS, 0) /* CPU clock */ +#define SYS_TCx_TLCS_DIV2 __REGVAL(SYS_TCx_TLCS, 1) /* CPU clock / 2 */ +#define SYS_TCx_TLCS_DIV4 __REGVAL(SYS_TCx_TLCS, 2) /* CPU clock / 4 */ +#define SYS_TCx_TLCS_DIV8 __REGVAL(SYS_TCx_TLCS, 3) /* CPU clock / 8 */ +#define SYS_TCx_TLCS_DIV16 __REGVAL(SYS_TCx_TLCS, 4) /* CPU clock / 16 */ +#define SYS_TCx_TLCS_DIV32 __REGVAL(SYS_TCx_TLCS, 5) /* CPU clock / 32 */ +#define SYS_TCx_TLCS_DIV64 __REGVAL(SYS_TCx_TLCS, 6) /* CPU clock / 64 */ +#define SYS_TCx_TLCS_EXT __REGVAL(SYS_TCx_TLCS, 7) + +/* Timer x Control register: Timer mode */ +#define SYS_TCx_TM __REGBITS(5, 4) +#define SYS_TCx_TM_IEE __REGVAL(SYS_TCx_TM, 0) /* Internal timer or external event */ +#define SYS_TCx_TM_ELL __REGVAL(SYS_TCx_TM, 1) /* External low-level, gated timer */ +#define SYS_TCx_TM_EHL __REGVAL(SYS_TCx_TM, 2) /* External high-level, gated timer */ +#define SYS_TCx_TM_CONCAT __REGVAL(SYS_TCx_TM, 3) /* Concatenate the lower timer. */ + +/* Timer x Control register: Interrupt select */ +#define SYS_TCx_INTS __REGBIT(3) +#define SYS_TCx_INTS_DIS __REGVAL(SYS_TCx_INTS, 0) +#define SYS_TCx_INTS_EN __REGVAL(SYS_TCx_INTS, 1) + +/* Timer x Control register: Up/down select */ +#define SYS_TCx_UDS __REGBIT(2) +#define SYS_TCx_UDS_UP __REGVAL(SYS_TCx_UDS, 0) +#define SYS_TCx_UDS_DOWN __REGVAL(SYS_TCx_UDS, 1) + +/* Timer x Control register: 32- or 16-bit timer */ +#define SYS_TCx_TSZ __REGBIT(1) +#define SYS_TCx_TSZ_16 __REGVAL(SYS_TCx_TSZ, 0) +#define SYS_TCx_TSZ_32 __REGVAL(SYS_TCx_TSZ, 1) + +/* Timer x Control register: Reload enable */ +#define SYS_TCx_REN __REGBIT(0) +#define SYS_TCx_REN_DIS __REGVAL(SYS_TCx_REN, 0) +#define SYS_TCx_REN_EN __REGVAL(SYS_TCx_REN, 1) + +/* System Memory Chip Select x Dynamic Memory Base */ +#define SYS_SMCSDMB(x) __REG2(0xa09001d0, (x) << 1) + +/* System Memory Chip Select x Dynamic Memory Mask */ +#define SYS_SMCSDMM(x) __REG2(0xa09001d4, (x) << 1) + +/* System Memory Chip Select x Static Memory Base */ +#define SYS_SMCSSMB(x) __REG2(0xa09001f0, (x) << 1) + +/* System Memory Chip Select x Static Memory Base: Chip select x base */ +#define SYS_SMCSSMB_CSxB __REGBITS(31, 12) + +/* System Memory Chip Select x Static Memory Mask */ +#define SYS_SMCSSMM(x) __REG2(0xa09001f4, (x) << 1) + +/* System Memory Chip Select x Static Memory Mask: Chip select x mask */ +#define SYS_SMCSSMM_CSxM __REGBITS(31, 12) + +/* System Memory Chip Select x Static Memory Mask: Chip select x enable */ +#define SYS_SMCSSMM_CSEx __REGBIT(0) +#define SYS_SMCSSMM_CSEx_DIS __REGVAL(SYS_SMCSSMM_CSEx, 0) +#define SYS_SMCSSMM_CSEx_EN __REGVAL(SYS_SMCSSMM_CSEx, 1) + +/* General purpose, user-defined ID register */ +#define SYS_GENID __REG(0xa0900210) + +/* External Interrupt x Control register */ +#define SYS_EIC(x) __REG2(0xa0900214, (x)) + +/* External Interrupt x Control register: Status */ +#define SYS_EIC_STS __REGBIT(3) + +/* External Interrupt x Control register: Clear */ +#define SYS_EIC_CLR __REGBIT(2) + +/* External Interrupt x Control register: Polarity */ +#define SYS_EIC_PLTY __REGBIT(1) +#define SYS_EIC_PLTY_AH __REGVAL(SYS_EIC_PLTY, 0) +#define SYS_EIC_PLTY_AL __REGVAL(SYS_EIC_PLTY, 1) + +/* External Interrupt x Control register: Level edge */ +#define SYS_EIC_LVEDG __REGBIT(0) +#define SYS_EIC_LVEDG_LEVEL __REGVAL(SYS_EIC_LVEDG, 0) +#define SYS_EIC_LVEDG_EDGE __REGVAL(SYS_EIC_LVEDG, 1) + +#endif /* ifndef __ASM_ARCH_REGSSYS_H */ diff --git a/include/asm-arm/arch-ns9xxx/system.h b/include/asm-arm/arch-ns9xxx/system.h new file mode 100644 index 00000000000..e3cd4d31b3f --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/system.h @@ -0,0 +1,34 @@ +/* + * include/asm-arm/arch-ns9xxx/system.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include <asm/proc-fns.h> +#include <asm/arch-ns9xxx/regs-sys.h> +#include <asm/mach-types.h> + +static inline void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + u32 reg; + + reg = SYS_PLL >> 16; + REGSET(reg, SYS_PLL, SWC, YES); + SYS_PLL = reg; + + BUG(); +} + +#endif /* ifndef __ASM_ARCH_SYSTEM_H */ diff --git a/include/asm-arm/arch-ns9xxx/timex.h b/include/asm-arm/arch-ns9xxx/timex.h new file mode 100644 index 00000000000..f776cbd2622 --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/timex.h @@ -0,0 +1,20 @@ +/* + * include/asm-arm/arch-ns9xxx/timex.h + * + * Copyright (C) 2005-2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_TIMEX_H +#define __ASM_ARCH_TIMEX_H + +/* + * value for CLOCK_TICK_RATE stolen from include/asm-arm/arch-s3c2410/timex.h. + * See there for an explanation. + */ +#define CLOCK_TICK_RATE 12000000 + +#endif /* ifndef __ASM_ARCH_TIMEX_H */ diff --git a/include/asm-arm/arch-ns9xxx/uncompress.h b/include/asm-arm/arch-ns9xxx/uncompress.h new file mode 100644 index 00000000000..961ca7dc995 --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/uncompress.h @@ -0,0 +1,35 @@ +/* + * include/asm-arm/arch-ns9xxx/uncompress.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_UNCOMPRESS_H +#define __ASM_ARCH_UNCOMPRESS_H + +static void putc(char c) +{ + volatile u8 *base = (volatile u8 *)0x40000000; + int t = 0x10000; + + do { + if (base[5] & 0x20) { + base[0] = c; + break; + } + } while (--t); +} + +#define arch_decomp_setup() +#define arch_decomp_wdog() + +static void flush(void) +{ + /* nothing */ +} + +#endif /* ifndef __ASM_ARCH_UNCOMPRESS_H */ diff --git a/include/asm-arm/arch-ns9xxx/vmalloc.h b/include/asm-arm/arch-ns9xxx/vmalloc.h new file mode 100644 index 00000000000..2f3cb6f6be2 --- /dev/null +++ b/include/asm-arm/arch-ns9xxx/vmalloc.h @@ -0,0 +1,16 @@ +/* + * include/asm-arm/arch-ns9xxx/vmalloc.h + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * 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. + */ +#ifndef __ASM_ARCH_VMALLOC_H +#define __ASM_ARCH_VMALLOC_H + +#define VMALLOC_END (0xf0000000) + +#endif /* ifndef __ASM_ARCH_VMALLOC_H */ diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index e24f6b6c79a..aec835b6f05 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -463,9 +463,6 @@ * Serial Audio Controller */ -/* FIXME: This clash with SA1111 defines */ -#ifndef _ASM_ARCH_SA1111 - #define SACR0 __REG(0x40400000) /* Global Control Register */ #define SACR1 __REG(0x40400004) /* Serial Audio I 2 S/MSB-Justified Control Register */ #define SASR0 __REG(0x4040000C) /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */ @@ -474,8 +471,8 @@ #define SADIV __REG(0x40400060) /* Audio Clock Divider Register. */ #define SADR __REG(0x40400080) /* Serial Audio Data Register (TX and RX FIFO access Register). */ -#define SACR0_RFTH(x) (x << 12) /* Rx FIFO Interrupt or DMA Trigger Threshold */ -#define SACR0_TFTH(x) (x << 8) /* Tx FIFO Interrupt or DMA Trigger Threshold */ +#define SACR0_RFTH(x) ((x) << 12) /* Rx FIFO Interrupt or DMA Trigger Threshold */ +#define SACR0_TFTH(x) ((x) << 8) /* Tx FIFO Interrupt or DMA Trigger Threshold */ #define SACR0_STRF (1 << 5) /* FIFO Select for EFWR Special Function */ #define SACR0_EFWR (1 << 4) /* Enable EFWR Function */ #define SACR0_RST (1 << 3) /* FIFO, i2s Register Reset */ @@ -503,8 +500,6 @@ #define SAIMR_RFS (1 << 4) /* Enable Rx FIFO Service Interrupt */ #define SAIMR_TFS (1 << 3) /* Enable Tx FIFO Service Interrupt */ -#endif - /* * AC97 Controller registers */ @@ -1682,15 +1677,18 @@ #define SSSR_PINT (1 << 18) /* Peripheral Trailing Byte Interrupt */ #define SSPSP_FSRT (1 << 25) /* Frame Sync Relative Timing */ -#define SSPSP_DMYSTOP(x) (x << 23) /* Dummy Stop */ -#define SSPSP_SFRMWDTH(x) (x << 16) /* Serial Frame Width */ -#define SSPSP_SFRMDLY(x) (x << 9) /* Serial Frame Delay */ -#define SSPSP_DMYSTRT(x) (x << 7) /* Dummy Start */ -#define SSPSP_STRTDLY(x) (x << 4) /* Start Delay */ +#define SSPSP_DMYSTOP(x) ((x) << 23) /* Dummy Stop */ +#define SSPSP_SFRMWDTH(x) ((x) << 16) /* Serial Frame Width */ +#define SSPSP_SFRMDLY(x) ((x) << 9) /* Serial Frame Delay */ +#define SSPSP_DMYSTRT(x) ((x) << 7) /* Dummy Start */ +#define SSPSP_STRTDLY(x) ((x) << 4) /* Start Delay */ #define SSPSP_ETDS (1 << 3) /* End of Transfer data State */ #define SSPSP_SFRMP (1 << 2) /* Serial Frame Polarity */ -#define SSPSP_SCMODE(x) (x << 0) /* Serial Bit Rate Clock Mode */ +#define SSPSP_SCMODE(x) ((x) << 0) /* Serial Bit Rate Clock Mode */ +#define SSACD_SCDB (1 << 3) /* SSPSYSCLK Divider Bypass */ +#define SSACD_ACPS(x) ((x) << 4) /* Audio clock PLL select */ +#define SSACD_ACDS(x) ((x) << 0) /* Audio clock divider select */ #define SSCR0_P1 __REG(0x41000000) /* SSP Port 1 Control Register 0 */ #define SSCR1_P1 __REG(0x41000004) /* SSP Port 1 Control Register 1 */ diff --git a/include/asm-arm/arch-pxa/udc.h b/include/asm-arm/arch-pxa/udc.h index 646480d3725..8bc6f9c3e3e 100644 --- a/include/asm-arm/arch-pxa/udc.h +++ b/include/asm-arm/arch-pxa/udc.h @@ -9,3 +9,33 @@ extern void pxa_set_udc_info(struct pxa2xx_udc_mach_info *info); +static inline int udc_gpio_to_irq(unsigned gpio) +{ + return IRQ_GPIO(gpio & GPIO_MD_MASK_NR); +} + +static inline void udc_gpio_init_vbus(unsigned gpio) +{ + pxa_gpio_mode((gpio & GPIO_MD_MASK_NR) | GPIO_IN); +} + +static inline void udc_gpio_init_pullup(unsigned gpio) +{ + pxa_gpio_mode((gpio & GPIO_MD_MASK_NR) | GPIO_OUT | GPIO_DFLT_LOW); +} + +static inline int udc_gpio_get(unsigned gpio) +{ + return (GPLR(gpio) & GPIO_bit(gpio)) != 0; +} + +static inline void udc_gpio_set(unsigned gpio, int is_on) +{ + int mask = GPIO_bit(gpio); + + if (is_on) + GPSR(gpio) = mask; + else + GPCR(gpio) = mask; +} + diff --git a/include/asm-arm/arch-realview/hardware.h b/include/asm-arm/arch-realview/hardware.h index 9ca76dc3a7a..aa78fe087ab 100644 --- a/include/asm-arm/arch-realview/hardware.h +++ b/include/asm-arm/arch-realview/hardware.h @@ -26,7 +26,7 @@ #include <asm/arch/platform.h> /* macro to get at IO space when running virtually */ -#define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000) +#define IO_ADDRESS(x) ((((x) & 0x0effffff) | (((x) >> 4) & 0x0f000000)) + 0xf0000000) #define __io_address(n) __io(IO_ADDRESS(n)) #endif diff --git a/include/asm-arm/arch-realview/irqs.h b/include/asm-arm/arch-realview/irqs.h index c16223c9588..5a5db56f86b 100644 --- a/include/asm-arm/arch-realview/irqs.h +++ b/include/asm-arm/arch-realview/irqs.h @@ -65,6 +65,21 @@ #define IRQ_AACI (IRQ_GIC_START + INT_AACI) #define IRQ_ETH (IRQ_GIC_START + INT_ETH) #define IRQ_USB (IRQ_GIC_START + INT_USB) +#define IRQ_PMU_CPU0 (IRQ_GIC_START + INT_PMU_CPU0) +#define IRQ_PMU_CPU1 (IRQ_GIC_START + INT_PMU_CPU1) +#define IRQ_PMU_CPU2 (IRQ_GIC_START + INT_PMU_CPU2) +#define IRQ_PMU_CPU3 (IRQ_GIC_START + INT_PMU_CPU3) +#define IRQ_PMU_SCU0 (IRQ_GIC_START + INT_PMU_SCU0) +#define IRQ_PMU_SCU1 (IRQ_GIC_START + INT_PMU_SCU1) +#define IRQ_PMU_SCU2 (IRQ_GIC_START + INT_PMU_SCU2) +#define IRQ_PMU_SCU3 (IRQ_GIC_START + INT_PMU_SCU3) +#define IRQ_PMU_SCU4 (IRQ_GIC_START + INT_PMU_SCU4) +#define IRQ_PMU_SCU5 (IRQ_GIC_START + INT_PMU_SCU5) +#define IRQ_PMU_SCU6 (IRQ_GIC_START + INT_PMU_SCU6) +#define IRQ_PMU_SCU7 (IRQ_GIC_START + INT_PMU_SCU7) + +#define IRQ_EB_IRQ1 (IRQ_GIC_START + INT_EB_IRQ1) +#define IRQ_EB_IRQ2 (IRQ_GIC_START + INT_EB_IRQ2) #define IRQMASK_WDOGINT INTMASK_WDOGINT #define IRQMASK_SOFTINT INTMASK_SOFTINT @@ -103,4 +118,4 @@ #define IRQMASK_ETH INTMASK_ETH #define IRQMASK_USB INTMASK_USB -#define NR_IRQS (IRQ_GIC_START + 64) +#define NR_IRQS (IRQ_GIC_START + 96) diff --git a/include/asm-arm/arch-realview/platform.h b/include/asm-arm/arch-realview/platform.h index 18d7c18b738..6e0eab95a3a 100644 --- a/include/asm-arm/arch-realview/platform.h +++ b/include/asm-arm/arch-realview/platform.h @@ -207,11 +207,25 @@ #define REALVIEW_GIC_CPU_BASE 0x10040000 /* Generic interrupt controller CPU interface */ #define REALVIEW_GIC_DIST_BASE 0x10041000 /* Generic interrupt controller distributor */ #else +#ifdef CONFIG_REALVIEW_MPCORE_REVB #define REALVIEW_MPCORE_SCU_BASE 0x10100000 /* SCU registers */ #define REALVIEW_GIC_CPU_BASE 0x10100100 /* Generic interrupt controller CPU interface */ #define REALVIEW_TWD_BASE 0x10100700 #define REALVIEW_TWD_SIZE 0x00000100 #define REALVIEW_GIC_DIST_BASE 0x10101000 /* Generic interrupt controller distributor */ +#define REALVIEW_MPCORE_L220_BASE 0x10102000 /* L220 registers */ +#define REALVIEW_MPCORE_SYS_PLD_CTRL1 0xD8 /* Register offset for MPCore sysctl */ +#else +#define REALVIEW_MPCORE_SCU_BASE 0x1F000000 /* SCU registers */ +#define REALVIEW_GIC_CPU_BASE 0x1F000100 /* Generic interrupt controller CPU interface */ +#define REALVIEW_TWD_BASE 0x1F000700 +#define REALVIEW_TWD_SIZE 0x00000100 +#define REALVIEW_GIC_DIST_BASE 0x1F001000 /* Generic interrupt controller distributor */ +#define REALVIEW_MPCORE_L220_BASE 0x1F002000 /* L220 registers */ +#define REALVIEW_MPCORE_SYS_PLD_CTRL1 0x74 /* Register offset for MPCore sysctl */ +#endif +#define REALVIEW_GIC1_CPU_BASE 0x10040000 /* Generic interrupt controller CPU interface */ +#define REALVIEW_GIC1_DIST_BASE 0x10041000 /* Generic interrupt controller distributor */ #endif #define REALVIEW_SMC_BASE 0x10080000 /* SMC */ /* Reserved 0x10090000 - 0x100EFFFF */ @@ -306,7 +320,11 @@ #define INT_USB 29 /* USB controller */ #define INT_TSPENINT 30 /* Touchscreen pen */ #define INT_TSKPADINT 31 /* Touchscreen keypad */ + #else + +#define MAX_GIC_NR 2 + #define INT_AACI 0 #define INT_TIMERINT0_1 1 #define INT_TIMERINT2_3 2 diff --git a/include/asm-arm/arch-realview/scu.h b/include/asm-arm/arch-realview/scu.h new file mode 100644 index 00000000000..cc293640178 --- /dev/null +++ b/include/asm-arm/arch-realview/scu.h @@ -0,0 +1,8 @@ +#ifndef __ASMARM_ARCH_SCU_H +#define __ASMARM_ARCH_SCU_H + +#include <asm/arch/platform.h> + +#define SCU_BASE REALVIEW_MPCORE_SCU_BASE + +#endif diff --git a/include/asm-arm/arch-s3c2410/dma.h b/include/asm-arm/arch-s3c2410/dma.h index 58ffa7ba3c8..c6e8d8f6493 100644 --- a/include/asm-arm/arch-s3c2410/dma.h +++ b/include/asm-arm/arch-s3c2410/dma.h @@ -51,13 +51,19 @@ enum dma_ch { DMACH_UART0_SRC2, /* s3c2412 second uart sources */ DMACH_UART1_SRC2, DMACH_UART2_SRC2, + DMACH_UART3, /* s3c2443 has extra uart */ + DMACH_UART3_SRC2, DMACH_MAX, /* the end entry */ }; #define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */ /* we have 4 dma channels */ -#define S3C2410_DMA_CHANNELS (4) +#ifndef CONFIG_CPU_S3C2443 +#define S3C2410_DMA_CHANNELS (4) +#else +#define S3C2410_DMA_CHANNELS (6) +#endif /* types */ @@ -321,6 +327,7 @@ extern int s3c2410_dma_set_buffdone_fn(dmach_t, s3c2410_dma_cbfn_t rtn); #define S3C2410_DMA_DCDST (0x1C) #define S3C2410_DMA_DMASKTRIG (0x20) #define S3C2412_DMA_DMAREQSEL (0x24) +#define S3C2443_DMA_DMAREQSEL (0x24) #define S3C2410_DISRCC_INC (1<<0) #define S3C2410_DISRCC_APB (1<<1) @@ -415,4 +422,31 @@ extern int s3c2410_dma_set_buffdone_fn(dmach_t, s3c2410_dma_cbfn_t rtn); #define S3C2412_DMAREQSEL_UART2_1 S3C2412_DMAREQSEL_SRC(24) #endif + +#define S3C2443_DMAREQSEL_SRC(x) ((x)<<1) + +#define S3C2443_DMAREQSEL_HW (1) + +#define S3C2443_DMAREQSEL_SPI0TX S3C2443_DMAREQSEL_SRC(0) +#define S3C2443_DMAREQSEL_SPI0RX S3C2443_DMAREQSEL_SRC(1) +#define S3C2443_DMAREQSEL_SPI1TX S3C2443_DMAREQSEL_SRC(2) +#define S3C2443_DMAREQSEL_SPI1RX S3C2443_DMAREQSEL_SRC(3) +#define S3C2443_DMAREQSEL_I2STX S3C2443_DMAREQSEL_SRC(4) +#define S3C2443_DMAREQSEL_I2SRX S3C2443_DMAREQSEL_SRC(5) +#define S3C2443_DMAREQSEL_TIMER S3C2443_DMAREQSEL_SRC(9) +#define S3C2443_DMAREQSEL_SDI S3C2443_DMAREQSEL_SRC(10) +#define S3C2443_DMAREQSEL_XDREQ0 S3C2443_DMAREQSEL_SRC(17) +#define S3C2443_DMAREQSEL_XDREQ1 S3C2443_DMAREQSEL_SRC(18) +#define S3C2443_DMAREQSEL_UART0_0 S3C2443_DMAREQSEL_SRC(19) +#define S3C2443_DMAREQSEL_UART0_1 S3C2443_DMAREQSEL_SRC(20) +#define S3C2443_DMAREQSEL_UART1_0 S3C2443_DMAREQSEL_SRC(21) +#define S3C2443_DMAREQSEL_UART1_1 S3C2443_DMAREQSEL_SRC(22) +#define S3C2443_DMAREQSEL_UART2_0 S3C2443_DMAREQSEL_SRC(23) +#define S3C2443_DMAREQSEL_UART2_1 S3C2443_DMAREQSEL_SRC(24) +#define S3C2443_DMAREQSEL_UART3_0 S3C2443_DMAREQSEL_SRC(25) +#define S3C2443_DMAREQSEL_UART3_1 S3C2443_DMAREQSEL_SRC(26) +#define S3C2443_DMAREQSEL_PCMOUT S3C2443_DMAREQSEL_SRC(27) +#define S3C2443_DMAREQSEL_PCMIN S3C2443_DMAREQSEL_SRC(28) +#define S3C2443_DMAREQSEL_MICIN S3C2443_DMAREQSEL_SRC(29) + #endif /* __ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-s3c2410/irqs.h b/include/asm-arm/arch-s3c2410/irqs.h index 4b7cff456c4..c79cb181991 100644 --- a/include/asm-arm/arch-s3c2410/irqs.h +++ b/include/asm-arm/arch-s3c2410/irqs.h @@ -34,10 +34,10 @@ #define IRQ_EINT4t7 S3C2410_IRQ(4) /* 20 */ #define IRQ_EINT8t23 S3C2410_IRQ(5) #define IRQ_RESERVED6 S3C2410_IRQ(6) /* for s3c2410 */ -#define IRQ_CAM S3C2410_IRQ(6) /* for s3c2440 */ +#define IRQ_CAM S3C2410_IRQ(6) /* for s3c2440,s3c2443 */ #define IRQ_BATT_FLT S3C2410_IRQ(7) #define IRQ_TICK S3C2410_IRQ(8) /* 24 */ -#define IRQ_WDT S3C2410_IRQ(9) +#define IRQ_WDT S3C2410_IRQ(9) /* WDT/AC97 for s3c2443 */ #define IRQ_TIMER0 S3C2410_IRQ(10) #define IRQ_TIMER1 S3C2410_IRQ(11) #define IRQ_TIMER2 S3C2410_IRQ(12) @@ -45,7 +45,7 @@ #define IRQ_TIMER4 S3C2410_IRQ(14) #define IRQ_UART2 S3C2410_IRQ(15) #define IRQ_LCD S3C2410_IRQ(16) /* 32 */ -#define IRQ_DMA0 S3C2410_IRQ(17) +#define IRQ_DMA0 S3C2410_IRQ(17) /* IRQ_DMA for s3c2443 */ #define IRQ_DMA1 S3C2410_IRQ(18) #define IRQ_DMA2 S3C2410_IRQ(19) #define IRQ_DMA3 S3C2410_IRQ(20) @@ -94,29 +94,63 @@ * these need to be ordered in number of appearance in the * SUBSRC mask register */ -#define IRQ_S3CUART_RX0 S3C2410_IRQ(54) /* 70 */ -#define IRQ_S3CUART_TX0 S3C2410_IRQ(55) /* 71 */ -#define IRQ_S3CUART_ERR0 S3C2410_IRQ(56) -#define IRQ_S3CUART_RX1 S3C2410_IRQ(57) -#define IRQ_S3CUART_TX1 S3C2410_IRQ(58) -#define IRQ_S3CUART_ERR1 S3C2410_IRQ(59) +#define S3C2410_IRQSUB(x) S3C2410_IRQ((x)+54) -#define IRQ_S3CUART_RX2 S3C2410_IRQ(60) -#define IRQ_S3CUART_TX2 S3C2410_IRQ(61) -#define IRQ_S3CUART_ERR2 S3C2410_IRQ(62) +#define IRQ_S3CUART_RX0 S3C2410_IRQSUB(0) /* 70 */ +#define IRQ_S3CUART_TX0 S3C2410_IRQSUB(1) +#define IRQ_S3CUART_ERR0 S3C2410_IRQSUB(2) -#define IRQ_TC S3C2410_IRQ(63) -#define IRQ_ADC S3C2410_IRQ(64) +#define IRQ_S3CUART_RX1 S3C2410_IRQSUB(3) /* 73 */ +#define IRQ_S3CUART_TX1 S3C2410_IRQSUB(4) +#define IRQ_S3CUART_ERR1 S3C2410_IRQSUB(5) -/* extra irqs for s3c2440 */ +#define IRQ_S3CUART_RX2 S3C2410_IRQSUB(6) /* 76 */ +#define IRQ_S3CUART_TX2 S3C2410_IRQSUB(7) +#define IRQ_S3CUART_ERR2 S3C2410_IRQSUB(8) -#define IRQ_S3C2440_CAM_C S3C2410_IRQ(65) -#define IRQ_S3C2440_CAM_P S3C2410_IRQ(66) -#define IRQ_S3C2440_WDT S3C2410_IRQ(67) -#define IRQ_S3C2440_AC97 S3C2410_IRQ(68) +#define IRQ_TC S3C2410_IRQSUB(9) +#define IRQ_ADC S3C2410_IRQSUB(10) -#define NR_IRQS (IRQ_S3C2440_AC97+1) +/* extra irqs for s3c2440 */ +#define IRQ_S3C2440_CAM_C S3C2410_IRQSUB(11) /* S3C2443 too */ +#define IRQ_S3C2440_CAM_P S3C2410_IRQSUB(12) /* S3C2443 too */ +#define IRQ_S3C2440_WDT S3C2410_IRQSUB(13) +#define IRQ_S3C2440_AC97 S3C2410_IRQSUB(14) + +/* irqs for s3c2443 */ + +#define IRQ_S3C2443_DMA S3C2410_IRQ(17) /* IRQ_DMA1 */ +#define IRQ_S3C2443_UART3 S3C2410_IRQ(18) /* IRQ_DMA2 */ +#define IRQ_S3C2443_CFCON S3C2410_IRQ(19) /* IRQ_DMA3 */ +#define IRQ_S3C2443_SDI1 S3C2410_IRQ(20) /* IRQ_SDI */ +#define IRQ_S3C2443_NAND S3C2410_IRQ(24) /* reserved */ + +#define IRQ_S3C2443_LCD1 S3C2410_IRQSUB(14) +#define IRQ_S3C2443_LCD2 S3C2410_IRQSUB(15) +#define IRQ_S3C2443_LCD3 S3C2410_IRQSUB(16) +#define IRQ_S3C2443_LCD4 S3C2410_IRQSUB(17) + +#define IRQ_S3C2443_DMA0 S3C2410_IRQSUB(18) +#define IRQ_S3C2443_DMA1 S3C2410_IRQSUB(19) +#define IRQ_S3C2443_DMA2 S3C2410_IRQSUB(20) +#define IRQ_S3C2443_DMA3 S3C2410_IRQSUB(21) +#define IRQ_S3C2443_DMA4 S3C2410_IRQSUB(22) +#define IRQ_S3C2443_DMA5 S3C2410_IRQSUB(23) + +/* UART3 */ +#define IRQ_S3C2443_RX3 S3C2410_IRQSUB(24) +#define IRQ_S3C2443_TX3 S3C2410_IRQSUB(25) +#define IRQ_S3C2443_ERR3 S3C2410_IRQSUB(26) + +#define IRQ_S3C2443_WDT S3C2410_IRQSUB(27) +#define IRQ_S3C2443_AC97 S3C2410_IRQSUB(28) + +#ifdef CONFIG_CPU_S3C2443 +#define NR_IRQS (IRQ_S3C2443_AC97+1) +#else +#define NR_IRQS (IRQ_S3C2440_AC97+1) +#endif #endif /* __ASM_ARCH_IRQ_H */ diff --git a/include/asm-arm/arch-s3c2410/regs-adc.h b/include/asm-arm/arch-s3c2410/regs-adc.h index 3196a2849e8..c7f231963e7 100644 --- a/include/asm-arm/arch-s3c2410/regs-adc.h +++ b/include/asm-arm/arch-s3c2410/regs-adc.h @@ -41,7 +41,7 @@ #define S3C2410_ADCTSC_XP_SEN (1<<4) #define S3C2410_ADCTSC_PULL_UP_DISABLE (1<<3) #define S3C2410_ADCTSC_AUTO_PST (1<<2) -#define S3C2410_ADCTSC_XY_PST (0x3<<0) +#define S3C2410_ADCTSC_XY_PST(x) (((x)&0x3)<<0) /* ADCDAT0 Bits */ #define S3C2410_ADCDAT0_UPDOWN (1<<15) diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h index eae91694edc..dea578b8f7f 100644 --- a/include/asm-arm/arch-s3c2410/regs-gpio.h +++ b/include/asm-arm/arch-s3c2410/regs-gpio.h @@ -201,7 +201,7 @@ #define S3C2400_GPBDAT S3C2410_GPIOREG(0x0C) #define S3C2400_GPBUP S3C2410_GPIOREG(0x10) -/* no i/o pin in port b can have value 3! */ +/* no i/o pin in port b can have value 3 (unless it is a s3c2443) ! */ #define S3C2410_GPB0 S3C2410_GPIONO(S3C2410_GPIO_BANKB, 0) #define S3C2410_GPB0_INP (0x00 << 0) @@ -242,6 +242,7 @@ #define S3C2410_GPB5_INP (0x00 << 10) #define S3C2410_GPB5_OUTP (0x01 << 10) #define S3C2410_GPB5_nXBACK (0x02 << 10) +#define S3C2443_GPB5_XBACK (0x03 << 10) #define S3C2400_GPB5_DATA21 (0x02 << 10) #define S3C2400_GPB5_nCTS1 (0x03 << 10) @@ -249,6 +250,7 @@ #define S3C2410_GPB6_INP (0x00 << 12) #define S3C2410_GPB6_OUTP (0x01 << 12) #define S3C2410_GPB6_nXBREQ (0x02 << 12) +#define S3C2443_GPB6_XBREQ (0x03 << 12) #define S3C2400_GPB6_DATA22 (0x02 << 12) #define S3C2400_GPB6_nRTS1 (0x03 << 12) @@ -256,6 +258,7 @@ #define S3C2410_GPB7_INP (0x00 << 14) #define S3C2410_GPB7_OUTP (0x01 << 14) #define S3C2410_GPB7_nXDACK1 (0x02 << 14) +#define S3C2443_GPB7_XDACK1 (0x03 << 14) #define S3C2400_GPB7_DATA23 (0x02 << 14) #define S3C2410_GPB8 S3C2410_GPIONO(S3C2410_GPIO_BANKB, 8) @@ -268,6 +271,7 @@ #define S3C2410_GPB9_INP (0x00 << 18) #define S3C2410_GPB9_OUTP (0x01 << 18) #define S3C2410_GPB9_nXDACK0 (0x02 << 18) +#define S3C2443_GPB9_XDACK0 (0x03 << 18) #define S3C2400_GPB9_DATA25 (0x02 << 18) #define S3C2400_GPB9_I2SSDI (0x03 << 18) @@ -275,6 +279,7 @@ #define S3C2410_GPB10_INP (0x00 << 20) #define S3C2410_GPB10_OUTP (0x01 << 20) #define S3C2410_GPB10_nXDRE0 (0x02 << 20) +#define S3C2443_GPB10_XDREQ0 (0x03 << 20) #define S3C2400_GPB10_DATA26 (0x02 << 20) #define S3C2400_GPB10_nSS (0x03 << 20) @@ -556,6 +561,7 @@ #define S3C2410_GPE0_INP (0x00 << 0) #define S3C2410_GPE0_OUTP (0x01 << 0) #define S3C2410_GPE0_I2SLRCK (0x02 << 0) +#define S3C2443_GPE0_AC_nRESET (0x03 << 0) #define S3C2400_GPE0_EINT0 (0x02 << 0) #define S3C2410_GPE0_MASK (0x03 << 0) @@ -563,6 +569,7 @@ #define S3C2410_GPE1_INP (0x00 << 2) #define S3C2410_GPE1_OUTP (0x01 << 2) #define S3C2410_GPE1_I2SSCLK (0x02 << 2) +#define S3C2443_GPE1_AC_SYNC (0x03 << 2) #define S3C2400_GPE1_EINT1 (0x02 << 2) #define S3C2400_GPE1_nSS (0x03 << 2) #define S3C2410_GPE1_MASK (0x03 << 2) @@ -571,6 +578,7 @@ #define S3C2410_GPE2_INP (0x00 << 4) #define S3C2410_GPE2_OUTP (0x01 << 4) #define S3C2410_GPE2_CDCLK (0x02 << 4) +#define S3C2443_GPE2_AC_BITCLK (0x03 << 4) #define S3C2400_GPE2_EINT2 (0x02 << 4) #define S3C2400_GPE2_I2SSDI (0x03 << 4) @@ -578,6 +586,7 @@ #define S3C2410_GPE3_INP (0x00 << 6) #define S3C2410_GPE3_OUTP (0x01 << 6) #define S3C2410_GPE3_I2SSDI (0x02 << 6) +#define S3C2443_GPE3_AC_SDI (0x03 << 6) #define S3C2400_GPE3_EINT3 (0x02 << 6) #define S3C2400_GPE3_nCTS1 (0x03 << 6) #define S3C2410_GPE3_nSS0 (0x03 << 6) @@ -587,6 +596,7 @@ #define S3C2410_GPE4_INP (0x00 << 8) #define S3C2410_GPE4_OUTP (0x01 << 8) #define S3C2410_GPE4_I2SSDO (0x02 << 8) +#define S3C2443_GPE4_AC_SDO (0x03 << 8) #define S3C2400_GPE4_EINT4 (0x02 << 8) #define S3C2400_GPE4_nRTS1 (0x03 << 8) #define S3C2410_GPE4_I2SSDI (0x03 << 8) @@ -596,6 +606,7 @@ #define S3C2410_GPE5_INP (0x00 << 10) #define S3C2410_GPE5_OUTP (0x01 << 10) #define S3C2410_GPE5_SDCLK (0x02 << 10) +#define S3C2443_GPE5_SD1_CLK (0x02 << 10) #define S3C2400_GPE5_EINT5 (0x02 << 10) #define S3C2400_GPE5_TCLK1 (0x03 << 10) @@ -603,24 +614,32 @@ #define S3C2410_GPE6_INP (0x00 << 12) #define S3C2410_GPE6_OUTP (0x01 << 12) #define S3C2410_GPE6_SDCMD (0x02 << 12) +#define S3C2443_GPE6_SD1_CMD (0x02 << 12) +#define S3C2443_GPE6_AC_BITCLK (0x03 << 12) #define S3C2400_GPE6_EINT6 (0x02 << 12) #define S3C2410_GPE7 S3C2410_GPIONO(S3C2410_GPIO_BANKE, 7) #define S3C2410_GPE7_INP (0x00 << 14) #define S3C2410_GPE7_OUTP (0x01 << 14) #define S3C2410_GPE7_SDDAT0 (0x02 << 14) +#define S3C2443_GPE5_SD1_DAT0 (0x02 << 14) +#define S3C2443_GPE7_AC_SDI (0x03 << 14) #define S3C2400_GPE7_EINT7 (0x02 << 14) #define S3C2410_GPE8 S3C2410_GPIONO(S3C2410_GPIO_BANKE, 8) #define S3C2410_GPE8_INP (0x00 << 16) #define S3C2410_GPE8_OUTP (0x01 << 16) #define S3C2410_GPE8_SDDAT1 (0x02 << 16) +#define S3C2443_GPE8_SD1_DAT1 (0x02 << 16) +#define S3C2443_GPE8_AC_SDO (0x03 << 16) #define S3C2400_GPE8_nXDACK0 (0x02 << 16) #define S3C2410_GPE9 S3C2410_GPIONO(S3C2410_GPIO_BANKE, 9) #define S3C2410_GPE9_INP (0x00 << 18) #define S3C2410_GPE9_OUTP (0x01 << 18) #define S3C2410_GPE9_SDDAT2 (0x02 << 18) +#define S3C2443_GPE9_SD1_DAT2 (0x02 << 18) +#define S3C2443_GPE9_AC_SYNC (0x03 << 18) #define S3C2400_GPE9_nXDACK1 (0x02 << 18) #define S3C2400_GPE9_nXBACK (0x03 << 18) @@ -628,6 +647,8 @@ #define S3C2410_GPE10_INP (0x00 << 20) #define S3C2410_GPE10_OUTP (0x01 << 20) #define S3C2410_GPE10_SDDAT3 (0x02 << 20) +#define S3C2443_GPE10_SD1_DAT3 (0x02 << 20) +#define S3C2443_GPE10_AC_nRESET (0x03 << 20) #define S3C2400_GPE10_nXDREQ0 (0x02 << 20) #define S3C2410_GPE11 S3C2410_GPIONO(S3C2410_GPIO_BANKE, 11) @@ -796,6 +817,7 @@ #define S3C2400_GPG4_MMCCLK (0x02 << 8) #define S3C2400_GPG4_I2SSDI (0x03 << 8) #define S3C2410_GPG4_LCDPWREN (0x03 << 8) +#define S3C2443_GPG4_LCDPWRDN (0x03 << 8) #define S3C2410_GPG5 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 5) #define S3C2410_GPG5_INP (0x00 << 10) @@ -803,7 +825,7 @@ #define S3C2410_GPG5_EINT13 (0x02 << 10) #define S3C2400_GPG5_MMCCMD (0x02 << 10) #define S3C2400_GPG5_IICSDA (0x03 << 10) -#define S3C2410_GPG5_SPIMISO1 (0x03 << 10) +#define S3C2410_GPG5_SPIMISO1 (0x03 << 10) /* not s3c2443 */ #define S3C2410_GPG6 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 6) #define S3C2410_GPG6_INP (0x00 << 12) @@ -845,6 +867,7 @@ #define S3C2410_GPG11_OUTP (0x01 << 22) #define S3C2410_GPG11_EINT19 (0x02 << 22) #define S3C2410_GPG11_TCLK1 (0x03 << 22) +#define S3C2443_GPG11_CF_nIREQ (0x03 << 22) #define S3C2410_GPG12 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 12) #define S3C2410_GPG12_INP (0x00 << 24) @@ -852,25 +875,28 @@ #define S3C2410_GPG12_EINT20 (0x02 << 24) #define S3C2410_GPG12_XMON (0x03 << 24) #define S3C2442_GPG12_nSPICS0 (0x03 << 24) +#define S3C2443_GPG12_nINPACK (0x03 << 24) #define S3C2410_GPG13 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 13) #define S3C2410_GPG13_INP (0x00 << 26) #define S3C2410_GPG13_OUTP (0x01 << 26) #define S3C2410_GPG13_EINT21 (0x02 << 26) #define S3C2410_GPG13_nXPON (0x03 << 26) +#define S3C2443_GPG13_CF_nREG (0x03 << 26) #define S3C2410_GPG14 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 14) #define S3C2410_GPG14_INP (0x00 << 28) #define S3C2410_GPG14_OUTP (0x01 << 28) #define S3C2410_GPG14_EINT22 (0x02 << 28) #define S3C2410_GPG14_YMON (0x03 << 28) +#define S3C2443_GPG14_CF_RESET (0x03 << 28) #define S3C2410_GPG15 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 15) #define S3C2410_GPG15_INP (0x00 << 30) #define S3C2410_GPG15_OUTP (0x01 << 30) #define S3C2410_GPG15_EINT23 (0x02 << 30) #define S3C2410_GPG15_nYPON (0x03 << 30) - +#define S3C2443_GPG15_CF_PWR (0x03 << 30) #define S3C2410_GPG_PUPDIS(x) (1<<(x)) diff --git a/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h b/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h new file mode 100644 index 00000000000..ff0536d2de4 --- /dev/null +++ b/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h @@ -0,0 +1,194 @@ +/* linux/include/asm-arm/arch-s3c2410/regs-clock.h + * + * Copyright (c) 2007 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * 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. + * + * S3C2443 clock register definitions +*/ + +#ifndef __ASM_ARM_REGS_S3C2443_CLOCK +#define __ASM_ARM_REGS_S3C2443_CLOCK + +#define S3C2443_CLKREG(x) ((x) + S3C24XX_VA_CLKPWR) + +#define S3C2443_PLLCON_MDIVSHIFT 16 +#define S3C2443_PLLCON_PDIVSHIFT 8 +#define S3C2443_PLLCON_SDIVSHIFT 0 +#define S3C2443_PLLCON_MDIVMASK ((1<<(1+(23-16)))-1) +#define S3C2443_PLLCON_PDIVMASK ((1<<(1+(9-8)))-1) +#define S3C2443_PLLCON_SDIVMASK (3) + +#define S3C2443_MPLLCON S3C2443_CLKREG(0x10) +#define S3C2443_EPLLCON S3C2443_CLKREG(0x18) +#define S3C2443_CLKSRC S3C2443_CLKREG(0x20) +#define S3C2443_CLKDIV0 S3C2443_CLKREG(0x24) +#define S3C2443_CLKDIV1 S3C2443_CLKREG(0x28) +#define S3C2443_HCLKCON S3C2443_CLKREG(0x30) +#define S3C2443_PCLKCON S3C2443_CLKREG(0x34) +#define S3C2443_SCLKCON S3C2443_CLKREG(0x38) +#define S3C2443_PWRMODE S3C2443_CLKREG(0x40) +#define S3C2443_SWRST S3C2443_CLKREG(0x44) +#define S3C2443_BUSPRI0 S3C2443_CLKREG(0x50) +#define S3C2443_SYSID S3C2443_CLKREG(0x5C) +#define S3C2443_PWRCFG S3C2443_CLKREG(0x60) +#define S3C2443_RSTCON S3C2443_CLKREG(0x64) + +#define S3C2443_SWRST_RESET (0x533c2443) + +#define S3C2443_PLLCON_OFF (1<<24) + +#define S3C2443_CLKSRC_I2S_EXT (1<<14) +#define S3C2443_CLKSRC_I2S_EPLLDIV (0<<14) +#define S3C2443_CLKSRC_I2S_EPLLREF (2<<14) +#define S3C2443_CLKSRC_I2S_EPLLREF3 (3<<14) +#define S3C2443_CLKSRC_I2S_MASK (3<<14) + +#define S3C2443_CLKSRC_EPLLREF_XTAL (2<<8) +#define S3C2443_CLKSRC_EPLLREF_EXTCLK (3<<8) +#define S3C2443_CLKSRC_EPLLREF_MPLLREF (0<<8) +#define S3C2443_CLKSRC_EPLLREF_MPLLREF2 (1<<8) +#define S3C2443_CLKSRC_EPLLREF_MASK (3<<8) + +#define S3C2443_CLKSRC_ESYSCLK_EPLL (1<<6) +#define S3C2443_CLKSRC_MSYSCLK_MPLL (1<<4) +#define S3C2443_CLKSRC_EXTCLK_DIV (1<<3) + +#define S3C2443_CLKDIV0_DVS (1<<13) +#define S3C2443_CLKDIV0_HALF_HCLK (1<<3) +#define S3C2443_CLKDIV0_HALF_PCLK (1<<2) + +#define S3C2443_CLKDIV0_HCLKDIV_MASK (3<<0) + +#define S3C2443_CLKDIV0_EXTDIV_MASK (3<<6) +#define S3C2443_CLKDIV0_EXTDIV_SHIFT (6) + +#define S3C2443_CLKDIV0_PREDIV_MASK (3<<4) +#define S3C2443_CLKDIV0_PREDIV_SHIFT (4) + +#define S3C2443_CLKDIV0_ARMDIV_MASK (15<<9) +#define S3C2443_CLKDIV0_ARMDIV_SHIFT (9) +#define S3C2443_CLKDIV0_ARMDIV_1 (0<<9) +#define S3C2443_CLKDIV0_ARMDIV_2 (8<<9) +#define S3C2443_CLKDIV0_ARMDIV_3 (2<<9) +#define S3C2443_CLKDIV0_ARMDIV_4 (9<<9) +#define S3C2443_CLKDIV0_ARMDIV_6 (10<<9) +#define S3C2443_CLKDIV0_ARMDIV_8 (11<<9) +#define S3C2443_CLKDIV0_ARMDIV_12 (13<<9) +#define S3C2443_CLKDIV0_ARMDIV_16 (15<<9) + +/* S3C2443_CLKDIV1 */ + +#define S3C2443_CLKDIV1_CAMDIV_MASK (15<<26) +#define S3C2443_CLKDIV1_CAMDIV_SHIFT (26) + +#define S3C2443_CLKDIV1_HSSPIDIV_MASK (3<<24) +#define S3C2443_CLKDIV1_HSSPIDIV_SHIFT (24) + +#define S3C2443_CLKDIV1_DISPDIV_MASK (0xff<<16) +#define S3C2443_CLKDIV1_DISPDIV_SHIFT (16) + +#define S3C2443_CLKDIV1_I2SDIV_MASK (15<<12) +#define S3C2443_CLKDIV1_I2SDIV_SHIFT (12) + +#define S3C2443_CLKDIV1_UARTDIV_MASK (15<<8) +#define S3C2443_CLKDIV1_UARTDIV_SHIFT (8) + +#define S3C2443_CLKDIV1_HSMMCDIV_MASK (3<<6) +#define S3C2443_CLKDIV1_HSMMCDIV_SHIFT (6) + +#define S3C2443_CLKDIV1_USBHOSTDIV_MASK (3<<4) +#define S3C2443_CLKDIV1_USBHOSTDIV_SHIFT (4) + +#define S3C2443_CLKCON_NAND + +#define S3C2443_HCLKCON_DMA0 (1<<0) +#define S3C2443_HCLKCON_DMA1 (1<<1) +#define S3C2443_HCLKCON_DMA2 (1<<2) +#define S3C2443_HCLKCON_DMA3 (1<<3) +#define S3C2443_HCLKCON_DMA4 (1<<4) +#define S3C2443_HCLKCON_DMA5 (1<<5) +#define S3C2443_HCLKCON_CAMIF (1<<8) +#define S3C2443_HCLKCON_DISP (1<<9) +#define S3C2443_HCLKCON_LCDC (1<<10) +#define S3C2443_HCLKCON_USBH (1<<11) +#define S3C2443_HCLKCON_USBD (1<<12) +#define S3C2443_HCLKCON_HSMMC (1<<16) +#define S3C2443_HCLKCON_CFC (1<<17) +#define S3C2443_HCLKCON_SSMC (1<<18) +#define S3C2443_HCLKCON_DRAMC (1<<19) + +#define S3C2443_PCLKCON_UART0 (1<<0) +#define S3C2443_PCLKCON_UART1 (1<<1) +#define S3C2443_PCLKCON_UART2 (1<<2) +#define S3C2443_PCLKCON_UART3 (1<<3) +#define S3C2443_PCLKCON_IIC (1<<4) +#define S3C2443_PCLKCON_SDI (1<<5) +#define S3C2443_PCLKCON_ADC (1<<7) +#define S3C2443_PCLKCON_IIS (1<<9) +#define S3C2443_PCLKCON_PWMT (1<<10) +#define S3C2443_PCLKCON_WDT (1<<11) +#define S3C2443_PCLKCON_RTC (1<<12) +#define S3C2443_PCLKCON_GPIO (1<<13) +#define S3C2443_PCLKCON_SPI0 (1<<14) +#define S3C2443_PCLKCON_SPI1 (1<<15) + +#define S3C2443_SCLKCON_DDRCLK (1<<16) +#define S3C2443_SCLKCON_SSMCCLK (1<<15) +#define S3C2443_SCLKCON_HSSPICLK (1<<14) +#define S3C2443_SCLKCON_HSMMCCLK_EXT (1<<13) +#define S3C2443_SCLKCON_HSMMCCLK_EPLL (1<<12) +#define S3C2443_SCLKCON_CAMCLK (1<<11) +#define S3C2443_SCLKCON_DISPCLK (1<<10) +#define S3C2443_SCLKCON_I2SCLK (1<<9) +#define S3C2443_SCLKCON_UARTCLK (1<<8) +#define S3C2443_SCLKCON_USBHOST (1<<1) + +#include <asm/div64.h> + +static inline unsigned int +s3c2443_get_mpll(unsigned int pllval, unsigned int baseclk) +{ + unsigned int mdiv, pdiv, sdiv; + uint64_t fvco; + + mdiv = pllval >> S3C2443_PLLCON_MDIVSHIFT; + pdiv = pllval >> S3C2443_PLLCON_PDIVSHIFT; + sdiv = pllval >> S3C2443_PLLCON_SDIVSHIFT; + + mdiv &= S3C2443_PLLCON_MDIVMASK; + pdiv &= S3C2443_PLLCON_PDIVMASK; + sdiv &= S3C2443_PLLCON_SDIVMASK; + + fvco = (uint64_t)baseclk * (2 * (mdiv + 8)); + do_div(fvco, pdiv << sdiv); + + return (unsigned int)fvco; +} + +static inline unsigned int +s3c2443_get_epll(unsigned int pllval, unsigned int baseclk) +{ + unsigned int mdiv, pdiv, sdiv; + uint64_t fvco; + + mdiv = pllval >> S3C2443_PLLCON_MDIVSHIFT; + pdiv = pllval >> S3C2443_PLLCON_PDIVSHIFT; + sdiv = pllval >> S3C2443_PLLCON_SDIVSHIFT; + + mdiv &= S3C2443_PLLCON_MDIVMASK; + pdiv &= S3C2443_PLLCON_PDIVMASK; + sdiv &= S3C2443_PLLCON_SDIVMASK; + + fvco = (uint64_t)baseclk * (mdiv + 8); + do_div(fvco, (pdiv + 2) << sdiv); + + return (unsigned int)fvco; +} + +#endif /* __ASM_ARM_REGS_S3C2443_CLOCK */ + diff --git a/include/asm-arm/arch-s3c2410/regs-serial.h b/include/asm-arm/arch-s3c2410/regs-serial.h index 46f52401d13..8946702a87f 100644 --- a/include/asm-arm/arch-s3c2410/regs-serial.h +++ b/include/asm-arm/arch-s3c2410/regs-serial.h @@ -35,10 +35,12 @@ #define S3C24XX_VA_UART0 (S3C24XX_VA_UART) #define S3C24XX_VA_UART1 (S3C24XX_VA_UART + 0x4000 ) #define S3C24XX_VA_UART2 (S3C24XX_VA_UART + 0x8000 ) +#define S3C24XX_VA_UART3 (S3C24XX_VA_UART + 0xC000 ) #define S3C2410_PA_UART0 (S3C24XX_PA_UART) #define S3C2410_PA_UART1 (S3C24XX_PA_UART + 0x4000 ) #define S3C2410_PA_UART2 (S3C24XX_PA_UART + 0x8000 ) +#define S3C2443_PA_UART3 (S3C24XX_PA_UART + 0xC000 ) #define S3C2410_URXH (0x24) #define S3C2410_UTXH (0x20) @@ -73,6 +75,8 @@ #define S3C2440_UCON_UCLK (1<<10) #define S3C2440_UCON_PCLK2 (2<<10) #define S3C2440_UCON_FCLK (3<<10) +#define S3C2443_UCON_EPLL (3<<10) + #define S3C2440_UCON2_FCLK_EN (1<<15) #define S3C2440_UCON0_DIVMASK (15 << 12) #define S3C2440_UCON1_DIVMASK (15 << 12) @@ -93,6 +97,8 @@ #define S3C2410_UCON_TXIRQMODE (1<<2) #define S3C2410_UCON_RXIRQMODE (1<<0) #define S3C2410_UCON_RXFIFO_TOI (1<<7) +#define S3C2443_UCON_RXERR_IRQEN (1<<6) +#define S3C2443_UCON_LOOPBACK (1<<5) #define S3C2410_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ S3C2410_UCON_RXILEVEL | \ @@ -127,7 +133,7 @@ #define S3C2410_UMCOM_AFC (1<<4) #define S3C2410_UMCOM_RTS_LOW (1<<0) -#define S3C2412_UMCON_AFC_63 (0<<5) +#define S3C2412_UMCON_AFC_63 (0<<5) /* same as s3c2443 */ #define S3C2412_UMCON_AFC_56 (1<<5) #define S3C2412_UMCON_AFC_48 (2<<5) #define S3C2412_UMCON_AFC_40 (3<<5) @@ -143,6 +149,7 @@ #define S3C2410_UFSTAT_RXMASK (15<<0) #define S3C2410_UFSTAT_RXSHIFT (0) +/* UFSTAT S3C2443 same as S3C2440 */ #define S3C2440_UFSTAT_TXFULL (1<<14) #define S3C2440_UFSTAT_RXFULL (1<<6) #define S3C2440_UFSTAT_TXSHIFT (8) @@ -157,6 +164,8 @@ #define S3C2410_UERSTAT_OVERRUN (1<<0) #define S3C2410_UERSTAT_FRAME (1<<2) #define S3C2410_UERSTAT_BREAK (1<<3) +#define S3C2443_UERSTAT_PARITY (1<<1) + #define S3C2410_UERSTAT_ANY (S3C2410_UERSTAT_OVERRUN | \ S3C2410_UERSTAT_FRAME | \ S3C2410_UERSTAT_BREAK) @@ -164,6 +173,8 @@ #define S3C2410_UMSTAT_CTS (1<<0) #define S3C2410_UMSTAT_DeltaCTS (1<<2) +#define S3C2443_DIVSLOT (0x2C) + #ifndef __ASSEMBLY__ /* struct s3c24xx_uart_clksrc diff --git a/include/asm-arm/arch-s3c2410/reset.h b/include/asm-arm/arch-s3c2410/reset.h new file mode 100644 index 00000000000..4f866cdecab --- /dev/null +++ b/include/asm-arm/arch-s3c2410/reset.h @@ -0,0 +1,22 @@ +/* linux/include/asm-arm/arch-s3c2410/reset.h + * + * Copyright (c) 2007 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * 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. + * + * S3C2410 CPU reset controls +*/ + +#ifndef __ASM_ARCH_RESET_H +#define __ASM_ARCH_RESET_H __FILE__ + +/* This allows the over-ride of the default reset code +*/ + +extern void (*s3c24xx_reset_hook)(void); + +#endif /* __ASM_ARCH_RESET_H */ diff --git a/include/asm-arm/arch-s3c2410/system.h b/include/asm-arm/arch-s3c2410/system.h index ecf250db45f..1c74ef17da3 100644 --- a/include/asm-arm/arch-s3c2410/system.h +++ b/include/asm-arm/arch-s3c2410/system.h @@ -15,15 +15,16 @@ #include <asm/arch/map.h> #include <asm/arch/idle.h> +#include <asm/arch/reset.h> #include <asm/arch/regs-watchdog.h> #include <asm/arch/regs-clock.h> void (*s3c24xx_idle)(void); +void (*s3c24xx_reset_hook)(void); void s3c24xx_default_idle(void) { - void __iomem *reg = S3C2410_CLKCON; unsigned long tmp; int i; @@ -33,16 +34,18 @@ void s3c24xx_default_idle(void) /* Warning: going into idle state upsets jtag scanning */ - __raw_writel(__raw_readl(reg) | (1<<2), reg); + __raw_writel(__raw_readl(S3C2410_CLKCON) | S3C2410_CLKCON_IDLE, + S3C2410_CLKCON); /* the samsung port seems to do a loop and then unset idle.. */ for (i = 0; i < 50; i++) { - tmp += __raw_readl(reg); /* ensure loop not optimised out */ + tmp += __raw_readl(S3C2410_CLKCON); /* ensure loop not optimised out */ } /* this bit is not cleared on re-start... */ - __raw_writel(__raw_readl(reg) & ~(1<<2), reg); + __raw_writel(__raw_readl(S3C2410_CLKCON) & ~S3C2410_CLKCON_IDLE, + S3C2410_CLKCON); } static void arch_idle(void) @@ -53,7 +56,6 @@ static void arch_idle(void) s3c24xx_default_idle(); } - static void arch_reset(char mode) { @@ -61,6 +63,9 @@ arch_reset(char mode) cpu_reset(0); } + if (s3c24xx_reset_hook) + s3c24xx_reset_hook(); + printk("arch_reset: attempting watchdog reset\n"); __raw_writel(0, S3C2410_WTCON); /* disable watchdog, to be safe */ diff --git a/include/asm-arm/arch-s3c2410/udc.h b/include/asm-arm/arch-s3c2410/udc.h new file mode 100644 index 00000000000..e59ec339d61 --- /dev/null +++ b/include/asm-arm/arch-s3c2410/udc.h @@ -0,0 +1,36 @@ +/* linux/include/asm/arch-s3c2410/udc.h + * + * Copyright (c) 2005 Arnaud Patard <arnaud.patard@rtp-net.org> + * + * + * 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. + * + * + * Changelog: + * 14-Mar-2005 RTP Created file + * 02-Aug-2005 RTP File rename + * 07-Sep-2005 BJD Minor cleanups, changed cmd to enum + * 18-Jan-2007 HMW Add per-platform vbus_draw function +*/ + +#ifndef __ASM_ARM_ARCH_UDC_H +#define __ASM_ARM_ARCH_UDC_H + +enum s3c2410_udc_cmd_e { + S3C2410_UDC_P_ENABLE = 1, /* Pull-up enable */ + S3C2410_UDC_P_DISABLE = 2, /* Pull-up disable */ + S3C2410_UDC_P_RESET = 3, /* UDC reset, in case of */ +}; + +struct s3c2410_udc_mach_info { + void (*udc_command)(enum s3c2410_udc_cmd_e); + void (*vbus_draw)(unsigned int ma); + unsigned int vbus_pin; + unsigned char vbus_pin_inverted; +}; + +extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *); + +#endif /* __ASM_ARM_ARCH_UDC_H */ diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h index 5f531ea0305..afad32c76e6 100644 --- a/include/asm-arm/cacheflush.h +++ b/include/asm-arm/cacheflush.h @@ -185,9 +185,15 @@ struct cpu_cache_fns { void (*coherent_user_range)(unsigned long, unsigned long); void (*flush_kern_dcache_page)(void *); - void (*dma_inv_range)(unsigned long, unsigned long); - void (*dma_clean_range)(unsigned long, unsigned long); - void (*dma_flush_range)(unsigned long, unsigned long); + void (*dma_inv_range)(const void *, const void *); + void (*dma_clean_range)(const void *, const void *); + void (*dma_flush_range)(const void *, const void *); +}; + +struct outer_cache_fns { + void (*inv_range)(unsigned long, unsigned long); + void (*clean_range)(unsigned long, unsigned long); + void (*flush_range)(unsigned long, unsigned long); }; /* @@ -240,9 +246,40 @@ extern void __cpuc_flush_dcache_page(void *); #define dmac_clean_range __glue(_CACHE,_dma_clean_range) #define dmac_flush_range __glue(_CACHE,_dma_flush_range) -extern void dmac_inv_range(unsigned long, unsigned long); -extern void dmac_clean_range(unsigned long, unsigned long); -extern void dmac_flush_range(unsigned long, unsigned long); +extern void dmac_inv_range(const void *, const void *); +extern void dmac_clean_range(const void *, const void *); +extern void dmac_flush_range(const void *, const void *); + +#endif + +#ifdef CONFIG_OUTER_CACHE + +extern struct outer_cache_fns outer_cache; + +static inline void outer_inv_range(unsigned long start, unsigned long end) +{ + if (outer_cache.inv_range) + outer_cache.inv_range(start, end); +} +static inline void outer_clean_range(unsigned long start, unsigned long end) +{ + if (outer_cache.clean_range) + outer_cache.clean_range(start, end); +} +static inline void outer_flush_range(unsigned long start, unsigned long end) +{ + if (outer_cache.flush_range) + outer_cache.flush_range(start, end); +} + +#else + +static inline void outer_inv_range(unsigned long start, unsigned long end) +{ } +static inline void outer_clean_range(unsigned long start, unsigned long end) +{ } +static inline void outer_flush_range(unsigned long start, unsigned long end) +{ } #endif diff --git a/include/asm-arm/checksum.h b/include/asm-arm/checksum.h index 8c0bb5bb14e..eaa0efd8d0d 100644 --- a/include/asm-arm/checksum.h +++ b/include/asm-arm/checksum.h @@ -40,13 +40,27 @@ __wsum csum_partial_copy_from_user(const void __user *src, void *dst, int len, __wsum sum, int *err_ptr); /* + * Fold a partial checksum without adding pseudo headers + */ +static inline __sum16 csum_fold(__wsum sum) +{ + __asm__( + "add %0, %1, %1, ror #16 @ csum_fold" + : "=r" (sum) + : "r" (sum) + : "cc"); + return (__force __sum16)(~(__force u32)sum >> 16); +} + +/* * This is a version of ip_compute_csum() optimized for IP headers, * which always checksum on 4 octet boundaries. */ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) { - unsigned int sum, tmp1; + unsigned int tmp1; + __wsum sum; __asm__ __volatile__( "ldr %0, [%1], #4 @ ip_fast_csum \n\ @@ -62,29 +76,11 @@ ip_fast_csum(const void *iph, unsigned int ihl) subne %2, %2, #1 @ without destroying \n\ bne 1b @ the carry flag \n\ adcs %0, %0, %3 \n\ - adc %0, %0, #0 \n\ - adds %0, %0, %0, lsl #16 \n\ - addcs %0, %0, #0x10000 \n\ - mvn %0, %0 \n\ - mov %0, %0, lsr #16" + adc %0, %0, #0" : "=r" (sum), "=r" (iph), "=r" (ihl), "=r" (tmp1) : "1" (iph), "2" (ihl) : "cc", "memory"); - return (__force __sum16)sum; -} - -/* - * Fold a partial checksum without adding pseudo headers - */ -static inline __sum16 csum_fold(__wsum sum) -{ - __asm__( - "adds %0, %1, %1, lsl #16 @ csum_fold \n\ - addcs %0, %0, #0x10000" - : "=r" (sum) - : "r" (sum) - : "cc"); - return (__force __sum16)(~(__force u32)sum >> 16); + return csum_fold(sum); } static inline __wsum @@ -114,23 +110,7 @@ static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len, unsigned short proto, __wsum sum) { - __asm__( - "adds %0, %1, %2 @ csum_tcpudp_magic \n\ - adcs %0, %0, %3 \n" -#ifdef __ARMEB__ - "adcs %0, %0, %4 \n" -#else - "adcs %0, %0, %4, lsl #8 \n" -#endif - "adcs %0, %0, %5 \n\ - adc %0, %0, #0 \n\ - adds %0, %0, %0, lsl #16 \n\ - addcs %0, %0, #0x10000 \n\ - mvn %0, %0" - : "=&r"(sum) - : "r" (sum), "r" (daddr), "r" (saddr), "r" (len), "Ir" (htons(proto)) - : "cc"); - return (__force __sum16)((__force u32)sum >> 16); + return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); } diff --git a/include/asm-arm/device.h b/include/asm-arm/device.h index d8f9872b0e2..c61642b4060 100644 --- a/include/asm-arm/device.h +++ b/include/asm-arm/device.h @@ -3,5 +3,13 @@ * * This file is released under the GPLv2 */ -#include <asm-generic/device.h> +#ifndef ASMARM_DEVICE_H +#define ASMARM_DEVICE_H +struct dev_archdata { +#ifdef CONFIG_DMABOUNCE + struct dmabounce_device_info *dmabounce; +#endif +}; + +#endif diff --git a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h index 9bc46b486af..abfb75b654c 100644 --- a/include/asm-arm/dma-mapping.h +++ b/include/asm-arm/dma-mapping.h @@ -17,7 +17,7 @@ * platforms with CONFIG_DMABOUNCE. * Use the driver DMA support - see dma-mapping.h (dma_sync_*) */ -extern void consistent_sync(void *kaddr, size_t size, int rw); +extern void consistent_sync(const void *kaddr, size_t size, int rw); /* * Return whether the given device DMA address mask can be supported @@ -61,6 +61,22 @@ static inline int dma_mapping_error(dma_addr_t dma_addr) return dma_addr == ~0; } +/* + * Dummy noncoherent implementation. We don't provide a dma_cache_sync + * function so drivers using this API are highlighted with build warnings. + */ +static inline void * +dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) +{ + return NULL; +} + +static inline void +dma_free_noncoherent(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t handle) +{ +} + /** * dma_alloc_coherent - allocate consistent memory for DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices diff --git a/include/asm-arm/domain.h b/include/asm-arm/domain.h index 4c2885abbe6..3c12a762530 100644 --- a/include/asm-arm/domain.h +++ b/include/asm-arm/domain.h @@ -57,6 +57,7 @@ __asm__ __volatile__( \ "mcr p15, 0, %0, c3, c0 @ set domain" \ : : "r" (x)); \ + isb(); \ } while (0) #define modify_domain(dom,type) \ diff --git a/include/asm-arm/hardware/arm_scu.h b/include/asm-arm/hardware/arm_scu.h index 9903f60c84b..7d28eb5a175 100644 --- a/include/asm-arm/hardware/arm_scu.h +++ b/include/asm-arm/hardware/arm_scu.h @@ -1,6 +1,8 @@ #ifndef ASMARM_HARDWARE_ARM_SCU_H #define ASMARM_HARDWARE_ARM_SCU_H +#include <asm/arch/scu.h> + /* * SCU registers */ diff --git a/include/asm-arm/hardware/cache-l2x0.h b/include/asm-arm/hardware/cache-l2x0.h new file mode 100644 index 00000000000..54029a74039 --- /dev/null +++ b/include/asm-arm/hardware/cache-l2x0.h @@ -0,0 +1,56 @@ +/* + * include/asm-arm/hardware/cache-l2x0.h + * + * Copyright (C) 2007 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARM_HARDWARE_L2X0_H +#define __ASM_ARM_HARDWARE_L2X0_H + +#define L2X0_CACHE_ID 0x000 +#define L2X0_CACHE_TYPE 0x004 +#define L2X0_CTRL 0x100 +#define L2X0_AUX_CTRL 0x104 +#define L2X0_EVENT_CNT_CTRL 0x200 +#define L2X0_EVENT_CNT1_CFG 0x204 +#define L2X0_EVENT_CNT0_CFG 0x208 +#define L2X0_EVENT_CNT1_VAL 0x20C +#define L2X0_EVENT_CNT0_VAL 0x210 +#define L2X0_INTR_MASK 0x214 +#define L2X0_MASKED_INTR_STAT 0x218 +#define L2X0_RAW_INTR_STAT 0x21C +#define L2X0_INTR_CLEAR 0x220 +#define L2X0_CACHE_SYNC 0x730 +#define L2X0_INV_LINE_PA 0x770 +#define L2X0_INV_WAY 0x77C +#define L2X0_CLEAN_LINE_PA 0x7B0 +#define L2X0_CLEAN_LINE_IDX 0x7B8 +#define L2X0_CLEAN_WAY 0x7BC +#define L2X0_CLEAN_INV_LINE_PA 0x7F0 +#define L2X0_CLEAN_INV_LINE_IDX 0x7F8 +#define L2X0_CLEAN_INV_WAY 0x7FC +#define L2X0_LOCKDOWN_WAY_D 0x900 +#define L2X0_LOCKDOWN_WAY_I 0x904 +#define L2X0_TEST_OPERATION 0xF00 +#define L2X0_LINE_DATA 0xF10 +#define L2X0_LINE_TAG 0xF30 +#define L2X0_DEBUG_CTRL 0xF40 + +#ifndef __ASSEMBLY__ +extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask); +#endif + +#endif diff --git a/include/asm-arm/hardware/gic.h b/include/asm-arm/hardware/gic.h index 3fa5eb70f64..966e428ad32 100644 --- a/include/asm-arm/hardware/gic.h +++ b/include/asm-arm/hardware/gic.h @@ -33,8 +33,9 @@ #define GIC_DIST_SOFTINT 0xf00 #ifndef __ASSEMBLY__ -void gic_dist_init(void __iomem *base); -void gic_cpu_init(void __iomem *base); +void gic_dist_init(unsigned int gic_nr, void __iomem *base, unsigned int irq_start); +void gic_cpu_init(unsigned int gic_nr, void __iomem *base); +void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); void gic_raise_softirq(cpumask_t cpumask, unsigned int irq); #endif diff --git a/include/asm-arm/hardware/iop3xx.h b/include/asm-arm/hardware/iop3xx.h index 13ac8a4cd01..c91b546e20e 100644 --- a/include/asm-arm/hardware/iop3xx.h +++ b/include/asm-arm/hardware/iop3xx.h @@ -37,6 +37,13 @@ extern void gpio_line_set(int line, int value); #define IOP3XX_PERIPHERAL_PHYS_BASE 0xffffe000 #define IOP3XX_PERIPHERAL_VIRT_BASE 0xfeffe000 #define IOP3XX_PERIPHERAL_SIZE 0x00002000 +#define IOP3XX_PERIPHERAL_UPPER_PA (IOP3XX_PERIPHERAL_PHYS_BASE +\ + IOP3XX_PERIPHERAL_SIZE - 1) +#define IOP3XX_PERIPHERAL_UPPER_VA (IOP3XX_PERIPHERAL_VIRT_BASE +\ + IOP3XX_PERIPHERAL_SIZE - 1) +#define IOP3XX_PMMR_PHYS_TO_VIRT(addr) (u32) ((u32) addr -\ + (IOP3XX_PERIPHERAL_PHYS_BASE\ + - IOP3XX_PERIPHERAL_VIRT_BASE)) #define IOP3XX_REG_ADDR(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + (reg)) /* Address Translation Unit */ @@ -258,12 +265,20 @@ extern void gpio_line_set(int line, int value); #define IOP3XX_PCI_LOWER_IO_PA 0x90000000 #define IOP3XX_PCI_LOWER_IO_VA 0xfe000000 #define IOP3XX_PCI_LOWER_IO_BA (*IOP3XX_OIOWTVR) +#define IOP3XX_PCI_UPPER_IO_PA (IOP3XX_PCI_LOWER_IO_PA +\ + IOP3XX_PCI_IO_WINDOW_SIZE - 1) +#define IOP3XX_PCI_UPPER_IO_VA (IOP3XX_PCI_LOWER_IO_VA +\ + IOP3XX_PCI_IO_WINDOW_SIZE - 1) +#define IOP3XX_PCI_IO_PHYS_TO_VIRT(addr) (((u32) addr -\ + IOP3XX_PCI_LOWER_IO_PA) +\ + IOP3XX_PCI_LOWER_IO_VA) #ifndef __ASSEMBLY__ void iop3xx_map_io(void); void iop3xx_init_time(unsigned long); unsigned long iop3xx_gettimeoffset(void); +void iop_init_cp6_handler(void); extern struct platform_device iop3xx_i2c0_device; extern struct platform_device iop3xx_i2c1_device; diff --git a/include/asm-arm/hardware/sa1111.h b/include/asm-arm/hardware/sa1111.h index 6aa0a5b75b6..61b1d05c7df 100644 --- a/include/asm-arm/hardware/sa1111.h +++ b/include/asm-arm/hardware/sa1111.h @@ -29,6 +29,9 @@ #define _SA1111(x) ((x) + sa1111->resource.start) #endif +#define sa1111_writel(val,addr) __raw_writel(val, addr) +#define sa1111_readl(addr) __raw_readl(addr) + /* * 26 bits of the SA-1110 address bus are available to the SA-1111. * Use these when feeding target addresses to the DMA engines. @@ -45,14 +48,6 @@ #define SA1111_SAC_DMA_MIN_XFER (0x800) /* - * SA1111 register definitions. - */ -#define __CCREG(x) __REGP(SA1111_VBASE + (x)) - -#define sa1111_writel(val,addr) __raw_writel(val, addr) -#define sa1111_readl(addr) __raw_readl(addr) - -/* * System Bus Interface (SBI) * * Registers @@ -194,55 +189,37 @@ * SADR Serial Audio Data Register (16 x 32-bit) */ -#define _SACR0 _SA1111( 0x0600 ) -#define _SACR1 _SA1111( 0x0604 ) -#define _SACR2 _SA1111( 0x0608 ) -#define _SASR0 _SA1111( 0x060c ) -#define _SASR1 _SA1111( 0x0610 ) -#define _SASCR _SA1111( 0x0618 ) -#define _L3_CAR _SA1111( 0x061c ) -#define _L3_CDR _SA1111( 0x0620 ) -#define _ACCAR _SA1111( 0x0624 ) -#define _ACCDR _SA1111( 0x0628 ) -#define _ACSAR _SA1111( 0x062c ) -#define _ACSDR _SA1111( 0x0630 ) -#define _SADTCS _SA1111( 0x0634 ) -#define _SADTSA _SA1111( 0x0638 ) -#define _SADTCA _SA1111( 0x063c ) -#define _SADTSB _SA1111( 0x0640 ) -#define _SADTCB _SA1111( 0x0644 ) -#define _SADRCS _SA1111( 0x0648 ) -#define _SADRSA _SA1111( 0x064c ) -#define _SADRCA _SA1111( 0x0650 ) -#define _SADRSB _SA1111( 0x0654 ) -#define _SADRCB _SA1111( 0x0658 ) -#define _SAITR _SA1111( 0x065c ) -#define _SADR _SA1111( 0x0680 ) - -#define SACR0 __CCREG(0x0600) -#define SACR1 __CCREG(0x0604) -#define SACR2 __CCREG(0x0608) -#define SASR0 __CCREG(0x060c) -#define SASR1 __CCREG(0x0610) -#define SASCR __CCREG(0x0618) -#define L3_CAR __CCREG(0x061c) -#define L3_CDR __CCREG(0x0620) -#define ACCAR __CCREG(0x0624) -#define ACCDR __CCREG(0x0628) -#define ACSAR __CCREG(0x062c) -#define ACSDR __CCREG(0x0630) -#define SADTCS __CCREG(0x0634) -#define SADTSA __CCREG(0x0638) -#define SADTCA __CCREG(0x063c) -#define SADTSB __CCREG(0x0640) -#define SADTCB __CCREG(0x0644) -#define SADRCS __CCREG(0x0648) -#define SADRSA __CCREG(0x064c) -#define SADRCA __CCREG(0x0650) -#define SADRSB __CCREG(0x0654) -#define SADRCB __CCREG(0x0658) -#define SAITR __CCREG(0x065c) -#define SADR __CCREG(0x0680) +#define SA1111_SERAUDIO 0x0600 + +/* + * These are offsets from the above base. + */ +#define SA1111_SACR0 0x00 +#define SA1111_SACR1 0x04 +#define SA1111_SACR2 0x08 +#define SA1111_SASR0 0x0c +#define SA1111_SASR1 0x10 +#define SA1111_SASCR 0x18 +#define SA1111_L3_CAR 0x1c +#define SA1111_L3_CDR 0x20 +#define SA1111_ACCAR 0x24 +#define SA1111_ACCDR 0x28 +#define SA1111_ACSAR 0x2c +#define SA1111_ACSDR 0x30 +#define SA1111_SADTCS 0x34 +#define SA1111_SADTSA 0x38 +#define SA1111_SADTCA 0x3c +#define SA1111_SADTSB 0x40 +#define SA1111_SADTCB 0x44 +#define SA1111_SADRCS 0x48 +#define SA1111_SADRSA 0x4c +#define SA1111_SADRCA 0x50 +#define SA1111_SADRSB 0x54 +#define SA1111_SADRCB 0x58 +#define SA1111_SAITR 0x5c +#define SA1111_SADR 0x80 + +#ifndef CONFIG_ARCH_PXA #define SACR0_ENB (1<<0) #define SACR0_BCKD (1<<2) @@ -330,6 +307,8 @@ #define SAITR_RDBDA (1<<10) #define SAITR_RDBDB (1<<11) +#endif /* !CONFIG_ARCH_PXA */ + /* * General-Purpose I/O Interface * diff --git a/include/asm-arm/kexec.h b/include/asm-arm/kexec.h new file mode 100644 index 00000000000..8c1c6162a80 --- /dev/null +++ b/include/asm-arm/kexec.h @@ -0,0 +1,30 @@ +#ifndef _ARM_KEXEC_H +#define _ARM_KEXEC_H + +#ifdef CONFIG_KEXEC + +/* Maximum physical address we can use pages from */ +#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) +/* Maximum address we can reach in physical address mode */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) +/* Maximum address we can use for the control code buffer */ +#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE + +#define KEXEC_CONTROL_CODE_SIZE 4096 + +#define KEXEC_ARCH KEXEC_ARCH_ARM + +#ifndef __ASSEMBLY__ + +#define MAX_NOTE_BYTES 1024 + +struct kimage; +/* Provide a dummy definition to avoid build failures. */ +static inline void crash_setup_regs(struct pt_regs *newregs, + struct pt_regs *oldregs) { } + +#endif /* __ASSEMBLY__ */ + +#endif /* CONFIG_KEXEC */ + +#endif /* _ARM_KEXEC_H */ diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h index b8cf2d5ec30..7b2bafce21a 100644 --- a/include/asm-arm/pgtable.h +++ b/include/asm-arm/pgtable.h @@ -175,19 +175,29 @@ extern void __pgd_error(const char *file, int line, unsigned long val); #ifndef __ASSEMBLY__ /* - * The following macros handle the cache and bufferable bits... + * The pgprot_* and protection_map entries will be fixed up in runtime + * to include the cachable and bufferable bits based on memory policy, + * as well as any architecture dependent bits like global/ASID and SMP + * shared mapping bits. */ #define _L_PTE_DEFAULT L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_CACHEABLE | L_PTE_BUFFERABLE #define _L_PTE_READ L_PTE_USER | L_PTE_EXEC +extern pgprot_t pgprot_user; extern pgprot_t pgprot_kernel; -#define PAGE_NONE __pgprot(_L_PTE_DEFAULT) -#define PAGE_COPY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ) -#define PAGE_SHARED __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_WRITE) -#define PAGE_READONLY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ) +#define PAGE_NONE pgprot_user +#define PAGE_COPY __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ) +#define PAGE_SHARED __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ | \ + L_PTE_WRITE) +#define PAGE_READONLY __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ) #define PAGE_KERNEL pgprot_kernel +#define __PAGE_NONE __pgprot(_L_PTE_DEFAULT) +#define __PAGE_COPY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ) +#define __PAGE_SHARED __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_WRITE) +#define __PAGE_READONLY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ) + #endif /* __ASSEMBLY__ */ /* @@ -198,23 +208,23 @@ extern pgprot_t pgprot_kernel; * 2) If we could do execute protection, then read is implied * 3) write implies read permissions */ -#define __P000 PAGE_NONE -#define __P001 PAGE_READONLY -#define __P010 PAGE_COPY -#define __P011 PAGE_COPY -#define __P100 PAGE_READONLY -#define __P101 PAGE_READONLY -#define __P110 PAGE_COPY -#define __P111 PAGE_COPY - -#define __S000 PAGE_NONE -#define __S001 PAGE_READONLY -#define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED -#define __S100 PAGE_READONLY -#define __S101 PAGE_READONLY -#define __S110 PAGE_SHARED -#define __S111 PAGE_SHARED +#define __P000 __PAGE_NONE +#define __P001 __PAGE_READONLY +#define __P010 __PAGE_COPY +#define __P011 __PAGE_COPY +#define __P100 __PAGE_READONLY +#define __P101 __PAGE_READONLY +#define __P110 __PAGE_COPY +#define __P111 __PAGE_COPY + +#define __S000 __PAGE_NONE +#define __S001 __PAGE_READONLY +#define __S010 __PAGE_SHARED +#define __S011 __PAGE_SHARED +#define __S100 __PAGE_READONLY +#define __S101 __PAGE_READONLY +#define __S110 __PAGE_SHARED +#define __S111 __PAGE_SHARED #ifndef __ASSEMBLY__ /* diff --git a/arch/arm/mach-s3c2410/clock.h b/include/asm-arm/plat-s3c24xx/clock.h index 7f0ea03e1d4..f6135dbb9fa 100644 --- a/arch/arm/mach-s3c2410/clock.h +++ b/include/asm-arm/plat-s3c24xx/clock.h @@ -1,4 +1,4 @@ -/* +/* linux/include/asm-arm/plat-s3c24xx/clock.h * linux/arch/arm/mach-s3c2410/clock.h * * Copyright (c) 2004-2005 Simtec Electronics diff --git a/arch/arm/mach-s3c2410/common-smdk.h b/include/asm-arm/plat-s3c24xx/common-smdk.h index 0e3a3be330a..58d9094c935 100644 --- a/arch/arm/mach-s3c2410/common-smdk.h +++ b/include/asm-arm/plat-s3c24xx/common-smdk.h @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/common-smdk.h +/* linux/include/asm-arm/plat-s3c24xx/common-smdk.h * * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> diff --git a/arch/arm/mach-s3c2410/cpu.h b/include/asm-arm/plat-s3c24xx/cpu.h index be42e4032a6..15dd1881090 100644 --- a/arch/arm/mach-s3c2410/cpu.h +++ b/include/asm-arm/plat-s3c24xx/cpu.h @@ -1,4 +1,4 @@ -/* arch/arm/mach-s3c2410/cpu.h +/* linux/include/asm-arm/plat-s3c24xx/cpu.h * * Copyright (c) 2004-2005 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -67,3 +67,4 @@ extern struct sysdev_class s3c2410_sysclass; extern struct sysdev_class s3c2412_sysclass; extern struct sysdev_class s3c2440_sysclass; extern struct sysdev_class s3c2442_sysclass; +extern struct sysdev_class s3c2443_sysclass; diff --git a/arch/arm/mach-s3c2410/devs.h b/include/asm-arm/plat-s3c24xx/devs.h index 14fb0bade71..dddf485fc06 100644 --- a/arch/arm/mach-s3c2410/devs.h +++ b/include/asm-arm/plat-s3c24xx/devs.h @@ -1,4 +1,4 @@ -/* arch/arm/mach-s3c2410/devs.h +/* linux/include/asm-arm/plat-s3c24xx/devs.h * * Copyright (c) 2004 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> diff --git a/arch/arm/mach-s3c2410/dma.h b/include/asm-arm/plat-s3c24xx/dma.h index 0ebfe0aab80..2c59406435e 100644 --- a/arch/arm/mach-s3c2410/dma.h +++ b/include/asm-arm/plat-s3c24xx/dma.h @@ -1,4 +1,4 @@ -/* arch/arm/mach-s3c2410/dma.h +/* linux/include/asm-arm/plat-s3c24xx/dma.h * * Copyright (C) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> @@ -14,6 +14,7 @@ extern struct sysdev_class dma_sysclass; extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS]; #define DMA_CH_VALID (1<<31) +#define DMA_CH_NEVER (1<<30) struct s3c24xx_dma_addr { unsigned long from; @@ -43,3 +44,34 @@ struct s3c24xx_dma_selection { }; extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel); + +/* struct s3c24xx_dma_order_ch + * + * channel map for one of the `enum dma_ch` dma channels. the list + * entry contains a set of low-level channel numbers, orred with + * DMA_CH_VALID, which are checked in the order in the array. +*/ + +struct s3c24xx_dma_order_ch { + unsigned int list[S3C2410_DMA_CHANNELS]; /* list of channels */ + unsigned int flags; /* flags */ +}; + +/* struct s3c24xx_dma_order + * + * information provided by either the core or the board to give the + * dma system a hint on how to allocate channels +*/ + +struct s3c24xx_dma_order { + struct s3c24xx_dma_order_ch channels[DMACH_MAX]; +}; + +extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map); + +/* DMA init code, called from the cpu support code */ + +extern int s3c2410_dma_init(void); + +extern int s3c24xx_dma_init(unsigned int channels, unsigned int irq, + unsigned int stride); diff --git a/arch/arm/mach-s3c2410/irq.h b/include/asm-arm/plat-s3c24xx/irq.h index e5913da3b91..8af6d9579b3 100644 --- a/arch/arm/mach-s3c2410/irq.h +++ b/include/asm-arm/plat-s3c24xx/irq.h @@ -1,4 +1,4 @@ -/* arch/arm/mach-s3c2410/irq.h +/* linux/include/asm-arm/plat-s3c24xx/irq.h * * Copyright (c) 2004-2005 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> diff --git a/arch/arm/mach-s3c2410/pm.h b/include/asm-arm/plat-s3c24xx/pm.h index ffe197a119f..cc623667e48 100644 --- a/arch/arm/mach-s3c2410/pm.h +++ b/include/asm-arm/plat-s3c24xx/pm.h @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/pm.h +/* linux/include/asm-arm/plat-s3c24xx/pm.h * * Copyright (c) 2004 Simtec Electronics * Written by Ben Dooks, <ben@simtec.co.uk> diff --git a/arch/arm/mach-s3c2410/s3c2400.h b/include/asm-arm/plat-s3c24xx/s3c2400.h index 8b2394e1ed4..3a5a16821af 100644 --- a/arch/arm/mach-s3c2410/s3c2400.h +++ b/include/asm-arm/plat-s3c24xx/s3c2400.h @@ -1,4 +1,4 @@ -/* arch/arm/mach-s3c2410/s3c2400.h +/* linux/include/asm-arm/plat-s3c24xx/s3c2400.h * * Copyright (c) 2004 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> diff --git a/arch/arm/mach-s3c2410/s3c2410.h b/include/asm-arm/plat-s3c24xx/s3c2410.h index fbed084f26d..36de0b83587 100644 --- a/arch/arm/mach-s3c2410/s3c2410.h +++ b/include/asm-arm/plat-s3c24xx/s3c2410.h @@ -1,4 +1,4 @@ -/* arch/arm/mach-s3c2410/s3c2410.h +/* linux/include/asm-arm/plat-s3c24xx/s3c2410.h * * Copyright (c) 2004 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> diff --git a/arch/arm/mach-s3c2410/s3c2412.h b/include/asm-arm/plat-s3c24xx/s3c2412.h index c6e56032a6e..3ec97685e78 100644 --- a/arch/arm/mach-s3c2410/s3c2412.h +++ b/include/asm-arm/plat-s3c24xx/s3c2412.h @@ -1,4 +1,4 @@ -/* arch/arm/mach-s3c2410/s3c2412.h +/* linux/include/asm-arm/plat-s3c24xx/s3c2412.h * * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> diff --git a/arch/arm/mach-s3c2410/s3c2440.h b/include/asm-arm/plat-s3c24xx/s3c2440.h index dcd316076c5..107853bf948 100644 --- a/arch/arm/mach-s3c2410/s3c2440.h +++ b/include/asm-arm/plat-s3c24xx/s3c2440.h @@ -1,4 +1,4 @@ -/* arch/arm/mach-s3c2410/s3c2440.h +/* linux/include/asm-arm/plat-s3c24xx/s3c2440.h * * Copyright (c) 2004-2005 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> diff --git a/arch/arm/mach-s3c2410/s3c2442.h b/include/asm-arm/plat-s3c24xx/s3c2442.h index 0ae37d24866..451a23a2092 100644 --- a/arch/arm/mach-s3c2410/s3c2442.h +++ b/include/asm-arm/plat-s3c24xx/s3c2442.h @@ -1,4 +1,4 @@ -/* arch/arm/mach-s3c2410/s3c2442.h +/* linux/include/asm-arm/plat-s3c24xx/s3c2442.h * * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> diff --git a/include/asm-arm/plat-s3c24xx/s3c2443.h b/include/asm-arm/plat-s3c24xx/s3c2443.h new file mode 100644 index 00000000000..11d83b5c84e --- /dev/null +++ b/include/asm-arm/plat-s3c24xx/s3c2443.h @@ -0,0 +1,32 @@ +/* linux/include/asm-arm/plat-s3c24xx/s3c2443.h + * + * Copyright (c) 2004-2005 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Header file for s3c2443 cpu support + * + * 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. +*/ + +#ifdef CONFIG_CPU_S3C2443 + +struct s3c2410_uartcfg; + +extern int s3c2443_init(void); + +extern void s3c2443_map_io(struct map_desc *mach_desc, int size); + +extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no); + +extern void s3c2443_init_clocks(int xtal); + +extern int s3c2443_baseclk_add(void); + +#else +#define s3c2443_init_clocks NULL +#define s3c2443_init_uarts NULL +#define s3c2443_map_io NULL +#define s3c2443_init NULL +#endif diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h index aa223fc546a..f4386906b20 100644 --- a/include/asm-arm/system.h +++ b/include/asm-arm/system.h @@ -140,6 +140,40 @@ static inline int cpu_is_xsc3(void) #define cpu_is_xscale() 1 #endif +#define UDBG_UNDEFINED (1 << 0) +#define UDBG_SYSCALL (1 << 1) +#define UDBG_BADABORT (1 << 2) +#define UDBG_SEGV (1 << 3) +#define UDBG_BUS (1 << 4) + +extern unsigned int user_debug; + +#if __LINUX_ARM_ARCH__ >= 4 +#define vectors_high() (cr_alignment & CR_V) +#else +#define vectors_high() (0) +#endif + +#if __LINUX_ARM_ARCH__ >= 6 +#define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \ + : : "r" (0) : "memory") +#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \ + : : "r" (0) : "memory") +#define dmb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \ + : : "r" (0) : "memory") +#else +#define isb() __asm__ __volatile__ ("" : : : "memory") +#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \ + : : "r" (0) : "memory") +#define dmb() __asm__ __volatile__ ("" : : : "memory") +#endif +#define mb() dmb() +#define rmb() mb() +#define wmb() mb() +#define read_barrier_depends() do { } while(0) +#define set_mb(var, value) do { var = value; mb(); } while (0) +#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t"); + extern unsigned long cr_no_alignment; /* defined in entry-armv.S */ extern unsigned long cr_alignment; /* defined in entry-armv.S */ @@ -154,6 +188,7 @@ static inline void set_cr(unsigned int val) { asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR" : : "r" (val) : "cc"); + isb(); } #ifndef CONFIG_SMP @@ -176,34 +211,9 @@ static inline void set_copro_access(unsigned int val) { asm volatile("mcr p15, 0, %0, c1, c0, 2 @ set copro access" : : "r" (val) : "cc"); + isb(); } -#define UDBG_UNDEFINED (1 << 0) -#define UDBG_SYSCALL (1 << 1) -#define UDBG_BADABORT (1 << 2) -#define UDBG_SEGV (1 << 3) -#define UDBG_BUS (1 << 4) - -extern unsigned int user_debug; - -#if __LINUX_ARM_ARCH__ >= 4 -#define vectors_high() (cr_alignment & CR_V) -#else -#define vectors_high() (0) -#endif - -#if __LINUX_ARM_ARCH__ >= 6 -#define mb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \ - : : "r" (0) : "memory") -#else -#define mb() __asm__ __volatile__ ("" : : : "memory") -#endif -#define rmb() mb() -#define wmb() mb() -#define read_barrier_depends() do { } while(0) -#define set_mb(var, value) do { var = value; mb(); } while (0) -#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t"); - /* * switch_mm() may do a full cache flush over the context switch, * so enable interrupts over the context switch to avoid high diff --git a/include/asm-arm/tlbflush.h b/include/asm-arm/tlbflush.h index cd10a0b5f8a..08c6991dc9c 100644 --- a/include/asm-arm/tlbflush.h +++ b/include/asm-arm/tlbflush.h @@ -247,7 +247,7 @@ static inline void local_flush_tlb_all(void) const unsigned int __tlb_flag = __cpu_tlb_flags; if (tlb_flag(TLB_WB)) - asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc"); + dsb(); if (tlb_flag(TLB_V3_FULL)) asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc"); @@ -257,6 +257,15 @@ static inline void local_flush_tlb_all(void) asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc"); if (tlb_flag(TLB_V4_I_FULL | TLB_V6_I_FULL)) asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc"); + + if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL | + TLB_V6_I_PAGE | TLB_V6_D_PAGE | + TLB_V6_I_ASID | TLB_V6_D_ASID)) { + /* flush the branch target cache */ + asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); + dsb(); + isb(); + } } static inline void local_flush_tlb_mm(struct mm_struct *mm) @@ -266,7 +275,7 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm) const unsigned int __tlb_flag = __cpu_tlb_flags; if (tlb_flag(TLB_WB)) - asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc"); + dsb(); if (cpu_isset(smp_processor_id(), mm->cpu_vm_mask)) { if (tlb_flag(TLB_V3_FULL)) @@ -285,6 +294,14 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm) asm("mcr p15, 0, %0, c8, c6, 2" : : "r" (asid) : "cc"); if (tlb_flag(TLB_V6_I_ASID)) asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc"); + + if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL | + TLB_V6_I_PAGE | TLB_V6_D_PAGE | + TLB_V6_I_ASID | TLB_V6_D_ASID)) { + /* flush the branch target cache */ + asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); + dsb(); + } } static inline void @@ -296,7 +313,7 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm); if (tlb_flag(TLB_WB)) - asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero)); + dsb(); if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) { if (tlb_flag(TLB_V3_PAGE)) @@ -317,6 +334,14 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc"); if (tlb_flag(TLB_V6_I_PAGE)) asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc"); + + if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL | + TLB_V6_I_PAGE | TLB_V6_D_PAGE | + TLB_V6_I_ASID | TLB_V6_D_ASID)) { + /* flush the branch target cache */ + asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); + dsb(); + } } static inline void local_flush_tlb_kernel_page(unsigned long kaddr) @@ -327,7 +352,7 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr) kaddr &= PAGE_MASK; if (tlb_flag(TLB_WB)) - asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc"); + dsb(); if (tlb_flag(TLB_V3_PAGE)) asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (kaddr) : "cc"); @@ -347,11 +372,14 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr) if (tlb_flag(TLB_V6_I_PAGE)) asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc"); - /* The ARM ARM states that the completion of a TLB maintenance - * operation is only guaranteed by a DSB instruction - */ - if (tlb_flag(TLB_V6_U_PAGE | TLB_V6_D_PAGE | TLB_V6_I_PAGE)) - asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL | + TLB_V6_I_PAGE | TLB_V6_D_PAGE | + TLB_V6_I_ASID | TLB_V6_D_ASID)) { + /* flush the branch target cache */ + asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); + dsb(); + isb(); + } } /* @@ -369,15 +397,13 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr) */ static inline void flush_pmd_entry(pmd_t *pmd) { - const unsigned int zero = 0; const unsigned int __tlb_flag = __cpu_tlb_flags; if (tlb_flag(TLB_DCLEAN)) asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd" : : "r" (pmd) : "cc"); if (tlb_flag(TLB_WB)) - asm("mcr p15, 0, %0, c7, c10, 4 @ flush_pmd" - : : "r" (zero) : "cc"); + dsb(); } static inline void clean_pmd_entry(pmd_t *pmd) diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index 97e7060000c..0991b7bc3f7 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h @@ -372,6 +372,7 @@ #define __NR_move_pages (__NR_SYSCALL_BASE+344) #define __NR_getcpu (__NR_SYSCALL_BASE+345) /* 346 for epoll_pwait */ +#define __NR_sys_kexec_load (__NR_SYSCALL_BASE+347) /* * The following SWIs are ARM private. diff --git a/include/asm-avr32/arch-at32ap/at91_pdc.h b/include/asm-avr32/arch-at32ap/at91_pdc.h deleted file mode 100644 index 79d6e02fa45..00000000000 --- a/include/asm-avr32/arch-at32ap/at91_pdc.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * include/asm-arm/arch-at91rm9200/at91_pdc.h - * - * Copyright (C) 2005 Ivan Kokshaysky - * Copyright (C) SAN People - * - * Peripheral Data Controller (PDC) registers. - * Based on AT91RM9200 datasheet revision E. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef AT91_PDC_H -#define AT91_PDC_H - -#define AT91_PDC_RPR 0x100 /* Receive Pointer Register */ -#define AT91_PDC_RCR 0x104 /* Receive Counter Register */ -#define AT91_PDC_TPR 0x108 /* Transmit Pointer Register */ -#define AT91_PDC_TCR 0x10c /* Transmit Counter Register */ -#define AT91_PDC_RNPR 0x110 /* Receive Next Pointer Register */ -#define AT91_PDC_RNCR 0x114 /* Receive Next Counter Register */ -#define AT91_PDC_TNPR 0x118 /* Transmit Next Pointer Register */ -#define AT91_PDC_TNCR 0x11c /* Transmit Next Counter Register */ - -#define AT91_PDC_PTCR 0x120 /* Transfer Control Register */ -#define AT91_PDC_RXTEN (1 << 0) /* Receiver Transfer Enable */ -#define AT91_PDC_RXTDIS (1 << 1) /* Receiver Transfer Disable */ -#define AT91_PDC_TXTEN (1 << 8) /* Transmitter Transfer Enable */ -#define AT91_PDC_TXTDIS (1 << 9) /* Transmitter Transfer Disable */ - -#define AT91_PDC_PTSR 0x124 /* Transfer Status Register */ - -#endif diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h index 5e657eb8946..449f3f272e0 100644 --- a/include/asm-i386/acpi.h +++ b/include/asm-i386/acpi.h @@ -127,6 +127,7 @@ extern int acpi_irq_balance_set(char *str); #define acpi_ioapic 0 static inline void acpi_noirq_set(void) { } static inline void acpi_disable_pci(void) { } +static inline void disable_acpi(void) { } #endif /* !CONFIG_ACPI */ diff --git a/include/asm-powerpc/atomic.h b/include/asm-powerpc/atomic.h index f038e33e6d4..2ce4b6b7b34 100644 --- a/include/asm-powerpc/atomic.h +++ b/include/asm-powerpc/atomic.h @@ -165,7 +165,8 @@ static __inline__ int atomic_dec_return(atomic_t *v) return t; } -#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) +#define atomic_cmpxchg(v, o, n) \ + ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n))) #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) /** @@ -413,6 +414,43 @@ static __inline__ long atomic64_dec_if_positive(atomic64_t *v) return t; } +#define atomic64_cmpxchg(v, o, n) \ + ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n))) +#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) + +/** + * atomic64_add_unless - add unless the number is a given value + * @v: pointer of type atomic64_t + * @a: the amount to add to v... + * @u: ...unless v is equal to u. + * + * Atomically adds @a to @v, so long as it was not @u. + * Returns non-zero if @v was not @u, and zero otherwise. + */ +static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) +{ + long t; + + __asm__ __volatile__ ( + LWSYNC_ON_SMP +"1: ldarx %0,0,%1 # atomic_add_unless\n\ + cmpd 0,%0,%3 \n\ + beq- 2f \n\ + add %0,%2,%0 \n" +" stdcx. %0,0,%1 \n\ + bne- 1b \n" + ISYNC_ON_SMP +" subf %0,%2,%0 \n\ +2:" + : "=&r" (t) + : "r" (&v->counter), "r" (a), "r" (u) + : "cc", "memory"); + + return t != u; +} + +#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) + #endif /* __powerpc64__ */ #include <asm-generic/atomic.h> diff --git a/include/asm-powerpc/dcr-native.h b/include/asm-powerpc/dcr-native.h index d7a1bc1551c..05af081222f 100644 --- a/include/asm-powerpc/dcr-native.h +++ b/include/asm-powerpc/dcr-native.h @@ -26,8 +26,8 @@ typedef struct {} dcr_host_t; #define DCR_MAP_OK(host) (1) -#define dcr_map(dev, dcr_n, dcr_c) {} -#define dcr_unmap(host, dcr_n, dcr_c) {} +#define dcr_map(dev, dcr_n, dcr_c) ((dcr_host_t){}) +#define dcr_unmap(host, dcr_n, dcr_c) do {} while (0) #define dcr_read(host, dcr_n) mfdcr(dcr_n) #define dcr_write(host, dcr_n, value) mtdcr(dcr_n, value) diff --git a/include/asm-powerpc/pmi.h b/include/asm-powerpc/pmi.h new file mode 100644 index 00000000000..cb0f8aa4308 --- /dev/null +++ b/include/asm-powerpc/pmi.h @@ -0,0 +1,67 @@ +#ifndef _POWERPC_PMI_H +#define _POWERPC_PMI_H + +/* + * Definitions for talking with PMI device on PowerPC + * + * PMI (Platform Management Interrupt) is a way to communicate + * with the BMC (Baseboard Management Controller) via interrupts. + * Unlike IPMI it is bidirectional and has a low latency. + * + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * + * Author: Christian Krafft <krafft@de.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef __KERNEL__ + +#include <asm/of_device.h> + +#define PMI_TYPE_FREQ_CHANGE 0x01 +#define PMI_READ_TYPE 0 +#define PMI_READ_DATA0 1 +#define PMI_READ_DATA1 2 +#define PMI_READ_DATA2 3 +#define PMI_WRITE_TYPE 4 +#define PMI_WRITE_DATA0 5 +#define PMI_WRITE_DATA1 6 +#define PMI_WRITE_DATA2 7 + +#define PMI_ACK 0x80 + +#define PMI_TIMEOUT 100 + +typedef struct { + u8 type; + u8 data0; + u8 data1; + u8 data2; +} pmi_message_t; + +struct pmi_handler { + struct list_head node; + u8 type; + void (*handle_pmi_message) (struct of_device *, pmi_message_t); +}; + +void pmi_register_handler(struct of_device *, struct pmi_handler *); +void pmi_unregister_handler(struct of_device *, struct pmi_handler *); + +void pmi_send_message(struct of_device *, pmi_message_t); + +#endif /* __KERNEL__ */ +#endif /* _POWERPC_PMI_H */ diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index 0afee17f33b..020ed015a94 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -255,6 +255,8 @@ extern void kdump_move_device_tree(void); /* CPU OF node matching */ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); +/* Get the MAC address */ +extern const void *of_get_mac_address(struct device_node *np); /* * OF interrupt mapping diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h index e5982ad4657..821581a8b64 100644 --- a/include/asm-powerpc/ps3.h +++ b/include/asm-powerpc/ps3.h @@ -355,13 +355,7 @@ extern struct bus_type ps3_system_bus_type; /* vuart routines */ -struct ps3_vuart_stats { - unsigned long bytes_written; - unsigned long bytes_read; - unsigned long tx_interrupts; - unsigned long rx_interrupts; - unsigned long disconnect_interrupts; -}; +struct ps3_vuart_port_priv; /** * struct ps3_vuart_port_device - a device on a vuart port @@ -370,24 +364,17 @@ struct ps3_vuart_stats { struct ps3_vuart_port_device { enum ps3_match_id match_id; struct device core; + struct ps3_vuart_port_priv* priv; /* private driver variables */ - /* private driver variables */ - unsigned int port_number; - u64 interrupt_mask; - struct { - spinlock_t lock; - struct list_head head; - } tx_list; - struct { - unsigned long bytes_held; - spinlock_t lock; - struct list_head head; - } rx_list; - struct ps3_vuart_stats stats; }; int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev); +/* system manager */ + +void ps3_sys_manager_restart(void); +void ps3_sys_manager_power_off(void); + struct ps3_prealloc { const char *name; void *address; diff --git a/include/asm-powerpc/ucc_slow.h b/include/asm-powerpc/ucc_slow.h index 1babad99c71..fdaac9d762b 100644 --- a/include/asm-powerpc/ucc_slow.h +++ b/include/asm-powerpc/ucc_slow.h @@ -150,7 +150,7 @@ struct ucc_slow_info { int ucc_num; enum qe_clock rx_clock; enum qe_clock tx_clock; - struct ucc_slow *regs; + u32 regs; int irq; u16 uccm_mask; int data_mem_part; @@ -199,9 +199,9 @@ struct ucc_slow_private { and length for first BD in a frame */ u32 tx_base_offset; /* first BD in Tx BD table offset (In MURAM) */ u32 rx_base_offset; /* first BD in Rx BD table offset (In MURAM) */ - u8 *confBd; /* next BD for confirm after Tx */ - u8 *tx_bd; /* next BD for new Tx request */ - u8 *rx_bd; /* next BD to collect after Rx */ + struct qe_bd *confBd; /* next BD for confirm after Tx */ + struct qe_bd *tx_bd; /* next BD for new Tx request */ + struct qe_bd *rx_bd; /* next BD to collect after Rx */ void *p_rx_frame; /* accumulating receive frame */ u16 *p_ucce; /* a pointer to the event register in memory. */ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 815f1fb4ce2..8bcfaa4c66a 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -75,7 +75,7 @@ enum acpi_address_range_id { typedef int (*acpi_table_handler) (struct acpi_table_header *table); -typedef int (*acpi_madt_entry_handler) (struct acpi_subtable_header *header, const unsigned long end); +typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header *header, const unsigned long end); char * __acpi_map_table (unsigned long phys_addr, unsigned long size); unsigned long acpi_find_rsdp (void); @@ -85,8 +85,10 @@ int acpi_numa_init (void); int acpi_table_init (void); int acpi_table_parse (char *id, acpi_table_handler handler); -int acpi_table_parse_madt (enum acpi_madt_type id, acpi_madt_entry_handler handler, unsigned int max_entries); -int acpi_table_parse_srat (enum acpi_srat_type id, acpi_madt_entry_handler handler, unsigned int max_entries); +int __init acpi_table_parse_entries(char *id, unsigned long table_size, + int entry_id, acpi_table_entry_handler handler, unsigned int max_entries); +int acpi_table_parse_madt (enum acpi_madt_type id, acpi_table_entry_handler handler, unsigned int max_entries); +int acpi_table_parse_srat (enum acpi_srat_type id, acpi_table_entry_handler handler, unsigned int max_entries); int acpi_parse_mcfg (struct acpi_table_header *header); void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); void acpi_table_print_srat_entry (struct acpi_subtable_header *srat); diff --git a/include/linux/atmel_pdc.h b/include/linux/atmel_pdc.h new file mode 100644 index 00000000000..5058a31d2ce --- /dev/null +++ b/include/linux/atmel_pdc.h @@ -0,0 +1,36 @@ +/* + * include/linux/atmel_pdc.h + * + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) SAN People + * + * Peripheral Data Controller (PDC) registers. + * Based on AT91RM9200 datasheet revision E. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef ATMEL_PDC_H +#define ATMEL_PDC_H + +#define ATMEL_PDC_RPR 0x100 /* Receive Pointer Register */ +#define ATMEL_PDC_RCR 0x104 /* Receive Counter Register */ +#define ATMEL_PDC_TPR 0x108 /* Transmit Pointer Register */ +#define ATMEL_PDC_TCR 0x10c /* Transmit Counter Register */ +#define ATMEL_PDC_RNPR 0x110 /* Receive Next Pointer Register */ +#define ATMEL_PDC_RNCR 0x114 /* Receive Next Counter Register */ +#define ATMEL_PDC_TNPR 0x118 /* Transmit Next Pointer Register */ +#define ATMEL_PDC_TNCR 0x11c /* Transmit Next Counter Register */ + +#define ATMEL_PDC_PTCR 0x120 /* Transfer Control Register */ +#define ATMEL_PDC_RXTEN (1 << 0) /* Receiver Transfer Enable */ +#define ATMEL_PDC_RXTDIS (1 << 1) /* Receiver Transfer Disable */ +#define ATMEL_PDC_TXTEN (1 << 8) /* Transmitter Transfer Enable */ +#define ATMEL_PDC_TXTDIS (1 << 9) /* Transmitter Transfer Disable */ + +#define ATMEL_PDC_PTSR 0x124 /* Transfer Status Register */ + +#endif diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 047567d34ca..9fa0983d1aa 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -33,6 +33,9 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode, struct dentry *debugfs_create_dir(const char *name, struct dentry *parent); +struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, + const char *dest); + void debugfs_remove(struct dentry *dentry); struct dentry *debugfs_create_u8(const char *name, mode_t mode, @@ -70,6 +73,13 @@ static inline struct dentry *debugfs_create_dir(const char *name, return ERR_PTR(-ENODEV); } +static inline struct dentry *debugfs_create_symlink(const char *name, + struct dentry *parent, + const char *dest) +{ + return ERR_PTR(-ENODEV); +} + static inline void debugfs_remove(struct dentry *dentry) { } diff --git a/include/linux/device.h b/include/linux/device.h index 4cc6c935864..d1a3a27c398 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -2,6 +2,7 @@ * device.h - generic, centralized driver model * * Copyright (c) 2001-2003 Patrick Mochel <mochel@osdl.org> + * Copyright (c) 2004-2007 Greg Kroah-Hartman <gregkh@suse.de> * * This file is released under the GPLv2 * diff --git a/include/linux/ide.h b/include/linux/ide.h index 04e0fa97ac9..79c028251c7 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -636,7 +636,6 @@ typedef struct ide_drive_s { unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */ unsigned int cyl; /* "real" number of cyls */ unsigned int drive_data; /* use by tuneproc/selectproc */ - unsigned int usage; /* current "open()" count for drive */ unsigned int failures; /* current failure count */ unsigned int max_failures; /* maximum allowed failure count */ u64 probed_capacity;/* initial reported media capacity (ide-cd only currently) */ @@ -736,23 +735,22 @@ typedef struct hwif_s { int (*ide_dma_end)(ide_drive_t *drive); int (*ide_dma_check)(ide_drive_t *drive); int (*ide_dma_on)(ide_drive_t *drive); - int (*ide_dma_off_quietly)(ide_drive_t *drive); + void (*dma_off_quietly)(ide_drive_t *drive); int (*ide_dma_test_irq)(ide_drive_t *drive); - int (*ide_dma_host_on)(ide_drive_t *drive); - int (*ide_dma_host_off)(ide_drive_t *drive); + void (*ide_dma_clear_irq)(ide_drive_t *drive); + void (*dma_host_on)(ide_drive_t *drive); + void (*dma_host_off)(ide_drive_t *drive); int (*ide_dma_lostirq)(ide_drive_t *drive); int (*ide_dma_timeout)(ide_drive_t *drive); void (*OUTB)(u8 addr, unsigned long port); void (*OUTBSYNC)(ide_drive_t *drive, u8 addr, unsigned long port); void (*OUTW)(u16 addr, unsigned long port); - void (*OUTL)(u32 addr, unsigned long port); void (*OUTSW)(unsigned long port, void *addr, u32 count); void (*OUTSL)(unsigned long port, void *addr, u32 count); u8 (*INB)(unsigned long port); u16 (*INW)(unsigned long port); - u32 (*INL)(unsigned long port); void (*INSW)(unsigned long port, void *addr, u32 count); void (*INSL)(unsigned long port, void *addr, u32 count); @@ -774,7 +772,6 @@ typedef struct hwif_s { unsigned int cursg; unsigned int cursg_ofs; - int mmio; /* hosts iomio (0) or custom (2) select */ int rqsize; /* max sectors per request */ int irq; /* our irq number */ @@ -802,12 +799,11 @@ typedef struct hwif_s { unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */ unsigned no_lba48 : 1; /* 1 = cannot do LBA48 */ unsigned no_lba48_dma : 1; /* 1 = cannot do LBA48 DMA */ - unsigned no_dsc : 1; /* 0 default, 1 dsc_overlap disabled */ unsigned auto_poll : 1; /* supports nop auto-poll */ unsigned sg_mapped : 1; /* sg_table and sg_nents are ready */ unsigned no_io_32bit : 1; /* 1 = can not do 32-bit IO ops */ unsigned err_stops_fifo : 1; /* 1=data FIFO is cleared by an error */ - unsigned atapi_irq_bogon : 1; /* Generates spurious DMA interrupts in PIO mode */ + unsigned mmio : 1; /* host uses MMIO */ struct device gendev; struct completion gendev_rel_comp; /* To deal with device release() */ @@ -1280,8 +1276,9 @@ int ide_in_drive_list(struct hd_driveid *, const struct drive_list_entry *); int __ide_dma_bad_drive(ide_drive_t *); int __ide_dma_good_drive(ide_drive_t *); int ide_use_dma(ide_drive_t *); -int __ide_dma_off(ide_drive_t *); +void ide_dma_off(ide_drive_t *); void ide_dma_verbose(ide_drive_t *); +int ide_set_dma(ide_drive_t *); ide_startstop_t ide_dma_intr(ide_drive_t *); #ifdef CONFIG_BLK_DEV_IDEDMA_PCI @@ -1291,9 +1288,9 @@ extern void ide_destroy_dmatable(ide_drive_t *); extern int ide_release_dma(ide_hwif_t *); extern void ide_setup_dma(ide_hwif_t *, unsigned long, unsigned int); -extern int __ide_dma_host_off(ide_drive_t *); -extern int __ide_dma_off_quietly(ide_drive_t *); -extern int __ide_dma_host_on(ide_drive_t *); +void ide_dma_host_off(ide_drive_t *); +void ide_dma_off_quietly(ide_drive_t *); +void ide_dma_host_on(ide_drive_t *); extern int __ide_dma_on(ide_drive_t *); extern int __ide_dma_check(ide_drive_t *); extern int ide_dma_setup(ide_drive_t *); @@ -1305,8 +1302,9 @@ extern int __ide_dma_timeout(ide_drive_t *); #else static inline int ide_use_dma(ide_drive_t *drive) { return 0; } -static inline int __ide_dma_off(ide_drive_t *drive) { return 0; } +static inline void ide_dma_off(ide_drive_t *drive) { ; } static inline void ide_dma_verbose(ide_drive_t *drive) { ; } +static inline int ide_set_dma(ide_drive_t *drive) { return 1; } #endif /* CONFIG_BLK_DEV_IDEDMA */ #ifndef CONFIG_BLK_DEV_IDEDMA_PCI @@ -1354,6 +1352,7 @@ extern int ide_dma_enable(ide_drive_t *drive); extern char *ide_xfer_verbose(u8 xfer_rate); extern void ide_toggle_bounce(ide_drive_t *drive, int on); extern int ide_set_xfer_rate(ide_drive_t *drive, u8 rate); +int ide_use_fast_pio(ide_drive_t *); u8 ide_dump_status(ide_drive_t *, const char *, u8); @@ -1367,7 +1366,6 @@ typedef struct ide_pio_data_s { u8 pio_mode; u8 use_iordy; u8 overridden; - u8 blacklisted; unsigned int cycle_time; } ide_pio_data_t; diff --git a/include/linux/jffs.h b/include/linux/jffs.h deleted file mode 100644 index 92213215277..00000000000 --- a/include/linux/jffs.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * JFFS -- Journalling Flash File System, Linux implementation. - * - * Copyright (C) 1999, 2000 Axis Communications AB. - * - * Created by Finn Hakansson <finn@axis.com>. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * $Id: jffs.h,v 1.20 2001/09/18 21:33:37 dwmw2 Exp $ - * - * Ported to Linux 2.3.x and MTD: - * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB - * - */ - -#ifndef __LINUX_JFFS_H__ -#define __LINUX_JFFS_H__ - -#include <linux/types.h> -#include <linux/completion.h> - -#define JFFS_VERSION_STRING "1.0" - -/* This is a magic number that is used as an identification number for - this file system. It is written to the super_block structure. */ -#define JFFS_MAGIC_SB_BITMASK 0x07c0 /* 1984 */ - -/* This is a magic number that every on-flash raw inode begins with. */ -#define JFFS_MAGIC_BITMASK 0x34383931 /* "1984" */ - -/* These two bitmasks are the valid ones for the flash memories we have - for the moment. */ -#define JFFS_EMPTY_BITMASK 0xffffffff -#define JFFS_DIRTY_BITMASK 0x00000000 - -/* This is the inode number of the root node. */ -#define JFFS_MIN_INO 1 - -/* How many slots in the file hash table should we have? */ -#define JFFS_HASH_SIZE 40 - -/* Don't use more than 254 bytes as the maximum allowed length of a file's - name due to errors that could occur during the scanning of the flash - memory. In fact, a name length of 255 or 0xff, could be the result of - an uncompleted write. For instance, if a raw inode is written to the - flash memory and there is a power lossage just before the length of - the name is written, the length 255 would be interpreted as an illegal - value. */ -#define JFFS_MAX_NAME_LEN 254 - -/* Commands for ioctl(). */ -#define JFFS_IOCTL_MAGIC 't' -#define JFFS_PRINT_HASH _IO(JFFS_IOCTL_MAGIC, 90) -#define JFFS_PRINT_TREE _IO(JFFS_IOCTL_MAGIC, 91) -#define JFFS_GET_STATUS _IO(JFFS_IOCTL_MAGIC, 92) - -/* XXX: This is something that we should try to get rid of in the future. */ -#define JFFS_MODIFY_INODE 0x01 -#define JFFS_MODIFY_NAME 0x02 -#define JFFS_MODIFY_DATA 0x04 -#define JFFS_MODIFY_EXIST 0x08 - -struct jffs_control; - -/* The JFFS raw inode structure: Used for storage on physical media. */ -/* Perhaps the uid, gid, atime, mtime and ctime members should have - more space due to future changes in the Linux kernel. Anyhow, since - a user of this filesystem probably have to fix a large number of - other things, we have decided to not be forward compatible. */ -struct jffs_raw_inode -{ - __u32 magic; /* A constant magic number. */ - __u32 ino; /* Inode number. */ - __u32 pino; /* Parent's inode number. */ - __u32 version; /* Version number. */ - __u32 mode; /* The file's type or mode. */ - __u16 uid; /* The file's owner. */ - __u16 gid; /* The file's group. */ - __u32 atime; /* Last access time. */ - __u32 mtime; /* Last modification time. */ - __u32 ctime; /* Creation time. */ - __u32 offset; /* Where to begin to write. */ - __u32 dsize; /* Size of the node's data. */ - __u32 rsize; /* How much are going to be replaced? */ - __u8 nsize; /* Name length. */ - __u8 nlink; /* Number of links. */ - __u8 spare : 6; /* For future use. */ - __u8 rename : 1; /* Rename to a name of an already existing file? */ - __u8 deleted : 1; /* Has this file been deleted? */ - __u8 accurate; /* The inode is obsolete if accurate == 0. */ - __u32 dchksum; /* Checksum for the data. */ - __u16 nchksum; /* Checksum for the name. */ - __u16 chksum; /* Checksum for the raw inode. */ -}; - -/* Define the offset of the accurate byte in struct jffs_raw_inode. */ -#define JFFS_RAW_INODE_ACCURATE_OFFSET (sizeof(struct jffs_raw_inode) \ - - 2 * sizeof(__u32) - sizeof(__u8)) - -/* Define the offset of the chksum member in struct jffs_raw_inode. */ -#define JFFS_RAW_INODE_CHKSUM_OFFSET (sizeof(struct jffs_raw_inode) \ - - sizeof(__u16)) - -/* Define the offset of the dchksum member in struct jffs_raw_inode. */ -#define JFFS_RAW_INODE_DCHKSUM_OFFSET (sizeof(struct jffs_raw_inode) \ - - sizeof(__u16) - sizeof(__u16) \ - - sizeof(__u32)) - - -/* The RAM representation of the node. The names of pointers to - jffs_nodes are very often just called `n' in the source code. */ -struct jffs_node -{ - __u32 ino; /* Inode number. */ - __u32 version; /* Version number. */ - __u32 data_offset; /* Logic location of the data to insert. */ - __u32 data_size; /* The amount of data this node inserts. */ - __u32 removed_size; /* The amount of data that this node removes. */ - __u32 fm_offset; /* Physical location of the data in the actual - flash memory data chunk. */ - __u8 name_size; /* Size of the name. */ - struct jffs_fm *fm; /* Physical memory information. */ - struct jffs_node *version_prev; - struct jffs_node *version_next; - struct jffs_node *range_prev; - struct jffs_node *range_next; -}; - - -/* The RAM representation of a file (plain files, directories, - links, etc.). Pointers to jffs_files are normally named `f' - in the JFFS source code. */ -struct jffs_file -{ - __u32 ino; /* Inode number. */ - __u32 pino; /* Parent's inode number. */ - __u32 mode; /* file_type, mode */ - __u16 uid; /* owner */ - __u16 gid; /* group */ - __u32 atime; /* Last access time. */ - __u32 mtime; /* Last modification time. */ - __u32 ctime; /* Creation time. */ - __u8 nsize; /* Name length. */ - __u8 nlink; /* Number of links. */ - __u8 deleted; /* Has this file been deleted? */ - char *name; /* The name of this file; NULL-terminated. */ - __u32 size; /* The total size of the file's data. */ - __u32 highest_version; /* The highest version number of this file. */ - struct jffs_control *c; - struct jffs_file *parent; /* Reference to the parent directory. */ - struct jffs_file *children; /* Always NULL for plain files. */ - struct jffs_file *sibling_prev; /* Siblings in the same directory. */ - struct jffs_file *sibling_next; - struct list_head hash; /* hash list. */ - struct jffs_node *range_head; /* The final data. */ - struct jffs_node *range_tail; /* The first data. */ - struct jffs_node *version_head; /* The youngest node. */ - struct jffs_node *version_tail; /* The oldest node. */ -}; - - -/* This is just a definition of a simple list used for keeping track of - files deleted due to a rename. This list is only used during the - mounting of the file system and only if there have been rename operations - earlier. */ -struct jffs_delete_list -{ - __u32 ino; - struct jffs_delete_list *next; -}; - - -/* A struct for the overall file system control. Pointers to - jffs_control structs are named `c' in the source code. */ -struct jffs_control -{ - struct super_block *sb; /* Reference to the VFS super block. */ - struct jffs_file *root; /* The root directory file. */ - struct list_head *hash; /* Hash table for finding files by ino. */ - struct jffs_fmcontrol *fmc; /* Flash memory control structure. */ - __u32 hash_len; /* The size of the hash table. */ - __u32 next_ino; /* Next inode number to use for new files. */ - __u16 building_fs; /* Is the file system being built right now? */ - struct jffs_delete_list *delete_list; /* Track deleted files. */ - pid_t thread_pid; /* GC thread's PID */ - struct task_struct *gc_task; /* GC task struct */ - struct completion gc_thread_comp; /* GC thread exit mutex */ - __u32 gc_minfree_threshold; /* GC trigger thresholds */ - __u32 gc_maxdirty_threshold; -}; - - -/* Used to inform about flash status. */ -struct jffs_flash_status -{ - __u32 size; - __u32 used; - __u32 dirty; - __u32 begin; - __u32 end; -}; - -/* This stuff could be used for finding memory leaks. */ -#define JFFS_MEMORY_DEBUG 0 - -extern long no_jffs_node; -#if defined(JFFS_MEMORY_DEBUG) && JFFS_MEMORY_DEBUG -extern long no_jffs_control; -extern long no_jffs_raw_inode; -extern long no_jffs_node_ref; -extern long no_jffs_fm; -extern long no_jffs_fmcontrol; -extern long no_hash; -extern long no_name; -#define DJM(x) x -#else -#define DJM(x) -#endif - -#endif /* __LINUX_JFFS_H__ */ diff --git a/include/linux/kexec.h b/include/linux/kexec.h index d02425cdd80..696e5ec63f7 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -125,6 +125,7 @@ extern struct kimage *kexec_crash_image; #define KEXEC_ARCH_PPC (20 << 16) #define KEXEC_ARCH_PPC64 (21 << 16) #define KEXEC_ARCH_IA_64 (50 << 16) +#define KEXEC_ARCH_ARM (40 << 16) #define KEXEC_ARCH_S390 (22 << 16) #define KEXEC_ARCH_SH (42 << 16) #define KEXEC_ARCH_MIPS_LE (10 << 16) diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 10f505c8431..cc8e674ae27 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -28,8 +28,10 @@ #ifdef CONFIG_KMOD /* modprobe exit status on success, -ve on error. Return value * usually useless though. */ +extern void kmod_sysfs_init(void); extern int request_module(const char * name, ...) __attribute__ ((format (printf, 1, 2))); #else +static inline void kmod_sysfs_init(void) {}; static inline int request_module(const char * name, ...) { return -ENOSYS; } #endif diff --git a/include/linux/libata.h b/include/linux/libata.h index b870b20df43..86762a9f52b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -35,6 +35,7 @@ #include <linux/ata.h> #include <linux/workqueue.h> #include <scsi/scsi_host.h> +#include <linux/acpi.h> /* * Define if arch has non-standard setup. This is a _PCI_ standard @@ -495,6 +496,10 @@ struct ata_device { /* error history */ struct ata_ering ering; unsigned int horkage; /* List of broken features */ +#ifdef CONFIG_SATA_ACPI + /* ACPI objects info */ + acpi_handle obj_handle; +#endif }; /* Offset into struct ata_device. Fields above it are maintained diff --git a/include/linux/module.h b/include/linux/module.h index 419d3ef293d..95679eb8571 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -76,8 +76,6 @@ void sort_extable(struct exception_table_entry *start, struct exception_table_entry *finish); void sort_main_extable(void); -extern struct subsystem module_subsys; - #ifdef MODULE #define MODULE_GENERIC_TABLE(gtype,name) \ extern const struct gtype##_id __mod_##gtype##_table \ @@ -467,10 +465,6 @@ int unregister_module_notifier(struct notifier_block * nb); extern void print_modules(void); -struct device_driver; -void module_add_driver(struct module *, struct device_driver *); -void module_remove_driver(struct device_driver *); - #else /* !CONFIG_MODULES... */ #define EXPORT_SYMBOL(sym) #define EXPORT_SYMBOL_GPL(sym) @@ -568,18 +562,59 @@ static inline void print_modules(void) { } +#endif /* CONFIG_MODULES */ + struct device_driver; +#ifdef CONFIG_SYSFS struct module; -static inline void module_add_driver(struct module *module, struct device_driver *driver) +extern struct subsystem module_subsys; + +int mod_sysfs_init(struct module *mod); +int mod_sysfs_setup(struct module *mod, + struct kernel_param *kparam, + unsigned int num_params); +int module_add_modinfo_attrs(struct module *mod); +void module_remove_modinfo_attrs(struct module *mod); + +#else /* !CONFIG_SYSFS */ + +static inline int mod_sysfs_init(struct module *mod) { + return 0; } -static inline void module_remove_driver(struct device_driver *driver) +static inline int mod_sysfs_setup(struct module *mod, + struct kernel_param *kparam, + unsigned int num_params) { + return 0; } -#endif /* CONFIG_MODULES */ +static inline int module_add_modinfo_attrs(struct module *mod) +{ + return 0; +} + +static inline void module_remove_modinfo_attrs(struct module *mod) +{ } + +#endif /* CONFIG_SYSFS */ + +#if defined(CONFIG_SYSFS) && defined(CONFIG_MODULES) + +void module_add_driver(struct module *mod, struct device_driver *drv); +void module_remove_driver(struct device_driver *drv); + +#else /* not both CONFIG_SYSFS && CONFIG_MODULES */ + +static inline void module_add_driver(struct module *mod, struct device_driver *drv) +{ } + +static inline void module_remove_driver(struct device_driver *drv) +{ } + +#endif #define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x) diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index bb151bcaad4..c83588c8d08 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -169,10 +169,22 @@ extern int param_get_string(char *buffer, struct kernel_param *kp); struct module; +#if defined(CONFIG_SYSFS) && defined(CONFIG_MODULES) extern int module_param_sysfs_setup(struct module *mod, struct kernel_param *kparam, unsigned int num_params); extern void module_param_sysfs_remove(struct module *mod); +#else +static inline int module_param_sysfs_setup(struct module *mod, + struct kernel_param *kparam, + unsigned int num_params) +{ + return 0; +} + +static inline void module_param_sysfs_remove(struct module *mod) +{ } +#endif #endif /* _LINUX_MODULE_PARAMS_H */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 98c8765a488..2c4b6842dfb 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -854,5 +854,8 @@ extern int pci_pci_problems; #define PCIPCI_ALIMAGIK 32 /* Need low latency setting */ #define PCIAGP_FAIL 64 /* No PCI to AGP DMA */ +extern unsigned long pci_cardbus_io_size; +extern unsigned long pci_cardbus_mem_size; + #endif /* __KERNEL__ */ #endif /* LINUX_PCI_H */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 182a96f77c8..600308fdf9c 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2089,6 +2089,7 @@ #define PCI_VENDOR_ID_PASEMI 0x1959 #define PCI_VENDOR_ID_ATTANSIC 0x1969 +#define PCI_DEVICE_ID_ATTANSIC_L1 0x1048 #define PCI_VENDOR_ID_JMICRON 0x197B #define PCI_DEVICE_ID_JMICRON_JMB360 0x2360 diff --git a/include/linux/usb.h b/include/linux/usb.h index b5c226a87ed..a8e8d1ecebb 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -935,7 +935,7 @@ struct usb_iso_packet_descriptor { unsigned int offset; unsigned int length; /* expected length */ unsigned int actual_length; - unsigned int status; + int status; }; struct urb; diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h index ba617c37245..956edf3bbec 100644 --- a/include/linux/usb/cdc.h +++ b/include/linux/usb/cdc.h @@ -73,6 +73,13 @@ struct usb_cdc_acm_descriptor { __u8 bmCapabilities; } __attribute__ ((packed)); +/* capabilities from 5.2.3.3 */ + +#define USB_CDC_COMM_FEATURE 0x01 +#define USB_CDC_CAP_LINE 0x02 +#define USB_CDC_CAP_BRK 0x04 +#define USB_CDC_CAP_NOTIFY 0x08 + /* "Union Functional Descriptor" from CDC spec 5.2.3.8 */ struct usb_cdc_union_desc { __u8 bLength; diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index ae7833749fa..245c7253122 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -367,7 +367,7 @@ struct usb_debug_descriptor { /* bulk endpoints with 8 byte maxpacket */ __u8 bDebugInEndpoint; __u8 bDebugOutEndpoint; -}; +} __attribute__((packed)); /*-------------------------------------------------------------------------*/ @@ -396,7 +396,7 @@ struct usb_security_descriptor { __le16 wTotalLength; __u8 bNumEncryptionTypes; -}; +} __attribute__((packed)); /*-------------------------------------------------------------------------*/ @@ -410,7 +410,7 @@ struct usb_key_descriptor { __u8 tTKID[3]; __u8 bReserved; __u8 bKeyData[0]; -}; +} __attribute__((packed)); /*-------------------------------------------------------------------------*/ @@ -426,7 +426,7 @@ struct usb_encryption_descriptor { #define USB_ENC_TYPE_RSA_1 3 /* rsa3072/sha1 auth */ __u8 bEncryptionValue; /* use in SET_ENCRYPTION */ __u8 bAuthKeyIndex; -}; +} __attribute__((packed)); /*-------------------------------------------------------------------------*/ @@ -438,7 +438,7 @@ struct usb_bos_descriptor { __le16 wTotalLength; __u8 bNumDeviceCaps; -}; +} __attribute__((packed)); /*-------------------------------------------------------------------------*/ @@ -447,7 +447,7 @@ struct usb_dev_cap_header { __u8 bLength; __u8 bDescriptorType; __u8 bDevCapabilityType; -}; +} __attribute__((packed)); #define USB_CAP_TYPE_WIRELESS_USB 1 @@ -475,7 +475,7 @@ struct usb_wireless_cap_descriptor { /* Ultra Wide Band */ __u8 bmFFITXPowerInfo; /* FFI power levels */ __le16 bmBandGroup; __u8 bReserved; -}; +} __attribute__((packed)); /*-------------------------------------------------------------------------*/ @@ -496,7 +496,7 @@ struct usb_wireless_ep_comp_descriptor { #define USB_ENDPOINT_SWITCH_NO 0 #define USB_ENDPOINT_SWITCH_SWITCH 1 #define USB_ENDPOINT_SWITCH_SCALE 2 -}; +} __attribute__((packed)); /*-------------------------------------------------------------------------*/ @@ -512,7 +512,7 @@ struct usb_handshake { __u8 CDID[16]; __u8 nonce[16]; __u8 MIC[8]; -}; +} __attribute__((packed)); /*-------------------------------------------------------------------------*/ @@ -524,7 +524,7 @@ struct usb_connection_context { __u8 CHID[16]; /* persistent host id */ __u8 CDID[16]; /* device id (unique w/in host context) */ __u8 CK[16]; /* connection key */ -}; +} __attribute__((packed)); /*-------------------------------------------------------------------------*/ diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 33dcd857669..32acbae28d2 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -54,6 +54,8 @@ * @write_wait: a wait_queue_head_t used by the port. * @work: work queue entry for the line discipline waking up. * @open_count: number of times this port has been opened. + * @throttled: nonzero if the read urb is inactive to throttle the device + * @throttle_req: nonzero if the tty wants to throttle us * * This structure is used by the usb-serial core and drivers for the specific * ports of a device. @@ -88,6 +90,8 @@ struct usb_serial_port { wait_queue_head_t write_wait; struct work_struct work; int open_count; + char throttled; + char throttle_req; struct device dev; }; #define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev) @@ -269,6 +273,8 @@ extern int usb_serial_generic_write_room (struct usb_serial_port *port); extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port); extern void usb_serial_generic_read_bulk_callback (struct urb *urb); extern void usb_serial_generic_write_bulk_callback (struct urb *urb); +extern void usb_serial_generic_throttle (struct usb_serial_port *port); +extern void usb_serial_generic_unthrottle (struct usb_serial_port *port); extern void usb_serial_generic_shutdown (struct usb_serial *serial); extern int usb_serial_generic_register (int debug); extern void usb_serial_generic_deregister (void); diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h index 2ae76fe52ff..1b792b9286b 100644 --- a/include/linux/usb_usual.h +++ b/include/linux/usb_usual.h @@ -46,7 +46,9 @@ US_FLAG(MAX_SECTORS_64, 0x00000400) \ /* Sets max_sectors to 64 */ \ US_FLAG(IGNORE_DEVICE, 0x00000800) \ - /* Don't claim device */ + /* Don't claim device */ \ + US_FLAG(CAPACITY_HEURISTICS, 0x00001000) \ + /* sometimes sizes is too big */ #define US_FLAG(name, value) US_FL_##name = value , enum { US_DO_ALL_FLAGS }; diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h index 617d8a1c59a..342dd5a7e8b 100644 --- a/include/linux/usbdevice_fs.h +++ b/include/linux/usbdevice_fs.h @@ -159,9 +159,9 @@ struct usbdevfs_ioctl32 { #define USBDEVFS_SUBMITURB32 _IOR('U', 10, struct usbdevfs_urb32) #define USBDEVFS_DISCARDURB _IO('U', 11) #define USBDEVFS_REAPURB _IOW('U', 12, void *) -#define USBDEVFS_REAPURB32 _IOW('U', 12, u32) +#define USBDEVFS_REAPURB32 _IOW('U', 12, __u32) #define USBDEVFS_REAPURBNDELAY _IOW('U', 13, void *) -#define USBDEVFS_REAPURBNDELAY32 _IOW('U', 13, u32) +#define USBDEVFS_REAPURBNDELAY32 _IOW('U', 13, __u32) #define USBDEVFS_DISCSIGNAL _IOR('U', 14, struct usbdevfs_disconnectsignal) #define USBDEVFS_CLAIMINTERFACE _IOR('U', 15, unsigned int) #define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int) diff --git a/include/pcmcia/ciscode.h b/include/pcmcia/ciscode.h index c1da8558339..eae7e2e8449 100644 --- a/include/pcmcia/ciscode.h +++ b/include/pcmcia/ciscode.h @@ -95,6 +95,7 @@ #define PRODID_QUATECH_DUAL_RS232 0x0012 #define PRODID_QUATECH_DUAL_RS232_D1 0x0007 #define PRODID_QUATECH_DUAL_RS232_D2 0x0052 +#define PRODID_QUATECH_DUAL_RS232_G 0x004d #define PRODID_QUATECH_QUAD_RS232 0x001b #define PRODID_QUATECH_DUAL_RS422 0x000e #define PRODID_QUATECH_QUAD_RS422 0x0045 diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h index c094e501286..c36750ff6ae 100644 --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -110,6 +110,12 @@ static inline void ib_addr_set_pkey(struct rdma_dev_addr *dev_addr, u16 pkey) dev_addr->broadcast[9] = (unsigned char) pkey; } +static inline void ib_addr_get_mgid(struct rdma_dev_addr *dev_addr, + union ib_gid *gid) +{ + memcpy(gid, dev_addr->broadcast + 4, sizeof *gid); +} + static inline void ib_addr_get_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) { diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index 97715b0c20b..5e26b2f53f8 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h @@ -285,18 +285,6 @@ int ib_sa_path_rec_get(struct ib_sa_client *client, void *context, struct ib_sa_query **query); -int ib_sa_mcmember_rec_query(struct ib_sa_client *client, - struct ib_device *device, u8 port_num, - u8 method, - struct ib_sa_mcmember_rec *rec, - ib_sa_comp_mask comp_mask, - int timeout_ms, gfp_t gfp_mask, - void (*callback)(int status, - struct ib_sa_mcmember_rec *resp, - void *context), - void *context, - struct ib_sa_query **query); - int ib_sa_service_rec_query(struct ib_sa_client *client, struct ib_device *device, u8 port_num, u8 method, @@ -309,93 +297,82 @@ int ib_sa_service_rec_query(struct ib_sa_client *client, void *context, struct ib_sa_query **sa_query); +struct ib_sa_multicast { + struct ib_sa_mcmember_rec rec; + ib_sa_comp_mask comp_mask; + int (*callback)(int status, + struct ib_sa_multicast *multicast); + void *context; +}; + /** - * ib_sa_mcmember_rec_set - Start an MCMember set query - * @client:SA client - * @device:device to send query on - * @port_num: port number to send query on - * @rec:MCMember Record to send in query - * @comp_mask:component mask to send in query - * @timeout_ms:time to wait for response - * @gfp_mask:GFP mask to use for internal allocations - * @callback:function called when query completes, times out or is - * canceled - * @context:opaque user context passed to callback - * @sa_query:query context, used to cancel query + * ib_sa_join_multicast - Initiates a join request to the specified multicast + * group. + * @client: SA client + * @device: Device associated with the multicast group. + * @port_num: Port on the specified device to associate with the multicast + * group. + * @rec: SA multicast member record specifying group attributes. + * @comp_mask: Component mask indicating which group attributes of %rec are + * valid. + * @gfp_mask: GFP mask for memory allocations. + * @callback: User callback invoked once the join operation completes. + * @context: User specified context stored with the ib_sa_multicast structure. * - * Send an MCMember Set query to the SA (eg to join a multicast - * group). The callback function will be called when the query - * completes (or fails); status is 0 for a successful response, -EINTR - * if the query is canceled, -ETIMEDOUT is the query timed out, or - * -EIO if an error occurred sending the query. The resp parameter of - * the callback is only valid if status is 0. + * This call initiates a multicast join request with the SA for the specified + * multicast group. If the join operation is started successfully, it returns + * an ib_sa_multicast structure that is used to track the multicast operation. + * Users must free this structure by calling ib_free_multicast, even if the + * join operation later fails. (The callback status is non-zero.) * - * If the return value of ib_sa_mcmember_rec_set() is negative, it is - * an error code. Otherwise it is a query ID that can be used to - * cancel the query. + * If the join operation fails; status will be non-zero, with the following + * failures possible: + * -ETIMEDOUT: The request timed out. + * -EIO: An error occurred sending the query. + * -EINVAL: The MCMemberRecord values differed from the existing group's. + * -ENETRESET: Indicates that an fatal error has occurred on the multicast + * group, and the user must rejoin the group to continue using it. */ -static inline int -ib_sa_mcmember_rec_set(struct ib_sa_client *client, - struct ib_device *device, u8 port_num, - struct ib_sa_mcmember_rec *rec, - ib_sa_comp_mask comp_mask, - int timeout_ms, gfp_t gfp_mask, - void (*callback)(int status, - struct ib_sa_mcmember_rec *resp, - void *context), - void *context, - struct ib_sa_query **query) -{ - return ib_sa_mcmember_rec_query(client, device, port_num, - IB_MGMT_METHOD_SET, - rec, comp_mask, - timeout_ms, gfp_mask, callback, - context, query); -} +struct ib_sa_multicast *ib_sa_join_multicast(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + struct ib_sa_mcmember_rec *rec, + ib_sa_comp_mask comp_mask, gfp_t gfp_mask, + int (*callback)(int status, + struct ib_sa_multicast + *multicast), + void *context); /** - * ib_sa_mcmember_rec_delete - Start an MCMember delete query - * @client:SA client - * @device:device to send query on - * @port_num: port number to send query on - * @rec:MCMember Record to send in query - * @comp_mask:component mask to send in query - * @timeout_ms:time to wait for response - * @gfp_mask:GFP mask to use for internal allocations - * @callback:function called when query completes, times out or is - * canceled - * @context:opaque user context passed to callback - * @sa_query:query context, used to cancel query - * - * Send an MCMember Delete query to the SA (eg to leave a multicast - * group). The callback function will be called when the query - * completes (or fails); status is 0 for a successful response, -EINTR - * if the query is canceled, -ETIMEDOUT is the query timed out, or - * -EIO if an error occurred sending the query. The resp parameter of - * the callback is only valid if status is 0. + * ib_free_multicast - Frees the multicast tracking structure, and releases + * any reference on the multicast group. + * @multicast: Multicast tracking structure allocated by ib_join_multicast. * - * If the return value of ib_sa_mcmember_rec_delete() is negative, it - * is an error code. Otherwise it is a query ID that can be used to - * cancel the query. + * This call blocks until the multicast identifier is destroyed. It may + * not be called from within the multicast callback; however, returning a non- + * zero value from the callback will result in destroying the multicast + * tracking structure. + */ +void ib_sa_free_multicast(struct ib_sa_multicast *multicast); + +/** + * ib_get_mcmember_rec - Looks up a multicast member record by its MGID and + * returns it if found. + * @device: Device associated with the multicast group. + * @port_num: Port on the specified device to associate with the multicast + * group. + * @mgid: MGID of multicast group. + * @rec: Location to copy SA multicast member record. */ -static inline int -ib_sa_mcmember_rec_delete(struct ib_sa_client *client, - struct ib_device *device, u8 port_num, - struct ib_sa_mcmember_rec *rec, - ib_sa_comp_mask comp_mask, - int timeout_ms, gfp_t gfp_mask, - void (*callback)(int status, - struct ib_sa_mcmember_rec *resp, - void *context), - void *context, - struct ib_sa_query **query) -{ - return ib_sa_mcmember_rec_query(client, device, port_num, - IB_SA_METHOD_DELETE, - rec, comp_mask, - timeout_ms, gfp_mask, callback, - context, query); -} +int ib_sa_get_mcmember_rec(struct ib_device *device, u8 port_num, + union ib_gid *mgid, struct ib_sa_mcmember_rec *rec); + +/** + * ib_init_ah_from_mcmember - Initialize address handle attributes based on + * an SA multicast member record. + */ +int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num, + struct ib_sa_mcmember_rec *rec, + struct ib_ah_attr *ah_attr); /** * ib_init_ah_from_path - Initialize address handle attributes based on an SA diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index 36cd8a8526a..2d6a7705eae 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -52,10 +52,13 @@ enum rdma_cm_event_type { RDMA_CM_EVENT_ESTABLISHED, RDMA_CM_EVENT_DISCONNECTED, RDMA_CM_EVENT_DEVICE_REMOVAL, + RDMA_CM_EVENT_MULTICAST_JOIN, + RDMA_CM_EVENT_MULTICAST_ERROR }; enum rdma_port_space { RDMA_PS_SDP = 0x0001, + RDMA_PS_IPOIB= 0x0002, RDMA_PS_TCP = 0x0106, RDMA_PS_UDP = 0x0111, RDMA_PS_SCTP = 0x0183 @@ -294,5 +297,21 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data, */ int rdma_disconnect(struct rdma_cm_id *id); -#endif /* RDMA_CM_H */ +/** + * rdma_join_multicast - Join the multicast group specified by the given + * address. + * @id: Communication identifier associated with the request. + * @addr: Multicast address identifying the group to join. + * @context: User-defined context associated with the join request, returned + * to the user through the private_data pointer in multicast events. + */ +int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, + void *context); +/** + * rdma_leave_multicast - Leave the multicast group specified by the given + * address. + */ +void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr); + +#endif /* RDMA_CM_H */ diff --git a/include/rdma/rdma_cm_ib.h b/include/rdma/rdma_cm_ib.h index 9b176df1d66..950424b38f1 100644 --- a/include/rdma/rdma_cm_ib.h +++ b/include/rdma/rdma_cm_ib.h @@ -44,7 +44,7 @@ int rdma_set_ib_paths(struct rdma_cm_id *id, struct ib_sa_path_rec *path_rec, int num_paths); -/* Global qkey for UD QPs and multicast groups. */ -#define RDMA_UD_QKEY 0x01234567 +/* Global qkey for UDP QPs and multicast groups. */ +#define RDMA_UDP_QKEY 0x01234567 #endif /* RDMA_CM_IB_H */ diff --git a/include/rdma/rdma_user_cm.h b/include/rdma/rdma_user_cm.h index 9572ab8eeac..f632b0c007c 100644 --- a/include/rdma/rdma_user_cm.h +++ b/include/rdma/rdma_user_cm.h @@ -38,7 +38,7 @@ #include <rdma/ib_user_verbs.h> #include <rdma/ib_user_sa.h> -#define RDMA_USER_CM_ABI_VERSION 3 +#define RDMA_USER_CM_ABI_VERSION 4 #define RDMA_MAX_PRIVATE_DATA 256 @@ -58,7 +58,9 @@ enum { RDMA_USER_CM_CMD_GET_EVENT, RDMA_USER_CM_CMD_GET_OPTION, RDMA_USER_CM_CMD_SET_OPTION, - RDMA_USER_CM_CMD_NOTIFY + RDMA_USER_CM_CMD_NOTIFY, + RDMA_USER_CM_CMD_JOIN_MCAST, + RDMA_USER_CM_CMD_LEAVE_MCAST }; /* @@ -188,6 +190,13 @@ struct rdma_ucm_notify { __u32 event; }; +struct rdma_ucm_join_mcast { + __u64 response; /* rdma_ucm_create_id_resp */ + __u64 uid; + struct sockaddr_in6 addr; + __u32 id; +}; + struct rdma_ucm_get_event { __u64 response; }; diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index ebf31b16dc4..9dd37e2f5a8 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -122,6 +122,7 @@ struct scsi_device { unsigned no_uld_attach:1; /* disable connecting to upper level drivers */ unsigned select_no_atn:1; unsigned fix_capacity:1; /* READ_CAPACITY is too high by 1 */ + unsigned guess_capacity:1; /* READ_CAPACITY might be too high by 1 */ unsigned retry_hwerror:1; /* Retry HARDWARE_ERROR */ unsigned int device_blocked; /* Device returned QUEUE_FULL. */ diff --git a/kernel/kmod.c b/kernel/kmod.c index 796276141e5..9f923f8ce6a 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -36,6 +36,8 @@ #include <linux/resource.h> #include <asm/uaccess.h> +extern int delete_module(const char *name, unsigned int flags); + extern int max_threads; static struct workqueue_struct *khelper_wq; @@ -46,6 +48,7 @@ static struct workqueue_struct *khelper_wq; modprobe_path is set via /proc/sys. */ char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; +struct module_kobject kmod_mk; /** * request_module - try to load a kernel module @@ -75,6 +78,11 @@ int request_module(const char *fmt, ...) static atomic_t kmod_concurrent = ATOMIC_INIT(0); #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ static int kmod_loop_msg; + char modalias[16 + MODULE_NAME_LEN] = "MODALIAS="; + char *uevent_envp[2] = { + modalias, + NULL + }; va_start(args, fmt); ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); @@ -82,6 +90,12 @@ int request_module(const char *fmt, ...) if (ret >= MODULE_NAME_LEN) return -ENAMETOOLONG; + strcpy(&modalias[strlen("MODALIAS=")], module_name); + kobject_uevent_env(&kmod_mk.kobj, KOBJ_CHANGE, uevent_envp); + + if (modprobe_path[0] == '\0') + goto out; + /* If modprobe needs a service that is in a module, we get a recursive * loop. Limit the number of running kmod threads to max_threads/2 or * MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method @@ -108,9 +122,115 @@ int request_module(const char *fmt, ...) ret = call_usermodehelper(modprobe_path, argv, envp, 1); atomic_dec(&kmod_concurrent); +out: return ret; } EXPORT_SYMBOL(request_module); + +static ssize_t store_mod_request(struct module_attribute *mattr, + struct module *mod, + const char *buffer, size_t count) +{ + char name[MODULE_NAME_LEN]; + int ret; + + if (count < 1 || count+1 > MODULE_NAME_LEN) + return -EINVAL; + memcpy(name, buffer, count); + name[count] = '\0'; + if (name[count-1] == '\n') + name[count-1] = '\0'; + + ret = request_module(name); + if (ret < 0) + return ret; + return count; +} + +static struct module_attribute mod_request = { + .attr = { .name = "mod_request", .mode = S_IWUSR, .owner = THIS_MODULE }, + .store = store_mod_request, +}; + +#ifdef CONFIG_MODULE_UNLOAD +static ssize_t store_mod_unload(struct module_attribute *mattr, + struct module *mod, + const char *buffer, size_t count) +{ + char name[MODULE_NAME_LEN]; + int ret; + + if (count < 1 || count+1 > MODULE_NAME_LEN) + return -EINVAL; + memcpy(name, buffer, count); + name[count] = '\0'; + if (name[count-1] == '\n') + name[count-1] = '\0'; + + ret = delete_module(name, O_NONBLOCK); + if (ret < 0) + return ret; + return count; +} + +static struct module_attribute mod_unload = { + .attr = { .name = "mod_unload", .mode = S_IWUSR, .owner = THIS_MODULE }, + .store = store_mod_unload, +}; +#endif + +static ssize_t show_mod_request_helper(struct module_attribute *mattr, + struct module *mod, + char *buffer) +{ + return sprintf(buffer, "%s\n", modprobe_path); +} + +static ssize_t store_mod_request_helper(struct module_attribute *mattr, + struct module *mod, + const char *buffer, size_t count) +{ + if (count < 1 || count+1 > KMOD_PATH_LEN) + return -EINVAL; + memcpy(modprobe_path, buffer, count); + modprobe_path[count] = '\0'; + if (modprobe_path[count-1] == '\n') + modprobe_path[count-1] = '\0'; + return count; +} + +static struct module_attribute mod_request_helper = { + .attr = { + .name = "mod_request_helper", + .mode = S_IWUSR | S_IRUGO, + .owner = THIS_MODULE + }, + .show = show_mod_request_helper, + .store = store_mod_request_helper, +}; + +void __init kmod_sysfs_init(void) +{ + int ret; + + kmod_mk.mod = THIS_MODULE; + kobj_set_kset_s(&kmod_mk, module_subsys); + kobject_set_name(&kmod_mk.kobj, "kmod"); + kobject_init(&kmod_mk.kobj); + ret = kobject_add(&kmod_mk.kobj); + if (ret < 0) + goto out; + + ret = sysfs_create_file(&kmod_mk.kobj, &mod_request_helper.attr); + ret = sysfs_create_file(&kmod_mk.kobj, &mod_request.attr); +#ifdef CONFIG_MODULE_UNLOAD + ret = sysfs_create_file(&kmod_mk.kobj, &mod_unload.attr); +#endif + + kobject_uevent(&kmod_mk.kobj, KOBJ_ADD); +out: + return; +} #endif /* CONFIG_KMOD */ struct subprocess_info { diff --git a/kernel/module.c b/kernel/module.c index 8a94e054230..8c25b1a04fa 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -653,20 +653,11 @@ static void wait_for_zero_refcount(struct module *mod) mutex_lock(&module_mutex); } -asmlinkage long -sys_delete_module(const char __user *name_user, unsigned int flags) +int delete_module(const char *name, unsigned int flags) { struct module *mod; - char name[MODULE_NAME_LEN]; int ret, forced = 0; - if (!capable(CAP_SYS_MODULE)) - return -EPERM; - - if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) - return -EFAULT; - name[MODULE_NAME_LEN-1] = '\0'; - if (mutex_lock_interruptible(&module_mutex) != 0) return -EINTR; @@ -727,6 +718,21 @@ sys_delete_module(const char __user *name_user, unsigned int flags) return ret; } +asmlinkage long +sys_delete_module(const char __user *name_user, unsigned int flags) +{ + char name[MODULE_NAME_LEN]; + + if (!capable(CAP_SYS_MODULE)) + return -EPERM; + + if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) + return -EFAULT; + name[MODULE_NAME_LEN-1] = '\0'; + + return delete_module(name, flags); +} + static void print_unload_info(struct seq_file *m, struct module *mod) { struct module_use *use; @@ -1068,7 +1074,8 @@ static inline void remove_sect_attrs(struct module *mod) } #endif /* CONFIG_KALLSYMS */ -static int module_add_modinfo_attrs(struct module *mod) +#ifdef CONFIG_SYSFS +int module_add_modinfo_attrs(struct module *mod) { struct module_attribute *attr; struct module_attribute *temp_attr; @@ -1094,7 +1101,7 @@ static int module_add_modinfo_attrs(struct module *mod) return error; } -static void module_remove_modinfo_attrs(struct module *mod) +void module_remove_modinfo_attrs(struct module *mod) { struct module_attribute *attr; int i; @@ -1109,8 +1116,10 @@ static void module_remove_modinfo_attrs(struct module *mod) } kfree(mod->modinfo_attrs); } +#endif -static int mod_sysfs_init(struct module *mod) +#ifdef CONFIG_SYSFS +int mod_sysfs_init(struct module *mod) { int err; @@ -1133,7 +1142,7 @@ out: return err; } -static int mod_sysfs_setup(struct module *mod, +int mod_sysfs_setup(struct module *mod, struct kernel_param *kparam, unsigned int num_params) { @@ -1169,16 +1178,14 @@ out_unreg: out: return err; } +#endif static void mod_kobject_remove(struct module *mod) { module_remove_modinfo_attrs(mod); module_param_sysfs_remove(mod); - if (mod->mkobj.drivers_dir) - kobject_unregister(mod->mkobj.drivers_dir); - if (mod->holders_dir) - kobject_unregister(mod->holders_dir); - + kobject_unregister(mod->mkobj.drivers_dir); + kobject_unregister(mod->holders_dir); kobject_unregister(&mod->mkobj.kobj); } @@ -2345,6 +2352,7 @@ void print_modules(void) printk("\n"); } +#ifdef CONFIG_SYSFS static char *make_driver_name(struct device_driver *drv) { char *driver_name; @@ -2419,6 +2427,7 @@ void module_remove_driver(struct device_driver *drv) } } EXPORT_SYMBOL(module_remove_driver); +#endif #ifdef CONFIG_MODVERSIONS /* Generate the signature for struct module here, too, for modversions. */ diff --git a/kernel/params.c b/kernel/params.c index 553cf7d6a4b..7a751570b56 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -30,8 +30,6 @@ #define DEBUGP(fmt, a...) #endif -static struct kobj_type module_ktype; - static inline char dash2underscore(char c) { if (c == '-') @@ -391,6 +389,7 @@ struct module_param_attrs struct param_attribute attrs[0]; }; +#ifdef CONFIG_SYSFS #define to_param_attr(n) container_of(n, struct param_attribute, mattr); static ssize_t param_attr_show(struct module_attribute *mattr, @@ -426,6 +425,7 @@ static ssize_t param_attr_store(struct module_attribute *mattr, return len; return err; } +#endif #ifdef CONFIG_MODULES #define __modinit @@ -433,6 +433,7 @@ static ssize_t param_attr_store(struct module_attribute *mattr, #define __modinit __init #endif +#ifdef CONFIG_SYSFS /* * param_sysfs_setup - setup sysfs support for one module or KBUILD_MODNAME * @mk: struct module_kobject (contains parent kobject) @@ -500,9 +501,7 @@ param_sysfs_setup(struct module_kobject *mk, return mp; } - #ifdef CONFIG_MODULES - /* * module_param_sysfs_setup - setup sysfs support for one module * @mod: module @@ -625,7 +624,6 @@ static void __init param_sysfs_builtin(void) /* module-related sysfs stuff */ -#ifdef CONFIG_SYSFS #define to_module_attr(n) container_of(n, struct module_attribute, attr); #define to_module_kobject(n) container_of(n, struct module_kobject, kobj); @@ -673,6 +671,8 @@ static struct sysfs_ops module_sysfs_ops = { .store = module_attr_store, }; +static struct kobj_type module_ktype; + static int uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); @@ -686,19 +686,12 @@ static struct kset_uevent_ops module_uevent_ops = { .filter = uevent_filter, }; -#else -static struct sysfs_ops module_sysfs_ops = { - .show = NULL, - .store = NULL, -}; -#endif +decl_subsys(module, &module_ktype, &module_uevent_ops); static struct kobj_type module_ktype = { .sysfs_ops = &module_sysfs_ops, }; -decl_subsys(module, &module_ktype, &module_uevent_ops); - /* * param_sysfs_init - wrapper for built-in params support */ @@ -714,11 +707,21 @@ static int __init param_sysfs_init(void) } param_sysfs_builtin(); + kmod_sysfs_init(); return 0; } subsys_initcall(param_sysfs_init); +#else +#if 0 +static struct sysfs_ops module_sysfs_ops = { + .show = NULL, + .store = NULL, +}; +#endif +#endif + EXPORT_SYMBOL(param_set_byte); EXPORT_SYMBOL(param_get_byte); EXPORT_SYMBOL(param_set_short); diff --git a/lib/kobject.c b/lib/kobject.c index 2782f49e906..f4f6176dcd1 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -171,7 +171,7 @@ int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent) return -ENOENT; if (!kobj->k_name) kobj->k_name = kobj->name; - if (!kobj->k_name) { + if (!*kobj->k_name) { pr_debug("kobject attempted to be registered with no name!\n"); WARN_ON(1); return -EINVAL; @@ -326,6 +326,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name) /** * kobject_rename - change the name of an object * @kobj: object in question. + * @new_parent: object's new parent * @new_name: object's new name */ diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 6189dc03108..4cbb1290a6a 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -340,7 +340,7 @@ static struct attribute_group netstat_group = { .attrs = netstat_attrs, }; -#ifdef WIRELESS_EXT +#ifdef CONFIG_WIRELESS_EXT /* helper function that does all the locking etc for wireless stats */ static ssize_t wireless_show(struct device *d, char *buf, ssize_t (*format)(const struct iw_statistics *, @@ -473,7 +473,7 @@ int netdev_register_sysfs(struct net_device *net) if (net->get_stats) *groups++ = &netstat_group; -#ifdef WIRELESS_EXT +#ifdef CONFIG_WIRELESS_EXT if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats) *groups++ = &wireless_group; #endif diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index c55949e5c58..0292d6348e1 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -502,9 +502,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) if (host_encrypt) ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); else if (host_build_iv) { - struct ieee80211_crypt_data *crypt; - - crypt = ieee->crypt[ieee->tx_keyidx]; atomic_inc(&crypt->refcnt); if (crypt->ops->build_iv) crypt->ops->build_iv(skb_frag, hdr_len, diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 53675cf4de4..5190d7acdb9 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -65,10 +65,12 @@ static void aaci_ac97_select_codec(struct aaci *aaci, struct snd_ac97 *ac97) * SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR * register. */ -static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) +static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, + unsigned short val) { struct aaci *aaci = ac97->private_data; u32 v; + int timeout = 5000; if (ac97->num >= 4) return; @@ -89,7 +91,11 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned */ do { v = readl(aaci->base + AACI_SLFR); - } while (v & (SLFR_1TXB|SLFR_2TXB)); + } while ((v & (SLFR_1TXB|SLFR_2TXB)) && timeout--); + + if (!timeout) + dev_err(&aaci->dev->dev, + "timeout waiting for write to complete\n"); mutex_unlock(&aaci->ac97_sem); } @@ -101,6 +107,8 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { struct aaci *aaci = ac97->private_data; u32 v; + int timeout = 5000; + int retries = 10; if (ac97->num >= 4) return ~0; @@ -119,7 +127,13 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) */ do { v = readl(aaci->base + AACI_SLFR); - } while (v & SLFR_1TXB); + } while ((v & SLFR_1TXB) && timeout--); + + if (!timeout) { + dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n"); + v = ~0; + goto out; + } /* * Give the AC'97 codec more than enough time @@ -130,21 +144,35 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) /* * Wait for slot 2 to indicate data. */ + timeout = 5000; do { cond_resched(); v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV); - } while (v != (SLFR_1RXV|SLFR_2RXV)); + } while ((v != (SLFR_1RXV|SLFR_2RXV)) && timeout--); - v = readl(aaci->base + AACI_SL1RX) >> 12; - if (v == reg) { - v = readl(aaci->base + AACI_SL2RX) >> 4; - } else { - dev_err(&aaci->dev->dev, - "wrong ac97 register read back (%x != %x)\n", - v, reg); + if (!timeout) { + dev_err(&aaci->dev->dev, "timeout on RX valid\n"); v = ~0; + goto out; } + do { + v = readl(aaci->base + AACI_SL1RX) >> 12; + if (v == reg) { + v = readl(aaci->base + AACI_SL2RX) >> 4; + break; + } else if (--retries) { + dev_warn(&aaci->dev->dev, + "ac97 read back fail. retry\n"); + continue; + } else { + dev_warn(&aaci->dev->dev, + "wrong ac97 register read back (%x != %x)\n", + v, reg); + v = ~0; + } + } while (retries); + out: mutex_unlock(&aaci->ac97_sem); return v; } @@ -164,10 +192,70 @@ static inline void aaci_chan_wait_ready(struct aaci_runtime *aacirun) /* * Interrupt support. */ -static void aaci_fifo_irq(struct aaci *aaci, u32 mask) +static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) { + if (mask & ISR_ORINTR) { + dev_warn(&aaci->dev->dev, "RX overrun on chan %d\n", channel); + writel(ICLR_RXOEC1 << channel, aaci->base + AACI_INTCLR); + } + + if (mask & ISR_RXTOINTR) { + dev_warn(&aaci->dev->dev, "RX timeout on chan %d\n", channel); + writel(ICLR_RXTOFEC1 << channel, aaci->base + AACI_INTCLR); + } + + if (mask & ISR_RXINTR) { + struct aaci_runtime *aacirun = &aaci->capture; + void *ptr; + + if (!aacirun->substream || !aacirun->start) { + dev_warn(&aaci->dev->dev, "RX interrupt???"); + writel(0, aacirun->base + AACI_IE); + return; + } + ptr = aacirun->ptr; + + do { + unsigned int len = aacirun->fifosz; + u32 val; + + if (aacirun->bytes <= 0) { + aacirun->bytes += aacirun->period; + aacirun->ptr = ptr; + spin_unlock(&aaci->lock); + snd_pcm_period_elapsed(aacirun->substream); + spin_lock(&aaci->lock); + } + if (!(aacirun->cr & CR_EN)) + break; + + val = readl(aacirun->base + AACI_SR); + if (!(val & SR_RXHF)) + break; + if (!(val & SR_RXFF)) + len >>= 1; + + aacirun->bytes -= len; + + /* reading 16 bytes at a time */ + for( ; len > 0; len -= 16) { + asm( + "ldmia %1, {r0, r1, r2, r3}\n\t" + "stmia %0!, {r0, r1, r2, r3}" + : "+r" (ptr) + : "r" (aacirun->fifo) + : "r0", "r1", "r2", "r3", "cc"); + + if (ptr >= aacirun->end) + ptr = aacirun->start; + } + } while(1); + aacirun->ptr = ptr; + } + if (mask & ISR_URINTR) { - writel(ICLR_TXUEC1, aaci->base + AACI_INTCLR); + dev_dbg(&aaci->dev->dev, "TX underrun on chan %d\n", channel); + writel(ICLR_TXUEC1 << channel, aaci->base + AACI_INTCLR); } if (mask & ISR_TXINTR) { @@ -192,7 +280,7 @@ static void aaci_fifo_irq(struct aaci *aaci, u32 mask) snd_pcm_period_elapsed(aacirun->substream); spin_lock(&aaci->lock); } - if (!(aacirun->cr & TXCR_TXEN)) + if (!(aacirun->cr & CR_EN)) break; val = readl(aacirun->base + AACI_SR); @@ -233,7 +321,7 @@ static irqreturn_t aaci_irq(int irq, void *devid) u32 m = mask; for (i = 0; i < 4; i++, m >>= 7) { if (m & 0x7f) { - aaci_fifo_irq(aaci, m); + aaci_fifo_irq(aaci, i, m); } } } @@ -330,8 +418,9 @@ static struct snd_pcm_hardware aaci_hw_info = { .periods_max = PAGE_SIZE / 16, }; -static int aaci_pcm_open(struct aaci *aaci, struct snd_pcm_substream *substream, - struct aaci_runtime *aacirun) +static int __aaci_pcm_open(struct aaci *aaci, + struct snd_pcm_substream *substream, + struct aaci_runtime *aacirun) { struct snd_pcm_runtime *runtime = substream->runtime; int ret; @@ -380,7 +469,7 @@ static int aaci_pcm_close(struct snd_pcm_substream *substream) struct aaci *aaci = substream->private_data; struct aaci_runtime *aacirun = substream->runtime->private_data; - WARN_ON(aacirun->cr & TXCR_TXEN); + WARN_ON(aacirun->cr & CR_EN); aacirun->substream = NULL; free_irq(aaci->dev->irq[0], aaci); @@ -395,7 +484,7 @@ static int aaci_pcm_hw_free(struct snd_pcm_substream *substream) /* * This must not be called with the device enabled. */ - WARN_ON(aacirun->cr & TXCR_TXEN); + WARN_ON(aacirun->cr & CR_EN); if (aacirun->pcm_open) snd_ac97_pcm_close(aacirun->pcm); @@ -422,9 +511,15 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) goto out; - err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), - params_channels(params), - aacirun->pcm->r[0].slots); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), + params_channels(params), + aacirun->pcm->r[0].slots); + else + err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), + params_channels(params), + aacirun->pcm->r[1].slots); + if (err) goto out; @@ -467,9 +562,9 @@ static int aaci_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_str * Playback specific ALSA stuff */ static const u32 channels_to_txmask[] = { - [2] = TXCR_TX3 | TXCR_TX4, - [4] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8, - [6] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8 | TXCR_TX6 | TXCR_TX9, + [2] = CR_SL3 | CR_SL4, + [4] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8, + [6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9, }; /* @@ -504,7 +599,7 @@ aaci_rule_channels(struct snd_pcm_hw_params *p, struct snd_pcm_hw_rule *rule) chan_mask); } -static int aaci_pcm_playback_open(struct snd_pcm_substream *substream) +static int aaci_pcm_open(struct snd_pcm_substream *substream) { struct aaci *aaci = substream->private_data; int ret; @@ -519,7 +614,12 @@ static int aaci_pcm_playback_open(struct snd_pcm_substream *substream) if (ret) return ret; - return aaci_pcm_open(aaci, substream, &aaci->playback); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = __aaci_pcm_open(aaci, substream, &aaci->playback); + } else { + ret = __aaci_pcm_open(aaci, substream, &aaci->capture); + } + return ret; } static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream, @@ -540,11 +640,11 @@ static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream, * FIXME: double rate slots? */ if (ret >= 0) { - aacirun->cr = TXCR_FEN | TXCR_COMPACT | TXCR_TSZ16; + aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; aacirun->cr |= channels_to_txmask[channels]; aacirun->fifosz = aaci->fifosize * 4; - if (aacirun->cr & TXCR_COMPACT) + if (aacirun->cr & CR_COMPACT) aacirun->fifosz >>= 1; } return ret; @@ -557,7 +657,7 @@ static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun) ie = readl(aacirun->base + AACI_IE); ie &= ~(IE_URIE|IE_TXIE); writel(ie, aacirun->base + AACI_IE); - aacirun->cr &= ~TXCR_TXEN; + aacirun->cr &= ~CR_EN; aaci_chan_wait_ready(aacirun); writel(aacirun->cr, aacirun->base + AACI_TXCR); } @@ -567,7 +667,7 @@ static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) u32 ie; aaci_chan_wait_ready(aacirun); - aacirun->cr |= TXCR_TXEN; + aacirun->cr |= CR_EN; ie = readl(aacirun->base + AACI_IE); ie |= IE_URIE | IE_TXIE; @@ -615,7 +715,7 @@ static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cm } static struct snd_pcm_ops aaci_playback_ops = { - .open = aaci_pcm_playback_open, + .open = aaci_pcm_open, .close = aaci_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = aaci_pcm_playback_hw_params, @@ -626,7 +726,133 @@ static struct snd_pcm_ops aaci_playback_ops = { .mmap = aaci_pcm_mmap, }; +static int aaci_pcm_capture_hw_params(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t *params) +{ + struct aaci *aaci = substream->private_data; + struct aaci_runtime *aacirun = substream->runtime->private_data; + int ret; + + ret = aaci_pcm_hw_params(substream, aacirun, params); + + if (ret >= 0) { + aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; + + /* Line in record: slot 3 and 4 */ + aacirun->cr |= CR_SL3 | CR_SL4; + + aacirun->fifosz = aaci->fifosize * 4; + + if (aacirun->cr & CR_COMPACT) + aacirun->fifosz >>= 1; + } + return ret; +} + +static void aaci_pcm_capture_stop(struct aaci_runtime *aacirun) +{ + u32 ie; + + aaci_chan_wait_ready(aacirun); + + ie = readl(aacirun->base + AACI_IE); + ie &= ~(IE_ORIE | IE_RXIE); + writel(ie, aacirun->base+AACI_IE); + + aacirun->cr &= ~CR_EN; + + writel(aacirun->cr, aacirun->base + AACI_RXCR); +} + +static void aaci_pcm_capture_start(struct aaci_runtime *aacirun) +{ + u32 ie; + + aaci_chan_wait_ready(aacirun); + +#ifdef DEBUG + /* RX Timeout value: bits 28:17 in RXCR */ + aacirun->cr |= 0xf << 17; +#endif + + aacirun->cr |= CR_EN; + writel(aacirun->cr, aacirun->base + AACI_RXCR); + + ie = readl(aacirun->base + AACI_IE); + ie |= IE_ORIE |IE_RXIE; // overrun and rx interrupt -- half full + writel(ie, aacirun->base + AACI_IE); +} + +static int aaci_pcm_capture_trigger(snd_pcm_substream_t *substream, int cmd){ + + struct aaci *aaci = substream->private_data; + struct aaci_runtime *aacirun = substream->runtime->private_data; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&aaci->lock, flags); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + aaci_pcm_capture_start(aacirun); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + aaci_pcm_capture_start(aacirun); + break; + + case SNDRV_PCM_TRIGGER_STOP: + aaci_pcm_capture_stop(aacirun); + break; + + case SNDRV_PCM_TRIGGER_SUSPEND: + aaci_pcm_capture_stop(aacirun); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + break; + + default: + ret = -EINVAL; + } + + spin_unlock_irqrestore(&aaci->lock, flags); + + return ret; +} +static int aaci_pcm_capture_prepare(snd_pcm_substream_t *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct aaci *aaci = substream->private_data; + + aaci_pcm_prepare(substream); + + /* allow changing of sample rate */ + aaci_ac97_write(aaci->ac97, AC97_EXTENDED_STATUS, 0x0001); /* VRA */ + aaci_ac97_write(aaci->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); + aaci_ac97_write(aaci->ac97, AC97_PCM_MIC_ADC_RATE, runtime->rate); + + /* Record select: Mic: 0, Aux: 3, Line: 4 */ + aaci_ac97_write(aaci->ac97, AC97_REC_SEL, 0x0404); + + return 0; +} + +static snd_pcm_ops_t aaci_capture_ops = { + .open = aaci_pcm_open, + .close = aaci_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = aaci_pcm_capture_hw_params, + .hw_free = aaci_pcm_hw_free, + .prepare = aaci_pcm_capture_prepare, + .trigger = aaci_pcm_capture_trigger, + .pointer = aaci_pcm_pointer, + .mmap = aaci_pcm_mmap, +}; /* * Power Management. @@ -666,7 +892,7 @@ static int aaci_resume(struct amba_device *dev) static struct ac97_pcm ac97_defs[] __devinitdata = { - [0] = { /* Front PCM */ + [0] = { /* Front PCM */ .exclusive = 1, .r = { [0] = { @@ -740,6 +966,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci) ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); if (ret) goto out; + aaci->ac97 = ac97; /* * Disable AC97 PC Beep input on audio codecs. @@ -752,6 +979,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci) goto out; aaci->playback.pcm = &ac97_bus->pcms[0]; + aaci->capture.pcm = &ac97_bus->pcms[1]; out: return ret; @@ -801,7 +1029,7 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) struct snd_pcm *pcm; int ret; - ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 0, &pcm); + ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 1, &pcm); if (ret == 0) { aaci->pcm = pcm; pcm->private_data = aaci; @@ -810,6 +1038,7 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops); } return ret; @@ -817,15 +1046,15 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) static unsigned int __devinit aaci_size_fifo(struct aaci *aaci) { - void __iomem *base = aaci->base + AACI_CSCH1; + struct aaci_runtime *aacirun = &aaci->playback; int i; - writel(TXCR_FEN | TXCR_TSZ16 | TXCR_TXEN, base + AACI_TXCR); + writel(CR_FEN | CR_SZ16 | CR_EN, aacirun->base + AACI_TXCR); - for (i = 0; !(readl(base + AACI_SR) & SR_TXFF) && i < 4096; i++) - writel(0, aaci->base + AACI_DR1); + for (i = 0; !(readl(aacirun->base + AACI_SR) & SR_TXFF) && i < 4096; i++) + writel(0, aacirun->fifo); - writel(0, base + AACI_TXCR); + writel(0, aacirun->base + AACI_TXCR); /* * Re-initialise the AACI after the FIFO depth test, to @@ -872,6 +1101,12 @@ static int __devinit aaci_probe(struct amba_device *dev, void *id) aaci->playback.base = aaci->base + AACI_CSCH1; aaci->playback.fifo = aaci->base + AACI_DR1; + /* + * Capture uses AACI channel 0 + */ + aaci->capture.base = aaci->base + AACI_CSCH1; + aaci->capture.fifo = aaci->base + AACI_DR1; + for (i = 0; i < 4; i++) { void __iomem *base = aaci->base + i * 0x14; @@ -907,7 +1142,7 @@ static int __devinit aaci_probe(struct amba_device *dev, void *id) ret = snd_card_register(aaci->card); if (ret == 0) { dev_info(&dev->dev, "%s, fifo %d\n", aaci->card->longname, - aaci->fifosize); + aaci->fifosize); amba_set_drvdata(dev, aaci->card); return ret; } diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h index 9175ff9ded0..924f69c1c44 100644 --- a/sound/arm/aaci.h +++ b/sound/arm/aaci.h @@ -49,27 +49,27 @@ #define AACI_DR4 0x0f0 /* data read/written fifo 4 */ /* - * transmit fifo control register. P48 + * TX/RX fifo control register (CR). P48 */ -#define TXCR_FEN (1 << 16) /* fifo enable */ -#define TXCR_COMPACT (1 << 15) /* compact mode */ -#define TXCR_TSZ16 (0 << 13) /* 16 bits */ -#define TXCR_TSZ18 (1 << 13) /* 18 bits */ -#define TXCR_TSZ20 (2 << 13) /* 20 bits */ -#define TXCR_TSZ12 (3 << 13) /* 12 bits */ -#define TXCR_TX12 (1 << 12) /* transmits slot 12 */ -#define TXCR_TX11 (1 << 11) /* transmits slot 12 */ -#define TXCR_TX10 (1 << 10) /* transmits slot 12 */ -#define TXCR_TX9 (1 << 9) /* transmits slot 12 */ -#define TXCR_TX8 (1 << 8) /* transmits slot 12 */ -#define TXCR_TX7 (1 << 7) /* transmits slot 12 */ -#define TXCR_TX6 (1 << 6) /* transmits slot 12 */ -#define TXCR_TX5 (1 << 5) /* transmits slot 12 */ -#define TXCR_TX4 (1 << 4) /* transmits slot 12 */ -#define TXCR_TX3 (1 << 3) /* transmits slot 12 */ -#define TXCR_TX2 (1 << 2) /* transmits slot 12 */ -#define TXCR_TX1 (1 << 1) /* transmits slot 12 */ -#define TXCR_TXEN (1 << 0) /* transmit enable */ +#define CR_FEN (1 << 16) /* fifo enable */ +#define CR_COMPACT (1 << 15) /* compact mode */ +#define CR_SZ16 (0 << 13) /* 16 bits */ +#define CR_SZ18 (1 << 13) /* 18 bits */ +#define CR_SZ20 (2 << 13) /* 20 bits */ +#define CR_SZ12 (3 << 13) /* 12 bits */ +#define CR_SL12 (1 << 12) +#define CR_SL11 (1 << 11) +#define CR_SL10 (1 << 10) +#define CR_SL9 (1 << 9) +#define CR_SL8 (1 << 8) +#define CR_SL7 (1 << 7) +#define CR_SL6 (1 << 6) +#define CR_SL5 (1 << 5) +#define CR_SL4 (1 << 4) +#define CR_SL3 (1 << 3) +#define CR_SL2 (1 << 2) +#define CR_SL1 (1 << 1) +#define CR_EN (1 << 0) /* transmit enable */ /* * status register bits. P49 @@ -229,6 +229,7 @@ struct aaci { /* AC'97 */ struct mutex ac97_sem; struct snd_ac97_bus *ac97_bus; + struct snd_ac97 *ac97; u32 maincr; spinlock_t lock; |